Refactor more TLS handshake tests in QUIC. QuicCryptoServerStreamTest now only tests QUIC Crypto. The TLS tests from that file have been moved to a new TlsServerHandshakerTest file. The remaining tests from TlsHandshakerTest have also been moved to TlsServerHandshakerTest (client tests were moved to TlsClientHandshakerTest in cl/306682737) and removes TlsHandshakerTest. gfe-relnote: n/a - test-only refactor. PiperOrigin-RevId: 307452036 Change-Id: I3f7cb8d88fcc1da9789a65305a9d4079154dde93
diff --git a/quic/core/quic_crypto_client_stream.h b/quic/core/quic_crypto_client_stream.h index a66dcba..5ec1b01 100644 --- a/quic/core/quic_crypto_client_stream.h +++ b/quic/core/quic_crypto_client_stream.h
@@ -21,6 +21,10 @@ namespace quic { +namespace test { +class QuicCryptoClientStreamPeer; +} // namespace test + class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream { public: explicit QuicCryptoClientStreamBase(QuicSession* session); @@ -221,6 +225,7 @@ } private: + friend class test::QuicCryptoClientStreamPeer; std::unique_ptr<HandshakerInterface> handshaker_; };
diff --git a/quic/core/quic_crypto_server_stream_test.cc b/quic/core/quic_crypto_server_stream_test.cc index a3f0d11..debfc3b 100644 --- a/quic/core/quic_crypto_server_stream_test.cc +++ b/quic/core/quic_crypto_server_stream_test.cc
@@ -50,6 +50,8 @@ const char kServerHostname[] = "test.example.com"; const uint16_t kServerPort = 443; +// This test tests the server-side of the QUIC crypto handshake. It does not +// test the TLS handshake - that is in tls_server_handshaker_test.cc. class QuicCryptoServerStreamTest : public QuicTest { public: QuicCryptoServerStreamTest() @@ -152,28 +154,6 @@ server_connection_, server_stream(), 0); } - void UseTlsHandshake() { - client_options_.only_tls_versions = true; - supported_versions_.clear(); - for (ParsedQuicVersion version : AllSupportedVersions()) { - if (version.handshake_protocol != PROTOCOL_TLS1_3) { - continue; - } - supported_versions_.push_back(version); - } - } - - void UseQuicCryptoHandshake() { - client_options_.only_quic_crypto_versions = true; - supported_versions_.clear(); - for (ParsedQuicVersion version : AllSupportedVersions()) { - if (version.handshake_protocol != PROTOCOL_QUIC_CRYPTO) { - continue; - } - supported_versions_.push_back(version); - } - } - protected: // Every connection gets its own MockQuicConnectionHelper and // MockAlarmFactory, tracked separately from the server and client state so @@ -197,7 +177,8 @@ crypto_test_utils::FakeClientOptions client_options_; // Which QUIC versions the client and server support. - ParsedQuicVersionVector supported_versions_ = AllSupportedVersions(); + ParsedQuicVersionVector supported_versions_ = + AllSupportedVersionsWithQuicCrypto(); }; TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) { @@ -211,24 +192,13 @@ // test should send: // * One to get a source-address token and certificates. // * One to complete the handshake. - UseQuicCryptoHandshake(); Initialize(); EXPECT_EQ(2, CompleteCryptoHandshake()); EXPECT_TRUE(server_stream()->encryption_established()); EXPECT_TRUE(server_stream()->one_rtt_keys_available()); } -TEST_F(QuicCryptoServerStreamTest, ConnectedAfterTlsHandshake) { - UseTlsHandshake(); - Initialize(); - CompleteCryptoHandshake(); - EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol()); - EXPECT_TRUE(server_stream()->encryption_established()); - EXPECT_TRUE(server_stream()->one_rtt_keys_available()); -} - TEST_F(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) { - UseQuicCryptoHandshake(); Initialize(); InitializeFakeClient(); @@ -250,7 +220,6 @@ } TEST_F(QuicCryptoServerStreamTest, ZeroRTT) { - UseQuicCryptoHandshake(); Initialize(); InitializeFakeClient(); @@ -282,7 +251,6 @@ } TEST_F(QuicCryptoServerStreamTest, FailByPolicy) { - UseQuicCryptoHandshake(); Initialize(); InitializeFakeClient(); @@ -295,7 +263,6 @@ } TEST_F(QuicCryptoServerStreamTest, MessageAfterHandshake) { - UseQuicCryptoHandshake(); Initialize(); CompleteCryptoHandshake(); EXPECT_CALL( @@ -307,7 +274,6 @@ } TEST_F(QuicCryptoServerStreamTest, BadMessageType) { - UseQuicCryptoHandshake(); Initialize(); message_.set_tag(kSHLO); @@ -326,7 +292,6 @@ } TEST_F(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) { - UseQuicCryptoHandshake(); Initialize(); InitializeFakeClient(); @@ -359,7 +324,6 @@ }; TEST_F(QuicCryptoServerStreamTestWithFailingProofSource, Test) { - UseQuicCryptoHandshake(); Initialize(); InitializeFakeClient(); @@ -393,7 +357,6 @@ // connection in close succession could cause a crash, especially when the use // of Mentat signing meant that it took a while for each CHLO to be processed. TEST_F(QuicCryptoServerStreamTestWithFakeProofSource, MultipleChlo) { - UseQuicCryptoHandshake(); Initialize(); GetFakeProofSource()->Activate(); EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
diff --git a/quic/core/tls_client_handshaker_test.cc b/quic/core/tls_client_handshaker_test.cc index 0283169..bb859c1 100644 --- a/quic/core/tls_client_handshaker_test.cc +++ b/quic/core/tls_client_handshaker_test.cc
@@ -256,7 +256,7 @@ EXPECT_FALSE(stream()->IsResumption()); } -TEST_P(TlsClientHandshakerTest, ConnecitonClosedOnTlsError) { +TEST_P(TlsClientHandshakerTest, ConnectionClosedOnTlsError) { // Have client send ClientHello. stream()->CryptoConnect(); EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
diff --git a/quic/core/tls_handshaker_test.cc b/quic/core/tls_handshaker_test.cc index de3a8a4..6103743 100644 --- a/quic/core/tls_handshaker_test.cc +++ b/quic/core/tls_handshaker_test.cc
@@ -434,138 +434,6 @@ ExpectHandshakeSuccessful(); } -TEST_P(TlsHandshakerTest, HandshakeWithAsyncProofSource) { - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - // Enable FakeProofSource to capture call to ComputeTlsSignature and run it - // asynchronously. - FakeProofSource* proof_source = server_stream_->GetFakeProofSource(); - proof_source->Activate(); - - // Start handshake. - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ASSERT_EQ(proof_source->NumPendingCallbacks(), 1); - proof_source->InvokePendingCallback(0); - - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ExpectHandshakeSuccessful(); -} - -TEST_P(TlsHandshakerTest, CancelPendingProofSource) { - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - // Enable FakeProofSource to capture call to ComputeTlsSignature and run it - // asynchronously. - FakeProofSource* proof_source = server_stream_->GetFakeProofSource(); - proof_source->Activate(); - - // Start handshake. - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ASSERT_EQ(proof_source->NumPendingCallbacks(), 1); - server_stream_ = nullptr; - - proof_source->InvokePendingCallback(0); -} - -TEST_P(TlsHandshakerTest, ServerExtractSNI) { - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - ExpectHandshakeSuccessful(); - - EXPECT_EQ(server_stream_->crypto_negotiated_params().sni, "test.example.com"); -} - -TEST_P(TlsHandshakerTest, ServerConnectionClosedOnTlsError) { - EXPECT_CALL(*server_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); - - // Send a zero-length ClientHello from client to server. - char bogus_handshake_message[] = { - // Handshake struct (RFC 8446 appendix B.3) - 1, // HandshakeType client_hello - 0, 0, 0, // uint24 length - }; - client_stream_->WriteCryptoData( - ENCRYPTION_INITIAL, - quiche::QuicheStringPiece(bogus_handshake_message, - QUICHE_ARRAYSIZE(bogus_handshake_message))); - client_stream_->SendCryptoMessagesToPeer(server_stream_); - - EXPECT_FALSE(server_stream_->one_rtt_keys_available()); -} - -TEST_P(TlsHandshakerTest, ClientNotSendingALPN) { - client_stream_->client_handshaker()->AllowEmptyAlpnForTests(); - EXPECT_CALL(client_session_, GetAlpnsToOffer()) - .WillOnce(Return(std::vector<std::string>())); - EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not select ALPN", _)); - EXPECT_CALL(*server_conn_, - CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not receive a known ALPN", _)); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - EXPECT_FALSE(client_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - client_stream_->encryption_established()); - EXPECT_FALSE(server_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - server_stream_->encryption_established()); -} - -TEST_P(TlsHandshakerTest, ClientSendingBadALPN) { - const std::string kTestBadClientAlpn = "bad-client-alpn"; - EXPECT_CALL(client_session_, GetAlpnsToOffer()) - .WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn}))); - EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not select ALPN", _)); - EXPECT_CALL(*server_conn_, - CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not receive a known ALPN", _)); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - EXPECT_FALSE(client_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - client_stream_->encryption_established()); - EXPECT_FALSE(server_stream_->one_rtt_keys_available()); - EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), - server_stream_->encryption_established()); -} - -TEST_P(TlsHandshakerTest, CustomALPNNegotiation) { - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - - const std::string kTestAlpn = "A Custom ALPN Value"; - const std::vector<std::string> kTestAlpns( - {"foo", "bar", kTestAlpn, "something else"}); - EXPECT_CALL(client_session_, GetAlpnsToOffer()) - .WillRepeatedly(Return(kTestAlpns)); - EXPECT_CALL(server_session_, SelectAlpn(_)) - .WillOnce([kTestAlpn, kTestAlpns]( - const std::vector<quiche::QuicheStringPiece>& alpns) { - EXPECT_THAT(alpns, ElementsAreArray(kTestAlpns)); - return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); - }); - EXPECT_CALL(client_session_, - OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn))); - EXPECT_CALL(server_session_, - OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn))); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ExpectHandshakeSuccessful(); -} - } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/tls_server_handshaker_test.cc b/quic/core/tls_server_handshaker_test.cc new file mode 100644 index 0000000..7a30a13 --- /dev/null +++ b/quic/core/tls_server_handshaker_test.cc
@@ -0,0 +1,352 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <utility> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_session.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { +class QuicConnection; +class QuicStream; +} // namespace quic + +using testing::_; +using testing::NiceMock; +using testing::Return; + +namespace quic { +namespace test { + +namespace { + +const char kServerHostname[] = "test.example.com"; +const uint16_t kServerPort = 443; + +class TlsServerHandshakerTest : public QuicTest { + public: + TlsServerHandshakerTest() + : proof_source_(new FakeProofSource()), + server_crypto_config_(QuicCryptoServerConfig::TESTING, + QuicRandom::GetInstance(), + std::unique_ptr<ProofSource>(proof_source_), + KeyExchangeSource::Default()), + server_compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), + server_id_(kServerHostname, kServerPort, false), + client_crypto_config_(crypto_test_utils::ProofVerifierForTesting()) { + InitializeServer(); + InitializeFakeClient(); + } + + ~TlsServerHandshakerTest() override { + // Ensure that anything that might reference |helpers_| is destroyed before + // |helpers_| is destroyed. + server_session_.reset(); + client_session_.reset(); + helpers_.clear(); + alarm_factories_.clear(); + } + + // Initializes the crypto server stream state for testing. May be + // called multiple times. + void InitializeServer() { + TestQuicSpdyServerSession* server_session = nullptr; + helpers_.push_back(std::make_unique<NiceMock<MockQuicConnectionHelper>>()); + alarm_factories_.push_back(std::make_unique<MockAlarmFactory>()); + CreateServerSessionForTest( + server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_, + helpers_.back().get(), alarm_factories_.back().get(), + &server_crypto_config_, &server_compressed_certs_cache_, + &server_connection_, &server_session); + CHECK(server_session); + server_session_.reset(server_session); + EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _)) + .Times(testing::AnyNumber()); + EXPECT_CALL(*server_session_, SelectAlpn(_)) + .WillRepeatedly( + [this](const std::vector<quiche::QuicheStringPiece>& alpns) { + return std::find( + alpns.cbegin(), alpns.cend(), + AlpnForVersion(server_session_->connection()->version())); + }); + crypto_test_utils::SetupCryptoServerConfigForTest( + server_connection_->clock(), server_connection_->random_generator(), + &server_crypto_config_); + } + + QuicCryptoServerStreamBase* server_stream() { + return server_session_->GetMutableCryptoStream(); + } + + QuicCryptoClientStream* client_stream() { + return client_session_->GetMutableCryptoStream(); + } + + // Initializes a fake client, and all its associated state, for + // testing. May be called multiple times. + void InitializeFakeClient() { + TestQuicSpdyClientSession* client_session = nullptr; + helpers_.push_back(std::make_unique<NiceMock<MockQuicConnectionHelper>>()); + alarm_factories_.push_back(std::make_unique<MockAlarmFactory>()); + CreateClientSessionForTest( + server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_, + helpers_.back().get(), alarm_factories_.back().get(), + &client_crypto_config_, &client_connection_, &client_session); + const std::string default_alpn = + AlpnForVersion(client_connection_->version()); + ON_CALL(*client_session, GetAlpnsToOffer()) + .WillByDefault(Return(std::vector<std::string>({default_alpn}))); + CHECK(client_session); + client_session_.reset(client_session); + } + + void CompleteCryptoHandshake() { + while (!client_stream()->one_rtt_keys_available() || + !server_stream()->one_rtt_keys_available()) { + auto previous_moved_messages_counts = moved_messages_counts_; + AdvanceHandshakeWithFakeClient(); + // Check that the handshake has made forward progress + ASSERT_NE(previous_moved_messages_counts, moved_messages_counts_); + } + } + + // Performs a single round of handshake message-exchange between the + // client and server. + void AdvanceHandshakeWithFakeClient() { + CHECK(server_connection_); + CHECK(client_session_ != nullptr); + + EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber()); + EXPECT_CALL(*client_session_, OnProofVerifyDetailsAvailable(_)) + .Times(testing::AnyNumber()); + EXPECT_CALL(*client_connection_, OnCanWrite()).Times(testing::AnyNumber()); + EXPECT_CALL(*server_connection_, OnCanWrite()).Times(testing::AnyNumber()); + // Call CryptoConnect if we haven't moved any client messages yet. + if (moved_messages_counts_.first == 0) { + client_stream()->CryptoConnect(); + } + moved_messages_counts_ = crypto_test_utils::AdvanceHandshake( + client_connection_, client_stream(), moved_messages_counts_.first, + server_connection_, server_stream(), moved_messages_counts_.second); + } + + void ExpectHandshakeSuccessful() { + EXPECT_TRUE(client_stream()->one_rtt_keys_available()); + EXPECT_TRUE(client_stream()->encryption_established()); + EXPECT_TRUE(server_stream()->one_rtt_keys_available()); + EXPECT_TRUE(server_stream()->encryption_established()); + EXPECT_EQ(HANDSHAKE_COMPLETE, client_stream()->GetHandshakeState()); + EXPECT_EQ(HANDSHAKE_CONFIRMED, server_stream()->GetHandshakeState()); + + const auto& client_crypto_params = + client_stream()->crypto_negotiated_params(); + const auto& server_crypto_params = + server_stream()->crypto_negotiated_params(); + // The TLS params should be filled in on the client. + EXPECT_NE(0, client_crypto_params.cipher_suite); + EXPECT_NE(0, client_crypto_params.key_exchange_group); + EXPECT_NE(0, client_crypto_params.peer_signature_algorithm); + + // The cipher suite and key exchange group should match on the client and + // server. + EXPECT_EQ(client_crypto_params.cipher_suite, + server_crypto_params.cipher_suite); + EXPECT_EQ(client_crypto_params.key_exchange_group, + server_crypto_params.key_exchange_group); + // We don't support client certs on the server (yet), so the server + // shouldn't have a peer signature algorithm to report. + EXPECT_EQ(0, server_crypto_params.peer_signature_algorithm); + } + + protected: + // Every connection gets its own MockQuicConnectionHelper and + // MockAlarmFactory, tracked separately from the server and client state so + // their lifetimes persist through the whole test. + std::vector<std::unique_ptr<MockQuicConnectionHelper>> helpers_; + std::vector<std::unique_ptr<MockAlarmFactory>> alarm_factories_; + + // Server state. + PacketSavingConnection* server_connection_; + std::unique_ptr<TestQuicSpdyServerSession> server_session_; + FakeProofSource* proof_source_; // owned by server_crypto_config_ + QuicCryptoServerConfig server_crypto_config_; + QuicCompressedCertsCache server_compressed_certs_cache_; + QuicServerId server_id_; + + // Client state. + PacketSavingConnection* client_connection_; + QuicCryptoClientConfig client_crypto_config_; + std::unique_ptr<TestQuicSpdyClientSession> client_session_; + + crypto_test_utils::FakeClientOptions client_options_; + // How many handshake messages have been moved from client to server and + // server to client. + std::pair<size_t, size_t> moved_messages_counts_ = {0, 0}; + + // Which QUIC versions the client and server support. + ParsedQuicVersionVector supported_versions_ = AllSupportedVersionsWithTls(); +}; + +TEST_F(TlsServerHandshakerTest, NotInitiallyConected) { + EXPECT_FALSE(server_stream()->encryption_established()); + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); +} + +TEST_F(TlsServerHandshakerTest, ConnectedAfterTlsHandshake) { + CompleteCryptoHandshake(); + EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol()); + ExpectHandshakeSuccessful(); +} + +TEST_F(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) { + EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); + EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0); + // Enable FakeProofSource to capture call to ComputeTlsSignature and run it + // asynchronously. + proof_source_->Activate(); + + // Start handshake. + AdvanceHandshakeWithFakeClient(); + + ASSERT_EQ(proof_source_->NumPendingCallbacks(), 1); + proof_source_->InvokePendingCallback(0); + + CompleteCryptoHandshake(); + + ExpectHandshakeSuccessful(); +} + +TEST_F(TlsServerHandshakerTest, CancelPendingProofSource) { + EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); + EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0); + // Enable FakeProofSource to capture call to ComputeTlsSignature and run it + // asynchronously. + proof_source_->Activate(); + + // Start handshake. + AdvanceHandshakeWithFakeClient(); + + ASSERT_EQ(proof_source_->NumPendingCallbacks(), 1); + server_session_ = nullptr; + + proof_source_->InvokePendingCallback(0); +} + +TEST_F(TlsServerHandshakerTest, ExtractSNI) { + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); + + EXPECT_EQ(server_stream()->crypto_negotiated_params().sni, + "test.example.com"); +} + +TEST_F(TlsServerHandshakerTest, ConnectionClosedOnTlsError) { + EXPECT_CALL(*server_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); + + // Send a zero-length ClientHello from client to server. + char bogus_handshake_message[] = { + // Handshake struct (RFC 8446 appendix B.3) + 1, // HandshakeType client_hello + 0, 0, 0, // uint24 length + }; + server_stream()->crypto_message_parser()->ProcessInput( + quiche::QuicheStringPiece(bogus_handshake_message, + QUICHE_ARRAYSIZE(bogus_handshake_message)), + ENCRYPTION_INITIAL); + + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); +} + +TEST_F(TlsServerHandshakerTest, ClientNotSendingALPN) { + static_cast<TlsClientHandshaker*>( + QuicCryptoClientStreamPeer::GetHandshaker(client_stream())) + ->AllowEmptyAlpnForTests(); + EXPECT_CALL(*client_session_, GetAlpnsToOffer()) + .WillOnce(Return(std::vector<std::string>())); + EXPECT_CALL( + *client_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, "Server did not select ALPN", _)); + EXPECT_CALL(*server_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, + "Server did not receive a known ALPN", _)); + + // Process two flights of handshake messages. + AdvanceHandshakeWithFakeClient(); + AdvanceHandshakeWithFakeClient(); + + EXPECT_FALSE(client_stream()->one_rtt_keys_available()); + EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), + client_stream()->encryption_established()); + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); + EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), + server_stream()->encryption_established()); +} + +TEST_F(TlsServerHandshakerTest, ClientSendingBadALPN) { + const std::string kTestBadClientAlpn = "bad-client-alpn"; + EXPECT_CALL(*client_session_, GetAlpnsToOffer()) + .WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn}))); + EXPECT_CALL( + *client_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, "Server did not select ALPN", _)); + EXPECT_CALL(*server_connection_, + CloseConnection(QUIC_HANDSHAKE_FAILED, + "Server did not receive a known ALPN", _)); + + // Process two flights of handshake messages. + AdvanceHandshakeWithFakeClient(); + AdvanceHandshakeWithFakeClient(); + + EXPECT_FALSE(client_stream()->one_rtt_keys_available()); + EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), + client_stream()->encryption_established()); + EXPECT_FALSE(server_stream()->one_rtt_keys_available()); + EXPECT_EQ(GetQuicRestartFlag(quic_send_settings_on_write_key_available), + server_stream()->encryption_established()); +} + +TEST_F(TlsServerHandshakerTest, CustomALPNNegotiation) { + EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); + EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0); + + const std::string kTestAlpn = "A Custom ALPN Value"; + const std::vector<std::string> kTestAlpns( + {"foo", "bar", kTestAlpn, "something else"}); + EXPECT_CALL(*client_session_, GetAlpnsToOffer()) + .WillRepeatedly(Return(kTestAlpns)); + EXPECT_CALL(*server_session_, SelectAlpn(_)) + .WillOnce([kTestAlpn, kTestAlpns]( + const std::vector<quiche::QuicheStringPiece>& alpns) { + EXPECT_THAT(alpns, testing::ElementsAreArray(kTestAlpns)); + return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); + }); + EXPECT_CALL(*client_session_, + OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn))); + EXPECT_CALL(*server_session_, + OnAlpnSelected(quiche::QuicheStringPiece(kTestAlpn))); + + CompleteCryptoHandshake(); + ExpectHandshakeSuccessful(); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/test_tools/crypto_test_utils.cc b/quic/test_tools/crypto_test_utils.cc index 1e3f14d..21561d9 100644 --- a/quic/test_tools/crypto_test_utils.cc +++ b/quic/test_tools/crypto_test_utils.cc
@@ -756,6 +756,8 @@ // packets should ever be encrypted with the NullEncrypter, instead // they're encrypted with an obfuscation cipher based on QUIC version and // connection ID. + QUIC_LOG(INFO) << "Attempting to decrypt with NullDecrypter: " + "expect a decryption failure on the next log line."; ASSERT_FALSE(null_encryption_framer.ProcessPacket( *source_conn->encrypted_packets_[index])) << "No TLS packets should be encrypted with the NullEncrypter";
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc index b534635..47fd05f 100644 --- a/quic/test_tools/quic_test_utils.cc +++ b/quic/test_tools/quic_test_utils.cc
@@ -1091,6 +1091,12 @@ MockSessionNotifier::MockSessionNotifier() {} MockSessionNotifier::~MockSessionNotifier() {} +// static +QuicCryptoClientStream::HandshakerInterface* +QuicCryptoClientStreamPeer::GetHandshaker(QuicCryptoClientStream* stream) { + return stream->handshaker_.get(); +} + void CreateClientSessionForTest( QuicServerId server_id, QuicTime::Delta connection_start_time,
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index fafe8d0..b8e0eae 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -858,6 +858,7 @@ MOCK_CONST_METHOD1(SelectAlpn, std::vector<quiche::QuicheStringPiece>::const_iterator( const std::vector<quiche::QuicheStringPiece>&)); + MOCK_METHOD(void, OnAlpnSelected, (quiche::QuicheStringPiece)); std::unique_ptr<QuicCryptoServerStreamBase> CreateQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, QuicCompressedCertsCache* compressed_certs_cache) override; @@ -924,6 +925,7 @@ MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool()); MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool()); MOCK_CONST_METHOD0(GetAlpnsToOffer, std::vector<std::string>()); + MOCK_METHOD(void, OnAlpnSelected, (quiche::QuicheStringPiece)); QuicCryptoClientStream* GetMutableCryptoStream() override; const QuicCryptoClientStream* GetCryptoStream() const override; @@ -1190,6 +1192,14 @@ MOCK_CONST_METHOD0(HasUnackedStreamData, bool()); }; +class QuicCryptoClientStreamPeer { + public: + QuicCryptoClientStreamPeer() = delete; + + static QuicCryptoClientStream::HandshakerInterface* GetHandshaker( + QuicCryptoClientStream* stream); +}; + // Creates a client session for testing. // // server_id: The server id associated with this stream.