Skip to content

Commit

Permalink
tls: add disable_stateful_session_resumption option (envoyproxy#29639)
Browse files Browse the repository at this point in the history
Signed-off-by: Kenneth Jenkins <[email protected]>
  • Loading branch information
kenjenkins authored Sep 18, 2023
1 parent 6b0d8f8 commit 62c9de7
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 11 deletions.
6 changes: 5 additions & 1 deletion api/envoy/extensions/transport_sockets/tls/v3/tls.proto
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ message UpstreamTlsContext {
google.protobuf.BoolValue enforce_rsa_key_usage = 5;
}

// [#next-free-field: 10]
// [#next-free-field: 11]
message DownstreamTlsContext {
option (udpa.annotations.versioning).previous_message_type =
"envoy.api.v2.auth.DownstreamTlsContext";
Expand Down Expand Up @@ -119,6 +119,10 @@ message DownstreamTlsContext {
bool disable_stateless_session_resumption = 7;
}

// If set to true, the TLS server will not maintain a session cache of TLS sessions. (This is
// relevant only for TLSv1.2 and earlier.)
bool disable_stateful_session_resumption = 10;

// If specified, ``session_timeout`` will change the maximum lifetime (in seconds) of the TLS session.
// Currently this value is used as a hint for the `TLS session ticket lifetime (for TLSv1.2) <https://tools.ietf.org/html/rfc5077#section-5.6>`_.
// Only seconds can be specified (fractional seconds are ignored).
Expand Down
5 changes: 5 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ new_features:
change: |
added :ref:`custom_sink <envoy_v3_api_field_config.tap.v3.OutputSink.custom_sink>` type to enable writing tap data
out to a custom sink extension.
- area: tls
change: |
added :ref:`disable_stateful_session_resumption
<envoy_v3_api_field_extensions.transport_sockets.tls.v3.DownstreamTlsContext.disable_stateful_session_resumption>` config option to
disable stateful TLS session resumption.
- area: udp_proxy
change: |
added :ref:`session_filters <envoy_v3_api_field_extensions.filters.udp.udp_proxy.v3.UdpProxyConfig.session_filters>` config to
Expand Down
5 changes: 5 additions & 0 deletions envoy/ssl/context_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ class ServerContextConfig : public virtual ContextConfig {
*/
virtual bool disableStatelessSessionResumption() const PURE;

/**
* @return True if stateful TLS session resumption is disabled, false otherwise.
*/
virtual bool disableStatefulSessionResumption() const PURE;

/**
* @return True if we allow full scan certificates when there is no cert matching SNI during
* downstream TLS handshake, false otherwise.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ ServerContextConfigImpl::ServerContextConfigImpl(
ocsp_staple_policy_(ocspStaplePolicyFromProto(config.ocsp_staple_policy())),
session_ticket_keys_provider_(getTlsSessionTicketKeysConfigProvider(factory_context, config)),
disable_stateless_session_resumption_(getStatelessSessionResumptionDisabled(config)),
disable_stateful_session_resumption_(config.disable_stateful_session_resumption()),
full_scan_certs_on_sni_mismatch_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
config, full_scan_certs_on_sni_mismatch,
!Runtime::runtimeFeatureEnabled(
Expand Down
4 changes: 4 additions & 0 deletions source/extensions/transport_sockets/tls/context_config_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ class ServerContextConfigImpl : public ContextConfigImpl, public Envoy::Ssl::Ser
bool disableStatelessSessionResumption() const override {
return disable_stateless_session_resumption_;
}
bool disableStatefulSessionResumption() const override {
return disable_stateful_session_resumption_;
}

bool fullScanCertsOnSNIMismatch() const override { return full_scan_certs_on_sni_mismatch_; }

Expand All @@ -190,6 +193,7 @@ class ServerContextConfigImpl : public ContextConfigImpl, public Envoy::Ssl::Ser

absl::optional<std::chrono::seconds> session_timeout_;
const bool disable_stateless_session_resumption_;
const bool disable_stateful_session_resumption_;
bool full_scan_certs_on_sni_mismatch_;
};

Expand Down
4 changes: 4 additions & 0 deletions source/extensions/transport_sockets/tls/context_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,10 @@ ServerContextImpl::ServerContextImpl(Stats::Scope& scope,
});
}

if (config.disableStatefulSessionResumption()) {
SSL_CTX_set_session_cache_mode(ctx.ssl_ctx_.get(), SSL_SESS_CACHE_OFF);
}

if (config.sessionTimeout() && !config.capabilities().handles_session_resumption) {
auto timeout = config.sessionTimeout().value().count();
SSL_CTX_set_timeout(ctx.ssl_ctx_.get(), uint32_t(timeout));
Expand Down
64 changes: 54 additions & 10 deletions test/extensions/transport_sockets/tls/ssl_socket_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3618,10 +3618,10 @@ void testTicketSessionResumption(const std::string& server_ctx_yaml1,
EXPECT_EQ(expect_reuse ? 1UL : 0UL, client_stats_store.counter("ssl.session_reused").value());
}

void testSupportForStatelessSessionResumption(const std::string& server_ctx_yaml,
const std::string& client_ctx_yaml,
bool expect_support,
const Network::Address::IpVersion ip_version) {
void testSupportForSessionResumption(const std::string& server_ctx_yaml,
const std::string& client_ctx_yaml, bool expect_stateless,
bool expect_stateful,
const Network::Address::IpVersion ip_version) {
Event::SimulatedTimeSystem time_system;
ContextManagerImpl manager(*time_system);

Expand Down Expand Up @@ -3681,11 +3681,17 @@ void testSupportForStatelessSessionResumption(const std::string& server_ctx_yaml
dynamic_cast<const SslHandshakerImpl*>(server_connection->ssl().get());
SSL* server_ssl_socket = ssl_socket->ssl();
SSL_CTX* server_ssl_context = SSL_get_SSL_CTX(server_ssl_socket);
if (expect_support) {
if (expect_stateless) {
EXPECT_EQ(0, (SSL_CTX_get_options(server_ssl_context) & SSL_OP_NO_TICKET));
} else {
EXPECT_EQ(SSL_OP_NO_TICKET, (SSL_CTX_get_options(server_ssl_context) & SSL_OP_NO_TICKET));
}
if (expect_stateful) {
EXPECT_EQ(SSL_SESS_CACHE_SERVER,
(SSL_CTX_get_session_cache_mode(server_ssl_context) & SSL_SESS_CACHE_SERVER));
} else {
EXPECT_EQ(SSL_SESS_CACHE_OFF, SSL_CTX_get_session_cache_mode(server_ssl_context));
}
}));
EXPECT_CALL(callbacks, recordConnectionsAcceptedOnSocketEvent(_));

Expand Down Expand Up @@ -4144,6 +4150,25 @@ TEST_P(SslSocketTest, TicketSessionResumptionDifferentServerCertDifferentSAN) {
version_);
}

TEST_P(SslSocketTest, SessionResumptionDisabled) {
const std::string server_ctx_yaml = R"EOF(
common_tls_context:
tls_certificates:
certificate_chain:
filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_cert.pem"
private_key:
filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_key.pem"
disable_stateless_session_resumption: true
disable_stateful_session_resumption: true
)EOF";

const std::string client_ctx_yaml = R"EOF(
common_tls_context:
)EOF";

testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, false, false, version_);
}

TEST_P(SslSocketTest, StatelessSessionResumptionDisabled) {
const std::string server_ctx_yaml = R"EOF(
common_tls_context:
Expand All @@ -4159,10 +4184,28 @@ TEST_P(SslSocketTest, StatelessSessionResumptionDisabled) {
common_tls_context:
)EOF";

testSupportForStatelessSessionResumption(server_ctx_yaml, client_ctx_yaml, false, version_);
testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, false, true, version_);
}

TEST_P(SslSocketTest, StatefulSessionResumptionDisabled) {
const std::string server_ctx_yaml = R"EOF(
common_tls_context:
tls_certificates:
certificate_chain:
filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_cert.pem"
private_key:
filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_key.pem"
disable_stateful_session_resumption: true
)EOF";

const std::string client_ctx_yaml = R"EOF(
common_tls_context:
)EOF";

testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, true, false, version_);
}

TEST_P(SslSocketTest, SatelessSessionResumptionEnabledExplicitly) {
TEST_P(SslSocketTest, SessionResumptionEnabledExplicitly) {
const std::string server_ctx_yaml = R"EOF(
common_tls_context:
tls_certificates:
Expand All @@ -4171,16 +4214,17 @@ TEST_P(SslSocketTest, SatelessSessionResumptionEnabledExplicitly) {
private_key:
filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/unittest_key.pem"
disable_stateless_session_resumption: false
disable_stateful_session_resumption: false
)EOF";

const std::string client_ctx_yaml = R"EOF(
common_tls_context:
)EOF";

testSupportForStatelessSessionResumption(server_ctx_yaml, client_ctx_yaml, true, version_);
testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, true, true, version_);
}

TEST_P(SslSocketTest, StatelessSessionResumptionEnabledByDefault) {
TEST_P(SslSocketTest, SessionResumptionEnabledByDefault) {
const std::string server_ctx_yaml = R"EOF(
common_tls_context:
tls_certificates:
Expand All @@ -4194,7 +4238,7 @@ TEST_P(SslSocketTest, StatelessSessionResumptionEnabledByDefault) {
common_tls_context:
)EOF";

testSupportForStatelessSessionResumption(server_ctx_yaml, client_ctx_yaml, true, version_);
testSupportForSessionResumption(server_ctx_yaml, client_ctx_yaml, true, true, version_);
}

// Test that if two listeners use the same cert and session ticket key, but
Expand Down
1 change: 1 addition & 0 deletions test/mocks/ssl/mocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class MockServerContextConfig : public ServerContextConfig {
MOCK_METHOD(OcspStaplePolicy, ocspStaplePolicy, (), (const));
MOCK_METHOD(const std::vector<SessionTicketKey>&, sessionTicketKeys, (), (const));
MOCK_METHOD(bool, disableStatelessSessionResumption, (), (const));
MOCK_METHOD(bool, disableStatefulSessionResumption, (), (const));
MOCK_METHOD(const Network::Address::IpList&, tlsKeyLogLocal, (), (const));
MOCK_METHOD(const Network::Address::IpList&, tlsKeyLogRemote, (), (const));
MOCK_METHOD(const std::string&, tlsKeyLogPath, (), (const));
Expand Down

0 comments on commit 62c9de7

Please sign in to comment.