mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
gpg: Don't check for ambiguous keys.
* g10/gpg.c (struct result): Move from here... * g10/keydb.h (struct pubkey): ... to here. Update users. * g10/gpg.c (check_user_ids): Move from here... * g10/getkey.c (get_pubkeys): ... to here. Update users. Use get_pubkey_byname to look up the keys (this also prunes invalid keys). (pubkey_free): New function. (pubkeys_free): New function. * g10/gpg.c (main): Don't check for ambiguous key specifications. -- Signed-off-by: Neal H. Walfield <neal@g10code.com> Regression-due-to: e8c53fc This change not only moves the checks for ambiguous key specifications from gpg.c to getkey.c, it also disables the checks. The old code was too divorced from the actual key lookups and, as such, it reproduced the logic. Unfortunately, the reproduction was a poor one: despite fixing some inconsistencies (e.g., 10cca02), it still didn't deal with group expansion or the auto key lookup functionality. Given the amount of instability introduced by this change, we (Neal & Werner) decided it is better to defer introducing this functionality until 2.3.
This commit is contained in:
parent
dc52995d85
commit
7195b94345
3
NEWS
3
NEWS
@ -1,6 +1,9 @@
|
|||||||
Noteworthy changes in version 2.1.11 (unreleased)
|
Noteworthy changes in version 2.1.11 (unreleased)
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
|
* gpg: Don't check for ambigious or non-matching key specification in
|
||||||
|
the config file or given to --encrypt-to. This feature will return
|
||||||
|
in 2.3.x.
|
||||||
|
|
||||||
Noteworthy changes in version 2.1.10 (2015-12-04)
|
Noteworthy changes in version 2.1.10 (2015-12-04)
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
276
g10/getkey.c
276
g10/getkey.c
@ -366,6 +366,282 @@ getkey_disable_caches ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
pubkey_free (struct pubkey *key)
|
||||||
|
{
|
||||||
|
xfree (key->pk);
|
||||||
|
release_kbnode (key->keyblock);
|
||||||
|
xfree (key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pubkeys_free (struct pubkey *keys)
|
||||||
|
{
|
||||||
|
while (keys)
|
||||||
|
{
|
||||||
|
struct pubkey *next = keys->next;
|
||||||
|
pubkey_free (keys);
|
||||||
|
keys = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns all keys that match the search specfication SEARCH_TERMS.
|
||||||
|
|
||||||
|
This function also checks for and warns about duplicate entries in
|
||||||
|
the keydb, which can occur if the user has configured multiple
|
||||||
|
keyrings or keyboxes or if a keyring or keybox was corrupted.
|
||||||
|
|
||||||
|
Note: SEARCH_TERMS will not be expanded (i.e., it may not be a
|
||||||
|
group).
|
||||||
|
|
||||||
|
USE is the operation for which the key is required. It must be
|
||||||
|
either PUBKEY_USAGE_ENC, PUBKEY_USAGE_SIG, PUBKEY_USAGE_CERT or
|
||||||
|
PUBKEY_USAGE_AUTH.
|
||||||
|
|
||||||
|
XXX: Currently, only PUBKEY_USAGE_ENC and PUBKEY_USAGE_SIG are
|
||||||
|
implemented.
|
||||||
|
|
||||||
|
INCLUDE_UNUSABLE indicates whether disabled keys are allowed.
|
||||||
|
(Recipients specified with --encrypt-to and --hidden-encrypt-to may
|
||||||
|
be disabled. It is possible to edit disabled keys.)
|
||||||
|
|
||||||
|
SOURCE is the context in which SEARCH_TERMS was specified, e.g.,
|
||||||
|
"--encrypt-to", etc. If this function is called interactively,
|
||||||
|
then this should be NULL.
|
||||||
|
|
||||||
|
If WARN_POSSIBLY_AMBIGUOUS is set, then emits a warning if the user
|
||||||
|
does not specify a long key id or a fingerprint.
|
||||||
|
|
||||||
|
The results are placed in *KEYS. *KEYS must be NULL! */
|
||||||
|
gpg_error_t
|
||||||
|
get_pubkeys (ctrl_t ctrl,
|
||||||
|
char *search_terms, int use, int include_unusable, char *source,
|
||||||
|
int warn_possibly_ambiguous,
|
||||||
|
struct pubkey **keys)
|
||||||
|
{
|
||||||
|
/* We show a warning when a key appears multiple times in the DB.
|
||||||
|
This can happen for two reasons:
|
||||||
|
|
||||||
|
- The user has configured multiple keyrings or keyboxes.
|
||||||
|
|
||||||
|
- The keyring or keybox has been corrupted in some way, e.g., a
|
||||||
|
bug or a random process changing them.
|
||||||
|
|
||||||
|
For each duplicate, we only want to show the key once. Hence,
|
||||||
|
this list. */
|
||||||
|
static strlist_t key_dups;
|
||||||
|
|
||||||
|
/* USE transformed to a string. */
|
||||||
|
char *use_str;
|
||||||
|
|
||||||
|
gpg_error_t err;
|
||||||
|
|
||||||
|
KEYDB_SEARCH_DESC desc;
|
||||||
|
|
||||||
|
GETKEY_CTX ctx;
|
||||||
|
struct pubkey *results = NULL;
|
||||||
|
struct pubkey *r;
|
||||||
|
|
||||||
|
int count;
|
||||||
|
|
||||||
|
char fingerprint[2 * MAX_FINGERPRINT_LEN + 1];
|
||||||
|
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
{
|
||||||
|
log_debug ("\n");
|
||||||
|
log_debug ("%s: Checking %s=%s\n",
|
||||||
|
__func__, source ? source : "user input", search_terms);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*keys)
|
||||||
|
log_bug ("%s: KEYS should be NULL!\n", __func__);
|
||||||
|
|
||||||
|
switch (use)
|
||||||
|
{
|
||||||
|
case PUBKEY_USAGE_ENC: use_str = "encrypt"; break;
|
||||||
|
case PUBKEY_USAGE_SIG: use_str = "sign"; break;
|
||||||
|
case PUBKEY_USAGE_CERT: use_str = "cetify"; break;
|
||||||
|
case PUBKEY_USAGE_AUTH: use_str = "authentication"; break;
|
||||||
|
default: log_bug ("%s: Bad value for USE (%d)\n", __func__, use);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use == PUBKEY_USAGE_CERT || use == PUBKEY_USAGE_AUTH)
|
||||||
|
log_bug ("%s: use=%s is unimplemented.\n", __func__, use_str);
|
||||||
|
|
||||||
|
err = classify_user_id (search_terms, &desc, 1);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_info (_("key \"%s\" not found: %s\n"),
|
||||||
|
search_terms, gpg_strerror (err));
|
||||||
|
if (!opt.quiet && source)
|
||||||
|
log_info (_("(check argument of option '%s')\n"), source);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warn_possibly_ambiguous
|
||||||
|
&& ! (desc.mode == KEYDB_SEARCH_MODE_LONG_KID
|
||||||
|
|| desc.mode == KEYDB_SEARCH_MODE_FPR16
|
||||||
|
|| desc.mode == KEYDB_SEARCH_MODE_FPR20
|
||||||
|
|| desc.mode == KEYDB_SEARCH_MODE_FPR))
|
||||||
|
{
|
||||||
|
log_info (_("Warning: '%s' should be a long key ID or a fingerprint\n"),
|
||||||
|
search_terms);
|
||||||
|
if (!opt.quiet && source)
|
||||||
|
log_info (_("(check argument of option '%s')\n"), source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gather all of the results. */
|
||||||
|
ctx = NULL;
|
||||||
|
count = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
PKT_public_key *pk = xmalloc_clear (sizeof *pk);
|
||||||
|
KBNODE kb;
|
||||||
|
pk->req_usage = use;
|
||||||
|
|
||||||
|
if (! ctx)
|
||||||
|
err = get_pubkey_byname (ctrl, &ctx, pk, search_terms, &kb, NULL,
|
||||||
|
include_unusable, 1);
|
||||||
|
else
|
||||||
|
err = getkey_next (ctx, pk, &kb);
|
||||||
|
|
||||||
|
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
|
||||||
|
/* No more results. */
|
||||||
|
{
|
||||||
|
xfree (pk);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (err)
|
||||||
|
/* An error (other than "not found"). */
|
||||||
|
{
|
||||||
|
log_error (_("error looking up: %s\n"),
|
||||||
|
gpg_strerror (err));
|
||||||
|
xfree (pk);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Another result! */
|
||||||
|
count ++;
|
||||||
|
|
||||||
|
r = xmalloc_clear (sizeof (*r));
|
||||||
|
r->pk = pk;
|
||||||
|
r->keyblock = kb;
|
||||||
|
r->next = results;
|
||||||
|
results = r;
|
||||||
|
}
|
||||||
|
while (ctx);
|
||||||
|
getkey_end (ctx);
|
||||||
|
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
{
|
||||||
|
log_debug ("%s resulted in %d matches.\n", search_terms, 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)
|
||||||
|
/* No match. */
|
||||||
|
{
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
log_debug ("%s: '%s' not found.\n", __func__, search_terms);
|
||||||
|
|
||||||
|
log_info (_("key \"%s\" not found\n"), search_terms);
|
||||||
|
if (!opt.quiet && source)
|
||||||
|
log_info (_("(check argument of option '%s')\n"), source);
|
||||||
|
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
|
||||||
|
/* No more matches. */
|
||||||
|
;
|
||||||
|
else if (err)
|
||||||
|
/* Some other error. An error message was already printed
|
||||||
|
out. Free RESULTS and continue. */
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Check for duplicates. */
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
log_debug ("%s: Checking results of %s='%s' for dups\n",
|
||||||
|
__func__, source ? source : "user input", search_terms);
|
||||||
|
count = 0;
|
||||||
|
for (r = results; r; r = r->next)
|
||||||
|
{
|
||||||
|
struct pubkey **prevp;
|
||||||
|
struct pubkey *next;
|
||||||
|
struct pubkey *r2;
|
||||||
|
int dups = 0;
|
||||||
|
|
||||||
|
prevp = &r->next;
|
||||||
|
next = r->next;
|
||||||
|
while ((r2 = next))
|
||||||
|
{
|
||||||
|
if (cmp_public_keys (r->keyblock->pkt->pkt.public_key,
|
||||||
|
r2->keyblock->pkt->pkt.public_key) != 0)
|
||||||
|
/* Not a dup. */
|
||||||
|
{
|
||||||
|
prevp = &r2->next;
|
||||||
|
next = r2->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dups ++;
|
||||||
|
count ++;
|
||||||
|
|
||||||
|
/* Remove R2 from the list. */
|
||||||
|
*prevp = r2->next;
|
||||||
|
release_kbnode (r2->keyblock);
|
||||||
|
next = r2->next;
|
||||||
|
xfree (r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dups)
|
||||||
|
{
|
||||||
|
hexfingerprint (r->keyblock->pkt->pkt.public_key,
|
||||||
|
fingerprint, sizeof fingerprint);
|
||||||
|
if (! strlist_find (key_dups, fingerprint))
|
||||||
|
{
|
||||||
|
char fingerprint_formatted[MAX_FORMATTED_FINGERPRINT_LEN + 1];
|
||||||
|
|
||||||
|
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 && count)
|
||||||
|
{
|
||||||
|
log_debug ("After removing %d dups:\n", count);
|
||||||
|
for (r = results, count = 0; r; r = r->next)
|
||||||
|
log_debug (" %d: %s\n",
|
||||||
|
count,
|
||||||
|
hexfingerprint (r->keyblock->pkt->pkt.public_key,
|
||||||
|
fingerprint, sizeof fingerprint));
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
while ((r = results))
|
||||||
|
{
|
||||||
|
results = results->next;
|
||||||
|
pubkey_free (r);
|
||||||
|
release_kbnode (r->keyblock);
|
||||||
|
xfree (r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*keys = results;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock,
|
pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock,
|
||||||
KBNODE found_key)
|
KBNODE found_key)
|
||||||
|
512
g10/gpg.c
512
g10/gpg.c
@ -2101,506 +2101,6 @@ get_default_configname (void)
|
|||||||
return configname;
|
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,
|
|
||||||
int warn_possibly_ambiguous,
|
|
||||||
int error_if_not_found)
|
|
||||||
{
|
|
||||||
strlist_t s = *sp;
|
|
||||||
strlist_t s2 = NULL;
|
|
||||||
strlist_t t;
|
|
||||||
|
|
||||||
gpg_error_t rc = 0;
|
|
||||||
gpg_error_t err;
|
|
||||||
|
|
||||||
KEYDB_HANDLE hd = NULL;
|
|
||||||
|
|
||||||
char fingerprint_formatted[MAX_FORMATTED_FINGERPRINT_LEN + 1];
|
|
||||||
|
|
||||||
/* A quick check to avoid allocating a new strlist if we can skip
|
|
||||||
all keys. Handles also the case of !SP. See below for details. */
|
|
||||||
for (t = s; t && (!(t->flags & PK_LIST_CONFIG)
|
|
||||||
&& !(t->flags & PK_LIST_ENCRYPT_TO)); t = t->next)
|
|
||||||
;
|
|
||||||
if (!t)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (t = s; t; t = t->next)
|
|
||||||
{
|
|
||||||
const char *option_str;
|
|
||||||
int option;
|
|
||||||
|
|
||||||
KEYDB_SEARCH_DESC desc;
|
|
||||||
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];
|
|
||||||
char fingerprint2[2 * MAX_FINGERPRINT_LEN + 1];
|
|
||||||
|
|
||||||
KBNODE best_kb;
|
|
||||||
PKT_public_key *best_pk;
|
|
||||||
|
|
||||||
/* Whether the key is for encryption or signing. */
|
|
||||||
int encrypt = 1;
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
checks. The reason is that the actual key selection code
|
|
||||||
does its own checks and provides proper status message to the
|
|
||||||
caller to detect the wrong keys. */
|
|
||||||
if (!(t->flags & PK_LIST_CONFIG) && !(t->flags & PK_LIST_ENCRYPT_TO))
|
|
||||||
{
|
|
||||||
add_to_strlist (&s2, t->d);
|
|
||||||
s2->flags = t->flags;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
option = t->flags >> PK_LIST_SHIFT;
|
|
||||||
switch (option)
|
|
||||||
{
|
|
||||||
case oDefaultKey:
|
|
||||||
option_str = "--default-key";
|
|
||||||
encrypt = 0;
|
|
||||||
break;
|
|
||||||
case oLocalUser:
|
|
||||||
option_str = "--local-user";
|
|
||||||
encrypt = 0;
|
|
||||||
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;
|
|
||||||
default:
|
|
||||||
log_bug ("Unsupport option: %d\n", (t->flags >> PK_LIST_SHIFT));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DBG_LOOKUP)
|
|
||||||
{
|
|
||||||
log_debug ("\n");
|
|
||||||
log_debug ("%s: Checking %s=%s\n", __func__, option_str, t->d);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = classify_user_id (t->d, &desc, 1);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
if (! rc)
|
|
||||||
rc = err;
|
|
||||||
|
|
||||||
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_str);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (warn_possibly_ambiguous
|
|
||||||
&& ! (desc.mode == KEYDB_SEARCH_MODE_LONG_KID
|
|
||||||
|| desc.mode == KEYDB_SEARCH_MODE_FPR16
|
|
||||||
|| desc.mode == KEYDB_SEARCH_MODE_FPR20
|
|
||||||
|| 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_str);
|
|
||||||
|
|
||||||
if (! hd)
|
|
||||||
{
|
|
||||||
hd = keydb_new ();
|
|
||||||
if (!hd)
|
|
||||||
{
|
|
||||||
rc = gpg_error_from_syserror ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
keydb_search_reset (hd);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
if (error_if_not_found)
|
|
||||||
{
|
|
||||||
if (! rc)
|
|
||||||
rc = err;
|
|
||||||
|
|
||||||
log_error (_("key \"%s\" not found\n"), t->d);
|
|
||||||
if (!opt.quiet)
|
|
||||||
log_info (_("(check argument of option '%s')\n"), option_str);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
|
|
||||||
while ((r = results))
|
|
||||||
{
|
|
||||||
results = results->next;
|
|
||||||
release_kbnode (r->keyblock);
|
|
||||||
xfree (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
KBNODE kb = r->keyblock;
|
|
||||||
PKT_public_key *pk = kb->pkt->pkt.public_key;
|
|
||||||
KBNODE n;
|
|
||||||
|
|
||||||
/* Merge in the data from the self sigs so that things
|
|
||||||
like the revoked status are available. */
|
|
||||||
merge_keys_and_selfsig (kb);
|
|
||||||
|
|
||||||
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));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (pk->flags.revoked)
|
|
||||||
{
|
|
||||||
if (DBG_LOOKUP)
|
|
||||||
log_debug (" Skipping revoked key: %s\n",
|
|
||||||
hexfingerprint (pk, fingerprint,
|
|
||||||
sizeof fingerprint));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (pk->has_expired)
|
|
||||||
{
|
|
||||||
if (DBG_LOOKUP)
|
|
||||||
log_debug (" Skipping expired key: %s\n",
|
|
||||||
hexfingerprint (pk, fingerprint,
|
|
||||||
sizeof fingerprint));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for the required encryption or signing
|
|
||||||
capability. */
|
|
||||||
n = kb;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
PKT_public_key *key = n->pkt->pkt.public_key;
|
|
||||||
|
|
||||||
if ((/* Using disabled keys with --encrypt-to is allowed. */
|
|
||||||
pk_is_disabled (key)
|
|
||||||
&& ! (option == oEncryptTo
|
|
||||||
|| option == oHiddenEncryptTo))
|
|
||||||
|| key->flags.revoked
|
|
||||||
|| key->has_expired)
|
|
||||||
/* Invalid. */
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (encrypt && ! (key->pubkey_usage & PUBKEY_USAGE_ENC))
|
|
||||||
continue;
|
|
||||||
if (! encrypt && ! (key->pubkey_usage & PUBKEY_USAGE_SIG))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Key passes basic tests. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while ((n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY)));
|
|
||||||
|
|
||||||
if (! n)
|
|
||||||
{
|
|
||||||
if (DBG_LOOKUP)
|
|
||||||
log_debug (" Skipping %s, which does not have %s capability.\n",
|
|
||||||
hexfingerprint (r->keyblock->pkt->pkt.public_key,
|
|
||||||
fingerprint, sizeof fingerprint),
|
|
||||||
encrypt ? "encrypt" : "sign");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (DBG_LOOKUP)
|
|
||||||
log_debug (" %s is valid and has %s capability.\n",
|
|
||||||
hexfingerprint (r->keyblock->pkt->pkt.public_key,
|
|
||||||
fingerprint, sizeof fingerprint),
|
|
||||||
encrypt ? "encrypt" : "sign");
|
|
||||||
|
|
||||||
|
|
||||||
if (! best_pk)
|
|
||||||
{
|
|
||||||
best_pk = pk;
|
|
||||||
best_kb = kb;
|
|
||||||
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 (! results)
|
|
||||||
{
|
|
||||||
if (encrypt)
|
|
||||||
log_error (_("%s: no matching keys are valid encryption keys"),
|
|
||||||
t->d);
|
|
||||||
else
|
|
||||||
log_error (_("%s: no matching keys are valid signing keys"),
|
|
||||||
t->d);
|
|
||||||
if (!opt.quiet)
|
|
||||||
log_info (_("(check argument of option '%s')\n"), option_str);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
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
|
|
||||||
|| desc.mode == KEYDB_SEARCH_MODE_FPR20)
|
|
||||||
&& strchr (t->d, '!'))
|
|
||||||
/* Exact search. In this case we want to set FINGERPRINT not
|
|
||||||
to the primary key, but the key (primary or sub) that
|
|
||||||
matched the search criteria. Note: there will always be
|
|
||||||
exactly one match. */
|
|
||||||
{
|
|
||||||
kbnode_t n = best_kb;
|
|
||||||
PKT_public_key *match = NULL;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if ((n->flag & 1))
|
|
||||||
/* The matched node. */
|
|
||||||
{
|
|
||||||
assert (! match);
|
|
||||||
match = n->pkt->pkt.public_key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ((n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY)));
|
|
||||||
assert (match);
|
|
||||||
|
|
||||||
hexfingerprint (match, fingerprint, sizeof fingerprint);
|
|
||||||
i = strlen (fingerprint);
|
|
||||||
fingerprint[i] = '!';
|
|
||||||
fingerprint[i + 1] = '\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
hexfingerprint (best_pk, fingerprint, sizeof fingerprint);
|
|
||||||
|
|
||||||
add_to_strlist (&s2, fingerprint);
|
|
||||||
s2->flags = s->flags;
|
|
||||||
|
|
||||||
{
|
|
||||||
struct result *next = results;
|
|
||||||
while ((r = next))
|
|
||||||
{
|
|
||||||
next = r->next;
|
|
||||||
release_kbnode (r->keyblock);
|
|
||||||
xfree (r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strlist_rev (&s2);
|
|
||||||
|
|
||||||
keydb_release (hd);
|
|
||||||
|
|
||||||
free_strlist (s);
|
|
||||||
*sp = s2;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -4280,18 +3780,6 @@ main (int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
rc = check_user_ids (&locusr, 1, 1);
|
|
||||||
if (rc)
|
|
||||||
g10_exit (1);
|
|
||||||
rc = check_user_ids (&remusr, 0, 1);
|
|
||||||
if (rc)
|
|
||||||
g10_exit (1);
|
|
||||||
rc = check_user_ids (&opt.def_secret_key, 1, 0);
|
|
||||||
if (rc)
|
|
||||||
g10_exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The command dispatcher. */
|
/* The command dispatcher. */
|
||||||
switch( cmd )
|
switch( cmd )
|
||||||
{
|
{
|
||||||
|
23
g10/keydb.h
23
g10/keydb.h
@ -485,6 +485,29 @@ int get_pubkey_fast ( PKT_public_key *pk, u32 *keyid );
|
|||||||
using merge_selfsigs. */
|
using merge_selfsigs. */
|
||||||
KBNODE get_pubkeyblock( u32 *keyid );
|
KBNODE get_pubkeyblock( u32 *keyid );
|
||||||
|
|
||||||
|
/* A list used by get_pubkeys to gather all of the matches. */
|
||||||
|
struct pubkey
|
||||||
|
{
|
||||||
|
struct pubkey *next;
|
||||||
|
/* The key to use (either the public key or the subkey). */
|
||||||
|
PKT_public_key *pk;
|
||||||
|
kbnode_t keyblock;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Free a single key. This does not remove key from any list! */
|
||||||
|
void pubkey_free (struct pubkey *key);
|
||||||
|
|
||||||
|
/* Free a list of public keys. */
|
||||||
|
void pubkeys_free (struct pubkey *keys);
|
||||||
|
|
||||||
|
/* Returns all keys that match the search specfication SEARCH_TERMS.
|
||||||
|
The returned keys should be freed using pubkeys_free. */
|
||||||
|
gpg_error_t
|
||||||
|
get_pubkeys (ctrl_t ctrl,
|
||||||
|
char *search_terms, int use, int include_unusable, char *source,
|
||||||
|
int warn_possibly_ambiguous,
|
||||||
|
struct pubkey **keys);
|
||||||
|
|
||||||
/* Find a public key identified by the name NAME.
|
/* Find a public key identified by the name NAME.
|
||||||
|
|
||||||
If name appears to be a valid valid RFC822 mailbox (i.e., email
|
If name appears to be a valid valid RFC822 mailbox (i.e., email
|
||||||
|
@ -914,6 +914,13 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
|
|||||||
else
|
else
|
||||||
remusr = rcpts;
|
remusr = rcpts;
|
||||||
|
|
||||||
|
/* XXX: Change this function to use get_pubkeys instead of
|
||||||
|
get_pubkey_byname to detect ambiguous key specifications and warn
|
||||||
|
about duplicate keyblocks. For ambiguous key specifications on
|
||||||
|
the command line or provided interactively, prompt the user to
|
||||||
|
select the best key. If a key specification is ambiguous and we
|
||||||
|
are in batch mode, die. */
|
||||||
|
|
||||||
if (opt.encrypt_to_default_key)
|
if (opt.encrypt_to_default_key)
|
||||||
{
|
{
|
||||||
static int warned;
|
static int warned;
|
||||||
|
@ -120,6 +120,13 @@ build_sk_list (ctrl_t ctrl,
|
|||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
SK_LIST sk_list = NULL;
|
SK_LIST sk_list = NULL;
|
||||||
|
|
||||||
|
/* XXX: Change this function to use get_pubkeys instead of
|
||||||
|
getkey_byname to detect ambiguous key specifications and warn
|
||||||
|
about duplicate keyblocks. For ambiguous key specifications on
|
||||||
|
the command line or provided interactively, prompt the user to
|
||||||
|
select the best key. If a key specification is ambiguous and we
|
||||||
|
are in batch mode, die. */
|
||||||
|
|
||||||
if (!locusr) /* No user ids given - use the default key. */
|
if (!locusr) /* No user ids given - use the default key. */
|
||||||
{
|
{
|
||||||
PKT_public_key *pk;
|
PKT_public_key *pk;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user