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