| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "quiche/quic/core/quic_framer.h" |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/base/macros.h" |
| #include "absl/memory/memory.h" |
| #include "absl/strings/escaping.h" |
| #include "absl/strings/match.h" |
| #include "absl/strings/string_view.h" |
| #include "quiche/quic/core/crypto/null_decrypter.h" |
| #include "quiche/quic/core/crypto/null_encrypter.h" |
| #include "quiche/quic/core/crypto/quic_decrypter.h" |
| #include "quiche/quic/core/crypto/quic_encrypter.h" |
| #include "quiche/quic/core/quic_connection_id.h" |
| #include "quiche/quic/core/quic_error_codes.h" |
| #include "quiche/quic/core/quic_packets.h" |
| #include "quiche/quic/core/quic_types.h" |
| #include "quiche/quic/core/quic_utils.h" |
| #include "quiche/quic/core/quic_versions.h" |
| #include "quiche/quic/platform/api/quic_expect_bug.h" |
| #include "quiche/quic/platform/api/quic_flags.h" |
| #include "quiche/quic/platform/api/quic_logging.h" |
| #include "quiche/quic/platform/api/quic_test.h" |
| #include "quiche/quic/test_tools/quic_framer_peer.h" |
| #include "quiche/quic/test_tools/quic_test_utils.h" |
| #include "quiche/quic/test_tools/simple_data_producer.h" |
| #include "quiche/common/test_tools/quiche_test_utils.h" |
| |
| using testing::_; |
| using testing::ContainerEq; |
| using testing::Return; |
| |
| namespace quic { |
| namespace test { |
| namespace { |
| |
| const uint64_t kEpoch = UINT64_C(1) << 32; |
| const uint64_t kMask = kEpoch - 1; |
| |
| const StatelessResetToken kTestStatelessResetToken{ |
| 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, |
| 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}; |
| |
| // Use fields in which each byte is distinct to ensure that every byte is |
| // framed correctly. The values are otherwise arbitrary. |
| QuicConnectionId FramerTestConnectionId() { |
| return TestConnectionId(UINT64_C(0xFEDCBA9876543210)); |
| } |
| |
| QuicConnectionId FramerTestConnectionIdPlusOne() { |
| return TestConnectionId(UINT64_C(0xFEDCBA9876543211)); |
| } |
| |
| QuicConnectionId FramerTestConnectionIdNineBytes() { |
| uint8_t connection_id_bytes[9] = {0xFE, 0xDC, 0xBA, 0x98, 0x76, |
| 0x54, 0x32, 0x10, 0x42}; |
| return QuicConnectionId(reinterpret_cast<char*>(connection_id_bytes), |
| sizeof(connection_id_bytes)); |
| } |
| |
| const QuicPacketNumber kPacketNumber = QuicPacketNumber(UINT64_C(0x12345678)); |
| const QuicPacketNumber kSmallLargestObserved = |
| QuicPacketNumber(UINT16_C(0x1234)); |
| const QuicPacketNumber kSmallMissingPacket = QuicPacketNumber(UINT16_C(0x1233)); |
| const QuicPacketNumber kLeastUnacked = QuicPacketNumber(UINT64_C(0x012345670)); |
| const QuicStreamId kStreamId = UINT64_C(0x01020304); |
| // Note that the high 4 bits of the stream offset must be less than 0x40 |
| // in order to ensure that the value can be encoded using VarInt62 encoding. |
| const QuicStreamOffset kStreamOffset = UINT64_C(0x3A98FEDC32107654); |
| const QuicPublicResetNonceProof kNonceProof = UINT64_C(0xABCDEF0123456789); |
| |
| // In testing that we can ack the full range of packets... |
| // This is the largest packet number that can be represented in IETF QUIC |
| // varint62 format. |
| const QuicPacketNumber kLargestIetfLargestObserved = |
| QuicPacketNumber(UINT64_C(0x3fffffffffffffff)); |
| // Encodings for the two bits in a VarInt62 that |
| // describe the length of the VarInt61. For binary packet |
| // formats in this file, the convention is to code the |
| // first byte as |
| // kVarInt62FourBytes + 0x<value_in_that_byte> |
| const uint8_t kVarInt62OneByte = 0x00; |
| const uint8_t kVarInt62TwoBytes = 0x40; |
| const uint8_t kVarInt62FourBytes = 0x80; |
| const uint8_t kVarInt62EightBytes = 0xc0; |
| |
| class TestEncrypter : public QuicEncrypter { |
| public: |
| ~TestEncrypter() override {} |
| bool SetKey(absl::string_view /*key*/) override { return true; } |
| bool SetNoncePrefix(absl::string_view /*nonce_prefix*/) override { |
| return true; |
| } |
| bool SetIV(absl::string_view /*iv*/) override { return true; } |
| bool SetHeaderProtectionKey(absl::string_view /*key*/) override { |
| return true; |
| } |
| bool EncryptPacket(uint64_t packet_number, absl::string_view associated_data, |
| absl::string_view plaintext, char* output, |
| size_t* output_length, |
| size_t /*max_output_length*/) override { |
| packet_number_ = QuicPacketNumber(packet_number); |
| associated_data_ = std::string(associated_data); |
| plaintext_ = std::string(plaintext); |
| memcpy(output, plaintext.data(), plaintext.length()); |
| *output_length = plaintext.length(); |
| return true; |
| } |
| std::string GenerateHeaderProtectionMask( |
| absl::string_view /*sample*/) override { |
| return std::string(5, 0); |
| } |
| size_t GetKeySize() const override { return 0; } |
| size_t GetNoncePrefixSize() const override { return 0; } |
| size_t GetIVSize() const override { return 0; } |
| size_t GetMaxPlaintextSize(size_t ciphertext_size) const override { |
| return ciphertext_size; |
| } |
| size_t GetCiphertextSize(size_t plaintext_size) const override { |
| return plaintext_size; |
| } |
| QuicPacketCount GetConfidentialityLimit() const override { |
| return std::numeric_limits<QuicPacketCount>::max(); |
| } |
| absl::string_view GetKey() const override { return absl::string_view(); } |
| absl::string_view GetNoncePrefix() const override { |
| return absl::string_view(); |
| } |
| |
| QuicPacketNumber packet_number_; |
| std::string associated_data_; |
| std::string plaintext_; |
| }; |
| |
| class TestDecrypter : public QuicDecrypter { |
| public: |
| ~TestDecrypter() override {} |
| bool SetKey(absl::string_view /*key*/) override { return true; } |
| bool SetNoncePrefix(absl::string_view /*nonce_prefix*/) override { |
| return true; |
| } |
| bool SetIV(absl::string_view /*iv*/) override { return true; } |
| bool SetHeaderProtectionKey(absl::string_view /*key*/) override { |
| return true; |
| } |
| bool SetPreliminaryKey(absl::string_view /*key*/) override { |
| QUIC_BUG(quic_bug_10486_1) << "should not be called"; |
| return false; |
| } |
| bool SetDiversificationNonce(const DiversificationNonce& /*key*/) override { |
| return true; |
| } |
| bool DecryptPacket(uint64_t packet_number, absl::string_view associated_data, |
| absl::string_view ciphertext, char* output, |
| size_t* output_length, |
| size_t /*max_output_length*/) override { |
| packet_number_ = QuicPacketNumber(packet_number); |
| associated_data_ = std::string(associated_data); |
| ciphertext_ = std::string(ciphertext); |
| memcpy(output, ciphertext.data(), ciphertext.length()); |
| *output_length = ciphertext.length(); |
| return true; |
| } |
| std::string GenerateHeaderProtectionMask( |
| QuicDataReader* /*sample_reader*/) override { |
| return std::string(5, 0); |
| } |
| size_t GetKeySize() const override { return 0; } |
| size_t GetNoncePrefixSize() const override { return 0; } |
| size_t GetIVSize() const override { return 0; } |
| absl::string_view GetKey() const override { return absl::string_view(); } |
| absl::string_view GetNoncePrefix() const override { |
| return absl::string_view(); |
| } |
| // Use a distinct value starting with 0xFFFFFF, which is never used by TLS. |
| uint32_t cipher_id() const override { return 0xFFFFFFF2; } |
| QuicPacketCount GetIntegrityLimit() const override { |
| return std::numeric_limits<QuicPacketCount>::max(); |
| } |
| QuicPacketNumber packet_number_; |
| std::string associated_data_; |
| std::string ciphertext_; |
| }; |
| |
| std::unique_ptr<QuicEncryptedPacket> EncryptPacketWithTagAndPhase( |
| const QuicPacket& packet, uint8_t tag, bool phase) { |
| std::string packet_data = std::string(packet.AsStringPiece()); |
| if (phase) { |
| packet_data[0] |= FLAGS_KEY_PHASE_BIT; |
| } else { |
| packet_data[0] &= ~FLAGS_KEY_PHASE_BIT; |
| } |
| |
| TaggingEncrypter crypter(tag); |
| const size_t packet_size = crypter.GetCiphertextSize(packet_data.size()); |
| char* buffer = new char[packet_size]; |
| size_t buf_len = 0; |
| if (!crypter.EncryptPacket(0, absl::string_view(), packet_data, buffer, |
| &buf_len, packet_size)) { |
| delete[] buffer; |
| return nullptr; |
| } |
| |
| return std::make_unique<QuicEncryptedPacket>(buffer, buf_len, |
| /*owns_buffer=*/true); |
| } |
| |
| class TestQuicVisitor : public QuicFramerVisitorInterface { |
| public: |
| TestQuicVisitor() |
| : error_count_(0), |
| version_mismatch_(0), |
| packet_count_(0), |
| frame_count_(0), |
| complete_packets_(0), |
| derive_next_key_count_(0), |
| decrypted_first_packet_in_key_phase_count_(0), |
| accept_packet_(true), |
| accept_public_header_(true) {} |
| |
| ~TestQuicVisitor() override {} |
| |
| void OnError(QuicFramer* f) override { |
| QUIC_DLOG(INFO) << "QuicFramer Error: " << QuicErrorCodeToString(f->error()) |
| << " (" << f->error() << ")"; |
| ++error_count_; |
| } |
| |
| void OnPacket() override {} |
| |
| void OnPublicResetPacket(const QuicPublicResetPacket& packet) override { |
| public_reset_packet_ = std::make_unique<QuicPublicResetPacket>((packet)); |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| |
| void OnVersionNegotiationPacket( |
| const QuicVersionNegotiationPacket& packet) override { |
| version_negotiation_packet_ = |
| std::make_unique<QuicVersionNegotiationPacket>((packet)); |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| |
| void OnRetryPacket(QuicConnectionId original_connection_id, |
| QuicConnectionId new_connection_id, |
| absl::string_view retry_token, |
| absl::string_view retry_integrity_tag, |
| absl::string_view retry_without_tag) override { |
| on_retry_packet_called_ = true; |
| retry_original_connection_id_ = |
| std::make_unique<QuicConnectionId>(original_connection_id); |
| retry_new_connection_id_ = |
| std::make_unique<QuicConnectionId>(new_connection_id); |
| retry_token_ = std::make_unique<std::string>(std::string(retry_token)); |
| retry_token_integrity_tag_ = |
| std::make_unique<std::string>(std::string(retry_integrity_tag)); |
| retry_without_tag_ = |
| std::make_unique<std::string>(std::string(retry_without_tag)); |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| |
| bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override { |
| QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: " |
| << received_version; |
| ++version_mismatch_; |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| return false; |
| } |
| |
| bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { |
| header_ = std::make_unique<QuicPacketHeader>((header)); |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| return accept_public_header_; |
| } |
| |
| bool OnUnauthenticatedHeader(const QuicPacketHeader& /*header*/) override { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| return true; |
| } |
| |
| void OnDecryptedPacket(size_t /*length*/, |
| EncryptionLevel /*level*/) override { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| |
| bool OnPacketHeader(const QuicPacketHeader& header) override { |
| ++packet_count_; |
| header_ = std::make_unique<QuicPacketHeader>((header)); |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| return accept_packet_; |
| } |
| |
| void OnCoalescedPacket(const QuicEncryptedPacket& packet) override { |
| coalesced_packets_.push_back(packet.Clone()); |
| } |
| |
| void OnUndecryptablePacket(const QuicEncryptedPacket& packet, |
| EncryptionLevel decryption_level, |
| bool has_decryption_key) override { |
| undecryptable_packets_.push_back(packet.Clone()); |
| undecryptable_decryption_levels_.push_back(decryption_level); |
| undecryptable_has_decryption_keys_.push_back(has_decryption_key); |
| } |
| |
| bool OnStreamFrame(const QuicStreamFrame& frame) override { |
| ++frame_count_; |
| // Save a copy of the data so it is valid after the packet is processed. |
| std::string* string_data = |
| new std::string(frame.data_buffer, frame.data_length); |
| stream_data_.push_back(absl::WrapUnique(string_data)); |
| stream_frames_.push_back(std::make_unique<QuicStreamFrame>( |
| frame.stream_id, frame.fin, frame.offset, *string_data)); |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| // Low order bits of type encode flags, ignore them for this test. |
| EXPECT_TRUE(IS_IETF_STREAM_FRAME(framer_->current_received_frame_type())); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnCryptoFrame(const QuicCryptoFrame& frame) override { |
| ++frame_count_; |
| // Save a copy of the data so it is valid after the packet is processed. |
| std::string* string_data = |
| new std::string(frame.data_buffer, frame.data_length); |
| crypto_data_.push_back(absl::WrapUnique(string_data)); |
| crypto_frames_.push_back(std::make_unique<QuicCryptoFrame>( |
| frame.level, frame.offset, *string_data)); |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_EQ(IETF_CRYPTO, framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnAckFrameStart(QuicPacketNumber largest_acked, |
| QuicTime::Delta ack_delay_time) override { |
| ++frame_count_; |
| QuicAckFrame ack_frame; |
| ack_frame.largest_acked = largest_acked; |
| ack_frame.ack_delay_time = ack_delay_time; |
| ack_frames_.push_back(std::make_unique<QuicAckFrame>(ack_frame)); |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_TRUE(IETF_ACK == framer_->current_received_frame_type() || |
| IETF_ACK_ECN == framer_->current_received_frame_type() || |
| IETF_ACK_RECEIVE_TIMESTAMPS == |
| framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override { |
| QUICHE_DCHECK(!ack_frames_.empty()); |
| ack_frames_[ack_frames_.size() - 1]->packets.AddRange(start, end); |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_TRUE(IETF_ACK == framer_->current_received_frame_type() || |
| IETF_ACK_ECN == framer_->current_received_frame_type() || |
| IETF_ACK_RECEIVE_TIMESTAMPS == |
| framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnAckTimestamp(QuicPacketNumber packet_number, |
| QuicTime timestamp) override { |
| ack_frames_[ack_frames_.size() - 1]->received_packet_times.push_back( |
| std::make_pair(packet_number, timestamp)); |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_TRUE(IETF_ACK == framer_->current_received_frame_type() || |
| IETF_ACK_ECN == framer_->current_received_frame_type() || |
| IETF_ACK_RECEIVE_TIMESTAMPS == |
| framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnAckFrameEnd(QuicPacketNumber /*start*/) override { return true; } |
| |
| bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override { |
| ++frame_count_; |
| stop_waiting_frames_.push_back( |
| std::make_unique<QuicStopWaitingFrame>(frame)); |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| return true; |
| } |
| |
| bool OnPaddingFrame(const QuicPaddingFrame& frame) override { |
| padding_frames_.push_back(std::make_unique<QuicPaddingFrame>(frame)); |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_EQ(IETF_PADDING, framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnPingFrame(const QuicPingFrame& frame) override { |
| ++frame_count_; |
| ping_frames_.push_back(std::make_unique<QuicPingFrame>(frame)); |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_EQ(IETF_PING, framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnMessageFrame(const QuicMessageFrame& frame) override { |
| ++frame_count_; |
| message_frames_.push_back( |
| std::make_unique<QuicMessageFrame>(frame.data, frame.message_length)); |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_TRUE(IETF_EXTENSION_MESSAGE_NO_LENGTH_V99 == |
| framer_->current_received_frame_type() || |
| IETF_EXTENSION_MESSAGE_V99 == |
| framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) override { |
| ++frame_count_; |
| handshake_done_frames_.push_back( |
| std::make_unique<QuicHandshakeDoneFrame>(frame)); |
| QUICHE_DCHECK(VersionHasIetfQuicFrames(transport_version_)); |
| EXPECT_EQ(IETF_HANDSHAKE_DONE, framer_->current_received_frame_type()); |
| return true; |
| } |
| |
| bool OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) override { |
| ++frame_count_; |
| ack_frequency_frames_.emplace_back( |
| std::make_unique<QuicAckFrequencyFrame>(frame)); |
| QUICHE_DCHECK(VersionHasIetfQuicFrames(transport_version_)); |
| EXPECT_EQ(IETF_ACK_FREQUENCY, framer_->current_received_frame_type()); |
| return true; |
| } |
| |
| void OnPacketComplete() override { ++complete_packets_; } |
| |
| bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override { |
| rst_stream_frame_ = frame; |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_EQ(IETF_RST_STREAM, framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override { |
| connection_close_frame_ = frame; |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_NE(GOOGLE_QUIC_CONNECTION_CLOSE, frame.close_type); |
| if (frame.close_type == IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) { |
| EXPECT_EQ(IETF_CONNECTION_CLOSE, |
| framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(IETF_APPLICATION_CLOSE, |
| framer_->current_received_frame_type()); |
| } |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override { |
| stop_sending_frame_ = frame; |
| EXPECT_EQ(IETF_STOP_SENDING, framer_->current_received_frame_type()); |
| EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_)); |
| return true; |
| } |
| |
| bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override { |
| path_challenge_frame_ = frame; |
| EXPECT_EQ(IETF_PATH_CHALLENGE, framer_->current_received_frame_type()); |
| EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_)); |
| return true; |
| } |
| |
| bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override { |
| path_response_frame_ = frame; |
| EXPECT_EQ(IETF_PATH_RESPONSE, framer_->current_received_frame_type()); |
| EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_)); |
| return true; |
| } |
| |
| bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override { |
| goaway_frame_ = frame; |
| EXPECT_FALSE(VersionHasIetfQuicFrames(transport_version_)); |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| return true; |
| } |
| |
| bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override { |
| max_streams_frame_ = frame; |
| EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_)); |
| EXPECT_TRUE(IETF_MAX_STREAMS_UNIDIRECTIONAL == |
| framer_->current_received_frame_type() || |
| IETF_MAX_STREAMS_BIDIRECTIONAL == |
| framer_->current_received_frame_type()); |
| return true; |
| } |
| |
| bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override { |
| streams_blocked_frame_ = frame; |
| EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_)); |
| EXPECT_TRUE(IETF_STREAMS_BLOCKED_UNIDIRECTIONAL == |
| framer_->current_received_frame_type() || |
| IETF_STREAMS_BLOCKED_BIDIRECTIONAL == |
| framer_->current_received_frame_type()); |
| return true; |
| } |
| |
| bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override { |
| window_update_frame_ = frame; |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_TRUE(IETF_MAX_DATA == framer_->current_received_frame_type() || |
| IETF_MAX_STREAM_DATA == |
| framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnBlockedFrame(const QuicBlockedFrame& frame) override { |
| blocked_frame_ = frame; |
| if (VersionHasIetfQuicFrames(transport_version_)) { |
| EXPECT_TRUE(IETF_DATA_BLOCKED == framer_->current_received_frame_type() || |
| IETF_STREAM_DATA_BLOCKED == |
| framer_->current_received_frame_type()); |
| } else { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| return true; |
| } |
| |
| bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override { |
| new_connection_id_ = frame; |
| EXPECT_EQ(IETF_NEW_CONNECTION_ID, framer_->current_received_frame_type()); |
| EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_)); |
| return true; |
| } |
| |
| bool OnRetireConnectionIdFrame( |
| const QuicRetireConnectionIdFrame& frame) override { |
| EXPECT_EQ(IETF_RETIRE_CONNECTION_ID, |
| framer_->current_received_frame_type()); |
| EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_)); |
| retire_connection_id_ = frame; |
| return true; |
| } |
| |
| bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override { |
| new_token_ = frame; |
| EXPECT_EQ(IETF_NEW_TOKEN, framer_->current_received_frame_type()); |
| EXPECT_TRUE(VersionHasIetfQuicFrames(transport_version_)); |
| return true; |
| } |
| |
| bool IsValidStatelessResetToken( |
| const StatelessResetToken& token) const override { |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| return token == kTestStatelessResetToken; |
| } |
| |
| void OnAuthenticatedIetfStatelessResetPacket( |
| const QuicIetfStatelessResetPacket& packet) override { |
| stateless_reset_packet_ = |
| std::make_unique<QuicIetfStatelessResetPacket>(packet); |
| EXPECT_EQ(0u, framer_->current_received_frame_type()); |
| } |
| |
| void OnKeyUpdate(KeyUpdateReason reason) override { |
| key_update_reasons_.push_back(reason); |
| } |
| |
| void OnDecryptedFirstPacketInKeyPhase() override { |
| decrypted_first_packet_in_key_phase_count_++; |
| } |
| |
| std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter() |
| override { |
| derive_next_key_count_++; |
| return std::make_unique<StrictTaggingDecrypter>(derive_next_key_count_); |
| } |
| std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() override { |
| return std::make_unique<TaggingEncrypter>(derive_next_key_count_); |
| } |
| |
| void set_framer(QuicFramer* framer) { |
| framer_ = framer; |
| transport_version_ = framer->transport_version(); |
| } |
| |
| size_t key_update_count() const { return key_update_reasons_.size(); } |
| |
| // Counters from the visitor_ callbacks. |
| int error_count_; |
| int version_mismatch_; |
| int packet_count_; |
| int frame_count_; |
| int complete_packets_; |
| std::vector<KeyUpdateReason> key_update_reasons_; |
| int derive_next_key_count_; |
| int decrypted_first_packet_in_key_phase_count_; |
| bool accept_packet_; |
| bool accept_public_header_; |
| |
| std::unique_ptr<QuicPacketHeader> header_; |
| std::unique_ptr<QuicPublicResetPacket> public_reset_packet_; |
| std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_; |
| std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_; |
| std::unique_ptr<QuicConnectionId> retry_original_connection_id_; |
| std::unique_ptr<QuicConnectionId> retry_new_connection_id_; |
| std::unique_ptr<std::string> retry_token_; |
| std::unique_ptr<std::string> retry_token_integrity_tag_; |
| std::unique_ptr<std::string> retry_without_tag_; |
| bool on_retry_packet_called_ = false; |
| std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_; |
| std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_; |
| std::vector<std::unique_ptr<QuicAckFrame>> ack_frames_; |
| std::vector<std::unique_ptr<QuicStopWaitingFrame>> stop_waiting_frames_; |
| std::vector<std::unique_ptr<QuicPaddingFrame>> padding_frames_; |
| std::vector<std::unique_ptr<QuicPingFrame>> ping_frames_; |
| std::vector<std::unique_ptr<QuicMessageFrame>> message_frames_; |
| std::vector<std::unique_ptr<QuicHandshakeDoneFrame>> handshake_done_frames_; |
| std::vector<std::unique_ptr<QuicAckFrequencyFrame>> ack_frequency_frames_; |
| std::vector<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_; |
| std::vector<std::unique_ptr<QuicEncryptedPacket>> undecryptable_packets_; |
| std::vector<EncryptionLevel> undecryptable_decryption_levels_; |
| std::vector<bool> undecryptable_has_decryption_keys_; |
| QuicRstStreamFrame rst_stream_frame_; |
| QuicConnectionCloseFrame connection_close_frame_; |
| QuicStopSendingFrame stop_sending_frame_; |
| QuicGoAwayFrame goaway_frame_; |
| QuicPathChallengeFrame path_challenge_frame_; |
| QuicPathResponseFrame path_response_frame_; |
| QuicWindowUpdateFrame window_update_frame_; |
| QuicBlockedFrame blocked_frame_; |
| QuicStreamsBlockedFrame streams_blocked_frame_; |
| QuicMaxStreamsFrame max_streams_frame_; |
| QuicNewConnectionIdFrame new_connection_id_; |
| QuicRetireConnectionIdFrame retire_connection_id_; |
| QuicNewTokenFrame new_token_; |
| std::vector<std::unique_ptr<std::string>> stream_data_; |
| std::vector<std::unique_ptr<std::string>> crypto_data_; |
| QuicTransportVersion transport_version_; |
| QuicFramer* framer_; |
| }; |
| |
| // Simple struct for defining a packet's content, and associated |
| // parse error. |
| struct PacketFragment { |
| std::string error_if_missing; |
| std::vector<unsigned char> fragment; |
| }; |
| |
| using PacketFragments = std::vector<struct PacketFragment>; |
| |
| class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { |
| public: |
| QuicFramerTest() |
| : encrypter_(new test::TestEncrypter()), |
| decrypter_(new test::TestDecrypter()), |
| version_(GetParam()), |
| start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)), |
| framer_(AllSupportedVersions(), start_, Perspective::IS_SERVER, |
| kQuicDefaultConnectionIdLength) { |
| framer_.set_version(version_); |
| if (framer_.version().KnowsWhichDecrypterToUse()) { |
| framer_.InstallDecrypter(ENCRYPTION_INITIAL, |
| std::unique_ptr<QuicDecrypter>(decrypter_)); |
| } else { |
| framer_.SetDecrypter(ENCRYPTION_INITIAL, |
| std::unique_ptr<QuicDecrypter>(decrypter_)); |
| } |
| framer_.SetEncrypter(ENCRYPTION_INITIAL, |
| std::unique_ptr<QuicEncrypter>(encrypter_)); |
| |
| framer_.set_visitor(&visitor_); |
| framer_.InferPacketHeaderTypeFromVersion(); |
| visitor_.set_framer(&framer_); |
| } |
| |
| void SetDecrypterLevel(EncryptionLevel level) { |
| if (!framer_.version().KnowsWhichDecrypterToUse()) { |
| return; |
| } |
| decrypter_ = new TestDecrypter(); |
| framer_.InstallDecrypter(level, std::unique_ptr<QuicDecrypter>(decrypter_)); |
| } |
| |
| // Helper function to get unsigned char representation of the handshake |
| // protocol byte at position |pos| of the current QUIC version number. |
| unsigned char GetQuicVersionByte(int pos) { |
| return (CreateQuicVersionLabel(version_) >> 8 * (3 - pos)) & 0xff; |
| } |
| |
| // Helper functions to take a v1 long header packet and make it v2. These are |
| // not needed for short header packets, but if sent, this function will exit |
| // cleanly. It needs to be called twice for coalesced packets (see references |
| // to length_of_first_coalesced_packet below for examples of how to do this). |
| inline void ReviseFirstByteByVersion(unsigned char packet_ietf[]) { |
| if (version_.UsesV2PacketTypes() && (packet_ietf[0] >= 0x80)) { |
| packet_ietf[0] = (packet_ietf[0] + 0x10) | 0xc0; |
| } |
| } |
| inline void ReviseFirstByteByVersion(PacketFragments& packet_ietf) { |
| ReviseFirstByteByVersion(&packet_ietf[0].fragment[0]); |
| } |
| |
| bool CheckEncryption(QuicPacketNumber packet_number, QuicPacket* packet) { |
| if (packet_number != encrypter_->packet_number_) { |
| QUIC_LOG(ERROR) << "Encrypted incorrect packet number. expected " |
| << packet_number |
| << " actual: " << encrypter_->packet_number_; |
| return false; |
| } |
| if (packet->AssociatedData(framer_.transport_version()) != |
| encrypter_->associated_data_) { |
| QUIC_LOG(ERROR) << "Encrypted incorrect associated data. expected " |
| << packet->AssociatedData(framer_.transport_version()) |
| << " actual: " << encrypter_->associated_data_; |
| return false; |
| } |
| if (packet->Plaintext(framer_.transport_version()) != |
| encrypter_->plaintext_) { |
| QUIC_LOG(ERROR) << "Encrypted incorrect plaintext data. expected " |
| << packet->Plaintext(framer_.transport_version()) |
| << " actual: " << encrypter_->plaintext_; |
| return false; |
| } |
| return true; |
| } |
| |
| bool CheckDecryption(const QuicEncryptedPacket& encrypted, |
| bool includes_version, |
| bool includes_diversification_nonce, |
| QuicConnectionIdLength destination_connection_id_length, |
| QuicConnectionIdLength source_connection_id_length) { |
| return CheckDecryption( |
| encrypted, includes_version, includes_diversification_nonce, |
| destination_connection_id_length, source_connection_id_length, |
| VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); |
| } |
| |
| bool CheckDecryption( |
| const QuicEncryptedPacket& encrypted, bool includes_version, |
| bool includes_diversification_nonce, |
| QuicConnectionIdLength destination_connection_id_length, |
| QuicConnectionIdLength source_connection_id_length, |
| QuicVariableLengthIntegerLength retry_token_length_length, |
| size_t retry_token_length, |
| QuicVariableLengthIntegerLength length_length) { |
| if (visitor_.header_->packet_number != decrypter_->packet_number_) { |
| QUIC_LOG(ERROR) << "Decrypted incorrect packet number. expected " |
| << visitor_.header_->packet_number |
| << " actual: " << decrypter_->packet_number_; |
| return false; |
| } |
| absl::string_view associated_data = |
| QuicFramer::GetAssociatedDataFromEncryptedPacket( |
| framer_.transport_version(), encrypted, |
| destination_connection_id_length, source_connection_id_length, |
| includes_version, includes_diversification_nonce, |
| PACKET_4BYTE_PACKET_NUMBER, retry_token_length_length, |
| retry_token_length, length_length); |
| if (associated_data != decrypter_->associated_data_) { |
| QUIC_LOG(ERROR) << "Decrypted incorrect associated data. expected " |
| << absl::BytesToHexString(associated_data) << " actual: " |
| << absl::BytesToHexString(decrypter_->associated_data_); |
| return false; |
| } |
| absl::string_view ciphertext( |
| encrypted.AsStringPiece().substr(GetStartOfEncryptedData( |
| framer_.transport_version(), destination_connection_id_length, |
| source_connection_id_length, includes_version, |
| includes_diversification_nonce, PACKET_4BYTE_PACKET_NUMBER, |
| retry_token_length_length, retry_token_length, length_length))); |
| if (ciphertext != decrypter_->ciphertext_) { |
| QUIC_LOG(ERROR) << "Decrypted incorrect ciphertext data. expected " |
| << absl::BytesToHexString(ciphertext) << " actual: " |
| << absl::BytesToHexString(decrypter_->ciphertext_) |
| << " associated data: " |
| << absl::BytesToHexString(associated_data); |
| return false; |
| } |
| return true; |
| } |
| |
| char* AsChars(unsigned char* data) { return reinterpret_cast<char*>(data); } |
| |
| // Creates a new QuicEncryptedPacket by concatenating the various |
| // packet fragments in |fragments|. |
| std::unique_ptr<QuicEncryptedPacket> AssemblePacketFromFragments( |
| const PacketFragments& fragments) { |
| char* buffer = new char[kMaxOutgoingPacketSize + 1]; |
| size_t len = 0; |
| for (const auto& fragment : fragments) { |
| memcpy(buffer + len, fragment.fragment.data(), fragment.fragment.size()); |
| len += fragment.fragment.size(); |
| } |
| return std::make_unique<QuicEncryptedPacket>(buffer, len, true); |
| } |
| |
| void CheckFramingBoundaries(const PacketFragments& fragments, |
| QuicErrorCode error_code) { |
| std::unique_ptr<QuicEncryptedPacket> packet( |
| AssemblePacketFromFragments(fragments)); |
| // Check all the various prefixes of |packet| for the expected |
| // parse error and error code. |
| for (size_t i = 0; i < packet->length(); ++i) { |
| std::string expected_error; |
| size_t len = 0; |
| for (const auto& fragment : fragments) { |
| len += fragment.fragment.size(); |
| if (i < len) { |
| expected_error = fragment.error_if_missing; |
| break; |
| } |
| } |
| |
| if (expected_error.empty()) continue; |
| |
| CheckProcessingFails(*packet, i, expected_error, error_code); |
| } |
| } |
| |
| void CheckProcessingFails(const QuicEncryptedPacket& packet, size_t len, |
| std::string expected_error, |
| QuicErrorCode error_code) { |
| QuicEncryptedPacket encrypted(packet.data(), len, false); |
| EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len; |
| EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len; |
| EXPECT_EQ(error_code, framer_.error()) << "len: " << len; |
| } |
| |
| void CheckProcessingFails(unsigned char* packet, size_t len, |
| std::string expected_error, |
| QuicErrorCode error_code) { |
| QuicEncryptedPacket encrypted(AsChars(packet), len, false); |
| EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len; |
| EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len; |
| EXPECT_EQ(error_code, framer_.error()) << "len: " << len; |
| } |
| |
| // Checks if the supplied string matches data in the supplied StreamFrame. |
| void CheckStreamFrameData(std::string str, QuicStreamFrame* frame) { |
| EXPECT_EQ(str, std::string(frame->data_buffer, frame->data_length)); |
| } |
| |
| void CheckCalculatePacketNumber(uint64_t expected_packet_number, |
| QuicPacketNumber last_packet_number) { |
| uint64_t wire_packet_number = expected_packet_number & kMask; |
| EXPECT_EQ(expected_packet_number, |
| QuicFramerPeer::CalculatePacketNumberFromWire( |
| &framer_, PACKET_4BYTE_PACKET_NUMBER, last_packet_number, |
| wire_packet_number)) |
| << "last_packet_number: " << last_packet_number |
| << " wire_packet_number: " << wire_packet_number; |
| } |
| |
| std::unique_ptr<QuicPacket> BuildDataPacket(const QuicPacketHeader& header, |
| const QuicFrames& frames) { |
| return BuildUnsizedDataPacket(&framer_, header, frames); |
| } |
| |
| std::unique_ptr<QuicPacket> BuildDataPacket(const QuicPacketHeader& header, |
| const QuicFrames& frames, |
| size_t packet_size) { |
| return BuildUnsizedDataPacket(&framer_, header, frames, packet_size); |
| } |
| |
| // N starts at 1. |
| QuicStreamId GetNthStreamid(QuicTransportVersion transport_version, |
| Perspective perspective, bool bidirectional, |
| int n) { |
| if (bidirectional) { |
| return QuicUtils::GetFirstBidirectionalStreamId(transport_version, |
| perspective) + |
| ((n - 1) * QuicUtils::StreamIdDelta(transport_version)); |
| } |
| // Unidirectional |
| return QuicUtils::GetFirstUnidirectionalStreamId(transport_version, |
| perspective) + |
| ((n - 1) * QuicUtils::StreamIdDelta(transport_version)); |
| } |
| |
| QuicTime CreationTimePlus(uint64_t offset_us) { |
| return framer_.creation_time() + |
| QuicTime::Delta::FromMicroseconds(offset_us); |
| } |
| |
| test::TestEncrypter* encrypter_; |
| test::TestDecrypter* decrypter_; |
| ParsedQuicVersion version_; |
| QuicTime start_; |
| QuicFramer framer_; |
| test::TestQuicVisitor visitor_; |
| quiche::SimpleBufferAllocator allocator_; |
| }; |
| |
| // Multiple test cases of QuicFramerTest use byte arrays to define packets for |
| // testing, and these byte arrays contain the QUIC version. This macro explodes |
| // the 32-bit version into four bytes in network order. Since it uses methods of |
| // QuicFramerTest, it is only valid to use this in a QuicFramerTest. |
| #define QUIC_VERSION_BYTES \ |
| GetQuicVersionByte(0), GetQuicVersionByte(1), GetQuicVersionByte(2), \ |
| GetQuicVersionByte(3) |
| |
| // Run all framer tests with all supported versions of QUIC. |
| INSTANTIATE_TEST_SUITE_P(QuicFramerTests, QuicFramerTest, |
| ::testing::ValuesIn(AllSupportedVersions()), |
| ::testing::PrintToStringParamName()); |
| |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) { |
| // A few quick manual sanity checks. |
| CheckCalculatePacketNumber(UINT64_C(1), QuicPacketNumber()); |
| CheckCalculatePacketNumber(kEpoch + 1, QuicPacketNumber(kMask)); |
| CheckCalculatePacketNumber(kEpoch, QuicPacketNumber(kMask)); |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(j, QuicPacketNumber()); |
| CheckCalculatePacketNumber(kEpoch - 1 - j, QuicPacketNumber()); |
| } |
| |
| // Cases where the last number was close to the start of the range. |
| for (QuicPacketNumber last = QuicPacketNumber(1); last < QuicPacketNumber(10); |
| last++) { |
| // Small numbers should not wrap (even if they're out of order). |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(j, last); |
| } |
| |
| // Large numbers should not wrap either (because we're near 0 already). |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(kEpoch - 1 - j, last); |
| } |
| } |
| } |
| |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochEnd) { |
| // Cases where the last number was close to the end of the range |
| for (uint64_t i = 0; i < 10; i++) { |
| QuicPacketNumber last = QuicPacketNumber(kEpoch - i); |
| |
| // Small numbers should wrap. |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(kEpoch + j, last); |
| } |
| |
| // Large numbers should not (even if they're out of order). |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(kEpoch - 1 - j, last); |
| } |
| } |
| } |
| |
| // Next check where we're in a non-zero epoch to verify we handle |
| // reverse wrapping, too. |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearPrevEpoch) { |
| const uint64_t prev_epoch = 1 * kEpoch; |
| const uint64_t cur_epoch = 2 * kEpoch; |
| // Cases where the last number was close to the start of the range |
| for (uint64_t i = 0; i < 10; i++) { |
| QuicPacketNumber last = QuicPacketNumber(cur_epoch + i); |
| // Small number should not wrap (even if they're out of order). |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(cur_epoch + j, last); |
| } |
| |
| // But large numbers should reverse wrap. |
| for (uint64_t j = 0; j < 10; j++) { |
| uint64_t num = kEpoch - 1 - j; |
| CheckCalculatePacketNumber(prev_epoch + num, last); |
| } |
| } |
| } |
| |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextEpoch) { |
| const uint64_t cur_epoch = 2 * kEpoch; |
| const uint64_t next_epoch = 3 * kEpoch; |
| // Cases where the last number was close to the end of the range |
| for (uint64_t i = 0; i < 10; i++) { |
| QuicPacketNumber last = QuicPacketNumber(next_epoch - 1 - i); |
| |
| // Small numbers should wrap. |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(next_epoch + j, last); |
| } |
| |
| // but large numbers should not (even if they're out of order). |
| for (uint64_t j = 0; j < 10; j++) { |
| uint64_t num = kEpoch - 1 - j; |
| CheckCalculatePacketNumber(cur_epoch + num, last); |
| } |
| } |
| } |
| |
| TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextMax) { |
| const uint64_t max_number = std::numeric_limits<uint64_t>::max(); |
| const uint64_t max_epoch = max_number & ~kMask; |
| |
| // Cases where the last number was close to the end of the range |
| for (uint64_t i = 0; i < 10; i++) { |
| // Subtract 1, because the expected next packet number is 1 more than the |
| // last packet number. |
| QuicPacketNumber last = QuicPacketNumber(max_number - i - 1); |
| |
| // Small numbers should not wrap, because they have nowhere to go. |
| for (uint64_t j = 0; j < 10; j++) { |
| CheckCalculatePacketNumber(max_epoch + j, last); |
| } |
| |
| // Large numbers should not wrap either. |
| for (uint64_t j = 0; j < 10; j++) { |
| uint64_t num = kEpoch - 1 - j; |
| CheckCalculatePacketNumber(max_epoch + num, last); |
| } |
| } |
| } |
| |
| TEST_P(QuicFramerTest, EmptyPacket) { |
| char packet[] = {0x00}; |
| QuicEncryptedPacket encrypted(packet, 0, false); |
| EXPECT_FALSE(framer_.ProcessPacket(encrypted)); |
| EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); |
| } |
| |
| TEST_P(QuicFramerTest, LargePacket) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| // clang-format off |
| unsigned char packet[kMaxIncomingPacketSize + 1] = { |
| // public flags (8 byte connection_id) |
| 0x28, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x78, 0x56, 0x34, 0x12, |
| // private flags |
| 0x00, |
| }; |
| unsigned char packet46[kMaxIncomingPacketSize + 1] = { |
| // type (short header 4 byte packet number) |
| 0x43, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x78, 0x56, 0x34, 0x12, |
| }; |
| // clang-format on |
| unsigned char* p = packet; |
| size_t p_size = ABSL_ARRAYSIZE(packet); |
| if (framer_.version().HasIetfInvariantHeader()) { |
| p = packet46; |
| p_size = ABSL_ARRAYSIZE(packet46); |
| } |
| |
| const size_t header_size = GetPacketHeaderSize( |
| framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, |
| PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, |
| !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, |
| VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); |
| |
| memset(p + header_size, 0, kMaxIncomingPacketSize - header_size); |
| |
| QuicEncryptedPacket encrypted(AsChars(p), p_size, false); |
| EXPECT_FALSE(framer_.ProcessPacket(encrypted)); |
| |
| ASSERT_TRUE(visitor_.header_.get()); |
| // Make sure we've parsed the packet header, so we can send an error. |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| // Make sure the correct error is propagated. |
| EXPECT_THAT(framer_.error(), IsError(QUIC_PACKET_TOO_LARGE)); |
| EXPECT_EQ("Packet too large.", framer_.detailed_error()); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeader) { |
| if (framer_.version().HasIetfInvariantHeader()) { |
| return; |
| } |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"Unable to read public flags.", |
| {0x28}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = packet; |
| |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| |
| PacketHeaderFormat format; |
| QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE; |
| bool version_flag; |
| QuicConnectionId destination_connection_id, source_connection_id; |
| QuicVersionLabel version_label; |
| std::string detailed_error; |
| bool use_length_prefix; |
| absl::optional<absl::string_view> retry_token; |
| ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); |
| const QuicErrorCode error_code = QuicFramer::ParsePublicHeaderDispatcher( |
| *encrypted, kQuicDefaultConnectionIdLength, &format, &long_packet_type, |
| &version_flag, &use_length_prefix, &version_label, &parsed_version, |
| &destination_connection_id, &source_connection_id, &retry_token, |
| &detailed_error); |
| EXPECT_FALSE(retry_token.has_value()); |
| EXPECT_FALSE(use_length_prefix); |
| EXPECT_THAT(error_code, IsQuicNoError()); |
| EXPECT_EQ(GOOGLE_QUIC_PACKET, format); |
| EXPECT_FALSE(version_flag); |
| EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id.length()); |
| EXPECT_EQ(FramerTestConnectionId(), destination_connection_id); |
| EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); |
| } |
| |
| TEST_P(QuicFramerTest, LongPacketHeader) { |
| // clang-format off |
| PacketFragments packet46 = { |
| // type (long header with packet type ZERO_RTT) |
| {"Unable to read first byte.", |
| {0xD3}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"Unable to read ConnectionId length.", |
| {0x50}}, |
| // connection_id |
| {"Unable to read destination connection ID.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| if (!framer_.version().HasIetfInvariantHeader() || |
| QuicVersionHasLongHeaderLengths(framer_.transport_version())) { |
| return; |
| } |
| |
| SetDecrypterLevel(ENCRYPTION_ZERO_RTT); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(packet46)); |
| |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_TRUE(visitor_.header_->version_flag); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(packet46, QUIC_INVALID_PACKET_HEADER); |
| |
| PacketHeaderFormat format; |
| QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE; |
| bool version_flag; |
| QuicConnectionId destination_connection_id, source_connection_id; |
| QuicVersionLabel version_label; |
| std::string detailed_error; |
| bool use_length_prefix; |
| absl::optional<absl::string_view> retry_token; |
| ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); |
| const QuicErrorCode error_code = QuicFramer::ParsePublicHeaderDispatcher( |
| *encrypted, kQuicDefaultConnectionIdLength, &format, &long_packet_type, |
| &version_flag, &use_length_prefix, &version_label, &parsed_version, |
| &destination_connection_id, &source_connection_id, &retry_token, |
| &detailed_error); |
| EXPECT_THAT(error_code, IsQuicNoError()); |
| EXPECT_EQ("", detailed_error); |
| EXPECT_FALSE(retry_token.has_value()); |
| EXPECT_FALSE(use_length_prefix); |
| EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); |
| EXPECT_TRUE(version_flag); |
| EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id.length()); |
| EXPECT_EQ(FramerTestConnectionId(), destination_connection_id); |
| EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); |
| } |
| |
| TEST_P(QuicFramerTest, LongPacketHeaderWithBothConnectionIds) { |
| if (!framer_.version().HasIetfInvariantHeader()) { |
| // This test requires an IETF long header. |
| return; |
| } |
| SetDecrypterLevel(ENCRYPTION_ZERO_RTT); |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (long header with packet type ZERO_RTT_PROTECTED and |
| // 4-byte packet number) |
| 0xD3, |
| // version |
| QUIC_VERSION_BYTES, |
| // connection ID lengths |
| 0x55, |
| // destination connection ID |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // source connection ID |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, |
| // packet number |
| 0x12, 0x34, 0x56, 0x00, |
| // padding frame |
| 0x00, |
| }; |
| unsigned char packet49[] = { |
| // public flags (long header with packet type ZERO_RTT_PROTECTED and |
| // 4-byte packet number) |
| 0xD3, |
| // version |
| QUIC_VERSION_BYTES, |
| // destination connection ID length |
| 0x08, |
| // destination connection ID |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // source connection ID length |
| 0x08, |
| // source connection ID |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, |
| // long header packet length |
| 0x05, |
| // packet number |
| 0x12, 0x34, 0x56, 0x00, |
| // padding frame |
| 0x00, |
| }; |
| // clang-format on |
| |
| unsigned char* p = packet; |
| size_t p_length = ABSL_ARRAYSIZE(packet); |
| if (framer_.version().HasLongHeaderLengths()) { |
| ReviseFirstByteByVersion(packet49); |
| p = packet49; |
| p_length = ABSL_ARRAYSIZE(packet49); |
| } |
| |
| QuicEncryptedPacket encrypted(AsChars(p), p_length, false); |
| PacketHeaderFormat format = GOOGLE_QUIC_PACKET; |
| QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE; |
| bool version_flag = false; |
| QuicConnectionId destination_connection_id, source_connection_id; |
| QuicVersionLabel version_label = 0; |
| std::string detailed_error = ""; |
| bool use_length_prefix; |
| absl::optional<absl::string_view> retry_token; |
| ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); |
| const QuicErrorCode error_code = QuicFramer::ParsePublicHeaderDispatcher( |
| encrypted, kQuicDefaultConnectionIdLength, &format, &long_packet_type, |
| &version_flag, &use_length_prefix, &version_label, &parsed_version, |
| &destination_connection_id, &source_connection_id, &retry_token, |
| &detailed_error); |
| EXPECT_THAT(error_code, IsQuicNoError()); |
| EXPECT_FALSE(retry_token.has_value()); |
| EXPECT_EQ(framer_.version().HasLengthPrefixedConnectionIds(), |
| use_length_prefix); |
| EXPECT_EQ("", detailed_error); |
| EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); |
| EXPECT_TRUE(version_flag); |
| EXPECT_EQ(FramerTestConnectionId(), destination_connection_id); |
| EXPECT_EQ(FramerTestConnectionIdPlusOne(), source_connection_id); |
| } |
| |
| TEST_P(QuicFramerTest, AllZeroPacketParsingFails) { |
| unsigned char packet[1200] = {}; |
| QuicEncryptedPacket encrypted(AsChars(packet), ABSL_ARRAYSIZE(packet), false); |
| PacketHeaderFormat format = GOOGLE_QUIC_PACKET; |
| QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE; |
| bool version_flag = false; |
| QuicConnectionId destination_connection_id, source_connection_id; |
| QuicVersionLabel version_label = 0; |
| std::string detailed_error = ""; |
| bool use_length_prefix; |
| absl::optional<absl::string_view> retry_token; |
| ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); |
| const QuicErrorCode error_code = QuicFramer::ParsePublicHeaderDispatcher( |
| encrypted, kQuicDefaultConnectionIdLength, &format, &long_packet_type, |
| &version_flag, &use_length_prefix, &version_label, &parsed_version, |
| &destination_connection_id, &source_connection_id, &retry_token, |
| &detailed_error); |
| EXPECT_EQ(error_code, QUIC_INVALID_PACKET_HEADER); |
| EXPECT_EQ(detailed_error, "Invalid flags."); |
| } |
| |
| TEST_P(QuicFramerTest, ParsePublicHeader) { |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (version included, 8-byte connection ID, |
| // 4-byte packet number) |
| 0x29, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // version |
| QUIC_VERSION_BYTES, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| // padding frame |
| 0x00, |
| }; |
| unsigned char packet46[] = { |
| // public flags (long header with packet type HANDSHAKE and |
| // 4-byte packet number) |
| 0xE3, |
| // version |
| QUIC_VERSION_BYTES, |
| // connection ID lengths |
| 0x50, |
| // destination connection ID |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // long header packet length |
| 0x05, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| // padding frame |
| 0x00, |
| }; |
| unsigned char packet49[] = { |
| // public flags (long header with packet type HANDSHAKE and |
| // 4-byte packet number) |
| 0xE3, |
| // version |
| QUIC_VERSION_BYTES, |
| // destination connection ID length |
| 0x08, |
| // destination connection ID |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // source connection ID length |
| 0x00, |
| // long header packet length |
| 0x05, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| // padding frame |
| 0x00, |
| }; |
| // clang-format on |
| unsigned char* p = packet; |
| size_t p_length = ABSL_ARRAYSIZE(packet); |
| if (framer_.version().HasLongHeaderLengths()) { |
| ReviseFirstByteByVersion(packet49); |
| p = packet49; |
| p_length = ABSL_ARRAYSIZE(packet49); |
| } else if (framer_.version().HasIetfInvariantHeader()) { |
| p = packet46; |
| p_length = ABSL_ARRAYSIZE(packet46); |
| } |
| |
| uint8_t first_byte = 0x33; |
| PacketHeaderFormat format = GOOGLE_QUIC_PACKET; |
| bool version_present = false, has_length_prefix = false; |
| QuicVersionLabel version_label = 0; |
| ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); |
| QuicConnectionId destination_connection_id = EmptyQuicConnectionId(), |
| source_connection_id = EmptyQuicConnectionId(); |
| QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE; |
| QuicVariableLengthIntegerLength retry_token_length_length = |
| VARIABLE_LENGTH_INTEGER_LENGTH_4; |
| absl::string_view retry_token; |
| std::string detailed_error = "foobar"; |
| |
| QuicDataReader reader(AsChars(p), p_length); |
| const QuicErrorCode parse_error = QuicFramer::ParsePublicHeader( |
| &reader, kQuicDefaultConnectionIdLength, |
| /*ietf_format=*/ |
| framer_.version().HasIetfInvariantHeader(), &first_byte, &format, |
| &version_present, &has_length_prefix, &version_label, &parsed_version, |
| &destination_connection_id, &source_connection_id, &long_packet_type, |
| &retry_token_length_length, &retry_token, &detailed_error); |
| EXPECT_THAT(parse_error, IsQuicNoError()); |
| EXPECT_EQ("", detailed_error); |
| EXPECT_EQ(p[0], first_byte); |
| EXPECT_TRUE(version_present); |
| EXPECT_EQ(framer_.version().HasLengthPrefixedConnectionIds(), |
| has_length_prefix); |
| EXPECT_EQ(CreateQuicVersionLabel(framer_.version()), version_label); |
| EXPECT_EQ(framer_.version(), parsed_version); |
| EXPECT_EQ(FramerTestConnectionId(), destination_connection_id); |
| EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); |
| EXPECT_EQ(VARIABLE_LENGTH_INTEGER_LENGTH_0, retry_token_length_length); |
| EXPECT_EQ(absl::string_view(), retry_token); |
| if (framer_.version().HasIetfInvariantHeader()) { |
| EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); |
| EXPECT_EQ(HANDSHAKE, long_packet_type); |
| } else { |
| EXPECT_EQ(GOOGLE_QUIC_PACKET, format); |
| } |
| } |
| |
| TEST_P(QuicFramerTest, ParsePublicHeaderProxBadSourceConnectionIdLength) { |
| if (!framer_.version().HasLengthPrefixedConnectionIds()) { |
| return; |
| } |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (long header with packet type HANDSHAKE and |
| // 4-byte packet number) |
| 0xE3, |
| // version |
| 'P', 'R', 'O', 'X', |
| // destination connection ID length |
| 0x08, |
| // destination connection ID |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // source connection ID length (bogus) |
| 0xEE, |
| // long header packet length |
| 0x05, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| // padding frame |
| 0x00, |
| }; |
| // clang-format on |
| unsigned char* p = packet; |
| size_t p_length = ABSL_ARRAYSIZE(packet); |
| |
| uint8_t first_byte = 0x33; |
| PacketHeaderFormat format = GOOGLE_QUIC_PACKET; |
| bool version_present = false, has_length_prefix = false; |
| QuicVersionLabel version_label = 0; |
| ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); |
| QuicConnectionId destination_connection_id = EmptyQuicConnectionId(), |
| source_connection_id = EmptyQuicConnectionId(); |
| QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE; |
| QuicVariableLengthIntegerLength retry_token_length_length = |
| VARIABLE_LENGTH_INTEGER_LENGTH_4; |
| absl::string_view retry_token; |
| std::string detailed_error = "foobar"; |
| |
| QuicDataReader reader(AsChars(p), p_length); |
| const QuicErrorCode parse_error = QuicFramer::ParsePublicHeader( |
| &reader, kQuicDefaultConnectionIdLength, |
| /*ietf_format=*/true, &first_byte, &format, &version_present, |
| &has_length_prefix, &version_label, &parsed_version, |
| &destination_connection_id, &source_connection_id, &long_packet_type, |
| &retry_token_length_length, &retry_token, &detailed_error); |
| EXPECT_THAT(parse_error, IsQuicNoError()); |
| EXPECT_EQ("", detailed_error); |
| EXPECT_EQ(p[0], first_byte); |
| EXPECT_TRUE(version_present); |
| EXPECT_TRUE(has_length_prefix); |
| EXPECT_EQ(0x50524F58u, version_label); // "PROX" |
| EXPECT_EQ(UnsupportedQuicVersion(), parsed_version); |
| EXPECT_EQ(FramerTestConnectionId(), destination_connection_id); |
| EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); |
| EXPECT_EQ(VARIABLE_LENGTH_INTEGER_LENGTH_0, retry_token_length_length); |
| EXPECT_EQ(absl::string_view(), retry_token); |
| EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); |
| } |
| |
| TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToClient) { |
| if (!framer_.version().SupportsClientConnectionIds()) { |
| return; |
| } |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| QuicFramerPeer::SetLastSerializedServerConnectionId(&framer_, |
| TestConnectionId(0x33)); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| framer_.SetExpectedClientConnectionIdLength(kQuicDefaultConnectionIdLength); |
| // clang-format off |
| unsigned char packet[] = { |
| // type (short header, 4 byte packet number) |
| 0x43, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x13, 0x37, 0x42, 0x33, |
| // padding frame |
| 0x00, |
| }; |
| // clang-format on |
| QuicEncryptedPacket encrypted(AsChars(packet), ABSL_ARRAYSIZE(packet), false); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| EXPECT_EQ("", framer_.detailed_error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| } |
| |
| // In short header packets from client to server, the client connection ID |
| // is omitted, but the framer adds it to the header struct using its |
| // last serialized client connection ID. This test ensures that this |
| // mechanism behaves as expected. |
| TEST_P(QuicFramerTest, ClientConnectionIdFromShortHeaderToServer) { |
| if (!framer_.version().SupportsClientConnectionIds()) { |
| return; |
| } |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| QuicFramerPeer::SetLastSerializedClientConnectionId(&framer_, |
| TestConnectionId(0x33)); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| // clang-format off |
| unsigned char packet[] = { |
| // type (short header, 4 byte packet number) |
| 0x43, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x13, 0x37, 0x42, 0x33, |
| // padding frame |
| 0x00, |
| }; |
| // clang-format on |
| QuicEncryptedPacket encrypted(AsChars(packet), ABSL_ARRAYSIZE(packet), false); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| EXPECT_EQ("", framer_.detailed_error()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| QuicFramerPeer::SetLastSerializedServerConnectionId(&framer_, |
| FramerTestConnectionId()); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (0 byte connection_id) |
| {"Unable to read public flags.", |
| {0x20}}, |
| // connection_id |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short header, 4 byte packet number) |
| {"Unable to read first byte.", |
| {0x43}}, |
| // connection_id |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet_hp = { |
| // type (short header, 4 byte packet number) |
| {"Unable to read first byte.", |
| {0x43}}, |
| // connection_id |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.version().HasHeaderProtection() |
| ? packet_hp |
| : (framer_.version().HasIetfInvariantHeader() ? packet46 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) { |
| SetDecrypterLevel(ENCRYPTION_ZERO_RTT); |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (0 byte connection_id) |
| {"Unable to read public flags.", |
| {0x29}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes |
| // packet number) |
| {"Unable to read first byte.", |
| {0xD3}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // connection_id length |
| {"Unable to read ConnectionId length.", |
| {0x50}}, |
| // connection_id |
| {"Unable to read destination connection ID.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet49 = { |
| // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes |
| // packet number) |
| {"Unable to read first byte.", |
| {0xD3}}, |
| // version tag |
| {"Unable to read protocol version.", |
| {QUIC_VERSION_BYTES}}, |
| // destination connection ID length |
| {"Unable to read destination connection ID.", |
| {0x08}}, |
| // destination connection ID |
| {"Unable to read destination connection ID.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // source connection ID length |
| {"Unable to read source connection ID.", |
| {0x00}}, |
| // long header packet length |
| {"Unable to read long header payload length.", |
| {0x04}}, |
| // packet number |
| {"Long header payload length longer than packet.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| ReviseFirstByteByVersion(packet49); |
| PacketFragments& fragments = |
| framer_.version().HasLongHeaderLengths() |
| ? packet49 |
| : (framer_.version().HasIetfInvariantHeader() ? packet46 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_TRUE(visitor_.header_->version_flag); |
| EXPECT_EQ(GetParam(), visitor_.header_->version); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id and 4 byte packet number) |
| {"Unable to read public flags.", |
| {0x28}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short header, 4 byte packet number) |
| {"Unable to read first byte.", |
| {0x43}}, |
| // connection_id |
| {"Unable to read destination connection ID.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet_hp = { |
| // type (short header, 4 byte packet number) |
| {"Unable to read first byte.", |
| {0x43}}, |
| // connection_id |
| {"Unable to read destination connection ID.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.version().HasHeaderProtection() |
| ? packet_hp |
| : (framer_.version().HasIetfInvariantHeader() ? packet46 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id and 2 byte packet number) |
| {"Unable to read public flags.", |
| {0x18}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (short header, 2 byte packet number) |
| {"Unable to read first byte.", |
| {0x41}}, |
| // connection_id |
| {"Unable to read destination connection ID.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x56, 0x78}}, |
| }; |
| |
| PacketFragments packet_hp = { |
| // type (short header, 2 byte packet number) |
| {"Unable to read first byte.", |
| {0x41}}, |
| // connection_id |
| {"Unable to read destination connection ID.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x56, 0x78}}, |
| // padding |
| {"", {0x00, 0x00}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.version().HasHeaderProtection() |
| ? packet_hp |
| : (framer_.version().HasIetfInvariantHeader() ? packet46 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| if (framer_.version().HasHeaderProtection()) { |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| } else { |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); |
| } |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2); |
| |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id and 1 byte packet number) |
| {"Unable to read public flags.", |
| {0x08}}, |
| // connection_id |
| {"Unable to read ConnectionId.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x78}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // type (8 byte connection_id and 1 byte packet number) |
| {"Unable to read first byte.", |
| {0x40}}, |
| // connection_id |
| {"Unable to read destination connection ID.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"Unable to read packet number.", |
| {0x78}}, |
| }; |
| |
| PacketFragments packet_hp = { |
| // type (8 byte connection_id and 1 byte packet number) |
| {"Unable to read first byte.", |
| {0x40}}, |
| // connection_id |
| {"Unable to read destination connection ID.", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x78}}, |
| // padding |
| {"", {0x00, 0x00, 0x00}}, |
| }; |
| |
| // clang-format on |
| |
| PacketFragments& fragments = |
| framer_.version().HasHeaderProtection() |
| ? packet_hp |
| : (framer_.version().HasIetfInvariantHeader() ? packet46 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| if (framer_.version().HasHeaderProtection()) { |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| } else { |
| EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); |
| EXPECT_THAT(framer_.error(), IsError(QUIC_MISSING_PAYLOAD)); |
| } |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_FALSE(visitor_.header_->reset_flag); |
| EXPECT_FALSE(visitor_.header_->version_flag); |
| EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER); |
| } |
| |
| TEST_P(QuicFramerTest, PacketNumberDecreasesThenIncreases) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| // Test the case when a packet is received from the past and future packet |
| // numbers are still calculated relative to the largest received packet. |
| QuicPacketHeader header; |
| header.destination_connection_id = FramerTestConnectionId(); |
| header.reset_flag = false; |
| header.version_flag = false; |
| header.packet_number = kPacketNumber - 2; |
| |
| QuicFrames frames = {QuicFrame(QuicPaddingFrame())}; |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); |
| ASSERT_TRUE(data != nullptr); |
| |
| QuicEncryptedPacket encrypted(data->data(), data->length(), false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber - 2, visitor_.header_->packet_number); |
| |
| // Receive a 1 byte packet number. |
| header.packet_number = kPacketNumber; |
| header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| data = BuildDataPacket(header, frames); |
| QuicEncryptedPacket encrypted1(data->data(), data->length(), false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted1)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); |
| |
| // Process a 2 byte packet number 256 packets ago. |
| header.packet_number = kPacketNumber - 256; |
| header.packet_number_length = PACKET_2BYTE_PACKET_NUMBER; |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| data = BuildDataPacket(header, frames); |
| QuicEncryptedPacket encrypted2(data->data(), data->length(), false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted2)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber - 256, visitor_.header_->packet_number); |
| |
| // Process another 1 byte packet number and ensure it works. |
| header.packet_number = kPacketNumber - 1; |
| header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| data = BuildDataPacket(header, frames); |
| QuicEncryptedPacket encrypted3(data->data(), data->length(), false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted3)); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(FramerTestConnectionId(), |
| visitor_.header_->destination_connection_id); |
| EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); |
| EXPECT_EQ(kPacketNumber - 1, visitor_.header_->packet_number); |
| } |
| |
| TEST_P(QuicFramerTest, PacketWithDiversificationNonce) { |
| SetDecrypterLevel(ENCRYPTION_ZERO_RTT); |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags: includes nonce flag |
| 0x2C, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // nonce |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (padding) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| unsigned char packet46[] = { |
| // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet |
| // number. |
| 0xD0, |
| // version tag |
| QUIC_VERSION_BYTES, |
| // connection_id length |
| 0x05, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x78, |
| // nonce |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
| |
| // frame type (padding) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| unsigned char packet49[] = { |
| // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet |
| // number. |
| 0xD0, |
| // version tag |
| QUIC_VERSION_BYTES, |
| // destination connection ID length |
| 0x00, |
| // source connection ID length |
| 0x08, |
| // source connection ID |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // long header packet length |
| 0x26, |
| // packet number |
| 0x78, |
| // nonce |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
| |
| // frame type (padding) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| // clang-format on |
| |
| if (framer_.version().handshake_protocol != PROTOCOL_QUIC_CRYPTO) { |
| return; |
| } |
| |
| unsigned char* p = packet; |
| size_t p_size = ABSL_ARRAYSIZE(packet); |
| if (framer_.version().HasLongHeaderLengths()) { |
| p = packet49; |
| p_size = ABSL_ARRAYSIZE(packet49); |
| } else if (framer_.version().HasIetfInvariantHeader()) { |
| p = packet46; |
| p_size = ABSL_ARRAYSIZE(packet46); |
| } |
| |
| QuicEncryptedPacket encrypted(AsChars(p), p_size, false); |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| ASSERT_TRUE(visitor_.header_->nonce != nullptr); |
| for (char i = 0; i < 32; ++i) { |
| EXPECT_EQ(i, (*visitor_.header_->nonce)[static_cast<size_t>(i)]); |
| } |
| EXPECT_EQ(1u, visitor_.padding_frames_.size()); |
| EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); |
| } |
| |
| TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (8 byte connection_id, version flag and an unknown flag) |
| 0x29, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // version tag |
| 'Q', '0', '0', '0', |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (padding frame) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| unsigned char packet46[] = { |
| // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) |
| 0xD3, |
| // version tag |
| 'Q', '0', '0', '0', |
| // connection_id length |
| 0x50, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (padding frame) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| unsigned char packet49[] = { |
| // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) |
| 0xD3, |
| // version tag |
| 'Q', '0', '0', '0', |
| // destination connection ID length |
| 0x08, |
| // destination connection ID |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // source connection ID length |
| 0x00, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // frame type (padding frame) |
| 0x00, |
| 0x00, 0x00, 0x00, 0x00 |
| }; |
| // clang-format on |
| |
| unsigned char* p = packet; |
| size_t p_size = ABSL_ARRAYSIZE(packet); |
| if (framer_.version().HasLongHeaderLengths()) { |
| p = packet49; |
| p_size = ABSL_ARRAYSIZE(packet49); |
| } else if (framer_.version().HasIetfInvariantHeader()) { |
| p = packet46; |
| p_size = ABSL_ARRAYSIZE(packet46); |
| } |
| QuicEncryptedPacket encrypted(AsChars(p), p_size, false); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_EQ(0, visitor_.frame_count_); |
| EXPECT_EQ(1, visitor_.version_mismatch_); |
| } |
| |
| TEST_P(QuicFramerTest, PaddingFrame) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (8 byte connection_id) |
| 0x28, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // paddings |
| 0x00, 0x00, |
| // frame type (stream frame with fin) |
| 0xFF, |
| // stream id |
| 0x01, 0x02, 0x03, 0x04, |
| // offset |
| 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| // paddings |
| 0x00, 0x00, |
| }; |
| |
| unsigned char packet46[] = { |
| // type (short header, 4 byte packet number) |
| 0x43, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // paddings |
| 0x00, 0x00, |
| // frame type (stream frame with fin) |
| 0xFF, |
| // stream id |
| 0x01, 0x02, 0x03, 0x04, |
| // offset |
| 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| // paddings |
| 0x00, 0x00, |
| }; |
| |
| unsigned char packet_ietf[] = { |
| // type (short header, 4 byte packet number) |
| 0x43, |
| // connection_id |
| 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| |
| // paddings |
| 0x00, 0x00, |
| // frame type - IETF_STREAM with FIN, LEN, and OFFSET bits set. |
| 0x08 | 0x01 | 0x02 | 0x04, |
| |
| // stream id |
| kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, |
| // offset |
| kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54, |
| // data length |
| kVarInt62OneByte + 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!', |
| // paddings |
| 0x00, 0x00, |
| }; |
| // clang-format on |
| |
| unsigned char* p = packet; |
| size_t p_size = ABSL_ARRAYSIZE(packet); |
| if (VersionHasIetfQuicFrames(framer_.transport_version())) { |
| p = packet_ietf; |
| p_size = ABSL_ARRAYSIZE(packet_ietf); |
| } else if (framer_.version().HasIetfInvariantHeader()) { |
| p = packet46; |
| p_size = ABSL_ARRAYSIZE(packet46); |
| } |
| |
| QuicEncryptedPacket encrypted(AsChars(p), p_size, false); |
| EXPECT_TRUE(framer_.ProcessPacket(encrypted)); |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| EXPECT_EQ(2u, visitor_.padding_frames_.size()); |
| EXPECT_EQ(2, visitor_.padding_frames_[0]->num_padding_bytes); |
| EXPECT_EQ(2, visitor_.padding_frames_[1]->num_padding_bytes); |
| EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| } |
| |
| TEST_P(QuicFramerTest, StreamFrame) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x28}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFF}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x01, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // 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 (stream frame with fin) |
| {"", |
| {0xFF}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x01, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet_ietf = { |
| // 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_STREAM with FIN, LEN, and OFFSET bits set. |
| {"", |
| { 0x08 | 0x01 | 0x02 | 0x04 }}, |
| // stream id |
| {"Unable to read IETF_STREAM frame stream id/count.", |
| {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read stream data offset.", |
| {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| // data length |
| {"Unable to read stream data length.", |
| {kVarInt62OneByte + 0x0c}}, |
| // data |
| {"Unable to read frame data.", |
| { 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| VersionHasIetfQuicFrames(framer_.transport_version()) |
| ? packet_ietf |
| : (framer_.version().HasIetfInvariantHeader() ? packet46 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); |
| } |
| |
| // Test an empty (no data) stream frame. |
| TEST_P(QuicFramerTest, EmptyStreamFrame) { |
| // Only the IETF QUIC spec explicitly says that empty |
| // stream frames are supported. |
| if (!VersionHasIetfQuicFrames(framer_.transport_version())) { |
| return; |
| } |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| // clang-format off |
| PacketFragments packet = { |
| // 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_STREAM with FIN, LEN, and OFFSET bits set. |
| {"", |
| { 0x08 | 0x01 | 0x02 | 0x04 }}, |
| // stream id |
| {"Unable to read IETF_STREAM frame stream id/count.", |
| {kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read stream data offset.", |
| {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| // data length |
| {"Unable to read stream data length.", |
| {kVarInt62OneByte + 0x00}}, |
| }; |
| // clang-format on |
| |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(packet)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| EXPECT_EQ(visitor_.stream_frames_[0].get()->data_length, 0u); |
| |
| CheckFramingBoundaries(packet, QUIC_INVALID_STREAM_DATA); |
| } |
| |
| TEST_P(QuicFramerTest, MissingDiversificationNonce) { |
| if (framer_.version().handshake_protocol != PROTOCOL_QUIC_CRYPTO) { |
| // TLS does not use diversification nonces. |
| return; |
| } |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); |
| decrypter_ = new test::TestDecrypter(); |
| if (framer_.version().KnowsWhichDecrypterToUse()) { |
| framer_.InstallDecrypter( |
| ENCRYPTION_INITIAL, |
| std::make_unique<NullDecrypter>(Perspective::IS_CLIENT)); |
| framer_.InstallDecrypter(ENCRYPTION_ZERO_RTT, |
| std::unique_ptr<QuicDecrypter>(decrypter_)); |
| } else { |
| framer_.SetDecrypter(ENCRYPTION_INITIAL, std::make_unique<NullDecrypter>( |
| Perspective::IS_CLIENT)); |
| framer_.SetAlternativeDecrypter( |
| ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false); |
| } |
| |
| // clang-format off |
| unsigned char packet[] = { |
| // public flags (8 byte connection_id) |
| 0x28, |
| // connection_id |
| 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| // padding frame |
| 0x00, |
| }; |
| |
| unsigned char packet46[] = { |
| // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) |
| 0xD3, |
| // version tag |
| QUIC_VERSION_BYTES, |
| // connection_id length |
| 0x05, |
| // connection_id |
| 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| // padding frame |
| 0x00, |
| }; |
| |
| unsigned char packet49[] = { |
| // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) |
| 0xD3, |
| // version tag |
| QUIC_VERSION_BYTES, |
| // destination connection ID length |
| 0x00, |
| // source connection ID length |
| 0x08, |
| // source connection ID |
| 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, |
| // IETF long header payload length |
| 0x05, |
| // packet number |
| 0x12, 0x34, 0x56, 0x78, |
| // padding frame |
| 0x00, |
| }; |
| // clang-format on |
| |
| unsigned char* p = packet; |
| size_t p_length = ABSL_ARRAYSIZE(packet); |
| if (framer_.version().HasLongHeaderLengths()) { |
| p = packet49; |
| p_length = ABSL_ARRAYSIZE(packet49); |
| } else if (framer_.version().HasIetfInvariantHeader()) { |
| p = packet46; |
| p_length = ABSL_ARRAYSIZE(packet46); |
| } |
| QuicEncryptedPacket encrypted(AsChars(p), p_length, false); |
| EXPECT_FALSE(framer_.ProcessPacket(encrypted)); |
| if (framer_.version().HasHeaderProtection()) { |
| EXPECT_THAT(framer_.error(), IsError(QUIC_DECRYPTION_FAILURE)); |
| EXPECT_EQ("Unable to decrypt ENCRYPTION_ZERO_RTT header protection.", |
| framer_.detailed_error()); |
| } else if (framer_.version().HasIetfInvariantHeader()) { |
| // Cannot read diversification nonce. |
| EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_PACKET_HEADER)); |
| EXPECT_EQ("Unable to read nonce.", framer_.detailed_error()); |
| } else { |
| EXPECT_THAT(framer_.error(), IsError(QUIC_DECRYPTION_FAILURE)); |
| } |
| } |
| |
| TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { |
| if (framer_.version().HasIetfInvariantHeader()) { |
| // This test is nonsensical for IETF Quic. |
| return; |
| } |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x28}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFE}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x02, 0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = packet; |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| // Stream ID should be the last 3 bytes of kStreamId. |
| EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); |
| } |
| |
| TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x28}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFD}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // 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 (stream frame with fin) |
| {"", |
| {0xFD}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x03, 0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet_ietf = { |
| // 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_STREAM frame with LEN, FIN, and OFFSET bits set) |
| {"", |
| {0x08 | 0x01 | 0x02 | 0x04}}, |
| // stream id |
| {"Unable to read IETF_STREAM frame stream id/count.", |
| {kVarInt62TwoBytes + 0x03, 0x04}}, |
| // offset |
| {"Unable to read stream data offset.", |
| {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| // data length |
| {"Unable to read stream data length.", |
| {kVarInt62OneByte + 0x0c}}, |
| // data |
| {"Unable to read frame data.", |
| { 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| // clang-format on |
| |
| PacketFragments& fragments = |
| VersionHasIetfQuicFrames(framer_.transport_version()) |
| ? packet_ietf |
| : (framer_.version().HasIetfInvariantHeader() ? packet46 : packet); |
| std::unique_ptr<QuicEncryptedPacket> encrypted( |
| AssemblePacketFromFragments(fragments)); |
| EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); |
| |
| EXPECT_THAT(framer_.error(), IsQuicNoError()); |
| ASSERT_TRUE(visitor_.header_.get()); |
| EXPECT_TRUE(CheckDecryption( |
| *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, |
| PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); |
| |
| ASSERT_EQ(1u, visitor_.stream_frames_.size()); |
| EXPECT_EQ(0u, visitor_.ack_frames_.size()); |
| // Stream ID should be the last 2 bytes of kStreamId. |
| EXPECT_EQ(0x0000FFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); |
| EXPECT_TRUE(visitor_.stream_frames_[0]->fin); |
| EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); |
| CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); |
| |
| CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); |
| } |
| |
| TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { |
| SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); |
| // clang-format off |
| PacketFragments packet = { |
| // public flags (8 byte connection_id) |
| {"", |
| {0x28}}, |
| // connection_id |
| {"", |
| {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, |
| // packet number |
| {"", |
| {0x12, 0x34, 0x56, 0x78}}, |
| // frame type (stream frame with fin) |
| {"", |
| {0xFC}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet46 = { |
| // 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 (stream frame with fin) |
| {"", |
| {0xFC}}, |
| // stream id |
| {"Unable to read stream_id.", |
| {0x04}}, |
| // offset |
| {"Unable to read offset.", |
| {0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| {"Unable to read frame data.", |
| { |
| // data length |
| 0x00, 0x0c, |
| // data |
| 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
| 'r', 'l', 'd', '!'}}, |
| }; |
| |
| PacketFragments packet_ietf = { |
| // 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_STREAM frame with LEN, FIN, and OFFSET bits set) |
| {"", |
| {0x08 | 0x01 | 0x02 | 0x04}}, |
| // stream id |
| {"Unable to read IETF_STREAM frame stream id/count.", |
| {kVarInt62OneByte + 0x04}}, |
| // offset |
| {"Unable to read stream data offset.", |
| {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, |
| 0x32, 0x10, 0x76, 0x54}}, |
| // data length |
| {"Unable to read stream data length.", |
| {kVarInt62OneByte + 0x0c}}, |
| // data |
| {"Unable to read frame data.", |
| { 'h', 'e', 'l', 'l', |
| 'o', ' ', 'w', 'o', |
|