diff --git a/gnutls-3.7.8-xts-key-check.patch b/gnutls-3.7.8-xts-key-check.patch
new file mode 100644
index 0000000..a922f93
--- /dev/null
+++ b/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/gnutls.spec b/gnutls.spec
index 0125327..5880299 100644
--- a/gnutls.spec
+++ b/gnutls.spec
@@ -13,7 +13,7 @@ print(string.sub(hash, 0, 16))
}
Version: 3.7.6
-Release: 12%{?dist}
+Release: 13%{?dist}
# not upstreamed
Patch: gnutls-3.6.7-no-now-guile.patch
Patch: gnutls-3.2.7-rpath.patch
@@ -30,6 +30,7 @@ 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
# not upstreamed
Patch: gnutls-3.7.3-disable-config-reload.patch
@@ -397,6 +398,9 @@ make check %{?_smp_mflags} GNUTLS_SYSTEM_PRIORITY_FILE=/dev/null
%endif
%changelog
+* Mon Nov 07 2022 Zoltan Fridrich - 3.7.6-13
+- fips: make XTS key check failure not fatal (#2130971)
+
* 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