From fbb2259d22e6c6eadc2af722bdc52922da348677 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 22 May 2017 09:27:36 +0900 Subject: [PATCH] g10: Fix default-key selection for signing, possibly by card. * g10/call-agent.c (warn_version_mismatch): Revert. (start_agent): Suppress version mismatch if relevant. * g10/getkey.c (get_seckey_default_or_card): New. * g10/skclist.c (build_sk_list): Use get_seckey_default_or_card. -- The change of 97a2394, which prefers available card than default key specified is too strong. Fixes-commit: 97a2394ecafaa6f58e4a1f70ecfd04408dc15606 Signed-off-by: NIIBE Yutaka --- g10/call-agent.c | 8 ++++---- g10/getkey.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ g10/keydb.h | 2 ++ g10/skclist.c | 16 ++++----------- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index 4698a25a7..e6dbb7347 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -184,8 +184,7 @@ default_inq_cb (void *opaque, const char *line) /* Print a warning if the server's version number is less than our - version number. Returns an error code on a connection problem. - Ignore an error for scdaemon (MODE==2). */ + version number. Returns an error code on a connection problem. */ static gpg_error_t warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode) { @@ -194,7 +193,7 @@ warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode) const char *myversion = strusage (13); err = get_assuan_server_version (ctx, mode, &serverversion); - if (err && mode != 2) + if (err) log_error (_("error getting version from '%s': %s\n"), servername, gpg_strerror (err)); else if (compare_version_strings (serverversion, myversion) < 0) @@ -290,7 +289,8 @@ start_agent (ctrl_t ctrl, int flag_for_card) memset (&info, 0, sizeof info); - rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2); + if (!(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS)) + rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2); if (!rc) rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp", NULL, NULL, NULL, NULL, diff --git a/g10/getkey.c b/g10/getkey.c index d8c81c937..04ecf4fc8 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -3960,6 +3960,58 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk) } } +gpg_error_t +get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk, + const byte *fpr_card, size_t fpr_len) +{ + gpg_error_t err; + strlist_t namelist = NULL; + + const char *def_secret_key = parse_def_secret_key (ctrl); + + if (def_secret_key) + add_to_strlist (&namelist, def_secret_key); + else if (fpr_card) + return get_pubkey_byfprint (ctrl, pk, NULL, fpr_card, fpr_len); + + if (!fpr_card + || (def_secret_key && def_secret_key[strlen (def_secret_key)-1] == '!')) + err = key_byname (ctrl, NULL, namelist, pk, 1, 0, NULL, NULL); + else + { /* Default key is specified and card key is also available. */ + kbnode_t k, keyblock = NULL; + + err = key_byname (ctrl, NULL, namelist, pk, 1, 0, &keyblock, NULL); + if (!err) + for (k = keyblock; k; k = k->next) + { + PKT_public_key *pk_candidate; + char fpr[MAX_FINGERPRINT_LEN]; + + if (k->pkt->pkttype != PKT_PUBLIC_KEY + &&k->pkt->pkttype != PKT_PUBLIC_SUBKEY) + continue; + + pk_candidate = k->pkt->pkt.public_key; + if (!pk_candidate->flags.valid) + continue; + if (!((pk_candidate->pubkey_usage & USAGE_MASK) & pk->req_usage)) + continue; + fingerprint_from_pk (pk_candidate, fpr, NULL); + if (!memcmp (fpr_card, fpr, fpr_len)) + { + release_public_key_parts (pk); + copy_public_key (pk, pk_candidate); + break; + } + } + release_kbnode (keyblock); + } + + free_strlist (namelist); + + return err; +} /********************************************* *********** User ID printing helpers ******* diff --git a/g10/keydb.h b/g10/keydb.h index 1da93a777..40167230c 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -351,6 +351,8 @@ const char *parse_def_secret_key (ctrl_t ctrl); /* Look up a secret key. */ gpg_error_t get_seckey_default (ctrl_t ctrl, PKT_public_key *pk); +gpg_error_t get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk, + const byte *fpr, size_t fpr_len); /* Search for keys matching some criteria. */ gpg_error_t getkey_bynames (ctrl_t ctrl, diff --git a/g10/skclist.c b/g10/skclist.c index 489277ca5..78890dc42 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -137,7 +137,7 @@ build_sk_list (ctrl_t ctrl, pk = xmalloc_clear (sizeof *pk); pk->req_usage = use; - /* Check if a card is available. If any, use it. */ + /* Check if a card is available. If any, use the key as a hint. */ err = agent_scd_serialno (&serialno, NULL); if (!err) { @@ -146,19 +146,11 @@ build_sk_list (ctrl_t ctrl, if (err) log_error ("error retrieving key fingerprint from card: %s\n", gpg_strerror (err)); - else if (info.fpr1valid) - { - if ((err = get_pubkey_byfprint (ctrl, pk, NULL, info.fpr1, 20))) - { - info.fpr1valid = 0; - log_error ("error on card key to sign: %s, try default\n", - gpg_strerror (err)); - } - } } - if (!info.fpr1valid - && (err = getkey_byname (ctrl, NULL, pk, NULL, 1, NULL))) + err = get_seckey_default_or_card (ctrl, pk, + info.fpr1valid? info.fpr1 : NULL, 20); + if (err) { free_public_key (pk); pk = NULL;