[Pkg-gnupg-commit] [gnupg2] 39/159: gpg: When checking for ambiguous keys, ignore invalid keys.
Daniel Kahn Gillmor
dkg at fifthhorseman.net
Wed Jan 27 13:23:51 UTC 2016
This is an automated email from the git hooks/post-receive script.
dkg pushed a commit to branch master
in repository gnupg2.
commit fc010b6c7fe14e609734e448775fa384421bdef1
Author: Neal H. Walfield <neal at g10code.com>
Date: Wed Dec 16 14:39:12 2015 +0100
gpg: When checking for ambiguous keys, ignore invalid keys.
* g10/gpg.c (check_user_ids): When checking for ambiguous keys, ignore
disabled, revoked and expired keys (if appropriate for the provided
option).
--
Signed-off-by: Neal H. Walfield <neal at g10code.com>
GnuPG-bug-id: 2186
---
g10/gpg.c | 436 ++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 297 insertions(+), 139 deletions(-)
diff --git a/g10/gpg.c b/g10/gpg.c
index 5c2a6c8..ee38be4 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -2101,6 +2101,15 @@ get_default_configname (void)
return configname;
}
+struct result
+{
+ struct result *next;
+ kbnode_t keyblock;
+ int processed;
+};
+
+/* We show a warning when a key appears multiple times in the DB. */
+static strlist_t key_dups;
static gpg_error_t
check_user_ids (strlist_t *sp,
@@ -2128,18 +2137,21 @@ check_user_ids (strlist_t *sp,
for (t = s; t; t = t->next)
{
- const char *option;
+ const char *option_str;
+ int option;
KEYDB_SEARCH_DESC desc;
- KBNODE kb;
- PKT_public_key *pk;
- char fingerprint_bin[MAX_FINGERPRINT_LEN];
- size_t fingerprint_bin_len = sizeof (fingerprint_bin);
+ struct result *results = NULL;
+ struct result *r;
+
+ int count;
+
/* We also potentially need a ! at the end. */
char fingerprint[2 * MAX_FINGERPRINT_LEN + 1 + 1];
- int added = 0;
- int dups = 0;
- int ambiguous = 0;
+ char fingerprint2[2 * MAX_FINGERPRINT_LEN + 1];
+
+ KBNODE best_kb;
+ PKT_public_key *best_pk;
/* If the key has been given on the command line and it has not
been given by one of the encrypt-to options, we skip the
@@ -2153,15 +2165,16 @@ check_user_ids (strlist_t *sp,
continue;
}
- switch (t->flags >> PK_LIST_SHIFT)
+ option = t->flags >> PK_LIST_SHIFT;
+ switch (option)
{
- case oDefaultKey: option = "--default-key"; break;
- case oEncryptTo: option = "--encrypt-to"; break;
- case oHiddenEncryptTo: option = "--hidden-encrypt-to"; break;
- case oEncryptToDefaultKey: option = "--encrypt-to-default-key"; break;
- case oRecipient: option = "--recipient"; break;
- case oHiddenRecipient: option = "--hidden-recipient"; break;
- case oLocalUser: option = "--local-user"; break;
+ case oDefaultKey: option_str = "--default-key"; break;
+ case oEncryptTo: option_str = "--encrypt-to"; break;
+ case oHiddenEncryptTo: option_str = "--hidden-encrypt-to"; break;
+ case oEncryptToDefaultKey: option_str = "--encrypt-to-default-key"; break;
+ case oRecipient: option_str = "--recipient"; break;
+ case oHiddenRecipient: option_str = "--hidden-recipient"; break;
+ case oLocalUser: option_str = "--local-user"; break;
default:
log_bug ("Unsupport option: %d\n", (t->flags >> PK_LIST_SHIFT));
}
@@ -2169,7 +2182,7 @@ check_user_ids (strlist_t *sp,
if (DBG_LOOKUP)
{
log_debug ("\n");
- log_debug ("%s: Checking %s=%s\n", __func__, option, t->d);
+ log_debug ("%s: Checking %s=%s\n", __func__, option_str, t->d);
}
err = classify_user_id (t->d, &desc, 1);
@@ -2181,7 +2194,7 @@ check_user_ids (strlist_t *sp,
log_error (_("key \"%s\" not found: %s\n"),
t->d, gpg_strerror (err));
if (!opt.quiet)
- log_info (_("(check argument of option '%s')\n"), option);
+ log_info (_("(check argument of option '%s')\n"), option_str);
continue;
}
@@ -2192,7 +2205,7 @@ check_user_ids (strlist_t *sp,
|| desc.mode == KEYDB_SEARCH_MODE_FPR))
log_info (_("Warning: value '%s' for option '%s'"
" should be a long key ID or a fingerprint\n"),
- t->d, option);
+ t->d, option_str);
if (! hd)
{
@@ -2206,8 +2219,53 @@ check_user_ids (strlist_t *sp,
else
keydb_search_reset (hd);
- err = keydb_search (hd, &desc, 1, NULL);
- if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+ /* Gather all of the results. */
+ count = 0;
+ while (1)
+ {
+ KBNODE kb;
+
+ err = keydb_search (hd, &desc, 1, NULL);
+ if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
+ || gpg_err_code (err) == GPG_ERR_EOF)
+ /* No more results. */
+ break;
+ else if (err)
+ /* An error (other than "not found"). */
+ {
+ log_error (_("error searching the keyring: %s\n"),
+ gpg_strerror (err));
+ break;
+ }
+
+ err = keydb_get_keyblock (hd, &kb);
+ if (err)
+ {
+ log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
+ break;
+ }
+
+ /* Another result! */
+ count ++;
+
+ r = xmalloc_clear (sizeof (*r));
+ r->keyblock = kb;
+ r->next = results;
+ results = r;
+ }
+
+ if (DBG_LOOKUP)
+ {
+ log_debug ("%s resulted in %d matches.\n", t->d, count);
+ for (r = results; r; r = r->next)
+ log_debug (" %s\n",
+ hexfingerprint (r->keyblock->pkt->pkt.public_key,
+ fingerprint, sizeof (fingerprint)));
+ }
+
+ if (! results && (gpg_err_code (err) == GPG_ERR_NOT_FOUND
+ || gpg_err_code (err) == GPG_ERR_EOF))
+ /* No match. */
{
if (DBG_LOOKUP)
log_debug ("%s: '%s' not found.\n", __func__, t->d);
@@ -2219,30 +2277,223 @@ check_user_ids (strlist_t *sp,
log_error (_("key \"%s\" not found\n"), t->d);
if (!opt.quiet)
- log_info (_("(check argument of option '%s')\n"), option);
+ log_info (_("(check argument of option '%s')\n"), option_str);
}
continue;
}
- if (err)
+ else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
+ || gpg_err_code (err) == GPG_ERR_EOF)
+ /* No more matches. */
+ ;
+ else if (err)
+ /* Some other error. An error message was already printed
+ out. Free RESULTS and continue. */
{
if (! rc)
rc = err;
- log_error (_("key \"%s\" not found: %s\n"), t->d, gpg_strerror (err));
- break;
+ while ((r = results))
+ {
+ results = results->next;
+ release_kbnode (r->keyblock);
+ xfree (r);
+ }
+
+ continue;
}
- err = keydb_get_keyblock (hd, &kb);
- if (err)
+ /* Check for duplicates. */
+
+ if (DBG_LOOKUP)
+ log_debug ("%s: Checking results of %s='%s' for dups\n",
+ __func__, option_str, t->d);
+ while (1)
{
- if (! rc)
- rc = err;
+ struct result **prevp;
+ struct result *next;
+ struct result *r2;
+ int dups = 0;
+
+ /* After checking a result, we set R->PROCESSED. Find the
+ next unprocessed result. */
+ for (r = results; r; r = r->next)
+ if (! r->processed)
+ break;
- log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
- continue;
+ if (! r)
+ /* There is nothing left to check. */
+ break;
+
+ hexfingerprint (r->keyblock->pkt->pkt.public_key,
+ fingerprint, sizeof fingerprint);
+ r->processed = 1;
+
+ prevp = &results;
+ next = results;
+ while ((r2 = next))
+ {
+ if (r2->processed)
+ {
+ prevp = &r2->next;
+ next = r2->next;
+ continue;
+ }
+
+ hexfingerprint (r2->keyblock->pkt->pkt.public_key,
+ fingerprint2, sizeof fingerprint2);
+
+ if (strcmp (fingerprint, fingerprint2) != 0)
+ /* Not a dup. */
+ {
+ prevp = &r2->next;
+ next = r2->next;
+ continue;
+ }
+
+ dups ++;
+
+ /* Remove R2 from the list. */
+ *prevp = r2->next;
+ release_kbnode (r2->keyblock);
+ next = r2->next;
+ xfree (r2);
+ }
+
+ if (dups && ! strlist_find (key_dups, fingerprint))
+ {
+ log_info (_("Warning: %s appears in the keyring %d times.\n"),
+ format_hexfingerprint (fingerprint,
+ fingerprint_formatted,
+ sizeof fingerprint_formatted),
+ 1 + dups);
+ add_to_strlist (&key_dups, fingerprint);
+ }
+ }
+
+ if (DBG_LOOKUP)
+ {
+ log_debug ("After removing dups:\n");
+ for (r = results, count = 0; r; r = r->next)
+ {
+ count ++;
+ log_debug (" %d: %s\n",
+ count,
+ hexfingerprint (r->keyblock->pkt->pkt.public_key,
+ fingerprint, sizeof fingerprint));
+ }
+ }
+
+ /* Now we find the best key. */
+ assert (results);
+ if (! results->next)
+ /* There is only one key. */
+ {
+ best_kb = results->keyblock;
+ best_pk = best_kb->pkt->pkt.public_key;
+ }
+ else
+ /* We have more than one matching key. Prune invalid
+ keys. */
+ {
+ int ambiguous = 0;
+
+ if (DBG_LOOKUP)
+ log_debug ("Pruning bad keys.\n");
+
+ best_pk = NULL;
+ for (r = results; r; r = r->next)
+ {
+ /* Merge in the data from the self sigs so that things
+ like the revoked status are available. */
+ merge_keys_and_selfsig (r->keyblock);
+ r->processed = 0;
+ }
+
+ for (r = results; r; r = r->next)
+ {
+ KBNODE kb = r->keyblock;
+ PKT_public_key *pk = kb->pkt->pkt.public_key;
+
+ if (/* Using disabled keys with --encrypt-to is allowed. */
+ ! (option == oEncryptTo || option == oHiddenEncryptTo)
+ && pk_is_disabled (pk))
+ {
+ if (DBG_LOOKUP)
+ log_debug (" Skipping disabled key: %s\n",
+ hexfingerprint (pk, fingerprint,
+ sizeof fingerprint));
+ r->processed = 1;
+ continue;
+ }
+ if (pk->flags.revoked)
+ {
+ if (DBG_LOOKUP)
+ log_debug (" Skipping revoked key: %s\n",
+ hexfingerprint (pk, fingerprint,
+ sizeof fingerprint));
+ r->processed = 1;
+ continue;
+ }
+ if (pk->has_expired)
+ {
+ if (DBG_LOOKUP)
+ log_debug (" Skipping expired key: %s\n",
+ hexfingerprint (pk, fingerprint,
+ sizeof fingerprint));
+ r->processed = 1;
+ continue;
+ }
+
+ if (! best_pk)
+ {
+ best_pk = pk;
+ best_kb = kb;
+ r->processed = 1;
+ continue;
+ }
+
+ /* We have multiple candidates. Prefer the newer key.
+
+ XXX: we should also consider key capabilities (if we
+ are encrypting to the key, does it have an encryption
+ capability?).
+
+ XXX: if we are signing, then we should consider the
+ key that is actually available (e.g., if one is on a
+ smart card). */
+ ambiguous = 1;
+ if (best_pk->timestamp < pk->timestamp)
+ best_pk = pk;
+ }
+
+ if (ambiguous)
+ {
+ /* TRANSLATORS: The %s prints a key specification which
+ for example has been given at the command line.
+ Lines with fingerprints are printed after this
+ message. */
+ log_error (_("key specification '%s' is ambiguous\n"),
+ t->d);
+ if (!opt.quiet)
+ log_info (_("(check argument of option '%s')\n"),
+ option_str);
+
+ log_info (_("'%s' matches at least:\n"), t->d);
+
+ for (r = results; r; r = r->next)
+ if (! r->processed)
+ log_info (" %s\n",
+ format_hexfingerprint
+ (hexfingerprint (r->keyblock->pkt->pkt.public_key,
+ fingerprint, sizeof fingerprint),
+ fingerprint_formatted,
+ sizeof fingerprint_formatted));
+
+ if (! rc)
+ rc = GPG_ERR_AMBIGUOUS_NAME;
+ }
}
- pk = kb->pkt->pkt.public_key;
if ((desc.mode == KEYDB_SEARCH_MODE_SHORT_KID
|| desc.mode == KEYDB_SEARCH_MODE_LONG_KID
|| desc.mode == KEYDB_SEARCH_MODE_FPR16
@@ -2253,7 +2504,7 @@ check_user_ids (strlist_t *sp,
matched the search criteria. Note: there will always be
exactly one match. */
{
- kbnode_t n = kb;
+ kbnode_t n = best_kb;
PKT_public_key *match = NULL;
int i;
@@ -2269,119 +2520,26 @@ check_user_ids (strlist_t *sp,
while ((n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY)));
assert (match);
- fingerprint_from_pk (match, fingerprint_bin, &fingerprint_bin_len);
- assert (fingerprint_bin_len == sizeof (fingerprint_bin));
- bin2hex (fingerprint_bin, MAX_FINGERPRINT_LEN, fingerprint);
-
+ hexfingerprint (match, fingerprint, sizeof fingerprint);
i = strlen (fingerprint);
fingerprint[i] = '!';
fingerprint[i + 1] = '\0';
-
- add_to_strlist (&s2, fingerprint);
- added = 1;
}
+ else
+ hexfingerprint (best_pk, fingerprint, sizeof fingerprint);
- /* We need the primary key's fingerprint to detect dups so
- always format it. */
- fingerprint_from_pk (pk, fingerprint_bin, &fingerprint_bin_len);
- assert (fingerprint_bin_len == sizeof (fingerprint_bin));
- bin2hex (fingerprint_bin, MAX_FINGERPRINT_LEN, fingerprint);
-
- if (! added)
- add_to_strlist (&s2, fingerprint);
+ add_to_strlist (&s2, fingerprint);
s2->flags = s->flags;
- release_kbnode (kb);
-
- /* Continue the search. */
- if (DBG_LOOKUP)
- log_debug ("%s: Checking if %s='%s' is ambiguous or there are dups\n",
- __func__, option, t->d);
- while (1)
- {
- char fingerprint_bin2[MAX_FINGERPRINT_LEN];
- size_t fingerprint_bin2_len = sizeof (fingerprint_bin2);
- char fingerprint2[2 * MAX_FINGERPRINT_LEN + 1];
-
- err = keydb_search (hd, &desc, 1, NULL);
- if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
- || gpg_err_code (err) == GPG_ERR_EOF)
- /* Not found => not ambiguous. */
- break;
- else if (err)
- /* An error (other than "not found"). */
- {
- log_error (_("error searching the keyring: %s\n"),
- gpg_strerror (err));
- if (! rc)
- rc = err;
-
- break;
- }
-
- /* Another result! */
-
- err = keydb_get_keyblock (hd, &kb);
- if (err)
- {
- log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
- if (! rc)
- rc = err;
- }
- else
- {
- pk = kb->pkt->pkt.public_key;
- fingerprint_from_pk (pk, fingerprint_bin2, &fingerprint_bin2_len);
- assert (fingerprint_bin2_len == sizeof (fingerprint_bin2));
- bin2hex (fingerprint_bin2, MAX_FINGERPRINT_LEN, fingerprint2);
-
- if (strcmp (fingerprint, fingerprint2) == 0)
- dups ++;
- else
- {
- ambiguous ++;
-
- if (! rc)
- rc = GPG_ERR_AMBIGUOUS_NAME;
-
- if (ambiguous == 1)
- {
- /* TRANSLATORS: The %s prints a key
- specification which for example has been
- given at the command line. Lines with
- fingerprints are printed after this
- message. */
- log_error (_("key specification '%s' is ambiguous\n"),
- t->d);
- if (!opt.quiet)
- log_info (_("(check argument of option '%s')\n"),
- option);
-
- log_info (_("'%s' matches at least:\n"), t->d);
- log_info (" %s\n",
- format_hexfingerprint
- (fingerprint,
- fingerprint_formatted,
- sizeof fingerprint_formatted));
- }
-
- log_info (" %s\n",
- format_hexfingerprint
- (fingerprint2,
- fingerprint_formatted,
- sizeof fingerprint_formatted));
- }
-
- release_kbnode (kb);
- }
- }
-
- if (dups)
- log_info (_("Warning: %s appears in the keyring %d times.\n"),
- format_hexfingerprint (fingerprint,
- fingerprint_formatted,
- sizeof fingerprint_formatted),
- 1 + dups);
+ {
+ struct result *next = results;
+ while ((r = next))
+ {
+ next = r->next;
+ release_kbnode (r->keyblock);
+ xfree (r);
+ }
+ }
}
strlist_rev (&s2);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gnupg2.git
More information about the Pkg-gnupg-commit
mailing list