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
|
/* encrypt.c - Main encryption driver
|
||||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
||||||
* 2006, 2009 Free Software Foundation, Inc.
|
* 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.
|
* 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
|
/* *SESKEY contains the unencrypted session key ((*SESKEY)->KEY) and
|
||||||
the algorithm that will be used to encrypt the contents of the SED
|
the algorithm that will be used to encrypt the contents of the SED
|
||||||
packet ((*SESKEY)->ALGO). If *SESKEY is NULL, then a random
|
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 )
|
if ( use_seskey )
|
||||||
{
|
{
|
||||||
DEK *dek = NULL;
|
DEK *dek = NULL; /* Dummy. */
|
||||||
|
|
||||||
seskeylen = openpgp_cipher_get_algo_keylen (default_cipher_algo ());
|
seskeylen = openpgp_cipher_get_algo_keylen (default_cipher_algo ());
|
||||||
encrypt_seskey( cfx.dek, &dek, enckey );
|
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
|
* Encrypt the file with the given userids (or ask if none is
|
||||||
* supplied). Either FILENAME or FILEFD must be given, but not both.
|
* 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;
|
progress_filter_context_t *pfx;
|
||||||
PK_LIST pk_list;
|
PK_LIST pk_list;
|
||||||
int do_compress;
|
int do_compress;
|
||||||
int compliant;
|
|
||||||
|
|
||||||
if (filefd != -1 && filename)
|
if (filefd != -1 && filename)
|
||||||
return gpg_error (GPG_ERR_INV_ARG); /* Both given. */
|
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);
|
push_armor_filter (afx, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a session key. */
|
/* Create a session key (a DEK). */
|
||||||
cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek);
|
cfx.dek = create_dek_with_warnings (1, pk_list);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* 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);
|
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 )
|
if ( !efx->header_okay )
|
||||||
{
|
{
|
||||||
efx->cfx.dek = xmalloc_secure_clear ( sizeof *efx->cfx.dek );
|
efx->cfx.dek = create_dek_with_warnings (0, efx->pk_list);
|
||||||
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
|
rc = check_encryption_compliance (efx->cfx.dek, efx->pk_list);
|
||||||
any key does not have a preference for AES. This
|
if (rc)
|
||||||
should help to indentify why encrypting to several
|
return rc;
|
||||||
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->use_mdc = use_mdc (efx->pk_list,efx->cfx.dek->algo);
|
efx->cfx.dek->use_mdc = use_mdc (efx->pk_list,efx->cfx.dek->algo);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user