aboutsummaryrefslogtreecommitdiffstats
path: root/g10/mainproc.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2024-09-09 14:41:35 +0000
committerWerner Koch <[email protected]>2024-09-09 14:47:04 +0000
commitd528d0b065334b4c8c52e66441160e308b51d24f (patch)
tree6d4e920f8b0c9fdda0515d8e035b3533ee475aba /g10/mainproc.c
parentgpg: Improve detection of input data read errors. (diff)
downloadgnupg-d528d0b065334b4c8c52e66441160e308b51d24f.tar.gz
gnupg-d528d0b065334b4c8c52e66441160e308b51d24f.zip
gpg: New commands --add-recipients and --change-recipients.
* g10/gpg.c (aAddRecipients, aChangeRecipients): New consts. (opts): Add --add-recipients and --change-recipients. (main): Handle them. * g10/gpg.h (struct server_control_s): Add fields modify_recipients, clear_recipients, and last_read_ctb. * g10/armor.c (was_armored): New. * g10/decrypt.c (decrypt_message): Add optional arg 'remusr'. Handle re-encryption if desired. * g10/encrypt.c (write_pubkey_enc): Factor info printing out to ... (show_encrypted_for_user_info): new. (reencrypt_to_new_recipients): New. * g10/packet.h (struct parse_packet_ctx_s): Add fields only_fookey_enc and last_ctb. (init_parse_packet): Clear them. * g10/parse-packet.c (parse): Store CTB in the context. Early return on pubkey_enc and symkey_enc packets if requested. * g10/mainproc.c (proc_encrypted): Allow for PKT being NULL. Return early in modify-recipients mode. (proc_encryption_packets): Add two optional args 'r_dek' and 'r_list'. Adjust callers. Call do_proc_packets in modify-recipients mode depending on the optional args. (do_proc_packets): Add arg 'keep_dek_and_list'. Adjust callers. Save the last read CTB in CTRL and return after the last fooenc_enc packets. -- This basically works but does not yet handle symmetric encrypted packets (symkey_enc). GnuPG-bug-id: 1825 (Yes, this is an at least 9 year old feature request)
Diffstat (limited to 'g10/mainproc.c')
-rw-r--r--g10/mainproc.c95
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);