Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/test/common/quic/envoy_quic_h3_fuzz_helper.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <set>
4
5
#include "source/common/common/assert.h"
6
7
#include "test/common/quic/envoy_quic_h3_fuzz.pb.h"
8
9
#include "quiche/quic/core/crypto/null_decrypter.h"
10
#include "quiche/quic/core/crypto/null_encrypter.h"
11
#include "quiche/quic/core/quic_connection.h"
12
#include "quiche/quic/core/quic_versions.h"
13
14
namespace Envoy {
15
namespace Quic {
16
17
// This class serializes structured protobuf `HTTP/3` messages to bytes as they
18
// would be sent over the wire.
19
class H3Serializer {
20
public:
21
  static constexpr size_t kMaxPacketSize = 1024;
22
1
  H3Serializer(std::set<uint32_t>& streams) : open_unidirectional_streams_(streams){};
23
  // This method serializes an `HTTP/3` frame given by `h3frame` to `std::string`.
24
  // If `unidirectional` is true, `type` will give the type of unidirectional
25
  // stream to be opened. `id` identifies an `HTTP/3` frame and is used to track
26
  // the whether the stream is already in flight.
27
  std::string serialize(bool unidirectional, uint32_t type, uint32_t id,
28
                        const test::common::quic::H3Frame& h3frame);
29
30
private:
31
  std::set<uint32_t>& open_unidirectional_streams_;
32
};
33
34
// This class serializes structured protobuf `QUIC + HTTP/3` messages to bytes as they
35
// would be sent over the wire.
36
class QuicPacketizer {
37
public:
38
  static constexpr size_t kMaxPacketSize = 1460;
39
  using QuicPacketPtr = std::unique_ptr<quic::QuicEncryptedPacket>;
40
  QuicPacketizer(const quic::ParsedQuicVersion& quic_version,
41
                 quic::QuicConnectionHelperInterface* connection_helper);
42
  std::vector<QuicPacketPtr> serializePackets(const test::common::quic::QuicH3FuzzCase& input);
43
  void reset();
44
45
private:
46
  QuicPacketPtr serializePacket(const test::common::quic::QuicFrame& frame);
47
  QuicPacketPtr serializeJunkPacket(const std::string& data);
48
  QuicPacketPtr serialize(quic::QuicFrame frame);
49
  QuicPacketPtr serializeStreamFrame(const test::common::quic::QuicStreamFrame& frame);
50
  QuicPacketPtr serializeNewTokenFrame(const test::common::quic::QuicNewTokenFrame& frame);
51
  QuicPacketPtr serializeMessageFrame(const test::common::quic::QuicMessageFrame& frame);
52
  QuicPacketPtr serializeCryptoFrame(const test::common::quic::QuicCryptoFrame& frame);
53
  QuicPacketPtr serializeAckFrame(const test::common::quic::QuicAckFrame& frame);
54
  QuicPacketPtr
55
  serializeNewConnectionIdFrame(const test::common::quic::QuicNewConnectionIdFrame& frame);
56
57
  quic::ParsedQuicVersion quic_version_;
58
  quic::QuicConnectionHelperInterface* connection_helper_;
59
  quic::QuicPacketNumber packet_number_;
60
61
  quic::QuicConnectionId destination_connection_id_;
62
  quic::QuicFramer framer_;
63
64
  H3Serializer h3serializer_;
65
66
  // Unidirectional streams are started by sending a variable-length integer
67
  // indicating the stream type (RFC9114, Sec. 6.2). H3Serializer serializes the
68
  // stream type into the stream payload upon seeing the stream for the first
69
  // time. This set tracks opened unidirectional streams in this flight. So that
70
  // multiple stream frames on the same stream will not cause the stream type to
71
  // be serialized again.
72
  std::set<uint32_t> open_unidirectional_streams_;
73
};
74
75
// The following two classes handle the encryption and decryption in the fuzzer
76
// and just pass the plain or cipher text as is. The classes override
77
// the `EncryptPacket` method, because the `Null{En,De}crypter` calculates
78
// a hash of the data for each packet, which is unnecessary in fuzzing.
79
class FuzzEncrypter : public quic::NullEncrypter {
80
public:
81
77.0k
  explicit FuzzEncrypter(quic::Perspective perspective) : NullEncrypter(perspective){};
82
  bool EncryptPacket(uint64_t, absl::string_view, absl::string_view plaintext, char* output,
83
7.37k
                     size_t* output_length, size_t max_output_length) override {
84
7.37k
    ASSERT(plaintext.length() <= max_output_length);
85
7.37k
    memcpy(output, plaintext.data(), plaintext.length());
86
7.37k
    *output_length = plaintext.length();
87
7.37k
    return true;
88
7.37k
  };
89
60.7k
  size_t GetMaxPlaintextSize(size_t ciphertext_size) const override { return ciphertext_size; }
90
0
  size_t GetCiphertextSize(size_t plaintext_size) const override { return plaintext_size; }
91
};
92
93
class FuzzDecrypter : public quic::NullDecrypter {
94
public:
95
16.4k
  explicit FuzzDecrypter(quic::Perspective perspective) : NullDecrypter(perspective){};
96
  bool DecryptPacket(uint64_t, absl::string_view, absl::string_view ciphertext, char* output,
97
56.1k
                     size_t* output_length, size_t max_output_length) override {
98
56.1k
    ASSERT(ciphertext.length() <= max_output_length);
99
56.1k
    memcpy(output, ciphertext.data(), ciphertext.length());
100
56.1k
    *output_length = ciphertext.length();
101
56.1k
    return true;
102
56.1k
  };
103
};
104
105
} // namespace Quic
106
} // namespace Envoy