diff options
-rw-r--r-- | g10/getkey.c | 174 | ||||
-rw-r--r-- | g10/gpgv.c | 2 | ||||
-rw-r--r-- | g10/mainproc.c | 165 | ||||
-rw-r--r-- | g10/packet.h | 12 | ||||
-rw-r--r-- | g10/pubkey-enc.c | 116 | ||||
-rw-r--r-- | g10/skclist.c | 251 | ||||
-rw-r--r-- | g10/test-stubs.c | 2 |
7 files changed, 378 insertions, 344 deletions
diff --git a/g10/getkey.c b/g10/getkey.c index 08e17e930..41afeb9e8 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -3947,180 +3947,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) diff --git a/g10/gpgv.c b/g10/gpgv.c index c142cef86..b33590655 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -490,7 +490,7 @@ read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock) * No encryption here but mainproc links to these functions. */ gpg_error_t -get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek) +get_session_key (ctrl_t ctrl, struct pubkey_enc_list *k, DEK *dek) { (void)ctrl; (void)k; diff --git a/g10/mainproc.c b/g10/mainproc.c index 1d56f1f30..dcf7dee01 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -46,16 +46,6 @@ #define MAX_NESTING_DEPTH 32 -/* An object to build a list of keyid related info. */ -struct kidlist_item -{ - struct kidlist_item *next; - u32 kid[2]; - int pubkey_algo; - int reason; -}; - - /* * Object to hold the processing context. */ @@ -95,7 +85,7 @@ struct mainproc_context iobuf_t iobuf; /* Used to get the filename etc. */ int trustletter; /* Temporary usage in list_node. */ ulong symkeys; /* Number of symmetrically encrypted session keys. */ - struct kidlist_item *pkenc_list; /* List of encryption packets. */ + struct pubkey_enc_list *pkenc_list; /* List of encryption packets. */ struct { unsigned int sig_seen:1; /* Set to true if a signature packet has been seen. */ @@ -135,7 +125,10 @@ release_list( CTX c ) release_kbnode (c->list); while (c->pkenc_list) { - struct kidlist_item *tmp = c->pkenc_list->next; + struct pubkey_enc_list *tmp = c->pkenc_list->next; + + mpi_release (c->pkenc_list->data[0]); + mpi_release (c->pkenc_list->data[1]); xfree (c->pkenc_list); c->pkenc_list = tmp; } @@ -461,7 +454,7 @@ static void proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt) { PKT_pubkey_enc *enc; - int result = 0; + struct pubkey_enc_list *x = xmalloc (sizeof *x); /* Check whether the secret key is available and store in this case. */ c->last_was_session_key = 1; @@ -472,76 +465,27 @@ proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt) if (opt.verbose) log_info (_("public key is %s\n"), keystr (enc->keyid)); - if (is_status_enabled()) + if (is_status_enabled ()) { char buf[50]; snprintf (buf, sizeof buf, "%08lX%08lX %d 0", - (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo); + (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo); write_status_text (STATUS_ENC_TO, buf); } - if (!opt.list_only && opt.override_session_key) - { - /* It does not make much sense to store the session key in - * secure memory because it has already been passed on the - * command line and the GCHQ knows about it. */ - c->dek = xmalloc_clear (sizeof *c->dek); - result = get_override_session_key (c->dek, opt.override_session_key); - if (result) - { - xfree (c->dek); - c->dek = NULL; - } - } - else if (enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E - || enc->pubkey_algo == PUBKEY_ALGO_ECDH - || enc->pubkey_algo == PUBKEY_ALGO_RSA - || enc->pubkey_algo == PUBKEY_ALGO_RSA_E - || enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL) - { - /* Note that we also allow type 20 Elgamal keys for decryption. - There are still a couple of those keys in active use as a - subkey. */ - - /* FIXME: Store this all in a list and process it later so that - we can prioritize what key to use. This gives a better user - experience if wildcard keyids are used. */ - if (!c->dek && ((!enc->keyid[0] && !enc->keyid[1]) - || opt.try_all_secrets - || have_secret_key_with_kid (enc->keyid))) - { - if(opt.list_only) - result = GPG_ERR_MISSING_ACTION; /* fixme: Use better error code. */ - else - { - c->dek = xmalloc_secure_clear (sizeof *c->dek); - if ((result = get_session_key (ctrl, enc, c->dek))) - { - /* Error: Delete the DEK. */ - xfree (c->dek); - c->dek = NULL; - } - } - } - else - result = GPG_ERR_NO_SECKEY; - } - else - result = GPG_ERR_PUBKEY_ALGO; - - if (1) + if (!opt.list_only && !opt.override_session_key) { - /* Store it for later display. */ - struct kidlist_item *x = xmalloc (sizeof *x); - x->kid[0] = enc->keyid[0]; - x->kid[1] = enc->keyid[1]; + x->keyid[0] = enc->keyid[0]; + x->keyid[1] = enc->keyid[1]; x->pubkey_algo = enc->pubkey_algo; - x->reason = result; + x->data[0] = x->data[1] = NULL; + if (enc->data[0]) + { + x->data[0] = mpi_copy (enc->data[0]); + x->data[1] = mpi_copy (enc->data[1]); + } x->next = c->pkenc_list; c->pkenc_list = x; - - if (!result && opt.verbose > 1) - log_info (_("public key encrypted data: good DEK\n")); } free_packet(pkt, NULL); @@ -553,60 +497,34 @@ proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt) * not decrypt. */ static void -print_pkenc_list (ctrl_t ctrl, struct kidlist_item *list, int failed) +print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list) { for (; list; list = list->next) { PKT_public_key *pk; const char *algstr; - if (failed && !list->reason) - continue; - if (!failed && list->reason) - continue; - algstr = openpgp_pk_algo_name (list->pubkey_algo); pk = xmalloc_clear (sizeof *pk); if (!algstr) algstr = "[?]"; pk->pubkey_algo = list->pubkey_algo; - if (!get_pubkey (ctrl, pk, list->kid)) + if (!get_pubkey (ctrl, pk, list->keyid)) { char *p; log_info (_("encrypted with %u-bit %s key, ID %s, created %s\n"), nbits_from_pk (pk), algstr, keystr_from_pk(pk), strtimestamp (pk->timestamp)); - p = get_user_id_native (ctrl, list->kid); + p = get_user_id_native (ctrl, list->keyid); log_printf (_(" \"%s\"\n"), p); xfree (p); } else log_info (_("encrypted with %s key, ID %s\n"), - algstr, keystr(list->kid)); + algstr, keystr(list->keyid)); free_public_key (pk); - - if (gpg_err_code (list->reason) == GPG_ERR_NO_SECKEY) - { - if (is_status_enabled()) - { - char buf[20]; - snprintf (buf, sizeof buf, "%08lX%08lX", - (ulong)list->kid[0], (ulong)list->kid[1]); - write_status_text (STATUS_NO_SECKEY, buf); - } - } - else if (gpg_err_code (list->reason) == GPG_ERR_MISSING_ACTION) - { - /* Not tested for secret key due to --list-only mode. */ - } - else if (list->reason) - { - log_info (_("public key decryption failed: %s\n"), - gpg_strerror (list->reason)); - write_status_error ("pkdecrypt_failed", list->reason); - } } } @@ -630,11 +548,42 @@ proc_encrypted (CTX c, PACKET *pkt) log_info (_("encrypted with %lu passphrases\n"), c->symkeys); else if (c->symkeys == 1) log_info (_("encrypted with 1 passphrase\n")); - print_pkenc_list (c->ctrl, c->pkenc_list, 1 ); - print_pkenc_list (c->ctrl, c->pkenc_list, 0 ); + print_pkenc_list (c->ctrl, c->pkenc_list); + } + + /* Figure out the session key by looking at all pkenc packets. */ + if (opt.list_only || c->dek) + ; + else if (opt.override_session_key) + { + c->dek = xmalloc_clear (sizeof *c->dek); + result = get_override_session_key (c->dek, opt.override_session_key); + if (result) + { + xfree (c->dek); + c->dek = NULL; + log_info (_("public key decryption failed: %s\n"), + gpg_strerror (result)); + write_status_error ("pkdecrypt_failed", result); + } + } + else + { + c->dek = xmalloc_secure_clear (sizeof *c->dek); + if ((result = get_session_key (c->ctrl, c->pkenc_list, c->dek))) + { + log_info (_("public key decryption failed: %s\n"), + gpg_strerror (result)); + write_status_error ("pkdecrypt_failed", result); + + /* Error: Delete the DEK. */ + xfree (c->dek); + c->dek = NULL; + } } - /* FIXME: Figure out the session key by looking at all pkenc packets. */ + if (c->dek && opt.verbose > 1) + log_info (_("public key encrypted data: good DEK\n")); write_status (STATUS_BEGIN_DECRYPTION); @@ -709,7 +658,7 @@ proc_encrypted (CTX c, PACKET *pkt) && gnupg_cipher_is_compliant (CO_DE_VS, c->dek->algo, GCRY_CIPHER_MODE_CFB)) { - struct kidlist_item *i; + struct pubkey_enc_list *i; int compliant = 1; PKT_public_key *pk = xmalloc (sizeof *pk); @@ -722,7 +671,7 @@ proc_encrypted (CTX c, PACKET *pkt) { memset (pk, 0, sizeof *pk); pk->pubkey_algo = i->pubkey_algo; - if (get_pubkey (c->ctrl, pk, i->kid) != 0 + if (get_pubkey (c->ctrl, pk, i->keyid) != 0 || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, nbits_from_pk (pk), NULL)) compliant = 0; diff --git a/g10/packet.h b/g10/packet.h index 695768695..3f872944b 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -131,6 +131,16 @@ typedef struct { } PKT_pubkey_enc; +/* An object to build a list of public-key encrypted session key. */ +struct pubkey_enc_list +{ + struct pubkey_enc_list *next; + u32 keyid[2]; + int pubkey_algo; + gcry_mpi_t data[PUBKEY_MAX_NENC]; +}; + + /* A one-pass signature packet as defined in RFC 4880, Section 5.4. All fields are serialized. */ typedef struct { @@ -889,7 +899,7 @@ gpg_error_t check_signature2 (ctrl_t ctrl, /*-- pubkey-enc.c --*/ -gpg_error_t get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek); +gpg_error_t get_session_key (ctrl_t ctrl, struct pubkey_enc_list *k, DEK *dek); gpg_error_t get_override_session_key (DEK *dek, const char *string); /*-- compress.c --*/ diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 0185097a4..32b1ed08b 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -38,7 +38,7 @@ #include "../common/compliance.h" -static gpg_error_t get_it (ctrl_t ctrl, PKT_pubkey_enc *k, +static gpg_error_t get_it (ctrl_t ctrl, struct pubkey_enc_list *k, DEK *dek, PKT_public_key *sk, u32 *keyid); @@ -72,92 +72,90 @@ 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 (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek) +get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) { PKT_public_key *sk = NULL; int rc; + void *enum_context = NULL; + u32 keyid[2]; + int search_for_secret_keys = 1; if (DBG_CLOCK) log_clock ("get_session_key enter"); - rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC); - if (rc) - goto leave; - - if ((k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets) + while (search_for_secret_keys) { + struct pubkey_enc_list *k; + sk = xmalloc_clear (sizeof *sk); - sk->pubkey_algo = k->pubkey_algo; /* We want a pubkey with this algo. */ - if (!(rc = get_seckey (ctrl, sk, k->keyid))) + rc = enum_secret_keys (ctrl, &enum_context, sk); + if (rc) { - /* Check compliance. */ - if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, - sk->pubkey_algo, - sk->pkey, nbits_from_pk (sk), NULL)) - { - log_info (_("key %s is not suitable for decryption" - " in %s mode\n"), - keystr_from_pk (sk), - gnupg_compliance_option_string (opt.compliance)); - rc = gpg_error (GPG_ERR_PUBKEY_ALGO); - } - else - rc = get_it (ctrl, k, dek, sk, k->keyid); + rc = GPG_ERR_NO_SECKEY; + break; } - } - else if (opt.skip_hidden_recipients) - rc = gpg_error (GPG_ERR_NO_SECKEY); - else /* Anonymous receiver: Try all available secret keys. */ - { - void *enum_context = NULL; - u32 keyid[2]; - for (;;) + if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) + continue; + + /* Check compliance. */ + if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, + sk->pubkey_algo, + sk->pkey, nbits_from_pk (sk), NULL)) { - free_public_key (sk); - sk = xmalloc_clear (sizeof *sk); - rc = enum_secret_keys (ctrl, &enum_context, sk); - if (rc) - { - rc = GPG_ERR_NO_SECKEY; - break; - } - if (sk->pubkey_algo != k->pubkey_algo) + log_info (_("key %s is not suitable for decryption" + " in %s mode\n"), + keystr_from_pk (sk), + gnupg_compliance_option_string (opt.compliance)); + continue; + } + + for (k = list; k; k = k->next) + { + if (!(k->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E + || k->pubkey_algo == PUBKEY_ALGO_ECDH + || k->pubkey_algo == PUBKEY_ALGO_RSA + || k->pubkey_algo == PUBKEY_ALGO_RSA_E + || k->pubkey_algo == PUBKEY_ALGO_ELGAMAL)) + continue; + + if (openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC)) continue; - if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) + + if (sk->pubkey_algo != k->pubkey_algo) continue; + keyid_from_pk (sk, keyid); - if (!opt.quiet) - log_info (_("anonymous recipient; trying secret key %s ...\n"), - keystr (keyid)); - - /* Check compliance. */ - if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, - sk->pubkey_algo, - sk->pkey, nbits_from_pk (sk), NULL)) + + if (!k->keyid[0] && !k->keyid[1]) { - log_info (_("key %s is not suitable for decryption" - " in %s mode\n"), - keystr_from_pk (sk), - gnupg_compliance_option_string (opt.compliance)); - continue; + if (!opt.quiet) + log_info (_("anonymous recipient; trying secret key %s ...\n"), + keystr (keyid)); } + else if (opt.try_all_secrets + || (k->keyid[0] == keyid[0] && k->keyid[1] == keyid[1])) + ; + else + continue; rc = get_it (ctrl, k, dek, sk, keyid); if (!rc) { - if (!opt.quiet) + if (!opt.quiet && !k->keyid[0] && !k->keyid[1]) log_info (_("okay, we are the anonymous recipient.\n")); + search_for_secret_keys = 0; break; } else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) - break; /* Don't try any more secret keys. */ + { + search_for_secret_keys = 0; + break; /* Don't try any more secret keys. */ + } } - enum_secret_keys (ctrl, &enum_context, NULL); /* free context */ } + enum_secret_keys (ctrl, &enum_context, NULL); /* free context */ - leave: - free_public_key (sk); if (DBG_CLOCK) log_clock ("get_session_key leave"); return rc; @@ -166,7 +164,7 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek) static gpg_error_t get_it (ctrl_t ctrl, - PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) + struct pubkey_enc_list *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) { gpg_error_t err; byte *frame = NULL; diff --git a/g10/skclist.c b/g10/skclist.c index 78890dc42..fe24b4a6d 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -286,3 +286,254 @@ build_sk_list (ctrl_t ctrl, *ret_sk_list = sk_list; return err; } + + +/* 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; + * sk = xmalloc_clear (sizeof (*sk)); + * } + * + * // Release any resources used by CTX. + * enum_secret_keys (&ctx, NULL); + * + * 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; + strlist_t card_list; + char *serialno; + char fpr2[43]; + struct agent_card_info_s info; + kbnode_t keyblock; + kbnode_t node; + getkey_ctx_t ctx; + pubkey_t results; + } *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. */ + xfree (c->serialno); + free_strlist (c->card_list); + pubkeys_free (c->results); + 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 list of card keys to try. */ + err = agent_scd_cardlist (&c->card_list); + if (!err) + agent_scd_serialno (&c->serialno, NULL); + c->sl = c->card_list; + c->state++; + break; + + case 4: /* Get next item from card list. */ + if (c->sl) + { + char *serialno; + + err = agent_scd_serialno (&serialno, c->sl->d); + if (err) + { + if (opt.verbose) + log_info (_("error getting serial number of card: %s\n"), + gpg_strerror (err)); + continue; + } + + xfree (serialno); + c->info.fpr2valid = 0; + err = agent_scd_getattr ("KEY-FPR", &c->info); + if (err) + log_error ("error retrieving key fingerprint from card: %s\n", + gpg_strerror (err)); + + if (c->info.fpr2valid) + { + c->fpr2[0] = '0'; + c->fpr2[1] = 'x'; + bin2hex (c->info.fpr2, 20, c->fpr2+2); + name = c->fpr2; + } + c->sl = c->sl->next; + } + else + { + if (c->serialno) + /* Select the original card again. */ + agent_scd_serialno (&c->serialno, c->serialno); + c->state++; + } + break; + + case 5: /* 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 6: /* 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) + { + pubkey_t r; + + /* Skip this candidate if it's already enumerated. */ + for (r = c->results; r; r = r->next) + if (!cmp_public_keys (r->pk, c->node->pkt->pkt.public_key)) + break; + if (r) + continue; + + copy_public_key (sk, c->node->pkt->pkt.public_key); + c->node = c->node->next; + + r = xtrycalloc (1, sizeof (*r)); + if (!r) + { + err = gpg_error_from_syserror (); + free_public_key (sk); + return err; + } + + r->pk = sk; + r->keyblock = NULL; + r->next = c->results; + c->results = r; + + return 0; /* Found. */ + } + } + + /* Dispose the keyblock and continue. */ + release_kbnode (c->keyblock); + c->keyblock = NULL; + } +} diff --git a/g10/test-stubs.c b/g10/test-stubs.c index 1e1363266..a2b0d2906 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -253,7 +253,7 @@ read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock) * No encryption here but mainproc links to these functions. */ gpg_error_t -get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek) +get_session_key (ctrl_t ctrl, struct pubkey_enc_list *k, DEK *dek) { (void)ctrl; (void)k; |