summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--g10/mainproc.c130
-rw-r--r--g10/packet.h14
-rw-r--r--g10/sig-check.c58
3 files changed, 111 insertions, 91 deletions
diff --git a/g10/mainproc.c b/g10/mainproc.c
index f861a3ea2..716363f4c 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -839,12 +839,13 @@ proc_compressed (CTX c, PACKET *pkt)
/*
- * check the signature
- * Returns: 0 = valid signature or an error code
+ * Check the signature. If R_PK is not NULL a copy of the public key
+ * used to verify the signature will be stored tehre, or NULL if not
+ * found. Returns: 0 = valid signature or an error code
*/
static int
do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
- int *is_expkey, int *is_revkey)
+ int *is_expkey, int *is_revkey, PKT_public_key **r_pk)
{
PKT_signature *sig;
gcry_md_hd_t md = NULL;
@@ -852,6 +853,9 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
gcry_md_hd_t md_good = NULL;
int algo, rc;
+ if (r_pk)
+ *r_pk = NULL;
+
log_assert (node->pkt->pkttype == PKT_SIGNATURE);
if (is_selfsig)
*is_selfsig = 0;
@@ -926,14 +930,24 @@ 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 (sig, md, NULL, is_expkey, is_revkey, NULL);
+ rc = check_signature2 (sig, md, NULL, is_expkey, is_revkey, r_pk);
if (! rc)
md_good = md;
else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
{
- rc = check_signature2 (sig, md2, NULL, is_expkey, is_revkey, NULL);
- if (! rc)
- md_good = md2;
+ PKT_public_key *pk2;
+
+ rc = check_signature2 (sig, md2, NULL, is_expkey, is_revkey,
+ r_pk? &pk2 : NULL);
+ if (!rc)
+ {
+ md_good = md2;
+ if (r_pk)
+ {
+ free_public_key (*r_pk);
+ *r_pk = pk2;
+ }
+ }
}
if (md_good)
@@ -1096,7 +1110,7 @@ list_node (CTX c, kbnode_t node)
if (opt.check_sigs)
{
fflush (stdout);
- rc2 = do_check_sig (c, node, &is_selfsig, NULL, NULL);
+ rc2 = do_check_sig (c, node, &is_selfsig, NULL, NULL, NULL);
switch (gpg_err_code (rc2))
{
case 0: sigrc = '!'; break;
@@ -1603,10 +1617,8 @@ check_sig_and_print (CTX c, kbnode_t node)
int rc;
int is_expkey = 0;
int is_revkey = 0;
- char pkstrbuf[PUBKEY_STRING_SIZE];
char *issuer_fpr;
-
- *pkstrbuf = 0;
+ PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */
if (opt.skip_verify)
{
@@ -1754,7 +1766,7 @@ 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 );
+ rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
/* If the key isn't found, check for a preferred keyserver. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks)
@@ -1783,11 +1795,14 @@ check_sig_and_print (CTX c, kbnode_t node)
{
int res;
+ free_public_key (pk);
+ pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_keyid (c->ctrl, sig->keyid,spec);
glo_ctrl.in_auto_key_retrieve--;
if (!res)
- rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey );
+ rc = do_check_sig (c, node, NULL,
+ &is_expkey, &is_revkey, &pk);
free_keyserver_spec (spec);
if (!rc)
@@ -1815,12 +1830,14 @@ check_sig_and_print (CTX c, kbnode_t node)
spec = parse_keyserver_uri (uri, 1);
if (spec)
{
+ free_public_key (pk);
+ pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_keyid (c->ctrl, sig->keyid, spec);
glo_ctrl.in_auto_key_retrieve--;
free_keyserver_spec (spec);
if (!res)
- rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
+ rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
}
}
}
@@ -1844,11 +1861,13 @@ check_sig_and_print (CTX c, kbnode_t node)
if (p && n == 21 && p[0] == 4)
{
/* v4 packet with a SHA-1 fingerprint. */
+ free_public_key (pk);
+ pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_fprint (c->ctrl, p+1, n-1, opt.keyserver);
glo_ctrl.in_auto_key_retrieve--;
if (!res)
- rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
+ rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
}
}
@@ -1862,13 +1881,15 @@ check_sig_and_print (CTX c, kbnode_t node)
{
int res;
+ free_public_key (pk);
+ pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_wkd (c->ctrl, sig->signers_uid, NULL, NULL);
glo_ctrl.in_auto_key_retrieve--;
/* 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 );
+ rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
}
/* If the above methods did't work, our next try is to use a
@@ -1879,11 +1900,13 @@ check_sig_and_print (CTX c, kbnode_t node)
{
int res;
+ free_public_key (pk);
+ pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver );
glo_ctrl.in_auto_key_retrieve--;
if (!res)
- rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
+ rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
}
if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE)
@@ -1892,7 +1915,7 @@ check_sig_and_print (CTX c, kbnode_t node)
int count = 0;
int statno;
char keyid_str[50];
- PKT_public_key *pk = NULL;
+ PKT_public_key *mainpk = NULL;
if (rc)
statno = STATUS_BADSIG;
@@ -1905,6 +1928,10 @@ 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
+ * keyboock 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 (sig->keyid);
snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ",
@@ -1918,7 +1945,7 @@ check_sig_and_print (CTX c, kbnode_t node)
if (un->pkt->pkttype==PKT_PUBLIC_KEY)
{
- pk=un->pkt->pkt.public_key;
+ mainpk = un->pkt->pkt.public_key;
continue;
}
if (un->pkt->pkttype != PKT_USER_ID)
@@ -1935,7 +1962,7 @@ check_sig_and_print (CTX c, kbnode_t node)
if (un->pkt->pkt.user_id->attrib_data)
continue;
- log_assert (pk);
+ log_assert (mainpk);
/* Since this is just informational, don't actually ask the
user to update any trust information. (Note: we register
@@ -1943,7 +1970,8 @@ check_sig_and_print (CTX c, kbnode_t node)
does not print a LF we need to compute the validity
before calling that function. */
if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY))
- valid = get_validity (c->ctrl, pk, un->pkt->pkt.user_id, sig, 0);
+ valid = get_validity (c->ctrl, mainpk, un->pkt->pkt.user_id,
+ sig, 0);
else
valid = 0; /* Not used. */
@@ -1956,13 +1984,11 @@ check_sig_and_print (CTX c, kbnode_t node)
else
log_printf ("\n");
- /* Get a string description of the algo for informational
- output we want to print later. It is convenient to do it
- here because we already have the right public key. */
- pubkey_string (pk, pkstrbuf, sizeof pkstrbuf);
count++;
}
+ log_assert (mainpk);
+
/* In case we did not found a valid valid textual userid above
we print the first user id packet or a "[?]" instead along
with the "Good|Expired|Bad signature" line. */
@@ -2019,13 +2045,13 @@ check_sig_and_print (CTX c, kbnode_t node)
/* If this user id has attribute data, print that. */
if (un->pkt->pkt.user_id->attrib_data)
{
- dump_attribs (un->pkt->pkt.user_id, pk);
+ dump_attribs (un->pkt->pkt.user_id, mainpk);
if (opt.verify_options&VERIFY_SHOW_PHOTOS)
show_photos (c->ctrl,
un->pkt->pkt.user_id->attribs,
un->pkt->pkt.user_id->numattribs,
- pk ,un->pkt->pkt.user_id);
+ mainpk ,un->pkt->pkt.user_id);
}
p = utf8_to_native (un->pkt->pkt.user_id->name,
@@ -2046,7 +2072,7 @@ check_sig_and_print (CTX c, kbnode_t node)
actually ask the user to update any trust
information. */
valid = (trust_value_to_string
- (get_validity (c->ctrl, pk,
+ (get_validity (c->ctrl, mainpk,
un->pkt->pkt.user_id, sig, 0)));
log_printf (" [%s]\n",valid);
}
@@ -2054,7 +2080,6 @@ check_sig_and_print (CTX c, kbnode_t node)
log_printf ("\n");
}
}
- release_kbnode( keyblock );
/* For good signatures print notation data. */
if (!rc)
@@ -2081,16 +2106,14 @@ check_sig_and_print (CTX c, kbnode_t node)
/* For good signatures print the VALIDSIG status line. */
if (!rc && is_status_enabled ())
{
- PKT_public_key *vpk = xmalloc_clear (sizeof *vpk);
-
- if (!get_pubkey (vpk, sig->keyid))
+ if (pk)
{
byte array[MAX_FINGERPRINT_LEN], *p;
char buf[MAX_FINGERPRINT_LEN*4+90], *bufp;
size_t i, n;
bufp = buf;
- fingerprint_from_pk (vpk, array, &n);
+ fingerprint_from_pk (pk, array, &n);
p = array;
for(i=0; i < n ; i++, p++, bufp += 2)
sprintf (bufp, "%02X", *p );
@@ -2103,29 +2126,13 @@ check_sig_and_print (CTX c, kbnode_t node)
sig->version,sig->pubkey_algo,sig->digest_algo,
sig->sig_class);
bufp = bufp + strlen (bufp);
- if (!vpk->flags.primary)
- {
- u32 akid[2];
-
- akid[0] = vpk->main_keyid[0];
- akid[1] = vpk->main_keyid[1];
- free_public_key (vpk);
- vpk = xmalloc_clear (sizeof *vpk);
- if (get_pubkey (vpk, akid))
- {
- /* Impossible error, we simply return a zeroed out fpr */
- n = MAX_FINGERPRINT_LEN < 20? MAX_FINGERPRINT_LEN : 20;
- memset (array, 0, n);
- }
- else
- fingerprint_from_pk( vpk, array, &n );
- }
+ if (!pk->flags.primary)
+ fingerprint_from_pk (mainpk, array, &n);
p = array;
for (i=0; i < n ; i++, p++, bufp += 2)
sprintf(bufp, "%02X", *p );
write_status_text (STATUS_VALIDSIG, buf);
}
- free_public_key (vpk);
}
/* For good signatures compute and print the trust information.
@@ -2148,12 +2155,20 @@ check_sig_and_print (CTX c, kbnode_t node)
log_info (_("Signature expires %s\n"), asctimestamp(sig->expiredate));
if (opt.verbose)
- log_info (_("%s signature, digest algorithm %s%s%s\n"),
- sig->sig_class==0x00?_("binary"):
- sig->sig_class==0x01?_("textmode"):_("unknown"),
- gcry_md_algo_name (sig->digest_algo),
- *pkstrbuf?_(", key algorithm "):"",
- pkstrbuf);
+ {
+ char pkstrbuf[PUBKEY_STRING_SIZE];
+
+ if (pk)
+ pubkey_string (pk, pkstrbuf, sizeof pkstrbuf);
+ else
+ *pkstrbuf = 0;
+
+ log_info (_("%s signature, digest algorithm %s%s%s\n"),
+ sig->sig_class==0x00?_("binary"):
+ sig->sig_class==0x01?_("textmode"):_("unknown"),
+ gcry_md_algo_name (sig->digest_algo),
+ *pkstrbuf?_(", key algorithm "):"", pkstrbuf);
+ }
/* Print final warnings. */
if (!rc && !c->signed_data.used)
@@ -2194,6 +2209,7 @@ check_sig_and_print (CTX c, kbnode_t node)
}
}
+ release_kbnode( keyblock );
if (rc)
g10_errors_seen = 1;
if (opt.batch && rc)
diff --git a/g10/packet.h b/g10/packet.h
index 9c9e909d8..60af2a233 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -802,13 +802,13 @@ int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
int check_signature (PKT_signature *sig, gcry_md_hd_t digest);
/* Check a signature. Looks up the public key from the key db. (If
- RET_PK is not NULL, it is returned in *RET_PK.) DIGEST contains a
- valid hash context that already includes the signed data. This
- function adds the relevant meta-data to the hash before finalizing
- it and verifying the signature. */
-int check_signature2 (PKT_signature *sig, gcry_md_hd_t digest,
- u32 *r_expiredate, int *r_expired, int *r_revoked,
- PKT_public_key *ret_pk);
+ * R_PK is not NULL, it is stored at RET_PK.) DIGEST contains a
+ * valid hash context that already includes the signed data. This
+ * function adds the relevant meta-data to the hash before finalizing
+ * it and verifying the signature. */
+gpg_error_t check_signature2 (PKT_signature *sig, gcry_md_hd_t digest,
+ u32 *r_expiredate, int *r_expired, int *r_revoked,
+ PKT_public_key **r_pk);
/*-- pubkey-enc.c --*/
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 334add785..4d39e0925 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -84,23 +84,29 @@ check_signature (PKT_signature *sig, gcry_md_hd_t digest)
* revoked (0 otherwise). Note: PK being revoked does not cause this
* function to fail.
*
- * If PK is not NULL, the public key is saved in *PK on success.
+ * If R_PK is not NULL, the public key is stored at that address if it
+ * was found; other wise NULL is stored.
*
* Returns 0 on success. An error code otherwise. */
-int
+gpg_error_t
check_signature2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
- int *r_expired, int *r_revoked, PKT_public_key *pk )
+ int *r_expired, int *r_revoked, PKT_public_key **r_pk)
{
int rc=0;
- int pk_internal;
+ PKT_public_key *pk;
- if (pk)
- pk_internal = 0;
- else
- {
- pk_internal = 1;
- pk = xmalloc_clear( sizeof *pk );
- }
+ if (r_expiredate)
+ *r_expiredate = 0;
+ if (r_expired)
+ *r_expired = 0;
+ if (r_revoked)
+ *r_revoked = 0;
+ if (r_pk)
+ *r_pk = NULL;
+
+ pk = xtrycalloc (1, sizeof *pk);
+ if (!pk)
+ return gpg_error_from_syserror ();
if ( (rc=openpgp_md_test_algo(sig->digest_algo)) )
; /* We don't have this digest. */
@@ -114,14 +120,14 @@ check_signature2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
header is missing or does not match the actual sig. */
log_info(_("WARNING: signature digest conflict in message\n"));
- rc = GPG_ERR_GENERAL;
+ rc = gpg_error (GPG_ERR_GENERAL);
}
else if( get_pubkey( pk, sig->keyid ) )
- rc = GPG_ERR_NO_PUBKEY;
+ rc = gpg_error (GPG_ERR_NO_PUBKEY);
else if(!pk->flags.valid)
{
/* You cannot have a good sig from an invalid key. */
- rc = GPG_ERR_BAD_PUBKEY;
+ rc = gpg_error (GPG_ERR_BAD_PUBKEY);
}
else
{
@@ -136,7 +142,7 @@ check_signature2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
them as their own. The attacker couldn't actually use the
subkey, but they could try and claim ownership of any
signatures issued by it. */
- if(rc==0 && !pk->flags.primary && pk->flags.backsig < 2)
+ if (!rc && !pk->flags.primary && pk->flags.backsig < 2)
{
if (!pk->flags.backsig)
{
@@ -148,27 +154,17 @@ check_signature2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
error. TODO: change the default to require this
after more keys have backsigs. */
if(opt.flags.require_cross_cert)
- rc = GPG_ERR_GENERAL;
+ rc = gpg_error (GPG_ERR_GENERAL);
}
else if(pk->flags.backsig == 1)
{
log_info(_("WARNING: signing subkey %s has an invalid"
" cross-certification\n"),keystr_from_pk(pk));
- rc = GPG_ERR_GENERAL;
+ rc = gpg_error (GPG_ERR_GENERAL);
}
}
}
- if (pk_internal || rc)
- {
- release_public_key_parts (pk);
- if (pk_internal)
- xfree (pk);
- else
- /* Be very sure that the caller doesn't try to use *PK. */
- memset (pk, 0, sizeof (*pk));
- }
-
if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
/* This signature id works best with DLP algorithms because
* they use a random parameter for every signature. Instead of
@@ -235,6 +231,14 @@ check_signature2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
xfree (buffer);
}
+ if (r_pk)
+ *r_pk = pk;
+ else
+ {
+ release_public_key_parts (pk);
+ xfree (pk);
+ }
+
return rc;
}