Reject IETF RETRY packets before they hit QUIC_BUGs

gfe-relnote: Fix QUIC framer bugs protected behind QUIC_VERSION_99, quic_supports_tls_handshake, and other QUIC flags

This is expected to fix crbug.com/952581

PiperOrigin-RevId: 244394240
Change-Id: I8b4ad2af67f690db5c12fb902277a324a63ae244
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index 0c65dc2..cc10cca 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -2514,6 +2514,12 @@
           set_detailed_error("Illegal long header type value.");
           return false;
         }
+        if (header->long_packet_type == RETRY &&
+            (version().KnowsWhichDecrypterToUse() ||
+             supports_multiple_packet_number_spaces_)) {
+          set_detailed_error("Not yet supported IETF RETRY packet received.");
+          return RaiseError(QUIC_INVALID_PACKET_HEADER);
+        }
         header->packet_number_length = GetLongHeaderPacketNumberLength(
             header->version.transport_version, type);
       }
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 2ffe54e..df72916 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -13341,6 +13341,61 @@
                                    &framer_, APPLICATION_DATA));
 }
 
+TEST_P(QuicFramerTest, IetfRetryPacketRejected) {
+  if (!framer_.version().KnowsWhichDecrypterToUse()) {
+    return;
+  }
+
+  // clang-format off
+  PacketFragments packet = {
+    // public flags (IETF Retry packet, 0-length original destination CID)
+    {"Unable to read type.",
+     {0xf0}},
+    // version tag
+    {"Unable to read protocol version.",
+     {QUIC_VERSION_BYTES}},
+    // connection_id length
+    {"Not yet supported IETF RETRY packet received.",
+     {0x00}},
+  };
+  // clang-format on
+
+  std::unique_ptr<QuicEncryptedPacket> encrypted(
+      AssemblePacketFromFragments(packet));
+
+  EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
+  EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
+  CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER);
+}
+
+TEST_P(QuicFramerTest, RetryPacketRejectedWithMultiplePacketNumberSpaces) {
+  if (framer_.transport_version() < QUIC_VERSION_46) {
+    return;
+  }
+  framer_.EnableMultiplePacketNumberSpacesSupport();
+
+  // clang-format off
+  PacketFragments packet = {
+    // public flags (IETF Retry packet, 0-length original destination CID)
+    {"Unable to read type.",
+     {0xf0}},
+    // version tag
+    {"Unable to read protocol version.",
+     {QUIC_VERSION_BYTES}},
+    // connection_id length
+    {"Not yet supported IETF RETRY packet received.",
+     {0x00}},
+  };
+  // clang-format on
+
+  std::unique_ptr<QuicEncryptedPacket> encrypted(
+      AssemblePacketFromFragments(packet));
+
+  EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
+  EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
+  CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic