From fc68cf21b572bc7fc76a39e4ec150d5d612f02e8 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Sat, 21 Sep 2024 15:25:53 +0100 Subject: [PATCH] kdfs: implement key length check in X9.42 Similar to other KDFs, the input key should be 112 bits long. Reviewed-by: Shane Lontis Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/25529) --- apps/fipsinstall.c | 11 ++++ doc/man1/openssl-fipsinstall.pod.in | 7 +++ doc/man5/fips_config.pod | 4 ++ doc/man7/EVP_KDF-X942-ASN1.pod | 22 ++++++++ .../fips/include/fips_indicator_params.inc | 1 + providers/implementations/kdfs/x942kdf.c | 52 ++++++++++++++++--- test/recipes/03-test_fipsinstall.t | 3 +- test/recipes/30-test_evp_data/evpkdf_x942.txt | 14 +++++ util/mk-fipsmodule-cnf.pl | 1 + util/perl/OpenSSL/paramnames.pm | 1 + 10 files changed, 109 insertions(+), 7 deletions(-) diff --git a/apps/fipsinstall.c b/apps/fipsinstall.c index 94ca7656c6..203f397a48 100644 --- a/apps/fipsinstall.c +++ b/apps/fipsinstall.c @@ -59,6 +59,7 @@ typedef enum OPTION_choice { OPT_SSHKDF_KEY_CHECK, OPT_SSKDF_KEY_CHECK, OPT_X963KDF_KEY_CHECK, + OPT_X942KDF_KEY_CHECK, OPT_NO_PBKDF2_LOWER_BOUND_CHECK, OPT_ECDH_COFACTOR_CHECK, OPT_SELF_TEST_ONLOAD, OPT_SELF_TEST_ONINSTALL @@ -128,6 +129,8 @@ const OPTIONS fipsinstall_options[] = { "Enable key check for SSKDF"}, {"x963kdf_key_check", OPT_X963KDF_KEY_CHECK, '-', "Enable key check for X963KDF"}, + {"x942kdf_key_check", OPT_X942KDF_KEY_CHECK, '-', + "Enable key check for X942KDF"}, {"no_pbkdf2_lower_bound_check", OPT_NO_PBKDF2_LOWER_BOUND_CHECK, '-', "Disable lower bound check for PBKDF2"}, {"ecdh_cofactor_check", OPT_ECDH_COFACTOR_CHECK, '-', @@ -176,6 +179,7 @@ typedef struct { unsigned int sshkdf_key_check : 1; unsigned int sskdf_key_check : 1; unsigned int x963kdf_key_check : 1; + unsigned int x942kdf_key_check : 1; unsigned int pbkdf2_lower_bound_check : 1; unsigned int ecdh_cofactor_check : 1; } FIPS_OPTS; @@ -209,6 +213,7 @@ static const FIPS_OPTS pedantic_opts = { 1, /* sshkdf_key_check */ 1, /* sskdf_key_check */ 1, /* x963kdf_key_check */ + 1, /* x942kdf_key_check */ 1, /* pbkdf2_lower_bound_check */ 1, /* ecdh_cofactor_check */ }; @@ -242,6 +247,7 @@ static FIPS_OPTS fips_opts = { 0, /* sshkdf_key_check */ 0, /* sskdf_key_check */ 0, /* x963kdf_key_check */ + 0, /* x942kdf_key_check */ 1, /* pbkdf2_lower_bound_check */ 0, /* ecdh_cofactor_check */ }; @@ -419,6 +425,8 @@ static int write_config_fips_section(BIO *out, const char *section, opts->sskdf_key_check ? "1": "0") <= 0 || BIO_printf(out, "%s = %s\n", OSSL_PROV_PARAM_X963KDF_KEY_CHECK, opts->x963kdf_key_check ? "1": "0") <= 0 + || BIO_printf(out, "%s = %s\n", OSSL_PROV_PARAM_X942KDF_KEY_CHECK, + opts->x942kdf_key_check ? "1": "0") <= 0 || BIO_printf(out, "%s = %s\n", OSSL_PROV_PARAM_PBKDF2_LOWER_BOUND_CHECK, opts->pbkdf2_lower_bound_check ? "1" : "0") <= 0 @@ -676,6 +684,9 @@ int fipsinstall_main(int argc, char **argv) case OPT_X963KDF_KEY_CHECK: fips_opts.x963kdf_key_check = 1; break; + case OPT_X942KDF_KEY_CHECK: + fips_opts.x942kdf_key_check = 1; + break; case OPT_NO_PBKDF2_LOWER_BOUND_CHECK: if (!check_non_pedantic_fips(pedantic, "no_pbkdf2_lower_bound_check")) goto end; diff --git a/doc/man1/openssl-fipsinstall.pod.in b/doc/man1/openssl-fipsinstall.pod.in index 6057aa5316..165179395b 100644 --- a/doc/man1/openssl-fipsinstall.pod.in +++ b/doc/man1/openssl-fipsinstall.pod.in @@ -47,6 +47,7 @@ B [B<-sshkdf_key_check>] [B<-sskdf_key_check>] [B<-x963kdf_key_check>] +[B<-x942kdf_key_check>] [B<-ecdh_cofactor_check>] [B<-self_test_onload>] [B<-self_test_oninstall>] @@ -340,6 +341,12 @@ Configure the module to enable a run-time short key-derivation key check when deriving a key by X963KDF. See NIST SP 800-131Ar2 for details. +=item B<-x942kdf_key_check> + +Configure the module to enable a run-time short key-derivation key check when +deriving a key by X942KDF. +See NIST SP 800-131Ar2 for details. + =item B<-no_pbkdf2_lower_bound_check> Configure the module to not perform run-time lower bound check for PBKDF2. diff --git a/doc/man5/fips_config.pod b/doc/man5/fips_config.pod index ef6f591184..a25ced3383 100644 --- a/doc/man5/fips_config.pod +++ b/doc/man5/fips_config.pod @@ -182,6 +182,10 @@ See L B<-sskdf_key_check> See L B<-x963kdf_key_check> +=item B + +See L B<-x942kdf_key_check> + =item B See L B<-no_pbkdf2_lower_bound_check> diff --git a/doc/man7/EVP_KDF-X942-ASN1.pod b/doc/man7/EVP_KDF-X942-ASN1.pod index b13610dc03..3f62b8b82e 100644 --- a/doc/man7/EVP_KDF-X942-ASN1.pod +++ b/doc/man7/EVP_KDF-X942-ASN1.pod @@ -77,6 +77,28 @@ Valid values are "AES-128-WRAP", "AES-192-WRAP", "AES-256-WRAP" and "DES3-WRAP". =back +The OpenSSL FIPS provider also supports the following parameters: + +=over 4 + +=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 "key-check" +parameter is set to 0 and the check fails. + +=item "key-check" (B) + +The default value of 1 causes an error during EVP_KDF_CTX_set_params() if the +length of used key-derivation key (B) is shorter than 112 +bits. +Setting this to zero will ignore the error and set the approved +"fips-indicator" to 0. +This option breaks FIPS compliance if it causes the approved "fips-indicator" +to return 0. + +=back + =head1 NOTES A context for X942KDF can be obtained by calling: diff --git a/providers/fips/include/fips_indicator_params.inc b/providers/fips/include/fips_indicator_params.inc index c1d12c32a6..78f9fc0655 100644 --- a/providers/fips/include/fips_indicator_params.inc +++ b/providers/fips/include/fips_indicator_params.inc @@ -23,5 +23,6 @@ OSSL_FIPS_PARAM(tls1_prf_key_check, TLS1_PRF_KEY_CHECK, 0) OSSL_FIPS_PARAM(sshkdf_key_check, SSHKDF_KEY_CHECK, 0) OSSL_FIPS_PARAM(sskdf_key_check, SSKDF_KEY_CHECK, 0) OSSL_FIPS_PARAM(x963kdf_key_check, X963KDF_KEY_CHECK, 0) +OSSL_FIPS_PARAM(x942kdf_key_check, X942KDF_KEY_CHECK, 0) OSSL_FIPS_PARAM(pbkdf2_lower_bound_check, PBKDF2_LOWER_BOUND_CHECK, 1) OSSL_FIPS_PARAM(ecdh_cofactor_check, ECDH_COFACTOR_CHECK, 0) diff --git a/providers/implementations/kdfs/x942kdf.c b/providers/implementations/kdfs/x942kdf.c index 51117c530f..8b72a6a9f2 100644 --- a/providers/implementations/kdfs/x942kdf.c +++ b/providers/implementations/kdfs/x942kdf.c @@ -22,6 +22,7 @@ #include "prov/providercommon.h" #include "prov/implementations.h" #include "prov/provider_util.h" +#include "prov/securitycheck.h" #include "prov/der_wrap.h" #define X942KDF_MAX_INLEN (1 << 30) @@ -49,6 +50,7 @@ typedef struct { const unsigned char *cek_oid; size_t cek_oid_len; int use_keybits; + OSSL_FIPS_IND_DECLARE } KDF_X942; /* @@ -336,9 +338,12 @@ static void *x942kdf_new(void *provctx) if (!ossl_prov_is_running()) return NULL; - if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) return NULL; + ctx->provctx = provctx; + OSSL_FIPS_IND_INIT(ctx) ctx->use_keybits = 1; return ctx; } @@ -397,6 +402,7 @@ static void *x942kdf_dup(void *vctx) dest->cek_oid_len = src->cek_oid_len; dest->dkm_len = src->dkm_len; dest->use_keybits = src->use_keybits; + OSSL_FIPS_IND_COPY(dest, src) } return dest; @@ -429,6 +435,24 @@ static size_t x942kdf_size(KDF_X942 *ctx) return (len <= 0) ? 0 : (size_t)len; } +#ifdef FIPS_MODULE +static int fips_x942kdf_key_check_passed(KDF_X942 *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + int key_approved = ossl_kdf_check_key_size(ctx->secret_len); + + if (!key_approved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + libctx, "X942KDF", "Key size", + ossl_fips_config_x942kdf_key_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + return 1; +} +#endif + static int x942kdf_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { @@ -513,6 +537,10 @@ static int x942kdf_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_KEY_CHECK)) + return 0; + if (OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST) != NULL) { if (!ossl_prov_digest_load_from_params(&ctx->digest, params, provctx)) return 0; @@ -526,8 +554,14 @@ static int x942kdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET); if (p == NULL) p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY); - if (p != NULL && !x942kdf_set_buffer(&ctx->secret, &ctx->secret_len, p)) - return 0; + if (p != NULL) { + if (!x942kdf_set_buffer(&ctx->secret, &ctx->secret_len, p)) + return 0; +#ifdef FIPS_MODULE + if (!fips_x942kdf_key_check_passed(ctx)) + return 0; +#endif + } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_X942_ACVPINFO); if (p != NULL @@ -598,6 +632,7 @@ static const OSSL_PARAM *x942kdf_settable_ctx_params(ossl_unused void *ctx, OSSL_PARAM_octet_string(OSSL_KDF_PARAM_X942_SUPP_PRIVINFO, NULL, 0), OSSL_PARAM_int(OSSL_KDF_PARAM_X942_USE_KEYBITS, NULL), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_KEY_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; @@ -608,9 +643,13 @@ static int x942kdf_get_ctx_params(void *vctx, OSSL_PARAM params[]) KDF_X942 *ctx = (KDF_X942 *)vctx; OSSL_PARAM *p; - if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) - return OSSL_PARAM_set_size_t(p, x942kdf_size(ctx)); - return -2; + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, x942kdf_size(ctx))) + return 0; + + if (!OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params)) + return 0; + return 1; } static const OSSL_PARAM *x942kdf_gettable_ctx_params(ossl_unused void *ctx, @@ -618,6 +657,7 @@ static const OSSL_PARAM *x942kdf_gettable_ctx_params(ossl_unused void *ctx, { static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; diff --git a/test/recipes/03-test_fipsinstall.t b/test/recipes/03-test_fipsinstall.t index f4dcb4bda0..4965b9e63d 100644 --- a/test/recipes/03-test_fipsinstall.t +++ b/test/recipes/03-test_fipsinstall.t @@ -59,7 +59,8 @@ my @commandline = ( 'tls1_prf_key_check', 'tls1-prf-key-check' ), ( 'sshkdf_key_check', 'sshkdf-key-check' ), ( 'sskdf_key_check', 'sskdf-key-check' ), - ( 'x963kdf_key_check', 'x963kdf-key-check' ) + ( 'x963kdf_key_check', 'x963kdf-key-check' ), + ( 'x942kdf_key_check', 'x942kdf-key-check' ) ); plan tests => 35 + (scalar @pedantic_okay) + (scalar @pedantic_fail) diff --git a/test/recipes/30-test_evp_data/evpkdf_x942.txt b/test/recipes/30-test_evp_data/evpkdf_x942.txt index 3cf2fffe12..b1774592e9 100644 --- a/test/recipes/30-test_evp_data/evpkdf_x942.txt +++ b/test/recipes/30-test_evp_data/evpkdf_x942.txt @@ -77,6 +77,7 @@ Output = 2c5c1f028c6d1fc9ba752e41fdb9edb2ea936f1b2449f214acd56d31 Title = X9.42 KDF tests (ACVP test vectors) +FIPSversion = <3.4.0 KDF = X942KDF-ASN1 Ctrl.digest = digest:SHA256 Ctrl.hexsecret = hexsecret:6B @@ -88,6 +89,7 @@ Output = C2E6A0978C24AF3932F478583ADBFB5F57D491822592EAD3C538875F46EB057A # Negative tests # Fail if both acvp and ukm values are specified. +FIPSversion = <3.4.0 KDF = X942KDF-ASN1 Ctrl.digest = digest:SHA256 Ctrl.hexsecret = hexsecret:6B @@ -118,3 +120,15 @@ Ctrl.cekalg = cekalg:id-aes128-wrap Ctrl.hexacvp-info = hexacvp-info:a020299D468D60BC6A257E0B6523D691A3FC1602453B35F308C762FBBAC6069A88BCa12080D49BFE5BE01C7D56489AB017663C22B8CBB34C3174D1D71F00CB7505AC759Aa2203C21A5EA5988562C007986E0503D039E7231D9F152FE72A231A1FD98C59BCA6Aa320FD47477542989B51E4A0845DFABD6EEAA465F69B3D75349B2520051782C7F3FC Result = KDF_CTRL_ERROR Reason = xof digests not allowed + +Availablein = fips +FIPSversion = >=3.4.0 +KDF = X942KDF-ASN1 +Ctrl.digest = digest:SHA256 +Ctrl.hexsecret = hexsecret:6B +Ctrl.use-keybits = use-keybits:0 +Ctrl.cekalg = cekalg:id-aes128-wrap +Ctrl.hexacvp-info = hexacvp-info:a020299D468D60BC6A257E0B6523D691A3FC1602453B35F308C762FBBAC6069A88BCa12080D49BFE5BE01C7D56489AB017663C22B8CBB34C3174D1D71F00CB7505AC759Aa2203C21A5EA5988562C007986E0503D039E7231D9F152FE72A231A1FD98C59BCA6Aa320FD47477542989B51E4A0845DFABD6EEAA465F69B3D75349B2520051782C7F3FC +Output = C2E6A0978C24AF3932F478583ADBFB5F57D491822592EAD3C538875F46EB057A +Result = KDF_CTRL_ERROR +Reason = invalid key length diff --git a/util/mk-fipsmodule-cnf.pl b/util/mk-fipsmodule-cnf.pl index 2c63e5a51a..6908592fc5 100644 --- a/util/mk-fipsmodule-cnf.pl +++ b/util/mk-fipsmodule-cnf.pl @@ -81,6 +81,7 @@ tls1-prf-key-check = $kdf_key_check sshkdf-key-check = $kdf_key_check sskdf-key-check = $kdf_key_check x963kdf-key-check = $kdf_key_check +x942kdf-key-check = $kdf_key_check pbkdf2-lower-bound-check = $pbkdf2_lower_bound_check ecdh-cofactor-check = $ec_cofactor_check hmac-key-check = $mac_key_check diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm index 0701064ccf..e67f0f2beb 100644 --- a/util/perl/OpenSSL/paramnames.pm +++ b/util/perl/OpenSSL/paramnames.pm @@ -54,6 +54,7 @@ my %params = ( 'PROV_PARAM_SSHKDF_KEY_CHECK' => "sshkdf-key-check", # uint 'PROV_PARAM_SSKDF_KEY_CHECK' => "sskdf-key-check", # uint 'PROV_PARAM_X963KDF_KEY_CHECK' => "x963kdf-key-check", # uint + 'PROV_PARAM_X942KDF_KEY_CHECK' => "x942kdf-key-check", # uint 'PROV_PARAM_PBKDF2_LOWER_BOUND_CHECK' => "pbkdf2-lower-bound-check", # uint 'PROV_PARAM_ECDH_COFACTOR_CHECK' => "ecdh-cofactor-check", # uint 'PROV_PARAM_SIGNATURE_DIGEST_CHECK' => "signature-digest-check", # uint