gpg: Check for ambiguous or non-matching key specs.

* g10/gpg.c (check_user_ids): New function.
(main): Check that any user id specifications passed to --local-user
and --remote-user correspond to exactly 1 user.  Check that any user
id specifications passed to --default-key correspond to at most 1
user.  Warn if any user id specifications passed to --local-user or
--default-user are possible ambiguous (are not specified by long keyid
or fingerprint).
* g10/getkey.c (parse_def_secret_key): Don't warn about possible
ambiguous key descriptions here.

--
Signed-off-by: Neal H. Walfield <neal@g10code.com>
GnuPG-bug-id: 1128
Debian-debug-id: 544490
This commit is contained in:
Neal H. Walfield 2015-11-05 17:29:53 +01:00
parent f38bac8883
commit e8c53fca95
2 changed files with 189 additions and 28 deletions

View File

@ -1142,15 +1142,6 @@ parse_def_secret_key (ctrl_t ctrl)
continue;
}
if (! (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)
&& ! warned)
log_info (_("Warning: value '%s' for --default-key"
" should be a long keyid or a fingerprint.\n"),
t->d);
if (! hd)
hd = keydb_new ();
else

208
g10/gpg.c
View File

@ -2081,6 +2081,159 @@ get_default_configname (void)
return configname;
}
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;
if (! s)
return 0;
for (t = s; t; t = t->next)
{
const char *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);
char fingerprint[2 * MAX_FINGERPRINT_LEN + 1];
switch (t->flags >> 2)
{
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;
default: log_bug ("Unsupport option: %d\n", t->flags >> 2);
}
err = classify_user_id (t->d, &desc, 1);
if (err)
{
if (! rc)
rc = err;
log_error (_("Invalid value ('%s')."), t->d);
if (!opt.quiet)
log_info (_("(check argument of option '%s')\n"), option);
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 %s"
" should be a long keyid or a fingerprint.\n"),
t->d, option);
if (! hd)
hd = keydb_new ();
else
keydb_search_reset (hd);
err = keydb_search (hd, &desc, 1, NULL);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
{
if (error_if_not_found)
{
if (! rc)
rc = err;
log_error (_("no such key corresponding to '%s'\n"), t->d);
if (!opt.quiet)
log_info (_("(check argument of option '%s')\n"), option);
}
continue;
}
if (err)
{
if (! rc)
rc = err;
log_error (_("error looking up '%s' in keyring: %s.\n"),
t->d, gpg_strerror (err));
break;
}
err = keydb_get_keyblock (hd, &kb);
if (err)
{
if (! rc)
rc = err;
log_error (_("error reading key block for '%s': %s\n"),
t->d, gpg_strerror (err));
continue;
}
pk = kb->pkt->pkt.public_key;
fingerprint_from_pk (pk, fingerprint_bin, &fingerprint_bin_len);
assert (fingerprint_bin_len == sizeof (fingerprint_bin));
bin2hex (fingerprint_bin, MAX_FINGERPRINT_LEN, fingerprint);
add_to_strlist (&s2, fingerprint);
s2->flags = s->flags;
release_kbnode (kb);
/* Continue the search. */
err = keydb_search (hd, &desc, 1, NULL);
if (! (gpg_err_code (err) == GPG_ERR_NOT_FOUND
|| gpg_err_code (err) == GPG_ERR_EOF))
{
char fingerprint_bin2[MAX_FINGERPRINT_LEN];
size_t fingerprint_bin2_len = sizeof (fingerprint_bin2);
char fingerprint2[2 * MAX_FINGERPRINT_LEN + 1];
log_error (_("Error: the key specification '%s' is ambiguous.\n"),
t->d);
if (!opt.quiet)
log_info (_("(check argument of option '%s')\n"), option);
err = keydb_get_keyblock (hd, &kb);
if (err)
log_error (_("error reading key block for '%s': %s.\n"),
t->d, gpg_strerror (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);
log_error ("'%s' matches at least: %s and %s.\n",
t->d, fingerprint, fingerprint2);
release_kbnode (kb);
}
}
}
strlist_rev (&s2);
if (hd)
keydb_release (hd);
free_strlist (s);
*sp = s2;
return rc;
}
int
main (int argc, char **argv)
@ -2582,7 +2735,8 @@ main (int argc, char **argv)
#endif /*!NO_TRUST_MODELS*/
case oDefaultKey:
add_to_strlist (&opt.def_secret_key, pargs.r.ret_str);
sl = add_to_strlist (&opt.def_secret_key, pargs.r.ret_str);
sl->flags = (pargs.r_opt << 2);
break;
case oDefRecipient:
if( *pargs.r.ret_str )
@ -2774,22 +2928,23 @@ main (int argc, char **argv)
case oNoEncryptTo: opt.no_encrypt_to = 1; break;
case oEncryptTo: /* store the recipient in the second list */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = 1;
sl->flags = (pargs.r_opt << 2) | 1;
break;
case oHiddenEncryptTo: /* store the recipient in the second list */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = 1|2;
sl->flags = (pargs.r_opt << 2) | 1|2;
break;
case oEncryptToDefaultKey:
opt.encrypt_to_default_key = 1;
break;
case oRecipient: /* store the recipient */
add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = (pargs.r_opt << 2);
any_explicit_recipient = 1;
break;
case oHiddenRecipient: /* store the recipient with a flag */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = 2;
sl->flags = (pargs.r_opt << 2) | 2;
any_explicit_recipient = 1;
break;
@ -2832,7 +2987,8 @@ main (int argc, char **argv)
case oAskCertLevel: opt.ask_cert_level = 1; break;
case oNoAskCertLevel: opt.ask_cert_level = 0; break;
case oLocalUser: /* store the local users */
add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
sl = add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
sl->flags = (pargs.r_opt << 2);
break;
case oCompress:
/* this is the -z command line option */
@ -3740,19 +3896,33 @@ main (int argc, char **argv)
break;
}
if (opt.encrypt_to_default_key)
{
const char *default_key = parse_def_secret_key (ctrl);
if (default_key)
{
sl = add_to_strlist2 (&remusr, default_key, utf8_strings);
sl->flags = 1;
}
else if (opt.def_secret_key)
log_info (_("--encrypt-to-default-key specified, but no valid default keys specified.\n"));
else
log_info (_("--encrypt-to-default-key specified, but --default-key not specified.\n"));
}
{
int have_def_secret_key = opt.def_secret_key != NULL;
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);
if (opt.encrypt_to_default_key)
{
const char *default_key = parse_def_secret_key (ctrl);
if (default_key)
{
sl = add_to_strlist2 (&remusr, default_key, utf8_strings);
sl->flags = (oEncryptToDefaultKey << 2) | 1;
}
else if (have_def_secret_key)
log_info (_("--encrypt-to-default-key specified, but no valid default keys specified.\n"));
else
log_info (_("--encrypt-to-default-key specified, but --default-key not specified.\n"));
}
}
/* The command dispatcher. */
switch( cmd )