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";
   }