diff --git a/.packit.yaml b/.packit.yaml index d053cc6..9514883 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -7,5 +7,7 @@ jobs: metadata: targets: *id001 trigger: pull_request +sources: +- {path: openssl-1.1.1g-hobbled.tar.xz, url: 'https://git.centos.org/sources/openssl/c8/b55517bdc9aa61627a9896c1a3a156d5f6a4348f'} specfile_path: SPECS/openssl.spec upstream_ref: c8-source-git diff --git a/SPECS/openssl-1.1.1-CVE-2021-3449.patch b/SPECS/openssl-1.1.1-CVE-2021-3449.patch new file mode 100644 index 0000000..c2032d3 --- /dev/null +++ b/SPECS/openssl-1.1.1-CVE-2021-3449.patch @@ -0,0 +1,140 @@ +diff -up openssl-1.1.1g/ssl/statem/extensions.c.sig-alg-null-dereference openssl-1.1.1g/ssl/statem/extensions.c +--- openssl-1.1.1g/ssl/statem/extensions.c.sig-alg-null-dereference 2021-03-25 15:04:24.781522476 +0100 ++++ openssl-1.1.1g/ssl/statem/extensions.c 2021-03-25 15:04:24.792522584 +0100 +@@ -1136,6 +1136,7 @@ static int init_sig_algs(SSL *s, unsigne + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->s3->tmp.peer_sigalgs); + s->s3->tmp.peer_sigalgs = NULL; ++ s->s3->tmp.peer_sigalgslen = 0; + + return 1; + } +@@ -1145,6 +1146,7 @@ static int init_sig_algs_cert(SSL *s, un + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->s3->tmp.peer_cert_sigalgs); + s->s3->tmp.peer_cert_sigalgs = NULL; ++ s->s3->tmp.peer_cert_sigalgslen = 0; + + return 1; + } +diff -up openssl-1.1.1g/test/recipes/70-test_renegotiation.t.sig-alg-null-dereference openssl-1.1.1g/test/recipes/70-test_renegotiation.t +--- openssl-1.1.1g/test/recipes/70-test_renegotiation.t.sig-alg-null-dereference 2021-03-25 15:59:52.226408743 +0100 ++++ openssl-1.1.1g/test/recipes/70-test_renegotiation.t 2021-03-25 16:07:25.528618852 +0100 +@@ -38,7 +38,7 @@ my $proxy = TLSProxy::Proxy->new( + $proxy->clientflags("-no_tls1_3"); + $proxy->reneg(1); + $proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; +-plan tests => 3; ++plan tests => 4; + ok(TLSProxy::Message->success(), "Basic renegotiation"); + + #Test 2: Client does not send the Reneg SCSV. Reneg should fail +@@ -77,6 +77,20 @@ SKIP: { + "Check ClientHello version is the same"); + } + ++SKIP: { ++ skip "TLSv1.2 disabled", 1 ++ if disabled("tls1_2"); ++ ++ #Test 4: Test for CVE-2021-3449. client_sig_algs instead of sig_algs in ++ # resumption ClientHello ++ $proxy->clear(); ++ $proxy->filter(\&sigalgs_filter); ++ $proxy->clientflags("-tls1_2"); ++ $proxy->reneg(1); ++ $proxy->start(); ++ ok(TLSProxy::Message->fail(), "client_sig_algs instead of sig_algs"); ++} ++ + sub reneg_filter + { + my $proxy = shift; +@@ -95,4 +109,24 @@ sub reneg_filter + $message->repack(); + } + } ++} ++ ++sub sigalgs_filter ++{ ++ my $proxy = shift; ++ my $cnt = 0; ++ ++ # We're only interested in the second ClientHello message ++ foreach my $message (@{$proxy->message_list}) { ++ if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) { ++ next if ($cnt++ == 0); ++ ++ my $sigs = pack "C10", 0x00, 0x08, ++ # rsa_pkcs_sha{256,384,512,1} ++ 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x01; ++ $message->set_extension(TLSProxy::Message::EXT_SIG_ALGS_CERT, $sigs); ++ $message->delete_extension(TLSProxy::Message::EXT_SIG_ALGS); ++ $message->repack(); ++ } ++ } + } +diff -up openssl-1.1.1g/util/perl/TLSProxy/Message.pm.sig-alg-null-dereference openssl-1.1.1g/util/perl/TLSProxy/Message.pm +--- openssl-1.1.1g/util/perl/TLSProxy/Message.pm.sig-alg-null-dereference 2021-03-25 15:59:19.648106296 +0100 ++++ openssl-1.1.1g/util/perl/TLSProxy/Message.pm 2021-03-25 16:04:25.623947880 +0100 +@@ -1,4 +1,4 @@ +-# Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. ++# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. + # + # Licensed under the OpenSSL license (the "License"). You may not use + # this file except in compliance with the License. You can obtain a copy +@@ -448,7 +448,7 @@ sub ciphersuite + } + + #Update all the underlying records with the modified data from this message +-#Note: Only supports re-encrypting for TLSv1.3 ++#Note: Only supports TLSv1.3 and ETM encryption. + sub repack + { + my $self = shift; +@@ -490,15 +490,38 @@ sub repack + # (If a length override is ever needed to construct invalid packets, + # use an explicit override field instead.) + $rec->decrypt_len(length($rec->decrypt_data)); +- $rec->len($rec->len + length($msgdata) - $old_length); +- # Only support re-encryption for TLSv1.3. +- if (TLSProxy::Proxy->is_tls13() && $rec->encrypted()) { +- #Add content type (1 byte) and 16 tag bytes +- $rec->data($rec->decrypt_data +- .pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16)); ++ # Only support re-encryption for TLSv1.3 and ETM. ++ if ($rec->encrypted()) { ++ if (TLSProxy::Proxy->is_tls13()) { ++ #Add content type (1 byte) and 16 tag bytes ++ $rec->data($rec->decrypt_data ++ .pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16)); ++ } elsif ($rec->etm()) { ++ my $data = $rec->decrypt_data; ++ #Add padding ++ my $padval = length($data) % 16; ++ $padval = 15 - $padval; ++ for (0..$padval) { ++ $data .= pack("C", $padval); ++ } ++ ++ #Add MAC. Assumed to be 20 bytes ++ foreach my $macval (0..19) { ++ $data .= pack("C", $macval); ++ } ++ ++ if ($rec->version() >= TLSProxy::Record::VERS_TLS_1_1) { ++ #Explicit IV ++ $data = ("\0"x16).$data; ++ } ++ $rec->data($data); ++ } else { ++ die "Unsupported encryption: No ETM"; ++ } + } else { + $rec->data($rec->decrypt_data); + } ++ $rec->len(length($rec->data)); + + #Update the fragment len in case we changed it above + ${$self->message_frag_lens}[0] = length($msgdata) diff --git a/SPECS/openssl-1.1.1-CVE-2021-3450.patch b/SPECS/openssl-1.1.1-CVE-2021-3450.patch new file mode 100644 index 0000000..a54a2f3 --- /dev/null +++ b/SPECS/openssl-1.1.1-CVE-2021-3450.patch @@ -0,0 +1,55 @@ +diff -up openssl-1.1.1g/crypto/x509/x509_vfy.c.bypass-strict-flag openssl-1.1.1g/crypto/x509/x509_vfy.c +--- openssl-1.1.1g/crypto/x509/x509_vfy.c.bypass-strict-flag 2021-03-25 15:04:24.786522525 +0100 ++++ openssl-1.1.1g/crypto/x509/x509_vfy.c 2021-03-25 15:14:01.392910477 +0100 +@@ -509,15 +509,19 @@ static int check_chain_extensions(X509_S + ret = 1; + break; + } +- if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) && num > 1) { ++ if (ret > 0 ++ && (ctx->param->flags & X509_V_FLAG_X509_STRICT) && num > 1) { + /* Check for presence of explicit elliptic curve parameters */ + ret = check_curve(x); +- if (ret < 0) ++ if (ret < 0) { + ctx->error = X509_V_ERR_UNSPECIFIED; +- else if (ret == 0) ++ ret = 0; ++ } else if (ret == 0) { + ctx->error = X509_V_ERR_EC_KEY_EXPLICIT_PARAMS; ++ } + } +- if ((x->ex_flags & EXFLAG_CA) == 0 ++ if (ret > 0 ++ && (x->ex_flags & EXFLAG_CA) == 0 + && x->ex_pathlen != -1 + && (ctx->param->flags & X509_V_FLAG_X509_STRICT)) { + ctx->error = X509_V_ERR_INVALID_EXTENSION; +diff -up openssl-1.1.1g/test/verify_extra_test.c.bypass-strict-flag openssl-1.1.1g/test/verify_extra_test.c +--- openssl-1.1.1g/test/verify_extra_test.c.bypass-strict-flag 2020-04-21 14:22:39.000000000 +0200 ++++ openssl-1.1.1g/test/verify_extra_test.c 2021-03-25 15:04:24.793522594 +0100 +@@ -125,10 +125,22 @@ static int test_alt_chains_cert_forgery( + + i = X509_verify_cert(sctx); + +- if (i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) { ++ if (i != 0 || X509_STORE_CTX_get_error(sctx) != X509_V_ERR_INVALID_CA) ++ goto err; ++ ++ /* repeat with X509_V_FLAG_X509_STRICT */ ++ X509_STORE_CTX_cleanup(sctx); ++ X509_STORE_set_flags(store, X509_V_FLAG_X509_STRICT); ++ ++ if (!X509_STORE_CTX_init(sctx, store, x, untrusted)) ++ goto err; ++ ++ i = X509_verify_cert(sctx); ++ ++ if (i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) + /* This is the result we were expecting: Test passed */ + ret = 1; +- } ++ + err: + X509_STORE_CTX_free(sctx); + X509_free(x); diff --git a/SPECS/openssl-1.1.1g-hobbled.tar.xz b/SPECS/openssl-1.1.1g-hobbled.tar.xz deleted file mode 100644 index 6321d86..0000000 Binary files a/SPECS/openssl-1.1.1g-hobbled.tar.xz and /dev/null differ diff --git a/SPECS/openssl.spec b/SPECS/openssl.spec index 99c8a73..33e26c3 100644 --- a/SPECS/openssl.spec +++ b/SPECS/openssl.spec @@ -22,7 +22,7 @@ Summary: Utilities from the general purpose cryptography library with TLS implementation Name: openssl Version: 1.1.1g -Release: 12%{?dist} +Release: 15%{?dist} Epoch: 1 # We have to remove certain patented algorithms from the openssl source # tarball with the hobble-openssl script which is included below. @@ -79,6 +79,8 @@ Patch55: openssl-1.1.1-arm-update.patch Patch56: openssl-1.1.1-s390x-ecc.patch Patch57: openssl-1.1.1-explicit-params.patch Patch71: openssl-1.1.1-CVE-2020-1971.patch +Patch72: openssl-1.1.1-CVE-2021-3449.patch +Patch73: openssl-1.1.1-CVE-2021-3450.patch License: OpenSSL and ASL 2.0 URL: http://www.openssl.org/ @@ -197,6 +199,8 @@ cp %{SOURCE13} test/ %patch70 -p1 -b .rewire-fips-drbg %patch57 -p1 -b .explicit-params %patch71 -p1 -b .null-dereference +%patch72 -p1 -b .sig-alg-null-dereference +%patch73 -p1 -b .bypass-strict-flag %build @@ -481,6 +485,16 @@ export LD_LIBRARY_PATH %postun libs -p /sbin/ldconfig %changelog +* Thu Mar 25 2021 Sahana Prasad 1.1.1g-15 +- version bump + +* Wed Mar 24 2021 Sahana Prasad 1.1.1g-14 +- CVE-2021-3450 openssl: CA certificate check + bypass with X509_V_FLAG_X509_STRICT + +* Wed Mar 24 2021 Sahana Prasad 1.1.1g-13 +- Fix CVE-2021-3449 NULL pointer deref in signature_algorithms processing + * Fri Dec 4 2020 Sahana Prasad 1.1.1g-12 - Fix CVE-2020-1971 ediparty null pointer dereference diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 1ee1219..5c3aad4 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -509,15 +509,19 @@ static int check_chain_extensions(X509_STORE_CTX *ctx) ret = 1; break; } - if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) && num > 1) { + if (ret > 0 + && (ctx->param->flags & X509_V_FLAG_X509_STRICT) && num > 1) { /* Check for presence of explicit elliptic curve parameters */ ret = check_curve(x); - if (ret < 0) + if (ret < 0) { ctx->error = X509_V_ERR_UNSPECIFIED; - else if (ret == 0) + ret = 0; + } else if (ret == 0) { ctx->error = X509_V_ERR_EC_KEY_EXPLICIT_PARAMS; + } } - if ((x->ex_flags & EXFLAG_CA) == 0 + if (ret > 0 + && (x->ex_flags & EXFLAG_CA) == 0 && x->ex_pathlen != -1 && (ctx->param->flags & X509_V_FLAG_X509_STRICT)) { ctx->error = X509_V_ERR_INVALID_EXTENSION; diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index c785ab7..3f3062f 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -1136,6 +1136,7 @@ static int init_sig_algs(SSL *s, unsigned int context) /* Clear any signature algorithms extension received */ OPENSSL_free(s->s3->tmp.peer_sigalgs); s->s3->tmp.peer_sigalgs = NULL; + s->s3->tmp.peer_sigalgslen = 0; return 1; } @@ -1145,6 +1146,7 @@ static int init_sig_algs_cert(SSL *s, unsigned int context) /* Clear any signature algorithms extension received */ OPENSSL_free(s->s3->tmp.peer_cert_sigalgs); s->s3->tmp.peer_cert_sigalgs = NULL; + s->s3->tmp.peer_cert_sigalgslen = 0; return 1; } diff --git a/test/recipes/70-test_renegotiation.t b/test/recipes/70-test_renegotiation.t index 734f1cd..89cab85 100644 --- a/test/recipes/70-test_renegotiation.t +++ b/test/recipes/70-test_renegotiation.t @@ -38,7 +38,7 @@ my $proxy = TLSProxy::Proxy->new( $proxy->clientflags("-no_tls1_3"); $proxy->reneg(1); $proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; -plan tests => 3; +plan tests => 4; ok(TLSProxy::Message->success(), "Basic renegotiation"); #Test 2: Client does not send the Reneg SCSV. Reneg should fail @@ -77,6 +77,20 @@ SKIP: { "Check ClientHello version is the same"); } +SKIP: { + skip "TLSv1.2 disabled", 1 + if disabled("tls1_2"); + + #Test 4: Test for CVE-2021-3449. client_sig_algs instead of sig_algs in + # resumption ClientHello + $proxy->clear(); + $proxy->filter(\&sigalgs_filter); + $proxy->clientflags("-tls1_2"); + $proxy->reneg(1); + $proxy->start(); + ok(TLSProxy::Message->fail(), "client_sig_algs instead of sig_algs"); +} + sub reneg_filter { my $proxy = shift; @@ -96,3 +110,23 @@ sub reneg_filter } } } + +sub sigalgs_filter +{ + my $proxy = shift; + my $cnt = 0; + + # We're only interested in the second ClientHello message + foreach my $message (@{$proxy->message_list}) { + if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) { + next if ($cnt++ == 0); + + my $sigs = pack "C10", 0x00, 0x08, + # rsa_pkcs_sha{256,384,512,1} + 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x01; + $message->set_extension(TLSProxy::Message::EXT_SIG_ALGS_CERT, $sigs); + $message->delete_extension(TLSProxy::Message::EXT_SIG_ALGS); + $message->repack(); + } + } +} diff --git a/test/verify_extra_test.c b/test/verify_extra_test.c index d9d1498..a3329dd 100644 --- a/test/verify_extra_test.c +++ b/test/verify_extra_test.c @@ -125,10 +125,22 @@ static int test_alt_chains_cert_forgery(void) i = X509_verify_cert(sctx); - if (i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) { + if (i != 0 || X509_STORE_CTX_get_error(sctx) != X509_V_ERR_INVALID_CA) + goto err; + + /* repeat with X509_V_FLAG_X509_STRICT */ + X509_STORE_CTX_cleanup(sctx); + X509_STORE_set_flags(store, X509_V_FLAG_X509_STRICT); + + if (!X509_STORE_CTX_init(sctx, store, x, untrusted)) + goto err; + + i = X509_verify_cert(sctx); + + if (i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) /* This is the result we were expecting: Test passed */ ret = 1; - } + err: X509_STORE_CTX_free(sctx); X509_free(x); diff --git a/util/perl/TLSProxy/Message.pm b/util/perl/TLSProxy/Message.pm index 10b6156..b264ec9 100644 --- a/util/perl/TLSProxy/Message.pm +++ b/util/perl/TLSProxy/Message.pm @@ -1,4 +1,4 @@ -# Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the OpenSSL license (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -448,7 +448,7 @@ sub ciphersuite } #Update all the underlying records with the modified data from this message -#Note: Only supports re-encrypting for TLSv1.3 +#Note: Only supports TLSv1.3 and ETM encryption. sub repack { my $self = shift; @@ -490,15 +490,38 @@ sub repack # (If a length override is ever needed to construct invalid packets, # use an explicit override field instead.) $rec->decrypt_len(length($rec->decrypt_data)); - $rec->len($rec->len + length($msgdata) - $old_length); - # Only support re-encryption for TLSv1.3. - if (TLSProxy::Proxy->is_tls13() && $rec->encrypted()) { - #Add content type (1 byte) and 16 tag bytes - $rec->data($rec->decrypt_data - .pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16)); + # Only support re-encryption for TLSv1.3 and ETM. + if ($rec->encrypted()) { + if (TLSProxy::Proxy->is_tls13()) { + #Add content type (1 byte) and 16 tag bytes + $rec->data($rec->decrypt_data + .pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16)); + } elsif ($rec->etm()) { + my $data = $rec->decrypt_data; + #Add padding + my $padval = length($data) % 16; + $padval = 15 - $padval; + for (0..$padval) { + $data .= pack("C", $padval); + } + + #Add MAC. Assumed to be 20 bytes + foreach my $macval (0..19) { + $data .= pack("C", $macval); + } + + if ($rec->version() >= TLSProxy::Record::VERS_TLS_1_1) { + #Explicit IV + $data = ("\0"x16).$data; + } + $rec->data($data); + } else { + die "Unsupported encryption: No ETM"; + } } else { $rec->data($rec->decrypt_data); } + $rec->len(length($rec->data)); #Update the fragment len in case we changed it above ${$self->message_frag_lens}[0] = length($msgdata)