diff options
Diffstat (limited to 'g10/getkey.c')
-rw-r--r-- | g10/getkey.c | 607 |
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) |