diff --git a/SOURCES/gnutls-3.7.6-fips-ccm-taglen.patch b/SOURCES/gnutls-3.7.6-fips-ccm-taglen.patch new file mode 100644 index 0000000..2ec015b --- /dev/null +++ b/SOURCES/gnutls-3.7.6-fips-ccm-taglen.patch @@ -0,0 +1,331 @@ +From 26b2caef673aba8bfd10db3b1b8117f941c18e58 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Fri, 21 Oct 2022 15:48:39 +0900 +Subject: [PATCH] cipher: add restriction on CCM tag length under FIPS mode + +This change prohibits any use of tag length other than 4, 6, 8, 10, +12, 14, and 16 bytes in CCM used under FIPS mode, in accordance with +SP800-38C A.1. While use of tag lengths smaller than 8 bytes is not +recommended, we simply allow 4 and 6 bytes tags for now. + +Signed-off-by: Daiki Ueno +--- + lib/accelerated/aarch64/aes-ccm-aarch64.c | 39 ++++++++++ + lib/accelerated/x86/aes-ccm-x86-aesni.c | 39 ++++++++++ + lib/nettle/cipher.c | 55 ++++++++++++++ + tests/fips-test.c | 87 ++++++++++++++++++++++- + 4 files changed, 218 insertions(+), 2 deletions(-) + +diff --git a/lib/accelerated/aarch64/aes-ccm-aarch64.c b/lib/accelerated/aarch64/aes-ccm-aarch64.c +index a2ba259e99..b415d4ddfb 100644 +--- a/lib/accelerated/aarch64/aes-ccm-aarch64.c ++++ b/lib/accelerated/aarch64/aes-ccm-aarch64.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + typedef struct ccm_aarch64_aes_ctx { + AES_KEY key; +@@ -103,6 +104,25 @@ aes_ccm_aead_encrypt(void *_ctx, + if (unlikely(encr_size < plain_size + tag_size)) + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + ++ /* SP800-38C A.1 says Tlen must be a multiple of 16 between 32 ++ * and 128. ++ */ ++ switch (tag_size) { ++ case 4: case 6: ++ /* SP800-38C B.2 says Tlen smaller than 64 should not be used ++ * under sufficient restriction. We simply allow those for now. ++ */ ++ FALLTHROUGH; ++ case 8: case 10: case 12: case 14: case 16: ++ break; ++ default: ++ if (_gnutls_fips_mode_enabled()) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ } ++ break; ++ } ++ + ccm_encrypt_message(&ctx->key, aarch64_aes_encrypt, + nonce_size, nonce, + auth_size, auth, +@@ -129,6 +149,25 @@ aes_ccm_aead_decrypt(void *_ctx, + if (unlikely(plain_size < encr_size - tag_size)) + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + ++ /* SP800-38C A.1 says Tlen must be a multiple of 16 between 32 ++ * and 128. ++ */ ++ switch (tag_size) { ++ case 4: case 6: ++ /* SP800-38C B.2 says Tlen smaller than 64 should not be used ++ * under sufficient restriction. We simply allow those for now. ++ */ ++ FALLTHROUGH; ++ case 8: case 10: case 12: case 14: case 16: ++ break; ++ default: ++ if (_gnutls_fips_mode_enabled()) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ } ++ break; ++ } ++ + ret = ccm_decrypt_message(&ctx->key, aarch64_aes_encrypt, + nonce_size, nonce, + auth_size, auth, +diff --git a/lib/accelerated/x86/aes-ccm-x86-aesni.c b/lib/accelerated/x86/aes-ccm-x86-aesni.c +index 701c0f992a..9ebbdd7b2a 100644 +--- a/lib/accelerated/x86/aes-ccm-x86-aesni.c ++++ b/lib/accelerated/x86/aes-ccm-x86-aesni.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + typedef struct ccm_x86_aes_ctx { + AES_KEY key; +@@ -95,6 +96,25 @@ aes_ccm_aead_encrypt(void *_ctx, + if (unlikely(encr_size < plain_size + tag_size)) + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + ++ /* SP800-38C A.1 says Tlen must be a multiple of 16 between 32 ++ * and 128. ++ */ ++ switch (tag_size) { ++ case 4: case 6: ++ /* SP800-38C B.2 says Tlen smaller than 64 should not be used ++ * under sufficient restriction. We simply allow those for now. ++ */ ++ FALLTHROUGH; ++ case 8: case 10: case 12: case 14: case 16: ++ break; ++ default: ++ if (_gnutls_fips_mode_enabled()) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ } ++ break; ++ } ++ + ccm_encrypt_message(&ctx->key, x86_aes_encrypt, + nonce_size, nonce, + auth_size, auth, +@@ -121,6 +141,25 @@ aes_ccm_aead_decrypt(void *_ctx, + if (unlikely(plain_size < encr_size - tag_size)) + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + ++ /* SP800-38C A.1 says Tlen must be a multiple of 16 between 32 ++ * and 128. ++ */ ++ switch (tag_size) { ++ case 4: case 6: ++ /* SP800-38C B.2 says Tlen smaller than 64 should not be used ++ * under sufficient restriction. We simply allow those for now. ++ */ ++ FALLTHROUGH; ++ case 8: case 10: case 12: case 14: case 16: ++ break; ++ default: ++ if (_gnutls_fips_mode_enabled()) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ } ++ break; ++ } ++ + ret = ccm_decrypt_message(&ctx->key, x86_aes_encrypt, + nonce_size, nonce, + auth_size, auth, +diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c +index 9c2ce19e7e..8c23d11252 100644 +--- a/lib/nettle/cipher.c ++++ b/lib/nettle/cipher.c +@@ -1253,6 +1253,34 @@ wrap_nettle_cipher_aead_encrypt(void *_ctx, + ctx->cipher->tag(ctx->ctx_ptr, tag_size, ((uint8_t*)encr) + plain_size); + } else { + /* CCM-style cipher */ ++ ++ switch (ctx->cipher->algo) { ++ case GNUTLS_CIPHER_AES_128_CCM: ++ case GNUTLS_CIPHER_AES_256_CCM: ++ /* SP800-38C A.1 says Tlen must be a multiple of 16 ++ * between 32 and 128. ++ */ ++ switch (tag_size) { ++ case 4: case 6: ++ /* SP800-38C B.2 says Tlen smaller than 64 ++ * should not be used under sufficient ++ * restriction. We simply allow those for now. ++ */ ++ FALLTHROUGH; ++ case 8: case 10: case 12: case 14: case 16: ++ break; ++ default: ++ if (_gnutls_fips_mode_enabled()) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ } ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ + ctx->cipher->aead_encrypt(ctx, + nonce_size, nonce, + auth_size, auth, +@@ -1302,6 +1330,33 @@ wrap_nettle_cipher_aead_decrypt(void *_ctx, + if (unlikely(plain_size < encr_size)) + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + ++ switch (ctx->cipher->algo) { ++ case GNUTLS_CIPHER_AES_128_CCM: ++ case GNUTLS_CIPHER_AES_256_CCM: ++ /* SP800-38C A.1 says Tlen must be a multiple of 16 ++ * between 32 and 128. ++ */ ++ switch (tag_size) { ++ case 4: case 6: ++ /* SP800-38C B.2 says Tlen smaller than 64 ++ * should not be used under sufficient ++ * restriction. We simply allow those for now. ++ */ ++ FALLTHROUGH; ++ case 8: case 10: case 12: case 14: case 16: ++ break; ++ default: ++ if (_gnutls_fips_mode_enabled()) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ } ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ + ret = ctx->cipher->aead_decrypt(ctx, + nonce_size, nonce, + auth_size, auth, +diff --git a/tests/fips-test.c b/tests/fips-test.c +index f7556d7bbb..c43503fba0 100644 +--- a/tests/fips-test.c ++++ b/tests/fips-test.c +@@ -1,4 +1,5 @@ + #include ++#include + #include + #include + #include +@@ -213,14 +214,96 @@ test_cipher_disallowed(gnutls_cipher_algorithm_t cipher) + FIPS_POP_CONTEXT(ERROR); + } + ++static void ++test_ccm_cipher(gnutls_cipher_algorithm_t cipher, size_t tag_length, ++ bool expect_encryption_fail, ++ gnutls_fips140_operation_state_t expected_state) ++{ ++ int ret; ++ unsigned key_size = gnutls_cipher_get_key_size(cipher); ++ gnutls_aead_cipher_hd_t h; ++ gnutls_datum_t key = { key_data, key_size }; ++ unsigned char buffer[256]; ++ size_t length; ++ gnutls_memset(key_data, 0, key_size); ++ ++ FIPS_PUSH_CONTEXT(); ++ ret = gnutls_aead_cipher_init(&h, cipher, &key); ++ if (ret < 0) { ++ fail("gnutls_aead_cipher_init failed for %s\n", ++ gnutls_cipher_get_name(cipher)); ++ } ++ FIPS_POP_CONTEXT(APPROVED); ++ ++ fips_push_context(fips_context); ++ memset(buffer, 0, sizeof(buffer)); ++ length = sizeof(buffer); ++ ret = gnutls_aead_cipher_encrypt(h, iv_data, ++ gnutls_cipher_get_iv_size(cipher), ++ NULL, 0, tag_length, ++ buffer, length - tag_length, ++ buffer, &length); ++ if (expect_encryption_fail) { ++ if (ret != GNUTLS_E_INVALID_REQUEST) { ++ fail("gnutls_aead_cipher_encrypt(%s) returned %d " ++ "while %d is expected\n", ++ gnutls_cipher_get_name(cipher), ++ ret, GNUTLS_E_INVALID_REQUEST); ++ } ++ } else if (ret < 0) { ++ fail("gnutls_aead_cipher_encrypt failed for %s\n", ++ gnutls_cipher_get_name(cipher)); ++ } ++ fips_pop_context(fips_context, expected_state); ++ ++ fips_push_context(fips_context); ++ length = sizeof(buffer); ++ ret = gnutls_aead_cipher_decrypt(h, iv_data, ++ gnutls_cipher_get_iv_size(cipher), ++ NULL, 0, tag_length, ++ buffer, length, ++ buffer, &length); ++ if (expect_encryption_fail) { ++ if (ret != GNUTLS_E_INVALID_REQUEST) { ++ fail("gnutls_aead_cipher_decrypt(%s) returned %d " ++ "while %d is expected\n", ++ gnutls_cipher_get_name(cipher), ++ ret, GNUTLS_E_INVALID_REQUEST); ++ } ++ } else if (ret < 0) { ++ fail("gnutls_aead_cipher_decrypt failed for %s\n", ++ gnutls_cipher_get_name(cipher)); ++ } ++ fips_pop_context(fips_context, expected_state); ++ ++ gnutls_aead_cipher_deinit(h); ++} ++ + static inline void + test_ciphers(void) + { ++ size_t i; ++ + test_cipher_approved(GNUTLS_CIPHER_AES_128_CBC); + test_cipher_approved(GNUTLS_CIPHER_AES_192_CBC); + test_cipher_approved(GNUTLS_CIPHER_AES_256_CBC); +- test_aead_cipher_approved(GNUTLS_CIPHER_AES_128_CCM); +- test_aead_cipher_approved(GNUTLS_CIPHER_AES_256_CCM); ++ ++ /* Check for all allowed Tlen */ ++ for (i = 4; i <= 16; i += 2) { ++ test_ccm_cipher(GNUTLS_CIPHER_AES_128_CCM, i, ++ false, GNUTLS_FIPS140_OP_APPROVED); ++ test_ccm_cipher(GNUTLS_CIPHER_AES_256_CCM, i, ++ false, GNUTLS_FIPS140_OP_APPROVED); ++ } ++ test_ccm_cipher(GNUTLS_CIPHER_AES_128_CCM, 3, ++ true, GNUTLS_FIPS140_OP_ERROR); ++ test_ccm_cipher(GNUTLS_CIPHER_AES_256_CCM, 3, ++ true, GNUTLS_FIPS140_OP_ERROR); ++ test_ccm_cipher(GNUTLS_CIPHER_AES_128_CCM, 5, ++ true, GNUTLS_FIPS140_OP_ERROR); ++ test_ccm_cipher(GNUTLS_CIPHER_AES_256_CCM, 5, ++ true, GNUTLS_FIPS140_OP_ERROR); ++ + test_aead_cipher_approved(GNUTLS_CIPHER_AES_128_CCM_8); + test_aead_cipher_approved(GNUTLS_CIPHER_AES_256_CCM_8); + test_cipher_approved(GNUTLS_CIPHER_AES_128_CFB8); +-- +2.38.1 + diff --git a/SOURCES/gnutls-3.7.6-fips-ecdsa-hash-check.patch b/SOURCES/gnutls-3.7.6-fips-ecdsa-hash-check.patch new file mode 100644 index 0000000..9280bb3 --- /dev/null +++ b/SOURCES/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/SOURCES/gnutls-3.7.6-fips-rsa-pss-saltlen.patch b/SOURCES/gnutls-3.7.6-fips-rsa-pss-saltlen.patch new file mode 100644 index 0000000..a6af4d5 --- /dev/null +++ b/SOURCES/gnutls-3.7.6-fips-rsa-pss-saltlen.patch @@ -0,0 +1,163 @@ +From 3bd42dc88ff062bf9ede2b593e1ad1afa6f68f62 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Wed, 16 Nov 2022 23:02:13 +0900 +Subject: [PATCH] nettle: mark non-compliant RSA-PSS salt length to be + not-approved + +According to FIPS 186-5 5.4, the salt length must be in the range +between 0 and the hash length inclusive. While the use of those salt +lengths is still allowed for compatibility, it is reported as +non-approved operation through FIPS service indicator. + +Signed-off-by: Daiki Ueno +--- + lib/nettle/pk.c | 9 ++++++++ + tests/rsa-rsa-pss.c | 54 ++++++++++++++++++++++++++++++++++++--------- + 2 files changed, 53 insertions(+), 10 deletions(-) + +diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c +index c098e2aa45..7732e90542 100644 +--- a/lib/nettle/pk.c ++++ b/lib/nettle/pk.c +@@ -1316,6 +1316,15 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo, + + mpz_init(s); + ++ me = hash_to_entry(sign_params->rsa_pss_dig); ++ ++ /* According to FIPS 186-5 5.4, the salt length must be ++ * in the range between 0 and the hash length inclusive. ++ */ ++ if (sign_params->salt_size > _gnutls_mac_get_algo_len(me)) { ++ not_approved = true; ++ } ++ + ret = + _rsa_pss_sign_digest_tr(sign_params->rsa_pss_dig, + &pub, &priv, +diff --git a/tests/rsa-rsa-pss.c b/tests/rsa-rsa-pss.c +index 19a175b722..d7799c1961 100644 +--- a/tests/rsa-rsa-pss.c ++++ b/tests/rsa-rsa-pss.c +@@ -46,6 +46,8 @@ const gnutls_datum_t raw_data = { + 11 + }; + ++static gnutls_fips140_context_t fips_context; ++ + static void inv_sign_check(unsigned sigalgo, + gnutls_privkey_t privkey, int exp_error) + { +@@ -86,13 +88,16 @@ static void inv_encryption_check(gnutls_pk_algorithm_t algorithm, + + static void sign_verify_data(unsigned sigalgo, gnutls_privkey_t privkey, + unsigned int sign_flags, unsigned int verify_flags, +- int sign_exp_error, int verify_exp_error) ++ int sign_exp_error, int verify_exp_error, ++ gnutls_fips140_operation_state_t sign_exp_state) + { + int ret; + gnutls_datum_t signature = { NULL, 0 }; + ++ fips_push_context(fips_context); + ret = gnutls_privkey_sign_data2(privkey, sigalgo, sign_flags, + &raw_data, &signature); ++ fips_pop_context(fips_context, sign_exp_state); + if (ret != sign_exp_error) + fail("gnutls_x509_privkey_sign_data returned unexpected error: %s\n", + gnutls_strerror(ret)); +@@ -180,11 +185,16 @@ void doit(void) + if (debug) + gnutls_global_set_log_level(4711); + ++ assert(gnutls_fips140_context_init(&fips_context) >= 0); ++ + prepare_keys(&pkey_rsa_pss, &pkey_rsa, GNUTLS_DIG_SHA256, 32); + +- sign_verify_data(GNUTLS_SIGN_RSA_PSS_SHA256, pkey_rsa_pss, 0, 0, 0, 0); +- sign_verify_data(GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, pkey_rsa, 0, 0, 0, 0); +- sign_verify_data(GNUTLS_SIGN_RSA_PSS_SHA256, pkey_rsa, 0, 0, 0, 0); ++ sign_verify_data(GNUTLS_SIGN_RSA_PSS_SHA256, pkey_rsa_pss, 0, 0, 0, 0, ++ GNUTLS_FIPS140_OP_APPROVED); ++ sign_verify_data(GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, pkey_rsa, 0, 0, 0, 0, ++ GNUTLS_FIPS140_OP_APPROVED); ++ sign_verify_data(GNUTLS_SIGN_RSA_PSS_SHA256, pkey_rsa, 0, 0, 0, 0, ++ GNUTLS_FIPS140_OP_APPROVED); + + if (debug) + success("success signing with RSA-PSS-SHA256\n"); +@@ -213,41 +223,65 @@ void doit(void) + gnutls_privkey_deinit(pkey_rsa_pss); + gnutls_privkey_deinit(pkey_rsa); + ++ /* Restrict key to use salt length larger than hash output ++ * length (not approved in FIPS). ++ */ ++ prepare_keys(&pkey_rsa_pss, &pkey_rsa, GNUTLS_DIG_SHA256, 33); ++ ++ sign_verify_data(GNUTLS_SIGN_RSA_PSS_SHA256, pkey_rsa_pss, 0, 0, 0, 0, ++ GNUTLS_FIPS140_OP_NOT_APPROVED); ++ ++ gnutls_privkey_deinit(pkey_rsa_pss); ++ gnutls_privkey_deinit(pkey_rsa); ++ + /* Use the mismatched salt length with the digest length */ + prepare_keys(&pkey_rsa_pss, &pkey_rsa, GNUTLS_DIG_SHA256, 48); + + sign_verify_data(GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, pkey_rsa_pss, +- 0, 0, 0, 0); ++ 0, 0, 0, 0, GNUTLS_FIPS140_OP_NOT_APPROVED); + sign_verify_data(GNUTLS_SIGN_RSA_PSS_SHA256, pkey_rsa_pss, + GNUTLS_PRIVKEY_FLAG_RSA_PSS_FIXED_SALT_LENGTH, + 0, + GNUTLS_E_CONSTRAINT_ERROR, +- 0); ++ 0, ++ /* The error is caught before calling the actual ++ * signing operation. ++ */ ++ GNUTLS_FIPS140_OP_INITIAL); + sign_verify_data(GNUTLS_SIGN_RSA_PSS_SHA256, pkey_rsa_pss, + 0, + GNUTLS_VERIFY_RSA_PSS_FIXED_SALT_LENGTH, + 0, +- GNUTLS_E_PK_SIG_VERIFY_FAILED); ++ GNUTLS_E_PK_SIG_VERIFY_FAILED, ++ GNUTLS_FIPS140_OP_NOT_APPROVED); + + assert(gnutls_x509_spki_init(&spki)>=0); + gnutls_x509_spki_set_rsa_pss_params(spki, GNUTLS_DIG_SHA256, 48); + assert(gnutls_privkey_set_spki(pkey_rsa, spki, 0)>=0); + +- sign_verify_data(GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, pkey_rsa, 0, 0, 0, 0); ++ sign_verify_data(GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, pkey_rsa, 0, 0, 0, 0, ++ GNUTLS_FIPS140_OP_NOT_APPROVED); + sign_verify_data(GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, pkey_rsa, + GNUTLS_PRIVKEY_FLAG_RSA_PSS_FIXED_SALT_LENGTH, + 0, + GNUTLS_E_CONSTRAINT_ERROR, +- 0); ++ 0, ++ /* The error is caught before calling the actual ++ * signing operation. ++ */ ++ GNUTLS_FIPS140_OP_INITIAL); + sign_verify_data(GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, pkey_rsa, + 0, + GNUTLS_VERIFY_RSA_PSS_FIXED_SALT_LENGTH, + 0, +- GNUTLS_E_PK_SIG_VERIFY_FAILED); ++ GNUTLS_E_PK_SIG_VERIFY_FAILED, ++ GNUTLS_FIPS140_OP_NOT_APPROVED); + + gnutls_privkey_deinit(pkey_rsa_pss); + gnutls_privkey_deinit(pkey_rsa); + gnutls_x509_spki_deinit(spki); + ++ gnutls_fips140_context_deinit(fips_context); ++ + gnutls_global_deinit(); + } +-- +2.38.1 + diff --git a/SOURCES/gnutls-3.7.6-fips-run-selftests.patch b/SOURCES/gnutls-3.7.6-fips-run-selftests.patch index 40cf389..d04a35d 100644 --- a/SOURCES/gnutls-3.7.6-fips-run-selftests.patch +++ b/SOURCES/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/SOURCES/gnutls-3.7.6-fips-service-indicator-test-functions.patch b/SOURCES/gnutls-3.7.6-fips-service-indicator-test-functions.patch new file mode 100644 index 0000000..99bd913 --- /dev/null +++ b/SOURCES/gnutls-3.7.6-fips-service-indicator-test-functions.patch @@ -0,0 +1,407 @@ +From e8b35d31817d207d8b4b87ccf104d3b93aa446e0 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Mon, 17 Oct 2022 11:11:43 +0900 +Subject: [PATCH] tests: move FIPS service indicator functions to common file + +Signed-off-by: Daiki Ueno +--- + tests/dh-compute.c | 36 +++++--------------------- + tests/fips-rsa-sizes.c | 24 ----------------- + tests/fips-test.c | 27 +++----------------- + tests/kdf-api.c | 27 +------------------- + tests/pkcs12_encode.c | 24 ----------------- + tests/privkey-keygen.c | 24 ----------------- + tests/utils.h | 58 ++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 69 insertions(+), 151 deletions(-) + +diff --git a/tests/dh-compute.c b/tests/dh-compute.c +index 828fb05e9c..6c1d5328f6 100644 +--- a/tests/dh-compute.c ++++ b/tests/dh-compute.c +@@ -156,34 +156,10 @@ void doit(void) + { NULL } + }; + +-#define FIPS_PUSH_CONTEXT() do { \ +- if (gnutls_fips140_mode_enabled()) { \ +- ret = gnutls_fips140_push_context(fips_context); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_push_context failed\n"); \ +- } \ +- } \ +-} while (0) +- +-#define FIPS_POP_CONTEXT(state) do { \ +- if (gnutls_fips140_mode_enabled()) { \ +- ret = gnutls_fips140_pop_context(); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_context_pop failed\n"); \ +- } \ +- fips_state = gnutls_fips140_get_operation_state(fips_context); \ +- if (fips_state != state) { \ +- fail("operation state is not %d (%d)\n", \ +- state, fips_state); \ +- } \ +- } \ +-} while (0) +- + for (int i = 0; test_data[i].name != NULL; i++) { + gnutls_datum_t priv_key, pub_key; + gnutls_dh_params_t dh_params; + gnutls_fips140_context_t fips_context; +- gnutls_fips140_operation_state_t fips_state; + int ret; + + if (gnutls_fips140_mode_enabled()) { +@@ -193,24 +169,24 @@ void doit(void) + } + } + +- FIPS_PUSH_CONTEXT(); ++ fips_push_context(fips_context); + params(&dh_params, &test_data[i].prime, &test_data[i].q, + &test_data[i].generator); +- FIPS_POP_CONTEXT(GNUTLS_FIPS140_OP_INITIAL); ++ fips_pop_context(fips_context, GNUTLS_FIPS140_OP_INITIAL); + + success("%s genkey\n", test_data[i].name); + +- FIPS_PUSH_CONTEXT(); ++ fips_push_context(fips_context); + genkey(dh_params, &priv_key, &pub_key); +- FIPS_POP_CONTEXT(test_data[i].fips_state_genkey); ++ fips_pop_context(fips_context, test_data[i].fips_state_genkey); + + success("%s compute_key\n", test_data[i].name); + +- FIPS_PUSH_CONTEXT(); ++ fips_push_context(fips_context); + compute_key(test_data[i].name, dh_params, &priv_key, + &pub_key, &test_data[i].peer_key, + test_data[i].expected_error, NULL, 0); +- FIPS_POP_CONTEXT(test_data[i].fips_state_compute_key); ++ fips_pop_context(fips_context, test_data[i].fips_state_compute_key); + + gnutls_dh_params_deinit(dh_params); + gnutls_free(priv_key.data); +diff --git a/tests/fips-rsa-sizes.c b/tests/fips-rsa-sizes.c +index 84b9affabb..5feb284503 100644 +--- a/tests/fips-rsa-sizes.c ++++ b/tests/fips-rsa-sizes.c +@@ -27,25 +27,6 @@ + #include + #include + +-#define FIPS_PUSH_CONTEXT() do { \ +- ret = gnutls_fips140_push_context(fips_context); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_push_context failed\n"); \ +- } \ +-} while (0) +- +-#define FIPS_POP_CONTEXT(state) do { \ +- ret = gnutls_fips140_pop_context(); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_context_pop failed\n"); \ +- } \ +- fips_state = gnutls_fips140_get_operation_state(fips_context); \ +- if (fips_state != GNUTLS_FIPS140_OP_ ## state) { \ +- fail("operation state is not " # state " (%d)\n", \ +- fips_state); \ +- } \ +-} while (0) +- + + void generate_successfully(gnutls_privkey_t* privkey, gnutls_pubkey_t* pubkey, + unsigned int size); +@@ -63,7 +44,6 @@ void generate_successfully(gnutls_privkey_t* privkey, gnutls_pubkey_t* pubkey, + int ret; + gnutls_x509_privkey_t xprivkey; + gnutls_fips140_context_t fips_context; +- gnutls_fips140_operation_state_t fips_state; + assert(gnutls_fips140_context_init(&fips_context) == 0); + + fprintf(stderr, "%d-bit\n", size); +@@ -102,7 +82,6 @@ void generate_unsuccessfully(gnutls_privkey_t* privkey, gnutls_pubkey_t* pubkey, + int ret; + gnutls_x509_privkey_t xprivkey; + gnutls_fips140_context_t fips_context; +- gnutls_fips140_operation_state_t fips_state; + assert(gnutls_fips140_context_init(&fips_context) == 0); + + fprintf(stderr, "%d-bit\n", size); +@@ -156,7 +135,6 @@ void generate_unsuccessfully(gnutls_privkey_t* privkey, gnutls_pubkey_t* pubkey, + void sign_verify_successfully(gnutls_privkey_t privkey, gnutls_pubkey_t pubkey) { + int ret; + gnutls_fips140_context_t fips_context; +- gnutls_fips140_operation_state_t fips_state; + + gnutls_datum_t signature; + gnutls_datum_t plaintext = { +@@ -190,7 +168,6 @@ void sign_verify_unsuccessfully(gnutls_privkey_t privkey, + gnutls_pubkey_t pubkey) { + int ret; + gnutls_fips140_context_t fips_context; +- gnutls_fips140_operation_state_t fips_state; + + gnutls_datum_t signature; + gnutls_datum_t plaintext = { +@@ -225,7 +202,6 @@ void sign_verify_unsuccessfully(gnutls_privkey_t privkey, + void nosign_verify(gnutls_privkey_t privkey, gnutls_pubkey_t pubkey) { + int ret; + gnutls_fips140_context_t fips_context; +- gnutls_fips140_operation_state_t fips_state; + + gnutls_datum_t signature; + gnutls_datum_t plaintext = { +diff --git a/tests/fips-test.c b/tests/fips-test.c +index f789afb107..b0bae4ef9f 100644 +--- a/tests/fips-test.c ++++ b/tests/fips-test.c +@@ -12,25 +12,6 @@ + /* This does check the FIPS140 support. + */ + +-#define FIPS_PUSH_CONTEXT() do { \ +- ret = gnutls_fips140_push_context(fips_context); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_push_context failed\n"); \ +- } \ +-} while (0) +- +-#define FIPS_POP_CONTEXT(state) do { \ +- ret = gnutls_fips140_pop_context(); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_context_pop failed\n"); \ +- } \ +- fips_state = gnutls_fips140_get_operation_state(fips_context); \ +- if (fips_state != GNUTLS_FIPS140_OP_ ## state) { \ +- fail("operation state is not " # state " (%d)\n", \ +- fips_state); \ +- } \ +-} while (0) +- + void _gnutls_lib_simulate_error(void); + + static void tls_log_func(int level, const char *str) +@@ -40,10 +21,9 @@ static void tls_log_func(int level, const char *str) + + static uint8_t key16[16]; + static uint8_t iv16[16]; +-uint8_t key_data[64]; +-uint8_t iv_data[16]; +-gnutls_fips140_context_t fips_context; +-gnutls_fips140_operation_state_t fips_state; ++static uint8_t key_data[64]; ++static uint8_t iv_data[16]; ++static gnutls_fips140_context_t fips_context; + + static const gnutls_datum_t data = { .data = (unsigned char *)"foo", 3 }; + static const uint8_t rsa2342_sha1_sig_data[] = { +@@ -276,6 +256,7 @@ test_ciphers(void) + void doit(void) + { + int ret; ++ gnutls_fips140_operation_state_t fips_state; + unsigned int mode; + gnutls_cipher_hd_t ch; + gnutls_hmac_hd_t mh; +diff --git a/tests/kdf-api.c b/tests/kdf-api.c +index 9724502005..a28ce82a62 100644 +--- a/tests/kdf-api.c ++++ b/tests/kdf-api.c +@@ -33,30 +33,7 @@ + #define MAX_BUF 1024 + + static gnutls_fips140_context_t fips_context; +-static gnutls_fips140_operation_state_t fips_state; +- +-#define FIPS_PUSH_CONTEXT() do { \ +- if (gnutls_fips140_mode_enabled()) { \ +- ret = gnutls_fips140_push_context(fips_context); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_push_context failed\n"); \ +- } \ +- } \ +-} while (0) +- +-#define FIPS_POP_CONTEXT(state) do { \ +- if (gnutls_fips140_mode_enabled()) { \ +- ret = gnutls_fips140_pop_context(); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_context_pop failed\n"); \ +- } \ +- fips_state = gnutls_fips140_get_operation_state(fips_context); \ +- if (fips_state != GNUTLS_FIPS140_OP_ ## state) { \ +- fail("operation state is not " # state " (%d)\n", \ +- fips_state); \ +- } \ +- } \ +-} while (0) ++ + + static void + test_hkdf(gnutls_mac_algorithm_t mac, +@@ -74,7 +51,6 @@ test_hkdf(gnutls_mac_algorithm_t mac, + gnutls_datum_t prk; + gnutls_datum_t okm; + uint8_t buf[MAX_BUF]; +- int ret; + + success("HKDF test with %s\n", gnutls_mac_get_name(mac)); + +@@ -144,7 +120,6 @@ test_pbkdf2(gnutls_mac_algorithm_t mac, + gnutls_datum_t salt; + gnutls_datum_t okm; + uint8_t buf[MAX_BUF]; +- int ret; + + success("PBKDF2 test with %s\n", gnutls_mac_get_name(mac)); + +diff --git a/tests/pkcs12_encode.c b/tests/pkcs12_encode.c +index ea39f3d69e..dc55daccde 100644 +--- a/tests/pkcs12_encode.c ++++ b/tests/pkcs12_encode.c +@@ -70,29 +70,6 @@ static void tls_log_func(int level, const char *str) + fprintf(stderr, "|<%d>| %s", level, str); + } + +-#define FIPS_PUSH_CONTEXT() do { \ +- if (gnutls_fips140_mode_enabled()) { \ +- ret = gnutls_fips140_push_context(fips_context); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_push_context failed\n"); \ +- } \ +- } \ +-} while (0) +- +-#define FIPS_POP_CONTEXT(state) do { \ +- if (gnutls_fips140_mode_enabled()) { \ +- ret = gnutls_fips140_pop_context(); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_context_pop failed\n"); \ +- } \ +- fips_state = gnutls_fips140_get_operation_state(fips_context); \ +- if (fips_state != GNUTLS_FIPS140_OP_ ## state) { \ +- fail("operation state is not " # state " (%d)\n", \ +- fips_state); \ +- } \ +- } \ +-} while (0) +- + void doit(void) + { + gnutls_pkcs12_t pkcs12; +@@ -106,7 +83,6 @@ void doit(void) + size_t size; + unsigned i; + gnutls_fips140_context_t fips_context; +- gnutls_fips140_operation_state_t fips_state; + size_t n_tests = 0; + struct tests { + const char *name; +diff --git a/tests/privkey-keygen.c b/tests/privkey-keygen.c +index 2766afee08..2531906d71 100644 +--- a/tests/privkey-keygen.c ++++ b/tests/privkey-keygen.c +@@ -119,30 +119,6 @@ void doit(void) + gnutls_x509_privkey_t pkey, dst; + int ret, algorithm, i; + gnutls_fips140_context_t fips_context; +- gnutls_fips140_operation_state_t fips_state; +- +-#define FIPS_PUSH_CONTEXT() do { \ +- if (gnutls_fips140_mode_enabled()) { \ +- ret = gnutls_fips140_push_context(fips_context); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_push_context failed\n"); \ +- } \ +- } \ +-} while (0) +- +-#define FIPS_POP_CONTEXT(state) do { \ +- if (gnutls_fips140_mode_enabled()) { \ +- ret = gnutls_fips140_pop_context(); \ +- if (ret < 0) { \ +- fail("gnutls_fips140_context_pop failed\n"); \ +- } \ +- fips_state = gnutls_fips140_get_operation_state(fips_context); \ +- if (fips_state != GNUTLS_FIPS140_OP_ ## state) { \ +- fail("operation state is not " # state " (%d)\n", \ +- fips_state); \ +- } \ +- } \ +-} while (0) + + ret = global_init(); + if (ret < 0) +diff --git a/tests/utils.h b/tests/utils.h +index d3a2ba8d16..4433a07057 100644 +--- a/tests/utils.h ++++ b/tests/utils.h +@@ -210,4 +210,62 @@ inline static unsigned int get_dtls_retransmit_timeout(void) { + return (unsigned int) ul; + } + ++static inline const char * ++fips_operation_state_to_string(gnutls_fips140_operation_state_t state) ++{ ++ switch (state) { ++ case GNUTLS_FIPS140_OP_INITIAL: ++ return "INITIAL"; ++ case GNUTLS_FIPS140_OP_APPROVED: ++ return "APPROVED"; ++ case GNUTLS_FIPS140_OP_NOT_APPROVED: ++ return "NOT_APPROVED"; ++ case GNUTLS_FIPS140_OP_ERROR: ++ return "ERROR"; ++ default: ++ /*NOTREACHED*/ ++ assert(0); ++ return NULL; ++ } ++} ++ ++static inline void ++fips_push_context(gnutls_fips140_context_t context) ++{ ++ if (gnutls_fips140_mode_enabled()) { ++ int ret; ++ ++ ret = gnutls_fips140_push_context(context); ++ if (ret < 0) { ++ fail("gnutls_fips140_push_context failed\n"); ++ } ++ } ++} ++ ++static inline void ++fips_pop_context(gnutls_fips140_context_t context, ++ gnutls_fips140_operation_state_t expected_state) ++{ ++ gnutls_fips140_operation_state_t state; ++ ++ if (gnutls_fips140_mode_enabled()) { ++ int ret; ++ ++ ret = gnutls_fips140_pop_context(); ++ if (ret < 0) { ++ fail("gnutls_fips140_context_pop failed\n"); ++ } ++ state = gnutls_fips140_get_operation_state(context); ++ if (state != expected_state) { ++ fail("operation state is not %s (%s)\n", ++ fips_operation_state_to_string(expected_state), ++ fips_operation_state_to_string(state)); ++ } ++ } ++} ++ ++/* To use those convenient macros, define fips_context variable. */ ++#define FIPS_PUSH_CONTEXT() fips_push_context(fips_context) ++#define FIPS_POP_CONTEXT(state) fips_pop_context(fips_context, GNUTLS_FIPS140_OP_ ## state) ++ + #endif /* GNUTLS_TESTS_UTILS_H */ +-- +2.38.1 + diff --git a/SOURCES/gnutls-3.7.6-fips-symkey-limit.patch b/SOURCES/gnutls-3.7.6-fips-symkey-limit.patch new file mode 100644 index 0000000..f9c7952 --- /dev/null +++ b/SOURCES/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/SOURCES/gnutls-3.7.6-gmp-static.patch b/SOURCES/gnutls-3.7.6-gmp-static.patch index 6d4bba4..df74247 100644 --- a/SOURCES/gnutls-3.7.6-gmp-static.patch +++ b/SOURCES/gnutls-3.7.6-gmp-static.patch @@ -1,4 +1,3 @@ -From 88808f0b8906bdc32579c144a2c44401ee97798a Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Fri, 19 Aug 2022 12:32:27 +0900 Subject: [PATCH] build: allow GMP to be statically linked @@ -17,17 +16,10 @@ and libhogweed in Nettle is also linked to the static library of GMP. Signed-off-by: Daiki Ueno --- - configure.ac | 14 +++++++++++++- - lib/fips.c | 10 ++++++++++ - lib/fipshmac.c | 5 ++++- - lib/global.c | 2 ++ - 4 files changed, 29 insertions(+), 2 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 96894b0be3..e4cf5eab81 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -742,6 +742,8 @@ AC_CHECK_FUNCS(nettle_cmac_kuznyechik_update) +diff --color -ruNp a/configure.ac b/configure.ac +--- a/configure.ac 2022-12-15 11:06:16.782726043 +0100 ++++ b/configure.ac 2022-12-15 11:08:35.603451427 +0100 +@@ -744,6 +744,8 @@ AC_CHECK_FUNCS(nettle_cmac_kuznyechik_up LIBS=$save_LIBS # Check sonames of the linked libraries needed for FIPS selftests. @@ -36,7 +28,7 @@ index 96894b0be3..e4cf5eab81 100644 save_LIBS=$LIBS LIBS="$LIBS $GMP_LIBS" AC_MSG_CHECKING([gmp soname]) -@@ -755,9 +757,14 @@ if test -z "$gmp_so"; then +@@ -757,9 +759,14 @@ if test -z "$gmp_so"; then gmp_so=none fi AC_MSG_RESULT($gmp_so) @@ -52,7 +44,7 @@ index 96894b0be3..e4cf5eab81 100644 save_LIBS=$LIBS LIBS="$LIBS $NETTLE_LIBS" AC_MSG_CHECKING([nettle soname]) -@@ -773,7 +780,11 @@ fi +@@ -775,7 +782,11 @@ fi AC_MSG_RESULT($nettle_so) AC_DEFINE_UNQUOTED([NETTLE_LIBRARY_SONAME], ["$nettle_so"], [The soname of nettle library]) LIBS=$save_LIBS @@ -64,7 +56,7 @@ index 96894b0be3..e4cf5eab81 100644 save_LIBS=$LIBS LIBS="$LIBS $HOGWEED_LIBS" AC_MSG_CHECKING([hogweed soname]) -@@ -789,6 +800,7 @@ fi +@@ -791,6 +802,7 @@ fi AC_MSG_RESULT($hogweed_so) AC_DEFINE_UNQUOTED([HOGWEED_LIBRARY_SONAME], ["$hogweed_so"], [The soname of hogweed library]) LIBS=$save_LIBS @@ -72,33 +64,42 @@ index 96894b0be3..e4cf5eab81 100644 gnutls_so=libgnutls.so.`expr "$LT_CURRENT" - "$LT_AGE"` AC_DEFINE_UNQUOTED([GNUTLS_LIBRARY_SONAME], ["$gnutls_so"], [The soname of gnutls library]) -diff --git a/lib/fips.c b/lib/fips.c -index 54eb4a37d4..42124ecf4e 100644 ---- a/lib/fips.c -+++ b/lib/fips.c -@@ -149,7 +149,11 @@ void _gnutls_fips_mode_reset_zombie(void) +diff --color -ruNp a/lib/fips.c b/lib/fips.c +--- a/lib/fips.c 2022-12-15 11:06:16.868727731 +0100 ++++ b/lib/fips.c 2022-12-15 11:12:42.744303409 +0100 +@@ -155,7 +155,11 @@ void _gnutls_fips_mode_reset_zombie(void #define GNUTLS_LIBRARY_NAME GNUTLS_LIBRARY_SONAME #define NETTLE_LIBRARY_NAME NETTLE_LIBRARY_SONAME #define HOGWEED_LIBRARY_NAME HOGWEED_LIBRARY_SONAME + -+/* GMP can be statically linked. */ ++/* GMP can be statically linked */ +#ifdef GMP_LIBRARY_SONAME #define GMP_LIBRARY_NAME GMP_LIBRARY_SONAME +#endif #define HMAC_SIZE 32 #define HMAC_ALGO GNUTLS_MAC_SHA256 -@@ -168,7 +172,9 @@ typedef struct +@@ -173,7 +177,9 @@ struct hmac_file struct hmac_entry gnutls; struct hmac_entry nettle; struct hmac_entry hogweed; +#ifdef GMP_LIBRARY_SONAME struct hmac_entry gmp; +#endif - } hmac_file; + }; + + struct lib_paths +@@ -181,7 +187,9 @@ struct lib_paths + char gnutls[GNUTLS_PATH_MAX]; + char nettle[GNUTLS_PATH_MAX]; + char hogweed[GNUTLS_PATH_MAX]; ++#ifdef GMP_LIBRARY_SONAME + char gmp[GNUTLS_PATH_MAX]; ++#endif + }; - static int get_library_path(const char* lib, const char* symbol, char* path, size_t path_size) -@@ -259,8 +265,10 @@ static int handler(void *user, const char *section, const char *name, const char + /* +@@ -245,8 +253,10 @@ static int handler(void *user, const cha return lib_handler(&p->nettle, section, name, value); } else if (!strcmp(section, HOGWEED_LIBRARY_NAME)) { return lib_handler(&p->hogweed, section, name, value); @@ -109,42 +110,60 @@ index 54eb4a37d4..42124ecf4e 100644 } else { return 0; } -@@ -408,9 +416,11 @@ static int check_binary_integrity(void) - ret = check_lib_hmac(&file.hogweed, HOGWEED_LIBRARY_NAME, "nettle_mpz_sizeinbase_256_u"); +@@ -389,8 +399,10 @@ static int callback(struct dl_phdr_info + _gnutls_str_cpy(paths->nettle, GNUTLS_PATH_MAX, path); + else if (!strcmp(soname, HOGWEED_LIBRARY_SONAME)) + _gnutls_str_cpy(paths->hogweed, GNUTLS_PATH_MAX, path); ++#ifdef GMP_LIBRARY_SONAME + else if (!strcmp(soname, GMP_LIBRARY_SONAME)) + _gnutls_str_cpy(paths->gmp, GNUTLS_PATH_MAX, path); ++#endif + return 0; + } + +@@ -411,10 +423,12 @@ static int load_lib_paths(struct lib_pat + _gnutls_debug_log("Hogweed library path was not found\n"); + return gnutls_assert_val(GNUTLS_E_FILE_ERROR); + } ++#ifdef GMP_LIBRARY_SONAME + if (paths->gmp[0] == '\0') { + _gnutls_debug_log("Gmp library path was not found\n"); + return gnutls_assert_val(GNUTLS_E_FILE_ERROR); + } ++#endif + + return GNUTLS_E_SUCCESS; + } +@@ -467,9 +481,11 @@ static int check_binary_integrity(void) + ret = check_lib_hmac(&hmac.hogweed, paths.hogweed); if (ret < 0) return ret; +#ifdef GMP_LIBRARY_SONAME - ret = check_lib_hmac(&file.gmp, GMP_LIBRARY_NAME, "__gmpz_init"); + ret = check_lib_hmac(&hmac.gmp, paths.gmp); if (ret < 0) return ret; +#endif return 0; } -diff --git a/lib/fipshmac.c b/lib/fipshmac.c -index b091572bdf..363077f3e2 100644 ---- a/lib/fipshmac.c -+++ b/lib/fipshmac.c -@@ -159,10 +159,13 @@ int main(int argc, char **argv) - ret = print_lib_dl(HOGWEED_LIBRARY_SONAME, "nettle_mpz_sizeinbase_256_u"); - if (ret < 0) - return EXIT_FAILURE; -- -+ -+ /* GMP can be statically linked. */ +diff --color -ruNp a/lib/fipshmac.c b/lib/fipshmac.c +--- a/lib/fipshmac.c 2022-12-15 11:06:16.785726102 +0100 ++++ b/lib/fipshmac.c 2022-12-15 11:13:34.533320156 +0100 +@@ -107,8 +107,10 @@ static int callback(struct dl_phdr_info + return print_lib(path, soname); + if (!strcmp(soname, HOGWEED_LIBRARY_SONAME)) + return print_lib(path, soname); +#ifdef GMP_LIBRARY_SONAME - ret = print_lib_dl(GMP_LIBRARY_SONAME, "__gmpz_init"); - if (ret < 0) - return EXIT_FAILURE; + if (!strcmp(soname, GMP_LIBRARY_SONAME)) + return print_lib(path, soname); +#endif - - return EXIT_SUCCESS; + return 0; } -diff --git a/lib/global.c b/lib/global.c -index 1b372c15bd..9f3c7b22bd 100644 ---- a/lib/global.c -+++ b/lib/global.c -@@ -548,7 +548,9 @@ static const struct gnutls_library_config_st _gnutls_library_config[] = { + +diff --color -ruNp a/lib/global.c b/lib/global.c +--- a/lib/global.c 2022-12-15 11:06:16.061711888 +0100 ++++ b/lib/global.c 2022-12-15 11:08:35.604451446 +0100 +@@ -540,7 +540,9 @@ static const struct gnutls_library_confi { "libgnutls-soname", GNUTLS_LIBRARY_SONAME }, { "libnettle-soname", NETTLE_LIBRARY_SONAME }, { "libhogweed-soname", HOGWEED_LIBRARY_SONAME }, @@ -154,6 +173,3 @@ index 1b372c15bd..9f3c7b22bd 100644 { "hardware-features", HW_FEATURES }, { "tls-features", TLS_FEATURES }, { NULL, NULL } --- -2.37.1 - diff --git a/SOURCES/gnutls-3.7.7-aes-cbc-padding-support.patch b/SOURCES/gnutls-3.7.7-aes-cbc-padding-support.patch new file mode 100644 index 0000000..6273a0d --- /dev/null +++ b/SOURCES/gnutls-3.7.7-aes-cbc-padding-support.patch @@ -0,0 +1,433 @@ +diff --color -ruNp a/doc/Makefile.am b/doc/Makefile.am +--- a/doc/Makefile.am 2022-11-15 14:14:10.632725399 +0100 ++++ b/doc/Makefile.am 2022-11-15 14:14:40.252300863 +0100 +@@ -575,6 +575,7 @@ ENUMS += enums/gnutls_certificate_verifi + ENUMS += enums/gnutls_certificate_verify_flags + ENUMS += enums/gnutls_channel_binding_t + ENUMS += enums/gnutls_cipher_algorithm_t ++ENUMS += enums/gnutls_cipher_flags_t + ENUMS += enums/gnutls_close_request_t + ENUMS += enums/gnutls_compression_method_t + ENUMS += enums/gnutls_credentials_type_t +@@ -882,12 +883,16 @@ FUNCS += functions/gnutls_cipher_decrypt + FUNCS += functions/gnutls_cipher_decrypt.short + FUNCS += functions/gnutls_cipher_decrypt2 + FUNCS += functions/gnutls_cipher_decrypt2.short ++FUNCS += functions/gnutls_cipher_decrypt3 ++FUNCS += functions/gnutls_cipher_decrypt3.short + FUNCS += functions/gnutls_cipher_deinit + FUNCS += functions/gnutls_cipher_deinit.short + FUNCS += functions/gnutls_cipher_encrypt + FUNCS += functions/gnutls_cipher_encrypt.short + FUNCS += functions/gnutls_cipher_encrypt2 + FUNCS += functions/gnutls_cipher_encrypt2.short ++FUNCS += functions/gnutls_cipher_encrypt3 ++FUNCS += functions/gnutls_cipher_encrypt3.short + FUNCS += functions/gnutls_cipher_get + FUNCS += functions/gnutls_cipher_get.short + FUNCS += functions/gnutls_cipher_get_block_size +diff --color -ruNp a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am +--- a/doc/manpages/Makefile.am 2022-11-15 14:14:10.634725438 +0100 ++++ b/doc/manpages/Makefile.am 2022-11-15 14:14:40.254300902 +0100 +@@ -273,9 +273,11 @@ APIMANS += gnutls_check_version.3 + APIMANS += gnutls_cipher_add_auth.3 + APIMANS += gnutls_cipher_decrypt.3 + APIMANS += gnutls_cipher_decrypt2.3 ++APIMANS += gnutls_cipher_decrypt3.3 + APIMANS += gnutls_cipher_deinit.3 + APIMANS += gnutls_cipher_encrypt.3 + APIMANS += gnutls_cipher_encrypt2.3 ++APIMANS += gnutls_cipher_encrypt3.3 + APIMANS += gnutls_cipher_get.3 + APIMANS += gnutls_cipher_get_block_size.3 + APIMANS += gnutls_cipher_get_id.3 +diff --color -ruNp a/lib/crypto-api.c b/lib/crypto-api.c +--- a/lib/crypto-api.c 2022-11-15 14:14:11.036733248 +0100 ++++ b/lib/crypto-api.c 2022-11-15 14:14:40.255300921 +0100 +@@ -413,6 +413,166 @@ gnutls_cipher_decrypt2(gnutls_cipher_hd_ + } + + /** ++ * gnutls_cipher_encrypt3: ++ * @handle: is a #gnutls_cipher_hd_t type ++ * @ptext: the data to encrypt ++ * @ptext_len: the length of data to encrypt ++ * @ctext: the encrypted data ++ * @ctext_len: the length of encrypted data (initially must hold the maximum available size) ++ * @flags: flags for padding ++ * ++ * This function will encrypt the given data using the algorithm ++ * specified by the context. For block ciphers, @ptext_len is ++ * typically a multiple of the block size. If not, the caller can ++ * instruct the function to pad the last block according to @flags. ++ * Currently, the only available padding scheme is ++ * %GNUTLS_CIPHER_PADDING_PKCS7. ++ * ++ * If @ctext is not %NULL, it must hold enough space to store ++ * resulting cipher text. To check the required size, this function ++ * can be called with @ctext set to %NULL. Then @ctext_len will be ++ * updated without performing actual encryption. ++ * ++ * Returns: Zero or a negative error code on error. ++ * ++ * Since: 3.7.7 ++ **/ ++int ++gnutls_cipher_encrypt3(gnutls_cipher_hd_t handle, ++ const void *ptext, size_t ptext_len, ++ void *ctext, size_t *ctext_len, ++ unsigned flags) ++{ ++ api_cipher_hd_st *h = handle; ++ const cipher_entry_st *e = h->ctx_enc.e; ++ int block_size = _gnutls_cipher_get_block_size(e); ++ int ret = 0; ++ ++ if (unlikely(ctext_len == NULL)) { ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ } ++ ++ if (_gnutls_cipher_type(e) == CIPHER_BLOCK && ++ (flags & GNUTLS_CIPHER_PADDING_PKCS7)) { ++ size_t n, r; ++ uint8_t last_block[MAX_CIPHER_BLOCK_SIZE]; ++ const uint8_t *p = ptext; ++ uint8_t *c = ctext; ++ ++ if (!INT_ADD_OK(ptext_len, block_size, &n)) { ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ } ++ ++ n = (n / block_size) * block_size; ++ ++ if (!ctext) { ++ *ctext_len = n; ++ return 0; ++ } ++ ++ if (*ctext_len < n) { ++ return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); ++ } ++ ++ /* Encrypt up to the last complete block */ ++ r = ptext_len % block_size; ++ ++ ret = _gnutls_cipher_encrypt2(&h->ctx_enc, ++ ptext, ptext_len - r, ++ ctext, ptext_len - r); ++ if (ret < 0) { ++ goto error; ++ } ++ ++ /* Encrypt the last block with padding */ ++ gnutls_memset(last_block, block_size - r, sizeof(last_block)); ++ if (r > 0) { ++ memcpy(last_block, &p[ptext_len - r], r); ++ } ++ ret = _gnutls_cipher_encrypt2(&h->ctx_enc, ++ last_block, block_size, ++ &c[ptext_len - r], block_size); ++ if (ret < 0) { ++ goto error; ++ } ++ *ctext_len = n; ++ } else { ++ if (!ctext) { ++ *ctext_len = ptext_len; ++ return 0; ++ } ++ ++ ret = _gnutls_cipher_encrypt2(&h->ctx_enc, ptext, ptext_len, ++ ctext, *ctext_len); ++ if (ret < 0) { ++ goto error; ++ } ++ *ctext_len = ptext_len; ++ } ++ ++ error: ++ if (ret < 0) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR); ++ } else { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED); ++ } ++ return ret; ++} ++ ++/** ++ * gnutls_cipher_decrypt3: ++ * @handle: is a #gnutls_cipher_hd_t type ++ * @ctext: the data to decrypt ++ * @ctext_len: the length of data to decrypt ++ * @ptext: the decrypted data ++ * @ptext_len: the available length for decrypted data ++ * @flags: flags for padding ++ * ++ * This function will decrypt the given data using the algorithm ++ * specified by the context. If @flags is specified, padding for the ++ * decrypted data will be removed accordingly and @ptext_len will be ++ * updated. ++ * ++ * Returns: Zero or a negative error code on error. ++ * ++ * Since: 3.7.7 ++ **/ ++int ++gnutls_cipher_decrypt3(gnutls_cipher_hd_t handle, ++ const void *ctext, size_t ctext_len, ++ void *ptext, size_t *ptext_len, ++ unsigned flags) ++{ ++ api_cipher_hd_st *h = handle; ++ int ret; ++ ++ ret = gnutls_cipher_decrypt2(handle, ++ ctext, ctext_len, ++ ptext, *ptext_len); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK && ++ (flags & GNUTLS_CIPHER_PADDING_PKCS7)) { ++ uint8_t *p = ptext; ++ uint8_t padding = p[*ptext_len - 1]; ++ if (!padding || padding > _gnutls_cipher_get_block_size(h->ctx_enc.e)) { ++ return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); ++ } ++ /* Check that the prior bytes are all PADDING */ ++ for (size_t i = *ptext_len - padding; i < *ptext_len; i++) { ++ if (padding != p[*ptext_len - 1]) { ++ return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); ++ } ++ } ++ *ptext_len -= padding; ++ } ++ ++ return 0; ++} ++ ++/** + * gnutls_cipher_deinit: + * @handle: is a #gnutls_cipher_hd_t type + * +diff --color -ruNp a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h +--- a/lib/includes/gnutls/crypto.h 2022-05-10 13:57:43.000000000 +0200 ++++ b/lib/includes/gnutls/crypto.h 2022-11-15 14:14:40.256300941 +0100 +@@ -49,6 +49,28 @@ int gnutls_cipher_encrypt2(gnutls_cipher + const void *text, size_t textlen, + void *ciphertext, size_t ciphertextlen); + ++/** ++ * gnutls_cipher_flags_t: ++ * @GNUTLS_CIPHER_PADDING_PKCS7: Flag to indicate PKCS#7 padding ++ * ++ * Enumeration of flags to control block cipher padding, used by ++ * gnutls_cipher_encrypt3() and gnutls_cipher_decrypt3(). ++ * ++ * Since: 3.7.7 ++ */ ++typedef enum gnutls_cipher_flags_t { ++ GNUTLS_CIPHER_PADDING_PKCS7 = 1 ++} gnutls_cipher_flags_t; ++ ++int gnutls_cipher_encrypt3(gnutls_cipher_hd_t handle, ++ const void *ptext, size_t ptext_len, ++ void *ctext, size_t *ctext_len, ++ unsigned flags); ++int gnutls_cipher_decrypt3(gnutls_cipher_hd_t handle, ++ const void *ctext, size_t ctext_len, ++ void *ptext, size_t *ptext_len, ++ unsigned flags); ++ + void gnutls_cipher_set_iv(gnutls_cipher_hd_t handle, void *iv, + size_t ivlen); + +diff --color -ruNp a/lib/libgnutls.map b/lib/libgnutls.map +--- a/lib/libgnutls.map 2022-11-15 14:14:11.142735308 +0100 ++++ b/lib/libgnutls.map 2022-11-15 14:14:40.256300941 +0100 +@@ -1403,6 +1403,8 @@ GNUTLS_3_7_7 + { + global: + gnutls_fips140_run_self_tests; ++ gnutls_cipher_encrypt3; ++ gnutls_cipher_decrypt3; + local: + *; + } GNUTLS_3_7_5; +diff --color -ruNp a/tests/cipher-padding.c b/tests/cipher-padding.c +--- a/tests/cipher-padding.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/tests/cipher-padding.c 2022-11-15 14:14:40.258300980 +0100 +@@ -0,0 +1,160 @@ ++/* ++ * Copyright (C) 2022 Red Hat, Inc. ++ * ++ * Author: Daiki Ueno ++ * ++ * This file is part of GnuTLS. ++ * ++ * The GnuTLS is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public License ++ * as published by the Free Software Foundation; either version 2.1 of ++ * the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program. If not, see ++ * ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include "utils.h" ++ ++static void tls_log_func(int level, const char *str) ++{ ++ fprintf(stderr, "<%d>| %s", level, str); ++} ++ ++#define CLAMP(x, b) (((x) + (b)) / (b)) * (b) ++ ++static void ++start(gnutls_cipher_algorithm_t algo, size_t plaintext_size, unsigned int flags) ++{ ++ int ret; ++ gnutls_cipher_hd_t ch; ++ uint8_t key16[64]; ++ uint8_t iv16[32]; ++ uint8_t plaintext[128]; ++ uint8_t ciphertext[128]; ++ size_t block_size; ++ size_t size; ++ gnutls_datum_t key, iv; ++ ++ success("%s %zu %u\n", ++ gnutls_cipher_get_name(algo), plaintext_size, flags); ++ ++ block_size = gnutls_cipher_get_block_size(algo); ++ ++ key.data = key16; ++ key.size = gnutls_cipher_get_key_size(algo); ++ assert(key.size <= sizeof(key16)); ++ ++ iv.data = iv16; ++ iv.size = gnutls_cipher_get_iv_size(algo); ++ assert(iv.size <= sizeof(iv16)); ++ ++ memset(iv.data, 0xff, iv.size); ++ memset(key.data, 0xfe, key.size); ++ memset(plaintext, 0xfa, sizeof(plaintext)); ++ ++ ret = gnutls_cipher_init(&ch, algo, &key, &iv); ++ if (ret < 0) { ++ fail("gnutls_cipher_init failed\n"); ++ } ++ ++ /* Check overflow if PKCS#7 is requested */ ++ if (flags & GNUTLS_CIPHER_PADDING_PKCS7) { ++ ret = gnutls_cipher_encrypt3(ch, ++ plaintext, SIZE_MAX, ++ NULL, &size, ++ flags); ++ if (ret != GNUTLS_E_INVALID_REQUEST) { ++ fail("gnutls_cipher_encrypt3 succeeded\n"); ++ } ++ } ++ ++ /* Get the ciphertext size */ ++ ret = gnutls_cipher_encrypt3(ch, ++ plaintext, plaintext_size, ++ NULL, &size, ++ flags); ++ if (ret < 0) { ++ fail("gnutls_cipher_encrypt3 failed\n"); ++ } ++ ++ if (flags & GNUTLS_CIPHER_PADDING_PKCS7) { ++ if (size <= plaintext_size) { ++ fail("no padding appended\n"); ++ } ++ if (size != CLAMP(plaintext_size, block_size)) { ++ fail("size does not match: %zu (expected %zu)\n", ++ size, CLAMP(plaintext_size, block_size)); ++ } ++ } else { ++ if (size != plaintext_size) { ++ fail("size does not match: %zu (expected %zu)\n", ++ size, plaintext_size); ++ } ++ } ++ ++ /* Encrypt with padding */ ++ ret = gnutls_cipher_encrypt3(ch, ++ plaintext, plaintext_size, ++ ciphertext, &size, ++ flags); ++ if (ret < 0) { ++ fail("gnutls_cipher_encrypt3 failed\n"); ++ } ++ ++ /* Decrypt with padding */ ++ ret = gnutls_cipher_decrypt3(ch, ++ ciphertext, size, ++ ciphertext, &size, ++ flags); ++ if (ret < 0) { ++ fail("gnutls_cipher_encrypt3 failed\n"); ++ } ++ ++ if (size != plaintext_size) { ++ fail("size does not match: %zu (expected %zu)\n", ++ size, plaintext_size); ++ } ++ ++ if (memcmp(ciphertext, plaintext, size) != 0) { ++ fail("plaintext does not match\n"); ++ } ++ ++ gnutls_cipher_deinit(ch); ++} ++ ++void doit(void) { ++ int ret; ++ ++ gnutls_global_set_log_function(tls_log_func); ++ if (debug) { ++ gnutls_global_set_log_level(4711); ++ } ++ ++ ret = global_init(); ++ if (ret < 0) { ++ fail("Cannot initialize library\n"); ++ } ++ ++ start(GNUTLS_CIPHER_AES_128_CBC, 0, GNUTLS_CIPHER_PADDING_PKCS7); ++ start(GNUTLS_CIPHER_AES_128_CBC, 11, GNUTLS_CIPHER_PADDING_PKCS7); ++ start(GNUTLS_CIPHER_AES_128_CBC, 77, GNUTLS_CIPHER_PADDING_PKCS7); ++ start(GNUTLS_CIPHER_AES_128_CBC, 80, GNUTLS_CIPHER_PADDING_PKCS7); ++ ++ start(GNUTLS_CIPHER_AES_128_CBC, 0, 0); ++ start(GNUTLS_CIPHER_AES_128_CBC, 80, 0); ++ ++ gnutls_global_deinit(); ++} +diff --color -ruNp a/tests/Makefile.am b/tests/Makefile.am +--- a/tests/Makefile.am 2022-11-15 14:14:11.144735347 +0100 ++++ b/tests/Makefile.am 2022-11-15 14:14:40.257300960 +0100 +@@ -233,7 +233,7 @@ ctests += mini-record-2 simple gnutls_hm + tls13-without-timeout-func buffer status-request-revoked \ + set_x509_ocsp_multi_cli kdf-api keylog-func handshake-write \ + x509cert-dntypes id-on-xmppAddr tls13-compat-mode ciphersuite-name \ +- x509-upnconstraint xts-key-check pkcs7-verify-double-free \ ++ x509-upnconstraint cipher-padding xts-key-check pkcs7-verify-double-free \ + fips-rsa-sizes tls12-rehandshake-ticket + + ctests += tls-channel-binding diff --git a/SOURCES/gnutls-3.7.8-clear-session-ticket.patch b/SOURCES/gnutls-3.7.8-clear-session-ticket.patch new file mode 100644 index 0000000..5c78c73 --- /dev/null +++ b/SOURCES/gnutls-3.7.8-clear-session-ticket.patch @@ -0,0 +1,215 @@ +diff --color -ruNp a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c +--- a/lib/ext/session_ticket.c 2022-05-10 13:55:00.000000000 +0200 ++++ b/lib/ext/session_ticket.c 2022-11-15 13:30:20.491830382 +0100 +@@ -624,6 +624,12 @@ gnutls_session_ticket_enable_server(gnut + return 0; + } + ++void ++_gnutls_session_ticket_disable_server(gnutls_session_t session) ++{ ++ session->internals.flags |= GNUTLS_NO_TICKETS; ++} ++ + /* + * Return zero if session tickets haven't been enabled. + */ +diff --color -ruNp a/lib/ext/session_ticket.h b/lib/ext/session_ticket.h +--- a/lib/ext/session_ticket.h 2022-02-22 15:34:48.000000000 +0100 ++++ b/lib/ext/session_ticket.h 2022-11-15 13:30:20.491830382 +0100 +@@ -36,5 +36,6 @@ int _gnutls_encrypt_session_ticket(gnutl + int _gnutls_decrypt_session_ticket(gnutls_session_t session, + const gnutls_datum_t *ticket_data, + gnutls_datum_t *state); ++void _gnutls_session_ticket_disable_server(gnutls_session_t session); + + #endif /* GNUTLS_LIB_EXT_SESSION_TICKET_H */ +diff --color -ruNp a/lib/libgnutls.map b/lib/libgnutls.map +--- a/lib/libgnutls.map 2022-11-15 13:12:57.781688194 +0100 ++++ b/lib/libgnutls.map 2022-11-15 13:30:20.492830401 +0100 +@@ -1510,4 +1510,6 @@ GNUTLS_PRIVATE_3_4 { + _gnutls_buffer_clear; + # needed by tests/cipher-alignment + _gnutls_crypto_register_cipher; ++ # needed by tests/tls12-rehandshake-cert-ticket ++ _gnutls_session_ticket_disable_server; + } GNUTLS_3_4; +diff --color -ruNp a/lib/state.c b/lib/state.c +--- a/lib/state.c 2022-05-16 17:10:08.000000000 +0200 ++++ b/lib/state.c 2022-11-15 13:30:20.493830420 +0100 +@@ -545,6 +545,7 @@ void _gnutls_handshake_internal_state_cl + session->internals.tfo.connect_addrlen = 0; + session->internals.tfo.connect_only = 0; + session->internals.early_data_received = 0; ++ session->internals.session_ticket_renew = 0; + } + + /** +diff --color -ruNp a/tests/Makefile.am b/tests/Makefile.am +--- a/tests/Makefile.am 2022-11-15 13:12:58.209696462 +0100 ++++ b/tests/Makefile.am 2022-11-15 13:30:20.494830440 +0100 +@@ -234,7 +234,7 @@ ctests += mini-record-2 simple gnutls_hm + set_x509_ocsp_multi_cli kdf-api keylog-func handshake-write \ + x509cert-dntypes id-on-xmppAddr tls13-compat-mode ciphersuite-name \ + x509-upnconstraint xts-key-check pkcs7-verify-double-free \ +- fips-rsa-sizes ++ fips-rsa-sizes tls12-rehandshake-ticket + + ctests += tls-channel-binding + +diff --color -ruNp a/tests/tls12-rehandshake-ticket.c b/tests/tls12-rehandshake-ticket.c +--- a/tests/tls12-rehandshake-ticket.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/tests/tls12-rehandshake-ticket.c 2022-11-15 13:30:20.495830459 +0100 +@@ -0,0 +1,152 @@ ++/* ++ * Copyright (C) 2022 Red Hat, Inc. ++ * ++ * Author: Daiki Ueno ++ * ++ * This file is part of GnuTLS. ++ * ++ * GnuTLS is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GnuTLS is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program. If not, see ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include "cert-common.h" ++ ++#include "utils.h" ++#include "eagain-common.h" ++ ++const char *side = ""; ++ ++static void tls_log_func(int level, const char *str) ++{ ++ fprintf(stderr, "%s|<%d>| %s", side, level, str); ++} ++ ++#define MAX_BUF 1024 ++ ++void _gnutls_session_ticket_disable_server(gnutls_session_t session); ++ ++static void run(void) ++{ ++ char buffer[MAX_BUF + 1]; ++ /* Server stuff. */ ++ gnutls_certificate_credentials_t scred; ++ gnutls_session_t server; ++ gnutls_datum_t session_ticket_key = { NULL, 0 }; ++ int sret; ++ /* Client stuff. */ ++ gnutls_certificate_credentials_t ccred; ++ gnutls_session_t client; ++ int cret; ++ ++ /* General init. */ ++ global_init(); ++ gnutls_global_set_log_function(tls_log_func); ++ if (debug) ++ gnutls_global_set_log_level(9); ++ ++ /* Init server */ ++ assert(gnutls_certificate_allocate_credentials(&scred) >= 0); ++ assert(gnutls_certificate_set_x509_key_mem(scred, ++ &server_ca3_localhost_cert, ++ &server_ca3_key, ++ GNUTLS_X509_FMT_PEM) >= 0); ++ assert(gnutls_certificate_set_x509_trust_mem(scred, ++ &ca3_cert, ++ GNUTLS_X509_FMT_PEM) >= 0); ++ ++ assert(gnutls_init(&server, GNUTLS_SERVER) >= 0); ++ gnutls_certificate_server_set_request(server, GNUTLS_CERT_REQUEST); ++ assert(gnutls_priority_set_direct(server, ++ "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.1:+VERS-TLS1.2", ++ NULL) >= 0); ++ ++ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, scred); ++ gnutls_transport_set_push_function(server, server_push); ++ gnutls_transport_set_pull_function(server, server_pull); ++ gnutls_transport_set_ptr(server, server); ++ ++ gnutls_session_ticket_key_generate(&session_ticket_key); ++ gnutls_session_ticket_enable_server(server, &session_ticket_key); ++ ++ /* Init client */ ++ assert(gnutls_certificate_allocate_credentials(&ccred) >= 0); ++ assert(gnutls_certificate_set_x509_key_mem ++ (ccred, &cli_ca3_cert_chain, &cli_ca3_key, GNUTLS_X509_FMT_PEM) >= 0); ++ assert(gnutls_certificate_set_x509_trust_mem ++ (ccred, &ca3_cert, GNUTLS_X509_FMT_PEM) >= 0); ++ ++ gnutls_init(&client, GNUTLS_CLIENT); ++ assert(gnutls_priority_set_direct(client, ++ "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.1:+VERS-TLS1.2", ++ NULL) >= 0); ++ ++ assert(gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, ccred) >= 0); ++ ++ gnutls_transport_set_push_function(client, client_push); ++ gnutls_transport_set_pull_function(client, client_pull); ++ gnutls_transport_set_ptr(client, client); ++ ++ HANDSHAKE(client, server); ++ ++ /* Server initiates rehandshake */ ++ switch_side("server"); ++ sret = gnutls_rehandshake(server); ++ if (sret < 0) { ++ fail("Error sending %d byte packet: %s\n", ++ (int)sizeof(buffer), gnutls_strerror(sret)); ++ } else if (debug) ++ success("server: starting rehandshake\n"); ++ ++ /* Stop sending session ticket */ ++ _gnutls_session_ticket_disable_server(server); ++ ++ /* Client gets notified with rehandshake */ ++ switch_side("client"); ++ do { ++ do { ++ cret = gnutls_record_recv(client, buffer, MAX_BUF); ++ } while (cret == GNUTLS_E_AGAIN || cret == GNUTLS_E_INTERRUPTED); ++ } while (cret > 0); ++ ++ if (cret != GNUTLS_E_REHANDSHAKE) { ++ fail("client: Error receiving rehandshake: %s\n", ++ gnutls_strerror(cret)); ++ } ++ ++ HANDSHAKE(client, server); ++ ++ gnutls_bye(client, GNUTLS_SHUT_WR); ++ gnutls_bye(server, GNUTLS_SHUT_WR); ++ ++ gnutls_deinit(client); ++ gnutls_deinit(server); ++ ++ gnutls_certificate_free_credentials(scred); ++ gnutls_certificate_free_credentials(ccred); ++ ++ gnutls_free(session_ticket_key.data); ++ ++ gnutls_global_deinit(); ++ reset_buffers(); ++} ++ ++void doit(void) ++{ ++ run(); ++} diff --git a/SOURCES/gnutls-3.7.8-fips-pct-dh.patch b/SOURCES/gnutls-3.7.8-fips-pct-dh.patch new file mode 100644 index 0000000..c38132e --- /dev/null +++ b/SOURCES/gnutls-3.7.8-fips-pct-dh.patch @@ -0,0 +1,58 @@ +From 51b721b69fd08ef1c4c4989f5e12b643e170ff56 Mon Sep 17 00:00:00 2001 +From: Pedro Monreal +Date: Thu, 16 Feb 2023 17:02:38 +0100 +Subject: [PATCH] pk: extend pair-wise consistency to cover DH key generation + +Perform SP800 56A (rev 3) 5.6.2.1.4 Owner Assurance of Pair-wise +Consistency check, even if we only support ephemeral DH, as it is +required by FIPS 140-3 IG 10.3.A. + +Signed-off-by: Pedro Monreal +Co-authored-by: Daiki Ueno +--- + lib/nettle/pk.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c +index d30bca594f..bd9c1b4c74 100644 +--- a/lib/nettle/pk.c ++++ b/lib/nettle/pk.c +@@ -2642,6 +2642,35 @@ static int pct_test(gnutls_pk_algorithm_t algo, + } + break; + case GNUTLS_PK_DH: ++ { ++ mpz_t y; ++ ++ /* Perform SP800 56A (rev 3) 5.6.2.1.4 Owner Assurance ++ * of Pair-wise Consistency check, even if we only ++ * support ephemeral DH, as it is required by FIPS ++ * 140-3 IG 10.3.A. ++ * ++ * Use the private key, x, along with the generator g ++ * and prime modulus p included in the domain ++ * parameters associated with the key pair to compute ++ * g^x mod p. Compare the result to the public key, y. ++ */ ++ mpz_init(y); ++ mpz_powm(y, ++ TOMPZ(params->params[DSA_G]), ++ TOMPZ(params->params[DSA_X]), ++ TOMPZ(params->params[DSA_P])); ++ if (unlikely ++ (mpz_cmp(y, TOMPZ(params->params[DSA_Y])) != 0)) { ++ ret = ++ gnutls_assert_val ++ (GNUTLS_E_PK_GENERATION_ERROR); ++ mpz_clear(y); ++ goto cleanup; ++ } ++ mpz_clear(y); ++ break; ++ } + case GNUTLS_PK_ECDH_X25519: + case GNUTLS_PK_ECDH_X448: + ret = 0; +-- +2.39.2 + diff --git a/SOURCES/gnutls-3.7.8-integrity-check.patch b/SOURCES/gnutls-3.7.8-integrity-check.patch new file mode 100644 index 0000000..8ff5fb0 --- /dev/null +++ b/SOURCES/gnutls-3.7.8-integrity-check.patch @@ -0,0 +1,54 @@ +diff --color -ruNp a/lib/fips.c b/lib/fips.c +--- a/lib/fips.c 2022-11-15 16:10:56.183185457 +0100 ++++ b/lib/fips.c 2022-11-15 16:10:23.488530716 +0100 +@@ -360,11 +360,6 @@ static int check_lib_hmac(struct hmac_en + return gnutls_assert_val(ret); + } + +- if (strncmp(entry->path, path, GNUTLS_PATH_MAX)) { +- _gnutls_debug_log("Library path for %s does not match with HMAC file\n", lib); +- return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); +- } +- + _gnutls_debug_log("Loading: %s\n", path); + ret = gnutls_load_file(path, &data); + if (ret < 0) { +diff --color -ruNp a/lib/fipshmac.c b/lib/fipshmac.c +--- a/lib/fipshmac.c 2022-11-15 16:10:56.183185457 +0100 ++++ b/lib/fipshmac.c 2022-11-15 16:10:23.489530737 +0100 +@@ -102,20 +102,30 @@ static int get_hmac(const char *path, ch + static int print_lib_path(const char *path) + { + int ret; ++ char *real_path = NULL; + char hmac[HMAC_STR_SIZE]; + +- ret = get_hmac(path, hmac, sizeof(hmac)); ++ real_path = canonicalize_file_name(path); ++ if (real_path == NULL) { ++ fprintf(stderr, "Could not get realpath from %s\n", path); ++ ret = GNUTLS_E_FILE_ERROR; ++ goto cleanup; ++ } ++ ++ ret = get_hmac(real_path, hmac, sizeof(hmac)); + if (ret < 0) { + fprintf(stderr, "Could not calculate HMAC for %s: %s\n", +- last_component(path), gnutls_strerror(ret)); +- return ret; ++ last_component(real_path), gnutls_strerror(ret)); ++ goto cleanup; + } + + printf("[%s]\n", last_component(path)); +- printf("path = %s\n", path); ++ printf("path = %s\n", real_path); + printf("hmac = %s\n", hmac); + +- return 0; ++cleanup: ++ free(real_path); ++ return ret; + } + + static int print_lib_dl(const char *lib, const char *sym) diff --git a/SOURCES/gnutls-3.7.8-revert-hmac-name.patch b/SOURCES/gnutls-3.7.8-revert-hmac-name.patch new file mode 100644 index 0000000..fa1a672 --- /dev/null +++ b/SOURCES/gnutls-3.7.8-revert-hmac-name.patch @@ -0,0 +1,534 @@ +diff --color -ruNp a/configure.ac b/configure.ac +--- a/configure.ac 2022-05-27 09:17:26.000000000 +0200 ++++ b/configure.ac 2022-12-15 11:00:18.830698584 +0100 +@@ -619,6 +619,8 @@ if [ test "$enable_fips" = "yes" ];then + if test "x$fips_module_version" != xnone; then + AC_DEFINE_UNQUOTED([FIPS_MODULE_VERSION], ["$fips_module_version"], [The FIPS140 module version]) + fi ++ ++ AC_CHECK_FUNCS(dl_iterate_phdr) + else + enable_fips=no + AC_MSG_WARN([[ +diff --color -ruNp a/lib/fips.c b/lib/fips.c +--- a/lib/fips.c 2022-12-15 10:59:57.460279029 +0100 ++++ b/lib/fips.c 2022-12-15 11:00:18.831698604 +0100 +@@ -23,9 +23,11 @@ + #include + #include + #include ++#include "dirname.h" + #include "errors.h" + #include "file.h" + #include "inih/ini.h" ++#include "str.h" + #include + #include + #include +@@ -34,6 +36,10 @@ + + #include "gthreads.h" + ++#ifdef HAVE_DL_ITERATE_PHDR ++#include ++#endif ++ + unsigned int _gnutls_lib_state = LIB_STATE_POWERON; + + struct gnutls_fips140_context_st { +@@ -153,7 +159,6 @@ void _gnutls_fips_mode_reset_zombie(void + + #define HMAC_SIZE 32 + #define HMAC_ALGO GNUTLS_MAC_SHA256 +-#define HMAC_FILE_NAME ".gnutls.hmac" + #define HMAC_FORMAT_VERSION 1 + + struct hmac_entry +@@ -162,51 +167,32 @@ struct hmac_entry + uint8_t hmac[HMAC_SIZE]; + }; + +-typedef struct ++struct hmac_file + { + int version; + struct hmac_entry gnutls; + struct hmac_entry nettle; + struct hmac_entry hogweed; + struct hmac_entry gmp; +-} hmac_file; ++}; + +-static int get_library_path(const char* lib, const char* symbol, char* path, size_t path_size) ++struct lib_paths + { +- int ret; +- void *dl, *sym; +- Dl_info info; +- +- dl = dlopen(lib, RTLD_LAZY); +- if (dl == NULL) +- return gnutls_assert_val(GNUTLS_E_FILE_ERROR); +- +- sym = dlsym(dl, symbol); +- if (sym == NULL) { +- ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR); +- goto cleanup; +- } +- +- ret = dladdr(sym, &info); +- if (ret == 0) { +- ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR); +- goto cleanup; +- } +- +- ret = snprintf(path, path_size, "%s", info.dli_fname); +- if ((size_t)ret >= path_size) { +- ret = gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); +- goto cleanup; +- } +- +- ret = 0; +-cleanup: +- dlclose(dl); +- return ret; +-} ++ char gnutls[GNUTLS_PATH_MAX]; ++ char nettle[GNUTLS_PATH_MAX]; ++ char hogweed[GNUTLS_PATH_MAX]; ++ char gmp[GNUTLS_PATH_MAX]; ++}; + +-/* Parses hmac data and copies hex value into dest. ++/* ++ * get_hmac: ++ * @dest: buffer for the hex value ++ * @value: hmac value ++ * ++ * Parses hmac data and copies hex value into dest. + * dest must point to at least HMAC_SIZE amount of memory ++ * ++ * Returns: 0 on success, a negative error code otherwise + */ + static int get_hmac(uint8_t *dest, const char *value) + { +@@ -245,7 +231,7 @@ lib_handler(struct hmac_entry *entry, + + static int handler(void *user, const char *section, const char *name, const char *value) + { +- hmac_file *p = (hmac_file *)user; ++ struct hmac_file *p = (struct hmac_file *)user; + + if (!strcmp(section, "global")) { + if (!strcmp(name, "format-version")) { +@@ -267,24 +253,29 @@ static int handler(void *user, const cha + return 1; + } + +-static int get_hmac_path(char *mac_file, size_t mac_file_size) ++/* ++ * get_hmac_path: ++ * @mac_file: buffer where the hmac file path will be written to ++ * @mac_file_size: size of the mac_file buffer ++ * @gnutls_path: path to the gnutls library, used to deduce hmac file path ++ * ++ * Deduces hmac file path from the gnutls library path. ++ * ++ * Returns: 0 on success, a negative error code otherwise ++ */ ++static int get_hmac_path(char *mac_file, size_t mac_file_size, const char *gnutls_path) + { + int ret; + char *p; +- char file[GNUTLS_PATH_MAX]; + +- ret = get_library_path(GNUTLS_LIBRARY_NAME, "gnutls_global_init", +- file, sizeof(file)); +- if (ret < 0) +- return ret; +- +- p = strrchr(file, '/'); ++ p = strrchr(gnutls_path, '/'); + + if (p == NULL) +- ret = snprintf(mac_file, mac_file_size, HMAC_FILE_NAME); ++ ret = snprintf(mac_file, mac_file_size, ".%s.hmac", gnutls_path); + else +- ret = snprintf(mac_file, mac_file_size, +- "%.*s/"HMAC_FILE_NAME, (int)(p - file), file); ++ ret = snprintf(mac_file, mac_file_size, "%.*s/.%s.hmac", ++ (int)(p - gnutls_path), gnutls_path, p + 1); ++ + if ((size_t)ret >= mac_file_size) + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + +@@ -293,10 +284,11 @@ static int get_hmac_path(char *mac_file, + return GNUTLS_E_SUCCESS; + + if (p == NULL) +- ret = snprintf(mac_file, mac_file_size, "fipscheck/"HMAC_FILE_NAME); ++ ret = snprintf(mac_file, mac_file_size, "fipscheck/.%s.hmac", gnutls_path); + else +- ret = snprintf(mac_file, mac_file_size, +- "%.*s/fipscheck/"HMAC_FILE_NAME, (int)(p - file), file); ++ ret = snprintf(mac_file, mac_file_size, "%.*s/fipscheck/.%s.hmac", ++ (int)(p - gnutls_path), gnutls_path, p + 1); ++ + if ((size_t)ret >= mac_file_size) + return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); + +@@ -307,51 +299,52 @@ static int get_hmac_path(char *mac_file, + return GNUTLS_E_FILE_ERROR; + } + +-static int load_hmac_file(hmac_file *p) ++/* ++ * load_hmac_file: ++ * @hmac_file: hmac file structure ++ * @hmac_path: path to the hmac file ++ * ++ * Loads the hmac file into the hmac file structure. ++ * ++ * Returns: 0 on success, a negative error code otherwise ++ */ ++static int load_hmac_file(struct hmac_file *hmac_file, const char *hmac_path) + { + int ret; + FILE *stream; +- char hmac_path[GNUTLS_PATH_MAX]; +- +- ret = get_hmac_path(hmac_path, sizeof(hmac_path)); +- if (ret < 0) +- return gnutls_assert_val(ret); + + stream = fopen(hmac_path, "r"); + if (stream == NULL) + return gnutls_assert_val(GNUTLS_E_FILE_ERROR); + +- gnutls_memset(p, 0, sizeof(*p)); +- ret = ini_parse_file(stream, handler, p); ++ gnutls_memset(hmac_file, 0, sizeof(*hmac_file)); ++ ret = ini_parse_file(stream, handler, hmac_file); + fclose(stream); + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + +- if (p->version != HMAC_FORMAT_VERSION) ++ if (hmac_file->version != HMAC_FORMAT_VERSION) + return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + + return 0; + } + +-/* Run an HMAC using the key above on the library binary data. +- * Returns 0 on success and negative value on error. ++/* ++ * check_lib_hmac: ++ * @entry: hmac file entry ++ * @path: path to the library which hmac should be compared ++ * ++ * Verify that HMAC from hmac file entry matches HMAC of given library. ++ * ++ * Returns: 0 on successful HMAC verification, a negative error code otherwise + */ +-static int check_lib_hmac(struct hmac_entry *entry, +- const char *lib, const char *sym) ++static int check_lib_hmac(struct hmac_entry *entry, const char *path) + { + int ret; + unsigned prev; +- char path[GNUTLS_PATH_MAX]; + uint8_t hmac[HMAC_SIZE]; + gnutls_datum_t data; + +- ret = get_library_path(lib, sym, path, sizeof(path)); +- if (ret < 0) { +- _gnutls_debug_log("Could not get lib path for %s: %s\n", +- lib, gnutls_strerror(ret)); +- return gnutls_assert_val(ret); +- } +- + _gnutls_debug_log("Loading: %s\n", path); + ret = gnutls_load_file(path, &data); + if (ret < 0) { +@@ -382,28 +375,99 @@ static int check_lib_hmac(struct hmac_en + return 0; + } + ++#ifdef HAVE_DL_ITERATE_PHDR ++ ++static int callback(struct dl_phdr_info *info, size_t size, void *data) ++{ ++ const char *path = info->dlpi_name; ++ const char *soname = last_component(path); ++ struct lib_paths *paths = (struct lib_paths *)data; ++ ++ if (!strcmp(soname, GNUTLS_LIBRARY_SONAME)) ++ _gnutls_str_cpy(paths->gnutls, GNUTLS_PATH_MAX, path); ++ else if (!strcmp(soname, NETTLE_LIBRARY_SONAME)) ++ _gnutls_str_cpy(paths->nettle, GNUTLS_PATH_MAX, path); ++ else if (!strcmp(soname, HOGWEED_LIBRARY_SONAME)) ++ _gnutls_str_cpy(paths->hogweed, GNUTLS_PATH_MAX, path); ++ else if (!strcmp(soname, GMP_LIBRARY_SONAME)) ++ _gnutls_str_cpy(paths->gmp, GNUTLS_PATH_MAX, path); ++ return 0; ++} ++ ++static int load_lib_paths(struct lib_paths *paths) ++{ ++ memset(paths, 0, sizeof(*paths)); ++ dl_iterate_phdr(callback, paths); ++ ++ if (paths->gnutls[0] == '\0') { ++ _gnutls_debug_log("Gnutls library path was not found\n"); ++ return gnutls_assert_val(GNUTLS_E_FILE_ERROR); ++ } ++ if (paths->nettle[0] == '\0') { ++ _gnutls_debug_log("Nettle library path was not found\n"); ++ return gnutls_assert_val(GNUTLS_E_FILE_ERROR); ++ } ++ if (paths->hogweed[0] == '\0') { ++ _gnutls_debug_log("Hogweed library path was not found\n"); ++ return gnutls_assert_val(GNUTLS_E_FILE_ERROR); ++ } ++ if (paths->gmp[0] == '\0') { ++ _gnutls_debug_log("Gmp library path was not found\n"); ++ return gnutls_assert_val(GNUTLS_E_FILE_ERROR); ++ } ++ ++ return GNUTLS_E_SUCCESS; ++} ++ ++#else ++ ++static int load_lib_paths(struct lib_paths *paths) ++{ ++ (void)paths; ++ _gnutls_debug_log("Function dl_iterate_phdr is missing\n"); ++ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ++} ++ ++#endif /* HAVE_DL_ITERATE_PHDR */ ++ + static int check_binary_integrity(void) + { + int ret; +- hmac_file file; ++ struct lib_paths paths; ++ struct hmac_file hmac; ++ char hmac_path[GNUTLS_PATH_MAX]; ++ ++ ret = load_lib_paths(&paths); ++ if (ret < 0) { ++ _gnutls_debug_log("Could not load library paths: %s\n", ++ gnutls_strerror(ret)); ++ return ret; ++ } ++ ++ ret = get_hmac_path(hmac_path, sizeof(hmac_path), paths.gnutls); ++ if (ret < 0) { ++ _gnutls_debug_log("Could not get hmac file path: %s\n", ++ gnutls_strerror(ret)); ++ return ret; ++ } + +- ret = load_hmac_file(&file); ++ ret = load_hmac_file(&hmac, hmac_path); + if (ret < 0) { + _gnutls_debug_log("Could not load hmac file: %s\n", + gnutls_strerror(ret)); + return ret; + } + +- ret = check_lib_hmac(&file.gnutls, GNUTLS_LIBRARY_NAME, "gnutls_global_init"); ++ ret = check_lib_hmac(&hmac.gnutls, paths.gnutls); + if (ret < 0) + return ret; +- ret = check_lib_hmac(&file.nettle, NETTLE_LIBRARY_NAME, "nettle_aes_set_encrypt_key"); ++ ret = check_lib_hmac(&hmac.nettle, paths.nettle); + if (ret < 0) + return ret; +- ret = check_lib_hmac(&file.hogweed, HOGWEED_LIBRARY_NAME, "nettle_mpz_sizeinbase_256_u"); ++ ret = check_lib_hmac(&hmac.hogweed, paths.hogweed); + if (ret < 0) + return ret; +- ret = check_lib_hmac(&file.gmp, GMP_LIBRARY_NAME, "__gmpz_init"); ++ ret = check_lib_hmac(&hmac.gmp, paths.gmp); + if (ret < 0) + return ret; + +diff --color -ruNp a/lib/fipshmac.c b/lib/fipshmac.c +--- a/lib/fipshmac.c 2022-12-15 10:59:57.461279049 +0100 ++++ b/lib/fipshmac.c 2022-12-15 11:00:18.832698623 +0100 +@@ -22,12 +22,14 @@ + + #include "config.h" + +-#include +-#include +-#include +-#include + #include + #include ++ ++#ifdef HAVE_DL_ITERATE_PHDR ++ ++#include ++#include ++#include + #include "dirname.h" + #include "errors.h" + +@@ -36,40 +38,6 @@ + #define HMAC_ALGO GNUTLS_MAC_SHA256 + #define HMAC_STR_SIZE (2 * HMAC_SIZE + 1) + +-static int get_path(const char *lib, const char *symbol, char *path, size_t path_size) +-{ +- int ret; +- void *dl, *sym; +- Dl_info info; +- +- dl = dlopen(lib, RTLD_LAZY); +- if (dl == NULL) +- return gnutls_assert_val(GNUTLS_E_FILE_ERROR); +- +- sym = dlsym(dl, symbol); +- if (sym == NULL) { +- ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR); +- goto cleanup; +- } +- +- ret = dladdr(sym, &info); +- if (ret == 0) { +- ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR); +- goto cleanup; +- } +- +- ret = snprintf(path, path_size, "%s", info.dli_fname); +- if ((size_t)ret >= path_size) { +- ret = gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER); +- goto cleanup; +- } +- +- ret = 0; +-cleanup: +- dlclose(dl); +- return ret; +-} +- + static int get_hmac(const char *path, char *hmac, size_t hmac_size) + { + int ret; +@@ -99,7 +67,7 @@ static int get_hmac(const char *path, ch + return 0; + } + +-static int print_lib_path(const char *path) ++static int print_lib(const char *path, const char *soname) + { + int ret; + char *real_path = NULL; +@@ -119,7 +87,7 @@ static int print_lib_path(const char *pa + goto cleanup; + } + +- printf("[%s]\n", last_component(path)); ++ printf("[%s]\n", soname); + printf("path = %s\n", real_path); + printf("hmac = %s\n", hmac); + +@@ -128,25 +96,24 @@ cleanup: + return ret; + } + +-static int print_lib_dl(const char *lib, const char *sym) ++static int callback(struct dl_phdr_info *info, size_t size, void *data) + { +- int ret; +- char path[GNUTLS_PATH_MAX]; +- +- ret = get_path(lib, sym, path, sizeof(path)); +- if (ret < 0) { +- fprintf(stderr, "Could not get lib path for %s: %s\n", +- lib, gnutls_strerror(ret)); +- return ret; +- } ++ const char *path = info->dlpi_name; ++ const char *soname = last_component(path); + +- return print_lib_path(path); ++ if (!strcmp(soname, GNUTLS_LIBRARY_SONAME)) ++ return print_lib(data ? data : path, soname); ++ if (!strcmp(soname, NETTLE_LIBRARY_SONAME)) ++ return print_lib(path, soname); ++ if (!strcmp(soname, HOGWEED_LIBRARY_SONAME)) ++ return print_lib(path, soname); ++ if (!strcmp(soname, GMP_LIBRARY_SONAME)) ++ return print_lib(path, soname); ++ return 0; + } + + int main(int argc, char **argv) + { +- int ret; +- + if (argc != 1 && argc != 2) { + fprintf(stderr, "Usage: %s [gnutls_so_path]\n", last_component(argv[0])); + return EXIT_FAILURE; +@@ -155,24 +122,15 @@ int main(int argc, char **argv) + printf("[global]\n"); + printf("format-version = %d\n", FORMAT_VERSION); + +- if (argc == 2) +- ret = print_lib_path(argv[1]); +- else +- ret = print_lib_dl(GNUTLS_LIBRARY_SONAME, "gnutls_global_init"); +- if (ret < 0) +- return EXIT_FAILURE; ++ return dl_iterate_phdr(callback, argc == 2 ? argv[1] : NULL); ++} + +- ret = print_lib_dl(NETTLE_LIBRARY_SONAME, "nettle_aes_set_encrypt_key"); +- if (ret < 0) +- return EXIT_FAILURE; +- +- ret = print_lib_dl(HOGWEED_LIBRARY_SONAME, "nettle_mpz_sizeinbase_256_u"); +- if (ret < 0) +- return EXIT_FAILURE; +- +- ret = print_lib_dl(GMP_LIBRARY_SONAME, "__gmpz_init"); +- if (ret < 0) +- return EXIT_FAILURE; ++#else + +- return EXIT_SUCCESS; ++int main(void) ++{ ++ fprintf(stderr, "Function dl_iterate_phdr is missing\n"); ++ return EXIT_FAILURE; + } ++ ++#endif /* HAVE_DL_ITERATE_PHDR */ +diff --color -ruNp a/lib/Makefile.am b/lib/Makefile.am +--- a/lib/Makefile.am 2022-05-18 16:46:00.000000000 +0200 ++++ b/lib/Makefile.am 2022-12-15 11:00:18.789697779 +0100 +@@ -202,14 +202,14 @@ noinst_PROGRAMS = fipshmac + fipshmac_SOURCES = fipshmac.c + fipshmac_LDADD = libgnutls.la ../gl/libgnu.la + +-hmac_files = .libs/.gnutls.hmac ++hmac_file = .libs/.$(gnutls_so).hmac + +-all-local: $(hmac_files) ++all-local: $(hmac_file) + +-.libs/.gnutls.hmac: libgnutls.la fipshmac ++$(hmac_file): libgnutls.la fipshmac + $(AM_V_GEN) $(builddir)/fipshmac > $@-t && mv $@-t $@ + +-CLEANFILES = $(hmac_files) ++CLEANFILES = $(hmac_file) + endif + + if NEED_LTLIBDL diff --git a/SOURCES/gnutls-3.7.8-rsa-kx-timing.patch b/SOURCES/gnutls-3.7.8-rsa-kx-timing.patch new file mode 100644 index 0000000..9107321 --- /dev/null +++ b/SOURCES/gnutls-3.7.8-rsa-kx-timing.patch @@ -0,0 +1,114 @@ +From c149dd0767f32789e391280cb1eb06b7eb7c6bce Mon Sep 17 00:00:00 2001 +From: Alexander Sosedkin +Date: Tue, 9 Aug 2022 16:05:53 +0200 +Subject: [PATCH 1/2] auth/rsa: side-step potential side-channel + +Remove branching that depends on secret data. + +Signed-off-by: Alexander Sosedkin +Signed-off-by: Hubert Kario +Tested-by: Hubert Kario +--- + lib/auth/rsa.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/lib/auth/rsa.c b/lib/auth/rsa.c +index 8108ee841d..6b158bacb2 100644 +--- a/lib/auth/rsa.c ++++ b/lib/auth/rsa.c +@@ -155,7 +155,6 @@ static int + proc_rsa_client_kx(gnutls_session_t session, uint8_t * data, + size_t _data_size) + { +- const char attack_error[] = "auth_rsa: Possible PKCS #1 attack\n"; + gnutls_datum_t ciphertext; + int ret, dsize; + ssize_t data_size = _data_size; +@@ -235,15 +234,6 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data, + ok &= CONSTCHECK_NOT_EQUAL(check_ver_min, 0) & + CONSTCHECK_EQUAL(session->key.key.data[1], ver_min); + +- if (ok) { +- /* call logging function unconditionally so all branches are +- * indistinguishable for timing and cache access when debug +- * logging is disabled */ +- _gnutls_no_log("%s", attack_error); +- } else { +- _gnutls_debug_log("%s", attack_error); +- } +- + /* This is here to avoid the version check attack + * discussed above. + */ +-- +2.39.1 + + +From 7c963102ec2119eecc1789b993aabe5edfd75f3b Mon Sep 17 00:00:00 2001 +From: Hubert Kario +Date: Wed, 8 Feb 2023 14:32:09 +0100 +Subject: [PATCH 2/2] rsa: remove dead code + +since the `ok` variable isn't used any more, we can remove all code +used to calculate it + +Signed-off-by: Hubert Kario +--- + lib/auth/rsa.c | 20 +++----------------- + 1 file changed, 3 insertions(+), 17 deletions(-) + +diff --git a/lib/auth/rsa.c b/lib/auth/rsa.c +index 6b158bacb2..858701fe6e 100644 +--- a/lib/auth/rsa.c ++++ b/lib/auth/rsa.c +@@ -159,8 +159,6 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data, + int ret, dsize; + ssize_t data_size = _data_size; + volatile uint8_t ver_maj, ver_min; +- volatile uint8_t check_ver_min; +- volatile uint32_t ok; + + #ifdef ENABLE_SSL3 + if (get_num_version(session) == GNUTLS_SSL3) { +@@ -186,7 +184,6 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data, + + ver_maj = _gnutls_get_adv_version_major(session); + ver_min = _gnutls_get_adv_version_minor(session); +- check_ver_min = (session->internals.allow_wrong_pms == 0); + + session->key.key.data = gnutls_malloc(GNUTLS_MASTER_SIZE); + if (session->key.key.data == NULL) { +@@ -205,10 +202,9 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data, + return ret; + } + +- ret = +- gnutls_privkey_decrypt_data2(session->internals.selected_key, +- 0, &ciphertext, session->key.key.data, +- session->key.key.size); ++ gnutls_privkey_decrypt_data2(session->internals.selected_key, ++ 0, &ciphertext, session->key.key.data, ++ session->key.key.size); + /* After this point, any conditional on failure that cause differences + * in execution may create a timing or cache access pattern side + * channel that can be used as an oracle, so treat very carefully */ +@@ -224,16 +220,6 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data, + * Vlastimil Klima, Ondej Pokorny and Tomas Rosa. + */ + +- /* ok is 0 in case of error and 1 in case of success. */ +- +- /* if ret < 0 */ +- ok = CONSTCHECK_EQUAL(ret, 0); +- /* session->key.key.data[0] must equal ver_maj */ +- ok &= CONSTCHECK_EQUAL(session->key.key.data[0], ver_maj); +- /* if check_ver_min then session->key.key.data[1] must equal ver_min */ +- ok &= CONSTCHECK_NOT_EQUAL(check_ver_min, 0) & +- CONSTCHECK_EQUAL(session->key.key.data[1], ver_min); +- + /* This is here to avoid the version check attack + * discussed above. + */ +-- +2.39.1 + diff --git a/SOURCES/gnutls-3.7.8-xts-key-check.patch b/SOURCES/gnutls-3.7.8-xts-key-check.patch new file mode 100644 index 0000000..a922f93 --- /dev/null +++ b/SOURCES/gnutls-3.7.8-xts-key-check.patch @@ -0,0 +1,220 @@ +diff --color -ruNp a/lib/accelerated/x86/aes-xts-x86-aesni.c b/lib/accelerated/x86/aes-xts-x86-aesni.c +--- a/lib/accelerated/x86/aes-xts-x86-aesni.c 2022-03-02 12:38:09.000000000 +0100 ++++ b/lib/accelerated/x86/aes-xts-x86-aesni.c 2022-11-07 14:12:38.476982750 +0100 +@@ -73,7 +73,6 @@ x86_aes_xts_cipher_setkey(void *_ctx, co + /* Check key block according to FIPS-140-2 IG A.9 */ + if (_gnutls_fips_mode_enabled()){ + if (gnutls_memcmp(key, key + (keysize / 2), keysize / 2) == 0) { +- _gnutls_switch_lib_state(LIB_STATE_ERROR); + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + } +diff --color -ruNp a/lib/nettle/cipher.c b/lib/nettle/cipher.c +--- a/lib/nettle/cipher.c 2022-11-07 14:10:13.672085930 +0100 ++++ b/lib/nettle/cipher.c 2022-11-07 14:12:38.477982770 +0100 +@@ -448,12 +448,14 @@ _gcm_decrypt(struct nettle_cipher_ctx *c + length, dst, src); + } + +-static void _des_set_key(struct des_ctx *ctx, const uint8_t *key) ++static void ++_des_set_key(struct des_ctx *ctx, const uint8_t *key) + { + des_set_key(ctx, key); + } + +-static void _des3_set_key(struct des3_ctx *ctx, const uint8_t *key) ++static void ++_des3_set_key(struct des3_ctx *ctx, const uint8_t *key) + { + des3_set_key(ctx, key); + } +@@ -477,50 +479,6 @@ _cfb8_decrypt(struct nettle_cipher_ctx * + } + + static void +-_xts_aes128_set_encrypt_key(struct xts_aes128_key *xts_key, +- const uint8_t *key) +-{ +- if (_gnutls_fips_mode_enabled() && +- gnutls_memcmp(key, key + AES128_KEY_SIZE, AES128_KEY_SIZE) == 0) +- _gnutls_switch_lib_state(LIB_STATE_ERROR); +- +- xts_aes128_set_encrypt_key(xts_key, key); +-} +- +-static void +-_xts_aes128_set_decrypt_key(struct xts_aes128_key *xts_key, +- const uint8_t *key) +-{ +- if (_gnutls_fips_mode_enabled() && +- gnutls_memcmp(key, key + AES128_KEY_SIZE, AES128_KEY_SIZE) == 0) +- _gnutls_switch_lib_state(LIB_STATE_ERROR); +- +- xts_aes128_set_decrypt_key(xts_key, key); +-} +- +-static void +-_xts_aes256_set_encrypt_key(struct xts_aes256_key *xts_key, +- const uint8_t *key) +-{ +- if (_gnutls_fips_mode_enabled() && +- gnutls_memcmp(key, key + AES256_KEY_SIZE, AES256_KEY_SIZE) == 0) +- _gnutls_switch_lib_state(LIB_STATE_ERROR); +- +- xts_aes256_set_encrypt_key(xts_key, key); +-} +- +-static void +-_xts_aes256_set_decrypt_key(struct xts_aes256_key *xts_key, +- const uint8_t *key) +-{ +- if (_gnutls_fips_mode_enabled() && +- gnutls_memcmp(key, key + AES256_KEY_SIZE, AES256_KEY_SIZE) == 0) +- _gnutls_switch_lib_state(LIB_STATE_ERROR); +- +- xts_aes256_set_decrypt_key(xts_key, key); +-} +- +-static void + _xts_aes128_encrypt(struct nettle_cipher_ctx *ctx, size_t length, uint8_t * dst, + const uint8_t * src) + { +@@ -1041,8 +999,8 @@ static const struct nettle_cipher_st bui + .ctx_size = sizeof(struct xts_aes128_key), + .encrypt = _xts_aes128_encrypt, + .decrypt = _xts_aes128_decrypt, +- .set_encrypt_key = (nettle_set_key_func*)_xts_aes128_set_encrypt_key, +- .set_decrypt_key = (nettle_set_key_func*)_xts_aes128_set_decrypt_key, ++ .set_encrypt_key = (nettle_set_key_func*)xts_aes128_set_encrypt_key, ++ .set_decrypt_key = (nettle_set_key_func*)xts_aes128_set_decrypt_key, + .max_iv_size = AES_BLOCK_SIZE, + }, + { .algo = GNUTLS_CIPHER_AES_256_XTS, +@@ -1052,8 +1010,8 @@ static const struct nettle_cipher_st bui + .ctx_size = sizeof(struct xts_aes256_key), + .encrypt = _xts_aes256_encrypt, + .decrypt = _xts_aes256_decrypt, +- .set_encrypt_key = (nettle_set_key_func*)_xts_aes256_set_encrypt_key, +- .set_decrypt_key = (nettle_set_key_func*)_xts_aes256_set_decrypt_key, ++ .set_encrypt_key = (nettle_set_key_func*)xts_aes256_set_encrypt_key, ++ .set_decrypt_key = (nettle_set_key_func*)xts_aes256_set_decrypt_key, + .max_iv_size = AES_BLOCK_SIZE, + }, + { .algo = GNUTLS_CIPHER_AES_128_SIV, +@@ -1144,6 +1102,21 @@ wrap_nettle_cipher_setkey(void *_ctx, co + return 0; + } + ++ switch (ctx->cipher->algo) { ++ case GNUTLS_CIPHER_AES_128_XTS: ++ if (_gnutls_fips_mode_enabled() && ++ gnutls_memcmp(key, (char *)key + AES128_KEY_SIZE, AES128_KEY_SIZE) == 0) ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ break; ++ case GNUTLS_CIPHER_AES_256_XTS: ++ if (_gnutls_fips_mode_enabled() && ++ gnutls_memcmp(key, (char *)key + AES256_KEY_SIZE, AES256_KEY_SIZE) == 0) ++ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ++ break; ++ default: ++ break; ++ } ++ + if (ctx->enc) + ctx->cipher->set_encrypt_key(ctx->ctx_ptr, key); + else +diff --color -ruNp a/tests/Makefile.am b/tests/Makefile.am +--- a/tests/Makefile.am 2022-11-07 14:10:13.836089211 +0100 ++++ b/tests/Makefile.am 2022-11-07 14:12:38.478982790 +0100 +@@ -233,7 +233,7 @@ ctests += mini-record-2 simple gnutls_hm + tls13-without-timeout-func buffer status-request-revoked \ + set_x509_ocsp_multi_cli kdf-api keylog-func handshake-write \ + x509cert-dntypes id-on-xmppAddr tls13-compat-mode ciphersuite-name \ +- x509-upnconstraint pkcs7-verify-double-free \ ++ x509-upnconstraint xts-key-check pkcs7-verify-double-free \ + fips-rsa-sizes + + ctests += tls-channel-binding +diff --color -ruNp a/tests/xts-key-check.c b/tests/xts-key-check.c +--- a/tests/xts-key-check.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/tests/xts-key-check.c 2022-11-07 14:12:38.478982790 +0100 +@@ -0,0 +1,78 @@ ++/* ++ * Copyright (C) 2022 Red Hat, Inc. ++ * ++ * Author: Zoltan Fridrich ++ * ++ * This file is part of GnuTLS. ++ * ++ * GnuTLS is free software: you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GnuTLS is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GnuTLS. If not, see . ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++ ++#include "utils.h" ++ ++static void test_xts_check(gnutls_cipher_algorithm_t alg) ++{ ++ int ret; ++ gnutls_cipher_hd_t ctx; ++ gnutls_datum_t key, iv; ++ ++ iv.size = gnutls_cipher_get_iv_size(alg); ++ iv.data = gnutls_malloc(iv.size); ++ if (iv.data == NULL) ++ fail("Error: %s\n", gnutls_strerror(GNUTLS_E_MEMORY_ERROR)); ++ gnutls_memset(iv.data, 0xf0, iv.size); ++ ++ key.size = gnutls_cipher_get_key_size(alg); ++ key.data = gnutls_malloc(key.size); ++ if (key.data == NULL) { ++ gnutls_free(iv.data); ++ fail("Error: %s\n", gnutls_strerror(GNUTLS_E_MEMORY_ERROR)); ++ } ++ gnutls_memset(key.data, 0xf0, key.size); ++ ++ ret = gnutls_cipher_init(&ctx, alg, &key, &iv); ++ if (ret == GNUTLS_E_SUCCESS) { ++ gnutls_cipher_deinit(ctx); ++ gnutls_free(iv.data); ++ gnutls_free(key.data); ++ fail("cipher initialization should fail for key1 == key2\n"); ++ } ++ ++ key.data[0] = 0xff; ++ ++ ret = gnutls_cipher_init(&ctx, alg, &key, &iv); ++ gnutls_free(iv.data); ++ gnutls_free(key.data); ++ ++ if (ret == GNUTLS_E_SUCCESS) ++ gnutls_cipher_deinit(ctx); ++ else ++ fail("cipher initialization should succeed with key1 != key2" ++ "\n%s\n", gnutls_strerror(ret)); ++} ++ ++void doit(void) ++{ ++ if (!gnutls_fips140_mode_enabled()) ++ exit(77); ++ ++ test_xts_check(GNUTLS_CIPHER_AES_128_XTS); ++ test_xts_check(GNUTLS_CIPHER_AES_256_XTS); ++} diff --git a/SPECS/gnutls.spec b/SPECS/gnutls.spec index a1e5410..4ec9226 100644 --- a/SPECS/gnutls.spec +++ b/SPECS/gnutls.spec @@ -13,7 +13,7 @@ print(string.sub(hash, 0, 16)) } Version: 3.7.6 -Release: 11%{?dist} +Release: 18%{?dist} # not upstreamed Patch: gnutls-3.6.7-no-now-guile.patch Patch: gnutls-3.2.7-rpath.patch @@ -28,6 +28,18 @@ 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 +Patch: gnutls-3.7.8-xts-key-check.patch +Patch: gnutls-3.7.8-clear-session-ticket.patch +Patch: gnutls-3.7.7-aes-cbc-padding-support.patch +Patch: gnutls-3.7.8-integrity-check.patch +Patch: gnutls-3.7.6-fips-service-indicator-test-functions.patch +Patch: gnutls-3.7.6-fips-ccm-taglen.patch +Patch: gnutls-3.7.6-fips-rsa-pss-saltlen.patch +Patch: gnutls-3.7.8-revert-hmac-name.patch +Patch: gnutls-3.7.8-rsa-kx-timing.patch +Patch: gnutls-3.7.8-fips-pct-dh.patch # not upstreamed Patch: gnutls-3.7.3-disable-config-reload.patch @@ -194,10 +206,7 @@ This package contains Guile bindings for the library. %endif %prep -# Workaround: to allow building the package under FIPS, do not treat -# errors in the GPG check as fatal, where EdDSA signature verification -# is not allowed: -%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' || : +%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' %autosetup -p1 -S git @@ -325,8 +334,10 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/gnutls-dane.pc # doing it twice should be a no-op the second time, # and this way we avoid redefining it and missing a future change %{__spec_install_post} -./lib/fipshmac "$RPM_BUILD_ROOT%{_libdir}/libgnutls.so.30" > $RPM_BUILD_ROOT%{_libdir}/.gnutls.hmac -sed -i "s^$RPM_BUILD_ROOT/usr^^" $RPM_BUILD_ROOT%{_libdir}/.gnutls.hmac +fname=`basename $RPM_BUILD_ROOT%{_libdir}/libgnutls.so.30.*.*` +./lib/fipshmac "$RPM_BUILD_ROOT%{_libdir}/libgnutls.so.30" > "$RPM_BUILD_ROOT%{_libdir}/.$fname.hmac" +sed -i "s^$RPM_BUILD_ROOT/usr^^" "$RPM_BUILD_ROOT%{_libdir}/.$fname.hmac" +ln -s ".$fname.hmac" "$RPM_BUILD_ROOT%{_libdir}/.libgnutls.so.30.hmac" %endif %if %{with fips} @@ -347,7 +358,7 @@ make check %{?_smp_mflags} GNUTLS_SYSTEM_PRIORITY_FILE=/dev/null %files -f gnutls.lang %{_libdir}/libgnutls.so.30* %if %{with fips} -%{_libdir}/.gnutls.hmac +%{_libdir}/.libgnutls.so.30*.hmac %endif %doc README.md AUTHORS NEWS THANKS %license LICENSE doc/COPYING doc/COPYING.LESSER @@ -395,6 +406,36 @@ make check %{?_smp_mflags} GNUTLS_SYSTEM_PRIORITY_FILE=/dev/null %endif %changelog +* Tue Feb 28 2023 Daiki Ueno - 3.7.6-18 +- Update gnutls-3.7.8-fips-pct-dh.patch to the upstream version (#2168143) + +* Fri Feb 10 2023 Daiki Ueno - 3.7.6-17 +- Fix timing side-channel in TLS RSA key exchange (#2162601) + +* Fri Feb 10 2023 Daiki Ueno - 3.7.6-16 +- fips: extend PCT to DH key generation (#2168143) + +* Thu Dec 15 2022 Zoltan Fridrich - 3.7.6-15 +- fips: rename hmac file to its previous name (#2148269) + +* Tue Nov 22 2022 Daiki Ueno - 3.7.6-14 +- cipher: add restriction on CCM tag length under FIPS mode (#2137807) +- nettle: mark non-compliant RSA-PSS salt length to be not-approved (#2143266) + +* Tue Nov 15 2022 Zoltan Fridrich - 3.7.6-13 +- fips: make XTS key check failure not fatal (#2130971) +- enable source archive verification again (#2127094) +- clear server's session ticket indication at rehandshake (#2136072) +- crypto-api: add block cipher API with automatic padding (#2084161) +- fips: remove library path checking from FIPS integrity check (#2140908) + +* 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 @@ -412,31 +453,31 @@ make check %{?_smp_mflags} GNUTLS_SYSTEM_PRIORITY_FILE=/dev/null - Update gnutls-3.7.6-cpuid-fixes.patch * Sat Aug 20 2022 Daiki Ueno - 3.7.6-6 -- Mark RSA SigVer operation approved for known modulus sizes (#2119770) +- Mark RSA SigVer operation approved for known modulus sizes (#2091903) - accelerated: clear AVX bits if it cannot be queried through XSAVE * Thu Aug 4 2022 Daiki Ueno - 3.7.6-5 -- Block DES-CBC usage in decrypting PKCS#12 bag under FIPS (#2115314) +- Block DES-CBC usage in decrypting PKCS#12 bag under FIPS (#2115244) - sysrng: reseed source DRBG for prediction resistance * Fri Jul 29 2022 Daiki Ueno - 3.7.6-4 - Make gnutls-cli work with KTLS for testing -- Fix double-free in gnutls_pkcs7_verify (#2109789) +- Fix double-free in gnutls_pkcs7_verify (#2109790) * Mon Jul 25 2022 Daiki Ueno - 3.7.6-3 -- Limit input size for AES-GCM according to SP800-38D (#2108635) +- Limit input size for AES-GCM according to SP800-38D (#2095251) - Do not treat GPG verification errors as fatal - Remove gnutls-3.7.6-libgnutlsxx-const.patch * Tue Jul 19 2022 Daiki Ueno - 3.7.6-2 -- Allow enabling KTLS with config file (#2108532) +- Allow enabling KTLS with config file (#2042009) * Fri Jul 1 2022 Daiki Ueno - 3.7.6-1 -- Update to gnutls 3.7.6 (#2102591) +- Update to gnutls 3.7.6 (#2097327) * Thu Mar 31 2022 Daiki Ueno - 3.7.3-10 -- Use only the first component of VERSION from /etc/os-release (#2076626) -- Don't run power-on self-tests on DSA (#2076627) +- Use only the first component of VERSION from /etc/os-release (#2070249) +- Don't run power-on self-tests on DSA (#2061325) * Fri Feb 25 2022 Daiki Ueno - 3.7.3-9 - Stop using typeof keyword for tss2 function prototypes (#2057490)