vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 1 | // 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 | |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 7 | #include <algorithm> |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 8 | #include <memory> |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 9 | #include <string> |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 10 | |
| 11 | #include "url/gurl.h" |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 12 | #include "url/url_constants.h" |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 13 | #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" |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 16 | #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_protocol.h" |
vasilvv | 312e3a5 | 2019-10-18 15:06:14 -0700 | [diff] [blame] | 17 | #include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h" |
dmcardle | 1ec1119 | 2019-12-12 10:36:42 -0800 | [diff] [blame] | 18 | #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" |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 20 | |
| 21 | namespace quic { |
| 22 | |
| 23 | namespace { |
| 24 | class 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 | }; |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 34 | |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 35 | } // namespace |
| 36 | |
| 37 | QuicTransportServerSession::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(); |
nharper | e5e28f9 | 2020-01-03 14:10:07 -0800 | [diff] [blame] | 58 | crypto_stream_ = CreateCryptoServerStream( |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 59 | crypto_config, compressed_certs_cache, this, helper); |
| 60 | } |
| 61 | |
| 62 | QuicStream* 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 | |
vasilvv | 312e3a5 | 2019-10-18 15:06:14 -0700 | [diff] [blame] | 70 | auto stream = std::make_unique<QuicTransportStream>(id, this, this); |
| 71 | QuicTransportStream* stream_ptr = stream.get(); |
| 72 | ActivateStream(std::move(stream)); |
vasilvv | d88f162 | 2019-11-04 13:50:53 -0800 | [diff] [blame] | 73 | OnIncomingDataStream(stream_ptr); |
vasilvv | 312e3a5 | 2019-10-18 15:06:14 -0700 | [diff] [blame] | 74 | return stream_ptr; |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 75 | } |
| 76 | |
| 77 | QuicTransportServerSession::ClientIndication::ClientIndication( |
| 78 | QuicTransportServerSession* session) |
| 79 | : QuicStream(ClientIndicationStream(), |
| 80 | session, |
| 81 | /* is_static= */ false, |
| 82 | StreamType::READ_UNIDIRECTIONAL), |
| 83 | session_(session) {} |
| 84 | |
| 85 | void QuicTransportServerSession::ClientIndication::OnDataAvailable() { |
| 86 | sequencer()->Read(&buffer_); |
| 87 | if (buffer_.size() > ClientIndicationMaxSize()) { |
| 88 | session_->connection()->CloseConnection( |
| 89 | QUIC_TRANSPORT_INVALID_CLIENT_INDICATION, |
dmcardle | 1ec1119 | 2019-12-12 10:36:42 -0800 | [diff] [blame] | 90 | quiche::QuicheStrCat("Client indication size exceeds ", |
| 91 | ClientIndicationMaxSize(), " bytes"), |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 92 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 93 | return; |
| 94 | } |
| 95 | if (sequencer()->IsClosed()) { |
| 96 | session_->ProcessClientIndication(buffer_); |
| 97 | OnFinRead(); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | bool QuicTransportServerSession::ClientIndicationParser::Parse() { |
| 102 | bool origin_received = false; |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 103 | bool path_received = false; |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 104 | while (!reader_.IsDoneReading()) { |
| 105 | uint16_t key; |
| 106 | if (!reader_.ReadUInt16(&key)) { |
| 107 | ParseError("Expected 16-bit key"); |
| 108 | return false; |
| 109 | } |
| 110 | |
dmcardle | 1ec1119 | 2019-12-12 10:36:42 -0800 | [diff] [blame] | 111 | quiche::QuicheStringPiece value; |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 112 | if (!reader_.ReadStringPiece16(&value)) { |
dmcardle | 1ec1119 | 2019-12-12 10:36:42 -0800 | [diff] [blame] | 113 | ParseError(quiche::QuicheStrCat("Failed to read value for key ", key)); |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 114 | 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 | |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 135 | case QuicTransportClientIndicationKeys::kPath: { |
| 136 | if (!ProcessPath(value)) { |
| 137 | return false; |
| 138 | } |
| 139 | path_received = true; |
| 140 | break; |
| 141 | } |
| 142 | |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 143 | 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 | } |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 153 | if (!path_received) { |
| 154 | Error("No path received"); |
| 155 | return false; |
| 156 | } |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 157 | |
| 158 | return true; |
| 159 | } |
| 160 | |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 161 | bool QuicTransportServerSession::ClientIndicationParser::ProcessPath( |
dmcardle | 1ec1119 | 2019-12-12 10:36:42 -0800 | [diff] [blame] | 162 | quiche::QuicheStringPiece path) { |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 163 | 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. |
dmcardle | 1ec1119 | 2019-12-12 10:36:42 -0800 | [diff] [blame] | 171 | std::string url_text = quiche::QuicheStrCat( |
| 172 | url::kQuicTransportScheme, url::kStandardSchemeSeparator, |
| 173 | session_->self_address().ToString(), path); |
vasilvv | 7857189 | 2019-12-06 07:14:57 -0800 | [diff] [blame] | 174 | 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 | |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 187 | void 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 | |
| 194 | void QuicTransportServerSession::ClientIndicationParser::ParseError( |
dmcardle | 1ec1119 | 2019-12-12 10:36:42 -0800 | [diff] [blame] | 195 | quiche::QuicheStringPiece error_message) { |
| 196 | Error(quiche::QuicheStrCat("Failed to parse the client indication stream: ", |
| 197 | error_message, reader_.DebugString())); |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | void QuicTransportServerSession::ProcessClientIndication( |
dmcardle | 1ec1119 | 2019-12-12 10:36:42 -0800 | [diff] [blame] | 201 | quiche::QuicheStringPiece indication) { |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 202 | ClientIndicationParser parser(this, indication); |
| 203 | if (!parser.Parse()) { |
| 204 | return; |
| 205 | } |
vasilvv | 59dc4b6 | 2019-10-11 12:56:14 -0700 | [diff] [blame] | 206 | // 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; |
vasilvv | efc6af8 | 2019-10-11 12:46:56 -0700 | [diff] [blame] | 212 | } |
| 213 | |
| 214 | } // namespace quic |