Add retire_prior_to to NewConnectionId frame

IETF altered the NewConnectionId frame format, adding a "retire_prior_to"
field. This CL adds that field and modifies the framer and tests as needed.

gfe-relnote: N/A is only for IETF QUIC (version 99 flag protected)

NEW_REQUIRED_FIELD_OK="Message not currently in use, nothing in the logs"

Note wrt the protobuf update - this CL adds a field to an IETF QUIC frame. Correspondingly, the relevant protobuf gets a new field. Since IETF QUIC is not in use, there are no instances of this protobuf in use/existance/etc yet ... so there is no incompatbility with other processes/etc to be concerned with.

PiperOrigin-RevId: 257833679
Change-Id: I80d80db9f1f23b8e570c504199fdd346b7cb4ca4
diff --git a/quic/core/frames/quic_new_connection_id_frame.cc b/quic/core/frames/quic_new_connection_id_frame.cc
index b7f63e2..f6c8661 100644
--- a/quic/core/frames/quic_new_connection_id_frame.cc
+++ b/quic/core/frames/quic_new_connection_id_frame.cc
@@ -16,17 +16,22 @@
     QuicControlFrameId control_frame_id,
     QuicConnectionId connection_id,
     QuicConnectionIdSequenceNumber sequence_number,
-    const QuicUint128 stateless_reset_token)
+    const QuicUint128 stateless_reset_token,
+    uint64_t retire_prior_to)
     : control_frame_id(control_frame_id),
       connection_id(connection_id),
       sequence_number(sequence_number),
-      stateless_reset_token(stateless_reset_token) {}
+      stateless_reset_token(stateless_reset_token),
+      retire_prior_to(retire_prior_to) {
+  DCHECK(retire_prior_to <= sequence_number);
+}
 
 std::ostream& operator<<(std::ostream& os,
                          const QuicNewConnectionIdFrame& frame) {
   os << "{ control_frame_id: " << frame.control_frame_id
      << ", connection_id: " << frame.connection_id
-     << ", sequence_number: " << frame.sequence_number << " }\n";
+     << ", sequence_number: " << frame.sequence_number
+     << ", retire_prior_to: " << frame.retire_prior_to << " }\n";
   return os;
 }
 
diff --git a/quic/core/frames/quic_new_connection_id_frame.h b/quic/core/frames/quic_new_connection_id_frame.h
index 1948d22..441ca1a 100644
--- a/quic/core/frames/quic_new_connection_id_frame.h
+++ b/quic/core/frames/quic_new_connection_id_frame.h
@@ -18,7 +18,8 @@
   QuicNewConnectionIdFrame(QuicControlFrameId control_frame_id,
                            QuicConnectionId connection_id,
                            QuicConnectionIdSequenceNumber sequence_number,
-                           const QuicUint128 stateless_reset_token);
+                           const QuicUint128 stateless_reset_token,
+                           uint64_t retire_prior_to);
 
   friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
       std::ostream& os,
@@ -30,6 +31,7 @@
   QuicConnectionId connection_id;
   QuicConnectionIdSequenceNumber sequence_number;
   QuicUint128 stateless_reset_token;
+  uint64_t retire_prior_to;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index cdb941f..6c089c1 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -768,6 +768,7 @@
     const QuicNewConnectionIdFrame& frame) {
   return kQuicFrameTypeSize +
          QuicDataWriter::GetVarInt62Len(frame.sequence_number) +
+         QuicDataWriter::GetVarInt62Len(frame.retire_prior_to) +
          kConnectionIdLengthSize + frame.connection_id.length() +
          sizeof(frame.stateless_reset_token);
 }
@@ -5998,6 +5999,10 @@
     set_detailed_error("Can not write New Connection ID sequence number");
     return false;
   }
+  if (!writer->WriteVarInt62(frame.retire_prior_to)) {
+    set_detailed_error("Can not write New Connection ID retire_prior_to");
+    return false;
+  }
   if (!writer->WriteUInt8(frame.connection_id.length())) {
     set_detailed_error(
         "Can not write New Connection ID frame connection ID Length");
@@ -6025,6 +6030,15 @@
     return false;
   }
 
+  if (!reader->ReadVarInt62(&frame->retire_prior_to)) {
+    set_detailed_error(
+        "Unable to read new connection ID frame retire_prior_to.");
+    return false;
+  }
+  if (frame->retire_prior_to > frame->sequence_number) {
+    set_detailed_error("Retire_prior_to > sequence_number.");
+    return false;
+  }
   uint8_t connection_id_length;
   if (!reader->ReadUInt8(&connection_id_length)) {
     set_detailed_error(
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 3e0f68b..0009470 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -11289,6 +11289,8 @@
       // error code
       {"Unable to read new connection ID frame sequence number.",
        {kVarInt62OneByte + 0x11}},
+      {"Unable to read new connection ID frame retire_prior_to.",
+       {kVarInt62OneByte + 0x09}},
       {"Unable to read new connection ID frame connection id length.",
        {0x08}},  // connection ID length
       {"Unable to read new connection ID frame connection id.",
@@ -11314,6 +11316,7 @@
   EXPECT_EQ(FramerTestConnectionIdPlusOne(),
             visitor_.new_connection_id_.connection_id);
   EXPECT_EQ(0x11u, visitor_.new_connection_id_.sequence_number);
+  EXPECT_EQ(0x09u, visitor_.new_connection_id_.retire_prior_to);
   EXPECT_EQ(kTestStatelessResetToken,
             visitor_.new_connection_id_.stateless_reset_token);
 
@@ -11345,6 +11348,8 @@
       // error code
       {"Unable to read new connection ID frame sequence number.",
        {kVarInt62OneByte + 0x11}},
+      {"Unable to read new connection ID frame retire_prior_to.",
+       {kVarInt62OneByte + 0x0a}},
       {"Unable to read new connection ID frame connection id length.",
        {0x09}},  // connection ID length
       {"Unable to read new connection ID frame connection id.",
@@ -11370,6 +11375,7 @@
   EXPECT_EQ(FramerTestConnectionIdNineBytes(),
             visitor_.new_connection_id_.connection_id);
   EXPECT_EQ(0x11u, visitor_.new_connection_id_.sequence_number);
+  EXPECT_EQ(0x0au, visitor_.new_connection_id_.retire_prior_to);
   EXPECT_EQ(kTestStatelessResetToken,
             visitor_.new_connection_id_.stateless_reset_token);
 
@@ -11403,6 +11409,8 @@
       // error code
       {"Unable to read new connection ID frame sequence number.",
        {kVarInt62OneByte + 0x11}},
+      {"Unable to read new connection ID frame retire_prior_to.",
+       {kVarInt62OneByte + 0x0b}},
       {"Unable to read new connection ID frame connection id length.",
        {0x13}},  // connection ID length
       {"Unable to read new connection ID frame connection id.",
@@ -11422,6 +11430,50 @@
   EXPECT_EQ("New connection ID length too high.", framer_.detailed_error());
 }
 
+// Verifies that parsing a NEW_CONNECTION_ID frame with an invalid
+// retire-prior-to fails.
+TEST_P(QuicFramerTest, InvalidRetirePriorToNewConnectionIdFrame) {
+  if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+    // The NEW_CONNECTION_ID frame is only for version 99.
+    return;
+  }
+  SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE);
+  // clang-format off
+  PacketFragments packet99 = {
+      // type (short header, 4 byte packet number)
+      {"",
+       {0x43}},
+      // connection_id
+      {"",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+      // packet number
+      {"",
+       {0x12, 0x34, 0x56, 0x78}},
+      // frame type (IETF_NEW_CONNECTION_ID frame)
+      {"",
+       {0x18}},
+      // sequence number
+      {"Unable to read new connection ID frame sequence number.",
+       {kVarInt62OneByte + 0x11}},
+      {"Unable to read new connection ID frame retire_prior_to.",
+       {kVarInt62OneByte + 0x1b}},
+      {"Unable to read new connection ID frame connection id length.",
+       {0x08}},  // connection ID length
+      {"Unable to read new connection ID frame connection id.",
+       {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11}},
+      {"Can not read new connection ID frame reset token.",
+       {0xb5, 0x69, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
+  };
+  // clang-format on
+
+  std::unique_ptr<QuicEncryptedPacket> encrypted(
+      AssemblePacketFromFragments(packet99));
+  EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
+  EXPECT_EQ(QUIC_INVALID_NEW_CONNECTION_ID_DATA, framer_.error());
+  EXPECT_EQ("Retire_prior_to > sequence_number.", framer_.detailed_error());
+}
+
 TEST_P(QuicFramerTest, BuildNewConnectionIdFramePacket) {
   if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
     // This frame is only for version 99.
@@ -11436,6 +11488,7 @@
 
   QuicNewConnectionIdFrame frame;
   frame.sequence_number = 0x11;
+  frame.retire_prior_to = 0x0c;
   // Use this value to force a 4-byte encoded variable length connection ID
   // in the frame.
   frame.connection_id = FramerTestConnectionIdPlusOne();
@@ -11456,6 +11509,8 @@
     0x18,
     // sequence number
     kVarInt62OneByte + 0x11,
+    // retire_prior_to
+    kVarInt62OneByte + 0x0c,
     // new connection id length
     0x08,
     // new connection id
@@ -11862,7 +11917,8 @@
     return;
   }
 
-  QuicNewConnectionIdFrame new_connection_id(5, TestConnectionId(), 1, 101111);
+  QuicNewConnectionIdFrame new_connection_id(5, TestConnectionId(), 1, 101111,
+                                             1);
   EXPECT_EQ(QuicFramer::GetNewConnectionIdFrameSize(new_connection_id),
             QuicFramer::GetRetransmittableControlFrameSize(
                 framer_.transport_version(), QuicFrame(&new_connection_id)));
diff --git a/quic/core/quic_ietf_framer_test.cc b/quic/core/quic_ietf_framer_test.cc
index 23ec1cb..9d07e49 100644
--- a/quic/core/quic_ietf_framer_test.cc
+++ b/quic/core/quic_ietf_framer_test.cc
@@ -1380,6 +1380,7 @@
   QuicNewConnectionIdFrame transmit_frame;
   transmit_frame.connection_id = TestConnectionId(UINT64_C(0x0edcba9876543201));
   transmit_frame.sequence_number = 0x01020304;
+  transmit_frame.retire_prior_to = 0x00020304;
   // The token is defined as a uint128 -- a 16-byte integer.
   // The value is set in this manner because we want each
   // byte to have a specific value so that the binary
@@ -1401,12 +1402,12 @@
   // Add the frame.
   EXPECT_TRUE(QuicFramerPeer::AppendNewConnectionIdFrame(
       &framer_, transmit_frame, &writer));
-  // Check that buffer length is correct
-  EXPECT_EQ(29u, writer.length());
   // clang-format off
   uint8_t packet[] = {
     // sequence number, 0x80 for varint62 encoding
     0x80 + 0x01, 0x02, 0x03, 0x04,
+    // retire_prior_to, 0x80 for varint62 encoding
+    0x80 + 0x00, 0x02, 0x03, 0x04,
     // new connection id length, is not varint62 encoded.
     0x08,
     // new connection id, is not varint62 encoded.
@@ -1415,8 +1416,10 @@
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
   };
-
   // clang-format on
+
+  // Check that buffer length is correct
+  EXPECT_EQ(sizeof(packet), writer.length());
   EXPECT_EQ(0, memcmp(packet_buffer, packet, sizeof(packet)));
 
   // Set up reader and empty receive QuicPaddingFrame.
@@ -1430,6 +1433,7 @@
   // Now check that received == sent
   EXPECT_EQ(transmit_frame.connection_id, receive_frame.connection_id);
   EXPECT_EQ(transmit_frame.sequence_number, receive_frame.sequence_number);
+  EXPECT_EQ(transmit_frame.retire_prior_to, receive_frame.retire_prior_to);
   EXPECT_EQ(transmit_frame.stateless_reset_token,
             receive_frame.stateless_reset_token);
 }