From 76709a08a851c9b96039e8aa9ca9dbb7b490e176 Mon Sep 17 00:00:00 2001 From: Piotr Sikora Date: Wed, 1 Nov 2017 11:45:28 -0700 Subject: [PATCH] ssl: add support for SNI. This version serves different TLS certificates based on SNI, but it doesn't select alternative filter chains. Partially fixes #95. Signed-off-by: Piotr Sikora --- include/envoy/ssl/context_manager.h | 11 ++- source/common/ssl/BUILD | 1 + source/common/ssl/context_impl.cc | 66 ++++++++++++++- source/common/ssl/context_impl.h | 18 +++-- source/common/ssl/context_manager_impl.cc | 81 +++++++++++++++++-- source/common/ssl/context_manager_impl.h | 13 ++- source/server/listener_manager_impl.cc | 29 ++++--- source/server/listener_manager_impl.h | 6 +- test/common/ssl/connection_impl_test.cc | 23 ++++-- test/common/ssl/context_impl_test.cc | 2 +- test/common/ssl/test_data/README.md | 4 +- .../ssl/test_data/san_multiple_dns_cert.cfg | 2 +- .../ssl/test_data/san_multiple_dns_cert.pem | 20 ++--- test/integration/ssl_integration_test.cc | 2 +- test/integration/xfcc_integration_test.cc | 2 +- test/mocks/ssl/mocks.h | 13 ++- 16 files changed, 234 insertions(+), 59 deletions(-) diff --git a/include/envoy/ssl/context_manager.h b/include/envoy/ssl/context_manager.h index da0bc6add0bc..4d5eb6c14b62 100644 --- a/include/envoy/ssl/context_manager.h +++ b/include/envoy/ssl/context_manager.h @@ -25,9 +25,18 @@ class ContextManager { /** * Builds a ServerContext from a ServerContextConfig. */ - virtual ServerContextPtr createSslServerContext(Stats::Scope& scope, + virtual ServerContextPtr createSslServerContext(const std::string& listener_name, + const std::vector& server_names, + Stats::Scope& scope, ServerContextConfig& config) PURE; + /** + * Find ServerContext for a given listener and server_name. + * @return ServerContext or nullptr in case there is no match. + */ + virtual ServerContext* findSslServerContext(const std::string& listener_name, + const std::string& server_name) PURE; + /** * @return the number of days until the next certificate being managed will expire. */ diff --git a/source/common/ssl/BUILD b/source/common/ssl/BUILD index 8eebea126900..af6906d3272e 100644 --- a/source/common/ssl/BUILD +++ b/source/common/ssl/BUILD @@ -56,6 +56,7 @@ envoy_cc_library( "//include/envoy/stats:stats_interface", "//include/envoy/stats:stats_macros", "//source/common/common:assert_lib", + "//source/common/common:empty_string", "//source/common/common:hex_lib", ], ) diff --git a/source/common/ssl/context_impl.cc b/source/common/ssl/context_impl.cc index 041dc26b4bfa..6af0ec406eef 100644 --- a/source/common/ssl/context_impl.cc +++ b/source/common/ssl/context_impl.cc @@ -9,6 +9,7 @@ #include "envoy/runtime/runtime.h" #include "common/common/assert.h" +#include "common/common/empty_string.h" #include "common/common/hex.h" #include "fmt/format.h" @@ -355,10 +356,20 @@ bssl::UniquePtr ClientContextImpl::newSsl() const { return ssl_con; } -ServerContextImpl::ServerContextImpl(ContextManagerImpl& parent, Stats::Scope& scope, - ServerContextConfig& config, Runtime::Loader& runtime) - : ContextImpl(parent, scope, config), runtime_(runtime), +ServerContextImpl::ServerContextImpl(ContextManagerImpl& parent, const std::string& listener_name, + const std::vector& server_names, + Stats::Scope& scope, ServerContextConfig& config, + Runtime::Loader& runtime) + : ContextImpl(parent, scope, config), listener_name_(listener_name), + server_names_(server_names), runtime_(runtime), session_ticket_keys_(config.sessionTicketKeys()) { + SSL_CTX_set_select_certificate_cb( + ctx_.get(), [](const SSL_CLIENT_HELLO* client_hello) -> ssl_select_cert_result_t { + ContextImpl* context_impl = static_cast( + SSL_CTX_get_ex_data(SSL_get_SSL_CTX(client_hello->ssl), sslContextIndex())); + return dynamic_cast(context_impl)->processClientHello(client_hello); + }); + if (!config.caCertFile().empty()) { bssl::UniquePtr list(SSL_load_client_CA_file(config.caCertFile().c_str())); if (nullptr == list) { @@ -473,6 +484,55 @@ ServerContextImpl::ServerContextImpl(ContextManagerImpl& parent, Stats::Scope& s RELEASE_ASSERT(rc == 1); } +ssl_select_cert_result_t +ServerContextImpl::processClientHello(const SSL_CLIENT_HELLO* client_hello) { + std::string server_name = EMPTY_STRING; + const uint8_t* data; + size_t len; + + if (SSL_early_callback_ctx_extension_get(client_hello, TLSEXT_TYPE_server_name, &data, &len)) { + /* Based on BoringSSL's ext_sni_parse_clienthello(). Match on empty SNI if we encounter any + * errors. */ + CBS extension; + CBS_init(&extension, data, len); + CBS server_name_list, host_name; + uint8_t name_type; + if (CBS_get_u16_length_prefixed(&extension, &server_name_list) && + CBS_get_u8(&server_name_list, &name_type) && + CBS_get_u16_length_prefixed(&server_name_list, &host_name) && + CBS_len(&server_name_list) == 0 && CBS_len(&extension) == 0 && + name_type == TLSEXT_NAMETYPE_host_name && CBS_len(&host_name) != 0 && + CBS_len(&host_name) <= TLSEXT_MAXLEN_host_name && !CBS_contains_zero_byte(&host_name)) { + server_name = + std::string(reinterpret_cast(CBS_data(&host_name)), CBS_len(&host_name)); + } + } + + ServerContext* new_ctx = parent_.findSslServerContext(listener_name_, server_name); + + // Reject connection if we didn't find a match. + if (new_ctx == nullptr) { + return ssl_select_cert_error; + } + + // Update context if it changed. + if (new_ctx != this) { + ServerContextImpl* new_impl = dynamic_cast(new_ctx); + new_impl->updateConnection(client_hello->ssl); + } + + return ssl_select_cert_success; +} + +void ServerContextImpl::updateConnection(SSL* ssl) { + RELEASE_ASSERT(ctx_); + + // Note: this updates only served certificates. + SSL_set_SSL_CTX(ssl, ctx_.get()); + + // TODO(PiotrSikora): update other settings. +} + int ServerContextImpl::sessionTicketProcess(SSL*, uint8_t* key_name, uint8_t* iv, EVP_CIPHER_CTX* ctx, HMAC_CTX* hmac_ctx, int encrypt) { const EVP_MD* hmac = EVP_sha256(); diff --git a/source/common/ssl/context_impl.h b/source/common/ssl/context_impl.h index 7a4c6f269519..3028b4d3836e 100644 --- a/source/common/ssl/context_impl.h +++ b/source/common/ssl/context_impl.h @@ -42,8 +42,6 @@ struct SslStats { class ContextImpl : public virtual Context { public: - ~ContextImpl() { parent_.releaseContext(this); } - virtual bssl::UniquePtr newSsl() const; /** @@ -124,6 +122,7 @@ class ContextImpl : public virtual Context { class ClientContextImpl : public ContextImpl, public ClientContext { public: ClientContextImpl(ContextManagerImpl& parent, Stats::Scope& scope, ClientContextConfig& config); + ~ClientContextImpl() { parent_.releaseClientContext(this); } bssl::UniquePtr newSsl() const override; @@ -133,19 +132,26 @@ class ClientContextImpl : public ContextImpl, public ClientContext { class ServerContextImpl : public ContextImpl, public ServerContext { public: - ServerContextImpl(ContextManagerImpl& parent, Stats::Scope& scope, ServerContextConfig& config, - Runtime::Loader& runtime); + ServerContextImpl(ContextManagerImpl& parent, const std::string& listener_name, + const std::vector& server_names, Stats::Scope& scope, + ServerContextConfig& config, Runtime::Loader& runtime); + ~ServerContextImpl() { parent_.releaseServerContext(this, listener_name_, server_names_); } private: + ssl_select_cert_result_t processClientHello(const SSL_CLIENT_HELLO* client_hello); + void updateConnection(SSL* ssl); + int alpnSelectCallback(const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen); int sessionTicketProcess(SSL* ssl, uint8_t* key_name, uint8_t* iv, EVP_CIPHER_CTX* ctx, HMAC_CTX* hmac_ctx, int encrypt); + const std::string listener_name_; + const std::vector server_names_; Runtime::Loader& runtime_; std::vector parsed_alt_alpn_protocols_; const std::vector session_ticket_keys_; }; -} // Ssl -} // Envoy +} // namespace Ssl +} // namespace Envoy diff --git a/source/common/ssl/context_manager_impl.cc b/source/common/ssl/context_manager_impl.cc index 4bbda5a005c4..c274984d4554 100644 --- a/source/common/ssl/context_manager_impl.cc +++ b/source/common/ssl/context_manager_impl.cc @@ -4,6 +4,7 @@ #include #include "common/common/assert.h" +#include "common/common/empty_string.h" #include "common/ssl/context_impl.h" namespace Envoy { @@ -11,7 +12,7 @@ namespace Ssl { ContextManagerImpl::~ContextManagerImpl() { ASSERT(contexts_.empty()); } -void ContextManagerImpl::releaseContext(Context* context) { +void ContextManagerImpl::releaseClientContext(ClientContext* context) { std::unique_lock lock(contexts_lock_); // context may not be found, in the case that a subclass of Context throws @@ -20,23 +21,93 @@ void ContextManagerImpl::releaseContext(Context* context) { contexts_.remove(context); } +void ContextManagerImpl::releaseServerContext(ServerContext* context, + const std::string& listener_name, + const std::vector& server_names) { + std::unique_lock lock(contexts_lock_); + + // Remove mappings. + if (server_names.empty()) { + if (map_exact_[listener_name][EMPTY_STRING] == context) { + map_exact_[listener_name][EMPTY_STRING] = nullptr; + } + } else { + for (const auto& name : server_names) { + if (name.size() > 2 && name[0] == '*' && name[1] == '.') { + if (map_wildcard_[listener_name][name] == context) { + map_wildcard_[listener_name][name] = nullptr; + } + } else { + if (map_exact_[listener_name][name] == context) { + map_exact_[listener_name][name] = nullptr; + } + } + } + } + + // context may not be found, in the case that a subclass of Context throws + // in it's constructor. In that case the context did not get added, but + // the destructor of Context will run and call releaseContext(). + contexts_.remove(context); +} + ClientContextPtr ContextManagerImpl::createSslClientContext(Stats::Scope& scope, ClientContextConfig& config) { - ClientContextPtr context(new ClientContextImpl(*this, scope, config)); std::unique_lock lock(contexts_lock_); contexts_.emplace_back(context.get()); return context; } -ServerContextPtr ContextManagerImpl::createSslServerContext(Stats::Scope& scope, - ServerContextConfig& config) { - ServerContextPtr context(new ServerContextImpl(*this, scope, config, runtime_)); +ServerContextPtr +ContextManagerImpl::createSslServerContext(const std::string& listener_name, + const std::vector& server_names, + Stats::Scope& scope, ServerContextConfig& config) { + ServerContextPtr context( + new ServerContextImpl(*this, listener_name, server_names, scope, config, runtime_)); std::unique_lock lock(contexts_lock_); contexts_.emplace_back(context.get()); + + // Save mappings. + if (server_names.empty()) { + map_exact_[listener_name][EMPTY_STRING] = context.get(); + } else { + for (const auto& name : server_names) { + if (name.size() > 2 && name[0] == '*' && name[1] == '.') { + map_wildcard_[listener_name][name] = context.get(); + } else { + map_exact_[listener_name][name] = context.get(); + } + } + } + return context; } +ServerContext* ContextManagerImpl::findSslServerContext(const std::string& listener_name, + const std::string& server_name) { + std::unique_lock lock(contexts_lock_); + if (map_exact_[listener_name][server_name] != nullptr) { + return map_exact_[listener_name][server_name]; + } + + // Try to construct and match wildcard domain. + if (server_name.size() >= 5) { + size_t pos = server_name.find('.'); + if (pos > 0) { + size_t rpos = server_name.rfind('.'); + if (rpos > pos + 1 && rpos != server_name.size() - 1) { + std::string wildcard = '*' + server_name.substr(pos); + if (map_wildcard_[listener_name][wildcard] != nullptr) { + return map_wildcard_[listener_name][wildcard]; + } + } + } + } + + return map_exact_[listener_name][EMPTY_STRING]; +} + size_t ContextManagerImpl::daysUntilFirstCertExpires() { std::unique_lock lock(contexts_lock_); size_t ret = std::numeric_limits::max(); diff --git a/source/common/ssl/context_manager_impl.h b/source/common/ssl/context_manager_impl.h index 9c20c40dcd8e..0b3d23faeca2 100644 --- a/source/common/ssl/context_manager_impl.h +++ b/source/common/ssl/context_manager_impl.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "envoy/runtime/runtime.h" #include "envoy/ssl/context_manager.h" @@ -27,13 +28,19 @@ class ContextManagerImpl final : public ContextManager { * admin purposes. When a caller frees a context it will tell us to release it also from the list * of contexts. */ - void releaseContext(Context* context); + void releaseClientContext(ClientContext* context); + void releaseServerContext(ServerContext* context, const std::string& listener_name, + const std::vector& server_names); // Ssl::ContextManager Ssl::ClientContextPtr createSslClientContext(Stats::Scope& scope, ClientContextConfig& config) override; - Ssl::ServerContextPtr createSslServerContext(Stats::Scope& scope, + Ssl::ServerContextPtr createSslServerContext(const std::string& listener_name, + const std::vector& server_names, + Stats::Scope& scope, ServerContextConfig& config) override; + Ssl::ServerContext* findSslServerContext(const std::string& listener_name, + const std::string& server_name) override; size_t daysUntilFirstCertExpires() override; void iterateContexts(std::function callback) override; @@ -41,6 +48,8 @@ class ContextManagerImpl final : public ContextManager { Runtime::Loader& runtime_; std::list contexts_; std::mutex contexts_lock_; + std::unordered_map> map_exact_; + std::unordered_map> map_wildcard_; }; } // namespace Ssl diff --git a/source/server/listener_manager_impl.cc b/source/server/listener_manager_impl.cc index 49c5c3ecbcb3..7ba1add2e8b6 100644 --- a/source/server/listener_manager_impl.cc +++ b/source/server/listener_manager_impl.cc @@ -77,6 +77,8 @@ ListenerImpl::ListenerImpl(const envoy::api::v2::Listener& config, ListenerManag Network::Utility::parseInternetAddress(config.address().socket_address().address(), config.address().socket_address().port_value())), global_scope_(parent_.server_.stats().createScope("")), + listener_scope_( + parent_.server_.stats().createScope(fmt::format("listener.{}.", address_->asString()))), bind_to_port_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.deprecated_v1(), bind_to_port, true)), use_proxy_proto_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.filter_chains()[0], use_proxy_proto, false)), @@ -88,19 +90,22 @@ ListenerImpl::ListenerImpl(const envoy::api::v2::Listener& config, ListenerManag local_drain_manager_(parent.factory_.createDrainManager()) { // TODO(htuch): Support multiple filter chains #1280, add constraint to ensure we have at least on // filter chain #1308. - ASSERT(config.filter_chains().size() == 1); - const auto& filter_chain = config.filter_chains()[0]; - - listener_scope_ = - parent_.server_.stats().createScope(fmt::format("listener.{}.", address_->asString())); - - if (filter_chain.has_tls_context()) { - Ssl::ServerContextConfigImpl context_config(filter_chain.tls_context()); - ssl_context_ = parent_.server_.sslContextManager().createSslServerContext(*listener_scope_, - context_config); + ASSERT(config.filter_chains().size() >= 1); + + for (const auto& filter_chain : config.filter_chains()) { + std::vector sni_domains(filter_chain.filter_chain_match().sni_domains().begin(), + filter_chain.filter_chain_match().sni_domains().end()); + if (filter_factories_.empty() || !filter_chain.filters().empty()) { + // Only one filter chain can have filters until multiple filter chains are properly supported. + RELEASE_ASSERT(filter_factories_.empty()); + filter_factories_ = parent_.factory_.createFilterFactoryList(filter_chain.filters(), *this); + } + if (filter_chain.has_tls_context()) { + Ssl::ServerContextConfigImpl context_config(filter_chain.tls_context()); + tls_contexts_.emplace_back(parent_.server_.sslContextManager().createSslServerContext( + name_, sni_domains, *listener_scope_, context_config)); + } } - - filter_factories_ = parent_.factory_.createFilterFactoryList(filter_chain.filters(), *this); } ListenerImpl::~ListenerImpl() { diff --git a/source/server/listener_manager_impl.h b/source/server/listener_manager_impl.h index ed00ab67eabd..f0b8d6d23312 100644 --- a/source/server/listener_manager_impl.h +++ b/source/server/listener_manager_impl.h @@ -194,7 +194,9 @@ class ListenerImpl : public Listener, Network::FilterChainFactory& filterChainFactory() override { return *this; } Network::ListenSocket& socket() override { return *socket_; } bool bindToPort() override { return bind_to_port_; } - Ssl::ServerContext* sslContext() override { return ssl_context_.get(); } + Ssl::ServerContext* sslContext() override { + return tls_contexts_.empty() ? nullptr : tls_contexts_[0].get(); + } bool useProxyProto() override { return use_proxy_proto_; } bool useOriginalDst() override { return use_original_dst_; } uint32_t perConnectionBufferLimitBytes() override { return per_connection_buffer_limit_bytes_; } @@ -236,7 +238,7 @@ class ListenerImpl : public Listener, Network::ListenSocketSharedPtr socket_; Stats::ScopePtr global_scope_; // Stats with global named scope, but needed for LDS cleanup. Stats::ScopePtr listener_scope_; // Stats with listener named scope. - Ssl::ServerContextPtr ssl_context_; + std::vector tls_contexts_; const bool bind_to_port_; const bool use_proxy_proto_; const bool use_original_dst_; diff --git a/test/common/ssl/connection_impl_test.cc b/test/common/ssl/connection_impl_test.cc index 7cd4c321bebb..4419eb987f28 100644 --- a/test/common/ssl/connection_impl_test.cc +++ b/test/common/ssl/connection_impl_test.cc @@ -46,7 +46,8 @@ void testUtil(const std::string& client_ctx_json, const std::string& server_ctx_ Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); ServerContextConfigImpl server_ctx_config(*server_ctx_loader); ContextManagerImpl manager(runtime); - ServerContextPtr server_ctx(manager.createSslServerContext(stats_store, server_ctx_config)); + ServerContextPtr server_ctx( + manager.createSslServerContext("", {}, stats_store, server_ctx_config)); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(version), true); @@ -342,7 +343,8 @@ TEST_P(SslConnectionImplTest, ClientAuthMultipleCAs) { Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); ServerContextConfigImpl server_ctx_config(*server_ctx_loader); ContextManagerImpl manager(runtime); - ServerContextPtr server_ctx(manager.createSslServerContext(stats_store, server_ctx_config)); + ServerContextPtr server_ctx( + manager.createSslServerContext("", {}, stats_store, server_ctx_config)); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(GetParam()), true); @@ -415,8 +417,10 @@ void testTicketSessionResumption(const std::string& server_ctx_json1, ServerContextConfigImpl server_ctx_config1(*server_ctx_loader1); ServerContextConfigImpl server_ctx_config2(*server_ctx_loader2); ContextManagerImpl manager(runtime); - ServerContextPtr server_ctx1(manager.createSslServerContext(stats_store, server_ctx_config1)); - ServerContextPtr server_ctx2(manager.createSslServerContext(stats_store, server_ctx_config2)); + ServerContextPtr server_ctx1( + manager.createSslServerContext("server1", {}, stats_store, server_ctx_config1)); + ServerContextPtr server_ctx2( + manager.createSslServerContext("server2", {}, stats_store, server_ctx_config2)); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket1(Network::Test::getCanonicalLoopbackAddress(ip_version), true); @@ -698,8 +702,10 @@ TEST_P(SslConnectionImplTest, ClientAuthCrossListenerSessionResumption) { Json::ObjectSharedPtr server2_ctx_loader = TestEnvironment::jsonLoadFromString(server2_ctx_json); ServerContextConfigImpl server2_ctx_config(*server2_ctx_loader); ContextManagerImpl manager(runtime); - ServerContextPtr server_ctx(manager.createSslServerContext(stats_store, server_ctx_config)); - ServerContextPtr server2_ctx(manager.createSslServerContext(stats_store, server2_ctx_config)); + ServerContextPtr server_ctx( + manager.createSslServerContext("server1", {}, stats_store, server_ctx_config)); + ServerContextPtr server2_ctx( + manager.createSslServerContext("server2", {}, stats_store, server2_ctx_config)); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(GetParam()), true); @@ -799,7 +805,8 @@ TEST_P(SslConnectionImplTest, SslError) { Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); ServerContextConfigImpl server_ctx_config(*server_ctx_loader); ContextManagerImpl manager(runtime); - ServerContextPtr server_ctx(manager.createSslServerContext(stats_store, server_ctx_config)); + ServerContextPtr server_ctx( + manager.createSslServerContext("", {}, stats_store, server_ctx_config)); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(GetParam()), true); @@ -841,7 +848,7 @@ class SslReadBufferLimitTest : public SslCertsTest, server_ctx_loader_ = TestEnvironment::jsonLoadFromString(server_ctx_json_); server_ctx_config_.reset(new ServerContextConfigImpl(*server_ctx_loader_)); manager_.reset(new ContextManagerImpl(runtime_)); - server_ctx_ = manager_->createSslServerContext(stats_store_, *server_ctx_config_); + server_ctx_ = manager_->createSslServerContext("", {}, stats_store_, *server_ctx_config_); listener_ = dispatcher_->createSslListener( connection_handler_, *server_ctx_, socket_, listener_callbacks_, stats_store_, diff --git a/test/common/ssl/context_impl_test.cc b/test/common/ssl/context_impl_test.cc index 9e3e1168ba8b..d531679ce385 100644 --- a/test/common/ssl/context_impl_test.cc +++ b/test/common/ssl/context_impl_test.cc @@ -174,7 +174,7 @@ class SslServerContextImplTicketTest : public SslContextImplTest { Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; - ServerContextPtr server_ctx(manager.createSslServerContext(store, cfg)); + ServerContextPtr server_ctx(manager.createSslServerContext("", {}, store, cfg)); } static void loadConfigV2(envoy::api::v2::DownstreamTlsContext& cfg) { diff --git a/test/common/ssl/test_data/README.md b/test/common/ssl/test_data/README.md index 03b013d6b52e..6ac2c16ff40c 100644 --- a/test/common/ssl/test_data/README.md +++ b/test/common/ssl/test_data/README.md @@ -16,8 +16,8 @@ There are 6 identities: field of DNS type. *san_dns_key.pem* is its private key. A second certificate and key, using the same config, is *san_dns_cert2*. - **SAN With Multiple DNS**: Same as *SAN With DNS* except there are multiple - SANs. It has certificate *san_multiple_dns_cert.pem*, *san_multiple_dns_key.pem* - is its private key. + SANs (including wildcard domain). It has certificate *san_multiple_dns_cert.pem*, + *san_multiple_dns_key.pem* is its private key. - **SAN only**: Same as *SAN With DNS* except that the certificate doesn't have the CommonName set. It has certificate *san_only_dns_cert.pem*, *san_only_dns_key.pem* is its private key. diff --git a/test/common/ssl/test_data/san_multiple_dns_cert.cfg b/test/common/ssl/test_data/san_multiple_dns_cert.cfg index 30b38a344305..36a8560eac07 100644 --- a/test/common/ssl/test_data/san_multiple_dns_cert.cfg +++ b/test/common/ssl/test_data/san_multiple_dns_cert.cfg @@ -33,5 +33,5 @@ subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always [alt_names] -DNS.1 = server1.example.com +DNS.1 = *.example.com DNS.2 = server2.example.com diff --git a/test/common/ssl/test_data/san_multiple_dns_cert.pem b/test/common/ssl/test_data/san_multiple_dns_cert.pem index c8e66522e11c..96aef135e580 100644 --- a/test/common/ssl/test_data/san_multiple_dns_cert.pem +++ b/test/common/ssl/test_data/san_multiple_dns_cert.pem @@ -1,19 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIJANtsmkrxbZCQMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV +MIIDGzCCAoSgAwIBAgIJAJvUixVO/5pSMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp c2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw -DgYDVQQDEwdUZXN0IENBMB4XDTE3MTAwOTIxMzIwOVoXDTE5MTAwOTIxMzIwOVow +DgYDVQQDEwdUZXN0IENBMB4XDTE3MTEwMTE5NTQzNFoXDTE5MTEwMTE5NTQzNFow ejELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNh biBGcmFuY2lzY28xDTALBgNVBAoMBEx5ZnQxGTAXBgNVBAsMEEx5ZnQgRW5naW5l ZXJpbmcxFDASBgNVBAMMC1Rlc3QgU2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GN ADCBiQKBgQDo7qO+QXHTaZqWvVaY8B8SkNmuiN5ST24HMf6XLXExw3AbkoqUnGGH Gkq2B1aMRKKbrdLaOFrhR9kMi4X6K/X7vTOfQTxvU5FSVbhh5mKNvabqf1UojvYw -l5UGHqanOtth35wfDgZM18m68uX6Kz4DiZR8bx2Lbc53Acd+m/MNMQIDAQABo4Gy -MIGvMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUF -BwMCBggrBgEFBQcDATAzBgNVHREELDAqghNzZXJ2ZXIxLmV4YW1wbGUuY29tghNz -ZXJ2ZXIyLmV4YW1wbGUuY29tMB0GA1UdDgQWBBR/VCPbybRPLGoTdAS6Md+H0kCw -zzAfBgNVHSMEGDAWgBQ7eKRRTxaEkxxIKHoMrSuWQcp9eTANBgkqhkiG9w0BAQsF -AAOBgQAjifXrpzTb35NQU/3nM0ew+f3JpvcHg5qaZsOb7Q27vRE32KBg0y4VAtRd -iqZSzZG+iKPB1GjvZxDtaEY7d5jXAu0gXyXH3HxBq26Da6S5CIEIz7l1hTXC+gEL -KipuP5b9ofiwoxkU1EJaAyvYQxB1vx7s0xwIfijqfJf3BT0LgA== +l5UGHqanOtth35wfDgZM18m68uX6Kz4DiZR8bx2Lbc53Acd+m/MNMQIDAQABo4Gs +MIGpMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUF +BwMCBggrBgEFBQcDATAtBgNVHREEJjAkgg0qLmV4YW1wbGUuY29tghNzZXJ2ZXIy +LmV4YW1wbGUuY29tMB0GA1UdDgQWBBR/VCPbybRPLGoTdAS6Md+H0kCwzzAfBgNV +HSMEGDAWgBQ7eKRRTxaEkxxIKHoMrSuWQcp9eTANBgkqhkiG9w0BAQsFAAOBgQA5 +q8MuQq/Z0GVXllVYzyxtauqn66pc7ZdQZSwtbDndg8/mP2092TehUfUI1DNxnVg1 +UfTrc/Oz3gfryPUzwEhjo5/FtMfhn5JfARFbTZs3dtF8n5zc6RL8DUZNDxwHJ+uA +isASUfDcdsobASF2+j5+gAYUBJxohBKnUUgQ2IYWeA== -----END CERTIFICATE----- diff --git a/test/integration/ssl_integration_test.cc b/test/integration/ssl_integration_test.cc index 708cd0d81972..9f26041be605 100644 --- a/test/integration/ssl_integration_test.cc +++ b/test/integration/ssl_integration_test.cc @@ -58,7 +58,7 @@ ServerContextPtr SslIntegrationTest::createUpstreamSslContext() { Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); ServerContextConfigImpl cfg(*loader); - return context_manager_->createSslServerContext(*upstream_stats_store, cfg); + return context_manager_->createSslServerContext("", {}, *upstream_stats_store, cfg); } Network::ClientConnectionPtr SslIntegrationTest::makeSslClientConnection(bool alpn, bool san) { diff --git a/test/integration/xfcc_integration_test.cc b/test/integration/xfcc_integration_test.cc index 1002306a277f..c16d7a7ed730 100644 --- a/test/integration/xfcc_integration_test.cc +++ b/test/integration/xfcc_integration_test.cc @@ -85,7 +85,7 @@ Ssl::ServerContextPtr XfccIntegrationTest::createUpstreamSslContext() { Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); Ssl::ServerContextConfigImpl cfg(*loader); static auto* upstream_stats_store = new Stats::TestIsolatedStoreImpl(); - return context_manager_->createSslServerContext(*upstream_stats_store, cfg); + return context_manager_->createSslServerContext("", {}, *upstream_stats_store, cfg); } Network::ClientConnectionPtr XfccIntegrationTest::makeClientConnection() { diff --git a/test/mocks/ssl/mocks.h b/test/mocks/ssl/mocks.h index 0743a91811e1..0e76ee37bd1d 100644 --- a/test/mocks/ssl/mocks.h +++ b/test/mocks/ssl/mocks.h @@ -24,15 +24,20 @@ class MockContextManager : public ContextManager { return ClientContextPtr{createSslClientContext_(scope, config)}; } - ServerContextPtr createSslServerContext(Stats::Scope& scope, + ServerContextPtr createSslServerContext(const std::string& listener_name, + const std::vector& server_names, + Stats::Scope& scope, ServerContextConfig& config) override { - return ServerContextPtr{createSslServerContext_(scope, config)}; + return ServerContextPtr{createSslServerContext_(listener_name, server_names, scope, config)}; } MOCK_METHOD2(createSslClientContext_, ClientContext*(Stats::Scope& scope, ClientContextConfig& config)); - MOCK_METHOD2(createSslServerContext_, - ServerContext*(Stats::Scope& stats, ServerContextConfig& config)); + MOCK_METHOD4(createSslServerContext_, + ServerContext*(const std::string& listener_name, + const std::vector& server_names, Stats::Scope& stats, + ServerContextConfig& config)); + MOCK_METHOD2(findSslServerContext, ServerContext*(const std::string&, const std::string&)); MOCK_METHOD0(daysUntilFirstCertExpires, size_t()); MOCK_METHOD1(iterateContexts, void(std::function callback)); };