From 432cfa2baa8db94abf0daa9821a42ef40723e3c0 Mon Sep 17 00:00:00 2001 From: Clemens Lang Date: Fri, 1 Apr 2022 16:17:28 +0200 Subject: [PATCH] Allow disabling of SHA1 signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NOTE: This patch is ported from CentOS 9 / RHEL 9, where it defaults to denying SHA1 signatures. On Fedora, the default is – for now – to allow SHA1 signatures. In order to phase out SHA1 signatures, introduce a new configuration option in the alg_section named 'rh-allow-sha1-signatures'. This option defaults to true. If set to false, any signature creation or verification operations that involve SHA1 as digest will fail. This also affects TLS, where the signature_algorithms extension of any ClientHello message sent by OpenSSL will no longer include signatures with the SHA1 digest if rh-allow-sha1-signatures is false. For servers that request a client certificate, the same also applies for CertificateRequest messages sent by them. Resolves: rhbz#2070977 Related: rhbz#2031742, rhbz#2062640 Signed-off-by: Clemens Lang --- 0049-Allow-disabling-of-SHA1-signatures.patch | 503 ++++++++++++++++++ ...clevel-1-if-rh-allow-sha1-signatures.patch | 217 ++++++++ openssl.spec | 14 +- 3 files changed, 733 insertions(+), 1 deletion(-) create mode 100644 0049-Allow-disabling-of-SHA1-signatures.patch create mode 100644 0052-Allow-SHA1-in-seclevel-1-if-rh-allow-sha1-signatures.patch diff --git a/0049-Allow-disabling-of-SHA1-signatures.patch b/0049-Allow-disabling-of-SHA1-signatures.patch new file mode 100644 index 0000000..e316a4b --- /dev/null +++ b/0049-Allow-disabling-of-SHA1-signatures.patch @@ -0,0 +1,503 @@ +From b4f8964ad1903e24cd2ee07f42ce97c3047f4af4 Mon Sep 17 00:00:00 2001 +From: Clemens Lang +Date: Mon, 21 Feb 2022 17:24:44 +0100 +Subject: [PATCH] Allow disabling of SHA1 signatures +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +NOTE: This patch is ported from CentOS 9 / RHEL 9, where it defaults to +denying SHA1 signatures. On Fedora, the default is – for now – to allow +SHA1 signatures. + +In order to phase out SHA1 signatures, introduce a new configuration +option in the alg_section named 'rh-allow-sha1-signatures'. This option +defaults to true. If set to false, any signature creation or +verification operations that involve SHA1 as digest will fail. + +This also affects TLS, where the signature_algorithms extension of any +ClientHello message sent by OpenSSL will no longer include signatures +with the SHA1 digest if rh-allow-sha1-signatures is false. For servers +that request a client certificate, the same also applies for +CertificateRequest messages sent by them. + +For signatures created using the EVP_PKEY API, this is a best-effort +check that will deny signatures in cases where the digest algorithm is +known. This means, for example, that that following steps will still +work: + + $> openssl dgst -sha1 -binary -out sha1 infile + $> openssl pkeyutl -inkey key.pem -sign -in sha1 -out sha1sig + $> openssl pkeyutl -inkey key.pem -verify -sigfile sha1sig -in sha1 + +whereas these will not: + + $> openssl dgst -sha1 -binary -out sha1 infile + $> openssl pkeyutl -inkey kem.pem -sign -in sha1 -out sha1sig -pkeyopt digest:sha1 + $> openssl pkeyutl -inkey kem.pem -verify -sigfile sha1sig -in sha1 -pkeyopt digest:sha1 + +This happens because in the first case, OpenSSL's signature +implementation does not know that it is signing a SHA1 hash (it could be +signing arbitrary data). +--- + crypto/evp/evp_cnf.c | 13 +++ + crypto/evp/m_sigver.c | 85 +++++++++++++++++++ + crypto/evp/pmeth_lib.c | 15 ++++ + doc/man5/config.pod | 13 +++ + include/internal/cryptlib.h | 3 +- + include/internal/sslconf.h | 4 + + providers/common/securitycheck.c | 20 +++++ + providers/common/securitycheck_default.c | 9 +- + providers/implementations/signature/dsa_sig.c | 11 ++- + .../implementations/signature/ecdsa_sig.c | 4 + + providers/implementations/signature/rsa_sig.c | 20 ++++- + ssl/t1_lib.c | 8 ++ + util/libcrypto.num | 2 + + 13 files changed, 198 insertions(+), 9 deletions(-) + +diff --git a/crypto/evp/evp_cnf.c b/crypto/evp/evp_cnf.c +index 0e7fe64cf9..b9d3b6d226 100644 +--- a/crypto/evp/evp_cnf.c ++++ b/crypto/evp/evp_cnf.c +@@ -10,6 +10,7 @@ + #include + #include + #include "internal/cryptlib.h" ++#include "internal/sslconf.h" + #include + #include + #include +@@ -57,6 +58,18 @@ static int alg_module_init(CONF_IMODULE *md, const CONF *cnf) + ERR_raise(ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE); + return 0; + } ++ } else if (strcmp(oval->name, "rh-allow-sha1-signatures") == 0) { ++ int m; ++ ++ /* Detailed error already reported. */ ++ if (!X509V3_get_value_bool(oval, &m)) ++ return 0; ++ ++ if (!ossl_ctx_legacy_digest_signatures_allowed_set( ++ NCONF_get0_libctx((CONF *)cnf), m > 0, 0)) { ++ ERR_raise(ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE); ++ return 0; ++ } + } else { + ERR_raise_data(ERR_LIB_EVP, EVP_R_UNKNOWN_OPTION, + "name=%s, value=%s", oval->name, oval->value); +diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c +index 76a6814b42..8da2183ce0 100644 +--- a/crypto/evp/m_sigver.c ++++ b/crypto/evp/m_sigver.c +@@ -16,6 +16,79 @@ + #include "internal/numbers.h" /* includes SIZE_MAX */ + #include "evp_local.h" + ++typedef struct ossl_legacy_digest_signatures_st { ++ int allowed; ++} OSSL_LEGACY_DIGEST_SIGNATURES; ++ ++static void ossl_ctx_legacy_digest_signatures_free(void *vldsigs) ++{ ++ OSSL_LEGACY_DIGEST_SIGNATURES *ldsigs = vldsigs; ++ ++ if (ldsigs != NULL) { ++ OPENSSL_free(ldsigs); ++ } ++} ++ ++static void *ossl_ctx_legacy_digest_signatures_new(OSSL_LIB_CTX *ctx) ++{ ++ OSSL_LEGACY_DIGEST_SIGNATURES* ldsigs = OPENSSL_zalloc(sizeof(OSSL_LEGACY_DIGEST_SIGNATURES)); ++ /* Warning: This patch differs from the same patch in CentOS and RHEL here, ++ * because the default on Fedora is to allow SHA-1 and support disabling ++ * it, while CentOS/RHEL disable it by default and allow enabling it. */ ++ ldsigs->allowed = 1; ++ return ldsigs; ++} ++ ++static const OSSL_LIB_CTX_METHOD ossl_ctx_legacy_digest_signatures_method = { ++ OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY, ++ ossl_ctx_legacy_digest_signatures_new, ++ ossl_ctx_legacy_digest_signatures_free, ++}; ++ ++static OSSL_LEGACY_DIGEST_SIGNATURES *ossl_ctx_legacy_digest_signatures( ++ OSSL_LIB_CTX *libctx, int loadconfig) ++{ ++#ifndef FIPS_MODULE ++ if (loadconfig && !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL)) ++ return NULL; ++#endif ++ ++ return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_LEGACY_DIGEST_SIGNATURES, ++ &ossl_ctx_legacy_digest_signatures_method); ++} ++ ++int ossl_ctx_legacy_digest_signatures_allowed(OSSL_LIB_CTX *libctx, int loadconfig) ++{ ++ OSSL_LEGACY_DIGEST_SIGNATURES *ldsigs ++ = ossl_ctx_legacy_digest_signatures(libctx, loadconfig); ++ ++#ifndef FIPS_MODULE ++ if (ossl_safe_getenv("OPENSSL_ENABLE_SHA1_SIGNATURES") != NULL) ++ /* used in tests */ ++ return 1; ++#endif ++ ++ /* Warning: This patch differs from the same patch in CentOS and RHEL here, ++ * because the default on Fedora is to allow SHA-1 and support disabling ++ * it, while CentOS/RHEL disable it by default and allow enabling it. */ ++ return ldsigs != NULL ? ldsigs->allowed : 1; ++} ++ ++int ossl_ctx_legacy_digest_signatures_allowed_set(OSSL_LIB_CTX *libctx, int allow, ++ int loadconfig) ++{ ++ OSSL_LEGACY_DIGEST_SIGNATURES *ldsigs ++ = ossl_ctx_legacy_digest_signatures(libctx, loadconfig); ++ ++ if (ldsigs == NULL) { ++ ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); ++ return 0; ++ } ++ ++ ldsigs->allowed = allow; ++ return 1; ++} ++ + #ifndef FIPS_MODULE + + static int update(EVP_MD_CTX *ctx, const void *data, size_t datalen) +@@ -258,6 +331,18 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + } + } + ++ if (ctx->reqdigest != NULL ++ && !EVP_PKEY_is_a(locpctx->pkey, SN_hmac) ++ && !EVP_PKEY_is_a(locpctx->pkey, SN_tls1_prf) ++ && !EVP_PKEY_is_a(locpctx->pkey, SN_hkdf)) { ++ int mdnid = EVP_MD_nid(ctx->reqdigest); ++ if (!ossl_ctx_legacy_digest_signatures_allowed(locpctx->libctx, 0) ++ && (mdnid == NID_sha1 || mdnid == NID_md5_sha1)) { ++ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_DIGEST); ++ goto err; ++ } ++ } ++ + if (ver) { + if (signature->digest_verify_init == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); +diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c +index 2b9c6c2351..3c5a1e6f5d 100644 +--- a/crypto/evp/pmeth_lib.c ++++ b/crypto/evp/pmeth_lib.c +@@ -33,6 +33,7 @@ + #include "internal/ffc.h" + #include "internal/numbers.h" + #include "internal/provider.h" ++#include "internal/sslconf.h" + #include "evp_local.h" + + #ifndef FIPS_MODULE +@@ -946,6 +947,20 @@ static int evp_pkey_ctx_set_md(EVP_PKEY_CTX *ctx, const EVP_MD *md, + return -2; + } + ++ if (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) ++ && md != NULL ++ && ctx->pkey != NULL ++ && !EVP_PKEY_is_a(ctx->pkey, SN_hmac) ++ && !EVP_PKEY_is_a(ctx->pkey, SN_tls1_prf) ++ && !EVP_PKEY_is_a(ctx->pkey, SN_hkdf)) { ++ int mdnid = EVP_MD_nid(md); ++ if ((mdnid == NID_sha1 || mdnid == NID_md5_sha1) ++ && !ossl_ctx_legacy_digest_signatures_allowed(ctx->libctx, 0)) { ++ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_DIGEST); ++ return -1; ++ } ++ } ++ + if (fallback) + return EVP_PKEY_CTX_ctrl(ctx, -1, op, ctrl, 0, (void *)(md)); + +diff --git a/doc/man5/config.pod b/doc/man5/config.pod +index 77a8055e81..0c9110d28a 100644 +--- a/doc/man5/config.pod ++++ b/doc/man5/config.pod +@@ -296,6 +296,19 @@ Within the algorithm properties section, the following names have meaning: + The value may be anything that is acceptable as a property query + string for EVP_set_default_properties(). + ++=item B ++ ++The value is a boolean that can be B or B. If the value is not set, ++it behaves as if it was set to B. ++ ++When set to B, any attempt to create or verify a signature with a SHA1 ++digest will fail. To test whether your software will work with future versions ++of OpenSSL, set this option to B. This setting also affects TLS, where ++signature algorithms that use SHA1 as digest will no longer be supported if ++this option is set to B. Because TLS 1.1 or lower use MD5-SHA1 as ++pseudorandom function (PRF) to derive key material, disabling ++B requires the use of TLS 1.2 or newer. ++ + =item B (deprecated) + + The value is a boolean that can be B or B. If the value is +diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h +index 1291299b6e..e234341e6a 100644 +--- a/include/internal/cryptlib.h ++++ b/include/internal/cryptlib.h +@@ -168,7 +168,8 @@ typedef struct ossl_ex_data_global_st { + # define OSSL_LIB_CTX_PROVIDER_CONF_INDEX 16 + # define OSSL_LIB_CTX_BIO_CORE_INDEX 17 + # define OSSL_LIB_CTX_CHILD_PROVIDER_INDEX 18 +-# define OSSL_LIB_CTX_MAX_INDEXES 19 ++# define OSSL_LIB_CTX_LEGACY_DIGEST_SIGNATURES 19 ++# define OSSL_LIB_CTX_MAX_INDEXES 20 + + # define OSSL_LIB_CTX_METHOD_LOW_PRIORITY -1 + # define OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY 0 +diff --git a/include/internal/sslconf.h b/include/internal/sslconf.h +index fd7f7e3331..05464b0655 100644 +--- a/include/internal/sslconf.h ++++ b/include/internal/sslconf.h +@@ -18,4 +18,8 @@ int conf_ssl_name_find(const char *name, size_t *idx); + void conf_ssl_get_cmd(const SSL_CONF_CMD *cmd, size_t idx, char **cmdstr, + char **arg); + ++/* Methods to support disabling all signatures with legacy digests */ ++int ossl_ctx_legacy_digest_signatures_allowed(OSSL_LIB_CTX *libctx, int loadconfig); ++int ossl_ctx_legacy_digest_signatures_allowed_set(OSSL_LIB_CTX *libctx, int allow, ++ int loadconfig); + #endif +diff --git a/providers/common/securitycheck.c b/providers/common/securitycheck.c +index 699ada7c52..e534ad0a5f 100644 +--- a/providers/common/securitycheck.c ++++ b/providers/common/securitycheck.c +@@ -19,6 +19,7 @@ + #include + #include + #include "prov/securitycheck.h" ++#include "internal/sslconf.h" + + /* + * FIPS requires a minimum security strength of 112 bits (for encryption or +@@ -235,6 +236,15 @@ int ossl_digest_get_approved_nid_with_sha1(OSSL_LIB_CTX *ctx, const EVP_MD *md, + mdnid = -1; /* disallowed by security checks */ + } + # endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ ++ ++#ifndef FIPS_MODULE ++ if (!ossl_ctx_legacy_digest_signatures_allowed(ctx, 0)) ++ /* SHA1 is globally disabled, check whether we want to locally allow ++ * it. */ ++ if (mdnid == NID_sha1 && !sha1_allowed) ++ mdnid = -1; ++#endif ++ + return mdnid; + } + +@@ -244,5 +254,15 @@ int ossl_digest_is_allowed(OSSL_LIB_CTX *ctx, const EVP_MD *md) + if (ossl_securitycheck_enabled(ctx)) + return ossl_digest_get_approved_nid(md) != NID_undef; + # endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ ++ ++#ifndef FIPS_MODULE ++ { ++ int mdnid = EVP_MD_nid(md); ++ if ((mdnid == NID_sha1 || mdnid == NID_md5_sha1) ++ && !ossl_ctx_legacy_digest_signatures_allowed(ctx, 0)) ++ return 0; ++ } ++#endif ++ + return 1; + } +diff --git a/providers/common/securitycheck_default.c b/providers/common/securitycheck_default.c +index de7f0d3a0a..ce54a94fbc 100644 +--- a/providers/common/securitycheck_default.c ++++ b/providers/common/securitycheck_default.c +@@ -15,6 +15,7 @@ + #include + #include "prov/securitycheck.h" + #include "internal/nelem.h" ++#include "internal/sslconf.h" + + /* Disable the security checks in the default provider */ + int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx) +@@ -23,9 +24,10 @@ int ossl_securitycheck_enabled(OSSL_LIB_CTX *libctx) + } + + int ossl_digest_rsa_sign_get_md_nid(OSSL_LIB_CTX *ctx, const EVP_MD *md, +- ossl_unused int sha1_allowed) ++ int sha1_allowed) + { + int mdnid; ++ int ldsigs_allowed; + + static const OSSL_ITEM name_to_nid[] = { + { NID_md5, OSSL_DIGEST_NAME_MD5 }, +@@ -36,8 +38,11 @@ int ossl_digest_rsa_sign_get_md_nid(OSSL_LIB_CTX *ctx, const EVP_MD *md, + { NID_ripemd160, OSSL_DIGEST_NAME_RIPEMD160 }, + }; + +- mdnid = ossl_digest_get_approved_nid_with_sha1(ctx, md, 1); ++ ldsigs_allowed = ossl_ctx_legacy_digest_signatures_allowed(ctx, 0); ++ mdnid = ossl_digest_get_approved_nid_with_sha1(ctx, md, sha1_allowed || ldsigs_allowed); + if (mdnid == NID_undef) + mdnid = ossl_digest_md_to_nid(md, name_to_nid, OSSL_NELEM(name_to_nid)); ++ if (mdnid == NID_md5_sha1 && !ldsigs_allowed) ++ mdnid = -1; + return mdnid; + } +diff --git a/providers/implementations/signature/dsa_sig.c b/providers/implementations/signature/dsa_sig.c +index 28fd7c498e..fa3822f39f 100644 +--- a/providers/implementations/signature/dsa_sig.c ++++ b/providers/implementations/signature/dsa_sig.c +@@ -124,12 +124,17 @@ static int dsa_setup_md(PROV_DSA_CTX *ctx, + mdprops = ctx->propq; + + if (mdname != NULL) { +- int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); + WPACKET pkt; + EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); +- int md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md, +- sha1_allowed); ++ int md_nid; + size_t mdname_len = strlen(mdname); ++#ifdef FIPS_MODULE ++ int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); ++#else ++ int sha1_allowed = 0; ++#endif ++ md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md, ++ sha1_allowed); + + if (md == NULL || md_nid < 0) { + if (md == NULL) +diff --git a/providers/implementations/signature/ecdsa_sig.c b/providers/implementations/signature/ecdsa_sig.c +index 865d49d100..99b228e82c 100644 +--- a/providers/implementations/signature/ecdsa_sig.c ++++ b/providers/implementations/signature/ecdsa_sig.c +@@ -237,7 +237,11 @@ static int ecdsa_setup_md(PROV_ECDSA_CTX *ctx, const char *mdname, + "%s could not be fetched", mdname); + return 0; + } ++#ifdef FIPS_MODULE + sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); ++#else ++ sha1_allowed = 0; ++#endif + md_nid = ossl_digest_get_approved_nid_with_sha1(ctx->libctx, md, + sha1_allowed); + if (md_nid < 0) { +diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c +index 325e855333..bea397f0c1 100644 +--- a/providers/implementations/signature/rsa_sig.c ++++ b/providers/implementations/signature/rsa_sig.c +@@ -26,6 +26,7 @@ + #include "internal/cryptlib.h" + #include "internal/nelem.h" + #include "internal/sizes.h" ++#include "internal/sslconf.h" + #include "crypto/rsa.h" + #include "prov/providercommon.h" + #include "prov/implementations.h" +@@ -34,6 +35,7 @@ + #include "prov/securitycheck.h" + + #define RSA_DEFAULT_DIGEST_NAME OSSL_DIGEST_NAME_SHA1 ++#define RSA_DEFAULT_DIGEST_NAME_NONLEGACY OSSL_DIGEST_NAME_SHA2_256 + + static OSSL_FUNC_signature_newctx_fn rsa_newctx; + static OSSL_FUNC_signature_sign_init_fn rsa_sign_init; +@@ -289,10 +291,15 @@ static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname, + + if (mdname != NULL) { + EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); ++ int md_nid; ++ size_t mdname_len = strlen(mdname); ++#ifdef FIPS_MODULE + int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); +- int md_nid = ossl_digest_rsa_sign_get_md_nid(ctx->libctx, md, ++#else ++ int sha1_allowed = 0; ++#endif ++ md_nid = ossl_digest_rsa_sign_get_md_nid(ctx->libctx, md, + sha1_allowed); +- size_t mdname_len = strlen(mdname); + + if (md == NULL + || md_nid <= 0 +@@ -1348,8 +1355,15 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) + prsactx->pad_mode = pad_mode; + + if (prsactx->md == NULL && pmdname == NULL +- && pad_mode == RSA_PKCS1_PSS_PADDING) ++ && pad_mode == RSA_PKCS1_PSS_PADDING) { + pmdname = RSA_DEFAULT_DIGEST_NAME; ++#ifndef FIPS_MODULE ++ if (!ossl_ctx_legacy_digest_signatures_allowed(prsactx->libctx, 0)) { ++ pmdname = RSA_DEFAULT_DIGEST_NAME_NONLEGACY; ++ } ++#endif ++ } ++ + + if (pmgf1mdname != NULL + && !rsa_setup_mgf1_md(prsactx, pmgf1mdname, pmgf1mdprops)) +diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c +index 41fddf22a7..dcd487ec2e 100644 +--- a/ssl/t1_lib.c ++++ b/ssl/t1_lib.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include "internal/sslconf.h" + #include "internal/nelem.h" + #include "internal/sizes.h" + #include "internal/tlsgroups.h" +@@ -1145,11 +1146,13 @@ int ssl_setup_sig_algs(SSL_CTX *ctx) + = OPENSSL_malloc(sizeof(*lu) * OSSL_NELEM(sigalg_lookup_tbl)); + EVP_PKEY *tmpkey = EVP_PKEY_new(); + int ret = 0; ++ int ldsigs_allowed; + + if (cache == NULL || tmpkey == NULL) + goto err; + + ERR_set_mark(); ++ ldsigs_allowed = ossl_ctx_legacy_digest_signatures_allowed(ctx->libctx, 0); + for (i = 0, lu = sigalg_lookup_tbl; + i < OSSL_NELEM(sigalg_lookup_tbl); lu++, i++) { + EVP_PKEY_CTX *pctx; +@@ -1169,6 +1172,11 @@ int ssl_setup_sig_algs(SSL_CTX *ctx) + cache[i].enabled = 0; + continue; + } ++ if ((lu->hash == NID_sha1 || lu->hash == NID_md5_sha1) ++ && !ldsigs_allowed) { ++ cache[i].enabled = 0; ++ continue; ++ } + + if (!EVP_PKEY_set_type(tmpkey, lu->sig)) { + cache[i].enabled = 0; +diff --git a/util/libcrypto.num b/util/libcrypto.num +index 10b4e57d79..2d3c363bb0 100644 +--- a/util/libcrypto.num ++++ b/util/libcrypto.num +@@ -5426,3 +5426,5 @@ ASN1_item_d2i_ex 5552 3_0_0 EXIST::FUNCTION: + EVP_PKEY_get0_provider 5554 3_0_0 EXIST::FUNCTION: + EVP_PKEY_CTX_get0_provider 5555 3_0_0 EXIST::FUNCTION: + ossl_safe_getenv ? 3_0_0 EXIST::FUNCTION: ++ossl_ctx_legacy_digest_signatures_allowed ? 3_0_1 EXIST::FUNCTION: ++ossl_ctx_legacy_digest_signatures_allowed_set ? 3_0_1 EXIST::FUNCTION: +-- +2.35.1 + diff --git a/0052-Allow-SHA1-in-seclevel-1-if-rh-allow-sha1-signatures.patch b/0052-Allow-SHA1-in-seclevel-1-if-rh-allow-sha1-signatures.patch new file mode 100644 index 0000000..eea02f8 --- /dev/null +++ b/0052-Allow-SHA1-in-seclevel-1-if-rh-allow-sha1-signatures.patch @@ -0,0 +1,217 @@ +From f695f140255f9b564cac4d5e9e38ba27ec927256 Mon Sep 17 00:00:00 2001 +From: Clemens Lang +Date: Tue, 1 Mar 2022 15:44:18 +0100 +Subject: [PATCH 2/2] Allow SHA1 in seclevel 1 if rh-allow-sha1-signatures = + yes + +NOTE: This patch is ported from CentOS 9 / RHEL 9, where it allows SHA1 +in seclevel 2 if rh-allow-sha1-signatures = yes. This was chosen because +on CentOS 9 and RHEL 9, the LEGACY crypto policy sets the security level +to 2. + +On Fedora 35 (with OpenSSL 1.1) the legacy crypto policy uses security +level 1. Because Fedora 36 supports both OpenSSL 1.1 and OpenSSL 3, and +we want the legacy crypto policy to allow SHA-1 in TLS, the only option +to make this happen consistently in both OpenSSL 1.1 and OpenSSL 3 is +SECLEVEL=1 (which will allow SHA-1 in OpenSSL 1.1) and this change to +allow SHA-1 in SECLEVEL=1 with rh-allow-sha1-signatures = yes (which +will allow SHA-1 in OpenSSL 3). + +The change from CentOS 9 / RHEL 9 cannot be applied unmodified, because +rh-allow-sha1-signatures will default to yes in Fedora (according to our +current plans including until F38), and the security level in the +DEFAULT crypto policy is 2, i.e., the unmodified change would weaken the +default configuration. + +Related: rhbz#2055796 +Related: rhbz#2070977 +--- + crypto/x509/x509_vfy.c | 19 ++++++++++- + doc/man5/config.pod | 7 ++++ + ssl/t1_lib.c | 64 ++++++++++++++++++++++++++++------- + test/recipes/25-test_verify.t | 4 +-- + 4 files changed, 78 insertions(+), 16 deletions(-) + +diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c +index 2f175ca517..60aa26f552 100644 +--- a/crypto/x509/x509_vfy.c ++++ b/crypto/x509/x509_vfy.c +@@ -25,6 +25,7 @@ + #include + #include + #include "internal/dane.h" ++#include "internal/sslconf.h" + #include "crypto/x509.h" + #include "x509_local.h" + +@@ -3441,14 +3442,30 @@ static int check_sig_level(X509_STORE_CTX *ctx, X509 *cert) + { + int secbits = -1; + int level = ctx->param->auth_level; ++ int nid; ++ OSSL_LIB_CTX *libctx = NULL; + + if (level <= 0) + return 1; + if (level > NUM_AUTH_LEVELS) + level = NUM_AUTH_LEVELS; + +- if (!X509_get_signature_info(cert, NULL, NULL, &secbits, NULL)) ++ if (ctx->libctx) ++ libctx = ctx->libctx; ++ else if (cert->libctx) ++ libctx = cert->libctx; ++ else ++ libctx = OSSL_LIB_CTX_get0_global_default(); ++ ++ if (!X509_get_signature_info(cert, &nid, NULL, &secbits, NULL)) + return 0; + ++ if (nid == NID_sha1 ++ && ossl_ctx_legacy_digest_signatures_allowed(libctx, 0) ++ && ctx->param->auth_level < 2) ++ /* When rh-allow-sha1-signatures = yes and security level <= 1, ++ * explicitly allow SHA1 for backwards compatibility. */ ++ return 1; ++ + return secbits >= minbits_table[level - 1]; + } +diff --git a/doc/man5/config.pod b/doc/man5/config.pod +index 0c9110d28a..02e7ca706f 100644 +--- a/doc/man5/config.pod ++++ b/doc/man5/config.pod +@@ -309,6 +309,13 @@ this option is set to B. Because TLS 1.1 or lower use MD5-SHA1 as + pseudorandom function (PRF) to derive key material, disabling + B requires the use of TLS 1.2 or newer. + ++Note that enabling B will allow TLS signature ++algorithms that use SHA1 in security level 1, despite the definition of ++security level 1 of FIXME bits of security, which SHA1 does not meet. This ++allows using SHA1 in TLS in the LEGACY crypto-policy on Fedora without ++requiring to set the security level to 0, which would include further insecure ++algorithms. ++ + =item B (deprecated) + + The value is a boolean that can be B or B. If the value is +diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c +index dcd487ec2e..e47ddf56f1 100644 +--- a/ssl/t1_lib.c ++++ b/ssl/t1_lib.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include "crypto/x509.h" + #include "internal/sslconf.h" + #include "internal/nelem.h" + #include "internal/sizes.h" +@@ -1561,19 +1562,27 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey) + SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_UNKNOWN_DIGEST); + return 0; + } +- /* +- * Make sure security callback allows algorithm. For historical +- * reasons we have to pass the sigalg as a two byte char array. +- */ +- sigalgstr[0] = (sig >> 8) & 0xff; +- sigalgstr[1] = sig & 0xff; +- secbits = sigalg_security_bits(s->ctx, lu); +- if (secbits == 0 || +- !ssl_security(s, SSL_SECOP_SIGALG_CHECK, secbits, +- md != NULL ? EVP_MD_get_type(md) : NID_undef, +- (void *)sigalgstr)) { +- SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_WRONG_SIGNATURE_TYPE); +- return 0; ++ ++ if (lu->hash == NID_sha1 ++ && ossl_ctx_legacy_digest_signatures_allowed(s->ctx->libctx, 0) ++ && SSL_get_security_level(s) < 2) { ++ /* when rh-allow-sha1-signatures = yes and security level <= 1, ++ * explicitly allow SHA1 for backwards compatibility */ ++ } else { ++ /* ++ * Make sure security callback allows algorithm. For historical ++ * reasons we have to pass the sigalg as a two byte char array. ++ */ ++ sigalgstr[0] = (sig >> 8) & 0xff; ++ sigalgstr[1] = sig & 0xff; ++ secbits = sigalg_security_bits(s->ctx, lu); ++ if (secbits == 0 || ++ !ssl_security(s, SSL_SECOP_SIGALG_CHECK, secbits, ++ md != NULL ? EVP_MD_get_type(md) : NID_undef, ++ (void *)sigalgstr)) { ++ SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_WRONG_SIGNATURE_TYPE); ++ return 0; ++ } + } + /* Store the sigalg the peer uses */ + s->s3.tmp.peer_sigalg = lu; +@@ -2106,6 +2115,14 @@ static int tls12_sigalg_allowed(const SSL *s, int op, const SIGALG_LOOKUP *lu) + } + } + ++ if (lu->hash == NID_sha1 ++ && ossl_ctx_legacy_digest_signatures_allowed(s->ctx->libctx, 0) ++ && SSL_get_security_level(s) < 2) { ++ /* when rh-allow-sha1-signatures = yes and security level <= 1, ++ * explicitly allow SHA1 for backwards compatibility */ ++ return 1; ++ } ++ + /* Finally see if security callback allows it */ + secbits = sigalg_security_bits(s->ctx, lu); + sigalgstr[0] = (lu->sigalg >> 8) & 0xff; +@@ -2977,6 +2994,8 @@ static int ssl_security_cert_sig(SSL *s, SSL_CTX *ctx, X509 *x, int op) + { + /* Lookup signature algorithm digest */ + int secbits, nid, pknid; ++ OSSL_LIB_CTX *libctx = NULL; ++ + /* Don't check signature if self signed */ + if ((X509_get_extension_flags(x) & EXFLAG_SS) != 0) + return 1; +@@ -2985,6 +3004,25 @@ static int ssl_security_cert_sig(SSL *s, SSL_CTX *ctx, X509 *x, int op) + /* If digest NID not defined use signature NID */ + if (nid == NID_undef) + nid = pknid; ++ ++ if (x && x->libctx) ++ libctx = x->libctx; ++ else if (ctx && ctx->libctx) ++ libctx = ctx->libctx; ++ else if (s && s->ctx && s->ctx->libctx) ++ libctx = s->ctx->libctx; ++ else ++ libctx = OSSL_LIB_CTX_get0_global_default(); ++ ++ if (nid == NID_sha1 ++ && ossl_ctx_legacy_digest_signatures_allowed(libctx, 0) ++ && ((s != NULL && SSL_get_security_level(s) < 2) ++ || (ctx != NULL && SSL_CTX_get_security_level(ctx) < 2) ++ )) ++ /* When rh-allow-sha1-signatures = yes and security level <= 1, ++ * explicitly allow SHA1 for backwards compatibility. */ ++ return 1; ++ + if (s) + return ssl_security(s, op, secbits, nid, x); + else +diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t +index 700bbd849c..280477bc9d 100644 +--- a/test/recipes/25-test_verify.t ++++ b/test/recipes/25-test_verify.t +@@ -387,8 +387,8 @@ ok(verify("ee-pss-sha1-cert", "", ["root-cert"], ["ca-cert"], "-auth_level", "0" + ok(verify("ee-pss-sha256-cert", "", ["root-cert"], ["ca-cert"], ), + "CA with PSS signature using SHA256"); + +-ok(!verify("ee-pss-sha1-cert", "", ["root-cert"], ["ca-cert"], "-auth_level", "1"), +- "Reject PSS signature using SHA1 and auth level 1"); ++ok(!verify("ee-pss-sha1-cert", "", ["root-cert"], ["ca-cert"], "-auth_level", "2"), ++ "Reject PSS signature using SHA1 and auth level 2"); + + ok(verify("ee-pss-sha256-cert", "", ["root-cert"], ["ca-cert"], "-auth_level", "2"), + "PSS signature using SHA256 and auth level 2"); +-- +2.35.1 + diff --git a/openssl.spec b/openssl.spec index 91e74a0..fb4de73 100644 --- a/openssl.spec +++ b/openssl.spec @@ -15,7 +15,7 @@ Summary: Utilities from the general purpose cryptography library with TLS implementation Name: openssl Version: 3.0.2 -Release: 1%{?dist} +Release: 2%{?dist} Epoch: 1 # We have to remove certain patented algorithms from the openssl source # tarball with the hobble-openssl script which is included below. @@ -56,8 +56,12 @@ Patch11: 0011-Remove-EC-curves.patch Patch12: 0012-Disable-explicit-ec.patch # Instructions to load legacy provider in openssl.cnf Patch24: 0024-load-legacy-prov.patch +# Selectively disallow SHA1 signatures rhbz#2070977 +Patch49: 0049-Allow-disabling-of-SHA1-signatures.patch # Backport of patch for RHEL for Edge rhbz #2027261 Patch51: 0051-Support-different-R_BITS-lengths-for-KBKDF.patch +# Support SHA1 in TLS in LEGACY crypto-policy (which is SECLEVEL=1) +Patch52: 0052-Allow-SHA1-in-seclevel-1-if-rh-allow-sha1-signatures.patch License: ASL 2.0 URL: http://www.openssl.org/ @@ -384,6 +388,14 @@ install -m644 %{SOURCE9} \ %ldconfig_scriptlets libs %changelog +* Thu Apr 07 2022 Clemens Lang - 1:3.0.2-2 +- Allow disabling SHA1 signature creation and verification. + Set rh-allow-sha1-signatures = no to disable. + Allow SHA1 in TLS in SECLEVEL 1 if rh-allow-sha1-signatures = yes. This will + support SHA1 in TLS in the LEGACY crypto-policy. + Resolves: rhbz#2070977 + Related: rhbz#2031742, rhbz#2062640 + * Fri Mar 18 2022 Dmitry Belyavskiy - 1:3.0.2-1 - Rebase to upstream version 3.0.2