Allow caller of QuicFramer::BuildIetfStatelessResetPacket to provide a random bytes generator.
PiperOrigin-RevId: 473306804
diff --git a/quiche/quic/core/quic_framer.cc b/quiche/quic/core/quic_framer.cc
index 99d9daa..9f81d06 100644
--- a/quiche/quic/core/quic_framer.cc
+++ b/quiche/quic/core/quic_framer.cc
@@ -1297,8 +1297,17 @@
// static
std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfStatelessResetPacket(
- QuicConnectionId /*connection_id*/, size_t received_packet_length,
+ QuicConnectionId connection_id, size_t received_packet_length,
StatelessResetToken stateless_reset_token) {
+ return BuildIetfStatelessResetPacket(connection_id, received_packet_length,
+ stateless_reset_token,
+ QuicRandom::GetInstance());
+}
+
+// static
+std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfStatelessResetPacket(
+ QuicConnectionId /*connection_id*/, size_t received_packet_length,
+ StatelessResetToken stateless_reset_token, QuicRandom* random) {
QUIC_DVLOG(1) << "Building IETF stateless reset packet.";
if (received_packet_length <= GetMinStatelessResetPacketLength()) {
QUICHE_DLOG(ERROR)
@@ -1318,10 +1327,10 @@
// from comparing the entire packet to a known value. Therefore it has no
// cryptographic use, and does not need a secure cryptographic pseudo-random
// number generator. It's therefore safe to use WriteInsecureRandomBytes.
- if (!writer.WriteInsecureRandomBytes(QuicRandom::GetInstance(),
- len - kStatelessResetTokenLength)) {
+ const size_t random_bytes_size = len - kStatelessResetTokenLength;
+ if (!writer.WriteInsecureRandomBytes(random, random_bytes_size)) {
QUIC_BUG(362045737_2) << "Failed to append random bytes of length: "
- << len - kStatelessResetTokenLength;
+ << random_bytes_size;
return nullptr;
}
// Change first 2 fixed bits to 01.
diff --git a/quiche/quic/core/quic_framer.h b/quiche/quic/core/quic_framer.h
index fbf9fdb..694e741 100644
--- a/quiche/quic/core/quic_framer.h
+++ b/quiche/quic/core/quic_framer.h
@@ -476,6 +476,13 @@
QuicConnectionId connection_id, size_t received_packet_length,
StatelessResetToken stateless_reset_token);
+ // Returns a new IETF stateless reset packet with random bytes generated from
+ // |random|->InsecureRandBytes(). NOTE: the first two bits of the random bytes
+ // will be modified to 01b to make it look like a short header packet.
+ static std::unique_ptr<QuicEncryptedPacket> BuildIetfStatelessResetPacket(
+ QuicConnectionId connection_id, size_t received_packet_length,
+ StatelessResetToken stateless_reset_token, QuicRandom* random);
+
// Returns a new version negotiation packet.
static std::unique_ptr<QuicEncryptedPacket> BuildVersionNegotiationPacket(
QuicConnectionId server_connection_id,
diff --git a/quiche/quic/core/quic_framer_test.cc b/quiche/quic/core/quic_framer_test.cc
index 8d1bc41..f4fa8a8 100644
--- a/quiche/quic/core/quic_framer_test.cc
+++ b/quiche/quic/core/quic_framer_test.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <cstdint>
+#include <cstring>
#include <map>
#include <memory>
#include <string>
@@ -10373,6 +10374,43 @@
data3->length());
}
+TEST_P(QuicFramerTest, BuildIetfStatelessResetPacketCallerProvidedRandomBytes) {
+ // clang-format off
+ unsigned char packet[] = {
+ // 1st byte 01XX XXXX
+ 0x7c,
+ // Random bytes
+ 0x7c, 0x7c, 0x7c, 0x7c,
+ // stateless reset token
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f
+ };
+ // clang-format on
+
+ // Build the minimal stateless reset packet with caller-provided random bytes.
+ MockRandom random;
+ auto generate_random_bytes = [](void* data, size_t len) {
+ std::string bytes(len, 0x7c);
+ memcpy(data, bytes.data(), bytes.size());
+ };
+ EXPECT_CALL(random, InsecureRandBytes(_, _))
+ .WillOnce(testing::Invoke(generate_random_bytes));
+ std::unique_ptr<QuicEncryptedPacket> data(
+ framer_.BuildIetfStatelessResetPacket(
+ FramerTestConnectionId(),
+ QuicFramer::GetMinStatelessResetPacketLength() + 1,
+ kTestStatelessResetToken, &random));
+ ASSERT_TRUE(data);
+ EXPECT_EQ(QuicFramer::GetMinStatelessResetPacketLength(), data->length());
+ // Verify the first 2 bits are 01.
+ EXPECT_FALSE(data->data()[0] & FLAGS_LONG_HEADER);
+ EXPECT_TRUE(data->data()[0] & FLAGS_FIXED_BIT);
+ // Verify the entire packet.
+ quiche::test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(), AsChars(packet),
+ ABSL_ARRAYSIZE(packet));
+}
+
TEST_P(QuicFramerTest, EncryptPacket) {
QuicPacketNumber packet_number = kPacketNumber;
// clang-format off
diff --git a/quiche/quic/test_tools/mock_random.cc b/quiche/quic/test_tools/mock_random.cc
index 2bea7c6..2c45e65 100644
--- a/quiche/quic/test_tools/mock_random.cc
+++ b/quiche/quic/test_tools/mock_random.cc
@@ -9,21 +9,33 @@
namespace quic {
namespace test {
-MockRandom::MockRandom() : base_(0xDEADBEEF), increment_(0) {}
+using testing::_;
+using testing::Invoke;
-MockRandom::MockRandom(uint32_t base) : base_(base), increment_(0) {}
+MockRandom::MockRandom() : MockRandom(0xDEADBEEF) {}
-void MockRandom::RandBytes(void* data, size_t len) {
+MockRandom::MockRandom(uint32_t base) : base_(base), increment_(0) {
+ ON_CALL(*this, RandBytes(_, _))
+ .WillByDefault(Invoke(this, &MockRandom::DefaultRandBytes));
+ ON_CALL(*this, RandUint64())
+ .WillByDefault(Invoke(this, &MockRandom::DefaultRandUint64));
+ ON_CALL(*this, InsecureRandBytes(_, _))
+ .WillByDefault(Invoke(this, &MockRandom::DefaultInsecureRandBytes));
+ ON_CALL(*this, InsecureRandUint64())
+ .WillByDefault(Invoke(this, &MockRandom::DefaultInsecureRandUint64));
+}
+
+void MockRandom::DefaultRandBytes(void* data, size_t len) {
memset(data, increment_ + static_cast<uint8_t>('r'), len);
}
-uint64_t MockRandom::RandUint64() { return base_ + increment_; }
+uint64_t MockRandom::DefaultRandUint64() { return base_ + increment_; }
-void MockRandom::InsecureRandBytes(void* data, size_t len) {
- RandBytes(data, len);
+void MockRandom::DefaultInsecureRandBytes(void* data, size_t len) {
+ DefaultRandBytes(data, len);
}
-uint64_t MockRandom::InsecureRandUint64() { return RandUint64(); }
+uint64_t MockRandom::DefaultInsecureRandUint64() { return DefaultRandUint64(); }
void MockRandom::ChangeValue() { increment_++; }
diff --git a/quiche/quic/test_tools/mock_random.h b/quiche/quic/test_tools/mock_random.h
index 03c1f00..0a4918d 100644
--- a/quiche/quic/test_tools/mock_random.h
+++ b/quiche/quic/test_tools/mock_random.h
@@ -6,6 +6,7 @@
#define QUICHE_QUIC_TEST_TOOLS_MOCK_RANDOM_H_
#include "quiche/quic/core/crypto/quic_random.h"
+#include "quiche/quic/platform/api/quic_test.h"
namespace quic {
namespace test {
@@ -18,22 +19,31 @@
MockRandom(const MockRandom&) = delete;
MockRandom& operator=(const MockRandom&) = delete;
- // QuicRandom:
+ MOCK_METHOD(void, RandBytes, (void* data, size_t len), (override));
+ MOCK_METHOD(uint64_t, RandUint64, (), (override));
+ MOCK_METHOD(void, InsecureRandBytes, (void* data, size_t len), (override));
+ MOCK_METHOD(uint64_t, InsecureRandUint64, (), (override));
+
+ // Default QuicRandom implementations. They are used if the caller does not
+ // setup the MockRandom via EXPECT_CALLs.
+
// Fills the |data| buffer with a repeating byte, initially 'r'.
- void RandBytes(void* data, size_t len) override;
+ void DefaultRandBytes(void* data, size_t len);
// Returns base + the current increment.
- uint64_t RandUint64() override;
+ uint64_t DefaultRandUint64();
// InsecureRandBytes behaves equivalently to RandBytes.
- void InsecureRandBytes(void* data, size_t len) override;
+ void DefaultInsecureRandBytes(void* data, size_t len);
// InsecureRandUint64 behaves equivalently to RandUint64.
- uint64_t InsecureRandUint64() override;
+ uint64_t DefaultInsecureRandUint64();
// ChangeValue increments |increment_|. This causes the value returned by
// |RandUint64| and the byte that |RandBytes| fills with, to change.
+ // Used by the Default implementations.
void ChangeValue();
// Sets the base to |base| and resets increment to zero.
+ // Used by the Default implementations.
void ResetBase(uint32_t base);
private: