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-drbg.patch b/SOURCES/libgcrypt-1.10.0-fips-drbg.patch
new file mode 100644
index 0000000..7b794e1
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-drbg.patch
@@ -0,0 +1,85 @@
+From 45b80678109e5817b7cd15566a9d6c96b064b95f Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Wed, 1 Mar 2023 15:39:15 +0100
+Subject: [PATCH] random: Remove unused SHA384 DRBGs.
+
+* random/random-drbg.c (global): Remove unused SHA384-based defines.
+(drbg_cores): Remove SHA384 configurations.
+(drbg_sec_strength): Remove unused SHA384.
+--
+
+These are no longer allowed by FIPS and it looks like they were never
+usable as they do not have any conversion from the string flags.
+
+GnuPG-bug-id: 6393
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ random/random-drbg.c | 13 ++-----------
+ 1 file changed, 2 insertions(+), 11 deletions(-)
+
+diff --git a/random/random-drbg.c b/random/random-drbg.c
+index f1cfe286..af49a5a5 100644
+--- a/random/random-drbg.c
++++ b/random/random-drbg.c
+@@ -188,11 +188,9 @@
+ #define DRBG_HASHSHA1		((u32)1<<4)
+ #define DRBG_HASHSHA224		((u32)1<<5)
+ #define DRBG_HASHSHA256		((u32)1<<6)
+-#define DRBG_HASHSHA384		((u32)1<<7)
+ #define DRBG_HASHSHA512		((u32)1<<8)
+ #define DRBG_HASH_MASK		(DRBG_HASHSHA1 | DRBG_HASHSHA224 \
+-				 | DRBG_HASHSHA256 | DRBG_HASHSHA384 \
+-				 | DRBG_HASHSHA512)
++				 | DRBG_HASHSHA256 | DRBG_HASHSHA512)
+ /* type modifiers (A.3)*/
+ #define DRBG_HMAC		((u32)1<<12)
+ #define DRBG_SYM128		((u32)1<<13)
+@@ -211,23 +209,18 @@
+ #define DRBG_NOPR_CTRAES256 (DRBG_CTRAES | DRBG_SYM256)
+ #define DRBG_PR_HASHSHA1     (DRBG_PREDICTION_RESIST | DRBG_HASHSHA1)
+ #define DRBG_PR_HASHSHA256   (DRBG_PREDICTION_RESIST | DRBG_HASHSHA256)
+-#define DRBG_PR_HASHSHA384   (DRBG_PREDICTION_RESIST | DRBG_HASHSHA384)
+ #define DRBG_PR_HASHSHA512   (DRBG_PREDICTION_RESIST | DRBG_HASHSHA512)
+ #define DRBG_NOPR_HASHSHA1   (DRBG_HASHSHA1)
+ #define DRBG_NOPR_HASHSHA256 (DRBG_HASHSHA256)
+-#define DRBG_NOPR_HASHSHA384 (DRBG_HASHSHA384)
+ #define DRBG_NOPR_HASHSHA512 (DRBG_HASHSHA512)
+ #define DRBG_PR_HMACSHA1     (DRBG_PREDICTION_RESIST | DRBG_HASHSHA1 \
+                               | DRBG_HMAC)
+ #define DRBG_PR_HMACSHA256   (DRBG_PREDICTION_RESIST | DRBG_HASHSHA256 \
+                               | DRBG_HMAC)
+-#define DRBG_PR_HMACSHA384   (DRBG_PREDICTION_RESIST | DRBG_HASHSHA384 \
+-                              | DRBG_HMAC)
+ #define DRBG_PR_HMACSHA512   (DRBG_PREDICTION_RESIST | DRBG_HASHSHA512 \
+                               | DRBG_HMAC)
+ #define DRBG_NOPR_HMACSHA1   (DRBG_HASHSHA1 | DRBG_HMAC)
+ #define DRBG_NOPR_HMACSHA256 (DRBG_HASHSHA256 | DRBG_HMAC)
+-#define DRBG_NOPR_HMACSHA384 (DRBG_HASHSHA384 | DRBG_HMAC)
+ #define DRBG_NOPR_HMACSHA512 (DRBG_HASHSHA512 | DRBG_HMAC)
+ 
+ 
+@@ -359,12 +352,10 @@ static const struct drbg_core_s drbg_cores[] = {
+   /* Hash DRBGs */
+   {DRBG_HASHSHA1, 55, 20, GCRY_MD_SHA1},
+   {DRBG_HASHSHA256, 55, 32, GCRY_MD_SHA256},
+-  {DRBG_HASHSHA384, 111, 48, GCRY_MD_SHA384},
+   {DRBG_HASHSHA512, 111, 64, GCRY_MD_SHA512},
+   /* HMAC DRBGs */
+   {DRBG_HASHSHA1   | DRBG_HMAC, 20, 20, GCRY_MD_SHA1},
+   {DRBG_HASHSHA256 | DRBG_HMAC, 32, 32, GCRY_MD_SHA256},
+-  {DRBG_HASHSHA384 | DRBG_HMAC, 48, 48, GCRY_MD_SHA384},
+   {DRBG_HASHSHA512 | DRBG_HMAC, 64, 64, GCRY_MD_SHA512},
+   /* block ciphers */
+   {DRBG_CTRAES | DRBG_SYM128, 32, 16, GCRY_CIPHER_AES128},
+@@ -543,7 +534,7 @@ drbg_sec_strength (u32 flags)
+   else if (flags & DRBG_SYM192)
+     return 24;
+   else if ((flags & DRBG_SYM256) || (flags & DRBG_HASHSHA256) ||
+-	   (flags & DRBG_HASHSHA384) || (flags & DRBG_HASHSHA512))
++	   (flags & DRBG_HASHSHA512))
+     return 32;
+   else
+     return 32;
+-- 
+2.39.2
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-indicator-md-hmac.patch b/SOURCES/libgcrypt-1.10.0-fips-indicator-md-hmac.patch
new file mode 100644
index 0000000..a1c4e18
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-indicator-md-hmac.patch
@@ -0,0 +1,277 @@
+From fd832687f36c1885d2388c55f7e8569184ba2593 Mon Sep 17 00:00:00 2001
+From: Tobias Heider <tobias.heider@canonical.com>
+Date: Thu, 16 Feb 2023 03:20:48 +0100
+Subject: [PATCH] fips: Add explicit indicators for md and mac algorithms
+
+* src/fips.c (_gcry_fips_indicator_mac): New function indicating
+  non-approved mac algorithms
+  (_gcry_fips_indicator_md): new functions indicating non-approved
+  message digest algorithms
+* src/g10lib.h (_gcry_fips_indicator_mac): new function
+  (_gcry_fips_indicator_md): ditto
+* src/gcrypt.h.in (enum gcry_ctl_cmds): New symbols
+  GCRYCTL_FIPS_SERVICE_INDICATOR_MAC and
+  GCRYCTL_FIPS_SERVICE_INDICATOR_MD
+* src/global.c (_gcry_vcontrol): Handle new FIPS indicators.
+* doc/gcrypt.texi: Document the new option.
+--
+
+Signed-off-by: Tobias Heider <tobias.heider@canonical.com>
+---
+ doc/gcrypt.texi | 13 +++++++++++++
+ src/fips.c      | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/g10lib.h    |  2 ++
+ src/gcrypt.h.in |  4 +++-
+ src/global.c    | 14 ++++++++++++++
+ 5 files changed, 83 insertions(+), 1 deletion(-)
+
+diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
+index e44c2f2e..462c5931 100644
+--- a/doc/gcrypt.texi
++++ b/doc/gcrypt.texi
+@@ -992,6 +992,19 @@ certification. If the function is approved, this function returns
+ @code{GPG_ERR_NO_ERROR} (other restrictions might still apply).
+ Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned.
+ 
++@item GCRYCTL_FIPS_SERVICE_INDICATOR_MAC; Arguments: enum gcry_mac_algos
++
++Check if the given MAC is approved under the current FIPS 140-3
++certification. If the MAC is approved, this function returns
++@code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED}
++is returned.
++
++@item GCRYCTL_FIPS_SERVICE_INDICATOR_MD; Arguments: enum gcry_md_algos
++
++Check if the given message digest algorithm is approved under the current
++FIPS 140-3 certification. If the algorithm is approved, this function returns
++@code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned.
++
+ @end table
+ 
+ @end deftypefun
+diff --git a/src/fips.c b/src/fips.c
+index 272aabae..8b3b3f04 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -377,6 +377,57 @@ _gcry_fips_indicator_cipher (va_list arg_ptr)
+     }
+ }
+ 
++int
++_gcry_fips_indicator_mac (va_list arg_ptr)
++{
++  enum gcry_mac_algos alg = va_arg (arg_ptr, enum gcry_mac_algos);
++
++  switch (alg)
++    {
++    case GCRY_MAC_CMAC_AES:
++    case GCRY_MAC_HMAC_SHA1:
++    case GCRY_MAC_HMAC_SHA224:
++    case GCRY_MAC_HMAC_SHA256:
++    case GCRY_MAC_HMAC_SHA384:
++    case GCRY_MAC_HMAC_SHA512:
++    case GCRY_MAC_HMAC_SHA512_224:
++    case GCRY_MAC_HMAC_SHA512_256:
++    case GCRY_MAC_HMAC_SHA3_224:
++    case GCRY_MAC_HMAC_SHA3_256:
++    case GCRY_MAC_HMAC_SHA3_384:
++    case GCRY_MAC_HMAC_SHA3_512:
++      return GPG_ERR_NO_ERROR;
++    default:
++      return GPG_ERR_NOT_SUPPORTED;
++    }
++}
++
++int
++_gcry_fips_indicator_md (va_list arg_ptr)
++{
++  enum gcry_md_algos alg = va_arg (arg_ptr, enum gcry_md_algos);
++
++  switch (alg)
++    {
++    case GCRY_MD_SHA1:
++    case GCRY_MD_SHA224:
++    case GCRY_MD_SHA256:
++    case GCRY_MD_SHA384:
++    case GCRY_MD_SHA512:
++    case GCRY_MD_SHA512_224:
++    case GCRY_MD_SHA512_256:
++    case GCRY_MD_SHA3_224:
++    case GCRY_MD_SHA3_256:
++    case GCRY_MD_SHA3_384:
++    case GCRY_MD_SHA3_512:
++    case GCRY_MD_SHAKE128:
++    case GCRY_MD_SHAKE256:
++      return GPG_ERR_NO_ERROR;
++    default:
++      return GPG_ERR_NOT_SUPPORTED;
++    }
++}
++
+ int
+ _gcry_fips_indicator_kdf (va_list arg_ptr)
+ {
+diff --git a/src/g10lib.h b/src/g10lib.h
+index 6be0ab21..86337eed 100644
+--- a/src/g10lib.h
++++ b/src/g10lib.h
+@@ -467,6 +467,8 @@ void _gcry_fips_signal_error (const char *srcfile,
+ #endif
+ 
+ int _gcry_fips_indicator_cipher (va_list arg_ptr);
++int _gcry_fips_indicator_mac (va_list arg_ptr);
++int _gcry_fips_indicator_md (va_list arg_ptr);
+ int _gcry_fips_indicator_kdf (va_list arg_ptr);
+ int _gcry_fips_indicator_function (va_list arg_ptr);
+ 
+diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
+index aba22bfc..54080d46 100644
+--- a/src/gcrypt.h.in
++++ b/src/gcrypt.h.in
+@@ -330,7 +330,9 @@ enum gcry_ctl_cmds
+     GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER = 81,
+     GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82,
+     GCRYCTL_NO_FIPS_MODE = 83,
+-    GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION = 84
++    GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION = 84,
++    GCRYCTL_FIPS_SERVICE_INDICATOR_MAC = 85,
++    GCRYCTL_FIPS_SERVICE_INDICATOR_MD = 86
+   };
+ 
+ /* Perform various operations defined by CMD. */
+diff --git a/src/global.c b/src/global.c
+index debf6194..d16d3709 100644
+--- a/src/global.c
++++ b/src/global.c
+@@ -791,6 +791,20 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
+       rc = _gcry_fips_indicator_cipher (arg_ptr);
+       break;
+ 
++    case GCRYCTL_FIPS_SERVICE_INDICATOR_MAC:
++      /* Get FIPS Service Indicator for a given message authentication code.
++       * Returns GPG_ERR_NO_ERROR if algorithm is allowed or
++       * GPG_ERR_NOT_SUPPORTED otherwise */
++      rc = _gcry_fips_indicator_mac (arg_ptr);
++      break;
++
++    case GCRYCTL_FIPS_SERVICE_INDICATOR_MD:
++      /* Get FIPS Service Indicator for a given message digest. Returns
++       * GPG_ERR_NO_ERROR if algorithm is allowed or GPG_ERR_NOT_SUPPORTED
++       * otherwise */
++      rc = _gcry_fips_indicator_md (arg_ptr);
++      break;
++
+     case GCRYCTL_FIPS_SERVICE_INDICATOR_KDF:
+       /* Get FIPS Service Indicator for a given KDF. Returns GPG_ERR_NO_ERROR
+        * if algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise */
+-- 
+2.39.2
+
+From 2d193a955d05b4b9caed2895cf25600add3484da Mon Sep 17 00:00:00 2001
+From: Tobias Heider <tobias.heider@canonical.com>
+Date: Thu, 16 Feb 2023 03:21:26 +0100
+Subject: [PATCH] fips: Unblock MD5 in fips mode but mark non-approved in
+ indicator.
+
+* cipher/mac-hmac.c (_gcry_mac_type_spec_hmac_md5): allow in fips mode
+* cipher/md5.c (_gcry_digest_spec_md5): allow in fips mode
+--
+
+Signed-off-by: Tobias Heider <tobias.heider@canonical.com>
+---
+ cipher/mac-hmac.c | 2 +-
+ cipher/md5.c      | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/cipher/mac-hmac.c b/cipher/mac-hmac.c
+index f1ab568b..9fac77dc 100644
+--- a/cipher/mac-hmac.c
++++ b/cipher/mac-hmac.c
+@@ -1413,7 +1413,7 @@ const gcry_mac_spec_t _gcry_mac_type_spec_hmac_tiger1 = {
+ #endif
+ #if USE_MD5
+ const gcry_mac_spec_t _gcry_mac_type_spec_hmac_md5 = {
+-  GCRY_MAC_HMAC_MD5, {0, 0}, "HMAC_MD5",
++  GCRY_MAC_HMAC_MD5, {0, 1}, "HMAC_MD5",
+   &hmac_ops
+ };
+ #endif
+diff --git a/cipher/md5.c b/cipher/md5.c
+index 5457fc38..744a2cc1 100644
+--- a/cipher/md5.c
++++ b/cipher/md5.c
+@@ -314,7 +314,7 @@ static const gcry_md_oid_spec_t oid_spec_md5[] =
+ 
+ const gcry_md_spec_t _gcry_digest_spec_md5 =
+   {
+-    GCRY_MD_MD5, {0, 0},
++    GCRY_MD_MD5, {0, 1},
+     "MD5", asn, DIM (asn), oid_spec_md5, 16,
+     md5_init, _gcry_md_block_write, md5_final, md5_read, NULL,
+     NULL,
+-- 
+2.39.2
+
+From f52f33389da3302f51b6b00451cf9fc7e7a7e277 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Mon, 6 Mar 2023 17:26:17 +0100
+Subject: [PATCH] tests: Improve test coverage for FIPS service indicators
+
+* tests/basic.c (check_digests): Check the FIPS indicators
+  (check_mac): Ditto.
+--
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ tests/basic.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/tests/basic.c b/tests/basic.c
+index 095bdc97..5d5ceac9 100644
+--- a/tests/basic.c
++++ b/tests/basic.c
+@@ -14086,6 +14086,7 @@ check_mac (void)
+ 	"\x13\x46\x76\xfb\x6d\xe0\x44\x60\x65\xc9\x74\x40\xfa\x8c\x6a\x58" },
+       {	0 },
+     };
++  gcry_error_t err;
+   int i;
+ 
+   if (verbose)
+@@ -15370,6 +15370,12 @@ check_digests (void)
+         {
+           if (in_fips_mode)
+             {
++              err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_MD, algos[i].md);
++              if (err == GPG_ERR_NO_ERROR)
++                {
++                  fail ("algo %d, gcry_md_test_algo failed while it should"
++                        " have worked in FIPS mode\n", algos[i].md);
++                }
+               if (verbose)
+                 fprintf (stderr, "  algorithm %d not available in fips mode\n",
+                          algos[i].md);
+@@ -16948,6 +16954,7 @@ check_mac (void)
+ #endif /* USE_GOST28147 */
+       { 0 },
+     };
++  gcry_error_t err;
+   int i;
+ 
+   if (verbose)
+@@ -16961,6 +16968,12 @@ check_mac (void)
+         {
+           if (in_fips_mode)
+             {
++              err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_MAC, algos[i].algo);
++              if (err == GPG_ERR_NO_ERROR)
++                {
++                  fail ("algo %d, gcry_mac_test_algo failed while it should"
++                        " have worked in FIPS mode\n", algos[i].algo);
++                }
+               if (verbose)
+                 fprintf (stderr, "  algorithm %d not available in fips mode\n",
+                          algos[i].algo);
+-- 
+2.39.2
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-indicator-pk-flags.patch b/SOURCES/libgcrypt-1.10.0-fips-indicator-pk-flags.patch
new file mode 100644
index 0000000..059c596
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-indicator-pk-flags.patch
@@ -0,0 +1,277 @@
+From 0c0268177666f6ce53c0a61e86c1c5bd2c53c0b0 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Mon, 6 Mar 2023 15:57:40 +0100
+Subject: [PATCH] fips: Explicitly allow only some PK flags
+
+* src/fips.c (_gcry_fips_indicator_pk_flags): New function for explicit
+  FIPS indicator for public key algorithm flags
+* src/g10lib.h (_gcry_fips_indicator_pk_flags): New.
+* src/gcrypt.h.in (GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS): New.
+* src/global.c (_gcry_vcontrol): Handle the new option.
+* doc/gcrypt.texi: Document new options.
+--
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ doc/gcrypt.texi |  6 ++++++
+ src/fips.c      | 15 +++++++++++++++
+ src/g10lib.h    |  1 +
+ src/gcrypt.h.in |  3 ++-
+ src/global.c    |  7 +++++++
+ 5 files changed, 31 insertions(+), 1 deletion(-)
+
+diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
+index 462c5931..750b6718 100644
+--- a/doc/gcrypt.texi
++++ b/doc/gcrypt.texi
+@@ -1005,6 +1005,12 @@ Check if the given message digest algorithm is approved under the current
+ FIPS 140-3 certification. If the algorithm is approved, this function returns
+ @code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned.
+ 
++@item GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS; Arguments: const char *
++
++Check if the given public key operation flag is approved under the current
++FIPS 140-3 certification. If the flag is approved, this function returns
++@code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned.
++
+ @end table
+ 
+ @end deftypefun
+diff --git a/src/fips.c b/src/fips.c
+index 974ed833..cb547aa2 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -457,6 +457,21 @@ _gcry_fips_indicator_function (va_list arg_ptr)
+ }
+ 
+ 
++int
++_gcry_fips_indicator_pk_flags (va_list arg_ptr)
++{
++  const char *flag = va_arg (arg_ptr, const char *);
++
++  if (strcmp (flag, "param") == 0 ||
++      strcmp (flag, "raw") == 0 ||
++      strcmp (flag, "no-blinding") == 0 ||
++      strcmp (flag, "pss") == 0)
++    return GPG_ERR_NO_ERROR;
++
++  return GPG_ERR_NOT_SUPPORTED;
++}
++
++
+ /* This is a test on whether the library is in the error or
+    operational state. */
+ int
+diff --git a/src/g10lib.h b/src/g10lib.h
+index 86337eed..acff2d6b 100644
+--- a/src/g10lib.h
++++ b/src/g10lib.h
+@@ -471,6 +471,7 @@ int _gcry_fips_indicator_mac (va_list arg_ptr);
+ int _gcry_fips_indicator_md (va_list arg_ptr);
+ int _gcry_fips_indicator_kdf (va_list arg_ptr);
+ int _gcry_fips_indicator_function (va_list arg_ptr);
++int _gcry_fips_indicator_pk_flags (va_list arg_ptr);
+ 
+ int _gcry_fips_is_operational (void);
+ 
+diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
+index 54080d46..121a2061 100644
+--- a/src/gcrypt.h.in
++++ b/src/gcrypt.h.in
+@@ -332,7 +332,8 @@ enum gcry_ctl_cmds
+     GCRYCTL_NO_FIPS_MODE = 83,
+     GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION = 84,
+     GCRYCTL_FIPS_SERVICE_INDICATOR_MAC = 85,
+-    GCRYCTL_FIPS_SERVICE_INDICATOR_MD = 86
++    GCRYCTL_FIPS_SERVICE_INDICATOR_MD = 86,
++    GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS = 87
+   };
+ 
+ /* Perform various operations defined by CMD. */
+diff --git a/src/global.c b/src/global.c
+index d16d3709..f39df422 100644
+--- a/src/global.c
++++ b/src/global.c
+@@ -818,6 +818,13 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
+       rc = _gcry_fips_indicator_function (arg_ptr);
+       break;
+ 
++    case GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS:
++      /* Get FIPS Service Indicator for a public key operation flags.
++       * Returns GPG_ERR_NO_ERROR if the flag is allowed to be used or
++       * GPG_ERR_NOT_SUPPORTED otherwise */
++      rc = _gcry_fips_indicator_pk_flags (arg_ptr);
++      break;
++
+     case PRIV_CTL_INIT_EXTRNG_TEST:  /* Init external random test.  */
+       rc = GPG_ERR_NOT_SUPPORTED;
+       break;
+-- 
+2.39.2
+
+From 22a40df4c0210a671b331932a434f70b50354873 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Mon, 6 Mar 2023 16:05:07 +0100
+Subject: [PATCH] fips: Explicitly disable overriding random in FIPS mode
+
+* src/fips.c: (_gcry_fips_indicator_function): Mark using random
+  override non-approved in FIPS mode.
+--
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ src/fips.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/fips.c b/src/fips.c
+index cb547aa2..a7342030 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -450,7 +450,8 @@ _gcry_fips_indicator_function (va_list arg_ptr)
+   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)
++      strcmp (function, "gcry_pk_decrypt") == 0 ||
++      strcmp (function, "gcry_pk_random_override_new") == 0)
+     return GPG_ERR_NOT_SUPPORTED;
+ 
+   return GPG_ERR_NO_ERROR;
+-- 
+2.39.2
+
+From 1c916b8c99ea0e30f1d81d606fd63b0c45657186 Mon Sep 17 00:00:00 2001
+From: NIIBE Yutaka <gniibe@fsij.org>
+Date: Fri, 24 Mar 2023 13:12:56 +0900
+Subject: [PATCH] fips: More elaborate way of getting FIPS pk flags indicators.
+
+* src/fips.c (_gcry_fips_indicator_pk_flags): List more allowed string
+in the S-expression.
+* doc/gcrypt.texi: Add document for the FIPS service indicator
+GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS with example.
+
+--
+
+GnuPG-bug-id: 6417
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
+---
+ doc/gcrypt.texi | 42 +++++++++++++++++++++++++++++++++++++++---
+ src/fips.c      | 41 +++++++++++++++++++++++++++++++++++++----
+ 2 files changed, 76 insertions(+), 7 deletions(-)
+
+diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
+index 750b6718..752f64d6 100644
+--- a/doc/gcrypt.texi
++++ b/doc/gcrypt.texi
+@@ -1007,9 +1007,45 @@ FIPS 140-3 certification. If the algorithm is approved, this function returns
+ 
+ @item GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS; Arguments: const char *
+ 
+-Check if the given public key operation flag is approved under the current
+-FIPS 140-3 certification. If the flag is approved, this function returns
+-@code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned.
++Check if the given public key operation flag or s-expression object name is
++approved under the current FIPS 140-3 certification.  If the flag is
++approved, this function returns @code{GPG_ERR_NO_ERROR}.
++
++Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned.
++
++For compound s-expression objects, if the object name is allowed, the user
++is responsible to check also the internal members.  For example:
++
++@example
++  gcry_sexp_t s_sig = NULL;
++  gcry_md_hd_t hd = NULL;
++  gcry_sexp_t s_sk = NULL;
++  const char *data_tmpl = "(data(flags pss)(hash %s %b)(salt-length 1:0))";
++
++  if (err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION, "gcry_md_open") &&
++      err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_MD, GCRY_MD_SHA512) &&
++      err = gcry_md_open (&hd, GCRY_MD_SHA512, 0))
++    @{
++      printf ("gcry_md_open failed: %s", gpg_strerror (err));
++      return;
++    @}
++  gcry_md_write (hd, buffer, buflen);
++
++  /* initialize the key in s_sk */
++
++  if (err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION, "gcry_pk_hash_sign") &&
++      err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS, "data") &&
++      err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS, "flags") &&
++      err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS, "pss") &&
++      err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS, "hash") &&
++      err = gcry_control(GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS, "salt-length")
++      err = gcry_pk_hash_sign (&s_sig, data_tmpl, s_sk, hd, NULL))
++    @{
++      printf ("gcry_pk_hash_sign failed: %s", gpg_strerror (err));
++      return;
++    @}
++  /* ok */
++@end example
+ 
+ @end table
+ 
+diff --git a/src/fips.c b/src/fips.c
+index a7342030..669cfd0e 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -457,16 +457,49 @@ _gcry_fips_indicator_function (va_list arg_ptr)
+   return GPG_ERR_NO_ERROR;
+ }
+ 
++/* Note: the array should be sorted.  */
++static const char *valid_string_in_sexp[] = {
++  "curve",
++  "d",
++  "data",
++  "e",
++  "ecdsa",
++  "flags",
++  "genkey",
++  "hash",
++  "n",
++  "nbits",
++  "pkcs1",
++  "private-key",
++  "pss",
++  "public-key",
++  "q",
++  "r",
++  "raw",
++  "rsa",
++  "rsa-use-e",
++  "s",
++  "salt-length",
++  "sig-val",
++  "value"
++};
++
++static int
++compare_string (const void *v1, const void *v2)
++{
++  const char * const *p_str1 = v1;
++  const char * const *p_str2 = v2;
++
++  return strcmp (*p_str1, *p_str2);
++}
+ 
+ int
+ _gcry_fips_indicator_pk_flags (va_list arg_ptr)
+ {
+   const char *flag = va_arg (arg_ptr, const char *);
+ 
+-  if (strcmp (flag, "param") == 0 ||
+-      strcmp (flag, "raw") == 0 ||
+-      strcmp (flag, "no-blinding") == 0 ||
+-      strcmp (flag, "pss") == 0)
++  if (bsearch (&flag, valid_string_in_sexp, DIM (valid_string_in_sexp),
++               sizeof (char *), compare_string))
+     return GPG_ERR_NO_ERROR;
+ 
+   return GPG_ERR_NOT_SUPPORTED;
+-- 
+2.39.2
+
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..a3c0235
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-integrity2.patch
@@ -0,0 +1,190 @@
+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
+
+
+From 3fd3bb31597f80c76a94ea62e42d58d796beabf1 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Mon, 20 Feb 2023 16:16:01 +0100
+Subject: [PATCH] fips: Check return value from ftell
+
+* src/fips.c (get_file_offset): Check return value of ftell to be able
+  to detect errors.
+--
+
+Originally reported by coverity.
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ src/fips.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/fips.c b/src/fips.c
+index 272aabae..0d89b6da 100644
+--- a/src/fips.c
++++ b/src/fips.c
+@@ -681,6 +681,8 @@ get_file_offset (FILE *fp, ElfW (Ehdr) *ehdr_p,
+         return gpg_error_from_syserror ();
+ 
+       off = ftell (fp);
++      if (off < 0)
++        return gpg_error_from_syserror ();
+       if (shdr.sh_type == SHT_NOTE && shdr.sh_flags == 0 && shdr.sh_size == 48)
+         {
+           const char header_of_the_note[] = {
+-- 
+2.39.2
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-kdf.patch b/SOURCES/libgcrypt-1.10.0-fips-kdf.patch
index de2a161..e9d3565 100644
--- a/SOURCES/libgcrypt-1.10.0-fips-kdf.patch
+++ b/SOURCES/libgcrypt-1.10.0-fips-kdf.patch
@@ -1,36 +1,3 @@
-From 857e6f467d0fc9fd858a73d84122695425970075 Mon Sep 17 00:00:00 2001
-From: NIIBE Yutaka <gniibe@fsij.org>
-Date: Tue, 27 Sep 2022 13:26:16 +0900
-Subject: [PATCH] kdf:pkdf2: Require longer input when FIPS mode.
-
-* cipher/kdf.c (_gcry_kdf_pkdf2): Add length check.
-
---
-
-GnuPG-bug-id: 6039
-Fixes-commit: 58c92098d053aae7c78cc42bdd7c80c13efc89bb
-Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
----
- cipher/kdf.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/cipher/kdf.c b/cipher/kdf.c
-index 3e51e115..81523320 100644
---- a/cipher/kdf.c
-+++ b/cipher/kdf.c
-@@ -160,6 +160,9 @@ _gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen,
-     return GPG_ERR_INV_VALUE;
- #endif
- 
-+  /* HMAC requires longer input for approved use case.  */
-+  if (fips_mode () && passphraselen < 14)
-+    return GPG_ERR_INV_VALUE;
- 
-   /* Step 2 */
-   l = ((dklen - 1)/ hlen) + 1;
--- 
-2.37.3
-
 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
@@ -58,9 +25,9 @@ index 81523320..67c60df8 100644
 +  if (fips_mode () && dklen < 14)
 +    return GPG_ERR_INV_VALUE;
 +
-   /* HMAC requires longer input for approved use case.  */
-   if (fips_mode () && passphraselen < 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
@@ -118,3 +85,103 @@ index c0192d7b..716fb53e 100644
 -- 
 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
+
+From f5fe94810f3099c9ccc2ca3a5891502922ab0576 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Tue, 28 Feb 2023 12:53:28 +0100
+Subject: [PATCH] kdf: Update tests in regards to the allowed parameters in
+ FIPS mode.
+
+* cipher/kdf.c (check_one): run selftests for more approved parameters
+and check that wrong parameters correctly fail in FIPS mode.
+
+--
+
+Fixes-commit: 535a4d345872aa2cd2ab3a5f9c4411d0a0313328
+GnuPG-bug-id: 5512
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ cipher/kdf.c | 22 +++++++++++++++-------
+ 1 file changed, 15 insertions(+), 7 deletions(-)
+
+diff --git a/cipher/kdf.c b/cipher/kdf.c
+index 823c744e..12beec56 100644
+--- a/cipher/kdf.c
++++ b/cipher/kdf.c
+@@ -2059,17 +2059,25 @@ check_one (int algo, int hash_algo,
+ {
+   unsigned char key[512]; /* hardcoded to avoid allocation */
+   size_t keysize = expectlen;
+-
+-  /* Skip test with shoter passphrase in FIPS mode.  */
+-  if (fips_mode () && passphraselen < 14)
+-    return NULL;
++  int rv;
+ 
+   if (keysize > sizeof(key))
+     return "invalid tests data";
+ 
+-  if (_gcry_kdf_derive (passphrase, passphraselen, algo,
+-                        hash_algo, salt, saltlen, iterations,
+-                        keysize, key))
++  rv = _gcry_kdf_derive (passphrase, passphraselen, algo,
++                         hash_algo, salt, saltlen, iterations,
++                         keysize, key);
++  /* In fips mode we have special requirements for the input and
++   * output parameters */
++  if (fips_mode ())
++    {
++      if (rv && (passphraselen < 8 || saltlen < 16 ||
++                 iterations < 1000 || expectlen < 14))
++        return NULL;
++      else if (rv)
++        return "gcry_kdf_derive unexpectedly failed in FIPS Mode";
++    }
++  else if (rv)
+     return "gcry_kdf_derive failed";
+ 
+   if (memcmp (key, expect, expectlen))
+-- 
+2.39.2
+
diff --git a/SOURCES/libgcrypt-1.10.0-fips-pct.patch b/SOURCES/libgcrypt-1.10.0-fips-pct.patch
new file mode 100644
index 0000000..252bd31
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-pct.patch
@@ -0,0 +1,145 @@
+From 2ddeec574bc1ae90bb4242c4ce9ad9e7975a27bd Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Wed, 1 Mar 2023 15:42:29 +0100
+Subject: [PATCH] ecc: Do not allow skipping tests in FIPS Mode.
+
+* cipher/ecc.c (ecc_generate): Do not allow skipping tests PCT tests
+in FIPS mode.
+
+--
+
+The new FIPS specification requires to run the PCT without any
+exceptions.
+
+GnuPG-bug-id: 6394
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ cipher/ecc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/cipher/ecc.c b/cipher/ecc.c
+index 1e80200e..797f2368 100644
+--- a/cipher/ecc.c
++++ b/cipher/ecc.c
+@@ -677,7 +677,7 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
+         log_debug ("ecgen result  using Ed25519+EdDSA\n");
+     }
+ 
+-  if (!(flags & PUBKEY_FLAG_NO_KEYTEST) && fips_mode ())
++  if (fips_mode ())
+     test_keys_fips (*r_skey);
+ 
+  leave:
+-- 
+2.39.2
+
+From 23a2d1285e35b2eb91bb422609eb1c965c8a9bf6 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Thu, 2 Mar 2023 09:43:44 +0100
+Subject: [PATCH] ecc: Make the PCT recoverable in FIPS mode and consistent
+ with RSA.
+
+* cipher/ecc.c (test_keys_fips): Replace calls to log_fatal with
+return code on error.
+(ecc_generate): Signal error when PCT fails in FIPS mode.
+
+--
+
+GnuPG-bug-id: 6397
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ cipher/ecc.c | 36 ++++++++++++++++++++++++++++--------
+ 1 file changed, 28 insertions(+), 8 deletions(-)
+
+diff --git a/cipher/ecc.c b/cipher/ecc.c
+index 797f2368..19520db3 100644
+--- a/cipher/ecc.c
++++ b/cipher/ecc.c
+@@ -101,7 +101,7 @@ static void *progress_cb_data;
+ 
+ /* Local prototypes. */
+ static void test_keys (mpi_ec_t ec, unsigned int nbits);
+-static void test_keys_fips (gcry_sexp_t skey);
++static int test_keys_fips (gcry_sexp_t skey);
+ static void test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags);
+ static unsigned int ecc_get_nbits (gcry_sexp_t parms);
+ 
+@@ -308,9 +308,10 @@ test_keys (mpi_ec_t ec, unsigned int nbits)
+ /* We should get here only with the NIST curves as they are the only ones
+  * having the fips bit set in ecc_domain_parms_t struct so this is slightly
+  * simpler than the whole ecc_generate function */
+-static void
++static int
+ test_keys_fips (gcry_sexp_t skey)
+ {
++  int result = -1; /* Default to failure */
+   gcry_md_hd_t hd = NULL;
+   const char *data_tmpl = "(data (flags rfc6979) (hash %s %b))";
+   gcry_sexp_t sig = NULL;
+@@ -323,18 +324,27 @@ test_keys_fips (gcry_sexp_t skey)
+   /* Open MD context and feed the random data in */
+   rc = _gcry_md_open (&hd, GCRY_MD_SHA256, 0);
+   if (rc)
+-    log_fatal ("ECDSA operation: failed to initialize MD context: %s\n", gpg_strerror (rc));
++    {
++      log_error ("ECDSA operation: failed to initialize MD context: %s\n", gpg_strerror (rc));
++      goto leave;
++    }
+   _gcry_md_write (hd, plaintext, sizeof(plaintext));
+ 
+   /* Sign the data */
+   rc = _gcry_pk_sign_md (&sig, data_tmpl, hd, skey, NULL);
+   if (rc)
+-    log_fatal ("ECDSA operation: signing failed: %s\n", gpg_strerror (rc));
++    {
++      log_error ("ECDSA operation: signing failed: %s\n", gpg_strerror (rc));
++      goto leave;
++    }
+ 
+   /* Verify this signature.  */
+   rc = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL);
+   if (rc)
+-    log_fatal ("ECDSA operation: verification failed: %s\n", gpg_strerror (rc));
++    {
++      log_error ("ECDSA operation: verification failed: %s\n", gpg_strerror (rc));
++      goto leave;
++    }
+ 
+   /* Modify the data and check that the signing fails.  */
+   _gcry_md_reset(hd);
+@@ -342,10 +352,16 @@ test_keys_fips (gcry_sexp_t skey)
+   _gcry_md_write (hd, plaintext, sizeof(plaintext));
+   rc = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL);
+   if (rc != GPG_ERR_BAD_SIGNATURE)
+-    log_fatal ("ECDSA operation: signature verification worked on modified data\n");
++    {
++      log_error ("ECDSA operation: signature verification worked on modified data\n");
++      goto leave;
++    }
+ 
++  result = 0;
++leave:
+   _gcry_md_close (hd);
+   sexp_release (sig);
++  return result;
+ }
+ 
+ 
+@@ -677,8 +693,12 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
+         log_debug ("ecgen result  using Ed25519+EdDSA\n");
+     }
+ 
+-  if (fips_mode ())
+-    test_keys_fips (*r_skey);
++  if (fips_mode () && test_keys_fips (*r_skey))
++    {
++      sexp_release (*r_skey); r_skey = NULL;
++      fips_signal_error ("self-test after key generation failed");
++      rc = GPG_ERR_SELFTEST_FAILED;
++    }
+ 
+  leave:
+   mpi_free (public);
+-- 
+2.39.2
+
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-status-sign-verify.patch b/SOURCES/libgcrypt-1.10.0-fips-status-sign-verify.patch
new file mode 100644
index 0000000..9cf20c3
--- /dev/null
+++ b/SOURCES/libgcrypt-1.10.0-fips-status-sign-verify.patch
@@ -0,0 +1,46 @@
+From 654d0dfa04993ebe28c0536d42f4bc6d87c28369 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Wed, 1 Mar 2023 17:14:00 +0100
+Subject: [PATCH] visibility: Check FIPS operational status for MD+Sign
+ operation.
+
+* src/visibility.c (gcry_pk_hash_sign): Check fips status before
+calling the operation itself.
+(gcry_pk_hash_verify): Ditto.
+
+--
+
+GnuPG-bug-id: 6396
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ src/visibility.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/visibility.c b/src/visibility.c
+index 73db3dea..1f17e147 100644
+--- a/src/visibility.c
++++ b/src/visibility.c
+@@ -1050,6 +1050,11 @@ gcry_error_t
+ gcry_pk_hash_sign (gcry_sexp_t *result, const char *data_tmpl, gcry_sexp_t skey,
+                    gcry_md_hd_t hd, gcry_ctx_t ctx)
+ {
++  if (!fips_is_operational ())
++    {
++      *result = NULL;
++      return gpg_error (fips_not_operational ());
++    }
+   return gpg_error (_gcry_pk_sign_md (result, data_tmpl, hd, skey, ctx));
+ }
+ 
+@@ -1065,6 +1070,8 @@ gcry_error_t
+ gcry_pk_hash_verify (gcry_sexp_t sigval, const char *data_tmpl, gcry_sexp_t pkey,
+                      gcry_md_hd_t hd, gcry_ctx_t ctx)
+ {
++  if (!fips_is_operational ())
++    return gpg_error (fips_not_operational ());
+   return gpg_error (_gcry_pk_verify_md (sigval, data_tmpl, hd, pkey, ctx));
+ }
+ 
+-- 
+2.39.2
+
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/SPECS/libgcrypt.spec b/SPECS/libgcrypt.spec
index a9297bb..1b1550a 100644
--- a/SPECS/libgcrypt.spec
+++ b/SPECS/libgcrypt.spec
@@ -16,7 +16,7 @@ print(string.sub(hash, 0, 16))
 
 Name: libgcrypt
 Version: 1.10.0
-Release: 7%{?dist}
+Release: 10%{?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
@@ -34,7 +34,35 @@ 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
+# 3fd3bb31597f80c76a94ea62e42d58d796beabf1
+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
+# https://dev.gnupg.org/T6376
+Patch17: libgcrypt-1.10.0-fips-indicator-md-hmac.patch
+# https://dev.gnupg.org/T6394
+# https://dev.gnupg.org/T6397
+Patch18: libgcrypt-1.10.0-fips-pct.patch
+# https://dev.gnupg.org/T6396
+Patch19: libgcrypt-1.10.0-fips-status-sign-verify.patch
+# https://dev.gnupg.org/T6393
+Patch20: libgcrypt-1.10.0-fips-drbg.patch
+# https://dev.gnupg.org/T6417
+Patch21: libgcrypt-1.10.0-fips-indicator-pk-flags.patch
 
 %global gcrylibdir %{_libdir}
 %global gcrysoname libgcrypt.so.20
@@ -79,6 +107,16 @@ applications using libgcrypt.
 %patch9 -p1
 %patch10 -p1
 %patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
+%patch17 -p1
+%patch18 -p1
+%patch19 -p1
+%patch20 -p1
+%patch21 -p1
 
 %build
 # This package has a configure test which uses ASMs, but does not link the
@@ -105,6 +143,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}"
@@ -122,12 +161,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
@@ -197,6 +236,24 @@ mkdir -p -m 755 $RPM_BUILD_ROOT/etc/gcrypt
 %license COPYING
 
 %changelog
+* Mon Mar 20 2023 Jakub Jelen <jjelen@redhat.com> - 1.10.0-10
+- Provide FIPS indicators for MD and HMACs
+- Improve PCT tests for ECDSA and always run them after key is generated
+- Add missing guards for FIPS status in md_sign/verify function
+- Provider FIPS indicators for public key operation flags
+
+* 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)