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: