blob: f316813412540bf4a8daf72afc31797d0ac39e96 [file] [log] [blame]
vasilvve6472f62019-10-02 06:50:56 -07001// Copyright (c) 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h"
6
vasilvvddf52472019-10-04 15:14:02 -07007#include <cstdint>
8#include <limits>
vasilvve6472f62019-10-02 06:50:56 -07009#include <memory>
bnc463f2352019-10-10 04:49:34 -070010#include <utility>
vasilvve6472f62019-10-02 06:50:56 -070011
12#include "url/gurl.h"
13#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
vasilvvddf52472019-10-04 15:14:02 -070014#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
15#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
vasilvve6472f62019-10-02 06:50:56 -070016#include "net/third_party/quiche/src/quic/core/quic_session.h"
17#include "net/third_party/quiche/src/quic/core/quic_types.h"
18#include "net/third_party/quiche/src/quic/core/quic_versions.h"
vasilvvd88f1622019-11-04 13:50:53 -080019#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
vasilvve6472f62019-10-02 06:50:56 -070020#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
21#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
22#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
vasilvvd88f1622019-11-04 13:50:53 -080023#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h"
vasilvv312e3a52019-10-18 15:06:14 -070024#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h"
vasilvve6472f62019-10-02 06:50:56 -070025
26namespace quic {
27
vasilvve6472f62019-10-02 06:50:56 -070028namespace {
29// ProofHandler is primarily used by QUIC crypto to persist QUIC server configs
30// and perform some of related debug logging. QuicTransport does not support
31// QUIC crypto, so those methods are not called.
32class DummyProofHandler : public QuicCryptoClientStream::ProofHandler {
33 public:
34 void OnProofValid(
35 const QuicCryptoClientConfig::CachedState& /*cached*/) override {}
36 void OnProofVerifyDetailsAvailable(
37 const ProofVerifyDetails& /*verify_details*/) override {}
38};
39} // namespace
40
41QuicTransportClientSession::QuicTransportClientSession(
42 QuicConnection* connection,
43 Visitor* owner,
44 const QuicConfig& config,
45 const ParsedQuicVersionVector& supported_versions,
vasilvve58d0f12019-12-04 14:35:25 -080046 const GURL& url,
vasilvve6472f62019-10-02 06:50:56 -070047 QuicCryptoClientConfig* crypto_config,
vasilvvdfbd3df2019-11-01 11:58:43 -070048 url::Origin origin,
49 ClientVisitor* visitor)
vasilvve6472f62019-10-02 06:50:56 -070050 : QuicSession(connection,
51 owner,
52 config,
53 supported_versions,
54 /*num_expected_unidirectional_static_streams*/ 0),
vasilvve58d0f12019-12-04 14:35:25 -080055 url_(url),
vasilvvdfbd3df2019-11-01 11:58:43 -070056 origin_(origin),
57 visitor_(visitor) {
vasilvve6472f62019-10-02 06:50:56 -070058 for (const ParsedQuicVersion& version : supported_versions) {
59 QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3)
60 << "QuicTransport requires TLS 1.3 handshake";
61 }
62 // ProofHandler API is not used by TLS 1.3.
63 static DummyProofHandler* proof_handler = new DummyProofHandler();
64 crypto_stream_ = std::make_unique<QuicCryptoClientStream>(
vasilvve58d0f12019-12-04 14:35:25 -080065 QuicServerId(url.host(), url.EffectiveIntPort()), this,
66 crypto_config->proof_verifier()->CreateDefaultContext(), crypto_config,
67 proof_handler);
vasilvve6472f62019-10-02 06:50:56 -070068}
69
vasilvv467b4222019-12-09 16:22:11 -080070void QuicTransportClientSession::OnAlpnSelected(QuicStringPiece alpn) {
71 // Defense in-depth: ensure the ALPN selected is the desired one.
72 if (alpn != QuicTransportAlpn()) {
73 QUIC_BUG << "QuicTransport negotiated non-QuicTransport ALPN: " << alpn;
74 connection()->CloseConnection(
75 QUIC_INTERNAL_ERROR, "QuicTransport negotiated non-QuicTransport ALPN",
76 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
77 return;
78 }
79
80 alpn_received_ = true;
81}
82
vasilvv312e3a52019-10-18 15:06:14 -070083QuicStream* QuicTransportClientSession::CreateIncomingStream(QuicStreamId id) {
vasilvvdfbd3df2019-11-01 11:58:43 -070084 QUIC_DVLOG(1) << "Creating incoming QuicTransport stream " << id;
vasilvvd88f1622019-11-04 13:50:53 -080085 QuicTransportStream* stream = CreateStream(id);
86 if (stream->type() == BIDIRECTIONAL) {
87 incoming_bidirectional_streams_.push_back(stream);
vasilvvdfbd3df2019-11-01 11:58:43 -070088 visitor_->OnIncomingBidirectionalStreamAvailable();
89 } else {
vasilvvd88f1622019-11-04 13:50:53 -080090 incoming_unidirectional_streams_.push_back(stream);
vasilvvdfbd3df2019-11-01 11:58:43 -070091 visitor_->OnIncomingUnidirectionalStreamAvailable();
92 }
vasilvvd88f1622019-11-04 13:50:53 -080093 return stream;
vasilvv312e3a52019-10-18 15:06:14 -070094}
95
vasilvve6472f62019-10-02 06:50:56 -070096void QuicTransportClientSession::OnCryptoHandshakeEvent(
97 CryptoHandshakeEvent event) {
98 QuicSession::OnCryptoHandshakeEvent(event);
99 if (event != HANDSHAKE_CONFIRMED) {
100 return;
101 }
102
vasilvvddf52472019-10-04 15:14:02 -0700103 SendClientIndication();
104}
105
fayangd58736d2019-11-27 13:35:31 -0800106void QuicTransportClientSession::SetDefaultEncryptionLevel(
107 EncryptionLevel level) {
108 QuicSession::SetDefaultEncryptionLevel(level);
109 if (level == ENCRYPTION_FORWARD_SECURE) {
110 SendClientIndication();
111 }
112}
113
vasilvvdfbd3df2019-11-01 11:58:43 -0700114QuicTransportStream*
115QuicTransportClientSession::AcceptIncomingBidirectionalStream() {
116 if (incoming_bidirectional_streams_.empty()) {
117 return nullptr;
118 }
119 QuicTransportStream* stream = incoming_bidirectional_streams_.front();
120 incoming_bidirectional_streams_.pop_front();
121 return stream;
122}
123
124QuicTransportStream*
125QuicTransportClientSession::AcceptIncomingUnidirectionalStream() {
126 if (incoming_unidirectional_streams_.empty()) {
127 return nullptr;
128 }
129 QuicTransportStream* stream = incoming_unidirectional_streams_.front();
130 incoming_unidirectional_streams_.pop_front();
131 return stream;
132}
133
vasilvvd88f1622019-11-04 13:50:53 -0800134QuicTransportStream*
135QuicTransportClientSession::OpenOutgoingBidirectionalStream() {
136 if (!CanOpenNextOutgoingBidirectionalStream()) {
137 QUIC_BUG << "Attempted to open a stream in violation of flow control";
138 return nullptr;
139 }
140 return CreateStream(GetNextOutgoingBidirectionalStreamId());
141}
142
143QuicTransportStream*
144QuicTransportClientSession::OpenOutgoingUnidirectionalStream() {
145 if (!CanOpenNextOutgoingUnidirectionalStream()) {
146 QUIC_BUG << "Attempted to open a stream in violation of flow control";
147 return nullptr;
148 }
149 return CreateStream(GetNextOutgoingUnidirectionalStreamId());
150}
151
152QuicTransportStream* QuicTransportClientSession::CreateStream(QuicStreamId id) {
153 auto stream = std::make_unique<QuicTransportStream>(id, this, this);
154 QuicTransportStream* stream_ptr = stream.get();
155 ActivateStream(std::move(stream));
156 return stream_ptr;
157}
158
vasilvvddf52472019-10-04 15:14:02 -0700159std::string QuicTransportClientSession::SerializeClientIndication() {
160 std::string serialized_origin = origin_.Serialize();
161 if (serialized_origin.size() > std::numeric_limits<uint16_t>::max()) {
162 QUIC_BUG << "Client origin too long";
vasilvve6472f62019-10-02 06:50:56 -0700163 connection()->CloseConnection(
vasilvvddf52472019-10-04 15:14:02 -0700164 QUIC_INTERNAL_ERROR, "Client origin too long",
165 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
166 return "";
167 }
168 QUIC_DLOG(INFO) << "Sending client indication with origin "
169 << serialized_origin;
170
vasilvve58d0f12019-12-04 14:35:25 -0800171 std::string path = url_.PathForRequest();
172 if (path.size() > std::numeric_limits<uint16_t>::max()) {
173 connection()->CloseConnection(
174 QUIC_TRANSPORT_INVALID_CLIENT_INDICATION, "Requested URL path too long",
175 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
176 return "";
177 }
vasilvvddf52472019-10-04 15:14:02 -0700178
vasilvve58d0f12019-12-04 14:35:25 -0800179 constexpr size_t kPrefixSize =
180 sizeof(QuicTransportClientIndicationKeys) + sizeof(uint16_t);
181 const size_t buffer_size =
182 2 * kPrefixSize + serialized_origin.size() + path.size();
183 if (buffer_size > std::numeric_limits<uint16_t>::max()) {
184 connection()->CloseConnection(
185 QUIC_TRANSPORT_INVALID_CLIENT_INDICATION,
186 "Client indication size limit exceeded",
187 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
188 return "";
189 }
190
191 std::string buffer;
192 buffer.resize(buffer_size);
193 QuicDataWriter writer(buffer.size(), &buffer[0]);
194 bool success =
195 writer.WriteUInt16(
196 static_cast<uint16_t>(QuicTransportClientIndicationKeys::kOrigin)) &&
197 writer.WriteUInt16(serialized_origin.size()) &&
198 writer.WriteStringPiece(serialized_origin) &&
199 writer.WriteUInt16(
200 static_cast<uint16_t>(QuicTransportClientIndicationKeys::kPath)) &&
201 writer.WriteUInt16(path.size()) && writer.WriteStringPiece(path);
202 QUIC_BUG_IF(!success) << "Failed to serialize client indication";
203 QUIC_BUG_IF(writer.length() != buffer.length())
204 << "Serialized client indication has length different from expected";
vasilvvddf52472019-10-04 15:14:02 -0700205 return buffer;
206}
207
208void QuicTransportClientSession::SendClientIndication() {
209 if (!crypto_stream_->encryption_established()) {
210 QUIC_BUG << "Client indication may only be sent once the encryption is "
211 "established.";
212 connection()->CloseConnection(
213 QUIC_INTERNAL_ERROR, "Attempted to send client indication unencrypted",
214 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
215 return;
216 }
vasilvv59dc4b62019-10-11 12:56:14 -0700217 if (ready_) {
vasilvvddf52472019-10-04 15:14:02 -0700218 QUIC_BUG << "Client indication may only be sent once.";
219 connection()->CloseConnection(
220 QUIC_INTERNAL_ERROR, "Attempted to send client indication twice",
vasilvve6472f62019-10-02 06:50:56 -0700221 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
222 return;
223 }
224
vasilvvddf52472019-10-04 15:14:02 -0700225 auto client_indication_owned = std::make_unique<ClientIndication>(
vasilvvd88f1622019-11-04 13:50:53 -0800226 /*stream_id=*/GetNextOutgoingUnidirectionalStreamId(), this,
227 /*is_static=*/false, WRITE_UNIDIRECTIONAL);
228 QUIC_BUG_IF(client_indication_owned->id() != ClientIndicationStream())
229 << "Client indication stream is " << client_indication_owned->id()
230 << " instead of expected " << ClientIndicationStream();
vasilvvddf52472019-10-04 15:14:02 -0700231 ClientIndication* client_indication = client_indication_owned.get();
232 ActivateStream(std::move(client_indication_owned));
vasilvve6472f62019-10-02 06:50:56 -0700233
vasilvvddf52472019-10-04 15:14:02 -0700234 client_indication->WriteOrBufferData(SerializeClientIndication(),
235 /*fin=*/true, nullptr);
236 client_indication_sent_ = true;
vasilvv59dc4b62019-10-11 12:56:14 -0700237
vasilvv467b4222019-12-09 16:22:11 -0800238 // Defense in depth: never set the ready bit unless ALPN has been confirmed.
239 if (!alpn_received_) {
240 QUIC_BUG << "ALPN confirmation missing after handshake complete";
241 connection()->CloseConnection(
242 QUIC_INTERNAL_ERROR,
243 "ALPN confirmation missing after handshake complete",
244 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
245 return;
246 }
247
vasilvv59dc4b62019-10-11 12:56:14 -0700248 // Don't set the ready bit if we closed the connection due to any error
249 // beforehand.
250 if (!connection()->connected()) {
251 return;
252 }
vasilvv467b4222019-12-09 16:22:11 -0800253
vasilvv59dc4b62019-10-11 12:56:14 -0700254 ready_ = true;
vasilvv467b4222019-12-09 16:22:11 -0800255 visitor_->OnSessionReady();
vasilvve6472f62019-10-02 06:50:56 -0700256}
257
258} // namespace quic