[git] GnuPG - branch, neal/issue2236, created. gnupg-2.1.11-34-gbff529a
by Neal H. Walfield
cvs at cvs.gnupg.org
Tue Feb 16 15:49:32 CET 2016
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".
The branch, neal/issue2236 has been created
at bff529a3ce936a5154bcd4f00abf83a2df3e758f (commit)
- Log -----------------------------------------------------------------
commit bff529a3ce936a5154bcd4f00abf83a2df3e758f
Author: Neal H. Walfield <neal at g10code.com>
Date: Tue Feb 16 15:47:30 2016 +0100
gpg: Reorder signatures, if appropriate.
XXX
--
Signed-off-by: Neal H. Walfield <neal at g10code.com>
GnuPG-bug-id: 2236
diff --git a/g10/gpg.c b/g10/gpg.c
index 330d5a3..458bba0 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -165,6 +165,7 @@ enum cmd_and_opt_values
aPasswd,
aServer,
aTOFUPolicy,
+ aCheckKey,
oTextmode,
oNoTextmode,
@@ -487,6 +488,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aServer, "server", N_("run in server mode")),
ARGPARSE_c (aTOFUPolicy, "tofu-policy",
N_("|VALUE|set the TOFU policy for a key")),
+ ARGPARSE_c (aCheckKey, "check-key", N_("Check a key")),
ARGPARSE_group (301, N_("@\nOptions:\n ")),
@@ -2464,6 +2466,10 @@ main (int argc, char **argv)
set_cmd (&cmd, pargs.r_opt);
break;
+ case aCheckKey:
+ set_cmd (&cmd, pargs.r_opt);
+ break;
+
case oArmor: opt.armor = 1; opt.no_armor=0; break;
case oOutput: opt.outfile = pargs.r.ret_str; break;
case oMaxOutput: opt.max_output = pargs.r.ret_ulong; break;
@@ -4589,6 +4595,31 @@ main (int argc, char **argv)
#endif /*USE_TOFU*/
break;
+ case aCheckKey:
+ {
+ int i;
+
+ if (argc < 1)
+ wrong_args ("--check-key KEYID...");
+
+ for (i = 0; i < argc; i ++)
+ {
+ kbnode_t kb;
+
+ rc = get_pubkey_byname (ctrl, NULL, NULL, argv[i], &kb,
+ NULL, 1, 1);
+ if (rc)
+ {
+ log_error (_("looking up key '%s': %s\n"),
+ argv[i], gpg_strerror (rc));
+ g10_exit (1);
+ }
+
+ keyblock_check_sigs (kb, 0);
+ }
+ }
+ break;
+
case aListPackets:
opt.list_packets=2;
default:
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 19ddf29..410817f 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1238,54 +1238,6 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
-/*
- * There are some keys out (due to a bug in gnupg), where the sequence
- * of the packets is wrong. This function fixes that.
- * Returns: true if the keyblock has been fixed.
- *
- * Note: This function does not work if there is more than one user ID.
- */
-static int
-fix_key_signature_order (KBNODE keyblock)
-{
- KBNODE node, last, subkey;
- int fixed = 0;
-
- /* Locate key signatures of class 0x10..0x13 behind sub key packets. */
- for (subkey = last = NULL, node = keyblock; node;
- last = node, node = node->next)
- {
- switch (node->pkt->pkttype)
- {
- case PKT_PUBLIC_SUBKEY:
- case PKT_SECRET_SUBKEY:
- if (!subkey)
- subkey = last; /* Actually it is the one before the subkey. */
- break;
- case PKT_SIGNATURE:
- if (subkey)
- {
- PKT_signature *sig = node->pkt->pkt.signature;
- if (sig->sig_class >= 0x10 && sig->sig_class <= 0x13)
- {
- log_info (_("moving a key signature to the correct place\n"));
- last->next = node->next;
- node->next = subkey->next;
- subkey->next = node;
- node = last;
- fixed = 1;
- }
- }
- break;
- default:
- break;
- }
- }
-
- return fixed;
-}
-
-
/* Fix various problems in the keyblock. Returns true if the keyblock
was changed. Note that a pointer to the keyblock must be given and
the function may change it (i.e. replacing the first node). */
@@ -1294,10 +1246,10 @@ fix_keyblock (kbnode_t *keyblockp)
{
int changed = 0;
- if (fix_key_signature_order (*keyblockp))
- changed++;
if (collapse_uids (keyblockp))
changed++;
+ if (keyblock_check_sigs (*keyblockp, 0))
+ changed++;
reorder_keyblock (*keyblockp);
/* If we modified the keyblock, make sure the flags are right. */
if (changed)
@@ -1370,7 +1322,7 @@ enum cmdids
cmdSHOWPREF,
cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST,
cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD,
- cmdCLEAN, cmdMINIMIZE, cmdGRIP, cmdNOP
+ cmdCLEAN, cmdMINIMIZE, cmdGRIP, cmdCHECKKEY, cmdNOP
};
static struct
@@ -1465,6 +1417,8 @@ static struct
N_("compact unusable user IDs and remove unusable signatures from key")},
{ "minimize", cmdMINIMIZE, KEYEDIT_NOT_SK,
N_("compact unusable user IDs and remove all signatures from key")},
+ { "checkkey", cmdCHECKKEY, KEYEDIT_NOT_SK,
+ N_("check the key")},
{ NULL, cmdNONE, 0, NULL}
};
@@ -2280,6 +2234,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
redisplay = modified = 1;
break;
+ case cmdCHECKKEY:
+ if (keyblock_check_sigs (keyblock, 0))
+ redisplay = modified = 1;
+ break;
+
case cmdQUIT:
if (have_commands)
goto leave;
diff --git a/g10/main.h b/g10/main.h
index 863afa9..bfa501d 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -263,6 +263,15 @@ int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
PKT_public_key *ret_pk, int *is_selfsig,
u32 *r_expiredate, int *r_expired );
+int check_signature_end (PKT_public_key *pk, PKT_signature *sig,
+ gcry_md_hd_t digest,
+ int *r_expired, int *r_revoked,
+ PKT_public_key *ret_pk);
+int check_signature_only_end (PKT_public_key *pk, PKT_signature *sig,
+ gcry_md_hd_t digest);
+void hash_uid_node( KBNODE unode, gcry_md_hd_t md, PKT_signature *sig );
+
+
/*-- delkey.c --*/
gpg_error_t delete_keys (strlist_t names, int secret, int allow_both);
diff --git a/g10/packet.h b/g10/packet.h
index 16524f8..f8f46d5 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -651,6 +651,8 @@ 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);
+/* Checks KB's signatures and possible reorders them. */
+int keyblock_check_sigs (KBNODE kb, int only_selfsigs);
/*-- pubkey-enc.c --*/
gpg_error_t get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek);
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 292adb9..d298765 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -34,11 +34,7 @@
#include "i18n.h"
#include "options.h"
#include "pkglue.h"
-
-static int check_signature_end (PKT_public_key *pk, PKT_signature *sig,
- gcry_md_hd_t digest,
- int *r_expired, int *r_revoked,
- PKT_public_key *ret_pk);
+#include "host2net.h"
/* Check a signature. This is shorthand for check_signature2 with
the unnamed arguments passed as NULL. */
@@ -371,19 +367,34 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
* If RET_PK is not NULL, PK is copied into RET_PK on success.
*
* Returns 0 on success. An error code other. */
-static int
+int
check_signature_end (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest,
int *r_expired, int *r_revoked, PKT_public_key *ret_pk)
{
- gcry_mpi_t result = NULL;
int rc = 0;
- const struct weakhash *weak;
if ((rc = check_signature_metadata_validity (pk, sig,
r_expired, r_revoked)))
return rc;
+ if ((rc = check_signature_only_end (pk, sig, digest)))
+ return rc;
+
+ if(!rc && ret_pk)
+ copy_public_key(ret_pk,pk);
+
+ return rc;
+}
+
+int
+check_signature_only_end (PKT_public_key *pk, PKT_signature *sig,
+ gcry_md_hd_t digest)
+{
+ gcry_mpi_t result = NULL;
+ int rc = 0;
+ const struct weakhash *weak;
+
if (!opt.flags.allow_weak_digest_algos)
for (weak = opt.weak_digests; weak; weak = weak->next)
if (sig->digest_algo == weak->algo)
@@ -453,16 +464,13 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
rc = GPG_ERR_BAD_SIGNATURE;
}
- if(!rc && ret_pk)
- copy_public_key(ret_pk,pk);
-
return rc;
}
/* Add a uid node to a hash context. See section 5.2.4, paragraph 4
of RFC 4880. */
-static void
+void
hash_uid_node( KBNODE unode, gcry_md_hd_t md, PKT_signature *sig )
{
PKT_user_id *uid = unode->pkt->pkt.user_id;
@@ -893,3 +901,661 @@ check_key_signature2 (kbnode_t root, kbnode_t node, PKT_public_key *check_pk,
return rc;
}
+
+
+void
+sig_print (estream_t fp,
+ PKT_public_key *pk, PKT_signature *sig, gpg_error_t sig_status,
+ int print_without_key, int extended)
+{
+ int sigrc;
+ int is_rev = sig->sig_class == 0x30;
+
+ switch (gpg_err_code (sig_status))
+ {
+ case GPG_ERR_NO_VALUE: /* Unknown. */
+ sigrc = ' ';
+ break;
+ case 0:
+ sigrc = '!';
+ break;
+ case GPG_ERR_BAD_SIGNATURE:
+ sigrc = '-';
+ break;
+ case GPG_ERR_NO_PUBKEY:
+ case GPG_ERR_UNUSABLE_PUBKEY:
+ sigrc = '?';
+ break;
+ default:
+ sigrc = '%';
+ break;
+ }
+ if (sigrc != '?' || print_without_key)
+ {
+ es_fprintf (fp, "%s%c%c %c%c%c%c%c%c %s %s",
+ is_rev ? "rev" : "sig", sigrc,
+ (sig->sig_class - 0x10 > 0 &&
+ sig->sig_class - 0x10 <
+ 4) ? '0' + sig->sig_class - 0x10 : ' ',
+ sig->flags.exportable ? ' ' : 'L',
+ sig->flags.revocable ? ' ' : 'R',
+ sig->flags.policy_url ? 'P' : ' ',
+ sig->flags.notation ? 'N' : ' ',
+ sig->flags.expired ? 'X' : ' ',
+ (sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
+ 0) ? '0' +
+ sig->trust_depth : ' ',
+ keystr (sig->keyid),
+ datestr_from_sig (sig));
+ if ((opt.list_options & LIST_SHOW_SIG_EXPIRE) || extended )
+ es_fprintf (fp, " %s", expirestr_from_sig (sig));
+ es_fprintf (fp, " ");
+ if (sigrc == '%')
+ es_fprintf (fp, "[%s] ", gpg_strerror (sig_status));
+ else if (sigrc == '?')
+ ;
+ else
+ {
+ size_t n;
+ char *p = get_user_id (sig->keyid, &n);
+ tty_print_utf8_string2 (fp, p, n,
+ opt.screen_columns - keystrlen () - 26 -
+ ((opt.
+ list_options & LIST_SHOW_SIG_EXPIRE) ? 11
+ : 0));
+ xfree (p);
+ }
+ es_fprintf (fp, "\n");
+
+ if (sig->flags.policy_url
+ && ((opt.list_options & LIST_SHOW_POLICY_URLS) || extended))
+ /* XXX: Change to print to FP. */
+ show_policy_url (sig, 3, 0);
+
+ if (sig->flags.notation
+ && ((opt.list_options & LIST_SHOW_NOTATIONS) || extended))
+ /* XXX: Change to print to FP. */
+ show_notation (sig, 3, 0,
+ ((opt.
+ list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) +
+ ((opt.
+ list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0));
+
+ if (sig->flags.pref_ks
+ && ((opt.list_options & LIST_SHOW_KEYSERVER_URLS) || extended))
+ /* XXX: Change to print to FP. */
+ show_keyserver_url (sig, 3, 0);
+
+ if (extended)
+ {
+ const unsigned char *s;
+
+ s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL);
+ if (s && *s)
+ es_fprintf (fp, " [primary]\n");
+
+ s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ if (s && buf32_to_u32 (s))
+ es_fprintf (fp, " [expires: %s]\n",
+ isotimestamp (pk->timestamp + buf32_to_u32 (s)));
+ }
+ }
+}
+
+
+char *
+sig_format (PKT_public_key *pk, PKT_signature *sig, gpg_error_t sig_status,
+ int print_without_key, int extended)
+{
+ estream_t fp;
+ char *s;
+
+ fp = es_fopenmem (0, "rw,samethread");
+ if (! fp)
+ log_fatal ("Error creating memory stream\n");
+
+ sig_print (fp, pk, sig, sig_status, print_without_key, extended);
+
+ es_fputc (0, fp);
+ if (es_fclose_snatch (fp, (void **) &s, NULL))
+ log_fatal ("error snatching memory stream\n");
+
+ if (s[strlen (s) - 1] == '\n')
+ s[strlen (s) - 1] = '\0';
+
+ return s;
+}
+
+/* Order two signatures. The actual ordering isn't important. Our
+ goal is to ensure that identical signatures occur together. */
+static int
+sig_comparison (const void *av, const void *bv)
+{
+ const KBNODE an = *(const KBNODE *) av;
+ const KBNODE bn = *(const KBNODE *) bv;
+ const PKT_signature *a;
+ const PKT_signature *b;
+ int ndataa;
+ int ndatab;
+ int i;
+
+ assert (an->pkt->pkttype == PKT_SIGNATURE);
+ assert (bn->pkt->pkttype == PKT_SIGNATURE);
+
+ a = an->pkt->pkt.signature;
+ b = bn->pkt->pkt.signature;
+
+ if (a->digest_algo < b->digest_algo)
+ return -1;
+ if (a->digest_algo > b->digest_algo)
+ return 1;
+
+ ndataa = pubkey_get_nsig (a->pubkey_algo);
+ ndatab = pubkey_get_nsig (a->pubkey_algo);
+ assert (ndataa == ndatab);
+
+ for (i = 0; i < ndataa; i ++)
+ {
+ int c = gcry_mpi_cmp (a->data[i], b->data[i]);
+ if (c != 0)
+ return c;
+ }
+
+ /* Okay, they are equal. */
+ return 0;
+}
+
+/* Check that a keyblock is okay and possibly repair some damage.
+ Concretely:
+
+ - Detect duplicate signatures and remove them.
+
+ - Detect out of order signatures and relocate them (e.g., a sig
+ over a user id located under a subkey)
+
+ Note: this function does not remove signatures that don't belong or
+ components that are not signed! (Although it would be trivial to
+ do.)
+
+ If ONLY_SELFSIGS is true, then this function only reorders self
+ signatures (it still checks all signatures for duplicates,
+ however).
+
+ Returns 1 if the keyblock was modified, 0 otherwise.
+ */
+int
+keyblock_check_sigs (KBNODE kb, int only_selfsigs)
+{
+ gpg_error_t err;
+ PKT_public_key *pk;
+ u32 pk_keyid[2];
+ KBNODE n, n_next, *n_prevp, n2;
+ char *pending_desc = NULL;
+ PKT_public_key *issuer;
+ KBNODE current_component = NULL;
+ int dups = 0;
+ int missing_issuer = 0;
+ int reordered = 0;
+ int bad_signature = 0;
+ int modified = 0;
+
+ assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
+ pk = kb->pkt->pkt.public_key;
+ keyid_from_pk (pk, pk_keyid);
+
+ /* First we look for duplicates. */
+ {
+ int nsigs = 0;
+ KBNODE *sigs;
+ int i;
+ int last_i;
+
+ /* Count the sigs. */
+ for (n = kb; n; n = n->next)
+ if (is_deleted_kbnode (n))
+ continue;
+ else if (n->pkt->pkttype == PKT_SIGNATURE)
+ nsigs ++;
+
+ /* Add them all to the SIGS array. */
+ sigs = xmalloc_clear (sizeof (*sigs) * nsigs);
+
+ i = 0;
+ for (n = kb; n; n = n->next)
+ {
+ if (is_deleted_kbnode (n))
+ continue;
+
+ if (n->pkt->pkttype != PKT_SIGNATURE)
+ continue;
+
+ sigs[i] = n;
+ i ++;
+ }
+ assert (i == nsigs);
+
+ qsort (sigs, nsigs, sizeof (sigs[0]), sig_comparison);
+
+ last_i = 0;
+ for (i = 1; i < nsigs; i ++)
+ {
+ assert (sigs[last_i]);
+ assert (sigs[last_i]->pkt->pkttype == PKT_SIGNATURE);
+ assert (sigs[i]);
+ assert (sigs[i]->pkt->pkttype == PKT_SIGNATURE);
+
+ if (sig_comparison (&sigs[last_i], &sigs[i]) == 0)
+ /* They are the same. Kill the latter. */
+ {
+ if (opt.verbose)
+ {
+ PKT_signature *sig = sigs[i]->pkt->pkt.signature;
+
+ log_info (_("Signature appears multiple times, deleting duplicate:\n"));
+ log_info (" sig: class 0x%x, issuer: %s, timestamp: %s (%lld), digest: %02x %02x\n",
+ sig->sig_class, keystr (sig->keyid),
+ isotimestamp (sig->timestamp),
+ (long long) sig->timestamp,
+ sig->digest_start[0], sig->digest_start[1]);
+ }
+
+ /* Remove sigs[i] from the keyblock. */
+ {
+ KBNODE z, *prevp;
+ int to_kill = i;
+
+ for (prevp = &kb, z = kb; z; prevp = &z->next, z = z->next)
+ if (z == sigs[to_kill])
+ break;
+
+ *prevp = sigs[to_kill]->next;
+
+ sigs[to_kill]->next = NULL;
+ release_kbnode (sigs[to_kill]);
+ sigs[to_kill] = NULL;
+
+ dups ++;
+ modified = 1;
+ }
+ }
+ else
+ last_i = i;
+ }
+
+ if (dups)
+ log_info (_("Ignored %d duplicate signatures (total: %d).\n"),
+ dups, nsigs);
+
+ xfree (sigs);
+ }
+
+ /* Make sure the sigs occur after the component (public key, subkey,
+ user id) that they sign. */
+ issuer = NULL;
+ for (n_prevp = &kb, n = kb; n; n_prevp = &n->next, n = n_next)
+ {
+ PACKET *p;
+ int processed_current_component;
+ KBNODE sig_over = NULL;
+ PKT_signature *sig;
+ int algo;
+ int pkttype;
+ gcry_md_hd_t md;
+ int dump_sig_params = 0;
+
+ n_next = n->next;
+
+ if (is_deleted_kbnode (n))
+ continue;
+
+ p = n->pkt;
+
+ if (issuer != pk)
+ free_public_key (issuer);
+ issuer = NULL;
+
+ xfree (pending_desc);
+ pending_desc = NULL;
+
+ switch (p->pkttype)
+ {
+ case PKT_PUBLIC_KEY:
+ assert (p->pkt.public_key == pk);
+ keyid_from_pk (pk, NULL);
+ log_info ("public key %s: timestamp: %s (%lld)\n",
+ keystr (pk->keyid),
+ isotimestamp (pk->timestamp),
+ (long long) pk->timestamp);
+ current_component = n;
+ break;
+ case PKT_PUBLIC_SUBKEY:
+ keyid_from_pk (p->pkt.public_key, NULL);
+ log_info ("subkey %s: timestamp: %s (%lld)\n",
+ keystr (p->pkt.public_key->keyid),
+ isotimestamp (p->pkt.public_key->timestamp),
+ (long long) p->pkt.public_key->timestamp);
+ current_component = n;
+ break;
+ case PKT_USER_ID:
+ log_info ("user id: %s\n",
+ p->pkt.user_id->attrib_data
+ ? "[ photo id ]"
+ : p->pkt.user_id->name);
+ current_component = n;
+ break;
+ case PKT_SIGNATURE:
+ sig = n->pkt->pkt.signature;
+ algo = sig->digest_algo;
+
+#if 1
+ pending_desc = xasprintf (" sig: class: 0x%x, issuer: %s, timestamp: %s (%lld), digest: %02x %02x",
+ sig->sig_class,
+ keystr (sig->keyid),
+ isotimestamp (sig->timestamp),
+ (long long) sig->timestamp,
+ sig->digest_start[0], sig->digest_start[1]);
+#else
+ pending_desc = sig_format (pk, sig, GPG_ERR_NO_VALUE, 1, 0);
+#endif
+
+
+ if (pk_keyid[0] == sig->keyid[0] && pk_keyid[1] == sig->keyid[1])
+ issuer = pk;
+ else
+ /* Issuer is a different key. */
+ {
+ if (only_selfsigs)
+ continue;
+
+ issuer = xmalloc (sizeof (*issuer));
+ err = get_pubkey (issuer, sig->keyid);
+ if (err)
+ {
+ xfree (issuer);
+ issuer = NULL;
+ if (opt.verbose)
+ {
+ if (pending_desc)
+ log_info ("%s", pending_desc);
+ log_info (_(" Can't check signature allegedly issued by %s: %s\n"),
+ keystr (sig->keyid), gpg_strerror (err));
+ }
+ missing_issuer ++;
+ break;
+ }
+ }
+
+ if ((err = openpgp_pk_test_algo (sig->pubkey_algo)))
+ {
+ if (pending_desc)
+ log_info ("%s", pending_desc);
+ log_info (_(" Unsupported algorithm: %s.\n"),
+ gpg_strerror (err));
+ break;
+ }
+ if ((err = openpgp_md_test_algo(algo)))
+ {
+ if (pending_desc)
+ log_info ("%s", pending_desc);
+ log_info (_(" Unimplemented algorithm: %s.\n"),
+ gpg_strerror (err));
+ break;
+ }
+
+ /* We iterate over the keyblock. Most likely, the matching
+ component is the current component so always try that
+ first. */
+ processed_current_component = 0;
+ for (n2 = current_component;
+ n2;
+ n2 = (processed_current_component ? n2->next : kb),
+ processed_current_component = 1)
+ if (is_deleted_kbnode (n2))
+ continue;
+ else if (processed_current_component && n2 == current_component)
+ /* Don't process it twice. */
+ continue;
+ else if (! ((pkttype = n2->pkt->pkttype)
+ && (pkttype == PKT_PUBLIC_KEY
+ || pkttype == PKT_PUBLIC_SUBKEY
+ || pkttype == PKT_USER_ID)))
+ continue;
+ else if (sig->sig_class == 0x20)
+ {
+ PKT_public_key *k;
+
+ if (pkttype != PKT_PUBLIC_KEY)
+ continue;
+
+ k = n2->pkt->pkt.public_key;
+
+ /* If issuer != pk, then we (may) have a designated
+ revoker. */
+
+ if (gcry_md_open (&md, algo, 0))
+ BUG ();
+ hash_public_key (md, k);
+ err = check_signature_only_end (issuer, sig, md);
+ gcry_md_close (md);
+ if (! err)
+ {
+ assert (! sig_over);
+ sig_over = n2;
+ break;
+ }
+ }
+ else if (sig->sig_class == 0x28)
+ /* subkey revocation */
+ {
+ PKT_public_key *k;
+
+ if (pkttype != PKT_PUBLIC_SUBKEY)
+ continue;
+
+ if (issuer != pk)
+ /* Definately invalid: class 0x28 keys must be made
+ by the primary key. */
+ {
+ n2 = NULL;
+ break;
+ }
+
+ k = n2->pkt->pkt.public_key;
+
+ if (gcry_md_open (&md, algo, 0))
+ BUG ();
+ hash_public_key (md, pk);
+ hash_public_key (md, k);
+ err = check_signature_only_end (pk, sig, md);
+ gcry_md_close (md);
+ if (! err)
+ {
+ assert (! sig_over);
+ sig_over = n2;
+ break;
+ }
+ }
+ else if (sig->sig_class == 0x18)
+ /* key binding */
+ {
+ PKT_public_key *k;
+
+ if (pkttype != PKT_PUBLIC_SUBKEY)
+ continue;
+
+ if (issuer != pk)
+ /* Definately invalid: class 0x18 keys must be made
+ by the primary key. */
+ {
+ n2 = NULL;
+ break;
+ }
+
+ k = n2->pkt->pkt.public_key;
+
+ if (gcry_md_open (&md, algo, 0))
+ BUG ();
+ hash_public_key (md, pk);
+ hash_public_key (md, k);
+ err = check_signature_only_end (pk, sig, md);
+ gcry_md_close (md);
+ if (! err)
+ {
+ assert (! sig_over);
+ sig_over = n2;
+ break;
+ }
+ }
+ else if (sig->sig_class == 0x1f)
+ /* direct key signature */
+ {
+ if (pkttype != PKT_PUBLIC_KEY)
+ continue;
+
+ if (issuer != pk)
+ /* Definately invalid: class 0x1f keys must be made
+ by the primary key. */
+ {
+ n2 = NULL;
+ break;
+ }
+
+ if (gcry_md_open (&md, algo, 0 ))
+ BUG ();
+ hash_public_key (md, pk);
+ err = check_signature_only_end (pk, sig, md);
+ gcry_md_close (md);
+ if (! err)
+ {
+ assert (! sig_over);
+ sig_over = n2;
+ break;
+ }
+ }
+ else
+ /* all other classes */
+ {
+ if (pkttype != PKT_USER_ID)
+ continue;
+
+ if (gcry_md_open (&md, algo, 0))
+ BUG ();
+ hash_public_key (md, pk);
+ hash_uid_node (n2, md, sig);
+ err = check_signature_only_end (issuer, sig, md);
+ gcry_md_close (md);
+ if (! err)
+ {
+ assert (! sig_over);
+ sig_over = n2;
+ break;
+ }
+ }
+
+ /* n/sig is a signature and n2 is the component (public key,
+ subkey or user id) that it signs, if any.
+ current_component is that component that it appears to
+ apply to (according to the ordering). */
+
+ if (current_component == n2)
+ {
+ log_info ("%s", pending_desc);
+ log_info (_(" Good signature over last major component!\n"));
+ cache_sig_result (sig, 0);
+ }
+ else if (n2)
+ {
+ assert (n2->pkt->pkttype == PKT_USER_ID
+ || n2->pkt->pkttype == PKT_PUBLIC_KEY
+ || n2->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+
+ log_info ("%s", pending_desc);
+ log_info (_(" Good signature out of order! (Over %s (%d) '%s')\n"),
+ n2->pkt->pkttype == PKT_USER_ID
+ ? "user id"
+ : n2->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ ? "subkey"
+ : "primary key",
+ n2->pkt->pkttype,
+ n2->pkt->pkttype == PKT_USER_ID
+ ? n2->pkt->pkt.user_id->name
+ : keystr (n2->pkt->pkt.public_key->keyid));
+
+ /* Reorder the packets: move the signature n to be just
+ after n2. */
+ assert (n_prevp);
+ *n_prevp = n->next;
+ n->next = n2->next;
+ n2->next = n;
+
+ cache_sig_result (sig, 0);
+
+ reordered ++;
+ modified = 1;
+ }
+ else
+ {
+ log_info ("%s", pending_desc);
+#if 0
+ log_info (_(" Bad signature, removing from key block.\n"));
+
+ /* Remove the signature n. */
+ *n_prevp = n->next;
+ n->next = NULL;
+ release_kbnode (n);
+
+ modified = 1;
+#else
+ log_info (_(" Bad signature.\n"));
+#endif
+
+ cache_sig_result (sig, GPG_ERR_BAD_SIGNATURE);
+
+ if (opt.verbose)
+ dump_sig_params = 1;
+
+ bad_signature ++;
+ }
+
+ if (dump_sig_params)
+ {
+ int i;
+
+ for (i = 0; i < pubkey_get_nsig (sig->pubkey_algo); i ++)
+ {
+ char buffer[1024];
+ size_t len;
+ char *printable;
+ gcry_mpi_print (GCRYMPI_FMT_USG,
+ buffer, sizeof (buffer), &len,
+ sig->data[i]);
+ printable = bin2hex (buffer, len, NULL);
+ log_info (" %d: %s\n", i, printable);
+ xfree (printable);
+ }
+ }
+ break;
+ default:
+ if (DBG_PACKET)
+ log_debug ("unhandled packet: %d\n", p->pkttype);
+ break;
+ }
+ }
+
+ xfree (pending_desc);
+ pending_desc = NULL;
+
+ if (issuer != pk)
+ free_public_key (issuer);
+ issuer = NULL;
+
+ if (missing_issuer)
+ log_info (_("Couldn't check %d signatures due to missing issuer keys.\n"),
+ missing_issuer);
+ if (bad_signature)
+ log_info (_("%d bad signatures.\n"), bad_signature);
+ if (reordered)
+ log_info (_("Reordered %d packets.\n"), reordered);
+
+ return modified;
+}
-----------------------------------------------------------------------
hooks/post-receive
--
The GNU Privacy Guard
http://git.gnupg.org
More information about the Gnupg-commits
mailing list