gpg: Allow multiple --default-key options. Take the last available key.

* g10/getkey.c (parse_def_secret_key): New function.
(get_seckey_default): Add parameter ctrl.  Update callers.  Use
parse_def_secret_key to get the default secret key, if any.
(getkey_byname): Likewise.
(enum_secret_keys): Likewise.
* g10/options.h (opt): Change def_secret_key's type from a char * to a
strlist_t.
* g10/gpg.c (main): When processing --default-key, add the key to
OPT.DEF_SECRET_KEY.
* g10/gpgv.c (get_session_key): Add parameter ctrl.  Update callers.
* g10/mainproc.c (proc_pubkey_enc): Likewise.
(do_proc_packets): Likewise.
* g10/pkclist.c (default_recipient): Likewise.
* g10/pubkey-enc.c (get_session_key): Likewise.
* g10/sign.c (clearsign_file): Likewise.
(sign_symencrypt_file): Likewise.
* g10/skclist.c (build_sk_list): Likewise.
* g10/test-stubs.c (get_session_key): Likewise.

--
Signed-off-by: Neal H. Walield <neal@g10code.com>
GnuPG-bug-id: 806
This commit is contained in:
Neal H. Walfield 2015-11-03 23:15:27 +01:00
parent 1e94a672ef
commit e16d7168c5
16 changed files with 145 additions and 53 deletions

View File

@ -993,6 +993,10 @@ in the option file.
Use @var{name} as the default key to sign with. If this option is not
used, the default key is the first key found in the secret keyring.
Note that @option{-u} or @option{--local-user} overrides this option.
This option may be given multiple times. In this case, the last key
for which a secret key is available is used. If there is no secret
key available for any of the specified values, GnuPG will not emit an
error message but continue as if this option wasn't given.
@item --default-recipient @var{name}
@opindex default-recipient

View File

@ -1121,17 +1121,93 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
return 0;
}
static const char *
parse_def_secret_key (ctrl_t ctrl)
{
KEYDB_HANDLE hd = NULL;
strlist_t t;
static int warned;
for (t = opt.def_secret_key; t; t = t->next)
{
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
KBNODE kb;
err = classify_user_id (t->d, &desc, 1);
if (err)
{
log_error (_("Invalid value ('%s') for --default-key.\n"),
t->d);
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
keydb_search_reset (hd);
err = keydb_search (hd, &desc, 1, NULL);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
continue;
if (err)
{
log_error (_("Error reading from keyring: %s.\n"),
gpg_strerror (err));
t = NULL;
break;
}
err = keydb_get_keyblock (hd, &kb);
if (err)
{
log_error (_("error reading keyblock: %s\n"),
gpg_strerror (err));
continue;
}
err = agent_probe_secret_key (ctrl, kb->pkt->pkt.public_key);
release_kbnode (kb);
if (! err)
{
if (! warned)
log_debug (_("Using %s as default secret key.\n"), t->d);
break;
}
}
warned = 1;
if (hd)
keydb_release (hd);
if (t)
return t->d;
return NULL;
}
/* For documentation see keydb.h. */
gpg_error_t
get_seckey_default (PKT_public_key *pk)
get_seckey_default (ctrl_t ctrl, PKT_public_key *pk)
{
gpg_error_t err;
strlist_t namelist = NULL;
int include_unusable = 1;
if (opt.def_secret_key && *opt.def_secret_key)
add_to_strlist (&namelist, opt.def_secret_key);
const char *def_secret_key = parse_def_secret_key (ctrl);
if (def_secret_key)
add_to_strlist (&namelist, def_secret_key);
else
include_unusable = 0;
@ -1154,15 +1230,19 @@ getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
/* For documentation see keydb.h. */
gpg_error_t
getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk,
getkey_byname (ctrl_t ctrl, getkey_ctx_t *retctx, PKT_public_key *pk,
const char *name, int want_secret, kbnode_t *ret_keyblock)
{
gpg_error_t err;
strlist_t namelist = NULL;
int with_unusable = 1;
const char *def_secret_key = NULL;
if (want_secret && !name && opt.def_secret_key && *opt.def_secret_key)
add_to_strlist (&namelist, opt.def_secret_key);
if (want_secret && !name)
def_secret_key = parse_def_secret_key (ctrl);
if (want_secret && !name && def_secret_key)
add_to_strlist (&namelist, def_secret_key);
else if (name)
add_to_strlist (&namelist, name);
else
@ -2737,7 +2817,7 @@ found:
/* For documentation see keydb.h. */
gpg_error_t
enum_secret_keys (void **context, PKT_public_key *sk)
enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
{
gpg_error_t err = 0;
const char *name;
@ -2783,8 +2863,7 @@ enum_secret_keys (void **context, PKT_public_key *sk)
switch (c->state)
{
case 0: /* First try to use the --default-key. */
if (opt.def_secret_key && *opt.def_secret_key)
name = opt.def_secret_key;
name = parse_def_secret_key (ctrl);
c->state = 1;
break;
@ -2810,7 +2889,7 @@ enum_secret_keys (void **context, PKT_public_key *sk)
}
while (!name || !*name);
err = getkey_byname (NULL, NULL, name, 1, &c->keyblock);
err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
if (err)
{
/* getkey_byname might return a keyblock even in the

View File

@ -2577,7 +2577,9 @@ main (int argc, char **argv)
case oTrustDBName: trustdb_name = pargs.r.ret_str; break;
#endif /*!NO_TRUST_MODELS*/
case oDefaultKey: opt.def_secret_key = pargs.r.ret_str; break;
case oDefaultKey:
add_to_strlist (&opt.def_secret_key, pargs.r.ret_str);
break;
case oDefRecipient:
if( *pargs.r.ret_str )
{
@ -3865,7 +3867,7 @@ main (int argc, char **argv)
case aSignSym: /* sign and conventionally encrypt the given file */
if (argc > 1)
wrong_args(_("--sign --symmetric [filename]"));
rc = sign_symencrypt_file (fname, locusr);
rc = sign_symencrypt_file (ctrl, fname, locusr);
if (rc)
{
write_status_failure ("sign-symencrypt", rc);
@ -3877,7 +3879,7 @@ main (int argc, char **argv)
case aClearsign: /* make a clearsig */
if( argc > 1 )
wrong_args(_("--clearsign [filename]"));
if( (rc = clearsign_file(fname, locusr, NULL)) )
if( (rc = clearsign_file (ctrl, fname, locusr, NULL)) )
{
write_status_failure ("sign", rc);
log_error("%s: clearsign failed: %s\n",

View File

@ -386,8 +386,9 @@ keyserver_import_ldap (const char *name)
* No encryption here but mainproc links to these functions.
*/
gpg_error_t
get_session_key (PKT_pubkey_enc *k, DEK *dek)
get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek)
{
(void)ctrl;
(void)k;
(void)dek;
return GPG_ERR_GENERAL;

View File

@ -364,8 +364,8 @@ void warn_missing_aes_from_pklist (PK_LIST pk_list);
/*-- skclist.c --*/
int random_is_faked (void);
void release_sk_list( SK_LIST sk_list );
gpg_error_t build_sk_list (strlist_t locusr, SK_LIST *ret_sk_list,
unsigned use);
gpg_error_t build_sk_list (ctrl_t ctrl, strlist_t locusr,
SK_LIST *ret_sk_list, unsigned use);
/*-- passphrase.h --*/
unsigned char encode_s2k_iterations (int iterations);
@ -605,7 +605,7 @@ int have_secret_key_with_kid (u32 *keyid);
This function returns the first match. Additional results can be
returned using getkey_next. */
gpg_error_t get_seckey_default (PKT_public_key *pk);
gpg_error_t get_seckey_default (ctrl_t ctrl, PKT_public_key *pk);
/* Search for keys matching some criteria.
@ -686,7 +686,8 @@ gpg_error_t getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
FIXME: We also have the get_pubkey_byname function which has a
different semantic. Should be merged with this one. */
gpg_error_t getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk,
gpg_error_t getkey_byname (ctrl_t ctrl,
getkey_ctx_t *retctx, PKT_public_key *pk,
const char *name, int want_secret,
kbnode_t *ret_keyblock);
@ -748,7 +749,7 @@ KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx);
if (gpg_err_code (err) != GPG_ERR_EOF)
; // An error occured.
*/
gpg_error_t enum_secret_keys (void **context, PKT_public_key *pk);
gpg_error_t enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *pk);
/* Set the mainkey_id fields for all keys in KEYBLOCK. This is
usually done by merge_selfsigs but at some places we only need the

View File

@ -565,7 +565,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
* why to sign keys using a subkey. Implementation of USAGE_CERT
* is just a hack in getkey.c and does not mean that a subkey
* marked as certification capable will be used. */
rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_CERT);
rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
if (rc)
goto leave;
@ -2319,7 +2319,7 @@ keyedit_passwd (ctrl_t ctrl, const char *username)
err = gpg_error_from_syserror ();
goto leave;
}
err = getkey_byname (NULL, pk, username, 1, &keyblock);
err = getkey_byname (ctrl, NULL, pk, username, 1, &keyblock);
if (err)
goto leave;

View File

@ -236,8 +236,9 @@ int complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md,
const char *cache_nonce);
int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
int do_encrypt, strlist_t remusr, const char *outfile );
int clearsign_file( const char *fname, strlist_t locusr, const char *outfile );
int sign_symencrypt_file (const char *fname, strlist_t locusr);
int clearsign_file (ctrl_t ctrl,
const char *fname, strlist_t locusr, const char *outfile);
int sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr);
/*-- sig-check.c --*/

View File

@ -106,7 +106,7 @@ struct mainproc_context
/*** Local prototypes. ***/
static int do_proc_packets (CTX c, iobuf_t a);
static int do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a);
static void list_node (CTX c, kbnode_t node);
static void proc_tree (CTX c, kbnode_t node);
static int literals_seen;
@ -366,7 +366,7 @@ proc_symkey_enc (CTX c, PACKET *pkt)
static void
proc_pubkey_enc (CTX c, PACKET *pkt)
proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt)
{
PKT_pubkey_enc *enc;
int result = 0;
@ -428,7 +428,7 @@ proc_pubkey_enc (CTX c, PACKET *pkt)
else
{
c->dek = xmalloc_secure_clear (sizeof *c->dek);
if ((result = get_session_key (enc, c->dek)))
if ((result = get_session_key (ctrl, enc, c->dek)))
{
/* Error: Delete the DEK. */
xfree (c->dek);
@ -1195,7 +1195,7 @@ proc_packets (ctrl_t ctrl, void *anchor, iobuf_t a )
c->ctrl = ctrl;
c->anchor = anchor;
rc = do_proc_packets (c, a);
rc = do_proc_packets (ctrl, c, a);
xfree (c);
return rc;
@ -1218,7 +1218,7 @@ proc_signature_packets (ctrl_t ctrl, void *anchor, iobuf_t a,
c->signed_data.used = !!signedfiles;
c->sigfilename = sigfilename;
rc = do_proc_packets ( c, a );
rc = do_proc_packets (ctrl, c, a);
/* If we have not encountered any signature we print an error
messages, send a NODATA status back and return an error code.
@ -1261,7 +1261,7 @@ proc_signature_packets_by_fd (ctrl_t ctrl,
c->signed_data.data_names = NULL;
c->signed_data.used = (signed_data_fd != -1);
rc = do_proc_packets ( c, a );
rc = do_proc_packets (ctrl, c, a);
/* If we have not encountered any signature we print an error
messages, send a NODATA status back and return an error code.
@ -1294,7 +1294,7 @@ proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a )
c->ctrl = ctrl;
c->anchor = anchor;
c->encrypt_only = 1;
rc = do_proc_packets (c, a);
rc = do_proc_packets (ctrl, c, a);
xfree (c);
return rc;
}
@ -1320,7 +1320,7 @@ check_nesting (CTX c)
static int
do_proc_packets (CTX c, iobuf_t a)
do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
{
PACKET *pkt;
int rc = 0;
@ -1352,7 +1352,7 @@ do_proc_packets (CTX c, iobuf_t a)
{
switch (pkt->pkttype)
{
case PKT_PUBKEY_ENC: proc_pubkey_enc (c, pkt); break;
case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break;
case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break;
case PKT_ENCRYPTED:
case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break;
@ -1396,7 +1396,7 @@ do_proc_packets (CTX c, iobuf_t a)
case PKT_SIGNATURE: newpkt = add_signature (c, pkt); break;
case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break;
case PKT_PUBKEY_ENC: proc_pubkey_enc (c, pkt); break;
case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break;
case PKT_ENCRYPTED:
case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break;
case PKT_PLAINTEXT: proc_plaintext (c, pkt); break;
@ -1422,7 +1422,7 @@ do_proc_packets (CTX c, iobuf_t a)
break;
case PKT_USER_ID: newpkt = add_user_id (c, pkt); break;
case PKT_SIGNATURE: newpkt = add_signature (c, pkt); break;
case PKT_PUBKEY_ENC: proc_pubkey_enc (c, pkt); break;
case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break;
case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break;
case PKT_ENCRYPTED:
case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break;

View File

@ -1,6 +1,7 @@
/* options.h
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007, 2010, 2011 Free Software Foundation, Inc.
* Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -87,7 +88,7 @@ struct
int compress_level;
int bz2_compress_level;
int bz2_decompress_lowmem;
const char *def_secret_key;
strlist_t def_secret_key;
char *def_recipient;
int def_recipient_self;
strlist_t secret_keys_to_try;

View File

@ -652,7 +652,7 @@ int check_signature2 (PKT_signature *sig, gcry_md_hd_t digest,
/*-- pubkey-enc.c --*/
gpg_error_t get_session_key (PKT_pubkey_enc *k, DEK *dek);
gpg_error_t get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek);
gpg_error_t get_override_session_key (DEK *dek, const char *string);
/*-- compress.c --*/

View File

@ -702,7 +702,7 @@ key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk)
* Return a malloced string with a default recipient if there is any
*/
static char *
default_recipient(void)
default_recipient(ctrl_t ctrl)
{
PKT_public_key *pk;
byte fpr[MAX_FINGERPRINT_LEN+1];
@ -715,7 +715,7 @@ default_recipient(void)
if( !opt.def_recipient_self )
return NULL;
pk = xmalloc_clear( sizeof *pk );
i = get_seckey_default (pk);
i = get_seckey_default (ctrl, pk);
if( i ) {
free_public_key( pk );
return NULL;
@ -1010,7 +1010,7 @@ build_pk_list (ctrl_t ctrl,
if (pk_list)
any_recipients = 1;
def_rec = default_recipient();
def_rec = default_recipient(ctrl);
have_def_rec = !!def_rec;
if ( !have_def_rec )
tty_printf(_("You did not specify a user ID. (you may use \"-r\")\n"));
@ -1153,7 +1153,7 @@ build_pk_list (ctrl_t ctrl,
pk = NULL;
}
}
else if ( !any_recipients && (def_rec = default_recipient()) )
else if ( !any_recipients && (def_rec = default_recipient(ctrl)) )
{
/* We are in batch mode and have only a default recipient. */
pk = xmalloc_clear( sizeof *pk );

View File

@ -72,7 +72,7 @@ is_algo_in_prefs (kbnode_t keyblock, preftype_t type, int algo)
* which should have been allocated in secure memory by the caller.
*/
gpg_error_t
get_session_key (PKT_pubkey_enc * k, DEK * dek)
get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
{
PKT_public_key *sk = NULL;
int rc;
@ -102,7 +102,7 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
{
free_public_key (sk);
sk = xmalloc_clear (sizeof *sk);
rc = enum_secret_keys (&enum_context, sk);
rc = enum_secret_keys (ctrl, &enum_context, sk);
if (rc)
{
rc = GPG_ERR_NO_SECKEY;
@ -127,7 +127,7 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
break; /* Don't try any more secret keys. */
}
enum_secret_keys (&enum_context, NULL); /* free context */
enum_secret_keys (ctrl, &enum_context, NULL); /* free context */
}
leave:

View File

@ -248,7 +248,7 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
if(locusr)
{
rc=build_sk_list(locusr, &sk_list, PUBKEY_USAGE_CERT);
rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
if(rc)
goto leave;
}

View File

@ -769,7 +769,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
/* Note: In the old non-agent version the following call used to
unprotect the secret key. This is now done on demand by the agent. */
if( (rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_SIG )) )
if( (rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) )
goto leave;
if (encryptflag
@ -1057,7 +1057,8 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
* make a clear signature. note that opt.armor is not needed
*/
int
clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
clearsign_file (ctrl_t ctrl,
const char *fname, strlist_t locusr, const char *outfile )
{
armor_filter_context_t *afx;
progress_filter_context_t *pfx;
@ -1080,7 +1081,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
/* Note: In the old non-agent version the following call used to
unprotect the secret key. This is now done on demand by the agent. */
if( (rc=build_sk_list( locusr, &sk_list, PUBKEY_USAGE_SIG )) )
if( (rc=build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) )
goto leave;
/* prepare iobufs */
@ -1191,7 +1192,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
* FIXME: Far too much code is duplicated - revamp the whole file.
*/
int
sign_symencrypt_file (const char *fname, strlist_t locusr)
sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
{
armor_filter_context_t *afx;
progress_filter_context_t *pfx;
@ -1224,7 +1225,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
/* Note: In the old non-agent version the following call used to
unprotect the secret key. This is now done on demand by the agent. */
rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_SIG);
rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG);
if (rc)
goto leave;

View File

@ -114,7 +114,8 @@ is_duplicated_entry (strlist_t list, strlist_t item)
gpg_error_t
build_sk_list (strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
build_sk_list (ctrl_t ctrl,
strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
{
gpg_error_t err;
SK_LIST sk_list = NULL;
@ -125,7 +126,7 @@ build_sk_list (strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
pk = xmalloc_clear (sizeof *pk);
pk->req_usage = use;
if ((err = getkey_byname (NULL, pk, NULL, 1, NULL)))
if ((err = getkey_byname (ctrl, NULL, pk, NULL, 1, NULL)))
{
free_public_key (pk);
pk = NULL;
@ -182,7 +183,7 @@ build_sk_list (strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
}
pk = xmalloc_clear (sizeof *pk);
pk->req_usage = use;
if ((err = getkey_byname (NULL, pk, locusr->d, 1, NULL)))
if ((err = getkey_byname (ctrl, NULL, pk, locusr->d, 1, NULL)))
{
free_public_key (pk);
pk = NULL;

View File

@ -198,8 +198,9 @@ keyserver_import_ldap (const char *name)
* No encryption here but mainproc links to these functions.
*/
gpg_error_t
get_session_key (PKT_pubkey_enc *k, DEK *dek)
get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek)
{
(void)ctrl;
(void)k;
(void)dek;
return GPG_ERR_GENERAL;