Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d4f4c64
Add support for 'crl' field in CertificateValidationContext and v1 co…
adunham-stripe Dec 22, 2017
26a9abc
Load CRLs from context
adunham-stripe Dec 22, 2017
40e9985
Add CRLs to X509_STORE if any are present
adunham-stripe Dec 22, 2017
3599a9d
Add test data for CRLs
adunham-stripe Dec 22, 2017
c1b339b
Add test that verifies our configuration parses
adunham-stripe Dec 22, 2017
99abed1
Add test that verifies that a revoked certificate + CRL works
adunham-stripe Dec 22, 2017
6d15f1f
Formatting fixes
adunham-stripe Dec 22, 2017
6914839
Review feedback: simplify iterating over X509_INFO stack, use real re…
adunham-stripe Dec 22, 2017
f05137d
Add a test for loading an invalid CRL
adunham-stripe Jan 2, 2018
518de3c
Review feedback: store raw CRL bytes in ContextConfig
adunham-stripe Jan 23, 2018
a680597
Fix tests and remove unnecessary X509_CRL_up_ref
adunham-stripe Jan 23, 2018
0db0cac
Review feedback: remove TODO
adunham-stripe Jan 23, 2018
8eb8991
Review feedback: naming and moving things around a bit
adunham-stripe Jan 24, 2018
0a9dfba
Review feedback: add tests for v2 config, including with inlined CRLs
adunham-stripe Jan 24, 2018
71063a8
Review feedback: be more specific in test assertion
adunham-stripe Jan 24, 2018
47150bc
Review feedback: don't generate a new cert for revocation
adunham-stripe Jan 24, 2018
5b53667
Review feedback: move CRL configuration into ca_cert.cfg
adunham-stripe Jan 24, 2018
ee2530f
Review feedback: add the X509_V_FLAG_CRL_CHECK_ALL flag
adunham-stripe Jan 25, 2018
c1c66ac
Review feedback: fix test data script and remove unnecessary file
adunham-stripe Jan 25, 2018
f1045df
Review feedback: move remaining CRL code to immediately after CA code
adunham-stripe Jan 25, 2018
8ce73bf
Review feedback: Clean up X509_STORE* code and remove unnecessary '-r…
adunham-stripe Jan 25, 2018
d4c3ccd
Review feedback: throw an exception if we have a CRL but no CA certif…
adunham-stripe Jan 26, 2018
7e07bf0
Review feedback: change exception message to match other errors
adunham-stripe Jan 26, 2018
fa2dfb7
Review feedback: fix missing '^' and add test data comment
adunham-stripe Jan 26, 2018
cdbb2b9
Review feedback: formatting fixes
adunham-stripe Jan 26, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/envoy/ssl/context_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ class ContextConfig {
*/
virtual const std::string& caCertPath() const PURE;

/**
* @return The CRL to check if a cert is revoked.
*/
virtual const std::string& certificateRevocationList() const PURE;

/**
* @return Path of the certificate revocation list, or "<inline>" if the CRL
* was inlined.
*/
virtual const std::string& certificateRevocationListPath() const PURE;

/**
* @return The certificate chain used to identify the local side.
*/
Expand Down
3 changes: 3 additions & 0 deletions source/common/config/tls_context_json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ void TlsContextJson::translateCommonTlsContext(
validation_context->mutable_trusted_ca()->set_filename(
json_tls_context.getString("ca_cert_file", ""));
}
if (json_tls_context.hasObject("crl_file")) {
validation_context->mutable_crl()->set_filename(json_tls_context.getString("crl_file", ""));
}
if (json_tls_context.hasObject("verify_certificate_hash")) {
validation_context->add_verify_certificate_hash(
json_tls_context.getString("verify_certificate_hash"));
Expand Down
3 changes: 2 additions & 1 deletion source/common/json/config_schemas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ const std::string Json::Schema::LISTENER_SCHEMA(R"EOF(
}
},
"cipher_suites" : {"type" : "string", "minLength" : 1},
"ecdh_curves" : {"type" : "string", "minLength" : 1}
"ecdh_curves" : {"type" : "string", "minLength" : 1},
"crl_file" : {"type" : "string"}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v1 APIs are deprecated, so I'm not sure if we're supposed to keep adding things here? cc @mattklein123 @htuch

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point v2 is required, v1 is optional but not blocked. If folks want to add and doc no problem.

},
"required": ["cert_chain_file", "private_key_file"],
"additionalProperties": false
Expand Down
6 changes: 6 additions & 0 deletions source/common/ssl/context_config_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ ContextConfigImpl::ContextConfigImpl(const envoy::api::v2::CommonTlsContext& con
RepeatedPtrUtil::join(config.tls_params().ecdh_curves(), ":"), DEFAULT_ECDH_CURVES)),
ca_cert_(readDataSource(config.validation_context().trusted_ca(), true)),
ca_cert_path_(getDataSourcePath(config.validation_context().trusted_ca())),
certificate_revocation_list_(readDataSource(config.validation_context().crl(), true)),
certificate_revocation_list_path_(getDataSourcePath(config.validation_context().crl())),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is one more thing missing here. You should throw an exception (down in the function body) if CRL is set, but there is no CA. All v1 tests are doing this, which obviously shouldn't work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good point - I've pushed a commit that adds this, along with some tests.

cert_chain_(config.tls_certificates().empty()
? ""
: readDataSource(config.tls_certificates()[0].certificate_chain(), true)),
Expand All @@ -66,6 +68,10 @@ ContextConfigImpl::ContextConfigImpl(const envoy::api::v2::CommonTlsContext& con
tlsVersionFromProto(config.tls_params().tls_maximum_protocol_version(), TLS1_2_VERSION)) {
// TODO(htuch): Support multiple hashes.
ASSERT(config.validation_context().verify_certificate_hash().size() <= 1);
if (ca_cert_.empty() && !certificate_revocation_list_.empty()) {
throw EnvoyException(fmt::format("Failed to load CRL from {} without trusted CA certificates",
certificateRevocationListPath()));
}
}

const std::string ContextConfigImpl::readDataSource(const envoy::api::v2::DataSource& source,
Expand Down
10 changes: 10 additions & 0 deletions source/common/ssl/context_config_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig {
const std::string& caCertPath() const override {
return (ca_cert_path_.empty() && !ca_cert_.empty()) ? INLINE_STRING : ca_cert_path_;
}
const std::string& certificateRevocationList() const override {
return certificate_revocation_list_;
}
const std::string& certificateRevocationListPath() const override {
return (certificate_revocation_list_path_.empty() && !certificate_revocation_list_.empty())
? INLINE_STRING
: certificate_revocation_list_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_;
Expand Down Expand Up @@ -60,6 +68,8 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig {
const std::string ecdh_curves_;
const std::string ca_cert_;
const std::string ca_cert_path_;
const std::string certificate_revocation_list_;
const std::string certificate_revocation_list_path_;
const std::string cert_chain_;
const std::string cert_chain_path_;
const std::string private_key_;
Expand Down
30 changes: 28 additions & 2 deletions source/common/ssl/context_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,18 @@ ContextImpl::ContextImpl(ContextManagerImpl& parent, Stats::Scope& scope,
throw EnvoyException(
fmt::format("Failed to load trusted CA certificates from {}", config.caCertPath()));
}

X509_STORE* store = SSL_CTX_get_cert_store(ctx_.get());
for (const X509_INFO* item : list.get()) {
if (item->x509) {
X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx_.get()), item->x509);
X509_STORE_add_cert(store, 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);
X509_STORE_add_crl(store, item->crl);
}
}
if (ca_cert_ == nullptr) {
Expand All @@ -85,6 +87,30 @@ ContextImpl::ContextImpl(ContextManagerImpl& parent, Stats::Scope& scope,
verify_mode = SSL_VERIFY_PEER;
}

if (!config.certificateRevocationList().empty()) {
bssl::UniquePtr<BIO> bio(
BIO_new_mem_buf(const_cast<char*>(config.certificateRevocationList().data()),
config.certificateRevocationList().size()));
RELEASE_ASSERT(bio != nullptr);

// Based on BoringSSL's X509_load_cert_crl_file().
bssl::UniquePtr<STACK_OF(X509_INFO)> list(
PEM_X509_INFO_read_bio(bio.get(), nullptr, nullptr, nullptr));
if (list == nullptr) {
throw EnvoyException(
fmt::format("Failed to load CRL from {}", config.certificateRevocationListPath()));
}

X509_STORE* store = SSL_CTX_get_cert_store(ctx_.get());
for (const X509_INFO* item : list.get()) {
if (item->crl) {
X509_STORE_add_crl(store, item->crl);
}
}

X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
}

if (!config.verifySubjectAltNameList().empty()) {
verify_subject_alt_name_list_ = config.verifySubjectAltNameList();
verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
Expand Down
41 changes: 41 additions & 0 deletions test/common/ssl/context_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "test/common/ssl/ssl_certs_test.h"
#include "test/mocks/runtime/mocks.h"
#include "test/test_common/environment.h"
#include "test/test_common/utility.h"

#include "gtest/gtest.h"

Expand Down Expand Up @@ -284,5 +285,45 @@ TEST_F(SslServerContextImplTicketTest, TicketKeyInlineStringFailTooSmall) {
EXPECT_THROW(loadConfigV2(cfg), EnvoyException);
}

TEST_F(SslServerContextImplTicketTest, CRLSuccess) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add a test case for invalid crl (empty file maybe?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I think an empty file is actually okay (list with 0 elements), so I added a file with invalid PEM data.

std::string json = 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",
"ca_cert_file": "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem",
"crl_file": "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.crl"
}
)EOF";

EXPECT_NO_THROW(loadConfigJson(json));
}

TEST_F(SslServerContextImplTicketTest, CRLInvalid) {
std::string json = 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",
"ca_cert_file": "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem",
"crl_file": "{{ test_rundir }}/test/common/ssl/test_data/not_a_crl.crl"
}
)EOF";

EXPECT_THROW_WITH_REGEX(loadConfigJson(json), EnvoyException,
"^Failed to load CRL from .*/not_a_crl.crl$");
}

TEST_F(SslServerContextImplTicketTest, CRLWithNoCA) {
std::string json = 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",
"crl_file": "{{ test_rundir }}/test/common/ssl/test_data/not_a_crl.crl"
}
)EOF";

EXPECT_THROW_WITH_REGEX(loadConfigJson(json), EnvoyException,
"^Failed to load CRL from .* without trusted CA certificates$");
}

} // namespace Ssl
} // namespace Envoy
31 changes: 31 additions & 0 deletions test/common/ssl/ssl_socket_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1842,6 +1842,37 @@ TEST_P(SslSocketTest, SniProtocolVersions) {
"ssl.handshake", 2, GetParam());
}

TEST_P(SslSocketTest, RevokedCertificate) {
std::string server_ctx_json = R"EOF(
{
"cert_chain_file": "{{ test_tmpdir }}/unittestcert.pem",
"private_key_file": "{{ test_tmpdir }}/unittestkey.pem",
"ca_cert_file": "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem",
"crl_file": "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.crl"
}
)EOF";

// This should fail, since the certificate has been revoked.
std::string revoked_client_ctx_json = 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"
}
)EOF";
testUtil(revoked_client_ctx_json, server_ctx_json, "", "", "", "", "", "ssl.fail_verify_error",
false, GetParam());

// This should succeed, since the cert isn't revoked.
std::string successful_client_ctx_json = R"EOF(
{
"cert_chain_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_cert2.pem",
"private_key_file": "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key2.pem"
}
)EOF";
testUtil(successful_client_ctx_json, server_ctx_json, "", "", "", "", "", "ssl.handshake", true,
GetParam());
}

class SslReadBufferLimitTest : public SslCertsTest,
public testing::WithParamInterface<Network::Address::IpVersion> {
public:
Expand Down
3 changes: 2 additions & 1 deletion test/common/ssl/test_data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
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.
private key. Additionally, we create a CRL for this CA (*ca_cert.crl*) that
revokes the certificate *san_dns_cert.pem*.
- **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.
Expand Down
16 changes: 16 additions & 0 deletions test/common/ssl/test_data/ca_cert.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,19 @@ basicConstraints = critical, CA:TRUE
keyUsage = critical, cRLSign, keyCertSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always

[ca]
default_ca = CA_default

[CA_default]
database = crl_index.txt
crlnumber = crl_number

default_days = 3650
default_crl_days = 3650
default_md = sha256
preserve = no
unique_subject = no

[crl_ext]
authorityKeyIdentifier = keyid:always,issuer:always
10 changes: 10 additions & 0 deletions test/common/ssl/test_data/ca_cert.crl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN X509 CRL-----
MIIBbDCB1gIBATANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzETMBEGA1UE
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzENMAsGA1UEChME
THlmdDEZMBcGA1UECxMQTHlmdCBFbmdpbmVlcmluZzEQMA4GA1UEAxMHVGVzdCBD
QRcNMTgwMTI0MjI1MzUxWhcNMjgwMTIyMjI1MzUxWjAcMBoCCQDzgo6yT9d50BcN
MTgwMTI0MjI1MzQ0WqAOMAwwCgYDVR0UBAMCAQAwDQYJKoZIhvcNAQELBQADgYEA
C5J09IOxdXzNEhkxgBu5uptb/l5NCZ3ajf1dYUkQsd0v7JBIx/LOz5XtluXJlet7
OCCFs4a9UmCFGJoGgSAKTJX/FckprBUTnqRBfKxqGuJ/mM0ff+dMuu75yapvBrIT
ys5oVHYIdL8rk0SyIvmx20/hhu5g5AGL35Wku2YVCR4=
-----END X509 CRL-----
9 changes: 9 additions & 0 deletions test/common/ssl/test_data/certs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,19 @@ openssl req -new -x509 -days 730 -key selfsigned_key.pem -out selfsigned_cert.pe
openssl req -new -key expired_key.pem -out expired_cert.csr -config selfsigned_cert.cfg -batch -sha256
openssl x509 -req -days -365 -in expired_cert.csr -signkey expired_key.pem -out expired_cert.pem

# Initialize information for CRL process
touch crl_index.txt crl_index.txt.attr
echo 00 > crl_number

# Revoke the certificate and generate a CRL
openssl ca -revoke san_dns_cert.pem -keyfile ca_key.pem -cert ca_cert.pem -config ca_cert.cfg
openssl ca -gencrl -keyfile ca_key.pem -cert ca_cert.pem -out ca_cert.crl -config ca_cert.cfg

# Write session ticket key files
openssl rand 80 > ticket_key_a
openssl rand 80 > ticket_key_b
openssl rand 79 > ticket_key_wrong_len

rm *csr
rm *srl
rm crl_*
3 changes: 3 additions & 0 deletions test/common/ssl/test_data/not_a_crl.crl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-----BEGIN X509 CRL-----
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you replace this with inline test?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I can do that easily since the v1 config doesn't support inline data, AFAIK. Happy to write out a temporary file during the test, perhaps?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine to replace the existing v1 test with v2 test, since that's the recommended syntax anyway...

Also, there should be v2 tests for success / invalid content (i.e. replacement for this file) / invalid file path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added success / failure cases to the v2 tests - do you want me to just remove the v1 tests in test/common/ssl/context_impl_test.cc?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you, I'm fine either way.

TOTALLY_NOT_A_CRL_HERE
-----END X509 CRL-----
84 changes: 84 additions & 0 deletions test/server/listener_manager_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1295,5 +1295,89 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, OriginalDstTestFilter) {
EXPECT_EQ("127.0.0.2:2345", socket.localAddress()->asString());
}

TEST_F(ListenerManagerImplWithRealFiltersTest, CRLFilename) {
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_cert.pem" }
private_key: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key.pem" }
validation_context:
trusted_ca: { filename: "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem" }
crl: { filename: "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.crl" }
)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, CRLInline) {
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_cert.pem" }
private_key: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key.pem" }
validation_context:
trusted_ca: { filename: "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem" }
crl: { inline_string: "-----BEGIN X509 CRL-----\nMIIBbDCB1gIBATANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzETMBEGA1UE\nCBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzENMAsGA1UEChME\nTHlmdDEZMBcGA1UECxMQTHlmdCBFbmdpbmVlcmluZzEQMA4GA1UEAxMHVGVzdCBD\nQRcNMTcxMjIwMTcxNDA4WhcNMjcxMjE4MTcxNDA4WjAcMBoCCQDZy/Qp7iAfHxcN\nMTcxMjIwMTcxMjU0WqAOMAwwCgYDVR0UBAMCAQAwDQYJKoZIhvcNAQELBQADgYEA\nOTn5Fgb44xtFd9QGtbTElZ3iwdlcOxRHjgQMd+ydzEEZRMzMgb4/NmEsgXAsxbrx\ntKmpgll8TblscitkglvGk8s4obi/OtgxNIvn+7pOBTjmrgJkcktBUDEWRbLZjsZx\nyH+5teBZ0tH0tVy914QeGitZFV8awK1hlJwlAz9g/jo=\n-----END X509 CRL-----" }
)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, InvalidCRLInline) {
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_cert.pem" }
private_key: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key.pem" }
validation_context:
trusted_ca: { filename: "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem" }
crl: { inline_string: "-----BEGIN X509 CRL-----\nTOTALLY_NOT_A_CRL_HERE\n-----END X509 CRL-----\n" }
)EOF",
Network::Address::IpVersion::v4);

EXPECT_THROW_WITH_MESSAGE(manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), true),
EnvoyException, "Failed to load CRL from <inline>");
}

TEST_F(ListenerManagerImplWithRealFiltersTest, CRLWithNoCA) {
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_cert.pem" }
private_key: { filename: "{{ test_rundir }}/test/common/ssl/test_data/san_dns_key.pem" }
validation_context:
crl: { filename: "{{ test_rundir }}/test/common/ssl/test_data/ca_cert.crl" }
)EOF",
Network::Address::IpVersion::v4);

EXPECT_THROW_WITH_REGEX(manager_->addOrUpdateListener(parseListenerFromV2Yaml(yaml), true),
EnvoyException,
"^Failed to load CRL from .* without trusted CA certificates$");
}

} // namespace Server
} // namespace Envoy