blob: 4e761b35e7728410214bf9151ea9ec52a58205fd [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.
dschinazi46730232020-05-07 10:01:21 -070062constexpr uint64_t kMinMaxPacketSizeTransportParam = 1200;
63constexpr uint64_t kMaxAckDelayExponentTransportParam = 20;
64constexpr uint64_t kDefaultAckDelayExponentTransportParam = 3;
65constexpr uint64_t kMaxMaxAckDelayTransportParam = 16383;
66constexpr uint64_t kDefaultMaxAckDelayTransportParam = 25;
67constexpr size_t kStatelessResetTokenLength = 16;
68constexpr uint64_t kMinActiveConnectionIdLimitTransportParam = 2;
69constexpr uint64_t kDefaultActiveConnectionIdLimitTransportParam = 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -050070
dschinazi52127d72019-04-17 15:12:38 -070071std::string TransportParameterIdToString(
72 TransportParameters::TransportParameterId param_id) {
73 switch (param_id) {
danzh9424add2019-06-06 14:04:36 -070074 case TransportParameters::kOriginalConnectionId:
dschinazi52127d72019-04-17 15:12:38 -070075 return "original_connection_id";
danzh9424add2019-06-06 14:04:36 -070076 case TransportParameters::kIdleTimeout:
dschinazi52127d72019-04-17 15:12:38 -070077 return "idle_timeout";
danzh9424add2019-06-06 14:04:36 -070078 case TransportParameters::kStatelessResetToken:
dschinazi52127d72019-04-17 15:12:38 -070079 return "stateless_reset_token";
danzh9424add2019-06-06 14:04:36 -070080 case TransportParameters::kMaxPacketSize:
dschinazi52127d72019-04-17 15:12:38 -070081 return "max_packet_size";
danzh9424add2019-06-06 14:04:36 -070082 case TransportParameters::kInitialMaxData:
dschinazi52127d72019-04-17 15:12:38 -070083 return "initial_max_data";
danzh9424add2019-06-06 14:04:36 -070084 case TransportParameters::kInitialMaxStreamDataBidiLocal:
dschinazi52127d72019-04-17 15:12:38 -070085 return "initial_max_stream_data_bidi_local";
danzh9424add2019-06-06 14:04:36 -070086 case TransportParameters::kInitialMaxStreamDataBidiRemote:
dschinazi52127d72019-04-17 15:12:38 -070087 return "initial_max_stream_data_bidi_remote";
danzh9424add2019-06-06 14:04:36 -070088 case TransportParameters::kInitialMaxStreamDataUni:
dschinazi52127d72019-04-17 15:12:38 -070089 return "initial_max_stream_data_uni";
danzh9424add2019-06-06 14:04:36 -070090 case TransportParameters::kInitialMaxStreamsBidi:
dschinazi52127d72019-04-17 15:12:38 -070091 return "initial_max_streams_bidi";
danzh9424add2019-06-06 14:04:36 -070092 case TransportParameters::kInitialMaxStreamsUni:
dschinazi52127d72019-04-17 15:12:38 -070093 return "initial_max_streams_uni";
danzh9424add2019-06-06 14:04:36 -070094 case TransportParameters::kAckDelayExponent:
dschinazi52127d72019-04-17 15:12:38 -070095 return "ack_delay_exponent";
danzh9424add2019-06-06 14:04:36 -070096 case TransportParameters::kMaxAckDelay:
dschinazi52127d72019-04-17 15:12:38 -070097 return "max_ack_delay";
danzh9424add2019-06-06 14:04:36 -070098 case TransportParameters::kDisableMigration:
dschinazi52127d72019-04-17 15:12:38 -070099 return "disable_migration";
danzh9424add2019-06-06 14:04:36 -0700100 case TransportParameters::kPreferredAddress:
dschinazi52127d72019-04-17 15:12:38 -0700101 return "preferred_address";
dschinazie9db63c2019-07-17 16:19:42 -0700102 case TransportParameters::kActiveConnectionIdLimit:
103 return "active_connection_id_limit";
dschinazicd86dd12019-11-14 10:11:13 -0800104 case TransportParameters::kMaxDatagramFrameSize:
105 return "max_datagram_frame_size";
danzh9424add2019-06-06 14:04:36 -0700106 case TransportParameters::kGoogleQuicParam:
dschinazi52127d72019-04-17 15:12:38 -0700107 return "google";
danzh9424add2019-06-06 14:04:36 -0700108 case TransportParameters::kGoogleQuicVersion:
dschinazi6cf4d2a2019-04-30 16:20:23 -0700109 return "google-version";
dschinazi52127d72019-04-17 15:12:38 -0700110 }
dmcardle904ef182019-12-13 08:34:33 -0800111 return "Unknown(" + quiche::QuicheTextUtils::Uint64ToString(param_id) + ")";
dschinazi52127d72019-04-17 15:12:38 -0700112}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113
dschinazid829b402020-04-10 14:27:21 -0700114bool TransportParameterIdIsKnown(
115 TransportParameters::TransportParameterId param_id) {
116 switch (param_id) {
117 case TransportParameters::kOriginalConnectionId:
118 case TransportParameters::kIdleTimeout:
119 case TransportParameters::kStatelessResetToken:
120 case TransportParameters::kMaxPacketSize:
121 case TransportParameters::kInitialMaxData:
122 case TransportParameters::kInitialMaxStreamDataBidiLocal:
123 case TransportParameters::kInitialMaxStreamDataBidiRemote:
124 case TransportParameters::kInitialMaxStreamDataUni:
125 case TransportParameters::kInitialMaxStreamsBidi:
126 case TransportParameters::kInitialMaxStreamsUni:
127 case TransportParameters::kAckDelayExponent:
128 case TransportParameters::kMaxAckDelay:
129 case TransportParameters::kDisableMigration:
130 case TransportParameters::kPreferredAddress:
131 case TransportParameters::kActiveConnectionIdLimit:
132 case TransportParameters::kMaxDatagramFrameSize:
133 case TransportParameters::kGoogleQuicParam:
134 case TransportParameters::kGoogleQuicVersion:
135 return true;
136 }
137 return false;
138}
139
dschinazi7b8f0c72020-03-02 13:17:57 -0800140bool WriteTransportParameterId(
141 QuicDataWriter* writer,
142 TransportParameters::TransportParameterId param_id,
143 ParsedQuicVersion version) {
144 if (version.HasVarIntTransportParams()) {
145 if (!writer->WriteVarInt62(param_id)) {
146 QUIC_BUG << "Failed to write param_id for "
147 << TransportParameterIdToString(param_id);
148 return false;
149 }
150 } else {
dschinazi55bc2952020-03-11 14:17:32 -0700151 if (static_cast<uint64_t>(param_id) >
152 std::numeric_limits<uint16_t>::max()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800153 QUIC_BUG << "Cannot serialize transport parameter "
154 << TransportParameterIdToString(param_id) << " with version "
155 << version;
156 return false;
157 }
158 if (!writer->WriteUInt16(param_id)) {
159 QUIC_BUG << "Failed to write param_id16 for "
160 << TransportParameterIdToString(param_id);
161 return false;
162 }
163 }
164 return true;
165}
166
167bool WriteTransportParameterLength(QuicDataWriter* writer,
168 uint64_t length,
169 ParsedQuicVersion version) {
170 if (version.HasVarIntTransportParams()) {
171 return writer->WriteVarInt62(length);
172 }
173 if (length > std::numeric_limits<uint16_t>::max()) {
174 QUIC_BUG << "Cannot serialize transport parameter length " << length
175 << " with version " << version;
176 return false;
177 }
178 return writer->WriteUInt16(length);
179}
180
181bool WriteTransportParameterStringPiece(QuicDataWriter* writer,
182 quiche::QuicheStringPiece value,
183 ParsedQuicVersion version) {
184 if (version.HasVarIntTransportParams()) {
185 return writer->WriteStringPieceVarInt62(value);
186 }
187 return writer->WriteStringPiece16(value);
188}
189
190bool ReadTransportParameterId(
191 QuicDataReader* reader,
192 ParsedQuicVersion version,
193 TransportParameters::TransportParameterId* out_param_id) {
194 if (version.HasVarIntTransportParams()) {
195 uint64_t param_id64;
196 if (!reader->ReadVarInt62(&param_id64)) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800197 return false;
198 }
199 *out_param_id =
200 static_cast<TransportParameters::TransportParameterId>(param_id64);
201 } else {
202 uint16_t param_id16;
203 if (!reader->ReadUInt16(&param_id16)) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800204 return false;
205 }
206 *out_param_id =
207 static_cast<TransportParameters::TransportParameterId>(param_id16);
208 }
209 return true;
210}
211
212bool ReadTransportParameterLengthAndValue(
213 QuicDataReader* reader,
214 ParsedQuicVersion version,
215 quiche::QuicheStringPiece* out_value) {
216 if (version.HasVarIntTransportParams()) {
217 return reader->ReadStringPieceVarInt62(out_value);
218 }
219 return reader->ReadStringPiece16(out_value);
220}
221
QUICHE teama6ef0a62019-03-07 20:34:33 -0500222} // namespace
223
dschinazi52127d72019-04-17 15:12:38 -0700224TransportParameters::IntegerParameter::IntegerParameter(
225 TransportParameters::TransportParameterId param_id,
226 uint64_t default_value,
227 uint64_t min_value,
228 uint64_t max_value)
229 : param_id_(param_id),
230 value_(default_value),
231 default_value_(default_value),
232 min_value_(min_value),
233 max_value_(max_value),
dschinazi7b8f0c72020-03-02 13:17:57 -0800234 has_been_read_(false) {
dschinazi52127d72019-04-17 15:12:38 -0700235 DCHECK_LE(min_value, default_value);
236 DCHECK_LE(default_value, max_value);
237 DCHECK_LE(max_value, kVarInt62MaxValue);
238}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500239
dschinazi52127d72019-04-17 15:12:38 -0700240TransportParameters::IntegerParameter::IntegerParameter(
241 TransportParameters::TransportParameterId param_id)
242 : TransportParameters::IntegerParameter::IntegerParameter(
243 param_id,
244 0,
245 0,
246 kVarInt62MaxValue) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500247
dschinazi52127d72019-04-17 15:12:38 -0700248void TransportParameters::IntegerParameter::set_value(uint64_t value) {
249 value_ = value;
250}
251
252uint64_t TransportParameters::IntegerParameter::value() const {
253 return value_;
254}
255
256bool TransportParameters::IntegerParameter::IsValid() const {
257 return min_value_ <= value_ && value_ <= max_value_;
258}
259
dschinazi7b8f0c72020-03-02 13:17:57 -0800260bool TransportParameters::IntegerParameter::Write(
261 QuicDataWriter* writer,
262 ParsedQuicVersion version) const {
dschinazi52127d72019-04-17 15:12:38 -0700263 DCHECK(IsValid());
264 if (value_ == default_value_) {
265 // Do not write if the value is default.
266 return true;
267 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800268 if (!WriteTransportParameterId(writer, param_id_, version)) {
269 QUIC_BUG << "Failed to write param_id for " << *this;
270 return false;
271 }
272 const QuicVariableLengthIntegerLength value_length =
273 QuicDataWriter::GetVarInt62Len(value_);
274 if (version.HasVarIntTransportParams()) {
275 if (!writer->WriteVarInt62(value_length)) {
276 QUIC_BUG << "Failed to write value_length for " << *this;
277 return false;
278 }
279 } else {
280 if (!writer->WriteUInt16(value_length)) {
281 QUIC_BUG << "Failed to write value_length16 for " << *this;
282 return false;
283 }
284 }
285 if (!writer->WriteVarInt62(value_, value_length)) {
286 QUIC_BUG << "Failed to write value for " << *this;
287 return false;
288 }
289 return true;
dschinazi52127d72019-04-17 15:12:38 -0700290}
291
dschinazi7b8f0c72020-03-02 13:17:57 -0800292bool TransportParameters::IntegerParameter::Read(QuicDataReader* reader,
293 std::string* error_details) {
294 if (has_been_read_) {
295 *error_details =
296 "Received a second " + TransportParameterIdToString(param_id_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500297 return false;
298 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800299 has_been_read_ = true;
300
301 if (!reader->ReadVarInt62(&value_)) {
302 *error_details =
303 "Failed to parse value for " + TransportParameterIdToString(param_id_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500304 return false;
305 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800306 if (!reader->IsDoneReading()) {
307 *error_details =
308 quiche::QuicheStrCat("Received unexpected ", reader->BytesRemaining(),
309 " bytes after parsing ", this->ToString(false));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500310 return false;
311 }
312 return true;
313}
314
dschinazi52127d72019-04-17 15:12:38 -0700315std::string TransportParameters::IntegerParameter::ToString(
316 bool for_use_in_list) const {
317 if (for_use_in_list && value_ == default_value_) {
318 return "";
319 }
320 std::string rv = for_use_in_list ? " " : "";
321 rv += TransportParameterIdToString(param_id_) + " ";
dmcardle904ef182019-12-13 08:34:33 -0800322 rv += quiche::QuicheTextUtils::Uint64ToString(value_);
dschinazi52127d72019-04-17 15:12:38 -0700323 if (!IsValid()) {
324 rv += " (Invalid)";
325 }
326 return rv;
327}
328
329std::ostream& operator<<(std::ostream& os,
330 const TransportParameters::IntegerParameter& param) {
331 os << param.ToString(/*for_use_in_list=*/false);
332 return os;
333}
334
335TransportParameters::PreferredAddress::PreferredAddress()
336 : ipv4_socket_address(QuicIpAddress::Any4(), 0),
337 ipv6_socket_address(QuicIpAddress::Any6(), 0),
338 connection_id(EmptyQuicConnectionId()),
339 stateless_reset_token(kStatelessResetTokenLength, 0) {}
340
341TransportParameters::PreferredAddress::~PreferredAddress() {}
342
renjietangdef6e342020-04-09 11:30:00 -0700343bool TransportParameters::PreferredAddress::operator==(
344 const PreferredAddress& rhs) const {
345 return ipv4_socket_address == rhs.ipv4_socket_address &&
346 ipv6_socket_address == rhs.ipv6_socket_address &&
347 connection_id == rhs.connection_id &&
348 stateless_reset_token == rhs.stateless_reset_token;
349}
350
dschinazid5361d82020-04-09 12:11:44 -0700351bool TransportParameters::PreferredAddress::operator!=(
352 const PreferredAddress& rhs) const {
353 return !(*this == rhs);
354}
355
dschinazi52127d72019-04-17 15:12:38 -0700356std::ostream& operator<<(
357 std::ostream& os,
358 const TransportParameters::PreferredAddress& preferred_address) {
359 os << preferred_address.ToString();
360 return os;
361}
362
363std::string TransportParameters::PreferredAddress::ToString() const {
364 return "[" + ipv4_socket_address.ToString() + " " +
365 ipv6_socket_address.ToString() + " connection_id " +
366 connection_id.ToString() + " stateless_reset_token " +
dmcardle904ef182019-12-13 08:34:33 -0800367 quiche::QuicheTextUtils::HexEncode(
dschinazi52127d72019-04-17 15:12:38 -0700368 reinterpret_cast<const char*>(stateless_reset_token.data()),
369 stateless_reset_token.size()) +
370 "]";
371}
372
373std::ostream& operator<<(std::ostream& os, const TransportParameters& params) {
374 os << params.ToString();
375 return os;
376}
377
378std::string TransportParameters::ToString() const {
379 std::string rv = "[";
380 if (perspective == Perspective::IS_SERVER) {
381 rv += "Server";
382 } else {
383 rv += "Client";
384 }
385 if (version != 0) {
386 rv += " version " + QuicVersionLabelToString(version);
387 }
388 if (!supported_versions.empty()) {
389 rv += " supported_versions " +
390 QuicVersionLabelVectorToString(supported_versions);
391 }
dschinazi39e5e552020-05-06 13:55:24 -0700392 if (original_connection_id.has_value()) {
dschinazi52127d72019-04-17 15:12:38 -0700393 rv += " " + TransportParameterIdToString(kOriginalConnectionId) + " " +
dschinazi39e5e552020-05-06 13:55:24 -0700394 original_connection_id.value().ToString();
dschinazi52127d72019-04-17 15:12:38 -0700395 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700396 rv += idle_timeout_milliseconds.ToString(/*for_use_in_list=*/true);
dschinazi52127d72019-04-17 15:12:38 -0700397 if (!stateless_reset_token.empty()) {
398 rv += " " + TransportParameterIdToString(kStatelessResetToken) + " " +
dmcardle904ef182019-12-13 08:34:33 -0800399 quiche::QuicheTextUtils::HexEncode(
dschinazi52127d72019-04-17 15:12:38 -0700400 reinterpret_cast<const char*>(stateless_reset_token.data()),
401 stateless_reset_token.size());
402 }
403 rv += max_packet_size.ToString(/*for_use_in_list=*/true);
404 rv += initial_max_data.ToString(/*for_use_in_list=*/true);
405 rv += initial_max_stream_data_bidi_local.ToString(/*for_use_in_list=*/true);
406 rv += initial_max_stream_data_bidi_remote.ToString(/*for_use_in_list=*/true);
407 rv += initial_max_stream_data_uni.ToString(/*for_use_in_list=*/true);
408 rv += initial_max_streams_bidi.ToString(/*for_use_in_list=*/true);
409 rv += initial_max_streams_uni.ToString(/*for_use_in_list=*/true);
410 rv += ack_delay_exponent.ToString(/*for_use_in_list=*/true);
411 rv += max_ack_delay.ToString(/*for_use_in_list=*/true);
412 if (disable_migration) {
413 rv += " " + TransportParameterIdToString(kDisableMigration);
414 }
415 if (preferred_address) {
416 rv += " " + TransportParameterIdToString(kPreferredAddress) + " " +
417 preferred_address->ToString();
418 }
dschinazie9db63c2019-07-17 16:19:42 -0700419 rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true);
dschinazicd86dd12019-11-14 10:11:13 -0800420 rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true);
dschinazi52127d72019-04-17 15:12:38 -0700421 if (google_quic_params) {
422 rv += " " + TransportParameterIdToString(kGoogleQuicParam);
423 }
424 rv += "]";
vasilvva2ef3012019-09-12 18:32:14 -0700425 for (const auto& kv : custom_parameters) {
dmcardle904ef182019-12-13 08:34:33 -0800426 rv += " 0x" + quiche::QuicheTextUtils::Hex(static_cast<uint32_t>(kv.first));
427 rv += "=" + quiche::QuicheTextUtils::HexEncode(kv.second);
vasilvva2ef3012019-09-12 18:32:14 -0700428 }
dschinazi52127d72019-04-17 15:12:38 -0700429 return rv;
430}
431
432TransportParameters::TransportParameters()
433 : version(0),
dschinazi6cf4d2a2019-04-30 16:20:23 -0700434 idle_timeout_milliseconds(kIdleTimeout),
dschinazi52127d72019-04-17 15:12:38 -0700435 max_packet_size(kMaxPacketSize,
436 kDefaultMaxPacketSizeTransportParam,
437 kMinMaxPacketSizeTransportParam,
438 kVarInt62MaxValue),
439 initial_max_data(kInitialMaxData),
440 initial_max_stream_data_bidi_local(kInitialMaxStreamDataBidiLocal),
441 initial_max_stream_data_bidi_remote(kInitialMaxStreamDataBidiRemote),
442 initial_max_stream_data_uni(kInitialMaxStreamDataUni),
443 initial_max_streams_bidi(kInitialMaxStreamsBidi),
444 initial_max_streams_uni(kInitialMaxStreamsUni),
445 ack_delay_exponent(kAckDelayExponent,
446 kDefaultAckDelayExponentTransportParam,
447 0,
448 kMaxAckDelayExponentTransportParam),
449 max_ack_delay(kMaxAckDelay,
450 kDefaultMaxAckDelayTransportParam,
451 0,
452 kMaxMaxAckDelayTransportParam),
dschinazie9db63c2019-07-17 16:19:42 -0700453 disable_migration(false),
dschinazi46730232020-05-07 10:01:21 -0700454 active_connection_id_limit(kActiveConnectionIdLimit,
455 kDefaultActiveConnectionIdLimitTransportParam,
456 kMinActiveConnectionIdLimitTransportParam,
457 kVarInt62MaxValue),
dschinazicd86dd12019-11-14 10:11:13 -0800458 max_datagram_frame_size(kMaxDatagramFrameSize)
dschinazi52127d72019-04-17 15:12:38 -0700459// Important note: any new transport parameters must be added
460// to TransportParameters::AreValid, SerializeTransportParameters and
renjietangdef6e342020-04-09 11:30:00 -0700461// ParseTransportParameters, TransportParameters's custom copy constructor, the
462// operator==, and TransportParametersTest.Comparator.
dschinazi52127d72019-04-17 15:12:38 -0700463{}
464
renjietang21128a22020-04-08 11:49:02 -0700465TransportParameters::TransportParameters(const TransportParameters& other)
466 : perspective(other.perspective),
467 version(other.version),
468 supported_versions(other.supported_versions),
469 original_connection_id(other.original_connection_id),
470 idle_timeout_milliseconds(other.idle_timeout_milliseconds),
471 stateless_reset_token(other.stateless_reset_token),
472 max_packet_size(other.max_packet_size),
473 initial_max_data(other.initial_max_data),
474 initial_max_stream_data_bidi_local(
475 other.initial_max_stream_data_bidi_local),
476 initial_max_stream_data_bidi_remote(
477 other.initial_max_stream_data_bidi_remote),
478 initial_max_stream_data_uni(other.initial_max_stream_data_uni),
479 initial_max_streams_bidi(other.initial_max_streams_bidi),
480 initial_max_streams_uni(other.initial_max_streams_uni),
481 ack_delay_exponent(other.ack_delay_exponent),
482 max_ack_delay(other.max_ack_delay),
483 disable_migration(other.disable_migration),
484 active_connection_id_limit(other.active_connection_id_limit),
485 max_datagram_frame_size(other.max_datagram_frame_size),
486 custom_parameters(other.custom_parameters) {
487 if (other.preferred_address) {
488 preferred_address = std::make_unique<TransportParameters::PreferredAddress>(
489 *other.preferred_address);
490 }
491 if (other.google_quic_params) {
492 google_quic_params =
493 std::make_unique<CryptoHandshakeMessage>(*other.google_quic_params);
494 }
495}
496
renjietangdef6e342020-04-09 11:30:00 -0700497bool TransportParameters::operator==(const TransportParameters& rhs) const {
498 if (!(perspective == rhs.perspective && version == rhs.version &&
499 supported_versions == rhs.supported_versions &&
500 original_connection_id == rhs.original_connection_id &&
501 idle_timeout_milliseconds.value() ==
502 rhs.idle_timeout_milliseconds.value() &&
503 stateless_reset_token == rhs.stateless_reset_token &&
504 max_packet_size.value() == rhs.max_packet_size.value() &&
505 initial_max_data.value() == rhs.initial_max_data.value() &&
506 initial_max_stream_data_bidi_local.value() ==
507 rhs.initial_max_stream_data_bidi_local.value() &&
508 initial_max_stream_data_bidi_remote.value() ==
509 rhs.initial_max_stream_data_bidi_remote.value() &&
510 initial_max_stream_data_uni.value() ==
511 rhs.initial_max_stream_data_uni.value() &&
512 initial_max_streams_bidi.value() ==
513 rhs.initial_max_streams_bidi.value() &&
514 initial_max_streams_uni.value() ==
515 rhs.initial_max_streams_uni.value() &&
516 ack_delay_exponent.value() == rhs.ack_delay_exponent.value() &&
517 max_ack_delay.value() == rhs.max_ack_delay.value() &&
518 disable_migration == rhs.disable_migration &&
519 active_connection_id_limit.value() ==
520 rhs.active_connection_id_limit.value() &&
521 max_datagram_frame_size.value() ==
522 rhs.max_datagram_frame_size.value() &&
523 custom_parameters == rhs.custom_parameters)) {
524 return false;
525 }
526
527 if ((!preferred_address && rhs.preferred_address) ||
528 (preferred_address && !rhs.preferred_address) ||
529 (!google_quic_params && rhs.google_quic_params) ||
530 (google_quic_params && !rhs.google_quic_params)) {
531 return false;
532 }
533 bool address = true;
534 if (preferred_address && rhs.preferred_address) {
535 address = (*preferred_address == *rhs.preferred_address);
536 }
537
538 bool google_quic = true;
539 if (google_quic_params && rhs.google_quic_params) {
540 google_quic = (*google_quic_params == *rhs.google_quic_params);
541 }
542 return address && google_quic;
543}
544
dschinazid5361d82020-04-09 12:11:44 -0700545bool TransportParameters::operator!=(const TransportParameters& rhs) const {
546 return !(*this == rhs);
547}
548
dschinazi7b8f0c72020-03-02 13:17:57 -0800549bool TransportParameters::AreValid(std::string* error_details) const {
dschinazi52127d72019-04-17 15:12:38 -0700550 DCHECK(perspective == Perspective::IS_CLIENT ||
551 perspective == Perspective::IS_SERVER);
552 if (perspective == Perspective::IS_CLIENT && !stateless_reset_token.empty()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800553 *error_details = "Client cannot send stateless reset token";
dschinazi52127d72019-04-17 15:12:38 -0700554 return false;
555 }
556 if (perspective == Perspective::IS_CLIENT &&
dschinazi39e5e552020-05-06 13:55:24 -0700557 original_connection_id.has_value()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800558 *error_details = "Client cannot send original connection ID";
dschinazi52127d72019-04-17 15:12:38 -0700559 return false;
560 }
561 if (!stateless_reset_token.empty() &&
562 stateless_reset_token.size() != kStatelessResetTokenLength) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800563 *error_details = quiche::QuicheStrCat(
564 "Stateless reset token has bad length ", stateless_reset_token.size());
dschinazi52127d72019-04-17 15:12:38 -0700565 return false;
566 }
567 if (perspective == Perspective::IS_CLIENT && preferred_address) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800568 *error_details = "Client cannot send preferred address";
dschinazi52127d72019-04-17 15:12:38 -0700569 return false;
570 }
571 if (preferred_address && preferred_address->stateless_reset_token.size() !=
572 kStatelessResetTokenLength) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800573 *error_details = quiche::QuicheStrCat(
574 "Preferred address stateless reset token has bad length ",
575 preferred_address->stateless_reset_token.size());
dschinazi52127d72019-04-17 15:12:38 -0700576 return false;
577 }
578 if (preferred_address &&
579 (!preferred_address->ipv4_socket_address.host().IsIPv4() ||
580 !preferred_address->ipv6_socket_address.host().IsIPv6())) {
581 QUIC_BUG << "Preferred address family failure";
dschinazi7b8f0c72020-03-02 13:17:57 -0800582 *error_details = "Internal preferred address family failure";
dschinazi52127d72019-04-17 15:12:38 -0700583 return false;
584 }
dschinazid829b402020-04-10 14:27:21 -0700585 for (const auto& kv : custom_parameters) {
586 if (TransportParameterIdIsKnown(kv.first)) {
587 *error_details = quiche::QuicheStrCat(
588 "Using custom_parameters with known ID ",
589 TransportParameterIdToString(kv.first), " is not allowed");
590 return false;
591 }
592 }
dschinazicd86dd12019-11-14 10:11:13 -0800593 const bool ok =
594 idle_timeout_milliseconds.IsValid() && max_packet_size.IsValid() &&
595 initial_max_data.IsValid() &&
596 initial_max_stream_data_bidi_local.IsValid() &&
597 initial_max_stream_data_bidi_remote.IsValid() &&
598 initial_max_stream_data_uni.IsValid() &&
599 initial_max_streams_bidi.IsValid() && initial_max_streams_uni.IsValid() &&
600 ack_delay_exponent.IsValid() && max_ack_delay.IsValid() &&
601 active_connection_id_limit.IsValid() && max_datagram_frame_size.IsValid();
dschinazi52127d72019-04-17 15:12:38 -0700602 if (!ok) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800603 *error_details = "Invalid transport parameters " + this->ToString();
dschinazi52127d72019-04-17 15:12:38 -0700604 }
605 return ok;
606}
607
608TransportParameters::~TransportParameters() = default;
609
dschinazi7b8f0c72020-03-02 13:17:57 -0800610bool SerializeTransportParameters(ParsedQuicVersion version,
dschinazi6c84c142019-07-31 09:11:49 -0700611 const TransportParameters& in,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500612 std::vector<uint8_t>* out) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800613 std::string error_details;
614 if (!in.AreValid(&error_details)) {
615 QUIC_BUG << "Not serializing invalid transport parameters: "
616 << error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500617 return false;
618 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700619 if (in.version == 0 || (in.perspective == Perspective::IS_SERVER &&
620 in.supported_versions.empty())) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800621 QUIC_BUG << "Refusing to serialize without versions";
dschinazi6cf4d2a2019-04-30 16:20:23 -0700622 return false;
623 }
624
dschinazi52127d72019-04-17 15:12:38 -0700625 // Empirically transport parameters generally fit within 128 bytes.
dschinazi7b8f0c72020-03-02 13:17:57 -0800626 // For now we hope this will be enough.
627 // TODO(dschinazi) make this grow if needed.
628 static const size_t kMaxTransportParametersLength = 4096;
629 out->resize(kMaxTransportParametersLength);
630 QuicDataWriter writer(out->size(), reinterpret_cast<char*>(out->data()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500631
dschinazi7b8f0c72020-03-02 13:17:57 -0800632 if (!version.HasVarIntTransportParams()) {
633 // Versions that do not use variable integer transport parameters carry
634 // a 16-bit length of the remaining transport parameters. We write 0 here
635 // to reserve 16 bits, and we fill it in at the end of this function.
636 // TODO(b/150465921) add support for doing this in QuicDataWriter.
637 if (!writer.WriteUInt16(0)) {
638 QUIC_BUG << "Failed to write transport parameter fake length prefix for "
639 << in;
640 return false;
641 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500642 }
643
dschinazi52127d72019-04-17 15:12:38 -0700644 // original_connection_id
dschinazi39e5e552020-05-06 13:55:24 -0700645 if (in.original_connection_id.has_value()) {
dschinazi52127d72019-04-17 15:12:38 -0700646 DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
dschinazi39e5e552020-05-06 13:55:24 -0700647 QuicConnectionId original_connection_id = in.original_connection_id.value();
dschinazi7b8f0c72020-03-02 13:17:57 -0800648 if (!WriteTransportParameterId(
649 &writer, TransportParameters::kOriginalConnectionId, version) ||
650 !WriteTransportParameterStringPiece(
651 &writer,
dschinazi39e5e552020-05-06 13:55:24 -0700652 quiche::QuicheStringPiece(original_connection_id.data(),
653 original_connection_id.length()),
dschinazi7b8f0c72020-03-02 13:17:57 -0800654 version)) {
dschinazi52127d72019-04-17 15:12:38 -0700655 QUIC_BUG << "Failed to write original_connection_id "
dschinazi39e5e552020-05-06 13:55:24 -0700656 << in.original_connection_id.value() << " for " << in;
dschinazi52127d72019-04-17 15:12:38 -0700657 return false;
658 }
659 }
660
dschinazi7b8f0c72020-03-02 13:17:57 -0800661 if (!in.idle_timeout_milliseconds.Write(&writer, version)) {
dschinazi52127d72019-04-17 15:12:38 -0700662 QUIC_BUG << "Failed to write idle_timeout for " << in;
663 return false;
664 }
665
666 // stateless_reset_token
QUICHE teama6ef0a62019-03-07 20:34:33 -0500667 if (!in.stateless_reset_token.empty()) {
dschinazi52127d72019-04-17 15:12:38 -0700668 DCHECK_EQ(kStatelessResetTokenLength, in.stateless_reset_token.size());
669 DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
dschinazi7b8f0c72020-03-02 13:17:57 -0800670 if (!WriteTransportParameterId(
671 &writer, TransportParameters::kStatelessResetToken, version) ||
672 !WriteTransportParameterStringPiece(
673 &writer,
674 quiche::QuicheStringPiece(
675 reinterpret_cast<const char*>(in.stateless_reset_token.data()),
676 in.stateless_reset_token.size()),
677 version)) {
dschinazi52127d72019-04-17 15:12:38 -0700678 QUIC_BUG << "Failed to write stateless_reset_token of length "
679 << in.stateless_reset_token.size() << " for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500680 return false;
681 }
682 }
683
dschinazi7b8f0c72020-03-02 13:17:57 -0800684 if (!in.max_packet_size.Write(&writer, version) ||
685 !in.initial_max_data.Write(&writer, version) ||
686 !in.initial_max_stream_data_bidi_local.Write(&writer, version) ||
687 !in.initial_max_stream_data_bidi_remote.Write(&writer, version) ||
688 !in.initial_max_stream_data_uni.Write(&writer, version) ||
689 !in.initial_max_streams_bidi.Write(&writer, version) ||
690 !in.initial_max_streams_uni.Write(&writer, version) ||
691 !in.ack_delay_exponent.Write(&writer, version) ||
692 !in.max_ack_delay.Write(&writer, version) ||
693 !in.active_connection_id_limit.Write(&writer, version) ||
694 !in.max_datagram_frame_size.Write(&writer, version)) {
dschinazi52127d72019-04-17 15:12:38 -0700695 QUIC_BUG << "Failed to write integers for " << in;
696 return false;
697 }
698
699 // disable_migration
700 if (in.disable_migration) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800701 if (!WriteTransportParameterId(
702 &writer, TransportParameters::kDisableMigration, version) ||
703 !WriteTransportParameterLength(&writer, /*length=*/0, version)) {
dschinazi52127d72019-04-17 15:12:38 -0700704 QUIC_BUG << "Failed to write disable_migration for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500705 return false;
706 }
707 }
dschinazi52127d72019-04-17 15:12:38 -0700708
709 // preferred_address
dschinazi52127d72019-04-17 15:12:38 -0700710 if (in.preferred_address) {
711 std::string v4_address_bytes =
712 in.preferred_address->ipv4_socket_address.host().ToPackedString();
713 std::string v6_address_bytes =
714 in.preferred_address->ipv6_socket_address.host().ToPackedString();
715 if (v4_address_bytes.length() != 4 || v6_address_bytes.length() != 16 ||
716 in.preferred_address->stateless_reset_token.size() !=
717 kStatelessResetTokenLength) {
718 QUIC_BUG << "Bad lengths " << *in.preferred_address;
719 return false;
720 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800721 const uint64_t preferred_address_length =
722 v4_address_bytes.length() + /* IPv4 port */ sizeof(uint16_t) +
723 v6_address_bytes.length() + /* IPv6 port */ sizeof(uint16_t) +
724 /* connection ID length byte */ sizeof(uint8_t) +
725 in.preferred_address->connection_id.length() +
726 in.preferred_address->stateless_reset_token.size();
727 if (!WriteTransportParameterId(
728 &writer, TransportParameters::kPreferredAddress, version) ||
729 !WriteTransportParameterLength(&writer, preferred_address_length,
730 version) ||
731 !writer.WriteStringPiece(v4_address_bytes) ||
732 !writer.WriteUInt16(in.preferred_address->ipv4_socket_address.port()) ||
733 !writer.WriteStringPiece(v6_address_bytes) ||
734 !writer.WriteUInt16(in.preferred_address->ipv6_socket_address.port()) ||
735 !writer.WriteUInt8(in.preferred_address->connection_id.length()) ||
736 !writer.WriteBytes(in.preferred_address->connection_id.data(),
737 in.preferred_address->connection_id.length()) ||
738 !writer.WriteBytes(
739 in.preferred_address->stateless_reset_token.data(),
740 in.preferred_address->stateless_reset_token.size())) {
dschinazi52127d72019-04-17 15:12:38 -0700741 QUIC_BUG << "Failed to write preferred_address for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500742 return false;
743 }
744 }
dschinazi52127d72019-04-17 15:12:38 -0700745
746 // Google-specific non-standard parameter.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500747 if (in.google_quic_params) {
748 const QuicData& serialized_google_quic_params =
749 in.google_quic_params->GetSerialized();
dschinazi7b8f0c72020-03-02 13:17:57 -0800750 if (!WriteTransportParameterId(
751 &writer, TransportParameters::kGoogleQuicParam, version) ||
752 !WriteTransportParameterStringPiece(
753 &writer, serialized_google_quic_params.AsStringPiece(), version)) {
dschinazi52127d72019-04-17 15:12:38 -0700754 QUIC_BUG << "Failed to write Google params of length "
755 << serialized_google_quic_params.length() << " for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500756 return false;
757 }
758 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700759
760 // Google-specific version extension.
dschinazi7b8f0c72020-03-02 13:17:57 -0800761 static_assert(sizeof(QuicVersionLabel) == sizeof(uint32_t), "bad length");
762 uint64_t google_version_length = sizeof(in.version);
763 if (in.perspective == Perspective::IS_SERVER) {
764 google_version_length +=
765 /* versions length */ sizeof(uint8_t) +
766 sizeof(QuicVersionLabel) * in.supported_versions.size();
767 }
768 if (!WriteTransportParameterId(
769 &writer, TransportParameters::kGoogleQuicVersion, version) ||
770 !WriteTransportParameterLength(&writer, google_version_length, version) ||
771 !writer.WriteUInt32(in.version)) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700772 QUIC_BUG << "Failed to write Google version extension for " << in;
773 return false;
774 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700775 if (in.perspective == Perspective::IS_SERVER) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800776 if (!writer.WriteUInt8(sizeof(QuicVersionLabel) *
777 in.supported_versions.size())) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700778 QUIC_BUG << "Failed to write versions length for " << in;
779 return false;
780 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800781 for (QuicVersionLabel version_label : in.supported_versions) {
782 if (!writer.WriteUInt32(version_label)) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700783 QUIC_BUG << "Failed to write supported version for " << in;
784 return false;
785 }
786 }
787 }
788
vasilvva2ef3012019-09-12 18:32:14 -0700789 for (const auto& kv : in.custom_parameters) {
dschinazid829b402020-04-10 14:27:21 -0700790 const TransportParameters::TransportParameterId param_id = kv.first;
791 if (param_id % 31 == 27) {
792 // See the "Reserved Transport Parameters" section of
793 // draft-ietf-quic-transport.
794 QUIC_BUG << "Serializing custom_parameters with GREASE ID " << param_id
795 << " is not allowed";
796 return false;
797 }
798 if (!WriteTransportParameterId(&writer, param_id, version) ||
dschinazi7b8f0c72020-03-02 13:17:57 -0800799 !WriteTransportParameterStringPiece(&writer, kv.second, version)) {
dschinazid829b402020-04-10 14:27:21 -0700800 QUIC_BUG << "Failed to write custom parameter " << param_id;
801 return false;
802 }
803 }
804
805 {
806 // Add a random GREASE transport parameter, as defined in the
807 // "Reserved Transport Parameters" section of draft-ietf-quic-transport.
808 // https://quicwg.org/base-drafts/draft-ietf-quic-transport.html
809 // This forces receivers to support unexpected input.
810 QuicRandom* random = QuicRandom::GetInstance();
811 uint64_t grease_id64 = random->RandUint64();
812 if (version.HasVarIntTransportParams()) {
813 // With these versions, identifiers are 62 bits long so we need to ensure
814 // that the output of the computation below fits in 62 bits.
815 grease_id64 %= ((1ULL << 62) - 31);
816 } else {
817 // Same with 16 bits.
818 grease_id64 %= ((1ULL << 16) - 31);
819 }
820 // Make sure grease_id % 31 == 27. Note that this is not uniformely
821 // distributed but is acceptable since no security depends on this
822 // randomness.
823 grease_id64 = (grease_id64 / 31) * 31 + 27;
824 DCHECK(version.HasVarIntTransportParams() ||
825 grease_id64 <= std::numeric_limits<uint16_t>::max())
826 << grease_id64 << " invalid for " << version;
827 TransportParameters::TransportParameterId grease_id =
828 static_cast<TransportParameters::TransportParameterId>(grease_id64);
ianswette71fb0b2020-04-13 11:18:52 -0700829 const size_t kMaxGreaseLength = 16;
830 const size_t grease_length = random->RandUint64() % kMaxGreaseLength;
831 DCHECK_GE(kMaxGreaseLength, grease_length);
832 char grease_contents[kMaxGreaseLength];
833 random->RandBytes(grease_contents, grease_length);
dschinazid829b402020-04-10 14:27:21 -0700834 if (!WriteTransportParameterId(&writer, grease_id, version) ||
renjietang897e7632020-04-14 12:27:13 -0700835 !WriteTransportParameterStringPiece(
836 &writer, quiche::QuicheStringPiece(grease_contents, grease_length),
837 version)) {
dschinazid829b402020-04-10 14:27:21 -0700838 QUIC_BUG << "Failed to write GREASE parameter "
839 << TransportParameterIdToString(grease_id);
vasilvva2ef3012019-09-12 18:32:14 -0700840 return false;
841 }
842 }
843
dschinazi7b8f0c72020-03-02 13:17:57 -0800844 if (!version.HasVarIntTransportParams()) {
845 // Fill in the length prefix at the start of the transport parameters.
846 if (writer.length() < sizeof(uint16_t) ||
847 writer.length() - sizeof(uint16_t) >
848 std::numeric_limits<uint16_t>::max()) {
849 QUIC_BUG << "Cannot write length " << writer.length() << " for " << in;
850 return false;
851 }
852 const uint16_t length_prefix = writer.length() - sizeof(uint16_t);
853 QuicDataWriter length_prefix_writer(out->size(),
854 reinterpret_cast<char*>(out->data()));
855 if (!length_prefix_writer.WriteUInt16(length_prefix)) {
856 QUIC_BUG << "Failed to write length prefix for " << in;
857 return false;
858 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500859 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800860
861 out->resize(writer.length());
862
863 QUIC_DLOG(INFO) << "Serialized " << in << " as " << writer.length()
dschinazi52127d72019-04-17 15:12:38 -0700864 << " bytes";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500865 return true;
866}
867
dschinazi6c84c142019-07-31 09:11:49 -0700868bool ParseTransportParameters(ParsedQuicVersion version,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500869 Perspective perspective,
dschinazi6c84c142019-07-31 09:11:49 -0700870 const uint8_t* in,
871 size_t in_len,
dschinazi7b8f0c72020-03-02 13:17:57 -0800872 TransportParameters* out,
873 std::string* error_details) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700874 out->perspective = perspective;
dschinazi7b8f0c72020-03-02 13:17:57 -0800875 QuicDataReader reader(reinterpret_cast<const char*>(in), in_len);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500876
dschinazi7b8f0c72020-03-02 13:17:57 -0800877 if (!version.HasVarIntTransportParams()) {
878 uint16_t full_length;
879 if (!reader.ReadUInt16(&full_length)) {
880 *error_details = "Failed to parse the transport parameter full length";
881 return false;
882 }
883 if (full_length != reader.BytesRemaining()) {
884 *error_details =
885 quiche::QuicheStrCat("Invalid transport parameter full length ",
886 full_length, " != ", reader.BytesRemaining());
887 return false;
888 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500889 }
dschinazi52127d72019-04-17 15:12:38 -0700890
dschinazi7b8f0c72020-03-02 13:17:57 -0800891 while (!reader.IsDoneReading()) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700892 TransportParameters::TransportParameterId param_id;
dschinazi7b8f0c72020-03-02 13:17:57 -0800893 if (!ReadTransportParameterId(&reader, version, &param_id)) {
894 *error_details = "Failed to parse transport parameter ID";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500895 return false;
896 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800897 quiche::QuicheStringPiece value;
898 if (!ReadTransportParameterLengthAndValue(&reader, version, &value)) {
899 *error_details =
900 "Failed to read length and value of transport parameter " +
901 TransportParameterIdToString(param_id);
dschinazi52127d72019-04-17 15:12:38 -0700902 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500903 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800904 QuicDataReader value_reader(value);
dschinazi52127d72019-04-17 15:12:38 -0700905 bool parse_success = true;
dschinazi6cf4d2a2019-04-30 16:20:23 -0700906 switch (param_id) {
dschinazi6c84c142019-07-31 09:11:49 -0700907 case TransportParameters::kOriginalConnectionId: {
dschinazi39e5e552020-05-06 13:55:24 -0700908 if (out->original_connection_id.has_value()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800909 *error_details = "Received a second original connection ID";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500910 return false;
911 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800912 const size_t connection_id_length = value_reader.BytesRemaining();
dschinazi6c84c142019-07-31 09:11:49 -0700913 if (!QuicUtils::IsConnectionIdLengthValidForVersion(
914 connection_id_length, version.transport_version)) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800915 *error_details = quiche::QuicheStrCat(
916 "Received original connection ID of invalid length ",
917 connection_id_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500918 return false;
919 }
dschinazi39e5e552020-05-06 13:55:24 -0700920 QuicConnectionId original_connection_id;
921 if (!value_reader.ReadConnectionId(&original_connection_id,
dschinazi7b8f0c72020-03-02 13:17:57 -0800922 connection_id_length)) {
923 *error_details = "Failed to read original connection ID";
924 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500925 }
dschinazi39e5e552020-05-06 13:55:24 -0700926 out->original_connection_id = original_connection_id;
dschinazi6c84c142019-07-31 09:11:49 -0700927 } break;
danzh9424add2019-06-06 14:04:36 -0700928 case TransportParameters::kIdleTimeout:
dschinazi7b8f0c72020-03-02 13:17:57 -0800929 parse_success =
930 out->idle_timeout_milliseconds.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700931 break;
dschinazi7b8f0c72020-03-02 13:17:57 -0800932 case TransportParameters::kStatelessResetToken: {
dschinazi52127d72019-04-17 15:12:38 -0700933 if (!out->stateless_reset_token.empty()) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800934 *error_details = "Received a second stateless reset token";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500935 return false;
936 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800937 quiche::QuicheStringPiece stateless_reset_token =
938 value_reader.ReadRemainingPayload();
939 if (stateless_reset_token.length() != kStatelessResetTokenLength) {
940 *error_details = quiche::QuicheStrCat(
941 "Received stateless reset token of invalid length ",
942 stateless_reset_token.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500943 return false;
944 }
dschinazi7b8f0c72020-03-02 13:17:57 -0800945 out->stateless_reset_token.assign(
946 stateless_reset_token.data(),
947 stateless_reset_token.data() + stateless_reset_token.length());
948 } break;
danzh9424add2019-06-06 14:04:36 -0700949 case TransportParameters::kMaxPacketSize:
dschinazi7b8f0c72020-03-02 13:17:57 -0800950 parse_success = out->max_packet_size.Read(&value_reader, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500951 break;
danzh9424add2019-06-06 14:04:36 -0700952 case TransportParameters::kInitialMaxData:
dschinazi7b8f0c72020-03-02 13:17:57 -0800953 parse_success =
954 out->initial_max_data.Read(&value_reader, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500955 break;
danzh9424add2019-06-06 14:04:36 -0700956 case TransportParameters::kInitialMaxStreamDataBidiLocal:
dschinazi7b8f0c72020-03-02 13:17:57 -0800957 parse_success = out->initial_max_stream_data_bidi_local.Read(
958 &value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700959 break;
danzh9424add2019-06-06 14:04:36 -0700960 case TransportParameters::kInitialMaxStreamDataBidiRemote:
dschinazi7b8f0c72020-03-02 13:17:57 -0800961 parse_success = out->initial_max_stream_data_bidi_remote.Read(
962 &value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700963 break;
danzh9424add2019-06-06 14:04:36 -0700964 case TransportParameters::kInitialMaxStreamDataUni:
dschinazi7b8f0c72020-03-02 13:17:57 -0800965 parse_success =
966 out->initial_max_stream_data_uni.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700967 break;
danzh9424add2019-06-06 14:04:36 -0700968 case TransportParameters::kInitialMaxStreamsBidi:
dschinazi7b8f0c72020-03-02 13:17:57 -0800969 parse_success =
970 out->initial_max_streams_bidi.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700971 break;
danzh9424add2019-06-06 14:04:36 -0700972 case TransportParameters::kInitialMaxStreamsUni:
dschinazi7b8f0c72020-03-02 13:17:57 -0800973 parse_success =
974 out->initial_max_streams_uni.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700975 break;
danzh9424add2019-06-06 14:04:36 -0700976 case TransportParameters::kAckDelayExponent:
dschinazi7b8f0c72020-03-02 13:17:57 -0800977 parse_success =
978 out->ack_delay_exponent.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700979 break;
danzh9424add2019-06-06 14:04:36 -0700980 case TransportParameters::kMaxAckDelay:
dschinazi7b8f0c72020-03-02 13:17:57 -0800981 parse_success = out->max_ack_delay.Read(&value_reader, error_details);
dschinazi52127d72019-04-17 15:12:38 -0700982 break;
danzh9424add2019-06-06 14:04:36 -0700983 case TransportParameters::kDisableMigration:
dschinazi52127d72019-04-17 15:12:38 -0700984 if (out->disable_migration) {
dschinazi7b8f0c72020-03-02 13:17:57 -0800985 *error_details = "Received a second disable migration";
dschinazi52127d72019-04-17 15:12:38 -0700986 return false;
987 }
988 out->disable_migration = true;
989 break;
danzh9424add2019-06-06 14:04:36 -0700990 case TransportParameters::kPreferredAddress: {
dschinazi7b8f0c72020-03-02 13:17:57 -0800991 TransportParameters::PreferredAddress preferred_address;
dschinazi52127d72019-04-17 15:12:38 -0700992 uint16_t ipv4_port, ipv6_port;
993 in_addr ipv4_address;
994 in6_addr ipv6_address;
dschinazi7b8f0c72020-03-02 13:17:57 -0800995 preferred_address.stateless_reset_token.resize(
996 kStatelessResetTokenLength);
997 if (!value_reader.ReadBytes(&ipv4_address, sizeof(ipv4_address)) ||
998 !value_reader.ReadUInt16(&ipv4_port) ||
999 !value_reader.ReadBytes(&ipv6_address, sizeof(ipv6_address)) ||
1000 !value_reader.ReadUInt16(&ipv6_port) ||
1001 !value_reader.ReadLengthPrefixedConnectionId(
1002 &preferred_address.connection_id) ||
1003 !value_reader.ReadBytes(&preferred_address.stateless_reset_token[0],
1004 kStatelessResetTokenLength)) {
1005 *error_details = "Failed to read preferred address";
dschinazi52127d72019-04-17 15:12:38 -07001006 return false;
1007 }
dschinazi52127d72019-04-17 15:12:38 -07001008 preferred_address.ipv4_socket_address =
1009 QuicSocketAddress(QuicIpAddress(ipv4_address), ipv4_port);
1010 preferred_address.ipv6_socket_address =
1011 QuicSocketAddress(QuicIpAddress(ipv6_address), ipv6_port);
1012 if (!preferred_address.ipv4_socket_address.host().IsIPv4() ||
1013 !preferred_address.ipv6_socket_address.host().IsIPv6()) {
dschinazi7b8f0c72020-03-02 13:17:57 -08001014 *error_details = "Received preferred addresses of bad families " +
1015 preferred_address.ToString();
dschinazi52127d72019-04-17 15:12:38 -07001016 return false;
1017 }
dschinazi7b8f0c72020-03-02 13:17:57 -08001018 if (!QuicUtils::IsConnectionIdValidForVersion(
1019 preferred_address.connection_id, version.transport_version)) {
1020 *error_details = "Received invalid preferred address connection ID " +
1021 preferred_address.ToString();
dschinazi52127d72019-04-17 15:12:38 -07001022 return false;
1023 }
dschinazi52127d72019-04-17 15:12:38 -07001024 out->preferred_address =
vasilvv0fc587f2019-09-06 13:33:08 -07001025 std::make_unique<TransportParameters::PreferredAddress>(
dschinazi52127d72019-04-17 15:12:38 -07001026 preferred_address);
1027 } break;
dschinazie9db63c2019-07-17 16:19:42 -07001028 case TransportParameters::kActiveConnectionIdLimit:
dschinazi7b8f0c72020-03-02 13:17:57 -08001029 parse_success =
1030 out->active_connection_id_limit.Read(&value_reader, error_details);
dschinazie9db63c2019-07-17 16:19:42 -07001031 break;
dschinazicd86dd12019-11-14 10:11:13 -08001032 case TransportParameters::kMaxDatagramFrameSize:
dschinazi7b8f0c72020-03-02 13:17:57 -08001033 parse_success =
1034 out->max_datagram_frame_size.Read(&value_reader, error_details);
dschinazicd86dd12019-11-14 10:11:13 -08001035 break;
danzh9424add2019-06-06 14:04:36 -07001036 case TransportParameters::kGoogleQuicParam: {
dschinazi52127d72019-04-17 15:12:38 -07001037 if (out->google_quic_params) {
dschinazi7b8f0c72020-03-02 13:17:57 -08001038 *error_details = "Received a second Google parameter";
dschinazi52127d72019-04-17 15:12:38 -07001039 return false;
1040 }
dschinazi7b8f0c72020-03-02 13:17:57 -08001041 out->google_quic_params =
1042 CryptoFramer::ParseMessage(value_reader.ReadRemainingPayload());
dschinazi6cf4d2a2019-04-30 16:20:23 -07001043 } break;
danzh9424add2019-06-06 14:04:36 -07001044 case TransportParameters::kGoogleQuicVersion: {
dschinazi7b8f0c72020-03-02 13:17:57 -08001045 if (!value_reader.ReadUInt32(&out->version)) {
1046 *error_details = "Failed to read Google version extension version";
dschinazi6cf4d2a2019-04-30 16:20:23 -07001047 return false;
1048 }
1049 if (perspective == Perspective::IS_SERVER) {
dschinazi7b8f0c72020-03-02 13:17:57 -08001050 uint8_t versions_length;
1051 if (!value_reader.ReadUInt8(&versions_length)) {
1052 *error_details = "Failed to parse Google supported versions length";
dschinazi6cf4d2a2019-04-30 16:20:23 -07001053 return false;
1054 }
dschinazi7b8f0c72020-03-02 13:17:57 -08001055 const uint8_t num_versions = versions_length / sizeof(uint32_t);
1056 for (uint8_t i = 0; i < num_versions; ++i) {
dschinazi6cf4d2a2019-04-30 16:20:23 -07001057 QuicVersionLabel version;
dschinazi7b8f0c72020-03-02 13:17:57 -08001058 if (!value_reader.ReadUInt32(&version)) {
1059 *error_details = "Failed to parse Google supported version";
dschinazi6cf4d2a2019-04-30 16:20:23 -07001060 return false;
1061 }
1062 out->supported_versions.push_back(version);
1063 }
1064 }
1065 } break;
vasilvva2ef3012019-09-12 18:32:14 -07001066 default:
dschinazi7b8f0c72020-03-02 13:17:57 -08001067 if (out->custom_parameters.find(param_id) !=
1068 out->custom_parameters.end()) {
1069 *error_details = "Received a second unknown parameter" +
1070 TransportParameterIdToString(param_id);
1071 return false;
1072 }
1073 out->custom_parameters[param_id] =
1074 std::string(value_reader.ReadRemainingPayload());
vasilvva2ef3012019-09-12 18:32:14 -07001075 break;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001076 }
dschinazi52127d72019-04-17 15:12:38 -07001077 if (!parse_success) {
dschinazi7b8f0c72020-03-02 13:17:57 -08001078 DCHECK(!error_details->empty());
1079 return false;
1080 }
1081 if (!value_reader.IsDoneReading()) {
1082 *error_details = quiche::QuicheStrCat(
1083 "Received unexpected ", value_reader.BytesRemaining(),
1084 " bytes after parsing ", TransportParameterIdToString(param_id));
dschinazi52127d72019-04-17 15:12:38 -07001085 return false;
1086 }
QUICHE teama6ef0a62019-03-07 20:34:33 -05001087 }
dschinazi52127d72019-04-17 15:12:38 -07001088
dschinazi7b8f0c72020-03-02 13:17:57 -08001089 if (!out->AreValid(error_details)) {
1090 DCHECK(!error_details->empty());
1091 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001092 }
dschinazi7b8f0c72020-03-02 13:17:57 -08001093
1094 QUIC_DLOG(INFO) << "Parsed transport parameters " << *out << " from "
1095 << in_len << " bytes";
1096
1097 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001098}
1099
1100} // namespace quic