Update QUIC transport parameters to draft 20
This CL updates from draft-18 to draft-19/20. The only changes are idle_timeout being in milliseconds instead of seconds, and the removal of the versions before the parameters. We've kept the versions in a custom Google-specific extension for now. This extension will eventually evolve into the IETF compatible version negotiation extension.
gfe-relnote: protected by disabled flag quic_supports_tls_handshake
PiperOrigin-RevId: 246043673
Change-Id: I35929d0f381f506e2275e639af41e840ab16b8ca
diff --git a/quic/core/crypto/transport_parameters.cc b/quic/core/crypto/transport_parameters.cc
index 84022fe..8982ae0 100644
--- a/quic/core/crypto/transport_parameters.cc
+++ b/quic/core/crypto/transport_parameters.cc
@@ -4,6 +4,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
+#include <cstdint>
#include <cstring>
#include "third_party/boringssl/src/include/openssl/bytestring.h"
@@ -41,6 +42,8 @@
kPreferredAddress = 0xd,
kGoogleQuicParam = 18257, // Used for non-standard Google-specific params.
+ kGoogleQuicVersion =
+ 18258, // Used to transmit version and supported_versions.
};
namespace {
@@ -89,6 +92,8 @@
return "preferred_address";
case kGoogleQuicParam:
return "google";
+ case kGoogleQuicVersion:
+ return "google-version";
}
return "Unknown(" + QuicTextUtils::Uint64ToString(param_id) + ")";
}
@@ -245,7 +250,7 @@
rv += " " + TransportParameterIdToString(kOriginalConnectionId) + " " +
original_connection_id.ToString();
}
- rv += idle_timeout_seconds.ToString(/*for_use_in_list=*/true);
+ rv += idle_timeout_milliseconds.ToString(/*for_use_in_list=*/true);
if (!stateless_reset_token.empty()) {
rv += " " + TransportParameterIdToString(kStatelessResetToken) + " " +
QuicTextUtils::HexEncode(
@@ -278,7 +283,7 @@
TransportParameters::TransportParameters()
: version(0),
original_connection_id(EmptyQuicConnectionId()),
- idle_timeout_seconds(kIdleTimeout),
+ idle_timeout_milliseconds(kIdleTimeout),
max_packet_size(kMaxPacketSize,
kDefaultMaxPacketSizeTransportParam,
kMinMaxPacketSizeTransportParam,
@@ -338,8 +343,8 @@
QUIC_BUG << "Preferred address family failure";
return false;
}
- const bool ok = idle_timeout_seconds.IsValid() && max_packet_size.IsValid() &&
- initial_max_data.IsValid() &&
+ const bool ok = idle_timeout_milliseconds.IsValid() &&
+ max_packet_size.IsValid() && initial_max_data.IsValid() &&
initial_max_stream_data_bidi_local.IsValid() &&
initial_max_stream_data_bidi_remote.IsValid() &&
initial_max_stream_data_uni.IsValid() &&
@@ -360,26 +365,19 @@
QUIC_DLOG(ERROR) << "Not serializing invalid transport parameters " << in;
return false;
}
+ if (in.version == 0 || (in.perspective == Perspective::IS_SERVER &&
+ in.supported_versions.empty())) {
+ QUIC_DLOG(ERROR) << "Refusing to serialize without versions";
+ return false;
+ }
+
bssl::ScopedCBB cbb;
// Empirically transport parameters generally fit within 128 bytes.
// The CBB will grow to fit larger serializations if required.
- if (!CBB_init(cbb.get(), 128) || !CBB_add_u32(cbb.get(), in.version)) {
- QUIC_BUG << "Failed to write version for " << in;
+ if (!CBB_init(cbb.get(), 128)) {
+ QUIC_BUG << "Failed to initialize CBB for " << in;
return false;
}
- CBB versions;
- if (in.perspective == Perspective::IS_SERVER) {
- if (!CBB_add_u8_length_prefixed(cbb.get(), &versions)) {
- QUIC_BUG << "Failed to write versions length for " << in;
- return false;
- }
- for (QuicVersionLabel version : in.supported_versions) {
- if (!CBB_add_u32(&versions, version)) {
- QUIC_BUG << "Failed to write supported version for " << in;
- return false;
- }
- }
- }
CBB params;
// Add length of the transport parameters list.
@@ -404,7 +402,7 @@
}
}
- if (!in.idle_timeout_seconds.WriteToCbb(¶ms)) {
+ if (!in.idle_timeout_milliseconds.WriteToCbb(¶ms)) {
QUIC_BUG << "Failed to write idle_timeout for " << in;
return false;
}
@@ -504,6 +502,29 @@
return false;
}
}
+
+ // Google-specific version extension.
+ CBB google_version_params;
+ if (!CBB_add_u16(¶ms, kGoogleQuicVersion) ||
+ !CBB_add_u16_length_prefixed(¶ms, &google_version_params) ||
+ !CBB_add_u32(&google_version_params, in.version)) {
+ QUIC_BUG << "Failed to write Google version extension for " << in;
+ return false;
+ }
+ CBB versions;
+ if (in.perspective == Perspective::IS_SERVER) {
+ if (!CBB_add_u8_length_prefixed(&google_version_params, &versions)) {
+ QUIC_BUG << "Failed to write versions length for " << in;
+ return false;
+ }
+ for (QuicVersionLabel version : in.supported_versions) {
+ if (!CBB_add_u32(&versions, version)) {
+ QUIC_BUG << "Failed to write supported version for " << in;
+ return false;
+ }
+ }
+ }
+
if (!CBB_flush(cbb.get())) {
QUIC_BUG << "Failed to flush CBB for " << in;
return false;
@@ -519,31 +540,9 @@
size_t in_len,
Perspective perspective,
TransportParameters* out) {
+ out->perspective = perspective;
CBS cbs;
CBS_init(&cbs, in, in_len);
- if (!CBS_get_u32(&cbs, &out->version)) {
- QUIC_DLOG(ERROR) << "Failed to parse transport parameter version";
- return false;
- }
- if (perspective == Perspective::IS_SERVER) {
- CBS versions;
- if (!CBS_get_u8_length_prefixed(&cbs, &versions) ||
- CBS_len(&versions) % 4 != 0) {
- QUIC_DLOG(ERROR)
- << "Failed to parse transport parameter supported versions";
- return false;
- }
- while (CBS_len(&versions) > 0) {
- QuicVersionLabel version;
- if (!CBS_get_u32(&versions, &version)) {
- QUIC_DLOG(ERROR)
- << "Failed to parse transport parameter supported version";
- return false;
- }
- out->supported_versions.push_back(version);
- }
- }
- out->perspective = perspective;
CBS params;
if (!CBS_get_u16_length_prefixed(&cbs, ¶ms)) {
@@ -552,19 +551,20 @@
}
while (CBS_len(¶ms) > 0) {
- uint16_t param_id;
+ TransportParameters::TransportParameterId param_id;
CBS value;
- if (!CBS_get_u16(¶ms, ¶m_id)) {
+ static_assert(sizeof(param_id) == sizeof(uint16_t), "bad size");
+ if (!CBS_get_u16(¶ms, reinterpret_cast<uint16_t*>(¶m_id))) {
QUIC_DLOG(ERROR) << "Failed to parse transport parameter ID";
return false;
}
if (!CBS_get_u16_length_prefixed(¶ms, &value)) {
QUIC_DLOG(ERROR) << "Failed to parse length of transport parameter "
- << param_id;
+ << TransportParameterIdToString(param_id);
return false;
}
bool parse_success = true;
- switch (static_cast<TransportParameters::TransportParameterId>(param_id)) {
+ switch (param_id) {
case kOriginalConnectionId:
if (!out->original_connection_id.IsEmpty()) {
QUIC_DLOG(ERROR) << "Received a second original connection ID";
@@ -582,7 +582,7 @@
}
break;
case kIdleTimeout:
- parse_success = out->idle_timeout_seconds.ReadFromCbs(&value);
+ parse_success = out->idle_timeout_milliseconds.ReadFromCbs(&value);
break;
case kStatelessResetToken:
if (!out->stateless_reset_token.empty()) {
@@ -692,7 +692,7 @@
QuicMakeUnique<TransportParameters::PreferredAddress>(
preferred_address);
} break;
- case kGoogleQuicParam:
+ case kGoogleQuicParam: {
if (out->google_quic_params) {
QUIC_DLOG(ERROR) << "Received a second Google parameter";
return false;
@@ -700,6 +700,30 @@
QuicStringPiece serialized_params(
reinterpret_cast<const char*>(CBS_data(&value)), CBS_len(&value));
out->google_quic_params = CryptoFramer::ParseMessage(serialized_params);
+ } break;
+ case kGoogleQuicVersion: {
+ if (!CBS_get_u32(&value, &out->version)) {
+ QUIC_DLOG(ERROR) << "Failed to parse Google version extension";
+ return false;
+ }
+ if (perspective == Perspective::IS_SERVER) {
+ CBS versions;
+ if (!CBS_get_u8_length_prefixed(&value, &versions) ||
+ CBS_len(&versions) % 4 != 0) {
+ QUIC_DLOG(ERROR)
+ << "Failed to parse Google supported versions length";
+ return false;
+ }
+ while (CBS_len(&versions) > 0) {
+ QuicVersionLabel version;
+ if (!CBS_get_u32(&versions, &version)) {
+ QUIC_DLOG(ERROR) << "Failed to parse Google supported version";
+ return false;
+ }
+ out->supported_versions.push_back(version);
+ }
+ }
+ } break;
}
if (!parse_success) {
return false;