mirror of https://github.com/openssl/openssl.git
				
				
				
			Use secure memory allocation for ML-KEM and ML-DSA private key storage areas
Resolves: #27603 Reviewed-by: Shane Lontis <shane.lontis@oracle.com> Reviewed-by: Viktor Dukhovni <viktor@openssl.org> (Merged from https://github.com/openssl/openssl/pull/27625)
This commit is contained in:
		
							parent
							
								
									4dbb537bd1
								
							
						
					
					
						commit
						815dde3e20
					
				|  | @ -713,7 +713,7 @@ int ossl_ml_dsa_sk_encode(ML_DSA_KEY *key) | ||||||
|     size_t enc_len = params->sk_len; |     size_t enc_len = params->sk_len; | ||||||
|     const POLY *t0 = key->t0.poly; |     const POLY *t0 = key->t0.poly; | ||||||
|     WPACKET pkt; |     WPACKET pkt; | ||||||
|     uint8_t *enc = OPENSSL_malloc(enc_len); |     uint8_t *enc = OPENSSL_secure_malloc(enc_len); | ||||||
| 
 | 
 | ||||||
|     if (enc == NULL) |     if (enc == NULL) | ||||||
|         return 0; |         return 0; | ||||||
|  | @ -741,7 +741,7 @@ int ossl_ml_dsa_sk_encode(ML_DSA_KEY *key) | ||||||
|     if (!WPACKET_get_total_written(&pkt, &written) |     if (!WPACKET_get_total_written(&pkt, &written) | ||||||
|             || written != enc_len) |             || written != enc_len) | ||||||
|         goto err; |         goto err; | ||||||
|     OPENSSL_clear_free(key->priv_encoding, enc_len); |     OPENSSL_secure_clear_free(key->priv_encoding, enc_len); | ||||||
|     key->priv_encoding = enc; |     key->priv_encoding = enc; | ||||||
|     ret = 1; |     ret = 1; | ||||||
| err: | err: | ||||||
|  | @ -805,9 +805,12 @@ int ossl_ml_dsa_sk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len) | ||||||
|             goto err; |             goto err; | ||||||
|     if (PACKET_remaining(&pkt) != 0) |     if (PACKET_remaining(&pkt) != 0) | ||||||
|         goto err; |         goto err; | ||||||
|     if (key->priv_encoding == NULL |     if (key->priv_encoding == NULL) { | ||||||
|         && (key->priv_encoding = OPENSSL_memdup(in, in_len)) == NULL) |         key->priv_encoding = OPENSSL_secure_malloc(in_len); | ||||||
|  |         if (key->priv_encoding == NULL) | ||||||
|             goto err; |             goto err; | ||||||
|  |         memcpy(key->priv_encoding, in, in_len); | ||||||
|  |     } | ||||||
|     /*
 |     /*
 | ||||||
|      * Computing the public key also computes its hash, which must be equal to |      * 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. |      * the |tr| value in the private key, else the key was corrupted. | ||||||
|  |  | ||||||
|  | @ -48,9 +48,13 @@ int ossl_ml_dsa_set_prekey(ML_DSA_KEY *key, int flags_set, int flags_clr, | ||||||
|         || key->seed != NULL) |         || key->seed != NULL) | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|     if (sk != NULL |     if (sk != NULL) { | ||||||
|         && (key->priv_encoding = OPENSSL_memdup(sk, sk_len)) == NULL) |         key->priv_encoding = OPENSSL_secure_malloc(sk_len); | ||||||
|  |         if (key->priv_encoding == NULL) | ||||||
|             goto end; |             goto end; | ||||||
|  |         memcpy(key->priv_encoding, sk, sk_len); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (seed != NULL |     if (seed != NULL | ||||||
|         && (key->seed = OPENSSL_memdup(seed, seed_len)) == NULL) |         && (key->seed = OPENSSL_memdup(seed, seed_len)) == NULL) | ||||||
|         goto end; |         goto end; | ||||||
|  | @ -60,7 +64,7 @@ int ossl_ml_dsa_set_prekey(ML_DSA_KEY *key, int flags_set, int flags_clr, | ||||||
| 
 | 
 | ||||||
|  end: |  end: | ||||||
|     if (!ret) { |     if (!ret) { | ||||||
|         OPENSSL_free(key->priv_encoding); |         OPENSSL_secure_free(key->priv_encoding); | ||||||
|         OPENSSL_free(key->seed); |         OPENSSL_free(key->seed); | ||||||
|         key->priv_encoding = key->seed = NULL; |         key->priv_encoding = key->seed = NULL; | ||||||
|     } |     } | ||||||
|  | @ -114,7 +118,7 @@ int ossl_ml_dsa_key_priv_alloc(ML_DSA_KEY *key) | ||||||
| 
 | 
 | ||||||
|     if (key->s1.poly != NULL) |     if (key->s1.poly != NULL) | ||||||
|         return 0; |         return 0; | ||||||
|     if (!vector_alloc(&key->s1, l + 2 * k)) |     if (!vector_secure_alloc(&key->s1, l + 2 * k)) | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|     poly = key->s1.poly; |     poly = key->s1.poly; | ||||||
|  | @ -151,7 +155,7 @@ void ossl_ml_dsa_key_reset(ML_DSA_KEY *key) | ||||||
|         vector_zero(&key->s1); |         vector_zero(&key->s1); | ||||||
|         vector_zero(&key->s2); |         vector_zero(&key->s2); | ||||||
|         vector_zero(&key->t0); |         vector_zero(&key->t0); | ||||||
|         vector_free(&key->s1); |         vector_secure_free(&key->s1); | ||||||
|         key->s2.poly = NULL; |         key->s2.poly = NULL; | ||||||
|         key->t0.poly = NULL; |         key->t0.poly = NULL; | ||||||
|     } |     } | ||||||
|  | @ -161,7 +165,7 @@ void ossl_ml_dsa_key_reset(ML_DSA_KEY *key) | ||||||
|     OPENSSL_free(key->pub_encoding); |     OPENSSL_free(key->pub_encoding); | ||||||
|     key->pub_encoding = NULL; |     key->pub_encoding = NULL; | ||||||
|     if (key->priv_encoding != NULL) |     if (key->priv_encoding != NULL) | ||||||
|         OPENSSL_clear_free(key->priv_encoding, key->params->sk_len); |         OPENSSL_secure_clear_free(key->priv_encoding, key->params->sk_len); | ||||||
|     key->priv_encoding = NULL; |     key->priv_encoding = NULL; | ||||||
|     if (key->seed != NULL) |     if (key->seed != NULL) | ||||||
|         OPENSSL_clear_free(key->seed, ML_DSA_SEED_BYTES); |         OPENSSL_clear_free(key->seed, ML_DSA_SEED_BYTES); | ||||||
|  | @ -217,10 +221,10 @@ ML_DSA_KEY *ossl_ml_dsa_key_dup(const ML_DSA_KEY *src, int selection) | ||||||
|                         vector_copy(&ret->s2, &src->s2); |                         vector_copy(&ret->s2, &src->s2); | ||||||
|                         vector_copy(&ret->t0, &src->t0); |                         vector_copy(&ret->t0, &src->t0); | ||||||
|                     } |                     } | ||||||
|                     if ((ret->priv_encoding = |                     ret->priv_encoding = OPENSSL_secure_malloc(src->params->sk_len); | ||||||
|                             OPENSSL_memdup(src->priv_encoding, |                     if (!ret->priv_encoding) | ||||||
|                                            src->params->sk_len)) == NULL) |  | ||||||
|                         goto err; |                         goto err; | ||||||
|  |                     memcpy(ret->priv_encoding, src->priv_encoding, src->params->sk_len); | ||||||
|                 } |                 } | ||||||
|                 if (src->seed != NULL |                 if (src->seed != NULL | ||||||
|                     && (ret->seed = OPENSSL_memdup(src->seed, |                     && (ret->seed = OPENSSL_memdup(src->seed, | ||||||
|  |  | ||||||
|  | @ -40,6 +40,16 @@ int vector_alloc(VECTOR *v, size_t num_polys) | ||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static ossl_inline ossl_unused | ||||||
|  | int vector_secure_alloc(VECTOR *v, size_t num_polys) | ||||||
|  | { | ||||||
|  |     v->poly = OPENSSL_secure_malloc(num_polys * sizeof(POLY)); | ||||||
|  |     if (v->poly == NULL) | ||||||
|  |         return 0; | ||||||
|  |     v->num_poly = num_polys; | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static ossl_inline ossl_unused | static ossl_inline ossl_unused | ||||||
| void vector_free(VECTOR *v) | void vector_free(VECTOR *v) | ||||||
| { | { | ||||||
|  | @ -48,6 +58,14 @@ void vector_free(VECTOR *v) | ||||||
|     v->num_poly = 0; |     v->num_poly = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static ossl_inline ossl_unused | ||||||
|  | void vector_secure_free(VECTOR *v) | ||||||
|  | { | ||||||
|  |     OPENSSL_secure_clear_free(v->poly, v->num_poly * sizeof(POLY)); | ||||||
|  |     v->poly = NULL; | ||||||
|  |     v->num_poly = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* @brief zeroize a vectors polynomial coefficients */ | /* @brief zeroize a vectors polynomial coefficients */ | ||||||
| static ossl_inline ossl_unused | static ossl_inline ossl_unused | ||||||
| void vector_zero(VECTOR *va) | void vector_zero(VECTOR *va) | ||||||
|  |  | ||||||
|  | @ -1582,11 +1582,18 @@ ossl_ml_kem_key_reset(ML_KEM_KEY *key) | ||||||
|      *   secret |z|, and seed |d|, we can cleanse all three in one call. |      *   secret |z|, and seed |d|, we can cleanse all three in one call. | ||||||
|      * |      * | ||||||
|      * - Otherwise, when key->d is set, cleanse the stashed seed. |      * - Otherwise, when key->d is set, cleanse the stashed seed. | ||||||
|  |      * | ||||||
|  |      * If the memory has been allocated with secure memory, it will be cleared | ||||||
|  |      * before being free'd under the OPENSSL_secure_free call. | ||||||
|      */ |      */ | ||||||
|     if (ossl_ml_kem_have_prvkey(key)) |     if (ossl_ml_kem_have_prvkey(key)) { | ||||||
|         OPENSSL_cleanse(key->s, |         if (!CRYPTO_secure_allocated(key->t)) | ||||||
|                         key->vinfo->rank * sizeof(scalar) + 2 * ML_KEM_RANDOM_BYTES); |             OPENSSL_cleanse(key->s, key->vinfo->rank * sizeof(scalar) + 2 * ML_KEM_RANDOM_BYTES); | ||||||
|  |         OPENSSL_secure_free(key->t); | ||||||
|  |     } else { | ||||||
|         OPENSSL_free(key->t); |         OPENSSL_free(key->t); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     key->d = key->z = (uint8_t *)(key->s = key->m = key->t = NULL); |     key->d = key->z = (uint8_t *)(key->s = key->m = key->t = NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1653,6 +1660,7 @@ ML_KEM_KEY *ossl_ml_kem_key_dup(const ML_KEM_KEY *key, int selection) | ||||||
| { | { | ||||||
|     int ok = 0; |     int ok = 0; | ||||||
|     ML_KEM_KEY *ret; |     ML_KEM_KEY *ret; | ||||||
|  |     void *tmp; | ||||||
| 
 | 
 | ||||||
|     /*
 |     /*
 | ||||||
|      * Partially decoded keys, not yet imported or loaded, should never be |      * Partially decoded keys, not yet imported or loaded, should never be | ||||||
|  | @ -1683,7 +1691,11 @@ ML_KEM_KEY *ossl_ml_kem_key_dup(const ML_KEM_KEY *key, int selection) | ||||||
|         ret->pkhash = ret->rho + ML_KEM_RANDOM_BYTES; |         ret->pkhash = ret->rho + ML_KEM_RANDOM_BYTES; | ||||||
|         break; |         break; | ||||||
|     case OSSL_KEYMGMT_SELECT_PRIVATE_KEY: |     case OSSL_KEYMGMT_SELECT_PRIVATE_KEY: | ||||||
|         ok = add_storage(OPENSSL_memdup(key->t, key->vinfo->prvalloc), 1, ret); |         tmp = OPENSSL_secure_malloc(key->vinfo->prvalloc); | ||||||
|  |         if (tmp == NULL) | ||||||
|  |             break; | ||||||
|  |         memcpy(tmp, key->t, key->vinfo->prvalloc); | ||||||
|  |         ok = add_storage(tmp, 1, ret); | ||||||
|         /* Duplicated keys retain |d|, if available */ |         /* Duplicated keys retain |d|, if available */ | ||||||
|         if (key->d != NULL) |         if (key->d != NULL) | ||||||
|             ret->d = ret->z + ML_KEM_RANDOM_BYTES; |             ret->d = ret->z + ML_KEM_RANDOM_BYTES; | ||||||
|  | @ -1715,10 +1727,8 @@ void ossl_ml_kem_key_free(ML_KEM_KEY *key) | ||||||
| 
 | 
 | ||||||
|     if (ossl_ml_kem_decoded_key(key)) { |     if (ossl_ml_kem_decoded_key(key)) { | ||||||
|         OPENSSL_cleanse(key->seedbuf, sizeof(key->seedbuf)); |         OPENSSL_cleanse(key->seedbuf, sizeof(key->seedbuf)); | ||||||
|         if (ossl_ml_kem_have_dkenc(key)) { |         if (ossl_ml_kem_have_dkenc(key)) | ||||||
|             OPENSSL_cleanse(key->encoded_dk, key->vinfo->prvkey_bytes); |             OPENSSL_secure_clear_free(key->encoded_dk, key->vinfo->prvkey_bytes); | ||||||
|             OPENSSL_free(key->encoded_dk); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     ossl_ml_kem_key_reset(key); |     ossl_ml_kem_key_reset(key); | ||||||
|     OPENSSL_free(key); |     OPENSSL_free(key); | ||||||
|  | @ -1831,7 +1841,7 @@ int ossl_ml_kem_parse_private_key(const uint8_t *in, size_t len, | ||||||
|         || (mdctx = EVP_MD_CTX_new()) == NULL) |         || (mdctx = EVP_MD_CTX_new()) == NULL) | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|     if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, key)) |     if (add_storage(OPENSSL_secure_malloc(vinfo->prvalloc), 1, key)) | ||||||
|         ret = parse_prvkey(in, mdctx, key); |         ret = parse_prvkey(in, mdctx, key); | ||||||
| 
 | 
 | ||||||
|     if (!ret) |     if (!ret) | ||||||
|  | @ -1878,7 +1888,7 @@ int ossl_ml_kem_genkey(uint8_t *pubenc, size_t publen, ML_KEM_KEY *key) | ||||||
|      */ |      */ | ||||||
|     CONSTTIME_SECRET(seed, ML_KEM_SEED_BYTES); |     CONSTTIME_SECRET(seed, ML_KEM_SEED_BYTES); | ||||||
| 
 | 
 | ||||||
|     if (add_storage(OPENSSL_malloc(vinfo->prvalloc), 1, key)) |     if (add_storage(OPENSSL_secure_malloc(vinfo->prvalloc), 1, key)) | ||||||
|         ret = genkey(seed, mdctx, pubenc, key); |         ret = genkey(seed, mdctx, pubenc, key); | ||||||
|     OPENSSL_cleanse(seed, sizeof(seed)); |     OPENSSL_cleanse(seed, sizeof(seed)); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -254,7 +254,7 @@ ossl_ml_kem_d2i_PKCS8(const uint8_t *prvenc, int prvlen, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if (p8fmt->priv_length > 0) { |     if (p8fmt->priv_length > 0) { | ||||||
|         if ((key->encoded_dk = OPENSSL_malloc(p8fmt->priv_length)) == NULL) { |         if ((key->encoded_dk = OPENSSL_secure_malloc(p8fmt->priv_length)) == NULL) { | ||||||
|             ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, |             ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, | ||||||
|                            "error parsing %s private key", |                            "error parsing %s private key", | ||||||
|                            v->algorithm_name); |                            v->algorithm_name); | ||||||
|  |  | ||||||
|  | @ -537,12 +537,12 @@ void *ml_kem_load(const void *reference, size_t reference_sz) | ||||||
|             if (!ml_kem_pairwise_test(key, key->prov_flags)) |             if (!ml_kem_pairwise_test(key, key->prov_flags)) | ||||||
|                 goto err; |                 goto err; | ||||||
|         } |         } | ||||||
|         OPENSSL_free(encoded_dk); |         OPENSSL_secure_clear_free(encoded_dk, key->vinfo->prvkey_bytes); | ||||||
|         return key; |         return key; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  err: |  err: | ||||||
|     OPENSSL_free(encoded_dk); |     OPENSSL_secure_clear_free(encoded_dk, key->vinfo->prvkey_bytes); | ||||||
|     ossl_ml_kem_key_free(key); |     ossl_ml_kem_key_free(key); | ||||||
|     return NULL; |     return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue