blob: 6c3f3c5ee555e760deaf64aace99c66b5926ca3b [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
6
dschinazi6cf4d2a2019-04-30 16:20:23 -07007#include <cstdint>
dschinazi52127d72019-04-17 15:12:38 -07008#include <cstring>
vasilvva2ef3012019-09-12 18:32:14 -07009#include <forward_list>
renjietang21128a22020-04-08 11:49:02 -070010#include <memory>
bnc463f2352019-10-10 04:49:34 -070011#include <utility>
dschinazi52127d72019-04-17 15:12:38 -070012
QUICHE teama6ef0a62019-03-07 20:34:33 -050013#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
renjietang21128a22020-04-08 11:49:02 -070014#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
dschinazi52127d72019-04-17 15:12:38 -070015#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
16#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
17#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
18#include "net/third_party/quiche/src/quic/core/quic_types.h"
dschinazi6c84c142019-07-31 09:11:49 -070019#include "net/third_party/quiche/src/quic/core/quic_utils.h"
dschinazi52127d72019-04-17 15:12:38 -070020#include "net/third_party/quiche/src/quic/core/quic_versions.h"
21#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
dschinazi7b8f0c72020-03-02 13:17:57 -080022#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
dmcardle904ef182019-12-13 08:34:33 -080023#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
24#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050025
26namespace quic {
27
dschinazi52127d72019-04-17 15:12:38 -070028// Values of the TransportParameterId enum as defined in the
29// "Transport Parameter Encoding" section of draft-ietf-quic-transport.
30// When parameters are encoded, one of these enum values is used to indicate
31// which parameter is encoded. The supported draft version is noted in
32// transport_parameters.h.
dschinazi7b8f0c72020-03-02 13:17:57 -080033enum TransportParameters::TransportParameterId : uint64_t {
dschinazi52127d72019-04-17 15:12:38 -070034 kOriginalConnectionId = 0,
35 kIdleTimeout = 1,
36 kStatelessResetToken = 2,
37 kMaxPacketSize = 3,
38 kInitialMaxData = 4,
39 kInitialMaxStreamDataBidiLocal = 5,
40 kInitialMaxStreamDataBidiRemote = 6,
41 kInitialMaxStreamDataUni = 7,
42 kInitialMaxStreamsBidi = 8,
43 kInitialMaxStreamsUni = 9,
44 kAckDelayExponent = 0xa,
45 kMaxAckDelay = 0xb,
46 kDisableMigration = 0xc,
47 kPreferredAddress = 0xd,
dschinazie9db63c2019-07-17 16:19:42 -070048 kActiveConnectionIdLimit = 0xe,
QUICHE teama6ef0a62019-03-07 20:34:33 -050049
dschinazicd86dd12019-11-14 10:11:13 -080050 kMaxDatagramFrameSize = 0x20,
51
dschinazi52127d72019-04-17 15:12:38 -070052 kGoogleQuicParam = 18257, // Used for non-standard Google-specific params.
dschinazi6cf4d2a2019-04-30 16:20:23 -070053 kGoogleQuicVersion =
54 18258, // Used to transmit version and supported_versions.
QUICHE teama6ef0a62019-03-07 20:34:33 -050055};
56
dschinazi52127d72019-04-17 15:12:38 -070057namespace {
QUICHE teama6ef0a62019-03-07 20:34:33 -050058
59// The following constants define minimum and maximum allowed values for some of
dschinazi52127d72019-04-17 15:12:38 -070060// the parameters. These come from the "Transport Parameter Definitions"
61// section of draft-ietf-quic-transport.
62const uint64_t kMinMaxPacketSizeTransportParam = 1200;
dschinazi52127d72019-04-17 15:12:38 -070063const uint64_t kMaxAckDelayExponentTransportParam = 20;
64const uint64_t kDefaultAckDelayExponentTransportParam = 3;
65const uint64_t kMaxMaxAckDelayTransportParam = 16383;
66const uint64_t kDefaultMaxAckDelayTransportParam = 25;
67const size_t kStatelessResetTokenLength = 16;
QUICHE teama6ef0a62019-03-07 20:34:33 -050068
dschinazi52127d72019-04-17 15:12:38 -070069std::string TransportParameterIdToString(
70 TransportParameters::TransportParameterId param_id) {
71 switch (param_id) {
danzh9424add2019-06-06 14:04:36 -070072 case TransportParameters::kOriginalConnectionId:
dschinazi52127d72019-04-17 15:12:38 -070073 return "original_connection_id";
danzh9424add2019-06-06 14:04:36 -070074 case TransportParameters::kIdleTimeout:
dschinazi52127d72019-04-17 15:12:38 -070075 return "idle_timeout";
danzh9424add2019-06-06 14:04:36 -070076 case TransportParameters::kStatelessResetToken:
dschinazi52127d72019-04-17 15:12:38 -070077 return "stateless_reset_token";
danzh9424add2019-06-06 14:04:36 -070078 case TransportParameters::kMaxPacketSize:
dschinazi52127d72019-04-17 15:12:38 -070079 return "max_packet_size";
danzh9424add2019-06-06 14:04:36 -070080 case TransportParameters::kInitialMaxData:
dschinazi52127d72019-04-17 15:12:38 -070081 return "initial_max_data";
danzh9424add2019-06-06 14:04:36 -070082 case TransportParameters::kInitialMaxStreamDataBidiLocal:
dschinazi52127d72019-04-17 15:12:38 -070083 return "initial_max_stream_data_bidi_local";
danzh9424add2019-06-06 14:04:36 -070084 case TransportParameters::kInitialMaxStreamDataBidiRemote:
dschinazi52127d72019-04-17 15:12:38 -070085 return "initial_max_stream_data_bidi_remote";
danzh9424add2019-06-06 14:04:36 -070086 case TransportParameters::kInitialMaxStreamDataUni:
dschinazi52127d72019-04-17 15:12:38 -070087 return "initial_max_stream_data_uni";
danzh9424add2019-06-06 14:04:36 -070088 case TransportParameters::kInitialMaxStreamsBidi:
dschinazi52127d72019-04-17 15:12:38 -070089 return "initial_max_streams_bidi";
danzh9424add2019-06-06 14:04:36 -070090 case TransportParameters::kInitialMaxStreamsUni:
dschinazi52127d72019-04-17 15:12:38 -070091 return "initial_max_streams_uni";
danzh9424add2019-06-06 14:04:36 -070092 case TransportParameters::kAckDelayExponent:
dschinazi52127d72019-04-17 15:12:38 -070093 return "ack_delay_exponent";
danzh9424add2019-06-06 14:04:36 -070094 case TransportParameters::kMaxAckDelay:
dschinazi52127d72019-04-17 15:12:38 -070095 return "max_ack_delay";
danzh9424add2019-06-06 14:04:36 -070096 case TransportParameters::kDisableMigration:
dschinazi52127d72019-04-17 15:12:38 -070097 return "disable_migration";
danzh9424add2019-06-06 14:04:36 -070098 case TransportParameters::kPreferredAddress:
dschinazi52127d72019-04-17 15:12:38 -070099 return "preferred_address";
dschinazie9db63c2019-07-17 16:19:42 -0700100 case TransportParameters::kActiveConnectionIdLimit:
101 return "active_connection_id_limit";
dschinazicd86dd12019-11-14 10:11:13 -0800102 case TransportParameters::kMaxDatagramFrameSize:
103 return "max_datagram_frame_size";
danzh9424add2019-06-06 14:04:36 -0700104 case TransportParameters::kGoogleQuicParam:
dschinazi52127d72019-04-17 15:12:38 -0700105 return "google";
danzh9424add2019-06-06 14:04:36 -0700106 case TransportParameters::kGoogleQuicVersion:
dschinazi6cf4d2a2019-04-30 16:20:23 -0700107 return "google-version";
dschinazi52127d72019-04-17 15:12:38 -0700108 }
dmcardle904ef182019-12-13 08:34:33 -0800109 return "Unknown(" + quiche::QuicheTextUtils::Uint64ToString(param_id) + ")";
dschinazi52127d72019-04-17 15:12:38 -0700110}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111
dschinazid829b402020-04-10 14:27:21 -0700112bool TransportParameterIdIsKnown(
113 TransportParameters::TransportParameterId param_id) {
114 switch (param_id) {
115 case TransportParameters::kOriginalConnectionId:
116 case TransportParameters::kIdleTimeout:
117 case TransportParameters::kStatelessResetToken:
118 case TransportParameters::kMaxPacketSize:
119 case TransportParameters::kInitialMaxData:
120 case TransportParameters::kInitialMaxStreamDataBidiLocal:
121 case TransportParameters::kInitialMaxStreamDataBidiRemote:
122 case TransportParameters::kInitialMaxStreamDataUni:
123 case TransportParameters::kInitialMaxStreamsBidi:
124 case TransportParameters::kInitialMaxStreamsUni:
125 case TransportParameters::kAckDelayExponent:
126 case TransportParameters::kMaxAckDelay:
127 case TransportParameters::kDisableMigration:
128 case TransportParameters::kPreferredAddress:
129 case TransportParameters::kActiveConnectionIdLimit:
130 case TransportParameters::kMaxDatagramFrameSize:
131 case TransportParameters::kGoogleQuicParam:
132 case TransportParameters::kGoogleQuicVersion:
133 return true;
134 }
135 return false;
136}
137
dschinazi7b8f0c72020-03-02 13:17:57 -0800138bool WriteTransportParameterId(
139 QuicDataWriter* writer,
140 TransportParameters::TransportParameterId param_id,
141 ParsedQuicVersion version) {
142 if (version.HasVarIntTransportParams()) {
143 if (!writer->WriteVarInt62(param_id)) {
144 QUIC_BUG << "Failed to write param_id for "
145 << TransportParameterIdToString(param_id);
146 return false;
147 }
148 } else {
dschinazi55bc2952020-03-11 14:17:32 -0700149 if (static_cast<uint64_t>(param_id) >
150 std::numeric_limits<uint16_t>::max()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800151 QUIC_BUG << "Cannot serialize transport parameter "
152 << TransportParameterIdToString(param_id) << " with version "
153 << version;
154 return false;
155 }
156 if (!writer->WriteUInt16(param_id)) {
157 QUIC_BUG << "Failed to write param_id16 for "
158 << TransportParameterIdToString(param_id);
159 return false;
160 }
161 }
162 return true;
163}
164
165bool WriteTransportParameterLength(QuicDataWriter* writer,
166 uint64_t length,
167 ParsedQuicVersion version) {
168 if (version.HasVarIntTransportParams()) {
169 return writer->WriteVarInt62(length);
170 }
171 if (length > std::numeric_limits<uint16_t>::max()) {
172 QUIC_BUG << "Cannot serialize transport parameter length " << length
173 << " with version " << version;
174 return false;
175 }
176 return writer->WriteUInt16(length);
177}
178
179bool WriteTransportParameterStringPiece(QuicDataWriter* writer,
180 quiche::QuicheStringPiece value,
181 ParsedQuicVersion version) {
182 if (version.HasVarIntTransportParams()) {
183 return writer->WriteStringPieceVarInt62(value);
184 }
185 return writer->WriteStringPiece16(value);
186}
187
188bool ReadTransportParameterId(
189 QuicDataReader* reader,
190 ParsedQuicVersion version,
191 TransportParameters::TransportParameterId* out_param_id) {
192 if (version.HasVarIntTransportParams()) {
193 uint64_t param_id64;
194 if (!reader->ReadVarInt62(&param_id64)) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800195 return false;
196 }
197 *out_param_id =
198 static_cast<TransportParameters::TransportParameterId>(param_id64);
199 } else {
200 uint16_t param_id16;
201 if (!reader->ReadUInt16(&param_id16)) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800202 return false;
203 }
204 *out_param_id =
205 static_cast<TransportParameters::TransportParameterId>(param_id16);
206 }
207 return true;
208}
209
210bool ReadTransportParameterLengthAndValue(
211 QuicDataReader* reader,
212 ParsedQuicVersion version,
213 quiche::QuicheStringPiece* out_value) {
214 if (version.HasVarIntTransportParams()) {
215 return reader->ReadStringPieceVarInt62(out_value);
216 }
217 return reader->ReadStringPiece16(out_value);
218}
219
QUICHE teama6ef0a62019-03-07 20:34:33 -0500220} // namespace
221
dschinazi52127d72019-04-17 15:12:38 -0700222TransportParameters::IntegerParameter::IntegerParameter(
223 TransportParameters::TransportParameterId param_id,
224 uint64_t default_value,
225 uint64_t min_value,
226 uint64_t max_value)
227 : param_id_(param_id),
228 value_(default_value),
229 default_value_(default_value),
230 min_value_(min_value),
231 max_value_(max_value),
dschinazi7b8f0c72020-03-02 13:17:57 -0800232 has_been_read_(false) {
dschinazi52127d72019-04-17 15:12:38 -0700233 DCHECK_LE(min_value, default_value);
234 DCHECK_LE(default_value, max_value);
235 DCHECK_LE(max_value, kVarInt62MaxValue);
236}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500237
dschinazi52127d72019-04-17 15:12:38 -0700238TransportParameters::IntegerParameter::IntegerParameter(
239 TransportParameters::TransportParameterId param_id)
240 : TransportParameters::IntegerParameter::IntegerParameter(
241 param_id,
242 0,
243 0,
244 kVarInt62MaxValue) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500245
dschinazi52127d72019-04-17 15:12:38 -0700246void TransportParameters::IntegerParameter::set_value(uint64_t value) {
247 value_ = value;
248}
249
250uint64_t TransportParameters::IntegerParameter::value() const {
251 return value_;
252}
253
254bool TransportParameters::IntegerParameter::IsValid() const {
255 return min_value_ <= value_ && value_ <= max_value_;
256}
257
dschinazi7b8f0c72020-03-02 13:17:57 -0800258bool TransportParameters::IntegerParameter::Write(
259 QuicDataWriter* writer,
260 ParsedQuicVersion version) const {
dschinazi52127d72019-04-17 15:12:38 -0700261 DCHECK(IsValid());
262 if (value_ == default_value_) {
263 // Do not write if the value is default.
264 return true;
265 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800266 if (!WriteTransportParameterId(writer, param_id_, version)) {
267 QUIC_BUG << "Failed to write param_id for " << *this;
268 return false;
269 }
270 const QuicVariableLengthIntegerLength value_length =
271 QuicDataWriter::GetVarInt62Len(value_);
272 if (version.HasVarIntTransportParams()) {
273 if (!writer->WriteVarInt62(value_length)) {
274 QUIC_BUG << "Failed to write value_length for " << *this;
275 return false;
276 }
277 } else {
278 if (!writer->WriteUInt16(value_length)) {
279 QUIC_BUG << "Failed to write value_length16 for " << *this;
280 return false;
281 }
282 }
283 if (!writer->WriteVarInt62(value_, value_length)) {
284 QUIC_BUG << "Failed to write value for " << *this;
285 return false;
286 }
287 return true;
dschinazi52127d72019-04-17 15:12:38 -0700288}
289
dschinazi7b8f0c72020-03-02 13:17:57 -0800290bool TransportParameters::IntegerParameter::Read(QuicDataReader* reader,
291 std::string* error_details) {
292 if (has_been_read_) {
293 *error_details =
294 "Received a second " + TransportParameterIdToString(param_id_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500295 return false;
296 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800297 has_been_read_ = true;
298
299 if (!reader->ReadVarInt62(&value_)) {
300 *error_details =
301 "Failed to parse value for " + TransportParameterIdToString(param_id_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500302 return false;
303 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800304 if (!reader->IsDoneReading()) {
305 *error_details =
306 quiche::QuicheStrCat("Received unexpected ", reader->BytesRemaining(),
307 " bytes after parsing ", this->ToString(false));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500308 return false;
309 }
310 return true;
311}
312
dschinazi52127d72019-04-17 15:12:38 -0700313std::string TransportParameters::IntegerParameter::ToString(
314 bool for_use_in_list) const {
315 if (for_use_in_list && value_ == default_value_) {
316 return "";
317 }
318 std::string rv = for_use_in_list ? " " : "";
319 rv += TransportParameterIdToString(param_id_) + " ";
dmcardle904ef182019-12-13 08:34:33 -0800320 rv += quiche::QuicheTextUtils::Uint64ToString(value_);
dschinazi52127d72019-04-17 15:12:38 -0700321 if (!IsValid()) {
322 rv += " (Invalid)";
323 }
324 return rv;
325}
326
327std::ostream& operator<<(std::ostream& os,
328 const TransportParameters::IntegerParameter& param) {
329 os << param.ToString(/*for_use_in_list=*/false);
330 return os;
331}
332
333TransportParameters::PreferredAddress::PreferredAddress()
334 : ipv4_socket_address(QuicIpAddress::Any4(), 0),
335 ipv6_socket_address(QuicIpAddress::Any6(), 0),
336 connection_id(EmptyQuicConnectionId()),
337 stateless_reset_token(kStatelessResetTokenLength, 0) {}
338
339TransportParameters::PreferredAddress::~PreferredAddress() {}
340
renjietangdef6e342020-04-09 11:30:00 -0700341bool TransportParameters::PreferredAddress::operator==(
342 const PreferredAddress& rhs) const {
343 return ipv4_socket_address == rhs.ipv4_socket_address &&
344 ipv6_socket_address == rhs.ipv6_socket_address &&
345 connection_id == rhs.connection_id &&
346 stateless_reset_token == rhs.stateless_reset_token;
347}
348
dschinazid5361d82020-04-09 12:11:44 -0700349bool TransportParameters::PreferredAddress::operator!=(
350 const PreferredAddress& rhs) const {
351 return !(*this == rhs);
352}
353
dschinazi52127d72019-04-17 15:12:38 -0700354std::ostream& operator<<(
355 std::ostream& os,
356 const TransportParameters::PreferredAddress& preferred_address) {
357 os << preferred_address.ToString();
358 return os;
359}
360
361std::string TransportParameters::PreferredAddress::ToString() const {
362 return "[" + ipv4_socket_address.ToString() + " " +
363 ipv6_socket_address.ToString() + " connection_id " +
364 connection_id.ToString() + " stateless_reset_token " +
dmcardle904ef182019-12-13 08:34:33 -0800365 quiche::QuicheTextUtils::HexEncode(
dschinazi52127d72019-04-17 15:12:38 -0700366 reinterpret_cast<const char*>(stateless_reset_token.data()),
367 stateless_reset_token.size()) +
368 "]";
369}
370
371std::ostream& operator<<(std::ostream& os, const TransportParameters& params) {
372 os << params.ToString();
373 return os;
374}
375
376std::string TransportParameters::ToString() const {
377 std::string rv = "[";
378 if (perspective == Perspective::IS_SERVER) {
379 rv += "Server";
380 } else {
381 rv += "Client";
382 }
383 if (version != 0) {
384 rv += " version " + QuicVersionLabelToString(version);
385 }
386 if (!supported_versions.empty()) {
387 rv += " supported_versions " +
388 QuicVersionLabelVectorToString(supported_versions);
389 }
390 if (!original_connection_id.IsEmpty()) {
391 rv += " " + TransportParameterIdToString(kOriginalConnectionId) + " " +
392 original_connection_id.ToString();
393 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700394 rv += idle_timeout_milliseconds.ToString(/*for_use_in_list=*/true);
dschinazi52127d72019-04-17 15:12:38 -0700395 if (!stateless_reset_token.empty()) {
396 rv += " " + TransportParameterIdToString(kStatelessResetToken) + " " +
dmcardle904ef182019-12-13 08:34:33 -0800397 quiche::QuicheTextUtils::HexEncode(
dschinazi52127d72019-04-17 15:12:38 -0700398 reinterpret_cast<const char*>(stateless_reset_token.data()),
399 stateless_reset_token.size());
400 }
401 rv += max_packet_size.ToString(/*for_use_in_list=*/true);
402 rv += initial_max_data.ToString(/*for_use_in_list=*/true);
403 rv += initial_max_stream_data_bidi_local.ToString(/*for_use_in_list=*/true);
404 rv += initial_max_stream_data_bidi_remote.ToString(/*for_use_in_list=*/true);
405 rv += initial_max_stream_data_uni.ToString(/*for_use_in_list=*/true);
406 rv += initial_max_streams_bidi.ToString(/*for_use_in_list=*/true);
407 rv += initial_max_streams_uni.ToString(/*for_use_in_list=*/true);
408 rv += ack_delay_exponent.ToString(/*for_use_in_list=*/true);
409 rv += max_ack_delay.ToString(/*for_use_in_list=*/true);
410 if (disable_migration) {
411 rv += " " + TransportParameterIdToString(kDisableMigration);
412 }
413 if (preferred_address) {
414 rv += " " + TransportParameterIdToString(kPreferredAddress) + " " +
415 preferred_address->ToString();
416 }
dschinazie9db63c2019-07-17 16:19:42 -0700417 rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true);
dschinazicd86dd12019-11-14 10:11:13 -0800418 rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true);
dschinazi52127d72019-04-17 15:12:38 -0700419 if (google_quic_params) {
420 rv += " " + TransportParameterIdToString(kGoogleQuicParam);
421 }
422 rv += "]";
vasilvva2ef3012019-09-12 18:32:14 -0700423 for (const auto& kv : custom_parameters) {
dmcardle904ef182019-12-13 08:34:33 -0800424 rv += " 0x" + quiche::QuicheTextUtils::Hex(static_cast<uint32_t>(kv.first));
425 rv += "=" + quiche::QuicheTextUtils::HexEncode(kv.second);
vasilvva2ef3012019-09-12 18:32:14 -0700426 }
dschinazi52127d72019-04-17 15:12:38 -0700427 return rv;
428}
429
430TransportParameters::TransportParameters()
431 : version(0),
432 original_connection_id(EmptyQuicConnectionId()),
dschinazi6cf4d2a2019-04-30 16:20:23 -0700433 idle_timeout_milliseconds(kIdleTimeout),
dschinazi52127d72019-04-17 15:12:38 -0700434 max_packet_size(kMaxPacketSize,
435 kDefaultMaxPacketSizeTransportParam,
436 kMinMaxPacketSizeTransportParam,
437 kVarInt62MaxValue),
438 initial_max_data(kInitialMaxData),
439 initial_max_stream_data_bidi_local(kInitialMaxStreamDataBidiLocal),
440 initial_max_stream_data_bidi_remote(kInitialMaxStreamDataBidiRemote),
441 initial_max_stream_data_uni(kInitialMaxStreamDataUni),
442 initial_max_streams_bidi(kInitialMaxStreamsBidi),
443 initial_max_streams_uni(kInitialMaxStreamsUni),
444 ack_delay_exponent(kAckDelayExponent,
445 kDefaultAckDelayExponentTransportParam,
446 0,
447 kMaxAckDelayExponentTransportParam),
448 max_ack_delay(kMaxAckDelay,
449 kDefaultMaxAckDelayTransportParam,
450 0,
451 kMaxMaxAckDelayTransportParam),
dschinazie9db63c2019-07-17 16:19:42 -0700452 disable_migration(false),
dschinazicd86dd12019-11-14 10:11:13 -0800453 active_connection_id_limit(kActiveConnectionIdLimit),
454 max_datagram_frame_size(kMaxDatagramFrameSize)
dschinazi52127d72019-04-17 15:12:38 -0700455// Important note: any new transport parameters must be added
456// to TransportParameters::AreValid, SerializeTransportParameters and
renjietangdef6e342020-04-09 11:30:00 -0700457// ParseTransportParameters, TransportParameters's custom copy constructor, the
458// operator==, and TransportParametersTest.Comparator.
dschinazi52127d72019-04-17 15:12:38 -0700459{}
460
renjietang21128a22020-04-08 11:49:02 -0700461TransportParameters::TransportParameters(const TransportParameters& other)
462 : perspective(other.perspective),
463 version(other.version),
464 supported_versions(other.supported_versions),
465 original_connection_id(other.original_connection_id),
466 idle_timeout_milliseconds(other.idle_timeout_milliseconds),
467 stateless_reset_token(other.stateless_reset_token),
468 max_packet_size(other.max_packet_size),
469 initial_max_data(other.initial_max_data),
470 initial_max_stream_data_bidi_local(
471 other.initial_max_stream_data_bidi_local),
472 initial_max_stream_data_bidi_remote(
473 other.initial_max_stream_data_bidi_remote),
474 initial_max_stream_data_uni(other.initial_max_stream_data_uni),
475 initial_max_streams_bidi(other.initial_max_streams_bidi),
476 initial_max_streams_uni(other.initial_max_streams_uni),
477 ack_delay_exponent(other.ack_delay_exponent),
478 max_ack_delay(other.max_ack_delay),
479 disable_migration(other.disable_migration),
480 active_connection_id_limit(other.active_connection_id_limit),
481 max_datagram_frame_size(other.max_datagram_frame_size),
482 custom_parameters(other.custom_parameters) {
483 if (other.preferred_address) {
484 preferred_address = std::make_unique<TransportParameters::PreferredAddress>(
485 *other.preferred_address);
486 }
487 if (other.google_quic_params) {
488 google_quic_params =
489 std::make_unique<CryptoHandshakeMessage>(*other.google_quic_params);
490 }
491}
492
renjietangdef6e342020-04-09 11:30:00 -0700493bool TransportParameters::operator==(const TransportParameters& rhs) const {
494 if (!(perspective == rhs.perspective && version == rhs.version &&
495 supported_versions == rhs.supported_versions &&
496 original_connection_id == rhs.original_connection_id &&
497 idle_timeout_milliseconds.value() ==
498 rhs.idle_timeout_milliseconds.value() &&
499 stateless_reset_token == rhs.stateless_reset_token &&
500 max_packet_size.value() == rhs.max_packet_size.value() &&
501 initial_max_data.value() == rhs.initial_max_data.value() &&
502 initial_max_stream_data_bidi_local.value() ==
503 rhs.initial_max_stream_data_bidi_local.value() &&
504 initial_max_stream_data_bidi_remote.value() ==
505 rhs.initial_max_stream_data_bidi_remote.value() &&
506 initial_max_stream_data_uni.value() ==
507 rhs.initial_max_stream_data_uni.value() &&
508 initial_max_streams_bidi.value() ==
509 rhs.initial_max_streams_bidi.value() &&
510 initial_max_streams_uni.value() ==
511 rhs.initial_max_streams_uni.value() &&
512 ack_delay_exponent.value() == rhs.ack_delay_exponent.value() &&
513 max_ack_delay.value() == rhs.max_ack_delay.value() &&
514 disable_migration == rhs.disable_migration &&
515 active_connection_id_limit.value() ==
516 rhs.active_connection_id_limit.value() &&
517 max_datagram_frame_size.value() ==
518 rhs.max_datagram_frame_size.value() &&
519 custom_parameters == rhs.custom_parameters)) {
520 return false;
521 }
522
523 if ((!preferred_address && rhs.preferred_address) ||
524 (preferred_address && !rhs.preferred_address) ||
525 (!google_quic_params && rhs.google_quic_params) ||
526 (google_quic_params && !rhs.google_quic_params)) {
527 return false;
528 }
529 bool address = true;
530 if (preferred_address && rhs.preferred_address) {
531 address = (*preferred_address == *rhs.preferred_address);
532 }
533
534 bool google_quic = true;
535 if (google_quic_params && rhs.google_quic_params) {
536 google_quic = (*google_quic_params == *rhs.google_quic_params);
537 }
538 return address && google_quic;
539}
540
dschinazid5361d82020-04-09 12:11:44 -0700541bool TransportParameters::operator!=(const TransportParameters& rhs) const {
542 return !(*this == rhs);
543}
544
dschinazi7b8f0c72020-03-02 13:17:57 -0800545bool TransportParameters::AreValid(std::string* error_details) const {
dschinazi52127d72019-04-17 15:12:38 -0700546 DCHECK(perspective == Perspective::IS_CLIENT ||
547 perspective == Perspective::IS_SERVER);
548 if (perspective == Perspective::IS_CLIENT && !stateless_reset_token.empty()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800549 *error_details = "Client cannot send stateless reset token";
dschinazi52127d72019-04-17 15:12:38 -0700550 return false;
551 }
552 if (perspective == Perspective::IS_CLIENT &&
553 !original_connection_id.IsEmpty()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800554 *error_details = "Client cannot send original connection ID";
dschinazi52127d72019-04-17 15:12:38 -0700555 return false;
556 }
557 if (!stateless_reset_token.empty() &&
558 stateless_reset_token.size() != kStatelessResetTokenLength) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800559 *error_details = quiche::QuicheStrCat(
560 "Stateless reset token has bad length ", stateless_reset_token.size());
dschinazi52127d72019-04-17 15:12:38 -0700561 return false;
562 }
563 if (perspective == Perspective::IS_CLIENT && preferred_address) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800564 *error_details = "Client cannot send preferred address";
dschinazi52127d72019-04-17 15:12:38 -0700565 return false;
566 }
567 if (preferred_address && preferred_address->stateless_reset_token.size() !=
568 kStatelessResetTokenLength) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800569 *error_details = quiche::QuicheStrCat(
570 "Preferred address stateless reset token has bad length ",
571 preferred_address->stateless_reset_token.size());
dschinazi52127d72019-04-17 15:12:38 -0700572 return false;
573 }
574 if (preferred_address &&
575 (!preferred_address->ipv4_socket_address.host().IsIPv4() ||
576 !preferred_address->ipv6_socket_address.host().IsIPv6())) {
577 QUIC_BUG << "Preferred address family failure";
dschinazi7b8f0c72020-03-02 13:17:57 -0800578 *error_details = "Internal preferred address family failure";
dschinazi52127d72019-04-17 15:12:38 -0700579 return false;
580 }
dschinazid829b402020-04-10 14:27:21 -0700581 for (const auto& kv : custom_parameters) {
582 if (TransportParameterIdIsKnown(kv.first)) {
583 *error_details = quiche::QuicheStrCat(
584 "Using custom_parameters with known ID ",
585 TransportParameterIdToString(kv.first), " is not allowed");
586 return false;
587 }
588 }
dschinazicd86dd12019-11-14 10:11:13 -0800589 const bool ok =
590 idle_timeout_milliseconds.IsValid() && max_packet_size.IsValid() &&
591 initial_max_data.IsValid() &&
592 initial_max_stream_data_bidi_local.IsValid() &&
593 initial_max_stream_data_bidi_remote.IsValid() &&
594 initial_max_stream_data_uni.IsValid() &&
595 initial_max_streams_bidi.IsValid() && initial_max_streams_uni.IsValid() &&
596 ack_delay_exponent.IsValid() && max_ack_delay.IsValid() &&
597 active_connection_id_limit.IsValid() && max_datagram_frame_size.IsValid();
dschinazi52127d72019-04-17 15:12:38 -0700598 if (!ok) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800599 *error_details = "Invalid transport parameters " + this->ToString();
dschinazi52127d72019-04-17 15:12:38 -0700600 }
601 return ok;
602}
603
604TransportParameters::~TransportParameters() = default;
605
dschinazi7b8f0c72020-03-02 13:17:57 -0800606bool SerializeTransportParameters(ParsedQuicVersion version,
dschinazi6c84c142019-07-31 09:11:49 -0700607 const TransportParameters& in,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500608 std::vector<uint8_t>* out) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800609 std::string error_details;
610 if (!in.AreValid(&error_details)) {
611 QUIC_BUG << "Not serializing invalid transport parameters: "
612 << error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500613 return false;
614 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700615 if (in.version == 0 || (in.perspective == Perspective::IS_SERVER &&
616 in.supported_versions.empty())) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800617 QUIC_BUG << "Refusing to serialize without versions";
dschinazi6cf4d2a2019-04-30 16:20:23 -0700618 return false;
619 }
620
dschinazi52127d72019-04-17 15:12:38 -0700621 // Empirically transport parameters generally fit within 128 bytes.
dschinazi7b8f0c72020-03-02 13:17:57 -0800622 // For now we hope this will be enough.
623 // TODO(dschinazi) make this grow if needed.
624 static const size_t kMaxTransportParametersLength = 4096;
625 out->resize(kMaxTransportParametersLength);
626 QuicDataWriter writer(out->size(), reinterpret_cast<char*>(out->data()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500627
dschinazi7b8f0c72020-03-02 13:17:57 -0800628 if (!version.HasVarIntTransportParams()) {
629 // Versions that do not use variable integer transport parameters carry
630 // a 16-bit length of the remaining transport parameters. We write 0 here
631 // to reserve 16 bits, and we fill it in at the end of this function.
632 // TODO(b/150465921) add support for doing this in QuicDataWriter.
633 if (!writer.WriteUInt16(0)) {
634 QUIC_BUG << "Failed to write transport parameter fake length prefix for "
635 << in;
636 return false;
637 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500638 }
639
dschinazi52127d72019-04-17 15:12:38 -0700640 // original_connection_id
dschinazi52127d72019-04-17 15:12:38 -0700641 if (!in.original_connection_id.IsEmpty()) {
642 DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
dschinazi7b8f0c72020-03-02 13:17:57 -0800643 if (!WriteTransportParameterId(
644 &writer, TransportParameters::kOriginalConnectionId, version) ||
645 !WriteTransportParameterStringPiece(
646 &writer,
647 quiche::QuicheStringPiece(in.original_connection_id.data(),
648 in.original_connection_id.length()),
649 version)) {
dschinazi52127d72019-04-17 15:12:38 -0700650 QUIC_BUG << "Failed to write original_connection_id "
651 << in.original_connection_id << " for " << in;
652 return false;
653 }
654 }
655
dschinazi7b8f0c72020-03-02 13:17:57 -0800656 if (!in.idle_timeout_milliseconds.Write(&writer, version)) {
dschinazi52127d72019-04-17 15:12:38 -0700657 QUIC_BUG << "Failed to write idle_timeout for " << in;
658 return false;
659 }
660
661 // stateless_reset_token
QUICHE teama6ef0a62019-03-07 20:34:33 -0500662 if (!in.stateless_reset_token.empty()) {
dschinazi52127d72019-04-17 15:12:38 -0700663 DCHECK_EQ(kStatelessResetTokenLength, in.stateless_reset_token.size());
664 DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
dschinazi7b8f0c72020-03-02 13:17:57 -0800665 if (!WriteTransportParameterId(
666 &writer, TransportParameters::kStatelessResetToken, version) ||
667 !WriteTransportParameterStringPiece(
668 &writer,
669 quiche::QuicheStringPiece(
670 reinterpret_cast<const char*>(in.stateless_reset_token.data()),
671 in.stateless_reset_token.size()),
672 version)) {
dschinazi52127d72019-04-17 15:12:38 -0700673 QUIC_BUG << "Failed to write stateless_reset_token of length "
674 << in.stateless_reset_token.size() << " for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500675 return false;
676 }
677 }
678
dschinazi7b8f0c72020-03-02 13:17:57 -0800679 if (!in.max_packet_size.Write(&writer, version) ||
680 !in.initial_max_data.Write(&writer, version) ||
681 !in.initial_max_stream_data_bidi_local.Write(&writer, version) ||
682 !in.initial_max_stream_data_bidi_remote.Write(&writer, version) ||
683 !in.initial_max_stream_data_uni.Write(&writer, version) ||
684 !in.initial_max_streams_bidi.Write(&writer, version) ||
685 !in.initial_max_streams_uni.Write(&writer, version) ||
686 !in.ack_delay_exponent.Write(&writer, version) ||
687 !in.max_ack_delay.Write(&writer, version) ||
688 !in.active_connection_id_limit.Write(&writer, version) ||
689 !in.max_datagram_frame_size.Write(&writer, version)) {
dschinazi52127d72019-04-17 15:12:38 -0700690 QUIC_BUG << "Failed to write integers for " << in;
691 return false;
692 }
693
694 // disable_migration
695 if (in.disable_migration) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800696 if (!WriteTransportParameterId(
697 &writer, TransportParameters::kDisableMigration, version) ||
698 !WriteTransportParameterLength(&writer, /*length=*/0, version)) {
dschinazi52127d72019-04-17 15:12:38 -0700699 QUIC_BUG << "Failed to write disable_migration for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500700 return false;
701 }
702 }
dschinazi52127d72019-04-17 15:12:38 -0700703
704 // preferred_address
dschinazi52127d72019-04-17 15:12:38 -0700705 if (in.preferred_address) {
706 std::string v4_address_bytes =
707 in.preferred_address->ipv4_socket_address.host().ToPackedString();
708 std::string v6_address_bytes =
709 in.preferred_address->ipv6_socket_address.host().ToPackedString();
710 if (v4_address_bytes.length() != 4 || v6_address_bytes.length() != 16 ||
711 in.preferred_address->stateless_reset_token.size() !=
712 kStatelessResetTokenLength) {
713 QUIC_BUG << "Bad lengths " << *in.preferred_address;
714 return false;
715 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800716 const uint64_t preferred_address_length =
717 v4_address_bytes.length() + /* IPv4 port */ sizeof(uint16_t) +
718 v6_address_bytes.length() + /* IPv6 port */ sizeof(uint16_t) +
719 /* connection ID length byte */ sizeof(uint8_t) +
720 in.preferred_address->connection_id.length() +
721 in.preferred_address->stateless_reset_token.size();
722 if (!WriteTransportParameterId(
723 &writer, TransportParameters::kPreferredAddress, version) ||
724 !WriteTransportParameterLength(&writer, preferred_address_length,
725 version) ||
726 !writer.WriteStringPiece(v4_address_bytes) ||
727 !writer.WriteUInt16(in.preferred_address->ipv4_socket_address.port()) ||
728 !writer.WriteStringPiece(v6_address_bytes) ||
729 !writer.WriteUInt16(in.preferred_address->ipv6_socket_address.port()) ||
730 !writer.WriteUInt8(in.preferred_address->connection_id.length()) ||
731 !writer.WriteBytes(in.preferred_address->connection_id.data(),
732 in.preferred_address->connection_id.length()) ||
733 !writer.WriteBytes(
734 in.preferred_address->stateless_reset_token.data(),
735 in.preferred_address->stateless_reset_token.size())) {
dschinazi52127d72019-04-17 15:12:38 -0700736 QUIC_BUG << "Failed to write preferred_address for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500737 return false;
738 }
739 }
dschinazi52127d72019-04-17 15:12:38 -0700740
741 // Google-specific non-standard parameter.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500742 if (in.google_quic_params) {
743 const QuicData& serialized_google_quic_params =
744 in.google_quic_params->GetSerialized();
dschinazi7b8f0c72020-03-02 13:17:57 -0800745 if (!WriteTransportParameterId(
746 &writer, TransportParameters::kGoogleQuicParam, version) ||
747 !WriteTransportParameterStringPiece(
748 &writer, serialized_google_quic_params.AsStringPiece(), version)) {
dschinazi52127d72019-04-17 15:12:38 -0700749 QUIC_BUG << "Failed to write Google params of length "
750 << serialized_google_quic_params.length() << " for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500751 return false;
752 }
753 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700754
755 // Google-specific version extension.
dschinazi7b8f0c72020-03-02 13:17:57 -0800756 static_assert(sizeof(QuicVersionLabel) == sizeof(uint32_t), "bad length");
757 uint64_t google_version_length = sizeof(in.version);
758 if (in.perspective == Perspective::IS_SERVER) {
759 google_version_length +=
760 /* versions length */ sizeof(uint8_t) +
761 sizeof(QuicVersionLabel) * in.supported_versions.size();
762 }
763 if (!WriteTransportParameterId(
764 &writer, TransportParameters::kGoogleQuicVersion, version) ||
765 !WriteTransportParameterLength(&writer, google_version_length, version) ||
766 !writer.WriteUInt32(in.version)) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700767 QUIC_BUG << "Failed to write Google version extension for " << in;
768 return false;
769 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700770 if (in.perspective == Perspective::IS_SERVER) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800771 if (!writer.WriteUInt8(sizeof(QuicVersionLabel) *
772 in.supported_versions.size())) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700773 QUIC_BUG << "Failed to write versions length for " << in;
774 return false;
775 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800776 for (QuicVersionLabel version_label : in.supported_versions) {
777 if (!writer.WriteUInt32(version_label)) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700778 QUIC_BUG << "Failed to write supported version for " << in;
779 return false;
780 }
781 }
782 }
783
vasilvva2ef3012019-09-12 18:32:14 -0700784 for (const auto& kv : in.custom_parameters) {
dschinazid829b402020-04-10 14:27:21 -0700785 const TransportParameters::TransportParameterId param_id = kv.first;
786 if (param_id % 31 == 27) {
787 // See the "Reserved Transport Parameters" section of
788 // draft-ietf-quic-transport.
789 QUIC_BUG << "Serializing custom_parameters with GREASE ID " << param_id
790 << " is not allowed";
791 return false;
792 }
793 if (!WriteTransportParameterId(&writer, param_id, version) ||
dschinazi7b8f0c72020-03-02 13:17:57 -0800794 !WriteTransportParameterStringPiece(&writer, kv.second, version)) {
dschinazid829b402020-04-10 14:27:21 -0700795 QUIC_BUG << "Failed to write custom parameter " << param_id;
796 return false;
797 }
798 }
799
800 {
801 // Add a random GREASE transport parameter, as defined in the
802 // "Reserved Transport Parameters" section of draft-ietf-quic-transport.
803 // https://quicwg.org/base-drafts/draft-ietf-quic-transport.html
804 // This forces receivers to support unexpected input.
805 QuicRandom* random = QuicRandom::GetInstance();
806 uint64_t grease_id64 = random->RandUint64();
807 if (version.HasVarIntTransportParams()) {
808 // With these versions, identifiers are 62 bits long so we need to ensure
809 // that the output of the computation below fits in 62 bits.
810 grease_id64 %= ((1ULL << 62) - 31);
811 } else {
812 // Same with 16 bits.
813 grease_id64 %= ((1ULL << 16) - 31);
814 }
815 // Make sure grease_id % 31 == 27. Note that this is not uniformely
816 // distributed but is acceptable since no security depends on this
817 // randomness.
818 grease_id64 = (grease_id64 / 31) * 31 + 27;
819 DCHECK(version.HasVarIntTransportParams() ||
820 grease_id64 <= std::numeric_limits<uint16_t>::max())
821 << grease_id64 << " invalid for " << version;
822 TransportParameters::TransportParameterId grease_id =
823 static_cast<TransportParameters::TransportParameterId>(grease_id64);
ianswette71fb0b2020-04-13 11:18:52 -0700824 const size_t kMaxGreaseLength = 16;
825 const size_t grease_length = random->RandUint64() % kMaxGreaseLength;
826 DCHECK_GE(kMaxGreaseLength, grease_length);
827 char grease_contents[kMaxGreaseLength];
828 random->RandBytes(grease_contents, grease_length);
dschinazid829b402020-04-10 14:27:21 -0700829 if (!WriteTransportParameterId(&writer, grease_id, version) ||
renjietang897e7632020-04-14 12:27:13 -0700830 !WriteTransportParameterStringPiece(
831 &writer, quiche::QuicheStringPiece(grease_contents, grease_length),
832 version)) {
dschinazid829b402020-04-10 14:27:21 -0700833 QUIC_BUG << "Failed to write GREASE parameter "
834 << TransportParameterIdToString(grease_id);
vasilvva2ef3012019-09-12 18:32:14 -0700835 return false;
836 }
837 }
838
dschinazi7b8f0c72020-03-02 13:17:57 -0800839 if (!version.HasVarIntTransportParams()) {
840 // Fill in the length prefix at the start of the transport parameters.
841 if (writer.length() < sizeof(uint16_t) ||
842 writer.length() - sizeof(uint16_t) >
843 std::numeric_limits<uint16_t>::max()) {
844 QUIC_BUG << "Cannot write length " << writer.length() << " for " << in;
845 return false;
846 }
847 const uint16_t length_prefix = writer.length() - sizeof(uint16_t);
848 QuicDataWriter length_prefix_writer(out->size(),
849 reinterpret_cast<char*>(out->data()));
850 if (!length_prefix_writer.WriteUInt16(length_prefix)) {
851 QUIC_BUG << "Failed to write length prefix for " << in;
852 return false;
853 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500854 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800855
856 out->resize(writer.length());
857
858 QUIC_DLOG(INFO) << "Serialized " << in << " as " << writer.length()
dschinazi52127d72019-04-17 15:12:38 -0700859 << " bytes";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500860 return true;
861}
862
dschinazi6c84c142019-07-31 09:11:49 -0700863bool ParseTransportParameters(ParsedQuicVersion version,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500864 Perspective perspective,
dschinazi6c84c142019-07-31 09:11:49 -0700865 const uint8_t* in,
866 size_t in_len,
dschinazi7b8f0c72020-03-02 13:17:57 -0800867 TransportParameters* out,
868 std::string* error_details) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700869 out->perspective = perspective;
dschinazi7b8f0c72020-03-02 13:17:57 -0800870 QuicDataReader reader(reinterpret_cast<const char*>(in), in_len);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500871
dschinazi7b8f0c72020-03-02 13:17:57 -0800872 if (!version.HasVarIntTransportParams()) {
873 uint16_t full_length;
874 if (!reader.ReadUInt16(&full_length)) {
875 *error_details = "Failed to parse the transport parameter full length";
876 return false;
877 }
878 if (full_length != reader.BytesRemaining()) {
879 *error_details =
880 quiche::QuicheStrCat("Invalid transport parameter full length ",
881 full_length, " != ", reader.BytesRemaining());
882 return false;
883 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500884 }
dschinazi52127d72019-04-17 15:12:38 -0700885
dschinazi7b8f0c72020-03-02 13:17:57 -0800886 while (!reader.IsDoneReading()) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700887 TransportParameters::TransportParameterId param_id;
dschinazi7b8f0c72020-03-02 13:17:57 -0800888 if (!ReadTransportParameterId(&reader, version, &param_id)) {
889 *error_details = "Failed to parse transport parameter ID";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500890 return false;
891 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800892 quiche::QuicheStringPiece value;
893 if (!ReadTransportParameterLengthAndValue(&reader, version, &value)) {
894 *error_details =
895 "Failed to read length and value of transport parameter " +
896 TransportParameterIdToString(param_id);
dschinazi52127d72019-04-17 15:12:38 -0700897 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500898 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800899 QuicDataReader value_reader(value);
dschinazi52127d72019-04-17 15:12:38 -0700900 bool parse_success = true;
dschinazi6cf4d2a2019-04-30 16:20:23 -0700901 switch (param_id) {
dschinazi6c84c142019-07-31 09:11:49 -0700902 case TransportParameters::kOriginalConnectionId: {
dschinazi52127d72019-04-17 15:12:38 -0700903 if (!out->original_connection_id.IsEmpty()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800904 *error_details = "Received a second original connection ID";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500905 return false;
906 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800907 const size_t connection_id_length = value_reader.BytesRemaining();
dschinazi6c84c142019-07-31 09:11:49 -0700908 if (!QuicUtils::IsConnectionIdLengthValidForVersion(
909 connection_id_length, version.transport_version)) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800910 *error_details = quiche::QuicheStrCat(
911 "Received original connection ID of invalid length ",
912 connection_id_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500913 return false;
914 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800915 if (!value_reader.ReadConnectionId(&out->original_connection_id,
916 connection_id_length)) {
917 *error_details = "Failed to read original connection ID";
918 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500919 }
dschinazi6c84c142019-07-31 09:11:49 -0700920 } break;
danzh9424add2019-06-06 14:04:36 -0700921 case TransportParameters::kIdleTimeout:
dschinazi7b8f0c72020-03-02 13:17:57 -0800922 parse_success =
923 out->idle_timeout_milliseconds.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700924 break;
dschinazi7b8f0c72020-03-02 13:17:57 -0800925 case TransportParameters::kStatelessResetToken: {
dschinazi52127d72019-04-17 15:12:38 -0700926 if (!out->stateless_reset_token.empty()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800927 *error_details = "Received a second stateless reset token";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500928 return false;
929 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800930 quiche::QuicheStringPiece stateless_reset_token =
931 value_reader.ReadRemainingPayload();
932 if (stateless_reset_token.length() != kStatelessResetTokenLength) {
933 *error_details = quiche::QuicheStrCat(
934 "Received stateless reset token of invalid length ",
935 stateless_reset_token.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500936 return false;
937 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800938 out->stateless_reset_token.assign(
939 stateless_reset_token.data(),
940 stateless_reset_token.data() + stateless_reset_token.length());
941 } break;
danzh9424add2019-06-06 14:04:36 -0700942 case TransportParameters::kMaxPacketSize:
dschinazi7b8f0c72020-03-02 13:17:57 -0800943 parse_success = out->max_packet_size.Read(&value_reader, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500944 break;
danzh9424add2019-06-06 14:04:36 -0700945 case TransportParameters::kInitialMaxData:
dschinazi7b8f0c72020-03-02 13:17:57 -0800946 parse_success =
947 out->initial_max_data.Read(&value_reader, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500948 break;
danzh9424add2019-06-06 14:04:36 -0700949 case TransportParameters::kInitialMaxStreamDataBidiLocal:
dschinazi7b8f0c72020-03-02 13:17:57 -0800950 parse_success = out->initial_max_stream_data_bidi_local.Read(
951 &value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700952 break;
danzh9424add2019-06-06 14:04:36 -0700953 case TransportParameters::kInitialMaxStreamDataBidiRemote:
dschinazi7b8f0c72020-03-02 13:17:57 -0800954 parse_success = out->initial_max_stream_data_bidi_remote.Read(
955 &value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700956 break;
danzh9424add2019-06-06 14:04:36 -0700957 case TransportParameters::kInitialMaxStreamDataUni:
dschinazi7b8f0c72020-03-02 13:17:57 -0800958 parse_success =
959 out->initial_max_stream_data_uni.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700960 break;
danzh9424add2019-06-06 14:04:36 -0700961 case TransportParameters::kInitialMaxStreamsBidi:
dschinazi7b8f0c72020-03-02 13:17:57 -0800962 parse_success =
963 out->initial_max_streams_bidi.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700964 break;
danzh9424add2019-06-06 14:04:36 -0700965 case TransportParameters::kInitialMaxStreamsUni:
dschinazi7b8f0c72020-03-02 13:17:57 -0800966 parse_success =
967 out->initial_max_streams_uni.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700968 break;
danzh9424add2019-06-06 14:04:36 -0700969 case TransportParameters::kAckDelayExponent:
dschinazi7b8f0c72020-03-02 13:17:57 -0800970 parse_success =
971 out->ack_delay_exponent.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700972 break;
danzh9424add2019-06-06 14:04:36 -0700973 case TransportParameters::kMaxAckDelay:
dschinazi7b8f0c72020-03-02 13:17:57 -0800974 parse_success = out->max_ack_delay.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700975 break;
danzh9424add2019-06-06 14:04:36 -0700976 case TransportParameters::kDisableMigration:
dschinazi52127d72019-04-17 15:12:38 -0700977 if (out->disable_migration) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800978 *error_details = "Received a second disable migration";
dschinazi52127d72019-04-17 15:12:38 -0700979 return false;
980 }
981 out->disable_migration = true;
982 break;
danzh9424add2019-06-06 14:04:36 -0700983 case TransportParameters::kPreferredAddress: {
dschinazi7b8f0c72020-03-02 13:17:57 -0800984 TransportParameters::PreferredAddress preferred_address;
dschinazi52127d72019-04-17 15:12:38 -0700985 uint16_t ipv4_port, ipv6_port;
986 in_addr ipv4_address;
987 in6_addr ipv6_address;
dschinazi7b8f0c72020-03-02 13:17:57 -0800988 preferred_address.stateless_reset_token.resize(
989 kStatelessResetTokenLength);
990 if (!value_reader.ReadBytes(&ipv4_address, sizeof(ipv4_address)) ||
991 !value_reader.ReadUInt16(&ipv4_port) ||
992 !value_reader.ReadBytes(&ipv6_address, sizeof(ipv6_address)) ||
993 !value_reader.ReadUInt16(&ipv6_port) ||
994 !value_reader.ReadLengthPrefixedConnectionId(
995 &preferred_address.connection_id) ||
996 !value_reader.ReadBytes(&preferred_address.stateless_reset_token[0],
997 kStatelessResetTokenLength)) {
998 *error_details = "Failed to read preferred address";
dschinazi52127d72019-04-17 15:12:38 -0700999 return false;
1000 }
dschinazi52127d72019-04-17 15:12:38 -07001001 preferred_address.ipv4_socket_address =
1002 QuicSocketAddress(QuicIpAddress(ipv4_address), ipv4_port);
1003 preferred_address.ipv6_socket_address =
1004 QuicSocketAddress(QuicIpAddress(ipv6_address), ipv6_port);
1005 if (!preferred_address.ipv4_socket_address.host().IsIPv4() ||
1006 !preferred_address.ipv6_socket_address.host().IsIPv6()) {
dschinazi7b8f0c72020-03-02 13:17:57 -08001007 *error_details = "Received preferred addresses of bad families " +
1008 preferred_address.ToString();
dschinazi52127d72019-04-17 15:12:38 -07001009 return false;
1010 }
dschinazi7b8f0c72020-03-02 13:17:57 -08001011 if (!QuicUtils::IsConnectionIdValidForVersion(
1012 preferred_address.connection_id, version.transport_version)) {
1013 *error_details = "Received invalid preferred address connection ID " +
1014 preferred_address.ToString();
dschinazi52127d72019-04-17 15:12:38 -07001015 return false;
1016 }
dschinazi52127d72019-04-17 15:12:38 -07001017 out->preferred_address =
vasilvv0fc587f2019-09-06 13:33:08 -07001018 std::make_unique<TransportParameters::PreferredAddress>(
dschinazi52127d72019-04-17 15:12:38 -07001019 preferred_address);
1020 } break;
dschinazie9db63c2019-07-17 16:19:42 -07001021 case TransportParameters::kActiveConnectionIdLimit:
dschinazi7b8f0c72020-03-02 13:17:57 -08001022 parse_success =
1023 out->active_connection_id_limit.Read(&value_reader, error_details);
dschinazie9db63c2019-07-17 16:19:42 -07001024 break;
dschinazicd86dd12019-11-14 10:11:13 -08001025 case TransportParameters::kMaxDatagramFrameSize:
dschinazi7b8f0c72020-03-02 13:17:57 -08001026 parse_success =
1027 out->max_datagram_frame_size.Read(&value_reader, error_details);
dschinazicd86dd12019-11-14 10:11:13 -08001028 break;
danzh9424add2019-06-06 14:04:36 -07001029 case TransportParameters::kGoogleQuicParam: {
dschinazi52127d72019-04-17 15:12:38 -07001030 if (out->google_quic_params) {
dschinazi7b8f0c72020-03-02 13:17:57 -08001031 *error_details = "Received a second Google parameter";
dschinazi52127d72019-04-17 15:12:38 -07001032 return false;
1033 }
dschinazi7b8f0c72020-03-02 13:17:57 -08001034 out->google_quic_params =
1035 CryptoFramer::ParseMessage(value_reader.ReadRemainingPayload());
dschinazi6cf4d2a2019-04-30 16:20:23 -07001036 } break;
danzh9424add2019-06-06 14:04:36 -07001037 case TransportParameters::kGoogleQuicVersion: {
dschinazi7b8f0c72020-03-02 13:17:57 -08001038 if (!value_reader.ReadUInt32(&out->version)) {
1039 *error_details = "Failed to read Google version extension version";
dschinazi6cf4d2a2019-04-30 16:20:23 -07001040 return false;
1041 }
1042 if (perspective == Perspective::IS_SERVER) {
dschinazi7b8f0c72020-03-02 13:17:57 -08001043 uint8_t versions_length;
1044 if (!value_reader.ReadUInt8(&versions_length)) {
1045 *error_details = "Failed to parse Google supported versions length";
dschinazi6cf4d2a2019-04-30 16:20:23 -07001046 return false;
1047 }
dschinazi7b8f0c72020-03-02 13:17:57 -08001048 const uint8_t num_versions = versions_length / sizeof(uint32_t);
1049 for (uint8_t i = 0; i < num_versions; ++i) {
dschinazi6cf4d2a2019-04-30 16:20:23 -07001050 QuicVersionLabel version;
dschinazi7b8f0c72020-03-02 13:17:57 -08001051 if (!value_reader.ReadUInt32(&version)) {
1052 *error_details = "Failed to parse Google supported version";
dschinazi6cf4d2a2019-04-30 16:20:23 -07001053 return false;
1054 }
1055 out->supported_versions.push_back(version);
1056 }
1057 }
1058 } break;
vasilvva2ef3012019-09-12 18:32:14 -07001059 default:
dschinazi7b8f0c72020-03-02 13:17:57 -08001060 if (out->custom_parameters.find(param_id) !=
1061 out->custom_parameters.end()) {
1062 *error_details = "Received a second unknown parameter" +
1063 TransportParameterIdToString(param_id);
1064 return false;
1065 }
1066 out->custom_parameters[param_id] =
1067 std::string(value_reader.ReadRemainingPayload());
vasilvva2ef3012019-09-12 18:32:14 -07001068 break;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001069 }
dschinazi52127d72019-04-17 15:12:38 -07001070 if (!parse_success) {
dschinazi7b8f0c72020-03-02 13:17:57 -08001071 DCHECK(!error_details->empty());
1072 return false;
1073 }
1074 if (!value_reader.IsDoneReading()) {
1075 *error_details = quiche::QuicheStrCat(
1076 "Received unexpected ", value_reader.BytesRemaining(),
1077 " bytes after parsing ", TransportParameterIdToString(param_id));
dschinazi52127d72019-04-17 15:12:38 -07001078 return false;
1079 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001080 }
dschinazi52127d72019-04-17 15:12:38 -07001081
dschinazi7b8f0c72020-03-02 13:17:57 -08001082 if (!out->AreValid(error_details)) {
1083 DCHECK(!error_details->empty());
1084 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001085 }
dschinazi7b8f0c72020-03-02 13:17:57 -08001086
1087 QUIC_DLOG(INFO) << "Parsed transport parameters " << *out << " from "
1088 << in_len << " bytes";
1089
1090 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001091}
1092
1093} // namespace quic