diff options
Diffstat (limited to 'g10/mainproc.c')
-rw-r--r-- | g10/mainproc.c | 95 |
1 files changed, 78 insertions, 17 deletions
diff --git a/g10/mainproc.c b/g10/mainproc.c index 3bb46b574..2429e1006 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -116,7 +116,7 @@ static int literals_seen; /*** Local prototypes. ***/ -static int do_proc_packets (CTX c, iobuf_t a); +static int do_proc_packets (CTX c, iobuf_t a, int keep_dek_and_list); static void list_node (CTX c, kbnode_t node); static void proc_tree (CTX c, kbnode_t node); @@ -580,10 +580,15 @@ proc_encrypted (CTX c, PACKET *pkt) int early_plaintext = literals_seen; unsigned int compliance_de_vs = 0; - if (pkt->pkttype == PKT_ENCRYPTED_AEAD) - c->seen_pkt_encrypted_aead = 1; - if (pkt->pkttype == PKT_ENCRYPTED_MDC) - c->seen_pkt_encrypted_mdc = 1; + if (pkt) + { + if (pkt->pkttype == PKT_ENCRYPTED_AEAD) + c->seen_pkt_encrypted_aead = 1; + if (pkt->pkttype == PKT_ENCRYPTED_MDC) + c->seen_pkt_encrypted_mdc = 1; + } + else /* No PKT indicates the the add-recipients mode. */ + log_assert (c->ctrl->modify_recipients); if (early_plaintext) { @@ -650,6 +655,22 @@ proc_encrypted (CTX c, PACKET *pkt) if (c->dek && opt.verbose > 1) log_info (_("public key encrypted data: good DEK\n")); + if (c->ctrl->modify_recipients) + { + if (c->anchor) + { + log_error ("command not possible with nested data\n"); + write_status_errcode ("decryption.mod_recp", GPG_ERR_BAD_DATA); + xfree (c->dek); + c->dek = NULL; + return; + } + literals_seen++; + /* Simply return here. Our caller will then test for DEK and + * the PK_list to decide whether decryption worked. */ + return; + } + if (!opt.show_only_session_key) write_status (STATUS_BEGIN_DECRYPTION); @@ -1112,7 +1133,7 @@ static int proc_encrypt_cb (iobuf_t a, void *info ) { CTX c = info; - return proc_encryption_packets (c->ctrl, info, a ); + return proc_encryption_packets (c->ctrl, info, a, NULL, NULL); } @@ -1502,7 +1523,7 @@ proc_packets (ctrl_t ctrl, void *anchor, iobuf_t a ) c->ctrl = ctrl; c->anchor = anchor; - rc = do_proc_packets (c, a); + rc = do_proc_packets (c, a, 0); xfree (c); return rc; @@ -1525,7 +1546,7 @@ proc_signature_packets (ctrl_t ctrl, void *anchor, iobuf_t a, c->signed_data.used = !!signedfiles; c->sigfilename = sigfilename; - rc = do_proc_packets (c, a); + rc = do_proc_packets (c, a, 0); /* If we have not encountered any signature we print an error messages, send a NODATA status back and return an error code. @@ -1568,7 +1589,7 @@ proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, iobuf_t a, c->signed_data.data_names = NULL; c->signed_data.used = (signed_data_fd != GNUPG_INVALID_FD); - rc = do_proc_packets (c, a); + rc = do_proc_packets (c, a, 0); /* If we have not encountered any signature we print an error messages, send a NODATA status back and return an error code. @@ -1592,8 +1613,13 @@ proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, iobuf_t a, } -int -proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a ) +/* Handle encryption packets. If called recursively the caller's CTX + * should be given for ANCHOR. If R_DEK and R_LIST are not NULL the + * DEK (or NULL) is returned there and the list at R_LIST; the caller + * needs to release them; even if the function returns an error. */ +gpg_error_t +proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a, + DEK **r_dek, struct pubkey_enc_list **r_list) { CTX c = xmalloc_clear (sizeof *c); int rc; @@ -1601,7 +1627,16 @@ proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a ) c->ctrl = ctrl; c->anchor = anchor; c->encrypt_only = 1; - rc = do_proc_packets (c, a); + if (r_dek && r_list) + { + rc = do_proc_packets (c, a, 1); + *r_dek = c->dek; + c->dek = NULL; + *r_list = c->pkenc_list; + c->pkenc_list = NULL; + } + else + rc = do_proc_packets (c, a, 0); xfree (c); return rc; } @@ -1626,8 +1661,11 @@ check_nesting (CTX c) } +/* Main processing loop. If KEEP_DEK_AND_LIST is set the DEK and + * PKENC_LIST of the context C are not released at the end of the + * function. The caller is then required to do this. */ static int -do_proc_packets (CTX c, iobuf_t a) +do_proc_packets (CTX c, iobuf_t a, int keep_dek_and_list) { PACKET *pkt; struct parse_packet_ctx_s parsectx; @@ -1648,6 +1686,18 @@ do_proc_packets (CTX c, iobuf_t a) any_data = 1; if (rc) { + if (c->ctrl->modify_recipients && gpg_err_code (rc) == GPG_ERR_TRUE) + { + /* Save the last read CTB (which was the last byte + * actually read from the input) and get out of the + * loop. */ + c->ctrl->last_read_ctb = parsectx.last_ctb; + /* We need to call the first part of the encrypted data + * handler to get the DEK. */ + proc_encrypted (c, NULL); + rc = -1; + break; + } free_packet (pkt, &parsectx); /* Stop processing when an invalid packet has been encountered * but don't do so when we are doing a --list-packets. */ @@ -1706,8 +1756,19 @@ do_proc_packets (CTX c, iobuf_t a) goto leave; case PKT_SIGNATURE: newpkt = add_signature (c, pkt); break; - case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; - case PKT_PUBKEY_ENC: proc_pubkey_enc (c, pkt); break; + + case PKT_SYMKEY_ENC: + case PKT_PUBKEY_ENC: + /* In --add-recipients mode set the stop flag as soon as + * we see the first of these packets. */ + if (c->ctrl->modify_recipients) + parsectx.only_fookey_enc = 1; + if (pkt->pkttype == PKT_SYMKEY_ENC) + proc_symkey_enc (c, pkt); + else + proc_pubkey_enc (c, pkt); + break; + case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break; @@ -1783,8 +1844,8 @@ do_proc_packets (CTX c, iobuf_t a) leave: - release_list (c); - xfree(c->dek); + if (!keep_dek_and_list) + release_list (c); free_packet (pkt, &parsectx); deinit_parse_packet (&parsectx); xfree (pkt); |