diff options
author | slontis <shane.lontis@oracle.com> | 2024-07-31 06:56:44 +0200 |
---|---|---|
committer | Tomas Mraz <tomas@openssl.org> | 2024-08-21 15:34:40 +0200 |
commit | 390f00a1e95f241b4a104c323020c7bc90d5e829 (patch) | |
tree | c3236df10f38563b0b15df196e5c8a80a0f21013 | |
parent | hashtable.c: Code style fixes (diff) | |
download | openssl-390f00a1e95f241b4a104c323020c7bc90d5e829.tar.xz openssl-390f00a1e95f241b4a104c323020c7bc90d5e829.zip |
Add HMAC FIPS keysize check.
HMAC has been changed to use a FIPS indicator for its key check.
HKDF and Single Step use a salt rather than a key when using HMAC,
so we need a mechanism to bypass this check in HMAC.
A seperate 'internal' query table has been added to the FIPS provider
for MACS. Giving HMAC a seprate dispatch table allows KDF's to ignore
the key check. If a KDF requires the key check then it must do the
check itself. The normal MAC dipatch table is used if the user fetches
HMAC directly.
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/25049)
-rw-r--r-- | apps/fipsinstall.c | 10 | ||||
-rw-r--r-- | doc/man1/openssl-fipsinstall.pod.in | 6 | ||||
-rw-r--r-- | doc/man7/EVP_MAC-HMAC.pod | 16 | ||||
-rw-r--r-- | doc/man7/provider-mac.pod | 14 | ||||
-rw-r--r-- | include/openssl/fips_names.h | 10 | ||||
-rw-r--r-- | providers/common/include/prov/fipscommon.h | 1 | ||||
-rw-r--r-- | providers/common/include/prov/fipsindicator.h | 4 | ||||
-rw-r--r-- | providers/common/include/prov/securitycheck.h | 1 | ||||
-rw-r--r-- | providers/common/securitycheck.c | 11 | ||||
-rw-r--r-- | providers/fips/fipsprov.c | 54 | ||||
-rw-r--r-- | providers/implementations/include/prov/implementations.h | 3 | ||||
-rw-r--r-- | providers/implementations/kdfs/hkdf.c | 7 | ||||
-rw-r--r-- | providers/implementations/macs/hmac_prov.c | 84 | ||||
-rw-r--r-- | test/evp_test.c | 6 | ||||
-rw-r--r-- | test/recipes/30-test_evp_data/evpmac_common.txt | 24 | ||||
-rw-r--r-- | util/mk-fipsmodule-cnf.pl | 2 | ||||
-rw-r--r-- | util/perl/OpenSSL/paramnames.pm | 2 |
17 files changed, 235 insertions, 20 deletions
diff --git a/apps/fipsinstall.c b/apps/fipsinstall.c index 4d0f916879..237a0bba84 100644 --- a/apps/fipsinstall.c +++ b/apps/fipsinstall.c @@ -41,6 +41,7 @@ typedef enum OPTION_choice { OPT_TLS_PRF_EMS_CHECK, OPT_NO_SHORT_MAC, OPT_DISALLOW_PKCS15_PADDING, OPT_RSA_PSS_SALTLEN_CHECK, OPT_DISALLOW_SIGNATURE_X931_PADDING, + OPT_HMAC_KEY_CHECK, OPT_DISALLOW_DRGB_TRUNC_DIGEST, OPT_SIGNATURE_DIGEST_CHECK, OPT_HKDF_DIGEST_CHECK, @@ -89,6 +90,7 @@ const OPTIONS fipsinstall_options[] = { "Disallow truncated digests with Hash and HMAC DRBGs"}, {"signature_digest_check", OPT_SIGNATURE_DIGEST_CHECK, '-', "Enable checking for approved digests for signatures"}, + {"hmac_key_check", OPT_HMAC_KEY_CHECK, '-', "Enable key check for HMAC"}, {"hkdf_digest_check", OPT_HKDF_DIGEST_CHECK, '-', "Enable digest check for HKDF"}, {"tls13_kdf_digest_check", OPT_TLS13_KDF_DIGEST_CHECK, '-', @@ -149,6 +151,7 @@ typedef struct { unsigned int self_test_onload : 1; unsigned int conditional_errors : 1; unsigned int security_checks : 1; + unsigned int hmac_key_check : 1; unsigned int tls_prf_ems_check : 1; unsigned int no_short_mac : 1; unsigned int drgb_no_trunc_dgst : 1; @@ -180,6 +183,7 @@ static const FIPS_OPTS pedantic_opts = { 1, /* self_test_onload */ 1, /* conditional_errors */ 1, /* security_checks */ + 1, /* hmac_key_check */ 1, /* tls_prf_ems_check */ 1, /* no_short_mac */ 1, /* drgb_no_trunc_dgst */ @@ -211,6 +215,7 @@ static FIPS_OPTS fips_opts = { 1, /* self_test_onload */ 1, /* conditional_errors */ 1, /* security_checks */ + 0, /* hmac_key_check */ 0, /* tls_prf_ems_check */ 0, /* no_short_mac */ 0, /* drgb_no_trunc_dgst */ @@ -354,6 +359,8 @@ static int write_config_fips_section(BIO *out, const char *section, opts->conditional_errors ? "1" : "0") <= 0 || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS, opts->security_checks ? "1" : "0") <= 0 + || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_HMAC_KEY_CHECK, + opts->hmac_key_check ? "1": "0") <= 0 || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_TLS1_PRF_EMS_CHECK, opts->tls_prf_ems_check ? "1" : "0") <= 0 || BIO_printf(out, "%s = %s\n", OSSL_PROV_PARAM_NO_SHORT_MAC, @@ -591,6 +598,9 @@ int fipsinstall_main(int argc, char **argv) goto end; fips_opts.security_checks = 0; break; + case OPT_HMAC_KEY_CHECK: + fips_opts.hmac_key_check = 1; + break; case OPT_TLS_PRF_EMS_CHECK: fips_opts.tls_prf_ems_check = 1; break; diff --git a/doc/man1/openssl-fipsinstall.pod.in b/doc/man1/openssl-fipsinstall.pod.in index d601544b60..413c490329 100644 --- a/doc/man1/openssl-fipsinstall.pod.in +++ b/doc/man1/openssl-fipsinstall.pod.in @@ -22,6 +22,7 @@ B<openssl fipsinstall> [B<-pedantic>] [B<-no_conditional_errors>] [B<-no_security_checks>] +[B<-hmac_key_check>] [B<-ems_check>] [B<-no_drbg_truncated_digests>] [B<-signature_digest_check>] @@ -212,6 +213,11 @@ See RFC 7627 for information related to EMS. Configure the module to not allow short MAC outputs. See SP 800-185 8.4.2 and FIPS 140-3 ID C.D for details. +=item B<-hmac_key_check> + +Configure the module to not allow small keys sizes when using HMAC. +See SP 800-131Ar2 for details. + =item B<-no_drbg_truncated_digests> Configure the module to not allow truncated digests to be used with Hash and diff --git a/doc/man7/EVP_MAC-HMAC.pod b/doc/man7/EVP_MAC-HMAC.pod index 474f62bb49..69342c630c 100644 --- a/doc/man7/EVP_MAC-HMAC.pod +++ b/doc/man7/EVP_MAC-HMAC.pod @@ -27,7 +27,7 @@ used with EVP_MAC_fetch(): The general description of these parameters can be found in L<EVP_MAC(3)/PARAMETERS>. -The following parameter can be set with EVP_MAC_CTX_set_params(): +The following parameters can be set with EVP_MAC_CTX_set_params(): =over 4 @@ -63,11 +63,15 @@ It may be set but is currently ignored. =item "tls-data-size" (B<OSSL_MAC_PARAM_TLS_DATA_SIZE>) <unsigned integer> +=item "key-check" (B<OSSL_MAC_PARAM_FIPS_KEY_CHECK>) <integer> + +See L<provider-mac(7)/Mac Parameters>. + =back =for comment The "flags" parameter is passed directly to HMAC_CTX_set_flags(). -The following parameter can be retrieved with EVP_MAC_CTX_get_params(): +The following parameters can be retrieved with EVP_MAC_CTX_get_params(): =over 4 @@ -76,15 +80,15 @@ The following parameter can be retrieved with EVP_MAC_CTX_get_params(): The "size" parameter can also be retrieved with EVP_MAC_CTX_get_mac_size(). The length of the "size" parameter is equal to that of an B<unsigned int>. -=back - -=over 4 - =item "block-size" (B<OSSL_MAC_PARAM_BLOCK_SIZE>) <unsigned integer> Gets the MAC block size. The "block-size" parameter can also be retrieved with EVP_MAC_CTX_get_block_size(). +=item "fips-indicator" (B<OSSL_KDF_PARAM_FIPS_APPROVED_INDICATOR>) <integer> + +See L<provider-mac(7)/Mac Parameters>. + =back =head1 SEE ALSO diff --git a/doc/man7/provider-mac.pod b/doc/man7/provider-mac.pod index 13be4a7fc0..15a86f51b4 100644 --- a/doc/man7/provider-mac.pod +++ b/doc/man7/provider-mac.pod @@ -196,9 +196,9 @@ Can be used to get the MAC block size (if supported by the algorithm). =item "fips-indicator" (B<OSSL_MAC_PARAM_FIPS_APPROVED_INDICATOR>) <int> A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. -This may be used after calling the final function. It may return 0 if -"no-short-mac" are set to 0. This option is used by the OpenSSL FIPS -provider. +This may be used after calling the final function. It may return 0 if +either "no-short-mac" or "key-check" are set to 0. +This option is used by the OpenSSL FIPS provider. =back @@ -212,6 +212,14 @@ asked for. Setting this to 0 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 "key-check" (B<OSSL_MAC_PARAM_FIPS_KEY_CHECK>) <integer> + +If required this parameter should be set before OSSL_FUNC_mac_init. +The default value of 1 causes an error when small key sizes are +asked for. Setting this to 0 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 =back diff --git a/include/openssl/fips_names.h b/include/openssl/fips_names.h index a94c4d2b1d..203ef54fe9 100644 --- a/include/openssl/fips_names.h +++ b/include/openssl/fips_names.h @@ -67,7 +67,15 @@ extern "C" { * This is enabled by default. * Type: OSSL_PARAM_UTF8_STRING */ -#define OSSL_PROV_FIPS_PARAM_NO_SHORT_MAC "no-short-mac" +# define OSSL_PROV_FIPS_PARAM_NO_SHORT_MAC "no-short-mac" + +/* + * A boolean that determines if the runtime FIPS key check for HMAC is + * performed. + * This is enabled by default. + * Type: OSSL_PARAM_UTF8_STRING + */ +# define OSSL_PROV_FIPS_PARAM_HMAC_KEY_CHECK "hmac-key-check" /* * A boolean that determines if truncated digests can be used with Hash and HMAC diff --git a/providers/common/include/prov/fipscommon.h b/providers/common/include/prov/fipscommon.h index 44e8c2ecf8..40e09f946e 100644 --- a/providers/common/include/prov/fipscommon.h +++ b/providers/common/include/prov/fipscommon.h @@ -13,6 +13,7 @@ int FIPS_security_check_enabled(OSSL_LIB_CTX *libctx); int FIPS_tls_prf_ems_check(OSSL_LIB_CTX *libctx); int FIPS_no_short_mac(OSSL_LIB_CTX *libctx); +int FIPS_hmac_key_check(OSSL_LIB_CTX *libctx); int FIPS_restricted_drbg_digests_enabled(OSSL_LIB_CTX *libctx); int FIPS_fips_signature_digest_check(OSSL_LIB_CTX *libctx); int FIPS_hkdf_digest_check(OSSL_LIB_CTX *libctx); diff --git a/providers/common/include/prov/fipsindicator.h b/providers/common/include/prov/fipsindicator.h index 4d674643b1..8f97bc35d9 100644 --- a/providers/common/include/prov/fipsindicator.h +++ b/providers/common/include/prov/fipsindicator.h @@ -114,12 +114,12 @@ void ossl_FIPS_IND_copy(OSSL_FIPS_IND *dst, const OSSL_FIPS_IND *src); # define OSSL_FIPS_IND_GET_CTX_PARAM(ctx, prms) \ ossl_FIPS_IND_get_ctx_param(&((ctx)->indicator), prms) -# define OSSL_FIPS_IND_GET(ctx) &((ctx)->indicator) +# define OSSL_FIPS_IND_GET(ctx) (&((ctx)->indicator)) # define OSSL_FIPS_IND_GET_PARAM(ctx, p, settable, id, name) \ *settable = ossl_FIPS_IND_get_settable(&((ctx)->indicator), id); \ if (*settable != OSSL_FIPS_IND_STATE_UNKNOWN) \ - *p = OSSL_PARAM_construct_int(name, settable); \ + *p = OSSL_PARAM_construct_int(name, settable); int ossl_fips_ind_rsa_key_check(OSSL_FIPS_IND *ind, int id, OSSL_LIB_CTX *libctx, const RSA *rsa, const char *desc, int protect); diff --git a/providers/common/include/prov/securitycheck.h b/providers/common/include/prov/securitycheck.h index a9cb3c570d..a932c7771d 100644 --- a/providers/common/include/prov/securitycheck.h +++ b/providers/common/include/prov/securitycheck.h @@ -18,6 +18,7 @@ int ossl_rsa_key_op_get_protect(const RSA *rsa, int operation, int *outprotect); int ossl_rsa_check_key_size(const RSA *rsa, int protect); int ossl_kdf_check_key_size(size_t keylen); +int ossl_mac_check_key_size(size_t keylen); #ifndef OPENSSL_NO_EC int ossl_ec_check_curve_allowed(const EC_GROUP *group); diff --git a/providers/common/securitycheck.c b/providers/common/securitycheck.c index 0831ef3204..fc22d5c3a0 100644 --- a/providers/common/securitycheck.c +++ b/providers/common/securitycheck.c @@ -21,6 +21,8 @@ #include "prov/securitycheck.h" #include "prov/fipsindicator.h" +#define OSSL_FIPS_MIN_SECURITY_STRENGTH_BITS 112 + int ossl_rsa_key_op_get_protect(const RSA *rsa, int operation, int *outprotect) { int protect = 0; @@ -78,7 +80,12 @@ int ossl_rsa_check_key_size(const RSA *rsa, int protect) */ int ossl_kdf_check_key_size(size_t keylen) { - return (keylen * 8) >= 112; + return (keylen * 8) >= OSSL_FIPS_MIN_SECURITY_STRENGTH_BITS; +} + +int ossl_mac_check_key_size(size_t keylen) +{ + return ossl_kdf_check_key_size(keylen); } #ifndef OPENSSL_NO_EC @@ -126,7 +133,7 @@ int ossl_ec_check_security_strength(const EC_GROUP *group, int protect) * For signing or key agreement only allow curves with at least 112 bits of * security strength */ - if (protect && strength < 112) + if (protect && strength < OSSL_FIPS_MIN_SECURITY_STRENGTH_BITS) return 0; return 1; } diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 5a016f70c0..e72faf4173 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -40,6 +40,7 @@ static OSSL_FUNC_provider_teardown_fn fips_teardown; static OSSL_FUNC_provider_gettable_params_fn fips_gettable_params; static OSSL_FUNC_provider_get_params_fn fips_get_params; static OSSL_FUNC_provider_query_operation_fn fips_query; +static OSSL_FUNC_provider_query_operation_fn fips_query_internal; #define ALGC(NAMES, FUNC, CHECK) \ { { NAMES, FIPS_DEFAULT_PROPERTIES, FUNC }, CHECK } @@ -89,6 +90,7 @@ typedef struct fips_global_st { FIPS_OPTION fips_security_checks; FIPS_OPTION fips_tls1_prf_ems_check; FIPS_OPTION fips_no_short_mac; + FIPS_OPTION fips_hmac_key_check; FIPS_OPTION fips_restricted_drgb_digests; FIPS_OPTION fips_signature_digest_check; FIPS_OPTION fips_hkdf_digest_check; @@ -128,6 +130,7 @@ 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_no_short_mac, 1); + init_fips_option(&fgbl->fips_hmac_key_check, 0); init_fips_option(&fgbl->fips_restricted_drgb_digests, 0); init_fips_option(&fgbl->fips_signature_digest_check, 0); init_fips_option(&fgbl->fips_hkdf_digest_check, 0); @@ -167,6 +170,7 @@ 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_NO_SHORT_MAC, OSSL_PARAM_INTEGER, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_HMAC_KEY_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), @@ -243,6 +247,8 @@ static int fips_get_params_from_core(FIPS_GLOBAL *fgbl) fips_tls1_prf_ems_check); FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_NO_SHORT_MAC, fips_no_short_mac); + FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_HMAC_KEY_CHECK, + fips_hmac_key_check); FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_DRBG_TRUNC_DIGEST, fips_restricted_drgb_digests); FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_SIGNATURE_DIGEST_CHECK, @@ -334,6 +340,8 @@ static int fips_get_params(void *provctx, OSSL_PARAM params[]) fips_tls1_prf_ems_check); FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_NO_SHORT_MAC, fips_no_short_mac); + FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_HMAC_KEY_CHECK, + fips_hmac_key_check); FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_DRBG_TRUNC_DIGEST, fips_restricted_drgb_digests); FIPS_FEATURE_GET(fgbl, OSSL_PROV_FIPS_PARAM_SIGNATURE_DIGEST_CHECK, @@ -534,6 +542,15 @@ static const OSSL_ALGORITHM fips_macs[] = { { NULL, NULL, NULL } }; +static const OSSL_ALGORITHM fips_macs_internal[] = { +#ifndef OPENSSL_NO_CMAC + { PROV_NAMES_CMAC, FIPS_DEFAULT_PROPERTIES, ossl_cmac_functions }, +#endif + { PROV_NAMES_HMAC, FIPS_DEFAULT_PROPERTIES, ossl_hmac_internal_functions }, + { PROV_NAMES_KMAC_128, FIPS_DEFAULT_PROPERTIES, ossl_kmac128_functions }, + { PROV_NAMES_KMAC_256, FIPS_DEFAULT_PROPERTIES, ossl_kmac256_functions }, +}; + static const OSSL_ALGORITHM fips_kdfs[] = { { PROV_NAMES_HKDF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_hkdf_functions }, { PROV_NAMES_TLS1_3_KDF, FIPS_DEFAULT_PROPERTIES, @@ -705,6 +722,39 @@ static const OSSL_ALGORITHM *fips_query(void *provctx, int operation_id, return NULL; } +static const OSSL_ALGORITHM *fips_query_internal(void *provctx, int operation_id, + int *no_cache) +{ + *no_cache = 0; + + if (!ossl_prov_is_running()) + return NULL; + + switch (operation_id) { + case OSSL_OP_DIGEST: + return fips_digests; + case OSSL_OP_CIPHER: + return exported_fips_ciphers; + case OSSL_OP_MAC: + return fips_macs_internal; + case OSSL_OP_KDF: + return fips_kdfs; + case OSSL_OP_RAND: + return fips_rands; + case OSSL_OP_KEYMGMT: + return fips_keymgmt; + case OSSL_OP_KEYEXCH: + return fips_keyexch; + case OSSL_OP_SIGNATURE: + return fips_signature; + case OSSL_OP_ASYM_CIPHER: + return fips_asym_cipher; + case OSSL_OP_KEM: + return fips_asym_kem; + } + return NULL; +} + static void fips_teardown(void *provctx) { OSSL_LIB_CTX_free(PROV_LIBCTX_OF(provctx)); @@ -735,7 +785,7 @@ static const OSSL_DISPATCH fips_dispatch_table[] = { /* Functions we provide to ourself */ static const OSSL_DISPATCH intern_dispatch_table[] = { { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))fips_intern_teardown }, - { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))fips_query }, + { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))fips_query_internal }, OSSL_DISPATCH_END }; @@ -934,6 +984,7 @@ 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_no_short_mac); + FIPS_SET_OPTION(fgbl, fips_hmac_key_check); FIPS_SET_OPTION(fgbl, fips_restricted_drgb_digests); FIPS_SET_OPTION(fgbl, fips_signature_digest_check); FIPS_SET_OPTION(fgbl, fips_hkdf_digest_check); @@ -1162,6 +1213,7 @@ int BIO_snprintf(char *buf, size_t n, const char *format, ...) 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_no_short_mac, fips_no_short_mac) +FIPS_FEATURE_CHECK(FIPS_hmac_key_check, fips_hmac_key_check) FIPS_FEATURE_CHECK(FIPS_restricted_drbg_digests_enabled, fips_restricted_drgb_digests) FIPS_FEATURE_CHECK(FIPS_fips_signature_digest_check, fips_signature_digest_check) diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index a2da68ed02..6199292c53 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -258,6 +258,9 @@ extern const OSSL_DISPATCH ossl_blake2smac_functions[]; extern const OSSL_DISPATCH ossl_cmac_functions[]; extern const OSSL_DISPATCH ossl_gmac_functions[]; extern const OSSL_DISPATCH ossl_hmac_functions[]; +#ifdef FIPS_MODULE +extern const OSSL_DISPATCH ossl_hmac_internal_functions[]; +#endif extern const OSSL_DISPATCH ossl_kmac128_functions[]; extern const OSSL_DISPATCH ossl_kmac256_functions[]; extern const OSSL_DISPATCH ossl_siphash_functions[]; diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c index 64a3e8f05e..e2bf3d5c3a 100644 --- a/providers/implementations/kdfs/hkdf.c +++ b/providers/implementations/kdfs/hkdf.c @@ -519,10 +519,9 @@ static int HKDF_Extract(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md, return 0; } /* calc: PRK = HMAC-Hash(salt, IKM) */ - return - EVP_Q_mac(libctx, "HMAC", NULL, EVP_MD_get0_name(evp_md), NULL, salt, - salt_len, ikm, ikm_len, prk, EVP_MD_get_size(evp_md), NULL) - != NULL; + return EVP_Q_mac(libctx, "HMAC", NULL, EVP_MD_get0_name(evp_md), NULL, salt, + salt_len, ikm, ikm_len, prk, EVP_MD_get_size(evp_md), NULL) + != NULL; } /* diff --git a/providers/implementations/macs/hmac_prov.c b/providers/implementations/macs/hmac_prov.c index c72c1e6c0f..d871a85033 100644 --- a/providers/implementations/macs/hmac_prov.c +++ b/providers/implementations/macs/hmac_prov.c @@ -20,6 +20,8 @@ #include <openssl/params.h> #include <openssl/evp.h> #include <openssl/hmac.h> +#include <openssl/proverr.h> +#include <openssl/err.h> #include "internal/ssl3_cbc.h" @@ -27,6 +29,9 @@ #include "prov/provider_ctx.h" #include "prov/provider_util.h" #include "prov/providercommon.h" +#include "prov/fipsindicator.h" +#include "prov/securitycheck.h" +#include "prov/fipscommon.h" /* * Forward declaration of everything implemented here. This is not strictly @@ -59,6 +64,15 @@ struct hmac_data_st { int tls_header_set; unsigned char tls_mac_out[EVP_MAX_MD_SIZE]; size_t tls_mac_out_size; +#ifdef FIPS_MODULE + /* + * 'internal' is set to 1 if HMAC is used inside another algorithm such as a + * KDF. In this case it is the parent algorithm that is responsible for + * performing any conditional FIPS indicator related checks for the HMAC. + */ + int internal; +#endif + OSSL_FIPS_IND_DECLARE }; static void *hmac_new(void *provctx) @@ -74,6 +88,7 @@ static void *hmac_new(void *provctx) return NULL; } macctx->provctx = provctx; + OSSL_FIPS_IND_INIT(macctx) return macctx; } @@ -144,12 +159,33 @@ static int hmac_setkey(struct hmac_data_st *macctx, { const EVP_MD *digest; +#ifdef FIPS_MODULE + /* + * KDF's pass a salt rather than a key, + * which is why it skips the key check unless "HMAC" is fetched directly. + */ + if (!macctx->internal) { + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(macctx->provctx); + int approved = ossl_mac_check_key_size(keylen); + + if (!approved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(macctx, OSSL_FIPS_IND_SETTABLE0, + libctx, "HMAC", "keysize", + FIPS_hmac_key_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + } +#endif + if (macctx->key != NULL) OPENSSL_secure_clear_free(macctx->key, macctx->keylen); /* Keep a copy of the key in case we need it for TLS HMAC */ macctx->key = OPENSSL_secure_malloc(keylen > 0 ? keylen : 1); if (macctx->key == NULL) return 0; + memcpy(macctx->key, key, keylen); macctx->keylen = keylen; @@ -235,6 +271,7 @@ static int hmac_final(void *vmacctx, unsigned char *out, size_t *outl, static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), OSSL_PARAM_size_t(OSSL_MAC_PARAM_BLOCK_SIZE, NULL), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; static const OSSL_PARAM *hmac_gettable_ctx_params(ossl_unused void *ctx, @@ -256,6 +293,17 @@ static int hmac_get_ctx_params(void *vmacctx, OSSL_PARAM params[]) && !OSSL_PARAM_set_int(p, hmac_block_size(macctx))) return 0; +#ifdef FIPS_MODULE + p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_FIPS_APPROVED_INDICATOR); + if (p != NULL) { + int approved = 0; + + if (!macctx->internal) + approved = OSSL_FIPS_IND_GET(macctx)->approved; + if (!OSSL_PARAM_set_int(p, approved)) + return 0; + } +#endif return 1; } @@ -266,6 +314,7 @@ static const OSSL_PARAM known_settable_ctx_params[] = { OSSL_PARAM_int(OSSL_MAC_PARAM_DIGEST_NOINIT, NULL), OSSL_PARAM_int(OSSL_MAC_PARAM_DIGEST_ONESHOT, NULL), OSSL_PARAM_size_t(OSSL_MAC_PARAM_TLS_DATA_SIZE, NULL), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_MAC_PARAM_FIPS_KEY_CHECK) OSSL_PARAM_END }; static const OSSL_PARAM *hmac_settable_ctx_params(ossl_unused void *ctx, @@ -286,12 +335,17 @@ static int hmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[]) if (params == NULL) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(macctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_MAC_PARAM_FIPS_KEY_CHECK)) + return 0; + if (!ossl_prov_digest_load_from_params(&macctx->digest, params, ctx)) return 0; if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL) { if (p->data_type != OSSL_PARAM_OCTET_STRING) return 0; + if (!hmac_setkey(macctx, p->data, p->data_size)) return 0; } @@ -319,3 +373,33 @@ const OSSL_DISPATCH ossl_hmac_functions[] = { { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))hmac_set_ctx_params }, OSSL_DISPATCH_END }; + +#ifdef FIPS_MODULE +static OSSL_FUNC_mac_newctx_fn hmac_internal_new; + +static void *hmac_internal_new(void *provctx) +{ + struct hmac_data_st *macctx = hmac_new(provctx); + + if (macctx != NULL) + macctx->internal = 1; + return macctx; +} + +const OSSL_DISPATCH ossl_hmac_internal_functions[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))hmac_internal_new }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))hmac_dup }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))hmac_free }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))hmac_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))hmac_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))hmac_final }, + { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, + (void (*)(void))hmac_gettable_ctx_params }, + { OSSL_FUNC_MAC_GET_CTX_PARAMS, (void (*)(void))hmac_get_ctx_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))hmac_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, (void (*)(void))hmac_set_ctx_params }, + OSSL_DISPATCH_END +}; + +#endif /* FIPS_MODULE */ diff --git a/test/evp_test.c b/test/evp_test.c index 4789438846..84e589cc7e 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -1937,8 +1937,12 @@ static int mac_test_run_mac(EVP_TEST *t) t->err = "MAC_CREATE_ERROR"; goto err; } - if (fips_provider_version_gt(libctx, 3, 2, 0)) + if (fips_provider_version_gt(libctx, 3, 2, 0)) { + /* HMAC will put an error on the stack here (digest is not set yet) */ + ERR_set_mark(); size_before_init = EVP_MAC_CTX_get_mac_size(ctx); + ERR_pop_to_mark(); + } if (!EVP_MAC_init(ctx, expected->key, expected->key_len, params)) { t->err = "MAC_INIT_ERROR"; goto err; diff --git a/test/recipes/30-test_evp_data/evpmac_common.txt b/test/recipes/30-test_evp_data/evpmac_common.txt index a7c8426dd7..d2caddbcea 100644 --- a/test/recipes/30-test_evp_data/evpmac_common.txt +++ b/test/recipes/30-test_evp_data/evpmac_common.txt @@ -262,6 +262,30 @@ Input = "Test that SHAKE128 fails" Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f Result = MAC_INIT_ERROR +Title = HMAC FIPS short key test + +# Test HMAC with key < 112 bits is not allowed +Availablein = fips +FIPSversion = >=3.4.0 +MAC = HMAC +Algorithm = SHA256 +Input = "Test Input" +Key = 0001020304 +Result = MAC_INIT_ERROR + +Title = HMAC FIPS short key indicator test + +# Test HMAC with key < 112 bits is unapproved +Availablein = fips +FIPSversion = >=3.4.0 +MAC = HMAC +Algorithm = SHA256 +Unapproved = 1 +Ctrl = key-check:0 +Input = "Test Input" +Key = 0001020304 +Output = db70da6176d87813b059879ccc27bc53e295c6eca74db8bdc4e77d7e951d894b + Title = CMAC tests (from FIPS module) MAC = CMAC diff --git a/util/mk-fipsmodule-cnf.pl b/util/mk-fipsmodule-cnf.pl index 5ff5c2de66..3fd7ee67fa 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 $no_short_mac = 1; +my $key_check = 1; my $drgb_no_trunc_dgst = 1; my $digest_check = 1; my $dsa_sign_disabled = 1; @@ -60,6 +61,7 @@ security-checks = $security_checks module-mac = $module_mac tls1-prf-ems-check = $ems_check no-short-mac = $no_short_mac +hmac-key-check = $key_check drbg-no-trunc-md = $drgb_no_trunc_dgst signature-digest-check = $digest_check dsa-sign-disabled = $dsa_sign_disabled diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm index 9117b62152..ccff1670c8 100644 --- a/util/perl/OpenSSL/paramnames.pm +++ b/util/perl/OpenSSL/paramnames.pm @@ -31,6 +31,7 @@ my %params = ( 'PROV_PARAM_BUILDINFO' => "buildinfo", # utf8_ptr 'PROV_PARAM_STATUS' => "status", # uint 'PROV_PARAM_SECURITY_CHECKS' => "security-checks", # uint + 'PROV_PARAM_HMAC_KEY_CHECK' => "hmac-key-check", # uint 'PROV_PARAM_TLS1_PRF_EMS_CHECK' => "tls1-prf-ems-check", # uint 'PROV_PARAM_NO_SHORT_MAC' => "no-short-mac", # uint 'PROV_PARAM_DRBG_TRUNC_DIGEST' => "drbg-no-trunc-md", # uint @@ -168,6 +169,7 @@ my %params = ( 'MAC_PARAM_SIZE' => "size", # size_t 'MAC_PARAM_BLOCK_SIZE' => "block-size", # size_t 'MAC_PARAM_TLS_DATA_SIZE' => "tls-data-size", # size_t + 'MAC_PARAM_FIPS_KEY_CHECK' => '*PKEY_PARAM_FIPS_KEY_CHECK', 'MAC_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR', # KDF / PRF parameters |