Add big red button to disable QUIC TLS resumption. Protected by FLAGS_quic_disable_server_tls_resumption. PiperOrigin-RevId: 341128029 Change-Id: Id6d81e63d8c5f58595565144c6af99525a5f25a6
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc index 91af8c6..91e3dd1 100644 --- a/quic/core/http/end_to_end_test.cc +++ b/quic/core/http/end_to_end_test.cc
@@ -5086,6 +5086,108 @@ server_thread_->Resume(); } +TEST_P(EndToEndTest, TlsResumptionEnabledOnTheFly) { + SetQuicFlag(FLAGS_quic_disable_server_tls_resumption, true); + ASSERT_TRUE(Initialize()); + + if (!version_.UsesTls()) { + // This test is TLS specific. + return; + } + + // Send the first request. Client should not have a resumption ticket. + SendSynchronousFooRequestAndCheckResponse(); + QuicSpdyClientSession* client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_EQ(client_session->GetCryptoStream()->EarlyDataReason(), + ssl_early_data_no_session_offered); + EXPECT_FALSE(client_session->EarlyDataAccepted()); + client_->Disconnect(); + + SetQuicFlag(FLAGS_quic_disable_server_tls_resumption, false); + + // Send the second request. Client should still have no resumption ticket, but + // it will receive one which can be used by the next request. + client_->Connect(); + SendSynchronousFooRequestAndCheckResponse(); + + client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_EQ(client_session->GetCryptoStream()->EarlyDataReason(), + ssl_early_data_no_session_offered); + EXPECT_FALSE(client_session->EarlyDataAccepted()); + client_->Disconnect(); + + // Send the third request in 0RTT. + client_->Connect(); + SendSynchronousFooRequestAndCheckResponse(); + + client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_TRUE(client_session->EarlyDataAccepted()); + client_->Disconnect(); +} + +TEST_P(EndToEndTest, TlsResumptionDisabledOnTheFly) { + SetQuicFlag(FLAGS_quic_disable_server_tls_resumption, false); + ASSERT_TRUE(Initialize()); + + if (!version_.UsesTls()) { + // This test is TLS specific. + return; + } + + // Send the first request and then disconnect. + SendSynchronousFooRequestAndCheckResponse(); + QuicSpdyClientSession* client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_FALSE(client_session->EarlyDataAccepted()); + client_->Disconnect(); + + // Send the second request in 0RTT. + client_->Connect(); + SendSynchronousFooRequestAndCheckResponse(); + + client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_TRUE(client_session->EarlyDataAccepted()); + client_->Disconnect(); + + SetQuicFlag(FLAGS_quic_disable_server_tls_resumption, true); + + // Send the third request. The client should try resumption but server should + // decline it. + client_->Connect(); + SendSynchronousFooRequestAndCheckResponse(); + + client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_FALSE(client_session->EarlyDataAccepted()); + EXPECT_EQ(client_session->GetCryptoStream()->EarlyDataReason(), + ssl_early_data_session_not_resumed); + client_->Disconnect(); + + // Keep sending until the client runs out of resumption tickets. + for (int i = 0; i < 10; ++i) { + client_->Connect(); + SendSynchronousFooRequestAndCheckResponse(); + + client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_FALSE(client_session->EarlyDataAccepted()); + const auto early_data_reason = + client_session->GetCryptoStream()->EarlyDataReason(); + client_->Disconnect(); + + if (early_data_reason != ssl_early_data_session_not_resumed) { + EXPECT_EQ(early_data_reason, ssl_early_data_no_session_offered); + return; + } + } + + ADD_FAILURE() << "Client should not have 10 resumption tickets."; +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/quic_protocol_flags_list.h b/quic/core/quic_protocol_flags_list.h index c39d1e0..9484a23 100644 --- a/quic/core/quic_protocol_flags_list.h +++ b/quic/core/quic_protocol_flags_list.h
@@ -237,4 +237,10 @@ false, "If true, QUIC client with TLS will not try 0-RTT.") +QUIC_PROTOCOL_FLAG(bool, + quic_disable_server_tls_resumption, + false, + "If true, QUIC server will disable TLS resumption by not " + "issuing or processing session tickets.") + #endif
diff --git a/quic/core/tls_server_handshaker.cc b/quic/core/tls_server_handshaker.cc index a935741..aa49597 100644 --- a/quic/core/tls_server_handshaker.cc +++ b/quic/core/tls_server_handshaker.cc
@@ -98,6 +98,10 @@ // Configure the SSL to be a server. SSL_set_accept_state(ssl()); + + if (GetQuicFlag(FLAGS_quic_disable_server_tls_resumption)) { + SSL_set_options(ssl(), SSL_OP_NO_TICKET); + } } TlsServerHandshaker::~TlsServerHandshaker() {
diff --git a/quic/core/tls_server_handshaker_test.cc b/quic/core/tls_server_handshaker_test.cc index f890684..7411ba2 100644 --- a/quic/core/tls_server_handshaker_test.cc +++ b/quic/core/tls_server_handshaker_test.cc
@@ -42,14 +42,39 @@ const char kServerHostname[] = "test.example.com"; const uint16_t kServerPort = 443; -class TlsServerHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> { +struct TestParams { + ParsedQuicVersion version; + bool disable_resumption; +}; + +// Used by ::testing::PrintToStringParamName(). +std::string PrintToString(const TestParams& p) { + return quiche::QuicheStrCat( + ParsedQuicVersionToString(p.version), "_", + (p.disable_resumption ? "ResumptionDisabled" : "ResumptionEnabled")); +} + +// Constructs test permutations. +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + for (const auto& version : AllSupportedVersionsWithTls()) { + for (bool disable_resumption : {false, true}) { + params.push_back(TestParams{version, disable_resumption}); + } + } + return params; +} + +class TlsServerHandshakerTest : public QuicTestWithParam<TestParams> { public: TlsServerHandshakerTest() : server_compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), server_id_(kServerHostname, kServerPort, false), - supported_versions_({GetParam()}) { + supported_versions_({GetParam().version}) { SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true); + SetQuicFlag(FLAGS_quic_disable_server_tls_resumption, + GetParam().disable_resumption); client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>( crypto_test_utils::ProofVerifierForTesting(), std::make_unique<test::SimpleSessionCache>()); @@ -228,7 +253,7 @@ INSTANTIATE_TEST_SUITE_P(TlsServerHandshakerTests, TlsServerHandshakerTest, - ::testing::ValuesIn(AllSupportedVersionsWithTls()), + ::testing::ValuesIn(GetTestParams()), ::testing::PrintToStringParamName()); TEST_P(TlsServerHandshakerTest, NotInitiallyConected) { @@ -369,9 +394,10 @@ InitializeFakeClient(); CompleteCryptoHandshake(); ExpectHandshakeSuccessful(); - EXPECT_TRUE(client_stream()->IsResumption()); - EXPECT_TRUE(server_stream()->IsResumption()); - EXPECT_TRUE(server_stream()->ResumptionAttempted()); + EXPECT_NE(client_stream()->IsResumption(), GetParam().disable_resumption); + EXPECT_NE(server_stream()->IsResumption(), GetParam().disable_resumption); + EXPECT_NE(server_stream()->ResumptionAttempted(), + GetParam().disable_resumption); } TEST_P(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) { @@ -386,6 +412,10 @@ InitializeFakeClient(); AdvanceHandshakeWithFakeClient(); + if (GetParam().disable_resumption) { + ASSERT_EQ(ticket_crypter_->NumPendingCallbacks(), 0u); + return; + } // Test that the DecryptCallback will be run asynchronously, and then run it. ASSERT_EQ(ticket_crypter_->NumPendingCallbacks(), 1u); ticket_crypter_->RunPendingCallback(0); @@ -398,6 +428,10 @@ } TEST_P(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) { + if (GetParam().disable_resumption) { + return; + } + // Do the first handshake InitializeFakeClient(); CompleteCryptoHandshake(); @@ -415,6 +449,10 @@ } TEST_P(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) { + if (GetParam().disable_resumption) { + return; + } + // Do the first handshake InitializeFakeClient(); CompleteCryptoHandshake(); @@ -469,8 +507,8 @@ InitializeFakeClient(); CompleteCryptoHandshake(); ExpectHandshakeSuccessful(); - EXPECT_TRUE(client_stream()->IsResumption()); - EXPECT_TRUE(server_stream()->IsZeroRtt()); + EXPECT_NE(client_stream()->IsResumption(), GetParam().disable_resumption); + EXPECT_NE(server_stream()->IsZeroRtt(), GetParam().disable_resumption); } TEST_P(TlsServerHandshakerTest, ZeroRttRejectOnApplicationStateChange) { @@ -493,7 +531,7 @@ InitializeFakeClient(); CompleteCryptoHandshake(); ExpectHandshakeSuccessful(); - EXPECT_TRUE(client_stream()->IsResumption()); + EXPECT_NE(client_stream()->IsResumption(), GetParam().disable_resumption); EXPECT_FALSE(server_stream()->IsZeroRtt()); }