diff --git a/RAW_RELEASE_NOTES.md b/RAW_RELEASE_NOTES.md index efafe66efb5bd..f63e22001a888 100644 --- a/RAW_RELEASE_NOTES.md +++ b/RAW_RELEASE_NOTES.md @@ -8,6 +8,7 @@ will make it substantially easier for the releaser to "linkify" all of the relea final version. ## 1.6.0 +* Added support for inline delivery of TLS certificates and private keys. * Added gRPC healthcheck based on [grpc.health.v1.Health](https://github.com/grpc/grpc/blob/master/src/proto/grpc/health/v1/health.proto) service. * Added Metrics Service implementation. * Added gRPC access logging. diff --git a/configs/BUILD b/configs/BUILD index 4ef4d27a9daad..b4ebc516c4405 100644 --- a/configs/BUILD +++ b/configs/BUILD @@ -21,9 +21,12 @@ envoy_py_test_binary( genrule( name = "example_configs", - srcs = ["//examples:configs"], + srcs = [ + "//examples:configs", + "//test/config/integration/certs", + ], outs = ["example_configs.tar"], - cmd = "$(location configgen.sh) $(location configgen) $(@D) $(locations //examples:configs)", + cmd = "$(location configgen.sh) $(location configgen) $(@D) $(locations //examples:configs) $(locations //test/config/integration/certs)", tools = [ "configgen.sh", ":configgen", diff --git a/configs/configgen.sh b/configs/configgen.sh index 71d1134a4d697..703d09b2c5494 100755 --- a/configs/configgen.sh +++ b/configs/configgen.sh @@ -7,9 +7,19 @@ shift OUT_DIR="$1" shift -mkdir -p "$OUT_DIR" +mkdir -p "$OUT_DIR/certs" "$CONFIGGEN" "$OUT_DIR" -cp $* "$OUT_DIR" + +for FILE in $*; do + case "$FILE" in + *.pem) + cp "$FILE" "$OUT_DIR/certs" + ;; + *) + cp "$FILE" "$OUT_DIR" + ;; + esac +done # tar is having issues with -C for some reason so just cd into OUT_DIR. -(cd "$OUT_DIR"; tar -cvf example_configs.tar *.json *.yaml) +(cd "$OUT_DIR"; tar -cvf example_configs.tar *.json *.yaml certs/*.pem) diff --git a/configs/envoy_double_proxy.template.json b/configs/envoy_double_proxy.template.json index 345d463eabbef..7f67784be80f3 100644 --- a/configs/envoy_double_proxy.template.json +++ b/configs/envoy_double_proxy.template.json @@ -5,8 +5,8 @@ "ssl_context": { "alpn_protocols": "h2,http/1.1", "alt_alpn_protocols": "http/1.1", - "cert_chain_file": "/etc/envoy/cert.pem", - "private_key_file": "/etc/envoy/key.pem" + "cert_chain_file": "certs/servercert.pem", + "private_key_file": "certs/serverkey.pem" }, {% endif -%} {% if proxy_proto -%} @@ -128,8 +128,8 @@ up with a better solution just limit the requests so we can cycle and get better spread. #} "ssl_context": { - "cert_chain_file": "/etc/envoy/envoy-double-proxy.pem", - "private_key_file": "/etc/envoy/envoy-double-proxy.key", + "cert_chain_file": "certs/clientcert.pem", + "private_key_file": "certs/clientkey.pem", "verify_subject_alt_name": ["front-proxy.yourcompany.net"] }, "hosts": [{"url": "tcp://front-proxy.yourcompany.net:9400"}] @@ -138,7 +138,7 @@ "name": "lightstep_saas", "features": "http2", "ssl_context": { - "ca_cert_file": "/etc/ssl/certs/ca-certificates.crt", + "ca_cert_file": "certs/cacert.pem", "verify_subject_alt_name": ["collector-grpc.lightstep.com"] }, "connect_timeout_ms": 1000, diff --git a/configs/envoy_front_proxy.template.json b/configs/envoy_front_proxy.template.json index 9b3d56df3e86f..6e6e45ef6a46c 100644 --- a/configs/envoy_front_proxy.template.json +++ b/configs/envoy_front_proxy.template.json @@ -8,13 +8,13 @@ "alpn_protocols": "h2,http/1.1", "alt_alpn_protocols": "http/1.1", {% if kwargs.get('pin_double_proxy_client', False) -%} - "ca_cert_file": "/etc/envoy/envoy-ca.pem", + "ca_cert_file": "certs/cacert.pem", {# This should be the hash of the /etc/envoy/envoy-double-proxy.pem cert used in the double proxy configuration. #} "verify_certificate_hash": "fill me in", {% endif -%} - "cert_chain_file": "/etc/envoy/cert.pem", - "private_key_file": "/etc/envoy/key.pem" + "cert_chain_file": "certs/servercert.pem", + "private_key_file": "certs/serverkey.pem" }, {% endif -%} {% if kwargs['proxy_proto'] -%} @@ -144,7 +144,7 @@ "name": "lightstep_saas", "features": "http2", "ssl_context": { - "ca_cert_file": "/etc/ssl/certs/ca-certificates.crt", + "ca_cert_file": "certs/cacert.pem", "verify_subject_alt_name": ["collector-grpc.lightstep.com"] }, "connect_timeout_ms": 1000, diff --git a/configs/envoy_service_to_service.template.json b/configs/envoy_service_to_service.template.json index 1bf1bdcc71405..ebfee83c9bdcd 100644 --- a/configs/envoy_service_to_service.template.json +++ b/configs/envoy_service_to_service.template.json @@ -362,7 +362,7 @@ "name": "egress_{{ host['name'] }}", {% if host.get('ssl', False) -%} "ssl_context": { - "ca_cert_file": "/etc/ssl/certs/ca-certificates.crt" + "ca_cert_file": "certs/cacert.pem" {% if host.get('sni', False) -%} ,"sni": "{{ host['sni'] }}" {% endif -%} @@ -446,7 +446,7 @@ "name": "lightstep_saas", "features": "http2", "ssl_context": { - "ca_cert_file": "/etc/ssl/certs/ca-certificates.crt", + "ca_cert_file": "certs/cacert.pem", "verify_subject_alt_name": ["collector-grpc.lightstep.com"] }, "connect_timeout_ms": 1000, diff --git a/include/envoy/ssl/context_config.h b/include/envoy/ssl/context_config.h index edabaf5772c48..83df4dc70360e 100644 --- a/include/envoy/ssl/context_config.h +++ b/include/envoy/ssl/context_config.h @@ -39,19 +39,37 @@ class ContextConfig { virtual const std::string& ecdhCurves() const PURE; /** - * @return The CA certificate file to use for peer validation. + * @return The CA certificate to use for peer validation. */ - virtual const std::string& caCertFile() const PURE; + virtual const std::string& caCert() const PURE; /** - * @return The certificate chain file used to identify the local side. + * @return Path of the CA certificate to use for peer validation or "" + * if the CA certificate was inlined. */ - virtual const std::string& certChainFile() const PURE; + virtual const std::string& caCertPath() const PURE; /** - * @return The private key chain file used to identify the local side. + * @return The certificate chain used to identify the local side. */ - virtual const std::string& privateKeyFile() const PURE; + virtual const std::string& certChain() const PURE; + + /** + * @return Path of the certificate chain used to identify the local side or "" + * if the certificate chain was inlined. + */ + virtual const std::string& certChainPath() const PURE; + + /** + * @return The private key used to identify the local side. + */ + virtual const std::string& privateKey() const PURE; + + /** + * @return Path of the private key used to identify the local side or "" + * if the private key was inlined. + */ + virtual const std::string& privateKeyPath() const PURE; /** * @return The subject alt names to be verified, if enabled. Otherwise, "" diff --git a/source/common/ssl/context_config_impl.cc b/source/common/ssl/context_config_impl.cc index 251cbe8af8d7f..9414002913228 100644 --- a/source/common/ssl/context_config_impl.cc +++ b/source/common/ssl/context_config_impl.cc @@ -41,13 +41,20 @@ ContextConfigImpl::ContextConfigImpl(const envoy::api::v2::CommonTlsContext& con RepeatedPtrUtil::join(config.tls_params().cipher_suites(), ":"), DEFAULT_CIPHER_SUITES)), ecdh_curves_(StringUtil::nonEmptyStringOrDefault( RepeatedPtrUtil::join(config.tls_params().ecdh_curves(), ":"), DEFAULT_ECDH_CURVES)), - ca_cert_file_(config.validation_context().trusted_ca().filename()), - cert_chain_file_(config.tls_certificates().empty() + ca_cert_(readDataSource(config.validation_context().trusted_ca(), true)), + ca_cert_path_(getDataSourcePath(config.validation_context().trusted_ca())), + cert_chain_(config.tls_certificates().empty() + ? "" + : readDataSource(config.tls_certificates()[0].certificate_chain(), true)), + cert_chain_path_(config.tls_certificates().empty() ? "" - : config.tls_certificates()[0].certificate_chain().filename()), - private_key_file_(config.tls_certificates().empty() + : getDataSourcePath(config.tls_certificates()[0].certificate_chain())), + private_key_(config.tls_certificates().empty() + ? "" + : readDataSource(config.tls_certificates()[0].private_key(), true)), + private_key_path_(config.tls_certificates().empty() ? "" - : config.tls_certificates()[0].private_key().filename()), + : getDataSourcePath(config.tls_certificates()[0].private_key())), verify_subject_alt_name_list_(config.validation_context().verify_subject_alt_name().begin(), config.validation_context().verify_subject_alt_name().end()), verify_certificate_hash_(config.validation_context().verify_certificate_hash().empty() @@ -61,6 +68,28 @@ ContextConfigImpl::ContextConfigImpl(const envoy::api::v2::CommonTlsContext& con ASSERT(config.validation_context().verify_certificate_hash().size() <= 1); } +const std::string ContextConfigImpl::readDataSource(const envoy::api::v2::DataSource& source, + bool allow_empty) { + switch (source.specifier_case()) { + case envoy::api::v2::DataSource::kFilename: + return Filesystem::fileReadToEnd(source.filename()); + case envoy::api::v2::DataSource::kInlineBytes: + return source.inline_bytes(); + case envoy::api::v2::DataSource::kInlineString: + return source.inline_string(); + default: + if (!allow_empty) { + throw EnvoyException( + fmt::format("Unexpected DataSource::specifier_case(): {}", source.specifier_case())); + } + return ""; + } +} + +const std::string ContextConfigImpl::getDataSourcePath(const envoy::api::v2::DataSource& source) { + return source.specifier_case() == envoy::api::v2::DataSource::kFilename ? source.filename() : ""; +} + unsigned ContextConfigImpl::tlsVersionFromProto(const envoy::api::v2::TlsParameters_TlsProtocol& version, unsigned default_version) { @@ -105,23 +134,7 @@ ServerContextConfigImpl::ServerContextConfigImpl(const envoy::api::v2::Downstrea switch (config.session_ticket_keys_type_case()) { case envoy::api::v2::DownstreamTlsContext::kSessionTicketKeys: for (const auto& datasource : config.session_ticket_keys().keys()) { - switch (datasource.specifier_case()) { - case envoy::api::v2::DataSource::kFilename: { - validateAndAppendKey(ret, Filesystem::fileReadToEnd(datasource.filename())); - break; - } - case envoy::api::v2::DataSource::kInlineBytes: { - validateAndAppendKey(ret, datasource.inline_bytes()); - break; - } - case envoy::api::v2::DataSource::kInlineString: { - validateAndAppendKey(ret, datasource.inline_string()); - break; - } - default: - throw EnvoyException(fmt::format("Unexpected DataSource::specifier_case(): {}", - datasource.specifier_case())); - } + validateAndAppendKey(ret, readDataSource(datasource, false)); } break; case envoy::api::v2::DownstreamTlsContext::kSessionTicketKeysSdsSecretConfig: @@ -139,12 +152,7 @@ ServerContextConfigImpl::ServerContextConfigImpl(const envoy::api::v2::Downstrea // TODO(PiotrSikora): Support multiple TLS certificates. // TODO(mattklein123): All of the ASSERTs in this file need to be converted to exceptions with // proper error handling. - // TODO(htuch): Support inline cert material delivery. ASSERT(config.common_tls_context().tls_certificates().size() == 1); - ASSERT(config.common_tls_context().tls_certificates()[0].certificate_chain().specifier_case() == - envoy::api::v2::DataSource::kFilename); - ASSERT(config.common_tls_context().tls_certificates()[0].private_key().specifier_case() == - envoy::api::v2::DataSource::kFilename); } ServerContextConfigImpl::ServerContextConfigImpl(const Json::Object& config) diff --git a/source/common/ssl/context_config_impl.h b/source/common/ssl/context_config_impl.h index fbf557847ee38..83212fa722e33 100644 --- a/source/common/ssl/context_config_impl.h +++ b/source/common/ssl/context_config_impl.h @@ -12,6 +12,8 @@ namespace Envoy { namespace Ssl { +static const std::string INLINE_STRING = ""; + class ContextConfigImpl : public virtual Ssl::ContextConfig { public: // Ssl::ContextConfig @@ -19,9 +21,18 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig { const std::string& altAlpnProtocols() const override { return alt_alpn_protocols_; } const std::string& cipherSuites() const override { return cipher_suites_; } const std::string& ecdhCurves() const override { return ecdh_curves_; } - const std::string& caCertFile() const override { return ca_cert_file_; } - const std::string& certChainFile() const override { return cert_chain_file_; } - const std::string& privateKeyFile() const override { return private_key_file_; } + const std::string& caCert() const override { return ca_cert_; } + const std::string& caCertPath() const override { + return (ca_cert_path_.empty() && !ca_cert_.empty()) ? INLINE_STRING : ca_cert_path_; + } + const std::string& certChain() const override { return cert_chain_; } + const std::string& certChainPath() const override { + return (cert_chain_path_.empty() && !cert_chain_.empty()) ? INLINE_STRING : cert_chain_path_; + } + const std::string& privateKey() const override { return private_key_; } + const std::string& privateKeyPath() const override { + return (private_key_path_.empty() && !private_key_.empty()) ? INLINE_STRING : private_key_path_; + } const std::vector& verifySubjectAltNameList() const override { return verify_subject_alt_name_list_; }; @@ -32,6 +43,10 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig { protected: ContextConfigImpl(const envoy::api::v2::CommonTlsContext& config); + static const std::string readDataSource(const envoy::api::v2::DataSource& source, + bool allow_empty); + static const std::string getDataSourcePath(const envoy::api::v2::DataSource& source); + private: static unsigned tlsVersionFromProto(const envoy::api::v2::TlsParameters_TlsProtocol& version, unsigned default_version); @@ -43,9 +58,12 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig { const std::string alt_alpn_protocols_; const std::string cipher_suites_; const std::string ecdh_curves_; - const std::string ca_cert_file_; - const std::string cert_chain_file_; - const std::string private_key_file_; + const std::string ca_cert_; + const std::string ca_cert_path_; + const std::string cert_chain_; + const std::string cert_chain_path_; + const std::string private_key_; + const std::string private_key_path_; const std::vector verify_subject_alt_name_list_; const std::string verify_certificate_hash_; const unsigned min_protocol_version_; diff --git a/source/common/ssl/context_impl.cc b/source/common/ssl/context_impl.cc index bc5e49627a61b..ea020a25eb85b 100644 --- a/source/common/ssl/context_impl.cc +++ b/source/common/ssl/context_impl.cc @@ -54,14 +54,33 @@ ContextImpl::ContextImpl(ContextManagerImpl& parent, Stats::Scope& scope, int verify_mode = SSL_VERIFY_NONE; - if (!config.caCertFile().empty()) { - ca_cert_ = loadCert(config.caCertFile()); - ca_file_path_ = config.caCertFile(); - // set CA certificate - int rc = SSL_CTX_load_verify_locations(ctx_.get(), config.caCertFile().c_str(), nullptr); - if (0 == rc) { + if (!config.caCert().empty()) { + ca_file_path_ = config.caCertPath(); + bssl::UniquePtr bio( + BIO_new_mem_buf(const_cast(config.caCert().data()), config.caCert().size())); + RELEASE_ASSERT(bio != nullptr); + // Based on BoringSSL's X509_load_cert_crl_file(). + bssl::UniquePtr list( + PEM_X509_INFO_read_bio(bio.get(), nullptr, nullptr, nullptr)); + if (list == nullptr) { throw EnvoyException( - fmt::format("Failed to load verify locations file {}", config.caCertFile())); + fmt::format("Failed to load trusted CA certificates from {}", config.caCertPath())); + } + for (const X509_INFO* item : list.get()) { + if (item->x509) { + X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx_.get()), item->x509); + if (ca_cert_ == nullptr) { + X509_up_ref(item->x509); + ca_cert_.reset(item->x509); + } + } + if (item->crl) { + X509_STORE_add_crl(SSL_CTX_get_cert_store(ctx_.get()), item->crl); + } + } + if (ca_cert_ == nullptr) { + throw EnvoyException( + fmt::format("Failed to load trusted CA certificates from {}", config.caCertPath())); } verify_mode = SSL_VERIFY_PEER; } @@ -84,19 +103,52 @@ ContextImpl::ContextImpl(ContextManagerImpl& parent, Stats::Scope& scope, SSL_CTX_set_cert_verify_callback(ctx_.get(), ContextImpl::verifyCallback, this); } - if (!config.certChainFile().empty()) { - cert_chain_ = loadCert(config.certChainFile()); - cert_chain_file_path_ = config.certChainFile(); - int rc = SSL_CTX_use_certificate_chain_file(ctx_.get(), config.certChainFile().c_str()); - if (0 == rc) { + if (config.certChain().empty() != config.privateKey().empty()) { + throw EnvoyException(fmt::format("Failed to load incomplete certificate from {}, {}", + config.certChainPath(), config.privateKeyPath())); + } + + if (!config.certChain().empty()) { + // Load certificate chain. + cert_chain_file_path_ = config.certChainPath(); + bssl::UniquePtr bio( + BIO_new_mem_buf(const_cast(config.certChain().data()), config.certChain().size())); + RELEASE_ASSERT(bio != nullptr); + cert_chain_.reset(PEM_read_bio_X509_AUX(bio.get(), nullptr, nullptr, nullptr)); + if (cert_chain_ == nullptr || !SSL_CTX_use_certificate(ctx_.get(), cert_chain_.get())) { + throw EnvoyException( + fmt::format("Failed to load certificate chain from {}", config.certChainPath())); + } + // Read rest of the certificate chain. + while (true) { + bssl::UniquePtr cert(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)); + if (cert == nullptr) { + break; + } + if (!SSL_CTX_add_extra_chain_cert(ctx_.get(), cert.get())) { + throw EnvoyException( + fmt::format("Failed to load certificate chain from {}", config.certChainPath())); + } + // SSL_CTX_add_extra_chain_cert() takes ownership. + cert.release(); + } + // Check for EOF. + uint32_t err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { + ERR_clear_error(); + } else { throw EnvoyException( - fmt::format("Failed to load certificate chain file {}", config.certChainFile())); + fmt::format("Failed to load certificate chain from {}", config.certChainPath())); } - rc = SSL_CTX_use_PrivateKey_file(ctx_.get(), config.privateKeyFile().c_str(), SSL_FILETYPE_PEM); - if (0 == rc) { + // Load private key. + bio.reset( + BIO_new_mem_buf(const_cast(config.privateKey().data()), config.privateKey().size())); + RELEASE_ASSERT(bio != nullptr); + bssl::UniquePtr pkey(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr)); + if (pkey == nullptr || !SSL_CTX_use_PrivateKey(ctx_.get(), pkey.get())) { throw EnvoyException( - fmt::format("Failed to load private key file {}", config.privateKeyFile())); + fmt::format("Failed to load private key from {}", config.privateKeyPath())); } } @@ -375,10 +427,41 @@ ServerContextImpl::ServerContextImpl(ContextManagerImpl& parent, const std::stri 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) { - throw EnvoyException(fmt::format("Failed to load client CA file {}", config.caCertFile())); + if (!config.caCert().empty()) { + bssl::UniquePtr bio( + BIO_new_mem_buf(const_cast(config.caCert().data()), config.caCert().size())); + RELEASE_ASSERT(bio != nullptr); + // Based on BoringSSL's SSL_add_file_cert_subjects_to_stack(). + bssl::UniquePtr list(sk_X509_NAME_new( + [](const X509_NAME** a, const X509_NAME** b) -> int { return X509_NAME_cmp(*a, *b); })); + RELEASE_ASSERT(list != nullptr); + for (;;) { + bssl::UniquePtr cert(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)); + if (cert == nullptr) { + break; + } + X509_NAME* name = X509_get_subject_name(cert.get()); + if (name == nullptr) { + throw EnvoyException(fmt::format("Failed to load trusted client CA certificates from {}", + config.caCertPath())); + } + // Check for duplicates. + if (sk_X509_NAME_find(list.get(), nullptr, name)) { + continue; + } + bssl::UniquePtr name_dup(X509_NAME_dup(name)); + if (name_dup == nullptr || !sk_X509_NAME_push(list.get(), name_dup.release())) { + throw EnvoyException(fmt::format("Failed to load trusted client CA certificates from {}", + config.caCertPath())); + } + } + // Check for EOF. + uint32_t err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { + ERR_clear_error(); + } else { + throw EnvoyException(fmt::format("Failed to load trusted client CA certificates from {}", + config.caCertPath())); } SSL_CTX_set_client_CA_list(ctx_.get(), list.release()); diff --git a/test/common/ssl/ssl_socket_test.cc b/test/common/ssl/ssl_socket_test.cc index a2a69f9daabb7..d5d2f9de471ad 100644 --- a/test/common/ssl/ssl_socket_test.cc +++ b/test/common/ssl/ssl_socket_test.cc @@ -264,6 +264,166 @@ TEST_P(SslSocketTest, GetCertDigest) { "ssl.handshake", true, GetParam()); } +TEST_P(SslSocketTest, GetCertDigestInline) { + envoy::api::v2::Listener listener; + envoy::api::v2::FilterChain* filter_chain = listener.add_filter_chains(); + envoy::api::v2::TlsCertificate* server_cert = + filter_chain->mutable_tls_context()->mutable_common_tls_context()->add_tls_certificates(); + + // From test/common/ssl/test_data/san_dns_cert.pem. + server_cert->mutable_certificate_chain()->set_inline_bytes( + "-----BEGIN CERTIFICATE-----\n" + "MIIDDDCCAnWgAwIBAgIJAPOCjrJP13nQMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV\n" + "BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\n" + "c2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw\n" + "DgYDVQQDEwdUZXN0IENBMB4XDTE3MDcwOTAxMzkzMloXDTE5MDcwOTAxMzkzMlow\n" + "ejELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\n" + "biBGcmFuY2lzY28xDTALBgNVBAoTBEx5ZnQxGTAXBgNVBAsTEEx5ZnQgRW5naW5l\n" + "ZXJpbmcxFDASBgNVBAMTC1Rlc3QgU2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GN\n" + "ADCBiQKBgQDARNUJMFkWF0E6mbdz/nkydVC4TU2SgR95vhJhWpG6xKkCNoXkJxNz\n" + "XOmFUUIXQyq7FnIWACYuMrE2KXnomeCGP9A6M21lumNseYSLX3/b+ao4E6gimm1/\n" + "Gp8C3FaoAs8Ep7VE+o2DMIfTIPJhFf6RBFPundGhEm8/gv+QObVhKQIDAQABo4Gd\n" + "MIGaMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUF\n" + "BwMCBggrBgEFBQcDATAeBgNVHREEFzAVghNzZXJ2ZXIxLmV4YW1wbGUuY29tMB0G\n" + "A1UdDgQWBBRCcUr8mIigWlR61OX/gmDY5vBV6jAfBgNVHSMEGDAWgBQ7eKRRTxaE\n" + "kxxIKHoMrSuWQcp9eTANBgkqhkiG9w0BAQsFAAOBgQAtn05e8U41heun5L7MKflv\n" + "tJM7w0whavdS8hLe63CxnS98Ap973mSiShKG+OxSJ0ClMWIZPy+KyC+T8yGIaynj\n" + "wEEuoSGRWmhzcMMnZWxqQyD95Fsx6mtdnq/DJxiYzmH76fALe/538j8pTcoygSGD\n" + "NWw1EW8TEwlFyuvCrlWQcg==\n" + "-----END CERTIFICATE-----"); + + // From test/common/ssl/test_data/san_dns_key.pem. + server_cert->mutable_private_key()->set_inline_bytes( + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIICXQIBAAKBgQDARNUJMFkWF0E6mbdz/nkydVC4TU2SgR95vhJhWpG6xKkCNoXk\n" + "JxNzXOmFUUIXQyq7FnIWACYuMrE2KXnomeCGP9A6M21lumNseYSLX3/b+ao4E6gi\n" + "mm1/Gp8C3FaoAs8Ep7VE+o2DMIfTIPJhFf6RBFPundGhEm8/gv+QObVhKQIDAQAB\n" + "AoGBAJM64kukC0QAUMHX/gRD5HkAHuzSvUknuXuXUincmeWEPMtmBwdb6OgZSPT+\n" + "8XYwx+L14Cz6tkIALXWFM0YrtyKfVdELRRs8dw5nenzK3wOeo/N/7XL4kwim4kV3\n" + "q817RO6NUN76vHOsvQMFsPlEfCZpOTIGJEJBI7eFLP0djOMlAkEA/yWEPfQoER/i\n" + "X6uNyXrU51A6gxyZg7rPNP0cxxRhDedtsJPNY6Tlu90v9SiTgQLUTp7BINH24t9a\n" + "MST1tmax+wJBAMDpeRy52q+sqLXI1C2oHPuXrXzeyp9pynV/9tsYL9+qoyP2XcEZ\n" + "DaI0tfXDJXOdYIaDnSfB50eqQUnaTmQjtCsCQGUFGaLd9K8zDJIMforzUzByl3gp\n" + "7q41XK0COk6oRvUWWFu9aWi2dS84mDBc7Gn8EMtAF/9CopmZDUC//XlGl9kCQQCr\n" + "6yWw8PywFHohzwEwUyLJIKpOnyoKGTiBsHGpXYvEk4hiEzwISzB4PutuQuRMfZM5\n" + "LW/Pr6FSn6shivjTi3ITAkACMTBczBQ+chMBcTXDqyqwccQOIhupxani9wfZhsrm\n" + "ZXbTTxnUZioQ2l/7IWa+K2O2NrWWT7b3KpCAob0bJsQz\n" + "-----END RSA PRIVATE KEY-----"); + + // From test/common/ssl/test_data/ca_certificates.pem. + filter_chain->mutable_tls_context() + ->mutable_common_tls_context() + ->mutable_validation_context() + ->mutable_trusted_ca() + ->set_inline_bytes("-----BEGIN CERTIFICATE-----\n" + "MIICzTCCAjagAwIBAgIJAPAEjHA3MX2BMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV\n" + "BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\n" + "c2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw\n" + "DgYDVQQDEwdGYWtlIENBMB4XDTE3MDcwOTAxMzkzMloXDTI3MDcwNzAxMzkzMlow\n" + "djELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\n" + "biBGcmFuY2lzY28xDTALBgNVBAoTBEx5ZnQxGTAXBgNVBAsTEEx5ZnQgRW5naW5l\n" + "ZXJpbmcxEDAOBgNVBAMTB0Zha2UgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ\n" + "AoGBAK/89R7j0kwhGh7NDAiuhlVmN1Hh73sGRzDBgON/ZfmJSgkvZIwQ4+hu0wZ6\n" + "wjN0am1iIKyp8O1OkmKurcfCRQM2QGiIUI7v7rSa0GzqENoEsQGXVk8/yhwD8Ys9\n" + "IPLTWXLVyh49yh5FCs6nt2/LrIuZX/K2cZQx+VuLCcg5sTllAgMBAAGjYzBhMA8G\n" + "A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRRsE37S/H/\n" + "lCd1pWH4sCn9qrON3TAfBgNVHSMEGDAWgBRRsE37S/H/lCd1pWH4sCn9qrON3TAN\n" + "BgkqhkiG9w0BAQsFAAOBgQAvFbQm1PrqeWlZssPDPfI5dlo2KEL9VedIlThqDU4z\n" + "MStNR/Tfw2A0WtjOyjm2R0viqLu8JdDe8umUqO9DkRhZOaUtLgQEkaQn75z8WQPk\n" + "Sj+kenx0v3GMrPZMAsELiPG5PcSk8l5prDgU7VkzNvoCtypCsB7RQRyvZs52Qih3\n" + "Ug==\n" + "-----END CERTIFICATE-----\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICzTCCAjagAwIBAgIJAOrzsOodDleaMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV\n" + "BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\n" + "c2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw\n" + "DgYDVQQDEwdUZXN0IENBMB4XDTE3MDcwOTAxMzkzMloXDTI3MDcwNzAxMzkzMlow\n" + "djELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\n" + "biBGcmFuY2lzY28xDTALBgNVBAoTBEx5ZnQxGTAXBgNVBAsTEEx5ZnQgRW5naW5l\n" + "ZXJpbmcxEDAOBgNVBAMTB1Rlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ\n" + "AoGBAJuJh8N5TheTHLKOxsLSAfiIu9VDeKPsV98KRJJaYCMoaof3j9wBs65HzIat\n" + "AunuV4DVZZ2c/x7/v741oWadYd3yqL7XSzQaeBvhXi+wv3g17FYrdxaowG7cfmsh\n" + "gCp7/9TRW0bRGL6Qp6od/u62L8dprdHXxnck/+sZMupam9YrAgMBAAGjYzBhMA8G\n" + "A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQ7eKRRTxaE\n" + "kxxIKHoMrSuWQcp9eTAfBgNVHSMEGDAWgBQ7eKRRTxaEkxxIKHoMrSuWQcp9eTAN\n" + "BgkqhkiG9w0BAQsFAAOBgQCN00/2k9k8HNeJ8eYuFH10jnc+td7+OaYWpRSEKCS7\n" + "ux3KAu0UFt90mojEMClt4Y6uP4oXTWbRzMzAgQHldHU8Gkj8tYnv7mToX7Bh/xdc\n" + "19epzjCmo/4Q6+16GZZvltiFjkkHSZEVI5ggljy1QdMIPRegsKKmX9mjZSCSSXD6\n" + "SA==\n" + "-----END CERTIFICATE-----"); + + envoy::api::v2::UpstreamTlsContext client_ctx; + envoy::api::v2::TlsCertificate* client_cert = + client_ctx.mutable_common_tls_context()->add_tls_certificates(); + + // From test/common/ssl/test_data/san_uri_cert.pem. + client_cert->mutable_certificate_chain()->set_inline_bytes( + "-----BEGIN CERTIFICATE-----\n" + "MIIDFDCCAn2gAwIBAgIJAN6Kky/8alfaMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV\n" + "BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\n" + "c2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw\n" + "DgYDVQQDEwdUZXN0IENBMB4XDTE3MDcwOTAxMzkzMloXDTE5MDcwOTAxMzkzMlow\n" + "ejELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\n" + "biBGcmFuY2lzY28xDTALBgNVBAoTBEx5ZnQxGTAXBgNVBAsTEEx5ZnQgRW5naW5l\n" + "ZXJpbmcxFDASBgNVBAMTC1Rlc3QgU2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GN\n" + "ADCBiQKBgQDQNSdVcQBlmLBHoyMtMJrYRMI4HkuCYqubvBD9gfZbt+bux5Lh2CRT\n" + "RVB9fUTh/bQ9fzZ+XpZu2OLG/otHi20Yu5XPgXL5+OSzCdzMqujGs8Ft9ugZI2UL\n" + "TufqMfesbs7y8cJg2y+UpQZlXlJ2iImMkqdomOsrNvzFzT3/LRncywIDAQABo4Gl\n" + "MIGiMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUF\n" + "BwMCBggrBgEFBQcDATAmBgNVHREEHzAdhhtzcGlmZmU6Ly9seWZ0LmNvbS90ZXN0\n" + "LXRlYW0wHQYDVR0OBBYEFCmCEC8ABzXj8S4E++Whd37lIhg5MB8GA1UdIwQYMBaA\n" + "FDt4pFFPFoSTHEgoegytK5ZByn15MA0GCSqGSIb3DQEBCwUAA4GBAF6p8V73RNLS\n" + "jWcS/NUuRFWNqJ0pGc06wsb7JnVnSn12zPrpzwTQOPHZYY+KZC8TtgpnLgLobWVu\n" + "mlDkUA5/25A1O+smL2nquUaix/I3X71U3MKo59JzrxNV3mlBSOmv9K1r/jpxZ96d\n" + "mMXJ1d7L5pUWxa3q0ANg+mywtpGMvqHL\n" + "-----END CERTIFICATE-----"); + + // From test/common/ssl/test_data/san_uri_key.pem. + client_cert->mutable_private_key()->set_inline_bytes( + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIICWwIBAAKBgQDQNSdVcQBlmLBHoyMtMJrYRMI4HkuCYqubvBD9gfZbt+bux5Lh\n" + "2CRTRVB9fUTh/bQ9fzZ+XpZu2OLG/otHi20Yu5XPgXL5+OSzCdzMqujGs8Ft9ugZ\n" + "I2ULTufqMfesbs7y8cJg2y+UpQZlXlJ2iImMkqdomOsrNvzFzT3/LRncywIDAQAB\n" + "AoGAUczQS00+LqwydbKuW07BRz6cX5fnaq6BZYoZ0r+AnsA9xoo6NujIPL76xJK2\n" + "wWL/sTmNm1BmId6sGipfZhhtH5kELxddygGYotTYfL9NHxf0FA3uPGnGVIEQphwa\n" + "orAe5NVpORUzZwYQdxohXR25+DnDb4cM7TktNb32P0hO2KECQQDqqRHdYzh/EPyz\n" + "7LEUsBPD28ijb+sFfSce+YFYVUuJBtN6zHnnpnbkuQK7EbRGVEB2XrpFj/3AFktz\n" + "tHymGI1NAkEA4yRCPSC5VEH9jJa6gpij7t8LPJ5gOh2EvrvzFVyN49E4hE2H1kKP\n" + "1kKs8TKbsNFgHhOxwsmTnOV0ZHlZ0THmdwJAJyDqCbBxyz5Z5Oai4IA7y3zqh9Yx\n" + "qkikLVYNa11NqxuoR+Gwsh/f02PGQMtC9Dc4SISjKtZHya/uBO0jm86cQQJAE10c\n" + "9H8crY0uo1SaM9X1a8DCAXny9CFeFrCJKZIJWpmUetrtMJveDUMD4VASK8G9svK0\n" + "3ck3d1GsWYBq4sWhQwJAKP1jLt3nwQEuSS88Yi2dMC3iPCWMljatC3u6976etDg7\n" + "AoETSNx+UIqKSg6LsNYqs4omsDPnZ2j+4m2fvHaVJg==\n" + "-----END RSA PRIVATE KEY-----"); + + // ssl.handshake logged by both: client & server. + testUtilV2(listener, client_ctx, "", true, "", + "1406294e80c818158697d65d2aaca16748ff132442ab0e2f28bc1109f1d47a2e", + "spiffe://lyft.com/test-team", "", "ssl.handshake", 2, GetParam()); +} + +TEST_P(SslSocketTest, GetCertDigestServerCertWithIntermediateCA) { + std::string client_ctx_json = R"EOF( + { + "cert_chain_file": "{{ test_rundir }}/test/common/ssl/test_data/no_san_cert.pem", + "private_key_file": "{{ test_rundir }}/test/common/ssl/test_data/no_san_key.pem", + "ca_cert_file": "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem" + } + )EOF"; + + std::string server_ctx_json = R"EOF( + { + "cert_chain_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_chain3.pem", + "private_key_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key3.pem", + "ca_cert_file": "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem" + } + )EOF"; + + testUtil(client_ctx_json, server_ctx_json, + "4444fbca965d916475f04fb4dd234dd556adb028ceb4300fa8ad6f2983c6aaa3", "", "", "", "", + "ssl.handshake", true, GetParam()); +} + TEST_P(SslSocketTest, GetCertDigestServerCertWithoutCommonName) { std::string client_ctx_json = R"EOF( { @@ -858,6 +1018,38 @@ TEST_P(SslSocketTest, TicketSessionResumptionDifferentServerCert) { GetParam()); } +// Sessions cannot be resumed because the server certificates are different, CN/SANs are identical, +// but the issuer is different. +TEST_P(SslSocketTest, TicketSessionResumptionDifferentServerCertIntermediateCA) { + std::string server_ctx_json1 = R"EOF( + { + "cert_chain_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_cert.pem", + "private_key_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key.pem", + "session_ticket_key_paths": [ + "{{ test_rundir }}/test/common/ssl/test_data/ticket_key_a" + ] + } + )EOF"; + + std::string server_ctx_json2 = R"EOF( + { + "cert_chain_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_chain3.pem", + "private_key_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key3.pem", + "session_ticket_key_paths": [ + "{{ test_rundir }}/test/common/ssl/test_data/ticket_key_a" + ] + } + )EOF"; + + std::string client_ctx_json = R"EOF( + { + } + )EOF"; + + testTicketSessionResumption(server_ctx_json1, server_ctx_json2, client_ctx_json, false, + GetParam()); +} + // Sessions cannot be resumed because the server certificates are different and the SANs // are not identical TEST_P(SslSocketTest, TicketSessionResumptionDifferentServerCertDifferentSAN) { diff --git a/test/common/ssl/test_data/README.md b/test/common/ssl/test_data/README.md index 7905bf545a3c0..5b8dcf372fc2c 100644 --- a/test/common/ssl/test_data/README.md +++ b/test/common/ssl/test_data/README.md @@ -1,8 +1,11 @@ # What are the identities, certificates and keys -There are 9 identities: +There are 10 identities: - **CA**: Certificate Authority for **No SAN**, **SAN With URI** and **SAN With DNS**. It has the self-signed certificate *ca_cert.pem*. *ca_key.pem* is its private key. +- **Intermediate CA**: Intermediate Certificate Authority, signed by the **CA**. + It has the certificate *intermediate_ca_cert.pem". *intermediate_ca_key.pem* + is its private key. - **Fake CA**: Fake Certificate Authority used to validate verification logic. It has the self-signed certificate *fake_ca_cert.pem"*. *fake_ca_key.pem" is its private key. @@ -14,7 +17,9 @@ There are 9 identities: - **SAN With DNS**: It has the certificate *san_dns_cert.pem*, which is signed by the **CA** using the config *san_dns_cert.cfg*. The certificate has SAN 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*. + and key, using the same config, is *san_dns_cert2*. A third certificate and key, + using the same config, but signed by the **Intermediate CA** is *san_dns_cert3*, + its certificate chain is *san_dns_chain3.pem*. - **SAN With Multiple DNS**: Same as *SAN With DNS* except there are multiple SANs (including wildcard domain). It has certificate *san_multiple_dns_cert.pem*, *san_multiple_dns_key.pem* is its private key. diff --git a/test/common/ssl/test_data/certs.sh b/test/common/ssl/test_data/certs.sh index 589a3ab8cf590..a442f31a5500a 100755 --- a/test/common/ssl/test_data/certs.sh +++ b/test/common/ssl/test_data/certs.sh @@ -4,10 +4,12 @@ set -e # Uncomment the following lines if you want to regenerate the private keys. # openssl genrsa -out ca_key.pem 1024 +# openssl genrsa -out intermediate_ca_key.pem 1024 # openssl genrsa -out fake_ca_key.pem 1024 # openssl genrsa -out no_san_key.pem 1024 # openssl genrsa -out san_dns_key.pem 1024 # openssl genrsa -out san_dns_key2.pem 1024 +# openssl genrsa -out san_dns_key3.pem 1024 # openssl genrsa -out san_multiple_dns_key.pem 1024 # openssl genrsa -out san_uri_key.pem 1024 # openssl genrsa -out selfsigned_key.pem 1024 @@ -17,6 +19,10 @@ set -e openssl req -new -key ca_key.pem -out ca_cert.csr -config ca_cert.cfg -batch -sha256 openssl x509 -req -days 3650 -in ca_cert.csr -signkey ca_key.pem -out ca_cert.pem -extensions v3_ca -extfile ca_cert.cfg +# Generate intermediate_ca_cert.pem. +openssl req -new -key intermediate_ca_key.pem -out intermediate_ca_cert.csr -config intermediate_ca_cert.cfg -batch -sha256 +openssl x509 -req -days 3650 -in intermediate_ca_cert.csr -sha256 -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out intermediate_ca_cert.pem -extensions v3_ca -extfile intermediate_ca_cert.cfg + # Generate fake_ca_cert.pem. openssl req -new -key fake_ca_key.pem -out fake_ca_cert.csr -config fake_ca_cert.cfg -batch -sha256 openssl x509 -req -days 3650 -in fake_ca_cert.csr -signkey fake_ca_key.pem -out fake_ca_cert.pem -extensions v3_ca -extfile fake_ca_cert.cfg @@ -32,10 +38,17 @@ openssl x509 -req -days 730 -in no_san_cert.csr -sha256 -CA ca_cert.pem -CAkey c openssl req -new -key san_dns_key.pem -out san_dns_cert.csr -config san_dns_cert.cfg -batch -sha256 openssl x509 -req -days 730 -in san_dns_cert.csr -sha256 -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out san_dns_cert.pem -extensions v3_ca -extfile san_dns_cert.cfg -# Generate san_dns_cert2.pem. +# Generate san_dns_cert2.pem (duplicate of san_dns_cert.pem, but with a different private key). openssl req -new -key san_dns_key2.pem -out san_dns_cert2.csr -config san_dns_cert.cfg -batch -sha256 openssl x509 -req -days 730 -in san_dns_cert2.csr -sha256 -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out san_dns_cert2.pem -extensions v3_ca -extfile san_dns_cert.cfg +# Generate san_dns_cert3.pem (signed by intermediate_ca_cert.pem). +openssl req -new -key san_dns_key3.pem -out san_dns_cert3.csr -config san_dns_cert.cfg -batch -sha256 +openssl x509 -req -days 730 -in san_dns_cert3.csr -sha256 -CA intermediate_ca_cert.pem -CAkey intermediate_ca_key.pem -CAcreateserial -out san_dns_cert3.pem -extensions v3_ca -extfile san_dns_cert.cfg + +# Concatenate san_dns_cert3.pem and Test Intermediate CA (intermediate_ca_cert.pem) to create valid certificate chain. +cat san_dns_cert3.pem intermediate_ca_cert.pem > san_dns_chain3.pem + # Generate san_multiple_dns_cert.pem. openssl req -new -key san_multiple_dns_key.pem -out san_multiple_dns_cert.csr -config san_multiple_dns_cert.cfg -batch -sha256 openssl x509 -req -days 730 -in san_multiple_dns_cert.csr -sha256 -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out san_multiple_dns_cert.pem -extensions v3_ca -extfile san_multiple_dns_cert.cfg diff --git a/test/common/ssl/test_data/intermediate_ca_cert.cfg b/test/common/ssl/test_data/intermediate_ca_cert.cfg new file mode 100644 index 0000000000000..b107e442c1822 --- /dev/null +++ b/test/common/ssl/test_data/intermediate_ca_cert.cfg @@ -0,0 +1,29 @@ +[req] +distinguished_name = req_distinguished_name +req_extensions = v3_req + +[req_distinguished_name] +countryName = US +countryName_default = US +stateOrProvinceName = California +stateOrProvinceName_default = California +localityName = San Francisco +localityName_default = San Francisco +organizationName = Lyft +organizationName_default = Lyft +organizationalUnitName = Lyft Engineering +organizationalUnitName_default = Lyft Engineering +commonName = Test Intermediate CA +commonName_default = Test Intermediate CA +commonName_max = 64 + +[v3_req] +basicConstraints = CA:TRUE, pathlen:0 +keyUsage = critical, cRLSign, keyCertSign +subjectKeyIdentifier = hash + +[v3_ca] +basicConstraints = critical, CA:TRUE, pathlen:0 +keyUsage = critical, cRLSign, keyCertSign +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always diff --git a/test/common/ssl/test_data/intermediate_ca_cert.pem b/test/common/ssl/test_data/intermediate_ca_cert.pem new file mode 100644 index 0000000000000..d1dc57c014b37 --- /dev/null +++ b/test/common/ssl/test_data/intermediate_ca_cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC3jCCAkegAwIBAgIJAJvUixVO/5pTMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp +c2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw +DgYDVQQDEwdUZXN0IENBMB4XDTE4MDExNTIyNDAyN1oXDTI4MDExMzIyNDAyN1ow +gYMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T +YW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2lu +ZWVyaW5nMR0wGwYDVQQDDBRUZXN0IEludGVybWVkaWF0ZSBDQTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAxd1kOhV+/2n+rJWKvrtkyyqkWgBXXhH15G9cusaR +zJtwxsvtPRYZ9nTc+A6GDFgZ0TS1sq/WJXfs3guMpFObXU+tSlezxHVRpWPTXKff +hblqtZMPKW5q5LmOHxKi8GUxwDnEeAiZmzstGCYkRKn+GmLYe26vFGBw4MvM89Vm +ecMCAwEAAaNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFIuDOLnI5iZPpH230VFAuWeNYuWdMB8GA1UdIwQYMBaAFDt4pFFP +FoSTHEgoegytK5ZByn15MA0GCSqGSIb3DQEBCwUAA4GBAGO77sBFzn63pM2Oy4XS ++FEcFj/lB4vBh4r8jtzdf5EMaKUeXY9i57MTryPTJZRFXW6BuQ/B3hiOW2fwkCdL +eHd0MwGv95cn1PCWZh1IidVrtrDeu0oLxhRk5mcflaaLBuGADUD3Y1ms2sl90Ean +6C+0EHH2O6Emesx9IhPZRx4H +-----END CERTIFICATE----- diff --git a/test/common/ssl/test_data/intermediate_ca_key.pem b/test/common/ssl/test_data/intermediate_ca_key.pem new file mode 100644 index 0000000000000..4a2593d9ecbb9 --- /dev/null +++ b/test/common/ssl/test_data/intermediate_ca_key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDF3WQ6FX7/af6slYq+u2TLKqRaAFdeEfXkb1y6xpHMm3DGy+09 +Fhn2dNz4DoYMWBnRNLWyr9Yld+zeC4ykU5tdT61KV7PEdVGlY9Ncp9+FuWq1kw8p +bmrkuY4fEqLwZTHAOcR4CJmbOy0YJiREqf4aYth7bq8UYHDgy8zz1WZ5wwIDAQAB +AoGAB91l930VQDfJXLjQ/AXc2sqGH+G1l1KlcIAQsofkEbr3/57pfi0buRUqF14U +a/cwh4VN151vqKucqbLR01JTcY8lfPtIBoSd3A0eXxZo6gZKQZcnj8aF1HGdonV9 +B06yfU9Hm3U40R9ZEPbZNfBzsNm+HHki1jd3ZvdvMQl961ECQQDvD/4M9RrveQK8 +A/H+EKf+pZq85tk5oTWLF5ZDItcOQ9VG5LnFKU2e8wNZkkgfT7p812veHsIw8Hg8 +55k65JipAkEA0+Isq701NAveNfgUy2rIMBRsKnXbczrMnpWUyaeGvm4pq1b5PmZY +As4MjXZLY7QLcJJ7o+Sark+GQKfJ+jqmiwJAMGfWkx0WJSMlkJhj6YPJ4F/74wAD +QA4KX22ZOWLWlMbbao1pqChi1SpzpTFfdSeZpSmhZ8pmm641Sm/CsRAUcQJAYSjB +my70Cp22k8DiqDSa/5Ed2IqaysgXtFCbHa04WHJjoTIMsNR1XzPlBalNALc617AU +Ch913qCQy20lbR0f6QJBAMoCSTXEsbPh3awPWMzNR71Yq4nnDk/1jFZX6JerUHEz +ylI4pXCRNs4vGjAF9q24HLXreapziANtWovEXJkoQAI= +-----END RSA PRIVATE KEY----- diff --git a/test/common/ssl/test_data/san_dns_cert3.pem b/test/common/ssl/test_data/san_dns_cert3.pem new file mode 100644 index 0000000000000..f8d6956a594af --- /dev/null +++ b/test/common/ssl/test_data/san_dns_cert3.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGjCCAoOgAwIBAgIJALE/9j8tvBGNMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j +aXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UECwwQTHlmdCBFbmdpbmVlcmluZzEd +MBsGA1UEAwwUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTgwMTE1MjI0MDI3WhcN +MjAwMTE1MjI0MDI3WjB6MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p +YTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UE +CwwQTHlmdCBFbmdpbmVlcmluZzEUMBIGA1UEAwwLVGVzdCBTZXJ2ZXIwgZ8wDQYJ +KoZIhvcNAQEBBQADgY0AMIGJAoGBALGG70n/nfIB64LH6jraqxpJ3EUO+gL/KkHG +4+/hQMMZpehPdcHa7vj1efBgaaddtjRZ3GLSSF968O19EbMwjQl1Azwn3Ql8SddQ +hyW30/Q/jgY54MnDBGgb5xhb7tdfjGvZ+lKapu9FypTcrre/wXSwBSsmm2me0CCN +AZKddyMzAgMBAAGjgZ0wgZowDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBeAwHQYD +VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB4GA1UdEQQXMBWCE3NlcnZlcjEu +ZXhhbXBsZS5jb20wHQYDVR0OBBYEFBZcRXhGXlFghYQ9/R6yF7XTHzkxMB8GA1Ud +IwQYMBaAFIuDOLnI5iZPpH230VFAuWeNYuWdMA0GCSqGSIb3DQEBCwUAA4GBAFZg +6ZznS3KuEus6ZJsLJH7J0BMKmpdj5hM0M++TBnP8LVy73ETc95Y2sxvB/B2c7f2v +wjz4nGd5O3kkiVlMrQ44GPUKrO3/Ltix+MT3ixuF7Z7vLFKwkIG2d0RXJVVb1MOM +w1bmtABHf8sVAFF6RZtjshWSaZYvIhiG1FedV4Vw +-----END CERTIFICATE----- diff --git a/test/common/ssl/test_data/san_dns_chain3.pem b/test/common/ssl/test_data/san_dns_chain3.pem new file mode 100644 index 0000000000000..7f61a41163960 --- /dev/null +++ b/test/common/ssl/test_data/san_dns_chain3.pem @@ -0,0 +1,37 @@ +-----BEGIN CERTIFICATE----- +MIIDGjCCAoOgAwIBAgIJALE/9j8tvBGNMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j +aXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UECwwQTHlmdCBFbmdpbmVlcmluZzEd +MBsGA1UEAwwUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTgwMTE1MjI0MDI3WhcN +MjAwMTE1MjI0MDI3WjB6MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p +YTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UE +CwwQTHlmdCBFbmdpbmVlcmluZzEUMBIGA1UEAwwLVGVzdCBTZXJ2ZXIwgZ8wDQYJ +KoZIhvcNAQEBBQADgY0AMIGJAoGBALGG70n/nfIB64LH6jraqxpJ3EUO+gL/KkHG +4+/hQMMZpehPdcHa7vj1efBgaaddtjRZ3GLSSF968O19EbMwjQl1Azwn3Ql8SddQ +hyW30/Q/jgY54MnDBGgb5xhb7tdfjGvZ+lKapu9FypTcrre/wXSwBSsmm2me0CCN +AZKddyMzAgMBAAGjgZ0wgZowDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBeAwHQYD +VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB4GA1UdEQQXMBWCE3NlcnZlcjEu +ZXhhbXBsZS5jb20wHQYDVR0OBBYEFBZcRXhGXlFghYQ9/R6yF7XTHzkxMB8GA1Ud +IwQYMBaAFIuDOLnI5iZPpH230VFAuWeNYuWdMA0GCSqGSIb3DQEBCwUAA4GBAFZg +6ZznS3KuEus6ZJsLJH7J0BMKmpdj5hM0M++TBnP8LVy73ETc95Y2sxvB/B2c7f2v +wjz4nGd5O3kkiVlMrQ44GPUKrO3/Ltix+MT3ixuF7Z7vLFKwkIG2d0RXJVVb1MOM +w1bmtABHf8sVAFF6RZtjshWSaZYvIhiG1FedV4Vw +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC3jCCAkegAwIBAgIJAJvUixVO/5pTMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp +c2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw +DgYDVQQDEwdUZXN0IENBMB4XDTE4MDExNTIyNDAyN1oXDTI4MDExMzIyNDAyN1ow +gYMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T +YW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2lu +ZWVyaW5nMR0wGwYDVQQDDBRUZXN0IEludGVybWVkaWF0ZSBDQTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAxd1kOhV+/2n+rJWKvrtkyyqkWgBXXhH15G9cusaR +zJtwxsvtPRYZ9nTc+A6GDFgZ0TS1sq/WJXfs3guMpFObXU+tSlezxHVRpWPTXKff +hblqtZMPKW5q5LmOHxKi8GUxwDnEeAiZmzstGCYkRKn+GmLYe26vFGBw4MvM89Vm +ecMCAwEAAaNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFIuDOLnI5iZPpH230VFAuWeNYuWdMB8GA1UdIwQYMBaAFDt4pFFP +FoSTHEgoegytK5ZByn15MA0GCSqGSIb3DQEBCwUAA4GBAGO77sBFzn63pM2Oy4XS ++FEcFj/lB4vBh4r8jtzdf5EMaKUeXY9i57MTryPTJZRFXW6BuQ/B3hiOW2fwkCdL +eHd0MwGv95cn1PCWZh1IidVrtrDeu0oLxhRk5mcflaaLBuGADUD3Y1ms2sl90Ean +6C+0EHH2O6Emesx9IhPZRx4H +-----END CERTIFICATE----- diff --git a/test/common/ssl/test_data/san_dns_key3.pem b/test/common/ssl/test_data/san_dns_key3.pem new file mode 100644 index 0000000000000..b0da70902f062 --- /dev/null +++ b/test/common/ssl/test_data/san_dns_key3.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQCxhu9J/53yAeuCx+o62qsaSdxFDvoC/ypBxuPv4UDDGaXoT3XB +2u749XnwYGmnXbY0Wdxi0khfevDtfRGzMI0JdQM8J90JfEnXUIclt9P0P44GOeDJ +wwRoG+cYW+7XX4xr2fpSmqbvRcqU3K63v8F0sAUrJptpntAgjQGSnXcjMwIDAQAB +AoGAJk4kQcZLEVYCuDRkwRA/zStUwP3rSkw+lPTSaAcljzNwjgDfOtX/rG5jQk+7 +XGanEwK0wAn5nciMReIvuIdoVt7zEtFygZ7D3yKh+Ywu0AYC8TaiszAaL0efMnAW +MtpgyrAoMB4bFON3oyNVZM161+cdrU0PrEDqh+GHl8abpokCQQDfn2jE3WmS/a36 +2Dt/e3yjNE/4xDshAcHkNmF+jpcB66bls5ZU5Yv07RUVExQ30fw3v+ADMxmNYg2f +qpAF2getAkEAyzr9GwgdKeruErwlLhMOG327zTcZlHZXU5Q378/S3bKi3c/voGCb +exKjxRBZTzSw5hfrOzbCEpMLcwZaoBiyXwJBAJAH2XAq98vQDpXpXfEPNUjc8cFV +iowI2LxHdmYQKxz2jemW0PXfX1Siuxh20GffnOa/c+Y7rHKOvB2hut+5/YUCQQCF +nBx2vxjdTBSEwKj455IoxLrJKeZpUnwK+LDluo35Ls4gYeo6WAkgGpsMnbj5d7yt +KSB/Z3qj14R5dL3z7wilAkEAp78JPrvWP5zc3YOmmr9s8IQ3almspwnlh1mdcgoX +4rHe3U4jRZwE6fw8W9G4QsFRlez1Re6g8T7yoFXiZETGqQ== +-----END RSA PRIVATE KEY----- diff --git a/test/config_test/config_test.cc b/test/config_test/config_test.cc index bb3fa3048ad5a..7de7607f71093 100644 --- a/test/config_test/config_test.cc +++ b/test/config_test/config_test.cc @@ -1,3 +1,5 @@ +#include + #include #include @@ -74,11 +76,17 @@ class ConfigTest { }; uint32_t run(const std::string& directory) { + // Change working directory, otherwise we won't be able to read files using relative paths. + char cwd[PATH_MAX]; + RELEASE_ASSERT(::getcwd(cwd, PATH_MAX) != nullptr); + RELEASE_ASSERT(::chdir(directory.c_str()) == 0); uint32_t num_tested = 0; - for (const std::string& filename : TestUtility::listFiles(directory, true)) { + for (const std::string& filename : TestUtility::listFiles(directory, false)) { ConfigTest config(filename); num_tested++; } + // Return to the original working directory, otherwise "bazel.coverage" breaks (...but why?). + RELEASE_ASSERT(::chdir(cwd) == 0); return num_tested; } diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index 42decc20025c2..9969e35b39162 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -1042,5 +1042,133 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, SniWithTwoDifferentFilterChains) "chains is currently not supported"); } +TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInline) { + const std::string yaml = R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + filter_chains: + - tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: { inline_string: "-----BEGIN CERTIFICATE-----\nMIIDGjCCAoOgAwIBAgIJALE/9j8tvBGNMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j\naXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UECwwQTHlmdCBFbmdpbmVlcmluZzEd\nMBsGA1UEAwwUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTgwMTE1MjI0MDI3WhcN\nMjAwMTE1MjI0MDI3WjB6MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p\nYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UE\nCwwQTHlmdCBFbmdpbmVlcmluZzEUMBIGA1UEAwwLVGVzdCBTZXJ2ZXIwgZ8wDQYJ\nKoZIhvcNAQEBBQADgY0AMIGJAoGBALGG70n/nfIB64LH6jraqxpJ3EUO+gL/KkHG\n4+/hQMMZpehPdcHa7vj1efBgaaddtjRZ3GLSSF968O19EbMwjQl1Azwn3Ql8SddQ\nhyW30/Q/jgY54MnDBGgb5xhb7tdfjGvZ+lKapu9FypTcrre/wXSwBSsmm2me0CCN\nAZKddyMzAgMBAAGjgZ0wgZowDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBeAwHQYD\nVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB4GA1UdEQQXMBWCE3NlcnZlcjEu\nZXhhbXBsZS5jb20wHQYDVR0OBBYEFBZcRXhGXlFghYQ9/R6yF7XTHzkxMB8GA1Ud\nIwQYMBaAFIuDOLnI5iZPpH230VFAuWeNYuWdMA0GCSqGSIb3DQEBCwUAA4GBAFZg\n6ZznS3KuEus6ZJsLJH7J0BMKmpdj5hM0M++TBnP8LVy73ETc95Y2sxvB/B2c7f2v\nwjz4nGd5O3kkiVlMrQ44GPUKrO3/Ltix+MT3ixuF7Z7vLFKwkIG2d0RXJVVb1MOM\nw1bmtABHf8sVAFF6RZtjshWSaZYvIhiG1FedV4Vw\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIC3jCCAkegAwIBAgIJAJvUixVO/5pTMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\nc2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw\nDgYDVQQDEwdUZXN0IENBMB4XDTE4MDExNTIyNDAyN1oXDTI4MDExMzIyNDAyN1ow\ngYMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T\nYW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2lu\nZWVyaW5nMR0wGwYDVQQDDBRUZXN0IEludGVybWVkaWF0ZSBDQTCBnzANBgkqhkiG\n9w0BAQEFAAOBjQAwgYkCgYEAxd1kOhV+/2n+rJWKvrtkyyqkWgBXXhH15G9cusaR\nzJtwxsvtPRYZ9nTc+A6GDFgZ0TS1sq/WJXfs3guMpFObXU+tSlezxHVRpWPTXKff\nhblqtZMPKW5q5LmOHxKi8GUxwDnEeAiZmzstGCYkRKn+GmLYe26vFGBw4MvM89Vm\necMCAwEAAaNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYw\nHQYDVR0OBBYEFIuDOLnI5iZPpH230VFAuWeNYuWdMB8GA1UdIwQYMBaAFDt4pFFP\nFoSTHEgoegytK5ZByn15MA0GCSqGSIb3DQEBCwUAA4GBAGO77sBFzn63pM2Oy4XS\n+FEcFj/lB4vBh4r8jtzdf5EMaKUeXY9i57MTryPTJZRFXW6BuQ/B3hiOW2fwkCdL\neHd0MwGv95cn1PCWZh1IidVrtrDeu0oLxhRk5mcflaaLBuGADUD3Y1ms2sl90Ean\n6C+0EHH2O6Emesx9IhPZRx4H\n-----END CERTIFICATE-----" } + private_key: { inline_string: "-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgQCxhu9J/53yAeuCx+o62qsaSdxFDvoC/ypBxuPv4UDDGaXoT3XB\n2u749XnwYGmnXbY0Wdxi0khfevDtfRGzMI0JdQM8J90JfEnXUIclt9P0P44GOeDJ\nwwRoG+cYW+7XX4xr2fpSmqbvRcqU3K63v8F0sAUrJptpntAgjQGSnXcjMwIDAQAB\nAoGAJk4kQcZLEVYCuDRkwRA/zStUwP3rSkw+lPTSaAcljzNwjgDfOtX/rG5jQk+7\nXGanEwK0wAn5nciMReIvuIdoVt7zEtFygZ7D3yKh+Ywu0AYC8TaiszAaL0efMnAW\nMtpgyrAoMB4bFON3oyNVZM161+cdrU0PrEDqh+GHl8abpokCQQDfn2jE3WmS/a36\n2Dt/e3yjNE/4xDshAcHkNmF+jpcB66bls5ZU5Yv07RUVExQ30fw3v+ADMxmNYg2f\nqpAF2getAkEAyzr9GwgdKeruErwlLhMOG327zTcZlHZXU5Q378/S3bKi3c/voGCb\nexKjxRBZTzSw5hfrOzbCEpMLcwZaoBiyXwJBAJAH2XAq98vQDpXpXfEPNUjc8cFV\niowI2LxHdmYQKxz2jemW0PXfX1Siuxh20GffnOa/c+Y7rHKOvB2hut+5/YUCQQCF\nnBx2vxjdTBSEwKj455IoxLrJKeZpUnwK+LDluo35Ls4gYeo6WAkgGpsMnbj5d7yt\nKSB/Z3qj14R5dL3z7wilAkEAp78JPrvWP5zc3YOmmr9s8IQ3almspwnlh1mdcgoX\n4rHe3U4jRZwE6fw8W9G4QsFRlez1Re6g8T7yoFXiZETGqQ==\n-----END RSA PRIVATE KEY-----" } + validation_context: + trusted_ca: { inline_string: "-----BEGIN CERTIFICATE-----\nMIICzTCCAjagAwIBAgIJAOrzsOodDleaMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\nc2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw\nDgYDVQQDEwdUZXN0IENBMB4XDTE3MDcwOTAxMzkzMloXDTI3MDcwNzAxMzkzMlow\ndjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xDTALBgNVBAoTBEx5ZnQxGTAXBgNVBAsTEEx5ZnQgRW5naW5l\nZXJpbmcxEDAOBgNVBAMTB1Rlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ\nAoGBAJuJh8N5TheTHLKOxsLSAfiIu9VDeKPsV98KRJJaYCMoaof3j9wBs65HzIat\nAunuV4DVZZ2c/x7/v741oWadYd3yqL7XSzQaeBvhXi+wv3g17FYrdxaowG7cfmsh\ngCp7/9TRW0bRGL6Qp6od/u62L8dprdHXxnck/+sZMupam9YrAgMBAAGjYzBhMA8G\nA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQ7eKRRTxaE\nkxxIKHoMrSuWQcp9eTAfBgNVHSMEGDAWgBQ7eKRRTxaEkxxIKHoMrSuWQcp9eTAN\nBgkqhkiG9w0BAQsFAAOBgQCN00/2k9k8HNeJ8eYuFH10jnc+td7+OaYWpRSEKCS7\nux3KAu0UFt90mojEMClt4Y6uP4oXTWbRzMzAgQHldHU8Gkj8tYnv7mToX7Bh/xdc\n19epzjCmo/4Q6+16GZZvltiFjkkHSZEVI5ggljy1QdMIPRegsKKmX9mjZSCSSXD6\nSA==\n-----END CERTIFICATE-----" } + )EOF"; + + EXPECT_CALL(server_.random_, uuid()); + EXPECT_CALL(listener_factory_, createListenSocket(_, true)); + manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), true); + EXPECT_EQ(1U, manager_->listeners().size()); +} + +TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateChainInlinePrivateKeyFilename) { + const std::string yaml = TestEnvironment::substitute(R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + filter_chains: + - tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: { inline_string: "-----BEGIN CERTIFICATE-----\nMIIDGjCCAoOgAwIBAgIJALE/9j8tvBGNMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j\naXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UECwwQTHlmdCBFbmdpbmVlcmluZzEd\nMBsGA1UEAwwUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTgwMTE1MjI0MDI3WhcN\nMjAwMTE1MjI0MDI3WjB6MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p\nYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UE\nCwwQTHlmdCBFbmdpbmVlcmluZzEUMBIGA1UEAwwLVGVzdCBTZXJ2ZXIwgZ8wDQYJ\nKoZIhvcNAQEBBQADgY0AMIGJAoGBALGG70n/nfIB64LH6jraqxpJ3EUO+gL/KkHG\n4+/hQMMZpehPdcHa7vj1efBgaaddtjRZ3GLSSF968O19EbMwjQl1Azwn3Ql8SddQ\nhyW30/Q/jgY54MnDBGgb5xhb7tdfjGvZ+lKapu9FypTcrre/wXSwBSsmm2me0CCN\nAZKddyMzAgMBAAGjgZ0wgZowDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBeAwHQYD\nVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB4GA1UdEQQXMBWCE3NlcnZlcjEu\nZXhhbXBsZS5jb20wHQYDVR0OBBYEFBZcRXhGXlFghYQ9/R6yF7XTHzkxMB8GA1Ud\nIwQYMBaAFIuDOLnI5iZPpH230VFAuWeNYuWdMA0GCSqGSIb3DQEBCwUAA4GBAFZg\n6ZznS3KuEus6ZJsLJH7J0BMKmpdj5hM0M++TBnP8LVy73ETc95Y2sxvB/B2c7f2v\nwjz4nGd5O3kkiVlMrQ44GPUKrO3/Ltix+MT3ixuF7Z7vLFKwkIG2d0RXJVVb1MOM\nw1bmtABHf8sVAFF6RZtjshWSaZYvIhiG1FedV4Vw\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIC3jCCAkegAwIBAgIJAJvUixVO/5pTMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\nc2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRAw\nDgYDVQQDEwdUZXN0IENBMB4XDTE4MDExNTIyNDAyN1oXDTI4MDExMzIyNDAyN1ow\ngYMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T\nYW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2lu\nZWVyaW5nMR0wGwYDVQQDDBRUZXN0IEludGVybWVkaWF0ZSBDQTCBnzANBgkqhkiG\n9w0BAQEFAAOBjQAwgYkCgYEAxd1kOhV+/2n+rJWKvrtkyyqkWgBXXhH15G9cusaR\nzJtwxsvtPRYZ9nTc+A6GDFgZ0TS1sq/WJXfs3guMpFObXU+tSlezxHVRpWPTXKff\nhblqtZMPKW5q5LmOHxKi8GUxwDnEeAiZmzstGCYkRKn+GmLYe26vFGBw4MvM89Vm\necMCAwEAAaNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYw\nHQYDVR0OBBYEFIuDOLnI5iZPpH230VFAuWeNYuWdMB8GA1UdIwQYMBaAFDt4pFFP\nFoSTHEgoegytK5ZByn15MA0GCSqGSIb3DQEBCwUAA4GBAGO77sBFzn63pM2Oy4XS\n+FEcFj/lB4vBh4r8jtzdf5EMaKUeXY9i57MTryPTJZRFXW6BuQ/B3hiOW2fwkCdL\neHd0MwGv95cn1PCWZh1IidVrtrDeu0oLxhRk5mcflaaLBuGADUD3Y1ms2sl90Ean\n6C+0EHH2O6Emesx9IhPZRx4H\n-----END CERTIFICATE-----" } + private_key: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key3.pem" } + )EOF", + Network::Address::IpVersion::v4); + + EXPECT_CALL(server_.random_, uuid()); + EXPECT_CALL(listener_factory_, createListenSocket(_, true)); + manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), true); + EXPECT_EQ(1U, manager_->listeners().size()); +} + +TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateIncomplete) { + const std::string yaml = TestEnvironment::substitute(R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + filter_chains: + - tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_chain3.pem" } + )EOF", + Network::Address::IpVersion::v4); + + EXPECT_THROW_WITH_MESSAGE( + manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), true), EnvoyException, + TestEnvironment::substitute("Failed to load incomplete certificate from {{ test_rundir }}" + "/test/common/ssl/test_data/san_dns_chain3.pem, ", + Network::Address::IpVersion::v4)); +} + +TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidCertificateChain) { + const std::string yaml = TestEnvironment::substitute(R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + filter_chains: + - tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: { inline_string: "invalid" } + private_key: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key3.pem" } + )EOF", + Network::Address::IpVersion::v4); + + EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), true), + EnvoyException, "Failed to load certificate chain from "); +} + +TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidIntermediateCA) { + const std::string yaml = TestEnvironment::substitute(R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + filter_chains: + - tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: { inline_string: "-----BEGIN CERTIFICATE-----\nMIIDGjCCAoOgAwIBAgIJALE/9j8tvBGNMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j\naXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UECwwQTHlmdCBFbmdpbmVlcmluZzEd\nMBsGA1UEAwwUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTgwMTE1MjI0MDI3WhcN\nMjAwMTE1MjI0MDI3WjB6MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p\nYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwETHlmdDEZMBcGA1UE\nCwwQTHlmdCBFbmdpbmVlcmluZzEUMBIGA1UEAwwLVGVzdCBTZXJ2ZXIwgZ8wDQYJ\nKoZIhvcNAQEBBQADgY0AMIGJAoGBALGG70n/nfIB64LH6jraqxpJ3EUO+gL/KkHG\n4+/hQMMZpehPdcHa7vj1efBgaaddtjRZ3GLSSF968O19EbMwjQl1Azwn3Ql8SddQ\nhyW30/Q/jgY54MnDBGgb5xhb7tdfjGvZ+lKapu9FypTcrre/wXSwBSsmm2me0CCN\nAZKddyMzAgMBAAGjgZ0wgZowDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBeAwHQYD\nVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB4GA1UdEQQXMBWCE3NlcnZlcjEu\nZXhhbXBsZS5jb20wHQYDVR0OBBYEFBZcRXhGXlFghYQ9/R6yF7XTHzkxMB8GA1Ud\nIwQYMBaAFIuDOLnI5iZPpH230VFAuWeNYuWdMA0GCSqGSIb3DQEBCwUAA4GBAFZg\n6ZznS3KuEus6ZJsLJH7J0BMKmpdj5hM0M++TBnP8LVy73ETc95Y2sxvB/B2c7f2v\nwjz4nGd5O3kkiVlMrQ44GPUKrO3/Ltix+MT3ixuF7Z7vLFKwkIG2d0RXJVVb1MOM\nw1bmtABHf8sVAFF6RZtjshWSaZYvIhiG1FedV4Vw\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\ninvalid" } + private_key: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key3.pem" } + )EOF", + Network::Address::IpVersion::v4); + + EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), true), + EnvoyException, "Failed to load certificate chain from "); +} + +TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidPrivateKey) { + const std::string yaml = TestEnvironment::substitute(R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + filter_chains: + - tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_chain3.pem" } + private_key: { inline_string: "invalid" } + )EOF", + Network::Address::IpVersion::v4); + + EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), true), + EnvoyException, "Failed to load private key from "); +} + +TEST_F(ListenerManagerImplWithRealFiltersTest, TlsCertificateInvalidTrustedCA) { + const std::string yaml = TestEnvironment::substitute(R"EOF( + address: + socket_address: { address: 127.0.0.1, port_value: 1234 } + filter_chains: + - tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_chain3.pem" } + private_key: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key3.pem" } + validation_context: + trusted_ca: { inline_string: "invalid" } + )EOF", + Network::Address::IpVersion::v4); + + EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), true), + EnvoyException, "Failed to load trusted CA certificates from "); +} + } // namespace Server } // namespace Envoy