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(SSL_CONNECTION_GET_CTX(s), 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->session_ctx->libctx, 0) + && SSL_get_security_level(SSL_CONNECTION_GET_SSL(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->session_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->session_ctx->libctx, 0) + && SSL_get_security_level(SSL_CONNECTION_GET_SSL(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(SSL_CONNECTION_GET_CTX(s), 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) @@ -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->session_ctx && s->session_ctx->libctx) + libctx = s->session_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(SSL_CONNECTION_GET_SSL(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 != NULL) 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 => 193; +plan tests => 192; # 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