From 3138976041e6637c732b11c1e0b3d57a1ebd4afb Mon Sep 17 00:00:00 2001 From: Viktor Dukhovni Date: Sun, 9 Feb 2025 13:07:39 +1100 Subject: [PATCH] Make the ML-DSA seed gettable as documented - Also fix the get_params keymgmt function to always return what's available. Requested, but unavailable, parameters are simply left unmodified. It is not an error to request more than is present. Reviewed-by: Tim Hudson Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/26674) --- .../implementations/keymgmt/ml_dsa_kmgmt.c | 33 ++++++++++--------- test/ml_dsa_test.c | 9 +++-- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/providers/implementations/keymgmt/ml_dsa_kmgmt.c b/providers/implementations/keymgmt/ml_dsa_kmgmt.c index ac837f3f96..ec49cb3efe 100644 --- a/providers/implementations/keymgmt/ml_dsa_kmgmt.c +++ b/providers/implementations/keymgmt/ml_dsa_kmgmt.c @@ -263,6 +263,7 @@ static int ml_dsa_import(void *keydata, int selection, const OSSL_PARAM params[] } #define ML_DSA_IMEXPORTABLE_PARAMETERS \ + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ML_DSA_SEED, NULL, 0), \ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), \ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0) @@ -294,7 +295,7 @@ static int ml_dsa_get_params(void *keydata, OSSL_PARAM params[]) { ML_DSA_KEY *key = keydata; OSSL_PARAM *p; - const uint8_t *pub, *priv; + const uint8_t *pub, *priv, *seed; if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL && !OSSL_PARAM_set_int(p, 8 * ossl_ml_dsa_key_get_pub_len(key))) @@ -308,22 +309,22 @@ static int ml_dsa_get_params(void *keydata, OSSL_PARAM params[]) pub = ossl_ml_dsa_key_get_pub(key); priv = ossl_ml_dsa_key_get_priv(key); + seed = ossl_ml_dsa_key_get_seed(key); - /* This just gets the private elements */ - p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY); - if (p != NULL) { - if (priv == NULL - || !OSSL_PARAM_set_octet_string(p, priv, - ossl_ml_dsa_key_get_priv_len(key))) - return 0; - } - p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PUB_KEY); - if (p != NULL) { - if (pub == NULL - || !OSSL_PARAM_set_octet_string(p, pub, - ossl_ml_dsa_key_get_pub_len(key))) - return 0; - } + if (seed != NULL + && (p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ML_DSA_SEED)) != NULL + && !OSSL_PARAM_set_octet_string(p, seed, ML_DSA_SEED_BYTES)) + return 0; + if (priv != NULL + && (p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY)) != NULL + && !OSSL_PARAM_set_octet_string(p, priv, + ossl_ml_dsa_key_get_priv_len(key))) + return 0; + if (pub != NULL + && (p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PUB_KEY)) != NULL + && !OSSL_PARAM_set_octet_string(p, pub, + ossl_ml_dsa_key_get_pub_len(key))) + return 0; /* * This allows apps to use an empty digest, so that the old API * for digest signing can be used. diff --git a/test/ml_dsa_test.c b/test/ml_dsa_test.c index 24d49a91b6..58bb2ede72 100644 --- a/test/ml_dsa_test.c +++ b/test/ml_dsa_test.c @@ -87,16 +87,19 @@ static int ml_dsa_keygen_test(int tst_id) int ret = 0; const ML_DSA_KEYGEN_TEST_DATA *tst = &ml_dsa_keygen_testdata[tst_id]; EVP_PKEY *pkey = NULL; - uint8_t priv[5 * 1024], pub[3 * 1024]; - size_t priv_len, pub_len; + uint8_t priv[5 * 1024], pub[3 * 1024], seed[ML_DSA_SEED_BYTES]; + size_t priv_len, pub_len, seed_len; if (!TEST_ptr(pkey = do_gen_key(tst->name, tst->seed, tst->seed_len)) + || !TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ML_DSA_SEED, + seed, sizeof(seed), &seed_len)) || !TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, priv, sizeof(priv), &priv_len)) || !TEST_true(EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, pub, sizeof(pub), &pub_len)) || !TEST_mem_eq(pub, pub_len, tst->pub, tst->pub_len) - || !TEST_mem_eq(priv, priv_len, tst->priv, tst->priv_len)) + || !TEST_mem_eq(priv, priv_len, tst->priv, tst->priv_len) + || !TEST_mem_eq(seed, seed_len, tst->seed, tst->seed_len)) goto err; ret = 1; err: