diff --git a/apps/fipsinstall.c b/apps/fipsinstall.c index d0d5716ab1..171d616617 100644 --- a/apps/fipsinstall.c +++ b/apps/fipsinstall.c @@ -40,6 +40,12 @@ typedef enum OPTION_choice { OPT_NO_SECURITY_CHECKS, OPT_TLS_PRF_EMS_CHECK, OPT_DISALLOW_DRGB_TRUNC_DIGEST, + OPT_HKDF_DIGEST_CHECK, + OPT_TLS13_KDF_DIGEST_CHECK, + OPT_TLS1_PRF_DIGEST_CHECK, + OPT_SSHKDF_DIGEST_CHECK, + OPT_SSKDF_DIGEST_CHECK, + OPT_X963KDF_DIGEST_CHECK, OPT_SELF_TEST_ONLOAD, OPT_SELF_TEST_ONINSTALL } OPTION_CHOICE; @@ -66,6 +72,18 @@ const OPTIONS fipsinstall_options[] = { "Enable the run-time FIPS check for EMS during TLS1_PRF"}, {"no_drbg_truncated_digests", OPT_DISALLOW_DRGB_TRUNC_DIGEST, '-', "Disallow truncated digests with Hash and HMAC DRBGs"}, + {"hkdf_digest_check", OPT_HKDF_DIGEST_CHECK, '-', + "Enable digest check for HKDF"}, + {"tls13_kdf_digest_check", OPT_TLS13_KDF_DIGEST_CHECK, '-', + "Enable digest check for TLS13-KDF"}, + {"tls1_prf_digest_check", OPT_TLS1_PRF_DIGEST_CHECK, '-', + "Enable digest check for TLS1-PRF"}, + {"sshkdf_digest_check", OPT_SSHKDF_DIGEST_CHECK, '-', + "Enable digest check for SSHKDF"}, + {"sskdf_digest_check", OPT_SSKDF_DIGEST_CHECK, '-', + "Enable digest check for SSKDF"}, + {"x963kdf_digest_check", OPT_X963KDF_DIGEST_CHECK, '-', + "Enable digest check for X963KDF"}, OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input config file, used when verifying"}, @@ -88,6 +106,12 @@ typedef struct { unsigned int security_checks : 1; unsigned int tls_prf_ems_check : 1; unsigned int drgb_no_trunc_dgst : 1; + unsigned int hkdf_digest_check : 1; + unsigned int tls13_kdf_digest_check : 1; + unsigned int tls1_prf_digest_check : 1; + unsigned int sshkdf_digest_check : 1; + unsigned int sskdf_digest_check : 1; + unsigned int x963kdf_digest_check : 1; } FIPS_OPTS; /* Pedantic FIPS compliance */ @@ -97,6 +121,12 @@ static const FIPS_OPTS pedantic_opts = { 1, /* security_checks */ 1, /* tls_prf_ems_check */ 1, /* drgb_no_trunc_dgst */ + 1, /* hkdf_digest_check */ + 1, /* tls13_kdf_digest_check */ + 1, /* tls1_prf_digest_check */ + 1, /* sshkdf_digest_check */ + 1, /* sskdf_digest_check */ + 1, /* x963kdf_digest_check */ }; /* Default FIPS settings for backward compatibility */ @@ -106,6 +136,12 @@ static FIPS_OPTS fips_opts = { 1, /* security_checks */ 0, /* tls_prf_ems_check */ 0, /* drgb_no_trunc_dgst */ + 0, /* hkdf_digest_check */ + 0, /* tls13_kdf_digest_check */ + 0, /* tls1_prf_digest_check */ + 0, /* sshkdf_digest_check */ + 0, /* sskdf_digest_check */ + 0, /* x963kdf_digest_check */ }; static int check_non_pedantic_fips(int pedantic, const char *name) @@ -229,6 +265,22 @@ static int write_config_fips_section(BIO *out, const char *section, opts->tls_prf_ems_check ? "1" : "0") <= 0 || BIO_printf(out, "%s = %s\n", OSSL_PROV_PARAM_DRBG_TRUNC_DIGEST, opts->drgb_no_trunc_dgst ? "1" : "0") <= 0 + || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_HKDF_DIGEST_CHECK, + opts->hkdf_digest_check ? "1": "0") <= 0 + || BIO_printf(out, "%s = %s\n", + OSSL_PROV_FIPS_PARAM_TLS13_KDF_DIGEST_CHECK, + opts->tls13_kdf_digest_check ? "1": "0") <= 0 + || BIO_printf(out, "%s = %s\n", + OSSL_PROV_FIPS_PARAM_TLS1_PRF_DIGEST_CHECK, + opts->tls1_prf_digest_check ? "1": "0") <= 0 + || BIO_printf(out, "%s = %s\n", + OSSL_PROV_FIPS_PARAM_SSHKDF_DIGEST_CHECK, + opts->sshkdf_digest_check ? "1": "0") <= 0 + || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_SSKDF_DIGEST_CHECK, + opts->sskdf_digest_check ? "1": "0") <= 0 + || BIO_printf(out, "%s = %s\n", + OSSL_PROV_FIPS_PARAM_X963KDF_DIGEST_CHECK, + opts->x963kdf_digest_check ? "1": "0") <= 0 || !print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac, module_mac_len)) goto end; @@ -415,6 +467,24 @@ opthelp: case OPT_DISALLOW_DRGB_TRUNC_DIGEST: fips_opts.drgb_no_trunc_dgst = 1; break; + case OPT_HKDF_DIGEST_CHECK: + fips_opts.hkdf_digest_check = 1; + break; + case OPT_TLS13_KDF_DIGEST_CHECK: + fips_opts.tls13_kdf_digest_check = 1; + break; + case OPT_TLS1_PRF_DIGEST_CHECK: + fips_opts.tls1_prf_digest_check = 1; + break; + case OPT_SSHKDF_DIGEST_CHECK: + fips_opts.sshkdf_digest_check = 1; + break; + case OPT_SSKDF_DIGEST_CHECK: + fips_opts.sskdf_digest_check = 1; + break; + case OPT_X963KDF_DIGEST_CHECK: + fips_opts.x963kdf_digest_check = 1; + break; case OPT_QUIET: quiet = 1; /* FALLTHROUGH */ diff --git a/doc/man1/openssl-fipsinstall.pod.in b/doc/man1/openssl-fipsinstall.pod.in index b1768b7f91..5bffe97d79 100644 --- a/doc/man1/openssl-fipsinstall.pod.in +++ b/doc/man1/openssl-fipsinstall.pod.in @@ -24,6 +24,12 @@ B [B<-no_security_checks>] [B<-ems_check>] [B<-no_drbg_truncated_digests>] +[B<-hkdf_digest_check>] +[B<-tls13_kdf_digest_check>] +[B<-tls1_prf_digest_check>] +[B<-sshkdf_digest_check>] +[B<-sskdf_digest_check>] +[B<-x963kdf_digest_check>] [B<-self_test_onload>] [B<-self_test_oninstall>] [B<-corrupt_desc> I] @@ -190,6 +196,42 @@ See RFC 7627 for information related to EMS. Configure the module to not allow truncated digests to be used with Hash and HMAC DRBGs. See FIPS 140-3 IG D.R for details. +=item B<-hkdf_digest_check> + +Configure the module to enable a run-time digest check when deriving a key by +HKDF. +See NIST SP 800-56Cr2 for details. + +=item B<-tls13_kdf_digest_check> + +Configure the module to enable a run-time digest check when deriving a key by +TLS13 KDF. +See RFC 8446 for details. + +=item B<-tls1_prf_digest_check> + +Configure the module to enable a run-time digest check when deriving a key by +TLS_PRF. +See NIST SP 800-135r1 for details. + +=item B<-sshkdf_digest_check> + +Configure the module to enable a run-time digest check when deriving a key by +SSHKDF. +See NIST SP 800-135r1 for details. + +=item B<-sskdf_digest_check> + +Configure the module to enable a run-time digest check when deriving a key by +SSKDF. +See NIST SP 800-56Cr2 for details. + +=item B<-x963kdf_digest_check> + +Configure the module to enable a run-time digest check when deriving a key by +X963KDF. +See NIST SP 800-131Ar2 for details. + =item B<-self_test_onload> Do not write the two fields related to the "test status indicator" and diff --git a/doc/man7/EVP_KDF-SS.pod b/doc/man7/EVP_KDF-SS.pod index c8d19691a7..6e09f9b845 100644 --- a/doc/man7/EVP_KDF-SS.pod +++ b/doc/man7/EVP_KDF-SS.pod @@ -61,6 +61,22 @@ This parameter set the shared secret that is used for key derivation. This parameter sets an optional value for fixedinfo, also known as otherinfo. +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check" +related parameter is set to 0 and the check fails. +This option is used by the OpenSSL FIPS provider. + +=item "digest-check" (B) + +The default value of 1 causes an error during EVP_KDF_derive() if +used digest is not approved. +Setting this to zero will ignore the error and set the approved +"fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + =back =head1 NOTES diff --git a/doc/man7/EVP_KDF-SSHKDF.pod b/doc/man7/EVP_KDF-SSHKDF.pod index c7a3263f45..396afa2b5d 100644 --- a/doc/man7/EVP_KDF-SSHKDF.pod +++ b/doc/man7/EVP_KDF-SSHKDF.pod @@ -80,6 +80,25 @@ A single char of value 70 (ASCII char 'F'). =back +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check" +related parameter is set to 0 and the check fails. +This option is used by the OpenSSL FIPS provider. + +=item "digest-check" (B) + +The default value of 1 causes an error during EVP_KDF_derive() if +used digest is not approved. +Setting this to zero will ignore the error and set the approved +"fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + +According to SP 800-135r1, the following are approved digest algorithms: SHA-1, +SHA2-224, SHA2-256, SHA2-384, SHA2-512. + =back =head1 NOTES diff --git a/doc/man7/EVP_KDF-TLS13_KDF.pod b/doc/man7/EVP_KDF-TLS13_KDF.pod index d588b121fa..f0d74d6992 100644 --- a/doc/man7/EVP_KDF-TLS13_KDF.pod +++ b/doc/man7/EVP_KDF-TLS13_KDF.pod @@ -54,6 +54,25 @@ Refer to RFC 8446 section 7.1 "Key Schedule" for details. This parameter sets the mode for the TLS 1.3 KDF operation. There are two modes that are currently defined: +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check" +related parameter is set to 0 and the check fails. +This option is used by the OpenSSL FIPS provider. + +=item "digest-check" (B) + +The default value of 1 causes an error during EVP_KDF_derive() if +used digest is not approved. +Setting this to zero will ignore the error and set the approved +"fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + +According to RFC 8446, the following are approved digest algorithms: SHA2-256, +SHA2-384. + =over 4 =item "EXTRACT_ONLY" or B diff --git a/doc/man7/EVP_KDF-TLS1_PRF.pod b/doc/man7/EVP_KDF-TLS1_PRF.pod index 9cfc9a2424..708d0ea4c2 100644 --- a/doc/man7/EVP_KDF-TLS1_PRF.pod +++ b/doc/man7/EVP_KDF-TLS1_PRF.pod @@ -47,8 +47,8 @@ this should be more than enough for any normal use of the TLS PRF. =item "fips-indicator" (B) A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. -This may be used after calling EVP_KDF_derive. It returns 0 if the "ems_check" -is set to 0 and the "extended master secret" test fails. +This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check" +related parameter is set to 0 and the check fails. This option is used by the OpenSSL FIPS provider. =item "ems_check" (B) @@ -59,6 +59,17 @@ will ignore the error and set the approved "fips-indicator" to 0. This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if set to 0. +=item "digest-check" (B) + +The default value of 1 causes an error during EVP_KDF_derive() if +used digest is not approved. +Setting this to zero will ignore the error and set the approved +"fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + +According to SP 800-135r1, the following are approved digest algorithms: +SHA2-256, SHA2-384, SHA2-512. =back diff --git a/doc/man7/EVP_KDF-X963.pod b/doc/man7/EVP_KDF-X963.pod index 3d6f4372cf..e275edeaa6 100644 --- a/doc/man7/EVP_KDF-X963.pod +++ b/doc/man7/EVP_KDF-X963.pod @@ -36,6 +36,26 @@ This parameter sets the secret. This parameter specifies an optional value for shared info. +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling EVP_KDF_derive. It returns 0 if any "***_check" +related parameter is set to 0 and the check fails. +This option is used by the OpenSSL FIPS provider. + +=item "digest-check" (B) + +The default value of 1 causes an error during EVP_KDF_derive() if +used digest is not approved. +Setting this to zero will ignore the error and set the approved +"fips-indicator" to 0. +This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if +set to 0. + +According to ANSI X9.63-2001, the following are approved digest algorithms: +SHA2-224, SHA2-256, SHA2-384, SHA2-512, SHA2-512/224, SHA2-512/256, SHA3-224, +SHA3-256, SHA3-384, SHA3-512. + =back =head1 NOTES diff --git a/include/openssl/fips_names.h b/include/openssl/fips_names.h index 5c77f6d691..dbf2716630 100644 --- a/include/openssl/fips_names.h +++ b/include/openssl/fips_names.h @@ -68,7 +68,55 @@ extern "C" { * This is disabled by default. * Type: OSSL_PARAM_UTF8_STRING */ -# define OSSL_PROV_FIPS_PARAM_DRBG_TRUNC_DIGEST "drbg-no-trunc-md" +# define OSSL_PROV_FIPS_PARAM_DRBG_TRUNC_DIGEST "drbg-no-trunc-md" + +/* + * A boolean that determines if the runtime FIPS digest check for HKDF is + * performed. + * This is disabled by default. + * Type: OSSL_PARAM_UTF8_STRING + */ +# define OSSL_PROV_FIPS_PARAM_HKDF_DIGEST_CHECK "hkdf-digest-check" + +/* + * A boolean that determines if the runtime FIPS digest check for TLS13 KDF is + * performed. + * This is disabled by default. + * Type: OSSL_PARAM_UTF8_STRING + */ +# define OSSL_PROV_FIPS_PARAM_TLS13_KDF_DIGEST_CHECK "tls13-kdf-digest-check" + +/* + * A boolean that determines if the runtime FIPS digest check for TLS1_PRF is + * performed. + * This is disabled by default. + * Type: OSSL_PARAM_UTF8_STRING + */ +# define OSSL_PROV_FIPS_PARAM_TLS1_PRF_DIGEST_CHECK "tls1-prf-digest-check" + +/* + * A boolean that determines if the runtime FIPS digest check for SSHKDF is + * performed. + * This is disabled by default. + * Type: OSSL_PARAM_UTF8_STRING + */ +# define OSSL_PROV_FIPS_PARAM_SSHKDF_DIGEST_CHECK "sshkdf-digest-check" + +/* + * A boolean that determines if the runtime FIPS digest check for SSKDF is + * performed. + * This is disabled by default. + * Type: OSSL_PARAM_UTF8_STRING + */ +# define OSSL_PROV_FIPS_PARAM_SSKDF_DIGEST_CHECK "sskdf-digest-check" + +/* + * A boolean that determines if the runtime FIPS digest check for X963KDF is + * performed. + * This is disabled by default. + * Type: OSSL_PARAM_UTF8_STRING + */ +# define OSSL_PROV_FIPS_PARAM_X963KDF_DIGEST_CHECK "x963kdf-digest-check" # ifdef __cplusplus } diff --git a/providers/common/include/prov/fipscommon.h b/providers/common/include/prov/fipscommon.h index 45ed248e99..a38bb33ed9 100644 --- a/providers/common/include/prov/fipscommon.h +++ b/providers/common/include/prov/fipscommon.h @@ -13,5 +13,11 @@ int FIPS_security_check_enabled(OSSL_LIB_CTX *libctx); int FIPS_tls_prf_ems_check(OSSL_LIB_CTX *libctx); int FIPS_restricted_drbg_digests_enabled(OSSL_LIB_CTX *libctx); +int FIPS_hkdf_digest_check(OSSL_LIB_CTX *libctx); +int FIPS_tls13_kdf_digest_check(OSSL_LIB_CTX *libctx); +int FIPS_tls1_prf_digest_check(OSSL_LIB_CTX *libctx); +int FIPS_sshkdf_digest_check(OSSL_LIB_CTX *libctx); +int FIPS_sskdf_digest_check(OSSL_LIB_CTX *libctx); +int FIPS_x963kdf_digest_check(OSSL_LIB_CTX *libctx); #endif diff --git a/providers/common/include/prov/securitycheck.h b/providers/common/include/prov/securitycheck.h index 4db5202c59..70d22492ff 100644 --- a/providers/common/include/prov/securitycheck.h +++ b/providers/common/include/prov/securitycheck.h @@ -19,8 +19,13 @@ int ossl_ec_check_curve_allowed(const EC_GROUP *group); int ossl_ec_check_security_strength(const EC_GROUP *group, int protect); #endif +#ifndef OPENSSL_NO_DSA int ossl_dsa_check_key(const DSA *dsa, int sign); +#endif + +#ifndef OPENSSL_NO_DH int ossl_dh_check_key(const DH *dh); +#endif int ossl_digest_md_to_nid(const EVP_MD *md, const OSSL_ITEM *it, size_t it_len); int ossl_digest_get_approved_nid(const EVP_MD *md); @@ -28,4 +33,3 @@ int ossl_digest_get_approved_nid(const EVP_MD *md); /* Functions that have different implementations for the FIPS_MODULE */ int ossl_digest_rsa_sign_get_md_nid(const EVP_MD *md); int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx); -int ossl_tls1_prf_ems_check_enabled(OSSL_LIB_CTX *libctx); diff --git a/providers/common/securitycheck_default.c b/providers/common/securitycheck_default.c index 85e5fddd5a..b9c1bda674 100644 --- a/providers/common/securitycheck_default.c +++ b/providers/common/securitycheck_default.c @@ -22,12 +22,6 @@ int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx) return 0; } -/* Disable the ems check in the default provider */ -int ossl_tls1_prf_ems_check_enabled(OSSL_LIB_CTX *libctx) -{ - return 0; -} - int ossl_digest_rsa_sign_get_md_nid(const EVP_MD *md) { int mdnid; diff --git a/providers/common/securitycheck_fips.c b/providers/common/securitycheck_fips.c index 84579dc7b3..a90233e701 100644 --- a/providers/common/securitycheck_fips.c +++ b/providers/common/securitycheck_fips.c @@ -30,11 +30,6 @@ int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx) #endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ } -int ossl_tls1_prf_ems_check_enabled(OSSL_LIB_CTX *libctx) -{ - return FIPS_tls_prf_ems_check(libctx); -} - int ossl_digest_rsa_sign_get_md_nid(const EVP_MD *md) { return ossl_digest_get_approved_nid(md); diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index bae56a8bba..71936e3ab0 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -91,6 +91,12 @@ typedef struct fips_global_st { FIPS_OPTION fips_security_checks; FIPS_OPTION fips_tls1_prf_ems_check; FIPS_OPTION fips_restricted_drgb_digests; + FIPS_OPTION fips_hkdf_digest_check; + FIPS_OPTION fips_tls13_kdf_digest_check; + FIPS_OPTION fips_tls1_prf_digest_check; + FIPS_OPTION fips_sshkdf_digest_check; + FIPS_OPTION fips_sskdf_digest_check; + FIPS_OPTION fips_x963kdf_digest_check; } FIPS_GLOBAL; static void init_fips_option(FIPS_OPTION *opt, int enabled) @@ -108,6 +114,12 @@ void *ossl_fips_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx) init_fips_option(&fgbl->fips_security_checks, 1); init_fips_option(&fgbl->fips_tls1_prf_ems_check, 0); /* Disabled by default */ init_fips_option(&fgbl->fips_restricted_drgb_digests, 0); + init_fips_option(&fgbl->fips_hkdf_digest_check, 0); + init_fips_option(&fgbl->fips_tls13_kdf_digest_check, 0); + init_fips_option(&fgbl->fips_tls1_prf_digest_check, 0); + init_fips_option(&fgbl->fips_sshkdf_digest_check, 0); + init_fips_option(&fgbl->fips_sskdf_digest_check, 0); + init_fips_option(&fgbl->fips_x963kdf_digest_check, 0); return fgbl; } @@ -125,6 +137,18 @@ static const OSSL_PARAM fips_param_types[] = { OSSL_PARAM_DEFN(OSSL_PROV_PARAM_SECURITY_CHECKS, OSSL_PARAM_INTEGER, NULL, 0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_TLS1_PRF_EMS_CHECK, OSSL_PARAM_INTEGER, NULL, 0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_DRBG_TRUNC_DIGEST, OSSL_PARAM_INTEGER, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_HKDF_DIGEST_CHECK, OSSL_PARAM_INTEGER, NULL, + 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_TLS13_KDF_DIGEST_CHECK, OSSL_PARAM_INTEGER, + NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_TLS1_PRF_DIGEST_CHECK, OSSL_PARAM_INTEGER, + NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_SSHKDF_DIGEST_CHECK, OSSL_PARAM_INTEGER, + NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_SSKDF_DIGEST_CHECK, OSSL_PARAM_INTEGER, + NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_X963KDF_DIGEST_CHECK, OSSL_PARAM_INTEGER, + NULL, 0), OSSL_PARAM_END }; @@ -138,7 +162,7 @@ static int fips_get_params_from_core(FIPS_GLOBAL *fgbl) * OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS and * OSSL_PROV_FIPS_PARAM_TLS1_PRF_EMS_CHECK are not self test parameters. */ - OSSL_PARAM core_params[10], *p = core_params; + OSSL_PARAM core_params[16], *p = core_params; *p++ = OSSL_PARAM_construct_utf8_ptr( OSSL_PROV_PARAM_CORE_MODULE_FILENAME, @@ -177,6 +201,18 @@ static int fips_get_params_from_core(FIPS_GLOBAL *fgbl) fips_tls1_prf_ems_check); FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_DRBG_TRUNC_DIGEST, fips_restricted_drgb_digests); + FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_HKDF_DIGEST_CHECK, + fips_hkdf_digest_check); + FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_TLS13_KDF_DIGEST_CHECK, + fips_tls13_kdf_digest_check); + FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_TLS1_PRF_DIGEST_CHECK, + fips_tls1_prf_digest_check); + FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_SSHKDF_DIGEST_CHECK, + fips_sshkdf_digest_check); + FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_SSKDF_DIGEST_CHECK, + fips_sskdf_digest_check); + FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_X963KDF_DIGEST_CHECK, + fips_x963kdf_digest_check); #undef FIPS_FEATURE_OPTION *p = OSSL_PARAM_construct_end(); @@ -224,6 +260,18 @@ static int fips_get_params(void *provctx, OSSL_PARAM params[]) fips_tls1_prf_ems_check); FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_DRBG_TRUNC_DIGEST, fips_restricted_drgb_digests); + FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_HKDF_DIGEST_CHECK, + fips_hkdf_digest_check); + FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_TLS13_KDF_DIGEST_CHECK, + fips_tls13_kdf_digest_check); + FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_TLS1_PRF_DIGEST_CHECK, + fips_tls1_prf_digest_check); + FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_SSHKDF_DIGEST_CHECK, + fips_sshkdf_digest_check); + FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_SSKDF_DIGEST_CHECK, + fips_sskdf_digest_check); + FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_X963KDF_DIGEST_CHECK, + fips_x963kdf_digest_check); #undef FIPS_FEATURE_GET return 1; } @@ -758,6 +806,12 @@ int OSSL_provider_init_int(const OSSL_CORE_HANDLE *handle, FIPS_SET_OPTION(fgbl, fips_security_checks); FIPS_SET_OPTION(fgbl, fips_tls1_prf_ems_check); FIPS_SET_OPTION(fgbl, fips_restricted_drgb_digests); + FIPS_SET_OPTION(fgbl, fips_hkdf_digest_check); + FIPS_SET_OPTION(fgbl, fips_tls13_kdf_digest_check); + FIPS_SET_OPTION(fgbl, fips_tls1_prf_digest_check); + FIPS_SET_OPTION(fgbl, fips_sshkdf_digest_check); + FIPS_SET_OPTION(fgbl, fips_sskdf_digest_check); + FIPS_SET_OPTION(fgbl, fips_x963kdf_digest_check); #undef FIPS_SET_OPTION ossl_prov_cache_exported_algorithms(fips_ciphers, exported_fips_ciphers); @@ -959,6 +1013,12 @@ FIPS_FEATURE_CHECK(FIPS_security_check_enabled, fips_security_checks) FIPS_FEATURE_CHECK(FIPS_tls_prf_ems_check, fips_tls1_prf_ems_check) FIPS_FEATURE_CHECK(FIPS_restricted_drbg_digests_enabled, fips_restricted_drgb_digests) +FIPS_FEATURE_CHECK(FIPS_hkdf_digest_check, fips_hkdf_digest_check) +FIPS_FEATURE_CHECK(FIPS_tls13_kdf_digest_check, fips_tls13_kdf_digest_check) +FIPS_FEATURE_CHECK(FIPS_tls1_prf_digest_check, fips_tls1_prf_digest_check) +FIPS_FEATURE_CHECK(FIPS_sshkdf_digest_check, fips_sshkdf_digest_check) +FIPS_FEATURE_CHECK(FIPS_sskdf_digest_check, fips_sskdf_digest_check) +FIPS_FEATURE_CHECK(FIPS_x963kdf_digest_check, fips_x963kdf_digest_check) #undef FIPS_FEATURE_CHECK diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c index 0618468075..3829ce1ee3 100644 --- a/providers/implementations/kdfs/hkdf.c +++ b/providers/implementations/kdfs/hkdf.c @@ -29,6 +29,9 @@ #include "prov/providercommon.h" #include "prov/implementations.h" #include "prov/provider_util.h" +#include "prov/securitycheck.h" +#include "prov/fipscommon.h" +#include "prov/fipsindicator.h" #include "internal/e_os.h" #include "internal/params.h" @@ -87,6 +90,7 @@ typedef struct { size_t data_len; unsigned char *info; size_t info_len; + OSSL_FIPS_IND_DECLARE } KDF_HKDF; static void *kdf_hkdf_new(void *provctx) @@ -96,8 +100,10 @@ static void *kdf_hkdf_new(void *provctx) if (!ossl_prov_is_running()) return NULL; - if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) { ctx->provctx = provctx; + OSSL_FIPS_IND_INIT(ctx) + } return ctx; } @@ -153,6 +159,7 @@ static void *kdf_hkdf_dup(void *vctx) || !ossl_prov_digest_copy(&dest->digest, &src->digest)) goto err; dest->mode = src->mode; + OSSL_FIPS_IND_COPY(dest, src) } return dest; @@ -180,6 +187,33 @@ static size_t kdf_hkdf_size(KDF_HKDF *ctx) return sz; } +#ifdef FIPS_MODULE +static int fips_hkdf_digest_check_passed(KDF_HKDF *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + /* + * Perform digest check + * + * HKDF is a TwoStep KDF defined in SP 800-56Cr2. According to section 7, + * the valid hash functions are specified in FIPS 180 and FIPS 202. + * However, it only lists SHA-1, SHA-2 and SHA-3 in the table in section + * 5.2. ACVP also only lists the same set of hash functions. + */ + int digest_unapproved = ((EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0); + + if (digest_unapproved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + libctx, "HKDF", "Digest", + FIPS_hkdf_digest_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); + return 0; + } + } + return 1; +} +#endif + static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { @@ -204,6 +238,11 @@ static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen, return 0; } +#ifdef FIPS_MODULE + if (!fips_hkdf_digest_check_passed(ctx)) + return 0; +#endif + switch (ctx->mode) { case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND: default: @@ -286,6 +325,10 @@ static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_KDF_PARAM_FIPS_DIGEST_CHECK)) + return 0; + if (!hkdf_common_set_ctx_params(ctx, params)) return 0; @@ -303,6 +346,7 @@ static const OSSL_PARAM *kdf_hkdf_settable_ctx_params(ossl_unused void *ctx, static const OSSL_PARAM known_settable_ctx_params[] = { HKDF_COMMON_SETTABLES, OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; @@ -318,16 +362,18 @@ static int kdf_hkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) if (sz == 0) return 0; - return OSSL_PARAM_set_size_t(p, sz); + if (!OSSL_PARAM_set_size_t(p, sz)) + return 0; } if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_INFO)) != NULL) { - if (ctx->info == NULL || ctx->info_len == 0) { + if (ctx->info == NULL || ctx->info_len == 0) p->return_size = 0; - return 1; - } - return OSSL_PARAM_set_octet_string(p, ctx->info, ctx->info_len); + else if (!OSSL_PARAM_set_octet_string(p, ctx->info, ctx->info_len)) + return 0; } - return -2; + if (!OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params)) + return 0; + return 1; } static const OSSL_PARAM *kdf_hkdf_gettable_ctx_params(ossl_unused void *ctx, @@ -336,6 +382,7 @@ 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), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; @@ -666,6 +713,33 @@ static int prov_tls13_hkdf_generate_secret(OSSL_LIB_CTX *libctx, return ret; } +#ifdef FIPS_MODULE +static int fips_tls1_3_digest_check_passed(KDF_HKDF *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + /* + * Perform digest check + * + * According to RFC 8446 appendix B.4, the valid hash functions are + * specified in FIPS 180-4. However, it only lists SHA2-256 and SHA2-384 in + * the table. ACVP also only lists the same set of hash functions. + */ + int digest_unapproved = !EVP_MD_is_a(md, SN_sha256) + && !EVP_MD_is_a(md, SN_sha384); + + if (digest_unapproved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + libctx, "TLS13 KDF", "Digest", + FIPS_tls13_kdf_digest_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); + return 0; + } + } + return 1; +} +#endif + static int kdf_tls1_3_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { @@ -681,6 +755,11 @@ static int kdf_tls1_3_derive(void *vctx, unsigned char *key, size_t keylen, return 0; } +#ifdef FIPS_MODULE + if (!fips_tls1_3_digest_check_passed(ctx)) + return 0; +#endif + switch (ctx->mode) { default: return 0; @@ -711,6 +790,10 @@ static int kdf_tls1_3_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_KDF_PARAM_FIPS_DIGEST_CHECK)) + return 0; + if (!hkdf_common_set_ctx_params(ctx, params)) return 0; @@ -752,6 +835,7 @@ static const OSSL_PARAM *kdf_tls1_3_settable_ctx_params(ossl_unused void *ctx, OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PREFIX, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_LABEL, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_DATA, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; diff --git a/providers/implementations/kdfs/sshkdf.c b/providers/implementations/kdfs/sshkdf.c index 90986bc762..767066bb2c 100644 --- a/providers/implementations/kdfs/sshkdf.c +++ b/providers/implementations/kdfs/sshkdf.c @@ -21,6 +21,9 @@ #include "prov/providercommon.h" #include "prov/implementations.h" #include "prov/provider_util.h" +#include "prov/securitycheck.h" +#include "prov/fipscommon.h" +#include "prov/fipsindicator.h" /* See RFC 4253, Section 7.2 */ static OSSL_FUNC_kdf_newctx_fn kdf_sshkdf_new; @@ -49,6 +52,7 @@ typedef struct { char type; /* X */ unsigned char *session_id; size_t session_id_len; + OSSL_FIPS_IND_DECLARE } KDF_SSHKDF; static void *kdf_sshkdf_new(void *provctx) @@ -58,8 +62,10 @@ static void *kdf_sshkdf_new(void *provctx) if (!ossl_prov_is_running()) return NULL; - if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) { ctx->provctx = provctx; + OSSL_FIPS_IND_INIT(ctx) + } return ctx; } @@ -102,6 +108,7 @@ static void *kdf_sshkdf_dup(void *vctx) || !ossl_prov_digest_copy(&dest->digest, &src->digest)) goto err; dest->type = src->type; + OSSL_FIPS_IND_COPY(dest, src) } return dest; @@ -119,6 +126,36 @@ static int sshkdf_set_membuf(unsigned char **dst, size_t *dst_len, return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len); } +#ifdef FIPS_MODULE +static int fips_digest_check_passed(KDF_SSHKDF *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + /* + * Perform digest check + * + * According to NIST SP 800-135r1 section 5.2, the valid hash functions are + * specified in FIPS 180-3. ACVP also only lists the same set of hash + * functions. + */ + int digest_unapproved = !EVP_MD_is_a(md, SN_sha1) + && !EVP_MD_is_a(md, SN_sha224) + && !EVP_MD_is_a(md, SN_sha256) + && !EVP_MD_is_a(md, SN_sha384) + && !EVP_MD_is_a(md, SN_sha512); + + if (digest_unapproved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + libctx, "SSHKDF", "Digest", + FIPS_sshkdf_digest_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); + return 0; + } + } + return 1; +} +#endif + static int kdf_sshkdf_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { @@ -149,6 +186,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 (!fips_digest_check_passed(ctx)) + return 0; +#endif + return SSHKDF(md, ctx->key, ctx->key_len, ctx->xcghash, ctx->xcghash_len, ctx->session_id, ctx->session_id_len, @@ -164,6 +207,10 @@ static int kdf_sshkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_KDF_PARAM_FIPS_DIGEST_CHECK)) + return 0; + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) return 0; @@ -209,6 +256,7 @@ static const OSSL_PARAM *kdf_sshkdf_settable_ctx_params(ossl_unused void *ctx, OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_XCGHASH, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SSHKDF_SESSION_ID, NULL, 0), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_SSHKDF_TYPE, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; @@ -218,9 +266,13 @@ static int kdf_sshkdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) { OSSL_PARAM *p; - 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) { + if (!OSSL_PARAM_set_size_t(p, SIZE_MAX)) + return 0; + } + if (!OSSL_FIPS_IND_GET_CTX_PARAM(((KDF_SSHKDF *)vctx), params)) + return 0; + return 1; } static const OSSL_PARAM *kdf_sshkdf_gettable_ctx_params(ossl_unused void *ctx, @@ -228,6 +280,7 @@ 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), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; diff --git a/providers/implementations/kdfs/sskdf.c b/providers/implementations/kdfs/sskdf.c index db750a4f23..f1edcda7ef 100644 --- a/providers/implementations/kdfs/sskdf.c +++ b/providers/implementations/kdfs/sskdf.c @@ -50,6 +50,9 @@ #include "prov/providercommon.h" #include "prov/implementations.h" #include "prov/provider_util.h" +#include "prov/securitycheck.h" +#include "prov/fipscommon.h" +#include "prov/fipsindicator.h" #include "internal/params.h" typedef struct { @@ -64,6 +67,7 @@ typedef struct { size_t salt_len; size_t out_len; /* optional KMAC parameter */ int is_kmac; + OSSL_FIPS_IND_DECLARE } KDF_SSKDF; #define SSKDF_MAX_INLEN (1<<30) @@ -292,8 +296,10 @@ static void *sskdf_new(void *provctx) if (!ossl_prov_is_running()) return NULL; - if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) { ctx->provctx = provctx; + OSSL_FIPS_IND_INIT(ctx) + } return ctx; } @@ -343,6 +349,7 @@ static void *sskdf_dup(void *vctx) goto err; dest->out_len = src->out_len; dest->is_kmac = src->is_kmac; + OSSL_FIPS_IND_COPY(dest, src) } return dest; @@ -368,6 +375,35 @@ static size_t sskdf_size(KDF_SSKDF *ctx) return (len <= 0) ? 0 : (size_t)len; } +#ifdef FIPS_MODULE +static int fips_sskdf_digest_check_passed(KDF_SSKDF *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + /* + * Perform digest check + * + * SSKDF is a OneStep KDF defined in SP 800-56Cr2. According to section 7, + * the valid hash functions are specified in FIPS 180 and FIPS 202. + * However, it only lists SHA-1, SHA-2 and SHA-3 in the table in section + * 4.2. ACVP also only lists the same set of hash functions. + */ + int digest_unapproved = (ctx->is_kmac != 1) + && (md != NULL) + && ((EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0); + + if (digest_unapproved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + libctx, "SSKDF", "Digest", + FIPS_sskdf_digest_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); + return 0; + } + } + return 1; +} +#endif + static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { @@ -380,6 +416,12 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen, ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SECRET); return 0; } + +#ifdef FIPS_MODULE + if (!fips_sskdf_digest_check_passed(ctx)) + return 0; +#endif + md = ossl_prov_digest_md(&ctx->digest); if (ctx->macctx != NULL) { @@ -435,6 +477,34 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen, } } +#ifdef FIPS_MODULE +static int fips_x963kdf_digest_check_passed(KDF_SSKDF *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + /* + * Perform digest check + * + * X963KDF is a KDF defined in ANSI-X9.63. According to ACVP specification + * section 7.3.1, only SHA-2 and SHA-3 can be regarded as valid hash + * functions. + */ + int digest_unapproved = (ctx->is_kmac != 1) + && (((EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0) + || EVP_MD_is_a(md, SN_sha1)); + + if (digest_unapproved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + libctx, "X963KDF", "Digest", + FIPS_x963kdf_digest_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); + return 0; + } + } + return 1; +} +#endif + static int x963kdf_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { @@ -461,6 +531,11 @@ static int x963kdf_derive(void *vctx, unsigned char *key, size_t keylen, return 0; } +#ifdef FIPS_MODULE + if (!fips_x963kdf_digest_check_passed(ctx)) + return 0; +#endif + return SSKDF_hash_kdm(md, ctx->secret, ctx->secret_len, ctx->info, ctx->info_len, 1, key, keylen); } @@ -476,6 +551,10 @@ static int sskdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_KDF_PARAM_FIPS_DIGEST_CHECK)) + return 0; + if (!ossl_prov_macctx_load_from_params(&ctx->macctx, params, NULL, NULL, NULL, libctx)) return 0; @@ -528,6 +607,7 @@ static const OSSL_PARAM *sskdf_settable_ctx_params(ossl_unused void *ctx, OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MAC, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), OSSL_PARAM_size_t(OSSL_KDF_PARAM_MAC_SIZE, NULL), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; @@ -538,9 +618,13 @@ static int sskdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) KDF_SSKDF *ctx = (KDF_SSKDF *)vctx; OSSL_PARAM *p; - if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) - return OSSL_PARAM_set_size_t(p, sskdf_size(ctx)); - return -2; + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) { + if (!OSSL_PARAM_set_size_t(p, sskdf_size(ctx))) + return 0; + } + if (!OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params)) + return 0; + return 1; } static const OSSL_PARAM *sskdf_gettable_ctx_params(ossl_unused void *ctx, @@ -548,6 +632,7 @@ 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), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; diff --git a/providers/implementations/kdfs/tls1_prf.c b/providers/implementations/kdfs/tls1_prf.c index cf4b656546..72af2e329b 100644 --- a/providers/implementations/kdfs/tls1_prf.c +++ b/providers/implementations/kdfs/tls1_prf.c @@ -68,6 +68,7 @@ #include "prov/implementations.h" #include "prov/provider_util.h" #include "prov/securitycheck.h" +#include "prov/fipscommon.h" #include "prov/fipsindicator.h" #include "internal/e_os.h" #include "internal/safe_math.h" @@ -107,6 +108,11 @@ typedef struct { /* Concatenated seed data */ unsigned char *seed; size_t seedlen; + +#ifdef FIPS_MODULE + PROV_DIGEST digest; +#endif + OSSL_FIPS_IND_DECLARE } TLS1_PRF; @@ -139,6 +145,9 @@ static void kdf_tls1_prf_reset(void *vctx) TLS1_PRF *ctx = (TLS1_PRF *)vctx; void *provctx = ctx->provctx; +#ifdef FIPS_MODULE + ossl_prov_digest_reset(&ctx->digest); +#endif EVP_MAC_CTX_free(ctx->P_hash); EVP_MAC_CTX_free(ctx->P_sha1); OPENSSL_clear_free(ctx->sec, ctx->seclen); @@ -165,6 +174,10 @@ static void *kdf_tls1_prf_dup(void *vctx) if (!ossl_prov_memdup(src->seed, src->seedlen, &dest->seed, &dest->seedlen)) goto err; +#ifdef FIPS_MODULE + if (!ossl_prov_digest_copy(&dest->digest, &src->digest)) + goto err; +#endif OSSL_FIPS_IND_COPY(dest, src) } return dest; @@ -194,13 +207,40 @@ static int fips_ems_check_passed(TLS1_PRF *ctx) if (!ems_approved) { if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, libctx, "TLS_PRF", "EMS", - ossl_tls1_prf_ems_check_enabled)) { + FIPS_tls_prf_ems_check)) { ERR_raise(ERR_LIB_PROV, PROV_R_EMS_NOT_ENABLED); return 0; } } return 1; } + +static int fips_digest_check_passed(TLS1_PRF *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + const EVP_MD *md = ossl_prov_digest_md(&ctx->digest); + /* + * Perform digest check + * + * According to NIST SP 800-135r1 section 5.2, the valid hash functions are + * specified in FIPS 180-3. ACVP also only lists the same set of hash + * functions. + */ + int digest_unapproved = (md != NULL) + && !EVP_MD_is_a(md, SN_sha256) + && !EVP_MD_is_a(md, SN_sha384) + && !EVP_MD_is_a(md, SN_sha512); + + if (digest_unapproved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE1, + libctx, "TLS_PRF", "Digest", + FIPS_tls1_prf_digest_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); + return 0; + } + } + return 1; +} #endif static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, @@ -231,6 +271,8 @@ static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, #ifdef FIPS_MODULE if (!fips_ems_check_passed(ctx)) return 0; + if (!fips_digest_check_passed(ctx)) + return 0; #endif return tls1_prf_alg(ctx->P_hash, ctx->P_sha1, @@ -250,7 +292,10 @@ static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, OSSL_KDF_PARAM_FIPS_EMS_CHECK)) - return 0; + return 0; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE1, params, + OSSL_KDF_PARAM_FIPS_DIGEST_CHECK)) + return 0; if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { if (OPENSSL_strcasecmp(p->data, SN_md5_sha1) == 0) { @@ -268,6 +313,11 @@ static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) NULL, NULL, libctx)) return 0; } + +#ifdef FIPS_MODULE + if (!ossl_prov_digest_load_from_params(&ctx->digest, params, libctx)) + return 0; +#endif } if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL) { @@ -317,6 +367,7 @@ static const OSSL_PARAM *kdf_tls1_prf_settable_ctx_params( OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0), OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_EMS_CHECK) + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_DIGEST_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; @@ -326,8 +377,10 @@ static int kdf_tls1_prf_get_ctx_params(void *vctx, OSSL_PARAM params[]) { OSSL_PARAM *p; - if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) - return OSSL_PARAM_set_size_t(p, SIZE_MAX); + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) { + if (!OSSL_PARAM_set_size_t(p, SIZE_MAX)) + return 0; + } if (!OSSL_FIPS_IND_GET_CTX_PARAM(((TLS1_PRF *)vctx), params)) return 0; return 1; diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c index 1e882e4108..f60364ba75 100644 --- a/test/evp_kdf_test.c +++ b/test/evp_kdf_test.c @@ -273,9 +273,9 @@ static int do_kdf_hkdf_gettables(int expand_only, int has_digest) goto err; } - /* Get params returns -2 if an unsupported parameter is requested */ + /* Get params returns 1 if an unsupported parameter is requested */ params_get[0] = OSSL_PARAM_construct_end(); - if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), -2)) + if (!TEST_int_eq(EVP_KDF_CTX_get_params(kctx, params_get), 1)) goto err; ret = 1; err: diff --git a/test/recipes/30-test_evp_data/evpkdf_hkdf.txt b/test/recipes/30-test_evp_data/evpkdf_hkdf.txt index 2fde0c9ca1..5cde7555d2 100644 --- a/test/recipes/30-test_evp_data/evpkdf_hkdf.txt +++ b/test/recipes/30-test_evp_data/evpkdf_hkdf.txt @@ -221,3 +221,14 @@ Ctrl.IKM = hexkey:1a2d Ctrl.salt = hexsalt:000000000000000000000000000000000000000000000000000000000000000000 Ctrl.info = info: Output = 62f99231760bedd72319cc6cad + +Title = HKDF bad digest test + +Availablein = fips +FIPSversion = >=3.4.0 +KDF = HKDF +Ctrl.digest = digest:SHAKE-256 +Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +Ctrl.salt = hexsalt:000102030405060708090a0b0c +Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9 +Result = KDF_DERIVE_ERROR diff --git a/test/recipes/30-test_evp_data/evpkdf_ss.txt b/test/recipes/30-test_evp_data/evpkdf_ss.txt index 80dcbcb071..fe3a1010b8 100644 --- a/test/recipes/30-test_evp_data/evpkdf_ss.txt +++ b/test/recipes/30-test_evp_data/evpkdf_ss.txt @@ -1131,3 +1131,13 @@ Ctrl.hexinfo = hexinfo:0553552e5345a11a3018a003020101a111300f1b066b72627467741b Ctrl.hexinfo = hexinfo:0553552e5345a22404223020a003020110a10c040aaaaaaaaaaaaaaa Ctrl.hexinfo = hexinfo:aaaaaaa20b0409bbbbbbbbbbbbbbbbbb Output = d3c78b78d75313e9a926f75dfb012363fa17fa01db + +Title = SSKDF bad digest test + +Availablein = fips +FIPSversion = >=3.4.0 +KDF = SSKDF +Ctrl.digest = digest:SHAKE-256 +Ctrl.hexsecret = hexsecret:d09a6b1a472f930db4f5e6b967900744 +Ctrl.hexinfo = hexinfo:b117255ab5f1b6b96fc434b0 +Result = KDF_DERIVE_ERROR diff --git a/test/recipes/30-test_evp_data/evpkdf_ssh.txt b/test/recipes/30-test_evp_data/evpkdf_ssh.txt index d870df7037..e9c79c1a09 100644 --- a/test/recipes/30-test_evp_data/evpkdf_ssh.txt +++ b/test/recipes/30-test_evp_data/evpkdf_ssh.txt @@ -4865,3 +4865,13 @@ Ctrl.hexsession_id = hexsession_id:a4ebd45934f56792b5112dcd75a1075fdc889245 Ctrl.type = type:A Output = FF Result = KDF_MISMATCH + +Availablein = fips +FIPSversion = >=3.4.0 +KDF = SSHKDF +Ctrl.digest = digest:SHA512-256 +Ctrl.hexkey = hexkey:0000008055bae931c07fd824bf10add1902b6fbc7c665347383498a686929ff5a25f8e40cb6645ea814fb1a5e0a11f852f86255641e5ed986e83a78bc8269480eac0b0dfd770cab92e7a28dd87ff452466d6ae867cead63b366b1c286e6c4811a9f14c27aea14c5171d49b78c06e3735d36e6a3be321dd5fc82308f34ee1cb17fba94a59 +Ctrl.hexxcghash = hexxcghash:a4ebd45934f56792b5112dcd75a1075fdc889245 +Ctrl.hexsession_id = hexsession_id:a4ebd45934f56792b5112dcd75a1075fdc889245 +Ctrl.type = type:A +Result = KDF_DERIVE_ERROR diff --git a/test/recipes/30-test_evp_data/evpkdf_tls13_kdf.txt b/test/recipes/30-test_evp_data/evpkdf_tls13_kdf.txt index 9ad8b9fbd2..c65470832d 100644 --- a/test/recipes/30-test_evp_data/evpkdf_tls13_kdf.txt +++ b/test/recipes/30-test_evp_data/evpkdf_tls13_kdf.txt @@ -4935,3 +4935,12 @@ Ctrl.mode = mode:EXTRACT_AND_EXPAND Ctrl.digest = digest:SHA256 Result = KDF_CTRL_ERROR +Title = TLS13-KDF bad digest test + +Availablein = fips +FIPSversion = >=3.4.0 +KDF = TLS13-KDF +Ctrl.mode = mode:EXTRACT_ONLY +Ctrl.digest = digest:SHA3-256 +Ctrl.key = hexkey:f8af6aea2d397baf2948a25b2834200692cff17eee9165e4e27babee9edefd05 +Result = KDF_DERIVE_ERROR diff --git a/test/recipes/30-test_evp_data/evpkdf_x963.txt b/test/recipes/30-test_evp_data/evpkdf_x963.txt index ad175acc11..e5e8b046c8 100644 --- a/test/recipes/30-test_evp_data/evpkdf_x963.txt +++ b/test/recipes/30-test_evp_data/evpkdf_x963.txt @@ -17,6 +17,7 @@ Title = X963 KDF tests (from NIST test vectors) +FIPSversion = <3.4.0 KDF = X963KDF Ctrl.digest = digest:SHA1 Ctrl.hexsecret = hexsecret:fd17198b89ab39c4ab5d7cca363b82f9fd7e23c3984dc8a2 @@ -119,3 +120,13 @@ Ctrl.hexsecret = hexsecret:0096172bf47d06d544ae98471490cf9e52ee59ea7a2208b33b26c Ctrl.hexinfo = hexinfo:cf3a74ba86 Ctrl.hexinfo = hexinfo:af42f1ae85477ead645583 Output = 995d1ab8557dfeafcb347f8182583fa0ac5e6cb3912393592590989f38a0214f6cf7d6fbe23917b0966c6a870876de2a2c13a45fa7aa1715be137ed332e1ffc204ce4dcce33ece6dec7f3da61fa049780040e44142cc8a1e5121cf56b386f65b7c261a192f05e5fefae4221a602bc51c41ef175dc45fb7eab8642421b4f7e3e7 + +Title = X963KDF bad digest test + +Availablein = fips +FIPSversion = >=3.4.0 +KDF = X963KDF +Ctrl.digest = digest:SHA1 +Ctrl.hexsecret = hexsecret:fd17198b89ab39c4ab5d7cca363b82f9fd7e23c3984dc8a2 +Ctrl.hexinfo = hexinfo:856a53f3e36a26bbc5792879f307cce2 +Result = KDF_DERIVE_ERROR diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t index 91006ba5b6..cff058f0a3 100644 --- a/test/recipes/80-test_cms.t +++ b/test/recipes/80-test_cms.t @@ -607,17 +607,17 @@ my @smime_cms_param_tests = ( ], [ "enveloped content test streaming S/MIME format, ECDH, AES-128-CBC, SHA256 KDF", - [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, + [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont, "-stream", "-out", "{output}.cms", "-recip", catfile($smdir, "smec1.pem"), "-aes128", "-keyopt", "ecdh_kdf_md:sha256" ], - [ "{cmd2}", @prov, "-decrypt", "-recip", catfile($smdir, "smec1.pem"), + [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smec1.pem"), "-in", "{output}.cms", "-out", "{output}.txt" ], \&final_compare ], [ "enveloped content test streaming S/MIME format, ECDH, AES-128-GCM cipher, SHA256 KDF", - [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, + [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont, "-stream", "-out", "{output}.cms", "-recip", catfile($smdir, "smec1.pem"), "-aes-128-gcm", "-keyopt", "ecdh_kdf_md:sha256" ], [ "{cmd2}", "-decrypt", "-recip", catfile($smdir, "smec1.pem"), @@ -626,11 +626,11 @@ my @smime_cms_param_tests = ( ], [ "enveloped content test streaming S/MIME format, ECDH, K-283, cofactor DH", - [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, + [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont, "-stream", "-out", "{output}.cms", "-recip", catfile($smdir, "smec2.pem"), "-aes128", "-keyopt", "ecdh_kdf_md:sha256", "-keyopt", "ecdh_cofactor_mode:1" ], - [ "{cmd2}", @prov, "-decrypt", "-recip", catfile($smdir, "smec2.pem"), + [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smec2.pem"), "-in", "{output}.cms", "-out", "{output}.txt" ], \&final_compare ], diff --git a/util/mk-fipsmodule-cnf.pl b/util/mk-fipsmodule-cnf.pl index 3eb397adad..070626a4f9 100644 --- a/util/mk-fipsmodule-cnf.pl +++ b/util/mk-fipsmodule-cnf.pl @@ -14,6 +14,7 @@ my $conditional_errors = 1; my $security_checks = 1; my $ems_check = 1; my $drgb_no_trunc_dgst = 1; +my $kdf_digest_check = 1; my $activate = 1; my $mac_key; @@ -48,4 +49,10 @@ security-checks = $security_checks tls1-prf-ems-check = $ems_check drbg-no-trunc-md = $drgb_no_trunc_dgst module-mac = $module_mac +hkdf-digest-check = $kdf_digest_check +tls13-kdf-digest-check = $kd_digest_check +tls1-prf-digest-check = $kdf_digest_check +sshkdf-digest-check = $k_digest_check +sskdf-digest-check = $kd_digest_check +x963kdf-digest-check = $kdf__digest_check _____ diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm index 8a859dfbf7..a7087fb3a2 100644 --- a/util/perl/OpenSSL/paramnames.pm +++ b/util/perl/OpenSSL/paramnames.pm @@ -33,6 +33,12 @@ my %params = ( 'PROV_PARAM_SECURITY_CHECKS' => "security-checks", # uint 'PROV_PARAM_TLS1_PRF_EMS_CHECK' => "tls1-prf-ems-check", # uint 'PROV_PARAM_DRBG_TRUNC_DIGEST' => "drbg-no-trunc-md", # uint + 'PROV_PARAM_HKDF_DIGEST_CHECK' => "hkdf-digest-check", # uint + 'PROV_PARAM_TLS13_KDF_DIGEST_CHECK' => "tls13-kdf-digest-check", # uint + 'PROV_PARAM_TLS1_PRF_DIGEST_CHECK' => "tls1-prf-digest-check", # uint + 'PROV_PARAM_SSHKDF_DIGEST_CHECK' => "sshkdf-digest-check", # uint + 'PROV_PARAM_SSKDF_DIGEST_CHECK' => "sskdf-digest-check", # uint + 'PROV_PARAM_X963KDF_DIGEST_CHECK' => "x963kdf-digest-check", # uint # Self test callback parameters 'PROV_PARAM_SELF_TEST_PHASE' => "st-phase",# utf8_string @@ -193,6 +199,7 @@ my %params = ( 'KDF_PARAM_ARGON2_MEMCOST' => "memcost", # uint32_t 'KDF_PARAM_ARGON2_VERSION' => "version", # uint32_t 'KDF_PARAM_FIPS_EMS_CHECK' => "ems_check", # int + 'KDF_PARAM_FIPS_DIGEST_CHECK' => '*PKEY_PARAM_FIPS_DIGEST_CHECK', 'KDF_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR', # Known RAND names