diff --git a/SOURCES/libgcrypt-1.10.0-allow-short-salt.patch b/SOURCES/libgcrypt-1.10.0-allow-short-salt.patch
index 46054cf..6800cf6 100644
--- a/SOURCES/libgcrypt-1.10.0-allow-short-salt.patch
+++ b/SOURCES/libgcrypt-1.10.0-allow-short-salt.patch
@@ -48,4 +48,30 @@ index c98247d8..aee5bffb 100644
  
 -- 
 2.37.1
+commit 02718ade6ab5eee38169c2102097166770a2456d
+Author: Jakub Jelen <jjelen@redhat.com>
+Date:   Thu Oct 20 16:33:11 2022 +0200
 
+    visiblity: Check the HMAC key length in FIPS mode
+    
+    ---
+    * src/visibility.c (gcry_md_setkey): Check the HMAC key length in FIPS
+      mode also in the md_ API.
+    
+    Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+
+diff --git a/src/visibility.c b/src/visibility.c
+index 150b197d..73db3dea 100644
+--- a/src/visibility.c
++++ b/src/visibility.c
+@@ -1357,6 +1357,10 @@ gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
+ {
+   if (!fips_is_operational ())
+     return gpg_error (fips_not_operational ());
++
++  if (fips_mode () && keylen < 14)
++    return GPG_ERR_INV_VALUE;
++
+   return gpg_error (_gcry_md_setkey (hd, key, keylen));
+ }
+ 
diff --git a/SOURCES/libgcrypt-1.10.0-fips-disable-oaep.patch b/SOURCES/libgcrypt-1.10.0-fips-disable-oaep.patch
deleted file mode 100644
index 3de63c8..0000000
--- a/SOURCES/libgcrypt-1.10.0-fips-disable-oaep.patch
+++ /dev/null
@@ -1,151 +0,0 @@
-From 34d8fc576b3a06dd205f45327a971eb6771e808c Mon Sep 17 00:00:00 2001
-From: Jakub Jelen <jjelen@redhat.com>
-Date: Wed, 17 Aug 2022 09:01:44 +0200
-Subject: [PATCH 1/2] Disable RSA-OAEP padding in FIPS mode
-
-* cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): Block OAEP padding
-  in FIPS mode for encryption
-* cipher/rsa.c (rsa_decrypt): Block OAEP padding in FIPS mode for
-  decryption
----
-
-Signed-off-by: Jakub Jelen <jjelen@redhat.com>
----
- cipher/pubkey-util.c | 5 ++++-
- cipher/rsa.c         | 3 ++-
- 2 files changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
-index 4953caf3..244dd5d4 100644
---- a/cipher/pubkey-util.c
-+++ b/cipher/pubkey-util.c
-@@ -1092,7 +1092,10 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
-       const void * value;
-       size_t valuelen;
- 
--      if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
-+      /* The RSA OAEP encryption requires some more assurances in FIPS */
-+      if (fips_mode ())
-+        rc = GPG_ERR_INV_FLAG;
-+      else if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
- 	rc = GPG_ERR_INV_OBJ;
-       else
- 	{
-diff --git a/cipher/rsa.c b/cipher/rsa.c
-index 96dba090..87f57b55 100644
---- a/cipher/rsa.c
-+++ b/cipher/rsa.c
-@@ -1457,7 +1457,8 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
-       rc = GPG_ERR_INV_DATA;
-       goto leave;
-     }
--  if (fips_mode () && (ctx.encoding == PUBKEY_ENC_PKCS1))
-+  if (fips_mode () && (ctx.encoding == PUBKEY_ENC_PKCS1 ||
-+                       ctx.encoding == PUBKEY_ENC_OAEP))
-     {
-       rc = GPG_ERR_INV_FLAG;
-       goto leave;
--- 
-2.37.1
-
-
-From c6d64e697c2748a49e875060aa753fc568c5f772 Mon Sep 17 00:00:00 2001
-From: Jakub Jelen <jjelen@redhat.com>
-Date: Wed, 17 Aug 2022 10:31:19 +0200
-Subject: [PATCH 2/2] tests: Expect the OEAP tests to fail in FIPS mode
-
-* tests/basic.c (check_pubkey_crypt): Expect the OAEP padding encryption
-  to fail in FIPS mode
-* tests/pkcs1v2.c (check_oaep): Expect the OAEP tests to fail in FIPS
-  mode
----
-
-Signed-off-by: Jakub Jelen <jjelen@redhat.com>
----
- tests/basic.c   | 14 +++++++++-----
- tests/pkcs1v2.c | 13 +++++++++++++
- 2 files changed, 22 insertions(+), 5 deletions(-)
-
-diff --git a/tests/basic.c b/tests/basic.c
-index 26980e15..b4102c9f 100644
---- a/tests/basic.c
-+++ b/tests/basic.c
-@@ -16892,21 +16892,24 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
- 	"(flags oaep)",
- 	1,
- 	0,
--	0 },
-+	0,
-+	FLAG_NOFIPS },
-       { GCRY_PK_RSA,
-         "(data\n (flags oaep)\n (hash-algo sha1)\n"
- 	" (value #11223344556677889900AA#))\n",
- 	"(flags oaep)(hash-algo sha1)",
- 	1,
- 	0,
--	0 },
-+	0,
-+	FLAG_NOFIPS },
-       { GCRY_PK_RSA,
-         "(data\n (flags oaep)\n (hash-algo sha1)\n (label \"test\")\n"
- 	" (value #11223344556677889900AA#))\n",
- 	"(flags oaep)(hash-algo sha1)(label \"test\")",
- 	1,
- 	0,
--	0 },
-+	0,
-+	FLAG_NOFIPS },
-       { GCRY_PK_RSA,
-         "(data\n (flags oaep)\n (hash-algo sha1)\n (label \"test\")\n"
- 	" (value #11223344556677889900AA#)\n"
-@@ -16914,7 +16917,8 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
- 	"(flags oaep)(hash-algo sha1)(label \"test\")",
- 	1,
- 	0,
--	0 },
-+	0,
-+	FLAG_NOFIPS },
-       {	0,
-         "(data\n (flags )\n" " (value #11223344556677889900AA#))\n",
- 	NULL,
-@@ -16960,7 +16964,7 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
- 	"(flags pkcs1)",
- 	1,
- 	0,
--	GPG_ERR_ENCODING_PROBLEM, FLAG_SPECIAL },
-+	GPG_ERR_ENCODING_PROBLEM, FLAG_SPECIAL | FLAG_NOFIPS },
-       {	0,
-         "(data\n (flags pss)\n"
- 	" (value #11223344556677889900AA#))\n",
-diff --git a/tests/pkcs1v2.c b/tests/pkcs1v2.c
-index 6c7f3d81..2fd495d5 100644
---- a/tests/pkcs1v2.c
-+++ b/tests/pkcs1v2.c
-@@ -186,11 +186,24 @@ check_oaep (void)
-           err = gcry_pk_encrypt (&ciph, plain, pub_key);
-           if (err)
-             {
-+              if (in_fips_mode)
-+                {
-+                  gcry_sexp_release (plain);
-+                  plain = NULL;
-+                  continue;
-+                }
-               show_sexp ("plain:\n", ciph);
-               fail ("gcry_pk_encrypt failed: %s\n", gpg_strerror (err));
-             }
-           else
-             {
-+              if (in_fips_mode)
-+                {
-+                  fail ("The OAEP encryption unexpectedly worked in FIPS mode\n");
-+                  gcry_sexp_release (plain);
-+                  plain = NULL;
-+                  continue;
-+                }
-               if (extract_cmp_data (ciph, "a", tbl[tno].m[mno].encr,
-                                     tbl[tno].m[mno].desc))
-                 {
--- 
-2.37.1
-
diff --git a/SOURCES/libgcrypt-1.10.0-fips-disable-pkcs1.5.patch b/SOURCES/libgcrypt-1.10.0-fips-disable-pkcs1.5.patch
deleted file mode 100644
index 325b2fd..0000000
--- a/SOURCES/libgcrypt-1.10.0-fips-disable-pkcs1.5.patch
+++ /dev/null
@@ -1,219 +0,0 @@
-From c7709f7b23848abf4ba65cb99cb2a9e9c7ebdefc Mon Sep 17 00:00:00 2001
-From: Jakub Jelen <jjelen@redhat.com>
-Date: Fri, 1 Apr 2022 18:29:08 +0200
-Subject: [PATCH 1/3] Do not allow PKCS #1.5 padding for encryption in FIPS
-
-* cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): Block PKCS #1.5
-  padding for encryption in FIPS mode
-* cipher/rsa.c (rsa_decrypt): Block PKCS #1.5 decryption in FIPS mode
---
-
-GnuPG-bug-id: 5918
-Signed-off-by: Jakub Jelen <jjelen@redhat.com>
----
- cipher/pubkey-util.c | 5 ++++-
- cipher/rsa.c         | 5 +++++
- 2 files changed, 9 insertions(+), 1 deletion(-)
-
-diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
-index 68defea6..4953caf3 100644
---- a/cipher/pubkey-util.c
-+++ b/cipher/pubkey-util.c
-@@ -957,7 +957,10 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
-       void *random_override = NULL;
-       size_t random_override_len = 0;
- 
--      if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
-+      /* The RSA PKCS#1.5 encryption is no longer supported by FIPS */
-+      if (fips_mode ())
-+        rc = GPG_ERR_INV_FLAG;
-+      else if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
-         rc = GPG_ERR_INV_OBJ;
-       else
-         {
-diff --git a/cipher/rsa.c b/cipher/rsa.c
-index 771413b3..c6319b67 100644
---- a/cipher/rsa.c
-+++ b/cipher/rsa.c
-@@ -1391,6 +1391,11 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
-       rc = GPG_ERR_INV_DATA;
-       goto leave;
-     }
-+  if (fips_mode () && (ctx.encoding == PUBKEY_ENC_PKCS1))
-+    {
-+      rc = GPG_ERR_INV_FLAG;
-+      goto leave;
-+    }
- 
-   /* Extract the key.  */
-   rc = sexp_extract_param (keyparms, NULL, "nedp?q?u?",
--- 
-2.34.1
-
-
-From 299e2f93415984919181e0ee651719bbf83bdd2f Mon Sep 17 00:00:00 2001
-From: Jakub Jelen <jjelen@redhat.com>
-Date: Fri, 1 Apr 2022 18:31:05 +0200
-Subject: [PATCH 2/3] tests: Replace custom bit with more generic flags
-
-* tests/basic.c (global): New flag FLAG_SPECIAL
-  (check_pubkey_crypt): Change to use bitfield flags
-
---
-
-GnuPG-bug-id: 5918
-Signed-off-by: Jakub Jelen <jjelen@redhat.com>
----
- tests/basic.c | 19 ++++++++++---------
- 1 file changed, 10 insertions(+), 9 deletions(-)
-
-diff --git a/tests/basic.c b/tests/basic.c
-index a0ad33eb..1c6cb40b 100644
---- a/tests/basic.c
-+++ b/tests/basic.c
-@@ -55,11 +55,12 @@ typedef struct test_spec_pubkey
- }
- test_spec_pubkey_t;
- 
--#define FLAG_CRYPT  (1 << 0)
--#define FLAG_SIGN   (1 << 1)
--#define FLAG_GRIP   (1 << 2)
--#define FLAG_NOFIPS (1 << 3)
--#define FLAG_CFB8   (1 << 4)
-+#define FLAG_CRYPT   (1 << 0)
-+#define FLAG_SIGN    (1 << 1)
-+#define FLAG_GRIP    (1 << 2)
-+#define FLAG_NOFIPS  (1 << 3)
-+#define FLAG_CFB8    (1 << 4)
-+#define FLAG_SPECIAL (1 << 5)
- 
- static int in_fips_mode;
- 
-@@ -15558,7 +15559,7 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
-     int unpadded;
-     int encrypt_expected_rc;
-     int decrypt_expected_rc;
--    int special;
-+    int flags;
-   } datas[] =
-     {
-       {	GCRY_PK_RSA,
-@@ -15642,14 +15643,14 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
- 	"(flags oaep)",
- 	1,
- 	0,
--	GPG_ERR_ENCODING_PROBLEM, 1 },
-+	GPG_ERR_ENCODING_PROBLEM, FLAG_SPECIAL },
-       { GCRY_PK_RSA,
-         "(data\n (flags oaep)\n"
- 	" (value #11223344556677889900AA#))\n",
- 	"(flags pkcs1)",
- 	1,
- 	0,
--	GPG_ERR_ENCODING_PROBLEM, 1 },
-+	GPG_ERR_ENCODING_PROBLEM, FLAG_SPECIAL },
-       {	0,
-         "(data\n (flags pss)\n"
- 	" (value #11223344556677889900AA#))\n",
-@@ -15725,7 +15726,7 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
- 	      ciph = list;
- 	    }
- 	  rc = gcry_pk_decrypt (&plain, ciph, skey);
--          if (!rc && datas[dataidx].special == 1)
-+          if (!rc && (datas[dataidx].flags & FLAG_SPECIAL))
-             {
-               /* It may happen that OAEP formatted data which is
-                  decrypted as pkcs#1 data returns a valid pkcs#1
--- 
-2.34.1
-
-
-From f736f3c70182d9c948f9105eb769c47c5578df35 Mon Sep 17 00:00:00 2001
-From: Jakub Jelen <jjelen@redhat.com>
-Date: Fri, 1 Apr 2022 18:34:42 +0200
-Subject: [PATCH 3/3] tests: Expect the RSA PKCS #1.5 encryption to fail in
- FIPS mode
-
-* tests/basic.c (check_pubkey_crypt): Expect RSA PKCS #1.5 encryption to
-  fail in FIPS mode. Expect failure when wrong padding is selected
-* tests/pkcs1v2.c (check_v15crypt): Expect RSA PKCS #1.5 encryption to
-  fail in FIPS mode
---
-
-GnuPG-bug-id: 5918
-Signed-off-by: Jakub Jelen <jjelen@redhat.com>
----
- tests/basic.c   | 11 +++++++----
- tests/pkcs1v2.c | 14 +++++++++++++-
- 2 files changed, 20 insertions(+), 5 deletions(-)
-
-diff --git a/tests/basic.c b/tests/basic.c
-index 1c6cb40b..85764591 100644
---- a/tests/basic.c
-+++ b/tests/basic.c
-@@ -15568,14 +15568,16 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
- 	NULL,
- 	0,
- 	0,
--	0 },
-+	0,
-+	FLAG_NOFIPS },
-       {	GCRY_PK_RSA,
-         "(data\n (flags pkcs1)\n"
- 	" (value #11223344556677889900AA#))\n",
- 	"(flags pkcs1)",
- 	1,
- 	0,
--	0 },
-+	0,
-+	FLAG_NOFIPS },
-       { GCRY_PK_RSA,
-         "(data\n (flags oaep)\n"
- 	" (value #11223344556677889900AA#))\n",
-@@ -15677,7 +15679,8 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
- 	die ("converting data failed: %s\n", gpg_strerror (rc));
- 
-       rc = gcry_pk_encrypt (&ciph, data, pkey);
--      if (in_fips_mode && (flags & FLAG_NOFIPS))
-+      if (in_fips_mode && ((flags & FLAG_NOFIPS) ||
-+                           (datas[dataidx].flags & FLAG_NOFIPS)))
-         {
-           if (!rc)
-             fail ("gcry_pk_encrypt did not fail as expected in FIPS mode\n");
-@@ -15726,7 +15729,7 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
- 	      ciph = list;
- 	    }
- 	  rc = gcry_pk_decrypt (&plain, ciph, skey);
--          if (!rc && (datas[dataidx].flags & FLAG_SPECIAL))
-+          if ((!rc || in_fips_mode) && (datas[dataidx].flags & FLAG_SPECIAL))
-             {
-               /* It may happen that OAEP formatted data which is
-                  decrypted as pkcs#1 data returns a valid pkcs#1
-diff --git a/tests/pkcs1v2.c b/tests/pkcs1v2.c
-index f26e779b..6c7f3d81 100644
---- a/tests/pkcs1v2.c
-+++ b/tests/pkcs1v2.c
-@@ -454,7 +454,19 @@ check_v15crypt (void)
-           gcry_free (seed);
- 
-           err = gcry_pk_encrypt (&ciph, plain, pub_key);
--          if (err)
-+          if (in_fips_mode)
-+            {
-+              if (!err)
-+                {
-+                  fail ("gcry_pk_encrypt should have failed in FIPS mode:\n");
-+                }
-+              gcry_sexp_release (plain);
-+              plain = NULL;
-+              gcry_sexp_release (ciph);
-+              ciph = NULL;
-+              continue;
-+            }
-+          else if (err)
-             {
-               show_sexp ("plain:\n", ciph);
-               fail ("gcry_pk_encrypt failed: %s\n", gpg_strerror (err));
--- 
-2.34.1
-
diff --git a/SOURCES/libgcrypt-1.10.0-fips-getrandom.patch b/SOURCES/libgcrypt-1.10.0-fips-getrandom.patch
index 39ac59c..b0d5bf2 100644
--- a/SOURCES/libgcrypt-1.10.0-fips-getrandom.patch
+++ b/SOURCES/libgcrypt-1.10.0-fips-getrandom.patch
@@ -24,15 +24,24 @@ diff --git a/random/rndgetentropy.c b/random/rndgetentropy.c
 index 7580873e..db4b09ed 100644
 --- a/random/rndgetentropy.c
 +++ b/random/rndgetentropy.c
-@@ -82,7 +82,10 @@ _gcry_rndgetentropy_gather_random (void (*add)(const void*, size_t,
+@@ -82,9 +82,18 @@ _gcry_rndgetentropy_gather_random (void (*add)(const void*, size_t,
+        * never blocking once the kernel is seeded.  */
+       do
          {
-           nbytes = length < sizeof (buffer)? length : sizeof (buffer);
+-          nbytes = length < sizeof (buffer)? length : sizeof (buffer);
            _gcry_pre_syscall ();
 -          ret = getentropy (buffer, nbytes);
 +          if (fips_mode ())
-+            ret = getrandom (buffer, nbytes, GRND_RANDOM);
++            {
++              /* The getrandom API returns maximum 32 B of strong entropy */
++              nbytes = length < 32 ? length : 32;
++              ret = getrandom (buffer, nbytes, GRND_RANDOM);
++            }
 +          else
-+            ret = getentropy (buffer, nbytes);
++            {
++              nbytes = length < sizeof (buffer) ? length : sizeof (buffer);
++              ret = getentropy (buffer, nbytes);
++            }
            _gcry_post_syscall ();
          }
        while (ret == -1 && errno == EINTR);
diff --git a/SOURCES/libgcrypt-1.10.0-fips-indicator.patch b/SOURCES/libgcrypt-1.10.0-fips-indicator.patch
new file mode 100644
index 0000000..2fdf808
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-indicator.patch
@@ -0,0 +1,55 @@
+From c34c9e70055ee43e5ef257384fa15941f064e5a4 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Tue, 15 Nov 2022 10:47:18 +0100
+Subject: [PATCH] fips: Mark AES key wrapping as approved.
+
+* src/fips.c (_gcry_fips_indicator_cipher): Add key wrapping mode as
+approved.
+
+--
+
+GnuPG-bug-id: 5512
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ src/fips.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/fips.c b/src/fips.c
+index 6599121c..272aabae 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -367,6 +367,7 @@ _gcry_fips_indicator_cipher (va_list arg_ptr)
+         case GCRY_CIPHER_MODE_CCM:
+         case GCRY_CIPHER_MODE_GCM:
+         case GCRY_CIPHER_MODE_XTS:
++        case GCRY_CIPHER_MODE_AESWRAP:
+           return GPG_ERR_NO_ERROR;
+         default:
+           return GPG_ERR_NOT_SUPPORTED;
+--
+ 
+commit d6117b04e0e4d5d68df8fb731f618b0d5126ee14
+Author: Jakub Jelen <jjelen@redhat.com>
+Date:   Tue Jan 17 14:39:34 2023 +0100
+
+    fips: Remove GCM mode from the allowed FIPS indicators
+    
+    * src/fips.c (_gcry_fips_indicator_cipher): Do not mark GCM mode as FIPS
+      approved.
+    ---
+    
+    Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+
+diff --git a/src/fips.c b/src/fips.c
+index 272aabae..774e7b4c 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -365,7 +365,6 @@ _gcry_fips_indicator_cipher (va_list arg_ptr)
+         case GCRY_CIPHER_MODE_OFB:
+         case GCRY_CIPHER_MODE_CTR:
+         case GCRY_CIPHER_MODE_CCM:
+-        case GCRY_CIPHER_MODE_GCM:
+         case GCRY_CIPHER_MODE_XTS:
+         case GCRY_CIPHER_MODE_AESWRAP:
+           return GPG_ERR_NO_ERROR;
+--
diff --git a/SOURCES/libgcrypt-1.10.0-fips-integrity.patch b/SOURCES/libgcrypt-1.10.0-fips-integrity.patch
new file mode 100644
index 0000000..8254381
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-integrity.patch
@@ -0,0 +1,1008 @@
+From beb5d6df5c5785db7c32a24a5d2a351cb964bfbc Mon Sep 17 00:00:00 2001
+From: Clemens Lang via Gcrypt-devel <gcrypt-devel@lists.gnupg.org>
+Date: Mon, 14 Feb 2022 18:49:59 +0100
+Subject: [PATCH] fips: Use ELF header to find hmac file offset
+
+* src/fips.c [ENABLE_HMAC_BINARY_CHECK] (hmac256_check): Use ELF headers
+  to locate the file offset for the HMAC in addition to information from
+  the loader
+
+--
+
+The previous method of locating the offset of the .rodata1 section in
+the ELF file on disk used information obtained from the loader. This
+computed the address of the value in memory at runtime, but the offset
+in the file can be different. Specifically, the old code computed
+a value relative to ElfW(Phdr).p_vaddr, but the offset in the file is
+relative to ElfW(Phdr).p_offset. These values can differ, so the
+computed address at runtime must be translated into a file offset
+relative to p_offset.
+
+This is largely cosmetic, since the text section that should contain the
+HMAC usually has both p_vaddr and p_offset set to 0.
+
+Signed-off-by: Clemens Lang <cllang@redhat.com>
+---
+ README     |  3 ++-
+ src/fips.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 69 insertions(+), 7 deletions(-)
+
+diff --git a/README b/README
+index 3b465c1b..4d7697dd 100644
+--- a/README
++++ b/README
+@@ -157,7 +157,8 @@
+      --enable-hmac-binary-check
+                      Include support to check the binary at runtime
+                      against a HMAC checksum.  This works only in FIPS
+-                     mode and on systems providing the dladdr function.
++                     mode on systems providing the dladdr function and using
++                     the ELF binary format.
+ 
+      --with-fips-module-version=version
+                      Specify a string used as a module version for FIPS
+diff --git a/src/fips.c b/src/fips.c
+index 391b94f1..c40274d9 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -25,6 +25,8 @@
+ #include <string.h>
+ #ifdef ENABLE_HMAC_BINARY_CHECK
+ # include <dlfcn.h>
++# include <elf.h>
++# include <limits.h>
+ # include <link.h>
+ #endif
+ #ifdef HAVE_SYSLOG
+@@ -594,6 +596,57 @@ run_random_selftests (void)
+ static const unsigned char __attribute__ ((section (".rodata1")))
+ hmac_for_the_implementation[HMAC_LEN];
+ 
++/**
++ * Determine the offset of the given virtual address in the ELF file opened as
++ * fp and return it in offset. Rewinds fp to the beginning on success.
++ */
++static gpg_error_t
++get_file_offset (FILE *fp, unsigned long paddr, unsigned long *offset)
++{
++  ElfW (Ehdr) ehdr;
++  ElfW (Phdr) phdr;
++  uint16_t e_phidx;
++
++  // read the ELF header
++  if (0 != fseek (fp, 0, SEEK_SET))
++    return gpg_error_from_syserror ();
++  if (1 != fread (&ehdr, sizeof (ehdr), 1, fp))
++    return gpg_error_from_syserror ();
++
++  // the section header entry size should match the size of the shdr struct
++  if (ehdr.e_phentsize != sizeof (phdr))
++    return gpg_error (GPG_ERR_INV_OBJ);
++  if (ehdr.e_phoff == 0)
++    return gpg_error (GPG_ERR_INV_OBJ);
++
++  // jump to the first program header
++  if (0 != fseek (fp, ehdr.e_phoff, SEEK_SET))
++    return gpg_error_from_syserror ();
++
++  // iterate over the program headers, compare their virtual addresses with the
++  // address we are looking for, and if the program header matches, calculate
++  // the offset of the given paddr in the file using the program header's
++  // p_offset field.
++  for (e_phidx = 0; e_phidx < ehdr.e_phnum; e_phidx++)
++    {
++      if (1 != fread (&phdr, sizeof (phdr), 1, fp))
++        return gpg_error_from_syserror ();
++      if (phdr.p_type == PT_LOAD && phdr.p_vaddr <= paddr
++          && phdr.p_vaddr + phdr.p_memsz > paddr)
++        {
++          // found section, compute the offset of paddr in the file
++          *offset = phdr.p_offset + (paddr - phdr.p_vaddr);
++
++          if (0 != fseek (fp, 0, SEEK_SET))
++            return gpg_error_from_syserror ();
++          return 0;
++        }
++    }
++
++  // section not found in the file
++  return gpg_error (GPG_ERR_INV_OBJ);
++}
++
+ static gpg_error_t
+ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+ {
+@@ -603,6 +656,7 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+   size_t buffer_size, nread;
+   char *buffer;
+   unsigned long paddr;
++  unsigned long offset = 0;
+   unsigned long off = 0;
+ 
+   paddr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
+@@ -611,6 +665,13 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+   if (!fp)
+     return gpg_error (GPG_ERR_INV_OBJ);
+ 
++  err = get_file_offset (fp, paddr, &offset);
++  if (err)
++    {
++      fclose (fp);
++      return err;
++    }
++
+   err = _gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+   if (err)
+     {
+@@ -651,14 +712,14 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+       nread = fread (buffer+HMAC_LEN, 1, buffer_size, fp);
+       if (nread < buffer_size)
+         {
+-          if (off - HMAC_LEN <= paddr && paddr <= off + nread)
+-            memset (buffer + HMAC_LEN + paddr - off, 0, HMAC_LEN);
++          if (off - HMAC_LEN <= offset && offset <= off + nread)
++            memset (buffer + HMAC_LEN + offset - off, 0, HMAC_LEN);
+           _gcry_md_write (hd, buffer, nread+HMAC_LEN);
+           break;
+         }
+ 
+-      if (off - HMAC_LEN <= paddr && paddr <= off + nread)
+-        memset (buffer + HMAC_LEN + paddr - off, 0, HMAC_LEN);
++      if (off - HMAC_LEN <= offset && offset <= off + nread)
++        memset (buffer + HMAC_LEN + offset - off, 0, HMAC_LEN);
+       _gcry_md_write (hd, buffer, nread);
+       memcpy (buffer, buffer+buffer_size, HMAC_LEN);
+       off += nread;
+@@ -694,8 +755,8 @@ check_binary_integrity (void)
+   const char *key = KEY_FOR_BINARY_CHECK;
+   void *extra_info;
+ 
+-  if (!dladdr1 (hmac_for_the_implementation,
+-                &info, &extra_info, RTLD_DL_LINKMAP))
++  if (!dladdr1 (hmac_for_the_implementation, &info, &extra_info,
++                RTLD_DL_LINKMAP))
+     err = gpg_error_from_syserror ();
+   else
+     err = hmac256_check (info.dli_fname, key, extra_info);
+-- 
+2.39.0
+
+
+From 521500624b4b11538d206137205e2a511dad7072 Mon Sep 17 00:00:00 2001
+From: NIIBE Yutaka <gniibe@fsij.org>
+Date: Tue, 15 Feb 2022 20:38:02 +0900
+Subject: [PATCH] fips: Fix previous commit.
+
+--
+
+Coding style fix.
+
+Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
+---
+ src/fips.c | 64 +++++++++++++++++++++++++++---------------------------
+ 1 file changed, 32 insertions(+), 32 deletions(-)
+
+diff --git a/src/fips.c b/src/fips.c
+index c40274d9..f16bce8b 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -596,54 +596,55 @@ run_random_selftests (void)
+ static const unsigned char __attribute__ ((section (".rodata1")))
+ hmac_for_the_implementation[HMAC_LEN];
+ 
+-/**
+- * Determine the offset of the given virtual address in the ELF file opened as
+- * fp and return it in offset. Rewinds fp to the beginning on success.
++/*
++ * In the ELF file opened as FP, determine the offset of the given
++ * virtual address ADDR and return it in OFFSET.  Rewinds FP to the
++ * beginning on success.
+  */
+ static gpg_error_t
+-get_file_offset (FILE *fp, unsigned long paddr, unsigned long *offset)
++get_file_offset (FILE *fp, unsigned long addr, unsigned long *offset)
+ {
+   ElfW (Ehdr) ehdr;
+   ElfW (Phdr) phdr;
+   uint16_t e_phidx;
+ 
+-  // read the ELF header
+-  if (0 != fseek (fp, 0, SEEK_SET))
++  /* Read the ELF header */
++  if (fseek (fp, 0, SEEK_SET) != 0)
+     return gpg_error_from_syserror ();
+-  if (1 != fread (&ehdr, sizeof (ehdr), 1, fp))
++  if (fread (&ehdr, sizeof (ehdr), 1, fp) != 1)
+     return gpg_error_from_syserror ();
+ 
+-  // the section header entry size should match the size of the shdr struct
++  /* The program header entry size should match the size of the phdr struct */
+   if (ehdr.e_phentsize != sizeof (phdr))
+     return gpg_error (GPG_ERR_INV_OBJ);
+   if (ehdr.e_phoff == 0)
+     return gpg_error (GPG_ERR_INV_OBJ);
+ 
+-  // jump to the first program header
+-  if (0 != fseek (fp, ehdr.e_phoff, SEEK_SET))
++  /* Jump to the first program header */
++  if (fseek (fp, ehdr.e_phoff, SEEK_SET) != 0)
+     return gpg_error_from_syserror ();
+ 
+-  // iterate over the program headers, compare their virtual addresses with the
+-  // address we are looking for, and if the program header matches, calculate
+-  // the offset of the given paddr in the file using the program header's
+-  // p_offset field.
++  /* Iterate over the program headers, compare their virtual addresses
++     with the address we are looking for, and if the program header
++     matches, calculate the offset of the given ADDR in the file using
++     the program header's p_offset field.  */
+   for (e_phidx = 0; e_phidx < ehdr.e_phnum; e_phidx++)
+     {
+-      if (1 != fread (&phdr, sizeof (phdr), 1, fp))
++      if (fread (&phdr, sizeof (phdr), 1, fp) != 1)
+         return gpg_error_from_syserror ();
+-      if (phdr.p_type == PT_LOAD && phdr.p_vaddr <= paddr
+-          && phdr.p_vaddr + phdr.p_memsz > paddr)
++      if (phdr.p_type == PT_LOAD
++          && phdr.p_vaddr <= addr && addr < phdr.p_vaddr + phdr.p_memsz)
+         {
+-          // found section, compute the offset of paddr in the file
+-          *offset = phdr.p_offset + (paddr - phdr.p_vaddr);
++          /* Found segment, compute the offset of ADDR in the file */
++          *offset = phdr.p_offset + (addr - phdr.p_vaddr);
+ 
+-          if (0 != fseek (fp, 0, SEEK_SET))
++          if (fseek (fp, 0, SEEK_SET) != 0)
+             return gpg_error_from_syserror ();
+           return 0;
+         }
+     }
+ 
+-  // section not found in the file
++  /* Segment not found in the file */
+   return gpg_error (GPG_ERR_INV_OBJ);
+ }
+ 
+@@ -655,17 +656,16 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+   gcry_md_hd_t hd;
+   size_t buffer_size, nread;
+   char *buffer;
+-  unsigned long paddr;
++  unsigned long addr;
+   unsigned long offset = 0;
+-  unsigned long off = 0;
+-
+-  paddr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
++  unsigned long pos = 0;
+ 
++  addr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
+   fp = fopen (filename, "rb");
+   if (!fp)
+     return gpg_error (GPG_ERR_INV_OBJ);
+ 
+-  err = get_file_offset (fp, paddr, &offset);
++  err = get_file_offset (fp, addr, &offset);
+   if (err)
+     {
+       fclose (fp);
+@@ -698,7 +698,7 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+     }
+ 
+   nread = fread (buffer, 1, HMAC_LEN, fp);
+-  off += nread;
++  pos += nread;
+   if (nread < HMAC_LEN)
+     {
+       xfree (buffer);
+@@ -712,17 +712,17 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+       nread = fread (buffer+HMAC_LEN, 1, buffer_size, fp);
+       if (nread < buffer_size)
+         {
+-          if (off - HMAC_LEN <= offset && offset <= off + nread)
+-            memset (buffer + HMAC_LEN + offset - off, 0, HMAC_LEN);
++          if (pos - HMAC_LEN <= offset && offset <= pos + nread)
++            memset (buffer + HMAC_LEN + offset - pos, 0, HMAC_LEN);
+           _gcry_md_write (hd, buffer, nread+HMAC_LEN);
+           break;
+         }
+ 
+-      if (off - HMAC_LEN <= offset && offset <= off + nread)
+-        memset (buffer + HMAC_LEN + offset - off, 0, HMAC_LEN);
++      if (pos - HMAC_LEN <= offset && offset <= pos + nread)
++        memset (buffer + HMAC_LEN + offset - pos, 0, HMAC_LEN);
+       _gcry_md_write (hd, buffer, nread);
+       memcpy (buffer, buffer+buffer_size, HMAC_LEN);
+-      off += nread;
++      pos += nread;
+     }
+ 
+   if (ferror (fp))
+-- 
+2.39.1
+
+
+From 9dcf9305962b90febdf2d7cc73b49feadbf6a01f Mon Sep 17 00:00:00 2001
+From: NIIBE Yutaka <gniibe@fsij.org>
+Date: Wed, 16 Feb 2022 14:06:02 +0900
+Subject: [PATCH] fips: Integrity check improvement, with only loadable
+ segments.
+
+* configure.ac (READELF): Check the tool.
+* src/Makefile.am (libgcrypt.so.hmac): Use genhmac.sh with hmac256.
+* src/fips.c (get_file_offsets): Rename from get_file_offset.
+Determine the OFFSET2 at the end of loadable segments, too.
+Add fixup of the ELF header to exclude section information.
+(hmac256_check): Finish scanning at the end of loadble segments.
+* src/genhmac.sh: New.
+
+--
+
+This change fixes the build with ld.gold.
+
+GnuPG-bug-id: 5835
+Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
+---
+ configure.ac    |  1 +
+ src/Makefile.am |  4 +--
+ src/fips.c      | 73 +++++++++++++++++++++++++++++--------------
+ src/genhmac.sh  | 83 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 136 insertions(+), 25 deletions(-)
+ create mode 100755 src/genhmac.sh
+
+diff --git a/configure.ac b/configure.ac
+index f0f1637f..ea01f5a6 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -579,6 +579,7 @@ else
+     AC_DEFINE(ENABLE_HMAC_BINARY_CHECK,1,
+               [Define to support an HMAC based integrity check])
+     AC_CHECK_TOOL(OBJCOPY, [objcopy])
++    AC_CHECK_TOOL(READELF, [readelf])
+     if test "$use_hmac_binary_check" != yes ; then
+         DEF_HMAC_BINARY_CHECK=-DKEY_FOR_BINARY_CHECK="'\"$use_hmac_binary_check\"'"
+     fi
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 018d5761..72100671 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -24,7 +24,7 @@ pkgconfigdir = $(libdir)/pkgconfig
+ pkgconfig_DATA = libgcrypt.pc
+ 
+ EXTRA_DIST = libgcrypt-config.in libgcrypt.m4 libgcrypt.vers \
+-             gcrypt.h.in libgcrypt.def libgcrypt.pc.in
++             gcrypt.h.in libgcrypt.def libgcrypt.pc.in genhmac.sh
+ 
+ bin_SCRIPTS = libgcrypt-config
+ m4datadir = $(datadir)/aclocal
+@@ -149,7 +149,7 @@ libgcrypt.la.done: libgcrypt.so.hmac
+ 	@touch libgcrypt.la.done
+ 
+ libgcrypt.so.hmac: hmac256 libgcrypt.la
+-	./hmac256 --stdkey --binary  < .libs/libgcrypt.so > $@
++	READELF=$(READELF) AWK=$(AWK) $(srcdir)/genhmac.sh > $@
+ else !USE_HMAC_BINARY_CHECK
+ libgcrypt.la.done: libgcrypt.la
+ 	@touch libgcrypt.la.done
+diff --git a/src/fips.c b/src/fips.c
+index f16bce8b..134d0eae 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -598,50 +598,68 @@ hmac_for_the_implementation[HMAC_LEN];
+ 
+ /*
+  * In the ELF file opened as FP, determine the offset of the given
+- * virtual address ADDR and return it in OFFSET.  Rewinds FP to the
++ * virtual address ADDR and return it in R_OFFSET1.  Determine the
++ * offset of last loadable section in R_OFFSET2.  Rewinds FP to the
+  * beginning on success.
+  */
+ static gpg_error_t
+-get_file_offset (FILE *fp, unsigned long addr, unsigned long *offset)
++get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
++                  unsigned long *r_offset1, unsigned long *r_offset2)
+ {
+-  ElfW (Ehdr) ehdr;
+   ElfW (Phdr) phdr;
+   uint16_t e_phidx;
++  long pos = 0;
+ 
+   /* Read the ELF header */
+   if (fseek (fp, 0, SEEK_SET) != 0)
+     return gpg_error_from_syserror ();
+-  if (fread (&ehdr, sizeof (ehdr), 1, fp) != 1)
++  if (fread (ehdr_p, sizeof (*ehdr_p), 1, fp) != 1)
+     return gpg_error_from_syserror ();
+ 
++  /* Fix up the ELF header, clean all section information.  */
++  ehdr_p->e_shoff = 0;
++  ehdr_p->e_shentsize = 0;
++  ehdr_p->e_shnum = 0;
++  ehdr_p->e_shstrndx = 0;
++
+   /* The program header entry size should match the size of the phdr struct */
+-  if (ehdr.e_phentsize != sizeof (phdr))
++  if (ehdr_p->e_phentsize != sizeof (phdr))
+     return gpg_error (GPG_ERR_INV_OBJ);
+-  if (ehdr.e_phoff == 0)
++  if (ehdr_p->e_phoff == 0)
+     return gpg_error (GPG_ERR_INV_OBJ);
+ 
+   /* Jump to the first program header */
+-  if (fseek (fp, ehdr.e_phoff, SEEK_SET) != 0)
++  if (fseek (fp, ehdr_p->e_phoff, SEEK_SET) != 0)
+     return gpg_error_from_syserror ();
+ 
+   /* Iterate over the program headers, compare their virtual addresses
+      with the address we are looking for, and if the program header
+      matches, calculate the offset of the given ADDR in the file using
+      the program header's p_offset field.  */
+-  for (e_phidx = 0; e_phidx < ehdr.e_phnum; e_phidx++)
++  for (e_phidx = 0; e_phidx < ehdr_p->e_phnum; e_phidx++)
+     {
+       if (fread (&phdr, sizeof (phdr), 1, fp) != 1)
+         return gpg_error_from_syserror ();
+-      if (phdr.p_type == PT_LOAD
+-          && phdr.p_vaddr <= addr && addr < phdr.p_vaddr + phdr.p_memsz)
+-        {
+-          /* Found segment, compute the offset of ADDR in the file */
+-          *offset = phdr.p_offset + (addr - phdr.p_vaddr);
+ 
+-          if (fseek (fp, 0, SEEK_SET) != 0)
+-            return gpg_error_from_syserror ();
+-          return 0;
+-        }
++      if (phdr.p_type == PT_PHDR)
++        continue;
++
++      if (phdr.p_type != PT_LOAD)
++        break;
++
++      pos = phdr.p_offset + phdr.p_filesz;
++      if (phdr.p_vaddr <= addr && addr < phdr.p_vaddr + phdr.p_memsz)
++        /* Found segment, compute the offset of ADDR in the file */
++        *r_offset1 = phdr.p_offset + (addr - phdr.p_vaddr);
++    }
++
++  if (*r_offset1)
++    {
++      if (fseek (fp, 0, SEEK_SET) != 0)
++        return gpg_error_from_syserror ();
++
++      *r_offset2 = (unsigned long)pos;
++      return 0;
+     }
+ 
+   /* Segment not found in the file */
+@@ -657,15 +675,17 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+   size_t buffer_size, nread;
+   char *buffer;
+   unsigned long addr;
+-  unsigned long offset = 0;
++  unsigned long offset1 = 0;
++  unsigned long offset2 = 0;
+   unsigned long pos = 0;
++  ElfW (Ehdr) ehdr;
+ 
+   addr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
+   fp = fopen (filename, "rb");
+   if (!fp)
+     return gpg_error (GPG_ERR_INV_OBJ);
+ 
+-  err = get_file_offset (fp, addr, &offset);
++  err = get_file_offsets (fp, addr, &ehdr, &offset1, &offset2);
+   if (err)
+     {
+       fclose (fp);
+@@ -710,16 +730,23 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+   while (1)
+     {
+       nread = fread (buffer+HMAC_LEN, 1, buffer_size, fp);
++      if (pos + nread >= offset2)
++        nread = offset2 - pos;
++
++      /* Copy, fixed ELF header at the beginning.  */
++      if (pos - HMAC_LEN == 0)
++        memcpy (buffer, &ehdr, sizeof (ehdr));
++
+       if (nread < buffer_size)
+         {
+-          if (pos - HMAC_LEN <= offset && offset <= pos + nread)
+-            memset (buffer + HMAC_LEN + offset - pos, 0, HMAC_LEN);
++          if (pos - HMAC_LEN <= offset1 && offset1 <= pos + nread)
++            memset (buffer + HMAC_LEN + offset1 - pos, 0, HMAC_LEN);
+           _gcry_md_write (hd, buffer, nread+HMAC_LEN);
+           break;
+         }
+ 
+-      if (pos - HMAC_LEN <= offset && offset <= pos + nread)
+-        memset (buffer + HMAC_LEN + offset - pos, 0, HMAC_LEN);
++      if (pos - HMAC_LEN <= offset1 && offset1 <= pos + nread)
++        memset (buffer + HMAC_LEN + offset1 - pos, 0, HMAC_LEN);
+       _gcry_md_write (hd, buffer, nread);
+       memcpy (buffer, buffer+buffer_size, HMAC_LEN);
+       pos += nread;
+diff --git a/src/genhmac.sh b/src/genhmac.sh
+new file mode 100755
+index 00000000..bb33b9c6
+--- /dev/null
++++ b/src/genhmac.sh
+@@ -0,0 +1,83 @@
++#! /bin/sh
++
++#
++# genhmac.sh - Build tool to generate hmac hash
++#
++# Copyright (C) 2022  g10 Code GmbH
++#
++# This file is part of libgcrypt.
++#
++# libgcrypt 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.
++#
++# libgcrypt 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 <https://www.gnu.org/licenses/>.
++#
++
++set -e
++
++#
++# Following variables should be defined to invoke this script
++#
++#   READELF
++#   AWK
++#
++
++AWK_VERSION_OUTPUT=$($AWK 'BEGIN { print PROCINFO["version"] }')
++if test -n "$AWK_VERSION_OUTPUT"; then
++    # It's GNU awk, which supports PROCINFO.
++    AWK_OPTION=--non-decimal-data
++fi
++
++FILE=.libs/libgcrypt.so
++
++#
++# Fixup the ELF header to clean up section information
++#
++printf '%b' '\002' > 2.bin
++dd ibs=1 skip=4 count=1 if=$FILE status=none > class-byte.bin
++if cmp class-byte.bin 2.bin; then
++    CLASS=64
++    HEADER_SIZE=64
++else
++    CLASS=32
++    HEADER_SIZE=52
++fi
++
++if test $CLASS -eq 64; then
++    dd ibs=1         count=40 if=$FILE     status=none
++    dd ibs=1         count=8  if=/dev/zero status=none
++    dd ibs=1 skip=48 count=10 if=$FILE     status=none
++    dd ibs=1         count=6  if=/dev/zero status=none
++else
++    dd ibs=1         count=32 if=$FILE     status=none
++    dd ibs=1         count=4  if=/dev/zero status=none
++    dd ibs=1 skip=36 count=10 if=$FILE     status=none
++    dd ibs=1         count=6  if=/dev/zero status=none
++fi > header-fixed.bin
++
++# Compute the end of loadable segment.
++#
++# This require computation in hexadecimal, and GNU awk needs
++# --non-decimal-data option
++#
++OFFSET=$($READELF --wide --program-headers $FILE | \
++         $AWK $AWK_OPTION "/^  LOAD/ { offset=\$2+\$5-$HEADER_SIZE }\
++END { print offset}")
++
++#
++# Feed the header fixed and loadable segments to HMAC256
++# to generate hmac hash of the FILE
++#
++(cat header-fixed.bin; \
++ dd ibs=1 skip=$HEADER_SIZE count=$OFFSET if=$FILE status=none) \
++ | ./hmac256 --stdkey --binary
++
++rm -f 2.bin class-byte.bin header-fixed.bin
+-- 
+2.39.1
+
+
+From a340e980388243ceae6df57d101036f3f2a955be Mon Sep 17 00:00:00 2001
+From: NIIBE Yutaka <gniibe@fsij.org>
+Date: Wed, 16 Feb 2022 20:08:15 +0900
+Subject: [PATCH] fips: More portable integrity check.
+
+* src/Makefile.am (EXTRA_DIST): Change the name of the script.
+(libgcrypt.la.done): Invoce OBJCOPY with --add-section.
+(libgcrypt.so.hmac): Specify ECHO_N.
+* src/fips.c (get_file_offset): Rename from get_file_offsets.
+Find the note section and return the value in HMAC.
+(hmac256_check): Simplify by HMAC from the note section, not loaded.
+(check_binary_integrity): Use dladdr instead of dladdr1.
+* src/gen-note-integrity.sh: Rename from genhmac.sh.
+Generate ElfN_Nhdr, and then the hmac.
+
+--
+
+The idea of use of .note is by Daiki Ueno.
+    https://gitlab.com/dueno/integrity-notes
+
+Further, instead of NOTE segment loaded onto memory, use noload
+section in the file.
+
+Thanks to Clemens Lang for initiating this direction of improvement.
+
+The namespace "FDO" would need to be changed.
+
+GnuPG-bug-id: 5835
+Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
+---
+ src/Makefile.am                           |   8 +-
+ src/fips.c                                | 167 +++++++++++++---------
+ src/{genhmac.sh => gen-note-integrity.sh} |  34 ++++-
+ 3 files changed, 134 insertions(+), 75 deletions(-)
+ rename src/{genhmac.sh => gen-note-integrity.sh} (78%)
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 72100671..b8bb187a 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -24,7 +24,7 @@ pkgconfigdir = $(libdir)/pkgconfig
+ pkgconfig_DATA = libgcrypt.pc
+ 
+ EXTRA_DIST = libgcrypt-config.in libgcrypt.m4 libgcrypt.vers \
+-             gcrypt.h.in libgcrypt.def libgcrypt.pc.in genhmac.sh
++             gcrypt.h.in libgcrypt.def libgcrypt.pc.in gen-note-integrity.sh
+ 
+ bin_SCRIPTS = libgcrypt-config
+ m4datadir = $(datadir)/aclocal
+@@ -143,13 +143,15 @@ if USE_HMAC_BINARY_CHECK
+ CLEANFILES += libgcrypt.so.hmac
+ 
+ libgcrypt.la.done: libgcrypt.so.hmac
+-	$(OBJCOPY) --update-section .rodata1=libgcrypt.so.hmac \
++	$(OBJCOPY) --add-section .note.fdo.integrity=libgcrypt.so.hmac \
++	  --set-section-flags .note.fdo.integrity=noload,readonly \
+ 	  .libs/libgcrypt.so .libs/libgcrypt.so.new
+ 	mv -f .libs/libgcrypt.so.new .libs/libgcrypt.so.*.*
+ 	@touch libgcrypt.la.done
+ 
+ libgcrypt.so.hmac: hmac256 libgcrypt.la
+-	READELF=$(READELF) AWK=$(AWK) $(srcdir)/genhmac.sh > $@
++	ECHO_N=$(ECHO_N) READELF=$(READELF) AWK=$(AWK) \
++	$(srcdir)/gen-note-integrity.sh > $@
+ else !USE_HMAC_BINARY_CHECK
+ libgcrypt.la.done: libgcrypt.la
+ 	@touch libgcrypt.la.done
+diff --git a/src/fips.c b/src/fips.c
+index 134d0eae..d798d577 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -593,22 +593,20 @@ run_random_selftests (void)
+ # endif
+ #define HMAC_LEN 32
+ 
+-static const unsigned char __attribute__ ((section (".rodata1")))
+-hmac_for_the_implementation[HMAC_LEN];
+-
+ /*
+- * In the ELF file opened as FP, determine the offset of the given
+- * virtual address ADDR and return it in R_OFFSET1.  Determine the
+- * offset of last loadable section in R_OFFSET2.  Rewinds FP to the
+- * beginning on success.
++ * In the ELF file opened as FP, fill the ELF header to the pointer
++ * EHDR_P, determine the offset of last loadable segment in R_OFFSET.
++ * Also, find the section which contains the hmac value and return it
++ * in HMAC.  Rewinds FP to the beginning on success.
+  */
+ static gpg_error_t
+-get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
+-                  unsigned long *r_offset1, unsigned long *r_offset2)
++get_file_offset (FILE *fp, ElfW (Ehdr) *ehdr_p,
++                 unsigned long *r_offset, unsigned char hmac[HMAC_LEN])
+ {
+   ElfW (Phdr) phdr;
+-  uint16_t e_phidx;
+-  long pos = 0;
++  ElfW (Shdr) shdr;
++  int i;
++  unsigned long off_segment = 0;
+ 
+   /* Read the ELF header */
+   if (fseek (fp, 0, SEEK_SET) != 0)
+@@ -616,12 +614,6 @@ get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
+   if (fread (ehdr_p, sizeof (*ehdr_p), 1, fp) != 1)
+     return gpg_error_from_syserror ();
+ 
+-  /* Fix up the ELF header, clean all section information.  */
+-  ehdr_p->e_shoff = 0;
+-  ehdr_p->e_shentsize = 0;
+-  ehdr_p->e_shnum = 0;
+-  ehdr_p->e_shstrndx = 0;
+-
+   /* The program header entry size should match the size of the phdr struct */
+   if (ehdr_p->e_phentsize != sizeof (phdr))
+     return gpg_error (GPG_ERR_INV_OBJ);
+@@ -632,11 +624,9 @@ get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
+   if (fseek (fp, ehdr_p->e_phoff, SEEK_SET) != 0)
+     return gpg_error_from_syserror ();
+ 
+-  /* Iterate over the program headers, compare their virtual addresses
+-     with the address we are looking for, and if the program header
+-     matches, calculate the offset of the given ADDR in the file using
+-     the program header's p_offset field.  */
+-  for (e_phidx = 0; e_phidx < ehdr_p->e_phnum; e_phidx++)
++  /* Iterate over the program headers, determine the last loadable
++     segment.  */
++  for (i = 0; i < ehdr_p->e_phnum; i++)
+     {
+       if (fread (&phdr, sizeof (phdr), 1, fp) != 1)
+         return gpg_error_from_syserror ();
+@@ -647,45 +637,100 @@ get_file_offsets (FILE *fp, unsigned long addr, ElfW (Ehdr) *ehdr_p,
+       if (phdr.p_type != PT_LOAD)
+         break;
+ 
+-      pos = phdr.p_offset + phdr.p_filesz;
+-      if (phdr.p_vaddr <= addr && addr < phdr.p_vaddr + phdr.p_memsz)
+-        /* Found segment, compute the offset of ADDR in the file */
+-        *r_offset1 = phdr.p_offset + (addr - phdr.p_vaddr);
++      off_segment = phdr.p_offset + phdr.p_filesz;
+     }
+ 
+-  if (*r_offset1)
++  if (!off_segment)
++    /* The segment not found in the file */
++    return gpg_error (GPG_ERR_INV_OBJ);
++
++  /* The section header entry size should match the size of the shdr struct */
++  if (ehdr_p->e_shentsize != sizeof (shdr))
++    return gpg_error (GPG_ERR_INV_OBJ);
++  if (ehdr_p->e_shoff == 0)
++    return gpg_error (GPG_ERR_INV_OBJ);
++
++  /* Jump to the first section header */
++  if (fseek (fp, ehdr_p->e_shoff, SEEK_SET) != 0)
++    return gpg_error_from_syserror ();
++
++  /* Iterate over the section headers, determine the note section,
++     read the hmac value.  */
++  for (i = 0; i < ehdr_p->e_shnum; i++)
+     {
+-      if (fseek (fp, 0, SEEK_SET) != 0)
++      long off;
++
++      if (fread (&shdr, sizeof (shdr), 1, fp) != 1)
+         return gpg_error_from_syserror ();
+ 
+-      *r_offset2 = (unsigned long)pos;
+-      return 0;
++      off = ftell (fp);
++      if (shdr.sh_type == SHT_NOTE && shdr.sh_flags == 0 && shdr.sh_size == 48)
++        {
++          const char header_of_the_note[] = {
++            0x04, 0x00, 0x00, 0x00,
++            0x20, 0x00, 0x00, 0x00,
++            0xca, 0xfe, 0x2a, 0x8e,
++            'F', 'D', 'O', 0x00
++          };
++          unsigned char header[16];
++
++          /* Jump to the note section.  */
++          if (fseek (fp, shdr.sh_offset, SEEK_SET) != 0)
++            return gpg_error_from_syserror ();
++
++          if (fread (header, sizeof (header), 1, fp) != 1)
++            return gpg_error_from_syserror ();
++
++          if (!memcmp (header, header_of_the_note, 16))
++            {
++              /* Found.  Read the hmac value into HMAC.  */
++              if (fread (hmac, HMAC_LEN, 1, fp) != 1)
++                return gpg_error_from_syserror ();
++              break;
++            }
++
++          /* Back to the next section header.  */
++          if (fseek (fp, off, SEEK_SET) != 0)
++            return gpg_error_from_syserror ();
++        }
+     }
+ 
+-  /* Segment not found in the file */
+-  return gpg_error (GPG_ERR_INV_OBJ);
++  if (i == ehdr_p->e_shnum)
++    /* The note section not found.  */
++    return gpg_error (GPG_ERR_INV_OBJ);
++
++  /* Fix up the ELF header, clean all section information.  */
++  ehdr_p->e_shoff = 0;
++  ehdr_p->e_shentsize = 0;
++  ehdr_p->e_shnum = 0;
++  ehdr_p->e_shstrndx = 0;
++
++  *r_offset = off_segment;
++  if (fseek (fp, 0, SEEK_SET) != 0)
++    return gpg_error_from_syserror ();
++
++  return 0;
+ }
+ 
+ static gpg_error_t
+-hmac256_check (const char *filename, const char *key, struct link_map *lm)
++hmac256_check (const char *filename, const char *key)
+ {
+   gpg_error_t err;
+   FILE *fp;
+   gcry_md_hd_t hd;
+-  size_t buffer_size, nread;
++  const size_t buffer_size = 32768;
++  size_t nread;
+   char *buffer;
+-  unsigned long addr;
+-  unsigned long offset1 = 0;
+-  unsigned long offset2 = 0;
++  unsigned long offset = 0;
+   unsigned long pos = 0;
+   ElfW (Ehdr) ehdr;
++  unsigned char hmac[HMAC_LEN];
+ 
+-  addr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
+   fp = fopen (filename, "rb");
+   if (!fp)
+     return gpg_error (GPG_ERR_INV_OBJ);
+ 
+-  err = get_file_offsets (fp, addr, &ehdr, &offset1, &offset2);
++  err = get_file_offset (fp, &ehdr, &offset, hmac);
+   if (err)
+     {
+       fclose (fp);
+@@ -707,8 +752,7 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+       return err;
+     }
+ 
+-  buffer_size = 32768;
+-  buffer = xtrymalloc (buffer_size + HMAC_LEN);
++  buffer = xtrymalloc (buffer_size);
+   if (!buffer)
+     {
+       err = gpg_error_from_syserror ();
+@@ -717,38 +761,21 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+       return err;
+     }
+ 
+-  nread = fread (buffer, 1, HMAC_LEN, fp);
+-  pos += nread;
+-  if (nread < HMAC_LEN)
+-    {
+-      xfree (buffer);
+-      fclose (fp);
+-      _gcry_md_close (hd);
+-      return gpg_error (GPG_ERR_TOO_SHORT);
+-    }
+-
+   while (1)
+     {
+-      nread = fread (buffer+HMAC_LEN, 1, buffer_size, fp);
+-      if (pos + nread >= offset2)
+-        nread = offset2 - pos;
++      nread = fread (buffer, 1, buffer_size, fp);
++      if (pos + nread >= offset)
++        nread = offset - pos;
+ 
+-      /* Copy, fixed ELF header at the beginning.  */
+-      if (pos - HMAC_LEN == 0)
++      /* Copy the fixed ELF header at the beginning.  */
++      if (pos == 0)
+         memcpy (buffer, &ehdr, sizeof (ehdr));
+ 
++      _gcry_md_write (hd, buffer, nread);
++
+       if (nread < buffer_size)
+-        {
+-          if (pos - HMAC_LEN <= offset1 && offset1 <= pos + nread)
+-            memset (buffer + HMAC_LEN + offset1 - pos, 0, HMAC_LEN);
+-          _gcry_md_write (hd, buffer, nread+HMAC_LEN);
+-          break;
+-        }
++        break;
+ 
+-      if (pos - HMAC_LEN <= offset1 && offset1 <= pos + nread)
+-        memset (buffer + HMAC_LEN + offset1 - pos, 0, HMAC_LEN);
+-      _gcry_md_write (hd, buffer, nread);
+-      memcpy (buffer, buffer+buffer_size, HMAC_LEN);
+       pos += nread;
+     }
+ 
+@@ -759,7 +786,7 @@ hmac256_check (const char *filename, const char *key, struct link_map *lm)
+       unsigned char *digest;
+ 
+       digest = _gcry_md_read (hd, 0);
+-      if (!memcmp (digest, hmac_for_the_implementation, HMAC_LEN))
++      if (!memcmp (digest, hmac, HMAC_LEN))
+         /* Success.  */
+         err = 0;
+       else
+@@ -780,13 +807,11 @@ check_binary_integrity (void)
+   gpg_error_t err;
+   Dl_info info;
+   const char *key = KEY_FOR_BINARY_CHECK;
+-  void *extra_info;
+ 
+-  if (!dladdr1 (hmac_for_the_implementation, &info, &extra_info,
+-                RTLD_DL_LINKMAP))
++  if (!dladdr (hmac256_check, &info))
+     err = gpg_error_from_syserror ();
+   else
+-    err = hmac256_check (info.dli_fname, key, extra_info);
++    err = hmac256_check (info.dli_fname, key);
+ 
+   reporter ("binary", 0, NULL, err? gpg_strerror (err):NULL);
+ #ifdef HAVE_SYSLOG
+diff --git a/src/genhmac.sh b/src/gen-note-integrity.sh
+similarity index 78%
+rename from src/genhmac.sh
+rename to src/gen-note-integrity.sh
+index bb33b9c6..969fdca6 100755
+--- a/src/genhmac.sh
++++ b/src/gen-note-integrity.sh
+@@ -1,7 +1,7 @@
+ #! /bin/sh
+ 
+ #
+-# genhmac.sh - Build tool to generate hmac hash
++# gen-note-integrity.sh - Build tool to generate hmac hash section
+ #
+ # Copyright (C) 2022  g10 Code GmbH
+ #
+@@ -28,8 +28,40 @@ set -e
+ #
+ #   READELF
+ #   AWK
++#   ECHO_N
+ #
+ 
++######## Emit ElfN_Nhdr for note.fdo.integrity ########
++
++NOTE_NAME="FDO"
++
++# n_namesz = 4 including NUL
++printf '%b' '\004'
++printf '%b' '\000'
++printf '%b' '\000'
++printf '%b' '\000'
++
++# n_descsz = 32
++printf '%b' '\040'
++printf '%b' '\000'
++printf '%b' '\000'
++printf '%b' '\000'
++
++# n_type: NT_FDO_INTEGRITY=0xCAFE2A8E
++printf '%b' '\312'
++printf '%b' '\376'
++printf '%b' '\052'
++printf '%b' '\216'
++
++# the name
++echo $ECHO_N $NOTE_NAME
++printf '%b' '\000'
++
++# Here comes the alignment.  As the size of name is 4, it's none.
++# NO PADDING HERE.
++
++######## Rest is to generate hmac hash ########
++
+ AWK_VERSION_OUTPUT=$($AWK 'BEGIN { print PROCINFO["version"] }')
+ if test -n "$AWK_VERSION_OUTPUT"; then
+     # It's GNU awk, which supports PROCINFO.
+-- 
+2.39.1
+
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-integrity2.patch b/SOURCES/libgcrypt-1.10.0-fips-integrity2.patch
new file mode 100644
index 0000000..c1b7d9e
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-integrity2.patch
@@ -0,0 +1,158 @@
+From 3c8b6c4a9cad59c5e1db5706f6774a3141b60210 Mon Sep 17 00:00:00 2001
+From: NIIBE Yutaka <gniibe@fsij.org>
+Date: Thu, 17 Feb 2022 10:28:05 +0900
+Subject: [PATCH] fips: Fix gen-note-integrity.sh script not to use cmp
+ utility.
+
+* src/gen-note-integrity.sh: Simplify detecting 32-bit machine
+or 64-bit machine.
+
+--
+
+GnuPG-bug-id: 5835
+Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
+---
+ src/gen-note-integrity.sh | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/gen-note-integrity.sh b/src/gen-note-integrity.sh
+index 969fdca6..878d7095 100755
+--- a/src/gen-note-integrity.sh
++++ b/src/gen-note-integrity.sh
+@@ -73,9 +73,9 @@ FILE=.libs/libgcrypt.so
+ #
+ # Fixup the ELF header to clean up section information
+ #
+-printf '%b' '\002' > 2.bin
+-dd ibs=1 skip=4 count=1 if=$FILE status=none > class-byte.bin
+-if cmp class-byte.bin 2.bin; then
++BYTE002=$(printf '%b' '\002')
++CLASS_BYTE=$(dd ibs=1 skip=4 count=1 if=$FILE status=none)
++if test "$CLASS_BYTE" = "$BYTE002"; then
+     CLASS=64
+     HEADER_SIZE=64
+ else
+@@ -112,4 +112,4 @@ END { print offset}")
+  dd ibs=1 skip=$HEADER_SIZE count=$OFFSET if=$FILE status=none) \
+  | ./hmac256 --stdkey --binary
+ 
+-rm -f 2.bin class-byte.bin header-fixed.bin
++rm -f header-fixed.bin
+-- 
+2.39.1
+
+
+From 052c5ef4cea56772b7015e36f231fa0bcbf91410 Mon Sep 17 00:00:00 2001
+From: NIIBE Yutaka <gniibe@fsij.org>
+Date: Thu, 17 Feb 2022 11:21:35 +0900
+Subject: [PATCH] fips: Clarify what to be hashed for the integrity check.
+
+* src/fips.c (get_file_offset): Compute the maximum offset
+of segments.
+* src/gen-note-integrity.sh: Likewise.
+
+--
+
+The result is same (in current format of ELF program).
+Semantics is more clear.  It hashes:
+
+  - From the start of shared library file,
+  - fixed up the ELF header to exclude link-time information,
+  - up to the last segment.
+
+Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
+---
+ src/fips.c                | 20 +++++++++-----------
+ src/gen-note-integrity.sh | 20 ++++++++++++++------
+ 2 files changed, 23 insertions(+), 17 deletions(-)
+
+diff --git a/src/fips.c b/src/fips.c
+index d798d577..89f8204b 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -595,7 +595,7 @@ run_random_selftests (void)
+ 
+ /*
+  * In the ELF file opened as FP, fill the ELF header to the pointer
+- * EHDR_P, determine the offset of last loadable segment in R_OFFSET.
++ * EHDR_P, determine the maximum offset of segments in R_OFFSET.
+  * Also, find the section which contains the hmac value and return it
+  * in HMAC.  Rewinds FP to the beginning on success.
+  */
+@@ -624,24 +624,22 @@ get_file_offset (FILE *fp, ElfW (Ehdr) *ehdr_p,
+   if (fseek (fp, ehdr_p->e_phoff, SEEK_SET) != 0)
+     return gpg_error_from_syserror ();
+ 
+-  /* Iterate over the program headers, determine the last loadable
+-     segment.  */
++  /* Iterate over the program headers, determine the last offset of
++     segments.  */
+   for (i = 0; i < ehdr_p->e_phnum; i++)
+     {
++      unsigned long off;
++
+       if (fread (&phdr, sizeof (phdr), 1, fp) != 1)
+         return gpg_error_from_syserror ();
+ 
+-      if (phdr.p_type == PT_PHDR)
+-        continue;
+-
+-      if (phdr.p_type != PT_LOAD)
+-        break;
+-
+-      off_segment = phdr.p_offset + phdr.p_filesz;
++      off = phdr.p_offset + phdr.p_filesz;
++      if (off_segment < off)
++        off_segment = off;
+     }
+ 
+   if (!off_segment)
+-    /* The segment not found in the file */
++    /* No segment found in the file */
+     return gpg_error (GPG_ERR_INV_OBJ);
+ 
+   /* The section header entry size should match the size of the shdr struct */
+diff --git a/src/gen-note-integrity.sh b/src/gen-note-integrity.sh
+index 878d7095..50071bf5 100755
+--- a/src/gen-note-integrity.sh
++++ b/src/gen-note-integrity.sh
+@@ -95,21 +95,29 @@ else
+     dd ibs=1         count=6  if=/dev/zero status=none
+ fi > header-fixed.bin
+ 
+-# Compute the end of loadable segment.
++#
++# Compute the end of segments, and emit the COUNT to read
++# (For each segment in program headers, calculate the offset
++#  and select the maximum)
+ #
+ # This require computation in hexadecimal, and GNU awk needs
+ # --non-decimal-data option
+ #
+-OFFSET=$($READELF --wide --program-headers $FILE | \
+-         $AWK $AWK_OPTION "/^  LOAD/ { offset=\$2+\$5-$HEADER_SIZE }\
+-END { print offset}")
++COUNT=$($READELF --wide --program-headers $FILE | \
++         $AWK $AWK_OPTION \
++"BEGIN { max_offset=0 }
++/^\$/ { if (program_headers_start) program_headers_end=1 }
++(program_headers_start && !program_headers_end) { offset = \$2 + \$5 }
++(max_offset < offset) { max_offset = offset }
++/^  Type/ { program_headers_start=1 }
++END { print max_offset- $HEADER_SIZE }")
+ 
+ #
+-# Feed the header fixed and loadable segments to HMAC256
++# Feed the header fixed and all segments to HMAC256
+ # to generate hmac hash of the FILE
+ #
+ (cat header-fixed.bin; \
+- dd ibs=1 skip=$HEADER_SIZE count=$OFFSET if=$FILE status=none) \
++ dd ibs=1 skip=$HEADER_SIZE count=$COUNT if=$FILE status=none) \
+  | ./hmac256 --stdkey --binary
+ 
+ rm -f header-fixed.bin
+-- 
+2.39.1
+
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-kdf.patch b/SOURCES/libgcrypt-1.10.0-fips-kdf.patch
new file mode 100644
index 0000000..021476a
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-kdf.patch
@@ -0,0 +1,129 @@
+From 3c04b692de1e7b45b764ff8d66bf84609b012e3a Mon Sep 17 00:00:00 2001
+From: Tobias Heider <tobias.heider@canonical.com>
+Date: Tue, 27 Sep 2022 13:31:05 +0900
+Subject: [PATCH] kdf:pkdf2: Check minimum allowed key size when running in
+ FIPS mode.
+
+* cipher/kdf.c (_gcry_kdf_pkdf2): Add output length check.
+
+--
+
+GnuPG-bug-id: 6219
+---
+ cipher/kdf.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/cipher/kdf.c b/cipher/kdf.c
+index 81523320..67c60df8 100644
+--- a/cipher/kdf.c
++++ b/cipher/kdf.c
+@@ -160,6 +160,10 @@ _gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen,
+     return GPG_ERR_INV_VALUE;
+ #endif
+ 
++  /* Check minimum key size */
++  if (fips_mode () && dklen < 14)
++    return GPG_ERR_INV_VALUE;
++
+ 
+   /* Step 2 */
+   l = ((dklen - 1)/ hlen) + 1;
+-- 
+2.37.3
+From e5a5e847b66eb6b80e60a2dffa347268f059aee3 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Tue, 4 Oct 2022 12:44:54 +0200
+Subject: [PATCH] tests: Reproducer for short dklen in FIPS mode
+
+* tests/t-kdf.c (check_pbkdf2): Add test vector with short dklen and
+  verify it fails in FIPS mode
+--
+
+GnuPG-bug-id: 6219
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ tests/t-kdf.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/tests/t-kdf.c b/tests/t-kdf.c
+index c0192d7b..716fb53e 100644
+--- a/tests/t-kdf.c
++++ b/tests/t-kdf.c
+@@ -909,6 +909,14 @@ check_pbkdf2 (void)
+       "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9"
+       "\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6"
+     },
++    {
++      "password", 8,
++      "salt", 4,
++      GCRY_MD_SHA1,
++      1,
++      10, /* too short dklen for FIPS */
++      "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9"
++    },
+     {
+       "password", 8,
+       "salt", 4,
+@@ -1109,7 +1117,7 @@ check_pbkdf2 (void)
+                              GCRY_KDF_PBKDF2, tv[tvidx].hashalgo,
+                              tv[tvidx].salt, tv[tvidx].saltlen,
+                              tv[tvidx].c, tv[tvidx].dklen, outbuf);
+-      if (in_fips_mode && tvidx > 6)
++      if (in_fips_mode && tvidx > 7)
+         {
+           if (!err)
+             fail ("pbkdf2 test %d unexpectedly passed in FIPS mode: %s\n",
+@@ -1118,7 +1126,7 @@ check_pbkdf2 (void)
+         }
+       if (err)
+         {
+-          if (in_fips_mode && tv[tvidx].plen < 14)
++          if (in_fips_mode && (tv[tvidx].plen < 14 || tv[tvidx].dklen < 14))
+             {
+               if (verbose)
+                 fprintf (stderr,
+-- 
+2.37.3
+
+From f4a861f3e5ae82f278284061e4829c03edf9c3a7 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Fri, 18 Nov 2022 09:49:50 +0900
+Subject: [PATCH] pkdf2: Add checks for FIPS.
+
+* cipher/kdf.c (_gcry_kdf_pkdf2): Require 8 chars passphrase for FIPS.
+Set bounds for salt length and iteration count in FIPS mode.
+
+--
+
+GnuPG-bug-id: 6039
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ cipher/kdf.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/cipher/kdf.c b/cipher/kdf.c
+index d22584da..823c744e 100644
+--- a/cipher/kdf.c
++++ b/cipher/kdf.c
+@@ -160,6 +160,18 @@ _gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen,
+     return GPG_ERR_INV_VALUE;
+ #endif
+ 
++  /* FIPS requires minimum passphrase length, see FIPS 140-3 IG D.N */
++  if (fips_mode () && passphraselen < 8)
++    return GPG_ERR_INV_VALUE;
++
++  /* FIPS requires minimum salt length of 128 b (SP 800-132 sec. 5.1, p.6) */
++  if (fips_mode () && saltlen < 16)
++    return GPG_ERR_INV_VALUE;
++
++  /* FIPS requires minimum iterations bound (SP 800-132 sec 5.2, p.6) */
++  if (fips_mode () && iterations < 1000)
++    return GPG_ERR_INV_VALUE;
++
+   /* Check minimum key size */
+   if (fips_mode () && dklen < 14)
+     return GPG_ERR_INV_VALUE;
+-- 
+2.39.0
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-keygen.patch b/SOURCES/libgcrypt-1.10.0-fips-keygen.patch
new file mode 100644
index 0000000..6df1429
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-keygen.patch
@@ -0,0 +1,55 @@
+From cd30ed3c0d715aa0c58a32a29cfb1476163a5b94 Mon Sep 17 00:00:00 2001
+From: NIIBE Yutaka <gniibe@fsij.org>
+Date: Wed, 20 Apr 2022 15:09:41 +0900
+Subject: [PATCH] cipher: Change the bounds for RSA key generation round.
+
+* cipher/rsa.c (generate_fips): Use 10 for p, 20 for q.
+
+--
+
+Constants from FIPS 186-5-draft.
+
+GnuPG-bug-id: 5919
+Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
+---
+ cipher/rsa.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/cipher/rsa.c b/cipher/rsa.c
+index 486a34f0..771413b3 100644
+--- a/cipher/rsa.c
++++ b/cipher/rsa.c
+@@ -476,7 +476,7 @@ generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
+ 
+  retry:
+   /* generate p and q */
+-  for (i = 0; i < 5 * pbits; i++)
++  for (i = 0; i < 10 * pbits; i++)
+     {
+     ploop:
+       if (!testparms)
+@@ -506,10 +506,10 @@ generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
+       else if (testparms)
+         goto err;
+     }
+-  if (i >= 5 * pbits)
++  if (i >= 10 * pbits)
+     goto err;
+ 
+-  for (i = 0; i < 5 * pbits; i++)
++  for (i = 0; i < 20 * pbits; i++)
+     {
+     qloop:
+       if (!testparms)
+@@ -555,7 +555,7 @@ generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
+       else if (testparms)
+         goto err;
+     }
+-  if (i >= 5 * pbits)
++  if (i >= 20 * pbits)
+     goto err;
+ 
+   if (testparms)
+-- 
+2.37.3
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-rsa-pss.patch b/SOURCES/libgcrypt-1.10.0-fips-rsa-pss.patch
new file mode 100644
index 0000000..af3f772
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-rsa-pss.patch
@@ -0,0 +1,109 @@
+From bf1e62e59200b2046680d1d3d1599facc88cfe63 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Tue, 29 Nov 2022 14:04:59 +0100
+Subject: [PATCH] rsa: Prevent usage of long salt in FIPS mode
+
+* cipher/rsa-common.c (_gcry_rsa_pss_encode): Prevent usage of large
+  salt lengths
+  (_gcry_rsa_pss_verify): Ditto.
+* tests/basic.c (check_pubkey_sign): Check longer salt length fails in
+  FIPS mode
+* tests/t-rsa-pss.c (one_test_sexp): Fix function name in error message
+---
+ cipher/rsa-common.c | 14 ++++++++++++++
+ tests/basic.c       | 19 ++++++++++++++++++-
+ tests/t-rsa-pss.c   |  2 +-
+ 3 files changed, 33 insertions(+), 2 deletions(-)
+
+diff --git a/cipher/rsa-common.c b/cipher/rsa-common.c
+index 233ddb2d..61cd60a4 100644
+--- a/cipher/rsa-common.c
++++ b/cipher/rsa-common.c
+@@ -809,6 +809,13 @@ _gcry_rsa_pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
+   hlen = _gcry_md_get_algo_dlen (algo);
+   gcry_assert (hlen);  /* We expect a valid ALGO here.  */
+ 
++  /* The FIPS 186-4 Section 5.5 allows only 0 <= sLen <= hLen */
++  if (fips_mode () && saltlen > hlen)
++    {
++      rc = GPG_ERR_INV_ARG;
++      goto leave;
++    }
++
+   /* Allocate a help buffer and setup some pointers.  */
+   buflen = 8 + hlen + saltlen + (emlen - hlen - 1);
+   buf = xtrymalloc (buflen);
+@@ -950,6 +957,13 @@ _gcry_rsa_pss_verify (gcry_mpi_t value, int hashed_already,
+   hlen = _gcry_md_get_algo_dlen (algo);
+   gcry_assert (hlen);  /* We expect a valid ALGO here.  */
+ 
++  /* The FIPS 186-4 Section 5.5 allows only 0 <= sLen <= hLen */
++  if (fips_mode () && saltlen > hlen)
++    {
++      rc = GPG_ERR_INV_ARG;
++      goto leave;
++    }
++
+   /* Allocate a help buffer and setup some pointers.
+      This buffer is used for two purposes:
+         +------------------------------+-------+
+diff --git a/tests/basic.c b/tests/basic.c
+index 77e2fd93..429bd237 100644
+--- a/tests/basic.c
++++ b/tests/basic.c
+@@ -16602,6 +16602,7 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
+     const char *data;
+     int algo;
+     int expected_rc;
++    int flags;
+   } datas[] =
+     {
+       { "(data\n (flags pkcs1)\n"
+@@ -16672,6 +16673,22 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
+         " (random-override #4253647587980912233445566778899019283747#))\n",
+ 	GCRY_PK_RSA,
+ 	0 },
++      { "(data\n (flags pss)\n"
++	" (hash-algo sha256)\n"
++	" (value #11223344556677889900AABBCCDDEEFF#)\n"
++	" (salt-length 2:32)\n"
++        " (random-override #42536475879809122334455667788990192837465564738291"
++                           "00122334455667#))\n",
++	GCRY_PK_RSA,
++	0 },
++      { "(data\n (flags pss)\n"
++	" (hash-algo sha256)\n"
++	" (value #11223344556677889900AABBCCDDEEFF#)\n"
++	" (salt-length 2:33)\n"
++        " (random-override #42536475879809122334455667788990192837465564738291"
++                           "0012233445566778#))\n",
++	GCRY_PK_RSA,
++	0, FLAG_NOFIPS },
+       { NULL }
+     };
+ 
+@@ -16695,7 +16712,7 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo,
+ 	die ("converting data failed: %s\n", gpg_strerror (rc));
+ 
+       rc = gcry_pk_sign (&sig, hash, skey);
+-      if (in_fips_mode && (flags & FLAG_NOFIPS))
++      if (in_fips_mode && (flags & FLAG_NOFIPS || datas[dataidx].flags & FLAG_NOFIPS))
+         {
+           if (!rc)
+             fail ("gcry_pk_sign did not fail as expected in FIPS mode\n");
+diff --git a/tests/t-rsa-pss.c b/tests/t-rsa-pss.c
+index c5f90116..82dd54b3 100644
+--- a/tests/t-rsa-pss.c
++++ b/tests/t-rsa-pss.c
+@@ -340,7 +340,7 @@ one_test_sexp (const char *n, const char *e, const char *d,
+     snprintf (p, 3, "%02x", out[i]);
+   if (strcmp (sig_string, s))
+     {
+-      fail ("gcry_pkhash_sign failed: %s",
++      fail ("gcry_pk_hash_sign failed: %s",
+             "wrong value returned");
+       info ("  expected: '%s'", s);
+       info ("       got: '%s'", sig_string);
+-- 
+2.39.0
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-selftest.patch b/SOURCES/libgcrypt-1.10.0-fips-selftest.patch
index 6840c07..7486f4a 100644
--- a/SOURCES/libgcrypt-1.10.0-fips-selftest.patch
+++ b/SOURCES/libgcrypt-1.10.0-fips-selftest.patch
@@ -921,3 +921,279 @@ index 78c26f2f..9d14a474 100644
  
 -- 
 2.37.1
+
+--
+
+ACVP testing uses the test-parms option to specify p and q to be checked
+for primality. When test-parms is specified, generate_fips() always
+returns keys with p=q=0. These keys then fail the pairwise consistency
+test, because they cannot be used to successfully sign a message and
+verify the signature.
+
+Skip the PCT when test-parms is specified.
+
+Add a regression test to check that this functionality continues to work
+in the future.
+
+Signed-off-by: Clemens Lang <cllang at redhat.com>
+---
+ cipher/rsa.c           |   5 +-
+ tests/Makefile.am      |   2 +-
+ tests/t-rsa-testparm.c | 130 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 135 insertions(+), 2 deletions(-)
+ create mode 100644 tests/t-rsa-testparm.c
+
+diff --git a/cipher/rsa.c b/cipher/rsa.c
+index 87f57b55..1a935d80 100644
+--- a/cipher/rsa.c
++++ b/cipher/rsa.c
+@@ -1218,6 +1218,7 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
+   int flags = 0;
+   gcry_sexp_t l1;
+   gcry_sexp_t swap_info = NULL;
++  int testparms = 0;
+ 
+   memset (&sk, 0, sizeof sk);
+ 
+@@ -1274,6 +1275,8 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
+         }
+       deriveparms = (genparms? sexp_find_token (genparms, "test-parms", 0)
+                      /**/    : NULL);
++      if (deriveparms)
++        testparms = 1;
+ 
+       /* Generate.  */
+       if (deriveparms || fips_mode ())
+@@ -1311,7 +1314,7 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
+   mpi_free (sk.u);
+   sexp_release (swap_info);
+ 
+-  if (!ec && fips_mode () && test_keys_fips (*r_skey))
++  if (!ec && !testparms && fips_mode () && test_keys_fips (*r_skey))
+     {
+       sexp_release (*r_skey); *r_skey = NULL;
+       fips_signal_error ("self-test after key generation failed");
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index f65725bc..302d923b 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -28,7 +28,7 @@ tests_bin = \
+ 	t-mpi-bit t-mpi-point curves t-lock \
+ 	prime basic keygen pubkey hmac hashtest t-kdf keygrip \
+ 	fips186-dsa aeswrap pkcs1v2 random dsa-rfc6979 \
+-	t-dsa t-ecdsa t-rsa-pss t-rsa-15 \
++	t-dsa t-ecdsa t-rsa-pss t-rsa-15 t-rsa-testparm \
+ 	t-ed25519 t-cv25519 t-x448 t-ed448
+
+ tests_bin_last = benchmark bench-slope
+diff --git a/tests/t-rsa-testparm.c b/tests/t-rsa-testparm.c
+new file mode 100644
+index 00000000..65617855
+--- /dev/null
++++ b/tests/t-rsa-testparm.c
+@@ -0,0 +1,130 @@
++/* t-rsa-testparm.c - Check the RSA Key Generation test-parm parameter
++ * Copyright (C) 2022 g10 Code GmbH
++ *
++ * This file is part of Libgcrypt.
++ *
++ * Libgcrypt 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.
++ *
++ * Libgcrypt 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 <https://www.gnu.org/licenses/>.
++ */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <gcrypt.h>
++
++#include "stopwatch.h"
++
++#define PGM "t-rsa-testparm"
++#include "t-common.h"
++
++
++static void
++check_rsa_testparm ()
++{
++  gpg_error_t err;
++  gcry_sexp_t keyspec = NULL;
++  gcry_sexp_t key = NULL;
++  const char *sexp = "(genkey (rsa (nbits \"2048\") (test-parms "
++    "(e \"65537\")"
++    "(p #00bbccabcee15d343944a47e492d4b1f4de79633e20cbb46f7d2d6813392a807ad048"
++        "cf77528edd19f77e7453f25173b9dcb70423afa2037aae147b81a33d541fc58f875ef"
++        "f1e852ab55e2e09a3debfbc151b3b0d17fef6f74d81fca14fbae531418e211ef81859"
++        "2af70de5cec3b92795cc3578572bf456099cd8727150e523261#)"
++    "(q #00ca87ecf2883f4ed00a9ec65abdeba81d28edbfcc34ecc563d587f166b52d42bfbe2"
++        "2bbc095b0b8426a2f8bbc55baaa8859b42cbc376ed3067db3ef7b135b63481322911e"
++        "bbd7014db83aa051e0ca2dbf302b75cd37f2ae8df90e134226e92f6353a284b28bb30"
++        "af0bbf925b345b955328379866ebac11d55bc80fe84f105d415#)"
++    ")))";
++
++  info ("Checking RSA KeyGen test-parm parameter.\n");
++
++  err = gcry_sexp_build (&keyspec, NULL, sexp);
++  if (err)
++    {
++      fail ("error building SEXP for test: %s", gpg_strerror (err));
++      goto leave;
++    }
++
++  err = gcry_pk_genkey (&key, keyspec);
++  if (err)
++    {
++      fail ("gcry_pk_genkey failed for test: %s", gpg_strerror (err));
++      goto leave;
++    }
++
++leave:
++  if (key)
++    gcry_sexp_release (key);
++  if (keyspec)
++    gcry_sexp_release (keyspec);
++}
++
++
++int
++main (int argc, char **argv)
++{
++  int last_argc = -1;
++
++  if (argc)
++    { argc--; argv++; }
++
++  while (argc && last_argc != argc )
++    {
++      last_argc = argc;
++      if (!strcmp (*argv, "--"))
++        {
++          argc--; argv++;
++          break;
++        }
++      else if (!strcmp (*argv, "--help"))
++        {
++          fputs ("usage: " PGM " [options]\n"
++                 "Options:\n"
++                 "  --verbose       print timings etc.\n"
++                 "  --debug         flyswatter\n",
++                 stdout);
++          exit (0);
++        }
++      else if (!strcmp (*argv, "--verbose"))
++        {
++          verbose++;
++          argc--; argv++;
++        }
++      else if (!strcmp (*argv, "--debug"))
++        {
++          verbose += 2;
++          debug++;
++          argc--; argv++;
++        }
++      else if (!strncmp (*argv, "--", 2))
++        die ("unknown option '%s'", *argv);
++
++    }
++
++  xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0));
++  if (!gcry_check_version (GCRYPT_VERSION))
++    die ("version mismatch\n");
++  if (debug)
++    xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 0xffffffff, 0));
++
++  start_timer ();
++  check_rsa_testparm ();
++  stop_timer ();
++
++  info ("All tests completed in %s.  Errors: %d\n",
++        elapsed_time (1), error_count);
++  return !!error_count;
++}
+-- 
+2.37.3
+From 149f6f8654fdeaf7aa1ff8ac3d00d7454c0e6eff Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Wed, 5 Oct 2022 16:50:08 +0200
+Subject: [PATCH] fips: Mark gcry_pk_encrypt/decrypt function non-approved
+
+* src/fips.c (_gcry_fips_indicator_function): Fix typo in sign/verify
+  function names and add gcry_pk_encrypt and gcry_pk_decrypt.
+--
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ src/fips.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/fips.c b/src/fips.c
+index 9a524ea4..6599121c 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -395,8 +395,10 @@ _gcry_fips_indicator_function (va_list arg_ptr)
+ {
+   const char *function = va_arg (arg_ptr, const char *);
+ 
+-  if (strcmp (function, "gcry_sign") == 0 ||
+-      strcmp (function, "gcry_verify") == 0)
++  if (strcmp (function, "gcry_pk_sign") == 0 ||
++      strcmp (function, "gcry_pk_verify") == 0 ||
++      strcmp (function, "gcry_pk_encrypt") == 0 ||
++      strcmp (function, "gcry_pk_decrypt") == 0)
+     return GPG_ERR_NOT_SUPPORTED;
+ 
+   return GPG_ERR_NO_ERROR;
+-- 
+2.37.3
+
+From f91a0ab12d242815f74bf26c6076e9cf7a790023 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Thu, 6 Oct 2022 09:30:24 +0200
+Subject: [PATCH] cipher: Do not run RSA encryption selftest by default
+
+* cipher/rsa.c (selftests_rsa): Skip encryption selftest as this
+  operation is not claimed as part of the certification.
+---
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ cipher/rsa.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/cipher/rsa.c b/cipher/rsa.c
+index 56dde3d1..df4af94b 100644
+--- a/cipher/rsa.c
++++ b/cipher/rsa.c
+@@ -2169,10 +2169,13 @@ selftests_rsa (selftest_report_func_t report, int extended)
+   if (errtxt)
+     goto failed;
+ 
+-  what = "encrypt";
+-  errtxt = selftest_encr_2048 (pkey, skey);
+-  if (errtxt)
+-    goto failed;
++  if (extended)
++    {
++      what = "encrypt";
++      errtxt = selftest_encr_2048 (pkey, skey);
++      if (errtxt)
++        goto failed;
++    }
+ 
+   sexp_release (pkey);
+   sexp_release (skey);
+-- 
+2.37.3
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-x931.patch b/SOURCES/libgcrypt-1.10.0-fips-x931.patch
new file mode 100644
index 0000000..b4a99ba
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-x931.patch
@@ -0,0 +1,139 @@
+From 06ea5b5332ffdb44a0a394d766be8989bcb6a95c Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Tue, 6 Dec 2022 10:03:47 +0900
+Subject: [PATCH] fips,rsa: Prevent usage of X9.31 keygen in FIPS mode.
+
+* cipher/rsa.c (rsa_generate): Do not accept use-x931 or derive-parms
+in FIPS mode.
+* tests/pubkey.c (get_keys_x931_new): Expect failure in FIPS mode.
+(check_run): Skip checking X9.31 keys in FIPS mode.
+* doc/gcrypt.texi: Document "test-parms" and clarify some cases around
+the X9.31 keygen.
+
+--
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ cipher/rsa.c    |  5 +++++
+ doc/gcrypt.texi | 41 ++++++++++++++++++++++++++++++++++++-----
+ tests/pubkey.c  | 15 +++++++++++++--
+ 3 files changed, 54 insertions(+), 7 deletions(-)
+
+diff --git a/cipher/rsa.c b/cipher/rsa.c
+index df4af94b..45523e6b 100644
+--- a/cipher/rsa.c
++++ b/cipher/rsa.c
+@@ -1256,6 +1256,11 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
+   if (deriveparms || (flags & PUBKEY_FLAG_USE_X931))
+     {
+       int swapped;
++      if (fips_mode ())
++        {
++          sexp_release (deriveparms);
++          return GPG_ERR_INV_SEXP;
++        }
+       ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped);
+       sexp_release (deriveparms);
+       if (!ec && swapped)
+diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
+index d0372f3e..e845a4dd 100644
+--- a/doc/gcrypt.texi
++++ b/doc/gcrypt.texi
+@@ -2699,8 +2699,7 @@ achieve fastest ECC key generation.
+ Force the use of the ANSI X9.31 key generation algorithm instead of
+ the default algorithm. This flag is only meaningful for RSA key
+ generation and usually not required.  Note that this algorithm is
+-implicitly used if either @code{derive-parms} is given or Libgcrypt is
+-in FIPS mode.
++implicitly used if either @code{derive-parms} is given.
+ 
+ @item use-fips186
+ @cindex FIPS 186
+@@ -3310,9 +3309,9 @@ This is currently only implemented for RSA and DSA keys.  It is not
+ allowed to use this together with a @code{domain} specification.  If
+ given, it is used to derive the keys using the given parameters.
+ 
+-If given for an RSA key the X9.31 key generation algorithm is used
+-even if libgcrypt is not in FIPS mode.  If given for a DSA key, the
+-FIPS 186 algorithm is used even if libgcrypt is not in FIPS mode.
++If given for an RSA key, the X9.31 key generation algorithm is used.
++If given for a DSA key, the FIPS 186 algorithm is used even if
++libgcrypt is not in FIPS mode.
+ 
+ @example
+ (genkey
+@@ -3342,6 +3341,38 @@ FIPS 186 algorithm is used even if libgcrypt is not in FIPS mode.
+       (seed @var{seed-mpi}))))
+ @end example
+ 
++@item test-parms @var{list}
++This is currently only implemented for RSA keys. If given, the
++libgcrypt will not generate parameter, but tests whether the p,q is
++probably prime. Returns key with zeroes.
++
++The FIPS key generation algorithm is used even if libgcrypt is not
++in FIPS mode.
++
++@example
++(genkey
++  (rsa
++    (nbits 4:1024)
++    (rsa-use-e 1:3)
++    (test-parms
++      (e "65537")
++      (p #00bbccabcee15d343944a47e492d4b1f4de79633e2
++          0cbb46f7d2d6813392a807ad048cf77528edd19f77
++          e7453f25173b9dcb70423afa2037aae147b81a33d5
++          41fc58f875eff1e852ab55e2e09a3debfbc151b3b0
++          d17fef6f74d81fca14fbae531418e211ef818592af
++          70de5cec3b92795cc3578572bf456099cd8727150e
++          523261#)
++      (q #00ca87ecf2883f4ed00a9ec65abdeba81d28edbfcc
++          34ecc563d587f166b52d42bfbe22bbc095b0b8426a
++          2f8bbc55baaa8859b42cbc376ed3067db3ef7b135b
++          63481322911ebbd7014db83aa051e0ca2dbf302b75
++          cd37f2ae8df90e134226e92f6353a284b28bb30af0
++          bbf925b345b955328379866ebac11d55bc80fe84f1
++          05d415#)
++
++@end example
++
+ 
+ @item flags @var{flaglist}
+ This is preferred way to define flags.  @var{flaglist} may contain any
+diff --git a/tests/pubkey.c b/tests/pubkey.c
+index bc44f3a5..2669b41a 100644
+--- a/tests/pubkey.c
++++ b/tests/pubkey.c
+@@ -430,7 +430,17 @@ get_keys_x931_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
+   rc = gcry_pk_genkey (&key, key_spec);
+   gcry_sexp_release (key_spec);
+   if (rc)
+-    die ("error generating RSA key: %s\n", gcry_strerror (rc));
++    {
++      if (in_fips_mode)
++        {
++          if (verbose)
++            fprintf (stderr, "The X9.31 RSA keygen is not available in FIPS modee.\n");
++          return;
++        }
++      die ("error generating RSA key: %s\n", gcry_strerror (rc));
++    }
++  else if (in_fips_mode)
++    die ("generating X9.31 RSA key unexpected worked in FIPS mode\n");
+ 
+   if (verbose > 1)
+     show_sexp ("generated RSA (X9.31) key:\n", key);
+@@ -777,7 +787,8 @@ check_run (void)
+   if (verbose)
+     fprintf (stderr, "Checking generated RSA key (X9.31).\n");
+   get_keys_x931_new (&pkey, &skey);
+-  check_keys (pkey, skey, 800, 0);
++  if (!in_fips_mode)
++    check_keys (pkey, skey, 800, 0);
+   gcry_sexp_release (pkey);
+   gcry_sexp_release (skey);
+   pkey = skey = NULL;
+-- 
+2.39.0
+
diff --git a/SOURCES/libgcrypt-1.10.0-sha3-large.patch b/SOURCES/libgcrypt-1.10.0-sha3-large.patch
new file mode 100644
index 0000000..d03407e
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-sha3-large.patch
@@ -0,0 +1,621 @@
+From 2c1bb2f34f2812888f75c476037afae6d9e21798 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Fri, 23 Sep 2022 18:39:20 +0200
+Subject: [PATCH] keccak: Use size_t to avoid integer overflow
+
+Any input to the SHA3 functions > 4GB was giving wrong result when it
+was invoked in one-shot, while working correctly when it was fed by
+chunks. It turned out that the calculation in the `keccak_write`
+overflows the `unsigned int` type (`nlanes * 8` does not fit 32b when
+the `inlen` > 4GB).
+
+* cipher/keccak-armv7-neon.S: Fix function name in comment and change
+  parameter type to size_t
+* cipher/keccak.c (keccak_ops_t): Change absorb function signature to
+  use size_t
+  (keccak_absorb_lanes64_avx512): Change nlanes type to size_t
+  (_gcry_keccak_absorb_lanes64_armv7_neon): Ditto.
+  (keccak_absorb_lanes64_armv7_neon): Ditto.
+  (keccak_absorb_lanes32bi): Ditto.
+  (keccak_absorb_lanes32bi_bmi2): Ditto.
+  (keccak_write): Change nlanes variable to use size_t and avoid
+  overflow when calculating count.
+* cipher/keccak_permute_64.h (KECCAK_F1600_ABSORB_FUNC_NAME): Change
+  nlanes argument to use size_t.
+
+---
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ cipher/keccak-armv7-neon.S | 10 +++++-----
+ cipher/keccak.c            | 20 ++++++++++----------
+ cipher/keccak_permute_64.h |  2 +-
+ 3 files changed, 16 insertions(+), 16 deletions(-)
+
+diff --git a/cipher/keccak-armv7-neon.S b/cipher/keccak-armv7-neon.S
+index 0bec8d50..28a284a1 100644
+--- a/cipher/keccak-armv7-neon.S
++++ b/cipher/keccak-armv7-neon.S
+@@ -467,11 +467,11 @@ _gcry_keccak_permute_armv7_neon:
+ .ltorg
+ .size _gcry_keccak_permute_armv7_neon,.-_gcry_keccak_permute_armv7_neon;
+ 
+-@//unsigned _gcry_keccak_permute_armv7_neon(u64 *state, @r4
+-@					    int pos,    @r1
+-@					    const byte *lanes,   @r2
+-@					    unsigned int nlanes, @r3
+-@					    int blocklanes) @ r5 callable from C
++@//unsigned _gcry_keccak_absorb_lanes64_armv7_neon(u64 *state, @r4
++@						int pos,    @r1
++@						const byte *lanes,   @r2
++@						size_t nlanes, @r3
++@						int blocklanes) @ r5 callable from C
+ .p2align 3
+ .global   _gcry_keccak_absorb_lanes64_armv7_neon
+ .type  _gcry_keccak_absorb_lanes64_armv7_neon,%function;
+diff --git a/cipher/keccak.c b/cipher/keccak.c
+index e7e42473..6c385f71 100644
+--- a/cipher/keccak.c
++++ b/cipher/keccak.c
+@@ -131,7 +131,7 @@ typedef struct
+ {
+   unsigned int (*permute)(KECCAK_STATE *hd);
+   unsigned int (*absorb)(KECCAK_STATE *hd, int pos, const byte *lanes,
+-			 unsigned int nlanes, int blocklanes);
++			 size_t nlanes, int blocklanes);
+   unsigned int (*extract) (KECCAK_STATE *hd, unsigned int pos, byte *outbuf,
+ 			   unsigned int outlen);
+ } keccak_ops_t;
+@@ -513,7 +513,7 @@ static const keccak_ops_t keccak_avx512_64_ops =
+ unsigned int _gcry_keccak_permute_armv7_neon(u64 *state);
+ unsigned int _gcry_keccak_absorb_lanes64_armv7_neon(u64 *state, int pos,
+ 						    const byte *lanes,
+-						    unsigned int nlanes,
++						    size_t nlanes,
+ 						    int blocklanes);
+ 
+ static unsigned int keccak_permute64_armv7_neon(KECCAK_STATE *hd)
+@@ -523,7 +523,7 @@ static unsigned int keccak_permute64_armv7_neon(KECCAK_STATE *hd)
+ 
+ static unsigned int
+ keccak_absorb_lanes64_armv7_neon(KECCAK_STATE *hd, int pos, const byte *lanes,
+-				 unsigned int nlanes, int blocklanes)
++				 size_t nlanes, int blocklanes)
+ {
+   if (blocklanes < 0)
+     {
+@@ -571,7 +571,7 @@ static const keccak_ops_t keccak_armv7_neon_64_ops =
+ 
+ static unsigned int
+ keccak_absorb_lanes32bi(KECCAK_STATE *hd, int pos, const byte *lanes,
+-		        unsigned int nlanes, int blocklanes)
++		        size_t nlanes, int blocklanes)
+ {
+   unsigned int burn = 0;
+ 
+@@ -653,7 +653,7 @@ keccak_absorb_lane32bi_bmi2(u32 *lane, u32 x0, u32 x1)
+ 
+ static unsigned int
+ keccak_absorb_lanes32bi_bmi2(KECCAK_STATE *hd, int pos, const byte *lanes,
+-		             unsigned int nlanes, int blocklanes)
++		             size_t nlanes, int blocklanes)
+ {
+   unsigned int burn = 0;
+ 
+@@ -873,7 +873,8 @@ keccak_write (void *context, const void *inbuf_arg, size_t inlen)
+   const byte *inbuf = inbuf_arg;
+   unsigned int nburn, burn = 0;
+   unsigned int count, i;
+-  unsigned int pos, nlanes;
++  unsigned int pos;
++  size_t nlanes;
+ 
+ #ifdef USE_S390X_CRYPTO
+   if (ctx->kimd_func)
+@@ -918,8 +919,7 @@ keccak_write (void *context, const void *inbuf_arg, size_t inlen)
+       burn = nburn > burn ? nburn : burn;
+       inlen -= nlanes * 8;
+       inbuf += nlanes * 8;
+-      count += nlanes * 8;
+-      count = count % bsize;
++      count = ((size_t) count + nlanes * 8) % bsize;
+     }
+ 
+   if (inlen)
+diff --git a/cipher/keccak_permute_64.h b/cipher/keccak_permute_64.h
+index b28c871e..45ef462f 100644
+--- a/cipher/keccak_permute_64.h
++++ b/cipher/keccak_permute_64.h
+@@ -292,7 +292,7 @@ KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd)
+ 
+ static unsigned int
+ KECCAK_F1600_ABSORB_FUNC_NAME(KECCAK_STATE *hd, int pos, const byte *lanes,
+-			      unsigned int nlanes, int blocklanes)
++			      size_t nlanes, int blocklanes)
+ {
+   unsigned int burn = 0;
+ 
+-- 
+GitLab
+
+
+
+From 910dcbcef36e1cd3de3dde192d829a1513273e14 Mon Sep 17 00:00:00 2001
+From: Jussi Kivilinna <jussi.kivilinna@iki.fi>
+Date: Sun, 25 Sep 2022 22:23:22 +0300
+Subject: [PATCH] tests/hashtest: add hugeblock & disable-hwf options and 6 gig
+ test vectors
+
+* .gitignore: Add 'tests/hashtest-6g'.
+* configure.ac: Add 'tests/hashtest-6g'.
+* tests/Makefile: Add 'hashtest-6g'.
+* tests/hashtest-6g.in: New.
+* tests/hashtest-256g.in: Add SHA3-512 to algos.
+* tests/hashtest.c (use_hugeblock): New.
+(testvectors): Add 256 GiB test vectors for BLAKE2S, BLAKE2B and
+whirlpool; Add 6 GiB test vectors for SHA1, SHA256, SHA512, SHA3, SM3,
+BLAKE2S, BLAKE2B, WHIRLPOOL, CRC32 and CRC24.
+(run_longtest); Use huge 5 GiB pattern block when requested.
+(main): Add '--hugeblock' and '--disable-hwf' options.
+* tests/testdrv.c: Add 'hashtest-6g'; Add SHA3 to 'hashtest-256g'.
+---
+
+Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
+---
+ .gitignore             |   1 +
+ configure.ac           |   1 +
+ tests/Makefile.am      |   9 +-
+ tests/hashtest-256g.in |   2 +-
+ tests/hashtest-6g.in   |   7 ++
+ tests/hashtest.c       | 249 +++++++++++++++++++++++++++++++++++++++--
+ tests/testdrv.c        |   7 +-
+ 7 files changed, 261 insertions(+), 15 deletions(-)
+ create mode 100644 tests/hashtest-6g.in
+
+diff --git a/configure.ac b/configure.ac
+index c8f24dcc..c39257b5 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -3511,6 +3511,7 @@ src/libgcrypt.pc
+ src/versioninfo.rc
+ tests/Makefile
+ ])
++AC_CONFIG_FILES([tests/hashtest-6g], [chmod +x tests/hashtest-6g])
+ AC_CONFIG_FILES([tests/hashtest-256g], [chmod +x tests/hashtest-256g])
+ AC_CONFIG_FILES([tests/basic-disable-all-hwf], [chmod +x tests/basic-disable-all-hwf])
+ AC_OUTPUT
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index 302d923b..75aa5cf7 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -44,13 +44,14 @@ tests_bin_last = benchmark bench-slope
+ 
+ tests_sh = basic-disable-all-hwf
+ 
+-tests_sh_last = hashtest-256g
++tests_sh_last = hashtest-6g hashtest-256g
+ 
+ TESTS = $(tests_bin) $(tests_sh) $(tests_bin_last) $(tests_sh_last)
+ 
+ # Force sequential run of some tests.
+ bench-slope.log:    benchmark.log
+-hashtest-256g.log:  bench-slope.log
++hashtest-6g.log:    bench-slope.log
++hashtest-256g.log:  hashtest-6g.log
+ 
+ 
+ TESTS_ENVIRONMENT = GCRYPT_IN_REGRESSION_TEST=1
+@@ -76,8 +77,8 @@ CLEANFILES = testdrv-build
+ EXTRA_DIST = README rsa-16k.key \
+ 	     pkcs1v2-oaep.h pkcs1v2-pss.h pkcs1v2-v15c.h pkcs1v2-v15s.h \
+ 	     t-ed25519.inp t-ed448.inp t-dsa.inp t-ecdsa.inp t-rsa-15.inp \
+-	     t-rsa-pss.inp stopwatch.h hashtest-256g.in sha3-224.h \
+-	     sha3-256.h sha3-384.h sha3-512.h blake2b.h blake2s.h \
++	     t-rsa-pss.inp stopwatch.h hashtest-6g.in hashtest-256g.in \
++	     sha3-224.h sha3-256.h sha3-384.h sha3-512.h blake2b.h blake2s.h \
+ 	     basic-disable-all-hwf.in basic_all_hwfeature_combinations.sh
+ 
+ LDADD = $(standard_ldadd) $(GPG_ERROR_LIBS) @LDADD_FOR_TESTS_KLUDGE@
+diff --git a/tests/hashtest-256g.in b/tests/hashtest-256g.in
+index a52b8692..44b69897 100755
+--- a/tests/hashtest-256g.in
++++ b/tests/hashtest-256g.in
+@@ -1,6 +1,6 @@
+ #!/bin/sh
+ 
+-algos="SHA1 SHA256 SHA512 SM3"
++algos="SHA1 SHA256 SHA512 SHA3-512 SM3"
+ 
+ test "@RUN_LARGE_DATA_TESTS@" = yes || exit 77
+ echo "      now running 256 GiB tests for $algos - this takes looong"
+diff --git a/tests/hashtest-6g.in b/tests/hashtest-6g.in
+new file mode 100644
+index 00000000..b3f3e2ff
+--- /dev/null
++++ b/tests/hashtest-6g.in
+@@ -0,0 +1,7 @@
++#!/bin/sh
++
++algos="SHA1 SHA256 SHA512 SHA3-512 SM3 BLAKE2S_256 BLAKE2B_512 CRC32 CRC24RFC2440"
++
++test "@RUN_LARGE_DATA_TESTS@" = yes || exit 77
++echo "      now running 6 GiB tests for $algos - this can take long"
++exec ./hashtest@EXEEXT@ --hugeblock --gigs 6 $algos
+diff --git a/tests/hashtest.c b/tests/hashtest.c
+index 4c9704f3..9389e50c 100644
+--- a/tests/hashtest.c
++++ b/tests/hashtest.c
+@@ -34,6 +34,7 @@
+ #define PGM "hashtest"
+ #include "t-common.h"
+ 
++static int use_hugeblock;
+ static int missing_test_vectors;
+ 
+ static struct {
+@@ -113,6 +114,169 @@ static struct {
+   { GCRY_MD_SM3, 256, +64,
+     "ed34869dbadd62e3bec1f511004d7bbfc9cafa965477cc48843b248293bbe867" },
+ 
++  { GCRY_MD_BLAKE2S_256, 256, -64,
++    "8a3d4f712275e8e8da70c76501cce364c75f8dd09748be58cf63c9ce38d62627" },
++  { GCRY_MD_BLAKE2S_256, 256, -1,
++    "0c01c9ad1e60e27dc889f2c9034a949ca8b9a9dc90dd99be64963af306d47b92" },
++  { GCRY_MD_BLAKE2S_256, 256, +0,
++    "f8c43d5c4bad93aca702c8c466987c5ac5e640a29b37dd9904252ff27b2348a0" },
++  { GCRY_MD_BLAKE2S_256, 256, +1,
++    "24c34b167b4eea1a7eb7d572ff3cf669a9856ea91bb112e9ef2ccd4b1aceccb4" },
++  { GCRY_MD_BLAKE2S_256, 256, +64,
++    "2f8d754f98e2d4ed7744389f89d0bdb9b770c9fa215b8badd3129ea1364af867" },
++
++  { GCRY_MD_BLAKE2B_512, 256, -64,
++    "36d32ae4deeacab4119401c52e2aec5545675bd2dce4f67871ddc73671a05f94"
++    "e8332c2a31f32f5601878606a571aa7b43029dac3ae71cf9ef141d05651dc4bf" },
++  { GCRY_MD_BLAKE2B_512, 256, -1,
++    "b5dc439f51664a6c9cbc87e2de98ce608ac4064a779e5140909d75d2120c9b2a"
++    "a1d4ae7be9c1ba97025be91ddcfbe42c791c3231cffbfa4b5368ba18f9590e1b" },
++  { GCRY_MD_BLAKE2B_512, 256, +0,
++    "c413d011ba9abbf118dd96bfc827f5fd94493d8350df9f7aff834faace5adba2"
++    "0c3037069dfb2c81718ffc7b418ce1c1320d334b6fe8cddfb5d2dd19eb530853" },
++  { GCRY_MD_BLAKE2B_512, 256, +1,
++    "b6dfb821f1c8167fb33995c29485010da56abd539c3d04ab9c222844301b8bba"
++    "6f57a48e45a748e40847084b93f26706aae82212550671c736becffcc6fb1496" },
++  { GCRY_MD_BLAKE2B_512, 256, +64,
++    "8c21316a4a02044e302d503d0fe669d905c40d9d80ecd5aafc8e30f1df06736f"
++    "51fdaf6002160bb8fe4e868eaad9623fc5ecdd728bcbfee4a19b386503710f48" },
++
++  { GCRY_MD_WHIRLPOOL, 256, -64,
++    "aabf62344c1aa82d2dc7605f339b3571d540f1f320f97e6a8c0229645ee61f1f"
++    "da796acde2f96caa1c56eb2c2f9a6029a6242ad690479def66feac44334cc3af" },
++  { GCRY_MD_WHIRLPOOL, 256, -1,
++    "9a35ec14aa9cefd40e04295d45d39f3111a98c2d76d90c54a7d2b8f2f5b9302b"
++    "79663eab6b6674625c3ae3e4b5dbb3b0a2f5b2f49a7a59cd1723e2b16a3efea2" },
++  { GCRY_MD_WHIRLPOOL, 256, +0,
++    "818ad31a5110b6217cc6ffa099d554aaadc9566bf5291e104a5d58b21d51ae4d"
++    "c216c6de888d1359066c584e24e6606f530a3fce80ef78aed8564de4a28801c8" },
++  { GCRY_MD_WHIRLPOOL, 256, +1,
++    "298805f5fc68488712427c1bcb27581d91aa04337c1c6b4657489ed3d239bb8b"
++    "c70ef654065d380ac1f5596aca5cb59e6da8044b5a067e32ea4cd94ca606f9f3" },
++  { GCRY_MD_WHIRLPOOL, 256, +64,
++    "7bd35c3bee621bc0fb8907904b3b84d6cf4fae4c22cc64fbc744c8c5c8de806d"
++    "0f11a27892d531dc907426597737762c83e3ddcdc62f50d16d130aaefaeec436" },
++
++  { GCRY_MD_SHA1, 6, -64,
++    "eeee82d952403313bd63d6d7c8e342df0a1eea77" },
++  { GCRY_MD_SHA1, 6, -1,
++    "8217b9f987d67db5880bcfff1d6763a6514d629f" },
++  { GCRY_MD_SHA1, 6, +0,
++    "2b38aa63c05668217e5331320a4aee0adad7fc3b" },
++  { GCRY_MD_SHA1, 6, +1,
++    "f3222de4d0704554cff0a537bc95b30f15daa94f" },
++  { GCRY_MD_SHA1, 6, +64,
++    "b3bdd8065bb92d8208d55d28fad2281c6fbf2601" },
++
++  { GCRY_MD_SHA256, 6, -64,
++    "a2d5add5be904b70d6ef9bcd5feb9c6cfc2be0799732a122d9eccb576ff5a922" },
++  { GCRY_MD_SHA256, 6, -1,
++    "88293b7e0e5a47fdef1148c6e510f95272770db6b5296958380209ba57db7a5d" },
++  { GCRY_MD_SHA256, 6, +0,
++    "ccee8e8dfc366eba67471e49c45057b0041be0d2206c6de1aa765ce07ecfc434" },
++  { GCRY_MD_SHA256, 6, +1,
++    "f4a89e92b38e0e61ee17079dc31411de06cfe1f77c83095ae1a2e7aa0205d94b" },
++  { GCRY_MD_SHA256, 6, +64,
++    "338708608c2356ed2927a85b08fe745223c6140243fb3a87f309e12b31b946a8" },
++
++  { GCRY_MD_SHA512, 6, -64,
++    "658f52850932633c00b2f1d65b874c540ab84e2c0fe84a8a6c35f8e90e6f6a9c"
++    "2f7e0ccca5064783562a42ad8f47eab48687aaf6998b04ee94441e82c14e834d" },
++  { GCRY_MD_SHA512, 6, -1,
++    "9ead6d66b46a3a72d77c7990874cfebc1575e5bfda6026430d76b3db6cc62d52"
++    "4ca0dd2674b9c24208b2e780d75542572eee8df6724acadcc23a03eed8f82f0a" },
++  { GCRY_MD_SHA512, 6, +0,
++    "03e4549eb28bd0fb1606c321f1498503b5e889bec8d799cf0688567c7f8ac0d9"
++    "a7ec4e84d1d729d6a359797656e286617c3ef82abb51991bb576aaf05f7b6573" },
++  { GCRY_MD_SHA512, 6, +1,
++    "ffe52f6385ccde6fa7d45845787d8f9993fdcb5833fb58b13c424a84e39ea50f"
++    "52d40e254fe667cb0104ffe3837dc8d0eee3c81721cb8eac10d5851dfb1f91db" },
++  { GCRY_MD_SHA512, 6, +64,
++    "4a19da3d5eaaa79ac1eaff5e4062f23ee56573411f8d302f7bf3c6da8779bd00"
++    "a936e9ad7f535597a49162ed308b0cced7724667f97a1bb24540152fcfe3ec95" },
++
++  { GCRY_MD_SHA3_512, 6, -64,
++    "a99f2913d3beb9b45273402e30daa4d25c7a5e9eb8cf6039996eb2292a45c04c"
++    "b9e3a1a187f71920626f465ed6cf7dc34047ec5578e05516374bb9c56683903a" },
++  { GCRY_MD_SHA3_512, 6, -1,
++    "fca50bde79c55e5fc4c9d97e66eb5cfacef7032395848731e645ca42f07f8d38"
++    "be1d593727c2a82b9a9bc058ebc9744971f867fa920cfa902023448243ac017b" },
++  { GCRY_MD_SHA3_512, 6, +0,
++    "c61bb345c0a553edaa89fd38114ac9799b6d307ba8e3cde53552ad4c77cfe4b7"
++    "2671d82c1519c8e7b23153a9268e2939239564fc7c2060608aa42955e938840d" },
++  { GCRY_MD_SHA3_512, 6, +1,
++    "502a83d8d1b977312806382a45c1cc9c0e7db437ca962e37eb181754d59db686"
++    "14d91df286d510411adf69f7c9befc1027bdc0c33a48a5dd6ae0957b9061e7ca" },
++  { GCRY_MD_SHA3_512, 6, +64,
++    "207bfb83ae788ddd4531188567f0892bbddbbc88d69bc196b2357bee3e668706"
++    "c27f832ecb50e9ae5b63e9f384bdc37373958d4a14f3825146d2f6b1a65d8e51" },
++
++  { GCRY_MD_SM3, 6, -64,
++    "41d96d19cef4c942b0f5f4cdc3e1afe440dc62c0bc103a2c0e9eee9e1733a74a" },
++  { GCRY_MD_SM3, 6, -1,
++    "b7689cc4ef6c7dc795b9e5e6998e5cc3dc1daec02bc1181cdbef8d6812b4957a" },
++  { GCRY_MD_SM3, 6, +0,
++    "c6eae4a82052423cf98017bde4dee8769947c66120a1a2ff79f0f0dc945a3272" },
++  { GCRY_MD_SM3, 6, +1,
++    "f6590f161fee11529585c7a9dfc725f8b81951e49b616844097a3dbdc9ffdbec" },
++  { GCRY_MD_SM3, 6, +64,
++    "f3277fa90c47afe5e4fc52374aadf8e96bc29c2b5a7a4ebf5d704245ada837ea" },
++
++  { GCRY_MD_BLAKE2S_256, 6, -64,
++    "0f3c17610777c34d40a0d11a93d5e5ed444ce16edefebabd0bc8e30392d5c2db" },
++  { GCRY_MD_BLAKE2S_256, 6, -1,
++    "92cbcf142c45de9d64da9791c51dce4e32b58f74d9f3d201b1ea74deac765f51" },
++  { GCRY_MD_BLAKE2S_256, 6, +0,
++    "b20702cb5a0bee2ab104f38eb513429589310a7edde81dd1f40043be7d16d0de" },
++  { GCRY_MD_BLAKE2S_256, 6, +1,
++    "bfc17dc74930989841da05aac08402bf0dcb4a597b17c52402a516ea7e541cdf" },
++  { GCRY_MD_BLAKE2S_256, 6, +64,
++    "d85588cdf5a00bec1327da02f22f1a10b68dd9d6b730f30a3aa65af3a51c1722" },
++
++  { GCRY_MD_BLAKE2B_512, 6, -64,
++    "30b6015f94524861b04b83f0455be10a993460e0f8f0fd755fc3d0270b0c7d00"
++    "039a6e01684ce0689ce4ef70932bd19a676acf4b4ea521c30337d2f445fc2055" },
++  { GCRY_MD_BLAKE2B_512, 6, -1,
++    "49abef820ad7fc5e6ed9b63acddce639a69dcd749b0798b140216649bc3b927c"
++    "637dbe1cb39a41bbafe7f8b675401ccdcf69a7fba227ae4cda5cd28b9ff36776" },
++  { GCRY_MD_BLAKE2B_512, 6, +0,
++    "4182a7307a89391b78af9dbc3ba1e8d643708abbed5919086aa6e2bc65ae9597"
++    "e40229450c86ac5d3117b006427dd0131f5ae4c1a1d64c81420d2731536c81d8" },
++  { GCRY_MD_BLAKE2B_512, 6, +1,
++    "33c0d9e65b1b18e9556134a08c1e725c19155bbf6ed4349d7d6d678f1827fef3"
++    "74b6e3381471f3d3fff7ffbcb9474ce9038143b99e25cd5f8afbb336313d4648" },
++  { GCRY_MD_BLAKE2B_512, 6, +64,
++    "d2d7f388611af78a2ea40b06f99993cff156afd25cbc47695bdb567d4d35b992"
++    "0ff8c325c359a2bdeddf54ececc671ac7b981031e90a7d63d6e0415ec4484282" },
++
++  { GCRY_MD_WHIRLPOOL, 6, -64,
++    "247707d1f9cf31b90ee68527144b1c20ad5ce96293bdccd1a81c8f40bc9df10c"
++    "e7441ac3b3097162d6fbf4d4b67b8fa09de451e2d920f16aad78c47ab00cb833" },
++  { GCRY_MD_WHIRLPOOL, 6, -1,
++    "af49e4a553bdbec1fdafc41713029e0fb1666894753c0ab3ecb280fc5af6eff8"
++    "253120745a229d7a8b5831711e4fd16ed0741258504d8a47e2b42aa2f1886968" },
++  { GCRY_MD_WHIRLPOOL, 6, +0,
++    "f269ffa424bc2aad2da654f01783fc9b2b431219f2b05784d718da0935e78792"
++    "9207b000ebbfb63dfdcc8adf8e5bd321d9616c1b8357430b9be6cb4640df8609" },
++  { GCRY_MD_WHIRLPOOL, 6, +1,
++    "52b77eb13129151b69b63c09abb655dc9cb046cafd4cbf7d4a82ae04b61ef9e6"
++    "531dde04cae7c5ab400ed8ee8da2e3f490d177289b2b3aa29b12b292954b902c" },
++  { GCRY_MD_WHIRLPOOL, 6, +64,
++    "60a950c92f3f08abbc81c41c86ce0463679ffd5ab420e988e15b210615b454ae"
++    "69607d14a1806fa44aacf8c926fbdcee998af46f56e0c642d3fb4ee54c8fb917" },
++
++  { GCRY_MD_CRC32, 6, -64, "20739052" },
++  { GCRY_MD_CRC32, 6, -1,  "971a5a74" },
++  { GCRY_MD_CRC32, 6, +0,  "bf48113c" },
++  { GCRY_MD_CRC32, 6, +1,  "c7678ad5" },
++  { GCRY_MD_CRC32, 6, +64, "1efa7255" },
++
++  { GCRY_MD_CRC24_RFC2440, 6, -64, "747e81" },
++  { GCRY_MD_CRC24_RFC2440, 6, -1,  "deb97d" },
++  { GCRY_MD_CRC24_RFC2440, 6, +0,  "7d5bea" },
++  { GCRY_MD_CRC24_RFC2440, 6, +1,  "acc351" },
++  { GCRY_MD_CRC24_RFC2440, 6, +64, "9d9032" },
++
+   { 0 }
+ };
+ 
+@@ -251,12 +415,38 @@ run_longtest (int algo, int gigs)
+   gcry_md_hd_t hd_post = NULL;
+   gcry_md_hd_t hd_post2 = NULL;
+   char pattern[1024];
+-  int i, g;
++  char *hugepattern = NULL;
++  size_t hugesize;
++  size_t hugegigs;
++  int i, g, gppos, gptot;
+   const unsigned char *digest;
+   unsigned int digestlen;
+ 
+   memset (pattern, 'a', sizeof pattern);
+ 
++  if (use_hugeblock)
++    {
++      hugegigs = 5;
++      if (sizeof(size_t) >= 8)
++        {
++          hugesize = hugegigs*1024*1024*1024;
++          hugepattern = malloc(hugesize);
++          if (hugepattern != NULL)
++            memset(hugepattern, 'a', hugesize);
++          else
++            show_note ("failed to allocate %d GiB huge pattern block: %s",
++                       hugegigs, strerror(errno));
++        }
++      else
++        show_note ("cannot allocate %d GiB huge pattern block on 32-bit system",
++                   hugegigs);
++    }
++  if (hugepattern == NULL)
++    {
++      hugegigs = 0;
++      hugesize = 0;
++    }
++
+   err = gcry_md_open (&hd, algo, 0);
+   if (err)
+     {
+@@ -267,9 +457,17 @@ run_longtest (int algo, int gigs)
+ 
+   digestlen = gcry_md_get_algo_dlen (algo);
+ 
+-
+-  for (g=0; g < gigs; g++)
++  gppos = 0;
++  gptot = 0;
++  for (g=0; g < gigs; )
+     {
++      if (gppos >= 16)
++        {
++          gptot += 16;
++          gppos -= 16;
++          show_note ("%d GiB so far hashed with %s", gptot,
++                     gcry_md_algo_name (algo));
++        }
+       if (g == gigs - 1)
+         {
+           for (i = 0; i < 1024*1023; i++)
+@@ -283,16 +481,24 @@ run_longtest (int algo, int gigs)
+             die ("gcry_md_copy failed for %s (%d): %s",
+                  gcry_md_algo_name (algo), algo, gpg_strerror (err));
+           gcry_md_write (hd, pattern, sizeof pattern);
++          g++;
++          gppos++;
++        }
++      else if (hugepattern != NULL && gigs - g > hugegigs)
++        {
++          gcry_md_write (hd, hugepattern, hugesize);
++          g += hugegigs;
++          gppos += hugegigs;
+         }
+       else
+         {
+           for (i = 0; i < 1024*1024; i++)
+             gcry_md_write (hd, pattern, sizeof pattern);
++          g++;
++          gppos++;
+         }
+-      if (g && !(g % 16))
+-        show_note ("%d GiB so far hashed with %s", g, gcry_md_algo_name (algo));
+     }
+-  if (g >= 16)
++  if (g >= 16 && gppos)
+     show_note ("%d GiB hashed with %s", g, gcry_md_algo_name (algo));
+ 
+   err = gcry_md_copy (&hd_post, hd);
+@@ -335,6 +541,8 @@ run_longtest (int algo, int gigs)
+   gcry_md_close (hd_pre2);
+   gcry_md_close (hd_post);
+   gcry_md_close (hd_post2);
++
++  free(hugepattern);
+ }
+ 
+ 
+@@ -361,9 +569,12 @@ main (int argc, char **argv)
+         {
+           fputs ("usage: " PGM " [options] [algos]\n"
+                  "Options:\n"
+-                 "  --verbose       print timings etc.\n"
+-                 "  --debug         flyswatter\n"
+-                 "  --gigs N        Run a test on N GiB\n",
++                 "  --verbose                 print timings etc.\n"
++                 "  --debug                   flyswatter\n"
++                 "  --hugeblock               Use 5 GiB pattern block\n"
++                 "  --gigs N                  Run a test on N GiB\n"
++                 "  --disable-hwf <features>  Disable hardware acceleration feature(s)\n"
++                 "                            for benchmarking.\n",
+                  stdout);
+           exit (0);
+         }
+@@ -378,6 +589,11 @@ main (int argc, char **argv)
+           debug++;
+           argc--; argv++;
+         }
++      else if (!strcmp (*argv, "--hugeblock"))
++        {
++          use_hugeblock = 1;
++          argc--; argv++;
++        }
+       else if (!strcmp (*argv, "--gigs"))
+         {
+           argc--; argv++;
+@@ -387,6 +603,21 @@ main (int argc, char **argv)
+               argc--; argv++;
+             }
+         }
++      else if (!strcmp (*argv, "--disable-hwf"))
++        {
++          argc--;
++          argv++;
++          if (argc)
++            {
++              if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
++                fprintf (stderr,
++                        PGM
++                        ": unknown hardware feature `%s' - option ignored\n",
++                        *argv);
++              argc--;
++              argv++;
++            }
++        }
+       else if (!strncmp (*argv, "--", 2))
+         die ("unknown option '%s'", *argv);
+     }
+diff --git a/tests/testdrv.c b/tests/testdrv.c
+index 0ccde326..bfca4c23 100644
+--- a/tests/testdrv.c
++++ b/tests/testdrv.c
+@@ -78,7 +78,12 @@ static struct {
+    { "t-ed448"     },
+    { "benchmark"   },
+    { "bench-slope" },
+-   { "hashtest-256g",  "hashtest", "--gigs 256 SHA1 SHA256 SHA512 SM3",
++   { "hashtest-6g", "hashtest", "--hugeblock --gigs 6 SHA1 SHA256 SHA512 "
++                                                     "SHA3-512 SM3 BLAKE2S_256 "
++                                                     "BLAKE2B_512 CRC32 "
++                                                     "CRC24RFC2440",
++     LONG_RUNNING },
++   { "hashtest-256g", "hashtest", "--gigs 256 SHA1 SHA256 SHA512 SHA3-512 SM3",
+      LONG_RUNNING },
+    { NULL }
+   };
+--
+2.34.1
+
+From 567bc62e1c3046594088de7209fee7c545ece1e3 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Fri, 30 Sep 2022 14:54:14 +0200
+Subject: [PATCH] tests: Avoid memory leak
+
+* tests/hashtest.c (run_longtest): Avoid memory leak on error
+--
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ tests/hashtest.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tests/hashtest.c b/tests/hashtest.c
+index 9389e50c..379f7c40 100644
+--- a/tests/hashtest.c
++++ b/tests/hashtest.c
+@@ -452,6 +452,7 @@ run_longtest (int algo, int gigs)
+     {
+       fail ("gcry_md_open failed for %s (%d): %s",
+             gcry_md_algo_name (algo), algo, gpg_strerror (err));
++      free(hugepattern);
+       return;
+     }
+ 
+-- 
+2.37.3
+
diff --git a/SPECS/libgcrypt.spec b/SPECS/libgcrypt.spec
index da99e44..7949727 100644
--- a/SPECS/libgcrypt.spec
+++ b/SPECS/libgcrypt.spec
@@ -16,19 +16,41 @@ print(string.sub(hash, 0, 16))
 
 Name: libgcrypt
 Version: 1.10.0
-Release: 5%{?dist}
+Release: 9%{?dist}
 URL: https://www.gnupg.org/
 Source0: https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-%{version}.tar.bz2
 Source1: https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-%{version}.tar.bz2.sig
 Source2: wk@g10code.com
 Patch1: libgcrypt-1.10.0-disable-brainpool.patch
-Patch2: libgcrypt-1.10.0-fips-disable-pkcs1.5.patch
 Patch3: libgcrypt-1.10.0-ppc-hwf.patch
 Patch4: libgcrypt-1.10.0-allow-small-RSA-verify.patch
 Patch5: libgcrypt-1.10.0-allow-short-salt.patch
 Patch6: libgcrypt-1.10.0-fips-getrandom.patch
+# https://dev.gnupg.org/T6127
+# https://lists.gnupg.org/pipermail/gcrypt-devel/2022-September/005379.html
 Patch7: libgcrypt-1.10.0-fips-selftest.patch
-Patch8: libgcrypt-1.10.0-fips-disable-oaep.patch
+# https://dev.gnupg.org/T6217
+Patch9: libgcrypt-1.10.0-sha3-large.patch
+# https://dev.gnupg.org/T5919
+Patch10: libgcrypt-1.10.0-fips-keygen.patch
+# https://dev.gnupg.org/T6219
+# f4a861f3e5ae82f278284061e4829c03edf9c3a7
+Patch11: libgcrypt-1.10.0-fips-kdf.patch
+# c34c9e70055ee43e5ef257384fa15941f064e5a4
+# https://gitlab.com/redhat-crypto/libgcrypt/libgcrypt-mirror/-/merge_requests/13
+Patch12: libgcrypt-1.10.0-fips-indicator.patch
+# beb5d6df5c5785db7c32a24a5d2a351cb964bfbc
+# 521500624b4b11538d206137205e2a511dad7072
+# 9dcf9305962b90febdf2d7cc73b49feadbf6a01f
+# a340e980388243ceae6df57d101036f3f2a955be
+Patch13: libgcrypt-1.10.0-fips-integrity.patch
+# 3c8b6c4a9cad59c5e1db5706f6774a3141b60210
+# 052c5ef4cea56772b7015e36f231fa0bcbf91410
+Patch14: libgcrypt-1.10.0-fips-integrity2.patch
+# 06ea5b5332ffdb44a0a394d766be8989bcb6a95c
+Patch15: libgcrypt-1.10.0-fips-x931.patch
+# bf1e62e59200b2046680d1d3d1599facc88cfe63
+Patch16: libgcrypt-1.10.0-fips-rsa-pss.patch
 
 %global gcrylibdir %{_libdir}
 %global gcrysoname libgcrypt.so.20
@@ -65,13 +87,19 @@ applications using libgcrypt.
 %prep
 %setup -q
 %patch1 -p1
-%patch2 -p1
 %patch3 -p1
 %patch4 -p1
 %patch5 -p1
 %patch6 -p1
 %patch7 -p1
-%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
 
 %build
 # This package has a configure test which uses ASMs, but does not link the
@@ -98,6 +126,7 @@ autoreconf -f
      --enable-noexecstack \
      --enable-hmac-binary-check=%{hmackey} \
      --disable-brainpool \
+     --disable-jent-support \
      --enable-digests="$DIGESTS" \
      --enable-ciphers="$CIPHERS" \
      --with-fips-module-version="$FIPS_MODULE_NAME %{version}-%{srpmhash}"
@@ -115,12 +144,12 @@ LIBGCRYPT_FORCE_FIPS_MODE=1 make check
     %{?__debug_package:%{__debug_install_post}} \
     %{__arch_install_post} \
     %{__os_install_post} \
-    dd if=/dev/zero of=%{libpath}.hmac bs=32 count=1 \
-    objcopy --update-section .rodata1=%{libpath}.hmac %{libpath} %{libpath}.empty \
-    src/hmac256 --binary %{hmackey} %{libpath}.empty > %{libpath}.hmac \
-    objcopy --update-section .rodata1=%{libpath}.hmac %{libpath}.empty %{libpath}.new \
+    cd src \
+    sed -i -e 's|FILE=.*|FILE=\\\$1|' gen-note-integrity.sh \
+    READELF=readelf AWK=awk ECHO_N="-n" bash gen-note-integrity.sh %{libpath} > %{libpath}.hmac \
+    objcopy --update-section .note.fdo.integrity=%{libpath}.hmac %{libpath} %{libpath}.new \
     mv -f %{libpath}.new %{libpath} \
-    rm -f %{libpath}.hmac %{libpath}.empty
+    rm -f %{libpath}.hmac
 %{nil}
 
 %install
@@ -190,6 +219,30 @@ mkdir -p -m 755 $RPM_BUILD_ROOT/etc/gcrypt
 %license COPYING
 
 %changelog
+* Tue Jan 24 2023 Jakub Jelen <jjelen@redhat.com> - 1.10.0-9
+- Avoid usage of invalid arguments sizes for PBKDF2 in FIPS mode
+- Do not allow large salt lengths with RSA-PSS padding
+- Disable X9.31 key generation in FIPS mode
+- Update the FIPS integrity checking code to upstream version
+- Update cipher modes FIPS indicators for AES WRAP and GCM
+- Disable jitter entropy generator
+
+* Thu Oct 20 2022 Jakub Jelen <jjelen@redhat.com> - 1.10.0-8
+- Fix unneeded PBKDF2 passphrase length limitation in FIPS mode
+- Enforce HMAC key lengths in MD API in FIPS mode
+
+* Thu Oct 06 2022 Jakub Jelen <jjelen@redhat.com> - 1.10.0-7
+- Properly enforce KDF limits in FIPS mode (#2130275)
+- Fix memory leak in large digest test (#2129150)
+- Fix function name FIPS service indicator by disabling PK encryption and decryption (#2130275)
+- Skip RSA encryption/decryption selftest in FIPS mode (#2130275)
+
+* Tue Sep 27 2022 Jakub Jelen <jjelen@redhat.com> - 1.10.0-6
+- Fix SHA3 digests with large inputs (#2129150)
+- Fix FIPS RSA PCT (#2128455)
+- Fix RSA FIPS Keygen that non-deterministically fails (#2130275)
+- Get max 32B from getrandom in FIPS mode (#2130275)
+
 * Wed Aug 17 2022 Jakub Jelen <jjelen@redhat.com> - 1.10.0-5
 - Allow signature verification with smaller RSA keys (#2083846)
 - Allow short salt for KDF (#2114870)