|
@@ -0,0 +1,624 @@
|
|
|
+From da0164efc7f32013bc24d97b9afa9f8d67c318bb Mon Sep 17 00:00:00 2001
|
|
|
+rom: Werner Koch <wk@gnupg.org>
|
|
|
+Date: Fri, 21 Feb 2025 12:16:17 +0100
|
|
|
+Subject: [PATCH] gpg: Fix a verification DoS due to a malicious subkey in the
|
|
|
+ keyring.
|
|
|
+
|
|
|
+* g10/getkey.c (get_pubkey): Factor code out to ...
|
|
|
+(get_pubkey_bykid): new. Add feature to return the keyblock.
|
|
|
+(get_pubkey_for_sig): Add arg r_keyblock to return the used keyblock.
|
|
|
+Request a signing usage.
|
|
|
+(get_pubkeyblock_for_sig): Remove.
|
|
|
+(finish_lookup): Improve debug output.
|
|
|
+* g10/sig-check.c (check_signature): Add arg r_keyblock and pass it
|
|
|
+down.
|
|
|
+* g10/mainproc.c (do_check_sig): Ditto.
|
|
|
+(check_sig_and_print): Use the keyblock returned by do_check_sig to
|
|
|
+show further information instead of looking it up again with
|
|
|
+get_pubkeyblock_for_sig. Also re-check the signature after the import
|
|
|
+of an included keyblock.
|
|
|
+--
|
|
|
+
|
|
|
+The problem here is that it is possible to import a key from someone
|
|
|
+who added a signature subkey from another public key and thus inhibits
|
|
|
+that a good signature good be verified.
|
|
|
+
|
|
|
+Such a malicious key signature subkey must have been created w/o the
|
|
|
+mandatory backsig which bind a signature subkey to its primary key.
|
|
|
+For encryption subkeys this is not an issue because the existence of a
|
|
|
+decryption private key is all you need to decrypt something and then
|
|
|
+it does not matter if the public subkey or its binding signature has
|
|
|
+been put below another primary key; in fact we do the latter for
|
|
|
+ADSKs.
|
|
|
+
|
|
|
+GnuPG-bug-id: 7527
|
|
|
+Backported-from-master: 48978ccb4e20866472ef18436a32744350a65158
|
|
|
+
|
|
|
+CVE: CVE-2025-30258
|
|
|
+Upstream-Status: Backport [https://dev.gnupg.org/rGda0164efc7f32013bc24d97b9afa9f8d67c318bb]
|
|
|
+
|
|
|
+Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
|
|
|
+---
|
|
|
+ g10/getkey.c | 106 ++++++++++++++++++++++++++++++------------------
|
|
|
+ g10/gpg.h | 3 +-
|
|
|
+ g10/keydb.h | 10 ++++-
|
|
|
+ g10/mainproc.c | 92 ++++++++++++++++++++++++++---------------
|
|
|
+ g10/packet.h | 2 +-
|
|
|
+ g10/sig-check.c | 23 +++++++----
|
|
|
+ 6 files changed, 152 insertions(+), 84 deletions(-)
|
|
|
+
|
|
|
+diff --git a/g10/getkey.c b/g10/getkey.c
|
|
|
+index 7a25643..0fa763a 100644
|
|
|
+--- a/g10/getkey.c
|
|
|
++++ b/g10/getkey.c
|
|
|
+@@ -310,27 +310,50 @@ pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key)
|
|
|
+
|
|
|
+ /* Specialized version of get_pubkey which retrieves the key based on
|
|
|
+ * 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. */
|
|
|
++ * 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. */
|
|
|
+ gpg_error_t
|
|
|
+ get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig,
|
|
|
+- PKT_public_key *forced_pk)
|
|
|
++ PKT_public_key *forced_pk, kbnode_t *r_keyblock)
|
|
|
+ {
|
|
|
++ gpg_error_t err;
|
|
|
+ const byte *fpr;
|
|
|
+ size_t fprlen;
|
|
|
+
|
|
|
++ if (r_keyblock)
|
|
|
++ *r_keyblock = NULL;
|
|
|
++
|
|
|
+ if (forced_pk)
|
|
|
+ {
|
|
|
+ copy_public_key (pk, forced_pk);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
++ /* 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;
|
|
|
++
|
|
|
+ /* First try the ISSUER_FPR info. */
|
|
|
+ fpr = issuer_fpr_raw (sig, &fprlen);
|
|
|
+- if (fpr && !get_pubkey_byfprint (ctrl, pk, NULL, fpr, fprlen))
|
|
|
++ if (fpr && !get_pubkey_byfprint (ctrl, pk, r_keyblock, fpr, fprlen))
|
|
|
+ return 0;
|
|
|
++ if (r_keyblock)
|
|
|
++ {
|
|
|
++ release_kbnode (*r_keyblock);
|
|
|
++ *r_keyblock = NULL;
|
|
|
++ }
|
|
|
+
|
|
|
+ /* Fallback to use the ISSUER_KEYID. */
|
|
|
+- return get_pubkey (ctrl, pk, sig->keyid);
|
|
|
++ err = get_pubkey_bykid (ctrl, pk, r_keyblock, sig->keyid);
|
|
|
++ if (err && r_keyblock)
|
|
|
++ {
|
|
|
++ release_kbnode (*r_keyblock);
|
|
|
++ *r_keyblock = NULL;
|
|
|
++ }
|
|
|
++ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+@@ -348,6 +371,10 @@ get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig,
|
|
|
+ * usage will be returned. As such, it is essential that
|
|
|
+ * PK->REQ_USAGE be correctly initialized!
|
|
|
+ *
|
|
|
++ * If R_KEYBLOCK is not NULL, then the first result's keyblock is
|
|
|
++ * returned in *R_KEYBLOCK. This should be freed using
|
|
|
++ * release_kbnode().
|
|
|
++ *
|
|
|
+ * Returns 0 on success, GPG_ERR_NO_PUBKEY if there is no public key
|
|
|
+ * with the specified key id, or another error code if an error
|
|
|
+ * occurs.
|
|
|
+@@ -355,24 +382,30 @@ get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig,
|
|
|
+ * If the data was not read from the cache, then the self-signed data
|
|
|
+ * has definitely been merged into the public key using
|
|
|
+ * merge_selfsigs. */
|
|
|
+-int
|
|
|
+-get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
|
|
|
++gpg_error_t
|
|
|
++get_pubkey_bykid (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
|
|
|
++ u32 *keyid)
|
|
|
+ {
|
|
|
+ int internal = 0;
|
|
|
+- int rc = 0;
|
|
|
++ gpg_error_t rc = 0;
|
|
|
++
|
|
|
++ if (r_keyblock)
|
|
|
++ *r_keyblock = NULL;
|
|
|
+
|
|
|
+ #if MAX_PK_CACHE_ENTRIES
|
|
|
+- if (pk)
|
|
|
++ if (pk && !r_keyblock)
|
|
|
+ {
|
|
|
+ /* 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. */
|
|
|
++ * 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
|
|
|
++ * 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. */
|
|
|
+ pk_cache_entry_t ce;
|
|
|
+ for (ce = pk_cache; ce; ce = ce->next)
|
|
|
+ {
|
|
|
+ if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1])
|
|
|
+- /* XXX: We don't check PK->REQ_USAGE here, but if we don't
|
|
|
+- read from the cache, we do check it! */
|
|
|
+ {
|
|
|
+ copy_public_key (pk, ce->pk);
|
|
|
+ return 0;
|
|
|
+@@ -380,6 +413,7 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endif
|
|
|
++
|
|
|
+ /* More init stuff. */
|
|
|
+ if (!pk)
|
|
|
+ {
|
|
|
+@@ -425,16 +459,18 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
|
|
|
+ ctx.req_usage = pk->req_usage;
|
|
|
+ rc = lookup (ctrl, &ctx, 0, &kb, &found_key);
|
|
|
+ if (!rc)
|
|
|
++ pk_from_block (pk, kb, found_key);
|
|
|
++ getkey_end (ctrl, &ctx);
|
|
|
++ if (!rc && r_keyblock)
|
|
|
+ {
|
|
|
+- pk_from_block (pk, kb, found_key);
|
|
|
++ *r_keyblock = kb;
|
|
|
++ kb = NULL;
|
|
|
+ }
|
|
|
+- getkey_end (ctrl, &ctx);
|
|
|
+ release_kbnode (kb);
|
|
|
+ }
|
|
|
+- if (!rc)
|
|
|
+- goto leave;
|
|
|
+
|
|
|
+- rc = GPG_ERR_NO_PUBKEY;
|
|
|
++ if (rc) /* Return a more useful error code. */
|
|
|
++ rc = gpg_error (GPG_ERR_NO_PUBKEY);
|
|
|
+
|
|
|
+ leave:
|
|
|
+ if (!rc)
|
|
|
+@@ -445,6 +481,14 @@ leave:
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
++/* Wrapper for get_pubkey_bykid w/o keyblock return feature. */
|
|
|
++int
|
|
|
++get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid)
|
|
|
++{
|
|
|
++ return get_pubkey_bykid (ctrl, pk, NULL, keyid);
|
|
|
++}
|
|
|
++
|
|
|
++
|
|
|
+ /* Same as get_pubkey but if the key was not found the function tries
|
|
|
+ * to import it from LDAP. FIXME: We should not need this but swicth
|
|
|
+ * to a fingerprint lookup. */
|
|
|
+@@ -557,28 +601,6 @@ get_pubkey_fast (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+-/* Return the entire keyblock used to create SIG. This is a
|
|
|
+- * specialized version of get_pubkeyblock.
|
|
|
+- *
|
|
|
+- * FIXME: This is a hack because get_pubkey_for_sig was already called
|
|
|
+- * and it could have used a cache to hold the key. */
|
|
|
+-kbnode_t
|
|
|
+-get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig)
|
|
|
+-{
|
|
|
+- const byte *fpr;
|
|
|
+- size_t fprlen;
|
|
|
+- kbnode_t keyblock;
|
|
|
+-
|
|
|
+- /* First try the ISSUER_FPR info. */
|
|
|
+- fpr = issuer_fpr_raw (sig, &fprlen);
|
|
|
+- if (fpr && !get_pubkey_byfprint (ctrl, NULL, &keyblock, fpr, fprlen))
|
|
|
+- return keyblock;
|
|
|
+-
|
|
|
+- /* Fallback to use the ISSUER_KEYID. */
|
|
|
+- return get_pubkeyblock (ctrl, sig->keyid);
|
|
|
+-}
|
|
|
+-
|
|
|
+-
|
|
|
+ /* Return the key block for the key with key id KEYID or NULL, if an
|
|
|
+ * error occurs. Use release_kbnode() to release the key block.
|
|
|
+ *
|
|
|
+@@ -3611,6 +3633,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
|
|
|
+ kbnode_t latest_key;
|
|
|
+ PKT_public_key *pk;
|
|
|
+ int req_prim;
|
|
|
++ int diag_exactfound = 0;
|
|
|
+ u32 curtime = make_timestamp ();
|
|
|
+
|
|
|
+ if (r_flags)
|
|
|
+@@ -3641,6 +3664,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
|
|
|
+ foundk = k;
|
|
|
+ pk = k->pkt->pkt.public_key;
|
|
|
+ pk->flags.exact = 1;
|
|
|
++ diag_exactfound = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+@@ -3661,10 +3685,14 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
|
|
|
+ log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x)\n",
|
|
|
+ (ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL),
|
|
|
+ foundk ? "one" : "all", req_usage);
|
|
|
++ if (diag_exactfound && DBG_LOOKUP)
|
|
|
++ log_debug ("\texact search requested and found\n");
|
|
|
+
|
|
|
+ if (!req_usage)
|
|
|
+ {
|
|
|
+ latest_key = foundk ? foundk : keyblock;
|
|
|
++ if (DBG_LOOKUP)
|
|
|
++ log_debug ("\tno usage requested - accepting key\n");
|
|
|
+ goto found;
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/g10/gpg.h b/g10/gpg.h
|
|
|
+index c51bbbb..0cdcb8b 100644
|
|
|
+--- a/g10/gpg.h
|
|
|
++++ b/g10/gpg.h
|
|
|
+@@ -69,7 +69,8 @@ struct dirmngr_local_s;
|
|
|
+ typedef struct dirmngr_local_s *dirmngr_local_t;
|
|
|
+
|
|
|
+ /* Object used to describe a keyblock node. */
|
|
|
+-typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */typedef struct kbnode_struct *kbnode_t;
|
|
|
++typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */
|
|
|
++typedef struct kbnode_struct *kbnode_t;
|
|
|
+
|
|
|
+ /* The handle for keydb operations. */
|
|
|
+ typedef struct keydb_handle_s *KEYDB_HANDLE;
|
|
|
+diff --git a/g10/keydb.h b/g10/keydb.h
|
|
|
+index 51dfece..8e494f6 100644
|
|
|
+--- a/g10/keydb.h
|
|
|
++++ b/g10/keydb.h
|
|
|
+@@ -332,9 +332,15 @@ void getkey_disable_caches(void);
|
|
|
+ /* Return the public key used for signature SIG and store it at PK. */
|
|
|
+ gpg_error_t get_pubkey_for_sig (ctrl_t ctrl,
|
|
|
+ PKT_public_key *pk, PKT_signature *sig,
|
|
|
+- PKT_public_key *forced_pk);
|
|
|
++ PKT_public_key *forced_pk,
|
|
|
++ kbnode_t *r_keyblock);
|
|
|
+
|
|
|
+-/* Return the public key with the key id KEYID and store it at PK. */
|
|
|
++/* Return the public key with the key id KEYID and store it at PK.
|
|
|
++ * Optionally return the entire keyblock. */
|
|
|
++gpg_error_t get_pubkey_bykid (ctrl_t ctrl, PKT_public_key *pk,
|
|
|
++ kbnode_t *r_keyblock, u32 *keyid);
|
|
|
++
|
|
|
++/* Same as get_pubkey_bykid but w/o r_keyblock. */
|
|
|
+ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
|
|
|
+
|
|
|
+ /* Same as get_pubkey but with auto LDAP fetch. */
|
|
|
+diff --git a/g10/mainproc.c b/g10/mainproc.c
|
|
|
+index 79d9ff2..6e114d2 100644
|
|
|
+--- a/g10/mainproc.c
|
|
|
++++ b/g10/mainproc.c
|
|
|
+@@ -1108,12 +1108,15 @@ proc_compressed (CTX c, PACKET *pkt)
|
|
|
+ * used to verify the signature will be stored there, or NULL if not
|
|
|
+ * found. If FORCED_PK is not NULL, this public key is used to verify
|
|
|
+ * _data signatures_ and no key lookup is done. Returns: 0 = valid
|
|
|
+- * signature or an error code
|
|
|
++ * signature or an error code. If R_KEYBLOCK is not NULL the keyblock
|
|
|
++ * carries the used PK is stored there. The caller should always free
|
|
|
++ * the return value using release_kbnode.
|
|
|
+ */
|
|
|
+ static int
|
|
|
+ do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen,
|
|
|
+ PKT_public_key *forced_pk, int *is_selfsig,
|
|
|
+- int *is_expkey, int *is_revkey, PKT_public_key **r_pk)
|
|
|
++ int *is_expkey, int *is_revkey,
|
|
|
++ PKT_public_key **r_pk, kbnode_t *r_keyblock)
|
|
|
+ {
|
|
|
+ PKT_signature *sig;
|
|
|
+ gcry_md_hd_t md = NULL;
|
|
|
+@@ -1123,6 +1126,8 @@ do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen,
|
|
|
+
|
|
|
+ if (r_pk)
|
|
|
+ *r_pk = NULL;
|
|
|
++ if (r_keyblock)
|
|
|
++ *r_keyblock = NULL;
|
|
|
+
|
|
|
+ log_assert (node->pkt->pkttype == PKT_SIGNATURE);
|
|
|
+ if (is_selfsig)
|
|
|
+@@ -1199,16 +1204,19 @@ do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen,
|
|
|
+ /* We only get here if we are checking the signature of a binary
|
|
|
+ (0x00) or text document (0x01). */
|
|
|
+ rc = check_signature (c->ctrl, sig, md, extrahash, extrahashlen,
|
|
|
+- forced_pk, NULL, is_expkey, is_revkey, r_pk);
|
|
|
++ forced_pk, NULL, is_expkey, is_revkey,
|
|
|
++ r_pk, r_keyblock);
|
|
|
+ if (! rc)
|
|
|
+ md_good = md;
|
|
|
+ else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
|
|
|
+ {
|
|
|
+ PKT_public_key *pk2;
|
|
|
+
|
|
|
++ if (r_keyblock)
|
|
|
++ release_kbnode (*r_keyblock);
|
|
|
+ rc = check_signature (c->ctrl, sig, md2, extrahash, extrahashlen,
|
|
|
+ forced_pk, NULL, is_expkey, is_revkey,
|
|
|
+- r_pk? &pk2 : NULL);
|
|
|
++ r_pk? &pk2 : NULL, r_keyblock);
|
|
|
+ if (!rc)
|
|
|
+ {
|
|
|
+ md_good = md2;
|
|
|
+@@ -1371,7 +1379,7 @@ list_node (CTX c, kbnode_t node)
|
|
|
+ {
|
|
|
+ fflush (stdout);
|
|
|
+ rc2 = do_check_sig (c, node, NULL, 0, NULL,
|
|
|
+- &is_selfsig, NULL, NULL, NULL);
|
|
|
++ &is_selfsig, NULL, NULL, NULL, NULL);
|
|
|
+ switch (gpg_err_code (rc2))
|
|
|
+ {
|
|
|
+ case 0: sigrc = '!'; break;
|
|
|
+@@ -1830,7 +1838,7 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */
|
|
|
+ const void *extrahash = NULL;
|
|
|
+ size_t extrahashlen = 0;
|
|
|
+- kbnode_t included_keyblock = NULL;
|
|
|
++ kbnode_t keyblock = NULL;
|
|
|
+
|
|
|
+ if (opt.skip_verify)
|
|
|
+ {
|
|
|
+@@ -1949,7 +1957,8 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ {
|
|
|
+ ambiguous:
|
|
|
+ log_error(_("can't handle this ambiguous signature data\n"));
|
|
|
+- return 0;
|
|
|
++ rc = 0;
|
|
|
++ goto leave;
|
|
|
+ }
|
|
|
+ } /* End checking signature packet composition. */
|
|
|
+
|
|
|
+@@ -1985,7 +1994,7 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ log_info (_(" issuer \"%s\"\n"), sig->signers_uid);
|
|
|
+
|
|
|
+ rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
|
|
|
+- NULL, &is_expkey, &is_revkey, &pk);
|
|
|
++ NULL, &is_expkey, &is_revkey, &pk, &keyblock);
|
|
|
+
|
|
|
+ /* If the key is not found but the signature includes a key block we
|
|
|
+ * use that key block for verification and on success import it. */
|
|
|
+@@ -1993,6 +2002,7 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ && sig->flags.key_block
|
|
|
+ && opt.flags.auto_key_import)
|
|
|
+ {
|
|
|
++ kbnode_t included_keyblock = NULL;
|
|
|
+ PKT_public_key *included_pk;
|
|
|
+ const byte *kblock;
|
|
|
+ size_t kblock_len;
|
|
|
+@@ -2004,10 +2014,12 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ kblock+1, kblock_len-1,
|
|
|
+ sig->keyid, &included_keyblock))
|
|
|
+ {
|
|
|
++ /* Note: This is the only place where we use the forced_pk
|
|
|
++ * arg (ie. included_pk) with do_check_sig. */
|
|
|
+ rc = do_check_sig (c, node, extrahash, extrahashlen, included_pk,
|
|
|
+- NULL, &is_expkey, &is_revkey, &pk);
|
|
|
++ NULL, &is_expkey, &is_revkey, &pk, NULL);
|
|
|
+ if (opt.verbose)
|
|
|
+- log_debug ("checked signature using included key block: %s\n",
|
|
|
++ log_info ("checked signature using included key block: %s\n",
|
|
|
+ gpg_strerror (rc));
|
|
|
+ if (!rc)
|
|
|
+ {
|
|
|
+@@ -2017,6 +2029,18 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+
|
|
|
+ }
|
|
|
+ free_public_key (included_pk);
|
|
|
++ release_kbnode (included_keyblock);
|
|
|
++
|
|
|
++ /* To make sure that nothing strange happened we check the
|
|
|
++ * signature again now using our own key store. This also
|
|
|
++ * returns the keyblock which we use later on. */
|
|
|
++ if (!rc)
|
|
|
++ {
|
|
|
++ release_kbnode (keyblock);
|
|
|
++ keyblock = NULL;
|
|
|
++ rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
|
|
|
++ NULL, &is_expkey, &is_revkey, &pk, &keyblock);
|
|
|
++ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If the key isn't found, check for a preferred keyserver. Note
|
|
|
+@@ -2063,8 +2087,13 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ KEYSERVER_IMPORT_FLAG_QUICK);
|
|
|
+ glo_ctrl.in_auto_key_retrieve--;
|
|
|
+ if (!res)
|
|
|
+- rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
|
|
|
+- NULL, &is_expkey, &is_revkey, &pk);
|
|
|
++ {
|
|
|
++ release_kbnode (keyblock);
|
|
|
++ keyblock = NULL;
|
|
|
++ rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
|
|
|
++ NULL, &is_expkey, &is_revkey, &pk,
|
|
|
++ &keyblock);
|
|
|
++ }
|
|
|
+ else if (DBG_LOOKUP)
|
|
|
+ log_debug ("lookup via %s failed: %s\n", "Pref-KS",
|
|
|
+ gpg_strerror (res));
|
|
|
+@@ -2105,8 +2134,12 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ /* Fixme: If the fingerprint is embedded in the signature,
|
|
|
+ * compare it to the fingerprint of the returned key. */
|
|
|
+ if (!res)
|
|
|
+- rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
|
|
|
+- NULL, &is_expkey, &is_revkey, &pk);
|
|
|
++ {
|
|
|
++ release_kbnode (keyblock);
|
|
|
++ keyblock = NULL;
|
|
|
++ rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
|
|
|
++ NULL, &is_expkey, &is_revkey, &pk, &keyblock);
|
|
|
++ }
|
|
|
+ else if (DBG_LOOKUP)
|
|
|
+ log_debug ("lookup via %s failed: %s\n", "WKD", gpg_strerror (res));
|
|
|
+ }
|
|
|
+@@ -2136,8 +2169,13 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ KEYSERVER_IMPORT_FLAG_QUICK);
|
|
|
+ glo_ctrl.in_auto_key_retrieve--;
|
|
|
+ if (!res)
|
|
|
+- rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
|
|
|
+- NULL, &is_expkey, &is_revkey, &pk);
|
|
|
++ {
|
|
|
++ release_kbnode (keyblock);
|
|
|
++ keyblock = NULL;
|
|
|
++ rc = do_check_sig (c, node, extrahash, extrahashlen, NULL,
|
|
|
++ NULL, &is_expkey, &is_revkey, &pk,
|
|
|
++ &keyblock);
|
|
|
++ }
|
|
|
+ else if (DBG_LOOKUP)
|
|
|
+ log_debug ("lookup via %s failed: %s\n", "KS", gpg_strerror (res));
|
|
|
+ }
|
|
|
+@@ -2148,7 +2186,7 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ {
|
|
|
+ /* We have checked the signature and the result is either a good
|
|
|
+ * signature or a bad signature. Further examination follows. */
|
|
|
+- kbnode_t un, keyblock;
|
|
|
++ kbnode_t un;
|
|
|
+ int count = 0;
|
|
|
+ int keyblock_has_pk = 0; /* For failsafe check. */
|
|
|
+ int statno;
|
|
|
+@@ -2166,18 +2204,6 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ else
|
|
|
+ statno = STATUS_GOODSIG;
|
|
|
+
|
|
|
+- /* FIXME: We should have the public key in PK and thus the
|
|
|
+- * keyblock has already been fetched. Thus we could use the
|
|
|
+- * fingerprint or PK itself to lookup the entire keyblock. That
|
|
|
+- * would best be done with a cache. */
|
|
|
+- if (included_keyblock)
|
|
|
+- {
|
|
|
+- keyblock = included_keyblock;
|
|
|
+- included_keyblock = NULL;
|
|
|
+- }
|
|
|
+- else
|
|
|
+- keyblock = get_pubkeyblock_for_sig (c->ctrl, sig);
|
|
|
+-
|
|
|
+ snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ",
|
|
|
+ (ulong)sig->keyid[0], (ulong)sig->keyid[1]);
|
|
|
+
|
|
|
+@@ -2243,10 +2269,10 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ * contained in the keyring.*/
|
|
|
+ }
|
|
|
+
|
|
|
+- log_assert (mainpk);
|
|
|
+- if (!keyblock_has_pk)
|
|
|
++ if (!mainpk || !keyblock_has_pk)
|
|
|
+ {
|
|
|
+- log_error ("signature key lost from keyblock\n");
|
|
|
++ log_error ("signature key lost from keyblock (%p,%p,%d)\n",
|
|
|
++ keyblock, mainpk, keyblock_has_pk);
|
|
|
+ rc = gpg_error (GPG_ERR_INTERNAL);
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -2514,8 +2540,8 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|
|
+ log_error (_("Can't check signature: %s\n"), gpg_strerror (rc));
|
|
|
+ }
|
|
|
+
|
|
|
++ leave:
|
|
|
+ free_public_key (pk);
|
|
|
+- release_kbnode (included_keyblock);
|
|
|
+ xfree (issuer_fpr);
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+diff --git a/g10/packet.h b/g10/packet.h
|
|
|
+index 8aaf32d..669739a 100644
|
|
|
+--- a/g10/packet.h
|
|
|
++++ b/g10/packet.h
|
|
|
+@@ -899,7 +899,7 @@ gpg_error_t check_signature (ctrl_t ctrl,
|
|
|
+ const void *extrahash, size_t extrahashlen,
|
|
|
+ PKT_public_key *forced_pk,
|
|
|
+ u32 *r_expiredate, int *r_expired, int *r_revoked,
|
|
|
+- PKT_public_key **r_pk);
|
|
|
++ PKT_public_key **r_pk, kbnode_t *r_keyblock);
|
|
|
+
|
|
|
+
|
|
|
+ /*-- pubkey-enc.c --*/
|
|
|
+diff --git a/g10/sig-check.c b/g10/sig-check.c
|
|
|
+index 2272fa4..11f3e0c 100644
|
|
|
+--- a/g10/sig-check.c
|
|
|
++++ b/g10/sig-check.c
|
|
|
+@@ -138,6 +138,11 @@ check_key_verify_compliance (PKT_public_key *pk)
|
|
|
+ * If R_PK is not NULL, the public key is stored at that address if it
|
|
|
+ * was found; other wise NULL is stored.
|
|
|
+ *
|
|
|
++ * If R_KEYBLOCK is not NULL, the entire keyblock used to verify the
|
|
|
++ * signature is stored at that address. If no key was found or on
|
|
|
++ * some other errors NULL is stored there. The callers needs to
|
|
|
++ * release the keyblock using release_kbnode (kb).
|
|
|
++ *
|
|
|
+ * Returns 0 on success. An error code otherwise. */
|
|
|
+ gpg_error_t
|
|
|
+ check_signature (ctrl_t ctrl,
|
|
|
+@@ -145,7 +150,7 @@ check_signature (ctrl_t ctrl,
|
|
|
+ const void *extrahash, size_t extrahashlen,
|
|
|
+ PKT_public_key *forced_pk,
|
|
|
+ u32 *r_expiredate, int *r_expired, int *r_revoked,
|
|
|
+- PKT_public_key **r_pk)
|
|
|
++ PKT_public_key **r_pk, kbnode_t *r_keyblock)
|
|
|
+ {
|
|
|
+ int rc=0;
|
|
|
+ PKT_public_key *pk;
|
|
|
+@@ -158,6 +163,8 @@ check_signature (ctrl_t ctrl,
|
|
|
+ *r_revoked = 0;
|
|
|
+ if (r_pk)
|
|
|
+ *r_pk = NULL;
|
|
|
++ if (r_keyblock)
|
|
|
++ *r_keyblock = NULL;
|
|
|
+
|
|
|
+ pk = xtrycalloc (1, sizeof *pk);
|
|
|
+ if (!pk)
|
|
|
+@@ -188,7 +195,7 @@ check_signature (ctrl_t ctrl,
|
|
|
+ log_info(_("WARNING: signature digest conflict in message\n"));
|
|
|
+ rc = gpg_error (GPG_ERR_GENERAL);
|
|
|
+ }
|
|
|
+- else if (get_pubkey_for_sig (ctrl, pk, sig, forced_pk))
|
|
|
++ else if (get_pubkey_for_sig (ctrl, pk, sig, forced_pk, r_keyblock))
|
|
|
+ rc = gpg_error (GPG_ERR_NO_PUBKEY);
|
|
|
+ else if ((rc = check_key_verify_compliance (pk)))
|
|
|
+ ;/* Compliance failure. */
|
|
|
+@@ -786,9 +793,9 @@ check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
|
|
|
+ keyid_from_fingerprint (ctrl, pk->revkey[i].fpr, pk->revkey[i].fprlen,
|
|
|
+ keyid);
|
|
|
+
|
|
|
+- if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1])
|
|
|
+- /* The signature was generated by a designated revoker.
|
|
|
+- Verify the signature. */
|
|
|
++ /* If the signature was generated by a designated revoker
|
|
|
++ * verify the signature. */
|
|
|
++ if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1])
|
|
|
+ {
|
|
|
+ gcry_md_hd_t md;
|
|
|
+
|
|
|
+@@ -796,9 +803,9 @@ check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
|
|
|
+ BUG ();
|
|
|
+ hash_public_key(md,pk);
|
|
|
+ /* Note: check_signature only checks that the signature
|
|
|
+- is good. It does not fail if the key is revoked. */
|
|
|
++ * is good. It does not fail if the key is revoked. */
|
|
|
+ rc = check_signature (ctrl, sig, md, NULL, 0, NULL,
|
|
|
+- NULL, NULL, NULL, NULL);
|
|
|
++ NULL, NULL, NULL, NULL, NULL);
|
|
|
+ cache_sig_result(sig,rc);
|
|
|
+ gcry_md_close (md);
|
|
|
+ break;
|
|
|
+@@ -1003,7 +1010,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
|
|
|
+ if (IS_CERT (sig))
|
|
|
+ signer->req_usage = PUBKEY_USAGE_CERT;
|
|
|
+
|
|
|
+- rc = get_pubkey_for_sig (ctrl, signer, sig, NULL);
|
|
|
++ rc = get_pubkey_for_sig (ctrl, signer, sig, NULL, NULL);
|
|
|
+ if (rc)
|
|
|
+ {
|
|
|
+ xfree (signer);
|
|
|
+--
|
|
|
+2.40.0
|