blob: 11497215bf1e70efcfd8a149afd2689cd047b1e4 [file] [log] [blame]
// 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 "quic/test_tools/quic_test_utils.h"
#include <algorithm>
#include <cstdint>
#include <memory>
#include <utility>
#include "absl/base/macros.h"
#include "absl/strings/string_view.h"
#include "third_party/boringssl/src/include/openssl/chacha.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
#include "quic/core/crypto/crypto_framer.h"
#include "quic/core/crypto/crypto_handshake.h"
#include "quic/core/crypto/crypto_utils.h"
#include "quic/core/crypto/null_decrypter.h"
#include "quic/core/crypto/null_encrypter.h"
#include "quic/core/crypto/quic_decrypter.h"
#include "quic/core/crypto/quic_encrypter.h"
#include "quic/core/http/quic_spdy_client_session.h"
#include "quic/core/quic_buffer_allocator.h"
#include "quic/core/quic_config.h"
#include "quic/core/quic_data_writer.h"
#include "quic/core/quic_framer.h"
#include "quic/core/quic_packet_creator.h"
#include "quic/core/quic_simple_buffer_allocator.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_error_code_wrappers.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/test_tools/crypto_test_utils.h"
#include "quic/test_tools/quic_config_peer.h"
#include "quic/test_tools/quic_connection_peer.h"
#include "common/quiche_endian.h"
#include "spdy/core/spdy_frame_builder.h"
using testing::_;
using testing::Invoke;
namespace quic {
namespace test {
QuicConnectionId TestConnectionId() {
// Chosen by fair dice roll.
// Guaranteed to be random.
return TestConnectionId(42);
}
QuicConnectionId TestConnectionId(uint64_t connection_number) {
const uint64_t connection_id64_net =
quiche::QuicheEndian::HostToNet64(connection_number);
return QuicConnectionId(reinterpret_cast<const char*>(&connection_id64_net),
sizeof(connection_id64_net));
}
QuicConnectionId TestConnectionIdNineBytesLong(uint64_t connection_number) {
const uint64_t connection_number_net =
quiche::QuicheEndian::HostToNet64(connection_number);
char connection_id_bytes[9] = {};
static_assert(
sizeof(connection_id_bytes) == 1 + sizeof(connection_number_net),
"bad lengths");
memcpy(connection_id_bytes + 1, &connection_number_net,
sizeof(connection_number_net));
return QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes));
}
uint64_t TestConnectionIdToUInt64(QuicConnectionId connection_id) {
QUICHE_DCHECK_EQ(connection_id.length(), kQuicDefaultConnectionIdLength);
uint64_t connection_id64_net = 0;
memcpy(&connection_id64_net, connection_id.data(),
std::min<size_t>(static_cast<size_t>(connection_id.length()),
sizeof(connection_id64_net)));
return quiche::QuicheEndian::NetToHost64(connection_id64_net);
}
std::vector<uint8_t> CreateStatelessResetTokenForTest() {
static constexpr uint8_t kStatelessResetTokenDataForTest[16] = {
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F};
return std::vector<uint8_t>(kStatelessResetTokenDataForTest,
kStatelessResetTokenDataForTest +
sizeof(kStatelessResetTokenDataForTest));
}
std::string TestHostname() { return "test.example.com"; }
QuicServerId TestServerId() {
return QuicServerId(TestHostname(), kTestPort);
}
QuicAckFrame InitAckFrame(const std::vector<QuicAckBlock>& ack_blocks) {
QUICHE_DCHECK_GT(ack_blocks.size(), 0u);
QuicAckFrame ack;
QuicPacketNumber end_of_previous_block(1);
for (const QuicAckBlock& block : ack_blocks) {
QUICHE_DCHECK_GE(block.start, end_of_previous_block);
QUICHE_DCHECK_GT(block.limit, block.start);
ack.packets.AddRange(block.start, block.limit);
end_of_previous_block = block.limit;
}
ack.largest_acked = ack.packets.Max();
return ack;
}
QuicAckFrame InitAckFrame(uint64_t largest_acked) {
return InitAckFrame(QuicPacketNumber(largest_acked));
}
QuicAckFrame InitAckFrame(QuicPacketNumber largest_acked) {
return InitAckFrame({{QuicPacketNumber(1), largest_acked + 1}});
}
QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks,
uint64_t least_unacked) {
QuicAckFrame ack;
ack.largest_acked = QuicPacketNumber(2 * num_ack_blocks + least_unacked);
// Add enough received packets to get num_ack_blocks ack blocks.
for (QuicPacketNumber i = QuicPacketNumber(2);
i < QuicPacketNumber(2 * num_ack_blocks + 1); i += 2) {
ack.packets.Add(i + least_unacked);
}
return ack;
}
QuicAckFrame MakeAckFrameWithGaps(uint64_t gap_size,
size_t max_num_gaps,
uint64_t largest_acked) {
QuicAckFrame ack;
ack.largest_acked = QuicPacketNumber(largest_acked);
ack.packets.Add(QuicPacketNumber(largest_acked));
for (size_t i = 0; i < max_num_gaps; ++i) {
if (largest_acked <= gap_size) {
break;
}
largest_acked -= gap_size;
ack.packets.Add(QuicPacketNumber(largest_acked));
}
return ack;
}
EncryptionLevel HeaderToEncryptionLevel(const QuicPacketHeader& header) {
if (header.form == IETF_QUIC_SHORT_HEADER_PACKET) {
return ENCRYPTION_FORWARD_SECURE;
} else if (header.form == IETF_QUIC_LONG_HEADER_PACKET) {
if (header.long_packet_type == HANDSHAKE) {
return ENCRYPTION_HANDSHAKE;
} else if (header.long_packet_type == ZERO_RTT_PROTECTED) {
return ENCRYPTION_ZERO_RTT;
}
}
return ENCRYPTION_INITIAL;
}
std::unique_ptr<QuicPacket> BuildUnsizedDataPacket(
QuicFramer* framer,
const QuicPacketHeader& header,
const QuicFrames& frames) {
const size_t max_plaintext_size =
framer->GetMaxPlaintextSize(kMaxOutgoingPacketSize);
size_t packet_size = GetPacketHeaderSize(framer->transport_version(), header);
for (size_t i = 0; i < frames.size(); ++i) {
QUICHE_DCHECK_LE(packet_size, max_plaintext_size);
bool first_frame = i == 0;
bool last_frame = i == frames.size() - 1;
const size_t frame_size = framer->GetSerializedFrameLength(
frames[i], max_plaintext_size - packet_size, first_frame, last_frame,
header.packet_number_length);
QUICHE_DCHECK(frame_size);
packet_size += frame_size;
}
return BuildUnsizedDataPacket(framer, header, frames, packet_size);
}
std::unique_ptr<QuicPacket> BuildUnsizedDataPacket(
QuicFramer* framer,
const QuicPacketHeader& header,
const QuicFrames& frames,
size_t packet_size) {
char* buffer = new char[packet_size];
EncryptionLevel level = HeaderToEncryptionLevel(header);
size_t length =
framer->BuildDataPacket(header, frames, buffer, packet_size, level);
if (length == 0) {
delete[] buffer;
return nullptr;
}
// Re-construct the data packet with data ownership.
return std::make_unique<QuicPacket>(
buffer, length, /* owns_buffer */ true,
GetIncludedDestinationConnectionIdLength(header),
GetIncludedSourceConnectionIdLength(header), header.version_flag,
header.nonce != nullptr, header.packet_number_length,
header.retry_token_length_length, header.retry_token.length(),
header.length_length);
}
std::string Sha1Hash(absl::string_view data) {
char buffer[SHA_DIGEST_LENGTH];
SHA1(reinterpret_cast<const uint8_t*>(data.data()), data.size(),
reinterpret_cast<uint8_t*>(buffer));
return std::string(buffer, ABSL_ARRAYSIZE(buffer));
}
bool ClearControlFrame(const QuicFrame& frame) {
DeleteFrame(&const_cast<QuicFrame&>(frame));
return true;
}
bool ClearControlFrameWithTransmissionType(const QuicFrame& frame,
TransmissionType /*type*/) {
return ClearControlFrame(frame);
}
uint64_t SimpleRandom::RandUint64() {
uint64_t result;
RandBytes(&result, sizeof(result));
return result;
}
void SimpleRandom::RandBytes(void* data, size_t len) {
uint8_t* data_bytes = reinterpret_cast<uint8_t*>(data);
while (len > 0) {
const size_t buffer_left = sizeof(buffer_) - buffer_offset_;
const size_t to_copy = std::min(buffer_left, len);
memcpy(data_bytes, buffer_ + buffer_offset_, to_copy);
data_bytes += to_copy;
buffer_offset_ += to_copy;
len -= to_copy;
if (buffer_offset_ == sizeof(buffer_)) {
FillBuffer();
}
}
}
void SimpleRandom::InsecureRandBytes(void* data, size_t len) {
RandBytes(data, len);
}
uint64_t SimpleRandom::InsecureRandUint64() {
return RandUint64();
}
void SimpleRandom::FillBuffer() {
uint8_t nonce[12];
memcpy(nonce, buffer_, sizeof(nonce));
CRYPTO_chacha_20(buffer_, buffer_, sizeof(buffer_), key_, nonce, 0);
buffer_offset_ = 0;
}
void SimpleRandom::set_seed(uint64_t seed) {
static_assert(sizeof(key_) == SHA256_DIGEST_LENGTH, "Key has to be 256 bits");
SHA256(reinterpret_cast<const uint8_t*>(&seed), sizeof(seed), key_);
memset(buffer_, 0, sizeof(buffer_));
FillBuffer();
}
MockFramerVisitor::MockFramerVisitor() {
// By default, we want to accept packets.
ON_CALL(*this, OnProtocolVersionMismatch(_))
.WillByDefault(testing::Return(false));
// By default, we want to accept packets.
ON_CALL(*this, OnUnauthenticatedHeader(_))
.WillByDefault(testing::Return(true));
ON_CALL(*this, OnUnauthenticatedPublicHeader(_))
.WillByDefault(testing::Return(true));
ON_CALL(*this, OnPacketHeader(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnStreamFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnCryptoFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnStopWaitingFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnPaddingFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnPingFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnRstStreamFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnConnectionCloseFrame(_))
.WillByDefault(testing::Return(true));
ON_CALL(*this, OnStopSendingFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnPathChallengeFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnPathResponseFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnGoAwayFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnMaxStreamsFrame(_)).WillByDefault(testing::Return(true));
ON_CALL(*this, OnStreamsBlockedFrame(_)).WillByDefault(testing::Return(true));
}
MockFramerVisitor::~MockFramerVisitor() {}
bool NoOpFramerVisitor::OnProtocolVersionMismatch(
ParsedQuicVersion /*version*/) {
return false;
}
bool NoOpFramerVisitor::OnUnauthenticatedPublicHeader(
const QuicPacketHeader& /*header*/) {
return true;
}
bool NoOpFramerVisitor::OnUnauthenticatedHeader(
const QuicPacketHeader& /*header*/) {
return true;
}
bool NoOpFramerVisitor::OnPacketHeader(const QuicPacketHeader& /*header*/) {
return true;
}
void NoOpFramerVisitor::OnCoalescedPacket(
const QuicEncryptedPacket& /*packet*/) {}
void NoOpFramerVisitor::OnUndecryptablePacket(
const QuicEncryptedPacket& /*packet*/,
EncryptionLevel /*decryption_level*/,
bool /*has_decryption_key*/) {}
bool NoOpFramerVisitor::OnStreamFrame(const QuicStreamFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnCryptoFrame(const QuicCryptoFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnAckFrameStart(QuicPacketNumber /*largest_acked*/,
QuicTime::Delta /*ack_delay_time*/) {
return true;
}
bool NoOpFramerVisitor::OnAckRange(QuicPacketNumber /*start*/,
QuicPacketNumber /*end*/) {
return true;
}
bool NoOpFramerVisitor::OnAckTimestamp(QuicPacketNumber /*packet_number*/,
QuicTime /*timestamp*/) {
return true;
}
bool NoOpFramerVisitor::OnAckFrameEnd(QuicPacketNumber /*start*/) {
return true;
}
bool NoOpFramerVisitor::OnStopWaitingFrame(
const QuicStopWaitingFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnPaddingFrame(const QuicPaddingFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnPingFrame(const QuicPingFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnConnectionCloseFrame(
const QuicConnectionCloseFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnNewConnectionIdFrame(
const QuicNewConnectionIdFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnRetireConnectionIdFrame(
const QuicRetireConnectionIdFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnNewTokenFrame(const QuicNewTokenFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnStopSendingFrame(
const QuicStopSendingFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnPathChallengeFrame(
const QuicPathChallengeFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnPathResponseFrame(
const QuicPathResponseFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnMaxStreamsFrame(
const QuicMaxStreamsFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnStreamsBlockedFrame(
const QuicStreamsBlockedFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnWindowUpdateFrame(
const QuicWindowUpdateFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnBlockedFrame(const QuicBlockedFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnMessageFrame(const QuicMessageFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnHandshakeDoneFrame(
const QuicHandshakeDoneFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::OnAckFrequencyFrame(
const QuicAckFrequencyFrame& /*frame*/) {
return true;
}
bool NoOpFramerVisitor::IsValidStatelessResetToken(
const StatelessResetToken& /*token*/) const {
return false;
}
MockQuicConnectionVisitor::MockQuicConnectionVisitor() {}
MockQuicConnectionVisitor::~MockQuicConnectionVisitor() {}
MockQuicConnectionHelper::MockQuicConnectionHelper() {}
MockQuicConnectionHelper::~MockQuicConnectionHelper() {}
const QuicClock* MockQuicConnectionHelper::GetClock() const {
return &clock_;
}
QuicRandom* MockQuicConnectionHelper::GetRandomGenerator() {
return &random_generator_;
}
QuicAlarm* MockAlarmFactory::CreateAlarm(QuicAlarm::Delegate* delegate) {
return new MockAlarmFactory::TestAlarm(
QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
}
QuicArenaScopedPtr<QuicAlarm> MockAlarmFactory::CreateAlarm(
QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
QuicConnectionArena* arena) {
if (arena != nullptr) {
return arena->New<TestAlarm>(std::move(delegate));
} else {
return QuicArenaScopedPtr<TestAlarm>(new TestAlarm(std::move(delegate)));
}
}
QuicBufferAllocator* MockQuicConnectionHelper::GetStreamSendBufferAllocator() {
return &buffer_allocator_;
}
void MockQuicConnectionHelper::AdvanceTime(QuicTime::Delta delta) {
clock_.AdvanceTime(delta);
}
MockQuicConnection::MockQuicConnection(MockQuicConnectionHelper* helper,
MockAlarmFactory* alarm_factory,
Perspective perspective)
: MockQuicConnection(TestConnectionId(),
QuicSocketAddress(TestPeerIPAddress(), kTestPort),
helper,
alarm_factory,
perspective,
ParsedVersionOfIndex(CurrentSupportedVersions(), 0)) {}
MockQuicConnection::MockQuicConnection(QuicSocketAddress address,
MockQuicConnectionHelper* helper,
MockAlarmFactory* alarm_factory,
Perspective perspective)
: MockQuicConnection(TestConnectionId(),
address,
helper,
alarm_factory,
perspective,
ParsedVersionOfIndex(CurrentSupportedVersions(), 0)) {}
MockQuicConnection::MockQuicConnection(QuicConnectionId connection_id,
MockQuicConnectionHelper* helper,
MockAlarmFactory* alarm_factory,
Perspective perspective)
: MockQuicConnection(connection_id,
QuicSocketAddress(TestPeerIPAddress(), kTestPort),
helper,
alarm_factory,
perspective,
ParsedVersionOfIndex(CurrentSupportedVersions(), 0)) {}
MockQuicConnection::MockQuicConnection(
MockQuicConnectionHelper* helper,
MockAlarmFactory* alarm_factory,
Perspective perspective,
const ParsedQuicVersionVector& supported_versions)
: MockQuicConnection(TestConnectionId(),
QuicSocketAddress(TestPeerIPAddress(), kTestPort),
helper,
alarm_factory,
perspective,
supported_versions) {}
MockQuicConnection::MockQuicConnection(
QuicConnectionId connection_id,
QuicSocketAddress initial_peer_address,
MockQuicConnectionHelper* helper,
MockAlarmFactory* alarm_factory,
Perspective perspective,
const ParsedQuicVersionVector& supported_versions)
: QuicConnection(
connection_id,
/*initial_self_address=*/QuicSocketAddress(QuicIpAddress::Any4(), 5),
initial_peer_address,
helper,
alarm_factory,
new testing::NiceMock<MockPacketWriter>(),
/* owns_writer= */ true,
perspective,
supported_versions) {
ON_CALL(*this, OnError(_))
.WillByDefault(
Invoke(this, &PacketSavingConnection::QuicConnection_OnError));
ON_CALL(*this, SendCryptoData(_, _, _))
.WillByDefault(
Invoke(this, &MockQuicConnection::QuicConnection_SendCryptoData));
SetSelfAddress(QuicSocketAddress(QuicIpAddress::Any4(), 5));
}
MockQuicConnection::~MockQuicConnection() {}
void MockQuicConnection::AdvanceTime(QuicTime::Delta delta) {
static_cast<MockQuicConnectionHelper*>(helper())->AdvanceTime(delta);
}
bool MockQuicConnection::OnProtocolVersionMismatch(
ParsedQuicVersion /*version*/) {
return false;
}
PacketSavingConnection::PacketSavingConnection(MockQuicConnectionHelper* helper,
MockAlarmFactory* alarm_factory,
Perspective perspective)
: MockQuicConnection(helper, alarm_factory, perspective) {}
PacketSavingConnection::PacketSavingConnection(
MockQuicConnectionHelper* helper,
MockAlarmFactory* alarm_factory,
Perspective perspective,
const ParsedQuicVersionVector& supported_versions)
: MockQuicConnection(helper,
alarm_factory,
perspective,
supported_versions) {}
PacketSavingConnection::~PacketSavingConnection() {}
void PacketSavingConnection::SendOrQueuePacket(SerializedPacket packet) {
encrypted_packets_.push_back(std::make_unique<QuicEncryptedPacket>(
CopyBuffer(packet), packet.encrypted_length, true));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
// Transfer ownership of the packet to the SentPacketManager and the
// ack notifier to the AckNotifierManager.
OnPacketSent(packet.encryption_level, packet.transmission_type);
QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent(
&packet, clock_.ApproximateNow(), NOT_RETRANSMISSION,
HAS_RETRANSMITTABLE_DATA, true);
}
MockQuicSession::MockQuicSession(QuicConnection* connection)
: MockQuicSession(connection, true) {}
MockQuicSession::MockQuicSession(QuicConnection* connection,
bool create_mock_crypto_stream)
: QuicSession(connection,
nullptr,
DefaultQuicConfig(),
connection->supported_versions(),
/*num_expected_unidirectional_static_streams = */ 0) {
if (create_mock_crypto_stream) {
crypto_stream_ = std::make_unique<MockQuicCryptoStream>(this);
}
ON_CALL(*this, WritevData(_, _, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
MockQuicSession::~MockQuicSession() {
DeleteConnection();
}
QuicCryptoStream* MockQuicSession::GetMutableCryptoStream() {
return crypto_stream_.get();
}
const QuicCryptoStream* MockQuicSession::GetCryptoStream() const {
return crypto_stream_.get();
}
void MockQuicSession::SetCryptoStream(QuicCryptoStream* crypto_stream) {
crypto_stream_.reset(crypto_stream);
}
QuicConsumedData MockQuicSession::ConsumeData(
QuicStreamId id,
size_t write_length,
QuicStreamOffset offset,
StreamSendingState state,
TransmissionType /*type*/,
absl::optional<EncryptionLevel> /*level*/) {
if (write_length > 0) {
auto buf = std::make_unique<char[]>(write_length);
QuicStream* stream = GetOrCreateStream(id);
QUICHE_DCHECK(stream);
QuicDataWriter writer(write_length, buf.get(), quiche::HOST_BYTE_ORDER);
stream->WriteStreamData(offset, write_length, &writer);
} else {
QUICHE_DCHECK(state != NO_FIN);
}
return QuicConsumedData(write_length, state != NO_FIN);
}
MockQuicCryptoStream::MockQuicCryptoStream(QuicSession* session)
: QuicCryptoStream(session), params_(new QuicCryptoNegotiatedParameters) {}
MockQuicCryptoStream::~MockQuicCryptoStream() {}
ssl_early_data_reason_t MockQuicCryptoStream::EarlyDataReason() const {
return ssl_early_data_unknown;
}
bool MockQuicCryptoStream::encryption_established() const {
return false;
}
bool MockQuicCryptoStream::one_rtt_keys_available() const {
return false;
}
const QuicCryptoNegotiatedParameters&
MockQuicCryptoStream::crypto_negotiated_params() const {
return *params_;
}
CryptoMessageParser* MockQuicCryptoStream::crypto_message_parser() {
return &crypto_framer_;
}
MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection)
: MockQuicSpdySession(connection, true) {}
MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection,
bool create_mock_crypto_stream)
: QuicSpdySession(connection,
nullptr,
DefaultQuicConfig(),
connection->supported_versions()) {
if (create_mock_crypto_stream) {
crypto_stream_ = std::make_unique<MockQuicCryptoStream>(this);
}
ON_CALL(*this, WritevData(_, _, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
ON_CALL(*this, SendWindowUpdate(_, _))
.WillByDefault([this](QuicStreamId id, QuicStreamOffset byte_offset) {
return QuicSpdySession::SendWindowUpdate(id, byte_offset);
});
ON_CALL(*this, SendBlocked(_)).WillByDefault([this](QuicStreamId id) {
return QuicSpdySession::SendBlocked(id);
});
ON_CALL(*this, OnCongestionWindowChange(_)).WillByDefault(testing::Return());
}
MockQuicSpdySession::~MockQuicSpdySession() {
DeleteConnection();
}
QuicCryptoStream* MockQuicSpdySession::GetMutableCryptoStream() {
return crypto_stream_.get();
}
const QuicCryptoStream* MockQuicSpdySession::GetCryptoStream() const {
return crypto_stream_.get();
}
void MockQuicSpdySession::SetCryptoStream(QuicCryptoStream* crypto_stream) {
crypto_stream_.reset(crypto_stream);
}
QuicConsumedData MockQuicSpdySession::ConsumeData(
QuicStreamId id,
size_t write_length,
QuicStreamOffset offset,
StreamSendingState state,
TransmissionType /*type*/,
absl::optional<EncryptionLevel> /*level*/) {
if (write_length > 0) {
auto buf = std::make_unique<char[]>(write_length);
QuicStream* stream = GetOrCreateStream(id);
QUICHE_DCHECK(stream);
QuicDataWriter writer(write_length, buf.get(), quiche::HOST_BYTE_ORDER);
stream->WriteStreamData(offset, write_length, &writer);
} else {
QUICHE_DCHECK(state != NO_FIN);
}
return QuicConsumedData(write_length, state != NO_FIN);
}
TestQuicSpdyServerSession::TestQuicSpdyServerSession(
QuicConnection* connection,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache)
: QuicServerSessionBase(config,
supported_versions,
connection,
&visitor_,
&helper_,
crypto_config,
compressed_certs_cache) {
ON_CALL(helper_, CanAcceptClientHello(_, _, _, _, _))
.WillByDefault(testing::Return(true));
}
TestQuicSpdyServerSession::~TestQuicSpdyServerSession() {
DeleteConnection();
}
std::unique_ptr<QuicCryptoServerStreamBase>
TestQuicSpdyServerSession::CreateQuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache) {
return CreateCryptoServerStream(crypto_config, compressed_certs_cache, this,
&helper_);
}
QuicCryptoServerStreamBase*
TestQuicSpdyServerSession::GetMutableCryptoStream() {
return QuicServerSessionBase::GetMutableCryptoStream();
}
const QuicCryptoServerStreamBase* TestQuicSpdyServerSession::GetCryptoStream()
const {
return QuicServerSessionBase::GetCryptoStream();
}
TestQuicSpdyClientSession::TestQuicSpdyClientSession(
QuicConnection* connection,
const QuicConfig& config,
const ParsedQuicVersionVector& supported_versions,
const QuicServerId& server_id,
QuicCryptoClientConfig* crypto_config)
: QuicSpdyClientSessionBase(connection,
&push_promise_index_,
config,
supported_versions) {
// TODO(b/153726130): Consider adding SetServerApplicationStateForResumption
// calls in tests and set |has_application_state| to true.
crypto_stream_ = std::make_unique<QuicCryptoClientStream>(
server_id, this, crypto_test_utils::ProofVerifyContextForTesting(),
crypto_config, this, /*has_application_state = */ false);
Initialize();
ON_CALL(*this, OnConfigNegotiated())
.WillByDefault(
Invoke(this, &TestQuicSpdyClientSession::RealOnConfigNegotiated));
}
TestQuicSpdyClientSession::~TestQuicSpdyClientSession() {}
bool TestQuicSpdyClientSession::IsAuthorized(const std::string& /*authority*/) {
return true;
}
QuicCryptoClientStream* TestQuicSpdyClientSession::GetMutableCryptoStream() {
return crypto_stream_.get();
}
const QuicCryptoClientStream* TestQuicSpdyClientSession::GetCryptoStream()
const {
return crypto_stream_.get();
}
void TestQuicSpdyClientSession::RealOnConfigNegotiated() {
QuicSpdyClientSessionBase::OnConfigNegotiated();
}
TestPushPromiseDelegate::TestPushPromiseDelegate(bool match)
: match_(match), rendezvous_fired_(false), rendezvous_stream_(nullptr) {}
bool TestPushPromiseDelegate::CheckVary(
const spdy::SpdyHeaderBlock& /*client_request*/,
const spdy::SpdyHeaderBlock& /*promise_request*/,
const spdy::SpdyHeaderBlock& /*promise_response*/) {
QUIC_DVLOG(1) << "match " << match_;
return match_;
}
void TestPushPromiseDelegate::OnRendezvousResult(QuicSpdyStream* stream) {
rendezvous_fired_ = true;
rendezvous_stream_ = stream;
}
MockPacketWriter::MockPacketWriter() {
ON_CALL(*this, GetMaxPacketSize(_))
.WillByDefault(testing::Return(kMaxOutgoingPacketSize));
ON_CALL(*this, IsBatchMode()).WillByDefault(testing::Return(false));
ON_CALL(*this, GetNextWriteLocation(_, _))
.WillByDefault(testing::Return(QuicPacketBuffer()));
ON_CALL(*this, Flush())
.WillByDefault(testing::Return(WriteResult(WRITE_STATUS_OK, 0)));
ON_CALL(*this, SupportsReleaseTime()).WillByDefault(testing::Return(false));
}
MockPacketWriter::~MockPacketWriter() {}
MockSendAlgorithm::MockSendAlgorithm() {
ON_CALL(*this, PacingRate(_))
.WillByDefault(testing::Return(QuicBandwidth::Zero()));
ON_CALL(*this, BandwidthEstimate())
.WillByDefault(testing::Return(QuicBandwidth::Zero()));
}
MockSendAlgorithm::~MockSendAlgorithm() {}
MockLossAlgorithm::MockLossAlgorithm() {}
MockLossAlgorithm::~MockLossAlgorithm() {}
MockAckListener::MockAckListener() {}
MockAckListener::~MockAckListener() {}
MockNetworkChangeVisitor::MockNetworkChangeVisitor() {}
MockNetworkChangeVisitor::~MockNetworkChangeVisitor() {}
QuicIpAddress TestPeerIPAddress() {
return QuicIpAddress::Loopback4();
}
ParsedQuicVersion QuicVersionMax() {
return AllSupportedVersions().front();
}
ParsedQuicVersion QuicVersionMin() {
return AllSupportedVersions().back();
}
void DisableQuicVersionsWithTls() {
for (const ParsedQuicVersion& version : AllSupportedVersionsWithTls()) {
QuicDisableVersion(version);
}
}
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
QuicConnectionId source_connection_id,
bool version_flag,
bool reset_flag,
uint64_t packet_number,
const std::string& data) {
return ConstructEncryptedPacket(
destination_connection_id, source_connection_id, version_flag, reset_flag,
packet_number, data, CONNECTION_ID_PRESENT, CONNECTION_ID_ABSENT,
PACKET_4BYTE_PACKET_NUMBER);
}
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
QuicConnectionId source_connection_id,
bool version_flag,
bool reset_flag,
uint64_t packet_number,
const std::string& data,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
QuicPacketNumberLength packet_number_length) {
return ConstructEncryptedPacket(
destination_connection_id, source_connection_id, version_flag, reset_flag,
packet_number, data, destination_connection_id_included,
source_connection_id_included, packet_number_length, nullptr);
}
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
QuicConnectionId source_connection_id,
bool version_flag,
bool reset_flag,
uint64_t packet_number,
const std::string& data,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
QuicPacketNumberLength packet_number_length,
ParsedQuicVersionVector* versions) {
return ConstructEncryptedPacket(
destination_connection_id, source_connection_id, version_flag, reset_flag,
packet_number, data, false, destination_connection_id_included,
source_connection_id_included, packet_number_length, versions,
Perspective::IS_CLIENT);
}
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
QuicConnectionId source_connection_id,
bool version_flag,
bool reset_flag,
uint64_t packet_number,
const std::string& data,
bool full_padding,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
QuicPacketNumberLength packet_number_length,
ParsedQuicVersionVector* versions) {
return ConstructEncryptedPacket(
destination_connection_id, source_connection_id, version_flag, reset_flag,
packet_number, data, full_padding, destination_connection_id_included,
source_connection_id_included, packet_number_length, versions,
Perspective::IS_CLIENT);
}
QuicEncryptedPacket* ConstructEncryptedPacket(
QuicConnectionId destination_connection_id,
QuicConnectionId source_connection_id,
bool version_flag,
bool reset_flag,
uint64_t packet_number,
const std::string& data,
bool full_padding,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
QuicPacketNumberLength packet_number_length,
ParsedQuicVersionVector* versions,
Perspective perspective) {
QuicPacketHeader header;
header.destination_connection_id = destination_connection_id;
header.destination_connection_id_included =
destination_connection_id_included;
header.source_connection_id = source_connection_id;
header.source_connection_id_included = source_connection_id_included;
header.version_flag = version_flag;
header.reset_flag = reset_flag;
header.packet_number_length = packet_number_length;
header.packet_number = QuicPacketNumber(packet_number);
ParsedQuicVersionVector supported_versions = CurrentSupportedVersions();
if (!versions) {
versions = &supported_versions;
}
EXPECT_FALSE(versions->empty());
ParsedQuicVersion version = (*versions)[0];
if (QuicVersionHasLongHeaderLengths(version.transport_version) &&
version_flag) {
header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
}
QuicFrames frames;
QuicFramer framer(*versions, QuicTime::Zero(), perspective,
kQuicDefaultConnectionIdLength);
framer.SetInitialObfuscators(destination_connection_id);
EncryptionLevel level =
header.version_flag ? ENCRYPTION_INITIAL : ENCRYPTION_FORWARD_SECURE;
if (level != ENCRYPTION_INITIAL) {
framer.SetEncrypter(level, std::make_unique<NullEncrypter>(perspective));
}
if (!QuicVersionUsesCryptoFrames(version.transport_version)) {
QuicFrame frame(
QuicStreamFrame(QuicUtils::GetCryptoStreamId(version.transport_version),
false, 0, absl::string_view(data)));
frames.push_back(frame);
} else {
QuicFrame frame(new QuicCryptoFrame(level, 0, data));
frames.push_back(frame);
}
if (full_padding) {
frames.push_back(QuicFrame(QuicPaddingFrame(-1)));
} else {
// We need a minimum number of bytes of encrypted payload. This will
// guarantee that we have at least that much. (It ignores the overhead of
// the stream/crypto framing, so it overpads slightly.)
size_t min_plaintext_size =
QuicPacketCreator::MinPlaintextPacketSize(version);
if (data.length() < min_plaintext_size) {
size_t padding_length = min_plaintext_size - data.length();
frames.push_back(QuicFrame(QuicPaddingFrame(padding_length)));
}
}
std::unique_ptr<QuicPacket> packet(
BuildUnsizedDataPacket(&framer, header, frames));
EXPECT_TRUE(packet != nullptr);
char* buffer = new char[kMaxOutgoingPacketSize];
size_t encrypted_length =
framer.EncryptPayload(level, QuicPacketNumber(packet_number), *packet,
buffer, kMaxOutgoingPacketSize);
EXPECT_NE(0u, encrypted_length);
DeleteFrames(&frames);
return new QuicEncryptedPacket(buffer, encrypted_length, true);
}
std::unique_ptr<QuicEncryptedPacket> GetUndecryptableEarlyPacket(
const ParsedQuicVersion& version,
const QuicConnectionId& server_connection_id) {
QuicPacketHeader header;
header.destination_connection_id = server_connection_id;
header.destination_connection_id_included = CONNECTION_ID_PRESENT;
header.source_connection_id = EmptyQuicConnectionId();
header.source_connection_id_included = CONNECTION_ID_PRESENT;
if (!version.SupportsClientConnectionIds()) {
header.source_connection_id_included = CONNECTION_ID_ABSENT;
}
header.version_flag = true;
header.reset_flag = false;
header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
header.packet_number = QuicPacketNumber(33);
header.long_packet_type = ZERO_RTT_PROTECTED;
if (version.HasLongHeaderLengths()) {
header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
}
QuicFrames frames;
frames.push_back(QuicFrame(QuicPingFrame()));
frames.push_back(QuicFrame(QuicPaddingFrame(100)));
QuicFramer framer({version}, QuicTime::Zero(), Perspective::IS_CLIENT,
kQuicDefaultConnectionIdLength);
framer.SetInitialObfuscators(server_connection_id);
framer.SetEncrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
std::unique_ptr<QuicPacket> packet(
BuildUnsizedDataPacket(&framer, header, frames));
EXPECT_TRUE(packet != nullptr);
char* buffer = new char[kMaxOutgoingPacketSize];
size_t encrypted_length =
framer.EncryptPayload(ENCRYPTION_ZERO_RTT, header.packet_number, *packet,
buffer, kMaxOutgoingPacketSize);
EXPECT_NE(0u, encrypted_length);
DeleteFrames(&frames);
return std::make_unique<QuicEncryptedPacket>(buffer, encrypted_length,
/*owns_buffer=*/true);
}
QuicReceivedPacket* ConstructReceivedPacket(
const QuicEncryptedPacket& encrypted_packet,
QuicTime receipt_time) {
char* buffer = new char[encrypted_packet.length()];
memcpy(buffer, encrypted_packet.data(), encrypted_packet.length());
return new QuicReceivedPacket(buffer, encrypted_packet.length(), receipt_time,
true);
}
QuicEncryptedPacket* ConstructMisFramedEncryptedPacket(
QuicConnectionId destination_connection_id,
QuicConnectionId source_connection_id,
bool version_flag,
bool reset_flag,
uint64_t packet_number,
const std::string& data,
QuicConnectionIdIncluded destination_connection_id_included,
QuicConnectionIdIncluded source_connection_id_included,
QuicPacketNumberLength packet_number_length,
ParsedQuicVersion version,
Perspective perspective) {
QuicPacketHeader header;
header.destination_connection_id = destination_connection_id;
header.destination_connection_id_included =
destination_connection_id_included;
header.source_connection_id = source_connection_id;
header.source_connection_id_included = source_connection_id_included;
header.version_flag = version_flag;
header.reset_flag = reset_flag;
header.packet_number_length = packet_number_length;
header.packet_number = QuicPacketNumber(packet_number);
if (QuicVersionHasLongHeaderLengths(version.transport_version) &&
version_flag) {
header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
}
QuicFrame frame(QuicStreamFrame(1, false, 0, absl::string_view(data)));
QuicFrames frames;
frames.push_back(frame);
QuicFramer framer({version}, QuicTime::Zero(), perspective,
kQuicDefaultConnectionIdLength);
framer.SetInitialObfuscators(destination_connection_id);
EncryptionLevel level =
version_flag ? ENCRYPTION_INITIAL : ENCRYPTION_FORWARD_SECURE;
if (level != ENCRYPTION_INITIAL) {
framer.SetEncrypter(level, std::make_unique<NullEncrypter>(perspective));
}
// We need a minimum of 7 bytes of encrypted payload. This will guarantee that
// we have at least that much. (It ignores the overhead of the stream/crypto
// framing, so it overpads slightly.)
if (data.length() < 7) {
size_t padding_length = 7 - data.length();
frames.push_back(QuicFrame(QuicPaddingFrame(padding_length)));
}
std::unique_ptr<QuicPacket> packet(
BuildUnsizedDataPacket(&framer, header, frames));
EXPECT_TRUE(packet != nullptr);
// Now set the frame type to 0x1F, which is an invalid frame type.
reinterpret_cast<unsigned char*>(
packet->mutable_data())[GetStartOfEncryptedData(
framer.transport_version(),
GetIncludedDestinationConnectionIdLength(header),
GetIncludedSourceConnectionIdLength(header), version_flag,
false /* no diversification nonce */, packet_number_length,
header.retry_token_length_length, 0, header.length_length)] = 0x1F;
char* buffer = new char[kMaxOutgoingPacketSize];
size_t encrypted_length =
framer.EncryptPayload(level, QuicPacketNumber(packet_number), *packet,
buffer, kMaxOutgoingPacketSize);
EXPECT_NE(0u, encrypted_length);
return new QuicEncryptedPacket(buffer, encrypted_length, true);
}
QuicConfig DefaultQuicConfig() {
QuicConfig config;
config.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend(
kInitialStreamFlowControlWindowForTest);
config.SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend(
kInitialStreamFlowControlWindowForTest);
config.SetInitialMaxStreamDataBytesUnidirectionalToSend(
kInitialStreamFlowControlWindowForTest);
config.SetInitialStreamFlowControlWindowToSend(
kInitialStreamFlowControlWindowForTest);
config.SetInitialSessionFlowControlWindowToSend(
kInitialSessionFlowControlWindowForTest);
QuicConfigPeer::SetReceivedMaxBidirectionalStreams(
&config, kDefaultMaxStreamsPerConnection);
// Default enable NSTP.
// This is unnecessary for versions > 44
if (!config.HasClientSentConnectionOption(quic::kNSTP,
quic::Perspective::IS_CLIENT)) {
quic::QuicTagVector connection_options;
connection_options.push_back(quic::kNSTP);
config.SetConnectionOptionsToSend(connection_options);
}
return config;
}
ParsedQuicVersionVector SupportedVersions(ParsedQuicVersion version) {
ParsedQuicVersionVector versions;
versions.push_back(version);
return versions;
}
MockQuicConnectionDebugVisitor::MockQuicConnectionDebugVisitor() {}
MockQuicConnectionDebugVisitor::~MockQuicConnectionDebugVisitor() {}
MockReceivedPacketManager::MockReceivedPacketManager(QuicConnectionStats* stats)
: QuicReceivedPacketManager(stats) {}
MockReceivedPacketManager::~MockReceivedPacketManager() {}
MockPacketCreatorDelegate::MockPacketCreatorDelegate() {}
MockPacketCreatorDelegate::~MockPacketCreatorDelegate() {}
MockSessionNotifier::MockSessionNotifier() {}
MockSessionNotifier::~MockSessionNotifier() {}
// static
QuicCryptoClientStream::HandshakerInterface*
QuicCryptoClientStreamPeer::GetHandshaker(QuicCryptoClientStream* stream) {
return stream->handshaker_.get();
}
void CreateClientSessionForTest(
QuicServerId server_id,
QuicTime::Delta connection_start_time,
const ParsedQuicVersionVector& supported_versions,
MockQuicConnectionHelper* helper,
MockAlarmFactory* alarm_factory,
QuicCryptoClientConfig* crypto_client_config,
PacketSavingConnection** client_connection,
TestQuicSpdyClientSession** client_session) {
QUICHE_CHECK(crypto_client_config);
QUICHE_CHECK(client_connection);
QUICHE_CHECK(client_session);
QUICHE_CHECK(!connection_start_time.IsZero())
<< "Connections must start at non-zero times, otherwise the "
<< "strike-register will be unhappy.";
QuicConfig config = DefaultQuicConfig();
*client_connection = new PacketSavingConnection(
helper, alarm_factory, Perspective::IS_CLIENT, supported_versions);
*client_session = new TestQuicSpdyClientSession(*client_connection, config,
supported_versions, server_id,
crypto_client_config);
(*client_connection)->AdvanceTime(connection_start_time);
}
void CreateServerSessionForTest(
QuicServerId /*server_id*/,
QuicTime::Delta connection_start_time,
ParsedQuicVersionVector supported_versions,
MockQuicConnectionHelper* helper,
MockAlarmFactory* alarm_factory,
QuicCryptoServerConfig* server_crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
PacketSavingConnection** server_connection,
TestQuicSpdyServerSession** server_session) {
QUICHE_CHECK(server_crypto_config);
QUICHE_CHECK(server_connection);
QUICHE_CHECK(server_session);
QUICHE_CHECK(!connection_start_time.IsZero())
<< "Connections must start at non-zero times, otherwise the "
<< "strike-register will be unhappy.";
*server_connection =
new PacketSavingConnection(helper, alarm_factory, Perspective::IS_SERVER,
ParsedVersionOfIndex(supported_versions, 0));
*server_session = new TestQuicSpdyServerSession(
*server_connection, DefaultQuicConfig(), supported_versions,
server_crypto_config, compressed_certs_cache);
(*server_session)->Initialize();
// We advance the clock initially because the default time is zero and the
// strike register worries that we've just overflowed a uint32_t time.
(*server_connection)->AdvanceTime(connection_start_time);
}
QuicStreamId GetNthClientInitiatedBidirectionalStreamId(
QuicTransportVersion version,
int n) {
int num = n;
if (!VersionUsesHttp3(version)) {
num++;
}
return QuicUtils::GetFirstBidirectionalStreamId(version,
Perspective::IS_CLIENT) +
QuicUtils::StreamIdDelta(version) * num;
}
QuicStreamId GetNthServerInitiatedBidirectionalStreamId(
QuicTransportVersion version,
int n) {
return QuicUtils::GetFirstBidirectionalStreamId(version,
Perspective::IS_SERVER) +
QuicUtils::StreamIdDelta(version) * n;
}
QuicStreamId GetNthServerInitiatedUnidirectionalStreamId(
QuicTransportVersion version,
int n) {
return QuicUtils::GetFirstUnidirectionalStreamId(version,
Perspective::IS_SERVER) +
QuicUtils::StreamIdDelta(version) * n;
}
QuicStreamId GetNthClientInitiatedUnidirectionalStreamId(
QuicTransportVersion version,
int n) {
return QuicUtils::GetFirstUnidirectionalStreamId(version,
Perspective::IS_CLIENT) +
QuicUtils::StreamIdDelta(version) * n;
}
StreamType DetermineStreamType(QuicStreamId id,
ParsedQuicVersion version,
Perspective perspective,
bool is_incoming,
StreamType default_type) {
return version.HasIetfQuicFrames()
? QuicUtils::GetStreamType(id, perspective, is_incoming, version)
: default_type;
}
QuicMemSlice MemSliceFromString(absl::string_view data) {
if (data.empty()) {
return QuicMemSlice();
}
static SimpleBufferAllocator* allocator = new SimpleBufferAllocator();
return QuicMemSlice(QuicBuffer::Copy(allocator, data));
}
bool TaggingEncrypter::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) {
const size_t len = plaintext.size() + kTagSize;
if (max_output_length < len) {
return false;
}
// Memmove is safe for inplace encryption.
memmove(output, plaintext.data(), plaintext.size());
output += plaintext.size();
memset(output, tag_, kTagSize);
*output_length = len;
return true;
}
bool TaggingDecrypter::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*/) {
if (ciphertext.size() < kTagSize) {
return false;
}
if (!CheckTag(ciphertext, GetTag(ciphertext))) {
return false;
}
*output_length = ciphertext.size() - kTagSize;
memcpy(output, ciphertext.data(), *output_length);
return true;
}
bool TaggingDecrypter::CheckTag(absl::string_view ciphertext, uint8_t tag) {
for (size_t i = ciphertext.size() - kTagSize; i < ciphertext.size(); i++) {
if (ciphertext.data()[i] != tag) {
return false;
}
}
return true;
}
TestPacketWriter::TestPacketWriter(ParsedQuicVersion version,
MockClock* clock,
Perspective perspective)
: version_(version),
framer_(SupportedVersions(version_),
QuicUtils::InvertPerspective(perspective)),
clock_(clock) {
QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(),
TestConnectionId());
framer_.framer()->SetInitialObfuscators(TestConnectionId());
for (int i = 0; i < 128; ++i) {
PacketBuffer* p = new PacketBuffer();
packet_buffer_pool_.push_back(p);
packet_buffer_pool_index_[p->buffer] = p;
packet_buffer_free_list_.push_back(p);
}
}
TestPacketWriter::~TestPacketWriter() {
EXPECT_EQ(packet_buffer_pool_.size(), packet_buffer_free_list_.size())
<< packet_buffer_pool_.size() - packet_buffer_free_list_.size()
<< " out of " << packet_buffer_pool_.size()
<< " packet buffers have been leaked.";
for (auto p : packet_buffer_pool_) {
delete p;
}
}
WriteResult TestPacketWriter::WritePacket(const char* buffer,
size_t buf_len,
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
PerPacketOptions* /*options*/) {
last_write_source_address_ = self_address;
last_write_peer_address_ = peer_address;
// If the buffer is allocated from the pool, return it back to the pool.
// Note the buffer content doesn't change.
if (packet_buffer_pool_index_.find(const_cast<char*>(buffer)) !=
packet_buffer_pool_index_.end()) {
FreePacketBuffer(buffer);
}
QuicEncryptedPacket packet(buffer, buf_len);
++packets_write_attempts_;
if (packet.length() >= sizeof(final_bytes_of_last_packet_)) {
final_bytes_of_previous_packet_ = final_bytes_of_last_packet_;
memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4,
sizeof(final_bytes_of_last_packet_));
}
if (use_tagging_decrypter_) {
if (framer_.framer()->version().KnowsWhichDecrypterToUse()) {
framer_.framer()->InstallDecrypter(ENCRYPTION_INITIAL,
std::make_unique<TaggingDecrypter>());
framer_.framer()->InstallDecrypter(ENCRYPTION_HANDSHAKE,
std::make_unique<TaggingDecrypter>());
framer_.framer()->InstallDecrypter(ENCRYPTION_ZERO_RTT,
std::make_unique<TaggingDecrypter>());
framer_.framer()->InstallDecrypter(ENCRYPTION_FORWARD_SECURE,
std::make_unique<TaggingDecrypter>());
} else {
framer_.framer()->SetDecrypter(ENCRYPTION_INITIAL,
std::make_unique<TaggingDecrypter>());
}
} else if (framer_.framer()->version().KnowsWhichDecrypterToUse()) {
framer_.framer()->InstallDecrypter(
ENCRYPTION_HANDSHAKE,
std::make_unique<NullDecrypter>(framer_.framer()->perspective()));
framer_.framer()->InstallDecrypter(
ENCRYPTION_ZERO_RTT,
std::make_unique<NullDecrypter>(framer_.framer()->perspective()));
framer_.framer()->InstallDecrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullDecrypter>(framer_.framer()->perspective()));
}
EXPECT_TRUE(framer_.ProcessPacket(packet))
<< framer_.framer()->detailed_error() << " perspective "
<< framer_.framer()->perspective();
if (block_on_next_write_) {
write_blocked_ = true;
block_on_next_write_ = false;
}
if (next_packet_too_large_) {
next_packet_too_large_ = false;
return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE);
}
if (always_get_packet_too_large_) {
return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE);
}
if (IsWriteBlocked()) {
return WriteResult(is_write_blocked_data_buffered_
? WRITE_STATUS_BLOCKED_DATA_BUFFERED
: WRITE_STATUS_BLOCKED,
0);
}
if (ShouldWriteFail()) {
return WriteResult(WRITE_STATUS_ERROR, write_error_code_);
}
last_packet_size_ = packet.length();
last_packet_header_ = framer_.header();
if (!framer_.connection_close_frames().empty()) {
++connection_close_packets_;
}
if (!write_pause_time_delta_.IsZero()) {
clock_->AdvanceTime(write_pause_time_delta_);
}
if (is_batch_mode_) {
bytes_buffered_ += last_packet_size_;
return WriteResult(WRITE_STATUS_OK, 0);
}
return WriteResult(WRITE_STATUS_OK, last_packet_size_);
}
QuicPacketBuffer TestPacketWriter::GetNextWriteLocation(
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/) {
return {AllocPacketBuffer(), [this](const char* p) { FreePacketBuffer(p); }};
}
WriteResult TestPacketWriter::Flush() {
flush_attempts_++;
if (block_on_next_flush_) {
block_on_next_flush_ = false;
SetWriteBlocked();
return WriteResult(WRITE_STATUS_BLOCKED, /*errno*/ -1);
}
if (write_should_fail_) {
return WriteResult(WRITE_STATUS_ERROR, /*errno*/ -1);
}
int bytes_flushed = bytes_buffered_;
bytes_buffered_ = 0;
return WriteResult(WRITE_STATUS_OK, bytes_flushed);
}
char* TestPacketWriter::AllocPacketBuffer() {
PacketBuffer* p = packet_buffer_free_list_.front();
EXPECT_FALSE(p->in_use);
p->in_use = true;
packet_buffer_free_list_.pop_front();
return p->buffer;
}
void TestPacketWriter::FreePacketBuffer(const char* buffer) {
auto iter = packet_buffer_pool_index_.find(const_cast<char*>(buffer));
ASSERT_TRUE(iter != packet_buffer_pool_index_.end());
PacketBuffer* p = iter->second;
ASSERT_TRUE(p->in_use);
p->in_use = false;
packet_buffer_free_list_.push_back(p);
}
bool WriteServerVersionNegotiationProbeResponse(
char* packet_bytes,
size_t* packet_length_out,
const char* source_connection_id_bytes,
uint8_t source_connection_id_length) {
if (packet_bytes == nullptr) {
QUIC_BUG(quic_bug_10256_1) << "Invalid packet_bytes";
return false;
}
if (packet_length_out == nullptr) {
QUIC_BUG(quic_bug_10256_2) << "Invalid packet_length_out";
return false;
}
QuicConnectionId source_connection_id(source_connection_id_bytes,
source_connection_id_length);
std::unique_ptr<QuicEncryptedPacket> encrypted_packet =
QuicFramer::BuildVersionNegotiationPacket(
source_connection_id, EmptyQuicConnectionId(),
/*ietf_quic=*/true, /*use_length_prefix=*/true,
ParsedQuicVersionVector{});
if (!encrypted_packet) {
QUIC_BUG(quic_bug_10256_3) << "Failed to create version negotiation packet";
return false;
}
if (*packet_length_out < encrypted_packet->length()) {
QUIC_BUG(quic_bug_10256_4)
<< "Invalid *packet_length_out " << *packet_length_out << " < "
<< encrypted_packet->length();
return false;
}
*packet_length_out = encrypted_packet->length();
memcpy(packet_bytes, encrypted_packet->data(), *packet_length_out);
return true;
}
bool ParseClientVersionNegotiationProbePacket(
const char* packet_bytes,
size_t packet_length,
char* destination_connection_id_bytes,
uint8_t* destination_connection_id_length_out) {
if (packet_bytes == nullptr) {
QUIC_BUG(quic_bug_10256_5) << "Invalid packet_bytes";
return false;
}
if (packet_length < kMinPacketSizeForVersionNegotiation ||
packet_length > 65535) {
QUIC_BUG(quic_bug_10256_6) << "Invalid packet_length";
return false;
}
if (destination_connection_id_bytes == nullptr) {
QUIC_BUG(quic_bug_10256_7) << "Invalid destination_connection_id_bytes";
return false;
}
if (destination_connection_id_length_out == nullptr) {
QUIC_BUG(quic_bug_10256_8)
<< "Invalid destination_connection_id_length_out";
return false;
}
QuicEncryptedPacket encrypted_packet(packet_bytes, packet_length);
PacketHeaderFormat format;
QuicLongHeaderType long_packet_type;
bool version_present, has_length_prefix;
QuicVersionLabel version_label;
ParsedQuicVersion parsed_version = ParsedQuicVersion::Unsupported();
QuicConnectionId destination_connection_id, source_connection_id;
absl::optional<absl::string_view> retry_token;
std::string detailed_error;
QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher(
encrypted_packet,
/*expected_destination_connection_id_length=*/0, &format,
&long_packet_type, &version_present, &has_length_prefix, &version_label,
&parsed_version, &destination_connection_id, &source_connection_id,
&retry_token, &detailed_error);
if (error != QUIC_NO_ERROR) {
QUIC_BUG(quic_bug_10256_9) << "Failed to parse packet: " << detailed_error;
return false;
}
if (!version_present) {
QUIC_BUG(quic_bug_10256_10) << "Packet is not a long header";
return false;
}
if (*destination_connection_id_length_out <
destination_connection_id.length()) {
QUIC_BUG(quic_bug_10256_11)
<< "destination_connection_id_length_out too small";
return false;
}
*destination_connection_id_length_out = destination_connection_id.length();
memcpy(destination_connection_id_bytes, destination_connection_id.data(),
*destination_connection_id_length_out);
return true;
}
} // namespace test
} // namespace quic