From 825dd7220ff6079cbe2d0df7fde93526c077fb6d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 10 Feb 2021 14:31:34 +0100 Subject: [PATCH] gpg: Do not allow old cipher algorithms for encryption. * g10/gpg.c: New option --allow-old-cipher-algos. (set_compliance_option): Set --rfc4880bis explictly to SHA256 and AES256. Allow old cipher algos for OpenPGP, rfc4880, and rfc2440. * g10/options.h (opt): Add flags.allow_old_cipher_algos. * g10/misc.c (print_sha1_keysig_rejected_note): Always print the note unless in --quiet mode. * g10/encrypt.c (setup_symkey): Disallow by default algos with a blocklengt < 128. (encrypt_crypt): Ditto. Fallback by default to AES instead of 3DES. * g10/pkclist.c (algo_available): Take care of old cipher also. (select_algo_from_prefs): Use AES as implicit algorithm by default. * tests/openpgp/defs.scm (create-gpghome): Set allow-old-cipher-algos. -- GnuPG-bug-id: 3415 --- doc/gpg.texi | 21 ++++++++++++++++----- g10/encrypt.c | 35 +++++++++++++++++++++++++++++++++-- g10/gpg.c | 26 +++++++++++++++++++++++++- g10/misc.c | 5 +++-- g10/options.h | 1 + g10/pkclist.c | 19 +++++++++++++------ tests/openpgp/defs.scm | 1 + 7 files changed, 92 insertions(+), 16 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index d44a9a211..8975cf9cd 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2848,16 +2848,17 @@ different compliance option in the gpg.conf file. @item --openpgp @opindex openpgp Reset all packet, cipher and digest options to strict OpenPGP -behavior. Use this option to reset all previous options like -@option{--s2k-*}, @option{--cipher-algo}, @option{--digest-algo} and +behavior. This option implies @option{--allow-old-cipher-algos}. Use +this option to reset all previous options like @option{--s2k-*}, +@option{--cipher-algo}, @option{--digest-algo} and @option{--compress-algo} to OpenPGP compliant values. All PGP workarounds are disabled. @item --rfc4880 @opindex rfc4880 Reset all packet, cipher and digest options to strict RFC-4880 -behavior. Note that this is currently the same thing as -@option{--openpgp}. +behavior. This option implies @option{--allow-old-cipher-algos}. +Note that this is currently the same thing as @option{--openpgp}. @item --rfc4880bis @opindex rfc4880bis @@ -2869,7 +2870,8 @@ proposed updates of RFC-4880. Reset all packet, cipher and digest options to strict RFC-2440 behavior. Note that by using this option encryption packets are created in a legacy mode without MDC protection. This is dangerous -and should thus only be used for experiments. See also option +and should thus only be used for experiments. This option implies +@option{--allow-old-cipher-algos}. See also option @option{--ignore-mdc-error}. @item --pgp6 @@ -3391,6 +3393,15 @@ necessary to get as much data as possible out of that garbled message. Be aware that a missing or failed MDC can be an indication of an attack. Use with great caution; see also option @option{--rfc2440}. +@item --allow-old-cipher-algos +@opindex allow-old-cipher-algos +Old cipher algorithms like 3DES, IDEA, or CAST5 encrypt data using +blocks of 64 bits; modern algorithms use blocks of 128 bit instead. +To avoid certain attack on these old algorithms it is suggested not to +encrypt more than 150 MiByte using the same key. For this reason gpg +does not allow the use of 64 bit block size algorithms for encryption +unless this option is specified. + @item --allow-weak-digest-algos @opindex allow-weak-digest-algos Signatures made with known-weak digest algorithms are normally diff --git a/g10/encrypt.c b/g10/encrypt.c index a021c0e07..388c3db74 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -538,6 +538,17 @@ setup_symkey (STRING2KEY **symkey_s2k, DEK **symkey_dek) int s2kdigest; defcipher = default_cipher_algo (); + if (openpgp_cipher_blocklen (defcipher) < 16 + && !opt.flags.allow_old_cipher_algos) + { + log_error (_("cipher algorithm '%s' may not be used for encryption\n"), + openpgp_cipher_algo_name (defcipher)); + if (!opt.quiet) + log_info (_("(use option \"%s\" to override)\n"), + "--allow-old-cipher-algos"); + return gpg_error (GPG_ERR_CIPHER_ALGO); + } + if (!gnupg_cipher_is_allowed (opt.compliance, 1, defcipher, GCRY_CIPHER_MODE_CFB)) { @@ -741,10 +752,18 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, 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. */ + 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) { - cfx.dek->algo = CIPHER_ALGO_3DES; + /* 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 @@ -770,6 +789,18 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, 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)) diff --git a/g10/gpg.c b/g10/gpg.c index e795f744a..b4b802248 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -345,6 +345,7 @@ enum cmd_and_opt_values oAllowFreeformUID, oNoAllowFreeformUID, oAllowSecretKeyImport, + oAllowOldCipherAlgos, oEnableSpecialFilenames, oNoLiteral, oSetFilesize, @@ -854,6 +855,7 @@ static gpgrt_opt_t opts[] = { /* Options to override new security defaults. */ ARGPARSE_s_n (oAllowWeakKeySignatures, "allow-weak-key-signatures", "@"), ARGPARSE_s_n (oAllowWeakDigestAlgos, "allow-weak-digest-algos", "@"), + ARGPARSE_s_n (oAllowOldCipherAlgos, "allow-old-cipher-algos", "@"), ARGPARSE_s_s (oWeakDigest, "weak-digest","@"), ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"), ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"), @@ -2186,7 +2188,23 @@ set_compliance_option (enum cmd_and_opt_values option) { case oRFC4880bis: opt.flags.rfc4880bis = 1; - /* fall through. */ + opt.compliance = CO_RFC4880; + opt.flags.dsa2 = 1; + opt.flags.require_cross_cert = 1; + opt.rfc2440_text = 0; + opt.allow_non_selfsigned_uid = 1; + opt.allow_freeform_uid = 1; + opt.escape_from = 1; + opt.not_dash_escaped = 0; + opt.def_cipher_algo = 0; + opt.def_aead_algo = 0; + opt.def_digest_algo = 0; + opt.cert_digest_algo = 0; + opt.compress_algo = -1; + opt.s2k_mode = 3; /* iterated+salted */ + opt.s2k_digest_algo = DIGEST_ALGO_SHA256; + opt.s2k_cipher_algo = CIPHER_ALGO_AES256; + break; case oOpenPGP: case oRFC4880: /* This is effectively the same as RFC2440, but with @@ -2208,6 +2226,7 @@ set_compliance_option (enum cmd_and_opt_values option) opt.s2k_mode = 3; /* iterated+salted */ opt.s2k_digest_algo = DIGEST_ALGO_SHA1; opt.s2k_cipher_algo = CIPHER_ALGO_3DES; + opt.flags.allow_old_cipher_algos = 1; break; case oRFC2440: opt.compliance = CO_RFC2440; @@ -2225,6 +2244,7 @@ set_compliance_option (enum cmd_and_opt_values option) opt.s2k_mode = 3; /* iterated+salted */ opt.s2k_digest_algo = DIGEST_ALGO_SHA1; opt.s2k_cipher_algo = CIPHER_ALGO_3DES; + opt.flags.allow_old_cipher_algos = 1; break; case oPGP7: opt.compliance = CO_PGP7; break; case oPGP8: opt.compliance = CO_PGP8; break; @@ -3604,6 +3624,10 @@ main (int argc, char **argv) opt.flags.allow_weak_key_signatures = 1; break; + case oAllowOldCipherAlgos: + opt.flags.allow_old_cipher_algos = 1; + break; + case oFakedSystemTime: { size_t len = strlen (pargs.r.ret_str); diff --git a/g10/misc.c b/g10/misc.c index cd5c1bd7a..2a431b137 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -396,8 +396,9 @@ print_sha1_keysig_rejected_note (void) log_info (_("Note: third-party key signatures using" " the %s algorithm are rejected\n"), gcry_md_algo_name (GCRY_MD_SHA1)); - print_further_info ("use option \"%s\" to override", - "--allow-weak-key-signatures"); + if (!opt.quiet) + log_info (_("(use option \"%s\" to override)\n"), + "--allow-weak-key-signatures"); } diff --git a/g10/options.h b/g10/options.h index 5b0b12fd3..61118314e 100644 --- a/g10/options.h +++ b/g10/options.h @@ -237,6 +237,7 @@ struct unsigned int use_embedded_filename:1; unsigned int utf8_filename:1; unsigned int dsa2:1; + unsigned int allow_old_cipher_algos:1; unsigned int allow_weak_digest_algos:1; unsigned int allow_weak_key_signatures:1; unsigned int large_rsa:1; diff --git a/g10/pkclist.c b/g10/pkclist.c index d53af7223..392689352 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1397,6 +1397,10 @@ algo_available( preftype_t preftype, int algo, const struct pref_hint *hint) { if( preftype == PREFTYPE_SYM ) { + if (!opt.flags.allow_old_cipher_algos + && openpgp_cipher_blocklen (algo) < 16) + return 0; /* We don't want this one. */ + if(PGP7 && (algo != CIPHER_ALGO_IDEA && algo != CIPHER_ALGO_3DES && algo != CIPHER_ALGO_CAST5 @@ -1494,12 +1498,15 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype, switch(preftype) { case PREFTYPE_SYM: - /* IDEA is implicitly there for v3 keys with v3 selfsigs if - --pgp2 mode is on. This was a 2440 thing that was - dropped from 4880 but is still relevant to GPG's 1991 - support. All this doesn't mean IDEA is actually - available, of course. */ - implicit=CIPHER_ALGO_3DES; + /* Historical note: IDEA is implicitly there for v3 keys + with v3 selfsigs if --pgp2 mode is on. This was a 2440 + thing that was dropped from 4880 but is still relevant to + GPG's 1991 support. All this doesn't mean IDEA is + actually available, of course. */ + if (opt.flags.allow_old_cipher_algos) + implicit = CIPHER_ALGO_3DES; + else + implicit = CIPHER_ALGO_AES; break; case PREFTYPE_AEAD: diff --git a/tests/openpgp/defs.scm b/tests/openpgp/defs.scm index fab033659..3f6248f9e 100644 --- a/tests/openpgp/defs.scm +++ b/tests/openpgp/defs.scm @@ -345,6 +345,7 @@ "no-auto-key-retrieve" "no-auto-key-locate" "allow-weak-digest-algos" + "allow-old-cipher-algos" "ignore-mdc-error" (if have-opt-always-trust "no-auto-check-trustdb" "#no-auto-check-trustdb")