From 17890d43187384d049d80af28a5baea8613ff6ea Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 8 Mar 2022 10:13:44 +0100 Subject: [PATCH] gpg: New option --require-compliance. * g10/options.h (opt): Add field flags.require_compliance. * g10/gpg.c (oRequireCompliance): New. (opts): Add --require-compliance. (main): Set option. * g10/mainproc.c (proc_encrypted): Emit error if non de-vs compliant. (check_sig_and_print): Ditto. * g10/encrypt.c (encrypt_crypt): Ditto. -- Note that in the --encrypt and --verify cased other checks may kick in earlier than this new --require-compliance controlled one. --- doc/gpg.texi | 11 +++++++++++ g10/encrypt.c | 12 ++++++++++++ g10/gpg.c | 6 ++++++ g10/mainproc.c | 41 +++++++++++++++++++++++++++++++++++------ g10/options.h | 3 +++ 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index 3399e24e0..f51c3d9ec 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2889,6 +2889,17 @@ This option adjusts the compliance mode "de-vs" for stricter key size requirements. For example, a value of 3000 turns rsa2048 and dsa2048 keys into non-VS-NfD compliant keys. +@item --require-compliance +@opindex require-compliance +To check that data has been encrypted according to the rules of the +current compliance mode, a gpg user needs to evaluate the status +lines. This is allows frontends to handle compliance check in a more +flexible way. However, for scripted use the required evaluation of +the status-line requires quite some effort; this option can be used +instead to make sure that the gpg process exits with a failure if the +compliance rules are not fulfilled. Note that this option has +currently an effect only in "de-vs" mode. + @end table diff --git a/g10/encrypt.c b/g10/encrypt.c index 94e233bcd..e3e044f23 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -655,6 +655,18 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, gnupg_status_compliance_flag (CO_DE_VS), NULL); + if (opt.flags.require_compliance + && opt.compliance == CO_DE_VS + && !compliant) + { + log_error (_("operation forced to fail due to" + " unfulfilled compliance rules\n")); + rc = gpg_error (GPG_ERR_FORBIDDEN); + g10_errors_seen = 1; + goto leave; + } + + cfx.dek->use_mdc = use_mdc (pk_list,cfx.dek->algo); /* Only do the is-file-already-compressed check if we are using a diff --git a/g10/gpg.c b/g10/gpg.c index eb1852109..bf8f4e58a 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -430,6 +430,7 @@ enum cmd_and_opt_values oNoIncludeKeyBlock, oForceSignKey, oForbidGenKey, + oRequireCompliance, oNoop }; @@ -890,6 +891,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oXauthority, "xauthority", "@"), ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"), ARGPARSE_s_n (oForbidGenKey, "forbid-gen-key", "@"), + ARGPARSE_s_n (oRequireCompliance, "require-compliance", "@"), /* Options which can be used in special circumstances. They are not * published and we hope they are never required. */ ARGPARSE_s_n (oUseOnlyOpenPGPCard, "use-only-openpgp-card", "@"), @@ -3596,6 +3598,10 @@ main (int argc, char **argv) mopt.forbid_gen_key = 1; break; + case oRequireCompliance: + opt.flags.require_compliance = 1; + break; + case oNoop: break; default: diff --git a/g10/mainproc.c b/g10/mainproc.c index 871403ad7..4939fdef3 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -638,6 +638,7 @@ proc_encrypted (CTX c, PACKET *pkt) { int result = 0; int early_plaintext = literals_seen; + unsigned int compliance_de_vs = 0; if (pkt->pkttype == PKT_ENCRYPTED_AEAD) c->seen_pkt_encrypted_aead = 1; @@ -761,10 +762,12 @@ 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); - + { + write_status_strings (STATUS_DECRYPTION_COMPLIANCE_MODE, + gnupg_status_compliance_flag (CO_DE_VS), + NULL); + compliance_de_vs |= 1; + } } @@ -820,9 +823,15 @@ proc_encrypted (CTX c, PACKET *pkt) log_info(_("decryption okay\n")); if (pkt->pkt.encrypted->aead_algo) - write_status (STATUS_GOODMDC); + { + write_status (STATUS_GOODMDC); + compliance_de_vs |= 2; + } else if (pkt->pkt.encrypted->mdc_method && !result) - write_status (STATUS_GOODMDC); + { + write_status (STATUS_GOODMDC); + compliance_de_vs |= 2; + } else log_info (_("WARNING: message was not integrity protected\n")); } @@ -864,6 +873,17 @@ proc_encrypted (CTX c, PACKET *pkt) * a misplace extra literal data packets follows after this * encrypted packet. */ literals_seen++; + + /* The --require-compliance option allows to simplify decryption in + * 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)) + { + log_error (_("operation forced to fail due to" + " unfulfilled compliance rules\n")); + g10_errors_seen = 1; + } } @@ -2538,6 +2558,15 @@ check_sig_and_print (CTX c, kbnode_t node) write_status_strings (STATUS_VERIFICATION_COMPLIANCE_MODE, gnupg_status_compliance_flag (CO_DE_VS), NULL); + else if (opt.flags.require_compliance + && opt.compliance == CO_DE_VS) + { + log_error (_("operation forced to fail due to" + " unfulfilled compliance rules\n")); + if (!rc) + rc = gpg_error (GPG_ERR_FORBIDDEN); + } + free_public_key (pk); pk = NULL; diff --git a/g10/options.h b/g10/options.h index 03b46f8de..b11e91c66 100644 --- a/g10/options.h +++ b/g10/options.h @@ -253,6 +253,9 @@ struct /* The next flag is set internally iff IMPORT_SELF_SIGS_ONLY has * been set by the user and is not the default value. */ unsigned int expl_import_self_sigs_only:1; + /* Fail if an operation can't be done in the requested compliance + * mode. */ + unsigned int require_compliance:1; } flags; /* Linked list of ways to find a key if the key isn't on the local