From e081a601f7b31fa278e46de7c6834a756b63cec2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 18 Mar 2022 11:13:23 +0100 Subject: [PATCH] gpg: Allow decryption of symencr even for non-compliant cipher. * g10/decrypt-data.c (decrypt_data): Add arg compliance_error. Adjust all callers. Fail on compliance error only in --require-compliance mode. Make sure to return an error if the buffer is missing; actually that should be an assert. * g10/mainproc.c (proc_encrypted): Delay printing of the compliance mode status. Consult the compliance error now returned by decrypt_data. -- The actual case here is that we fail hard if a message has been AEAD encrypted with one AEAD capable key and also with one passphrase. In general the preference system takes care of not using AEAD if one recipient's key does not support it. However, if the sender uses her own AEAD-capable key _and_ a passphrase the message will be AEAD encrypted. This change allows to decrypt that anyway along with a warning message. Note that this does currently not work in 2.3 due to a non-compliant libgcrypt. We will however, backport this to 2.2. --- g10/decrypt-data.c | 21 +++++++++++++++++---- g10/gpgv.c | 4 +++- g10/mainproc.c | 31 +++++++++++++++++++++---------- g10/packet.h | 5 +++-- g10/test-stubs.c | 4 +++- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c index 279388509..89d7c9a70 100644 --- a/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -215,10 +215,14 @@ aead_checktag (decode_filter_ctx_t dfx, int final, const void *tagbuf) /**************** - * Decrypt the data, specified by ED with the key DEK. + * Decrypt the data, specified by ED with the key DEK. On return + * COMPLIANCE_ERROR is set to true iff the decryption can claim that + * it was compliant in the current mode; otherwise this flag is set to + * false. */ int -decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) +decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek, + int *compliance_error) { decode_filter_ctx_t dfx; enum gcry_cipher_modes ciphermode; @@ -229,6 +233,8 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) unsigned blocksize; unsigned nprefix; + *compliance_error = 0; + dfx = xtrycalloc (1, sizeof *dfx); if (!dfx) return gpg_error_from_syserror (); @@ -260,8 +266,14 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) log_error (_("cipher algorithm '%s' may not be used in %s mode\n"), openpgp_cipher_algo_name (dek->algo), gnupg_compliance_option_string (opt.compliance)); - rc = gpg_error (GPG_ERR_CIPHER_ALGO); - goto leave; + *compliance_error = 1; + if (opt.flags.require_compliance) + { + /* We fail early in this case because it does not make sense + * to first decrypt everything. */ + rc = gpg_error (GPG_ERR_CIPHER_ALGO); + goto leave; + } } write_status_printf (STATUS_DECRYPTION_INFO, "%d %d %d", @@ -420,6 +432,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) if (!ed->buf) { log_error (_("problem handling encrypted packet\n")); + rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } diff --git a/g10/gpgv.c b/g10/gpgv.c index 71adb0488..4e9c35de5 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -549,12 +549,14 @@ get_override_session_key (DEK *dek, const char *string) /* Stub: */ int -decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) +decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek, + int *compliance_error) { (void)ctrl; (void)procctx; (void)ed; (void)dek; + (void)compliance_error; return GPG_ERR_GENERAL; } diff --git a/g10/mainproc.c b/g10/mainproc.c index 4939fdef3..4fb7d6840 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -762,17 +762,18 @@ proc_encrypted (CTX c, PACKET *pkt) xfree (pk); if (compliant) - { - write_status_strings (STATUS_DECRYPTION_COMPLIANCE_MODE, - gnupg_status_compliance_flag (CO_DE_VS), - NULL); - compliance_de_vs |= 1; - } + compliance_de_vs |= 1; } if (!result) - result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek ); + { + int compl_error; + result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek, + &compl_error); + if (!result && !compl_error) + compliance_de_vs |= 2; + } /* Trigger the deferred error. */ if (!result && early_plaintext) @@ -825,12 +826,12 @@ proc_encrypted (CTX c, PACKET *pkt) if (pkt->pkt.encrypted->aead_algo) { write_status (STATUS_GOODMDC); - compliance_de_vs |= 2; + compliance_de_vs |= 4; } else if (pkt->pkt.encrypted->mdc_method && !result) { write_status (STATUS_GOODMDC); - compliance_de_vs |= 2; + compliance_de_vs |= 4; } else log_info (_("WARNING: message was not integrity protected\n")); @@ -862,6 +863,16 @@ proc_encrypted (CTX c, PACKET *pkt) * ways to specify the session key (symmmetric and PK). */ } + + /* If we concluded that the decryption was compliant, issue a + * compliance status before the thed end of decryption status. */ + if (compliance_de_vs == (4|2|1)) + { + write_status_strings (STATUS_DECRYPTION_COMPLIANCE_MODE, + gnupg_status_compliance_flag (CO_DE_VS), + NULL); + } + xfree (c->dek); c->dek = NULL; free_packet (pkt, NULL); @@ -878,7 +889,7 @@ proc_encrypted (CTX c, PACKET *pkt) * de-vs compliance mode by just looking at the exit status. */ if (opt.flags.require_compliance && opt.compliance == CO_DE_VS - && compliance_de_vs != (2|1)) + && compliance_de_vs != (4|2|1)) { log_error (_("operation forced to fail due to" " unfulfilled compliance rules\n")); diff --git a/g10/packet.h b/g10/packet.h index 187fffc7c..7f7608c95 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -906,8 +906,9 @@ gpg_error_t get_override_session_key (DEK *dek, const char *string); int handle_compressed (ctrl_t ctrl, void *ctx, PKT_compressed *cd, int (*callback)(iobuf_t, void *), void *passthru ); -/*-- encr-data.c --*/ -int decrypt_data (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek ); +/*-- decrypt-data.c --*/ +int decrypt_data (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek, + int *compliance_error); /*-- plaintext.c --*/ gpg_error_t get_output_file (const byte *embedded_name, int embedded_namelen, diff --git a/g10/test-stubs.c b/g10/test-stubs.c index f0ce10b38..2ae4a4183 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -306,12 +306,14 @@ get_override_session_key (DEK *dek, const char *string) /* Stub: */ int -decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) +decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek, + int *compliance_error) { (void)ctrl; (void)procctx; (void)ed; (void)dek; + (void)compliance_error; return GPG_ERR_GENERAL; }