Add google_handshake_message transport parameter.

PiperOrigin-RevId: 483816526
diff --git a/quiche/quic/core/crypto/transport_parameters.cc b/quiche/quic/core/crypto/transport_parameters.cc
index 140c16a..7aa2e05 100644
--- a/quiche/quic/core/crypto/transport_parameters.cc
+++ b/quiche/quic/core/crypto/transport_parameters.cc
@@ -53,6 +53,8 @@
 
   kMaxDatagramFrameSize = 0x20,
 
+  kGoogleHandshakeMessage = 0x26ab,
+
   kInitialRoundTripTime = 0x3127,
   kGoogleConnectionOptions = 0x3128,
   // 0x3129 was used to convey the user agent string.
@@ -119,6 +121,8 @@
       return "retry_source_connection_id";
     case TransportParameters::kMaxDatagramFrameSize:
       return "max_datagram_frame_size";
+    case TransportParameters::kGoogleHandshakeMessage:
+      return "google_handshake_message";
     case TransportParameters::kInitialRoundTripTime:
       return "initial_round_trip_time";
     case TransportParameters::kGoogleConnectionOptions:
@@ -154,6 +158,7 @@
     case TransportParameters::kInitialSourceConnectionId:
     case TransportParameters::kRetrySourceConnectionId:
     case TransportParameters::kMaxDatagramFrameSize:
+    case TransportParameters::kGoogleHandshakeMessage:
     case TransportParameters::kInitialRoundTripTime:
     case TransportParameters::kGoogleConnectionOptions:
     case TransportParameters::kGoogleQuicVersion:
@@ -419,6 +424,11 @@
           retry_source_connection_id.value().ToString();
   }
   rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true);
+  if (google_handshake_message.has_value()) {
+    absl::StrAppend(&rv, " ",
+                    TransportParameterIdToString(kGoogleHandshakeMessage),
+                    " length: ", google_handshake_message.value().length());
+  }
   rv += initial_round_trip_time_us.ToString(/*for_use_in_list=*/true);
   if (google_connection_options.has_value()) {
     rv += " " + TransportParameterIdToString(kGoogleConnectionOptions) + " ";
@@ -505,6 +515,7 @@
       retry_source_connection_id(other.retry_source_connection_id),
       max_datagram_frame_size(other.max_datagram_frame_size),
       initial_round_trip_time_us(other.initial_round_trip_time_us),
+      google_handshake_message(other.google_handshake_message),
       google_connection_options(other.google_connection_options),
       custom_parameters(other.custom_parameters) {
   if (other.preferred_address) {
@@ -545,6 +556,7 @@
             rhs.max_datagram_frame_size.value() &&
         initial_round_trip_time_us.value() ==
             rhs.initial_round_trip_time_us.value() &&
+        google_handshake_message == rhs.google_handshake_message &&
         google_connection_options == rhs.google_connection_options &&
         custom_parameters == rhs.custom_parameters)) {
     return false;
@@ -616,6 +628,11 @@
     }
   }
   if (perspective == Perspective::IS_SERVER &&
+      google_handshake_message.has_value()) {
+    *error_details = "Server cannot send google_handshake_message";
+    return false;
+  }
+  if (perspective == Perspective::IS_SERVER &&
       initial_round_trip_time_us.value() > 0) {
     *error_details = "Server cannot send initial round trip time";
     return false;
@@ -726,6 +743,7 @@
       kConnectionIdParameterLength +      // retry_source_connection_id
       kIntegerParameterLength +           // max_datagram_frame_size
       kIntegerParameterLength +           // initial_round_trip_time_us
+      kTypeAndValueLength +               // google_handshake_message
       kTypeAndValueLength +               // google_connection_options
       kTypeAndValueLength;                // google-version
 
@@ -745,6 +763,7 @@
       TransportParameters::kMinAckDelay,
       TransportParameters::kActiveConnectionIdLimit,
       TransportParameters::kMaxDatagramFrameSize,
+      TransportParameters::kGoogleHandshakeMessage,
       TransportParameters::kInitialRoundTripTime,
       TransportParameters::kDisableActiveMigration,
       TransportParameters::kPreferredAddress,
@@ -777,6 +796,10 @@
         (in.version_information.value().other_versions.size() + 1) *
             sizeof(QuicVersionLabel);
   }
+  // google_handshake_message.
+  if (in.google_handshake_message.has_value()) {
+    max_transport_param_length += in.google_handshake_message.value().length();
+  }
 
   // Add a random GREASE transport parameter, as defined in the
   // "Reserved Transport Parameters" section of RFC 9000.
@@ -958,6 +981,20 @@
           return false;
         }
       } break;
+      // google_handshake_message
+      case TransportParameters::kGoogleHandshakeMessage: {
+        if (in.google_handshake_message.has_value()) {
+          if (!writer.WriteVarInt62(
+                  TransportParameters::kGoogleHandshakeMessage) ||
+              !writer.WriteStringPieceVarInt62(
+                  in.google_handshake_message.value())) {
+            QUIC_BUG(Failed to write google_handshake_message)
+                << "Failed to write google_handshake_message: "
+                << in.google_handshake_message.value() << " for " << in;
+            return false;
+          }
+        }
+      } break;
       // initial_round_trip_time_us
       case TransportParameters::kInitialRoundTripTime: {
         if (!in.initial_round_trip_time_us.Write(&writer)) {
@@ -1386,6 +1423,14 @@
         parse_success =
             out->max_datagram_frame_size.Read(&value_reader, error_details);
         break;
+      case TransportParameters::kGoogleHandshakeMessage:
+        if (out->google_handshake_message.has_value()) {
+          *error_details = "Received a second google_handshake_message";
+          return false;
+        }
+        out->google_handshake_message =
+            std::string(value_reader.ReadRemainingPayload());
+        break;
       case TransportParameters::kInitialRoundTripTime:
         parse_success =
             out->initial_round_trip_time_us.Read(&value_reader, error_details);
diff --git a/quiche/quic/core/crypto/transport_parameters.h b/quiche/quic/core/crypto/transport_parameters.h
index 14ae6e9..e62d1ef 100644
--- a/quiche/quic/core/crypto/transport_parameters.h
+++ b/quiche/quic/core/crypto/transport_parameters.h
@@ -252,6 +252,9 @@
   // initial round-trip time in microseconds.
   IntegerParameter initial_round_trip_time_us;
 
+  // Google internal handshake message.
+  absl::optional<std::string> google_handshake_message;
+
   // Google-specific connection options.
   absl::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 76613f0..569a5a0 100644
--- a/quiche/quic/core/crypto/transport_parameters_test.cc
+++ b/quiche/quic/core/crypto/transport_parameters_test.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "absl/base/macros.h"
+#include "absl/strings/escaping.h"
 #include "absl/strings/string_view.h"
 #include "quiche/quic/core/crypto/crypto_protocol.h"
 #include "quiche/quic/core/quic_connection_id.h"
@@ -45,6 +46,9 @@
     static_cast<TransportParameters::TransportParameterId>(0xff34);
 const char* kCustomParameter2Value = "bar";
 
+const char kFakeGoogleHandshakeMessage[] =
+    "01000106030392655f5230270d4964a4f99b15bbad220736d972aea97bf9ac494ead62e6";
+
 QuicConnectionId CreateFakeOriginalDestinationConnectionId() {
   return TestConnectionId(0x1337);
 }
@@ -284,6 +288,8 @@
       CreateFakeInitialSourceConnectionId();
   orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId();
   orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
+  orig_params.google_handshake_message =
+      absl::HexStringToBytes(kFakeGoogleHandshakeMessage);
   orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
   orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
   orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
@@ -318,6 +324,8 @@
   orig_params.initial_source_connection_id =
       CreateFakeInitialSourceConnectionId();
   orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
+  orig_params.google_handshake_message =
+      absl::HexStringToBytes(kFakeGoogleHandshakeMessage);
   orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
   orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
   orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
@@ -548,6 +556,12 @@
       0x0f,  // parameter id
       0x08,  // length
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
+      // google_handshake_message
+      0x66, 0xab,  // parameter id
+      0x24,  // length
+      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,
       // initial_round_trip_time_us
       0x71, 0x27,  // parameter id
       0x01,  // length
@@ -620,6 +634,8 @@
   ASSERT_TRUE(new_params.google_connection_options.has_value());
   EXPECT_EQ(CreateFakeGoogleConnectionOptions(),
             new_params.google_connection_options.value());
+  EXPECT_EQ(absl::HexStringToBytes(kFakeGoogleHandshakeMessage),
+            new_params.google_handshake_message);
 }
 
 TEST_P(TransportParametersTest,
diff --git a/quiche/quic/core/quic_config.cc b/quiche/quic/core/quic_config.cc
index 04aa196..c059787 100644
--- a/quiche/quic/core/quic_config.cc
+++ b/quiche/quic/core/quic_config.cc
@@ -467,6 +467,15 @@
   connection_options_.SetSendValues(connection_options);
 }
 
+void QuicConfig::SetGoogleHandshakeMessageToSend(const std::string& message) {
+  google_handshake_message_to_send_ = message;
+}
+
+absl::optional<std::string> QuicConfig::GetReceivedGoogleHandshakeMessage()
+    const {
+  return received_google_handshake_message_;
+}
+
 bool QuicConfig::HasReceivedConnectionOptions() const {
   return connection_options_.HasReceivedValues();
 }
@@ -1253,6 +1262,10 @@
     params->google_connection_options = connection_options_.GetSendValues();
   }
 
+  if (google_handshake_message_to_send_.has_value()) {
+    params->google_handshake_message = google_handshake_message_to_send_;
+  }
+
   params->custom_parameters = custom_transport_parameters_to_send_;
 
   return true;
@@ -1384,6 +1397,9 @@
     connection_options_.SetReceivedValues(
         params.google_connection_options.value());
   }
+  if (params.google_handshake_message.has_value()) {
+    received_google_handshake_message_ = params.google_handshake_message;
+  }
 
   received_custom_transport_parameters_ = params.custom_parameters;
 
diff --git a/quiche/quic/core/quic_config.h b/quiche/quic/core/quic_config.h
index 846872f..7abfb7d 100644
--- a/quiche/quic/core/quic_config.h
+++ b/quiche/quic/core/quic_config.h
@@ -247,6 +247,10 @@
 
   bool HasReceivedConnectionOptions() const;
 
+  void SetGoogleHandshakeMessageToSend(const std::string& message);
+
+  absl::optional<std::string> GetReceivedGoogleHandshakeMessage() 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
@@ -657,6 +661,10 @@
   // handshake.
   TransportParameters::ParameterMap custom_transport_parameters_to_send_;
   TransportParameters::ParameterMap received_custom_transport_parameters_;
+
+  // Google internal handshake message.
+  absl::optional<std::string> google_handshake_message_to_send_;
+  absl::optional<std::string> received_google_handshake_message_;
 };
 
 }  // namespace quic
diff --git a/quiche/quic/core/quic_config_test.cc b/quiche/quic/core/quic_config_test.cc
index fc8afe8..244d967 100644
--- a/quiche/quic/core/quic_config_test.cc
+++ b/quiche/quic/core/quic_config_test.cc
@@ -459,6 +459,7 @@
     // TransportParameters are only used for QUIC+TLS.
     return;
   }
+  const std::string kFakeGoogleHandshakeMessage = "Fake handshake message";
   config_.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(
       2 * kMinimumFlowControlSendWindow);
   config_.SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend(
@@ -473,6 +474,7 @@
   config_.SetInitialSourceConnectionIdToSend(TestConnectionId(0x2222));
   config_.SetRetrySourceConnectionIdToSend(TestConnectionId(0x3333));
   config_.SetMinAckDelayMs(kDefaultMinAckDelayTimeMs);
+  config_.SetGoogleHandshakeMessageToSend(kFakeGoogleHandshakeMessage);
 
   QuicIpAddress host;
   host.FromString("127.0.3.1");
@@ -520,6 +522,7 @@
   EXPECT_EQ(*reinterpret_cast<StatelessResetToken*>(
                 &params.preferred_address->stateless_reset_token.front()),
             new_stateless_reset_token);
+  EXPECT_EQ(kFakeGoogleHandshakeMessage, params.google_handshake_message);
 }
 
 TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
@@ -527,6 +530,7 @@
     // TransportParameters are only used for QUIC+TLS.
     return;
   }
+  const std::string kFakeGoogleHandshakeMessage = "Fake handshake message";
   TransportParameters params;
 
   params.initial_max_stream_data_bidi_local.set_value(
@@ -546,6 +550,7 @@
   params.original_destination_connection_id = TestConnectionId(0x1111);
   params.initial_source_connection_id = TestConnectionId(0x2222);
   params.retry_source_connection_id = TestConnectionId(0x3333);
+  params.google_handshake_message = kFakeGoogleHandshakeMessage;
 
   std::string error_details;
   EXPECT_THAT(config_.ProcessTransportParameters(
@@ -664,6 +669,8 @@
   ASSERT_TRUE(config_.HasReceivedRetrySourceConnectionId());
   EXPECT_EQ(config_.ReceivedRetrySourceConnectionId(),
             TestConnectionId(0x3333));
+  EXPECT_EQ(kFakeGoogleHandshakeMessage,
+            config_.GetReceivedGoogleHandshakeMessage());
 }
 
 TEST_P(QuicConfigTest, DisableMigrationTransportParameter) {