From c848506cd4a0f978f22dbbba9826b11992afa33e Mon Sep 17 00:00:00 2001 From: slontis Date: Fri, 17 Jan 2025 15:05:21 +1100 Subject: [PATCH] ML-DSA: Add support for dup. Reviewed-by: Viktor Dukhovni Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/26451) --- crypto/ml_dsa/ml_dsa_key.c | 67 +++++++++++++++++++ crypto/ml_dsa/ml_dsa_key.h | 1 + crypto/ml_dsa/ml_dsa_vector.h | 1 + include/crypto/ml_dsa.h | 1 + .../implementations/keymgmt/ml_dsa_kmgmt.c | 9 +++ .../implementations/signature/ml_dsa_sig.c | 16 +++++ 6 files changed, 95 insertions(+) diff --git a/crypto/ml_dsa/ml_dsa_key.c b/crypto/ml_dsa/ml_dsa_key.c index 00f1dc4a367..6694a94e22d 100644 --- a/crypto/ml_dsa/ml_dsa_key.c +++ b/crypto/ml_dsa/ml_dsa_key.c @@ -96,6 +96,73 @@ void ossl_ml_dsa_key_free(ML_DSA_KEY *key) OPENSSL_free(key); } +/** + * @brief Duplicate a key + * + * @param src A ML_DSA_KEY object to copy + * @param selection to select public and/or private components. Selecting the + * private key will also select the public key + * @returns The duplicated key, or NULL on failure. + */ +ML_DSA_KEY *ossl_ml_dsa_key_dup(const ML_DSA_KEY *src, int selection) +{ + ML_DSA_KEY *ret = NULL; + + if (src == NULL) + return NULL; + + ret = OPENSSL_zalloc(sizeof(*ret)); + if (ret != NULL) { + ret->libctx = src->libctx; + ret->params = src->params; + if (src->propq != NULL) { + if ((ret->propq = OPENSSL_strdup(src->propq)) == NULL) + goto err; + } + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + if (src->pub_encoding != NULL) { + /* The public components are present if the private key is present */ + memcpy(ret->rho, src->rho, sizeof(src->rho)); + memcpy(ret->tr, src->tr, sizeof(src->tr)); + if (src->t1.poly != NULL) { + if (!ossl_ml_dsa_key_pub_alloc(ret)) + goto err; + vector_copy(&ret->t1, &src->t1); + } + if ((ret->pub_encoding = OPENSSL_memdup(src->pub_encoding, + src->params->pk_len)) == NULL) + goto err; + } + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + if (src->priv_encoding != NULL) { + memcpy(ret->K, src->K, sizeof(src->K)); + if (src->s1.poly != NULL) { + if (!ossl_ml_dsa_key_priv_alloc(ret)) + goto err; + vector_copy(&ret->s1, &src->s1); + vector_copy(&ret->s2, &src->s2); + vector_copy(&ret->t0, &src->t0); + } + if (src->priv_encoding != NULL) { + if ((ret->priv_encoding = + OPENSSL_memdup(src->priv_encoding, + src->params->sk_len)) == NULL) + goto err; + } + } + } + } + EVP_MD_up_ref(src->shake128_md); + EVP_MD_up_ref(src->shake256_md); + ret->shake128_md = src->shake128_md; + ret->shake256_md = src->shake256_md; + } + return ret; + err: + ossl_ml_dsa_key_free(ret); + return NULL; +} + /** * @brief Are 2 keys equal? * diff --git a/crypto/ml_dsa/ml_dsa_key.h b/crypto/ml_dsa/ml_dsa_key.h index aeef961cb80..26ffe2ebbc4 100644 --- a/crypto/ml_dsa/ml_dsa_key.h +++ b/crypto/ml_dsa/ml_dsa_key.h @@ -12,6 +12,7 @@ #include "internal/refcount.h" #include "ml_dsa_vector.h" +/* NOTE - any changes to this struct may require updates to ossl_ml_dsa_dup() */ struct ml_dsa_key_st { OSSL_LIB_CTX *libctx; const ML_DSA_PARAMS *params; diff --git a/crypto/ml_dsa/ml_dsa_vector.h b/crypto/ml_dsa/ml_dsa_vector.h index e5b05069980..dd45a46627f 100644 --- a/crypto/ml_dsa/ml_dsa_vector.h +++ b/crypto/ml_dsa/ml_dsa_vector.h @@ -45,6 +45,7 @@ void vector_free(VECTOR *v) { OPENSSL_free(v->poly); v->poly = NULL; + v->num_poly = 0; } /* @brief zeroize a vectors polynomial coefficients */ diff --git a/include/crypto/ml_dsa.h b/include/crypto/ml_dsa.h index 2008da79683..7e15cffb0b2 100644 --- a/include/crypto/ml_dsa.h +++ b/include/crypto/ml_dsa.h @@ -24,6 +24,7 @@ __owur ML_DSA_KEY *ossl_ml_dsa_key_new(OSSL_LIB_CTX *libctx, const char *propq, __owur int ossl_ml_dsa_key_pub_alloc(ML_DSA_KEY *key); __owur int ossl_ml_dsa_key_priv_alloc(ML_DSA_KEY *key); void ossl_ml_dsa_key_free(ML_DSA_KEY *key); +__owur ML_DSA_KEY *ossl_ml_dsa_key_dup(const ML_DSA_KEY *src, int selection); __owur int ossl_ml_dsa_key_equal(const ML_DSA_KEY *key1, const ML_DSA_KEY *key2, int selection); __owur int ossl_ml_dsa_key_has(const ML_DSA_KEY *key, int selection); diff --git a/providers/implementations/keymgmt/ml_dsa_kmgmt.c b/providers/implementations/keymgmt/ml_dsa_kmgmt.c index e959022adf0..fbe5cc87d56 100644 --- a/providers/implementations/keymgmt/ml_dsa_kmgmt.c +++ b/providers/implementations/keymgmt/ml_dsa_kmgmt.c @@ -26,6 +26,7 @@ static OSSL_FUNC_keymgmt_export_fn ml_dsa_export; static OSSL_FUNC_keymgmt_import_types_fn ml_dsa_imexport_types; static OSSL_FUNC_keymgmt_export_types_fn ml_dsa_imexport_types; static OSSL_FUNC_keymgmt_load_fn ml_dsa_load; +static OSSL_FUNC_keymgmt_dup_fn ml_dsa_dup_key; static OSSL_FUNC_keymgmt_get_params_fn ml_dsa_get_params; static OSSL_FUNC_keymgmt_gettable_params_fn ml_dsa_gettable_params; static OSSL_FUNC_keymgmt_validate_fn ml_dsa_validate; @@ -54,6 +55,13 @@ static void ml_dsa_free_key(void *keydata) ossl_ml_dsa_key_free((ML_DSA_KEY *)keydata); } +static void *ml_dsa_dup_key(const void *keydata_from, int selection) +{ + if (ossl_prov_is_running()) + return ossl_ml_dsa_key_dup(keydata_from, selection); + return NULL; +} + static int ml_dsa_has(const void *keydata, int selection) { const ML_DSA_KEY *key = keydata; @@ -361,6 +369,7 @@ static void ml_dsa_gen_cleanup(void *genctx) (void (*)(void))ml_dsa_gen_set_params }, \ { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, \ (void (*)(void))ml_dsa_gen_settable_params }, \ + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))ml_dsa_dup_key }, \ OSSL_DISPATCH_END \ } diff --git a/providers/implementations/signature/ml_dsa_sig.c b/providers/implementations/signature/ml_dsa_sig.c index a429bae66f5..a4803859c87 100644 --- a/providers/implementations/signature/ml_dsa_sig.c +++ b/providers/implementations/signature/ml_dsa_sig.c @@ -32,6 +32,7 @@ static OSSL_FUNC_signature_verify_fn ml_dsa_verify; static OSSL_FUNC_signature_freectx_fn ml_dsa_freectx; static OSSL_FUNC_signature_set_ctx_params_fn ml_dsa_set_ctx_params; static OSSL_FUNC_signature_settable_ctx_params_fn ml_dsa_settable_ctx_params; +static OSSL_FUNC_signature_dupctx_fn ml_dsa_dupctx; typedef struct { ML_DSA_KEY *key; @@ -71,6 +72,20 @@ static void *ml_dsa_newctx(void *provctx, const char *alg, const char *propq) return ctx; } +static void *ml_dsa_dupctx(void *vctx) +{ + PROV_ML_DSA_CTX *srcctx = (PROV_ML_DSA_CTX *)vctx; + + if (!ossl_prov_is_running()) + return NULL; + + /* + * Note that the ML_DSA_KEY is ref counted via EVP_PKEY so we can just copy + * the key here. + */ + return OPENSSL_memdup(srcctx, sizeof(*srcctx)); +} + static int ml_dsa_signverify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[], int operation, const char *desc) @@ -227,6 +242,7 @@ static const OSSL_PARAM *ml_dsa_settable_ctx_params(void *vctx, (void (*)(void))ml_dsa_set_ctx_params }, \ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \ (void (*)(void))ml_dsa_settable_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))ml_dsa_dupctx }, \ OSSL_DISPATCH_END \ } -- 2.47.2