blob: e5df9feee598aa10a765136f7bf538848b81f122 [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>
9
QUICHE teama6ef0a62019-03-07 20:34:33 -050010#include "third_party/boringssl/src/include/openssl/bytestring.h"
11#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
dschinazi52127d72019-04-17 15:12:38 -070012#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
13#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
14#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
15#include "net/third_party/quiche/src/quic/core/quic_types.h"
16#include "net/third_party/quiche/src/quic/core/quic_versions.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050020
21namespace quic {
22
dschinazi52127d72019-04-17 15:12:38 -070023// Values of the TransportParameterId enum as defined in the
24// "Transport Parameter Encoding" section of draft-ietf-quic-transport.
25// When parameters are encoded, one of these enum values is used to indicate
26// which parameter is encoded. The supported draft version is noted in
27// transport_parameters.h.
28enum TransportParameters::TransportParameterId : uint16_t {
29 kOriginalConnectionId = 0,
30 kIdleTimeout = 1,
31 kStatelessResetToken = 2,
32 kMaxPacketSize = 3,
33 kInitialMaxData = 4,
34 kInitialMaxStreamDataBidiLocal = 5,
35 kInitialMaxStreamDataBidiRemote = 6,
36 kInitialMaxStreamDataUni = 7,
37 kInitialMaxStreamsBidi = 8,
38 kInitialMaxStreamsUni = 9,
39 kAckDelayExponent = 0xa,
40 kMaxAckDelay = 0xb,
41 kDisableMigration = 0xc,
42 kPreferredAddress = 0xd,
QUICHE teama6ef0a62019-03-07 20:34:33 -050043
dschinazi52127d72019-04-17 15:12:38 -070044 kGoogleQuicParam = 18257, // Used for non-standard Google-specific params.
dschinazi6cf4d2a2019-04-30 16:20:23 -070045 kGoogleQuicVersion =
46 18258, // Used to transmit version and supported_versions.
QUICHE teama6ef0a62019-03-07 20:34:33 -050047};
48
dschinazi52127d72019-04-17 15:12:38 -070049namespace {
QUICHE teama6ef0a62019-03-07 20:34:33 -050050
51// The following constants define minimum and maximum allowed values for some of
dschinazi52127d72019-04-17 15:12:38 -070052// the parameters. These come from the "Transport Parameter Definitions"
53// section of draft-ietf-quic-transport.
54const uint64_t kMinMaxPacketSizeTransportParam = 1200;
55const uint64_t kDefaultMaxPacketSizeTransportParam = 65527;
56const uint64_t kMaxAckDelayExponentTransportParam = 20;
57const uint64_t kDefaultAckDelayExponentTransportParam = 3;
58const uint64_t kMaxMaxAckDelayTransportParam = 16383;
59const uint64_t kDefaultMaxAckDelayTransportParam = 25;
60const size_t kStatelessResetTokenLength = 16;
QUICHE teama6ef0a62019-03-07 20:34:33 -050061
dschinazi52127d72019-04-17 15:12:38 -070062std::string TransportParameterIdToString(
63 TransportParameters::TransportParameterId param_id) {
64 switch (param_id) {
danzh9424add2019-06-06 14:04:36 -070065 case TransportParameters::kOriginalConnectionId:
dschinazi52127d72019-04-17 15:12:38 -070066 return "original_connection_id";
danzh9424add2019-06-06 14:04:36 -070067 case TransportParameters::kIdleTimeout:
dschinazi52127d72019-04-17 15:12:38 -070068 return "idle_timeout";
danzh9424add2019-06-06 14:04:36 -070069 case TransportParameters::kStatelessResetToken:
dschinazi52127d72019-04-17 15:12:38 -070070 return "stateless_reset_token";
danzh9424add2019-06-06 14:04:36 -070071 case TransportParameters::kMaxPacketSize:
dschinazi52127d72019-04-17 15:12:38 -070072 return "max_packet_size";
danzh9424add2019-06-06 14:04:36 -070073 case TransportParameters::kInitialMaxData:
dschinazi52127d72019-04-17 15:12:38 -070074 return "initial_max_data";
danzh9424add2019-06-06 14:04:36 -070075 case TransportParameters::kInitialMaxStreamDataBidiLocal:
dschinazi52127d72019-04-17 15:12:38 -070076 return "initial_max_stream_data_bidi_local";
danzh9424add2019-06-06 14:04:36 -070077 case TransportParameters::kInitialMaxStreamDataBidiRemote:
dschinazi52127d72019-04-17 15:12:38 -070078 return "initial_max_stream_data_bidi_remote";
danzh9424add2019-06-06 14:04:36 -070079 case TransportParameters::kInitialMaxStreamDataUni:
dschinazi52127d72019-04-17 15:12:38 -070080 return "initial_max_stream_data_uni";
danzh9424add2019-06-06 14:04:36 -070081 case TransportParameters::kInitialMaxStreamsBidi:
dschinazi52127d72019-04-17 15:12:38 -070082 return "initial_max_streams_bidi";
danzh9424add2019-06-06 14:04:36 -070083 case TransportParameters::kInitialMaxStreamsUni:
dschinazi52127d72019-04-17 15:12:38 -070084 return "initial_max_streams_uni";
danzh9424add2019-06-06 14:04:36 -070085 case TransportParameters::kAckDelayExponent:
dschinazi52127d72019-04-17 15:12:38 -070086 return "ack_delay_exponent";
danzh9424add2019-06-06 14:04:36 -070087 case TransportParameters::kMaxAckDelay:
dschinazi52127d72019-04-17 15:12:38 -070088 return "max_ack_delay";
danzh9424add2019-06-06 14:04:36 -070089 case TransportParameters::kDisableMigration:
dschinazi52127d72019-04-17 15:12:38 -070090 return "disable_migration";
danzh9424add2019-06-06 14:04:36 -070091 case TransportParameters::kPreferredAddress:
dschinazi52127d72019-04-17 15:12:38 -070092 return "preferred_address";
danzh9424add2019-06-06 14:04:36 -070093 case TransportParameters::kGoogleQuicParam:
dschinazi52127d72019-04-17 15:12:38 -070094 return "google";
danzh9424add2019-06-06 14:04:36 -070095 case TransportParameters::kGoogleQuicVersion:
dschinazi6cf4d2a2019-04-30 16:20:23 -070096 return "google-version";
dschinazi52127d72019-04-17 15:12:38 -070097 }
98 return "Unknown(" + QuicTextUtils::Uint64ToString(param_id) + ")";
99}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100
101} // namespace
102
dschinazi52127d72019-04-17 15:12:38 -0700103TransportParameters::IntegerParameter::IntegerParameter(
104 TransportParameters::TransportParameterId param_id,
105 uint64_t default_value,
106 uint64_t min_value,
107 uint64_t max_value)
108 : param_id_(param_id),
109 value_(default_value),
110 default_value_(default_value),
111 min_value_(min_value),
112 max_value_(max_value),
113 has_been_read_from_cbs_(false) {
114 DCHECK_LE(min_value, default_value);
115 DCHECK_LE(default_value, max_value);
116 DCHECK_LE(max_value, kVarInt62MaxValue);
117}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500118
dschinazi52127d72019-04-17 15:12:38 -0700119TransportParameters::IntegerParameter::IntegerParameter(
120 TransportParameters::TransportParameterId param_id)
121 : TransportParameters::IntegerParameter::IntegerParameter(
122 param_id,
123 0,
124 0,
125 kVarInt62MaxValue) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500126
dschinazi52127d72019-04-17 15:12:38 -0700127void TransportParameters::IntegerParameter::set_value(uint64_t value) {
128 value_ = value;
129}
130
131uint64_t TransportParameters::IntegerParameter::value() const {
132 return value_;
133}
134
135bool TransportParameters::IntegerParameter::IsValid() const {
136 return min_value_ <= value_ && value_ <= max_value_;
137}
138
139bool TransportParameters::IntegerParameter::WriteToCbb(CBB* parent_cbb) const {
140 DCHECK(IsValid());
141 if (value_ == default_value_) {
142 // Do not write if the value is default.
143 return true;
144 }
145 uint8_t encoded_data[sizeof(uint64_t)] = {};
146 QuicDataWriter writer(sizeof(encoded_data),
147 reinterpret_cast<char*>(encoded_data));
148 writer.WriteVarInt62(value_);
149 const uint16_t value_length = writer.length();
150 DCHECK_LE(value_length, sizeof(encoded_data));
151 const bool ok = CBB_add_u16(parent_cbb, param_id_) &&
152 CBB_add_u16(parent_cbb, value_length) &&
153 CBB_add_bytes(parent_cbb, encoded_data, value_length);
154 QUIC_BUG_IF(!ok) << "Failed to write " << this;
155 return ok;
156}
157
158bool TransportParameters::IntegerParameter::ReadFromCbs(CBS* const value_cbs) {
159 if (has_been_read_from_cbs_) {
160 QUIC_DLOG(ERROR) << "Received a second "
161 << TransportParameterIdToString(param_id_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500162 return false;
163 }
dschinazi52127d72019-04-17 15:12:38 -0700164 has_been_read_from_cbs_ = true;
165 QuicDataReader reader(reinterpret_cast<const char*>(CBS_data(value_cbs)),
166 CBS_len(value_cbs));
167 QuicVariableLengthIntegerLength value_length = reader.PeekVarInt62Length();
168 if (value_length == 0 || !reader.ReadVarInt62(&value_)) {
169 QUIC_DLOG(ERROR) << "Failed to parse value for "
170 << TransportParameterIdToString(param_id_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500171 return false;
172 }
dschinazi52127d72019-04-17 15:12:38 -0700173 if (!reader.IsDoneReading()) {
174 QUIC_DLOG(ERROR) << "Received unexpected " << reader.BytesRemaining()
175 << " bytes after parsing " << this;
176 return false;
177 }
178 if (!CBS_skip(value_cbs, value_length)) {
179 QUIC_BUG << "Failed to advance CBS past value for " << this;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500180 return false;
181 }
182 return true;
183}
184
dschinazi52127d72019-04-17 15:12:38 -0700185std::string TransportParameters::IntegerParameter::ToString(
186 bool for_use_in_list) const {
187 if (for_use_in_list && value_ == default_value_) {
188 return "";
189 }
190 std::string rv = for_use_in_list ? " " : "";
191 rv += TransportParameterIdToString(param_id_) + " ";
192 rv += QuicTextUtils::Uint64ToString(value_);
193 if (!IsValid()) {
194 rv += " (Invalid)";
195 }
196 return rv;
197}
198
199std::ostream& operator<<(std::ostream& os,
200 const TransportParameters::IntegerParameter& param) {
201 os << param.ToString(/*for_use_in_list=*/false);
202 return os;
203}
204
205TransportParameters::PreferredAddress::PreferredAddress()
206 : ipv4_socket_address(QuicIpAddress::Any4(), 0),
207 ipv6_socket_address(QuicIpAddress::Any6(), 0),
208 connection_id(EmptyQuicConnectionId()),
209 stateless_reset_token(kStatelessResetTokenLength, 0) {}
210
211TransportParameters::PreferredAddress::~PreferredAddress() {}
212
213std::ostream& operator<<(
214 std::ostream& os,
215 const TransportParameters::PreferredAddress& preferred_address) {
216 os << preferred_address.ToString();
217 return os;
218}
219
220std::string TransportParameters::PreferredAddress::ToString() const {
221 return "[" + ipv4_socket_address.ToString() + " " +
222 ipv6_socket_address.ToString() + " connection_id " +
223 connection_id.ToString() + " stateless_reset_token " +
224 QuicTextUtils::HexEncode(
225 reinterpret_cast<const char*>(stateless_reset_token.data()),
226 stateless_reset_token.size()) +
227 "]";
228}
229
230std::ostream& operator<<(std::ostream& os, const TransportParameters& params) {
231 os << params.ToString();
232 return os;
233}
234
235std::string TransportParameters::ToString() const {
236 std::string rv = "[";
237 if (perspective == Perspective::IS_SERVER) {
238 rv += "Server";
239 } else {
240 rv += "Client";
241 }
242 if (version != 0) {
243 rv += " version " + QuicVersionLabelToString(version);
244 }
245 if (!supported_versions.empty()) {
246 rv += " supported_versions " +
247 QuicVersionLabelVectorToString(supported_versions);
248 }
249 if (!original_connection_id.IsEmpty()) {
250 rv += " " + TransportParameterIdToString(kOriginalConnectionId) + " " +
251 original_connection_id.ToString();
252 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700253 rv += idle_timeout_milliseconds.ToString(/*for_use_in_list=*/true);
dschinazi52127d72019-04-17 15:12:38 -0700254 if (!stateless_reset_token.empty()) {
255 rv += " " + TransportParameterIdToString(kStatelessResetToken) + " " +
256 QuicTextUtils::HexEncode(
257 reinterpret_cast<const char*>(stateless_reset_token.data()),
258 stateless_reset_token.size());
259 }
260 rv += max_packet_size.ToString(/*for_use_in_list=*/true);
261 rv += initial_max_data.ToString(/*for_use_in_list=*/true);
262 rv += initial_max_stream_data_bidi_local.ToString(/*for_use_in_list=*/true);
263 rv += initial_max_stream_data_bidi_remote.ToString(/*for_use_in_list=*/true);
264 rv += initial_max_stream_data_uni.ToString(/*for_use_in_list=*/true);
265 rv += initial_max_streams_bidi.ToString(/*for_use_in_list=*/true);
266 rv += initial_max_streams_uni.ToString(/*for_use_in_list=*/true);
267 rv += ack_delay_exponent.ToString(/*for_use_in_list=*/true);
268 rv += max_ack_delay.ToString(/*for_use_in_list=*/true);
269 if (disable_migration) {
270 rv += " " + TransportParameterIdToString(kDisableMigration);
271 }
272 if (preferred_address) {
273 rv += " " + TransportParameterIdToString(kPreferredAddress) + " " +
274 preferred_address->ToString();
275 }
276 if (google_quic_params) {
277 rv += " " + TransportParameterIdToString(kGoogleQuicParam);
278 }
279 rv += "]";
280 return rv;
281}
282
283TransportParameters::TransportParameters()
284 : version(0),
285 original_connection_id(EmptyQuicConnectionId()),
dschinazi6cf4d2a2019-04-30 16:20:23 -0700286 idle_timeout_milliseconds(kIdleTimeout),
dschinazi52127d72019-04-17 15:12:38 -0700287 max_packet_size(kMaxPacketSize,
288 kDefaultMaxPacketSizeTransportParam,
289 kMinMaxPacketSizeTransportParam,
290 kVarInt62MaxValue),
291 initial_max_data(kInitialMaxData),
292 initial_max_stream_data_bidi_local(kInitialMaxStreamDataBidiLocal),
293 initial_max_stream_data_bidi_remote(kInitialMaxStreamDataBidiRemote),
294 initial_max_stream_data_uni(kInitialMaxStreamDataUni),
295 initial_max_streams_bidi(kInitialMaxStreamsBidi),
296 initial_max_streams_uni(kInitialMaxStreamsUni),
297 ack_delay_exponent(kAckDelayExponent,
298 kDefaultAckDelayExponentTransportParam,
299 0,
300 kMaxAckDelayExponentTransportParam),
301 max_ack_delay(kMaxAckDelay,
302 kDefaultMaxAckDelayTransportParam,
303 0,
304 kMaxMaxAckDelayTransportParam),
305 disable_migration(false)
306// Important note: any new transport parameters must be added
307// to TransportParameters::AreValid, SerializeTransportParameters and
308// ParseTransportParameters.
309{}
310
311bool TransportParameters::AreValid() const {
312 DCHECK(perspective == Perspective::IS_CLIENT ||
313 perspective == Perspective::IS_SERVER);
314 if (perspective == Perspective::IS_CLIENT && !stateless_reset_token.empty()) {
315 QUIC_DLOG(ERROR) << "Client cannot send stateless reset token";
316 return false;
317 }
318 if (perspective == Perspective::IS_CLIENT &&
319 !original_connection_id.IsEmpty()) {
320 QUIC_DLOG(ERROR) << "Client cannot send original connection ID";
321 return false;
322 }
323 if (!stateless_reset_token.empty() &&
324 stateless_reset_token.size() != kStatelessResetTokenLength) {
325 QUIC_DLOG(ERROR) << "Stateless reset token has bad length "
326 << stateless_reset_token.size();
327 return false;
328 }
329 if (perspective == Perspective::IS_CLIENT && preferred_address) {
330 QUIC_DLOG(ERROR) << "Client cannot send preferred address";
331 return false;
332 }
333 if (preferred_address && preferred_address->stateless_reset_token.size() !=
334 kStatelessResetTokenLength) {
335 QUIC_DLOG(ERROR)
336 << "Preferred address stateless reset token has bad length "
337 << preferred_address->stateless_reset_token.size();
338 return false;
339 }
340 if (preferred_address &&
341 (!preferred_address->ipv4_socket_address.host().IsIPv4() ||
342 !preferred_address->ipv6_socket_address.host().IsIPv6())) {
343 QUIC_BUG << "Preferred address family failure";
344 return false;
345 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700346 const bool ok = idle_timeout_milliseconds.IsValid() &&
347 max_packet_size.IsValid() && initial_max_data.IsValid() &&
dschinazi52127d72019-04-17 15:12:38 -0700348 initial_max_stream_data_bidi_local.IsValid() &&
349 initial_max_stream_data_bidi_remote.IsValid() &&
350 initial_max_stream_data_uni.IsValid() &&
351 initial_max_streams_bidi.IsValid() &&
352 initial_max_streams_uni.IsValid() &&
353 ack_delay_exponent.IsValid() && max_ack_delay.IsValid();
354 if (!ok) {
355 QUIC_DLOG(ERROR) << "Invalid transport parameters " << *this;
356 }
357 return ok;
358}
359
360TransportParameters::~TransportParameters() = default;
361
QUICHE teama6ef0a62019-03-07 20:34:33 -0500362bool SerializeTransportParameters(const TransportParameters& in,
363 std::vector<uint8_t>* out) {
dschinazi52127d72019-04-17 15:12:38 -0700364 if (!in.AreValid()) {
365 QUIC_DLOG(ERROR) << "Not serializing invalid transport parameters " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500366 return false;
367 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700368 if (in.version == 0 || (in.perspective == Perspective::IS_SERVER &&
369 in.supported_versions.empty())) {
370 QUIC_DLOG(ERROR) << "Refusing to serialize without versions";
371 return false;
372 }
373
QUICHE teama6ef0a62019-03-07 20:34:33 -0500374 bssl::ScopedCBB cbb;
dschinazi52127d72019-04-17 15:12:38 -0700375 // Empirically transport parameters generally fit within 128 bytes.
376 // The CBB will grow to fit larger serializations if required.
dschinazi6cf4d2a2019-04-30 16:20:23 -0700377 if (!CBB_init(cbb.get(), 128)) {
378 QUIC_BUG << "Failed to initialize CBB for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500379 return false;
380 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500381
dschinazi52127d72019-04-17 15:12:38 -0700382 CBB params;
383 // Add length of the transport parameters list.
384 if (!CBB_add_u16_length_prefixed(cbb.get(), &params)) {
385 QUIC_BUG << "Failed to write parameter length for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500386 return false;
387 }
388
dschinazi52127d72019-04-17 15:12:38 -0700389 // original_connection_id
390 CBB original_connection_id_param;
391 if (!in.original_connection_id.IsEmpty()) {
392 DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
danzh9424add2019-06-06 14:04:36 -0700393 if (!CBB_add_u16(&params, TransportParameters::kOriginalConnectionId) ||
dschinazi52127d72019-04-17 15:12:38 -0700394 !CBB_add_u16_length_prefixed(&params, &original_connection_id_param) ||
395 !CBB_add_bytes(
396 &original_connection_id_param,
397 reinterpret_cast<const uint8_t*>(in.original_connection_id.data()),
398 in.original_connection_id.length())) {
399 QUIC_BUG << "Failed to write original_connection_id "
400 << in.original_connection_id << " for " << in;
401 return false;
402 }
403 }
404
dschinazi6cf4d2a2019-04-30 16:20:23 -0700405 if (!in.idle_timeout_milliseconds.WriteToCbb(&params)) {
dschinazi52127d72019-04-17 15:12:38 -0700406 QUIC_BUG << "Failed to write idle_timeout for " << in;
407 return false;
408 }
409
410 // stateless_reset_token
QUICHE teama6ef0a62019-03-07 20:34:33 -0500411 CBB stateless_reset_token_param;
412 if (!in.stateless_reset_token.empty()) {
dschinazi52127d72019-04-17 15:12:38 -0700413 DCHECK_EQ(kStatelessResetTokenLength, in.stateless_reset_token.size());
414 DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
danzh9424add2019-06-06 14:04:36 -0700415 if (!CBB_add_u16(&params, TransportParameters::kStatelessResetToken) ||
QUICHE teama6ef0a62019-03-07 20:34:33 -0500416 !CBB_add_u16_length_prefixed(&params, &stateless_reset_token_param) ||
417 !CBB_add_bytes(&stateless_reset_token_param,
418 in.stateless_reset_token.data(),
419 in.stateless_reset_token.size())) {
dschinazi52127d72019-04-17 15:12:38 -0700420 QUIC_BUG << "Failed to write stateless_reset_token of length "
421 << in.stateless_reset_token.size() << " for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500422 return false;
423 }
424 }
425
dschinazi52127d72019-04-17 15:12:38 -0700426 if (!in.max_packet_size.WriteToCbb(&params) ||
427 !in.initial_max_data.WriteToCbb(&params) ||
428 !in.initial_max_stream_data_bidi_local.WriteToCbb(&params) ||
429 !in.initial_max_stream_data_bidi_remote.WriteToCbb(&params) ||
430 !in.initial_max_stream_data_uni.WriteToCbb(&params) ||
431 !in.initial_max_streams_bidi.WriteToCbb(&params) ||
432 !in.initial_max_streams_uni.WriteToCbb(&params) ||
433 !in.ack_delay_exponent.WriteToCbb(&params) ||
434 !in.max_ack_delay.WriteToCbb(&params)) {
435 QUIC_BUG << "Failed to write integers for " << in;
436 return false;
437 }
438
439 // disable_migration
440 if (in.disable_migration) {
danzh9424add2019-06-06 14:04:36 -0700441 if (!CBB_add_u16(&params, TransportParameters::kDisableMigration) ||
dschinazi52127d72019-04-17 15:12:38 -0700442 !CBB_add_u16(&params, 0u)) { // 0 is the length of this parameter.
443 QUIC_BUG << "Failed to write disable_migration for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500444 return false;
445 }
446 }
dschinazi52127d72019-04-17 15:12:38 -0700447
448 // preferred_address
449 CBB preferred_address_params, preferred_address_connection_id_param;
450 if (in.preferred_address) {
451 std::string v4_address_bytes =
452 in.preferred_address->ipv4_socket_address.host().ToPackedString();
453 std::string v6_address_bytes =
454 in.preferred_address->ipv6_socket_address.host().ToPackedString();
455 if (v4_address_bytes.length() != 4 || v6_address_bytes.length() != 16 ||
456 in.preferred_address->stateless_reset_token.size() !=
457 kStatelessResetTokenLength) {
458 QUIC_BUG << "Bad lengths " << *in.preferred_address;
459 return false;
460 }
danzh9424add2019-06-06 14:04:36 -0700461 if (!CBB_add_u16(&params, TransportParameters::kPreferredAddress) ||
dschinazi52127d72019-04-17 15:12:38 -0700462 !CBB_add_u16_length_prefixed(&params, &preferred_address_params) ||
463 !CBB_add_bytes(
464 &preferred_address_params,
465 reinterpret_cast<const uint8_t*>(v4_address_bytes.data()),
466 v4_address_bytes.length()) ||
467 !CBB_add_u16(&preferred_address_params,
468 in.preferred_address->ipv4_socket_address.port()) ||
469 !CBB_add_bytes(
470 &preferred_address_params,
471 reinterpret_cast<const uint8_t*>(v6_address_bytes.data()),
472 v6_address_bytes.length()) ||
473 !CBB_add_u16(&preferred_address_params,
474 in.preferred_address->ipv6_socket_address.port()) ||
dschinazi3b5dc922019-05-01 20:58:30 -0700475 !CBB_add_u8_length_prefixed(&preferred_address_params,
476 &preferred_address_connection_id_param) ||
dschinazi52127d72019-04-17 15:12:38 -0700477 !CBB_add_bytes(&preferred_address_connection_id_param,
478 reinterpret_cast<const uint8_t*>(
479 in.preferred_address->connection_id.data()),
480 in.preferred_address->connection_id.length()) ||
481 !CBB_add_bytes(&preferred_address_params,
482 in.preferred_address->stateless_reset_token.data(),
483 in.preferred_address->stateless_reset_token.size())) {
484 QUIC_BUG << "Failed to write preferred_address for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500485 return false;
486 }
487 }
dschinazi52127d72019-04-17 15:12:38 -0700488
489 // Google-specific non-standard parameter.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500490 CBB google_quic_params;
491 if (in.google_quic_params) {
492 const QuicData& serialized_google_quic_params =
493 in.google_quic_params->GetSerialized();
danzh9424add2019-06-06 14:04:36 -0700494 if (!CBB_add_u16(&params, TransportParameters::kGoogleQuicParam) ||
QUICHE teama6ef0a62019-03-07 20:34:33 -0500495 !CBB_add_u16_length_prefixed(&params, &google_quic_params) ||
496 !CBB_add_bytes(&google_quic_params,
497 reinterpret_cast<const uint8_t*>(
498 serialized_google_quic_params.data()),
499 serialized_google_quic_params.length())) {
dschinazi52127d72019-04-17 15:12:38 -0700500 QUIC_BUG << "Failed to write Google params of length "
501 << serialized_google_quic_params.length() << " for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500502 return false;
503 }
504 }
dschinazi6cf4d2a2019-04-30 16:20:23 -0700505
506 // Google-specific version extension.
507 CBB google_version_params;
danzh9424add2019-06-06 14:04:36 -0700508 if (!CBB_add_u16(&params, TransportParameters::kGoogleQuicVersion) ||
dschinazi6cf4d2a2019-04-30 16:20:23 -0700509 !CBB_add_u16_length_prefixed(&params, &google_version_params) ||
510 !CBB_add_u32(&google_version_params, in.version)) {
511 QUIC_BUG << "Failed to write Google version extension for " << in;
512 return false;
513 }
514 CBB versions;
515 if (in.perspective == Perspective::IS_SERVER) {
516 if (!CBB_add_u8_length_prefixed(&google_version_params, &versions)) {
517 QUIC_BUG << "Failed to write versions length for " << in;
518 return false;
519 }
520 for (QuicVersionLabel version : in.supported_versions) {
521 if (!CBB_add_u32(&versions, version)) {
522 QUIC_BUG << "Failed to write supported version for " << in;
523 return false;
524 }
525 }
526 }
527
QUICHE teama6ef0a62019-03-07 20:34:33 -0500528 if (!CBB_flush(cbb.get())) {
dschinazi52127d72019-04-17 15:12:38 -0700529 QUIC_BUG << "Failed to flush CBB for " << in;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500530 return false;
531 }
532 out->resize(CBB_len(cbb.get()));
533 memcpy(out->data(), CBB_data(cbb.get()), CBB_len(cbb.get()));
dschinazi52127d72019-04-17 15:12:38 -0700534 QUIC_DLOG(INFO) << "Serialized " << in << " as " << CBB_len(cbb.get())
535 << " bytes";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500536 return true;
537}
538
539bool ParseTransportParameters(const uint8_t* in,
540 size_t in_len,
541 Perspective perspective,
542 TransportParameters* out) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700543 out->perspective = perspective;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500544 CBS cbs;
545 CBS_init(&cbs, in, in_len);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500546
QUICHE teama6ef0a62019-03-07 20:34:33 -0500547 CBS params;
548 if (!CBS_get_u16_length_prefixed(&cbs, &params)) {
dschinazi52127d72019-04-17 15:12:38 -0700549 QUIC_DLOG(ERROR) << "Failed to parse the number of transport parameters";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500550 return false;
551 }
dschinazi52127d72019-04-17 15:12:38 -0700552
QUICHE teama6ef0a62019-03-07 20:34:33 -0500553 while (CBS_len(&params) > 0) {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700554 TransportParameters::TransportParameterId param_id;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500555 CBS value;
dschinazi6cf4d2a2019-04-30 16:20:23 -0700556 static_assert(sizeof(param_id) == sizeof(uint16_t), "bad size");
557 if (!CBS_get_u16(&params, reinterpret_cast<uint16_t*>(&param_id))) {
dschinazi52127d72019-04-17 15:12:38 -0700558 QUIC_DLOG(ERROR) << "Failed to parse transport parameter ID";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500559 return false;
560 }
dschinazi52127d72019-04-17 15:12:38 -0700561 if (!CBS_get_u16_length_prefixed(&params, &value)) {
562 QUIC_DLOG(ERROR) << "Failed to parse length of transport parameter "
dschinazi6cf4d2a2019-04-30 16:20:23 -0700563 << TransportParameterIdToString(param_id);
dschinazi52127d72019-04-17 15:12:38 -0700564 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500565 }
dschinazi52127d72019-04-17 15:12:38 -0700566 bool parse_success = true;
dschinazi6cf4d2a2019-04-30 16:20:23 -0700567 switch (param_id) {
danzh9424add2019-06-06 14:04:36 -0700568 case TransportParameters::kOriginalConnectionId:
dschinazi52127d72019-04-17 15:12:38 -0700569 if (!out->original_connection_id.IsEmpty()) {
570 QUIC_DLOG(ERROR) << "Received a second original connection ID";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500571 return false;
572 }
dschinazi52127d72019-04-17 15:12:38 -0700573 if (CBS_len(&value) > static_cast<size_t>(kQuicMaxConnectionIdLength)) {
574 QUIC_DLOG(ERROR) << "Received original connection ID of "
575 << "invalid length " << CBS_len(&value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500576 return false;
577 }
dschinazi52127d72019-04-17 15:12:38 -0700578 if (CBS_len(&value) != 0) {
579 out->original_connection_id.set_length(CBS_len(&value));
580 memcpy(out->original_connection_id.mutable_data(), CBS_data(&value),
581 CBS_len(&value));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500582 }
583 break;
danzh9424add2019-06-06 14:04:36 -0700584 case TransportParameters::kIdleTimeout:
dschinazi6cf4d2a2019-04-30 16:20:23 -0700585 parse_success = out->idle_timeout_milliseconds.ReadFromCbs(&value);
dschinazi52127d72019-04-17 15:12:38 -0700586 break;
danzh9424add2019-06-06 14:04:36 -0700587 case TransportParameters::kStatelessResetToken:
dschinazi52127d72019-04-17 15:12:38 -0700588 if (!out->stateless_reset_token.empty()) {
589 QUIC_DLOG(ERROR) << "Received a second stateless reset token";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500590 return false;
591 }
dschinazi52127d72019-04-17 15:12:38 -0700592 if (CBS_len(&value) != kStatelessResetTokenLength) {
593 QUIC_DLOG(ERROR) << "Received stateless reset token of "
594 << "invalid length " << CBS_len(&value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500595 return false;
596 }
597 out->stateless_reset_token.assign(CBS_data(&value),
598 CBS_data(&value) + CBS_len(&value));
599 break;
danzh9424add2019-06-06 14:04:36 -0700600 case TransportParameters::kMaxPacketSize:
dschinazi52127d72019-04-17 15:12:38 -0700601 parse_success = out->max_packet_size.ReadFromCbs(&value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500602 break;
danzh9424add2019-06-06 14:04:36 -0700603 case TransportParameters::kInitialMaxData:
dschinazi52127d72019-04-17 15:12:38 -0700604 parse_success = out->initial_max_data.ReadFromCbs(&value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500605 break;
danzh9424add2019-06-06 14:04:36 -0700606 case TransportParameters::kInitialMaxStreamDataBidiLocal:
dschinazi52127d72019-04-17 15:12:38 -0700607 parse_success =
608 out->initial_max_stream_data_bidi_local.ReadFromCbs(&value);
609 break;
danzh9424add2019-06-06 14:04:36 -0700610 case TransportParameters::kInitialMaxStreamDataBidiRemote:
dschinazi52127d72019-04-17 15:12:38 -0700611 parse_success =
612 out->initial_max_stream_data_bidi_remote.ReadFromCbs(&value);
613 break;
danzh9424add2019-06-06 14:04:36 -0700614 case TransportParameters::kInitialMaxStreamDataUni:
dschinazi52127d72019-04-17 15:12:38 -0700615 parse_success = out->initial_max_stream_data_uni.ReadFromCbs(&value);
616 break;
danzh9424add2019-06-06 14:04:36 -0700617 case TransportParameters::kInitialMaxStreamsBidi:
dschinazi52127d72019-04-17 15:12:38 -0700618 parse_success = out->initial_max_streams_bidi.ReadFromCbs(&value);
619 break;
danzh9424add2019-06-06 14:04:36 -0700620 case TransportParameters::kInitialMaxStreamsUni:
dschinazi52127d72019-04-17 15:12:38 -0700621 parse_success = out->initial_max_streams_uni.ReadFromCbs(&value);
622 break;
danzh9424add2019-06-06 14:04:36 -0700623 case TransportParameters::kAckDelayExponent:
dschinazi52127d72019-04-17 15:12:38 -0700624 parse_success = out->ack_delay_exponent.ReadFromCbs(&value);
625 break;
danzh9424add2019-06-06 14:04:36 -0700626 case TransportParameters::kMaxAckDelay:
dschinazi52127d72019-04-17 15:12:38 -0700627 parse_success = out->max_ack_delay.ReadFromCbs(&value);
628 break;
danzh9424add2019-06-06 14:04:36 -0700629 case TransportParameters::kDisableMigration:
dschinazi52127d72019-04-17 15:12:38 -0700630 if (out->disable_migration) {
631 QUIC_DLOG(ERROR) << "Received a second disable migration";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500632 return false;
633 }
dschinazi52127d72019-04-17 15:12:38 -0700634 if (CBS_len(&value) != 0) {
635 QUIC_DLOG(ERROR) << "Received disable migration of invalid length "
636 << CBS_len(&value);
637 return false;
638 }
639 out->disable_migration = true;
640 break;
danzh9424add2019-06-06 14:04:36 -0700641 case TransportParameters::kPreferredAddress: {
dschinazi52127d72019-04-17 15:12:38 -0700642 uint16_t ipv4_port, ipv6_port;
643 in_addr ipv4_address;
644 in6_addr ipv6_address;
645 if (!CBS_copy_bytes(&value, reinterpret_cast<uint8_t*>(&ipv4_address),
646 sizeof(ipv4_address)) ||
647 !CBS_get_u16(&value, &ipv4_port) ||
648 !CBS_copy_bytes(&value, reinterpret_cast<uint8_t*>(&ipv6_address),
649 sizeof(ipv6_address)) ||
650 !CBS_get_u16(&value, &ipv6_port)) {
651 QUIC_DLOG(ERROR) << "Failed to parse preferred address IPs and ports";
652 return false;
653 }
654 TransportParameters::PreferredAddress preferred_address;
655 preferred_address.ipv4_socket_address =
656 QuicSocketAddress(QuicIpAddress(ipv4_address), ipv4_port);
657 preferred_address.ipv6_socket_address =
658 QuicSocketAddress(QuicIpAddress(ipv6_address), ipv6_port);
659 if (!preferred_address.ipv4_socket_address.host().IsIPv4() ||
660 !preferred_address.ipv6_socket_address.host().IsIPv6()) {
661 QUIC_DLOG(ERROR) << "Received preferred addresses of bad families "
662 << preferred_address;
663 return false;
664 }
665 CBS connection_id_cbs;
dschinazi3b5dc922019-05-01 20:58:30 -0700666 if (!CBS_get_u8_length_prefixed(&value, &connection_id_cbs)) {
dschinazi52127d72019-04-17 15:12:38 -0700667 QUIC_DLOG(ERROR)
668 << "Failed to parse length of preferred address connection ID";
669 return false;
670 }
671 if (CBS_len(&connection_id_cbs) > kQuicMaxConnectionIdLength) {
672 QUIC_DLOG(ERROR) << "Bad preferred address connection ID length";
673 return false;
674 }
675 preferred_address.connection_id.set_length(CBS_len(&connection_id_cbs));
676 if (preferred_address.connection_id.length() > 0 &&
677 !CBS_copy_bytes(&connection_id_cbs,
678 reinterpret_cast<uint8_t*>(
679 preferred_address.connection_id.mutable_data()),
680 preferred_address.connection_id.length())) {
681 QUIC_DLOG(ERROR) << "Failed to read preferred address connection ID";
682 return false;
683 }
684 if (CBS_len(&value) != kStatelessResetTokenLength) {
685 QUIC_DLOG(ERROR) << "Received preferred address with "
686 << "invalid remaining length " << CBS_len(&value);
687 return false;
688 }
689 preferred_address.stateless_reset_token.assign(
690 CBS_data(&value), CBS_data(&value) + CBS_len(&value));
691 out->preferred_address =
692 QuicMakeUnique<TransportParameters::PreferredAddress>(
693 preferred_address);
694 } break;
danzh9424add2019-06-06 14:04:36 -0700695 case TransportParameters::kGoogleQuicParam: {
dschinazi52127d72019-04-17 15:12:38 -0700696 if (out->google_quic_params) {
697 QUIC_DLOG(ERROR) << "Received a second Google parameter";
698 return false;
699 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500700 QuicStringPiece serialized_params(
701 reinterpret_cast<const char*>(CBS_data(&value)), CBS_len(&value));
702 out->google_quic_params = CryptoFramer::ParseMessage(serialized_params);
dschinazi6cf4d2a2019-04-30 16:20:23 -0700703 } break;
danzh9424add2019-06-06 14:04:36 -0700704 case TransportParameters::kGoogleQuicVersion: {
dschinazi6cf4d2a2019-04-30 16:20:23 -0700705 if (!CBS_get_u32(&value, &out->version)) {
706 QUIC_DLOG(ERROR) << "Failed to parse Google version extension";
707 return false;
708 }
709 if (perspective == Perspective::IS_SERVER) {
710 CBS versions;
711 if (!CBS_get_u8_length_prefixed(&value, &versions) ||
712 CBS_len(&versions) % 4 != 0) {
713 QUIC_DLOG(ERROR)
714 << "Failed to parse Google supported versions length";
715 return false;
716 }
717 while (CBS_len(&versions) > 0) {
718 QuicVersionLabel version;
719 if (!CBS_get_u32(&versions, &version)) {
720 QUIC_DLOG(ERROR) << "Failed to parse Google supported version";
721 return false;
722 }
723 out->supported_versions.push_back(version);
724 }
725 }
726 } break;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500727 }
dschinazi52127d72019-04-17 15:12:38 -0700728 if (!parse_success) {
729 return false;
730 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500731 }
dschinazi52127d72019-04-17 15:12:38 -0700732
733 const bool ok = out->AreValid();
734 if (ok) {
735 QUIC_DLOG(INFO) << "Parsed transport parameters " << *out << " from "
736 << in_len << " bytes";
737 } else {
738 QUIC_DLOG(ERROR) << "Transport parameter validity check failed " << *out
739 << " from " << in_len << " bytes";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500740 }
dschinazi52127d72019-04-17 15:12:38 -0700741 return ok;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500742}
743
744} // namespace quic