From 1e7b545d7debbb0dbdb6d16ed10a397ad149ad28 Mon Sep 17 00:00:00 2001 From: RodriM11 <62776780+RodriM11@users.noreply.github.com> Date: Sat, 4 Jan 2025 12:21:08 +0100 Subject: [PATCH 1/2] Include use of loaded 'libctx' context in KEM and SIG procedures (#557) Signed-off-by: RodriM11 <62776780+RodriM11@users.noreply.github.com> --- oqs-template/generate.py | 2 +- .../composite_sig_algs.fragment | 0 .../hybrid_kem_algs.fragment | 0 .../hybrid_sig_algs.fragment | 0 oqsprov/oqs_hyb_kem.c | 18 +- oqsprov/oqs_sig.c | 28 +- oqsprov/oqsprov_keys.c | 115 ++-- test/CMakeLists.txt | 23 + test/oqs_test_evp_pkey_params.c | 155 ----- test/oqs_test_libctx.c | 598 ++++++++++++++++++ test/test_common.c | 144 +++++ test/test_common.h | 32 + 12 files changed, 891 insertions(+), 224 deletions(-) rename oqs-template/test/{oqs_test_evp_pkey_params.c => test_common.c}/composite_sig_algs.fragment (100%) rename oqs-template/test/{oqs_test_evp_pkey_params.c => test_common.c}/hybrid_kem_algs.fragment (100%) rename oqs-template/test/{oqs_test_evp_pkey_params.c => test_common.c}/hybrid_sig_algs.fragment (100%) create mode 100644 test/oqs_test_libctx.c diff --git a/oqs-template/generate.py b/oqs-template/generate.py index d93e9e6a..cfc69c3a 100644 --- a/oqs-template/generate.py +++ b/oqs-template/generate.py @@ -247,7 +247,7 @@ def load_config(include_disabled_sigs=False): populate('oqsprov/oqs_decode_der2key.c', config, '/////') populate('oqsprov/oqsprov_keys.c', config, '/////') populate('scripts/common.py', config, '#####') -populate('test/oqs_test_evp_pkey_params.c', config, '/////') +populate('test/test_common.c', config, '/////') config2 = load_config(include_disabled_sigs=True) config2 = complete_config(config2) diff --git a/oqs-template/test/oqs_test_evp_pkey_params.c/composite_sig_algs.fragment b/oqs-template/test/test_common.c/composite_sig_algs.fragment similarity index 100% rename from oqs-template/test/oqs_test_evp_pkey_params.c/composite_sig_algs.fragment rename to oqs-template/test/test_common.c/composite_sig_algs.fragment diff --git a/oqs-template/test/oqs_test_evp_pkey_params.c/hybrid_kem_algs.fragment b/oqs-template/test/test_common.c/hybrid_kem_algs.fragment similarity index 100% rename from oqs-template/test/oqs_test_evp_pkey_params.c/hybrid_kem_algs.fragment rename to oqs-template/test/test_common.c/hybrid_kem_algs.fragment diff --git a/oqs-template/test/oqs_test_evp_pkey_params.c/hybrid_sig_algs.fragment b/oqs-template/test/test_common.c/hybrid_sig_algs.fragment similarity index 100% rename from oqs-template/test/oqs_test_evp_pkey_params.c/hybrid_sig_algs.fragment rename to oqs-template/test/test_common.c/hybrid_sig_algs.fragment diff --git a/oqsprov/oqs_hyb_kem.c b/oqsprov/oqs_hyb_kem.c index 6f9c9d94..a238fc70 100644 --- a/oqsprov/oqs_hyb_kem.c +++ b/oqsprov/oqs_hyb_kem.c @@ -19,6 +19,7 @@ static int oqs_evp_kem_encaps_keyslot(void *vpkemctx, unsigned char *ct, const PROV_OQSKEM_CTX *pkemctx = (PROV_OQSKEM_CTX *)vpkemctx; const OQSX_EVP_CTX *evp_ctx = pkemctx->kem->oqsx_provider_ctx.oqsx_evp_ctx; + OSSL_LIB_CTX *libctx = pkemctx->libctx; size_t pubkey_kexlen = 0; size_t kexDeriveLen = 0, pkeylen = 0; @@ -51,7 +52,7 @@ static int oqs_evp_kem_encaps_keyslot(void *vpkemctx, unsigned char *ct, ret2 = EVP_PKEY_set1_encoded_public_key(peerpk, pubkey_kex, pubkey_kexlen); ON_ERR_SET_GOTO(ret2 <= 0, ret, -1, err); - kgctx = EVP_PKEY_CTX_new(evp_ctx->keyParam, NULL); + kgctx = EVP_PKEY_CTX_new_from_pkey(libctx, evp_ctx->keyParam, NULL); ON_ERR_SET_GOTO(!kgctx, ret, -1, err); ret2 = EVP_PKEY_keygen_init(kgctx); @@ -60,7 +61,7 @@ static int oqs_evp_kem_encaps_keyslot(void *vpkemctx, unsigned char *ct, ret2 = EVP_PKEY_keygen(kgctx, &pkey); ON_ERR_SET_GOTO(ret2 != 1, ret, -1, err); - ctx = EVP_PKEY_CTX_new(pkey, NULL); + ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, NULL); ON_ERR_SET_GOTO(!ctx, ret, -1, err); ret = EVP_PKEY_derive_init(ctx); @@ -96,6 +97,7 @@ static int oqs_evp_kem_decaps_keyslot(void *vpkemctx, unsigned char *secret, int ret = OQS_SUCCESS, ret2 = 0; const PROV_OQSKEM_CTX *pkemctx = (PROV_OQSKEM_CTX *)vpkemctx; const OQSX_EVP_CTX *evp_ctx = pkemctx->kem->oqsx_provider_ctx.oqsx_evp_ctx; + OSSL_LIB_CTX *libctx = pkemctx->libctx; size_t pubkey_kexlen = evp_ctx->evp_info->length_public_key; size_t kexDeriveLen = evp_ctx->evp_info->kex_length_secret; @@ -111,12 +113,14 @@ static int oqs_evp_kem_decaps_keyslot(void *vpkemctx, unsigned char *secret, return 1; if (evp_ctx->evp_info->raw_key_support) { - pkey = EVP_PKEY_new_raw_private_key(evp_ctx->evp_info->keytype, NULL, - privkey_kex, privkey_kexlen); + pkey = EVP_PKEY_new_raw_private_key_ex( + libctx, OBJ_nid2sn(evp_ctx->evp_info->keytype), NULL, privkey_kex, + privkey_kexlen); ON_ERR_SET_GOTO(!pkey, ret, -10, err); } else { - pkey = d2i_AutoPrivateKey(&pkey, (const unsigned char **)&privkey_kex, - privkey_kexlen); + pkey = + d2i_AutoPrivateKey_ex(&pkey, (const unsigned char **)&privkey_kex, + privkey_kexlen, libctx, NULL); ON_ERR_SET_GOTO(!pkey, ret, -2, err); } @@ -129,7 +133,7 @@ static int oqs_evp_kem_decaps_keyslot(void *vpkemctx, unsigned char *secret, ret2 = EVP_PKEY_set1_encoded_public_key(peerpkey, ct, pubkey_kexlen); ON_ERR_SET_GOTO(ret2 <= 0 || !peerpkey, ret, -5, err); - ctx = EVP_PKEY_CTX_new(pkey, NULL); + ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, NULL); ON_ERR_SET_GOTO(!ctx, ret, -6, err); ret = EVP_PKEY_derive_init(ctx); diff --git a/oqsprov/oqs_sig.c b/oqsprov/oqs_sig.c index b6f07a70..8f3371ca 100644 --- a/oqsprov/oqs_sig.c +++ b/oqsprov/oqs_sig.c @@ -330,6 +330,7 @@ static int oqs_sig_sign(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen, PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx; OQSX_KEY *oqsxkey = poqs_sigctx->sig; OQS_SIG *oqs_key = poqs_sigctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig; + OSSL_LIB_CTX *libctx = poqs_sigctx->libctx; EVP_PKEY *oqs_key_classic = NULL; EVP_PKEY *cmp_key_classic = NULL; EVP_PKEY *evpkey = oqsxkey->classical_pkey; @@ -373,7 +374,8 @@ static int oqs_sig_sign(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen, } if (is_hybrid) { - if ((classical_ctx_sign = EVP_PKEY_CTX_new(evpkey, NULL)) == NULL || + if ((classical_ctx_sign = + EVP_PKEY_CTX_new_from_pkey(libctx, evpkey, NULL)) == NULL || EVP_PKEY_sign_init(classical_ctx_sign) <= 0) { ERR_raise(ERR_LIB_USER, ERR_R_FATAL); goto endsign; @@ -551,8 +553,9 @@ static int oqs_sig_sign(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen, if (name[0] == 'e') { // ed25519 or ed448 EVP_MD_CTX *evp_ctx = EVP_MD_CTX_new(); - if ((EVP_DigestSignInit(evp_ctx, NULL, NULL, NULL, - oqs_key_classic) <= 0) || + if ((EVP_DigestSignInit_ex(evp_ctx, NULL, NULL, libctx, + NULL, oqs_key_classic, + NULL) <= 0) || (EVP_DigestSign(evp_ctx, buf, &oqs_sig_len, (const unsigned char *)final_tbs, final_tbslen) <= 0)) { @@ -566,8 +569,8 @@ static int oqs_sig_sign(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen, } EVP_MD_CTX_free(evp_ctx); } else { - if ((classical_ctx_sign = - EVP_PKEY_CTX_new(oqs_key_classic, NULL)) == NULL || + if ((classical_ctx_sign = EVP_PKEY_CTX_new_from_pkey( + libctx, oqs_key_classic, NULL)) == NULL || (EVP_PKEY_sign_init(classical_ctx_sign) <= 0)) { ERR_raise(ERR_LIB_USER, ERR_R_FATAL); CompositeSignature_free(compsig); @@ -711,6 +714,7 @@ static int oqs_sig_verify(void *vpoqs_sigctx, const unsigned char *sig, PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx; OQSX_KEY *oqsxkey = poqs_sigctx->sig; OQS_SIG *oqs_key = poqs_sigctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig; + OSSL_LIB_CTX *libctx = poqs_sigctx->libctx; EVP_PKEY *evpkey = oqsxkey->classical_pkey; EVP_PKEY_CTX *classical_ctx_sign = NULL; EVP_PKEY_CTX *ctx_verify = NULL; @@ -741,8 +745,8 @@ static int oqs_sig_verify(void *vpoqs_sigctx, const unsigned char *sig, size_t max_classical_sig_len = oqsxkey->oqsx_provider_ctx.oqsx_evp_ctx->evp_info->length_signature; - if ((ctx_verify = EVP_PKEY_CTX_new(oqsxkey->classical_pkey, NULL)) == - NULL || + if ((ctx_verify = EVP_PKEY_CTX_new_from_pkey( + libctx, oqsxkey->classical_pkey, NULL)) == NULL || EVP_PKEY_verify_init(ctx_verify) <= 0) { ERR_raise(ERR_LIB_USER, OQSPROV_R_VERIFY_ERROR); goto endverify; @@ -925,8 +929,9 @@ static int oqs_sig_verify(void *vpoqs_sigctx, const unsigned char *sig, if (name[0] == 'e') { // ed25519 or ed448 EVP_MD_CTX *evp_ctx = EVP_MD_CTX_new(); - if ((EVP_DigestVerifyInit(evp_ctx, NULL, NULL, NULL, - oqsxkey->classical_pkey) <= 0) || + if ((EVP_DigestVerifyInit_ex(evp_ctx, NULL, NULL, libctx, + NULL, oqsxkey->classical_pkey, + NULL) <= 0) || (EVP_DigestVerify(evp_ctx, buf, buf_len, (const unsigned char *)final_tbs, final_tbslen) <= 0)) { @@ -939,8 +944,9 @@ static int oqs_sig_verify(void *vpoqs_sigctx, const unsigned char *sig, } EVP_MD_CTX_free(evp_ctx); } else { - if (((ctx_verify = EVP_PKEY_CTX_new(oqsxkey->classical_pkey, - NULL)) == NULL) || + if (((ctx_verify = EVP_PKEY_CTX_new_from_pkey( + libctx, oqsxkey->classical_pkey, NULL)) == + NULL) || (EVP_PKEY_verify_init(ctx_verify) <= 0)) { ERR_raise(ERR_LIB_USER, OQSPROV_R_VERIFY_ERROR); OPENSSL_free(name); diff --git a/oqsprov/oqsprov_keys.c b/oqsprov/oqsprov_keys.c index 0d607b41..933ad568 100644 --- a/oqsprov/oqsprov_keys.c +++ b/oqsprov/oqsprov_keys.c @@ -551,7 +551,7 @@ static const OQSX_EVP_INFO nids_ecx[] = { }; static int oqsx_hybsig_init(int bit_security, OQSX_EVP_CTX *evp_ctx, - char *algname) { + OSSL_LIB_CTX *libctx, char *algname) { int ret = 1; int idx = (bit_security - 128) / 64; ON_ERR_GOTO(idx < 0 || idx > 5, err_init); @@ -583,12 +583,14 @@ static int oqsx_hybsig_init(int bit_security, OQSX_EVP_CTX *evp_ctx, ret = EVP_PKEY_set_type(evp_ctx->keyParam, evp_ctx->evp_info->keytype); ON_ERR_SET_GOTO(ret <= 0, ret, -1, err_init); - evp_ctx->ctx = EVP_PKEY_CTX_new(evp_ctx->keyParam, NULL); + evp_ctx->ctx = + EVP_PKEY_CTX_new_from_pkey(libctx, evp_ctx->keyParam, NULL); ON_ERR_SET_GOTO(!evp_ctx->ctx, ret, -1, err_init); } else { evp_ctx->evp_info = &nids_sig[idx]; - evp_ctx->ctx = EVP_PKEY_CTX_new_id(evp_ctx->evp_info->keytype, NULL); + evp_ctx->ctx = EVP_PKEY_CTX_new_from_name( + libctx, OBJ_nid2sn(evp_ctx->evp_info->keytype), NULL); ON_ERR_GOTO(!evp_ctx->ctx, err_init); if (idx < 5) { // EC @@ -614,7 +616,8 @@ static int oqsx_hybsig_init(int bit_security, OQSX_EVP_CTX *evp_ctx, return ret; } -static const int oqshybkem_init_ecp(char *tls_name, OQSX_EVP_CTX *evp_ctx) { +static const int oqshybkem_init_ecp(char *tls_name, OQSX_EVP_CTX *evp_ctx, + OSSL_LIB_CTX *libctx) { int ret = 1; int idx = 0; @@ -627,7 +630,8 @@ static const int oqshybkem_init_ecp(char *tls_name, OQSX_EVP_CTX *evp_ctx) { evp_ctx->evp_info = &nids_ecp[idx]; - evp_ctx->ctx = EVP_PKEY_CTX_new_id(evp_ctx->evp_info->keytype, NULL); + evp_ctx->ctx = EVP_PKEY_CTX_new_from_name( + libctx, OBJ_nid2sn(evp_ctx->evp_info->keytype), NULL); ON_ERR_GOTO(!evp_ctx->ctx, err_init_ecp); ret = EVP_PKEY_paramgen_init(evp_ctx->ctx); @@ -644,7 +648,8 @@ static const int oqshybkem_init_ecp(char *tls_name, OQSX_EVP_CTX *evp_ctx) { return ret; } -static const int oqshybkem_init_ecx(char *tls_name, OQSX_EVP_CTX *evp_ctx) { +static const int oqshybkem_init_ecx(char *tls_name, OQSX_EVP_CTX *evp_ctx, + OSSL_LIB_CTX *libctx) { int ret = 1; int idx = 0; @@ -663,7 +668,7 @@ static const int oqshybkem_init_ecx(char *tls_name, OQSX_EVP_CTX *evp_ctx) { ret = EVP_PKEY_set_type(evp_ctx->keyParam, evp_ctx->evp_info->keytype); ON_ERR_SET_GOTO(ret <= 0, ret, -1, err_init_ecx); - evp_ctx->ctx = EVP_PKEY_CTX_new(evp_ctx->keyParam, NULL); + evp_ctx->ctx = EVP_PKEY_CTX_new_from_pkey(libctx, evp_ctx->keyParam, NULL); ON_ERR_SET_GOTO(!evp_ctx->ctx, ret, -1, err_init_ecx); err_init_ecx: @@ -969,9 +974,10 @@ static int oqsx_key_recreate_classickey(OQSX_KEY *key, oqsx_key_op_t op) { ->keytype, &npk, &enc_pubkey, key->pubkeylen_cmp[i]); } else - key->classical_pkey = EVP_PKEY_new_raw_public_key( - key->oqsx_provider_ctx.oqsx_evp_ctx->evp_info - ->keytype, + key->classical_pkey = EVP_PKEY_new_raw_public_key_ex( + key->libctx, + OBJ_nid2sn(key->oqsx_provider_ctx.oqsx_evp_ctx + ->evp_info->keytype), NULL, enc_pubkey, key->pubkeylen_cmp[i]); if (!key->classical_pkey) { ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_ENCODING); @@ -996,14 +1002,16 @@ static int oqsx_key_recreate_classickey(OQSX_KEY *key, oqsx_key_op_t op) { if (!key->oqsx_provider_ctx.oqsx_evp_ctx->evp_info ->raw_key_support) { EVP_PKEY *npk; - key->classical_pkey = d2i_PrivateKey( + key->classical_pkey = d2i_PrivateKey_ex( key->oqsx_provider_ctx.oqsx_evp_ctx->evp_info ->keytype, - NULL, &enc_privkey, key->privkeylen_cmp[i]); + NULL, &enc_privkey, key->privkeylen_cmp[i], + key->libctx, NULL); } else { - key->classical_pkey = EVP_PKEY_new_raw_private_key( - key->oqsx_provider_ctx.oqsx_evp_ctx->evp_info - ->keytype, + key->classical_pkey = EVP_PKEY_new_raw_private_key_ex( + key->libctx, + OBJ_nid2sn(key->oqsx_provider_ctx.oqsx_evp_ctx + ->evp_info->keytype), NULL, enc_privkey, key->privkeylen_cmp[i]); } if (!key->classical_pkey) { @@ -1056,9 +1064,9 @@ static int oqsx_key_recreate_classickey(OQSX_KEY *key, oqsx_key_op_t op) { goto rec_err; } if (key->evp_info->raw_key_support) { - key->classical_pkey = EVP_PKEY_new_raw_public_key( - key->evp_info->keytype, NULL, enc_pubkey, - classical_pubkey_len); + key->classical_pkey = EVP_PKEY_new_raw_public_key_ex( + key->libctx, OBJ_nid2sn(key->evp_info->keytype), NULL, + enc_pubkey, classical_pubkey_len); if (!key->classical_pkey) { ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_ENCODING); goto rec_err; @@ -1088,9 +1096,9 @@ static int oqsx_key_recreate_classickey(OQSX_KEY *key, oqsx_key_op_t op) { key->comp_privkey[idx_classic]; unsigned char *enc_pubkey = key->comp_pubkey[idx_classic]; if (key->evp_info->raw_key_support) { - key->classical_pkey = EVP_PKEY_new_raw_private_key( - key->evp_info->keytype, NULL, enc_privkey, - classical_privkey_len); + key->classical_pkey = EVP_PKEY_new_raw_private_key_ex( + key->libctx, OBJ_nid2sn(key->evp_info->keytype), NULL, + enc_privkey, classical_privkey_len); if (!key->classical_pkey) { ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_ENCODING); goto rec_err; @@ -1110,9 +1118,9 @@ static int oqsx_key_recreate_classickey(OQSX_KEY *key, oqsx_key_op_t op) { } #endif } else { - key->classical_pkey = - d2i_PrivateKey(key->evp_info->keytype, NULL, - &enc_privkey, classical_privkey_len); + key->classical_pkey = d2i_PrivateKey_ex( + key->evp_info->keytype, NULL, &enc_privkey, + classical_privkey_len, key->libctx, NULL); if (!key->classical_pkey) { ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_ENCODING); goto rec_err; @@ -1295,15 +1303,15 @@ OQSX_KEY *oqsx_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf, return NULL; } ec_pkey = EVP_PKEY_new(); - d2i_PrivateKey( - EVP_PKEY_EC, &ec_pkey, &buf3, - aType->value.sequence->length); // create - // a new - // EVP_PKEY - // using - // ec - // priv - // key + d2i_PrivateKey_ex(EVP_PKEY_EC, &ec_pkey, &buf3, + aType->value.sequence->length, + libctx, NULL); // create + // a new + // EVP_PKEY + // using + // ec + // priv + // key // set parameters for the // new priv key format @@ -1402,7 +1410,7 @@ OQSX_KEY *oqsx_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf, return oqsx; } -static const int (*init_kex_fun[])(char *, OQSX_EVP_CTX *) = { +static const int (*init_kex_fun[])(char *, OQSX_EVP_CTX *, OSSL_LIB_CTX *) = { oqshybkem_init_ecp, oqshybkem_init_ecx}; extern const char *oqs_oid_alg_list[]; @@ -1489,8 +1497,8 @@ OQSX_KEY *oqsx_key_new(OSSL_LIB_CTX *libctx, char *oqs_name, char *tls_name, evp_ctx = OPENSSL_zalloc(sizeof(OQSX_EVP_CTX)); ON_ERR_GOTO(!evp_ctx, err); - ret2 = - (init_kex_fun[primitive - KEY_TYPE_ECP_HYB_KEM])(tls_name, evp_ctx); + ret2 = (init_kex_fun[primitive - KEY_TYPE_ECP_HYB_KEM])( + tls_name, evp_ctx, libctx); ON_ERR_GOTO(ret2 <= 0 || !evp_ctx->keyParam || !evp_ctx->ctx, err); ret->numkeys = 2; @@ -1522,7 +1530,7 @@ OQSX_KEY *oqsx_key_new(OSSL_LIB_CTX *libctx, char *oqs_name, char *tls_name, evp_ctx = OPENSSL_zalloc(sizeof(OQSX_EVP_CTX)); ON_ERR_GOTO(!evp_ctx, err); - ret2 = oqsx_hybsig_init(bit_security, evp_ctx, tls_name); + ret2 = oqsx_hybsig_init(bit_security, evp_ctx, libctx, tls_name); ON_ERR_GOTO(ret2 <= 0 || !evp_ctx->ctx, err); ret->numkeys = 2; @@ -1576,7 +1584,7 @@ OQSX_KEY *oqsx_key_new(OSSL_LIB_CTX *libctx, char *oqs_name, char *tls_name, evp_ctx = OPENSSL_zalloc(sizeof(OQSX_EVP_CTX)); ON_ERR_GOTO(!evp_ctx, err); - ret2 = oqsx_hybsig_init(bit_security, evp_ctx, name); + ret2 = oqsx_hybsig_init(bit_security, evp_ctx, libctx, name); ON_ERR_GOTO(ret2 <= 0 || !evp_ctx->ctx, err); ret->oqsx_provider_ctx.oqsx_evp_ctx = evp_ctx; ret->privkeylen_cmp[i] = ret->oqsx_provider_ctx.oqsx_evp_ctx @@ -1792,6 +1800,7 @@ static int oqsx_key_gen_oqs(OQSX_KEY *key, int gen_kem) { * pubkey/privkey buffers; returned EVP_PKEY must be freed if not used */ static EVP_PKEY *oqsx_key_gen_evp_key_sig(OQSX_EVP_CTX *ctx, + OSSL_LIB_CTX *libctx, unsigned char *pubkey, unsigned char *privkey, int encode) { int ret = 0, ret2 = 0, aux = 0; @@ -1808,9 +1817,10 @@ static EVP_PKEY *oqsx_key_gen_evp_key_sig(OQSX_EVP_CTX *ctx, } if (ctx->keyParam) - kgctx = EVP_PKEY_CTX_new(ctx->keyParam, NULL); + kgctx = EVP_PKEY_CTX_new_from_pkey(libctx, ctx->keyParam, NULL); else - kgctx = EVP_PKEY_CTX_new_id(ctx->evp_info->nid, NULL); + kgctx = EVP_PKEY_CTX_new_from_name( + libctx, OBJ_nid2sn(ctx->evp_info->nid), NULL); ON_ERR_SET_GOTO(!kgctx, ret, -1, errhyb); ret2 = EVP_PKEY_keygen_init(kgctx); @@ -1862,8 +1872,9 @@ static EVP_PKEY *oqsx_key_gen_evp_key_sig(OQSX_EVP_CTX *ctx, privkeylen > (int)ctx->evp_info->length_private_key, ret, -12, errhyb); // selftest: - EVP_PKEY *ck2 = d2i_PrivateKey(ctx->evp_info->keytype, NULL, - &privkey_enc2, privkeylen); + EVP_PKEY *ck2 = + d2i_PrivateKey_ex(ctx->evp_info->keytype, NULL, &privkey_enc2, + privkeylen, libctx, NULL); ON_ERR_SET_GOTO(!ck2, ret, -14, errhyb); EVP_PKEY_free(ck2); } @@ -1899,6 +1910,7 @@ static EVP_PKEY *oqsx_key_gen_evp_key_kem(OQSX_KEY *key, unsigned char *pubkey, unsigned char *pubkey_encoded = NULL; int idx_classic; OQSX_EVP_CTX *ctx = key->oqsx_provider_ctx.oqsx_evp_ctx; + OSSL_LIB_CTX *libctx = key->libctx; size_t pubkeylen = 0, privkeylen = 0; @@ -1906,9 +1918,10 @@ static EVP_PKEY *oqsx_key_gen_evp_key_kem(OQSX_KEY *key, unsigned char *pubkey, unsigned char *privkey_sizeenc = key->privkey; if (ctx->keyParam) - kgctx = EVP_PKEY_CTX_new(ctx->keyParam, NULL); + kgctx = EVP_PKEY_CTX_new_from_pkey(libctx, ctx->keyParam, NULL); else - kgctx = EVP_PKEY_CTX_new_id(ctx->evp_info->nid, NULL); + kgctx = EVP_PKEY_CTX_new_from_name( + libctx, OBJ_nid2sn(ctx->evp_info->nid), NULL); ON_ERR_SET_GOTO(!kgctx, ret, -1, errhyb); ret2 = EVP_PKEY_keygen_init(kgctx); @@ -1952,8 +1965,9 @@ static EVP_PKEY *oqsx_key_gen_evp_key_kem(OQSX_KEY *key, unsigned char *pubkey, privkeylen > (int)ctx->evp_info->length_private_key, ret, -12, errhyb); // selftest: - EVP_PKEY *ck2 = d2i_PrivateKey(ctx->evp_info->keytype, NULL, - &privkey_enc2, privkeylen); + EVP_PKEY *ck2 = + d2i_PrivateKey_ex(ctx->evp_info->keytype, NULL, &privkey_enc2, + privkeylen, libctx, NULL); ON_ERR_SET_GOTO(!ck2, ret, -14, errhyb); EVP_PKEY_free(ck2); } @@ -1992,8 +2006,9 @@ int oqsx_key_gen(OQSX_KEY *key) { ON_ERR_GOTO(ret, err_gen); ret = oqsx_key_gen_oqs(key, 1); } else if (key->keytype == KEY_TYPE_HYB_SIG) { - pkey = oqsx_key_gen_evp_key_sig(key->oqsx_provider_ctx.oqsx_evp_ctx, - key->pubkey, key->privkey, 1); + pkey = + oqsx_key_gen_evp_key_sig(key->oqsx_provider_ctx.oqsx_evp_ctx, + key->libctx, key->pubkey, key->privkey, 1); ON_ERR_GOTO(pkey == NULL, err_gen); ret = !oqsx_key_set_composites(key, 0); ON_ERR_GOTO(ret, err_gen); @@ -2029,8 +2044,8 @@ int oqsx_key_gen(OQSX_KEY *key) { } if (get_oqsname_fromtls(name) == 0) { pkey = oqsx_key_gen_evp_key_sig( - key->oqsx_provider_ctx.oqsx_evp_ctx, key->comp_pubkey[i], - key->comp_privkey[i], 0); + key->oqsx_provider_ctx.oqsx_evp_ctx, key->libctx, + key->comp_pubkey[i], key->comp_privkey[i], 0); OPENSSL_free(name); ON_ERR_GOTO(pkey == NULL, err_gen); key->classical_pkey = pkey; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 53ec05cb..e6864e13 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -59,6 +59,28 @@ endif() add_executable(oqs_test_kems oqs_test_kems.c test_common.c) target_link_libraries(oqs_test_kems PRIVATE ${OPENSSL_CRYPTO_LIBRARY} ${OQS_ADDL_SOCKET_LIBS} ${REQ_LIBS_T}) +add_test( + NAME oqs_libctx + COMMAND oqs_test_libctx + "oqsprovider" + "${CMAKE_SOURCE_DIR}/test/oqs.cnf" +) +# openssl under MSVC seems to have a bug registering NIDs: +# It only works when setting OPENSSL_CONF, not when loading the same cnf file: +if (MSVC) +set_tests_properties(oqs_libctx + PROPERTIES ENVIRONMENT "OPENSSL_MODULES=${OQS_PROV_BINARY_DIR};OPENSSL_CONF=${CMAKE_CURRENT_SOURCE_DIR}/openssl-ca.cnf" +) +else() +set_tests_properties(oqs_libctx + PROPERTIES ENVIRONMENT "OPENSSL_MODULES=${OQS_PROV_BINARY_DIR}" +) +endif() + +add_executable(oqs_test_libctx oqs_test_libctx.c test_common.c) +target_include_directories(oqs_test_libctx PRIVATE "../oqsprov") +target_link_libraries(oqs_test_libctx PRIVATE ${OPENSSL_CRYPTO_LIBRARY} ${OQS_ADDL_SOCKET_LIBS} ${REQ_LIBS_T}) + add_test( NAME oqs_groups COMMAND oqs_test_groups @@ -146,6 +168,7 @@ endif() if (OQS_PROVIDER_BUILD_STATIC) targets_set_static_provider(oqs_test_signatures oqs_test_kems + oqs_test_libctx oqs_test_groups oqs_test_tlssig oqs_test_endecode diff --git a/test/oqs_test_evp_pkey_params.c b/test/oqs_test_evp_pkey_params.c index 7f56c233..d32063ef 100644 --- a/test/oqs_test_evp_pkey_params.c +++ b/test/oqs_test_evp_pkey_params.c @@ -13,115 +13,6 @@ #include "oqs_prov.h" #include "test_common.h" -///// OQS_TEMPLATE_FRAGMENT_HYBRID_SIG_ALGS_START - -/** \brief List of hybrid signature algorithms. */ -const char *kHybridSignatureAlgorithms[] = { - "p256_mldsa44", - "rsa3072_mldsa44", - "p384_mldsa65", - "p521_mldsa87", - "p256_falcon512", - "rsa3072_falcon512", - "p256_falconpadded512", - "rsa3072_falconpadded512", - "p521_falcon1024", - "p521_falconpadded1024", - "p256_sphincssha2128fsimple", - "rsa3072_sphincssha2128fsimple", - "p256_sphincssha2128ssimple", - "rsa3072_sphincssha2128ssimple", - "p384_sphincssha2192fsimple", - "p256_sphincsshake128fsimple", - "rsa3072_sphincsshake128fsimple", - "p256_mayo1", - "p256_mayo2", - "p384_mayo3", - "p521_mayo5", - NULL, -}; -///// OQS_TEMPLATE_FRAGMENT_HYBRID_SIG_ALGS_END - -///// OQS_TEMPLATE_FRAGMENT_COMPOSITE_SIG_ALGS_START - -/** \brief List of composite signature algorithms. */ -const char *kCompositeSignatureAlgorithms[] = { - "mldsa44_pss2048", "mldsa44_rsa2048", - "mldsa44_ed25519", "mldsa44_p256", - "mldsa44_bp256", "mldsa65_pss3072", - "mldsa65_rsa3072", "mldsa65_p256", - "mldsa65_bp256", "mldsa65_ed25519", - "mldsa87_p384", "mldsa87_bp384", - "mldsa87_ed448", NULL, -}; -///// OQS_TEMPLATE_FRAGMENT_COMPOSITE_SIG_ALGS_END - -///// OQS_TEMPLATE_FRAGMENT_HYBRID_KEM_ALGS_START - -/** \brief List of hybrid KEMs. */ -const char *kHybridKEMAlgorithms[] = { - "p256_frodo640aes", - "x25519_frodo640aes", - "p256_frodo640shake", - "x25519_frodo640shake", - "p384_frodo976aes", - "x448_frodo976aes", - "p384_frodo976shake", - "x448_frodo976shake", - "p521_frodo1344aes", - "p521_frodo1344shake", - "p256_mlkem512", - "x25519_mlkem512", - "p384_mlkem768", - "x448_mlkem768", - "X25519MLKEM768", - "SecP256r1MLKEM768", - "p521_mlkem1024", - "SecP384r1MLKEM1024", - "p256_bikel1", - "x25519_bikel1", - "p384_bikel3", - "x448_bikel3", - "p521_bikel5", - "p256_hqc128", - "x25519_hqc128", - "p384_hqc192", - "x448_hqc192", - "p521_hqc256", - NULL, -}; ///// OQS_TEMPLATE_FRAGMENT_HYBRID_KEM_ALGS_END - -/** \brief Indicates if a string is in a given list of strings. - * - * \param list List of strings. - * \param s String to test. - * - * \return 1 if `s` is in `list`, else 0. */ -static int is_string_in_list(const char **list, const char *s) { - for (; *list != NULL && strcmp(*list, s) != 0; ++list) - ; - if (*list != NULL) { - return 1; - } - return 0; -} - -/** \brief Indicates if a signature algorithm is hybrid or not. - * - * \param alg Algorithm name. - * - * \returns 1 if hybrid, else 0. */ -#define is_signature_algorithm_hybrid(_alg_) \ - is_string_in_list(kHybridSignatureAlgorithms, (_alg_)) - -/** \brief Indicates if an kem algorithm is hybrid or not. - * - * \param alg Algorithm name. - * - * \returns 1 if hybrid, else 0. */ -#define is_kem_algorithm_hybrid(_alg_) \ - is_string_in_list(kHybridKEMAlgorithms, (_alg_)) - /** \brief A pair of keys. */ struct KeyPair { /** \brief The public key. */ @@ -229,52 +120,6 @@ static EVP_PKEY *generate_private_key(EVP_PKEY_CTX *ctx) { return private_key; } -/** \brief Extracts an octet string from a parameter of an EVP_PKEY. - * - * \param key The EVP_PKEY; - * \param param_name Name of the parameter. - * \param[out] buf Out buffer. - * \param[out] buf_len Size of out buffer. - * - * \returns 0 on success. */ -static int get_param_octet_string(const EVP_PKEY *key, const char *param_name, - uint8_t **buf, size_t *buf_len) { - *buf = NULL; - *buf_len = 0; - int ret = -1; - - if (EVP_PKEY_get_octet_string_param(key, param_name, NULL, 0, buf_len) != - 1) { - fprintf(stderr, - cRED - "`EVP_PKEY_get_octet_string_param` failed with param `%s`: ", - param_name); - ERR_print_errors_fp(stderr); - fputs(cNORM "\n", stderr); - goto out; - } - if (!(*buf = malloc(*buf_len))) { - fprintf(stderr, "failed to allocate %#zx byte(s)\n", *buf_len); - goto out; - } - if (EVP_PKEY_get_octet_string_param(key, param_name, *buf, *buf_len, - buf_len) != 1) { - fprintf(stderr, - cRED - "`EVP_PKEY_get_octet_string_param` failed with param `%s`: ", - param_name); - ERR_print_errors_fp(stderr); - fputs(cNORM "\n", stderr); - free(*buf); - *buf = NULL; - } else { - ret = 0; - } - -out: - return ret; -} - /** \brief Extracts the classical keys from an hybrid key. * * \param private_key The private key. diff --git a/test/oqs_test_libctx.c b/test/oqs_test_libctx.c new file mode 100644 index 00000000..fcee86a3 --- /dev/null +++ b/test/oqs_test_libctx.c @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: Apache-2.0 AND MIT + +#include +#include +#include +#include +#include +#include + +#include "oqs_prov.h" +#include "test_common.h" + +#define MAX_DUMMY_ENTROPY_BUFFERLEN 0x100000 + +/** \brief The info about classical elements needed. */ +struct ClassicalInfo { + /** \brief Name label. */ + const char *name; + + /** \brief The public key length, in bytes. */ + size_t pubkey_len; + + /** \brief The private key length, in bytes. */ + size_t privkey_len; + + /** \brief The shared secret length, in bytes. */ + size_t sec_len; + + /** \brief The signature length, in bytes. */ + size_t sig_len; +}; + +static const struct ClassicalInfo info_classical[] = { + {"p256", 65, 121, 32, 72}, {"SecP256r1", 65, 121, 32, 72}, + {"p384", 97, 167, 48, 104}, {"SecP384r1", 97, 167, 48, 104}, + {"p521", 133, 223, 66, 141}, {"SecP521r1", 133, 223, 66, 141}, + {"bp256", 65, 122, 32, 72}, {"bp384", 97, 171, 48, 104}, + {"rsa3072", 398, 1770, 0, 384}, {"pss3072", 398, 1770, 0, 384}, + {"rsa2048", 270, 1193, 0, 256}, {"pss2048", 270, 1193, 0, 256}, + {"ed25519", 32, 32, 0, 64}, {"ed448", 57, 57, 0, 114}, + {"x25519", 32, 32, 32, 0}, {"X25519", 32, 32, 32, 0}, + {"x448", 56, 56, 56, 0}, +}; + +static OSSL_LIB_CTX *libctx = NULL; +static char *modulename = NULL; +static char *configfile = NULL; + +/** \brief Loads OpenSSL's 'TEST-RAND' deterministic pseudorandom generator for + * the given library context + * + * \param libctx Library context. + * + * \return 1 if the configuration is successfully loaded, else 0. */ +static int oqs_load_det_pseudorandom_generator(OSSL_LIB_CTX *libctx) { + OSSL_PARAM params[2], *p = params; + unsigned char entropy[MAX_DUMMY_ENTROPY_BUFFERLEN]; + RAND_bytes(entropy, sizeof(entropy)); + + if (!RAND_set_DRBG_type(libctx, "TEST-RAND", NULL, NULL, NULL)) { + return 0; + } + + *p++ = OSSL_PARAM_construct_octet_string(OSSL_RAND_PARAM_TEST_ENTROPY, + entropy, sizeof(entropy)); + *p = OSSL_PARAM_construct_end(); + + EVP_RAND_CTX *rctx_public = RAND_get0_public(libctx); + if (!rctx_public) { + return 0; + } + + if (!EVP_RAND_CTX_set_params(rctx_public, params)) { + return 0; + } + + EVP_RAND_CTX *rctx_private = RAND_get0_private(libctx); + if (!rctx_private) { + return 0; + } + + if (!EVP_RAND_CTX_set_params(rctx_private, params)) { + return 0; + } + + return 1; +} + +/** \brief Resets the given library context's DRBG instances + * + * \param libctx Library context. + * + * \return 1 if the configuration is successfully restarted, else 0. */ +static int oqs_reset_det_pseudorandom_generator(OSSL_LIB_CTX *libctx) { + OSSL_PARAM params[2], *p = params; + unsigned int strength = 256; + + // information not needed, but for RAND to reset, it needs at least one + // param + *p++ = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, &strength); + *p = OSSL_PARAM_construct_end(); + + EVP_RAND_CTX *rctx_public = RAND_get0_public(libctx); + if (!rctx_public) { + return 0; + } + + EVP_RAND_uninstantiate(rctx_public); + if (!EVP_RAND_instantiate(rctx_public, strength, 0, NULL, 0, params)) { + return 0; + } + + EVP_RAND_CTX *rctx_private = RAND_get0_private(libctx); + if (!rctx_private) { + return 0; + } + + EVP_RAND_uninstantiate(rctx_private); + if (!EVP_RAND_instantiate(rctx_private, strength, 0, NULL, 0, params)) { + return 0; + } + + return 1; +} + +/** \brief Performs the expected KEM operations (KeyGen, Encaps, Decaps) + * + * \param kemalg_name algorithm name. + * \param[out] key The object to hold the key pair. + * \param[out] secenc Encaps Shared Secret buffer. + * \param[out] seclen Shared Secret length. + * \param[out] secdec Decaps Shared Secret buffer. + * \param[out] out Encapsulation buffer. + * \param[out] outlen Encapsulation length. + * + * \return 1 if the operations are successful, else 0. */ +static int oqs_generate_kem_elems(const char *kemalg_name, EVP_PKEY **key, + unsigned char **secenc, size_t *seclen, + unsigned char **secdec, unsigned char **out, + size_t *outlen) { + int testresult = 0; + EVP_PKEY_CTX *ctx = NULL; + + if (!oqs_reset_det_pseudorandom_generator(libctx)) { + return 0; + } + + if (OSSL_PROVIDER_available(libctx, "default")) { + testresult = (ctx = EVP_PKEY_CTX_new_from_name(libctx, kemalg_name, + NULL)) != NULL && + EVP_PKEY_keygen_init(ctx) && EVP_PKEY_generate(ctx, key); + + if (!testresult) + goto err; + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + + testresult &= + (ctx = EVP_PKEY_CTX_new_from_pkey(libctx, *key, NULL)) != NULL && + EVP_PKEY_encapsulate_init(ctx, NULL) && + EVP_PKEY_encapsulate(ctx, NULL, outlen, NULL, seclen) && + (*out = OPENSSL_malloc(*outlen)) != NULL && + (*secenc = OPENSSL_malloc(*seclen)) != NULL && + memset(*secenc, 0x11, *seclen) != NULL && + (*secdec = OPENSSL_malloc(*seclen)) != NULL && + memset(*secdec, 0xff, *seclen) != NULL && + EVP_PKEY_encapsulate(ctx, *out, outlen, *secenc, seclen) && + EVP_PKEY_decapsulate_init(ctx, NULL) && + EVP_PKEY_decapsulate(ctx, *secdec, seclen, *out, *outlen) && + memcmp(*secenc, *secdec, *seclen) == 0; + } + +err: + EVP_PKEY_CTX_free(ctx); + return testresult; +} + +/** \brief Performs the expected SIG operations (KeyGen, Sign, Verify) + * + * \param sigalg_name algorithm name. + * \param msg Message to be signed. + * \param msglen Message length. + * \param[out] key The object to hold the key pair. + * \param[out] sig Signature buffer. + * \param[out] siglen Signature length. + * + * \return 1 if the operations are successful, else 0. */ +static int oqs_generate_sig_elems(const char *sigalg_name, const char *msg, + size_t msglen, EVP_PKEY **key, + unsigned char **sig, size_t *siglen) { + int testresult = 0; + EVP_PKEY_CTX *ctx = NULL; + EVP_MD_CTX *mdctx = NULL; + + if (!oqs_reset_det_pseudorandom_generator(libctx)) { + return 0; + } + + if (OSSL_PROVIDER_available(libctx, "default")) { + testresult = (ctx = EVP_PKEY_CTX_new_from_name(libctx, sigalg_name, + NULL)) != NULL && + EVP_PKEY_keygen_init(ctx) && EVP_PKEY_generate(ctx, key) && + (mdctx = EVP_MD_CTX_new()) != NULL && + EVP_DigestSignInit_ex(mdctx, NULL, "SHA512", libctx, NULL, + *key, NULL) && + EVP_DigestSignUpdate(mdctx, msg, msglen) && + EVP_DigestSignFinal(mdctx, NULL, siglen) && + (*sig = OPENSSL_malloc(*siglen)) != NULL && + EVP_DigestSignFinal(mdctx, *sig, siglen) && + EVP_DigestVerifyInit_ex(mdctx, NULL, "SHA512", libctx, + NULL, *key, NULL) && + EVP_DigestVerifyUpdate(mdctx, msg, msglen) && + EVP_DigestVerifyFinal(mdctx, *sig, *siglen); + } + +err: + EVP_PKEY_CTX_free(ctx); + EVP_MD_CTX_free(mdctx); + return testresult; +} + +/** \brief Compares the classical keys of two hybrid key pairs + * + * \param key1 A key pair. + * \param key2 A key pair. + * + * \return 1 if the compare operation is successful, else 0. */ +static int oqs_cmp_classical_keys(const EVP_PKEY *key1, const EVP_PKEY *key2) { + int ret = 0; + unsigned char *pubkey1 = NULL, *pubkey2 = NULL, *privkey1 = NULL, + *privkey2 = NULL; + size_t pubkey1_len, pubkey2_len, privkey1_len, privkey2_len; + + if (get_param_octet_string(key1, OQS_HYBRID_PKEY_PARAM_CLASSICAL_PUB_KEY, + &pubkey1, &pubkey1_len)) { + goto out; + } + if (get_param_octet_string(key2, OQS_HYBRID_PKEY_PARAM_CLASSICAL_PUB_KEY, + &pubkey2, &pubkey2_len)) { + goto out; + } + + if (get_param_octet_string(key1, OQS_HYBRID_PKEY_PARAM_CLASSICAL_PRIV_KEY, + &privkey1, &privkey1_len)) { + goto out; + } + if (get_param_octet_string(key2, OQS_HYBRID_PKEY_PARAM_CLASSICAL_PRIV_KEY, + &privkey2, &privkey2_len)) { + goto out; + } + ret = (pubkey1_len == pubkey2_len) && (privkey1_len == privkey2_len); + if (!ret) { + goto out; + } + ret &= memcmp(pubkey1, pubkey2, pubkey1_len) == 0 && + memcmp(privkey1, privkey2, privkey1_len) == 0; + +out: + free(pubkey1); + free(pubkey2); + free(privkey1); + free(privkey2); + return ret; +} + +/** \brief Returns the index associated to the 'info_classical' struct + * + * \param alg_name algorithm name. + * + * \return The associated index, or -1 in case no match is found. */ +static int get_idx_info_classical(const char *alg_name) { + int idx = 0; + char *algdup = strdup(alg_name); + char *name = strtok(algdup, "_"); + + while (idx < OSSL_NELEM(info_classical)) { + if (!strncmp(name, info_classical[idx].name, + strlen(info_classical[idx].name))) + goto err; + idx++; + } + + if (idx == + OSSL_NELEM(info_classical)) { // Might have encountered a 'composite' + // alg, so try again with the second + // part of the separator + idx = 0; + name = strtok(NULL, "_"); + } + + while (idx < OSSL_NELEM(info_classical)) { + if (!strncmp(name, info_classical[idx].name, + strlen(info_classical[idx].name))) + break; + idx++; + } + + if (idx == OSSL_NELEM(info_classical)) + idx = -1; + +err: + free(algdup); + return idx; +} + +/** \brief Compares the classical keys of two composite key pairs + * + * \param sigalg_name algorithm name. + * \param key1 A key pair. + * \param key2 A key pair. + * + * \return 1 if the compare operation is successful, else 0. */ +static int oqs_cmp_composite_sig_keys(const char *sigalg_name, + const EVP_PKEY *key1, + const EVP_PKEY *key2) { + int ret = 0, idx; + unsigned char *pubkey1 = NULL, *pubkey2 = NULL, *privkey1 = NULL, + *privkey2 = NULL; + size_t pubkey1_len, pubkey2_len, privkey1_len, privkey2_len; + + if (get_param_octet_string(key1, OSSL_PKEY_PARAM_PUB_KEY, &pubkey1, + &pubkey1_len)) { + goto out; + } + if (get_param_octet_string(key2, OSSL_PKEY_PARAM_PUB_KEY, &pubkey2, + &pubkey2_len)) { + goto out; + } + + if (get_param_octet_string(key1, OSSL_PKEY_PARAM_PRIV_KEY, &privkey1, + &privkey1_len)) { + goto out; + } + if (get_param_octet_string(key2, OSSL_PKEY_PARAM_PRIV_KEY, &privkey2, + &privkey2_len)) { + goto out; + } + + if ((idx = get_idx_info_classical(sigalg_name)) < 0) { + goto out; + } + + if (!((pubkey1_len == pubkey2_len) && (privkey1_len == privkey2_len))) { + goto out; + } + + ret = memcmp(pubkey1, pubkey2, info_classical[idx].pubkey_len) == 0 && + memcmp(privkey1, privkey2, info_classical[idx].privkey_len) == 0; + + if (ret) + return ret; + + ret = memcmp(pubkey1 + pubkey1_len - info_classical[idx].pubkey_len, + pubkey2 + pubkey2_len - info_classical[idx].pubkey_len, + info_classical[idx].pubkey_len) == 0 && + memcmp(privkey1 + privkey1_len - info_classical[idx].privkey_len, + privkey2 + privkey2_len - info_classical[idx].privkey_len, + info_classical[idx].privkey_len) == 0; + +out: + free(pubkey1); + free(pubkey2); + free(privkey1); + free(privkey2); + return ret; +} + +/** \brief Compares the classical KEM elements of two Encaps/Decaps executions + * + * \param kemalg_name algorithm name. + * \param sec1 A shared secret. + * \param sec2 A shared secret. + * \param seclen Shared secret length. + * \param ct1 An encapsulation. + * \param ct1 An encapsulation. + * \param ctlen Encapsulation length. + * + * \return 1 if the compare operation is successful, else 0. */ +static int oqs_cmp_kem_elems(const char *kemalg_name, const unsigned char *sec1, + size_t sec1len, const unsigned char *sec2, + size_t sec2len, const unsigned char *ct1, + size_t ct1len, const unsigned char *ct2, + size_t ct2len) { + int ret, idx; + + if ((idx = get_idx_info_classical(kemalg_name)) < 0) { + return 0; + } + + ret = memcmp(sec1 + sec1len - info_classical[idx].sec_len, + sec2 + sec2len - info_classical[idx].sec_len, + info_classical[idx].sec_len) == 0 && + memcmp(ct1 + ct1len - info_classical[idx].pubkey_len, + ct2 + ct2len - info_classical[idx].pubkey_len, + info_classical[idx].pubkey_len) == 0; + + if (ret) + return ret; + + ret = memcmp(sec1, sec2, info_classical[idx].sec_len) == 0 && + memcmp(ct1, ct2, info_classical[idx].pubkey_len) == 0; + + return ret; +} + +/** \brief Compares the classical SIG elements of two Sign executions + * + * \param sigalg_name algorithm name. + * \param sig1 A signature. + * \param sig1len Signature length. + * \param sig2 A signature. + * \param sig2len Signature length. + * + * \return 1 if the compare operation is successful, else 0. */ +static int oqs_cmp_sig_elems(const char *sigalg_name, const unsigned char *sig1, + size_t sig1len, const unsigned char *sig2, + size_t sig2len) { + int ret, idx; + uint32_t classical_sig1_len = 0, classical_sig2_len = 0; + + if ((idx = get_idx_info_classical(sigalg_name)) < 0) { + return 0; + } + + ret = memcmp(sig1 + sig1len - info_classical[idx].sig_len, + sig2 + sig2len - info_classical[idx].sig_len, + info_classical[idx].sig_len) == 0; + if (ret) + return ret; + + if (is_signature_algorithm_hybrid(sigalg_name)) { + DECODE_UINT32(classical_sig1_len, sig1); + DECODE_UINT32(classical_sig2_len, sig2); + } + + ret = classical_sig1_len == classical_sig2_len != 0; + if (!ret) + return ret; + + ret &= memcmp(sig1 + SIZE_OF_UINT32, sig2 + SIZE_OF_UINT32, + classical_sig1_len) == 0; + + return ret; +} + +/** \brief Executes the complete comparison of two KEM executions + * + * \param kemalg_name algorithm name. + * + * \return 1 if the compare operation is successful, else 0. */ +static int test_oqs_kems_libctx(const char *kemalg_name) { + EVP_PKEY *key1 = NULL, *key2 = NULL; + unsigned char *out1 = NULL, *out2 = NULL; + unsigned char *secenc1 = NULL, *secenc2 = NULL; + unsigned char *secdec1 = NULL, *secdec2 = NULL; + size_t out1len, out2len, sec1len, sec2len; + + int testresult = 1; + + if (!alg_is_enabled(kemalg_name)) { + printf("Not testing disabled algorithm %s.\n", kemalg_name); + return 1; + } + testresult &= oqs_generate_kem_elems(kemalg_name, &key1, &secenc1, &sec1len, + &secdec1, &out1, &out1len) && + oqs_generate_kem_elems(kemalg_name, &key2, &secenc2, &sec2len, + &secdec2, &out2, &out2len); + if (!testresult) + goto err; + + testresult &= oqs_cmp_classical_keys(key1, key2); + if (!testresult) + goto err; + + testresult &= oqs_cmp_kem_elems(kemalg_name, secenc1, sec1len, secenc2, + sec2len, out1, out1len, out2, out2len); + +err: + EVP_PKEY_free(key1); + EVP_PKEY_free(key2); + OPENSSL_free(out1); + OPENSSL_free(out2); + OPENSSL_free(secenc1); + OPENSSL_free(secenc2); + OPENSSL_free(secdec1); + OPENSSL_free(secdec2); + return testresult; +} + +/** \brief Executes the complete comparison of two SIG executions + * + * \param sigalg_name algorithm name. + * + * \return 1 if the compare operation is successful, else 0. */ +static int test_oqs_sigs_libctx(const char *sigalg_name) { + EVP_PKEY *key1 = NULL, *key2 = NULL; + const char msg[] = "The quick brown fox jumps over... you know what"; + unsigned char *sig1 = NULL, *sig2 = NULL; + size_t sig1len, sig2len; + + int testresult = 1; + + if (!alg_is_enabled(sigalg_name)) { + printf("Not testing disabled algorithm %s.\n", sigalg_name); + return 1; + } + testresult &= oqs_generate_sig_elems(sigalg_name, msg, sizeof(msg), &key1, + &sig1, &sig1len) && + oqs_generate_sig_elems(sigalg_name, msg, sizeof(msg), &key2, + &sig2, &sig2len); + + if (!testresult) + goto err; + + if (is_signature_algorithm_hybrid(sigalg_name)) { + testresult &= oqs_cmp_classical_keys(key1, key2); + } else { + testresult &= oqs_cmp_composite_sig_keys(sigalg_name, key1, key2); + } + + if (!testresult) + goto err; + + testresult &= oqs_cmp_sig_elems(sigalg_name, sig1, sig1len, sig2, sig2len); + +err: + EVP_PKEY_free(key1); + EVP_PKEY_free(key2); + OPENSSL_free(sig1); + OPENSSL_free(sig2); + return testresult; +} + +#define nelem(a) (sizeof(a) / sizeof((a)[0])) + +int main(int argc, char *argv[]) { + size_t i; + int errcnt = 0, test = 0, query_nocache; + OSSL_PROVIDER *oqsprov = NULL; + const OSSL_ALGORITHM *kemalgs, *sigalgs; + + T((libctx = OSSL_LIB_CTX_new()) != NULL); + T(argc == 3); + modulename = argv[1]; + configfile = argv[2]; + + oqs_load_det_pseudorandom_generator(libctx); + load_oqs_provider(libctx, modulename, configfile); + + oqsprov = OSSL_PROVIDER_load(libctx, modulename); + + kemalgs = + OSSL_PROVIDER_query_operation(oqsprov, OSSL_OP_KEM, &query_nocache); + if (kemalgs) { + for (; kemalgs->algorithm_names != NULL; kemalgs++) { + if (!is_kem_algorithm_hybrid(kemalgs->algorithm_names)) { + continue; + } + if (test_oqs_kems_libctx(kemalgs->algorithm_names)) { + fprintf(stderr, + cGREEN " libctx KEM test succeeded: %s" cNORM "\n", + kemalgs->algorithm_names); + } else { + fprintf(stderr, cRED " libctx KEM test failed: %s" cNORM "\n", + kemalgs->algorithm_names); + ERR_print_errors_fp(stderr); + errcnt++; + } + } + } + + sigalgs = OSSL_PROVIDER_query_operation(oqsprov, OSSL_OP_SIGNATURE, + &query_nocache); + if (sigalgs) { + for (; sigalgs->algorithm_names != NULL; sigalgs++) { + if (!is_signature_algorithm_hybrid(sigalgs->algorithm_names) && + !is_signature_algorithm_composite(sigalgs->algorithm_names)) { + continue; + } + if (test_oqs_sigs_libctx(sigalgs->algorithm_names)) { + fprintf(stderr, + cGREEN " libctx SIG test succeeded: %s" cNORM "\n", + sigalgs->algorithm_names); + } else { + fprintf(stderr, cRED " libctx SIG test failed: %s" cNORM "\n", + sigalgs->algorithm_names); + ERR_print_errors_fp(stderr); + errcnt++; + } + } + } + + OSSL_PROVIDER_unload(oqsprov); + OSSL_LIB_CTX_free(libctx); + + TEST_ASSERT(errcnt == 0) + return !test; +} diff --git a/test/test_common.c b/test/test_common.c index 645b2839..35381f53 100644 --- a/test/test_common.c +++ b/test/test_common.c @@ -2,8 +2,87 @@ #include "test_common.h" +#include #include +///// OQS_TEMPLATE_FRAGMENT_HYBRID_SIG_ALGS_START + +/** \brief List of hybrid signature algorithms. */ +const char *kHybridSignatureAlgorithms[] = { + "p256_mldsa44", + "rsa3072_mldsa44", + "p384_mldsa65", + "p521_mldsa87", + "p256_falcon512", + "rsa3072_falcon512", + "p256_falconpadded512", + "rsa3072_falconpadded512", + "p521_falcon1024", + "p521_falconpadded1024", + "p256_sphincssha2128fsimple", + "rsa3072_sphincssha2128fsimple", + "p256_sphincssha2128ssimple", + "rsa3072_sphincssha2128ssimple", + "p384_sphincssha2192fsimple", + "p256_sphincsshake128fsimple", + "rsa3072_sphincsshake128fsimple", + "p256_mayo1", + "p256_mayo2", + "p384_mayo3", + "p521_mayo5", + NULL, +}; +///// OQS_TEMPLATE_FRAGMENT_HYBRID_SIG_ALGS_END + +///// OQS_TEMPLATE_FRAGMENT_COMPOSITE_SIG_ALGS_START + +/** \brief List of composite signature algorithms. */ +const char *kCompositeSignatureAlgorithms[] = { + "mldsa44_pss2048", "mldsa44_rsa2048", + "mldsa44_ed25519", "mldsa44_p256", + "mldsa44_bp256", "mldsa65_pss3072", + "mldsa65_rsa3072", "mldsa65_p256", + "mldsa65_bp256", "mldsa65_ed25519", + "mldsa87_p384", "mldsa87_bp384", + "mldsa87_ed448", NULL, +}; +///// OQS_TEMPLATE_FRAGMENT_COMPOSITE_SIG_ALGS_END + +///// OQS_TEMPLATE_FRAGMENT_HYBRID_KEM_ALGS_START + +/** \brief List of hybrid KEMs. */ +const char *kHybridKEMAlgorithms[] = { + "p256_frodo640aes", + "x25519_frodo640aes", + "p256_frodo640shake", + "x25519_frodo640shake", + "p384_frodo976aes", + "x448_frodo976aes", + "p384_frodo976shake", + "x448_frodo976shake", + "p521_frodo1344aes", + "p521_frodo1344shake", + "p256_mlkem512", + "x25519_mlkem512", + "p384_mlkem768", + "x448_mlkem768", + "X25519MLKEM768", + "SecP256r1MLKEM768", + "p521_mlkem1024", + "SecP384r1MLKEM1024", + "p256_bikel1", + "x25519_bikel1", + "p384_bikel3", + "x448_bikel3", + "p521_bikel5", + "p256_hqc128", + "x25519_hqc128", + "p384_hqc192", + "x448_hqc192", + "p521_hqc256", + NULL, +}; ///// OQS_TEMPLATE_FRAGMENT_HYBRID_KEM_ALGS_END + void hexdump(const void *ptr, size_t len) { const unsigned char *p = ptr; size_t i, j; @@ -69,3 +148,68 @@ void load_oqs_provider(OSSL_LIB_CTX *libctx, const char *modulename, } #endif // ifndef OQS_PROVIDER_STATIC + +/** \brief Indicates if a string is in a given list of strings. + * + * \param list List of strings. + * \param s String to test. + * + * \return 1 if `s` is in `list`, else 0. */ +static int is_string_in_list(const char **list, const char *s) { + for (; *list != NULL && strcmp(*list, s) != 0; ++list) + ; + if (*list != NULL) { + return 1; + } + return 0; +} + +int is_signature_algorithm_hybrid(const char *_alg_) { + return is_string_in_list(kHybridSignatureAlgorithms, _alg_); +} + +int is_signature_algorithm_composite(const char *_alg_) { + return is_string_in_list(kCompositeSignatureAlgorithms, _alg_); +} + +int is_kem_algorithm_hybrid(const char *_alg_) { + return is_string_in_list(kHybridKEMAlgorithms, _alg_); +} + +int get_param_octet_string(const EVP_PKEY *key, const char *param_name, + uint8_t **buf, size_t *buf_len) { + *buf = NULL; + *buf_len = 0; + int ret = -1; + + if (EVP_PKEY_get_octet_string_param(key, param_name, NULL, 0, buf_len) != + 1) { + fprintf(stderr, + cRED + "`EVP_PKEY_get_octet_string_param` failed with param `%s`: ", + param_name); + ERR_print_errors_fp(stderr); + fputs(cNORM "\n", stderr); + goto out; + } + if (!(*buf = malloc(*buf_len))) { + fprintf(stderr, "failed to allocate %#zx byte(s)\n", *buf_len); + goto out; + } + if (EVP_PKEY_get_octet_string_param(key, param_name, *buf, *buf_len, + buf_len) != 1) { + fprintf(stderr, + cRED + "`EVP_PKEY_get_octet_string_param` failed with param `%s`: ", + param_name); + ERR_print_errors_fp(stderr); + fputs(cNORM "\n", stderr); + free(*buf); + *buf = NULL; + } else { + ret = 0; + } + +out: + return ret; +} diff --git a/test/test_common.h b/test/test_common.h index b7aa76ff..ba864bff 100644 --- a/test/test_common.h +++ b/test/test_common.h @@ -46,3 +46,35 @@ OSSL_PROVIDER *load_default_provider(OSSL_LIB_CTX *libctx); /* Loads the oqs-provider. */ void load_oqs_provider(OSSL_LIB_CTX *libctx, const char *modulename, const char *configfile); + +/** \brief Indicates if a signature algorithm is hybrid or not. + * + * \param alg Algorithm name. + * + * \returns 1 if hybrid, else 0. */ +int is_signature_algorithm_hybrid(const char *_alg_); + +/** \brief Indicates if a signature algorithm is composite or not. + * + * \param alg Algorithm name. + * + * \returns 1 if hybrid, else 0. */ +int is_signature_algorithm_composite(const char *_alg_); + +/** \brief Indicates if an kem algorithm is hybrid or not. + * + * \param alg Algorithm name. + * + * \returns 1 if hybrid, else 0. */ +int is_kem_algorithm_hybrid(const char *_alg_); + +/** \brief Extracts an octet string from a parameter of an EVP_PKEY. + * + * \param key The EVP_PKEY; + * \param param_name Name of the parameter. + * \param[out] buf Out buffer. + * \param[out] buf_len Size of out buffer. + * + * \returns 0 on success. */ +int get_param_octet_string(const EVP_PKEY *key, const char *param_name, + uint8_t **buf, size_t *buf_len); From 1e07b8115a0a254f8a9d1754074fd487c855d493 Mon Sep 17 00:00:00 2001 From: RodriM11 <62776780+RodriM11@users.noreply.github.com> Date: Sun, 5 Jan 2025 13:50:26 +0100 Subject: [PATCH 2/2] better error checks oqs_test_libctx MSVC Signed-off-by: RodriM11 <62776780+RodriM11@users.noreply.github.com> --- test/oqs_test_libctx.c | 97 ++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 37 deletions(-) diff --git a/test/oqs_test_libctx.c b/test/oqs_test_libctx.c index fcee86a3..1058b6d5 100644 --- a/test/oqs_test_libctx.c +++ b/test/oqs_test_libctx.c @@ -10,6 +10,10 @@ #include "oqs_prov.h" #include "test_common.h" +#ifdef _MSC_VER +#define strtok_r strtok_s +#endif + #define MAX_DUMMY_ENTROPY_BUFFERLEN 0x100000 /** \brief The info about classical elements needed. */ @@ -47,51 +51,59 @@ static char *modulename = NULL; static char *configfile = NULL; /** \brief Loads OpenSSL's 'TEST-RAND' deterministic pseudorandom generator for - * the given library context - * - * \param libctx Library context. + * the test's library context * * \return 1 if the configuration is successfully loaded, else 0. */ -static int oqs_load_det_pseudorandom_generator(OSSL_LIB_CTX *libctx) { +static int oqs_load_det_pseudorandom_generator() { OSSL_PARAM params[2], *p = params; - unsigned char entropy[MAX_DUMMY_ENTROPY_BUFFERLEN]; - RAND_bytes(entropy, sizeof(entropy)); + unsigned int entropy_len = MAX_DUMMY_ENTROPY_BUFFERLEN; + int ret = 0; + unsigned char *entropy = OPENSSL_malloc(entropy_len); + + if (!entropy) { + goto err; + } + + if (!RAND_bytes(entropy, entropy_len)) { + goto err; + } if (!RAND_set_DRBG_type(libctx, "TEST-RAND", NULL, NULL, NULL)) { - return 0; + goto err; } *p++ = OSSL_PARAM_construct_octet_string(OSSL_RAND_PARAM_TEST_ENTROPY, - entropy, sizeof(entropy)); + entropy, entropy_len); *p = OSSL_PARAM_construct_end(); EVP_RAND_CTX *rctx_public = RAND_get0_public(libctx); if (!rctx_public) { - return 0; + goto err; } if (!EVP_RAND_CTX_set_params(rctx_public, params)) { - return 0; + goto err; } EVP_RAND_CTX *rctx_private = RAND_get0_private(libctx); if (!rctx_private) { - return 0; + goto err; } if (!EVP_RAND_CTX_set_params(rctx_private, params)) { - return 0; + goto err; } + ret = 1; - return 1; +err: + OPENSSL_free(entropy); + return ret; } -/** \brief Resets the given library context's DRBG instances - * - * \param libctx Library context. +/** \brief Resets the test's library context DRBG instances * * \return 1 if the configuration is successfully restarted, else 0. */ -static int oqs_reset_det_pseudorandom_generator(OSSL_LIB_CTX *libctx) { +static int oqs_reset_det_pseudorandom_generator() { OSSL_PARAM params[2], *p = params; unsigned int strength = 256; @@ -141,7 +153,7 @@ static int oqs_generate_kem_elems(const char *kemalg_name, EVP_PKEY **key, int testresult = 0; EVP_PKEY_CTX *ctx = NULL; - if (!oqs_reset_det_pseudorandom_generator(libctx)) { + if (!oqs_reset_det_pseudorandom_generator()) { return 0; } @@ -192,7 +204,7 @@ static int oqs_generate_sig_elems(const char *sigalg_name, const char *msg, EVP_PKEY_CTX *ctx = NULL; EVP_MD_CTX *mdctx = NULL; - if (!oqs_reset_det_pseudorandom_generator(libctx)) { + if (!oqs_reset_det_pseudorandom_generator()) { return 0; } @@ -268,36 +280,50 @@ static int oqs_cmp_classical_keys(const EVP_PKEY *key1, const EVP_PKEY *key2) { * \param alg_name algorithm name. * * \return The associated index, or -1 in case no match is found. */ -static int get_idx_info_classical(const char *alg_name) { +int get_idx_info_classical(const char *alg_name) { + char *name = NULL, *rest = NULL, *algdup = NULL; int idx = 0; - char *algdup = strdup(alg_name); - char *name = strtok(algdup, "_"); + + if (alg_name == NULL || strlen(alg_name) == 0) { + return -1; + } + + algdup = strdup(alg_name); + if (algdup == NULL) { + return -1; + } + rest = algdup; + + name = strtok_r(rest, "_", &rest); + if (name == NULL) { + idx = -1; + goto err; + } while (idx < OSSL_NELEM(info_classical)) { - if (!strncmp(name, info_classical[idx].name, + if (strlen(name) >= strlen(info_classical[idx].name) && + !strncmp(name, info_classical[idx].name, strlen(info_classical[idx].name))) goto err; idx++; } - if (idx == - OSSL_NELEM(info_classical)) { // Might have encountered a 'composite' - // alg, so try again with the second - // part of the separator + if (idx == OSSL_NELEM(info_classical) && + rest) { // Might have encountered a 'composite' + // alg, so try again with the second + // part of the separator + name = rest; idx = 0; - name = strtok(NULL, "_"); } while (idx < OSSL_NELEM(info_classical)) { - if (!strncmp(name, info_classical[idx].name, + if (strlen(name) >= strlen(info_classical[idx].name) && + !strncmp(name, info_classical[idx].name, strlen(info_classical[idx].name))) - break; + goto err; idx++; } - if (idx == OSSL_NELEM(info_classical)) - idx = -1; - err: free(algdup); return idx; @@ -508,7 +534,6 @@ static int test_oqs_sigs_libctx(const char *sigalg_name) { &sig1, &sig1len) && oqs_generate_sig_elems(sigalg_name, msg, sizeof(msg), &key2, &sig2, &sig2len); - if (!testresult) goto err; @@ -531,8 +556,6 @@ static int test_oqs_sigs_libctx(const char *sigalg_name) { return testresult; } -#define nelem(a) (sizeof(a) / sizeof((a)[0])) - int main(int argc, char *argv[]) { size_t i; int errcnt = 0, test = 0, query_nocache; @@ -544,7 +567,7 @@ int main(int argc, char *argv[]) { modulename = argv[1]; configfile = argv[2]; - oqs_load_det_pseudorandom_generator(libctx); + oqs_load_det_pseudorandom_generator(); load_oqs_provider(libctx, modulename, configfile); oqsprov = OSSL_PROVIDER_load(libctx, modulename);