From 8cc7ebf6fed2a6c49dd71a090988d68390d0563c Mon Sep 17 00:00:00 2001 From: Viktor Dukhovni Date: Sun, 9 Feb 2025 13:41:04 +1100 Subject: [PATCH] Reject private keys with an incorrect pk hash Reviewed-by: Tim Hudson Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/26674) --- crypto/ml_dsa/ml_dsa_encoders.c | 15 +++++++++++++-- crypto/ml_dsa/ml_dsa_key.c | 15 +++++++++++++-- include/crypto/ml_dsa.h | 2 ++ providers/implementations/keymgmt/ml_dsa_kmgmt.c | 4 +++- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/crypto/ml_dsa/ml_dsa_encoders.c b/crypto/ml_dsa/ml_dsa_encoders.c index 67b750fbaf4..28c2b0c55df 100644 --- a/crypto/ml_dsa/ml_dsa_encoders.c +++ b/crypto/ml_dsa/ml_dsa_encoders.c @@ -764,6 +764,7 @@ int ossl_ml_dsa_sk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len) DECODE_FN *decode_fn; const ML_DSA_PARAMS *params = key->params; size_t i, k = params->k, l = params->l; + uint8_t input_tr[ML_DSA_TR_BYTES]; PACKET pkt; /* When loading from an explicit key, drop the seed. */ @@ -788,7 +789,7 @@ int ossl_ml_dsa_sk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len) if (!PACKET_buf_init(&pkt, in, in_len) || !PACKET_copy_bytes(&pkt, key->rho, sizeof(key->rho)) || !PACKET_copy_bytes(&pkt, key->K, sizeof(key->K)) - || !PACKET_copy_bytes(&pkt, key->tr, sizeof(key->tr))) + || !PACKET_copy_bytes(&pkt, input_tr, sizeof(input_tr))) return 0; for (i = 0; i < l; ++i) @@ -805,7 +806,17 @@ int ossl_ml_dsa_sk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len) if (key->priv_encoding == NULL && (key->priv_encoding = OPENSSL_memdup(in, in_len)) == NULL) return 0; - return ossl_ml_dsa_key_public_from_private(key); + /* + * Computing the public key also computes its hash, which must be equal to + * the |tr| value in the private key, else the key was corrupted. + */ + if (ossl_ml_dsa_key_public_from_private(key) != 0 + && memcmp(input_tr, key->tr, sizeof(input_tr)) == 0) + return 1; + + /* On error, reset the key back to uninitialised. */ + ossl_ml_dsa_key_reset(key); + return 0; } /* diff --git a/crypto/ml_dsa/ml_dsa_key.c b/crypto/ml_dsa/ml_dsa_key.c index 12b28b28f5a..e0667f8902d 100644 --- a/crypto/ml_dsa/ml_dsa_key.c +++ b/crypto/ml_dsa/ml_dsa_key.c @@ -132,7 +132,7 @@ int ossl_ml_dsa_key_priv_alloc(ML_DSA_KEY *key) } /** - * @brief Destroy a ML_DSA_KEY object + * @brief Destroy an ML_DSA_KEY object */ void ossl_ml_dsa_key_free(ML_DSA_KEY *key) { @@ -141,6 +141,15 @@ void ossl_ml_dsa_key_free(ML_DSA_KEY *key) EVP_MD_free(key->shake128_md); EVP_MD_free(key->shake256_md); + ossl_ml_dsa_key_reset(key); + OPENSSL_free(key); +} + +/** + * @brief Factory reset an ML_DSA_KEY object + */ +void ossl_ml_dsa_key_reset(ML_DSA_KEY *key) +{ vector_zero(&key->s2); vector_zero(&key->s1); vector_zero(&key->t0); @@ -148,11 +157,13 @@ void ossl_ml_dsa_key_free(ML_DSA_KEY *key) vector_free(&key->t1); OPENSSL_cleanse(key->K, sizeof(key->K)); OPENSSL_free(key->pub_encoding); + key->pub_encoding = NULL; if (key->priv_encoding != NULL) OPENSSL_clear_free(key->priv_encoding, key->params->sk_len); + key->priv_encoding = NULL; if (key->seed != NULL) OPENSSL_clear_free(key->seed, ML_DSA_SEED_BYTES); - OPENSSL_free(key); + key->seed = NULL; } /** diff --git a/include/crypto/ml_dsa.h b/include/crypto/ml_dsa.h index 2999fe488f1..b3fef85e39e 100644 --- a/include/crypto/ml_dsa.h +++ b/include/crypto/ml_dsa.h @@ -70,6 +70,8 @@ const ML_DSA_PARAMS *ossl_ml_dsa_params_get(int evp_type); const ML_DSA_PARAMS *ossl_ml_dsa_key_params(const ML_DSA_KEY *key); __owur ML_DSA_KEY *ossl_ml_dsa_key_new(OSSL_LIB_CTX *libctx, const char *propq, int evp_type); +/* Factory reset for keys that fail initialisation */ +void ossl_ml_dsa_key_reset(ML_DSA_KEY *key); __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); diff --git a/providers/implementations/keymgmt/ml_dsa_kmgmt.c b/providers/implementations/keymgmt/ml_dsa_kmgmt.c index ec49cb3efef..c38a5a3ec43 100644 --- a/providers/implementations/keymgmt/ml_dsa_kmgmt.c +++ b/providers/implementations/keymgmt/ml_dsa_kmgmt.c @@ -255,8 +255,10 @@ static int ml_dsa_import(void *keydata, int selection, const OSSL_PARAM params[] #ifdef FIPS_MODULE if (res > 0) { res = ml_dsa_pairwise_test(key); - if (res <= 0) + if (res <= 0) { + ossl_ml_dsa_key_reset(key); ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); + } } #endif return res; -- 2.47.2