gfe-relnote: Allow no SNI in TLS QUIC handshake, protected by quic_enable_version_t0XX flags This allows using a QuicCryptoClientStream with TLS when the QuicServerId has an empty hostname. It also modifies the server to expose the received SNI in the crypto_negotiated_params. //gfe/gfe2/quic:end_to_end_test runs with an empty servername; this change will be needed to support TLS in that end to end test. PiperOrigin-RevId: 285099863 Change-Id: I80e94a91824e8b53ed9fd5149a40dd63845fe9b5
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc index a65fefc..a222c20 100644 --- a/quic/core/tls_client_handshaker.cc +++ b/quic/core/tls_client_handshaker.cc
@@ -68,9 +68,10 @@ bool TlsClientHandshaker::CryptoConnect() { state_ = STATE_HANDSHAKE_RUNNING; - // Configure the SSL to be a client. + // Set the SNI to send, if any. SSL_set_connect_state(ssl()); - if (SSL_set_tlsext_host_name(ssl(), server_id_.host().c_str()) != 1) { + if (!server_id_.host().empty() && + SSL_set_tlsext_host_name(ssl(), server_id_.host().c_str()) != 1) { return false; }
diff --git a/quic/core/tls_handshaker_test.cc b/quic/core/tls_handshaker_test.cc index 75f07aa..a0a3b19 100644 --- a/quic/core/tls_handshaker_test.cc +++ b/quic/core/tls_handshaker_test.cc
@@ -17,6 +17,7 @@ #include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h" #include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h" namespace quic { namespace test { @@ -26,9 +27,9 @@ using ::testing::ElementsAreArray; using ::testing::Return; -class FakeProofVerifier : public ProofVerifier { +class TestProofVerifier : public ProofVerifier { public: - FakeProofVerifier() + TestProofVerifier() : verifier_(crypto_test_utils::ProofVerifierForTesting()) {} QuicAsyncStatus VerifyProof( @@ -118,7 +119,7 @@ delegate_(delegate) {} void Run() { - // FakeProofVerifier depends on crypto_test_utils::ProofVerifierForTesting + // TestProofVerifier depends on crypto_test_utils::ProofVerifierForTesting // running synchronously. It passes a FailingProofVerifierCallback and // runs the original callback after asserting that the verification ran // synchronously. @@ -224,11 +225,18 @@ class TestQuicCryptoClientStream : public TestQuicCryptoStream { public: explicit TestQuicCryptoClientStream(QuicSession* session) + : TestQuicCryptoClientStream(session, + QuicServerId("test.example.com", 443), + std::make_unique<TestProofVerifier>()) {} + + TestQuicCryptoClientStream(QuicSession* session, + const QuicServerId& server_id, + std::unique_ptr<ProofVerifier> proof_verifier) : TestQuicCryptoStream(session), - crypto_config_(std::make_unique<FakeProofVerifier>(), + crypto_config_(std::move(proof_verifier), /*session_cache*/ nullptr), handshaker_(new TlsClientHandshaker( - QuicServerId("test.example.com", 443, false), + server_id, this, session, crypto_test_utils::ProofVerifyContextForTesting(), @@ -243,8 +251,8 @@ bool CryptoConnect() { return handshaker_->CryptoConnect(); } - FakeProofVerifier* GetFakeProofVerifier() const { - return static_cast<FakeProofVerifier*>(crypto_config_.proof_verifier()); + TestProofVerifier* GetTestProofVerifier() const { + return static_cast<TestProofVerifier*>(crypto_config_.proof_verifier()); } private: @@ -425,9 +433,9 @@ TEST_F(TlsHandshakerTest, HandshakeWithAsyncProofVerifier) { EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - // Enable FakeProofVerifier to capture call to VerifyCertChain and run it + // Enable TestProofVerifier to capture call to VerifyCertChain and run it // asynchronously. - FakeProofVerifier* proof_verifier = client_stream_->GetFakeProofVerifier(); + TestProofVerifier* proof_verifier = client_stream_->GetTestProofVerifier(); proof_verifier->Activate(); EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable); @@ -444,6 +452,34 @@ ExpectHandshakeSuccessful(); } +TEST_F(TlsHandshakerTest, ClientSendsNoSNI) { + // Create a new client stream (and handshaker) with an empty server hostname. + client_stream_ = + new TestQuicCryptoClientStream(&client_session_, QuicServerId("", 443), + std::make_unique<FakeProofVerifier>()); + client_session_.SetCryptoStream(client_stream_); + + 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_F(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_F(TlsHandshakerTest, ClientConnectionClosedOnTlsError) { // Have client send ClientHello. client_stream_->CryptoConnect();
diff --git a/quic/core/tls_server_handshaker.cc b/quic/core/tls_server_handshaker.cc index 24af98d..d9217c4 100644 --- a/quic/core/tls_server_handshaker.cc +++ b/quic/core/tls_server_handshaker.cc
@@ -11,6 +11,7 @@ #include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" #include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic { @@ -314,6 +315,8 @@ const char* hostname = SSL_get_servername(ssl(), TLSEXT_NAMETYPE_host_name); if (hostname) { hostname_ = hostname; + crypto_negotiated_params_->sni = + QuicHostnameUtils::NormalizeHostname(hostname_); } else { QUIC_LOG(INFO) << "No hostname indicated in SNI"; }