mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-17 14:07:03 +01:00
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
This commit is contained in:
parent
530d709607
commit
a51067a21f
300
g10/encrypt.c
300
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;
|
||||
}
|
||||
cfx.dek = create_dek_with_warnings (pk_list);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
efx->cfx.dek = create_dek_with_warnings (efx->pk_list);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user