diff options
Diffstat (limited to 'g10/mainproc.c')
-rw-r--r-- | g10/mainproc.c | 72 |
1 files changed, 61 insertions, 11 deletions
diff --git a/g10/mainproc.c b/g10/mainproc.c index e9e886f59..07366b068 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1,6 +1,7 @@ /* mainproc.c - handle packets * Copyright (C) 1998-2009 Free Software Foundation, Inc. * Copyright (C) 2013-2014 Werner Koch + * Copyright (C) 2020 g10 Code GmbH * * This file is part of GnuPG. * @@ -956,10 +957,13 @@ proc_compressed (CTX c, PACKET *pkt) /* * Check the signature. If R_PK is not NULL a copy of the public key * used to verify the signature will be stored there, or NULL if not - * found. Returns: 0 = valid signature or an error code + * 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 */ static int -do_check_sig (CTX c, kbnode_t node, int *is_selfsig, +do_check_sig (CTX c, kbnode_t node, + PKT_public_key *forced_pk, int *is_selfsig, int *is_expkey, int *is_revkey, PKT_public_key **r_pk) { PKT_signature *sig; @@ -1045,14 +1049,18 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig, /* We only get here if we are checking the signature of a binary (0x00) or text document (0x01). */ - rc = check_signature2 (c->ctrl, sig, md, NULL, is_expkey, is_revkey, r_pk); + rc = check_signature2 (c->ctrl, sig, md, + forced_pk, + NULL, is_expkey, is_revkey, r_pk); if (! rc) md_good = md; else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2) { PKT_public_key *pk2; - rc = check_signature2 (c->ctrl, sig, md2, NULL, is_expkey, is_revkey, + rc = check_signature2 (c->ctrl, sig, md2, + forced_pk, + NULL, is_expkey, is_revkey, r_pk? &pk2 : NULL); if (!rc) { @@ -1215,7 +1223,7 @@ list_node (CTX c, kbnode_t node) if (opt.check_sigs) { fflush (stdout); - rc2 = do_check_sig (c, node, &is_selfsig, NULL, NULL, NULL); + rc2 = do_check_sig (c, node, NULL, &is_selfsig, NULL, NULL, NULL); switch (gpg_err_code (rc2)) { case 0: sigrc = '!'; break; @@ -1746,6 +1754,7 @@ check_sig_and_print (CTX c, kbnode_t node) int is_revkey = 0; char *issuer_fpr = NULL; PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */ + kbnode_t included_keyblock = NULL; if (opt.skip_verify) { @@ -1894,7 +1903,39 @@ check_sig_and_print (CTX c, kbnode_t node) if (sig->signers_uid) log_info (_(" issuer \"%s\"\n"), sig->signers_uid); - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, NULL, NULL, &is_expkey, &is_revkey, &pk); + + /* If the key is not found but the signaure includes a key bnlock we + * import that key block and trry again. We keep this key block + * only if the signature verifies. */ + /* FIXME: Shall we add an option to disable it or use it only if + * --auto-key-retriueve is set? */ + if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY + && sig->flags.key_block) + /* && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)) */ + { + PKT_public_key *included_pk; + const byte *kblock; + size_t kblock_len; + + included_pk = xcalloc (1, sizeof *included_pk); + kblock = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_BLOCK, &kblock_len); + if (kblock && kblock_len > 1 + && !get_pubkey_from_buffer (c->ctrl, included_pk, + kblock+1, kblock_len-1, + sig->keyid, &included_keyblock)) + { + rc = do_check_sig (c, node, included_pk, + NULL, &is_expkey, &is_revkey, &pk); + if (!rc) + { + /* The keyblock has been verified, we now import it. */ + rc = import_included_key_block (c->ctrl, included_keyblock); + } + + } + free_public_key (included_pk); + } /* If the key isn't found, check for a preferred keyserver. Note * that this is only done if honor-keyserver-url has been set. We @@ -1940,7 +1981,7 @@ check_sig_and_print (CTX c, kbnode_t node) glo_ctrl.in_auto_key_retrieve--; if (!res) rc = do_check_sig (c, node, NULL, - &is_expkey, &is_revkey, &pk); + NULL, &is_expkey, &is_revkey, &pk); else if (DBG_LOOKUP) log_debug ("lookup via %s failed: %s\n", "Pref-KS", gpg_strerror (res)); @@ -1980,7 +2021,7 @@ 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, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, NULL, NULL, &is_expkey, &is_revkey, &pk); else if (DBG_LOOKUP) log_debug ("lookup via %s failed: %s\n", "WKD", gpg_strerror (res)); } @@ -2014,7 +2055,8 @@ check_sig_and_print (CTX c, kbnode_t node) glo_ctrl.in_auto_key_retrieve--; free_keyserver_spec (spec); if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, NULL, + NULL, &is_expkey, &is_revkey, &pk); else if (DBG_LOOKUP) log_debug ("lookup via %s failed: %s\n", "PKA", gpg_strerror (res)); @@ -2046,7 +2088,8 @@ check_sig_and_print (CTX c, kbnode_t node) res = keyserver_import_fprint (c->ctrl, p, n, opt.keyserver, 1); glo_ctrl.in_auto_key_retrieve--; if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, NULL, + NULL, &is_expkey, &is_revkey, &pk); else if (DBG_LOOKUP) log_debug ("lookup via %s failed: %s\n", "KS", gpg_strerror (res)); } @@ -2075,7 +2118,13 @@ check_sig_and_print (CTX c, kbnode_t node) * 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. */ - keyblock = get_pubkeyblock_for_sig (c->ctrl, sig); + 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]); @@ -2388,6 +2437,7 @@ check_sig_and_print (CTX c, kbnode_t node) } free_public_key (pk); + release_kbnode (included_keyblock); xfree (issuer_fpr); return rc; } |