From b9e2912acb72837b2fdef5cd8f96dc4e0d2a8fea 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 9384f1da9bad9e104550ff270d9ae8dc61da073d..859d5caf4529e193336022bc8a4bdd640df26066 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" @@ -3430,14 +3431,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 f7ac6a743b44c786cf18ccf2ed28105855ceb3ac..f850075d2d0da73e2ab8fc402b1884d3ef6254a8 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 89c1dd31c72271b1923ab972e3d3359b6c8e1a03..831e594c00f1c048c9cd920b6c7e62cd6d7a06ed 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; @@ -2116,6 +2125,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; @@ -2985,6 +3002,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; @@ -2993,6 +3012,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 2a4c36e86daff04f87ad4726a9fb359d958189bf..309cda877d15ff18f5e492c05372f5c9f1393525 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 => 164; +plan tests => 163; # Canonical success ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]), @@ -419,8 +419,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.39.1