No public description

PiperOrigin-RevId: 817181651
diff --git a/quiche/quic/core/crypto/transport_parameters.cc b/quiche/quic/core/crypto/transport_parameters.cc
index bdbae3b..d8235e2 100644
--- a/quiche/quic/core/crypto/transport_parameters.cc
+++ b/quiche/quic/core/crypto/transport_parameters.cc
@@ -35,6 +35,19 @@
 
 namespace quic {
 
+namespace {
+std::string ObfuscateSni(const absl::string_view& input) {
+  static constexpr char kObfuscationKey[] = {0x42, 0x7b, 0x40, 0x63, 0x11, 0x2a,
+                                             0x6f, 0x05, 0x58, 0x1f, 0x7f, 0x33,
+                                             0x32, 0x4d, 0x64, 0x16};
+  std::string output = std::string(input);
+  for (size_t i = 0; i < output.size(); ++i) {
+    output[i] ^= kObfuscationKey[i % sizeof(kObfuscationKey)];
+  }
+  return output;
+}
+}  // namespace
+
 // Values of the TransportParameterId enum as defined in the
 // "Transport Parameter Encoding" section of draft-ietf-quic-transport.
 // When parameters are encoded, one of these enum values is used to indicate
@@ -65,6 +78,7 @@
   kDiscard = 0x173E,
 
   kGoogleHandshakeMessage = 0x26ab,
+  kDebuggingSni = 0x219bbcd0,
 
   kInitialRoundTripTime = 0x3127,
   kGoogleConnectionOptions = 0x3128,
@@ -142,6 +156,8 @@
       return "discard";
     case TransportParameters::kGoogleHandshakeMessage:
       return "google_handshake_message";
+    case TransportParameters::kDebuggingSni:
+      return "debugging_sni";
     case TransportParameters::kInitialRoundTripTime:
       return "initial_round_trip_time";
     case TransportParameters::kGoogleConnectionOptions:
@@ -223,6 +239,7 @@
     case TransportParameters::kMaxDatagramFrameSize:
     case TransportParameters::kDiscard:
     case TransportParameters::kGoogleHandshakeMessage:
+    case TransportParameters::kDebuggingSni:
     case TransportParameters::kInitialRoundTripTime:
     case TransportParameters::kGoogleConnectionOptions:
     case TransportParameters::kGoogleQuicVersion:
@@ -478,6 +495,10 @@
                     TransportParameterIdToString(kGoogleHandshakeMessage),
                     " length: ", google_handshake_message->length());
   }
+  if (debugging_sni.has_value()) {
+    absl::StrAppend(&rv, " ", TransportParameterIdToString(kDebuggingSni),
+                    " value: ", *debugging_sni);
+  }
   rv += initial_round_trip_time_us.ToString(/*for_use_in_list=*/true);
   if (google_connection_options.has_value()) {
     rv += " " + TransportParameterIdToString(kGoogleConnectionOptions) + " ";
@@ -566,6 +587,7 @@
       initial_round_trip_time_us(other.initial_round_trip_time_us),
       discard_length(other.discard_length),
       google_handshake_message(other.google_handshake_message),
+      debugging_sni(other.debugging_sni),
       google_connection_options(other.google_connection_options),
       custom_parameters(other.custom_parameters) {
   if (other.preferred_address) {
@@ -609,6 +631,7 @@
             rhs.initial_round_trip_time_us.value() &&
         discard_length == rhs.discard_length &&
         google_handshake_message == rhs.google_handshake_message &&
+        debugging_sni == rhs.debugging_sni &&
         google_connection_options == rhs.google_connection_options &&
         custom_parameters == rhs.custom_parameters)) {
     return false;
@@ -684,6 +707,10 @@
     *error_details = "Server cannot send google_handshake_message";
     return false;
   }
+  if (perspective == Perspective::IS_SERVER && debugging_sni.has_value()) {
+    *error_details = "Server cannot send debugging_sni";
+    return false;
+  }
   if (perspective == Perspective::IS_SERVER &&
       initial_round_trip_time_us.value() > 0) {
     *error_details = "Server cannot send initial round trip time";
@@ -804,6 +831,7 @@
       kIntegerParameterLength +           // initial_round_trip_time_us
       kTypeAndValueLength +               // discard
       kTypeAndValueLength +               // google_handshake_message
+      kTypeAndValueLength +               // debugging_sni
       kTypeAndValueLength +               // google_connection_options
       kTypeAndValueLength;                // google-version
 
@@ -826,6 +854,7 @@
       TransportParameters::kReliableStreamReset,
       TransportParameters::kDiscard,
       TransportParameters::kGoogleHandshakeMessage,
+      TransportParameters::kDebuggingSni,
       TransportParameters::kInitialRoundTripTime,
       TransportParameters::kDisableActiveMigration,
       TransportParameters::kPreferredAddress,
@@ -866,6 +895,10 @@
   if (in.google_handshake_message.has_value()) {
     max_transport_param_length += in.google_handshake_message->length();
   }
+  // debugging_sni.
+  if (in.debugging_sni.has_value()) {
+    max_transport_param_length += in.debugging_sni->length();
+  }
 
   // Add a random GREASE transport parameter, as defined in the
   // "Reserved Transport Parameters" section of RFC 9000.
@@ -1078,6 +1111,21 @@
           }
         }
       } break;
+      // debugging_sni.
+      case TransportParameters::kDebuggingSni: {
+        if (in.debugging_sni.has_value()) {
+          QUICHE_DCHECK_EQ(Perspective::IS_CLIENT, in.perspective);
+          // Obfuscate the SNI before writing it to the transport parameters.
+          std::string obfuscated_sni = ObfuscateSni(*in.debugging_sni);
+          if (!writer.WriteVarInt62(TransportParameters::kDebuggingSni) ||
+              !writer.WriteStringPieceVarInt62(obfuscated_sni)) {
+            QUIC_BUG(failed_to_write_debugging_sni)
+                << "Failed to write debugging_sni: " << *in.debugging_sni
+                << " obfuscated to: " << obfuscated_sni << " for " << in;
+            return false;
+          }
+        }
+      } break;
       // initial_round_trip_time_us
       case TransportParameters::kInitialRoundTripTime: {
         if (!in.initial_round_trip_time_us.Write(&writer)) {
@@ -1526,6 +1574,14 @@
         out->google_handshake_message =
             std::string(value_reader.ReadRemainingPayload());
         break;
+      case TransportParameters::kDebuggingSni:
+        if (out->debugging_sni.has_value()) {
+          *error_details = "Received a second debugging_sni";
+          return false;
+        }
+        // Deobfuscate the SNI and store it in the transport parameters.
+        out->debugging_sni = ObfuscateSni(value_reader.ReadRemainingPayload());
+        break;
       case TransportParameters::kInitialRoundTripTime:
         parse_success =
             out->initial_round_trip_time_us.Read(&value_reader, error_details);
@@ -1762,5 +1818,4 @@
     parameters.version_information->other_versions = std::move(clean_versions);
   }
 }
-
 }  // namespace quic
diff --git a/quiche/quic/core/crypto/transport_parameters.h b/quiche/quic/core/crypto/transport_parameters.h
index 7467814..e82a42b 100644
--- a/quiche/quic/core/crypto/transport_parameters.h
+++ b/quiche/quic/core/crypto/transport_parameters.h
@@ -265,6 +265,10 @@
   // Google internal handshake message.
   std::optional<std::string> google_handshake_message;
 
+  // Debugging Server Name Indication. This is used to send the obfuscated SNI
+  // in the transport parameters to the server for debugging purposes only.
+  std::optional<std::string> debugging_sni;
+
   // Google-specific connection options.
   std::optional<QuicTagVector> google_connection_options;
 
diff --git a/quiche/quic/core/crypto/transport_parameters_test.cc b/quiche/quic/core/crypto/transport_parameters_test.cc
index 04f3311..bf69dc1 100644
--- a/quiche/quic/core/crypto/transport_parameters_test.cc
+++ b/quiche/quic/core/crypto/transport_parameters_test.cc
@@ -57,6 +57,8 @@
 const char kFakeGoogleHandshakeMessage[] =
     "01000106030392655f5230270d4964a4f99b15bbad220736d972aea97bf9ac494ead62e6";
 
+const char kFakeSni[] = "example.com";
+
 QuicConnectionId CreateFakeOriginalDestinationConnectionId() {
   return TestConnectionId(0x1337);
 }
@@ -302,6 +304,7 @@
   ASSERT_TRUE(absl::HexStringToBytes(kFakeGoogleHandshakeMessage,
                                      &google_handshake_message));
   orig_params.google_handshake_message = std::move(google_handshake_message);
+  orig_params.debugging_sni = kFakeSni;
   orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
   orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
   orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
@@ -342,6 +345,7 @@
   ASSERT_TRUE(absl::HexStringToBytes(kFakeGoogleHandshakeMessage,
                                      &google_handshake_message));
   orig_params.google_handshake_message = std::move(google_handshake_message);
+  orig_params.debugging_sni = kFakeSni;
   orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
   orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
   orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
@@ -497,6 +501,14 @@
               "Invalid transport parameters [Client active_connection_id_limit"
               " 0 (Invalid)]");
   }
+  {
+    TransportParameters params;
+    std::string error_details;
+    params.perspective = Perspective::IS_SERVER;
+    params.debugging_sni = kFakeSni;
+    EXPECT_FALSE(params.AreValid(&error_details));
+    EXPECT_EQ(error_details, "Server cannot send debugging_sni");
+  }
 }
 
 TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) {
@@ -587,6 +599,10 @@
       0x01, 0x00, 0x01, 0x06, 0x03, 0x03, 0x92, 0x65, 0x5f, 0x52, 0x30, 0x27,
       0x0d, 0x49, 0x64, 0xa4, 0xf9, 0x9b, 0x15, 0xbb, 0xad, 0x22, 0x07, 0x36,
       0xd9, 0x72, 0xae, 0xa9, 0x7b, 0xf9, 0xac, 0x49, 0x4e, 0xad, 0x62, 0xe6,
+      // debugging_sni
+      0xc0, 0x00, 0x00, 0x00, 0x21, 0x9b, 0xbc, 0xd0,  // parameter id
+      0x0b,  // length
+      0x27, 0x03, 0x21, 0x0e, 0x61, 0x46, 0x0a, 0x2b, 0x3b, 0x70, 0x12,
       // initial_round_trip_time_us
       0x71, 0x27,  // parameter id
       0x01,  // length
@@ -664,8 +680,11 @@
   std::string expected_google_handshake_message;
   ASSERT_TRUE(absl::HexStringToBytes(kFakeGoogleHandshakeMessage,
                                      &expected_google_handshake_message));
+
   EXPECT_EQ(expected_google_handshake_message,
             new_params.google_handshake_message);
+
+  EXPECT_EQ(kFakeSni, new_params.debugging_sni);
 }
 
 TEST_P(TransportParametersTest,
@@ -1106,6 +1125,8 @@
   ASSERT_TRUE(absl::HexStringToBytes(kFakeGoogleHandshakeMessage,
                                      &google_handshake_message));
   orig_params.google_handshake_message = std::move(google_handshake_message);
+  orig_params.debugging_sni = kFakeSni;
+
   orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
   orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
   orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
@@ -1128,6 +1149,39 @@
   EXPECT_EQ(new_params, orig_params);
 }
 
+TEST_P(TransportParametersTest, DebuggingSniParsingClientToServer) {
+  TransportParameters orig_params;
+  orig_params.perspective = Perspective::IS_CLIENT;
+  orig_params.legacy_version_information =
+      CreateFakeLegacyVersionInformationClient();
+  orig_params.debugging_sni = kFakeSni;
+
+  std::vector<uint8_t> serialized;
+  ASSERT_TRUE(SerializeTransportParameters(orig_params, &serialized));
+
+  TransportParameters parsed_params;
+  std::string error_details;
+  ASSERT_TRUE(ParseTransportParameters(GetParam(), Perspective::IS_CLIENT,
+                                       serialized.data(), serialized.size(),
+                                       &parsed_params, &error_details));
+  EXPECT_TRUE(parsed_params.debugging_sni.has_value());
+  EXPECT_EQ(parsed_params.debugging_sni, kFakeSni);
+}
+
+TEST_P(TransportParametersTest, ServerCannotSendDebuggingSni) {
+  TransportParameters orig_params;
+  orig_params.perspective = Perspective::IS_SERVER;
+  orig_params.legacy_version_information =
+      CreateFakeLegacyVersionInformationServer();
+  orig_params.debugging_sni = kFakeSni;
+
+  std::vector<uint8_t> out;
+  EXPECT_QUIC_BUG(
+      EXPECT_FALSE(SerializeTransportParameters(orig_params, &out)),
+      "Not serializing invalid transport parameters: Server cannot send "
+      "debugging_sni");
+}
+
 class TransportParametersTicketSerializationTest : public QuicTest {
  protected:
   void SetUp() override {
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc
index 386112a..7d08ba8 100644
--- a/quiche/quic/core/http/end_to_end_test.cc
+++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -6801,6 +6801,51 @@
   server_thread_->Resume();
 }
 
+TEST_P(EndToEndTest, SniInClientTransportParameters) {
+  if (!version_.UsesTls()) {
+    ASSERT_TRUE(Initialize());
+    return;
+  }
+  const std::string debugging_sni = "test.example.com";
+  client_config_.SetDebuggingSniToSend(debugging_sni);
+  ASSERT_TRUE(Initialize());
+
+  EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+
+  server_thread_->Pause();
+  QuicSpdySession* server_session = GetServerSession();
+  QuicConfig* server_config = nullptr;
+  ASSERT_TRUE(server_session);
+  server_config = server_session->config();
+  ASSERT_TRUE(server_config);
+  const std::optional<std::string>& received_sni =
+      server_config->GetReceivedDebuggingSni();
+  EXPECT_THAT(received_sni, testing::Optional(debugging_sni));
+  server_thread_->Resume();
+}
+
+TEST_P(EndToEndTest, NoSniInClientTransportParameters) {
+  if (!version_.UsesTls()) {
+    // SNI in transport parameters is only supported with TLS.
+    ASSERT_TRUE(Initialize());
+    return;
+  }
+  ASSERT_TRUE(Initialize());
+
+  EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+
+  server_thread_->Pause();
+  QuicSpdySession* server_session = GetServerSession();
+  QuicConfig* server_config = nullptr;
+  ASSERT_TRUE(server_session);
+  server_config = server_session->config();
+  ASSERT_TRUE(server_config);
+  const std::optional<std::string>& received_sni =
+      server_config->GetReceivedDebuggingSni();
+  ASSERT_FALSE(received_sni.has_value());
+  server_thread_->Resume();
+}
+
 // Testing packet writer that parses initial packets and saves information
 // relevant to chaos protection.
 class ChaosPacketWriter : public PacketDroppingTestWriter {
diff --git a/quiche/quic/core/quic_config.cc b/quiche/quic/core/quic_config.cc
index 8e92841..222b3ad 100644
--- a/quiche/quic/core/quic_config.cc
+++ b/quiche/quic/core/quic_config.cc
@@ -507,6 +507,14 @@
   return received_google_handshake_message_;
 }
 
+void QuicConfig::SetDebuggingSniToSend(const std::string& debugging_sni) {
+  debugging_sni_to_send_ = debugging_sni;
+}
+
+const std::optional<std::string>& QuicConfig::GetReceivedDebuggingSni() const {
+  return received_debugging_sni_;
+}
+
 void QuicConfig::SetDiscardLengthToSend(int32_t discard_length) {
   discard_length_to_send_ = discard_length;
 }
@@ -1292,6 +1300,9 @@
   if (google_handshake_message_to_send_.has_value()) {
     params->google_handshake_message = google_handshake_message_to_send_;
   }
+  if (debugging_sni_to_send_.has_value()) {
+    params->debugging_sni = debugging_sni_to_send_;
+  }
 
   params->discard_length = discard_length_to_send_;
 
@@ -1429,6 +1440,9 @@
   if (params.google_handshake_message.has_value()) {
     received_google_handshake_message_ = params.google_handshake_message;
   }
+  if (params.debugging_sni.has_value()) {
+    received_debugging_sni_ = params.debugging_sni;
+  }
 
   received_custom_transport_parameters_ = params.custom_parameters;
 
diff --git a/quiche/quic/core/quic_config.h b/quiche/quic/core/quic_config.h
index 343ca2a..05908ae 100644
--- a/quiche/quic/core/quic_config.h
+++ b/quiche/quic/core/quic_config.h
@@ -266,6 +266,10 @@
 
   const std::optional<std::string>& GetReceivedGoogleHandshakeMessage() const;
 
+  void SetDebuggingSniToSend(const std::string& debugging_sni);
+
+  const std::optional<std::string>& GetReceivedDebuggingSni() const;
+
   // Sets initial received connection options.  All received connection options
   // will be initialized with these fields. Initial received options may only be
   // set once per config, prior to the setting of any other options.  If options
@@ -744,6 +748,12 @@
   std::optional<std::string> google_handshake_message_to_send_;
   std::optional<std::string> received_google_handshake_message_;
 
+  // Debugging Server Name Indication. These fields are used to send and get the
+  // SNI in the transport parameters from client to the server for
+  // debugging purposes only.
+  std::optional<std::string> debugging_sni_to_send_;
+  std::optional<std::string> received_debugging_sni_;
+
   // Support for RESET_STREAM_AT frame.
   bool reliable_stream_reset_;
 };
diff --git a/quiche/quic/core/quic_config_test.cc b/quiche/quic/core/quic_config_test.cc
index 7c4d3f9..7229ac0 100644
--- a/quiche/quic/core/quic_config_test.cc
+++ b/quiche/quic/core/quic_config_test.cc
@@ -474,6 +474,7 @@
     return;
   }
   const std::string kFakeGoogleHandshakeMessage = "Fake handshake message";
+  const std::string kFakeSni = "example.com";
   const int32_t kDiscardLength = 2000;
   config_.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(
       2 * kMinimumFlowControlSendWindow);
@@ -491,6 +492,7 @@
   config_.SetMinAckDelayDraft10Ms(kDefaultMinAckDelayTimeMs);
   config_.SetDiscardLengthToSend(kDiscardLength);
   config_.SetGoogleHandshakeMessageToSend(kFakeGoogleHandshakeMessage);
+  config_.SetDebuggingSniToSend(kFakeSni);
   config_.SetReliableStreamReset(true);
 
   QuicIpAddress host;
@@ -553,6 +555,7 @@
             new_stateless_reset_token);
   EXPECT_EQ(kDiscardLength, params.discard_length);
   EXPECT_EQ(kFakeGoogleHandshakeMessage, params.google_handshake_message);
+  EXPECT_EQ(kFakeSni, params.debugging_sni);
 
   EXPECT_TRUE(params.reliable_stream_reset);
 }
@@ -665,6 +668,7 @@
     return;
   }
   const std::string kFakeGoogleHandshakeMessage = "Fake handshake message";
+  const std::string kFakeSni = "example.com";
   const int32_t kDiscardLength = 2000;
   TransportParameters params;
 
@@ -687,6 +691,7 @@
   params.retry_source_connection_id = TestConnectionId(0x3333);
   params.discard_length = kDiscardLength;
   params.google_handshake_message = kFakeGoogleHandshakeMessage;
+  params.debugging_sni = kFakeSni;
 
   std::string error_details;
   EXPECT_THAT(config_.ProcessTransportParameters(
@@ -807,6 +812,7 @@
             TestConnectionId(0x3333));
   EXPECT_EQ(kFakeGoogleHandshakeMessage,
             config_.GetReceivedGoogleHandshakeMessage());
+  EXPECT_EQ(kFakeSni, config_.GetReceivedDebuggingSni());
   EXPECT_EQ(kDiscardLength, config_.GetDiscardLengthReceived());
 }