aboutsummaryrefslogtreecommitdiffstats
path: root/g10/getkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/getkey.c')
-rw-r--r--g10/getkey.c607
1 files changed, 148 insertions, 459 deletions
diff --git a/g10/getkey.c b/g10/getkey.c
index f0132bb08..c776a6100 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -60,7 +60,7 @@ struct getkey_ctx_s
search or not. A search that is exact requires that a key or
subkey meet all of the specified criteria. A search that is not
exact allows selecting a different key or subkey from the
- keyblock that matched the critera. Further, an exact search
+ keyblock that matched the criteria. Further, an exact search
returns the key or subkey that matched whereas a non-exact search
typically returns the primary key. See finish_lookup for
details. */
@@ -88,6 +88,9 @@ struct getkey_ctx_s
their address used in ITEMS. */
strlist_t extra_list;
+ /* Hack to return the mechanism (AKL_foo) used to find the key. */
+ int found_via_akl;
+
/* Part of the search criteria: The low-level search specification
as passed to keydb_search. */
int nitems;
@@ -391,280 +394,21 @@ getkey_disable_caches ()
}
-void
-pubkey_free (pubkey_t key)
-{
- if (key)
- {
- xfree (key->pk);
- release_kbnode (key->keyblock);
- xfree (key);
- }
-}
-
+/* Free a list of pubkey_t objects. */
void
pubkeys_free (pubkey_t keys)
{
while (keys)
{
pubkey_t next = keys->next;
- pubkey_free (keys);
+ xfree (keys->pk);
+ release_kbnode (keys->keyblock);
+ xfree (keys);
keys = next;
}
}
-/* Returns all keys that match the search specification 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.
- *
- * 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!
- *
- * Fixme: Currently, only PUBKEY_USAGE_ENC and PUBKEY_USAGE_SIG are
- * implemented. */
-gpg_error_t
-get_pubkeys (ctrl_t ctrl,
- char *search_terms, int use, int include_unusable, char *source,
- int warn_possibly_ambiguous,
- pubkey_t *r_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;
- gpg_error_t err;
- char *use_str; /* USE transformed to a string. */
- KEYDB_SEARCH_DESC desc;
- GETKEY_CTX ctx;
- pubkey_t results = NULL;
- pubkey_t 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 (*r_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 leave;
- }
-
- 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;
- KBNODE kb;
-
- pk = xtrycalloc (1, sizeof *pk);
- if (!pk)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
-
- pk->req_usage = use;
-
- if (! ctx)
- err = get_pubkey_byname (ctrl, &ctx, pk, search_terms, &kb, NULL,
- include_unusable, 1);
- else
- err = getkey_next (ctrl, 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 = xtrycalloc (1, sizeof (*r));
- if (!r)
- {
- err = gpg_error_from_syserror ();
- xfree (pk);
- goto leave;
- }
- r->pk = pk;
- r->keyblock = kb;
- r->next = results;
- results = r;
- }
- while (ctx);
- getkey_end (ctrl, 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 leave;
- }
- 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 leave;
- }
-
- /* 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)
- {
- pubkey_t *prevp;
- pubkey_t next;
- pubkey_t 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));
- }
-
- leave:
- if (err)
- pubkeys_free (results);
- else
- *r_keys = results;
-
- return err;
-}
-
-
static void
pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key)
{
@@ -677,6 +421,24 @@ pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key)
}
+/* Specialized version of get_pubkey which retrieves the key based on
+ * information in SIG. In contrast to get_pubkey PK is required. */
+gpg_error_t
+get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
+{
+ const byte *fpr;
+ size_t fprlen;
+
+ /* First try the new ISSUER_FPR info. */
+ fpr = issuer_fpr_raw (sig, &fprlen);
+ if (fpr && !get_pubkey_byfprint (ctrl, pk, NULL, fpr, fprlen))
+ return 0;
+
+ /* Fallback to use the ISSUER_KEYID. */
+ return get_pubkey (ctrl, pk, sig->keyid);
+}
+
+
/* Return the public key with the key id KEYID and store it at PK.
* The resources in *PK should be released using
* release_public_key_parts(). This function also stores a copy of
@@ -739,8 +501,9 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
/* Do a lookup. */
{
struct getkey_ctx_s ctx;
- KBNODE kb = NULL;
- KBNODE found_key = NULL;
+ kbnode_t kb = NULL;
+ kbnode_t found_key = NULL;
+
memset (&ctx, 0, sizeof ctx);
ctx.exact = 1; /* Use the key ID exactly as given. */
ctx.not_allocated = 1;
@@ -863,6 +626,28 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
}
+/* Return the entire keyblock used to create SIG. This is a
+ * specialized version of get_pubkeyblock.
+ *
+ * FIXME: This is a hack because get_pubkey_for_sig was already called
+ * and it could have used a cache to hold the key. */
+kbnode_t
+get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig)
+{
+ const byte *fpr;
+ size_t fprlen;
+ kbnode_t keyblock;
+
+ /* First try the new ISSUER_FPR info. */
+ fpr = issuer_fpr_raw (sig, &fprlen);
+ if (fpr && !get_pubkey_byfprint (ctrl, NULL, &keyblock, fpr, fprlen))
+ return keyblock;
+
+ /* Fallback to use the ISSUER_KEYID. */
+ return get_pubkeyblock (ctrl, sig->keyid);
+}
+
+
/* Return the key block for the key with key id KEYID or NULL, if an
* error occurs. Use release_kbnode() to release the key block.
*
@@ -1224,6 +1009,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
int is_mbox;
int nodefault = 0;
int anylocalfirst = 0;
+ int mechanism_type = AKL_NODEFAULT;
/* If RETCTX is not NULL, then RET_KDBHD must be NULL. */
log_assert (retctx == NULL || ret_kdbhd == NULL);
@@ -1313,18 +1099,19 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
size_t fpr_len;
int did_akl_local = 0;
int no_fingerprint = 0;
- const char *mechanism = "?";
+ const char *mechanism_string = "?";
- switch (akl->type)
+ mechanism_type = akl->type;
+ switch (mechanism_type)
{
case AKL_NODEFAULT:
/* This is a dummy mechanism. */
- mechanism = "None";
+ mechanism_string = "None";
rc = GPG_ERR_NO_PUBKEY;
break;
case AKL_LOCAL:
- mechanism = "Local";
+ mechanism_string = "Local";
did_akl_local = 1;
if (retctx)
{
@@ -1338,35 +1125,35 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
break;
case AKL_CERT:
- mechanism = "DNS CERT";
+ mechanism_string = "DNS CERT";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 0, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_PKA:
- mechanism = "PKA";
+ mechanism_string = "PKA";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_DANE:
- mechanism = "DANE";
+ mechanism_string = "DANE";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 1, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_WKD:
- mechanism = "WKD";
+ mechanism_string = "WKD";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_wkd (ctrl, name, 0, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_LDAP:
- mechanism = "LDAP";
+ mechanism_string = "LDAP";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
@@ -1379,7 +1166,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
* and getting a whole lot of keys back. */
if (keyserver_any_configured (ctrl))
{
- mechanism = "keyserver";
+ mechanism_string = "keyserver";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len,
opt.keyserver);
@@ -1387,7 +1174,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
}
else
{
- mechanism = "Unconfigured keyserver";
+ mechanism_string = "Unconfigured keyserver";
rc = GPG_ERR_NO_PUBKEY;
}
break;
@@ -1396,7 +1183,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
{
struct keyserver_spec *keyserver;
- mechanism = akl->spec->uri;
+ mechanism_string = akl->spec->uri;
keyserver = keyserver_match (akl->spec);
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl,
@@ -1458,13 +1245,13 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
/* Key found. */
if (opt.verbose)
log_info (_("automatically retrieved '%s' via %s\n"),
- name, mechanism);
+ name, mechanism_string);
break;
}
if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY
|| opt.verbose || no_fingerprint)
log_info (_("error retrieving '%s' via %s: %s\n"),
- name, mechanism,
+ name, mechanism_string,
no_fingerprint ? _("No fingerprint") : gpg_strerror (rc));
}
}
@@ -1480,6 +1267,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
{
log_assert (!(*retctx)->extra_list);
(*retctx)->extra_list = namelist;
+ (*retctx)->found_via_akl = mechanism_type;
}
else
free_strlist (namelist);
@@ -1527,6 +1315,34 @@ subkey_is_ok (const PKT_public_key *sub)
return ! sub->flags.revoked && sub->flags.valid && ! sub->flags.disabled;
}
+/* Return true if KEYBLOCK has only expired encryption subkyes. Note
+ * that the function returns false if the key has no encryption
+ * subkeys at all or the subkecys are revoked. */
+static int
+only_expired_enc_subkeys (kbnode_t keyblock)
+{
+ kbnode_t node;
+ PKT_public_key *sub;
+ int any = 0;
+
+ for (node = find_next_kbnode (keyblock, PKT_PUBLIC_SUBKEY);
+ node; node = find_next_kbnode (node, PKT_PUBLIC_SUBKEY))
+ {
+ sub = node->pkt->pkt.public_key;
+
+ if (!(sub->pubkey_usage & PUBKEY_USAGE_ENC))
+ continue;
+
+ if (!subkey_is_ok (sub))
+ continue;
+
+ any = 1;
+ if (!sub->has_expired)
+ return 0;
+ }
+
+ return any? 1 : 0;
+}
/* Finally this function compares a NEW key to the former candidate
* OLD. Returns < 0 if the old key is worse, > 0 if the old key is
@@ -1557,7 +1373,7 @@ pubkey_cmp (ctrl_t ctrl, const char *name, struct pubkey_cmp_cookie *old,
n; n = find_next_kbnode (n, PKT_USER_ID))
{
PKT_user_id *uid = n->pkt->pkt.user_id;
- char *mbox = mailbox_from_userid (uid->name);
+ char *mbox = mailbox_from_userid (uid->name, 0);
int match = mbox ? strcasecmp (name, mbox) == 0 : 0;
xfree (mbox);
@@ -1595,23 +1411,68 @@ pubkey_cmp (ctrl_t ctrl, const char *name, struct pubkey_cmp_cookie *old,
gpg_error_t
get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name, KBNODE *ret_keyblock,
- int include_unusable, int no_akl)
+ int include_unusable)
{
gpg_error_t err;
struct getkey_ctx_s *ctx = NULL;
+ int is_mbox = is_valid_mailbox (name);
+ int wkd_tried = 0;
if (retctx)
*retctx = NULL;
+ start_over:
+ if (ctx) /* Clear in case of a start over. */
+ {
+ if (ret_keyblock)
+ {
+ release_kbnode (*ret_keyblock);
+ *ret_keyblock = NULL;
+ }
+ getkey_end (ctrl, ctx);
+ ctx = NULL;
+ }
err = get_pubkey_byname (ctrl, &ctx, pk, name, ret_keyblock,
- NULL, include_unusable, no_akl);
+ NULL, include_unusable, 0);
if (err)
{
getkey_end (ctrl, ctx);
return err;
}
- if (is_valid_mailbox (name) && ctx)
+ /* If the keyblock was retrieved from the local database and the key
+ * has expired, do further checks. However, we can do this only if
+ * the caller requested a keyblock. */
+ if (is_mbox && ctx && ctx->found_via_akl == AKL_LOCAL && ret_keyblock)
+ {
+ u32 now = make_timestamp ();
+ PKT_public_key *pk2 = (*ret_keyblock)->pkt->pkt.public_key;
+ int found;
+
+ /* If the key has expired and its origin was the WKD then try to
+ * get a fresh key from the WKD. We also try this if the key
+ * has any only expired encryption subkeys. In case we checked
+ * for a fresh copy in the last 3 hours we won't do that again.
+ * Unfortunately that does not yet work because KEYUPDATE is
+ * only updated during import iff the key has actually changed
+ * (see import.c:import_one). */
+ if (!wkd_tried && pk2->keyorg == KEYORG_WKD
+ && (pk2->keyupdate + 3*3600) < now
+ && (pk2->has_expired || only_expired_enc_subkeys (*ret_keyblock)))
+ {
+ if (opt.verbose)
+ log_info (_("checking for a fresh copy of an expired key via %s\n"),
+ "WKD");
+ wkd_tried = 1;
+ glo_ctrl.in_auto_key_retrieve++;
+ found = !keyserver_import_wkd (ctrl, name, 0, NULL, NULL);
+ glo_ctrl.in_auto_key_retrieve--;
+ if (found)
+ goto start_over;
+ }
+ }
+
+ if (is_mbox && ctx)
{
/* Rank results and return only the most relevant key. */
struct pubkey_cmp_cookie best = { 0 };
@@ -1802,6 +1663,8 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
memset (&ctx, 0, sizeof ctx);
ctx.exact = 1;
ctx.not_allocated = 1;
+ /* FIXME: We should get the handle from the cache like we do in
+ * get_pubkey. */
ctx.kr_handle = keydb_new ();
if (!ctx.kr_handle)
return gpg_error_from_syserror ();
@@ -3501,7 +3364,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
*
* 1. No requested usage and no primary key requested
* Examples for this case are that we have a keyID to be used
- * for decrytion or verification.
+ * for decryption or verification.
* 2. No usage but primary key requested
* This is the case for all functions which work on an
* entire keyblock, e.g. for editing or listing
@@ -3904,180 +3767,6 @@ lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret,
}
-/* Enumerate some secret keys (specifically, those specified with
- * --default-key and --try-secret-key). Use the following procedure:
- *
- * 1) Initialize a void pointer to NULL
- * 2) Pass a reference to this pointer to this function (content)
- * and provide space for the secret key (sk)
- * 3) Call this function as long as it does not return an error (or
- * until you are done). The error code GPG_ERR_EOF indicates the
- * end of the listing.
- * 4) Call this function a last time with SK set to NULL,
- * so that can free it's context.
- *
- * In pseudo-code:
- *
- * void *ctx = NULL;
- * PKT_public_key *sk = xmalloc_clear (sizeof (*sk));
- *
- * while ((err = enum_secret_keys (&ctx, sk)))
- * { // Process SK.
- * if (done)
- * break;
- * free_public_key (sk);
- * sk = xmalloc_clear (sizeof (*sk));
- * }
- *
- * // Release any resources used by CTX.
- * enum_secret_keys (&ctx, NULL);
- * free_public_key (sk);
- *
- * if (gpg_err_code (err) != GPG_ERR_EOF)
- * ; // An error occurred.
- */
-gpg_error_t
-enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
-{
- gpg_error_t err = 0;
- const char *name;
- kbnode_t keyblock;
- struct
- {
- int eof;
- int state;
- strlist_t sl;
- kbnode_t keyblock;
- kbnode_t node;
- getkey_ctx_t ctx;
- } *c = *context;
-
- if (!c)
- {
- /* Make a new context. */
- c = xtrycalloc (1, sizeof *c);
- if (!c)
- return gpg_error_from_syserror ();
- *context = c;
- }
-
- if (!sk)
- {
- /* Free the context. */
- release_kbnode (c->keyblock);
- getkey_end (ctrl, c->ctx);
- xfree (c);
- *context = NULL;
- return 0;
- }
-
- if (c->eof)
- return gpg_error (GPG_ERR_EOF);
-
- for (;;)
- {
- /* Loop until we have a keyblock. */
- while (!c->keyblock)
- {
- /* Loop over the list of secret keys. */
- do
- {
- name = NULL;
- keyblock = NULL;
- switch (c->state)
- {
- case 0: /* First try to use the --default-key. */
- name = parse_def_secret_key (ctrl);
- c->state = 1;
- break;
-
- case 1: /* Init list of keys to try. */
- c->sl = opt.secret_keys_to_try;
- c->state++;
- break;
-
- case 2: /* Get next item from list. */
- if (c->sl)
- {
- name = c->sl->d;
- c->sl = c->sl->next;
- }
- else
- c->state++;
- break;
-
- case 3: /* Init search context to enum all secret keys. */
- err = getkey_bynames (ctrl, &c->ctx, NULL, NULL, 1,
- &keyblock);
- if (err)
- {
- release_kbnode (keyblock);
- keyblock = NULL;
- getkey_end (ctrl, c->ctx);
- c->ctx = NULL;
- }
- c->state++;
- break;
-
- case 4: /* Get next item from the context. */
- if (c->ctx)
- {
- err = getkey_next (ctrl, c->ctx, NULL, &keyblock);
- if (err)
- {
- release_kbnode (keyblock);
- keyblock = NULL;
- getkey_end (ctrl, c->ctx);
- c->ctx = NULL;
- }
- }
- else
- c->state++;
- break;
-
- default: /* No more names to check - stop. */
- c->eof = 1;
- return gpg_error (GPG_ERR_EOF);
- }
- }
- while ((!name || !*name) && !keyblock);
-
- if (keyblock)
- c->node = c->keyblock = keyblock;
- else
- {
- err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
- if (err)
- {
- /* getkey_byname might return a keyblock even in the
- error case - I have not checked. Thus better release
- it. */
- release_kbnode (c->keyblock);
- c->keyblock = NULL;
- }
- else
- c->node = c->keyblock;
- }
- }
-
- /* Get the next key from the current keyblock. */
- for (; c->node; c->node = c->node->next)
- {
- if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
- || c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
- {
- copy_public_key (sk, c->node->pkt->pkt.public_key);
- c->node = c->node->next;
- return 0; /* Found. */
- }
- }
-
- /* Dispose the keyblock and continue. */
- release_kbnode (c->keyblock);
- c->keyblock = NULL;
- }
-}
-
gpg_error_t
get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk,
const byte *fpr_card, size_t fpr_len)