From 26ad3b905a6d4b1fa50b304f21f67aa0d35265e9 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 30 May 2025 16:17:37 +0200 Subject: [PATCH 58/58] Allow hybrid MLKEM in FIPS mode --- crypto/ml_kem/ml_kem.c | 11 ++-- include/crypto/ml_kem.h | 2 + providers/defltprov.c | 8 +-- providers/implementations/kem/mlx_kem.c | 33 +++++++++- providers/implementations/keymgmt/mlx_kmgmt.c | 61 ++++++++++++++++++- 5 files changed, 103 insertions(+), 12 deletions(-) diff --git a/crypto/ml_kem/ml_kem.c b/crypto/ml_kem/ml_kem.c index ec75233435..8d0cc1a82c 100644 --- a/crypto/ml_kem/ml_kem.c +++ b/crypto/ml_kem/ml_kem.c @@ -1581,6 +1581,7 @@ ML_KEM_KEY *ossl_ml_kem_key_new(OSSL_LIB_CTX *libctx, const char *properties, { const ML_KEM_VINFO *vinfo = ossl_ml_kem_get_vinfo(evp_type); ML_KEM_KEY *key; + char *adjusted_propq = NULL; if (vinfo == NULL) return NULL; @@ -1588,15 +1589,17 @@ ML_KEM_KEY *ossl_ml_kem_key_new(OSSL_LIB_CTX *libctx, const char *properties, if ((key = OPENSSL_malloc(sizeof(*key))) == NULL) return NULL; + adjusted_propq = get_adjusted_propq(properties); key->vinfo = vinfo; key->libctx = libctx; key->prov_flags = ML_KEM_KEY_PROV_FLAGS_DEFAULT; - key->shake128_md = EVP_MD_fetch(libctx, "SHAKE128", properties); - key->shake256_md = EVP_MD_fetch(libctx, "SHAKE256", properties); - key->sha3_256_md = EVP_MD_fetch(libctx, "SHA3-256", properties); - key->sha3_512_md = EVP_MD_fetch(libctx, "SHA3-512", properties); + key->shake128_md = EVP_MD_fetch(libctx, "SHAKE128", adjusted_propq ? adjusted_propq : properties); + key->shake256_md = EVP_MD_fetch(libctx, "SHAKE256", adjusted_propq ? adjusted_propq : properties); + key->sha3_256_md = EVP_MD_fetch(libctx, "SHA3-256", adjusted_propq ? adjusted_propq : properties); + key->sha3_512_md = EVP_MD_fetch(libctx, "SHA3-512", adjusted_propq ? adjusted_propq : properties); key->d = key->z = key->rho = key->pkhash = key->encoded_dk = NULL; key->s = key->m = key->t = NULL; + OPENSSL_free(adjusted_propq); if (key->shake128_md != NULL && key->shake256_md != NULL diff --git a/include/crypto/ml_kem.h b/include/crypto/ml_kem.h index 67d55697e9..ab1aaae8ac 100644 --- a/include/crypto/ml_kem.h +++ b/include/crypto/ml_kem.h @@ -278,4 +278,6 @@ int ossl_ml_kem_decap(uint8_t *shared_secret, size_t slen, __owur int ossl_ml_kem_pubkey_cmp(const ML_KEM_KEY *key1, const ML_KEM_KEY *key2); +char *get_adjusted_propq(const char *propq); + #endif /* OPENSSL_HEADER_ML_KEM_H */ diff --git a/providers/defltprov.c b/providers/defltprov.c index eee2178b41..0dba017f3f 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -517,8 +517,8 @@ static const OSSL_ALGORITHM deflt_asym_kem[] = { { "X448MLKEM1024", "provider=default", ossl_mlx_kem_asym_kem_functions }, # endif # if !defined(OPENSSL_NO_EC) - { "SecP256r1MLKEM768", "provider=default", ossl_mlx_kem_asym_kem_functions }, - { "SecP384r1MLKEM1024", "provider=default", ossl_mlx_kem_asym_kem_functions }, + { "SecP256r1MLKEM768", "provider=default,fips=yes", ossl_mlx_kem_asym_kem_functions }, + { "SecP384r1MLKEM1024", "provider=default,fips=yes", ossl_mlx_kem_asym_kem_functions }, # endif #endif { NULL, NULL, NULL } @@ -597,9 +597,9 @@ static const OSSL_ALGORITHM deflt_keymgmt[] = { PROV_DESCS_X448MLKEM1024 }, # endif # if !defined(OPENSSL_NO_EC) - { PROV_NAMES_SecP256r1MLKEM768, "provider=default", ossl_mlx_p256_kem_kmgmt_functions, + { PROV_NAMES_SecP256r1MLKEM768, "provider=default,fips=yes", ossl_mlx_p256_kem_kmgmt_functions, PROV_DESCS_SecP256r1MLKEM768 }, - { PROV_NAMES_SecP384r1MLKEM1024, "provider=default", ossl_mlx_p384_kem_kmgmt_functions, + { PROV_NAMES_SecP384r1MLKEM1024, "provider=default,fips=yes", ossl_mlx_p384_kem_kmgmt_functions, PROV_DESCS_SecP384r1MLKEM1024 }, # endif #endif diff --git a/providers/implementations/kem/mlx_kem.c b/providers/implementations/kem/mlx_kem.c index 197c345d85..08fbf99a76 100644 --- a/providers/implementations/kem/mlx_kem.c +++ b/providers/implementations/kem/mlx_kem.c @@ -19,6 +19,7 @@ #include "prov/mlx_kem.h" #include "prov/provider_ctx.h" #include "prov/providercommon.h" +#include static OSSL_FUNC_kem_newctx_fn mlx_kem_newctx; static OSSL_FUNC_kem_freectx_fn mlx_kem_freectx; @@ -103,6 +104,28 @@ mlx_kem_set_ctx_params(void *vctx, const OSSL_PARAM params[]) return 1; } +char *get_adjusted_propq(const char *propq) +{ + char *adjusted_propq = NULL; + const char *nofips = "-fips"; + size_t len = propq ? strlen(propq) + 1 + strlen(nofips) + 1 : + strlen(nofips) + 1; + char *ptr = NULL; + + adjusted_propq = OPENSSL_zalloc(len); + if (adjusted_propq != NULL) { + ptr = adjusted_propq; + if (propq && strlen(propq) > 0) { + memcpy(ptr, propq, strlen(propq)); + ptr += strlen(propq); + *ptr = ','; + ptr++; + } + memcpy(ptr, nofips, strlen(nofips)); + } + return adjusted_propq; +} + static int mlx_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen, unsigned char *shsec, size_t *slen) { @@ -115,6 +138,7 @@ static int mlx_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen, uint8_t *sbuf; int ml_kem_slot = key->xinfo->ml_kem_slot; int ret = 0; + char *adjusted_propq = NULL; if (!mlx_kem_have_pubkey(key)) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); @@ -167,7 +191,8 @@ static int mlx_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen, encap_slen = ML_KEM_SHARED_SECRET_BYTES; cbuf = ctext + ml_kem_slot * key->xinfo->pubkey_bytes; sbuf = shsec + ml_kem_slot * key->xinfo->shsec_bytes; - ctx = EVP_PKEY_CTX_new_from_pkey(key->libctx, key->mkey, key->propq); + adjusted_propq = get_adjusted_propq(key->propq); + ctx = EVP_PKEY_CTX_new_from_pkey(key->libctx, key->mkey, adjusted_propq ? adjusted_propq : key->propq); if (ctx == NULL || EVP_PKEY_encapsulate_init(ctx, NULL) <= 0 || EVP_PKEY_encapsulate(ctx, cbuf, &encap_clen, sbuf, &encap_slen) <= 0) @@ -237,6 +262,7 @@ static int mlx_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen, end: EVP_PKEY_free(xkey); EVP_PKEY_CTX_free(ctx); + OPENSSL_free(adjusted_propq); return ret; } @@ -252,6 +278,7 @@ static int mlx_kem_decapsulate(void *vctx, uint8_t *shsec, size_t *slen, size_t decap_clen = key->minfo->ctext_bytes + key->xinfo->pubkey_bytes; int ml_kem_slot = key->xinfo->ml_kem_slot; int ret = 0; + char *adjusted_propq = NULL; if (!mlx_kem_have_prvkey(key)) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); @@ -287,7 +314,8 @@ static int mlx_kem_decapsulate(void *vctx, uint8_t *shsec, size_t *slen, decap_slen = ML_KEM_SHARED_SECRET_BYTES; cbuf = ctext + ml_kem_slot * key->xinfo->pubkey_bytes; sbuf = shsec + ml_kem_slot * key->xinfo->shsec_bytes; - ctx = EVP_PKEY_CTX_new_from_pkey(key->libctx, key->mkey, key->propq); + adjusted_propq = get_adjusted_propq(key->propq); + ctx = EVP_PKEY_CTX_new_from_pkey(key->libctx, key->mkey, adjusted_propq ? adjusted_propq : key->propq); if (ctx == NULL || EVP_PKEY_decapsulate_init(ctx, NULL) <= 0 || EVP_PKEY_decapsulate(ctx, sbuf, &decap_slen, cbuf, decap_clen) <= 0) @@ -325,6 +353,7 @@ static int mlx_kem_decapsulate(void *vctx, uint8_t *shsec, size_t *slen, end: EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(xkey); + OPENSSL_free(adjusted_propq); return ret; } diff --git a/providers/implementations/keymgmt/mlx_kmgmt.c b/providers/implementations/keymgmt/mlx_kmgmt.c index bea8783276..aeef0c8f84 100644 --- a/providers/implementations/keymgmt/mlx_kmgmt.c +++ b/providers/implementations/keymgmt/mlx_kmgmt.c @@ -156,6 +156,52 @@ typedef struct export_cb_arg_st { size_t prvlen; } EXPORT_CB_ARG; +#ifndef FIPS_MODULE +# include +# include +static size_t decompress_pub_key(void *pub, size_t compressed_len, size_t decompressed_len) +{ + EC_GROUP *group = NULL; + EC_POINT *point = NULL; + BN_CTX *ctx = NULL; + size_t len = compressed_len; + int group_nid = NID_undef; + + switch (len) { + case 33: + group_nid = NID_X9_62_prime256v1; + break; + case 49: + group_nid = NID_secp384r1; + break; + default: + return len; + break; + } + + ctx = BN_CTX_new(); + group = EC_GROUP_new_by_curve_name(group_nid); + if (ctx == NULL || group == NULL) + goto err; + + point = EC_POINT_new(group); + if (point == NULL) + goto err; + + if (!EC_POINT_oct2point(group, point, pub, len, ctx)) + goto err; + + len = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, pub, decompressed_len, ctx); + +err: + EC_POINT_free(point); + EC_GROUP_free(group); + BN_CTX_free(ctx); + + return len; +} +#endif + /* Copy any exported key material into its storage slot */ static int export_sub_cb(const OSSL_PARAM *params, void *varg) { @@ -176,6 +222,10 @@ static int export_sub_cb(const OSSL_PARAM *params, void *varg) if (OSSL_PARAM_get_octet_string(p, &pub, sub_arg->publen, &len) != 1) return 0; +#ifndef FIPS_MODULE + if (len < sub_arg->publen) + len = decompress_pub_key(pub, len, sub_arg->publen); +#endif if (len != sub_arg->publen) { ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR, "Unexpected %s public key length %lu != %lu", @@ -344,12 +394,14 @@ load_slot(OSSL_LIB_CTX *libctx, const char *propq, const char *pname, void *val; int ml_kem_slot = key->xinfo->ml_kem_slot; int ret = 0; + char *adjusted_propq = NULL; if (slot == ml_kem_slot) { alg = key->minfo->algorithm_name; ppkey = &key->mkey; off = slot * xbytes; len = mbytes; + adjusted_propq = get_adjusted_propq(propq); } else { alg = key->xinfo->algorithm_name; group = (char *) key->xinfo->group_name; @@ -359,7 +411,8 @@ load_slot(OSSL_LIB_CTX *libctx, const char *propq, const char *pname, } val = (void *)(in + off); - if ((ctx = EVP_PKEY_CTX_new_from_name(libctx, alg, propq)) == NULL + if ((ctx = EVP_PKEY_CTX_new_from_name(libctx, alg, + adjusted_propq ? adjusted_propq : propq)) == NULL || EVP_PKEY_fromdata_init(ctx) <= 0) goto err; parr[0] = OSSL_PARAM_construct_octet_string(pname, val, len); @@ -370,6 +423,7 @@ load_slot(OSSL_LIB_CTX *libctx, const char *propq, const char *pname, ret = 1; err: + OPENSSL_free(adjusted_propq); EVP_PKEY_CTX_free(ctx); return ret; } @@ -688,6 +742,7 @@ static void *mlx_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg) PROV_ML_KEM_GEN_CTX *gctx = vgctx; MLX_KEY *key; char *propq; + char *adjusted_propq = NULL; if (gctx == NULL || (gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == @@ -704,8 +759,10 @@ static void *mlx_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg) return key; /* For now, using the same "propq" for all components */ - key->mkey = EVP_PKEY_Q_keygen(key->libctx, key->propq, + adjusted_propq = get_adjusted_propq(propq); + key->mkey = EVP_PKEY_Q_keygen(key->libctx, adjusted_propq ? adjusted_propq : key->propq, key->minfo->algorithm_name); + OPENSSL_free(adjusted_propq); key->xkey = EVP_PKEY_Q_keygen(key->libctx, key->propq, key->xinfo->algorithm_name, key->xinfo->group_name); -- 2.49.0