From 033a4a68f259e32ea58e5a9f478f59d7dabe70af Mon Sep 17 00:00:00 2001 From: Clemens Lang Date: Tue, 1 Mar 2022 15:44:18 +0100 Subject: [PATCH 23/38] 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 d19efeaa99..451fa10bf2 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" @@ -3438,14 +3439,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 e5a88d11aa..2d5649f90b 100644 --- a/doc/man5/config.pod +++ b/doc/man5/config.pod @@ -305,7 +305,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 8bc550ea5b..a9d21a6a96 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" @@ -1567,19 +1568,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; @@ -2117,6 +2126,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; @@ -2986,6 +3003,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; @@ -2994,6 +3013,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 f69af793e4..a7481254e1 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 => 175; +plan tests => 174; # Canonical success ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]), @@ -439,8 +439,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.40.1