ELN: Disable SHA-1 by default using CentOS patches

ELN should ideally be ahead of CentOS and RHEL with policy changes, but
due to time constraints was not. Fix that by bringing the current CentOS
9 / RHEL 9 state of SHA-1 disabling to ELN.

Due to differences in their lifecycles, Fedora's packages will stay at
allowing SHA-1 by default for now. There is a plan to gradually catch up
to the ELN state over the next few releases.

Signed-off-by: Clemens Lang <cllang@redhat.com>
This commit is contained in:
Clemens Lang 2022-04-20 15:12:30 +02:00
parent 82a6212c47
commit 0967bb5953
3 changed files with 713 additions and 1 deletions

View File

@ -0,0 +1,489 @@
From 243201772cc6d583fae9eba81cb2c2c7425bc564 Mon Sep 17 00:00:00 2001
From: Clemens Lang <cllang@redhat.com>
Date: Mon, 21 Feb 2022 17:24:44 +0100
Subject: Selectively disallow SHA1 signatures
For RHEL 9.0, we want to phase out SHA1. One of the steps to do that is
disabling SHA1 signatures. Introduce a new configuration option in the
alg_section named 'rh-allow-sha1-signatures'. This option defaults to
false. If set to false (or unset), 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).
Resolves: rhbz#2031742
---
crypto/evp/evp_cnf.c | 13 ++++
crypto/evp/m_sigver.c | 77 +++++++++++++++++++
crypto/evp/pmeth_lib.c | 15 ++++
doc/man5/config.pod | 11 +++
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, 188 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 <stdio.h>
#include <openssl/crypto.h>
#include "internal/cryptlib.h"
+#include "internal/sslconf.h"
#include <openssl/conf.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
@@ -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 9188edbc21..db1a1d7bc3 100644
--- a/crypto/evp/m_sigver.c
+++ b/crypto/evp/m_sigver.c
@@ -16,6 +16,71 @@
#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)
+{
+ return OPENSSL_zalloc(sizeof(OSSL_LEGACY_DIGEST_SIGNATURES));
+}
+
+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 0;
+#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
+
+ return ldsigs != NULL ? ldsigs->allowed : 0;
+}
+
+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 +323,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..aa1be5ca7f 100644
--- a/doc/man5/config.pod
+++ b/doc/man5/config.pod
@@ -304,6 +304,17 @@ 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<rh-allow-sha1-signatures>
+
+The value is a boolean that can be B<yes> or B<no>. If the value is not set,
+it behaves as if it was set to B<no>.
+
+When set to B<no>, any attempt to create or verify a signature with a SHA1
+digest will fail. For compatibility with older versions of OpenSSL, set this
+option to B<yes>. 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<no>.
+
=item B<fips_mode> (deprecated)
The value is a boolean that can be B<yes> or B<no>. 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 <openssl/core_names.h>
#include <openssl/obj_mac.h>
#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 <openssl/obj_mac.h>
#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 fc32bb3556..4b74ee1a34 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -20,6 +20,7 @@
#include <openssl/bn.h>
#include <openssl/provider.h>
#include <openssl/param_build.h>
+#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_TIME_print_ex 5553 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

View File

@ -0,0 +1,206 @@
From c63599ee9708d543205a9173207ee7167315c624 Mon Sep 17 00:00:00 2001
From: Clemens Lang <cllang@redhat.com>
Date: Tue, 1 Mar 2022 15:44:18 +0100
Subject: [PATCH] Allow SHA1 in seclevel 2 if rh-allow-sha1-signatures = yes
References: rhbz#2055796
---
crypto/x509/x509_vfy.c | 19 ++++++++++-
doc/man5/config.pod | 7 +++-
ssl/t1_lib.c | 64 ++++++++++++++++++++++++++++-------
test/recipes/25-test_verify.t | 7 ++--
4 files changed, 79 insertions(+), 18 deletions(-)
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index ff3ca83de6..a549c1c111 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -25,6 +25,7 @@
#include <openssl/objects.h>
#include <openssl/core_names.h>
#include "internal/dane.h"
+#include "internal/sslconf.h"
#include "crypto/x509.h"
#include "x509_local.h"
@@ -3440,14 +3441,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 < 3)
+ /* When rh-allow-sha1-signatures = yes and security level <= 2,
+ * 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 aa1be5ca7f..aa69e2b844 100644
--- a/doc/man5/config.pod
+++ b/doc/man5/config.pod
@@ -305,7 +305,12 @@ When set to B<no>, any attempt to create or verify a signature with a SHA1
digest will fail. For compatibility with older versions of OpenSSL, set this
option to B<yes>. 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<no>.
+B<no>. Note that enabling B<rh-allow-sha1-signatures> will allow TLS signature
+algorithms that use SHA1 in security level 2, despite the definition of
+security level 2 of 112 bits of security, which SHA1 does not meet. Because
+TLS 1.1 or lower use MD5-SHA1 as pseudorandom function (PRF) to derive key
+material, disabling B<rh-allow-sha1-signatures> requires the use of TLS 1.2 or
+newer.
=item B<fips_mode> (deprecated)
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 4b74ee1a34..5f089de107 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -20,6 +20,7 @@
#include <openssl/bn.h>
#include <openssl/provider.h>
#include <openssl/param_build.h>
+#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) < 3) {
+ /* when rh-allow-sha1-signatures = yes and security level <= 2,
+ * 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) < 3) {
+ /* when rh-allow-sha1-signatures = yes and security level <= 2,
+ * 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) < 3)
+ || (ctx != NULL && SSL_CTX_get_security_level(ctx) < 3)
+ ))
+ /* When rh-allow-sha1-signatures = yes and security level <= 2,
+ * 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..2de1d76b5e 100644
--- a/test/recipes/25-test_verify.t
+++ b/test/recipes/25-test_verify.t
@@ -29,7 +29,7 @@ sub verify {
run(app([@args]));
}
-plan tests => 160;
+plan tests => 159;
# Canonical success
ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]),
@@ -387,8 +387,9 @@ 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");
+## rh-allow-sha1-signatures=yes allows this to pass despite -auth_level 1
+#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-sha256-cert", "", ["root-cert"], ["ca-cert"], "-auth_level", "2"),
"PSS signature using SHA256 and auth level 2");
--
2.35.1

View File

@ -15,7 +15,7 @@
Summary: Utilities from the general purpose cryptography library with TLS implementation
Name: openssl
Version: 3.0.2
Release: 2%{?dist}
Release: 3%{?dist}
Epoch: 1
# We have to remove certain patented algorithms from the openssl source
# tarball with the hobble-openssl script which is included below.
@ -57,12 +57,22 @@ 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
%if 0%{?rhel}
# Selectively disallow SHA1 signatures
Patch49: 0049-Selectively-disallow-SHA1-signatures.patch
%else
# Selectively disallow SHA1 signatures rhbz#2070977
Patch49: 0049-Allow-disabling-of-SHA1-signatures.patch
%endif
# Backport of patch for RHEL for Edge rhbz #2027261
Patch51: 0051-Support-different-R_BITS-lengths-for-KBKDF.patch
%if 0%{?rhel}
# Allow SHA1 in seclevel 2 if rh-allow-sha1-signatures = yes
Patch52: 0052-Allow-SHA1-in-seclevel-2-if-rh-allow-sha1-signatures.patch
%else
# 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
%endif
License: ASL 2.0
URL: http://www.openssl.org/
@ -236,6 +246,10 @@ patch -p1 -R < %{PATCH4}
OPENSSL_ENABLE_MD5_VERIFY=
export OPENSSL_ENABLE_MD5_VERIFY
%if 0%{?rhel}
OPENSSL_ENABLE_SHA1_SIGNATURES=
export OPENSSL_ENABLE_SHA1_SIGNATURES
%endif
OPENSSL_SYSTEM_CIPHERS_OVERRIDE=xyz_nonexistent_file
export OPENSSL_SYSTEM_CIPHERS_OVERRIDE
make test HARNESS_JOBS=8
@ -389,6 +403,9 @@ install -m644 %{SOURCE9} \
%ldconfig_scriptlets libs
%changelog
* Wed Apr 20 2022 Clemens Lang <cllang@redhat.com> - 1:3.0.2-3
- Disable SHA-1 by default in ELN using the patches from CentOS
* Thu Apr 07 2022 Clemens Lang <cllang@redhat.com> - 1:3.0.2-2
- Silence a few rpmlint false positives.