Introduce QUIC version draft-28

This CL adds a new QUIC version and plumbs it where needed. It doesn't add any features specific to draft-28; those will come in subsequent CLs. The flag is marked enabling_blocked_by until then.

Introduce quic draft-28, protected by blocked flag gfe2_reloadable_flag_quic_enable_version_draft_28

PiperOrigin-RevId: 312770917
Change-Id: I89f8f41f902b1465b1c6d269177682865e7aae21
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc
index b6c6b7a..94d738a 100644
--- a/quic/core/crypto/crypto_utils.cc
+++ b/quic/core/crypto/crypto_utils.cc
@@ -117,6 +117,7 @@
 
 // Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-25#section-5.2
 // and https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-5.2
+// and https://tools.ietf.org/html/draft-ietf-quic-tls-28#section-5.2
 const uint8_t kDraft25InitialSalt[] = {0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb,
                                        0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4,
                                        0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02};
@@ -135,7 +136,7 @@
 
 const uint8_t* InitialSaltForVersion(const ParsedQuicVersion& version,
                                      size_t* out_len) {
-  static_assert(SupportedVersions().size() == 8u,
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync with initial encryption salts");
   switch (version.handshake_protocol) {
     case PROTOCOL_QUIC_CRYPTO:
@@ -166,6 +167,10 @@
           // draft-27 uses the same salt as draft-25.
           *out_len = QUICHE_ARRAYSIZE(kDraft25InitialSalt);
           return kDraft25InitialSalt;
+        case QUIC_VERSION_IETF_DRAFT_28:
+          // draft-28 uses the same salt as draft-25.
+          *out_len = QUICHE_ARRAYSIZE(kDraft25InitialSalt);
+          return kDraft25InitialSalt;
         default:
           QUIC_BUG << "No initial obfuscation salt for version " << version;
       }
@@ -183,6 +188,7 @@
 // Retry Integrity Protection Keys and Nonces.
 // https://tools.ietf.org/html/draft-ietf-quic-tls-25#section-5.8
 // https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-5.8
+// https://tools.ietf.org/html/draft-ietf-quic-tls-28#section-5.8
 const uint8_t kDraft25RetryIntegrityKey[] = {0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21,
                                              0x33, 0xc8, 0x41, 0xe4, 0x04, 0x3d,
                                              0xf2, 0x7d, 0x44, 0x30};
@@ -218,7 +224,9 @@
   if (version ==
           ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25) ||
       version ==
-          ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)) {
+          ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27) ||
+      version ==
+          ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_28)) {
     *key = quiche::QuicheStringPiece(
         reinterpret_cast<const char*>(kDraft25RetryIntegrityKey),
         QUICHE_ARRAYSIZE(kDraft25RetryIntegrityKey));
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index bb61130..34a4b4c 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -10384,11 +10384,19 @@
       0xff, 0xff, 0x00, 0x00, 0x1b, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a,
       0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xa5, 0x23, 0xcb, 0x5b,
       0xa5, 0x24, 0x69, 0x5f, 0x65, 0x69, 0xf2, 0x93, 0xa1, 0x35, 0x9d, 0x8e};
+  char retry_packet28[] = {
+      0xff, 0xff, 0x00, 0x00, 0x1c, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a,
+      0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xf7, 0x1a, 0x5f, 0x12,
+      0xaf, 0xe3, 0xec, 0xf8, 0x00, 0x1a, 0x92, 0x0e, 0x6f, 0xdf, 0x1d, 0x63};
 
   char* retry_packet;
   size_t retry_packet_length;
   if (version() ==
-      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)) {
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_28)) {
+    retry_packet = retry_packet28;
+    retry_packet_length = QUICHE_ARRAYSIZE(retry_packet28);
+  } else if (version() ==
+             ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27)) {
     retry_packet = retry_packet27;
     retry_packet_length = QUICHE_ARRAYSIZE(retry_packet27);
   } else if (version() ==
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index 38cf329..b1fbbab 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -1029,7 +1029,7 @@
 
 TEST_P(QuicDispatcherTestOneVersion,
        RejectDeprecatedVersionsWithVersionNegotiation) {
-  static_assert(quic::SupportedVersions().size() == 8u,
+  static_assert(quic::SupportedVersions().size() == 9u,
                 "Please add deprecated versions to this test");
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   CreateTimeWaitListManager();
@@ -2309,7 +2309,7 @@
 // Regression test for b/117874922.
 TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
   // Ensure the preferred version is not supported by the server.
-  SetQuicReloadableFlag(quic_enable_version_draft_27, false);
+  SetQuicReloadableFlag(quic_enable_version_draft_28, false);
   uint64_t last_connection_id = kMaxNumSessionsToCreate + 5;
   ParsedQuicVersionVector supported_versions = CurrentSupportedVersions();
   for (uint64_t conn_id = 1; conn_id <= last_connection_id; ++conn_id) {
diff --git a/quic/core/quic_version_manager.cc b/quic/core/quic_version_manager.cc
index 0a014be..d4cc329 100644
--- a/quic/core/quic_version_manager.cc
+++ b/quic/core/quic_version_manager.cc
@@ -15,7 +15,9 @@
 
 QuicVersionManager::QuicVersionManager(
     ParsedQuicVersionVector supported_versions)
-    : enable_version_draft_27_(
+    : enable_version_draft_28_(
+          GetQuicReloadableFlag(quic_enable_version_draft_28)),
+      enable_version_draft_27_(
           GetQuicReloadableFlag(quic_enable_version_draft_27)),
       enable_version_draft_25_(
           GetQuicReloadableFlag(quic_enable_version_draft_25_v3)),
@@ -26,7 +28,7 @@
       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() == 8u,
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync");
   RefilterSupportedVersions();
 }
@@ -56,9 +58,11 @@
 }
 
 void QuicVersionManager::MaybeRefilterSupportedVersions() {
-  static_assert(SupportedVersions().size() == 8u,
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync");
-  if (enable_version_draft_27_ !=
+  if (enable_version_draft_28_ !=
+          GetQuicReloadableFlag(quic_enable_version_draft_28) ||
+      enable_version_draft_27_ !=
           GetQuicReloadableFlag(quic_enable_version_draft_27) ||
       enable_version_draft_25_ !=
           GetQuicReloadableFlag(quic_enable_version_draft_25_v3) ||
@@ -74,6 +78,8 @@
           GetQuicReloadableFlag(quic_disable_version_q046) ||
       disable_version_q043_ !=
           GetQuicReloadableFlag(quic_disable_version_q043)) {
+    enable_version_draft_28_ =
+        GetQuicReloadableFlag(quic_enable_version_draft_28);
     enable_version_draft_27_ =
         GetQuicReloadableFlag(quic_enable_version_draft_27);
     enable_version_draft_25_ =
diff --git a/quic/core/quic_version_manager.h b/quic/core/quic_version_manager.h
index c5111ed..6a1afd2 100644
--- a/quic/core/quic_version_manager.h
+++ b/quic/core/quic_version_manager.h
@@ -52,6 +52,8 @@
 
  private:
   // Cached value of reloadable flags.
+  // quic_enable_version_draft_28 flag
+  bool enable_version_draft_28_;
   // quic_enable_version_draft_27 flag
   bool enable_version_draft_27_;
   // quic_enable_version_draft_25_v3 flag
diff --git a/quic/core/quic_version_manager_test.cc b/quic/core/quic_version_manager_test.cc
index 3a8e98f..7fbd2d1 100644
--- a/quic/core/quic_version_manager_test.cc
+++ b/quic/core/quic_version_manager_test.cc
@@ -18,8 +18,9 @@
 class QuicVersionManagerTest : public QuicTest {};
 
 TEST_F(QuicVersionManagerTest, QuicVersionManager) {
-  static_assert(SupportedVersions().size() == 8u,
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync");
+  SetQuicReloadableFlag(quic_enable_version_draft_28, false);
   SetQuicReloadableFlag(quic_enable_version_draft_27, false);
   SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false);
   SetQuicReloadableFlag(quic_enable_version_t050_v2, false);
@@ -54,10 +55,10 @@
       manager.GetSupportedAlpns(),
       ElementsAre("h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046", "h3-Q043"));
 
-  SetQuicReloadableFlag(quic_enable_version_draft_27, true);
+  SetQuicReloadableFlag(quic_enable_version_draft_28, true);
   expected_parsed_versions.insert(
       expected_parsed_versions.begin(),
-      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27));
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_28));
   EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
   EXPECT_EQ(expected_parsed_versions.size() - 1,
             manager.GetSupportedVersionsWithQuicCrypto().size());
@@ -66,36 +67,51 @@
   EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
             manager.GetSupportedVersionsWithQuicCrypto());
   EXPECT_THAT(manager.GetSupportedAlpns(),
-              ElementsAre("h3-27", "h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046",
+              ElementsAre("h3-28", "h3-Q050", "h3-Q049", "h3-Q048", "h3-Q046",
                           "h3-Q043"));
 
-  SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
+  SetQuicReloadableFlag(quic_enable_version_draft_27, true);
   expected_parsed_versions.insert(
       expected_parsed_versions.begin() + 1,
-      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27));
   EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
   EXPECT_EQ(expected_parsed_versions.size() - 2,
             manager.GetSupportedVersionsWithQuicCrypto().size());
-  EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
-            manager.GetSupportedVersionsWithQuicCrypto());
-  EXPECT_THAT(manager.GetSupportedAlpns(),
-              ElementsAre("h3-27", "h3-25", "h3-Q050", "h3-Q049", "h3-Q048",
-                          "h3-Q046", "h3-Q043"));
-
-  SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
-  expected_parsed_versions.insert(
-      expected_parsed_versions.begin() + 2,
-      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
-  EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
-  EXPECT_EQ(expected_parsed_versions.size() - 3,
-            manager.GetSupportedVersionsWithQuicCrypto().size());
   EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
             manager.GetSupportedVersions());
   EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
             manager.GetSupportedVersionsWithQuicCrypto());
   EXPECT_THAT(manager.GetSupportedAlpns(),
-              ElementsAre("h3-27", "h3-25", "h3-T050", "h3-Q050", "h3-Q049",
+              ElementsAre("h3-28", "h3-27", "h3-Q050", "h3-Q049", "h3-Q048",
+                          "h3-Q046", "h3-Q043"));
+
+  SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
+  expected_parsed_versions.insert(
+      expected_parsed_versions.begin() + 2,
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
+  EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
+  EXPECT_EQ(expected_parsed_versions.size() - 3,
+            manager.GetSupportedVersionsWithQuicCrypto().size());
+  EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
+            manager.GetSupportedVersionsWithQuicCrypto());
+  EXPECT_THAT(manager.GetSupportedAlpns(),
+              ElementsAre("h3-28", "h3-27", "h3-25", "h3-Q050", "h3-Q049",
                           "h3-Q048", "h3-Q046", "h3-Q043"));
+
+  SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
+  expected_parsed_versions.insert(
+      expected_parsed_versions.begin() + 3,
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
+  EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions());
+  EXPECT_EQ(expected_parsed_versions.size() - 4,
+            manager.GetSupportedVersionsWithQuicCrypto().size());
+  EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
+            manager.GetSupportedVersions());
+  EXPECT_EQ(CurrentSupportedVersionsWithQuicCrypto(),
+            manager.GetSupportedVersionsWithQuicCrypto());
+  EXPECT_THAT(manager.GetSupportedAlpns(),
+              ElementsAre("h3-28", "h3-27", "h3-25", "h3-T050", "h3-Q050",
+                          "h3-Q049", "h3-Q048", "h3-Q046", "h3-Q043"));
 }
 
 }  // namespace
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
index bf93e83..7e09d2f 100644
--- a/quic/core/quic_versions.cc
+++ b/quic/core/quic_versions.cc
@@ -158,6 +158,11 @@
   return transport_version >= QUIC_VERSION_IETF_DRAFT_27;
 }
 
+bool ParsedQuicVersion::AuthenticatesHandshakeConnectionIds() const {
+  DCHECK(IsKnown());
+  return transport_version >= QUIC_VERSION_IETF_DRAFT_28;
+}
+
 bool ParsedQuicVersion::UsesTls() const {
   DCHECK(IsKnown());
   return handshake_protocol == PROTOCOL_TLS1_3;
@@ -211,7 +216,7 @@
                << parsed_version.handshake_protocol;
       return 0;
   }
-  static_assert(SupportedVersions().size() == 8u,
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync");
   switch (parsed_version.transport_version) {
     case QUIC_VERSION_43:
@@ -236,6 +241,12 @@
       }
       QUIC_BUG << "QUIC_VERSION_IETF_DRAFT_27 requires TLS";
       return 0;
+    case QUIC_VERSION_IETF_DRAFT_28:
+      if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
+        return MakeVersionLabel(0xff, 0x00, 0x00, 28);
+      }
+      QUIC_BUG << "QUIC_VERSION_IETF_DRAFT_28 requires TLS";
+      return 0;
     case QUIC_VERSION_RESERVED_FOR_NEGOTIATION:
       return CreateRandomVersionLabelForNegotiation();
     default:
@@ -391,8 +402,13 @@
     ParsedQuicVersionVector versions) {
   ParsedQuicVersionVector filtered_versions;
   filtered_versions.reserve(versions.size());
-  for (ParsedQuicVersion version : versions) {
-    if (version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
+  for (const ParsedQuicVersion& version : versions) {
+    if (version.transport_version == QUIC_VERSION_IETF_DRAFT_28) {
+      QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3);
+      if (GetQuicReloadableFlag(quic_enable_version_draft_28)) {
+        filtered_versions.push_back(version);
+      }
+    } else if (version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
       QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3);
       if (GetQuicReloadableFlag(quic_enable_version_draft_27)) {
         filtered_versions.push_back(version);
@@ -518,7 +534,7 @@
     return #x
 
 std::string QuicVersionToString(QuicTransportVersion transport_version) {
-  static_assert(SupportedTransportVersions().size() == 7u,
+  static_assert(SupportedTransportVersions().size() == 8u,
                 "Supported versions out of sync");
   switch (transport_version) {
     RETURN_STRING_LITERAL(QUIC_VERSION_43);
@@ -528,6 +544,7 @@
     RETURN_STRING_LITERAL(QUIC_VERSION_50);
     RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_25);
     RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_27);
+    RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_28);
     RETURN_STRING_LITERAL(QUIC_VERSION_UNSUPPORTED);
     RETURN_STRING_LITERAL(QUIC_VERSION_RESERVED_FOR_NEGOTIATION);
   }
@@ -631,11 +648,12 @@
 
 std::string AlpnForVersion(ParsedQuicVersion parsed_version) {
   if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
-    if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_25) {
-      return "h3-25";
-    }
-    if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
+    if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_28) {
+      return "h3-28";
+    } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
       return "h3-27";
+    } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_25) {
+      return "h3-25";
     }
   }
   return "h3-" + ParsedQuicVersionToString(parsed_version);
@@ -646,9 +664,12 @@
 }
 
 void QuicEnableVersion(ParsedQuicVersion parsed_version) {
-  static_assert(SupportedVersions().size() == 8u,
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync");
-  if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
+  if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_28) {
+    QUIC_BUG_IF(parsed_version.handshake_protocol != PROTOCOL_TLS1_3);
+    SetQuicReloadableFlag(quic_enable_version_draft_28, true);
+  } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_27) {
     QUIC_BUG_IF(parsed_version.handshake_protocol != PROTOCOL_TLS1_3);
     SetQuicReloadableFlag(quic_enable_version_draft_27, true);
   } else if (parsed_version.transport_version == QUIC_VERSION_IETF_DRAFT_25) {
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h
index 8456a98..9e6a184 100644
--- a/quic/core/quic_versions.h
+++ b/quic/core/quic_versions.h
@@ -119,6 +119,7 @@
   QUIC_VERSION_50 = 50,  // Header protection and initial obfuscators.
   QUIC_VERSION_IETF_DRAFT_25 = 70,  // draft-ietf-quic-transport-25.
   QUIC_VERSION_IETF_DRAFT_27 = 71,  // draft-ietf-quic-transport-27.
+  QUIC_VERSION_IETF_DRAFT_28 = 72,  // draft-ietf-quic-transport-28.
   // Version 99 was a dumping ground for IETF QUIC changes which were not yet
   // yet ready for production between 2018-02 and 2020-02.
 
@@ -133,8 +134,9 @@
 
 // This array contains QUIC transport versions which we currently support.
 // DEPRECATED. Use SupportedVersions() instead.
-constexpr std::array<QuicTransportVersion, 7> SupportedTransportVersions() {
-  return {QUIC_VERSION_IETF_DRAFT_27,
+constexpr std::array<QuicTransportVersion, 8> SupportedTransportVersions() {
+  return {QUIC_VERSION_IETF_DRAFT_28,
+          QUIC_VERSION_IETF_DRAFT_27,
           QUIC_VERSION_IETF_DRAFT_25,
           QUIC_VERSION_50,
           QUIC_VERSION_49,
@@ -196,7 +198,8 @@
     case PROTOCOL_QUIC_CRYPTO:
       return transport_version != QUIC_VERSION_UNSUPPORTED &&
              transport_version != QUIC_VERSION_IETF_DRAFT_25 &&
-             transport_version != QUIC_VERSION_IETF_DRAFT_27;
+             transport_version != QUIC_VERSION_IETF_DRAFT_27 &&
+             transport_version != QUIC_VERSION_IETF_DRAFT_28;
     case PROTOCOL_TLS1_3:
       // The TLS handshake is only deployable if CRYPTO frames are also used.
       // We explicitly removed support for T048 and T049 to reduce test load.
@@ -336,6 +339,10 @@
   // encoding transport parameter types and lengths.
   bool HasVarIntTransportParams() const;
 
+  // Returns true if this version uses transport parameters to authenticate all
+  // the connection IDs used during the handshake.
+  bool AuthenticatesHandshakeConnectionIds() const;
+
   // Returns whether this version uses PROTOCOL_TLS1_3.
   bool UsesTls() const;
 
@@ -370,8 +377,9 @@
   return {PROTOCOL_TLS1_3, PROTOCOL_QUIC_CRYPTO};
 }
 
-constexpr std::array<ParsedQuicVersion, 8> SupportedVersions() {
+constexpr std::array<ParsedQuicVersion, 9> SupportedVersions() {
   return {
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_28),
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25),
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc
index 3a07221..52278f7 100644
--- a/quic/core/quic_versions_test.cc
+++ b/quic/core/quic_versions_test.cc
@@ -248,6 +248,10 @@
             ParseQuicVersionString("T050"));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
             ParseQuicVersionString("h3-T050"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_28),
+            ParseQuicVersionString("ff00001c"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_28),
+            ParseQuicVersionString("h3-28"));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
             ParseQuicVersionString("ff00001b"));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
@@ -266,6 +270,8 @@
                                      QUIC_VERSION_IETF_DRAFT_25);
   ParsedQuicVersion version_draft_27(PROTOCOL_TLS1_3,
                                      QUIC_VERSION_IETF_DRAFT_27);
+  ParsedQuicVersion version_draft_28(PROTOCOL_TLS1_3,
+                                     QUIC_VERSION_IETF_DRAFT_28);
 
   EXPECT_THAT(ParseQuicVersionVectorString(""), IsEmpty());
 
@@ -286,6 +292,8 @@
               ElementsAre(version_draft_25, version_draft_27));
   EXPECT_THAT(ParseQuicVersionVectorString("h3-27,h3-25"),
               ElementsAre(version_draft_27, version_draft_25));
+  EXPECT_THAT(ParseQuicVersionVectorString("h3-28,h3-27"),
+              ElementsAre(version_draft_28, version_draft_27));
 
   EXPECT_THAT(ParseQuicVersionVectorString("h3-27,50"),
               ElementsAre(version_draft_27, version_q050));
@@ -442,8 +450,47 @@
 }
 
 TEST_F(QuicVersionsTest, FilterSupportedVersionsAllVersions) {
-  static_assert(SupportedVersions().size() == 8u,
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync");
+  SetQuicReloadableFlag(quic_enable_version_draft_28, true);
+  SetQuicReloadableFlag(quic_enable_version_draft_27, true);
+  SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
+  SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
+  SetQuicReloadableFlag(quic_disable_version_q050, false);
+  SetQuicReloadableFlag(quic_disable_version_q049, false);
+  SetQuicReloadableFlag(quic_disable_version_q048, false);
+  SetQuicReloadableFlag(quic_disable_version_q046, false);
+  SetQuicReloadableFlag(quic_disable_version_q043, false);
+
+  ParsedQuicVersionVector expected_parsed_versions;
+  expected_parsed_versions.push_back(
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_28));
+  expected_parsed_versions.push_back(
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27));
+  expected_parsed_versions.push_back(
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
+  expected_parsed_versions.push_back(
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
+  expected_parsed_versions.push_back(
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
+  expected_parsed_versions.push_back(
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
+  expected_parsed_versions.push_back(
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48));
+  expected_parsed_versions.push_back(
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46));
+  expected_parsed_versions.push_back(
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43));
+
+  ASSERT_EQ(expected_parsed_versions,
+            FilterSupportedVersions(AllSupportedVersions()));
+  ASSERT_EQ(expected_parsed_versions, AllSupportedVersions());
+}
+
+TEST_F(QuicVersionsTest, FilterSupportedVersionsWithoutFirstVersion) {
+  static_assert(SupportedVersions().size() == 9u,
+                "Supported versions out of sync");
+  SetQuicReloadableFlag(quic_enable_version_draft_28, false);
   SetQuicReloadableFlag(quic_enable_version_draft_27, true);
   SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
   SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
@@ -473,44 +520,12 @@
 
   ASSERT_EQ(expected_parsed_versions,
             FilterSupportedVersions(AllSupportedVersions()));
-  ASSERT_EQ(expected_parsed_versions, AllSupportedVersions());
 }
 
-TEST_F(QuicVersionsTest, FilterSupportedVersionsNo99) {
-  static_assert(SupportedVersions().size() == 8u,
+TEST_F(QuicVersionsTest, FilterSupportedVersionsNoEnabledFlags) {
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync");
-  SetQuicReloadableFlag(quic_enable_version_draft_27, false);
-  SetQuicReloadableFlag(quic_enable_version_draft_25_v3, true);
-  SetQuicReloadableFlag(quic_enable_version_t050_v2, true);
-  SetQuicReloadableFlag(quic_disable_version_q050, false);
-  SetQuicReloadableFlag(quic_disable_version_q049, false);
-  SetQuicReloadableFlag(quic_disable_version_q048, false);
-  SetQuicReloadableFlag(quic_disable_version_q046, false);
-  SetQuicReloadableFlag(quic_disable_version_q043, false);
-
-  ParsedQuicVersionVector expected_parsed_versions;
-  expected_parsed_versions.push_back(
-      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25));
-  expected_parsed_versions.push_back(
-      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50));
-  expected_parsed_versions.push_back(
-      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
-  expected_parsed_versions.push_back(
-      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49));
-  expected_parsed_versions.push_back(
-      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48));
-  expected_parsed_versions.push_back(
-      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46));
-  expected_parsed_versions.push_back(
-      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43));
-
-  ASSERT_EQ(expected_parsed_versions,
-            FilterSupportedVersions(AllSupportedVersions()));
-}
-
-TEST_F(QuicVersionsTest, FilterSupportedVersionsNoFlags) {
-  static_assert(SupportedVersions().size() == 8u,
-                "Supported versions out of sync");
+  SetQuicReloadableFlag(quic_enable_version_draft_28, false);
   SetQuicReloadableFlag(quic_enable_version_draft_27, false);
   SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false);
   SetQuicReloadableFlag(quic_enable_version_t050_v2, false);
@@ -575,7 +590,7 @@
 // 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(SupportedTransportVersions().size() == 7u,
+  static_assert(SupportedTransportVersions().size() == 8u,
                 "Supported versions out of sync");
   EXPECT_EQ(QUIC_VERSION_43, 43);
   EXPECT_EQ(QUIC_VERSION_46, 46);
@@ -584,10 +599,11 @@
   EXPECT_EQ(QUIC_VERSION_50, 50);
   EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_25, 70);
   EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_27, 71);
+  EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_28, 72);
 }
 
 TEST_F(QuicVersionsTest, AlpnForVersion) {
-  static_assert(SupportedVersions().size() == 8u,
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync");
   ParsedQuicVersion parsed_version_q048 =
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48);
@@ -601,6 +617,8 @@
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25);
   ParsedQuicVersion parsed_version_draft_27 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27);
+  ParsedQuicVersion parsed_version_draft_28 =
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_28);
 
   EXPECT_EQ("h3-Q048", AlpnForVersion(parsed_version_q048));
   EXPECT_EQ("h3-Q049", AlpnForVersion(parsed_version_q049));
@@ -608,11 +626,14 @@
   EXPECT_EQ("h3-T050", AlpnForVersion(parsed_version_t050));
   EXPECT_EQ("h3-25", AlpnForVersion(parsed_version_draft_25));
   EXPECT_EQ("h3-27", AlpnForVersion(parsed_version_draft_27));
+  EXPECT_EQ("h3-28", AlpnForVersion(parsed_version_draft_28));
 }
 
 TEST_F(QuicVersionsTest, QuicEnableVersion) {
-  static_assert(SupportedVersions().size() == 8u,
+  static_assert(SupportedVersions().size() == 9u,
                 "Supported versions out of sync");
+  ParsedQuicVersion parsed_version_draft_28 =
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_28);
   ParsedQuicVersion parsed_version_draft_27 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27);
   ParsedQuicVersion parsed_version_draft_25 =
@@ -624,6 +645,13 @@
 
   {
     QuicFlagSaver flag_saver;
+    SetQuicReloadableFlag(quic_enable_version_draft_28, false);
+    QuicEnableVersion(parsed_version_draft_28);
+    EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_draft_28));
+  }
+
+  {
+    QuicFlagSaver flag_saver;
     SetQuicReloadableFlag(quic_enable_version_draft_27, false);
     QuicEnableVersion(parsed_version_draft_27);
     EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_draft_27));
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc
index aecec0e..44e2d34 100644
--- a/quic/test_tools/quic_test_utils.cc
+++ b/quic/test_tools/quic_test_utils.cc
@@ -841,6 +841,7 @@
 }
 
 void DisableQuicVersionsWithTls() {
+  SetQuicReloadableFlag(quic_enable_version_draft_28, false);
   SetQuicReloadableFlag(quic_enable_version_draft_27, false);
   SetQuicReloadableFlag(quic_enable_version_draft_25_v3, false);
   SetQuicReloadableFlag(quic_enable_version_t050_v2, false);