gfe-relnote: Introduce QUIC_VERSION_50, protected by quic_enable_version_50

Version 50 uses header protection, initial obfuscators, and IETF IV construction.

PiperOrigin-RevId: 273780903
Change-Id: I2750db51f2a6e30d93ab52e9978129353134e5ee
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc
index 96bc86c..f486042 100644
--- a/quic/core/crypto/crypto_utils.cc
+++ b/quic/core/crypto/crypto_utils.cc
@@ -111,9 +111,77 @@
 
 static_assert(kQuicIetfDraftVersion == 23, "Salts do not match draft version");
 // Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-23#section-5.2
-const uint8_t kInitialSalt[] = {0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb,
-                                0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4,
-                                0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02};
+const std::vector<const uint8_t> kDraft23InitialSalt = {
+    0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7,
+    0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02};
+
+// Salts used by deployed versions of QUIC. When introducing a new version,
+// generate a new salt by running `openssl rand -hex 20`.
+
+// Salt to use for initial obfuscators in version T048.
+const std::vector<const uint8_t> kT048Salt = {
+    0x1f, 0x89, 0xf6, 0xe7, 0xc2, 0x18, 0xf4, 0x2e, 0x6c, 0xe1,
+    0x9e, 0x91, 0xb2, 0x23, 0xbb, 0x4c, 0x47, 0xc9, 0x12, 0xff};
+// Salt to use for initial obfuscators in version T049.
+const std::vector<const uint8_t> kT049Salt = {
+    0x69, 0xe5, 0x79, 0x2a, 0x41, 0xd0, 0xa2, 0x9c, 0xf9, 0xbc,
+    0x5c, 0x04, 0x5a, 0xeb, 0xcf, 0xeb, 0x51, 0xf6, 0x9f, 0x22};
+// Salt to use for initial obfuscators in version Q050.
+const std::vector<const uint8_t> kQ050Salt = {
+    0x50, 0x45, 0x74, 0xef, 0xd0, 0x66, 0xfe, 0x2f, 0x9d, 0x94,
+    0x5c, 0xfc, 0xdb, 0xd3, 0xa7, 0xf0, 0xd3, 0xb5, 0x6b, 0x45};
+// Salt to use for initial obfuscators in version T050.
+const std::vector<const uint8_t> kT050Salt = {
+    0x7f, 0xf5, 0x79, 0xe5, 0xac, 0xd0, 0x72, 0x91, 0x55, 0x80,
+    0x30, 0x4c, 0x43, 0xa2, 0x36, 0x7c, 0x60, 0x48, 0x83, 0x10};
+// Salt to use for initial obfuscators in version Q099.
+const std::vector<const uint8_t> kQ099Salt = {
+    0xc0, 0xa2, 0xee, 0x20, 0xc7, 0xe1, 0x83, 0x74, 0xc8, 0xa1,
+    0xa0, 0xc8, 0xa5, 0x21, 0xb5, 0x31, 0xee, 0x04, 0x7e, 0xc8};
+
+const std::vector<const uint8_t> InitialSaltForVersion(
+    const ParsedQuicVersion& version) {
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
+                "Supported versions out of sync with initial encryption salts");
+  switch (version.handshake_protocol) {
+    case PROTOCOL_QUIC_CRYPTO:
+      switch (version.transport_version) {
+        case QUIC_VERSION_50:
+          return kQ050Salt;
+        case QUIC_VERSION_99:
+          return kQ099Salt;
+        case QUIC_VERSION_RESERVED_FOR_NEGOTIATION:
+          // It doesn't matter what salt we use for
+          // QUIC_VERSION_RESERVED_FOR_NEGOTIATION, but some tests try to use a
+          // QuicFramer with QUIC_VERSION_RESERVED_FOR_NEGOTIATION and will hit
+          // the following QUIC_BUG if there isn't a case for it. ):
+          return kDraft23InitialSalt;
+        default:
+          QUIC_BUG << "No initial obfuscation salt for version " << version;
+      }
+      break;
+    case PROTOCOL_TLS1_3:
+      switch (version.transport_version) {
+        case QUIC_VERSION_48:
+          return kT048Salt;
+        case QUIC_VERSION_49:
+          return kT049Salt;
+        case QUIC_VERSION_50:
+          return kT050Salt;
+        case QUIC_VERSION_99:
+          // ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99) uses the IETF
+          // salt.
+          return kDraft23InitialSalt;
+        default:
+          QUIC_BUG << "No initial obfuscation salt for version " << version;
+      }
+      break;
+    case PROTOCOL_UNSUPPORTED:
+    default:
+      QUIC_BUG << "No initial obfuscation salt for version " << version;
+  }
+  return kDraft23InitialSalt;
+}
 
 const char kPreSharedKeyLabel[] = "QUIC PSK";
 
@@ -140,13 +208,14 @@
       << connection_id << " which is invalid with version " << version;
   const EVP_MD* hash = EVP_sha256();
 
+  const std::vector<const uint8_t> salt = InitialSaltForVersion(version);
   std::vector<uint8_t> handshake_secret;
   handshake_secret.resize(EVP_MAX_MD_SIZE);
   size_t handshake_secret_len;
-  const bool hkdf_extract_success = HKDF_extract(
-      handshake_secret.data(), &handshake_secret_len, hash,
-      reinterpret_cast<const uint8_t*>(connection_id.data()),
-      connection_id.length(), kInitialSalt, QUIC_ARRAYSIZE(kInitialSalt));
+  const bool hkdf_extract_success =
+      HKDF_extract(handshake_secret.data(), &handshake_secret_len, hash,
+                   reinterpret_cast<const uint8_t*>(connection_id.data()),
+                   connection_id.length(), salt.data(), salt.size());
   QUIC_BUG_IF(!hkdf_extract_success)
       << "HKDF_extract failed when creating initial crypters";
   handshake_secret.resize(handshake_secret_len);
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index b03efdb..60c6e1b 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -5964,11 +5964,12 @@
                              ENCRYPTION_ZERO_RTT);
   }
   // Check that ack is sent and that delayed ack alarm is reset.
+  size_t padding_frame_count = writer_->padding_frames().size();
   if (GetParam().no_stop_waiting) {
-    EXPECT_EQ(1u, writer_->frame_count());
+    EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
     EXPECT_TRUE(writer_->stop_waiting_frames().empty());
   } else {
-    EXPECT_EQ(2u, writer_->frame_count());
+    EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
     EXPECT_FALSE(writer_->stop_waiting_frames().empty());
   }
   EXPECT_FALSE(writer_->ack_frames().empty());
@@ -6084,11 +6085,12 @@
                              ENCRYPTION_ZERO_RTT);
   }
   // Check that ack is sent and that delayed ack alarm is reset.
+  padding_frame_count = writer_->padding_frames().size();
   if (GetParam().no_stop_waiting) {
-    EXPECT_EQ(1u, writer_->frame_count());
+    EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
     EXPECT_TRUE(writer_->stop_waiting_frames().empty());
   } else {
-    EXPECT_EQ(2u, writer_->frame_count());
+    EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
     EXPECT_FALSE(writer_->stop_waiting_frames().empty());
   }
   EXPECT_FALSE(writer_->ack_frames().empty());
@@ -6213,11 +6215,12 @@
                              ENCRYPTION_ZERO_RTT);
   }
   // Check that ack is sent and that delayed ack alarm is reset.
+  size_t padding_frame_count = writer_->padding_frames().size();
   if (GetParam().no_stop_waiting) {
-    EXPECT_EQ(1u, writer_->frame_count());
+    EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
     EXPECT_TRUE(writer_->stop_waiting_frames().empty());
   } else {
-    EXPECT_EQ(2u, writer_->frame_count());
+    EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
     EXPECT_FALSE(writer_->stop_waiting_frames().empty());
   }
   EXPECT_FALSE(writer_->ack_frames().empty());
@@ -6276,11 +6279,12 @@
                                !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
     }
     // Check that ack is sent and that delayed ack alarm is reset.
+    size_t padding_frame_count = writer_->padding_frames().size();
     if (GetParam().no_stop_waiting) {
-      EXPECT_EQ(1u, writer_->frame_count());
+      EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
       EXPECT_TRUE(writer_->stop_waiting_frames().empty());
     } else {
-      EXPECT_EQ(2u, writer_->frame_count());
+      EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
       EXPECT_FALSE(writer_->stop_waiting_frames().empty());
     }
     EXPECT_FALSE(writer_->ack_frames().empty());
@@ -6427,11 +6431,12 @@
                              ENCRYPTION_ZERO_RTT);
   }
   // Check that ack is sent and that delayed ack alarm is reset.
+  size_t padding_frame_count = writer_->padding_frames().size();
   if (GetParam().no_stop_waiting) {
-    EXPECT_EQ(1u, writer_->frame_count());
+    EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count());
     EXPECT_TRUE(writer_->stop_waiting_frames().empty());
   } else {
-    EXPECT_EQ(2u, writer_->frame_count());
+    EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count());
     EXPECT_FALSE(writer_->stop_waiting_frames().empty());
   }
   EXPECT_FALSE(writer_->ack_frames().empty());
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index 280d110..abae0f2 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -930,12 +930,13 @@
 }
 
 TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_48_2, true);
   SetQuicReloadableFlag(quic_enable_version_49, true);
+  SetQuicReloadableFlag(quic_enable_version_50, true);
   SetQuicReloadableFlag(quic_enable_version_99, true);
 
   VerifyVersionNotSupported(QuicVersionReservedForNegotiation());
@@ -944,6 +945,16 @@
                                            QuicVersionMin().transport_version));
   VerifyVersionSupported(QuicVersionMax());
 
+  // Turn off version 50.
+  SetQuicReloadableFlag(quic_enable_version_50, false);
+  VerifyVersionNotSupported(
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
+
+  // Turn on version 50.
+  SetQuicReloadableFlag(quic_enable_version_50, true);
+  VerifyVersionSupported(
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50));
+
   // Turn off version 49.
   SetQuicReloadableFlag(quic_enable_version_49, false);
   VerifyVersionNotSupported(
@@ -986,7 +997,7 @@
 }
 
 TEST_F(QuicDispatcherTest, RejectDeprecatedVersionsWithVersionNegotiation) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Please add deprecated versions to this test");
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   CreateTimeWaitListManager();
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 5ca325c..b614faa 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -8808,7 +8808,7 @@
     'm',  'n',  'o',  'p',
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet50[] = {
     // type (short header, 4 byte packet number)
     0x43,
     // connection_id
@@ -8827,9 +8827,9 @@
 
   unsigned char* p = packet;
   size_t p_size = QUIC_ARRAYSIZE(packet);
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_size = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() >= QUIC_VERSION_50) {
+    p = packet50;
+    p_size = QUIC_ARRAYSIZE(packet50);
   } else if (framer_.transport_version() >= QUIC_VERSION_46) {
     p = packet46;
   }
@@ -8887,7 +8887,7 @@
     'm',  'n',  'o',  'p',
   };
 
-  unsigned char packet99[] = {
+  unsigned char packet50[] = {
     // type (long header with packet type ZERO_RTT_PROTECTED)
     0xD3,
     // version tag
@@ -8913,9 +8913,9 @@
   unsigned char* p = packet;
   size_t p_size = QUIC_ARRAYSIZE(packet);
   // TODO(ianswett): see todo in previous test.
-  if (framer_.transport_version() == QUIC_VERSION_99) {
-    p = packet99;
-    p_size = QUIC_ARRAYSIZE(packet99);
+  if (framer_.transport_version() >= QUIC_VERSION_50) {
+    p = packet50;
+    p_size = QUIC_ARRAYSIZE(packet50);
   } else if (framer_.transport_version() >= QUIC_VERSION_46) {
     p = packet46;
     p_size = QUIC_ARRAYSIZE(packet46);
@@ -9033,6 +9033,9 @@
 
   // Create a packet with just the ack.
   QuicFrames frames = {QuicFrame(&ack_frame)};
+  if (framer_.version().HasHeaderProtection()) {
+    frames.push_back(QuicFrame(QuicPaddingFrame(12)));
+  }
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
   std::unique_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames));
   ASSERT_TRUE(raw_ack_packet != nullptr);
@@ -9052,6 +9055,9 @@
   // original packets to the re-serialized packets.
   frames.clear();
   frames.push_back(QuicFrame(visitor_.ack_frames_[0].get()));
+  if (framer_.version().HasHeaderProtection()) {
+    frames.push_back(QuicFrame(*visitor_.padding_frames_[0].get()));
+  }
 
   size_t original_raw_length = raw_ack_packet->length();
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index 75ea7f5..075b5b4 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -343,6 +343,10 @@
         EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
         EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
       }
+      if (client_framer_.version().HasHeaderProtection()) {
+        EXPECT_CALL(framer_visitor_, OnPaddingFrame(_))
+            .Times(testing::AnyNumber());
+      }
       EXPECT_CALL(framer_visitor_, OnPacketComplete());
     }
     ProcessPacket(serialized);
diff --git a/quic/core/quic_version_manager.cc b/quic/core/quic_version_manager.cc
index 849dfc5..5f14ad4 100644
--- a/quic/core/quic_version_manager.cc
+++ b/quic/core/quic_version_manager.cc
@@ -16,13 +16,14 @@
 QuicVersionManager::QuicVersionManager(
     ParsedQuicVersionVector supported_versions)
     : enable_version_99_(GetQuicReloadableFlag(quic_enable_version_99)),
+      enable_version_50_(GetQuicReloadableFlag(quic_enable_version_50)),
       enable_version_49_(GetQuicReloadableFlag(quic_enable_version_49)),
       enable_version_48_(GetQuicReloadableFlag(quic_enable_version_48_2)),
       enable_version_47_(GetQuicReloadableFlag(quic_enable_version_47)),
       disable_version_39_(GetQuicReloadableFlag(quic_disable_version_39)),
       enable_tls_(GetQuicReloadableFlag(quic_supports_tls_handshake)),
       allowed_supported_versions_(std::move(supported_versions)) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   RefilterSupportedVersions();
 }
@@ -41,15 +42,17 @@
 }
 
 void QuicVersionManager::MaybeRefilterSupportedVersions() {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   if (enable_version_99_ != GetQuicReloadableFlag(quic_enable_version_99) ||
+      enable_version_50_ != GetQuicReloadableFlag(quic_enable_version_50) ||
       enable_version_49_ != GetQuicReloadableFlag(quic_enable_version_49) ||
       enable_version_48_ != GetQuicReloadableFlag(quic_enable_version_48_2) ||
       enable_version_47_ != GetQuicReloadableFlag(quic_enable_version_47) ||
       disable_version_39_ != GetQuicReloadableFlag(quic_disable_version_39) ||
       enable_tls_ != GetQuicReloadableFlag(quic_supports_tls_handshake)) {
     enable_version_99_ = GetQuicReloadableFlag(quic_enable_version_99);
+    enable_version_50_ = GetQuicReloadableFlag(quic_enable_version_50);
     enable_version_49_ = GetQuicReloadableFlag(quic_enable_version_49);
     enable_version_48_ = GetQuicReloadableFlag(quic_enable_version_48_2);
     enable_version_47_ = GetQuicReloadableFlag(quic_enable_version_47);
diff --git a/quic/core/quic_version_manager.h b/quic/core/quic_version_manager.h
index b62b302..3b2ec85 100644
--- a/quic/core/quic_version_manager.h
+++ b/quic/core/quic_version_manager.h
@@ -43,6 +43,8 @@
   // Cached value of reloadable flags.
   // quic_enable_version_99 flag
   bool enable_version_99_;
+  // quic_enable_version_50 flag
+  bool enable_version_50_;
   // quic_enable_version_49 flag
   bool enable_version_49_;
   // quic_enable_version_48_2 flag
diff --git a/quic/core/quic_version_manager_test.cc b/quic/core/quic_version_manager_test.cc
index b73b729..8749477 100644
--- a/quic/core/quic_version_manager_test.cc
+++ b/quic/core/quic_version_manager_test.cc
@@ -16,9 +16,10 @@
 class QuicVersionManagerTest : public QuicTest {};
 
 TEST_F(QuicVersionManagerTest, QuicVersionManager) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_enable_version_99, false);
+  SetQuicReloadableFlag(quic_enable_version_50, false);
   SetQuicReloadableFlag(quic_enable_version_49, false);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
   SetQuicReloadableFlag(quic_enable_version_47, false);
@@ -53,11 +54,25 @@
                                         QUIC_VERSION_43, QUIC_VERSION_39}),
             manager.GetSupportedTransportVersions());
 
+  SetQuicReloadableFlag(quic_enable_version_50, true);
+  EXPECT_EQ(
+      QuicTransportVersionVector(
+          {QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47,
+           QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}),
+      manager.GetSupportedTransportVersions());
+
   SetQuicReloadableFlag(quic_enable_version_99, true);
   EXPECT_EQ(
       QuicTransportVersionVector(
-          {QUIC_VERSION_99, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47,
-           QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}),
+          {QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48,
+           QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}),
+      manager.GetSupportedTransportVersions());
+
+  SetQuicReloadableFlag(quic_enable_version_99, true);
+  EXPECT_EQ(
+      QuicTransportVersionVector(
+          {QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48,
+           QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39}),
       manager.GetSupportedTransportVersions());
 
   // Ensure that all versions are now supported.
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
index 5edc410..7aabc3d 100644
--- a/quic/core/quic_versions.cc
+++ b/quic/core/quic_versions.cc
@@ -55,7 +55,7 @@
 }
 
 bool ParsedQuicVersion::UsesInitialObfuscators() const {
-  return transport_version == QUIC_VERSION_99 ||
+  return transport_version > QUIC_VERSION_49 ||
          handshake_protocol == PROTOCOL_TLS1_3;
 }
 
@@ -65,7 +65,7 @@
 }
 
 bool ParsedQuicVersion::HasHeaderProtection() const {
-  return transport_version == QUIC_VERSION_99;
+  return transport_version > QUIC_VERSION_49;
 }
 
 bool ParsedQuicVersion::SupportsRetry() const {
@@ -113,7 +113,7 @@
                << parsed_version.handshake_protocol;
       return 0;
   }
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   switch (parsed_version.transport_version) {
     case QUIC_VERSION_39:
@@ -128,6 +128,8 @@
       return MakeVersionLabel(proto, '0', '4', '8');
     case QUIC_VERSION_49:
       return MakeVersionLabel(proto, '0', '4', '9');
+    case QUIC_VERSION_50:
+      return MakeVersionLabel(proto, '0', '5', '0');
     case QUIC_VERSION_99:
       if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
         return MakeVersionLabel(0xff, 0x00, 0x00, kQuicIetfDraftVersion);
@@ -268,6 +270,10 @@
       if (GetQuicReloadableFlag(quic_enable_version_99)) {
         filtered_versions.push_back(version);
       }
+    } else if (version.transport_version == QUIC_VERSION_50) {
+      if (GetQuicReloadableFlag(quic_enable_version_50)) {
+        filtered_versions.push_back(version);
+      }
     } else if (version.transport_version == QUIC_VERSION_49) {
       if (GetQuicReloadableFlag(quic_enable_version_49)) {
         filtered_versions.push_back(version);
@@ -371,7 +377,7 @@
     return #x
 
 std::string QuicVersionToString(QuicTransportVersion transport_version) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   switch (transport_version) {
     RETURN_STRING_LITERAL(QUIC_VERSION_39);
@@ -380,6 +386,7 @@
     RETURN_STRING_LITERAL(QUIC_VERSION_47);
     RETURN_STRING_LITERAL(QUIC_VERSION_48);
     RETURN_STRING_LITERAL(QUIC_VERSION_49);
+    RETURN_STRING_LITERAL(QUIC_VERSION_50);
     RETURN_STRING_LITERAL(QUIC_VERSION_99);
     default:
       return "QUIC_VERSION_UNSUPPORTED";
@@ -478,11 +485,14 @@
   if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
     SetQuicReloadableFlag(quic_supports_tls_handshake, true);
   }
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   if (parsed_version.transport_version == QUIC_VERSION_99) {
     SetQuicReloadableFlag(quic_enable_version_99, true);
   }
+  if (parsed_version.transport_version == QUIC_VERSION_50) {
+    SetQuicReloadableFlag(quic_enable_version_50, true);
+  }
   if (parsed_version.transport_version == QUIC_VERSION_49) {
     SetQuicReloadableFlag(quic_enable_version_49, true);
   }
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h
index 2137677..fe8c9ef 100644
--- a/quic/core/quic_versions.h
+++ b/quic/core/quic_versions.h
@@ -107,6 +107,7 @@
   QUIC_VERSION_48 = 48,  // Use CRYPTO frames for the handshake.
   QUIC_VERSION_49 = 49,  // Client connection IDs, long header lengths, IETF
                          // header format from draft-ietf-quic-invariants-06.
+  QUIC_VERSION_50 = 50,  // Header protection and initial obfuscators.
   QUIC_VERSION_99 = 99,  // Dumping ground for IETF QUIC changes which are not
                          // yet ready for production.
   // QUIC_VERSION_RESERVED_FOR_NEGOTIATION is sent over the wire as ?a?a?a?a
@@ -214,8 +215,8 @@
 //
 // See go/new-quic-version for more details on how to roll out new versions.
 static const QuicTransportVersion kSupportedTransportVersions[] = {
-    QUIC_VERSION_99, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47,
-    QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39,
+    QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48,
+    QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39,
 };
 
 // This vector contains all crypto handshake protocols that are supported.
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc
index 1ab12e5..a631187 100644
--- a/quic/core/quic_versions_test.cc
+++ b/quic/core/quic_versions_test.cc
@@ -122,6 +122,8 @@
             ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '7')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48),
             ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '8')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
+            ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '5', '0')));
 
   // Test TLS versions:
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39),
@@ -134,6 +136,8 @@
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7')));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_48),
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '8')));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
+            ParseQuicVersionLabel(MakeVersionLabel('T', '0', '5', '0')));
 }
 
 TEST_F(QuicVersionsTest, ParseQuicVersionString) {
@@ -147,6 +151,8 @@
             ParseQuicVersionString("Q047"));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48),
             ParseQuicVersionString("Q048"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
+            ParseQuicVersionString("Q050"));
 
   EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString(""));
   EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q 47"));
@@ -164,6 +170,8 @@
             ParseQuicVersionString("T047"));
   EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_48),
             ParseQuicVersionString("T048"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
+            ParseQuicVersionString("T050"));
 }
 
 TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
@@ -182,6 +190,9 @@
   EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '8'),
             CreateQuicVersionLabel(
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48)));
+  EXPECT_EQ(MakeVersionLabel('Q', '0', '5', '0'),
+            CreateQuicVersionLabel(
+                ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50)));
 
   // Test a TLS version:
   EXPECT_EQ(MakeVersionLabel('T', '0', '3', '9'),
@@ -199,6 +210,9 @@
   EXPECT_EQ(MakeVersionLabel('T', '0', '4', '8'),
             CreateQuicVersionLabel(
                 ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_48)));
+  EXPECT_EQ(MakeVersionLabel('T', '0', '5', '0'),
+            CreateQuicVersionLabel(
+                ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50)));
 
   // Make sure the negotiation reserved version is in the IETF reserved space.
   EXPECT_EQ(MakeVersionLabel(0xda, 0x5a, 0x3a, 0x3a) & 0x0f0f0f0f,
@@ -293,20 +307,21 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_48_2, true);
   SetQuicReloadableFlag(quic_enable_version_49, true);
+  SetQuicReloadableFlag(quic_enable_version_50, true);
   SetQuicReloadableFlag(quic_enable_version_99, true);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
     parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
   }
   QuicTransportVersionVector expected_versions = {
-      QUIC_VERSION_99, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47,
-      QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39};
+      QUIC_VERSION_99, QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48,
+      QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39};
   ParsedQuicVersionVector expected_parsed_versions;
   for (QuicTransportVersion version : expected_versions) {
     expected_parsed_versions.push_back(
@@ -319,12 +334,38 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_48_2, true);
   SetQuicReloadableFlag(quic_enable_version_49, true);
+  SetQuicReloadableFlag(quic_enable_version_50, true);
+  SetQuicReloadableFlag(quic_enable_version_99, false);
+  ParsedQuicVersionVector parsed_versions;
+  for (QuicTransportVersion version : all_versions) {
+    parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+  }
+  QuicTransportVersionVector expected_versions = {
+      QUIC_VERSION_50, QUIC_VERSION_49, QUIC_VERSION_48, QUIC_VERSION_47,
+      QUIC_VERSION_46, QUIC_VERSION_43, QUIC_VERSION_39};
+  ParsedQuicVersionVector expected_parsed_versions;
+  for (QuicTransportVersion version : expected_versions) {
+    expected_parsed_versions.push_back(
+        ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version));
+  }
+
+  ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions));
+  ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions));
+}
+
+TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo50) {
+  QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
+  SetQuicReloadableFlag(quic_disable_version_39, false);
+  SetQuicReloadableFlag(quic_enable_version_47, true);
+  SetQuicReloadableFlag(quic_enable_version_48_2, true);
+  SetQuicReloadableFlag(quic_enable_version_49, true);
+  SetQuicReloadableFlag(quic_enable_version_50, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -345,12 +386,13 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo49) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_48_2, true);
   SetQuicReloadableFlag(quic_enable_version_49, false);
+  SetQuicReloadableFlag(quic_enable_version_50, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -371,12 +413,13 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo48) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, true);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
   SetQuicReloadableFlag(quic_enable_version_49, false);
+  SetQuicReloadableFlag(quic_enable_version_50, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -396,12 +439,13 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, false);
   SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
   SetQuicReloadableFlag(quic_enable_version_49, false);
+  SetQuicReloadableFlag(quic_enable_version_50, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -421,12 +465,13 @@
 
 TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo39) {
   QuicTransportVersionVector all_versions = AllSupportedTransportVersions();
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_disable_version_39, true);
   SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
   SetQuicReloadableFlag(quic_enable_version_49, false);
+  SetQuicReloadableFlag(quic_enable_version_50, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
   ParsedQuicVersionVector parsed_versions;
   for (QuicTransportVersion version : all_versions) {
@@ -483,7 +528,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, CheckVersionNumbersForTypos) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   EXPECT_EQ(QUIC_VERSION_39, 39);
   EXPECT_EQ(QUIC_VERSION_43, 43);
@@ -491,11 +536,12 @@
   EXPECT_EQ(QUIC_VERSION_47, 47);
   EXPECT_EQ(QUIC_VERSION_48, 48);
   EXPECT_EQ(QUIC_VERSION_49, 49);
+  EXPECT_EQ(QUIC_VERSION_50, 50);
   EXPECT_EQ(QUIC_VERSION_99, 99);
 }
 
 TEST_F(QuicVersionsTest, AlpnForVersion) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   ParsedQuicVersion parsed_version_q047 =
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47);
@@ -509,6 +555,10 @@
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49);
   ParsedQuicVersion parsed_version_t049 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_49);
+  ParsedQuicVersion parsed_version_q050 =
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50);
+  ParsedQuicVersion parsed_version_t050 =
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50);
   ParsedQuicVersion parsed_version_t099 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
 
@@ -518,11 +568,13 @@
   EXPECT_EQ("h3-T048", AlpnForVersion(parsed_version_t048));
   EXPECT_EQ("h3-Q049", AlpnForVersion(parsed_version_q049));
   EXPECT_EQ("h3-T049", AlpnForVersion(parsed_version_t049));
+  EXPECT_EQ("h3-Q050", AlpnForVersion(parsed_version_q050));
+  EXPECT_EQ("h3-T050", AlpnForVersion(parsed_version_t050));
   EXPECT_EQ("h3-23", AlpnForVersion(parsed_version_t099));
 }
 
 TEST_F(QuicVersionsTest, QuicEnableVersion) {
-  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u,
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u,
                 "Supported versions out of sync");
   SetQuicReloadableFlag(quic_supports_tls_handshake, true);
   ParsedQuicVersion parsed_version_q047 =
@@ -537,6 +589,10 @@
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_49);
   ParsedQuicVersion parsed_version_t049 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_49);
+  ParsedQuicVersion parsed_version_q050 =
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50);
+  ParsedQuicVersion parsed_version_t050 =
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50);
   ParsedQuicVersion parsed_version_t099 =
       ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
   SetQuicReloadableFlag(quic_supports_tls_handshake, false);
@@ -544,6 +600,7 @@
   SetQuicReloadableFlag(quic_enable_version_47, false);
   SetQuicReloadableFlag(quic_enable_version_48_2, false);
   SetQuicReloadableFlag(quic_enable_version_49, false);
+  SetQuicReloadableFlag(quic_enable_version_50, false);
   SetQuicReloadableFlag(quic_enable_version_99, false);
 
   {
@@ -552,6 +609,7 @@
     EXPECT_FALSE(GetQuicReloadableFlag(quic_supports_tls_handshake));
     EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
   }
 
@@ -561,6 +619,7 @@
     EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake));
     EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
   }
 
@@ -570,6 +629,7 @@
     EXPECT_FALSE(GetQuicReloadableFlag(quic_supports_tls_handshake));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
     EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_48_2));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
   }
 
@@ -579,6 +639,27 @@
     EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
     EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_48_2));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
+  }
+
+  {
+    QuicFlagSaver flag_saver;
+    QuicEnableVersion(parsed_version_q050);
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_supports_tls_handshake));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
+    EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_50));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
+  }
+
+  {
+    QuicFlagSaver flag_saver;
+    QuicEnableVersion(parsed_version_t050);
+    EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
+    EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_50));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
   }
 
@@ -608,6 +689,7 @@
     EXPECT_TRUE(GetQuicReloadableFlag(quic_supports_tls_handshake));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_47));
     EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_48_2));
+    EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_50));
     EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_99));
   }
 }