Skip to content

Commit

Permalink
tls: improve wildcard matching (envoyproxy#11921) (envoyproxy#11927)
Browse files Browse the repository at this point in the history
Patching in 11885 with runtime guards and release notes

Risk Level: Medium (changes to cert matching)
Testing: new unit test
Docs Changes: n/a
Release Notes: inline
Runtime guard: envoy.reloadable_features.fix_wildcard_matching

Signed-off-by: Yann Soubeyrand <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Piotr Sikora <[email protected]>
  • Loading branch information
PiotrSikora authored and duderino committed Jul 8, 2020
1 parent 54e9758 commit b0dc1c4
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 17 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.12.5-dev
1.12.6
26 changes: 12 additions & 14 deletions docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
Version history
---------------

1.12.3 (Pending)
==========================
* buffer: force copy when appending small slices to OwnedImpl buffer to avoid fragmentation.
* listeners: fixed issue where :ref:`TLS inspector listener filter <config_listener_filters_tls_inspector>` could have been bypassed by a client using only TLS 1.3.
* sds: fixed the SDS vulnerability that TLS validation context (e.g., subject alt name or hash) cannot be effectively validated in some cases.
* http: added HTTP/1.1 flood protection. Can be temporarily disabled using the runtime feature `envoy.reloadable_features.http1_flood_protection`.
1.12.5 (Pending)
================
* http: the :ref:`stream_idle_timeout <envoy_api_field_config.filter.network.http_connection_manager.v2.HttpConnectionManager.stream_idle_timeout>`
now also defends against an HTTP/2 peer that does not open stream window once an entire response has been buffered to be sent to a downstream client.
* listener: add runtime support for `per-listener limits <config_listeners_runtime>` on active/accepted connections.
* overload management: add runtime support for :ref:`global limits <config_overload_manager>` on active/accepted connections.
1.12.6 (July 7, 2020)
=====================
* tls: fixed a bug where wilcard matching for "\*.foo.com" also matched domains of the form "a.b.foo.com". This behavior can be temporarily reverted by setting runtime feature `envoy.reloadable_features.fix_wildcard_matching` to false.

1.12.5 (June 30, 2020)
======================
* buffer: fixed CVE-2020-12603 by avoiding fragmentation, and tracking of HTTP/2 data and control frames in the output buffer.
* http: fixed CVE-2020-12604 by changing :ref:`stream_idle_timeout <envoy_api_field_config.filter.network.http_connection_manager.v2.HttpConnectionManager.stream_idle_timeout>`
to also defend against an HTTP/2 peer that does not open stream window once an entire response has been buffered to be sent to a downstream client.
* http: fixed CVE-2020-12605 by including request URL in request header size computation, and rejecting partial headers that exceed configured limits.
* listener: mitigated CVE-2020-8663 by adding runtime support for :ref:`per-listener limits <config_listeners_runtime>` on active/accepted connections.
* overload management: mitigated CVE-2020-8663 by adding runtime support for :ref:`global limits <config_overload_manager>` on active/accepted connections.

1.12.4 (June 8, 2020)
=====================
Expand Down Expand Up @@ -87,11 +87,9 @@ Version history
* http: :ref:`AUTO <envoy_api_enum_value_config.filter.network.http_connection_manager.v2.HttpConnectionManager.CodecType.AUTO>` codec protocol inference now requires the H2 magic bytes to be the first bytes transmitted by a downstream client.
* http: remove h2c upgrade headers for HTTP/1 as h2c upgrades are currently not supported.
* http: absolute URL support is now on by default. The prior behavior can be reinstated by setting :ref:`allow_absolute_url <envoy_api_field_core.Http1ProtocolOptions.allow_absolute_url>` to false.
* http: added strict authority checking. This can be reversed temporarily by setting the runtime feature `envoy.reloadable_features.strict_authority_validation` to false.
* http: support :ref:`host rewrite <envoy_api_msg_config.filter.http.dynamic_forward_proxy.v2alpha.PerRouteConfig>` in the dynamic forward proxy.
* http: support :ref:`disabling the filter per route <envoy_api_msg_config.filter.http.grpc_http1_reverse_bridge.v2alpha1.FilterConfigPerRoute>` in the grpc http1 reverse bridge filter.
* http: added the ability to :ref:`configure max connection duration <envoy_api_field_core.HttpProtocolOptions.max_connection_duration>` for downstream connections.
* http: trim LWS at the end of header keys, for correct HTTP/1.1 header parsing.
* listeners: added :ref:`continue_on_listener_filters_timeout <envoy_api_field_Listener.continue_on_listener_filters_timeout>` to configure whether a listener will still create a connection when listener filters time out.
* listeners: added :ref:`HTTP inspector listener filter <config_listener_filters_http_inspector>`.
* listeners: added :ref:`connection balancer <envoy_api_field_Listener.connection_balance_config>`
Expand Down
1 change: 1 addition & 0 deletions source/common/runtime/runtime_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ constexpr const char* runtime_features[] = {
"envoy.reloadable_features.outlier_detection_support_for_grpc_status",
"envoy.reloadable_features.strict_header_validation",
"envoy.reloadable_features.strict_authority_validation",
"envoy.reloadable_features.fix_wildcard_matching",
};

// This is a list of configuration fields which are disallowed by default in Envoy
Expand Down
1 change: 1 addition & 0 deletions source/extensions/transport_sockets/tls/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ envoy_cc_library(
"//source/common/common:utility_lib",
"//source/common/network:address_lib",
"//source/common/protobuf:utility_lib",
"//source/common/runtime:runtime_lib",
"//source/common/stats:symbol_table_lib",
"//source/extensions/transport_sockets/tls/private_key:private_key_manager_lib",
"@envoy_api//envoy/admin/v2alpha:pkg_cc_proto",
Expand Down
10 changes: 8 additions & 2 deletions source/extensions/transport_sockets/tls/context_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "common/common/utility.h"
#include "common/network/address_impl.h"
#include "common/protobuf/utility.h"
#include "common/runtime/runtime_impl.h"

#include "extensions/transport_sockets/tls/utility.h"

Expand Down Expand Up @@ -635,8 +636,13 @@ bool ContextImpl::dnsNameMatch(const std::string& dns_name, const char* pattern)
size_t pattern_len = strlen(pattern);
if (pattern_len > 1 && pattern[0] == '*' && pattern[1] == '.') {
if (dns_name.length() > pattern_len - 1) {
size_t off = dns_name.length() - pattern_len + 1;
return dns_name.compare(off, pattern_len - 1, pattern + 1) == 0;
const size_t off = dns_name.length() - pattern_len + 1;
if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.fix_wildcard_matching")) {
return dns_name.substr(0, off).find('.') == std::string::npos &&
dns_name.compare(off, pattern_len - 1, pattern + 1) == 0;
} else {
return dns_name.compare(off, pattern_len - 1, pattern + 1) == 0;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions test/extensions/transport_sockets/tls/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ envoy_cc_test(
"//test/mocks/ssl:ssl_mocks",
"//test/test_common:environment_lib",
"//test/test_common:simulated_time_system_lib",
"//test/test_common:test_runtime_lib",
],
)

Expand Down
37 changes: 37 additions & 0 deletions test/extensions/transport_sockets/tls/context_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "test/mocks/ssl/mocks.h"
#include "test/test_common/environment.h"
#include "test/test_common/simulated_time_system.h"
#include "test/test_common/test_runtime.h"
#include "test/test_common/utility.h"

#include "gtest/gtest.h"
Expand All @@ -44,6 +45,23 @@ class SslContextImplTest : public SslCertsTest {
TEST_F(SslContextImplTest, TestDnsNameMatching) {
EXPECT_TRUE(ContextImpl::dnsNameMatch("lyft.com", "lyft.com"));
EXPECT_TRUE(ContextImpl::dnsNameMatch("a.lyft.com", "*.lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("a.b.lyft.com", "*.lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("foo.test.com", "*.lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("lyft.com", "*.lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("alyft.com", "*.lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("alyft.com", "*lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("lyft.com", "*lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("", "*lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("lyft.com", ""));
}

TEST_F(SslContextImplTest, TestDnsNameMatchingLegacy) {
TestScopedRuntime scoped_runtime;
Runtime::LoaderSingleton::getExisting()->mergeValues(
{{"envoy.reloadable_features.fix_wildcard_matching", "false"}});
EXPECT_TRUE(ContextImpl::dnsNameMatch("lyft.com", "lyft.com"));
EXPECT_TRUE(ContextImpl::dnsNameMatch("a.lyft.com", "*.lyft.com"));
// Legacy behavior
EXPECT_TRUE(ContextImpl::dnsNameMatch("a.b.lyft.com", "*.lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("foo.test.com", "*.lyft.com"));
EXPECT_FALSE(ContextImpl::dnsNameMatch("lyft.com", "*.lyft.com"));
Expand All @@ -70,6 +88,25 @@ TEST_F(SslContextImplTest, TestVerifySubjectAltNameURIMatched) {
EXPECT_TRUE(ContextImpl::verifySubjectAltName(cert.get(), verify_subject_alt_name_list));
}

TEST_F(SslContextImplTest, TestVerifySubjectAltMultiDomain) {
bssl::UniquePtr<X509> cert = readCertFromFile(TestEnvironment::substitute(
"{{ test_rundir "
"}}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_cert.pem"));
std::vector<std::string> verify_subject_alt_name_list = {"https://a.www.example.com"};
EXPECT_FALSE(ContextImpl::verifySubjectAltName(cert.get(), verify_subject_alt_name_list));
}

TEST_F(SslContextImplTest, TestVerifySubjectAltMultiDomainLegacy) {
TestScopedRuntime scoped_runtime;
Runtime::LoaderSingleton::getExisting()->mergeValues(
{{"envoy.reloadable_features.fix_wildcard_matching", "false"}});
bssl::UniquePtr<X509> cert = readCertFromFile(TestEnvironment::substitute(
"{{ test_rundir "
"}}/test/extensions/transport_sockets/tls/test_data/san_multiple_dns_cert.pem"));
std::vector<std::string> verify_subject_alt_name_list = {"https://a.www.example.com"};
EXPECT_TRUE(ContextImpl::verifySubjectAltName(cert.get(), verify_subject_alt_name_list));
}

TEST_F(SslContextImplTest, TestVerifySubjectAltNameNotMatched) {
bssl::UniquePtr<X509> cert = readCertFromFile(TestEnvironment::substitute(
"{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/san_dns_cert.pem"));
Expand Down

0 comments on commit b0dc1c4

Please sign in to comment.