From 0e436524899d58ceea807cf277d7fcffa14f9065 Mon Sep 17 00:00:00 2001 From: slontis Date: Tue, 11 Feb 2025 15:30:59 +1100 Subject: [PATCH] SLH-DSA: Add EVP_PKEY_CTX_dup() support. Reviewed-by: Tim Hudson Reviewed-by: Viktor Dukhovni Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/26701) --- crypto/slh_dsa/slh_dsa_hash_ctx.c | 36 ++++++++++++++++ crypto/slh_dsa/slh_dsa_key.h | 3 ++ crypto/slh_dsa/slh_dsa_local.h | 3 ++ include/crypto/slh_dsa.h | 1 + .../implementations/keymgmt/slh_dsa_kmgmt.c | 9 ++++ .../implementations/signature/slh_dsa_sig.c | 34 +++++++++++++++ test/slh_dsa_test.c | 43 +++++++++++++------ 7 files changed, 116 insertions(+), 13 deletions(-) diff --git a/crypto/slh_dsa/slh_dsa_hash_ctx.c b/crypto/slh_dsa/slh_dsa_hash_ctx.c index f640801be56..89ec68467b7 100644 --- a/crypto/slh_dsa/slh_dsa_hash_ctx.c +++ b/crypto/slh_dsa/slh_dsa_hash_ctx.c @@ -60,6 +60,42 @@ SLH_DSA_HASH_CTX *ossl_slh_dsa_hash_ctx_new(const SLH_DSA_KEY *key) return NULL; } +/** + * @brief Duplicate a SLH_DSA_HASH_CTX + * + * @param ctx The SLH_DSA_HASH_CTX object to duplicate. + */ +SLH_DSA_HASH_CTX *ossl_slh_dsa_hash_ctx_dup(const SLH_DSA_HASH_CTX *src) +{ + SLH_DSA_HASH_CTX *ret = OPENSSL_zalloc(sizeof(*ret)); + + if (ret == NULL) + return NULL; + + ret->hmac_digest_used = src->hmac_digest_used; + /* Note that the key is not ref counted, since it does not own the key */ + ret->key = src->key; + + if (src->md_ctx != NULL + && (ret->md_ctx = EVP_MD_CTX_dup(src->md_ctx)) == NULL) + goto err; + if (src->md_big_ctx != NULL) { + if (src->md_big_ctx != src->md_ctx) { + if ((ret->md_big_ctx = EVP_MD_CTX_dup(src->md_big_ctx)) == NULL) + goto err; + } else { + ret->md_big_ctx = ret->md_ctx; + } + } + if (src->hmac_ctx != NULL + && (ret->hmac_ctx = EVP_MAC_CTX_dup(src->hmac_ctx)) == NULL) + goto err; + return ret; + err: + ossl_slh_dsa_hash_ctx_free(ret); + return NULL; +} + /** * @brief Destroy a SLH_DSA_HASH_CTX * diff --git a/crypto/slh_dsa/slh_dsa_key.h b/crypto/slh_dsa/slh_dsa_key.h index 3c81b55d56c..851821c8dd0 100644 --- a/crypto/slh_dsa/slh_dsa_key.h +++ b/crypto/slh_dsa/slh_dsa_key.h @@ -17,6 +17,9 @@ #define SLH_DSA_PUB(key) SLH_DSA_PK_SEED(key) #define SLH_DSA_PRIV(key) SLH_DSA_SK_SEED(key) +/* + * NOTE: Any changes to this structure may require updating ossl_slh_dsa_key_dup(). + */ struct slh_dsa_key_st { /* * A private key consists of diff --git a/crypto/slh_dsa/slh_dsa_local.h b/crypto/slh_dsa/slh_dsa_local.h index 40d26f67202..1c66382c72b 100644 --- a/crypto/slh_dsa/slh_dsa_local.h +++ b/crypto/slh_dsa/slh_dsa_local.h @@ -41,6 +41,9 @@ * SLH_DSA_HASH_CTX is a container to hold all of these objects. This object is * resolved early and is then passed to most SLH_DSA related functions, since * there are many nested layers of calls that require these values. + * + * NOTE: Any changes to this structure will need updating in + * ossl_slh_dsa_hash_ctx_dup(). */ struct slh_dsa_hash_ctx_st { const SLH_DSA_KEY *key; /* This key is not owned by this object */ diff --git a/include/crypto/slh_dsa.h b/include/crypto/slh_dsa.h index 72390783bbe..002427e1ab0 100644 --- a/include/crypto/slh_dsa.h +++ b/include/crypto/slh_dsa.h @@ -51,6 +51,7 @@ __owur int ossl_slh_dsa_key_get_type(const SLH_DSA_KEY *key); __owur int ossl_slh_dsa_key_type_matches(const SLH_DSA_KEY *key, const char *alg); __owur SLH_DSA_HASH_CTX *ossl_slh_dsa_hash_ctx_new(const SLH_DSA_KEY *key); void ossl_slh_dsa_hash_ctx_free(SLH_DSA_HASH_CTX *ctx); +__owur SLH_DSA_HASH_CTX *ossl_slh_dsa_hash_ctx_dup(const SLH_DSA_HASH_CTX *src); __owur int ossl_slh_dsa_sign(SLH_DSA_HASH_CTX *slh_ctx, const uint8_t *msg, size_t msg_len, diff --git a/providers/implementations/keymgmt/slh_dsa_kmgmt.c b/providers/implementations/keymgmt/slh_dsa_kmgmt.c index 4b33f891877..e7ef60871b5 100644 --- a/providers/implementations/keymgmt/slh_dsa_kmgmt.c +++ b/providers/implementations/keymgmt/slh_dsa_kmgmt.c @@ -32,6 +32,7 @@ static OSSL_FUNC_keymgmt_gen_init_fn slh_dsa_gen_init; static OSSL_FUNC_keymgmt_gen_cleanup_fn slh_dsa_gen_cleanup; static OSSL_FUNC_keymgmt_gen_set_params_fn slh_dsa_gen_set_params; static OSSL_FUNC_keymgmt_gen_settable_params_fn slh_dsa_gen_settable_params; +static OSSL_FUNC_keymgmt_dup_fn slh_dsa_dup_key; #define SLH_DSA_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR) @@ -56,6 +57,13 @@ static void slh_dsa_free_key(void *keydata) ossl_slh_dsa_key_free((SLH_DSA_KEY *)keydata); } +static void *slh_dsa_dup_key(const void *keydata_from, int selection) +{ + if (ossl_prov_is_running()) + return ossl_slh_dsa_key_dup(keydata_from, selection); + return NULL; +} + static int slh_dsa_has(const void *keydata, int selection) { const SLH_DSA_KEY *key = keydata; @@ -412,6 +420,7 @@ static void slh_dsa_gen_cleanup(void *genctx) const OSSL_DISPATCH ossl_slh_dsa_##fn##_keymgmt_functions[] = { \ { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))slh_dsa_##fn##_new_key }, \ { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))slh_dsa_free_key }, \ + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))slh_dsa_dup_key }, \ { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))slh_dsa_has }, \ { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))slh_dsa_match }, \ { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))slh_dsa_import }, \ diff --git a/providers/implementations/signature/slh_dsa_sig.c b/providers/implementations/signature/slh_dsa_sig.c index b30ebcf5328..f8c07f4236c 100644 --- a/providers/implementations/signature/slh_dsa_sig.c +++ b/providers/implementations/signature/slh_dsa_sig.c @@ -34,9 +34,13 @@ static OSSL_FUNC_signature_digest_sign_init_fn slh_dsa_digest_signverify_init; static OSSL_FUNC_signature_digest_sign_fn slh_dsa_digest_sign; static OSSL_FUNC_signature_digest_verify_fn slh_dsa_digest_verify; static OSSL_FUNC_signature_freectx_fn slh_dsa_freectx; +static OSSL_FUNC_signature_dupctx_fn slh_dsa_dupctx; static OSSL_FUNC_signature_set_ctx_params_fn slh_dsa_set_ctx_params; static OSSL_FUNC_signature_settable_ctx_params_fn slh_dsa_settable_ctx_params; +/* + * NOTE: Any changes to this structure may require updating slh_dsa_dupctx(). + */ typedef struct { SLH_DSA_KEY *key; /* Note that the key is not owned by this object */ SLH_DSA_HASH_CTX *hash_ctx; @@ -86,6 +90,35 @@ static void *slh_dsa_newctx(void *provctx, const char *alg, const char *propq) return NULL; } +static void *slh_dsa_dupctx(void *vctx) +{ + PROV_SLH_DSA_CTX *src = (PROV_SLH_DSA_CTX *)vctx; + PROV_SLH_DSA_CTX *ret; + + if (!ossl_prov_is_running()) + return NULL; + + /* + * Note that the SLH_DSA_KEY is ref counted via EVP_PKEY so we can just copy + * the key here. + */ + ret = OPENSSL_memdup(src, sizeof(*src)); + if (ret == NULL) + return NULL; + ret->propq = NULL; + ret->hash_ctx = NULL; + if (src->propq != NULL && (ret->propq = OPENSSL_strdup(src->propq)) == NULL) + goto err; + ret->hash_ctx = ossl_slh_dsa_hash_ctx_dup(src->hash_ctx); + if (ret->hash_ctx == NULL) + goto err; + + return ret; + err: + slh_dsa_freectx(ret); + return NULL; +} + static int slh_dsa_set_alg_id_buffer(PROV_SLH_DSA_CTX *ctx) { int ret; @@ -334,6 +367,7 @@ static int slh_dsa_get_ctx_params(void *vctx, OSSL_PARAM *params) { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, \ (void (*)(void))slh_dsa_digest_verify }, \ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))slh_dsa_freectx }, \ + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))slh_dsa_dupctx }, \ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))slh_dsa_set_ctx_params },\ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \ (void (*)(void))slh_dsa_settable_ctx_params }, \ diff --git a/test/slh_dsa_test.c b/test/slh_dsa_test.c index d39b1146ee3..7f5a4e54d31 100644 --- a/test/slh_dsa_test.c +++ b/test/slh_dsa_test.c @@ -116,7 +116,8 @@ end: static int slh_dsa_key_eq_test(void) { int ret = 0; - EVP_PKEY *key[3] = { NULL, NULL, NULL }; + size_t i; + EVP_PKEY *key[4] = { NULL, NULL, NULL, NULL }; SLH_DSA_SIG_TEST_DATA *td1 = &slh_dsa_sig_testdata[0]; SLH_DSA_SIG_TEST_DATA *td2 = &slh_dsa_sig_testdata[1]; #ifndef OPENSSL_NO_EC @@ -125,11 +126,13 @@ static int slh_dsa_key_eq_test(void) if (!TEST_ptr(key[0] = slh_dsa_key_from_data(td1->alg, td1->pub, td1->pub_len, 1)) || !TEST_ptr(key[1] = slh_dsa_key_from_data(td1->alg, td1->pub, td1->pub_len, 1)) - || !TEST_ptr(key[2] = slh_dsa_key_from_data(td2->alg, td2->pub, td2->pub_len, 1))) + || !TEST_ptr(key[2] = slh_dsa_key_from_data(td2->alg, td2->pub, td2->pub_len, 1)) + || !TEST_ptr(key[3] = EVP_PKEY_dup(key[0]))) goto end; if (!TEST_int_eq(EVP_PKEY_eq(key[0], key[1]), 1) - || !TEST_int_ne(EVP_PKEY_eq(key[0], key[2]), 1)) + || !TEST_int_ne(EVP_PKEY_eq(key[0], key[2]), 1) + || !TEST_int_eq(EVP_PKEY_eq(key[0], key[3]), 1)) goto end; #ifndef OPENSSL_NO_EC @@ -140,10 +143,9 @@ static int slh_dsa_key_eq_test(void) #else ret = 1; #endif -end: - EVP_PKEY_free(key[2]); - EVP_PKEY_free(key[1]); - EVP_PKEY_free(key[0]); + end: + for (i = 0; i < OSSL_NELEM(key); ++i) + EVP_PKEY_free(key[i]); return ret; } @@ -433,11 +435,11 @@ static int slh_dsa_deterministic_usage_test(void) EVP_CIPHER *cipher = NULL; /* Used to encrypt the private key */ char *pass = "Password"; BIO *pub_bio = NULL, *priv_bio = NULL; - EVP_PKEY_CTX *gctx = NULL, *sctx = NULL, *vctx = NULL; + EVP_PKEY_CTX *gctx = NULL, *sctx = NULL, *vctx = NULL, *dupctx = NULL; EVP_PKEY *gkey = NULL, *pub = NULL, *priv = NULL; EVP_SIGNATURE *sig_alg = NULL; uint8_t *sig = NULL; - size_t sig_len = 0; + size_t sig_len = 0, len = 0; uint8_t msg[] = { 0x01, 0x02, 0x03, 0x04 }; size_t msg_len = sizeof(msg); const SLH_DSA_KEYGEN_TEST_DATA *tst = &slh_dsa_keygen_testdata[0]; @@ -471,18 +473,32 @@ static int slh_dsa_deterministic_usage_test(void) || !TEST_int_eq(EVP_PKEY_sign_message_init(sctx, sig_alg, params), 1)) goto err; + if (!TEST_ptr(dupctx = EVP_PKEY_CTX_dup(sctx))) + goto err; + /* Determine the size of the signature & allocate space */ - if (!TEST_int_eq(EVP_PKEY_sign(sctx, NULL, &sig_len, msg, msg_len), 1) - || !TEST_ptr(sig = OPENSSL_malloc(sig_len)) - || !TEST_int_eq(EVP_PKEY_sign(sctx, sig, &sig_len, msg, msg_len), 1)) + if (!TEST_int_eq(EVP_PKEY_sign(sctx, NULL, &sig_len, msg, msg_len), 1)) + goto err; + len = sig_len; + if (!TEST_ptr(sig = OPENSSL_zalloc(sig_len * 2)) + || !TEST_int_eq(EVP_PKEY_sign(sctx, sig, &len, msg, msg_len), 1) + || !TEST_size_t_eq(sig_len, len) + || !TEST_int_eq(EVP_PKEY_sign(dupctx, sig + sig_len, &len, + msg, msg_len), 1) + || !TEST_size_t_eq(sig_len, len)) goto err; /* Read the public key and add to a verify ctx */ if (!TEST_ptr(PEM_read_bio_PUBKEY_ex(pub_bio, &pub, NULL, NULL, lib_ctx, NULL)) || !TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, pub, NULL))) goto err; + EVP_PKEY_CTX_free(dupctx); + /* verify the signature */ if (!TEST_int_eq(EVP_PKEY_verify_message_init(vctx, sig_alg, NULL), 1) - || !TEST_int_eq(EVP_PKEY_verify(vctx, sig, sig_len, msg, msg_len), 1)) + || !TEST_ptr(dupctx = EVP_PKEY_CTX_dup(vctx)) + || !TEST_int_eq(EVP_PKEY_verify(vctx, sig, sig_len, msg, msg_len), 1) + || !TEST_int_eq(EVP_PKEY_verify(dupctx, sig + sig_len, sig_len, + msg, msg_len), 1)) goto err; ret = 1; err: @@ -494,6 +510,7 @@ err: EVP_PKEY_CTX_free(gctx); EVP_PKEY_CTX_free(sctx); EVP_PKEY_CTX_free(vctx); + EVP_PKEY_CTX_free(dupctx); BIO_free(pub_bio); BIO_free(priv_bio); OPENSSL_free(sig); -- 2.47.2