From dbd1021466572be733dfc6f7ae484f1adf467f40 Mon Sep 17 00:00:00 2001 From: Clemens Lang 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 2f175ca517f5dd8f8e7d79e5d562981b74c8f987..d1c7d0ce204ca31021a4497ddaa8e7dee45ff6f6 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 < 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 f1536258470563b4fe74f8d1e3db6d73ed316341..29ca805ea7152aa9d39bb14e74cc7fd704ec7acf 100644 --- a/doc/man5/config.pod +++ b/doc/man5/config.pod @@ -313,7 +313,12 @@ When set to B, 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. 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. +B. Note that enabling B 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 requires the use of TLS 1.2 or +newer. =item B (deprecated) diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 909e38c2fe88324884a939b583fd7f43d01f3920..860c7a81d1eaa834e72f81e433e7a0a6a8b1b641 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" @@ -1566,19 +1567,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; @@ -2111,6 +2120,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; @@ -2980,6 +2997,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; @@ -2988,6 +3007,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 bf85ba57c1cf51fe4e8e54654890121bac6738fe..d5665434aaef1ca2b5f2f37b2499f40b1405fd9d 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 => 163; +plan tests => 162; # Canonical success ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]), @@ -410,8 +410,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.37.2