Add support for IETF QUIC RFCv1

This CL adds support for the final RFC version of QUIC, which will have ALPN h3. Since the RFC has not shipped yet, the flag is marked enabling_blocked_by until we get the go-ahead to ship from the IETF.

Protected by quic_reloadable_flag_quic_enable_version_rfcv1.

PiperOrigin-RevId: 355042709
Change-Id: Idf80d71435c38855a89958037123e4944abc35bb
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc
index 113d9cf..a2e205b 100644
--- a/quic/core/crypto/crypto_utils.cc
+++ b/quic/core/crypto/crypto_utils.cc
@@ -135,6 +135,9 @@
 const uint8_t kDraft29InitialSalt[] = {0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2,
                                        0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61,
                                        0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99};
+const uint8_t kRFCv1InitialSalt[] = {0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34,
+                                     0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
+                                     0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a};
 
 // Salts used by deployed versions of QUIC. When introducing a new version,
 // generate a new salt by running `openssl rand -hex 20`.
@@ -155,9 +158,12 @@
 
 const uint8_t* InitialSaltForVersion(const ParsedQuicVersion& version,
                                      size_t* out_len) {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync with initial encryption salts");
-  if (version == ParsedQuicVersion::Draft29()) {
+  if (version == ParsedQuicVersion::RFCv1()) {
+    *out_len = ABSL_ARRAYSIZE(kRFCv1InitialSalt);
+    return kRFCv1InitialSalt;
+  } else if (version == ParsedQuicVersion::Draft29()) {
     *out_len = ABSL_ARRAYSIZE(kDraft29InitialSalt);
     return kDraft29InitialSalt;
   } else if (version == ParsedQuicVersion::T051()) {
@@ -184,6 +190,11 @@
                                              0x6c, 0xb9, 0x6b, 0xe1};
 const uint8_t kDraft29RetryIntegrityNonce[] = {
     0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c};
+const uint8_t kRFCv1RetryIntegrityKey[] = {0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66,
+                                           0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54,
+                                           0xe3, 0x68, 0xc8, 0x4e};
+const uint8_t kRFCv1RetryIntegrityNonce[] = {
+    0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb};
 
 // Keys used by Google versions of QUIC. When introducing a new version,
 // generate a new key by running `openssl rand -hex 16`.
@@ -205,12 +216,20 @@
 bool RetryIntegrityKeysForVersion(const ParsedQuicVersion& version,
                                   absl::string_view* key,
                                   absl::string_view* nonce) {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync with retry integrity keys");
   if (!version.UsesTls()) {
     QUIC_BUG << "Attempted to get retry integrity keys for invalid version "
              << version;
     return false;
+  } else if (version == ParsedQuicVersion::RFCv1()) {
+    *key = absl::string_view(
+        reinterpret_cast<const char*>(kRFCv1RetryIntegrityKey),
+        ABSL_ARRAYSIZE(kRFCv1RetryIntegrityKey));
+    *nonce = absl::string_view(
+        reinterpret_cast<const char*>(kRFCv1RetryIntegrityNonce),
+        ABSL_ARRAYSIZE(kRFCv1RetryIntegrityNonce));
+    return true;
   } else if (version == ParsedQuicVersion::Draft29()) {
     *key = absl::string_view(
         reinterpret_cast<const char*>(kDraft29RetryIntegrityKey),
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index b3a3d13..9ad044d 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -10007,6 +10007,10 @@
   }
 
   // These values come from draft-ietf-quic-tls Appendix A.4.
+  char retry_packet_rfcv1[] = {
+      0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a,
+      0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x04, 0xa2, 0x65, 0xba,
+      0x2e, 0xff, 0x4d, 0x82, 0x90, 0x58, 0xfb, 0x3f, 0x0f, 0x24, 0x96, 0xba};
   char retry_packet29[] = {
       0xff, 0xff, 0x00, 0x00, 0x1d, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a,
       0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xd1, 0x69, 0x26, 0xd8,
@@ -10014,7 +10018,10 @@
 
   char* retry_packet;
   size_t retry_packet_length;
-  if (version() == ParsedQuicVersion::Draft29()) {
+  if (version() == ParsedQuicVersion::RFCv1()) {
+    retry_packet = retry_packet_rfcv1;
+    retry_packet_length = ABSL_ARRAYSIZE(retry_packet_rfcv1);
+  } else if (version() == ParsedQuicVersion::Draft29()) {
     retry_packet = retry_packet29;
     retry_packet_length = ABSL_ARRAYSIZE(retry_packet29);
   } else {
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index 26742d7..3f2f8cc 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -1306,7 +1306,7 @@
                              received_packet44);
 }
 
-static_assert(quic::SupportedVersions().size() == 5u,
+static_assert(quic::SupportedVersions().size() == 6u,
               "Please add new RejectDeprecatedVersion tests above this assert "
               "when deprecating versions");
 
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index aa198ce..4f75fc1 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -41,6 +41,7 @@
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_server_on_wire_ping, true)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_token_based_address_validation, true)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_version_rfcv1, false)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_encrypted_control_frames, false)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_encrypted_goaway, true)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_willing_and_able_to_write2, true)
diff --git a/quic/core/quic_trace_visitor_test.cc b/quic/core/quic_trace_visitor_test.cc
index 5ebaea8..4deec7c 100644
--- a/quic/core/quic_trace_visitor_test.cc
+++ b/quic/core/quic_trace_visitor_test.cc
@@ -81,7 +81,9 @@
 TEST_F(QuicTraceVisitorTest, Version) {
   std::string version = trace_.protocol_version();
   ASSERT_EQ(4u, version.size());
-  EXPECT_NE(0, version[0]);
+  // Ensure version isn't all-zeroes.
+  EXPECT_TRUE(version[0] != 0 || version[1] != 0 || version[2] != 0 ||
+              version[3] != 0);
 }
 
 // Check that basic metadata about sent packets is recorded.
diff --git a/quic/core/quic_version_manager.cc b/quic/core/quic_version_manager.cc
index b8f99bd..1d4dcca 100644
--- a/quic/core/quic_version_manager.cc
+++ b/quic/core/quic_version_manager.cc
@@ -15,14 +15,15 @@
 
 QuicVersionManager::QuicVersionManager(
     ParsedQuicVersionVector supported_versions)
-    : disable_version_draft_29_(
+    : enable_version_rfcv1_(GetQuicReloadableFlag(quic_enable_version_rfcv1)),
+      disable_version_draft_29_(
           GetQuicReloadableFlag(quic_disable_version_draft_29)),
       disable_version_t051_(GetQuicReloadableFlag(quic_disable_version_t051)),
       disable_version_q050_(GetQuicReloadableFlag(quic_disable_version_q050)),
       disable_version_q046_(GetQuicReloadableFlag(quic_disable_version_q046)),
       disable_version_q043_(GetQuicReloadableFlag(quic_disable_version_q043)),
       allowed_supported_versions_(std::move(supported_versions)) {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync");
   RefilterSupportedVersions();
 }
@@ -46,9 +47,11 @@
 }
 
 void QuicVersionManager::MaybeRefilterSupportedVersions() {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync");
-  if (disable_version_draft_29_ !=
+  if (enable_version_rfcv1_ !=
+          GetQuicReloadableFlag(quic_enable_version_rfcv1) ||
+      disable_version_draft_29_ !=
           GetQuicReloadableFlag(quic_disable_version_draft_29) ||
       disable_version_t051_ !=
           GetQuicReloadableFlag(quic_disable_version_t051) ||
@@ -58,6 +61,7 @@
           GetQuicReloadableFlag(quic_disable_version_q046) ||
       disable_version_q043_ !=
           GetQuicReloadableFlag(quic_disable_version_q043)) {
+    enable_version_rfcv1_ = GetQuicReloadableFlag(quic_enable_version_rfcv1);
     disable_version_draft_29_ =
         GetQuicReloadableFlag(quic_disable_version_draft_29);
     disable_version_t051_ = GetQuicReloadableFlag(quic_disable_version_t051);
diff --git a/quic/core/quic_version_manager.h b/quic/core/quic_version_manager.h
index 0d0d021..f443395 100644
--- a/quic/core/quic_version_manager.h
+++ b/quic/core/quic_version_manager.h
@@ -50,6 +50,8 @@
 
  private:
   // Cached value of reloadable flags.
+  // quic_enable_version_rfcv1 flag
+  bool enable_version_rfcv1_;
   // quic_disable_version_draft_29 flag
   bool disable_version_draft_29_;
   // quic_disable_version_t051 flag
diff --git a/quic/core/quic_version_manager_test.cc b/quic/core/quic_version_manager_test.cc
index 63e17f9..5776b39 100644
--- a/quic/core/quic_version_manager_test.cc
+++ b/quic/core/quic_version_manager_test.cc
@@ -18,11 +18,12 @@
 class QuicVersionManagerTest : public QuicTest {};
 
 TEST_F(QuicVersionManagerTest, QuicVersionManager) {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync");
   for (const ParsedQuicVersion& version : AllSupportedVersions()) {
     QuicEnableVersion(version);
   }
+  QuicDisableVersion(ParsedQuicVersion::RFCv1());
   QuicDisableVersion(ParsedQuicVersion::Draft29());
   QuicDisableVersion(ParsedQuicVersion::T051());
   QuicVersionManager manager(AllSupportedVersions());
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
index 5320dd9..a189e26 100644
--- a/quic/core/quic_versions.cc
+++ b/quic/core/quic_versions.cc
@@ -42,11 +42,13 @@
 }
 
 void SetVersionFlag(const ParsedQuicVersion& version, bool should_enable) {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync");
   const bool enable = should_enable;
   const bool disable = !should_enable;
-  if (version == ParsedQuicVersion::Draft29()) {
+  if (version == ParsedQuicVersion::RFCv1()) {
+    SetQuicReloadableFlag(quic_enable_version_rfcv1, enable);
+  } else if (version == ParsedQuicVersion::Draft29()) {
     SetQuicReloadableFlag(quic_disable_version_draft_29, disable);
   } else if (version == ParsedQuicVersion::T051()) {
     SetQuicReloadableFlag(quic_disable_version_t051, disable);
@@ -167,6 +169,11 @@
   return VersionHasIetfQuicFrames(transport_version);
 }
 
+bool ParsedQuicVersion::UsesLegacyTlsExtension() const {
+  QUICHE_DCHECK(IsKnown());
+  return UsesTls() && transport_version <= QUIC_VERSION_IETF_DRAFT_29;
+}
+
 bool ParsedQuicVersion::UsesTls() const {
   QUICHE_DCHECK(IsKnown());
   return handshake_protocol == PROTOCOL_TLS1_3;
@@ -208,9 +215,11 @@
 }
 
 QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync");
-  if (parsed_version == ParsedQuicVersion::Draft29()) {
+  if (parsed_version == ParsedQuicVersion::RFCv1()) {
+    return MakeVersionLabel(0x00, 0x00, 0x00, 0x01);
+  } else if (parsed_version == ParsedQuicVersion::Draft29()) {
     return MakeVersionLabel(0xff, 0x00, 0x00, 29);
   } else if (parsed_version == ParsedQuicVersion::T051()) {
     return MakeVersionLabel('T', '0', '5', '1');
@@ -380,7 +389,11 @@
   ParsedQuicVersionVector filtered_versions;
   filtered_versions.reserve(versions.size());
   for (const ParsedQuicVersion& version : versions) {
-    if (version == ParsedQuicVersion::Draft29()) {
+    if (version == ParsedQuicVersion::RFCv1()) {
+      if (GetQuicReloadableFlag(quic_enable_version_rfcv1)) {
+        filtered_versions.push_back(version);
+      }
+    } else if (version == ParsedQuicVersion::Draft29()) {
       if (!GetQuicReloadableFlag(quic_disable_version_draft_29)) {
         filtered_versions.push_back(version);
       }
@@ -455,6 +468,7 @@
     RETURN_STRING_LITERAL(QUIC_VERSION_50);
     RETURN_STRING_LITERAL(QUIC_VERSION_51);
     RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_29);
+    RETURN_STRING_LITERAL(QUIC_VERSION_IETF_RFC_V1);
     RETURN_STRING_LITERAL(QUIC_VERSION_UNSUPPORTED);
     RETURN_STRING_LITERAL(QUIC_VERSION_RESERVED_FOR_NEGOTIATION);
   }
@@ -473,12 +487,14 @@
 }
 
 std::string ParsedQuicVersionToString(ParsedQuicVersion version) {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync");
   if (version == UnsupportedQuicVersion()) {
     return "0";
-  }
-  if (version == ParsedQuicVersion::Draft29()) {
+  } else if (version == ParsedQuicVersion::RFCv1()) {
+    QUICHE_DCHECK(version.UsesHttp3());
+    return "RFCv1";
+  } else if (version == ParsedQuicVersion::Draft29()) {
     QUICHE_DCHECK(version.UsesHttp3());
     return "draft29";
   }
@@ -567,7 +583,9 @@
 }
 
 std::string AlpnForVersion(ParsedQuicVersion parsed_version) {
-  if (parsed_version == ParsedQuicVersion::Draft29()) {
+  if (parsed_version == ParsedQuicVersion::RFCv1()) {
+    return "h3";
+  } else if (parsed_version == ParsedQuicVersion::Draft29()) {
     return "h3-29";
   }
   return "h3-" + ParsedQuicVersionToString(parsed_version);
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h
index dbcbd81..75a6826 100644
--- a/quic/core/quic_versions.h
+++ b/quic/core/quic_versions.h
@@ -123,6 +123,7 @@
   // Number 71 used to represent draft-ietf-quic-transport-27.
   // Number 72 used to represent draft-ietf-quic-transport-28.
   QUIC_VERSION_IETF_DRAFT_29 = 73,  // draft-ietf-quic-transport-29.
+  QUIC_VERSION_IETF_RFC_V1 = 80,    // Not-yet-published RFC.
   // Version 99 was a dumping ground for IETF QUIC changes which were not yet
   // yet ready for production between 2018-02 and 2020-02.
 
@@ -170,6 +171,7 @@
     QuicTransportVersion transport_version) {
   bool transport_version_is_valid = false;
   constexpr QuicTransportVersion valid_transport_versions[] = {
+      QUIC_VERSION_IETF_RFC_V1,
       QUIC_VERSION_IETF_DRAFT_29,
       QUIC_VERSION_51,
       QUIC_VERSION_50,
@@ -194,7 +196,8 @@
       return transport_version != QUIC_VERSION_UNSUPPORTED &&
              transport_version != QUIC_VERSION_RESERVED_FOR_NEGOTIATION &&
              transport_version != QUIC_VERSION_51 &&
-             transport_version != QUIC_VERSION_IETF_DRAFT_29;
+             transport_version != QUIC_VERSION_IETF_DRAFT_29 &&
+             transport_version != QUIC_VERSION_IETF_RFC_V1;
     case PROTOCOL_TLS1_3:
       return transport_version != QUIC_VERSION_UNSUPPORTED &&
              transport_version != QUIC_VERSION_50 &&
@@ -244,6 +247,10 @@
            transport_version != other.transport_version;
   }
 
+  static constexpr ParsedQuicVersion RFCv1() {
+    return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_RFC_V1);
+  }
+
   static constexpr ParsedQuicVersion Draft29() {
     return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_29);
   }
@@ -352,6 +359,9 @@
   // frames or not.
   bool HasIetfQuicFrames() const;
 
+  // Returns whether this version uses the legacy TLS extension codepoint.
+  bool UsesLegacyTlsExtension() const;
+
   // Returns whether this version uses PROTOCOL_TLS1_3.
   bool UsesTls() const;
 
@@ -390,11 +400,11 @@
   return {PROTOCOL_TLS1_3, PROTOCOL_QUIC_CRYPTO};
 }
 
-constexpr std::array<ParsedQuicVersion, 5> SupportedVersions() {
+constexpr std::array<ParsedQuicVersion, 6> SupportedVersions() {
   return {
-      ParsedQuicVersion::Draft29(), ParsedQuicVersion::T051(),
-      ParsedQuicVersion::Q050(),    ParsedQuicVersion::Q046(),
-      ParsedQuicVersion::Q043(),
+      ParsedQuicVersion::RFCv1(), ParsedQuicVersion::Draft29(),
+      ParsedQuicVersion::T051(),  ParsedQuicVersion::Q050(),
+      ParsedQuicVersion::Q046(),  ParsedQuicVersion::Q043(),
   };
 }
 
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc
index e3f46f6..c9bc8b3 100644
--- a/quic/core/quic_versions_test.cc
+++ b/quic/core/quic_versions_test.cc
@@ -371,23 +371,25 @@
 // yet a typo was made in doing the #defines and it was caught
 // only in some test far removed from here... Better safe than sorry.
 TEST_F(QuicVersionsTest, CheckTransportVersionNumbersForTypos) {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync");
   EXPECT_EQ(QUIC_VERSION_43, 43);
   EXPECT_EQ(QUIC_VERSION_46, 46);
   EXPECT_EQ(QUIC_VERSION_50, 50);
   EXPECT_EQ(QUIC_VERSION_51, 51);
   EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_29, 73);
+  EXPECT_EQ(QUIC_VERSION_IETF_RFC_V1, 80);
 }
 
 TEST_F(QuicVersionsTest, AlpnForVersion) {
-  static_assert(SupportedVersions().size() == 5u,
+  static_assert(SupportedVersions().size() == 6u,
                 "Supported versions out of sync");
   EXPECT_EQ("h3-Q043", AlpnForVersion(ParsedQuicVersion::Q043()));
   EXPECT_EQ("h3-Q046", AlpnForVersion(ParsedQuicVersion::Q046()));
   EXPECT_EQ("h3-Q050", AlpnForVersion(ParsedQuicVersion::Q050()));
   EXPECT_EQ("h3-T051", AlpnForVersion(ParsedQuicVersion::T051()));
   EXPECT_EQ("h3-29", AlpnForVersion(ParsedQuicVersion::Draft29()));
+  EXPECT_EQ("h3", AlpnForVersion(ParsedQuicVersion::RFCv1()));
 }
 
 TEST_F(QuicVersionsTest, QuicVersionEnabling) {
diff --git a/quic/core/tls_chlo_extractor.cc b/quic/core/tls_chlo_extractor.cc
index e03d7db..ca9eb5b 100644
--- a/quic/core/tls_chlo_extractor.cc
+++ b/quic/core/tls_chlo_extractor.cc
@@ -357,6 +357,13 @@
   const int rv = SSL_set_ex_data(ssl_.get(), ex_data_index, this);
   QUICHE_CHECK_EQ(rv, 1) << "Internal allocation failure in SSL_set_ex_data";
   SSL_set_accept_state(ssl_.get());
+
+  // Make sure we use the right TLS extension codepoint.
+  int use_legacy_extension = 0;
+  if (framer_->version().UsesLegacyTlsExtension()) {
+    use_legacy_extension = 1;
+  }
+  SSL_set_quic_use_legacy_codepoint(ssl_.get(), use_legacy_extension);
 }
 
 // Called by other methods to record any unrecoverable failures they experience.
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc
index b878ab8..448136f 100644
--- a/quic/core/tls_client_handshaker.cc
+++ b/quic/core/tls_client_handshaker.cc
@@ -63,6 +63,13 @@
     return false;
   }
 
+  // Make sure we use the right TLS extension codepoint.
+  int use_legacy_extension = 0;
+  if (session()->version().UsesLegacyTlsExtension()) {
+    use_legacy_extension = 1;
+  }
+  SSL_set_quic_use_legacy_codepoint(ssl(), use_legacy_extension);
+
   // Set the SNI to send, if any.
   SSL_set_connect_state(ssl());
   if (QUIC_DLOG_INFO_IS_ON() &&
diff --git a/quic/core/tls_server_handshaker.cc b/quic/core/tls_server_handshaker.cc
index 02fceed..c16eba9 100644
--- a/quic/core/tls_server_handshaker.cc
+++ b/quic/core/tls_server_handshaker.cc
@@ -189,6 +189,13 @@
   // Configure the SSL to be a server.
   SSL_set_accept_state(ssl());
 
+  // Make sure we use the right TLS extension codepoint.
+  int use_legacy_extension = 0;
+  if (session->version().UsesLegacyTlsExtension()) {
+    use_legacy_extension = 1;
+  }
+  SSL_set_quic_use_legacy_codepoint(ssl(), use_legacy_extension);
+
   if (GetQuicFlag(FLAGS_quic_disable_server_tls_resumption)) {
     SSL_set_options(ssl(), SSL_OP_NO_TICKET);
   }
@@ -379,12 +386,17 @@
   const uint8_t* client_params_bytes;
   size_t params_bytes_len;
   if (use_early_select_cert_) {
+    // Make sure we use the right TLS extension codepoint.
+    uint16_t extension_type = TLSEXT_TYPE_quic_transport_parameters_standard;
+    if (session()->version().UsesLegacyTlsExtension()) {
+      extension_type = TLSEXT_TYPE_quic_transport_parameters_legacy;
+    }
     // When using early select cert callback, SSL_get_peer_quic_transport_params
     // can not be used to retrieve the client's transport parameters, but we can
     // use SSL_early_callback_ctx_extension_get to do that.
-    if (!SSL_early_callback_ctx_extension_get(
-            client_hello, TLSEXT_TYPE_quic_transport_parameters,
-            &client_params_bytes, &params_bytes_len)) {
+    if (!SSL_early_callback_ctx_extension_get(client_hello, extension_type,
+                                              &client_params_bytes,
+                                              &params_bytes_len)) {
       params_bytes_len = 0;
     }
   } else {