File gnupg-CVE-2025-30258-Fix-regression-for-the-recent-malicious-subkey-DoS-fix.patch of Package gpg2.41297

From 8acc6e990c1f6ee0cacbacf3ddb7b051439c6e59 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Thu, 6 Mar 2025 17:17:17 +0100
Subject: [PATCH 4/6] gpg: Fix regression for the recent malicious subkey
 DoS fix.

* g10/packet.h (PUBKEY_USAGE_VERIFY): New.
* g10/getkey.c (get_pubkey_for_sig): Pass new flag also to requested
usage.
(finish_lookup): Introduce a verify_mode.
--

Fixes-commit: da0164efc7f32013bc24d97b9afa9f8d67c318bb
GnuPG-bug-id: 7547
Signed-off-by: Lucas Mulling <lucas.mulling@suse.com>
---
 g10/getkey.c | 43 +++++++++++++++++++++++++++----------------
 g10/packet.h |  1 +
 2 files changed, 28 insertions(+), 16 deletions(-)

Index: gnupg-2.2.27/g10/getkey.c
===================================================================
--- gnupg-2.2.27.orig/g10/getkey.c
+++ gnupg-2.2.27/g10/getkey.c
@@ -422,11 +422,12 @@ pk_from_block (PKT_public_key *pk, kbnod
 
 
 /* Specialized version of get_pubkey which retrieves the key based on
- * information in SIG.  In contrast to get_pubkey PK is required.  IF
+ * information in SIG.  In contrast to get_pubkey PK is required.  If
  * FORCED_PK is not NULL, this public key is used and copied to PK.
  * If R_KEYBLOCK is not NULL the entire keyblock is stored there if
  * found and FORCED_PK is not used; if not used or on error NULL is
- * stored there. */
+ * stored there.  Use this function only to find the key for
+ * verification; it can't be used to select a key for signing.  */
 gpg_error_t
 get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig,
                     PKT_public_key *forced_pk, kbnode_t *r_keyblock)
@@ -446,8 +447,9 @@ get_pubkey_for_sig (ctrl_t ctrl, PKT_pub
 
   /* Make sure to request only keys cabable of signing.  This makes
    * sure that a subkey w/o a valid backsig or with bad usage flags
-   * will be skipped.  */
-  pk->req_usage = PUBKEY_USAGE_SIG;
+   * will be skipped.  We also request the verification mode so that
+   * expired and reoked keys are returned.  */
+  pk->req_usage = (PUBKEY_USAGE_SIG | PUBKEY_USAGE_VERIFY);
 
   /* First try the ISSUER_FPR info.  */
   fpr = issuer_fpr_raw (sig, &fprlen);
@@ -511,10 +513,10 @@ get_pubkey_bykid (ctrl_t ctrl, PKT_publi
       /* Try to get it from the cache.  We don't do this when pk is
        * NULL as it does not guarantee that the user IDs are cached.
        * The old get_pubkey_function did not check PK->REQ_USAGE when
-       * reading form the caceh.  This is probably a bug.  Note that
+       * reading from the cache.  This is probably a bug.  Note that
        * the cache is not used when the caller asked to return the
        * entire keyblock.  This is because the cache does not
-       * associate the public key wit its primary key.  */
+       * associate the public key with its primary key.  */
       pk_cache_entry_t ce;
       for (ce = pk_cache; ce; ce = ce->next)
 	{
@@ -3528,11 +3530,18 @@ finish_lookup (kbnode_t keyblock, unsign
   PKT_public_key *pk;
   int req_prim;
   int diag_exactfound = 0;
+  int verify_mode = 0;
   u32 curtime = make_timestamp ();
 
   if (r_flags)
     *r_flags = 0;
 
+
+  /* The verify mode is used to change the behaviour so that we can
+   * return an expired or revoked key for signature verification.  */
+  verify_mode = ((req_usage & PUBKEY_USAGE_VERIFY)
+                 && (req_usage & PUBKEY_USAGE_SIG));
+
 #define USAGE_MASK  (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
   req_usage &= USAGE_MASK;
 
@@ -3576,9 +3585,9 @@ finish_lookup (kbnode_t keyblock, unsign
     }
 
   if (DBG_LOOKUP)
-    log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x)\n",
+    log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x%s)\n",
 	       (ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL),
-	       foundk ? "one" : "all", req_usage);
+	       foundk ? "one" : "all", req_usage, verify_mode? ",verify":"");
   if (diag_exactfound && DBG_LOOKUP)
     log_debug ("\texact search requested and found\n");
 
@@ -3640,36 +3649,37 @@ finish_lookup (kbnode_t keyblock, unsign
 	    }
 
           n_subkeys++;
-	  if (pk->flags.revoked)
-	    {
-	      if (DBG_LOOKUP)
-		log_debug ("\tsubkey has been revoked\n");
+          if (!verify_mode && pk->flags.revoked)
+            {
+              if (DBG_LOOKUP)
+                log_debug ("\tsubkey has been revoked\n");
               n_revoked_or_expired++;
-	      continue;
-	    }
-	  if (pk->has_expired)
-	    {
-	      if (DBG_LOOKUP)
-		log_debug ("\tsubkey has expired\n");
+              continue;
+            }
+          if (!verify_mode && pk->has_expired)
+            {
+              if (DBG_LOOKUP)
+                log_debug ("\tsubkey has expired\n");
               n_revoked_or_expired++;
-	      continue;
-	    }
-	  if (pk->timestamp > curtime && !opt.ignore_valid_from)
-	    {
-	      if (DBG_LOOKUP)
-		log_debug ("\tsubkey not yet valid\n");
-	      continue;
-	    }
+              continue;
+            }
+          if (!verify_mode && pk->timestamp > curtime && !opt.ignore_valid_from)
+            {
+              if (DBG_LOOKUP)
+                log_debug ("\tsubkey not yet valid\n");
+              continue;
+            }
 
-          if (want_secret && agent_probe_secret_key (NULL, pk))
+          if (!verify_mode && want_secret && agent_probe_secret_key (NULL, pk))
             {
               if (DBG_LOOKUP)
                 log_debug ("\tno secret key\n");
               continue;
             }
 
-	  if (DBG_LOOKUP)
-	    log_debug ("\tsubkey might be fine\n");
+          if (DBG_LOOKUP)
+            log_debug ("\tsubkey might be fine%s\n",
+                       verify_mode? " for verification":"");
 	  /* In case a key has a timestamp of 0 set, we make sure
 	     that it is used.  A better change would be to compare
 	     ">=" but that might also change the selected keys and
@@ -3710,22 +3720,23 @@ finish_lookup (kbnode_t keyblock, unsign
 	    log_debug ("\tprimary key usage does not match: "
 		       "want=%x have=%x\n", req_usage, pk->pubkey_usage);
 	}
-      else if (pk->flags.revoked)
-	{
-	  if (DBG_LOOKUP)
-	    log_debug ("\tprimary key has been revoked\n");
-	}
-      else if (pk->has_expired)
-	{
-	  if (DBG_LOOKUP)
-	    log_debug ("\tprimary key has expired\n");
-	}
+      else if (!verify_mode && pk->flags.revoked)
+        {
+          if (DBG_LOOKUP)
+            log_debug ("\tprimary key has been revoked\n");
+        }
+      else if (!verify_mode && pk->has_expired)
+        {
+          if (DBG_LOOKUP)
+            log_debug ("\tprimary key has expired\n");
+        }
       else /* Okay.  */
-	{
-	  if (DBG_LOOKUP)
-	    log_debug ("\tprimary key may be used\n");
-	  latest_key = keyblock;
-	}
+        {
+          if (DBG_LOOKUP)
+            log_debug ("\tprimary key may be used%s\n",
+                       verify_mode? " for verification":"");
+          latest_key = keyblock;
+        }
     }
 
   if (!latest_key)
Index: gnupg-2.2.27/g10/packet.h
===================================================================
--- gnupg-2.2.27.orig/g10/packet.h
+++ gnupg-2.2.27/g10/packet.h
@@ -57,6 +57,8 @@
 # error Please choose another value for PUBKEY_USAGE_NONE
 #endif
 
+#define PUBKEY_USAGE_VERIFY  16384               /* Verify only modifier.  */
+
 /* Helper macros.  */
 #define is_RSA(a)     ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \
 		       || (a)==PUBKEY_ALGO_RSA_S )
@@ -385,8 +387,8 @@ typedef struct
   byte    selfsigversion; /* highest version of all of the self-sigs */
   /* The public key algorithm.  (Serialized.)  */
   byte    pubkey_algo;
-  byte    pubkey_usage;   /* for now only used to pass it to getkey() */
-  byte    req_usage;      /* hack to pass a request to getkey() */
+  u16     pubkey_usage;   /* for now only used to pass it to getkey() */
+  u16     req_usage;      /* hack to pass a request to getkey() */
   u32     has_expired;    /* set to the expiration date if expired */
   /* keyid of the primary key.  Never access this value directly.
      Instead, use pk_main_keyid().  */
openSUSE Build Service is sponsored by