1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-17 00:39:50 +02:00

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@g10code.com>
GnuPG-bug-id: 2186
This commit is contained in:
Neal H. Walfield 2015-12-16 14:39:12 +01:00
parent 4ffe44c587
commit fc010b6c7f

440
g10/gpg.c
View File

@ -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);
}
err = keydb_get_keyblock (hd, &kb);
if (err)
{
if (! rc)
rc = err;
log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
continue;
}
pk = kb->pkt->pkt.public_key;
/* Check for duplicates. */
if (DBG_LOOKUP)
log_debug ("%s: Checking results of %s='%s' for dups\n",
__func__, option_str, t->d);
while (1)
{
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;
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;
}
}
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);