Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

quic: support cert selection by SNI, non-PEM formats #32260

Merged
merged 32 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
fd93527
quic: support multiple certs, selected by SNI
ggreenway Feb 7, 2024
c6e5291
comments and whitespace
ggreenway Feb 8, 2024
534667a
wip: try to fix integration tests
ggreenway Feb 8, 2024
1a343fa
Merge remote-tracking branch 'upstream/main' into quic-multi-cert
ggreenway Feb 8, 2024
05d5e62
fix quic handoff hotrestart test
ggreenway Feb 8, 2024
34b39f6
integration test fixes
ggreenway Feb 8, 2024
aa980d1
fix tls transport socket tests
ggreenway Feb 8, 2024
ba6799f
fix quic tests
ggreenway Feb 12, 2024
0e105cd
re-use already loaded certs
ggreenway Feb 12, 2024
e6bab00
changelog
ggreenway Feb 13, 2024
6d77bc1
fix format
ggreenway Feb 13, 2024
176791c
fix spelling
ggreenway Feb 13, 2024
5db400b
remove some unneeded stuff
ggreenway Feb 13, 2024
f9b4a25
Merge remote-tracking branch 'upstream/main' into quic-multi-cert
ggreenway Feb 13, 2024
f4ac1ae
fix another test
ggreenway Feb 13, 2024
16c8bbd
fix test
ggreenway Feb 13, 2024
e7355bb
fix compile-time-options
ggreenway Feb 13, 2024
fac9719
fix asan error
ggreenway Feb 14, 2024
4c095a1
slightly lower coverage for quic
ggreenway Feb 14, 2024
0849a2f
create chain more directly
ggreenway Feb 14, 2024
e9fe675
asan
ggreenway Feb 14, 2024
a43ec56
runtime guard
ggreenway Feb 27, 2024
5ac03b2
Merge remote-tracking branch 'upstream/main' into quic-multi-cert
ggreenway Feb 27, 2024
9b7ae24
re-add unit tests for old code to improve coverage
ggreenway Feb 28, 2024
1beac83
latch runtime value
ggreenway Feb 28, 2024
031cfa4
rename function
ggreenway Feb 28, 2024
1d0a7b7
Merge remote-tracking branch 'upstream/main' into quic-multi-cert
ggreenway Mar 1, 2024
5c1c95d
switch from assert to exception
ggreenway Mar 4, 2024
92f49f5
factor out common code; use latched runtime value
ggreenway Mar 4, 2024
53cde4d
Merge remote-tracking branch 'upstream/main' into quic-multi-cert
ggreenway Mar 4, 2024
ce2a2f8
remove conflict marker
ggreenway Mar 4, 2024
48393d1
Merge remote-tracking branch 'upstream/main' into quic-multi-cert
ggreenway Mar 5, 2024
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
4 changes: 4 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ new_features:
Added QUIC protocol option :ref:`send_disable_active_migration
<envoy_v3_api_field_config.listener.v3.QuicProtocolOptions.send_disable_active_migration>` to make the server send clients a transport
parameter to discourage client endpoints from active migration.
- area: quic
change: |
Added support for QUIC listeners to :ref:`choose certificates based on SNI <arch_overview_ssl_cert_select>` and load certificates
from formats other than PEM, such as :ref:`pkcs12 <envoy_v3_api_field_extensions.transport_sockets.tls.v3.TlsCertificate.pkcs12>`.
- area: ext_proc
change: |
implemented
Expand Down
4 changes: 2 additions & 2 deletions docs/root/intro/arch_overview/security/ssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@ See the reference for :ref:`UpstreamTlsContexts <envoy_v3_api_msg_extensions.tra
subject name, hash, etc. Other validation context configuration is typically required depending
on the deployment.

.. _arch_overview_ssl_cert_select:

Custom Certificate Validator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -110,6 +108,8 @@ For example, Envoy can be configured to verify peer certificates following the `
with multiple trust bundles in a single listener or cluster.
For more detail, please refer to :ref:`the documentation of custom_validator_config field<envoy_v3_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.custom_validator_config>`.

.. _arch_overview_ssl_cert_select:

Certificate selection
---------------------

Expand Down
9 changes: 8 additions & 1 deletion envoy/ssl/context_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
namespace Envoy {
namespace Ssl {

// Opaque type defined and used by the ``ServerContext``.
struct TlsContext;

using ContextAdditionalInitFunc =
std::function<void(Ssl::TlsContext& context, const Ssl::TlsCertificateConfig& cert)>;

/**
* Manages all of the SSL contexts in the process
*/
Expand All @@ -30,7 +36,8 @@ class ContextManager {
*/
virtual ServerContextSharedPtr
createSslServerContext(Stats::Scope& scope, const ServerContextConfig& config,
const std::vector<std::string>& server_names) PURE;
const std::vector<std::string>& server_names,
ContextAdditionalInitFunc additional_init) PURE;
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of passing in a nullable function pointer, why not just pass in a bool and initialize quic cert per string and private key in ServerContextImpl constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was trying to keep as much quic-specific code in source/common/quic is possible.


/**
* @return the number of days until the next certificate being managed will expire, the value is
Expand Down
81 changes: 18 additions & 63 deletions source/common/quic/envoy_quic_proof_source.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,67 +18,27 @@ quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain>
EnvoyQuicProofSource::GetCertChain(const quic::QuicSocketAddress& server_address,
const quic::QuicSocketAddress& client_address,
const std::string& hostname, bool* cert_matched_sni) {
// TODO(DavidSchinazi) parse the certificate to correctly fill in |cert_matched_sni|.
*cert_matched_sni = false;

CertConfigWithFilterChain res =
getTlsCertConfigAndFilterChain(server_address, client_address, hostname);
absl::optional<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> cert_config_ref =
res.cert_config_;
if (!cert_config_ref.has_value()) {
return nullptr;
}
auto& cert_config = cert_config_ref.value().get();
const std::string& chain_str = cert_config.certificateChain();
std::stringstream pem_stream(chain_str);
std::vector<std::string> chain = quic::CertificateView::LoadPemFromStream(&pem_stream);

quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> cert_chain(
new quic::ProofSource::Chain(chain));
std::string error_details;
bssl::UniquePtr<X509> cert = parseDERCertificate(cert_chain->certs[0], &error_details);
if (cert == nullptr) {
ENVOY_LOG(warn, absl::StrCat("Invalid leaf cert: ", error_details));
return nullptr;
}

bssl::UniquePtr<EVP_PKEY> pub_key(X509_get_pubkey(cert.get()));
int sign_alg = deduceSignatureAlgorithmFromPublicKey(pub_key.get(), &error_details);
if (sign_alg == 0) {
ENVOY_LOG(warn, absl::StrCat("Failed to deduce signature algorithm from public key: ",
error_details));
return nullptr;
}
return cert_chain;
CertWithFilterChain res =
Copy link
Contributor

Choose a reason for hiding this comment

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

This needs to be protected by the same RUNTIME_GUARD.

getTlsCertConfigAndFilterChain(server_address, client_address, hostname, cert_matched_sni);
return res.cert_;
}

void EnvoyQuicProofSource::signPayload(
const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address,
const std::string& hostname, uint16_t signature_algorithm, absl::string_view in,
std::unique_ptr<quic::ProofSource::SignatureCallback> callback) {
CertConfigWithFilterChain res =
getTlsCertConfigAndFilterChain(server_address, client_address, hostname);
absl::optional<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> cert_config_ref =
res.cert_config_;
if (!cert_config_ref.has_value()) {
CertWithFilterChain res = getTlsCertConfigAndFilterChain(server_address, client_address, hostname,
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

nullptr /* cert_matched_sni */);
if (res.private_key_ == nullptr) {
ENVOY_LOG(warn, "No matching filter chain found for handshake.");
callback->Run(false, "", nullptr);
return;
}
auto& cert_config = cert_config_ref.value().get();
// Load private key.
const std::string& pkey = cert_config.privateKey();
std::stringstream pem_str(pkey);
std::unique_ptr<quic::CertificatePrivateKey> pem_key =
quic::CertificatePrivateKey::LoadPemFromStream(&pem_str);
if (pem_key == nullptr) {
ENVOY_LOG(warn, "Failed to load private key.");
callback->Run(false, "", nullptr);
return;
}

// Verify the signature algorithm is as expected.
std::string error_details;
int sign_alg = deduceSignatureAlgorithmFromPublicKey(pem_key->private_key(), &error_details);
int sign_alg =
deduceSignatureAlgorithmFromPublicKey(res.private_key_->private_key(), &error_details);
if (sign_alg != signature_algorithm) {
ENVOY_LOG(warn,
fmt::format("The signature algorithm {} from the private key is not expected: {}",
Expand All @@ -88,17 +48,16 @@ void EnvoyQuicProofSource::signPayload(
}

// Sign.
std::string sig = pem_key->Sign(in, signature_algorithm);
std::string sig = res.private_key_->Sign(in, signature_algorithm);
bool success = !sig.empty();
ASSERT(res.filter_chain_.has_value());
callback->Run(success, sig,
std::make_unique<EnvoyQuicProofSourceDetails>(res.filter_chain_.value().get()));
}

EnvoyQuicProofSource::CertConfigWithFilterChain
EnvoyQuicProofSource::getTlsCertConfigAndFilterChain(const quic::QuicSocketAddress& server_address,
const quic::QuicSocketAddress& client_address,
const std::string& hostname) {
EnvoyQuicProofSource::CertWithFilterChain EnvoyQuicProofSource::getTlsCertConfigAndFilterChain(
const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address,
const std::string& hostname, bool* cert_matched_sni) {
ENVOY_LOG(trace, "Getting cert chain for {}", hostname);
// TODO(danzh) modify QUICHE to make quic session or ALPN accessible to avoid hard-coded ALPN.
Network::ConnectionSocketPtr connection_socket = createServerConnectionSocket(
Expand All @@ -111,23 +70,19 @@ EnvoyQuicProofSource::getTlsCertConfigAndFilterChain(const quic::QuicSocketAddre
if (filter_chain == nullptr) {
listener_stats_.no_filter_chain_match_.inc();
ENVOY_LOG(warn, "No matching filter chain found for handshake.");
return {absl::nullopt, absl::nullopt};
return {};
}
ENVOY_LOG(trace, "Got a matching cert chain {}", filter_chain->name());

auto& transport_socket_factory =
dynamic_cast<const QuicServerTransportSocketFactory&>(filter_chain->transportSocketFactory());
Copy link
Contributor

Choose a reason for hiding this comment

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

If you split this part out, you should be able to use a bool in QuicServerTransportSocketFactory to guard the new behaviors both in this class and in QuicServerTransportSocketFactory.


std::vector<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> tls_cert_configs =
transport_socket_factory.getTlsCertificates();
if (tls_cert_configs.empty()) {
auto [cert, key] = transport_socket_factory.getTlsCertificateAndKey(hostname, cert_matched_sni);
if (cert == nullptr || key == nullptr) {
ENVOY_LOG(warn, "No certificate is configured in transport socket config.");
return {absl::nullopt, absl::nullopt};
return {};
}
// Only return the first TLS cert config.
// TODO(danzh) Choose based on supported cipher suites in TLS1.3 CHLO and prefer EC
// certs if supported.
return {tls_cert_configs[0].get(), *filter_chain};
return {std::move(cert), std::move(key), *filter_chain};
}

void EnvoyQuicProofSource::updateFilterChainManager(
Expand Down
13 changes: 7 additions & 6 deletions source/common/quic/envoy_quic_proof_source.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@ class EnvoyQuicProofSource : public EnvoyQuicProofSourceBase {
std::unique_ptr<quic::ProofSource::SignatureCallback> callback) override;

private:
struct CertConfigWithFilterChain {
absl::optional<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> cert_config_;
struct CertWithFilterChain {
quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> cert_;
std::shared_ptr<quic::CertificatePrivateKey> private_key_;
absl::optional<std::reference_wrapper<const Network::FilterChain>> filter_chain_;
};

CertConfigWithFilterChain
getTlsCertConfigAndFilterChain(const quic::QuicSocketAddress& server_address,
const quic::QuicSocketAddress& client_address,
const std::string& hostname);
CertWithFilterChain getTlsCertConfigAndFilterChain(const quic::QuicSocketAddress& server_address,
ggreenway marked this conversation as resolved.
Show resolved Hide resolved
const quic::QuicSocketAddress& client_address,
const std::string& hostname,
bool* cert_matched_sni);

Network::Socket& listen_socket_;
Network::FilterChainManager* filter_chain_manager_{nullptr};
Expand Down
111 changes: 109 additions & 2 deletions source/common/quic/quic_server_transport_socket_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "envoy/extensions/transport_sockets/quic/v3/quic_transport.pb.validate.h"

#include "source/common/quic/envoy_quic_utils.h"
#include "source/common/runtime/runtime_features.h"
#include "source/extensions/transport_sockets/tls/context_config_impl.h"

Expand All @@ -13,7 +14,7 @@ namespace Quic {
Network::DownstreamTransportSocketFactoryPtr
QuicServerTransportSocketConfigFactory::createTransportSocketFactory(
const Protobuf::Message& config, Server::Configuration::TransportSocketFactoryContext& context,
const std::vector<std::string>& /*server_names*/) {
const std::vector<std::string>& server_names) {
auto quic_transport = MessageUtil::downcastAndValidate<
const envoy::extensions::transport_sockets::quic::v3::QuicDownstreamTransport&>(
config, context.messageValidationVisitor());
Expand All @@ -26,11 +27,77 @@ QuicServerTransportSocketConfigFactory::createTransportSocketFactory(

auto factory = std::make_unique<QuicServerTransportSocketFactory>(
PROTOBUF_GET_WRAPPED_OR_DEFAULT(quic_transport, enable_early_data, true),
context.statsScope(), std::move(server_config));
context.statsScope(), std::move(server_config), context.sslContextManager(), server_names);
factory->initialize();
return factory;
}

namespace {
void initializeQuicCertAndKey(Ssl::TlsContext& context,
const Ssl::TlsCertificateConfig& /*cert_config*/) {
// Convert the certificate chain loaded into the context into PEM, as that is what the QUICHE
// API expects. By using the version already loaded, instead of loading it from the source,
// we can reuse all the code that loads from different formats, allows using passwords on the key,
// etc.
std::string certs_str;
auto process_one_cert = [&](X509* cert) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Would it make sense to just make this function in the anonymous namespace?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I prefer having it in the function that uses it to make it clear the scope in which it's used, and it can capture a variable instead of needing a parameter. But it's just a small style preference. I'll change it if you insist.

bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
int result = PEM_write_bio_X509(bio.get(), cert);
ASSERT(result == 1);
BUF_MEM* buf_mem = nullptr;
result = BIO_get_mem_ptr(bio.get(), &buf_mem);
certs_str.append(buf_mem->data, buf_mem->length);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you directly populate a std::vector<std::string> instead of concatenating the pem string here and then calling CertificateView::LoadPemFromStream() to split them apart?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I took at stab at this in latest commit; PTAL and let me know if this is what you had in mind.

My understanding is that each string in this vector should be a pem-encoded (base64) string of a cert, without newlines or the begin/end block. Is there a boringssl API to get that directly? I didn't find a more direct way than what's in my latest commit.

};

process_one_cert(SSL_CTX_get0_certificate(context.ssl_ctx_.get()));

STACK_OF(X509)* chain_stack = nullptr;
int result = SSL_CTX_get0_chain_certs(context.ssl_ctx_.get(), &chain_stack);
ASSERT(result == 1);
for (size_t i = 0; i < sk_X509_num(chain_stack); i++) {
process_one_cert(sk_X509_value(chain_stack, i));
}

std::istringstream pem_stream(certs_str);
std::vector<std::string> chain = quic::CertificateView::LoadPemFromStream(&pem_stream);
quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> cert_chain(
new quic::ProofSource::Chain(chain));

std::string error_details;
bssl::UniquePtr<EVP_PKEY> pub_key(X509_get_pubkey(context.cert_chain_.get()));
int sign_alg = deduceSignatureAlgorithmFromPublicKey(pub_key.get(), &error_details);
if (sign_alg == 0) {
throwEnvoyExceptionOrPanic(
absl::StrCat("Failed to deduce signature algorithm from public key: ", error_details));
}

context.quic_cert_ = std::move(cert_chain);

bssl::UniquePtr<EVP_PKEY> privateKey(
bssl::UpRef(SSL_CTX_get0_privatekey(context.ssl_ctx_.get())));
std::unique_ptr<quic::CertificatePrivateKey> pem_key =
std::make_unique<quic::CertificatePrivateKey>(std::move(privateKey));
if (pem_key == nullptr) {
throwEnvoyExceptionOrPanic("Failed to load QUIC private key.");
}

context.quic_private_key_ = std::move(pem_key);
}
} // namespace

QuicServerTransportSocketFactory::QuicServerTransportSocketFactory(
bool enable_early_data, Stats::Scope& scope, Ssl::ServerContextConfigPtr config,
Envoy::Ssl::ContextManager& manager, const std::vector<std::string>& server_names)
: QuicTransportSocketFactoryBase(scope, "server"), manager_(manager), stats_scope_(scope),
config_(std::move(config)), server_names_(server_names),
ssl_ctx_(manager_.createSslServerContext(stats_scope_, *config_, server_names_,
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we need a RUNTIME_GUARD to protect all the interaction with ssl_ctx_ in this class and keep the old interface till the RUNTIME_GUARD gets deprecated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@danzh2010 This is going to be difficult to runtime-guard, due to the changes across a few different files/classes.

Are you concerned about behavior changes (related to which cert is selected), or bugs? If it's bugs, is there additional test coverage we could add to alleviate concern?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm more concerned about bugs. I think you can use a bool in this class to latch the value of a RUNTIME_GUARD and use it to guard both this class and the proof source. Please see my other comment.

initializeQuicCertAndKey)),
enable_early_data_(enable_early_data) {}

QuicServerTransportSocketFactory::~QuicServerTransportSocketFactory() {
manager_.removeContext(ssl_ctx_);
}

ProtobufTypes::MessagePtr QuicServerTransportSocketConfigFactory::createEmptyConfigProto() {
return std::make_unique<
envoy::extensions::transport_sockets::quic::v3::QuicDownstreamTransport>();
Expand All @@ -46,6 +113,46 @@ void QuicServerTransportSocketFactory::initialize() {
}
}

std::pair<quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain>,
std::shared_ptr<quic::CertificatePrivateKey>>
QuicServerTransportSocketFactory::getTlsCertificateAndKey(absl::string_view sni,
bool* cert_matched_sni) const {
// onSecretUpdated() could be invoked in the middle of checking the existence of , and using,
// ssl_ctx. Capture ssl_ctx_ into a local variable so that we check and use the same ssl_ctx.
Envoy::Ssl::ServerContextSharedPtr ssl_ctx;
{
absl::ReaderMutexLock l(&ssl_ctx_mu_);
ssl_ctx = ssl_ctx_;
}
if (!ssl_ctx) {
ENVOY_LOG(warn, "SDS hasn't finished updating Ssl context config yet.");
stats_.downstream_context_secrets_not_ready_.inc();
return {};
}
auto ctx =
std::dynamic_pointer_cast<Extensions::TransportSockets::Tls::ServerContextImpl>(ssl_ctx);
auto [tls_context, ocsp_staple_action] = ctx->findTlsContext(
sni, true /* TODO: ecdsa_capable */, false /* TODO: ocsp_capable */, cert_matched_sni);
ggreenway marked this conversation as resolved.
Show resolved Hide resolved

// Thread safety note: accessing the tls_context requires holding a shared_ptr to the ``ssl_ctx``.
// Both of these members are themselves reference counted, so it is safe to use them after
// ``ssl_ctx`` goes out of scope after the function returns.
return {tls_context.quic_cert_, tls_context.quic_private_key_};
}

void QuicServerTransportSocketFactory::onSecretUpdated() {
ENVOY_LOG(debug, "Secret is updated.");
auto ctx = manager_.createSslServerContext(stats_scope_, *config_, server_names_,
initializeQuicCertAndKey);
{
absl::WriterMutexLock l(&ssl_ctx_mu_);
std::swap(ctx, ssl_ctx_);
}
manager_.removeContext(ctx);

stats_.context_config_update_by_sds_.inc();
}

REGISTER_FACTORY(QuicServerTransportSocketConfigFactory,
Server::Configuration::DownstreamTransportSocketConfigFactory);

Expand Down
27 changes: 13 additions & 14 deletions source/common/quic/quic_server_transport_socket_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ class QuicServerTransportSocketFactory : public Network::DownstreamTransportSock
public QuicTransportSocketFactoryBase {
public:
QuicServerTransportSocketFactory(bool enable_early_data, Stats::Scope& store,
Ssl::ServerContextConfigPtr config)
: QuicTransportSocketFactoryBase(store, "server"), config_(std::move(config)),
enable_early_data_(enable_early_data) {}
Ssl::ServerContextConfigPtr config,
Envoy::Ssl::ContextManager& manager,
const std::vector<std::string>& server_names);
~QuicServerTransportSocketFactory() override;

// Network::DownstreamTransportSocketFactory
Network::TransportSocketPtr createDownstreamTransportSocket() const override {
Expand All @@ -31,24 +32,22 @@ class QuicServerTransportSocketFactory : public Network::DownstreamTransportSock

void initialize() override;

// Return TLS certificates if the context config is ready.
std::vector<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>>
getTlsCertificates() const {
if (!config_->isReady()) {
ENVOY_LOG(warn, "SDS hasn't finished updating Ssl context config yet.");
stats_.downstream_context_secrets_not_ready_.inc();
return {};
}
return config_->tlsCertificates();
}
std::pair<quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain>,
std::shared_ptr<quic::CertificatePrivateKey>>
getTlsCertificateAndKey(absl::string_view sni, bool* cert_matched_sni) const;

bool earlyDataEnabled() const { return enable_early_data_; }

protected:
void onSecretUpdated() override { stats_.context_config_update_by_sds_.inc(); }
void onSecretUpdated() override;

private:
Envoy::Ssl::ContextManager& manager_;
Stats::Scope& stats_scope_;
Ssl::ServerContextConfigPtr config_;
const std::vector<std::string> server_names_;
mutable absl::Mutex ssl_ctx_mu_;
Envoy::Ssl::ServerContextSharedPtr ssl_ctx_ ABSL_GUARDED_BY(ssl_ctx_mu_);
bool enable_early_data_;
};

Expand Down
Loading
Loading