From bc43158797a7f8bc36cb736524bf812db7d8635e Mon Sep 17 00:00:00 2001 From: slontis Date: Mon, 22 Jul 2024 17:24:53 +1000 Subject: [PATCH] Add FIPS indicator support for Triple-DES encryption. This leaves 3DES with the FIPS query "FIPS=yes", which allows Triple-DES to be used for Decryption by default. Disallow CMAC using Triple-DES in FIPS. This does not use a FIPS indicator. Reviewed-by: Neil Horman Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/24960) --- apps/fipsinstall.c | 11 ++++ doc/man1/openssl-fipsinstall.pod.in | 7 +++ doc/man3/EVP_EncryptInit.pod | 16 +++++ doc/man7/EVP_CIPHER-DES.pod | 2 +- include/openssl/fips_names.h | 8 +++ providers/common/include/prov/fipscommon.h | 1 + providers/fips/fipsprov.c | 21 ++++--- .../implementations/ciphers/cipher_tdes.h | 8 ++- .../ciphers/cipher_tdes_common.c | 48 ++++++++++++-- providers/implementations/macs/cmac_prov.c | 13 ++++ test/evp_libctx_test.c | 14 ++++- test/evp_test.c | 62 ++++++++++++++----- .../30-test_evp_data/evpciph_des3_common.txt | 44 +++++++++++++ .../30-test_evp_data/evpmac_cmac_des.txt | 3 +- test/recipes/80-test_cms.t | 2 +- util/mk-fipsmodule-cnf.pl | 4 +- util/perl/OpenSSL/paramnames.pm | 3 + 17 files changed, 230 insertions(+), 37 deletions(-) diff --git a/apps/fipsinstall.c b/apps/fipsinstall.c index 3b7d0819ec..5c585da4f2 100644 --- a/apps/fipsinstall.c +++ b/apps/fipsinstall.c @@ -47,6 +47,7 @@ typedef enum OPTION_choice { OPT_SSKDF_DIGEST_CHECK, OPT_X963KDF_DIGEST_CHECK, OPT_DISALLOW_DSA_SIGN, + OPT_DISALLOW_TDES_ENCRYPT, OPT_SELF_TEST_ONLOAD, OPT_SELF_TEST_ONINSTALL } OPTION_CHOICE; @@ -88,6 +89,8 @@ const OPTIONS fipsinstall_options[] = { "Enable digest check for X963KDF"}, {"dsa_sign_disabled", OPT_DISALLOW_DSA_SIGN, '-', "Disallow DSA signing"}, + {"tdes_encrypt_disabled", OPT_DISALLOW_TDES_ENCRYPT, '-', + "Disallow Triple-DES encryption"}, OPT_SECTION("Input"), {"in", OPT_IN, '<', "Input config file, used when verifying"}, @@ -118,6 +121,7 @@ typedef struct { unsigned int sskdf_digest_check : 1; unsigned int x963kdf_digest_check : 1; unsigned int dsa_sign_disabled : 1; + unsigned int tdes_encrypt_disabled : 1; } FIPS_OPTS; /* Pedantic FIPS compliance */ @@ -135,6 +139,7 @@ static const FIPS_OPTS pedantic_opts = { 1, /* sskdf_digest_check */ 1, /* x963kdf_digest_check */ 1, /* dsa_sign_disabled */ + 1, /* tdes_encrypt_disabled */ }; /* Default FIPS settings for backward compatibility */ @@ -152,6 +157,7 @@ static FIPS_OPTS fips_opts = { 0, /* sskdf_digest_check */ 0, /* x963kdf_digest_check */ 0, /* dsa_sign_disabled */ + 0, /* tdes_encrypt_disabled */ }; static int check_non_pedantic_fips(int pedantic, const char *name) @@ -295,6 +301,8 @@ static int write_config_fips_section(BIO *out, const char *section, opts->x963kdf_digest_check ? "1": "0") <= 0 || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_DSA_SIGN_DISABLED, opts->dsa_sign_disabled ? "1" : "0") <= 0 + || BIO_printf(out, "%s = %s\n", OSSL_PROV_PARAM_TDES_ENCRYPT_DISABLED, + opts->tdes_encrypt_disabled ? "1" : "0") <= 0 || !print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac, module_mac_len)) goto end; @@ -505,6 +513,9 @@ int fipsinstall_main(int argc, char **argv) case OPT_DISALLOW_DSA_SIGN: fips_opts.dsa_sign_disabled = 1; break; + case OPT_DISALLOW_TDES_ENCRYPT: + fips_opts.tdes_encrypt_disabled = 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 0524c0fef1..e9d6d140f1 100644 --- a/doc/man1/openssl-fipsinstall.pod.in +++ b/doc/man1/openssl-fipsinstall.pod.in @@ -32,6 +32,7 @@ B [B<-x963kdf_digest_check>] [B<-dsa_sign_disabled>] [B<-no_short_mac>] +[B<-tdes_encrypt_disabled>] [B<-self_test_onload>] [B<-self_test_oninstall>] [B<-corrupt_desc> I] @@ -244,6 +245,12 @@ See NIST SP 800-131Ar2 for details. Configure the module to not allow DSA signing (DSA signature verification is still allowed). See FIPS 140-3 IG C.K for details. +=item B<-tdes_encrypt_disabled> + +Configure the module to not allow Triple-DES encryption. +Triple-DES decryption is still allowed for legacy purposes. +See SP800-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/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod index f89fc9ae05..41b5e10777 100644 --- a/doc/man3/EVP_EncryptInit.pod +++ b/doc/man3/EVP_EncryptInit.pod @@ -893,6 +893,12 @@ Gets the result of running the "tls1multi_aad" operation. Used to pass the TLS MAC data. +=item "fips-indicator" (B) + +A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. +This may be used after calling a cipher final operation such as +EVP_EncryptFinal_ex(). It may return 0 if the "encrypt-check" option is set to 0. + =back =head2 Settable EVP_CIPHER_CTX parameters @@ -1039,6 +1045,16 @@ The IEEE Std. 1619-2007 variant of SM4-XTS algorithm. The default value is "GB". +=item "encrypt-check" (B) + +If required this parameter should be set early via an cipher encrypt init +function such as EVP_EncryptInit_ex2(). +The default value of 1 causes an error when an encryption operation is triggered. +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 =head1 CONTROLS diff --git a/doc/man7/EVP_CIPHER-DES.pod b/doc/man7/EVP_CIPHER-DES.pod index 25603f6fc6..3f17723704 100644 --- a/doc/man7/EVP_CIPHER-DES.pod +++ b/doc/man7/EVP_CIPHER-DES.pod @@ -59,7 +59,7 @@ The following algorithms are available in the legacy provider: =head2 Parameters This implementation supports the parameters described in -L. +L including "encrypt-check" and "fips-indicator". =head1 SEE ALSO diff --git a/include/openssl/fips_names.h b/include/openssl/fips_names.h index c72c639007..bdc667d65c 100644 --- a/include/openssl/fips_names.h +++ b/include/openssl/fips_names.h @@ -133,6 +133,14 @@ extern "C" { */ # define OSSL_PROV_FIPS_PARAM_DSA_SIGN_DISABLED "dsa-sign-disabled" +/* + * A boolean that determines if Triple-DES encryption operations are allowed. + * See SP800-131A r2 for further information. + * This is disabled by default. + * Type: OSSL_PARAM_UTF8_STRING + */ +# define OSSL_PROV_FIPS_PARAM_TDES_ENCRYPT_DISABLED "tdes-encrypt-disabled" + # ifdef __cplusplus } # endif diff --git a/providers/common/include/prov/fipscommon.h b/providers/common/include/prov/fipscommon.h index 8468fa7825..43a92a4f3d 100644 --- a/providers/common/include/prov/fipscommon.h +++ b/providers/common/include/prov/fipscommon.h @@ -21,5 +21,6 @@ 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); int FIPS_dsa_sign_check(OSSL_LIB_CTX *libctx); +int FIPS_tdes_encrypt_check(OSSL_LIB_CTX *libctx); #endif diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 31fb3338a1..b844d293ac 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -42,10 +42,7 @@ static OSSL_FUNC_provider_query_operation_fn fips_query; #define ALGC(NAMES, FUNC, CHECK) \ { { NAMES, FIPS_DEFAULT_PROPERTIES, FUNC }, CHECK } -#define UNAPPROVED_ALGC(NAMES, FUNC, CHECK) \ - { { NAMES, FIPS_UNAPPROVED_PROPERTIES, FUNC }, CHECK } #define ALG(NAMES, FUNC) ALGC(NAMES, FUNC, NULL) -#define UNAPPROVED_ALG(NAMES, FUNC) UNAPPROVED_ALGC(NAMES, FUNC, NULL) extern OSSL_FUNC_core_thread_start_fn *c_thread_start; @@ -99,6 +96,7 @@ typedef struct fips_global_st { FIPS_OPTION fips_sskdf_digest_check; FIPS_OPTION fips_x963kdf_digest_check; FIPS_OPTION fips_dsa_sign_disallowed; + FIPS_OPTION fips_tdes_encrypt_disallowed; } FIPS_GLOBAL; static void init_fips_option(FIPS_OPTION *opt, int enabled) @@ -124,6 +122,7 @@ void *ossl_fips_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx) init_fips_option(&fgbl->fips_sskdf_digest_check, 0); init_fips_option(&fgbl->fips_x963kdf_digest_check, 0); init_fips_option(&fgbl->fips_dsa_sign_disallowed, 0); + init_fips_option(&fgbl->fips_tdes_encrypt_disallowed, 0); return fgbl; } @@ -154,8 +153,10 @@ static const OSSL_PARAM fips_param_types[] = { NULL, 0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_X963KDF_DIGEST_CHECK, OSSL_PARAM_INTEGER, NULL, 0), - OSSL_PARAM_DEFN(OSSL_PROV_PARAM_DSA_SIGN_DISABLED, - OSSL_PARAM_INTEGER, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_DSA_SIGN_DISABLED, OSSL_PARAM_INTEGER, + NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_TDES_ENCRYPT_DISABLED, OSSL_PARAM_INTEGER, + NULL, 0), OSSL_PARAM_END }; @@ -224,6 +225,8 @@ static int fips_get_params_from_core(FIPS_GLOBAL *fgbl) fips_x963kdf_digest_check); FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_DSA_SIGN_DISABLED, fips_dsa_sign_disallowed); + FIPS_FEATURE_OPTION(fgbl, OSSL_PROV_FIPS_PARAM_TDES_ENCRYPT_DISABLED, + fips_tdes_encrypt_disallowed); #undef FIPS_FEATURE_OPTION *p = OSSL_PARAM_construct_end(); @@ -287,6 +290,8 @@ static int fips_get_params(void *provctx, OSSL_PARAM params[]) fips_x963kdf_digest_check); FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_DSA_SIGN_DISABLED, fips_dsa_sign_disallowed); + FIPS_FEATURE_GET(fgbl, OSSL_PROV_PARAM_TDES_ENCRYPT_DISABLED, + fips_tdes_encrypt_disallowed); #undef FIPS_FEATURE_GET return 1; } @@ -425,8 +430,8 @@ static const OSSL_ALGORITHM_CAPABLE fips_ciphers[] = { ALGC(PROV_NAMES_AES_256_CBC_HMAC_SHA256, ossl_aes256cbc_hmac_sha256_functions, ossl_cipher_capable_aes_cbc_hmac_sha256), #ifndef OPENSSL_NO_DES - UNAPPROVED_ALG(PROV_NAMES_DES_EDE3_ECB, ossl_tdes_ede3_ecb_functions), - UNAPPROVED_ALG(PROV_NAMES_DES_EDE3_CBC, ossl_tdes_ede3_cbc_functions), + ALG(PROV_NAMES_DES_EDE3_ECB, ossl_tdes_ede3_ecb_functions), + ALG(PROV_NAMES_DES_EDE3_CBC, ossl_tdes_ede3_cbc_functions), #endif /* OPENSSL_NO_DES */ { { NULL, NULL, NULL }, NULL } }; @@ -829,6 +834,7 @@ int OSSL_provider_init_int(const OSSL_CORE_HANDLE *handle, FIPS_SET_OPTION(fgbl, fips_sskdf_digest_check); FIPS_SET_OPTION(fgbl, fips_x963kdf_digest_check); FIPS_SET_OPTION(fgbl, fips_dsa_sign_disallowed); + FIPS_SET_OPTION(fgbl, fips_tdes_encrypt_disallowed); #undef FIPS_SET_OPTION ossl_prov_cache_exported_algorithms(fips_ciphers, exported_fips_ciphers); @@ -1038,6 +1044,7 @@ 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) FIPS_FEATURE_CHECK(FIPS_dsa_sign_check, fips_dsa_sign_disallowed) +FIPS_FEATURE_CHECK(FIPS_tdes_encrypt_check, fips_tdes_encrypt_disallowed) #undef FIPS_FEATURE_CHECK diff --git a/providers/implementations/ciphers/cipher_tdes.h b/providers/implementations/ciphers/cipher_tdes.h index 3c98ed241d..765ec8b5e1 100644 --- a/providers/implementations/ciphers/cipher_tdes.h +++ b/providers/implementations/ciphers/cipher_tdes.h @@ -10,6 +10,7 @@ #include #include #include "crypto/des_platform.h" +#include "prov/fipsindicator.h" #define DES_BLOCK_SIZE 8 #define TDES_IVLEN 8 @@ -25,6 +26,7 @@ typedef struct prov_tdes_ctx_st { void (*cbc) (const void *, void *, size_t, const DES_key_schedule *, unsigned char *); } tstream; + OSSL_FIPS_IND_DECLARE } PROV_TDES_CTX; @@ -64,9 +66,9 @@ const OSSL_DISPATCH ossl_tdes_##type##_##lcmode##_functions[] = { \ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ (void (*)(void))ossl_tdes_gettable_ctx_params }, \ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ - (void (*)(void))ossl_cipher_generic_set_ctx_params }, \ + (void (*)(void))ossl_tdes_set_ctx_params }, \ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ - (void (*)(void))ossl_cipher_generic_settable_ctx_params }, \ + (void (*)(void))ossl_tdes_settable_ctx_params }, \ OSSL_DISPATCH_END \ } @@ -78,6 +80,8 @@ OSSL_FUNC_cipher_encrypt_init_fn ossl_tdes_einit; OSSL_FUNC_cipher_decrypt_init_fn ossl_tdes_dinit; OSSL_FUNC_cipher_get_ctx_params_fn ossl_tdes_get_ctx_params; OSSL_FUNC_cipher_gettable_ctx_params_fn ossl_tdes_gettable_ctx_params; +OSSL_FUNC_cipher_set_ctx_params_fn ossl_tdes_set_ctx_params; +OSSL_FUNC_cipher_settable_ctx_params_fn ossl_tdes_settable_ctx_params; #define PROV_CIPHER_HW_tdes_mode(type, mode) \ static const PROV_CIPHER_HW type##_##mode = { \ diff --git a/providers/implementations/ciphers/cipher_tdes_common.c b/providers/implementations/ciphers/cipher_tdes_common.c index c80d9f16b1..1c7572c77d 100644 --- a/providers/implementations/ciphers/cipher_tdes_common.c +++ b/providers/implementations/ciphers/cipher_tdes_common.c @@ -19,6 +19,7 @@ #include "cipher_tdes.h" #include "prov/implementations.h" #include "prov/providercommon.h" +#include "prov/fipscommon.h" void *ossl_tdes_newctx(void *provctx, int mode, size_t kbits, size_t blkbits, size_t ivbits, uint64_t flags, const PROV_CIPHER_HW *hw) @@ -29,9 +30,11 @@ void *ossl_tdes_newctx(void *provctx, int mode, size_t kbits, size_t blkbits, return NULL; tctx = OPENSSL_zalloc(sizeof(*tctx)); - if (tctx != NULL) + if (tctx != NULL) { + OSSL_FIPS_IND_INIT(tctx) ossl_cipher_generic_initkey(tctx, kbits, blkbits, ivbits, mode, flags, hw, provctx); + } return tctx; } @@ -46,6 +49,7 @@ void *ossl_tdes_dupctx(void *ctx) ret = OPENSSL_malloc(sizeof(*ret)); if (ret == NULL) return NULL; + OSSL_FIPS_IND_COPY(ret, in) in->base.hw->copyctx(&ret->base, &in->base); return ret; @@ -59,6 +63,19 @@ void ossl_tdes_freectx(void *vctx) OPENSSL_clear_free(ctx, sizeof(*ctx)); } +#ifdef FIPS_MODULE +static int tdes_encrypt_check_approved(PROV_TDES_CTX *ctx, int enc) +{ + /* Triple-DES encryption is not approved in FIPS 140-3 */ + if (enc && !OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + ctx->base.libctx, + "Triple-DES", "Encryption", + FIPS_tdes_encrypt_check)) + return 0; + return 1; +} +#endif + static int tdes_init(void *vctx, const unsigned char *key, size_t keylen, const unsigned char *iv, size_t ivlen, const OSSL_PARAM params[], int enc) @@ -92,7 +109,13 @@ static int tdes_init(void *vctx, const unsigned char *key, size_t keylen, return 0; ctx->key_set = 1; } - return ossl_cipher_generic_set_ctx_params(ctx, params); + if (!ossl_tdes_set_ctx_params(ctx, params)) + return 0; +#ifdef FIPS_MODULE + if (!tdes_encrypt_check_approved((PROV_TDES_CTX *)ctx, enc)) + return 0; +#endif + return 1; } int ossl_tdes_einit(void *vctx, const unsigned char *key, size_t keylen, @@ -111,11 +134,11 @@ int ossl_tdes_dinit(void *vctx, const unsigned char *key, size_t keylen, CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(ossl_tdes) OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_RANDOM_KEY, NULL, 0), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(ossl_tdes) static int tdes_generatekey(PROV_CIPHER_CTX *ctx, void *ptr) { - DES_cblock *deskey = ptr; size_t kl = ctx->keylen; @@ -132,7 +155,7 @@ static int tdes_generatekey(PROV_CIPHER_CTX *ctx, void *ptr) int ossl_tdes_get_ctx_params(void *vctx, OSSL_PARAM params[]) { - PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; + PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; OSSL_PARAM *p; if (!ossl_cipher_generic_get_ctx_params(vctx, params)) @@ -143,5 +166,22 @@ int ossl_tdes_get_ctx_params(void *vctx, OSSL_PARAM params[]) ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY); return 0; } + if (!OSSL_FIPS_IND_GET_CTX_PARAM((PROV_TDES_CTX *)vctx, params)) + return 0; return 1; } + +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(ossl_tdes) + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_PADDING, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK) +CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(ossl_tdes) + +int ossl_tdes_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + if (!OSSL_FIPS_IND_SET_CTX_PARAM((PROV_TDES_CTX *)vctx, + OSSL_FIPS_IND_SETTABLE0, params, + OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK)) + return 0; + return ossl_cipher_generic_set_ctx_params(vctx, params); +} diff --git a/providers/implementations/macs/cmac_prov.c b/providers/implementations/macs/cmac_prov.c index fa0b576b97..ec7be448eb 100644 --- a/providers/implementations/macs/cmac_prov.c +++ b/providers/implementations/macs/cmac_prov.c @@ -210,6 +210,19 @@ static int cmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[]) ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); return 0; } +#ifdef FIPS_MODULE + { + const EVP_CIPHER *cipher = ossl_prov_cipher_cipher(&macctx->cipher); + int approved = EVP_CIPHER_is_a(cipher, "AES-256-CBC") + || EVP_CIPHER_is_a(cipher, "AES-192-CBC") + || EVP_CIPHER_is_a(cipher, "AES-128-CBC"); + + if (!approved) { + ERR_raise(ERR_LIB_PROV, EVP_R_UNSUPPORTED_CIPHER); + return 0; + } + } +#endif } if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY)) != NULL) { diff --git a/test/evp_libctx_test.c b/test/evp_libctx_test.c index 3ca25d12f7..35a1127193 100644 --- a/test/evp_libctx_test.c +++ b/test/evp_libctx_test.c @@ -21,6 +21,7 @@ */ #include "internal/deprecated.h" #include +#include #include #include #include @@ -398,7 +399,6 @@ static int test_cipher_reinit(int test_id) /* DES3-WRAP uses random every update - so it will give a different value */ diff = EVP_CIPHER_is_a(cipher, "DES3-WRAP"); - if (!TEST_true(EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv)) || !TEST_true(EVP_EncryptUpdate(ctx, out1, &out1_len, in, sizeof(in))) || !TEST_true(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) @@ -519,7 +519,6 @@ err: return ret; } - static int name_cmp(const char * const *a, const char * const *b) { return OPENSSL_strcasecmp(*a, *b); @@ -531,6 +530,10 @@ static void collect_cipher_names(EVP_CIPHER *cipher, void *cipher_names_list) const char *name = EVP_CIPHER_get0_name(cipher); char *namedup = NULL; + /* Skip Triple-DES encryption operations in FIPS mode */ + if (OSSL_PROVIDER_available(libctx, "fips") + && strncmp(name, "DES", 3) == 0) + return; assert(name != NULL); /* the cipher will be freed after returning, strdup is needed */ if ((namedup = OPENSSL_strdup(name)) != NULL @@ -614,13 +617,18 @@ static int test_cipher_tdes_randkey(void) EVP_CIPHER_CTX *ctx = NULL; EVP_CIPHER *tdes_cipher = NULL, *aes_cipher = NULL; unsigned char key[24] = { 0 }; + OSSL_PARAM params[2]; + int check = 0; + params[0] = OSSL_PARAM_construct_int("encrypt-check", &check); + params[1] = OSSL_PARAM_construct_end(); ret = TEST_ptr(aes_cipher = EVP_CIPHER_fetch(libctx, "AES-256-CBC", NULL)) && TEST_int_eq(EVP_CIPHER_get_flags(aes_cipher) & EVP_CIPH_RAND_KEY, 0) && TEST_ptr(tdes_cipher = EVP_CIPHER_fetch(libctx, "DES-EDE3-CBC", NULL)) && TEST_int_ne(EVP_CIPHER_get_flags(tdes_cipher) & EVP_CIPH_RAND_KEY, 0) && TEST_ptr(ctx = EVP_CIPHER_CTX_new()) - && TEST_true(EVP_CipherInit_ex(ctx, tdes_cipher, NULL, NULL, NULL, 1)) + && TEST_true(EVP_CipherInit_ex2(ctx, tdes_cipher, NULL, NULL, 1, + params)) && TEST_int_gt(EVP_CIPHER_CTX_rand_key(ctx, key), 0); EVP_CIPHER_CTX_free(ctx); diff --git a/test/evp_test.c b/test/evp_test.c index 5d720d56e0..efe4253f9f 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -206,6 +206,7 @@ static const OSSL_PARAM settable_ctx_params[] = { OSSL_PARAM_int("digest-check", NULL), OSSL_PARAM_int("ems_check", NULL), OSSL_PARAM_int("sign-check", NULL), + OSSL_PARAM_int("encrypt-check", NULL), OSSL_PARAM_END }; @@ -272,6 +273,18 @@ static int kdf_check_fips_approved(EVP_KDF_CTX *ctx, EVP_TEST *t) return check_fips_approved(t, approved); } +static int cipher_check_fips_approved(EVP_CIPHER_CTX *ctx, EVP_TEST *t) +{ + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + int approved = 1; + + params[0] = OSSL_PARAM_construct_int(OSSL_CIPHER_PARAM_FIPS_APPROVED_INDICATOR, + &approved); + if (!EVP_CIPHER_CTX_get_params(ctx, params)) + return 0; + return check_fips_approved(t, approved); +} + /* * Compare two memory regions for equality, returning zero if they differ. * However, if there is expected to be an error and the actual error @@ -855,6 +868,7 @@ typedef struct cipher_data_st { unsigned char *mac_key; size_t mac_key_len; const char *xts_standard; + STACK_OF(OPENSSL_STRING) *init_controls; /* collection of controls */ } CIPHER_DATA; @@ -906,6 +920,7 @@ static int cipher_test_init(EVP_TEST *t, const char *alg) if (!TEST_ptr(cdat = OPENSSL_zalloc(sizeof(*cdat)))) return 0; + cdat->init_controls = sk_OPENSSL_STRING_new_null(); cdat->cipher = cipher; cdat->fetched_cipher = fetched_cipher; cdat->enc = -1; @@ -945,6 +960,7 @@ static void cipher_test_cleanup(EVP_TEST *t) OPENSSL_free(cdat->tag); OPENSSL_free(cdat->mac_key); EVP_CIPHER_free(cdat->fetched_cipher); + ctrlfree(cdat->init_controls); } static int cipher_test_parse(EVP_TEST *t, const char *keyword, @@ -1027,11 +1043,14 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword, cdat->xts_standard = value; return 1; } + if (strcmp(keyword, "CtrlInit") == 0) + return ctrladd(cdat->init_controls, value); return 0; } static int cipher_test_enc(EVP_TEST *t, int enc, size_t out_misalign, - size_t inp_misalign, int frag, int in_place) + size_t inp_misalign, int frag, int in_place, + const OSSL_PARAM initparams[]) { CIPHER_DATA *expected = t->data; unsigned char *in, *expected_out, *tmp = NULL; @@ -1081,7 +1100,8 @@ static int cipher_test_enc(EVP_TEST *t, int enc, size_t out_misalign, in = memcpy(tmp + out_misalign + in_len + 2 * EVP_MAX_BLOCK_LENGTH + inp_misalign, in, in_len); } - if (!EVP_CipherInit_ex(ctx_base, expected->cipher, NULL, NULL, NULL, enc)) { + if (!EVP_CipherInit_ex2(ctx_base, expected->cipher, NULL, NULL, enc, + initparams)) { t->err = "CIPHERINIT_ERROR"; goto err; } @@ -1355,6 +1375,11 @@ static int cipher_test_enc(EVP_TEST *t, int enc, size_t out_misalign, t->err = "CIPHERFINAL_ERROR"; goto err; } + if (!cipher_check_fips_approved(ctx, t)) { + t->err = "FIPSAPPROVED_ERROR"; + goto err; + } + if (!enc && expected->tls_aad) { if (expected->tls_version >= TLS1_1_VERSION && (EVP_CIPHER_is_a(expected->cipher, "AES-128-CBC-HMAC-SHA1") @@ -1414,6 +1439,8 @@ static int cipher_test_run(EVP_TEST *t) CIPHER_DATA *cdat = t->data; int rv, frag, fragmax, in_place; size_t out_misalign, inp_misalign; + OSSL_PARAM initparams[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + size_t params_n = 0; TEST_info("RUNNING TEST FOR CIPHER %s\n", EVP_CIPHER_get0_name(cdat->cipher)); if (!cdat->key) { @@ -1432,6 +1459,12 @@ static int cipher_test_run(EVP_TEST *t) return 0; } + if (sk_OPENSSL_STRING_num(cdat->init_controls) > 0) { + if (!ctrl2params(t, cdat->init_controls, NULL, + initparams, OSSL_NELEM(initparams), ¶ms_n)) + return 0; + } + fragmax = (cipher_test_valid_fragmentation(cdat) == 0) ? 0 : 1; for (in_place = 1; in_place >= 0; in_place--) { static char aux_err[64]; @@ -1463,31 +1496,26 @@ static int cipher_test_run(EVP_TEST *t) } if (cdat->enc) { rv = cipher_test_enc(t, 1, out_misalign, inp_misalign, - frag, in_place); - /* Not fatal errors: return */ - if (rv != 1) { - if (rv < 0) - return 0; - return 1; - } + frag, in_place, initparams); + if (rv != 1) + goto end; } if (cdat->enc != 1) { rv = cipher_test_enc(t, 0, out_misalign, inp_misalign, - frag, in_place); - /* Not fatal errors: return */ - if (rv != 1) { - if (rv < 0) - return 0; - return 1; - } + frag, in_place, initparams); + if (rv != 1) + goto end; } } } } } + ctrl2params_free(initparams, params_n, 0); t->aux_err = NULL; - return 1; + end: + ctrl2params_free(initparams, params_n, 0); + return (rv < 0 ? 0 : 1); } static const EVP_TEST_METHOD cipher_test_method = { diff --git a/test/recipes/30-test_evp_data/evpciph_des3_common.txt b/test/recipes/30-test_evp_data/evpciph_des3_common.txt index aa238df2d9..fa4c4f06a6 100644 --- a/test/recipes/30-test_evp_data/evpciph_des3_common.txt +++ b/test/recipes/30-test_evp_data/evpciph_des3_common.txt @@ -14,6 +14,7 @@ Title = DES3 Tests # DES EDE3 CBC tests (from destest) +FIPSversion = <3.4.0 Cipher = DES-EDE3-CBC Key = 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 IV = fedcba9876543210 @@ -24,6 +25,7 @@ NextIV = 1c673812cfde9675 # DES EDE3 ECB test # FIPS(3.0.0): has a bug in the IV length #17591 FIPSversion = >3.0.0 +FIPSversion = <3.4.0 Cipher = DES-EDE3-ECB Key = 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000 @@ -35,3 +37,45 @@ Cipher = DES-EDE-ECB Key = 0123456789abcdeffedcba9876543210 Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000 Ciphertext = 4d1332e49f380e23d80a0d8b2bae5e4e6a0094171abcfc27df2bfd40da9f4e4d + +# DES EDE3 CBC tests (from destest) + +# Test that DES3 CBC mode encryption fails because it is not FIPS approved +FIPSversion = >=3.4.0 +Cipher = DES-EDE3-CBC +Key = 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 +IV = fedcba9876543210 +Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000 +Ciphertext = 3FE301C962AC01D02213763C1CBD4CDC799657C064ECF5D41C673812CFDE9675 +Result = CIPHERINIT_ERROR + +# Test that DES3 EBC mode encryption fails because it is not FIPS approved +FIPSversion = >=3.4.0 +Cipher = DES-EDE3-ECB +Key = 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 +Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000 +Ciphertext = 62c10cc9efbf15aaa5ae2e487b690e56d8b1dfb8f5c5b293855e77dd9024b1b1 +Result = CIPHERINIT_ERROR + +Title = DES3 FIPS Indicator Tests + +# Test that DES3 CBC mode encryption is not FIPS approved +FIPSversion = >=3.4.0 +Cipher = DES-EDE3-CBC +Unapproved = 1 +CtrlInit = encrypt-check:0 +Operation = ENCRYPT +Key = 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 +IV = fedcba9876543210 +Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000 +Ciphertext = 3FE301C962AC01D02213763C1CBD4CDC799657C064ECF5D41C673812CFDE9675 + +# Test that DES3 ECB mode encryption is not FIPS approved +FIPSversion = >=3.4.0 +Cipher = DES-EDE3-ECB +Operation = ENCRYPT +Unapproved = 1 +CtrlInit = encrypt-check:0 +Key = 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 +Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000 +Ciphertext = 62c10cc9efbf15aaa5ae2e487b690e56d8b1dfb8f5c5b293855e77dd9024b1b1 diff --git a/test/recipes/30-test_evp_data/evpmac_cmac_des.txt b/test/recipes/30-test_evp_data/evpmac_cmac_des.txt index cf42927e11..d23abe1f97 100644 --- a/test/recipes/30-test_evp_data/evpmac_cmac_des.txt +++ b/test/recipes/30-test_evp_data/evpmac_cmac_des.txt @@ -14,15 +14,16 @@ Title = CMAC tests (from FIPS module) +FIPSversion = <3.4.0 MAC = CMAC Algorithm = DES-EDE3-CBC Key = 89BCD952A8C8AB371AF48AC7D07085D5EFF702E6D62CDC23 Input = FA620C1BBE97319E9A0CF0492121F7A20EB08A6A709DCBD00AAF38E4F99E754E Output = 8F49A1B7D6AA2258 +FIPSversion = <3.4.0 MAC = CMAC by EVP_PKEY Algorithm = DES-EDE3-CBC Key = 89BCD952A8C8AB371AF48AC7D07085D5EFF702E6D62CDC23 Input = FA620C1BBE97319E9A0CF0492121F7A20EB08A6A709DCBD00AAF38E4F99E754E Output = 8F49A1B7D6AA2258 - diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t index 84e0fe2d87..c103b3055a 100644 --- a/test/recipes/80-test_cms.t +++ b/test/recipes/80-test_cms.t @@ -380,7 +380,7 @@ my @smime_cms_tests = ( ], [ "encrypted content test streaming PEM format, triple DES key", - [ "{cmd1}", @prov, "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM", + [ "{cmd1}", @defaultprov, "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM", "-des3", "-secretkey", "000102030405060708090A0B0C0D0E0F1011121314151617", "-stream", "-out", "{output}.cms" ], [ "{cmd2}", @prov, "-EncryptedData_decrypt", "-in", "{output}.cms", diff --git a/util/mk-fipsmodule-cnf.pl b/util/mk-fipsmodule-cnf.pl index 6ff8fc20b7..1ca841c52d 100644 --- a/util/mk-fipsmodule-cnf.pl +++ b/util/mk-fipsmodule-cnf.pl @@ -17,6 +17,7 @@ my $no_short_mac = 1; my $drgb_no_trunc_dgst = 1; my $kdf_digest_check = 1; my $dsa_sign_disabled = 1; +my $tdes_encrypt_disabled = 1; my $activate = 1; my $version = 1; @@ -50,15 +51,16 @@ activate = $activate install-version = $version conditional-errors = $conditional_errors security-checks = $security_checks +module-mac = $module_mac tls1-prf-ems-check = $ems_check no-short-mac = $no_short_mac drbg-no-trunc-md = $drgb_no_trunc_dgst dsa-sign-disabled = $dsa_sign_disabled -module-mac = $module_mac hkdf-digest-check = $kdf_digest_check tls13-kdf-digest-check = $kdf_digest_check tls1-prf-digest-check = $kdf_digest_check sshkdf-digest-check = $kdf_digest_check sskdf-digest-check = $kdf_digest_check x963kdf-digest-check = $kdf_digest_check +tdes-encrypt-disabled = $tdes_encrypt_disabled _____ diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm index 09235c08c2..6a138e1c00 100644 --- a/util/perl/OpenSSL/paramnames.pm +++ b/util/perl/OpenSSL/paramnames.pm @@ -41,6 +41,7 @@ my %params = ( 'PROV_PARAM_SSKDF_DIGEST_CHECK' => "sskdf-digest-check", # uint 'PROV_PARAM_X963KDF_DIGEST_CHECK' => "x963kdf-digest-check", # uint 'PROV_PARAM_DSA_SIGN_DISABLED' => "dsa-sign-disabled", # uint + 'PROV_PARAM_TDES_ENCRYPT_DISABLED' => "tdes-encrypt-disabled", # uint # Self test callback parameters 'PROV_PARAM_SELF_TEST_PHASE' => "st-phase",# utf8_string @@ -109,6 +110,8 @@ my %params = ( 'CIPHER_PARAM_RC2_KEYBITS' => "keybits", # size_t 'CIPHER_PARAM_SPEED' => "speed", # uint 'CIPHER_PARAM_CTS_MODE' => "cts_mode", # utf8_string + 'CIPHER_PARAM_FIPS_ENCRYPT_CHECK' => "encrypt-check", # int + 'CIPHER_PARAM_FIPS_APPROVED_INDICATOR' => '*ALG_PARAM_FIPS_APPROVED_INDICATOR', # For passing the AlgorithmIdentifier parameter in DER form 'CIPHER_PARAM_ALGORITHM_ID_PARAMS' => "alg_id_param",# octet_string 'CIPHER_PARAM_XTS_STANDARD' => "xts_standard",# utf8_string