mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-10 13:04:23 +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
This commit is contained in:
parent
15cf36f6a8
commit
f88cb12f8e
284
g10/encrypt.c
284
g10/encrypt.c
@ -1,7 +1,7 @@
|
||||
/* encrypt.c - Main encryption driver
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
||||
* 2006, 2009 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2016 g10 Code GmbH
|
||||
* Copyright (C) 2016, 2022 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -67,6 +67,65 @@ encrypt_store (const char *filename)
|
||||
}
|
||||
|
||||
|
||||
/* Create an setup DEK structure and print approriate warnings. The
|
||||
* FALLBACK_TO_3DES flag is used to handle the two different ways we
|
||||
* use this code. 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 (int fallback_to_3des, 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 && fallback_to_3des)
|
||||
{
|
||||
/* 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. */
|
||||
dek->algo = CIPHER_ALGO_3DES;
|
||||
}
|
||||
else if (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. */
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/* *SESKEY contains the unencrypted session key ((*SESKEY)->KEY) and
|
||||
the algorithm that will be used to encrypt the contents of the SED
|
||||
packet ((*SESKEY)->ALGO). If *SESKEY is NULL, then a random
|
||||
@ -212,7 +271,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
|
||||
|
||||
if ( use_seskey )
|
||||
{
|
||||
DEK *dek = NULL;
|
||||
DEK *dek = NULL; /* Dummy. */
|
||||
|
||||
seskeylen = openpgp_cipher_get_algo_keylen (default_cipher_algo ());
|
||||
encrypt_seskey( cfx.dek, &dek, enckey );
|
||||
@ -446,6 +505,80 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *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;
|
||||
|
||||
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)
|
||||
{
|
||||
log_error (_("operation forced to fail due to"
|
||||
" unfulfilled compliance rules\n"));
|
||||
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||
g10_errors_seen = 1;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
leave:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encrypt the file with the given userids (or ask if none is
|
||||
* supplied). Either FILENAME or FILEFD must be given, but not both.
|
||||
@ -475,7 +608,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. */
|
||||
@ -563,109 +695,13 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
|
||||
push_armor_filter (afx, out);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
if (cfx.dek->algo == -1)
|
||||
{
|
||||
cfx.dek->algo = CIPHER_ALGO_3DES;
|
||||
}
|
||||
|
||||
/* 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 && 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
/* Create a session key (a DEK). */
|
||||
cfx.dek = create_dek_with_warnings (1, pk_list);
|
||||
|
||||
/* Check compliance etc. */
|
||||
rc = check_encryption_compliance (cfx.dek, pk_list);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
cfx.dek->use_mdc = use_mdc (pk_list,cfx.dek->algo);
|
||||
|
||||
@ -842,41 +878,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 (0, 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 indentify 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_mdc = use_mdc (efx->pk_list,efx->cfx.dek->algo);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user