wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 1 | // Copyright (c) 2019 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include <fuzzer/FuzzedDataProvider.h> |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 6 | #include <algorithm> |
rch | 3bc4bdd | 2019-11-14 15:08:11 -0800 | [diff] [blame] | 7 | #include <cstdint> |
| 8 | #include <string> |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 9 | |
vasilvv | 035fe3d | 2020-10-20 08:38:37 -0700 | [diff] [blame] | 10 | #include "absl/base/macros.h" |
QUICHE team | 5be974e | 2020-12-29 18:35:24 -0500 | [diff] [blame] | 11 | #include "quic/core/crypto/null_decrypter.h" |
| 12 | #include "quic/core/crypto/null_encrypter.h" |
| 13 | #include "quic/core/quic_connection_id.h" |
| 14 | #include "quic/core/quic_constants.h" |
| 15 | #include "quic/core/quic_data_writer.h" |
| 16 | #include "quic/core/quic_framer.h" |
| 17 | #include "quic/core/quic_time.h" |
| 18 | #include "quic/core/quic_types.h" |
| 19 | #include "quic/core/quic_versions.h" |
| 20 | #include "quic/test_tools/quic_framer_peer.h" |
| 21 | #include "quic/test_tools/quic_test_utils.h" |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 22 | |
| 23 | using quic::DiversificationNonce; |
| 24 | using quic::EncryptionLevel; |
| 25 | using quic::FirstSendingPacketNumber; |
| 26 | using quic::GetPacketHeaderSize; |
| 27 | using quic::kEthernetMTU; |
| 28 | using quic::kQuicDefaultConnectionIdLength; |
| 29 | using quic::NullDecrypter; |
| 30 | using quic::NullEncrypter; |
| 31 | using quic::PacketHeaderFormat; |
| 32 | using quic::ParsedQuicVersion; |
| 33 | using quic::ParsedQuicVersionVector; |
| 34 | using quic::Perspective; |
| 35 | using quic::QuicConnectionId; |
| 36 | using quic::QuicDataReader; |
| 37 | using quic::QuicDataWriter; |
| 38 | using quic::QuicEncryptedPacket; |
| 39 | using quic::QuicFramer; |
| 40 | using quic::QuicFramerVisitorInterface; |
| 41 | using quic::QuicLongHeaderType; |
| 42 | using quic::QuicPacketHeader; |
| 43 | using quic::QuicPacketNumber; |
| 44 | using quic::QuicTime; |
| 45 | using quic::QuicTransportVersion; |
| 46 | using quic::test::NoOpFramerVisitor; |
| 47 | using quic::test::QuicFramerPeer; |
| 48 | |
| 49 | PacketHeaderFormat ConsumePacketHeaderFormat(FuzzedDataProvider* provider, |
| 50 | ParsedQuicVersion version) { |
dschinazi | cc7d40d | 2020-12-02 11:28:18 -0800 | [diff] [blame] | 51 | if (!version.HasIetfInvariantHeader()) { |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 52 | return quic::GOOGLE_QUIC_PACKET; |
| 53 | } |
| 54 | return provider->ConsumeBool() ? quic::IETF_QUIC_LONG_HEADER_PACKET |
| 55 | : quic::IETF_QUIC_SHORT_HEADER_PACKET; |
| 56 | } |
| 57 | |
| 58 | ParsedQuicVersion ConsumeParsedQuicVersion(FuzzedDataProvider* provider) { |
| 59 | // TODO(wub): Add support for v49+. |
wub | d77a45c | 2019-10-18 06:53:29 -0700 | [diff] [blame] | 60 | const QuicTransportVersion transport_versions[] = { |
| 61 | quic::QUIC_VERSION_43, |
| 62 | quic::QUIC_VERSION_46, |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 63 | }; |
| 64 | |
| 65 | return ParsedQuicVersion( |
| 66 | quic::PROTOCOL_QUIC_CRYPTO, |
wub | d77a45c | 2019-10-18 06:53:29 -0700 | [diff] [blame] | 67 | transport_versions[provider->ConsumeIntegralInRange<uint8_t>( |
vasilvv | 035fe3d | 2020-10-20 08:38:37 -0700 | [diff] [blame] | 68 | 0, ABSL_ARRAYSIZE(transport_versions) - 1)]); |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | // QuicSelfContainedPacketHeader is a QuicPacketHeader with built-in stroage for |
| 72 | // diversification nonce. |
| 73 | struct QuicSelfContainedPacketHeader : public QuicPacketHeader { |
| 74 | DiversificationNonce nonce_storage; |
| 75 | }; |
| 76 | |
| 77 | // Construct a random data packet header that 1) can be successfully serialized |
| 78 | // at sender, and 2) the serialzied buffer can pass the receiver framer's |
| 79 | // ProcessPublicHeader and DecryptPayload functions. |
| 80 | QuicSelfContainedPacketHeader ConsumeQuicPacketHeader( |
| 81 | FuzzedDataProvider* provider, |
| 82 | Perspective receiver_perspective) { |
| 83 | QuicSelfContainedPacketHeader header; |
| 84 | |
| 85 | header.version = ConsumeParsedQuicVersion(provider); |
| 86 | |
| 87 | header.form = ConsumePacketHeaderFormat(provider, header.version); |
| 88 | |
rch | 3bc4bdd | 2019-11-14 15:08:11 -0800 | [diff] [blame] | 89 | const std::string cid_bytes = |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 90 | provider->ConsumeBytesAsString(kQuicDefaultConnectionIdLength); |
| 91 | if (receiver_perspective == Perspective::IS_SERVER) { |
| 92 | header.destination_connection_id = |
| 93 | QuicConnectionId(cid_bytes.c_str(), cid_bytes.size()); |
| 94 | header.destination_connection_id_included = quic::CONNECTION_ID_PRESENT; |
| 95 | header.source_connection_id_included = quic::CONNECTION_ID_ABSENT; |
| 96 | } else { |
| 97 | header.source_connection_id = |
| 98 | QuicConnectionId(cid_bytes.c_str(), cid_bytes.size()); |
| 99 | header.source_connection_id_included = quic::CONNECTION_ID_PRESENT; |
| 100 | header.destination_connection_id_included = quic::CONNECTION_ID_ABSENT; |
| 101 | } |
| 102 | |
| 103 | header.version_flag = receiver_perspective == Perspective::IS_SERVER; |
| 104 | header.reset_flag = false; |
| 105 | |
| 106 | header.packet_number = |
| 107 | QuicPacketNumber(provider->ConsumeIntegral<uint32_t>()); |
| 108 | if (header.packet_number < FirstSendingPacketNumber()) { |
| 109 | header.packet_number = FirstSendingPacketNumber(); |
| 110 | } |
| 111 | header.packet_number_length = quic::PACKET_4BYTE_PACKET_NUMBER; |
| 112 | |
| 113 | header.remaining_packet_length = 0; |
| 114 | |
| 115 | if (header.form != quic::GOOGLE_QUIC_PACKET && header.version_flag) { |
| 116 | header.long_packet_type = static_cast<QuicLongHeaderType>( |
| 117 | provider->ConsumeIntegralInRange<uint8_t>( |
| 118 | // INITIAL, ZERO_RTT_PROTECTED, or HANDSHAKE. |
| 119 | static_cast<uint8_t>(quic::INITIAL), |
| 120 | static_cast<uint8_t>(quic::HANDSHAKE))); |
| 121 | } else { |
| 122 | header.long_packet_type = quic::INVALID_PACKET_TYPE; |
| 123 | } |
| 124 | |
| 125 | if (header.form == quic::IETF_QUIC_LONG_HEADER_PACKET && |
| 126 | header.long_packet_type == quic::ZERO_RTT_PROTECTED && |
| 127 | receiver_perspective == Perspective::IS_CLIENT && |
| 128 | header.version.handshake_protocol == quic::PROTOCOL_QUIC_CRYPTO) { |
| 129 | for (size_t i = 0; i < header.nonce_storage.size(); ++i) { |
| 130 | header.nonce_storage[i] = provider->ConsumeIntegral<char>(); |
| 131 | } |
| 132 | header.nonce = &header.nonce_storage; |
| 133 | } else { |
| 134 | header.nonce = nullptr; |
| 135 | } |
| 136 | |
| 137 | return header; |
| 138 | } |
| 139 | |
| 140 | void SetupFramer(QuicFramer* framer, QuicFramerVisitorInterface* visitor) { |
| 141 | framer->set_visitor(visitor); |
| 142 | for (EncryptionLevel level : |
| 143 | {quic::ENCRYPTION_INITIAL, quic::ENCRYPTION_HANDSHAKE, |
| 144 | quic::ENCRYPTION_ZERO_RTT, quic::ENCRYPTION_FORWARD_SECURE}) { |
| 145 | framer->SetEncrypter( |
| 146 | level, std::make_unique<NullEncrypter>(framer->perspective())); |
| 147 | if (framer->version().KnowsWhichDecrypterToUse()) { |
| 148 | framer->InstallDecrypter( |
| 149 | level, std::make_unique<NullDecrypter>(framer->perspective())); |
| 150 | } |
| 151 | } |
wub | 2b19fc6 | 2019-10-18 12:54:25 -0700 | [diff] [blame] | 152 | |
| 153 | if (!framer->version().KnowsWhichDecrypterToUse()) { |
| 154 | framer->SetDecrypter( |
| 155 | quic::ENCRYPTION_INITIAL, |
| 156 | std::make_unique<NullDecrypter>(framer->perspective())); |
| 157 | } |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | class FuzzingFramerVisitor : public NoOpFramerVisitor { |
| 161 | public: |
| 162 | // Called after a successful ProcessPublicHeader. |
| 163 | bool OnUnauthenticatedPublicHeader( |
| 164 | const QuicPacketHeader& /*header*/) override { |
| 165 | ++process_public_header_success_count_; |
| 166 | return true; |
| 167 | } |
| 168 | |
| 169 | // Called after a successful DecryptPayload. |
| 170 | bool OnPacketHeader(const QuicPacketHeader& /*header*/) override { |
| 171 | ++decrypted_packet_count_; |
| 172 | return true; |
| 173 | } |
| 174 | |
| 175 | uint64_t process_public_header_success_count_ = 0; |
| 176 | uint64_t decrypted_packet_count_ = 0; |
| 177 | }; |
| 178 | |
| 179 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| 180 | FuzzedDataProvider data_provider(data, size); |
| 181 | |
| 182 | const QuicTime creation_time = |
| 183 | QuicTime::Zero() + QuicTime::Delta::FromMicroseconds( |
| 184 | data_provider.ConsumeIntegral<int32_t>()); |
| 185 | Perspective receiver_perspective = data_provider.ConsumeBool() |
| 186 | ? Perspective::IS_CLIENT |
| 187 | : Perspective::IS_SERVER; |
| 188 | Perspective sender_perspective = |
| 189 | (receiver_perspective == Perspective::IS_CLIENT) ? Perspective::IS_SERVER |
| 190 | : Perspective::IS_CLIENT; |
| 191 | |
| 192 | QuicSelfContainedPacketHeader header = |
| 193 | ConsumeQuicPacketHeader(&data_provider, receiver_perspective); |
| 194 | |
| 195 | NoOpFramerVisitor sender_framer_visitor; |
| 196 | ParsedQuicVersionVector framer_versions = {header.version}; |
| 197 | QuicFramer sender_framer(framer_versions, creation_time, sender_perspective, |
| 198 | kQuicDefaultConnectionIdLength); |
| 199 | SetupFramer(&sender_framer, &sender_framer_visitor); |
| 200 | |
| 201 | FuzzingFramerVisitor receiver_framer_visitor; |
| 202 | QuicFramer receiver_framer(framer_versions, creation_time, |
| 203 | receiver_perspective, |
| 204 | kQuicDefaultConnectionIdLength); |
| 205 | SetupFramer(&receiver_framer, &receiver_framer_visitor); |
| 206 | if (receiver_perspective == Perspective::IS_CLIENT) { |
| 207 | QuicFramerPeer::SetLastSerializedServerConnectionId( |
| 208 | &receiver_framer, header.source_connection_id); |
| 209 | } else { |
| 210 | QuicFramerPeer::SetLastSerializedClientConnectionId( |
| 211 | &receiver_framer, header.source_connection_id); |
| 212 | } |
| 213 | |
| 214 | std::array<char, kEthernetMTU> packet_buffer; |
| 215 | while (data_provider.remaining_bytes() > 16) { |
| 216 | const size_t last_remaining_bytes = data_provider.remaining_bytes(); |
| 217 | |
| 218 | // Get a randomized packet size. |
| 219 | uint16_t max_payload_size = static_cast<uint16_t>( |
| 220 | std::min<size_t>(data_provider.remaining_bytes(), 1350u)); |
| 221 | uint16_t min_payload_size = std::min<uint16_t>(16u, max_payload_size); |
| 222 | uint16_t payload_size = data_provider.ConsumeIntegralInRange<uint16_t>( |
| 223 | min_payload_size, max_payload_size); |
| 224 | |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 225 | QUICHE_CHECK_NE(last_remaining_bytes, data_provider.remaining_bytes()) |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 226 | << "Check fail to avoid an infinite loop. ConsumeIntegralInRange(" |
| 227 | << min_payload_size << ", " << max_payload_size |
| 228 | << ") did not consume any bytes. remaining_bytes:" |
| 229 | << last_remaining_bytes; |
| 230 | |
| 231 | std::vector<char> payload_buffer = |
| 232 | data_provider.ConsumeBytes<char>(payload_size); |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 233 | QUICHE_CHECK_GE( |
| 234 | packet_buffer.size(), |
| 235 | GetPacketHeaderSize(sender_framer.transport_version(), header) + |
| 236 | payload_buffer.size()); |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 237 | |
| 238 | // Serialize the null-encrypted packet into |packet_buffer|. |
| 239 | QuicDataWriter writer(packet_buffer.size(), packet_buffer.data()); |
| 240 | size_t length_field_offset = 0; |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 241 | QUICHE_CHECK(sender_framer.AppendPacketHeader(header, &writer, |
| 242 | &length_field_offset)); |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 243 | |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 244 | QUICHE_CHECK( |
| 245 | writer.WriteBytes(payload_buffer.data(), payload_buffer.size())); |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 246 | |
| 247 | EncryptionLevel encryption_level = |
| 248 | quic::test::HeaderToEncryptionLevel(header); |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 249 | QUICHE_CHECK(sender_framer.WriteIetfLongHeaderLength( |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 250 | header, &writer, length_field_offset, encryption_level)); |
| 251 | |
| 252 | size_t encrypted_length = sender_framer.EncryptInPlace( |
| 253 | encryption_level, header.packet_number, |
| 254 | GetStartOfEncryptedData(sender_framer.transport_version(), header), |
| 255 | writer.length(), packet_buffer.size(), packet_buffer.data()); |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 256 | QUICHE_CHECK_NE(encrypted_length, 0u); |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 257 | |
| 258 | // Use receiver's framer to process the packet. Ensure both |
| 259 | // ProcessPublicHeader and DecryptPayload were called and succeeded. |
| 260 | QuicEncryptedPacket packet(packet_buffer.data(), encrypted_length); |
| 261 | QuicDataReader reader(packet.data(), packet.length()); |
| 262 | |
| 263 | const uint64_t process_public_header_success_count = |
| 264 | receiver_framer_visitor.process_public_header_success_count_; |
| 265 | const uint64_t decrypted_packet_count = |
| 266 | receiver_framer_visitor.decrypted_packet_count_; |
| 267 | |
| 268 | receiver_framer.ProcessPacket(packet); |
| 269 | |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 270 | QUICHE_DCHECK_EQ( |
| 271 | process_public_header_success_count + 1, |
| 272 | receiver_framer_visitor.process_public_header_success_count_) |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 273 | << "ProcessPublicHeader failed. error:" |
| 274 | << QuicErrorCodeToString(receiver_framer.error()) |
| 275 | << ", error_detail:" << receiver_framer.detailed_error() |
| 276 | << ". header:" << header; |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 277 | QUICHE_DCHECK_EQ(decrypted_packet_count + 1, |
| 278 | receiver_framer_visitor.decrypted_packet_count_) |
wub | f482d1a | 2019-10-15 06:27:25 -0700 | [diff] [blame] | 279 | << "Packet was not decrypted. error:" |
| 280 | << QuicErrorCodeToString(receiver_framer.error()) |
| 281 | << ", error_detail:" << receiver_framer.detailed_error() |
| 282 | << ". header:" << header; |
| 283 | } |
| 284 | return 0; |
| 285 | } |