diff options
-rw-r--r-- | CHANGES.md | 7 | ||||
-rw-r--r-- | apps/fipsinstall.c | 24 | ||||
-rw-r--r-- | crypto/err/openssl.txt | 1 | ||||
-rw-r--r-- | doc/man1/openssl-fipsinstall.pod.in | 10 | ||||
-rw-r--r-- | doc/man7/OSSL_PROVIDER-FIPS.pod | 15 | ||||
-rw-r--r-- | include/openssl/core_names.h | 11 | ||||
-rw-r--r-- | include/openssl/fips_names.h | 8 | ||||
-rw-r--r-- | include/openssl/proverr.h | 3 | ||||
-rw-r--r-- | providers/common/include/prov/proverr.h | 2 | ||||
-rw-r--r-- | providers/common/include/prov/securitycheck.h | 1 | ||||
-rw-r--r-- | providers/common/provider_err.c | 3 | ||||
-rw-r--r-- | providers/common/securitycheck_default.c | 6 | ||||
-rw-r--r-- | providers/common/securitycheck_fips.c | 6 | ||||
-rw-r--r-- | providers/fips/fipsprov.c | 32 | ||||
-rw-r--r-- | providers/implementations/kdfs/tls1_prf.c | 26 | ||||
-rw-r--r-- | test/recipes/03-test_fipsinstall.t | 3 | ||||
-rw-r--r-- | test/recipes/90-test_sslapi.t | 103 | ||||
-rw-r--r-- | test/sslapitest.c | 58 |
18 files changed, 281 insertions, 38 deletions
diff --git a/CHANGES.md b/CHANGES.md index b5381e9847..711454ec43 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -237,6 +237,13 @@ OpenSSL 3.1 ### Changes between 3.0 and 3.1.0 [xx XXX xxxx] + * Add FIPS provider configuration option to enforce the + Extended Master Secret (EMS) check during the TLS1_PRF KDF. + The option '-ems-check' can optionally be supplied to + 'openssl fipsinstall'. + + *Shane Lontis* + * The FIPS provider includes a few non-approved algorithms for backward compatibility purposes and the "fips=yes" property query must be used for all algorithm fetches to ensure FIPS compliance. diff --git a/apps/fipsinstall.c b/apps/fipsinstall.c index 5198e0863e..2e6edc007a 100644 --- a/apps/fipsinstall.c +++ b/apps/fipsinstall.c @@ -38,6 +38,7 @@ typedef enum OPTION_choice { OPT_NO_LOG, OPT_CORRUPT_DESC, OPT_CORRUPT_TYPE, OPT_QUIET, OPT_CONFIG, OPT_NO_CONDITIONAL_ERRORS, OPT_NO_SECURITY_CHECKS, + OPT_TLS_PRF_EMS_CHECK, OPT_SELF_TEST_ONLOAD, OPT_SELF_TEST_ONINSTALL } OPTION_CHOICE; @@ -50,15 +51,17 @@ const OPTIONS fipsinstall_options[] = { {"provider_name", OPT_PROV_NAME, 's', "FIPS provider name"}, {"section_name", OPT_SECTION_NAME, 's', "FIPS Provider config section name (optional)"}, - {"no_conditional_errors", OPT_NO_CONDITIONAL_ERRORS, '-', - "Disable the ability of the fips module to enter an error state if" - " any conditional self tests fail"}, + {"no_conditional_errors", OPT_NO_CONDITIONAL_ERRORS, '-', + "Disable the ability of the fips module to enter an error state if" + " any conditional self tests fail"}, {"no_security_checks", OPT_NO_SECURITY_CHECKS, '-', "Disable the run-time FIPS security checks in the module"}, {"self_test_onload", OPT_SELF_TEST_ONLOAD, '-', "Forces self tests to always run on module load"}, {"self_test_oninstall", OPT_SELF_TEST_ONINSTALL, '-', "Forces self tests to run once on module installation"}, + {"ems_check", OPT_TLS_PRF_EMS_CHECK, '-', + "Enable the run-time FIPS check for EMS during TLS1_PRF"}, OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input config file, used when verifying"}, @@ -171,6 +174,7 @@ static int write_config_fips_section(BIO *out, const char *section, size_t module_mac_len, int conditional_errors, int security_checks, + int ems_check, unsigned char *install_mac, size_t install_mac_len) { @@ -184,6 +188,8 @@ static int write_config_fips_section(BIO *out, const char *section, conditional_errors ? "1" : "0") <= 0 || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS, security_checks ? "1" : "0") <= 0 + || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_TLS1_PRF_EMS_CHECK, + ems_check ? "1" : "0") <= 0 || !print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac, module_mac_len)) goto end; @@ -205,7 +211,8 @@ static CONF *generate_config_and_load(const char *prov_name, unsigned char *module_mac, size_t module_mac_len, int conditional_errors, - int security_checks) + int security_checks, + int ems_check) { BIO *mem_bio = NULL; CONF *conf = NULL; @@ -218,6 +225,7 @@ static CONF *generate_config_and_load(const char *prov_name, module_mac, module_mac_len, conditional_errors, security_checks, + ems_check, NULL, 0)) goto end; @@ -315,6 +323,7 @@ int fipsinstall_main(int argc, char **argv) { int ret = 1, verify = 0, gotkey = 0, gotdigest = 0, self_test_onload = 1; int enable_conditional_errors = 1, enable_security_checks = 1; + int enable_tls_prf_ems_check = 0; /* This is off by default */ const char *section_name = "fips_sect"; const char *mac_name = "HMAC"; const char *prov_name = "fips"; @@ -360,6 +369,9 @@ opthelp: case OPT_NO_SECURITY_CHECKS: enable_security_checks = 0; break; + case OPT_TLS_PRF_EMS_CHECK: + enable_tls_prf_ems_check = 1; + break; case OPT_QUIET: quiet = 1; /* FALLTHROUGH */ @@ -523,7 +535,8 @@ opthelp: conf = generate_config_and_load(prov_name, section_name, module_mac, module_mac_len, enable_conditional_errors, - enable_security_checks); + enable_security_checks, + enable_tls_prf_ems_check); if (conf == NULL) goto end; if (!load_fips_prov_and_run_self_test(prov_name)) @@ -540,6 +553,7 @@ opthelp: module_mac, module_mac_len, enable_conditional_errors, enable_security_checks, + enable_tls_prf_ems_check, install_mac, install_mac_len)) goto end; if (!quiet) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index e90e5dc033..f391e75647 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1006,6 +1006,7 @@ PROV_R_BN_ERROR:160:bn error PROV_R_CIPHER_OPERATION_FAILED:102:cipher operation failed PROV_R_DERIVATION_FUNCTION_INIT_FAILED:205:derivation function init failed PROV_R_DIGEST_NOT_ALLOWED:174:digest not allowed +PROV_R_EMS_NOT_ENABLED:233:ems not enabled PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK:186:entropy source strength too weak PROV_R_ERROR_INSTANTIATING_DRBG:188:error instantiating drbg PROV_R_ERROR_RETRIEVING_ENTROPY:189:error retrieving entropy diff --git a/doc/man1/openssl-fipsinstall.pod.in b/doc/man1/openssl-fipsinstall.pod.in index af18f361e6..8b066453f9 100644 --- a/doc/man1/openssl-fipsinstall.pod.in +++ b/doc/man1/openssl-fipsinstall.pod.in @@ -21,6 +21,7 @@ B<openssl fipsinstall> [B<-quiet>] [B<-no_conditional_errors>] [B<-no_security_checks>] +[B<-ems_check>] [B<-self_test_onload>] [B<-self_test_oninstall>] [B<-corrupt_desc> I<selftest_description>] @@ -165,6 +166,15 @@ fails as described above. Configure the module to not perform run-time security checks as described above. +Enabling the configuration option "no-fips-securitychecks" provides another way to +turn off the check at compile time. + +=item B<-ems_check> + +Configure the module to enable a run-time Extended Master Secret (EMS) check +when using the TLS1_PRF KDF algorithm. This check is disabled by default. +See RFC 7627 for information related to EMS. + =item B<-self_test_onload> Do not write the two fields related to the "test status indicator" and diff --git a/doc/man7/OSSL_PROVIDER-FIPS.pod b/doc/man7/OSSL_PROVIDER-FIPS.pod index 1e1601cef1..a18703f568 100644 --- a/doc/man7/OSSL_PROVIDER-FIPS.pod +++ b/doc/man7/OSSL_PROVIDER-FIPS.pod @@ -41,6 +41,21 @@ query. Including C<provider=fips> in your property query guarantees that the OpenSSL FIPS provider is used for cryptographic operations rather than other FIPS capable providers. +=head2 Provider parameters + +See L<provider-base(7)/Provider parameters> for a list of base parameters. +Additionally the OpenSSL FIPS provider also supports the following gettable +parameters: + +=over 4 + +=item "security-checks" (B<OSSL_OSSL_PROV_PARAM_SECURITY_CHECKS>) <unsigned integer> + +For further information refer to the L<openssl-fipsinstall(1)> option +B<-no_security_checks>. + +=back + =head1 OPERATIONS AND ALGORITHMS The OpenSSL FIPS provider supports these operations and algorithms: diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index 173a81d28b..5e5be567a5 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -21,11 +21,12 @@ extern "C" { #define OSSL_PROV_PARAM_CORE_MODULE_FILENAME "module-filename" /* utf8_ptr */ /* Well known parameter names that Providers can define */ -#define OSSL_PROV_PARAM_NAME "name" /* utf8_ptr */ -#define OSSL_PROV_PARAM_VERSION "version" /* utf8_ptr */ -#define OSSL_PROV_PARAM_BUILDINFO "buildinfo" /* utf8_ptr */ -#define OSSL_PROV_PARAM_STATUS "status" /* uint */ -#define OSSL_PROV_PARAM_SECURITY_CHECKS "security-checks" /* uint */ +#define OSSL_PROV_PARAM_NAME "name" /* utf8_ptr */ +#define OSSL_PROV_PARAM_VERSION "version" /* utf8_ptr */ +#define OSSL_PROV_PARAM_BUILDINFO "buildinfo" /* utf8_ptr */ +#define OSSL_PROV_PARAM_STATUS "status" /* uint */ +#define OSSL_PROV_PARAM_SECURITY_CHECKS "security-checks" /* uint */ +#define OSSL_PROV_PARAM_TLS1_PRF_EMS_CHECK "tls1-prf-ems-check" /* uint */ /* Self test callback parameters */ #define OSSL_PROV_PARAM_SELF_TEST_PHASE "st-phase" /* utf8_string */ diff --git a/include/openssl/fips_names.h b/include/openssl/fips_names.h index 0fdf5440c7..3f29369b3f 100644 --- a/include/openssl/fips_names.h +++ b/include/openssl/fips_names.h @@ -53,6 +53,14 @@ extern "C" { */ # define OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS "security-checks" +/* + * A boolean that determines if the runtime FIPS check for TLS1_PRF EMS is performed. + * This is disabled by default. + * + * Type: OSSL_PARAM_UTF8_STRING + */ +# define OSSL_PROV_FIPS_PARAM_TLS1_PRF_EMS_CHECK "tls1-prf-ems-check" + # ifdef __cplusplus } # endif diff --git a/include/openssl/proverr.h b/include/openssl/proverr.h index 3685430f5d..bf4dc135f5 100644 --- a/include/openssl/proverr.h +++ b/include/openssl/proverr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -32,6 +32,7 @@ # define PROV_R_CIPHER_OPERATION_FAILED 102 # define PROV_R_DERIVATION_FUNCTION_INIT_FAILED 205 # define PROV_R_DIGEST_NOT_ALLOWED 174 +# define PROV_R_EMS_NOT_ENABLED 233 # define PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK 186 # define PROV_R_ERROR_INSTANTIATING_DRBG 188 # define PROV_R_ERROR_RETRIEVING_ENTROPY 189 diff --git a/providers/common/include/prov/proverr.h b/providers/common/include/prov/proverr.h index 8ad6cc048d..69e14465c7 100644 --- a/providers/common/include/prov/proverr.h +++ b/providers/common/include/prov/proverr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy diff --git a/providers/common/include/prov/securitycheck.h b/providers/common/include/prov/securitycheck.h index 4a7f85f711..62e60cc010 100644 --- a/providers/common/include/prov/securitycheck.h +++ b/providers/common/include/prov/securitycheck.h @@ -28,3 +28,4 @@ int ossl_digest_get_approved_nid(const EVP_MD *md); int ossl_digest_rsa_sign_get_md_nid(OSSL_LIB_CTX *ctx, const EVP_MD *md, int sha1_allowed); int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx); +int ossl_tls1_prf_ems_check_enabled(OSSL_LIB_CTX *libctx); diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c index f6144072aa..954aabe80c 100644 --- a/providers/common/provider_err.c +++ b/providers/common/provider_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -33,6 +33,7 @@ static const ERR_STRING_DATA PROV_str_reasons[] = { "derivation function init failed"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_DIGEST_NOT_ALLOWED), "digest not allowed"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_EMS_NOT_ENABLED), "ems not enabled"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK), "entropy source strength too weak"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_ERROR_INSTANTIATING_DRBG), diff --git a/providers/common/securitycheck_default.c b/providers/common/securitycheck_default.c index de7f0d3a0a..63c875ecd0 100644 --- a/providers/common/securitycheck_default.c +++ b/providers/common/securitycheck_default.c @@ -22,6 +22,12 @@ 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(OSSL_LIB_CTX *ctx, const EVP_MD *md, ossl_unused int sha1_allowed) { diff --git a/providers/common/securitycheck_fips.c b/providers/common/securitycheck_fips.c index b7659bd395..2bc8a59926 100644 --- a/providers/common/securitycheck_fips.c +++ b/providers/common/securitycheck_fips.c @@ -20,6 +20,7 @@ #include "prov/securitycheck.h" int FIPS_security_check_enabled(OSSL_LIB_CTX *libctx); +int FIPS_tls_prf_ems_check(OSSL_LIB_CTX *libctx); int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx) { @@ -30,6 +31,11 @@ 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(OSSL_LIB_CTX *ctx, const EVP_MD *md, int sha1_allowed) { diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index ab58ab891d..a16c379fba 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -47,6 +47,7 @@ static OSSL_FUNC_provider_query_operation_fn fips_query; extern OSSL_FUNC_core_thread_start_fn *c_thread_start; int FIPS_security_check_enabled(OSSL_LIB_CTX *libctx); +int FIPS_tls_prf_ems_check(OSSL_LIB_CTX *libctx); /* * Should these function pointers be stored in the provider side provctx? Could @@ -82,7 +83,9 @@ typedef struct fips_global_st { const OSSL_CORE_HANDLE *handle; SELF_TEST_POST_PARAMS selftest_params; int fips_security_checks; + int fips_tls1_prf_ems_check; const char *fips_security_check_option; + const char *fips_tls1_prf_ems_check_option; } FIPS_GLOBAL; void *ossl_fips_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx) @@ -94,6 +97,9 @@ void *ossl_fips_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx) fgbl->fips_security_checks = 1; fgbl->fips_security_check_option = "1"; + fgbl->fips_tls1_prf_ems_check = 0; /* Disabled by default */ + fgbl->fips_tls1_prf_ems_check_option = "0"; + return fgbl; } @@ -109,6 +115,7 @@ static const OSSL_PARAM fips_param_types[] = { OSSL_PARAM_DEFN(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR, NULL, 0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_INTEGER, NULL, 0), 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_END }; @@ -119,9 +126,10 @@ static int fips_get_params_from_core(FIPS_GLOBAL *fgbl) * NOTE: inside core_get_params() these will be loaded from config items * stored inside prov->parameters (except for * OSSL_PROV_PARAM_CORE_MODULE_FILENAME). - * OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS is not a self test parameter. + * OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS and + * OSSL_PROV_FIPS_PARAM_TLS1_PRF_EMS_CHECK are not self test parameters. */ - OSSL_PARAM core_params[8], *p = core_params; + OSSL_PARAM core_params[9], *p = core_params; *p++ = OSSL_PARAM_construct_utf8_ptr( OSSL_PROV_PARAM_CORE_MODULE_FILENAME, @@ -151,6 +159,10 @@ static int fips_get_params_from_core(FIPS_GLOBAL *fgbl) OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS, (char **)&fgbl->fips_security_check_option, sizeof(fgbl->fips_security_check_option)); + *p++ = OSSL_PARAM_construct_utf8_ptr( + OSSL_PROV_FIPS_PARAM_TLS1_PRF_EMS_CHECK, + (char **)&fgbl->fips_tls1_prf_ems_check_option, + sizeof(fgbl->fips_tls1_prf_ems_check_option)); *p = OSSL_PARAM_construct_end(); if (!c_get_params(fgbl->handle, core_params)) { @@ -187,6 +199,9 @@ static int fips_get_params(void *provctx, OSSL_PARAM params[]) p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_SECURITY_CHECKS); if (p != NULL && !OSSL_PARAM_set_int(p, fgbl->fips_security_checks)) return 0; + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_TLS1_PRF_EMS_CHECK); + if (p != NULL && !OSSL_PARAM_set_int(p, fgbl->fips_tls1_prf_ems_check)) + return 0; return 1; } @@ -698,6 +713,11 @@ int OSSL_provider_init_int(const OSSL_CORE_HANDLE *handle, && strcmp(fgbl->fips_security_check_option, "0") == 0) fgbl->fips_security_checks = 0; + /* Enable the ems check if it's enabled in the fips config file. */ + if (fgbl->fips_tls1_prf_ems_check_option != NULL + && strcmp(fgbl->fips_tls1_prf_ems_check_option, "1") == 0) + fgbl->fips_tls1_prf_ems_check = 1; + ossl_prov_cache_exported_algorithms(fips_ciphers, exported_fips_ciphers); if (!SELF_TEST_post(&fgbl->selftest_params, 0)) { @@ -893,6 +913,14 @@ int FIPS_security_check_enabled(OSSL_LIB_CTX *libctx) return fgbl->fips_security_checks; } +int FIPS_tls_prf_ems_check(OSSL_LIB_CTX *libctx) +{ + FIPS_GLOBAL *fgbl = ossl_lib_ctx_get_data(libctx, + OSSL_LIB_CTX_FIPS_PROV_INDEX); + + return fgbl->fips_tls1_prf_ems_check; +} + void OSSL_SELF_TEST_get_callback(OSSL_LIB_CTX *libctx, OSSL_CALLBACK **cb, void **cbarg) { diff --git a/providers/implementations/kdfs/tls1_prf.c b/providers/implementations/kdfs/tls1_prf.c index 8a38073084..2c2dbf31cc 100644 --- a/providers/implementations/kdfs/tls1_prf.c +++ b/providers/implementations/kdfs/tls1_prf.c @@ -45,6 +45,13 @@ * A(0) = seed * A(i) = HMAC_<hash>(secret, A(i-1)) */ + +/* + * Low level APIs (such as DH) are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> #include <stdarg.h> #include <string.h> @@ -60,6 +67,7 @@ #include "prov/providercommon.h" #include "prov/implementations.h" #include "prov/provider_util.h" +#include "prov/securitycheck.h" #include "internal/e_os.h" static OSSL_FUNC_kdf_newctx_fn kdf_tls1_prf_new; @@ -78,6 +86,8 @@ static int tls1_prf_alg(EVP_MAC_CTX *mdctx, EVP_MAC_CTX *sha1ctx, unsigned char *out, size_t olen); #define TLS1_PRF_MAXBUF 1024 +#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" +#define TLS_MD_MASTER_SECRET_CONST_SIZE 13 /* TLS KDF kdf context structure */ typedef struct { @@ -160,6 +170,7 @@ static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { TLS1_PRF *ctx = (TLS1_PRF *)vctx; + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); if (!ossl_prov_is_running() || !kdf_tls1_prf_set_ctx_params(ctx, params)) return 0; @@ -181,6 +192,21 @@ static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, return 0; } + /* + * The seed buffer is prepended with a label. + * If EMS mode is enforced then the label "master secret" is not allowed, + * We do the check this way since the PRF is used for other purposes, as well + * as "extended master secret". + */ + if (ossl_tls1_prf_ems_check_enabled(libctx)) { + if (ctx->seedlen >= TLS_MD_MASTER_SECRET_CONST_SIZE + && memcmp(ctx->seed, TLS_MD_MASTER_SECRET_CONST, + TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_EMS_NOT_ENABLED); + return 0; + } + } + return tls1_prf_alg(ctx->P_hash, ctx->P_sha1, ctx->sec, ctx->seclen, ctx->seed, ctx->seedlen, diff --git a/test/recipes/03-test_fipsinstall.t b/test/recipes/03-test_fipsinstall.t index 812210e471..10a2fcaffa 100644 --- a/test/recipes/03-test_fipsinstall.t +++ b/test/recipes/03-test_fipsinstall.t @@ -347,6 +347,7 @@ SKIP: { ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile, '-provider_name', 'fips', '-mac_name', 'HMAC', '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey", - '-section_name', 'fips_sect', '-self_test_oninstall'])), + '-section_name', 'fips_sect', '-self_test_oninstall', + '-ems_check'])), "fipsinstall fails when attempting to run self tests on install"); } diff --git a/test/recipes/90-test_sslapi.t b/test/recipes/90-test_sslapi.t index 70fa7e50e2..70d789d6c4 100644 --- a/test/recipes/90-test_sslapi.t +++ b/test/recipes/90-test_sslapi.t @@ -1,12 +1,11 @@ #! /usr/bin/env perl -# Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html - use OpenSSL::Test::Utils; use OpenSSL::Test qw/:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file/; use File::Temp qw(tempfile); @@ -19,13 +18,22 @@ use lib srctop_dir('Configurations'); use lib bldtop_dir('.'); my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0); +my $fipsmodcfg_filename = "fipsmodule.cnf"; +my $fipsmodcfg = bldtop_file("providers", $fipsmodcfg_filename); + +my $provconf = srctop_file("test", "fips-and-base.cnf"); + +# A modified copy of "fipsmodule.cnf" +my $fipsmodcfgnew_filename = "fipsmodule_mod.cnf"; +my $fipsmodcfgnew = bldtop_file("test", $fipsmodcfgnew_filename); + +# A modified copy of "fips-and-base.cnf" +my $provconfnew = bldtop_file("test", "temp.cnf"); plan skip_all => "No TLS/SSL protocols are supported by this OpenSSL build" if alldisabled(grep { $_ ne "ssl3" } available_protocols("tls")); -plan tests => - ($no_fips ? 0 : 1) # sslapitest with fips - + 1; # sslapitest with default provider +plan tests => 3; (undef, my $tmpfilename) = tempfile(); @@ -39,16 +47,97 @@ ok(run(test(["sslapitest", srctop_dir("test", "certs"), "dhparams.pem")])), "running sslapitest"); -unless ($no_fips) { +SKIP: { + skip "Skipping FIPS tests", 2 + if $no_fips; + ok(run(test(["sslapitest", srctop_dir("test", "certs"), srctop_file("test", "recipes", "90-test_sslapi_data", "passwd.txt"), $tmpfilename, "fips", - srctop_file("test", "fips-and-base.cnf"), + $provconf, srctop_file("test", "recipes", "90-test_sslapi_data", "dhparams.pem")])), "running sslapitest"); + + run(test(["fips_version_test", "-config", $provconf, ">=3.1.0"]), + capture => 1, statusvar => \my $exit); + + skip "FIPS provider version is too old for TLS_PRF EMS option test", 1 + if !$exit; + + # Read in a text $infile and replace the regular expression in $srch with the + # value in $repl and output to a new file $outfile. + sub replace_line_file_internal { + + my ($infile, $srch, $repl, $outfile) = @_; + my $msg; + + open(my $in, "<", $infile) or return 0; + read($in, $msg, 1024); + close $in; + + $msg =~ s/$srch/$repl/; + + open(my $fh, ">", $outfile) or return 0; + print $fh $msg; + close $fh; + return 1; + } + + # Read in the text input file $infile + # and replace a single Key = Value line with a new value in $value. + # OR remove the Key = Value line if the passed in $value is empty. + # and then output a new file $outfile. + # $key is the Key to find + sub replace_kv_file { + my ($infile, $key, $value, $outfile) = @_; + my $srch = qr/$key\s*=\s*\S*\n/; + my $rep; + if ($value eq "") { + $rep = ""; + } else { + $rep = "$key = $value\n"; + } + return replace_line_file_internal($infile, $srch, $rep, $outfile); + } + + # Read in the text $input file + # and search for the $key and replace with $newkey + # and then output a new file $outfile. + sub replace_line_file { + my ($infile, $key, $newkey, $outfile) = @_; + my $srch = qr/$key/; + my $rep = "$newkey"; + return replace_line_file_internal($infile, + $srch, $rep, $outfile); + } + + # In order to enable the tls1-prf-ems-check=1 in a fips config file + # copy the existing fipsmodule.cnf and modify it. + # Then copy fips-and-base.cfg to make a file that includes the changed file + # NOTE that this just runs test_no_ems() to check that the connection + # fails if ems is not used and the fips check is enabled. + ok(replace_kv_file($fipsmodcfg, + 'tls1-prf-ems-check', '1', + $fipsmodcfgnew) + && replace_line_file($provconf, + $fipsmodcfg_filename, $fipsmodcfgnew_filename, + $provconfnew) + && run(test(["sslapitest", srctop_dir("test", "certs"), + srctop_file("test", "recipes", "90-test_sslapi_data", + "passwd.txt"), + $tmpfilename, "fips", + $provconfnew, + srctop_file("test", + "recipes", + "90-test_sslapi_data", + "dhparams.pem")])), + "running sslapitest"); + + unlink $fipsmodcfgnew; + unlink $provconfnew; } unlink $tmpfilename; diff --git a/test/sslapitest.c b/test/sslapitest.c index 585260950a..102b590aae 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -99,6 +99,7 @@ static char *tmpfilename = NULL; static char *dhfile = NULL; static int is_fips = 0; +static int fips_ems_check = 0; #define LOG_BUFFER_SIZE 2048 static char server_log_buffer[LOG_BUFFER_SIZE + 1] = {0}; @@ -796,7 +797,7 @@ static int test_no_ems(void) { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; - int testresult = 0; + int testresult = 0, status; if (!create_ssl_ctx_pair(libctx, TLS_server_method(), TLS_client_method(), TLS1_VERSION, TLS1_2_VERSION, @@ -812,19 +813,25 @@ static int test_no_ems(void) goto end; } - if (!create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) { - printf("Creating SSL connection failed\n"); - goto end; - } - - if (SSL_get_extms_support(serverssl)) { - printf("Server reports Extended Master Secret support\n"); - goto end; - } - - if (SSL_get_extms_support(clientssl)) { - printf("Client reports Extended Master Secret support\n"); - goto end; + status = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE); + if (fips_ems_check) { + if (status == 1) { + printf("When FIPS uses the EMS check a connection that doesnt use EMS should fail\n"); + goto end; + } + } else { + if (!status) { + printf("Creating SSL connection failed\n"); + goto end; + } + if (SSL_get_extms_support(serverssl)) { + printf("Server reports Extended Master Secret support\n"); + goto end; + } + if (SSL_get_extms_support(clientssl)) { + printf("Client reports Extended Master Secret support\n"); + goto end; + } } testresult = 1; @@ -10848,9 +10855,24 @@ int setup_tests(void) && !TEST_false(OSSL_PROVIDER_available(libctx, "default"))) return 0; - if (strcmp(modulename, "fips") == 0) + if (strcmp(modulename, "fips") == 0) { + OSSL_PROVIDER *prov = NULL; + OSSL_PARAM params[2]; + is_fips = 1; + prov = OSSL_PROVIDER_load(libctx, "fips"); + if (prov != NULL) { + /* Query the fips provider to check if the check ems option is enabled */ + params[0] = + OSSL_PARAM_construct_int(OSSL_PROV_PARAM_TLS1_PRF_EMS_CHECK, + &fips_ems_check); + params[1] = OSSL_PARAM_construct_end(); + OSSL_PROVIDER_get_params(prov, params); + OSSL_PROVIDER_unload(prov); + } + } + /* * We add, but don't load the test "tls-provider". We'll load it when we * need it. @@ -10924,6 +10946,12 @@ int setup_tests(void) if (privkey8192 == NULL) goto err; + if (fips_ems_check) { +#ifndef OPENSSL_NO_TLS1_2 + ADD_TEST(test_no_ems); +#endif + return 1; + } #if !defined(OPENSSL_NO_KTLS) && !defined(OPENSSL_NO_SOCK) # if !defined(OPENSSL_NO_TLS1_2) || !defined(OSSL_NO_USABLE_TLS1_3) ADD_ALL_TESTS(test_ktls, NUM_KTLS_TEST_CIPHERS * 4); |