diff options
Diffstat (limited to 'g10/mainproc.c')
-rw-r--r-- | g10/mainproc.c | 144 |
1 files changed, 106 insertions, 38 deletions
diff --git a/g10/mainproc.c b/g10/mainproc.c index 6ec15894d..7acf67b1e 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -86,6 +86,7 @@ struct mainproc_context int trustletter; /* Temporary usage in list_node. */ ulong symkeys; /* Number of symmetrically encrypted session keys. */ struct pubkey_enc_list *pkenc_list; /* List of encryption packets. */ + int seen_pkt_encrypted_aead; /* PKT_ENCRYPTED_AEAD packet seen. */ struct { unsigned int sig_seen:1; /* Set to true if a signature packet has been seen. */ @@ -137,6 +138,7 @@ release_list( CTX c ) c->any.data = 0; c->any.uncompress_failed = 0; c->last_was_session_key = 0; + c->seen_pkt_encrypted_aead = 0; xfree (c->dek); c->dek = NULL; } @@ -479,6 +481,7 @@ proc_pubkey_enc (CTX c, PACKET *pkt) x->keyid[0] = enc->keyid[0]; x->keyid[1] = enc->keyid[1]; x->pubkey_algo = enc->pubkey_algo; + x->result = -1; x->data[0] = x->data[1] = NULL; if (enc->data[0]) { @@ -536,6 +539,9 @@ proc_encrypted (CTX c, PACKET *pkt) int result = 0; int early_plaintext = literals_seen; + if (pkt->pkttype == PKT_ENCRYPTED_AEAD) + c->seen_pkt_encrypted_aead = 1; + if (early_plaintext) { log_info (_("WARNING: multiple plaintexts seen\n")); @@ -572,22 +578,21 @@ proc_encrypted (CTX c, PACKET *pkt) { c->dek = xmalloc_secure_clear (sizeof *c->dek); result = get_session_key (c->ctrl, c->pkenc_list, c->dek); - if (result == GPG_ERR_NO_SECKEY) - { - if (is_status_enabled ()) - { - struct pubkey_enc_list *list; - - for (list = c->pkenc_list; list; list = list->next) - { - char buf[20]; - snprintf (buf, sizeof buf, "%08lX%08lX", - (ulong)list->keyid[0], (ulong)list->keyid[1]); - write_status_text (STATUS_NO_SECKEY, buf); - } - } + if (is_status_enabled ()) + { + struct pubkey_enc_list *list; + + for (list = c->pkenc_list; list; list = list->next) + if (list->result == GPG_ERR_NO_SECKEY) + { + char buf[20]; + snprintf (buf, sizeof buf, "%08lX%08lX", + (ulong)list->keyid[0], (ulong)list->keyid[1]); + write_status_text (STATUS_NO_SECKEY, buf); + } } - else if (result) + + if (result) { log_info (_("public key decryption failed: %s\n"), gpg_strerror (result)); @@ -704,7 +709,6 @@ proc_encrypted (CTX c, PACKET *pkt) } - if (!result) result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek ); @@ -804,14 +808,31 @@ proc_encrypted (CTX c, PACKET *pkt) } +static int +have_seen_pkt_encrypted_aead( CTX c ) +{ + CTX cc; + + for (cc = c; cc; cc = cc->anchor) + { + if (cc->seen_pkt_encrypted_aead) + return 1; + } + + return 0; +} + + static void proc_plaintext( CTX c, PACKET *pkt ) { PKT_plaintext *pt = pkt->pkt.plaintext; int any, clearsig, rc; kbnode_t n; + unsigned char *extrahash; + size_t extrahashlen; - /* This is a literal data packet. Bumb a counter for later checks. */ + /* This is a literal data packet. Bump a counter for later checks. */ literals_seen++; if (pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8)) @@ -843,7 +864,10 @@ proc_plaintext( CTX c, PACKET *pkt ) /* The onepass signature case. */ if (n->pkt->pkt.onepass_sig->digest_algo) { - gcry_md_enable (c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo); + if (!opt.skip_verify) + gcry_md_enable (c->mfx.md, + n->pkt->pkt.onepass_sig->digest_algo); + any = 1; } } @@ -861,7 +885,8 @@ proc_plaintext( CTX c, PACKET *pkt ) * documents. */ clearsig = (*data == 0x01); for (data++, datalen--; datalen; datalen--, data++) - gcry_md_enable (c->mfx.md, *data); + if (!opt.skip_verify) + gcry_md_enable (c->mfx.md, *data); any = 1; break; /* Stop here as one-pass signature packets are not expected. */ @@ -869,12 +894,13 @@ proc_plaintext( CTX c, PACKET *pkt ) else if (n->pkt->pkttype == PKT_SIGNATURE) { /* The SIG+LITERAL case that PGP used to use. */ - gcry_md_enable ( c->mfx.md, n->pkt->pkt.signature->digest_algo ); + if (!opt.skip_verify) + gcry_md_enable (c->mfx.md, n->pkt->pkt.signature->digest_algo); any = 1; } } - if (!any && !opt.skip_verify) + if (!any && !opt.skip_verify && !have_seen_pkt_encrypted_aead(c)) { /* This is for the old GPG LITERAL+SIG case. It's not legal according to 2440, so hopefully it won't come up that often. @@ -920,12 +946,37 @@ proc_plaintext( CTX c, PACKET *pkt ) if (rc) log_error ("handle plaintext failed: %s\n", gpg_strerror (rc)); + /* We add a marker control packet instead of the plaintext packet. + * This is so that we can later detect invalid packet sequences. + * The apcket is further used to convey extra data from the + * plaintext packet to the signature verification. */ + extrahash = xtrymalloc (6 + pt->namelen); + if (!extrahash) + { + /* No way to return an error. */ + rc = gpg_error_from_syserror (); + log_error ("malloc failed in %s: %s\n", __func__, gpg_strerror (rc)); + extrahashlen = 0; + } + else + { + extrahash[0] = pt->mode; + extrahash[1] = pt->namelen; + if (pt->namelen) + memcpy (extrahash+2, pt->name, pt->namelen); + extrahashlen = 2 + pt->namelen; + extrahash[extrahashlen++] = pt->timestamp >> 24; + extrahash[extrahashlen++] = pt->timestamp >> 16; + extrahash[extrahashlen++] = pt->timestamp >> 8; + extrahash[extrahashlen++] = pt->timestamp ; + } + free_packet (pkt, NULL); c->last_was_session_key = 0; - /* We add a marker control packet instead of the plaintext packet. - * This is so that we can later detect invalid packet sequences. */ - n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0)); + n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, + extrahash, extrahashlen)); + xfree (extrahash); if (c->list) add_kbnode (c->list, n); else @@ -995,7 +1046,8 @@ proc_compressed (CTX c, PACKET *pkt) * found. Returns: 0 = valid signature or an error code */ static int -do_check_sig (CTX c, kbnode_t node, int *is_selfsig, +do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen, + int *is_selfsig, int *is_expkey, int *is_revkey, PKT_public_key **r_pk) { PKT_signature *sig; @@ -1081,14 +1133,16 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig, /* We only get here if we are checking the signature of a binary (0x00) or text document (0x01). */ - rc = check_signature2 (c->ctrl, sig, md, NULL, is_expkey, is_revkey, r_pk); + rc = check_signature2 (c->ctrl, sig, md, extrahash, extrahashlen, + NULL, is_expkey, is_revkey, r_pk); if (! rc) md_good = md; else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2) { PKT_public_key *pk2; - rc = check_signature2 (c->ctrl, sig, md2, NULL, is_expkey, is_revkey, + rc = check_signature2 (c->ctrl, sig, md2, extrahash, extrahashlen, + NULL, is_expkey, is_revkey, r_pk? &pk2 : NULL); if (!rc) { @@ -1251,7 +1305,7 @@ list_node (CTX c, kbnode_t node) if (opt.check_sigs) { fflush (stdout); - rc2 = do_check_sig (c, node, &is_selfsig, NULL, NULL, NULL); + rc2 = do_check_sig (c, node, NULL, 0, &is_selfsig, NULL, NULL, NULL); switch (gpg_err_code (rc2)) { case 0: sigrc = '!'; break; @@ -1714,7 +1768,7 @@ akl_has_wkd_method (void) } -/* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN. +/* Return the ISSUER fingerprint buffer and its length at R_LEN. * Returns NULL if not available. The returned buffer is valid as * long as SIG is not modified. */ const byte * @@ -1724,7 +1778,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len) size_t n; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n); - if (p && n == 21 && p[0] == 4) + if (p && ((n == 21 && p[0] == 4) || (n == 33 && p[0] == 5))) { *r_len = n - 1; return p+1; @@ -1787,6 +1841,8 @@ check_sig_and_print (CTX c, kbnode_t node) char *issuer_fpr = NULL; PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */ int tried_ks_by_fpr; + const void *extrahash = NULL; + size_t extrahashlen = 0; if (opt.skip_verify) { @@ -1844,6 +1900,8 @@ check_sig_and_print (CTX c, kbnode_t node) { if (n->next) goto ambiguous; /* We only allow one P packet. */ + extrahash = n->pkt->pkt.gpg_control->data; + extrahashlen = n->pkt->pkt.gpg_control->datalen; } else goto ambiguous; @@ -1858,6 +1916,9 @@ check_sig_and_print (CTX c, kbnode_t node) && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK))) goto ambiguous; + extrahash = n->pkt->pkt.gpg_control->data; + extrahashlen = n->pkt->pkt.gpg_control->datalen; + for (n_sig=0, n = n->next; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) n_sig++; @@ -1888,6 +1949,8 @@ check_sig_and_print (CTX c, kbnode_t node) && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK))) goto ambiguous; + extrahash = n->pkt->pkt.gpg_control->data; + extrahashlen = n->pkt->pkt.gpg_control->datalen; for (n_sig=0, n = n->next; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) n_sig++; @@ -1933,7 +1996,8 @@ check_sig_and_print (CTX c, kbnode_t node) if (sig->signers_uid) log_info (_(" issuer \"%s\"\n"), sig->signers_uid); - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); /* If the key isn't found, check for a preferred keyserver. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks) @@ -1968,8 +2032,8 @@ check_sig_and_print (CTX c, kbnode_t node) res = keyserver_import_keyid (c->ctrl, sig->keyid,spec, 1); glo_ctrl.in_auto_key_retrieve--; if (!res) - rc = do_check_sig (c, node, NULL, - &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); free_keyserver_spec (spec); if (!rc) @@ -2004,7 +2068,8 @@ check_sig_and_print (CTX c, kbnode_t node) glo_ctrl.in_auto_key_retrieve--; free_keyserver_spec (spec); if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); } } } @@ -2026,7 +2091,7 @@ check_sig_and_print (CTX c, kbnode_t node) p = issuer_fpr_raw (sig, &n); if (p) { - /* v4 packet with a SHA-1 fingerprint. */ + /* v4 or v5 packet with a SHA-1/256 fingerprint. */ free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; @@ -2034,7 +2099,8 @@ check_sig_and_print (CTX c, kbnode_t node) tried_ks_by_fpr = 1; glo_ctrl.in_auto_key_retrieve--; if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); } } @@ -2056,7 +2122,8 @@ check_sig_and_print (CTX c, kbnode_t node) /* Fixme: If the fingerprint is embedded in the signature, * compare it to the fingerprint of the returned key. */ if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); } /* If the above methods did't work, our next try is to use a @@ -2074,7 +2141,8 @@ check_sig_and_print (CTX c, kbnode_t node) res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1); glo_ctrl.in_auto_key_retrieve--; if (!res) - rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); + rc = do_check_sig (c, node, extrahash, extrahashlen, + NULL, &is_expkey, &is_revkey, &pk); } if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE) |