Skip to content

Commit

Permalink
Dynamically load libcrypto.so.*
Browse files Browse the repository at this point in the history
This switches the default cryptographic algorithms implementation to
use dlopen libcrypto.so.* rather than linking to it at build time.
That way the applications could use their favorite implementation of
common cryptographic primitives without pulling in the OpenSSL as a
dependency.

Signed-off-by: Daiki Ueno <[email protected]>
  • Loading branch information
ueno committed Nov 6, 2023
1 parent a087f61 commit 76d86e1
Show file tree
Hide file tree
Showing 18 changed files with 561 additions and 270 deletions.
58 changes: 39 additions & 19 deletions src/common/aes/aes_ossl.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

#include "aes.h"

#include <openssl/evp.h>
#include "../ossl_helpers.h"

struct key_schedule {
Expand All @@ -33,17 +32,17 @@ static void AES128_ECB_load_schedule(const uint8_t *key, void **schedule) {
OQS_EXIT_IF_NULLPTR(*schedule, "OpenSSL");
struct key_schedule *ks = (struct key_schedule *) *schedule;
ks->for_ECB = 1;
ks->ctx = EVP_CIPHER_CTX_new();
ks->ctx = _oqs_ossl_EVP_CIPHER_CTX_new();
OQS_EXIT_IF_NULLPTR(ks->ctx, "OpenSSL");
OQS_OPENSSL_GUARD(EVP_EncryptInit_ex(ks->ctx, oqs_aes_128_ecb(), NULL, key, NULL));
EVP_CIPHER_CTX_set_padding(ks->ctx, 0);
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptInit_ex(ks->ctx, oqs_aes_128_ecb(), NULL, key, NULL));
_oqs_ossl_EVP_CIPHER_CTX_set_padding(ks->ctx, 0);
}

static void AES128_free_schedule(void *schedule) {
if (schedule != NULL) {
struct key_schedule *ks = (struct key_schedule *) schedule;
if (ks->ctx != NULL) {
EVP_CIPHER_CTX_free(ks->ctx);
_oqs_ossl_EVP_CIPHER_CTX_free(ks->ctx);
}
OQS_MEM_cleanse(ks->key, 32);
OQS_MEM_secure_free(schedule, sizeof(struct key_schedule));
Expand All @@ -62,26 +61,26 @@ static void AES128_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_
int outlen;
const struct key_schedule *ks = (const struct key_schedule *) schedule;
SIZE_T_TO_INT_OR_EXIT(plaintext_len, plaintext_len_int)
OQS_OPENSSL_GUARD(EVP_EncryptUpdate(ks->ctx, ciphertext, &outlen, plaintext, plaintext_len_int));
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptUpdate(ks->ctx, ciphertext, &outlen, plaintext, plaintext_len_int));
assert(outlen == plaintext_len_int);
OQS_OPENSSL_GUARD(EVP_EncryptFinal_ex(ks->ctx, ciphertext, &outlen));
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptFinal_ex(ks->ctx, ciphertext, &outlen));
}

static void AES256_ECB_load_schedule(const uint8_t *key, void **schedule) {
*schedule = malloc(sizeof(struct key_schedule));
OQS_EXIT_IF_NULLPTR(*schedule, "OpenSSL");
struct key_schedule *ks = (struct key_schedule *) *schedule;
ks->for_ECB = 1;
ks->ctx = EVP_CIPHER_CTX_new();
ks->ctx = _oqs_ossl_EVP_CIPHER_CTX_new();
OQS_EXIT_IF_NULLPTR(ks->ctx, "OpenSSL");
OQS_OPENSSL_GUARD(EVP_EncryptInit_ex(ks->ctx, oqs_aes_256_ecb(), NULL, key, NULL));
EVP_CIPHER_CTX_set_padding(ks->ctx, 0);
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptInit_ex(ks->ctx, oqs_aes_256_ecb(), NULL, key, NULL));
_oqs_ossl_EVP_CIPHER_CTX_set_padding(ks->ctx, 0);
}

static void AES256_CTR_inc_init(const uint8_t *key, void **schedule) {
*schedule = malloc(sizeof(struct key_schedule));
struct key_schedule *ks = (struct key_schedule *) *schedule;
EVP_CIPHER_CTX *ctr_ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX *ctr_ctx = _oqs_ossl_EVP_CIPHER_CTX_new();
assert(ctr_ctx != NULL);

OQS_EXIT_IF_NULLPTR(*schedule, "OpenSSL");
Expand All @@ -101,15 +100,15 @@ static void AES256_CTR_inc_iv(const uint8_t *iv, size_t iv_len, void *schedule)
} else {
exit(EXIT_FAILURE);
}
OQS_OPENSSL_GUARD(EVP_EncryptInit_ex(ks->ctx, oqs_aes_256_ctr(), NULL, ks->key, ks->iv));
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptInit_ex(ks->ctx, oqs_aes_256_ctr(), NULL, ks->key, ks->iv));
}

static void AES256_CTR_inc_ivu64(uint64_t iv, void *schedule) {
OQS_EXIT_IF_NULLPTR(schedule, "OpenSSL");
struct key_schedule *ks = (struct key_schedule *) schedule;
br_enc64be(ks->iv, iv);
memset(&ks->iv[8], 0, 8);
OQS_OPENSSL_GUARD(EVP_EncryptInit_ex(ks->ctx, oqs_aes_256_ctr(), NULL, ks->key, ks->iv));
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptInit_ex(ks->ctx, oqs_aes_256_ctr(), NULL, ks->key, ks->iv));
}

static void AES256_free_schedule(void *schedule) {
Expand All @@ -130,7 +129,7 @@ static void AES256_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_
}

static void AES256_CTR_inc_stream_iv(const uint8_t *iv, size_t iv_len, const void *schedule, uint8_t *out, size_t out_len) {
EVP_CIPHER_CTX *ctr_ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX *ctr_ctx = _oqs_ossl_EVP_CIPHER_CTX_new();
assert(ctr_ctx != NULL);
uint8_t iv_ctr[16];
if (iv_len == 12) {
Expand All @@ -145,14 +144,14 @@ static void AES256_CTR_inc_stream_iv(const uint8_t *iv, size_t iv_len, const voi
exit(EXIT_FAILURE);
}
const struct key_schedule *ks = (const struct key_schedule *) schedule;
OQS_OPENSSL_GUARD(EVP_EncryptInit_ex(ctr_ctx, oqs_aes_256_ctr(), NULL, ks->key, iv_ctr));
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptInit_ex(ctr_ctx, oqs_aes_256_ctr(), NULL, ks->key, iv_ctr));

SIZE_T_TO_INT_OR_EXIT(out_len, out_len_input_int)
memset(out, 0, (size_t)out_len_input_int);
int out_len_output;
OQS_OPENSSL_GUARD(EVP_EncryptUpdate(ctr_ctx, out, &out_len_output, out, out_len_input_int));
OQS_OPENSSL_GUARD(EVP_EncryptFinal_ex(ctr_ctx, out + out_len_output, &out_len_output));
EVP_CIPHER_CTX_free(ctr_ctx);
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptUpdate(ctr_ctx, out, &out_len_output, out, out_len_input_int));
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptFinal_ex(ctr_ctx, out + out_len_output, &out_len_output));
_oqs_ossl_EVP_CIPHER_CTX_free(ctr_ctx);
}

static void AES256_CTR_inc_stream_blks(void *schedule, uint8_t *out, size_t out_blks) {
Expand All @@ -161,7 +160,7 @@ static void AES256_CTR_inc_stream_blks(void *schedule, uint8_t *out, size_t out_
int out_len_output;
SIZE_T_TO_INT_OR_EXIT(out_len, out_len_input_int);
memset(out, 0, (size_t)out_len_input_int);
OQS_OPENSSL_GUARD(EVP_EncryptUpdate(ks->ctx, out, &out_len_output, out, (int) out_len));
OQS_OPENSSL_GUARD(_oqs_ossl_EVP_EncryptUpdate(ks->ctx, out, &out_len_output, out, (int) out_len));
}

struct OQS_AES_callbacks aes_default_callbacks = {
Expand All @@ -179,3 +178,24 @@ struct OQS_AES_callbacks aes_default_callbacks = {
AES256_CTR_inc_stream_iv,
AES256_CTR_inc_stream_blks,
};

void OQS_AES_init(void) {
oqs_ossl_ensure_library();
OQS_OSSL_ENSURE_FUNCTION(EVP_CIPHER_CTX_new);
OQS_OSSL_ENSURE_FUNCTION(EVP_CIPHER_CTX_free);
OQS_OSSL_ENSURE_FUNCTION(EVP_CIPHER_CTX_set_padding);
OQS_OSSL_ENSURE_FUNCTION(EVP_EncryptInit_ex);
OQS_OSSL_ENSURE_FUNCTION(EVP_EncryptUpdate);
OQS_OSSL_ENSURE_FUNCTION(EVP_EncryptFinal_ex);

/* Used by ossl_helpers.c */
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
OQS_OSSL_ENSURE_FUNCTION(CRYPTO_THREAD_run_once);
OQS_OSSL_ENSURE_FUNCTION(EVP_CIPHER_fetch);
OQS_OSSL_ENSURE_FUNCTION(EVP_CIPHER_free);
#else
OQS_OSSL_ENSURE_FUNCTION(EVP_aes_128_ecb);
OQS_OSSL_ENSURE_FUNCTION(EVP_aes_256_ecb);
OQS_OSSL_ENSURE_FUNCTION(EVP_aes_256_ctr);
#endif
}
12 changes: 9 additions & 3 deletions src/common/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
#endif

#if defined(OQS_USE_OPENSSL)
#include <openssl/evp.h>
#include "ossl_helpers.h"
CRYPTO_ONCE OQS_ONCE_STATIC_FREE;
#endif
#include "aes/aes.h"
#include "sha2/sha2.h"
#include "sha3/sha3.h"
#include "sha3/sha3x4.h"
#include "rand/rand.h"

/* Identifying the CPU is expensive so we cache the results in cpu_ext_data */
#if defined(OQS_DIST_BUILD)
Expand Down Expand Up @@ -224,6 +226,10 @@ OQS_API void OQS_init(void) {
OQS_CPU_has_extension(OQS_CPU_EXT_INIT);
#endif
OQS_AES_init();
OQS_SHA2_init();
OQS_SHA3_init();
OQS_SHA3_x4_init();
OQS_RAND_init();
return;
}

Expand All @@ -233,7 +239,7 @@ OQS_API const char *OQS_version(void) {

OQS_API void OQS_destroy(void) {
#if defined(OQS_USE_OPENSSL)
CRYPTO_THREAD_run_once(&OQS_ONCE_STATIC_FREE, oqs_free_ossl_objects);
oqs_ossl_unload_library();
#endif
return;
}
Expand Down
31 changes: 31 additions & 0 deletions src/common/openssl_shim.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: Apache-2.0

#define OQS_OSS_DEFINE_FUNC 1
#include "openssl_shim.h"

#include <assert.h>
#include <dlfcn.h>

static void *libcrypto_dlhandle;

void oqs_ossl_ensure_library(void) {
if (!libcrypto_dlhandle) {
libcrypto_dlhandle = dlopen("libcrypto.so.3", RTLD_NOW | RTLD_GLOBAL);
if (!libcrypto_dlhandle) {
exit(EXIT_FAILURE);
}
}
}

void oqs_ossl_ensure_function(const char *name, void **funcp) {
void *func = dlsym(libcrypto_dlhandle, name);
if (!func) {
exit(EXIT_FAILURE);
}
*funcp = func;
}

void oqs_ossl_unload_library(void) {
assert(libcrypto_dlhandle);
dlclose(libcrypto_dlhandle);
}
49 changes: 49 additions & 0 deletions src/common/openssl_shim.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: Apache-2.0

#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>

#ifdef OQS_OSS_DEFINE_FUNC
#define OQS_OSSL_FUNC(name) \
__typeof__(name)(*_oqs_ossl_##name)
#else
#define OQS_OSSL_FUNC(name) \
extern __typeof__(name)(*_oqs_ossl_##name)
#endif

OQS_OSSL_FUNC(ERR_print_errors_fp);
OQS_OSSL_FUNC(EVP_CIPHER_CTX_free);
OQS_OSSL_FUNC(EVP_CIPHER_CTX_new);
OQS_OSSL_FUNC(EVP_CIPHER_CTX_set_padding);
OQS_OSSL_FUNC(EVP_DigestFinalXOF);
OQS_OSSL_FUNC(EVP_DigestFinal_ex);
OQS_OSSL_FUNC(EVP_DigestInit_ex);
OQS_OSSL_FUNC(EVP_DigestUpdate);
OQS_OSSL_FUNC(EVP_EncryptFinal_ex);
OQS_OSSL_FUNC(EVP_EncryptInit_ex);
OQS_OSSL_FUNC(EVP_EncryptUpdate);
OQS_OSSL_FUNC(EVP_MD_CTX_copy_ex);
OQS_OSSL_FUNC(EVP_MD_CTX_free);
OQS_OSSL_FUNC(EVP_MD_CTX_new);
OQS_OSSL_FUNC(EVP_aes_128_ecb);
OQS_OSSL_FUNC(EVP_aes_256_ecb);
OQS_OSSL_FUNC(EVP_aes_256_ctr);
OQS_OSSL_FUNC(EVP_sha256);
OQS_OSSL_FUNC(EVP_sha384);
OQS_OSSL_FUNC(EVP_sha3_256);
OQS_OSSL_FUNC(EVP_sha3_384);
OQS_OSSL_FUNC(EVP_sha3_512);
OQS_OSSL_FUNC(EVP_sha512);
OQS_OSSL_FUNC(EVP_shake128);
OQS_OSSL_FUNC(EVP_shake256);
OQS_OSSL_FUNC(RAND_bytes);
OQS_OSSL_FUNC(RAND_poll);
OQS_OSSL_FUNC(RAND_status);

void oqs_ossl_ensure_library(void);

#define OQS_OSSL_ENSURE_FUNCTION(name) \
oqs_ossl_ensure_function(#name, (void **)&_oqs_ossl_##name)

void oqs_ossl_ensure_function(const char *name, void **funcp);
Loading

0 comments on commit 76d86e1

Please sign in to comment.