blob: 45465cf94da978b5aab7e9570723484de53d3748 [file] [log] [blame]
vasilvvefc6af82019-10-11 12:46: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_server_session.h"
6
vasilvv78571892019-12-06 07:14:57 -08007#include <algorithm>
vasilvvefc6af82019-10-11 12:46:56 -07008#include <memory>
vasilvv78571892019-12-06 07:14:57 -08009#include <string>
vasilvvefc6af82019-10-11 12:46:56 -070010
11#include "url/gurl.h"
vasilvv78571892019-12-06 07:14:57 -080012#include "url/url_constants.h"
vasilvvefc6af82019-10-11 12:46:56 -070013#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
14#include "net/third_party/quiche/src/quic/core/quic_stream.h"
15#include "net/third_party/quiche/src/quic/core/quic_types.h"
vasilvvefc6af82019-10-11 12:46:56 -070016#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h"
vasilvv312e3a52019-10-18 15:06:14 -070017#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h"
dmcardle1ec11192019-12-12 10:36:42 -080018#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
19#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
vasilvvefc6af82019-10-11 12:46:56 -070020
21namespace quic {
22
23namespace {
24class QuicTransportServerCryptoHelper : public QuicCryptoServerStream::Helper {
25 public:
26 bool CanAcceptClientHello(const CryptoHandshakeMessage& /*message*/,
27 const QuicSocketAddress& /*client_address*/,
28 const QuicSocketAddress& /*peer_address*/,
29 const QuicSocketAddress& /*self_address*/,
30 std::string* /*error_details*/) const override {
31 return true;
32 }
33};
vasilvv78571892019-12-06 07:14:57 -080034
vasilvvefc6af82019-10-11 12:46:56 -070035} // namespace
36
37QuicTransportServerSession::QuicTransportServerSession(
38 QuicConnection* connection,
39 Visitor* owner,
40 const QuicConfig& config,
41 const ParsedQuicVersionVector& supported_versions,
42 const QuicCryptoServerConfig* crypto_config,
43 QuicCompressedCertsCache* compressed_certs_cache,
44 ServerVisitor* visitor)
45 : QuicSession(connection,
46 owner,
47 config,
48 supported_versions,
49 /*num_expected_unidirectional_static_streams*/ 0),
50 visitor_(visitor) {
51 for (const ParsedQuicVersion& version : supported_versions) {
52 QUIC_BUG_IF(version.handshake_protocol != PROTOCOL_TLS1_3)
53 << "QuicTransport requires TLS 1.3 handshake";
54 }
55
56 static QuicTransportServerCryptoHelper* helper =
57 new QuicTransportServerCryptoHelper();
nharpere5e28f92020-01-03 14:10:07 -080058 crypto_stream_ = CreateCryptoServerStream(
vasilvvefc6af82019-10-11 12:46:56 -070059 crypto_config, compressed_certs_cache, this, helper);
60}
61
62QuicStream* QuicTransportServerSession::CreateIncomingStream(QuicStreamId id) {
63 if (id == ClientIndicationStream()) {
64 auto indication = std::make_unique<ClientIndication>(this);
65 ClientIndication* indication_ptr = indication.get();
66 ActivateStream(std::move(indication));
67 return indication_ptr;
68 }
69
vasilvv312e3a52019-10-18 15:06:14 -070070 auto stream = std::make_unique<QuicTransportStream>(id, this, this);
71 QuicTransportStream* stream_ptr = stream.get();
72 ActivateStream(std::move(stream));
vasilvvd88f1622019-11-04 13:50:53 -080073 OnIncomingDataStream(stream_ptr);
vasilvv312e3a52019-10-18 15:06:14 -070074 return stream_ptr;
vasilvvefc6af82019-10-11 12:46:56 -070075}
76
77QuicTransportServerSession::ClientIndication::ClientIndication(
78 QuicTransportServerSession* session)
79 : QuicStream(ClientIndicationStream(),
80 session,
81 /* is_static= */ false,
82 StreamType::READ_UNIDIRECTIONAL),
83 session_(session) {}
84
85void QuicTransportServerSession::ClientIndication::OnDataAvailable() {
86 sequencer()->Read(&buffer_);
87 if (buffer_.size() > ClientIndicationMaxSize()) {
88 session_->connection()->CloseConnection(
89 QUIC_TRANSPORT_INVALID_CLIENT_INDICATION,
dmcardle1ec11192019-12-12 10:36:42 -080090 quiche::QuicheStrCat("Client indication size exceeds ",
91 ClientIndicationMaxSize(), " bytes"),
vasilvvefc6af82019-10-11 12:46:56 -070092 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
93 return;
94 }
95 if (sequencer()->IsClosed()) {
96 session_->ProcessClientIndication(buffer_);
97 OnFinRead();
98 }
99}
100
101bool QuicTransportServerSession::ClientIndicationParser::Parse() {
102 bool origin_received = false;
vasilvv78571892019-12-06 07:14:57 -0800103 bool path_received = false;
vasilvvefc6af82019-10-11 12:46:56 -0700104 while (!reader_.IsDoneReading()) {
105 uint16_t key;
106 if (!reader_.ReadUInt16(&key)) {
107 ParseError("Expected 16-bit key");
108 return false;
109 }
110
dmcardle1ec11192019-12-12 10:36:42 -0800111 quiche::QuicheStringPiece value;
vasilvvefc6af82019-10-11 12:46:56 -0700112 if (!reader_.ReadStringPiece16(&value)) {
dmcardle1ec11192019-12-12 10:36:42 -0800113 ParseError(quiche::QuicheStrCat("Failed to read value for key ", key));
vasilvvefc6af82019-10-11 12:46:56 -0700114 return false;
115 }
116
117 switch (static_cast<QuicTransportClientIndicationKeys>(key)) {
118 case QuicTransportClientIndicationKeys::kOrigin: {
119 GURL origin_url{std::string(value)};
120 if (!origin_url.is_valid()) {
121 Error("Unable to parse the specified origin");
122 return false;
123 }
124
125 url::Origin origin = url::Origin::Create(origin_url);
126 QUIC_DLOG(INFO) << "QuicTransport server received origin " << origin;
127 if (!session_->visitor_->CheckOrigin(origin)) {
128 Error("Origin check failed");
129 return false;
130 }
131 origin_received = true;
132 break;
133 }
134
vasilvv78571892019-12-06 07:14:57 -0800135 case QuicTransportClientIndicationKeys::kPath: {
136 if (!ProcessPath(value)) {
137 return false;
138 }
139 path_received = true;
140 break;
141 }
142
vasilvvefc6af82019-10-11 12:46:56 -0700143 default:
144 QUIC_DLOG(INFO) << "Unknown client indication key: " << key;
145 break;
146 }
147 }
148
149 if (!origin_received) {
150 Error("No origin received");
151 return false;
152 }
vasilvv78571892019-12-06 07:14:57 -0800153 if (!path_received) {
154 Error("No path received");
155 return false;
156 }
vasilvvefc6af82019-10-11 12:46:56 -0700157
158 return true;
159}
160
vasilvv78571892019-12-06 07:14:57 -0800161bool QuicTransportServerSession::ClientIndicationParser::ProcessPath(
dmcardle1ec11192019-12-12 10:36:42 -0800162 quiche::QuicheStringPiece path) {
vasilvv78571892019-12-06 07:14:57 -0800163 if (path.empty() || path[0] != '/') {
164 // https://tools.ietf.org/html/draft-vvv-webtransport-quic-01#section-3.2.2
165 Error("Path must begin with a '/'");
166 return false;
167 }
168
169 // TODO(b/145674008): use the SNI value from the handshake instead of the IP
170 // address.
dmcardle1ec11192019-12-12 10:36:42 -0800171 std::string url_text = quiche::QuicheStrCat(
172 url::kQuicTransportScheme, url::kStandardSchemeSeparator,
173 session_->self_address().ToString(), path);
vasilvv78571892019-12-06 07:14:57 -0800174 GURL url{url_text};
175 if (!url.is_valid()) {
176 Error("Invalid path specified");
177 return false;
178 }
179
180 if (!session_->visitor_->ProcessPath(url)) {
181 Error("Specified path rejected");
182 return false;
183 }
184 return true;
185}
186
vasilvvefc6af82019-10-11 12:46:56 -0700187void QuicTransportServerSession::ClientIndicationParser::Error(
188 const std::string& error_message) {
189 session_->connection()->CloseConnection(
190 QUIC_TRANSPORT_INVALID_CLIENT_INDICATION, error_message,
191 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
192}
193
194void QuicTransportServerSession::ClientIndicationParser::ParseError(
dmcardle1ec11192019-12-12 10:36:42 -0800195 quiche::QuicheStringPiece error_message) {
196 Error(quiche::QuicheStrCat("Failed to parse the client indication stream: ",
197 error_message, reader_.DebugString()));
vasilvvefc6af82019-10-11 12:46:56 -0700198}
199
200void QuicTransportServerSession::ProcessClientIndication(
dmcardle1ec11192019-12-12 10:36:42 -0800201 quiche::QuicheStringPiece indication) {
vasilvvefc6af82019-10-11 12:46:56 -0700202 ClientIndicationParser parser(this, indication);
203 if (!parser.Parse()) {
204 return;
205 }
vasilvv59dc4b62019-10-11 12:56:14 -0700206 // Don't set the ready bit if we closed the connection due to any error
207 // beforehand.
208 if (!connection()->connected()) {
209 return;
210 }
211 ready_ = true;
vasilvvefc6af82019-10-11 12:46:56 -0700212}
213
214} // namespace quic