diff --git a/bazel/external/quiche.BUILD b/bazel/external/quiche.BUILD index 807089028873c..7b7146a0adbcf 100644 --- a/bazel/external/quiche.BUILD +++ b/bazel/external/quiche.BUILD @@ -2003,6 +2003,7 @@ envoy_cc_library( "quiche/quic/core/crypto/curve25519_key_exchange.cc", "quiche/quic/core/crypto/key_exchange.cc", "quiche/quic/core/crypto/p256_key_exchange.cc", + "quiche/quic/core/crypto/quic_client_session_cache.cc", "quiche/quic/core/crypto/quic_compressed_certs_cache.cc", "quiche/quic/core/crypto/quic_crypto_client_config.cc", "quiche/quic/core/crypto/quic_crypto_server_config.cc", @@ -2023,6 +2024,7 @@ envoy_cc_library( "quiche/quic/core/crypto/key_exchange.h", "quiche/quic/core/crypto/p256_key_exchange.h", "quiche/quic/core/crypto/proof_verifier.h", + "quiche/quic/core/crypto/quic_client_session_cache.h", "quiche/quic/core/crypto/quic_compressed_certs_cache.h", "quiche/quic/core/crypto/quic_crypto_client_config.h", "quiche/quic/core/crypto/quic_crypto_server_config.h", diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 89485043ef4e4..1279bc5d24e64 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -838,12 +838,12 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "QUICHE", project_desc = "QUICHE (QUIC, HTTP/2, Etc) is Google‘s implementation of QUIC and related protocols", project_url = "https://github.com/google/quiche", - version = "81314ecbd8cfd3c8399fcd1c1e7ca557b41d18de", - sha256 = "61e28bf91daba19f65af53b19fbefd5876b3365835e7c0091ccf0c91dba72ba6", + version = "c2ddf95dc2380e1d7cd5aa8fe9f61b4e01b23e6b", + sha256 = "435dc3c3858d8328c48fb633bc46431aa5aea2a29e0b5f125f743b0b5b5c1513", urls = ["https://github.com/google/quiche/archive/{version}.tar.gz"], strip_prefix = "quiche-{version}", use_category = ["dataplane_core"], - release_date = "2021-11-17", + release_date = "2021-11-22", cpe = "N/A", ), com_googlesource_googleurl = dict( diff --git a/source/common/quic/BUILD b/source/common/quic/BUILD index a651426c188b2..bab6a0c97cde2 100644 --- a/source/common/quic/BUILD +++ b/source/common/quic/BUILD @@ -124,17 +124,6 @@ envoy_cc_library( ], ) -envoy_cc_library( - name = "envoy_quic_session_cache_lib", - srcs = ["envoy_quic_session_cache.cc"], - hdrs = ["envoy_quic_session_cache.h"], - external_deps = ["quiche_quic_platform"], - tags = ["nofips"], - deps = [ - "@com_github_google_quiche//:quic_core_crypto_crypto_handshake_lib", - ], -) - envoy_cc_library( name = "spdy_server_push_utils_for_envoy_lib", srcs = ["spdy_server_push_utils_for_envoy.cc"], @@ -173,7 +162,6 @@ envoy_cc_library( ":envoy_quic_connection_helper_lib", ":envoy_quic_proof_verifier_lib", ":envoy_quic_server_session_lib", - ":envoy_quic_session_cache_lib", ":envoy_quic_utils_lib", "//envoy/http:codec_interface", "//envoy/registry", diff --git a/source/common/quic/client_connection_factory_impl.cc b/source/common/quic/client_connection_factory_impl.cc index 42a57d4c66f82..c6465aca4453f 100644 --- a/source/common/quic/client_connection_factory_impl.cc +++ b/source/common/quic/client_connection_factory_impl.cc @@ -1,8 +1,9 @@ #include "source/common/quic/client_connection_factory_impl.h" -#include "source/common/quic/envoy_quic_session_cache.h" #include "source/common/quic/quic_transport_socket_factory.h" +#include "quiche/quic/core/crypto/quic_client_session_cache.h" + namespace Envoy { namespace Quic { @@ -34,7 +35,7 @@ std::shared_ptr PersistentQuicInfoImpl::cryptoConf client_context_ = context; client_config_ = std::make_shared( std::make_unique(getContext(transport_socket_factory_)), - std::make_unique((time_source_))); + std::make_unique()); } // Return the latest client config. return client_config_; diff --git a/source/common/quic/envoy_quic_session_cache.cc b/source/common/quic/envoy_quic_session_cache.cc deleted file mode 100644 index b6ce80f7717c6..0000000000000 --- a/source/common/quic/envoy_quic_session_cache.cc +++ /dev/null @@ -1,171 +0,0 @@ -#include "source/common/quic/envoy_quic_session_cache.h" - -namespace Envoy { -namespace Quic { -namespace { - -// This value was chosen arbitrarily. We can make this configurable if needed. -// TODO(14829) ensure this is tested and scaled for upstream. -constexpr size_t MaxSessionCacheEntries = 1024; - -// Returns false if the SSL session doesn't exist or it is expired. -bool isSessionValid(SSL_SESSION* session, SystemTime now) { - if (session == nullptr) { - return false; - } - const time_t now_time_t = std::chrono::system_clock::to_time_t(now); - if (now_time_t < 0) { - return false; - } - const uint64_t now_u64 = static_cast(now_time_t); - const uint64_t session_time = SSL_SESSION_get_time(session); - const uint64_t session_expiration = session_time + SSL_SESSION_get_timeout(session); - // now_u64 may be slightly behind because of differences in how time is calculated at this layer - // versus BoringSSL. Add a second of wiggle room to account for this. - return session_time <= now_u64 + 1 && now_u64 < session_expiration; -} - -bool doApplicationStatesMatch(const quic::ApplicationState* state, - const quic::ApplicationState* other) { - if (state == other) { - return true; - } - if ((state != nullptr && other == nullptr) || (state == nullptr && other != nullptr)) { - return false; - } - return (*state == *other); -} - -} // namespace - -EnvoyQuicSessionCache::EnvoyQuicSessionCache(TimeSource& time_source) : time_source_(time_source) {} - -EnvoyQuicSessionCache::~EnvoyQuicSessionCache() = default; - -void EnvoyQuicSessionCache::Insert(const quic::QuicServerId& server_id, - bssl::UniquePtr session, - const quic::TransportParameters& params, - const quic::ApplicationState* application_state) { - auto it = cache_.find(server_id); - if (it == cache_.end()) { - // New server ID, add a new entry. - createAndInsertEntry(server_id, std::move(session), params, application_state); - return; - } - Entry& entry = it->second; - if (params == *entry.params && - doApplicationStatesMatch(application_state, entry.application_state.get())) { - // The states are both the same, so we only need to insert the session. - entry.pushSession(std::move(session)); - return; - } - // States are different, replace the entry. - cache_.erase(it); - createAndInsertEntry(server_id, std::move(session), params, application_state); -} - -std::unique_ptr -EnvoyQuicSessionCache::Lookup(const quic::QuicServerId& server_id, const SSL_CTX* /*ctx*/) { - auto it = cache_.find(server_id); - if (it == cache_.end()) { - return nullptr; - } - Entry& entry = it->second; - const SystemTime system_time = time_source_.systemTime(); - if (!isSessionValid(entry.peekSession(), system_time)) { - cache_.erase(it); - return nullptr; - } - auto state = std::make_unique(); - state->tls_session = entry.popSession(); - if (entry.params != nullptr) { - state->transport_params = std::make_unique(*entry.params); - } - if (entry.application_state != nullptr) { - state->application_state = std::make_unique(*entry.application_state); - } - return state; -} - -void EnvoyQuicSessionCache::ClearEarlyData(const quic::QuicServerId& server_id) { - auto it = cache_.find(server_id); - if (it == cache_.end()) { - return; - } - for (bssl::UniquePtr& session : it->second.sessions) { - if (session != nullptr) { - session.reset(SSL_SESSION_copy_without_early_data(session.get())); - } - } -} - -void EnvoyQuicSessionCache::prune() { - quic::QuicServerId oldest_id; - uint64_t oldest_expiration = std::numeric_limits::max(); - const SystemTime system_time = time_source_.systemTime(); - auto it = cache_.begin(); - while (it != cache_.end()) { - Entry& entry = it->second; - SSL_SESSION* session = entry.peekSession(); - if (!isSessionValid(session, system_time)) { - it = cache_.erase(it); - } else { - if (cache_.size() >= MaxSessionCacheEntries) { - // Only track the oldest session if we are at the size limit. - const uint64_t session_expiration = - SSL_SESSION_get_time(session) + SSL_SESSION_get_timeout(session); - if (session_expiration < oldest_expiration) { - oldest_expiration = session_expiration; - oldest_id = it->first; - } - } - ++it; - } - } - if (cache_.size() >= MaxSessionCacheEntries) { - cache_.erase(oldest_id); - } -} - -void EnvoyQuicSessionCache::createAndInsertEntry(const quic::QuicServerId& server_id, - bssl::UniquePtr session, - const quic::TransportParameters& params, - const quic::ApplicationState* application_state) { - prune(); - ASSERT(cache_.size() < MaxSessionCacheEntries); - Entry entry; - entry.pushSession(std::move(session)); - entry.params = std::make_unique(params); - if (application_state != nullptr) { - entry.application_state = std::make_unique(*application_state); - } - cache_.insert(std::make_pair(server_id, std::move(entry))); -} - -size_t EnvoyQuicSessionCache::size() const { return cache_.size(); } - -EnvoyQuicSessionCache::Entry::Entry() = default; -EnvoyQuicSessionCache::Entry::Entry(Entry&&) noexcept = default; -EnvoyQuicSessionCache::Entry::~Entry() = default; - -void EnvoyQuicSessionCache::Entry::pushSession(bssl::UniquePtr session) { - if (sessions[0] != nullptr) { - sessions[1] = std::move(sessions[0]); - } - sessions[0] = std::move(session); -} - -bssl::UniquePtr EnvoyQuicSessionCache::Entry::popSession() { - if (sessions[0] == nullptr) { - return nullptr; - } - bssl::UniquePtr session = std::move(sessions[0]); - sessions[0] = std::move(sessions[1]); - sessions[1] = nullptr; - return session; -} - -SSL_SESSION* EnvoyQuicSessionCache::Entry::peekSession() { return sessions[0].get(); } - -} // namespace Quic -} // namespace Envoy diff --git a/source/common/quic/envoy_quic_session_cache.h b/source/common/quic/envoy_quic_session_cache.h deleted file mode 100644 index c15fe0d0e658e..0000000000000 --- a/source/common/quic/envoy_quic_session_cache.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "envoy/common/time.h" - -#include "quiche/quic/core/crypto/quic_crypto_client_config.h" - -namespace Envoy { -namespace Quic { - -// Implementation of quic::SessionCache using an Envoy time source. -class EnvoyQuicSessionCache : public quic::SessionCache { -public: - explicit EnvoyQuicSessionCache(TimeSource& time_source); - ~EnvoyQuicSessionCache() override; - - // From quic::SessionCache. - void Insert(const quic::QuicServerId& server_id, bssl::UniquePtr session, - const quic::TransportParameters& params, - const quic::ApplicationState* application_state) override; - std::unique_ptr Lookup(const quic::QuicServerId& server_id, - const SSL_CTX* ctx) override; - void ClearEarlyData(const quic::QuicServerId& server_id) override; - - // Returns number of entries in the cache. - size_t size() const; - -private: - struct Entry { - Entry(); - Entry(Entry&&) noexcept; - ~Entry(); - - // Adds a new session onto sessions, dropping the oldest one if two are - // already stored. - void pushSession(bssl::UniquePtr session); - - // Retrieves and removes the latest session from the entry. - bssl::UniquePtr popSession(); - - SSL_SESSION* peekSession(); - - // We only save the last two sessions per server as that is sufficient in practice. This is - // because we only need one to create a new connection, and that new connection should send - // us another ticket. We keep two instead of one in case that connection attempt fails. - bssl::UniquePtr sessions[2]; - std::unique_ptr params; - std::unique_ptr application_state; - }; - - // Remove all entries that are no longer valid. If all entries were valid but the cache is at its - // size limit, instead remove the oldest entry. This walks the entire list of entries. - void prune(); - - // Creates a new entry and insert into cache_. This walks the entire list of entries. - void createAndInsertEntry(const quic::QuicServerId& server_id, - bssl::UniquePtr session, - const quic::TransportParameters& params, - const quic::ApplicationState* application_state); - - std::map cache_; - TimeSource& time_source_; -}; - -} // namespace Quic -} // namespace Envoy diff --git a/test/common/quic/BUILD b/test/common/quic/BUILD index 604eaf1cd8f24..f549b51982aec 100644 --- a/test/common/quic/BUILD +++ b/test/common/quic/BUILD @@ -80,16 +80,6 @@ envoy_cc_test( ], ) -envoy_cc_test( - name = "envoy_quic_session_cache_test", - srcs = ["envoy_quic_session_cache_test.cc"], - external_deps = ["quiche_quic_platform"], - tags = ["nofips"], - deps = [ - "//source/common/quic:envoy_quic_session_cache_lib", - ], -) - envoy_cc_test( name = "envoy_quic_proof_verifier_test", srcs = ["envoy_quic_proof_verifier_test.cc"], diff --git a/test/common/quic/envoy_quic_session_cache_test.cc b/test/common/quic/envoy_quic_session_cache_test.cc deleted file mode 100644 index c7601331597fb..0000000000000 --- a/test/common/quic/envoy_quic_session_cache_test.cc +++ /dev/null @@ -1,343 +0,0 @@ -#include "source/common/quic/envoy_quic_session_cache.h" - -#include "absl/strings/escaping.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace Envoy { -namespace Quic { -namespace { - -constexpr uint32_t Timeout = 1000; -const quic::QuicVersionLabel FakeVersionLabel = 0x01234567; -const quic::QuicVersionLabel FakeVersionLabel2 = 0x89ABCDEF; -const uint64_t FakeIdleTimeoutMilliseconds = 12012; -const uint8_t FakeStatelessResetTokenData[16] = {0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F}; -const uint64_t FakeMaxPacketSize = 9001; -const uint64_t FakeInitialMaxData = 101; -const bool FakeDisableMigration = true; -const auto CustomParameter1 = static_cast(0xffcd); -const char* CustomParameter1Value = "foo"; -const auto CustomParameter2 = static_cast(0xff34); -const char* CustomParameter2Value = "bar"; - -std::vector createFakeStatelessResetToken() { - return std::vector(FakeStatelessResetTokenData, - FakeStatelessResetTokenData + sizeof(FakeStatelessResetTokenData)); -} - -// Make a TransportParameters that has a few fields set to help test comparison. -std::unique_ptr makeFakeTransportParams() { - auto params = std::make_unique(); - params->perspective = quic::Perspective::IS_CLIENT; - params->legacy_version_information = quic::TransportParameters::LegacyVersionInformation(); - params->legacy_version_information->version = FakeVersionLabel; - params->legacy_version_information->supported_versions.push_back(FakeVersionLabel); - params->legacy_version_information->supported_versions.push_back(FakeVersionLabel2); - params->max_idle_timeout_ms.set_value(FakeIdleTimeoutMilliseconds); - params->stateless_reset_token = createFakeStatelessResetToken(); - params->max_udp_payload_size.set_value(FakeMaxPacketSize); - params->initial_max_data.set_value(FakeInitialMaxData); - params->disable_active_migration = FakeDisableMigration; - params->custom_parameters[CustomParameter1] = CustomParameter1Value; - params->custom_parameters[CustomParameter2] = CustomParameter2Value; - return params; -} - -// Generated with SSL_SESSION_to_bytes. -static constexpr char CachedSession[] = - "3082068702010102020304040213010420b9c2a657e565db0babd09e192a9fc4d768fbd706" - "9f03f9278a4a0be62392e55b0420d87ed2ab8cafc986fd2e288bd2d654cd57c3a2bed1d532" - "20726e55fed39d021ea10602045ed16771a205020302a300a382025f3082025b30820143a0" - "03020102020104300d06092a864886f70d01010b0500302c3110300e060355040a13074163" - "6d6520436f311830160603550403130f496e7465726d656469617465204341301e170d3133" - "303130313130303030305a170d3233313233313130303030305a302d3110300e060355040a" - "130741636d6520436f3119301706035504031310746573742e6578616d706c652e636f6d30" - "59301306072a8648ce3d020106082a8648ce3d030107034200040526220e77278300d06bc0" - "86aff4f999a828a2ed5cc75adc2972794befe885aa3a9b843de321b36b0a795289cebff1a5" - "428bad5e34665ce5e36daad08fb3ffd8a3523050300e0603551d0f0101ff04040302078030" - "130603551d25040c300a06082b06010505070301300c0603551d130101ff04023000301b06" - "03551d11041430128210746573742e6578616d706c652e636f6d300d06092a864886f70d01" - "010b050003820101008c1f1e380831b6437a8b9284d28d4ead38d9503a9fc936db89048aa2" - "edd6ec2fb830d962ef7a4f384e679504f4d5520f3272e0b9e702b110aff31711578fa5aeb1" - "11e9d184c994b0f97e7b17d1995f3f477f25bc1258398ec0ec729caed55d594a009f48093a" - "17f33a7f3bb6e420cc3499838398a421d93c7132efa8bee5ed2645cbc55179c400da006feb" - "761badd356cac3bd7a0e6b22a511106a355ec62a4c0ac2541d2996adb4a918c866d10c3e31" - "62039a91d4ce600b276740d833380b37f66866d261bf6efa8855e7ae6c7d12a8a864cd9a1f" - "4663e07714b0204e51bbc189a2d04c2a5043202379ff1c8cbf30cbb44fde4ee9a1c0c976dc" - "4943df2c132ca4020400aa7f047d494e534543555245003072020101020203040402130104" - "000420d87ed2ab8cafc986fd2e288bd2d654cd57c3a2bed1d53220726e55fed39d021ea106" - "02045ed16771a205020302a300a4020400b20302011db5060404bd909308b807020500ffff" - "ffffb9050203093a80ba07040568332d3238bb030101ffbc03040100b20302011db3820307" - "30820303308201eba003020102020102300d06092a864886f70d01010b050030243110300e" - "060355040a130741636d6520436f3110300e06035504031307526f6f74204341301e170d31" - "33303130313130303030305a170d3233313233313130303030305a302c3110300e06035504" - "0a130741636d6520436f311830160603550403130f496e7465726d65646961746520434130" - "820122300d06092a864886f70d01010105000382010f003082010a0282010100cd3550e70a" - "6880e52bf0012b93110c50f723e1d8d2ed489aea3b649f82fae4ad2396a8a19b31d1d64ab2" - "79f1c18003184154a5303a82bd57109cfd5d34fd19d3211bcb06e76640e1278998822dd72e" - "0d5c059a740d45de325e784e81b4c86097f08b2a8ce057f6b9db5a53641d27e09347d993ee" - "acf67be7d297b1a6853775ffaaf78fae924e300b5654fd32f99d3cd82e95f56417ff26d265" - "e2b1786c835d67a4d8ae896b6eb34b35a5b1033c209779ed0bf8de25a13a507040ae9e0475" - "a26a2f15845b08c3e0554e47dbbc7925b02e580dbcaaa6f2eecde6b8028c5b00b33d44d0a6" - "bfb3e72e9d4670de45d1bd79bdc0f2470b71286091c29873152db4b1f30203010001a33830" - "36300e0603551d0f0101ff04040302020430130603551d25040c300a06082b060105050703" - "01300f0603551d130101ff040530030101ff300d06092a864886f70d01010b050003820101" - "00bc4f8234860558dd404a626403819bfc759029d625a002143e75ebdb2898d1befdd326c3" - "4b14dc3507d732bb29af7e6af31552db53052a2be0d950efee5e0f699304231611ed8bf73a" - "6f216a904c6c2f1a2186d1ed08a8005a7914394d71e7d4b643c808f86365c5fecad8b52934" - "2d3b3f03447126d278d75b1dab3ed53f23e36e9b3d695f28727916e5ee56ce22d387c81f05" - "919b2a37bd4981eb67d9f57b7072285dbbb61f48b6b14768c069a092aad5a094cf295dafd2" - "3ca008f89a5f5ab37a56e5f68df45091c7cb85574677127087a2887ba3baa6d4fc436c6e40" - "40885e81621d38974f0c7f0d792418c5adebb10e92a165f8d79b169617ff575c0d4a85b506" - "0404bd909308b603010100b70402020403b807020500ffffffffb9050203093a80ba070405" - "68332d3238bb030101ff"; - -class FakeTimeSource : public TimeSource { -public: - // From TimeSource. - SystemTime systemTime() override { return fake_time_; } - MonotonicTime monotonicTime() override { - // EnvoyQuicSessionCache does not use monotonic time, return empty value. - ADD_FAILURE() << "Unexpected call to monotonicTime"; - return MonotonicTime(); - } - - void advance(int seconds) { fake_time_ += std::chrono::seconds(seconds); } - -private: - SystemTime fake_time_{}; -}; - -} // namespace - -class EnvoyQuicSessionCacheTest : public ::testing::Test { -public: - EnvoyQuicSessionCacheTest() - : ssl_ctx_(SSL_CTX_new(TLS_method())), cache_(time_source_), - params_(makeFakeTransportParams()) {} - -protected: - bssl::UniquePtr makeSession(uint32_t timeout = Timeout) { - std::string cached_session = - absl::HexStringToBytes(absl::string_view(CachedSession, sizeof(CachedSession))); - SSL_SESSION* session = - SSL_SESSION_from_bytes(reinterpret_cast(cached_session.data()), - cached_session.size(), ssl_ctx_.get()); - SSL_SESSION_set_time(session, std::chrono::system_clock::to_time_t(time_source_.systemTime())); - SSL_SESSION_set_timeout(session, timeout); - return bssl::UniquePtr(session); - } - - bssl::UniquePtr ssl_ctx_; - FakeTimeSource time_source_; - EnvoyQuicSessionCache cache_; - std::unique_ptr params_; -}; - -// Tests that simple insertion and lookup work correctly. -TEST_F(EnvoyQuicSessionCacheTest, SingleSession) { - bssl::UniquePtr session = makeSession(); - quic::QuicServerId id1("a.com", 443); - - std::unique_ptr params2 = makeFakeTransportParams(); - bssl::UniquePtr session2 = makeSession(); - SSL_SESSION* unowned2 = session2.get(); - quic::QuicServerId id2("b.com", 443); - - EXPECT_EQ(nullptr, cache_.Lookup(id1, ssl_ctx_.get())); - EXPECT_EQ(nullptr, cache_.Lookup(id2, ssl_ctx_.get())); - EXPECT_EQ(0u, cache_.size()); - - cache_.Insert(id1, std::move(session), *params_, nullptr); - EXPECT_EQ(1u, cache_.size()); - std::unique_ptr resumption_state = cache_.Lookup(id1, ssl_ctx_.get()); - ASSERT_NE(resumption_state, nullptr); - ASSERT_NE(resumption_state->transport_params, nullptr); - EXPECT_EQ(*params_, *(resumption_state->transport_params)); - EXPECT_EQ(nullptr, cache_.Lookup(id2, ssl_ctx_.get())); - // No session is available for id1, even though the entry exists. - EXPECT_EQ(1u, cache_.size()); - EXPECT_EQ(nullptr, cache_.Lookup(id1, ssl_ctx_.get())); - // Lookup() will trigger a deletion of invalid entry. - EXPECT_EQ(0u, cache_.size()); - - bssl::UniquePtr session3 = makeSession(); - SSL_SESSION* unowned3 = session3.get(); - quic::QuicServerId id3("c.com", 443); - cache_.Insert(id3, std::move(session3), *params_, nullptr); - cache_.Insert(id2, std::move(session2), *params2, nullptr); - EXPECT_EQ(2u, cache_.size()); - std::unique_ptr resumption_state2 = cache_.Lookup(id2, ssl_ctx_.get()); - ASSERT_NE(resumption_state2, nullptr); - EXPECT_EQ(unowned2, resumption_state2->tls_session.get()); - std::unique_ptr resumption_state3 = cache_.Lookup(id3, ssl_ctx_.get()); - ASSERT_NE(resumption_state3, nullptr); - EXPECT_EQ(unowned3, resumption_state3->tls_session.get()); - - // Verify that the cache is cleared after Lookups. - EXPECT_EQ(nullptr, cache_.Lookup(id1, ssl_ctx_.get())); - EXPECT_EQ(nullptr, cache_.Lookup(id2, ssl_ctx_.get())); - EXPECT_EQ(nullptr, cache_.Lookup(id3, ssl_ctx_.get())); - EXPECT_EQ(0u, cache_.size()); -} - -TEST_F(EnvoyQuicSessionCacheTest, MultipleSessions) { - bssl::UniquePtr session = makeSession(); - quic::QuicServerId id1("a.com", 443); - bssl::UniquePtr session2 = makeSession(); - SSL_SESSION* unowned2 = session2.get(); - bssl::UniquePtr session3 = makeSession(); - SSL_SESSION* unowned3 = session3.get(); - - cache_.Insert(id1, std::move(session), *params_, nullptr); - cache_.Insert(id1, std::move(session2), *params_, nullptr); - cache_.Insert(id1, std::move(session3), *params_, nullptr); - // The latest session is popped first. - std::unique_ptr resumption_state1 = cache_.Lookup(id1, ssl_ctx_.get()); - ASSERT_NE(resumption_state1, nullptr); - EXPECT_EQ(unowned3, resumption_state1->tls_session.get()); - std::unique_ptr resumption_state2 = cache_.Lookup(id1, ssl_ctx_.get()); - ASSERT_NE(resumption_state2, nullptr); - EXPECT_EQ(unowned2, resumption_state2->tls_session.get()); - // Only two sessions are cache. - EXPECT_EQ(nullptr, cache_.Lookup(id1, ssl_ctx_.get())); -} - -// Test that when a different TransportParameter is inserted for -// the same server id, the existing entry is removed. -TEST_F(EnvoyQuicSessionCacheTest, DifferentTransportParams) { - bssl::UniquePtr session = makeSession(); - quic::QuicServerId id1("a.com", 443); - bssl::UniquePtr session2 = makeSession(); - bssl::UniquePtr session3 = makeSession(); - SSL_SESSION* unowned3 = session3.get(); - - cache_.Insert(id1, std::move(session), *params_, nullptr); - cache_.Insert(id1, std::move(session2), *params_, nullptr); - // tweak the transport parameters a little bit. - params_->perspective = quic::Perspective::IS_SERVER; - cache_.Insert(id1, std::move(session3), *params_, nullptr); - std::unique_ptr resumption_state = cache_.Lookup(id1, ssl_ctx_.get()); - ASSERT_NE(resumption_state, nullptr); - EXPECT_EQ(unowned3, resumption_state->tls_session.get()); - EXPECT_EQ(*params_.get(), *resumption_state->transport_params); - EXPECT_EQ(nullptr, cache_.Lookup(id1, ssl_ctx_.get())); -} - -TEST_F(EnvoyQuicSessionCacheTest, DifferentApplicationState) { - bssl::UniquePtr session = makeSession(); - quic::QuicServerId id1("a.com", 443); - bssl::UniquePtr session2 = makeSession(); - bssl::UniquePtr session3 = makeSession(); - SSL_SESSION* unowned3 = session3.get(); - quic::ApplicationState state; - state.push_back('a'); - - cache_.Insert(id1, std::move(session), *params_, &state); - cache_.Insert(id1, std::move(session2), *params_, &state); - cache_.Insert(id1, std::move(session3), *params_, nullptr); - std::unique_ptr resumption_state = cache_.Lookup(id1, ssl_ctx_.get()); - ASSERT_NE(resumption_state, nullptr); - EXPECT_EQ(unowned3, resumption_state->tls_session.get()); - EXPECT_EQ(nullptr, resumption_state->application_state); - EXPECT_EQ(nullptr, cache_.Lookup(id1, ssl_ctx_.get())); -} - -TEST_F(EnvoyQuicSessionCacheTest, BothStatesDifferent) { - bssl::UniquePtr session = makeSession(); - quic::QuicServerId id1("a.com", 443); - bssl::UniquePtr session2 = makeSession(); - bssl::UniquePtr session3 = makeSession(); - SSL_SESSION* unowned3 = session3.get(); - quic::ApplicationState state; - state.push_back('a'); - - cache_.Insert(id1, std::move(session), *params_, &state); - cache_.Insert(id1, std::move(session2), *params_, &state); - params_->perspective = quic::Perspective::IS_SERVER; - cache_.Insert(id1, std::move(session3), *params_, nullptr); - std::unique_ptr resumption_state = cache_.Lookup(id1, ssl_ctx_.get()); - ASSERT_NE(resumption_state, nullptr); - EXPECT_EQ(unowned3, resumption_state->tls_session.get()); - EXPECT_EQ(*params_, *resumption_state->transport_params); - EXPECT_EQ(nullptr, resumption_state->application_state); - EXPECT_EQ(nullptr, cache_.Lookup(id1, ssl_ctx_.get())); -} - -// When the size limit is exceeded, the oldest entry should be erased. -TEST_F(EnvoyQuicSessionCacheTest, SizeLimit) { - constexpr size_t size_limit = 1024; - std::array unowned_sessions; - for (size_t i = 0; i <= size_limit; i++) { - time_source_.advance(1); - bssl::UniquePtr session = makeSession(/*timeout=*/10000); - unowned_sessions[i] = session.get(); - quic::QuicServerId id(absl::StrCat("domain", i, ".example.com"), 443); - cache_.Insert(id, std::move(session), *params_, nullptr); - } - EXPECT_EQ(cache_.size(), size_limit); - // First entry has been removed. - quic::QuicServerId id0("domain0.example.com", 443); - EXPECT_EQ(nullptr, cache_.Lookup(id0, ssl_ctx_.get())); - // All other entries all present. - for (size_t i = 1; i <= size_limit; i++) { - quic::QuicServerId id(absl::StrCat("domain", i, ".example.com"), 443); - std::unique_ptr resumption_state = cache_.Lookup(id, ssl_ctx_.get()); - ASSERT_NE(resumption_state, nullptr) << i; - EXPECT_EQ(resumption_state->tls_session.get(), unowned_sessions[i]); - } -} - -TEST_F(EnvoyQuicSessionCacheTest, ClearEarlyData) { - SSL_CTX_set_early_data_enabled(ssl_ctx_.get(), 1); - bssl::UniquePtr session = makeSession(); - quic::QuicServerId id1("a.com", 443); - bssl::UniquePtr session2 = makeSession(); - - EXPECT_TRUE(SSL_SESSION_early_data_capable(session.get())); - EXPECT_TRUE(SSL_SESSION_early_data_capable(session2.get())); - - cache_.Insert(id1, std::move(session), *params_, nullptr); - cache_.Insert(id1, std::move(session2), *params_, nullptr); - - cache_.ClearEarlyData(id1); - - std::unique_ptr resumption_state = cache_.Lookup(id1, ssl_ctx_.get()); - ASSERT_NE(resumption_state, nullptr); - EXPECT_FALSE(SSL_SESSION_early_data_capable(resumption_state->tls_session.get())); - resumption_state = cache_.Lookup(id1, ssl_ctx_.get()); - EXPECT_FALSE(SSL_SESSION_early_data_capable(resumption_state->tls_session.get())); - EXPECT_EQ(nullptr, cache_.Lookup(id1, ssl_ctx_.get())); -} - -// Expired session isn't considered valid and nullptr will be returned upon -// Lookup. -TEST_F(EnvoyQuicSessionCacheTest, Expiration) { - bssl::UniquePtr session = makeSession(); - quic::QuicServerId id1("a.com", 443); - - bssl::UniquePtr session2 = makeSession(3 * Timeout); - SSL_SESSION* unowned2 = session2.get(); - quic::QuicServerId id2("b.com", 443); - - cache_.Insert(id1, std::move(session), *params_, nullptr); - cache_.Insert(id2, std::move(session2), *params_, nullptr); - - EXPECT_EQ(2u, cache_.size()); - // Expire the session. - time_source_.advance(Timeout * 2); - // The entry has not been removed yet. - EXPECT_EQ(2u, cache_.size()); - - EXPECT_EQ(nullptr, cache_.Lookup(id1, ssl_ctx_.get())); - EXPECT_EQ(1u, cache_.size()); - std::unique_ptr resumption_state = cache_.Lookup(id2, ssl_ctx_.get()); - ASSERT_NE(resumption_state, nullptr); - EXPECT_EQ(unowned2, resumption_state->tls_session.get()); - EXPECT_EQ(1u, cache_.size()); -} - -} // namespace Quic -} // namespace Envoy