diff --git a/gnutls-3.7.6-fips-ecdsa-hash-check.patch b/gnutls-3.7.6-fips-ecdsa-hash-check.patch new file mode 100644 index 0000000..9280bb3 --- /dev/null +++ b/gnutls-3.7.6-fips-ecdsa-hash-check.patch @@ -0,0 +1,427 @@ +From 171b934a8c054e98b110892cae4130e1db64e656 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Thu, 29 Sep 2022 21:28:19 +0900 +Subject: [PATCH] gnutls-3.7.6-fips-ecdsa-hash-check.patch + +--- + lib/crypto-backend.h | 12 ++-- + lib/nettle/pk.c | 33 +++++----- + lib/privkey.c | 42 ++++++++---- + lib/pubkey.c | 5 +- + tests/fips-test.c | 150 ++++++++++++++++++++++++++++++++++++++++++- + 5 files changed, 205 insertions(+), 37 deletions(-) + +diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h +index f0f68c3..4dd1ae2 100644 +--- a/lib/crypto-backend.h ++++ b/lib/crypto-backend.h +@@ -247,11 +247,13 @@ typedef enum { + GNUTLS_PK_FLAG_RSA_PSS_FIXED_SALT_LENGTH = 4 + } gnutls_pk_flag_t; + +-#define FIX_SIGN_PARAMS(params, flags, dig) do { \ +- if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) { \ +- (params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE; \ +- (params).dsa_dig = (dig); \ +- } \ ++#define FIX_SIGN_PARAMS(params, flags, dig) do { \ ++ if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) { \ ++ (params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE; \ ++ } \ ++ if ((params).pk == GNUTLS_PK_DSA || (params).pk == GNUTLS_PK_ECDSA) { \ ++ (params).dsa_dig = (dig); \ ++ } \ + } while (0) + + void gnutls_pk_params_release(gnutls_pk_params_st * p); +diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c +index f38016b..c098e2a 100644 +--- a/lib/nettle/pk.c ++++ b/lib/nettle/pk.c +@@ -1104,8 +1104,16 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo, + me = _gnutls_dsa_q_to_hash(pk_params, + &hash_len); + ++ if (hash_len > vdata->size) { ++ gnutls_assert(); ++ _gnutls_debug_log ++ ("Security level of algorithm requires hash %s(%d) or better\n", ++ _gnutls_mac_get_name(me), hash_len); ++ hash_len = vdata->size; ++ } ++ + /* Only SHA-2 is allowed in FIPS 140-3 */ +- switch (me->id) { ++ switch (DIG_TO_MAC(sign_params->dsa_dig)) { + case GNUTLS_MAC_SHA256: + case GNUTLS_MAC_SHA384: + case GNUTLS_MAC_SHA512: +@@ -1115,14 +1123,6 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo, + not_approved = true; + } + +- if (hash_len > vdata->size) { +- gnutls_assert(); +- _gnutls_debug_log +- ("Security level of algorithm requires hash %s(%d) or better\n", +- _gnutls_mac_get_name(me), hash_len); +- hash_len = vdata->size; +- } +- + mpz_init(k); + if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST || + (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) { +@@ -1545,7 +1545,6 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo, + struct dsa_signature sig; + int curve_id = pk_params->curve; + const struct ecc_curve *curve; +- const mac_entry_st *me; + + curve = get_supported_nist_curve(curve_id); + if (curve == NULL) { +@@ -1571,11 +1570,14 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo, + memcpy(sig.r, tmp[0], SIZEOF_MPZT); + memcpy(sig.s, tmp[1], SIZEOF_MPZT); + +- me = _gnutls_dsa_q_to_hash(pk_params, &hash_len); ++ (void)_gnutls_dsa_q_to_hash(pk_params, &hash_len); ++ ++ if (hash_len > vdata->size) ++ hash_len = vdata->size; + + /* SHA-1 is allowed for SigVer in FIPS 140-3 in legacy + * mode */ +- switch (me->id) { ++ switch (DIG_TO_MAC(sign_params->dsa_dig)) { + case GNUTLS_MAC_SHA1: + case GNUTLS_MAC_SHA256: + case GNUTLS_MAC_SHA384: +@@ -1586,9 +1588,6 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo, + not_approved = true; + } + +- if (hash_len > vdata->size) +- hash_len = vdata->size; +- + ret = + ecdsa_verify(&pub, hash_len, vdata->data, + &sig); +@@ -2390,8 +2389,10 @@ static int pct_test(gnutls_pk_algorithm_t algo, const gnutls_pk_params_st* param + + if (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_EC) { + unsigned hash_len; ++ const mac_entry_st *me; + +- _gnutls_dsa_q_to_hash(params, &hash_len); ++ me = _gnutls_dsa_q_to_hash(params, &hash_len); ++ spki.dsa_dig = MAC_TO_DIG(me->id); + gen_data = gnutls_malloc(hash_len); + gnutls_rnd(GNUTLS_RND_NONCE, gen_data, hash_len); + +diff --git a/lib/privkey.c b/lib/privkey.c +index 0b77443..2069fc0 100644 +--- a/lib/privkey.c ++++ b/lib/privkey.c +@@ -1251,27 +1251,36 @@ gnutls_privkey_sign_hash2(gnutls_privkey_t signer, + se = _gnutls_sign_to_entry(GNUTLS_SIGN_RSA_RAW); + } else { + se = _gnutls_sign_to_entry(algo); +- if (unlikely(se == NULL)) +- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); +- ++ if (unlikely(se == NULL)) { ++ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ goto cleanup; ++ } + } + + ret = _gnutls_privkey_get_spki_params(signer, ¶ms); + if (ret < 0) { + gnutls_assert(); +- return ret; ++ goto cleanup; + } + + ret = _gnutls_privkey_update_spki_params(signer, se->pk, se->hash, + flags, ¶ms); + if (ret < 0) { + gnutls_assert(); +- return ret; ++ goto cleanup; + } + + FIX_SIGN_PARAMS(params, flags, se->hash); + +- return privkey_sign_prehashed(signer, se, hash_data, signature, ¶ms); ++ ret = privkey_sign_prehashed(signer, se, hash_data, signature, ¶ms); ++ ++ cleanup: ++ if (ret < 0) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ } else { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED); ++ } ++ return ret; + } + + int +@@ -1366,14 +1375,14 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer, + ret = _gnutls_privkey_get_spki_params(signer, ¶ms); + if (ret < 0) { + gnutls_assert(); +- return ret; ++ goto cleanup; + } + + ret = _gnutls_privkey_update_spki_params(signer, signer->pk_algorithm, + hash_algo, flags, ¶ms); + if (ret < 0) { + gnutls_assert(); +- return ret; ++ goto cleanup; + } + + /* legacy callers of this API could use a hash algorithm of 0 (unknown) +@@ -1391,13 +1400,22 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer, + se = _gnutls_pk_to_sign_entry(params.pk, hash_algo); + } + +- if (unlikely(se == NULL)) +- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ if (unlikely(se == NULL)) { ++ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ goto cleanup; ++ } + + FIX_SIGN_PARAMS(params, flags, hash_algo); + +- return privkey_sign_prehashed(signer, se, +- hash_data, signature, ¶ms); ++ ret = privkey_sign_prehashed(signer, se, ++ hash_data, signature, ¶ms); ++ cleanup: ++ if (ret < 0) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ } else { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED); ++ } ++ return ret; + } + + static int +diff --git a/lib/pubkey.c b/lib/pubkey.c +index eba1f5b..35126f3 100644 +--- a/lib/pubkey.c ++++ b/lib/pubkey.c +@@ -1985,7 +1985,7 @@ gnutls_pubkey_import_dsa_raw(gnutls_pubkey_t key, + * parameters (if any) with the signature algorithm */ + static + int fixup_spki_params(const gnutls_pk_params_st *key_params, const gnutls_sign_entry_st *se, +- const mac_entry_st *me, gnutls_x509_spki_st *params) ++ const mac_entry_st *me, gnutls_x509_spki_st *params) + { + unsigned bits; + +@@ -2018,6 +2018,9 @@ int fixup_spki_params(const gnutls_pk_params_st *key_params, const gnutls_sign_e + + if (params->rsa_pss_dig != se->hash) + return gnutls_assert_val(GNUTLS_E_CONSTRAINT_ERROR); ++ } else if (params->pk == GNUTLS_PK_DSA || ++ params->pk == GNUTLS_PK_ECDSA) { ++ params->dsa_dig = se->hash; + } + + return 0; +diff --git a/tests/fips-test.c b/tests/fips-test.c +index 788f4ab..ec0f4b4 100644 +--- a/tests/fips-test.c ++++ b/tests/fips-test.c +@@ -80,8 +80,22 @@ static const gnutls_datum_t rsa2342_sha1_sig = { + .size = sizeof(rsa2342_sha1_sig_data), + }; + ++static const uint8_t ecc256_sha1_sig_data[] = { ++ 0x30, 0x45, 0x02, 0x21, 0x00, 0x9a, 0x28, 0xc9, 0xbf, 0xc8, 0x70, 0x4f, ++ 0x27, 0x2d, 0xe1, 0x66, 0xc4, 0xa5, 0xc6, 0xf2, 0xdc, 0x33, 0xb9, 0x41, ++ 0xdf, 0x78, 0x98, 0x8a, 0x22, 0x4d, 0x29, 0x37, 0xa0, 0x0f, 0x6f, 0xd4, ++ 0xed, 0x02, 0x20, 0x0b, 0x15, 0xca, 0x30, 0x09, 0x2d, 0x55, 0x44, 0xb4, ++ 0x1d, 0x3f, 0x48, 0x7a, 0xc3, 0xd1, 0x2a, 0xc1, 0x0e, 0x47, 0xfa, 0xe6, ++ 0xe9, 0x0f, 0x03, 0xe2, 0x01, 0x4e, 0xe4, 0x73, 0x37, 0xa7, 0x90, ++}; ++ ++static const gnutls_datum_t ecc256_sha1_sig = { ++ .data = (unsigned char *)ecc256_sha1_sig_data, ++ .size = sizeof(ecc256_sha1_sig_data), ++}; ++ + static void +-rsa_import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey, ++import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey, + const char *filename) + { + const char *srcdir; +@@ -274,6 +288,8 @@ void doit(void) + gnutls_datum_t signature; + unsigned int bits; + uint8_t hmac[64]; ++ uint8_t hash[64]; ++ gnutls_datum_t hashed_data; + uint8_t pbkdf2[64]; + gnutls_datum_t temp_key = { NULL, 0 }; + +@@ -473,7 +489,7 @@ void doit(void) + + /* Import 2432-bit RSA key; not a security function */ + FIPS_PUSH_CONTEXT(); +- rsa_import_keypair(&privkey, &pubkey, "rsa-2432.pem"); ++ import_keypair(&privkey, &pubkey, "rsa-2432.pem"); + FIPS_POP_CONTEXT(INITIAL); + + /* Create a signature with 2432-bit RSA and SHA256; approved */ +@@ -519,7 +535,7 @@ void doit(void) + + /* Import 512-bit RSA key; not a security function */ + FIPS_PUSH_CONTEXT(); +- rsa_import_keypair(&privkey, &pubkey, "rsa-512.pem"); ++ import_keypair(&privkey, &pubkey, "rsa-512.pem"); + FIPS_POP_CONTEXT(INITIAL); + + /* Create a signature with 512-bit RSA and SHA256; not approved */ +@@ -543,6 +559,134 @@ void doit(void) + gnutls_pubkey_deinit(pubkey); + gnutls_privkey_deinit(privkey); + ++ /* Import ECDSA key; not a security function */ ++ FIPS_PUSH_CONTEXT(); ++ import_keypair(&privkey, &pubkey, "ecc256.pem"); ++ FIPS_POP_CONTEXT(INITIAL); ++ ++ /* Create a signature with ECDSA and SHA256; approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA256, 0, ++ &data, &signature); ++ if (ret < 0) { ++ fail("gnutls_privkey_sign_data2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(APPROVED); ++ ++ /* Verify a signature with ECDSA and SHA256; approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA256, 0, ++ &data, &signature); ++ if (ret < 0) { ++ fail("gnutls_pubkey_verify_data2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(APPROVED); ++ gnutls_free(signature.data); ++ ++ /* Create a signature with ECDSA and SHA256 (old API); approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0, ++ &data, &signature); ++ if (ret < 0) { ++ fail("gnutls_privkey_sign_data failed\n"); ++ } ++ FIPS_POP_CONTEXT(APPROVED); ++ ++ /* Create a SHA256 hashed data for 2-pass signature API; not a ++ * crypto operation */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, data.data, data.size, hash); ++ if (ret < 0) { ++ fail("gnutls_hash_fast failed\n"); ++ } ++ hashed_data.data = hash; ++ hashed_data.size = 32; ++ FIPS_POP_CONTEXT(INITIAL); ++ ++ /* Create a signature with ECDSA and SHA256 (2-pass API); not-approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_privkey_sign_hash2(privkey, GNUTLS_SIGN_ECDSA_SHA256, 0, ++ &hashed_data, &signature); ++ if (ret < 0) { ++ fail("gnutls_privkey_sign_hash2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ gnutls_free(signature.data); ++ ++ /* Create a signature with ECDSA and SHA256 (2-pass old API); not-approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA256, 0, ++ &hashed_data, &signature); ++ if (ret < 0) { ++ fail("gnutls_privkey_sign_hash failed\n"); ++ } ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ gnutls_free(signature.data); ++ ++ /* Create a signature with ECDSA and SHA-1; not approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0, ++ &data, &signature); ++ if (ret < 0) { ++ fail("gnutls_privkey_sign_data2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ ++ /* Verify a signature created with ECDSA and SHA-1; approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA1, ++ GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1, &data, ++ &ecc256_sha1_sig); ++ if (ret < 0) { ++ fail("gnutls_pubkey_verify_data2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(APPROVED); ++ gnutls_free(signature.data); ++ ++ /* Create a signature with ECDSA and SHA-1 (old API); not approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, ++ &data, &signature); ++ if (ret < 0) { ++ fail("gnutls_privkey_sign_data failed\n"); ++ } ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ gnutls_free(signature.data); ++ ++ /* Create a SHA1 hashed data for 2-pass signature API; not a ++ * crypto operation */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, data.data, data.size, hash); ++ if (ret < 0) { ++ fail("gnutls_hash_fast failed\n"); ++ } ++ hashed_data.data = hash; ++ hashed_data.size = 20; ++ FIPS_POP_CONTEXT(INITIAL); ++ ++ /* Create a signature with ECDSA and SHA1 (2-pass API); not-approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_privkey_sign_hash2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0, ++ &hashed_data, &signature); ++ if (ret < 0) { ++ fail("gnutls_privkey_sign_hash2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ gnutls_free(signature.data); ++ ++ /* Create a signature with ECDSA and SHA1 (2-pass old API); not-approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA1, 0, ++ &hashed_data, &signature); ++ if (ret < 0) { ++ fail("gnutls_privkey_sign_hash failed\n"); ++ } ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ gnutls_free(signature.data); ++ ++ gnutls_pubkey_deinit(pubkey); ++ gnutls_privkey_deinit(privkey); ++ + /* Test RND functions */ + FIPS_PUSH_CONTEXT(); + ret = gnutls_rnd(GNUTLS_RND_RANDOM, key16, sizeof(key16)); +-- +2.37.3 + diff --git a/gnutls-3.7.6-fips-run-selftests.patch b/gnutls-3.7.6-fips-run-selftests.patch index 40cf389..d04a35d 100644 --- a/gnutls-3.7.6-fips-run-selftests.patch +++ b/gnutls-3.7.6-fips-run-selftests.patch @@ -440,3 +440,201 @@ index a6a283fa67..31a5e26111 100644 -- 2.36.1 +From 354027c0c09db60d3083fa48ae791046d336957b Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Tue, 28 Jun 2022 17:22:36 +0200 +Subject: [PATCH] tests/fips-test: minor extension + +Signed-off-by: Alexander Sosedkin +--- + tests/fips-test.c | 36 +++++++++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 9 deletions(-) + +diff --git a/tests/fips-test.c b/tests/fips-test.c +index 31a5e26111..f9bd34586a 100644 +--- a/tests/fips-test.c ++++ b/tests/fips-test.c +@@ -427,34 +427,43 @@ void doit(void) + rsa_import_keypair(&privkey, &pubkey, "rsa-2432.pem"); + FIPS_POP_CONTEXT(INITIAL); + +- /* Create a signature with SHA256; approved */ ++ /* Create a signature with 2432-bit RSA and SHA256; approved */ + FIPS_PUSH_CONTEXT(); + ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0, + &data, &signature); + if (ret < 0) { + fail("gnutls_privkey_sign_data failed\n"); + } +- gnutls_free(signature.data); + FIPS_POP_CONTEXT(APPROVED); + +- /* Create a signature with SHA-1; not approved */ ++ /* Verify a signature with 2432-bit RSA and SHA256; approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA256, 0, ++ &data, &signature); ++ if (ret < 0) { ++ fail("gnutls_pubkey_verify_data2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(APPROVED); ++ gnutls_free(signature.data); ++ ++ /* Create a signature with 2432-bit RSA and SHA-1; not approved */ + FIPS_PUSH_CONTEXT(); + ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0, + &data, &signature); + if (ret < 0) { + fail("gnutls_privkey_sign_data failed\n"); + } +- gnutls_free(signature.data); + FIPS_POP_CONTEXT(NOT_APPROVED); + +- /* Verify a signature created with SHA-1; approved */ ++ /* Verify a signature created with 2432-bit RSA and SHA-1; approved */ + FIPS_PUSH_CONTEXT(); +- ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &data, +- &rsa2342_sha1_sig); ++ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, ++ &data, &rsa2342_sha1_sig); + if (ret < 0) { + fail("gnutls_pubkey_verify_data2 failed\n"); + } + FIPS_POP_CONTEXT(APPROVED); ++ gnutls_free(signature.data); + gnutls_pubkey_deinit(pubkey); + gnutls_privkey_deinit(privkey); + +@@ -463,15 +472,24 @@ void doit(void) + rsa_import_keypair(&privkey, &pubkey, "rsa-512.pem"); + FIPS_POP_CONTEXT(INITIAL); + +- /* Create a signature; not approved */ ++ /* Create a signature with 512-bit RSA and SHA256; not approved */ + FIPS_PUSH_CONTEXT(); + ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0, + &data, &signature); + if (ret < 0) { + fail("gnutls_privkey_sign_data failed\n"); + } +- gnutls_free(signature.data); + FIPS_POP_CONTEXT(NOT_APPROVED); ++ ++ /* Verify a signature with 512-bit RSA and SHA256; not approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA256, 0, ++ &data, &signature); ++ if (ret < 0) { ++ fail("gnutls_pubkey_verify_data2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ gnutls_free(signature.data); + gnutls_pubkey_deinit(pubkey); + gnutls_privkey_deinit(privkey); + +-- +2.37.3 + +From 5a745120148861d873f47c1428c8c6dcadcf109b Mon Sep 17 00:00:00 2001 +From: Richard Costa +Date: Sat, 9 Jul 2022 00:50:21 +0000 +Subject: [PATCH] Add self-test code inside a FIPS context + +Self-test code exercise lots of different FIPS-related code with +side-effects. So, in order to prevent it from losing information when +executing inside another context, we create an appropriated one. + +If the self-test fails, then the library is placed in error state, so it +doesn't matter for other contexts. + +Signed-off-by: Richard Maciel Costa +--- + lib/fips.c | 19 +++++++++++++++++++ + tests/fips-test.c | 20 ++++++++++++-------- + 2 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/lib/fips.c b/lib/fips.c +index 31a52a990f..7d143e608e 100644 +--- a/lib/fips.c ++++ b/lib/fips.c +@@ -902,6 +902,16 @@ gnutls_fips140_run_self_tests(void) + #ifdef ENABLE_FIPS140 + int ret; + unsigned prev_lib_state; ++ gnutls_fips140_context_t fips_context = NULL; ++ ++ /* Save the FIPS context, because self tests change it */ ++ if (gnutls_fips140_mode_enabled() != GNUTLS_FIPS140_DISABLED) { ++ if (gnutls_fips140_context_init(&fips_context) < 0 || ++ gnutls_fips140_push_context(fips_context) < 0) { ++ gnutls_fips140_context_deinit(fips_context); ++ fips_context = NULL; ++ } ++ } + + /* Temporarily switch to LIB_STATE_SELFTEST as some of the + * algorithms are implemented using special constructs in +@@ -918,6 +928,15 @@ gnutls_fips140_run_self_tests(void) + /* Restore the previous library state */ + _gnutls_switch_lib_state(prev_lib_state); + } ++ ++ /* Restore the previous FIPS context */ ++ if (gnutls_fips140_mode_enabled() != GNUTLS_FIPS140_DISABLED && fips_context) { ++ if (gnutls_fips140_pop_context() < 0) { ++ _gnutls_switch_lib_state(LIB_STATE_ERROR); ++ _gnutls_audit_log(NULL, "FIPS140-2 context restoration failed\n"); ++ } ++ gnutls_fips140_context_deinit(fips_context); ++ } + return ret; + #else + return 0; +diff --git a/tests/fips-test.c b/tests/fips-test.c +index f9bd34586a..475b739197 100644 +--- a/tests/fips-test.c ++++ b/tests/fips-test.c +@@ -457,8 +457,9 @@ void doit(void) + + /* Verify a signature created with 2432-bit RSA and SHA-1; approved */ + FIPS_PUSH_CONTEXT(); +- ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, +- &data, &rsa2342_sha1_sig); ++ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, ++ GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1, &data, ++ &rsa2342_sha1_sig); + if (ret < 0) { + fail("gnutls_pubkey_verify_data2 failed\n"); + } +@@ -501,6 +502,15 @@ void doit(void) + } + FIPS_POP_CONTEXT(APPROVED); + ++ /* run self-tests manually */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_rnd(GNUTLS_RND_RANDOM, key16, sizeof(key16)); ++ ret = gnutls_fips140_run_self_tests(); ++ if (ret < 0) { ++ fail("gnutls_fips140_run_self_tests failed\n"); ++ } ++ FIPS_POP_CONTEXT(APPROVED); ++ + /* Test when FIPS140 is set to error state */ + _gnutls_lib_simulate_error(); + +@@ -544,12 +554,6 @@ void doit(void) + + gnutls_fips140_context_deinit(fips_context); + +- /* run self-tests manually */ +- ret = gnutls_fips140_run_self_tests(); +- if (ret < 0) { +- fail("gnutls_fips140_run_self_tests failed\n"); +- } +- + gnutls_global_deinit(); + return; + } +-- +2.37.3 + diff --git a/gnutls-3.7.6-fips-symkey-limit.patch b/gnutls-3.7.6-fips-symkey-limit.patch new file mode 100644 index 0000000..f9c7952 --- /dev/null +++ b/gnutls-3.7.6-fips-symkey-limit.patch @@ -0,0 +1,310 @@ +From f8a8961cfa176fc74c153cb6e1e68aff5e2d42f2 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 27 Sep 2022 10:52:19 +0900 +Subject: [PATCH] gnutls-3.7.6-fips-symkey-limit.patch + +--- + lib/crypto-api.c | 26 ++++++++++++++++++++++--- + tests/fips-test.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++ + tests/kdf-api.c | 9 ++++++++- + 3 files changed, 80 insertions(+), 4 deletions(-) + +diff --git a/lib/crypto-api.c b/lib/crypto-api.c +index b3e1eec..35200fb 100644 +--- a/lib/crypto-api.c ++++ b/lib/crypto-api.c +@@ -896,6 +896,7 @@ gnutls_hash_hd_t gnutls_hash_copy(gnutls_hash_hd_t handle) + int gnutls_key_generate(gnutls_datum_t * key, unsigned int key_size) + { + int ret; ++ bool not_approved = false; + + FAIL_IF_LIB_ERROR; + +@@ -912,17 +913,31 @@ int gnutls_key_generate(gnutls_datum_t * key, unsigned int key_size) + key->data = gnutls_malloc(key->size); + if (!key->data) { + gnutls_assert(); +- return GNUTLS_E_MEMORY_ERROR; ++ ret = GNUTLS_E_MEMORY_ERROR; ++ goto error; ++ } ++ ++ /* Key lengths of less than 112 bits are not approved */ ++ if (key_size < 14) { ++ not_approved = true; + } + + ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size); + if (ret < 0) { + gnutls_assert(); + _gnutls_free_datum(key); +- return ret; ++ goto error; + } + +- return 0; ++ error: ++ if (ret < 0) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ } else if (not_approved) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED); ++ } else { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED); ++ } ++ return ret; + } + + /* AEAD API */ +@@ -2058,6 +2073,11 @@ gnutls_pbkdf2(gnutls_mac_algorithm_t mac, + not_approved = true; + } + ++ /* Key lengths and output sizes of less than 112 bits are not approved */ ++ if (key->size < 14 || length < 14) { ++ not_approved = true; ++ } ++ + ret = _gnutls_kdf_ops.pbkdf2(mac, key->data, key->size, + salt->data, salt->size, iter_count, + output, length); +diff --git a/tests/fips-test.c b/tests/fips-test.c +index 31a5e26..27da414 100644 +--- a/tests/fips-test.c ++++ b/tests/fips-test.c +@@ -274,6 +274,8 @@ void doit(void) + gnutls_datum_t signature; + unsigned int bits; + uint8_t hmac[64]; ++ uint8_t pbkdf2[64]; ++ gnutls_datum_t temp_key = { NULL, 0 }; + + fprintf(stderr, + "Please note that if in FIPS140 mode, you need to assure the library's integrity prior to running this test\n"); +@@ -371,11 +373,58 @@ void doit(void) + } + FIPS_POP_CONTEXT(NOT_APPROVED); + ++ /* PBKDF2 with key equal to or longer than 112 bits: approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_pbkdf2(GNUTLS_MAC_SHA256, &key, &iv, 100, ++ &pbkdf2, sizeof(pbkdf2)); ++ if (ret < 0) { ++ fail("gnutls_pbkdf2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(APPROVED); ++ ++ /* PBKDF2 with key shorter than 112 bits: not approved */ ++ FIPS_PUSH_CONTEXT(); ++ key.size = 13; ++ ret = gnutls_pbkdf2(GNUTLS_MAC_SHA256, &key, &iv, 100, ++ &pbkdf2, sizeof(pbkdf2)); ++ if (ret < 0) { ++ fail("gnutls_pbkdf2 failed\n"); ++ } ++ key.size = sizeof(key16); ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ ++ /* PBKDF2 with output shorter than 112 bits: not approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_pbkdf2(GNUTLS_MAC_SHA256, &key, &iv, 100, ++ &pbkdf2, 13); ++ if (ret < 0) { ++ fail("gnutls_pbkdf2 failed\n"); ++ } ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ + ret = gnutls_rnd(GNUTLS_RND_NONCE, key16, sizeof(key16)); + if (ret < 0) { + fail("gnutls_rnd failed\n"); + } + ++ /* Symmetric key generation equal to or longer than 112 bits: approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_key_generate(&temp_key, 14); ++ if (ret < 0) { ++ fail("gnutls_key_generate failed\n"); ++ } ++ gnutls_free(temp_key.data); ++ FIPS_POP_CONTEXT(APPROVED); ++ ++ /* Symmetric key generation shorter than 112 bits: not approved */ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_key_generate(&temp_key, 13); ++ if (ret < 0) { ++ fail("gnutls_key_generate failed\n"); ++ } ++ gnutls_free(temp_key.data); ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ + ret = gnutls_pubkey_init(&pubkey); + if (ret < 0) { + fail("gnutls_pubkey_init failed\n"); +diff --git a/tests/kdf-api.c b/tests/kdf-api.c +index 25fbc6a..8a4677c 100644 +--- a/tests/kdf-api.c ++++ b/tests/kdf-api.c +@@ -89,6 +89,7 @@ test_hkdf(gnutls_mac_algorithm_t mac, + + FIPS_PUSH_CONTEXT(); + assert(gnutls_hkdf_extract(mac, &ikm, &salt, buf) >= 0); ++ /* HKDF outside of TLS usage is not approved */ + FIPS_POP_CONTEXT(NOT_APPROVED); + gnutls_free(ikm.data); + gnutls_free(salt.data); +@@ -110,6 +111,7 @@ test_hkdf(gnutls_mac_algorithm_t mac, + + FIPS_PUSH_CONTEXT(); + assert(gnutls_hkdf_expand(mac, &prk, &info, buf, length) >= 0); ++ /* HKDF outside of TLS usage is not approved */ + FIPS_POP_CONTEXT(NOT_APPROVED); + gnutls_free(info.data); + +@@ -151,7 +153,12 @@ test_pbkdf2(gnutls_mac_algorithm_t mac, + + FIPS_PUSH_CONTEXT(); + assert(gnutls_pbkdf2(mac, &ikm, &salt, iter_count, buf, length) >= 0); +- FIPS_POP_CONTEXT(APPROVED); ++ /* Key sizes and output sizes less than 112-bit are not approved. */ ++ if (ikm.size < 14 || length < 14) { ++ FIPS_POP_CONTEXT(NOT_APPROVED); ++ } else { ++ FIPS_POP_CONTEXT(APPROVED); ++ } + gnutls_free(ikm.data); + gnutls_free(salt.data); + +-- +2.37.3 + +From 86eded166f77612c70201c0d85d3abe711edd77d Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Thu, 29 Sep 2022 21:19:26 +0900 +Subject: [PATCH] fips: only mark HMAC as approved in PBKDF2 + +As ACVP only allows HMAC used with PBKDF2[1], this change marks other +hash algorithms not-approved. + +1. https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html + +Signed-off-by: Daiki Ueno +--- + lib/crypto-api.c | 5 ++++- + lib/fips.h | 16 +++++++++++++++- + tests/kdf-api.c | 30 +++++++++++++++++++++++++++++- + 3 files changed, 48 insertions(+), 3 deletions(-) + +diff --git a/lib/crypto-api.c b/lib/crypto-api.c +index d3e601ab3a..9f7e18db11 100644 +--- a/lib/crypto-api.c ++++ b/lib/crypto-api.c +@@ -2229,7 +2229,10 @@ gnutls_pbkdf2(gnutls_mac_algorithm_t mac, + if (!is_mac_algo_allowed(mac)) { + _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); + return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); +- } else if (!is_mac_algo_approved_in_fips(mac)) { ++ } else if (!is_mac_algo_hmac_approved_in_fips(mac)) { ++ /* ACVP only allows HMAC used with PBKDF2: ++ * https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html ++ */ + not_approved = true; + } + +diff --git a/lib/fips.h b/lib/fips.h +index 3a74f254e7..bf61b36741 100644 +--- a/lib/fips.h ++++ b/lib/fips.h +@@ -76,7 +76,7 @@ void _gnutls_lib_simulate_error(void); + void _gnutls_lib_force_operational(void); + + inline static bool +-is_mac_algo_approved_in_fips(gnutls_mac_algorithm_t algo) ++is_mac_algo_hmac_approved_in_fips(gnutls_mac_algorithm_t algo) + { + switch (algo) { + case GNUTLS_MAC_SHA1: +@@ -88,6 +88,20 @@ is_mac_algo_approved_in_fips(gnutls_mac_algorithm_t algo) + case GNUTLS_MAC_SHA3_256: + case GNUTLS_MAC_SHA3_384: + case GNUTLS_MAC_SHA3_512: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++inline static bool ++is_mac_algo_approved_in_fips(gnutls_mac_algorithm_t algo) ++{ ++ if (is_mac_algo_hmac_approved_in_fips(algo)) { ++ return true; ++ } ++ ++ switch (algo) { + case GNUTLS_MAC_AES_CMAC_128: + case GNUTLS_MAC_AES_CMAC_256: + case GNUTLS_MAC_AES_GMAC_128: +diff --git a/tests/kdf-api.c b/tests/kdf-api.c +index 577cbf7a17..4feb22688b 100644 +--- a/tests/kdf-api.c ++++ b/tests/kdf-api.c +@@ -26,6 +26,7 @@ + #include + + #include ++#include + #include + + #include "utils.h" +@@ -133,6 +134,25 @@ test_hkdf(gnutls_mac_algorithm_t mac, + gnutls_free(hex.data); + } + ++inline static bool ++is_mac_algo_hmac_approved_in_fips(gnutls_mac_algorithm_t algo) ++{ ++ switch (algo) { ++ case GNUTLS_MAC_SHA1: ++ case GNUTLS_MAC_SHA256: ++ case GNUTLS_MAC_SHA384: ++ case GNUTLS_MAC_SHA512: ++ case GNUTLS_MAC_SHA224: ++ case GNUTLS_MAC_SHA3_224: ++ case GNUTLS_MAC_SHA3_256: ++ case GNUTLS_MAC_SHA3_384: ++ case GNUTLS_MAC_SHA3_512: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static void + test_pbkdf2(gnutls_mac_algorithm_t mac, + const char *ikm_hex, +@@ -161,7 +181,8 @@ test_pbkdf2(gnutls_mac_algorithm_t mac, + FIPS_PUSH_CONTEXT(); + assert(gnutls_pbkdf2(mac, &ikm, &salt, iter_count, buf, length) >= 0); + /* Key sizes and output sizes less than 112-bit are not approved. */ +- if (ikm.size < 14 || length < 14) { ++ if (ikm.size < 14 || length < 14 || ++ !is_mac_algo_hmac_approved_in_fips(mac)) { + FIPS_POP_CONTEXT(NOT_APPROVED); + } else { + FIPS_POP_CONTEXT(APPROVED); +@@ -208,5 +229,12 @@ doit(void) + 20, + "4b007901b765489abead49d926f721d065a429c1"); + ++ test_pbkdf2(GNUTLS_MAC_AES_CMAC_128, ++ "70617373776f726470617373776f7264", /* "passwordpassword" */ ++ "73616c74", /* "salt" */ ++ 4096, ++ 20, ++ "c4c112c6e1e3b8757640603dec78825ff87605a7"); ++ + gnutls_fips140_context_deinit(fips_context); + } +-- +2.37.3 + diff --git a/gnutls.spec b/gnutls.spec index a5c957a..0125327 100644 --- a/gnutls.spec +++ b/gnutls.spec @@ -13,7 +13,7 @@ print(string.sub(hash, 0, 16)) } Version: 3.7.6 -Release: 11%{?dist} +Release: 12%{?dist} # not upstreamed Patch: gnutls-3.6.7-no-now-guile.patch Patch: gnutls-3.2.7-rpath.patch @@ -28,6 +28,8 @@ Patch: gnutls-3.7.6-aes-gcm-pt-limit.patch Patch: gnutls-3.7.6-pkcs7-verify.patch Patch: gnutls-3.7.6-fips-pkcs12-des-cbc.patch Patch: gnutls-3.7.6-fips-rsa-key-sizes.patch +Patch: gnutls-3.7.6-fips-symkey-limit.patch +Patch: gnutls-3.7.6-fips-ecdsa-hash-check.patch # not upstreamed Patch: gnutls-3.7.3-disable-config-reload.patch @@ -395,6 +397,13 @@ make check %{?_smp_mflags} GNUTLS_SYSTEM_PRIORITY_FILE=/dev/null %endif %changelog +* Tue Sep 27 2022 Daiki Ueno - 3.7.6-12 +- fips: mark PBKDF2 with short key and output sizes non-approved +- fips: only mark HMAC as approved in PBKDF2 +- fips: mark gnutls_key_generate with short key sizes non-approved +- fips: fix checking on hash algorithm used in ECDSA +- fips: preserve operation context around FIPS selftests API + * Fri Aug 26 2022 Daiki Ueno - 3.7.6-11 - Supply --with{,out}-{zlib,brotli,zstd} explicitly