summaryrefslogtreecommitdiffstats
path: root/g10/encrypt.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2022-09-29 15:03:26 +0200
committerWerner Koch <wk@gnupg.org>2022-09-29 15:03:26 +0200
commita51067a21f688086bd8e44234a88ae367582cc76 (patch)
treef0d213ea7a8af1efcaa0a7491290d08949b29615 /g10/encrypt.c
parentdirnmgr: Fix the function prototype. (diff)
downloadgnupg2-a51067a21f688086bd8e44234a88ae367582cc76.tar.xz
gnupg2-a51067a21f688086bd8e44234a88ae367582cc76.zip
gpg: Make --require-compliance work for -se
* g10/encrypt.c (encrypt_crypt, encrypt_filter): Factor common code out to ... (create_dek_with_warnings): new (check_encryption_compliance): and new. * g10/encrypt.c (encrypt_filter): Add the compliance check. -- GnuPG-bug-id: 6174 Ported-from: f88cb12f8e3c1234a094d09e2505d3a3eec4cbfe
Diffstat (limited to 'g10/encrypt.c')
-rw-r--r--g10/encrypt.c302
1 files changed, 146 insertions, 156 deletions
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 28a761747..bd98d06e4 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -67,6 +67,143 @@ encrypt_store (const char *filename)
}
+/* Create and setup a DEK structure and print approriate warnings.
+ * PK_LIST gives the list of public keys. Always returns a DEK. The
+ * actual session needs to be added later. */
+static DEK *
+create_dek_with_warnings (pk_list_t pk_list)
+{
+ DEK *dek;
+
+ dek = xmalloc_secure_clear (sizeof *dek);
+ if (!opt.def_cipher_algo)
+ {
+ /* Try to get it from the prefs. */
+ dek->algo = select_algo_from_prefs (pk_list, PREFTYPE_SYM, -1, NULL);
+ if (dek->algo == -1)
+ {
+ /* If does not make sense to fallback to the rfc4880
+ * required 3DES if we will reject that algo later. Thus we
+ * fallback to AES anticipating RFC4880bis rules. */
+ if (opt.flags.allow_old_cipher_algos)
+ dek->algo = CIPHER_ALGO_3DES;
+ else
+ dek->algo = CIPHER_ALGO_AES;
+ }
+
+ /* In case 3DES has been selected, print a warning if any key
+ * does not have a preference for AES. This should help to
+ * indentify why encrypting to several recipients falls back to
+ * 3DES. */
+ if (opt.verbose && dek->algo == CIPHER_ALGO_3DES)
+ warn_missing_aes_from_pklist (pk_list);
+ }
+ else
+ {
+ if (!opt.expert
+ && (select_algo_from_prefs (pk_list, PREFTYPE_SYM,
+ opt.def_cipher_algo, NULL)
+ != opt.def_cipher_algo))
+ {
+ log_info(_("WARNING: forcing symmetric cipher %s (%d)"
+ " violates recipient preferences\n"),
+ openpgp_cipher_algo_name (opt.def_cipher_algo),
+ opt.def_cipher_algo);
+ }
+
+ dek->algo = opt.def_cipher_algo;
+ }
+
+ return dek;
+}
+
+
+/* Check whether all encryption keys are compliant with the current
+ * mode and issue respective status lines. DEK has the info about the
+ * session key and PK_LIST the list of public keys. */
+static gpg_error_t
+check_encryption_compliance (DEK *dek, pk_list_t pk_list)
+{
+ gpg_error_t err = 0;
+ pk_list_t pkr;
+ int compliant;
+
+ /* First check whether we should use the algo at all. */
+ if (openpgp_cipher_blocklen (dek->algo) < 16
+ && !opt.flags.allow_old_cipher_algos)
+ {
+ log_error (_("cipher algorithm '%s' may not be used for encryption\n"),
+ openpgp_cipher_algo_name (dek->algo));
+ if (!opt.quiet)
+ log_info (_("(use option \"%s\" to override)\n"),
+ "--allow-old-cipher-algos");
+ err = gpg_error (GPG_ERR_CIPHER_ALGO);
+ goto leave;
+ }
+
+ /* Now check the compliance. */
+ if (! gnupg_cipher_is_allowed (opt.compliance, 1, dek->algo,
+ GCRY_CIPHER_MODE_CFB))
+ {
+ 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));
+ err = gpg_error (GPG_ERR_CIPHER_ALGO);
+ goto leave;
+ }
+
+ if (!gnupg_rng_is_compliant (opt.compliance))
+ {
+ err = gpg_error (GPG_ERR_FORBIDDEN);
+ log_error (_("%s is not compliant with %s mode\n"),
+ "RNG",
+ gnupg_compliance_option_string (opt.compliance));
+ write_status_error ("random-compliance", err);
+ goto leave;
+ }
+
+ compliant = gnupg_cipher_is_compliant (CO_DE_VS, dek->algo,
+ GCRY_CIPHER_MODE_CFB);
+
+ for (pkr = pk_list; pkr; pkr = pkr->next)
+ {
+ PKT_public_key *pk = pkr->pk;
+ unsigned int nbits = nbits_from_pk (pk);
+
+ if (!gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, 0,
+ pk->pkey, nbits, NULL))
+ log_info (_("WARNING: key %s is not suitable for encryption"
+ " in %s mode\n"),
+ keystr_from_pk (pk),
+ gnupg_compliance_option_string (opt.compliance));
+
+ if (compliant
+ && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey,
+ nbits, NULL))
+ compliant = 0; /* Not compliant - reset flag. */
+ }
+
+ /* If we are compliant print the status for de-vs compliance. */
+ if (compliant)
+ write_status_strings (STATUS_ENCRYPTION_COMPLIANCE_MODE,
+ gnupg_status_compliance_flag (CO_DE_VS),
+ NULL);
+
+ /* Check whether we should fail the operation. */
+ if (opt.flags.require_compliance
+ && opt.compliance == CO_DE_VS
+ && !compliant)
+ {
+ compliance_failure ();
+ err = gpg_error (GPG_ERR_FORBIDDEN);
+ goto leave;
+ }
+
+ leave:
+ return err;
+}
+
+
/* Encrypt a session key using DEK and store a pointer to the result
* at R_ENCKEY and its length at R_ENCKEYLEN.
*
@@ -647,7 +784,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
progress_filter_context_t *pfx;
PK_LIST pk_list;
int do_compress;
- int compliant;
if (filefd != -1 && filename)
return gpg_error (GPG_ERR_INV_ARG); /* Both given. */
@@ -736,127 +872,11 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
}
/* Create a session key. */
- cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek);
- if (!opt.def_cipher_algo)
- {
- /* Try to get it from the prefs. */
- cfx.dek->algo = select_algo_from_prefs (pk_list, PREFTYPE_SYM, -1, NULL);
- /* The only way select_algo_from_prefs can fail here is when
- mixing v3 and v4 keys, as v4 keys have an implicit preference
- entry for 3DES, and the pk_list cannot be empty. In this
- case, use 3DES anyway as it's the safest choice - perhaps the
- v3 key is being used in an OpenPGP implementation and we know
- that the implementation behind any v4 key can handle 3DES.
- Note that we do not support v3 keys since version 2.2 so the
- above description gives only historical background. */
- if (cfx.dek->algo == -1)
- {
- /* If does not make sense to fallback to the rfc4880
- * required 3DES if we will reject that algo later. Thus we
- * fallback to AES anticipating RFC4880bis rules. */
- if (opt.flags.allow_old_cipher_algos)
- cfx.dek->algo = CIPHER_ALGO_3DES;
- else
- cfx.dek->algo = CIPHER_ALGO_AES;
- }
-
- /* In case 3DES has been selected, print a warning if any key
- does not have a preference for AES. This should help to
- identify why encrypting to several recipients falls back to
- 3DES. */
- if (opt.verbose && cfx.dek->algo == CIPHER_ALGO_3DES)
- warn_missing_aes_from_pklist (pk_list);
- }
- else
- {
- if (!opt.expert
- && (select_algo_from_prefs (pk_list, PREFTYPE_SYM,
- opt.def_cipher_algo, NULL)
- != opt.def_cipher_algo))
- {
- log_info(_("WARNING: forcing symmetric cipher %s (%d)"
- " violates recipient preferences\n"),
- openpgp_cipher_algo_name (opt.def_cipher_algo),
- opt.def_cipher_algo);
- }
-
- cfx.dek->algo = opt.def_cipher_algo;
- }
-
- if (openpgp_cipher_blocklen (cfx.dek->algo) < 16
- && !opt.flags.allow_old_cipher_algos)
- {
- log_error (_("cipher algorithm '%s' may not be used for encryption\n"),
- openpgp_cipher_algo_name (cfx.dek->algo));
- if (!opt.quiet)
- log_info (_("(use option \"%s\" to override)\n"),
- "--allow-old-cipher-algos");
- rc = gpg_error (GPG_ERR_CIPHER_ALGO);
- goto leave;
- }
-
- /* Check compliance. */
- if (! gnupg_cipher_is_allowed (opt.compliance, 1, cfx.dek->algo,
- GCRY_CIPHER_MODE_CFB))
- {
- log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
- openpgp_cipher_algo_name (cfx.dek->algo),
- gnupg_compliance_option_string (opt.compliance));
- rc = gpg_error (GPG_ERR_CIPHER_ALGO);
- goto leave;
- }
-
- if (!gnupg_rng_is_compliant (opt.compliance))
- {
- rc = gpg_error (GPG_ERR_FORBIDDEN);
- log_error (_("%s is not compliant with %s mode\n"),
- "RNG",
- gnupg_compliance_option_string (opt.compliance));
- write_status_error ("random-compliance", rc);
- goto leave;
- }
-
- compliant = gnupg_cipher_is_compliant (CO_DE_VS, cfx.dek->algo,
- GCRY_CIPHER_MODE_CFB);
-
- {
- pk_list_t pkr;
-
- for (pkr = pk_list; pkr; pkr = pkr->next)
- {
- PKT_public_key *pk = pkr->pk;
- unsigned int nbits = nbits_from_pk (pk);
-
- if (!gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, 0,
- pk->pkey, nbits, NULL))
- log_info (_("WARNING: key %s is not suitable for encryption"
- " in %s mode\n"),
- keystr_from_pk (pk),
- gnupg_compliance_option_string (opt.compliance));
-
- if (compliant
- && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey,
- nbits, NULL))
- compliant = 0;
- }
-
- }
+ cfx.dek = create_dek_with_warnings (pk_list);
- if (compliant)
- write_status_strings (STATUS_ENCRYPTION_COMPLIANCE_MODE,
- 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;
- }
+ rc = check_encryption_compliance (cfx.dek, pk_list);
+ if (rc)
+ goto leave;
cfx.dek->use_aead = use_aead (pk_list, cfx.dek->algo);
if (!cfx.dek->use_aead)
@@ -1040,41 +1060,11 @@ encrypt_filter (void *opaque, int control,
{
if ( !efx->header_okay )
{
- efx->cfx.dek = xmalloc_secure_clear ( sizeof *efx->cfx.dek );
- if ( !opt.def_cipher_algo )
- {
- /* Try to get it from the prefs. */
- efx->cfx.dek->algo =
- select_algo_from_prefs (efx->pk_list, PREFTYPE_SYM, -1, NULL);
- if (efx->cfx.dek->algo == -1 )
- {
- /* Because 3DES is implicitly in the prefs, this can
- only happen if we do not have any public keys in
- the list. */
- efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO;
- }
-
- /* In case 3DES has been selected, print a warning if
- any key does not have a preference for AES. This
- should help to identify why encrypting to several
- recipients falls back to 3DES. */
- if (opt.verbose
- && efx->cfx.dek->algo == CIPHER_ALGO_3DES)
- warn_missing_aes_from_pklist (efx->pk_list);
- }
- else
- {
- if (!opt.expert
- && select_algo_from_prefs (efx->pk_list,PREFTYPE_SYM,
- opt.def_cipher_algo,
- NULL) != opt.def_cipher_algo)
- log_info(_("forcing symmetric cipher %s (%d) "
- "violates recipient preferences\n"),
- openpgp_cipher_algo_name (opt.def_cipher_algo),
- opt.def_cipher_algo);
-
- efx->cfx.dek->algo = opt.def_cipher_algo;
- }
+ efx->cfx.dek = create_dek_with_warnings (efx->pk_list);
+
+ rc = check_encryption_compliance (efx->cfx.dek, efx->pk_list);
+ if (rc)
+ return rc;
efx->cfx.dek->use_aead = use_aead (efx->pk_list, efx->cfx.dek->algo);
if (!efx->cfx.dek->use_aead)