diff --git a/g10/gpgv.c b/g10/gpgv.c index c43067dfd..16d90440c 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 d5fee7314..835ab6b72 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; - gcry_mpi_t data[2]; -}; - - /* * 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,7 @@ 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]); @@ -464,7 +454,7 @@ static void proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt) { PKT_pubkey_enc *enc; - struct kidlist_item *x = xmalloc (sizeof *x); + 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; @@ -485,8 +475,8 @@ proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt) if (!opt.list_only && !opt.override_session_key) { - 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->data[0] = x->data[1] = NULL; if (enc->data[0]) @@ -507,7 +497,7 @@ proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt) * not decrypt. */ static void -print_pkenc_list (ctrl_t ctrl, struct kidlist_item *list) +print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list) { for (; list; list = list->next) { @@ -520,19 +510,19 @@ print_pkenc_list (ctrl_t ctrl, struct kidlist_item *list) 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); } @@ -542,7 +532,6 @@ print_pkenc_list (ctrl_t ctrl, struct kidlist_item *list) static void proc_encrypted (CTX c, PACKET *pkt) { - struct kidlist_item *item; int result = 0; if (!opt.quiet) @@ -555,7 +544,7 @@ proc_encrypted (CTX c, PACKET *pkt) } /* Figure out the session key by looking at all pkenc packets. */ - if (opt.list_only) + if (opt.list_only || c->dek) ; else if (opt.override_session_key) { @@ -572,53 +561,16 @@ proc_encrypted (CTX c, PACKET *pkt) } else { - for (item = c->pkenc_list; item; item = item->next) - if (item->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E - || item->pubkey_algo == PUBKEY_ALGO_ECDH - || item->pubkey_algo == PUBKEY_ALGO_RSA - || item->pubkey_algo == PUBKEY_ALGO_RSA_E - || item->pubkey_algo == PUBKEY_ALGO_ELGAMAL) - { - if (((!item->kid[0] && !item->kid[1]) - || opt.try_all_secrets - || have_secret_key_with_kid (item->kid))) - { - PKT_pubkey_enc enc; - - enc.keyid[0] = item->kid[0]; - enc.keyid[1] = item->kid[1]; - enc.pubkey_algo = item->pubkey_algo; - enc.data[0] = item->data[0]; - enc.data[1] = item->data[1]; - - c->dek = xmalloc_secure_clear (sizeof *c->dek); - if (!(result = get_session_key (c->ctrl, &enc, c->dek))) - break; - - 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; - } - else - { - if (is_status_enabled ()) - { - char buf[20]; - snprintf (buf, sizeof buf, "%08lX%08lX", - (ulong)item->kid[0], (ulong)item->kid[1]); - write_status_text (STATUS_NO_SECKEY, buf); - } - } - } - 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 (GPG_ERR_PUBKEY_ALGO)); - write_status_error ("pkdecrypt_failed", GPG_ERR_PUBKEY_ALGO); + gpg_strerror (result)); + write_status_error ("pkdecrypt_failed", result); + + /* Error: Delete the DEK. */ + xfree (c->dek); + c->dek = NULL; } } @@ -698,7 +650,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); @@ -711,7 +663,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 e8397eaee..a4157c53f 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 { @@ -887,7 +897,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..8540e03c9 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,92 @@ 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; + + free_public_key (sk); 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; - } + 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_algo != k->pubkey_algo) continue; - if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) - 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)) + keyid_from_pk (sk, keyid); + + 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 */ } - - leave: + enum_secret_keys (ctrl, &enum_context, NULL); /* free context */ free_public_key (sk); + if (DBG_CLOCK) log_clock ("get_session_key leave"); return rc; @@ -166,7 +166,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/test-stubs.c b/g10/test-stubs.c index e5fd3ae9a..088aba8c6 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;