From 2000eaead63732669283e6b54c8ef02e268eaeb8 Mon Sep 17 00:00:00 2001 From: rpm-build Date: Mon, 31 Jul 2023 09:41:29 +0200 Subject: [PATCH 34/48] 0078-Add-FIPS-indicator-parameter-to-HKDF.patch Patch-name: 0078-Add-FIPS-indicator-parameter-to-HKDF.patch Patch-id: 78 Patch-status: | # https://bugzilla.redhat.com/show_bug.cgi?id=2114772 From-dist-git-commit: 9409bc7044cf4b5773639cce20f51399888c45fd --- include/crypto/evp.h | 7 ++ include/openssl/core_names.h | 1 + include/openssl/kdf.h | 4 + providers/implementations/kdfs/hkdf.c | 100 +++++++++++++++++++++- providers/implementations/kdfs/kbkdf.c | 82 ++++++++++++++++-- providers/implementations/kdfs/sshkdf.c | 75 +++++++++++++++- providers/implementations/kdfs/sskdf.c | 100 +++++++++++++++++++++- providers/implementations/kdfs/tls1_prf.c | 74 +++++++++++++++- providers/implementations/kdfs/x942kdf.c | 66 +++++++++++++- 9 files changed, 487 insertions(+), 22 deletions(-) diff --git a/include/crypto/evp.h b/include/crypto/evp.h index dbbdcccbda..aa07153441 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -219,6 +219,13 @@ struct evp_mac_st { OSSL_FUNC_mac_set_ctx_params_fn *set_ctx_params; }; +#ifdef FIPS_MODULE +/* According to NIST Special Publication 800-131Ar2, Section 8: Deriving + * Additional Keys from a Cryptographic Key, "[t]he length of the + * key-derivation key [i.e., the input key] shall be at least 112 bits". */ +# define EVP_KDF_FIPS_MIN_KEY_LEN (112 / 8) +#endif + struct evp_kdf_st { OSSL_PROVIDER *prov; int name_id; diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index c0cce14297..b431b9f871 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -226,6 +226,7 @@ extern "C" { #define OSSL_KDF_PARAM_X942_SUPP_PUBINFO "supp-pubinfo" #define OSSL_KDF_PARAM_X942_SUPP_PRIVINFO "supp-privinfo" #define OSSL_KDF_PARAM_X942_USE_KEYBITS "use-keybits" +#define OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR "redhat-fips-indicator" /* Known KDF names */ #define OSSL_KDF_NAME_HKDF "HKDF" diff --git a/include/openssl/kdf.h b/include/openssl/kdf.h index 0983230a48..86171635ea 100644 --- a/include/openssl/kdf.h +++ b/include/openssl/kdf.h @@ -63,6 +63,10 @@ int EVP_KDF_names_do_all(const EVP_KDF *kdf, # define EVP_KDF_HKDF_MODE_EXTRACT_ONLY 1 # define EVP_KDF_HKDF_MODE_EXPAND_ONLY 2 +# define EVP_KDF_REDHAT_FIPS_INDICATOR_UNDETERMINED 0 +# define EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED 1 +# define EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED 2 + #define EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV 65 #define EVP_KDF_SSHKDF_TYPE_INITIAL_IV_SRV_TO_CLI 66 #define EVP_KDF_SSHKDF_TYPE_ENCRYPTION_KEY_CLI_TO_SRV 67 diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c index 5304baa6c9..f9c77f4236 100644 --- a/providers/implementations/kdfs/hkdf.c +++ b/providers/implementations/kdfs/hkdf.c @@ -43,6 +43,7 @@ static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_hkdf_settable_ctx_params; static OSSL_FUNC_kdf_set_ctx_params_fn kdf_hkdf_set_ctx_params; static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_hkdf_gettable_ctx_params; static OSSL_FUNC_kdf_get_ctx_params_fn kdf_hkdf_get_ctx_params; +static OSSL_FUNC_kdf_newctx_fn kdf_tls1_3_new; static OSSL_FUNC_kdf_derive_fn kdf_tls1_3_derive; static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_tls1_3_settable_ctx_params; static OSSL_FUNC_kdf_set_ctx_params_fn kdf_tls1_3_set_ctx_params; @@ -86,6 +87,10 @@ typedef struct { size_t data_len; unsigned char *info; size_t info_len; + int is_tls13; +#ifdef FIPS_MODULE + int fips_indicator; +#endif /* defined(FIPS_MODULE) */ } KDF_HKDF; static void *kdf_hkdf_new(void *provctx) @@ -201,6 +206,11 @@ static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen, return 0; } +#ifdef FIPS_MODULE + if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN) + ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; +#endif /* defined(FIPS_MODULE) */ + switch (ctx->mode) { case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND: default: @@ -363,15 +373,78 @@ static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) { KDF_HKDF *ctx = (KDF_HKDF *)vctx; OSSL_PARAM *p; + int any_valid = 0; /* set to 1 when at least one parameter was valid */ if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) { size_t sz = kdf_hkdf_size(ctx); - if (sz == 0) + any_valid = 1; + + if (sz == 0 || !OSSL_PARAM_set_size_t(p, sz)) return 0; - return OSSL_PARAM_set_size_t(p, sz); } - return -2; + +#ifdef FIPS_MODULE + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR)) + != NULL) { + int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED; + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + + any_valid = 1; + + /* According to NIST Special Publication 800-131Ar2, Section 8: + * Deriving Additional Keys from a Cryptographic Key, "[t]he length of + * the key-derivation key [i.e., the input key] shall be at least 112 + * bits". */ + if (ctx->key_len < EVP_KDF_FIPS_MIN_KEY_LEN) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Verification Program, Section D.B and NIST Special Publication + * 800-131Ar2, Section 1.2.2 say that any algorithm at a security + * strength < 112 bits is legacy use only, so all derived keys should + * be longer than that. If a derived key has ever been shorter than + * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we + * should also set the returned FIPS indicator to unapproved. */ + if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + if (ctx->is_tls13) { + if (md != NULL + && !EVP_MD_is_a(md, "SHA2-256") + && !EVP_MD_is_a(md, "SHA2-384")) { + /* Implementation Guidance for FIPS 140-3 and the Cryptographic + * Module Validation Program, Section 2.4.B, (5): "The TLS 1.3 + * key derivation function documented in Section 7.1 of RFC + * 8446. This is considered an approved CVL because the + * underlying functions performed within the TLS 1.3 KDF map to + * NIST approved standards, namely: SP 800-133rev2 (Section 6.3 + * Option #3), SP 800-56Crev2, and SP 800-108." + * + * RFC 8446 appendix B.4 only lists SHA-256 and SHA-384. */ + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + } + } else { + if (md != NULL + && (EVP_MD_is_a(md, "SHAKE-128") || + EVP_MD_is_a(md, "SHAKE-256"))) { + /* HKDF is a SP 800-56Cr2 TwoStep KDF, for which all SHA-1, + * SHA-2 and SHA-3 are approved. SHAKE is not approved, because + * of FIPS 140-3 IG, section C.C: "The SHAKE128 and SHAKE256 + * extendable-output functions may only be used as the + * standalone algorithms." */ + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + } + } + if (!OSSL_PARAM_set_int(p, fips_indicator)) + return 0; + } +#endif /* defined(FIPS_MODULE) */ + + if (!any_valid) + return -2; + + return 1; } static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(ossl_unused void *ctx, @@ -379,6 +452,9 @@ static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(ossl_unused void *ctx, { static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), +#ifdef FIPS_MODULE + OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, NULL), +#endif /* defined(FIPS_MODULE) */ OSSL_PARAM_END }; return known_gettable_ctx_params; @@ -709,6 +785,17 @@ static int prov_tls13_hkdf_generate_secret(OSSL_LIB_CTX *libctx, return ret; } +static void *kdf_tls1_3_new(void *provctx) +{ + KDF_HKDF *hkdf = kdf_hkdf_new(provctx); + + if (hkdf != NULL) + hkdf->is_tls13 = 1; + + return hkdf; +} + + static int kdf_tls1_3_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { @@ -724,6 +811,11 @@ static int kdf_tls1_3_derive(void *vctx, unsigned char *key, size_t keylen, return 0; } +#ifdef FIPS_MODULE + if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN) + ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; +#endif /* defined(FIPS_MODULE) */ + switch (ctx->mode) { default: return 0; @@ -801,7 +893,7 @@ static const OSSL_PARAM *kdf_tls1_3_settable_ctx_params(ossl_unused void *ctx, } const OSSL_DISPATCH ossl_kdf_tls1_3_kdf_functions[] = { - { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_hkdf_new }, + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_tls1_3_new }, { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_hkdf_dup }, { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_hkdf_free }, { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_hkdf_reset }, diff --git a/providers/implementations/kdfs/kbkdf.c b/providers/implementations/kdfs/kbkdf.c index aa3df15bc7..3f82710061 100644 --- a/providers/implementations/kdfs/kbkdf.c +++ b/providers/implementations/kdfs/kbkdf.c @@ -59,6 +59,9 @@ typedef struct { kbkdf_mode mode; EVP_MAC_CTX *ctx_init; + /* HMAC digest algorithm, if any; used to compute FIPS indicator */ + PROV_DIGEST digest; + /* Names are lowercased versions of those found in SP800-108. */ int r; unsigned char *ki; @@ -72,6 +75,9 @@ typedef struct { int use_l; int is_kmac; int use_separator; +#ifdef FIPS_MODULE + int fips_indicator; +#endif /* defined(FIPS_MODULE) */ } KBKDF; /* Definitions needed for typechecking. */ @@ -143,6 +149,7 @@ static void kbkdf_reset(void *vctx) void *provctx = ctx->provctx; EVP_MAC_CTX_free(ctx->ctx_init); + ossl_prov_digest_reset(&ctx->digest); OPENSSL_clear_free(ctx->context, ctx->context_len); OPENSSL_clear_free(ctx->label, ctx->label_len); OPENSSL_clear_free(ctx->ki, ctx->ki_len); @@ -308,6 +315,11 @@ static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen, goto done; } +#ifdef FIPS_MODULE + if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN) + ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; +#endif /* defined(FIPS_MODULE) */ + h = EVP_MAC_CTX_get_mac_size(ctx->ctx_init); if (h == 0) goto done; @@ -381,6 +393,9 @@ static int kbkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) } } + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx)) + return 0; + p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE); if (p != NULL && OPENSSL_strncasecmp("counter", p->data, p->data_size) == 0) { @@ -461,20 +476,77 @@ static const OSSL_PARAM *kbkdf_settable_ctx_params(ossl_unused void *ctx, static int kbkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) { OSSL_PARAM *p; + int any_valid = 0; /* set to 1 when at least one parameter was valid */ p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE); - if (p == NULL) + if (p != NULL) { + any_valid = 1; + + /* KBKDF can produce results as large as you like. */ + if (!OSSL_PARAM_set_size_t(p, SIZE_MAX)) + return 0; + } + +#ifdef FIPS_MODULE + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR); + if (p != NULL) { + KBKDF *ctx = (KBKDF *)vctx; + int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED; + + any_valid = 1; + + /* According to NIST Special Publication 800-131Ar2, Section 8: + * Deriving Additional Keys from a Cryptographic Key, "[t]he length of + * the key-derivation key [i.e., the input key] shall be at least 112 + * bits". */ + if (ctx->ki_len < EVP_KDF_FIPS_MIN_KEY_LEN) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Verification Program, Section D.B and NIST Special Publication + * 800-131Ar2, Section 1.2.2 say that any algorithm at a security + * strength < 112 bits is legacy use only, so all derived keys should + * be longer than that. If a derived key has ever been shorter than + * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we + * should also set the returned FIPS indicator to unapproved. */ + if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program, Section C.C: "The SHAKE128 and SHAKE256 + * extendable-output functions may only be used as the standalone + * algorithms." Note that the digest is only used when the MAC + * algorithm is HMAC. */ + if (ctx->ctx_init != NULL + && EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->ctx_init), OSSL_MAC_NAME_HMAC)) { + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + if (md != NULL + && (EVP_MD_is_a(md, "SHAKE-128") || EVP_MD_is_a(md, "SHAKE-256"))) { + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + } + } + + if (!OSSL_PARAM_set_int(p, fips_indicator)) + return 0; + } +#endif + + if (!any_valid) return -2; - /* KBKDF can produce results as large as you like. */ - return OSSL_PARAM_set_size_t(p, SIZE_MAX); + return 1; } static const OSSL_PARAM *kbkdf_gettable_ctx_params(ossl_unused void *ctx, ossl_unused void *provctx) { - static const OSSL_PARAM known_gettable_ctx_params[] = - { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), OSSL_PARAM_END }; + static const OSSL_PARAM known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), +#ifdef FIPS_MODULE + OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, NULL), +#endif /* defined(FIPS_MODULE) */ + OSSL_PARAM_END + }; return known_gettable_ctx_params; } diff --git a/providers/implementations/kdfs/sshkdf.c b/providers/implementations/kdfs/sshkdf.c index 1afac4e477..389b82b714 100644 --- a/providers/implementations/kdfs/sshkdf.c +++ b/providers/implementations/kdfs/sshkdf.c @@ -49,6 +49,9 @@ typedef struct { char type; /* X */ unsigned char *session_id; size_t session_id_len; +#ifdef FIPS_MODULE + int fips_indicator; +#endif /* defined(FIPS_MODULE) */ } KDF_SSHKDF; static void *kdf_sshkdf_new(void *provctx) @@ -151,6 +154,12 @@ static int kdf_sshkdf_derive(void *vctx, unsigned char *key, size_t keylen, ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_TYPE); return 0; } + +#ifdef FIPS_MODULE + if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN) + ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; +#endif /* defined(FIPS_MODULE) */ + return SSHKDF(md, ctx->key, ctx->key_len, ctx->xcghash, ctx->xcghash_len, ctx->session_id, ctx->session_id_len, @@ -219,10 +228,67 @@ static const OSSL_PARAM *kdf_sshkdf_settable_ctx_params(ossl_unused void *ctx, static int kdf_sshkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) { OSSL_PARAM *p; + int any_valid = 0; /* set to 1 when at least one parameter was valid */ - if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) - return OSSL_PARAM_set_size_t(p, SIZE_MAX); - return -2; + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) { + any_valid = 1; + + if (!OSSL_PARAM_set_size_t(p, SIZE_MAX)) + return 0; + } + +#ifdef FIPS_MODULE + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR); + if (p != NULL) { + KDF_SSHKDF *ctx = vctx; + int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED; + + any_valid = 1; + + /* According to NIST Special Publication 800-131Ar2, Section 8: + * Deriving Additional Keys from a Cryptographic Key, "[t]he length of + * the key-derivation key [i.e., the input key] shall be at least 112 + * bits". */ + if (ctx->key_len < EVP_KDF_FIPS_MIN_KEY_LEN) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Verification Program, Section D.B and NIST Special Publication + * 800-131Ar2, Section 1.2.2 say that any algorithm at a security + * strength < 112 bits is legacy use only, so all derived keys should + * be longer than that. If a derived key has ever been shorter than + * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we + * should also set the returned FIPS indicator to unapproved. */ + if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program, Section C.C: "The SHAKE128 and SHAKE256 + * extendable-output functions may only be used as the standalone + * algorithms." + * + * Additionally, SP 800-135r1 section 5.2 specifies that the hash + * function used in SSHKDF "is one of the hash functions specified in + * FIPS 180-3.", which rules out SHA-3 and truncated variants of SHA-2. + * */ + if (ctx->digest.md != NULL + && !EVP_MD_is_a(ctx->digest.md, "SHA-1") + && !EVP_MD_is_a(ctx->digest.md, "SHA2-224") + && !EVP_MD_is_a(ctx->digest.md, "SHA2-256") + && !EVP_MD_is_a(ctx->digest.md, "SHA2-384") + && !EVP_MD_is_a(ctx->digest.md, "SHA2-512")) { + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + } + + if (!OSSL_PARAM_set_int(p, fips_indicator)) + return 0; + } +#endif + + if (!any_valid) + return -2; + + return 1; } static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(ossl_unused void *ctx, @@ -230,6 +296,9 @@ static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(ossl_unused void *ctx, { static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), +#ifdef FIPS_MODULE + OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, NULL), +#endif /* defined(FIPS_MODULE) */ OSSL_PARAM_END }; return known_gettable_ctx_params; diff --git a/providers/implementations/kdfs/sskdf.c b/providers/implementations/kdfs/sskdf.c index ecb98de6fd..98fcc583d8 100644 --- a/providers/implementations/kdfs/sskdf.c +++ b/providers/implementations/kdfs/sskdf.c @@ -63,6 +63,10 @@ typedef struct { size_t salt_len; size_t out_len; /* optional KMAC parameter */ int is_kmac; + int is_x963kdf; +#ifdef FIPS_MODULE + int fips_indicator; +#endif /* defined(FIPS_MODULE) */ } KDF_SSKDF; #define SSKDF_MAX_INLEN (1<<30) @@ -73,6 +77,7 @@ typedef struct { static const unsigned char kmac_custom_str[] = { 0x4B, 0x44, 0x46 }; static OSSL_FUNC_kdf_newctx_fn sskdf_new; +static OSSL_FUNC_kdf_newctx_fn x963kdf_new; static OSSL_FUNC_kdf_dupctx_fn sskdf_dup; static OSSL_FUNC_kdf_freectx_fn sskdf_free; static OSSL_FUNC_kdf_reset_fn sskdf_reset; @@ -297,6 +302,16 @@ static void *sskdf_new(void *provctx) return ctx; } +static void *x963kdf_new(void *provctx) +{ + KDF_SSKDF *ctx = sskdf_new(provctx); + + if (ctx) + ctx->is_x963kdf = 1; + + return ctx; +} + static void sskdf_reset(void *vctx) { KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; @@ -392,6 +407,11 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen, } md = ossl_prov_digest_md(&ctx->digest); +#ifdef FIPS_MODULE + if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN) + ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; +#endif /* defined(FIPS_MODULE) */ + if (ctx->macctx != NULL) { /* H(x) = KMAC or H(x) = HMAC */ int ret; @@ -473,6 +493,11 @@ static int x963kdf_derive(void *vctx, unsigned char *key, size_t keylen, return 0; } +#ifdef FIPS_MODULE + if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN) + ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; +#endif /* defined(FIPS_MODULE) */ + return SSKDF_hash_kdm(md, ctx->secret, ctx->secret_len, ctx->info, ctx->info_len, 1, key, keylen); } @@ -545,10 +570,74 @@ static int sskdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) { KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; OSSL_PARAM *p; + int any_valid = 0; /* set to 1 when at least one parameter was valid */ + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) { + any_valid = 1; + + if (!OSSL_PARAM_set_size_t(p, sskdf_size(ctx))) + return 0; + } - if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) - return OSSL_PARAM_set_size_t(p, sskdf_size(ctx)); - return -2; +#ifdef FIPS_MODULE + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR); + if (p != NULL) { + int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED; + + any_valid = 1; + + /* According to NIST Special Publication 800-131Ar2, Section 8: + * Deriving Additional Keys from a Cryptographic Key, "[t]he length of + * the key-derivation key [i.e., the input key] shall be at least 112 + * bits". */ + if (ctx->secret_len < EVP_KDF_FIPS_MIN_KEY_LEN) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Verification Program, Section D.B and NIST Special Publication + * 800-131Ar2, Section 1.2.2 say that any algorithm at a security + * strength < 112 bits is legacy use only, so all derived keys should + * be longer than that. If a derived key has ever been shorter than + * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we + * should also set the returned FIPS indicator to unapproved. */ + if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program, Section C.C: "The SHAKE128 and SHAKE256 + * extendable-output functions may only be used as the standalone + * algorithms." */ + if (ctx->macctx == NULL + || (ctx->macctx != NULL && + EVP_MAC_is_a(EVP_MAC_CTX_get0_mac(ctx->macctx), OSSL_MAC_NAME_HMAC))) { + if (ctx->digest.md != NULL + && (EVP_MD_is_a(ctx->digest.md, "SHAKE-128") || + EVP_MD_is_a(ctx->digest.md, "SHAKE-256"))) { + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + } + + /* Table H-3 in ANS X9.63-2001 says that 160-bit hash functions + * should only be used for 80-bit key agreement, but FIPS 140-3 + * requires a security strength of 112 bits, so SHA-1 cannot be + * used with X9.63. See the discussion in + * https://github.com/usnistgov/ACVP/issues/1403#issuecomment-1435300395. + */ + if (ctx->is_x963kdf + && ctx->digest.md != NULL + && EVP_MD_is_a(ctx->digest.md, "SHA-1")) { + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + } + } + + if (!OSSL_PARAM_set_int(p, fips_indicator)) + return 0; + } +#endif + + if (!any_valid) + return -2; + + return 1; } static const OSSL_PARAM *sskdf_gettable_ctx_params(ossl_unused void *ctx, @@ -556,6 +645,9 @@ static const OSSL_PARAM *sskdf_gettable_ctx_params(ossl_unused void *ctx, { static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), +#ifdef FIPS_MODULE + OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, 0), +#endif /* defined(FIPS_MODULE) */ OSSL_PARAM_END }; return known_gettable_ctx_params; @@ -577,7 +669,7 @@ const OSSL_DISPATCH ossl_kdf_sskdf_functions[] = { }; const OSSL_DISPATCH ossl_kdf_x963_kdf_functions[] = { - { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))sskdf_new }, + { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))x963kdf_new }, { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))sskdf_dup }, { OSSL_FUNC_KDF_FREECTX, (void(*)(void))sskdf_free }, { OSSL_FUNC_KDF_RESET, (void(*)(void))sskdf_reset }, diff --git a/providers/implementations/kdfs/tls1_prf.c b/providers/implementations/kdfs/tls1_prf.c index 54124ad4cb..25a6c79a2e 100644 --- a/providers/implementations/kdfs/tls1_prf.c +++ b/providers/implementations/kdfs/tls1_prf.c @@ -104,6 +104,13 @@ typedef struct { /* Buffer of concatenated seed data */ unsigned char seed[TLS1_PRF_MAXBUF]; size_t seedlen; + + /* MAC digest algorithm; used to compute FIPS indicator */ + PROV_DIGEST digest; + +#ifdef FIPS_MODULE + int fips_indicator; +#endif /* defined(FIPS_MODULE) */ } TLS1_PRF; static void *kdf_tls1_prf_new(void *provctx) @@ -140,6 +147,7 @@ static void kdf_tls1_prf_reset(void *vctx) EVP_MAC_CTX_free(ctx->P_sha1); OPENSSL_clear_free(ctx->sec, ctx->seclen); OPENSSL_cleanse(ctx->seed, ctx->seedlen); + ossl_prov_digest_reset(&ctx->digest); memset(ctx, 0, sizeof(*ctx)); ctx->provctx = provctx; } @@ -194,6 +202,10 @@ static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); return 0; } +#ifdef FIPS_MODULE + if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN) + ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; +#endif /* defined(FIPS_MODULE) */ /* * The seed buffer is prepended with a label. @@ -243,6 +255,9 @@ static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) } } + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL) { OPENSSL_clear_free(ctx->sec, ctx->seclen); ctx->sec = NULL; @@ -284,10 +299,60 @@ static const OSSL_PARAM *kdf_tls1_prf_settable_ctx_params( static int kdf_tls1_prf_get_ctx_params(void *vctx, OSSL_PARAM params[]) { OSSL_PARAM *p; +#ifdef FIPS_MODULE + TLS1_PRF *ctx = vctx; +#endif /* defined(FIPS_MODULE) */ + int any_valid = 0; /* set to 1 when at least one parameter was valid */ + + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) { + any_valid = 1; + + if (!OSSL_PARAM_set_size_t(p, SIZE_MAX)) + return 0; + } + +#ifdef FIPS_MODULE + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR); + if (p != NULL) { + int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED; + + any_valid = 1; + + /* According to NIST Special Publication 800-131Ar2, Section 8: + * Deriving Additional Keys from a Cryptographic Key, "[t]he length of + * the key-derivation key [i.e., the input key] shall be at least 112 + * bits". */ + if (ctx->seclen < EVP_KDF_FIPS_MIN_KEY_LEN) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Verification Program, Section D.B and NIST Special Publication + * 800-131Ar2, Section 1.2.2 say that any algorithm at a security + * strength < 112 bits is legacy use only, so all derived keys should + * be longer than that. If a derived key has ever been shorter than + * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we + * should also set the returned FIPS indicator to unapproved. */ + if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* SP 800-135r1 section 4.2.2 says TLS 1.2 KDF is approved when "(3) + * P_HASH uses either SHA-256, SHA-384 or SHA-512." */ + if (ctx->digest.md != NULL + && !EVP_MD_is_a(ctx->digest.md, "SHA2-256") + && !EVP_MD_is_a(ctx->digest.md, "SHA2-384") + && !EVP_MD_is_a(ctx->digest.md, "SHA2-512")) { + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + } + + if (!OSSL_PARAM_set_int(p, fips_indicator)) + return 0; + } +#endif - if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) - return OSSL_PARAM_set_size_t(p, SIZE_MAX); - return -2; + if (!any_valid) + return -2; + + return 1; } static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params( @@ -295,6 +360,9 @@ static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params( { static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), +#ifdef FIPS_MODULE + OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, 0), +#endif /* defined(FIPS_MODULE) */ OSSL_PARAM_END }; return known_gettable_ctx_params; diff --git a/providers/implementations/kdfs/x942kdf.c b/providers/implementations/kdfs/x942kdf.c index 4c274fe27a..5ce23c8eb9 100644 --- a/providers/implementations/kdfs/x942kdf.c +++ b/providers/implementations/kdfs/x942kdf.c @@ -13,11 +13,13 @@ #include #include #include +#include #include #include #include "internal/packet.h" #include "internal/der.h" #include "internal/nelem.h" +#include "crypto/evp.h" #include "prov/provider_ctx.h" #include "prov/providercommon.h" #include "prov/implementations.h" @@ -49,6 +51,9 @@ typedef struct { const unsigned char *cek_oid; size_t cek_oid_len; int use_keybits; +#ifdef FIPS_MODULE + int fips_indicator; +#endif /* defined(FIPS_MODULE) */ } KDF_X942; /* @@ -497,6 +502,10 @@ static int x942kdf_derive(void *vctx, unsigned char *key, size_t keylen, ERR_raise(ERR_LIB_PROV, PROV_R_BAD_ENCODING); return 0; } +#ifdef FIPS_MODULE + if (keylen < EVP_KDF_FIPS_MIN_KEY_LEN) + ctx->fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; +#endif /* defined(FIPS_MODULE) */ ret = x942kdf_hash_kdm(md, ctx->secret, ctx->secret_len, der, der_len, ctr, key, keylen); OPENSSL_free(der); @@ -600,10 +609,58 @@ static int x942kdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) { KDF_X942 *ctx = (KDF_X942 *)vctx; OSSL_PARAM *p; + int any_valid = 0; /* set to 1 when at least one parameter was valid */ - if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) - return OSSL_PARAM_set_size_t(p, x942kdf_size(ctx)); - return -2; + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) { + any_valid = 1; + + if (!OSSL_PARAM_set_size_t(p, x942kdf_size(ctx))) + return 0; + } + +#ifdef FIPS_MODULE + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR); + if (p != NULL) { + int fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_APPROVED; + + any_valid = 1; + + /* According to NIST Special Publication 800-131Ar2, Section 8: + * Deriving Additional Keys from a Cryptographic Key, "[t]he length of + * the key-derivation key [i.e., the input key] shall be at least 112 + * bits". */ + if (ctx->secret_len < EVP_KDF_FIPS_MIN_KEY_LEN) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Verification Program, Section D.B and NIST Special Publication + * 800-131Ar2, Section 1.2.2 say that any algorithm at a security + * strength < 112 bits is legacy use only, so all derived keys should + * be longer than that. If a derived key has ever been shorter than + * that, ctx->output_keyelen_indicator will be NOT_APPROVED, and we + * should also set the returned FIPS indicator to unapproved. */ + if (ctx->fips_indicator == EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED) + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + + /* Implementation Guidance for FIPS 140-3 and the Cryptographic Module + * Validation Program, Section C.C: "The SHAKE128 and SHAKE256 + * extendable-output functions may only be used as the standalone + * algorithms." */ + if (ctx->digest.md != NULL + && (EVP_MD_is_a(ctx->digest.md, "SHAKE-128") || + EVP_MD_is_a(ctx->digest.md, "SHAKE-256"))) { + fips_indicator = EVP_KDF_REDHAT_FIPS_INDICATOR_NOT_APPROVED; + } + + if (!OSSL_PARAM_set_int(p, fips_indicator)) + return 0; + } +#endif + + if (!any_valid) + return -2; + + return 1; } static const OSSL_PARAM *x942kdf_gettable_ctx_params(ossl_unused void *ctx, @@ -611,6 +668,9 @@ static const OSSL_PARAM *x942kdf_gettable_ctx_params(ossl_unused void *ctx, { static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), +#ifdef FIPS_MODULE + OSSL_PARAM_int(OSSL_KDF_PARAM_REDHAT_FIPS_INDICATOR, 0), +#endif /* defined(FIPS_MODULE) */ OSSL_PARAM_END }; return known_gettable_ctx_params; -- 2.41.0