gfe-relnote: In QUIC, enable multiple packet number support in QuicFramer. Not used yet. Not protected.

PiperOrigin-RevId: 239686851
Change-Id: Ia2bb33e823fa4d80ad11366f8bc58079e39eeb47
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index 3e4f921..4640d39 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -316,6 +316,35 @@
   return PACKET_4BYTE_PACKET_NUMBER;
 }
 
+// Used to get packet number space before packet gets decrypted.
+PacketNumberSpace GetPacketNumberSpace(const QuicPacketHeader& header) {
+  switch (header.form) {
+    case GOOGLE_QUIC_PACKET:
+      QUIC_BUG << "Try to get packet number space of Google QUIC packet";
+      break;
+    case IETF_QUIC_SHORT_HEADER_PACKET:
+      return APPLICATION_DATA;
+    case IETF_QUIC_LONG_HEADER_PACKET:
+      switch (header.long_packet_type) {
+        case INITIAL:
+          return INITIAL_DATA;
+        case HANDSHAKE:
+          return HANDSHAKE_DATA;
+        case ZERO_RTT_PROTECTED:
+          return APPLICATION_DATA;
+        case VERSION_NEGOTIATION:
+        case RETRY:
+        case INVALID_PACKET_TYPE:
+          QUIC_BUG << "Try to get packet number space of long header type: "
+                   << QuicUtils::QuicLongHeaderTypetoString(
+                          header.long_packet_type);
+          break;
+      }
+  }
+
+  return NUM_PACKET_NUMBER_SPACES;
+}
+
 QuicStringPiece TruncateErrorString(QuicStringPiece error) {
   if (error.length() <= kMaxErrorStringLength) {
     return error;
@@ -472,7 +501,8 @@
       infer_packet_header_type_from_version_(perspective ==
                                              Perspective::IS_CLIENT),
       expected_connection_id_length_(expected_connection_id_length),
-      should_update_expected_connection_id_length_(false) {
+      should_update_expected_connection_id_length_(false),
+      supports_multiple_packet_number_spaces_(false) {
   DCHECK(!supported_versions.empty());
   version_ = supported_versions_[0];
   decrypter_ = QuicMakeUnique<NullDecrypter>(perspective);
@@ -1770,7 +1800,13 @@
   if (header->form == IETF_QUIC_SHORT_HEADER_PACKET ||
       header->long_packet_type != VERSION_NEGOTIATION) {
     // Process packet number.
-    QuicPacketNumber base_packet_number = largest_packet_number_;
+    QuicPacketNumber base_packet_number;
+    if (supports_multiple_packet_number_spaces_) {
+      base_packet_number =
+          largest_decrypted_packet_numbers_[GetPacketNumberSpace(*header)];
+    } else {
+      base_packet_number = largest_packet_number_;
+    }
     uint64_t full_packet_number;
     if (!ProcessAndCalculatePacketNumber(
             encrypted_reader, header->packet_number_length, base_packet_number,
@@ -1831,8 +1867,9 @@
       header->length_length);
 
   size_t decrypted_length = 0;
+  EncryptionLevel decrypted_level;
   if (!DecryptPayload(encrypted, associated_data, *header, decrypted_buffer,
-                      buffer_length, &decrypted_length)) {
+                      buffer_length, &decrypted_length, &decrypted_level)) {
     if (IsIetfStatelessResetPacket(*header)) {
       // This is a stateless reset packet.
       QuicIetfStatelessResetPacket packet(
@@ -1848,7 +1885,13 @@
 
   // Update the largest packet number after we have decrypted the packet
   // so we are confident is not attacker controlled.
-  largest_packet_number_.UpdateMax(header->packet_number);
+  if (supports_multiple_packet_number_spaces_) {
+    largest_decrypted_packet_numbers_[QuicUtils::GetPacketNumberSpace(
+                                          decrypted_level)]
+        .UpdateMax(header->packet_number);
+  } else {
+    largest_packet_number_.UpdateMax(header->packet_number);
+  }
 
   if (!visitor_->OnPacketHeader(*header)) {
     RecordDroppedPacketReason(DroppedPacketReason::INVALID_PACKET_NUMBER);
@@ -1910,8 +1953,9 @@
       header->length_length);
 
   size_t decrypted_length = 0;
+  EncryptionLevel decrypted_level;
   if (!DecryptPayload(encrypted, associated_data, *header, decrypted_buffer,
-                      buffer_length, &decrypted_length)) {
+                      buffer_length, &decrypted_length, &decrypted_level)) {
     RecordDroppedPacketReason(DroppedPacketReason::DECRYPTION_FAILURE);
     set_detailed_error("Unable to decrypt payload.");
     return RaiseError(QUIC_DECRYPTION_FAILURE);
@@ -1921,7 +1965,13 @@
 
   // Update the largest packet number after we have decrypted the packet
   // so we are confident is not attacker controlled.
-  largest_packet_number_.UpdateMax(header->packet_number);
+  if (supports_multiple_packet_number_spaces_) {
+    largest_decrypted_packet_numbers_[QuicUtils::GetPacketNumberSpace(
+                                          decrypted_level)]
+        .UpdateMax(header->packet_number);
+  } else {
+    largest_packet_number_.UpdateMax(header->packet_number);
+  }
 
   if (!visitor_->OnPacketHeader(*header)) {
     // The visitor suppresses further processing of the packet.
@@ -2418,7 +2468,13 @@
 
 bool QuicFramer::ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader,
                                               QuicPacketHeader* header) {
-  QuicPacketNumber base_packet_number = largest_packet_number_;
+  QuicPacketNumber base_packet_number;
+  if (supports_multiple_packet_number_spaces_) {
+    base_packet_number =
+        largest_decrypted_packet_numbers_[GetPacketNumberSpace(*header)];
+  } else {
+    base_packet_number = largest_packet_number_;
+  }
   uint64_t full_packet_number;
   if (!ProcessAndCalculatePacketNumber(
           encrypted_reader, header->packet_number_length, base_packet_number,
@@ -3959,7 +4015,8 @@
                                 const QuicPacketHeader& header,
                                 char* decrypted_buffer,
                                 size_t buffer_length,
-                                size_t* decrypted_length) {
+                                size_t* decrypted_length,
+                                EncryptionLevel* decrypted_level) {
   DCHECK(decrypter_ != nullptr);
 
   bool success = decrypter_->DecryptPacket(
@@ -3967,6 +4024,7 @@
       decrypted_buffer, decrypted_length, buffer_length);
   if (success) {
     visitor_->OnDecryptedPacket(decrypter_level_);
+    *decrypted_level = decrypter_level_;
   } else if (alternative_decrypter_ != nullptr) {
     if (header.nonce != nullptr) {
       DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
@@ -3991,6 +4049,7 @@
     }
     if (success) {
       visitor_->OnDecryptedPacket(alternative_decrypter_level_);
+      *decrypted_level = decrypter_level_;
       if (alternative_decrypter_latch_) {
         // Switch to the alternative decrypter and latch so that we cannot
         // switch back.
@@ -5700,5 +5759,19 @@
   infer_packet_header_type_from_version_ = true;
 }
 
+void QuicFramer::EnableMultiplePacketNumberSpacesSupport() {
+  if (supports_multiple_packet_number_spaces_) {
+    QUIC_BUG << "Multiple packet number spaces has already been enabled";
+    return;
+  }
+  if (largest_packet_number_.IsInitialized()) {
+    QUIC_BUG << "Try to enable multiple packet number spaces support after any "
+                "packet has been received.";
+    return;
+  }
+
+  supports_multiple_packet_number_spaces_ = true;
+}
+
 #undef ENDPOINT  // undef for jumbo builds
 }  // namespace quic
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index 312dbb2..98f7385 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -577,6 +577,8 @@
     return expected_connection_id_length_;
   }
 
+  void EnableMultiplePacketNumberSpacesSupport();
+
  private:
   friend class test::QuicFramerPeer;
 
@@ -678,7 +680,8 @@
                       const QuicPacketHeader& header,
                       char* decrypted_buffer,
                       size_t buffer_length,
-                      size_t* decrypted_length);
+                      size_t* decrypted_length,
+                      EncryptionLevel* decrypted_level);
 
   // Returns the full packet number from the truncated
   // wire format version and the last seen packet number.
@@ -876,6 +879,9 @@
   QuicErrorCode error_;
   // Updated by ProcessPacketHeader when it succeeds decrypting a larger packet.
   QuicPacketNumber largest_packet_number_;
+  // Largest successfully decrypted packet number per packet number space. Only
+  // used when supports_multiple_packet_number_spaces_ is true.
+  QuicPacketNumber largest_decrypted_packet_numbers_[NUM_PACKET_NUMBER_SPACES];
   // Updated by WritePacketHeader.
   QuicConnectionId last_serialized_connection_id_;
   // The last QUIC version label received.
@@ -938,6 +944,9 @@
   // When this is true, QuicFramer will change expected_connection_id_length_
   // to the received destination connection ID length of all IETF long headers.
   bool should_update_expected_connection_id_length_;
+
+  // Indicates whether this framer supports multiple packet number spaces.
+  bool supports_multiple_packet_number_spaces_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 782ff03..2985059 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -13141,6 +13141,99 @@
             QuicPacketNumber(UINT64_C(0x13374233)));
 }
 
+TEST_P(QuicFramerTest, MultiplePacketNumberSpaces) {
+  if (framer_.transport_version() < QUIC_VERSION_46) {
+    return;
+  }
+  framer_.SetShouldUpdateExpectedConnectionIdLength(true);
+  framer_.EnableMultiplePacketNumberSpacesSupport();
+
+  // clang-format off
+  unsigned char long_header_packet[] = {
+       // public flags (long header with packet type ZERO_RTT_PROTECTED and
+       // 4-byte packet number)
+       0xD3,
+       // version
+       QUIC_VERSION_BYTES,
+       // destination connection ID length
+       0x60,
+       // destination connection ID
+       0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42,
+       // packet number
+       0x12, 0x34, 0x56, 0x78,
+       // padding frame
+       0x00,
+   };
+  unsigned char long_header_packet99[] = {
+       // public flags (long header with packet type ZERO_RTT_PROTECTED and
+       // 4-byte packet number)
+       0xD3,
+       // version
+       QUIC_VERSION_BYTES,
+       // destination connection ID length
+       0x60,
+       // destination connection ID
+       0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42,
+       // long header packet length
+       0x05,
+       // packet number
+       0x12, 0x34, 0x56, 0x78,
+       // padding frame
+       0x00,
+  };
+  // clang-format on
+
+  framer_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TestDecrypter>());
+  if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) {
+    EXPECT_TRUE(framer_.ProcessPacket(
+        QuicEncryptedPacket(AsChars(long_header_packet),
+                            QUIC_ARRAYSIZE(long_header_packet), false)));
+  } else {
+    EXPECT_TRUE(framer_.ProcessPacket(
+        QuicEncryptedPacket(AsChars(long_header_packet99),
+                            QUIC_ARRAYSIZE(long_header_packet99), false)));
+  }
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  EXPECT_FALSE(
+      QuicFramerPeer::GetLargestDecryptedPacketNumber(&framer_, INITIAL_DATA)
+          .IsInitialized());
+  EXPECT_FALSE(
+      QuicFramerPeer::GetLargestDecryptedPacketNumber(&framer_, HANDSHAKE_DATA)
+          .IsInitialized());
+  EXPECT_EQ(kPacketNumber, QuicFramerPeer::GetLargestDecryptedPacketNumber(
+                               &framer_, APPLICATION_DATA));
+
+  // clang-format off
+  unsigned char short_header_packet[] = {
+     // type (short header, 1 byte packet number)
+     0x40,
+     // connection_id
+     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42,
+     // packet number
+     0x79,
+     // padding frame
+     0x00,
+  };
+  // clang-format on
+
+  QuicEncryptedPacket short_header_encrypted(
+      AsChars(short_header_packet), QUIC_ARRAYSIZE(short_header_packet), false);
+  framer_.SetDecrypter(ENCRYPTION_FORWARD_SECURE,
+                       QuicMakeUnique<TestDecrypter>());
+  EXPECT_TRUE(framer_.ProcessPacket(short_header_encrypted));
+
+  EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+  EXPECT_FALSE(
+      QuicFramerPeer::GetLargestDecryptedPacketNumber(&framer_, INITIAL_DATA)
+          .IsInitialized());
+  EXPECT_FALSE(
+      QuicFramerPeer::GetLargestDecryptedPacketNumber(&framer_, HANDSHAKE_DATA)
+          .IsInitialized());
+  EXPECT_EQ(kPacketNumber + 1, QuicFramerPeer::GetLargestDecryptedPacketNumber(
+                                   &framer_, APPLICATION_DATA));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc
index d12ebeb..63b9b85 100644
--- a/quic/core/quic_utils.cc
+++ b/quic/core/quic_utils.cc
@@ -531,5 +531,23 @@
       QuicEndian::NetToHost64(data_bytes[0]));
 }
 
+// static
+PacketNumberSpace QuicUtils::GetPacketNumberSpace(
+    EncryptionLevel encryption_level) {
+  switch (encryption_level) {
+    case ENCRYPTION_INITIAL:
+      return INITIAL_DATA;
+    case ENCRYPTION_HANDSHAKE:
+      return HANDSHAKE_DATA;
+    case ENCRYPTION_ZERO_RTT:
+    case ENCRYPTION_FORWARD_SECURE:
+      return APPLICATION_DATA;
+    default:
+      QUIC_BUG << "Try to get packet number space of encryption level: "
+               << EncryptionLevelToString(encryption_level);
+      return NUM_PACKET_NUMBER_SPACES;
+  }
+}
+
 #undef RETURN_STRING_LITERAL  // undef for jumbo builds
 }  // namespace quic
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h
index 709ea64..515056c 100644
--- a/quic/core/quic_utils.h
+++ b/quic/core/quic_utils.h
@@ -179,6 +179,10 @@
   // Generates a 128bit stateless reset token based on a connection ID.
   static QuicUint128 GenerateStatelessResetToken(
       QuicConnectionId connection_id);
+
+  // Determines packet number space from |encryption_level|.
+  static PacketNumberSpace GetPacketNumberSpace(
+      EncryptionLevel encryption_level);
 };
 
 }  // namespace quic
diff --git a/quic/test_tools/quic_framer_peer.cc b/quic/test_tools/quic_framer_peer.cc
index 9d8ec86..b8b749f 100644
--- a/quic/test_tools/quic_framer_peer.cc
+++ b/quic/test_tools/quic_framer_peer.cc
@@ -354,5 +354,12 @@
       expected_connection_id_length;
 }
 
+// static
+QuicPacketNumber QuicFramerPeer::GetLargestDecryptedPacketNumber(
+    QuicFramer* framer,
+    PacketNumberSpace packet_number_space) {
+  return framer->largest_decrypted_packet_numbers_[packet_number_space];
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/quic/test_tools/quic_framer_peer.h b/quic/test_tools/quic_framer_peer.h
index f6de152..6e34be2 100644
--- a/quic/test_tools/quic_framer_peer.h
+++ b/quic/test_tools/quic_framer_peer.h
@@ -167,6 +167,9 @@
   static void SetExpectedConnectionIDLength(
       QuicFramer* framer,
       uint8_t expected_connection_id_length);
+  static QuicPacketNumber GetLargestDecryptedPacketNumber(
+      QuicFramer* framer,
+      PacketNumberSpace packet_number_space);
 };
 
 }  // namespace test