1 // Copyright (c) 2020 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 "quiche/quic/core/tls_chlo_extractor.h"
6
7 #include <cstring>
8 #include <memory>
9
10 #include "absl/strings/str_cat.h"
11 #include "absl/strings/string_view.h"
12 #include "openssl/ssl.h"
13 #include "quiche/quic/core/frames/quic_crypto_frame.h"
14 #include "quiche/quic/core/quic_data_reader.h"
15 #include "quiche/quic/core/quic_error_codes.h"
16 #include "quiche/quic/core/quic_framer.h"
17 #include "quiche/quic/core/quic_time.h"
18 #include "quiche/quic/core/quic_types.h"
19 #include "quiche/quic/core/quic_versions.h"
20 #include "quiche/quic/platform/api/quic_bug_tracker.h"
21 #include "quiche/common/platform/api/quiche_logging.h"
22
23 namespace quic {
24
25 namespace {
HasExtension(const SSL_CLIENT_HELLO * client_hello,uint16_t extension)26 bool HasExtension(const SSL_CLIENT_HELLO* client_hello, uint16_t extension) {
27 const uint8_t* unused_extension_bytes;
28 size_t unused_extension_len;
29 return 1 == SSL_early_callback_ctx_extension_get(client_hello, extension,
30 &unused_extension_bytes,
31 &unused_extension_len);
32 }
33 } // namespace
34
TlsChloExtractor()35 TlsChloExtractor::TlsChloExtractor()
36 : crypto_stream_sequencer_(this),
37 state_(State::kInitial),
38 parsed_crypto_frame_in_this_packet_(false) {}
39
TlsChloExtractor(TlsChloExtractor && other)40 TlsChloExtractor::TlsChloExtractor(TlsChloExtractor&& other)
41 : TlsChloExtractor() {
42 *this = std::move(other);
43 }
44
operator =(TlsChloExtractor && other)45 TlsChloExtractor& TlsChloExtractor::operator=(TlsChloExtractor&& other) {
46 framer_ = std::move(other.framer_);
47 if (framer_) {
48 framer_->set_visitor(this);
49 }
50 crypto_stream_sequencer_ = std::move(other.crypto_stream_sequencer_);
51 crypto_stream_sequencer_.set_stream(this);
52 ssl_ = std::move(other.ssl_);
53 if (ssl_) {
54 std::pair<SSL_CTX*, int> shared_handles = GetSharedSslHandles();
55 int ex_data_index = shared_handles.second;
56 const int rv = SSL_set_ex_data(ssl_.get(), ex_data_index, this);
57 QUICHE_CHECK_EQ(rv, 1) << "Internal allocation failure in SSL_set_ex_data";
58 }
59 state_ = other.state_;
60 error_details_ = std::move(other.error_details_);
61 parsed_crypto_frame_in_this_packet_ =
62 other.parsed_crypto_frame_in_this_packet_;
63 alpns_ = std::move(other.alpns_);
64 server_name_ = std::move(other.server_name_);
65 client_hello_bytes_ = std::move(other.client_hello_bytes_);
66 return *this;
67 }
68
IngestPacket(const ParsedQuicVersion & version,const QuicReceivedPacket & packet)69 void TlsChloExtractor::IngestPacket(const ParsedQuicVersion& version,
70 const QuicReceivedPacket& packet) {
71 if (state_ == State::kUnrecoverableFailure) {
72 QUIC_DLOG(ERROR) << "Not ingesting packet after unrecoverable error";
73 return;
74 }
75 if (version == UnsupportedQuicVersion()) {
76 QUIC_DLOG(ERROR) << "Not ingesting packet with unsupported version";
77 return;
78 }
79 if (version.handshake_protocol != PROTOCOL_TLS1_3) {
80 QUIC_DLOG(ERROR) << "Not ingesting packet with non-TLS version " << version;
81 return;
82 }
83 if (framer_) {
84 // This is not the first packet we have ingested, check if version matches.
85 if (!framer_->IsSupportedVersion(version)) {
86 QUIC_DLOG(ERROR)
87 << "Not ingesting packet with version mismatch, expected "
88 << framer_->version() << ", got " << version;
89 return;
90 }
91 } else {
92 // This is the first packet we have ingested, setup parser.
93 framer_ = std::make_unique<QuicFramer>(
94 ParsedQuicVersionVector{version}, QuicTime::Zero(),
95 Perspective::IS_SERVER, /*expected_server_connection_id_length=*/0);
96 // Note that expected_server_connection_id_length only matters for short
97 // headers and we explicitly drop those so we can pass any value here.
98 framer_->set_visitor(this);
99 }
100
101 // When the framer parses |packet|, if it sees a CRYPTO frame it will call
102 // OnCryptoFrame below and that will set parsed_crypto_frame_in_this_packet_
103 // to true.
104 parsed_crypto_frame_in_this_packet_ = false;
105 const bool parse_success = framer_->ProcessPacket(packet);
106 if (state_ == State::kInitial && parsed_crypto_frame_in_this_packet_) {
107 // If we parsed a CRYPTO frame but didn't advance the state from initial,
108 // then it means that we will need more packets to reassemble the full CHLO,
109 // so we advance the state here. This can happen when the first packet
110 // received is not the first one in the crypto stream. This allows us to
111 // differentiate our state between single-packet CHLO and multi-packet CHLO.
112 state_ = State::kParsedPartialChloFragment;
113 }
114
115 if (!parse_success) {
116 // This could be due to the packet being non-initial for example.
117 QUIC_DLOG(ERROR) << "Failed to process packet";
118 return;
119 }
120 }
121
122 // This is called when the framer parsed the unencrypted parts of the header.
OnUnauthenticatedPublicHeader(const QuicPacketHeader & header)123 bool TlsChloExtractor::OnUnauthenticatedPublicHeader(
124 const QuicPacketHeader& header) {
125 if (header.form != IETF_QUIC_LONG_HEADER_PACKET) {
126 QUIC_DLOG(ERROR) << "Not parsing non-long-header packet " << header;
127 return false;
128 }
129 if (header.long_packet_type != INITIAL) {
130 QUIC_DLOG(ERROR) << "Not parsing non-initial packet " << header;
131 return false;
132 }
133 // QuicFramer is constructed without knowledge of the server's connection ID
134 // so it needs to be set up here in order to decrypt the packet.
135 framer_->SetInitialObfuscators(header.destination_connection_id);
136 return true;
137 }
138
139 // This is called by the framer if it detects a change in version during
140 // parsing.
OnProtocolVersionMismatch(ParsedQuicVersion version)141 bool TlsChloExtractor::OnProtocolVersionMismatch(ParsedQuicVersion version) {
142 // This should never be called because we already check versions in
143 // IngestPacket.
144 QUIC_BUG(quic_bug_10855_1) << "Unexpected version mismatch, expected "
145 << framer_->version() << ", got " << version;
146 return false;
147 }
148
149 // This is called by the QuicStreamSequencer if it encounters an unrecoverable
150 // error that will prevent it from reassembling the crypto stream data.
OnUnrecoverableError(QuicErrorCode error,const std::string & details)151 void TlsChloExtractor::OnUnrecoverableError(QuicErrorCode error,
152 const std::string& details) {
153 HandleUnrecoverableError(absl::StrCat(
154 "Crypto stream error ", QuicErrorCodeToString(error), ": ", details));
155 }
156
OnUnrecoverableError(QuicErrorCode error,QuicIetfTransportErrorCodes ietf_error,const std::string & details)157 void TlsChloExtractor::OnUnrecoverableError(
158 QuicErrorCode error, QuicIetfTransportErrorCodes ietf_error,
159 const std::string& details) {
160 HandleUnrecoverableError(absl::StrCat(
161 "Crypto stream error ", QuicErrorCodeToString(error), "(",
162 QuicIetfTransportErrorCodeString(ietf_error), "): ", details));
163 }
164
165 // This is called by the framer if it sees a CRYPTO frame during parsing.
OnCryptoFrame(const QuicCryptoFrame & frame)166 bool TlsChloExtractor::OnCryptoFrame(const QuicCryptoFrame& frame) {
167 if (frame.level != ENCRYPTION_INITIAL) {
168 // Since we drop non-INITIAL packets in OnUnauthenticatedPublicHeader,
169 // we should never receive any CRYPTO frames at other encryption levels.
170 QUIC_BUG(quic_bug_10855_2) << "Parsed bad-level CRYPTO frame " << frame;
171 return false;
172 }
173 // parsed_crypto_frame_in_this_packet_ is checked in IngestPacket to allow
174 // advancing our state to track the difference between single-packet CHLO
175 // and multi-packet CHLO.
176 parsed_crypto_frame_in_this_packet_ = true;
177 crypto_stream_sequencer_.OnCryptoFrame(frame);
178 return true;
179 }
180
181 // Called by the QuicStreamSequencer when it receives a CRYPTO frame that
182 // advances the amount of contiguous data we now have starting from offset 0.
OnDataAvailable()183 void TlsChloExtractor::OnDataAvailable() {
184 // Lazily set up BoringSSL handle.
185 SetupSslHandle();
186
187 // Get data from the stream sequencer and pass it to BoringSSL.
188 struct iovec iov;
189 while (crypto_stream_sequencer_.GetReadableRegion(&iov)) {
190 const int rv = SSL_provide_quic_data(
191 ssl_.get(), ssl_encryption_initial,
192 reinterpret_cast<const uint8_t*>(iov.iov_base), iov.iov_len);
193 if (rv != 1) {
194 HandleUnrecoverableError("SSL_provide_quic_data failed");
195 return;
196 }
197 crypto_stream_sequencer_.MarkConsumed(iov.iov_len);
198 }
199
200 // Instruct BoringSSL to attempt parsing a full CHLO from the provided data.
201 // We ignore the return value since we know the handshake is going to fail
202 // because we explicitly cancel processing once we've parsed the CHLO.
203 (void)SSL_do_handshake(ssl_.get());
204 }
205
206 // static
GetInstanceFromSSL(SSL * ssl)207 TlsChloExtractor* TlsChloExtractor::GetInstanceFromSSL(SSL* ssl) {
208 std::pair<SSL_CTX*, int> shared_handles = GetSharedSslHandles();
209 int ex_data_index = shared_handles.second;
210 return reinterpret_cast<TlsChloExtractor*>(
211 SSL_get_ex_data(ssl, ex_data_index));
212 }
213
214 // static
SetReadSecretCallback(SSL * ssl,enum ssl_encryption_level_t,const SSL_CIPHER *,const uint8_t *,size_t)215 int TlsChloExtractor::SetReadSecretCallback(
216 SSL* ssl, enum ssl_encryption_level_t /*level*/,
217 const SSL_CIPHER* /*cipher*/, const uint8_t* /*secret*/,
218 size_t /*secret_length*/) {
219 GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("SetReadSecretCallback");
220 return 0;
221 }
222
223 // static
SetWriteSecretCallback(SSL * ssl,enum ssl_encryption_level_t,const SSL_CIPHER *,const uint8_t *,size_t)224 int TlsChloExtractor::SetWriteSecretCallback(
225 SSL* ssl, enum ssl_encryption_level_t /*level*/,
226 const SSL_CIPHER* /*cipher*/, const uint8_t* /*secret*/,
227 size_t /*secret_length*/) {
228 GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("SetWriteSecretCallback");
229 return 0;
230 }
231
232 // static
WriteMessageCallback(SSL * ssl,enum ssl_encryption_level_t,const uint8_t *,size_t)233 int TlsChloExtractor::WriteMessageCallback(
234 SSL* ssl, enum ssl_encryption_level_t /*level*/, const uint8_t* /*data*/,
235 size_t /*len*/) {
236 GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("WriteMessageCallback");
237 return 0;
238 }
239
240 // static
FlushFlightCallback(SSL * ssl)241 int TlsChloExtractor::FlushFlightCallback(SSL* ssl) {
242 GetInstanceFromSSL(ssl)->HandleUnexpectedCallback("FlushFlightCallback");
243 return 0;
244 }
245
HandleUnexpectedCallback(const std::string & callback_name)246 void TlsChloExtractor::HandleUnexpectedCallback(
247 const std::string& callback_name) {
248 std::string error_details =
249 absl::StrCat("Unexpected callback ", callback_name);
250 QUIC_BUG(quic_bug_10855_3) << error_details;
251 HandleUnrecoverableError(error_details);
252 }
253
254 // static
SendAlertCallback(SSL * ssl,enum ssl_encryption_level_t,uint8_t desc)255 int TlsChloExtractor::SendAlertCallback(SSL* ssl,
256 enum ssl_encryption_level_t /*level*/,
257 uint8_t desc) {
258 GetInstanceFromSSL(ssl)->SendAlert(desc);
259 return 0;
260 }
261
SendAlert(uint8_t tls_alert_value)262 void TlsChloExtractor::SendAlert(uint8_t tls_alert_value) {
263 if (tls_alert_value == SSL3_AD_HANDSHAKE_FAILURE && HasParsedFullChlo()) {
264 // This is the most common scenario. Since we return an error from
265 // SelectCertCallback in order to cancel further processing, BoringSSL will
266 // try to send this alert to tell the client that the handshake failed.
267 return;
268 }
269 HandleUnrecoverableError(absl::StrCat(
270 "BoringSSL attempted to send alert ", static_cast<int>(tls_alert_value),
271 " ", SSL_alert_desc_string_long(tls_alert_value)));
272 if (state_ == State::kUnrecoverableFailure) {
273 tls_alert_ = tls_alert_value;
274 }
275 }
276
277 // static
SelectCertCallback(const SSL_CLIENT_HELLO * client_hello)278 enum ssl_select_cert_result_t TlsChloExtractor::SelectCertCallback(
279 const SSL_CLIENT_HELLO* client_hello) {
280 GetInstanceFromSSL(client_hello->ssl)->HandleParsedChlo(client_hello);
281 // Always return an error to cancel any further processing in BoringSSL.
282 return ssl_select_cert_error;
283 }
284
285 // Extracts the server name and ALPN from the parsed ClientHello.
HandleParsedChlo(const SSL_CLIENT_HELLO * client_hello)286 void TlsChloExtractor::HandleParsedChlo(const SSL_CLIENT_HELLO* client_hello) {
287 const char* server_name =
288 SSL_get_servername(client_hello->ssl, TLSEXT_NAMETYPE_host_name);
289 if (server_name) {
290 server_name_ = std::string(server_name);
291 }
292
293 resumption_attempted_ =
294 HasExtension(client_hello, TLSEXT_TYPE_pre_shared_key);
295 early_data_attempted_ = HasExtension(client_hello, TLSEXT_TYPE_early_data);
296
297 QUICHE_DCHECK(client_hello_bytes_.empty());
298 client_hello_bytes_.assign(
299 client_hello->client_hello,
300 client_hello->client_hello + client_hello->client_hello_len);
301
302 const uint8_t* alpn_data;
303 size_t alpn_len;
304 int rv = SSL_early_callback_ctx_extension_get(
305 client_hello, TLSEXT_TYPE_application_layer_protocol_negotiation,
306 &alpn_data, &alpn_len);
307 if (rv == 1) {
308 QuicDataReader alpns_reader(reinterpret_cast<const char*>(alpn_data),
309 alpn_len);
310 absl::string_view alpns_payload;
311 if (!alpns_reader.ReadStringPiece16(&alpns_payload)) {
312 HandleUnrecoverableError("Failed to read alpns_payload");
313 return;
314 }
315 QuicDataReader alpns_payload_reader(alpns_payload);
316 while (!alpns_payload_reader.IsDoneReading()) {
317 absl::string_view alpn_payload;
318 if (!alpns_payload_reader.ReadStringPiece8(&alpn_payload)) {
319 HandleUnrecoverableError("Failed to read alpn_payload");
320 return;
321 }
322 alpns_.emplace_back(std::string(alpn_payload));
323 }
324 }
325
326 // Update our state now that we've parsed a full CHLO.
327 if (state_ == State::kInitial) {
328 state_ = State::kParsedFullSinglePacketChlo;
329 } else if (state_ == State::kParsedPartialChloFragment) {
330 state_ = State::kParsedFullMultiPacketChlo;
331 } else {
332 QUIC_BUG(quic_bug_10855_4)
333 << "Unexpected state on successful parse " << StateToString(state_);
334 }
335 }
336
337 // static
GetSharedSslHandles()338 std::pair<SSL_CTX*, int> TlsChloExtractor::GetSharedSslHandles() {
339 // Use a lambda to benefit from C++11 guarantee that static variables are
340 // initialized lazily in a thread-safe manner. |shared_handles| is therefore
341 // guaranteed to be initialized exactly once and never destructed.
342 static std::pair<SSL_CTX*, int>* shared_handles = []() {
343 CRYPTO_library_init();
344 SSL_CTX* ssl_ctx = SSL_CTX_new(TLS_with_buffers_method());
345 SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
346 SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
347 static const SSL_QUIC_METHOD kQuicCallbacks{
348 TlsChloExtractor::SetReadSecretCallback,
349 TlsChloExtractor::SetWriteSecretCallback,
350 TlsChloExtractor::WriteMessageCallback,
351 TlsChloExtractor::FlushFlightCallback,
352 TlsChloExtractor::SendAlertCallback};
353 SSL_CTX_set_quic_method(ssl_ctx, &kQuicCallbacks);
354 SSL_CTX_set_select_certificate_cb(ssl_ctx,
355 TlsChloExtractor::SelectCertCallback);
356 int ex_data_index =
357 SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
358 return new std::pair<SSL_CTX*, int>(ssl_ctx, ex_data_index);
359 }();
360 return *shared_handles;
361 }
362
363 // Sets up the per-instance SSL handle needed by BoringSSL.
SetupSslHandle()364 void TlsChloExtractor::SetupSslHandle() {
365 if (ssl_) {
366 // Handles have already been set up.
367 return;
368 }
369
370 std::pair<SSL_CTX*, int> shared_handles = GetSharedSslHandles();
371 SSL_CTX* ssl_ctx = shared_handles.first;
372 int ex_data_index = shared_handles.second;
373
374 ssl_ = bssl::UniquePtr<SSL>(SSL_new(ssl_ctx));
375 const int rv = SSL_set_ex_data(ssl_.get(), ex_data_index, this);
376 QUICHE_CHECK_EQ(rv, 1) << "Internal allocation failure in SSL_set_ex_data";
377 SSL_set_accept_state(ssl_.get());
378
379 // Make sure we use the right TLS extension codepoint.
380 int use_legacy_extension = 0;
381 if (framer_->version().UsesLegacyTlsExtension()) {
382 use_legacy_extension = 1;
383 }
384 SSL_set_quic_use_legacy_codepoint(ssl_.get(), use_legacy_extension);
385 }
386
387 // Called by other methods to record any unrecoverable failures they experience.
HandleUnrecoverableError(const std::string & error_details)388 void TlsChloExtractor::HandleUnrecoverableError(
389 const std::string& error_details) {
390 if (HasParsedFullChlo()) {
391 // Ignore errors if we've parsed everything successfully.
392 QUIC_DLOG(ERROR) << "Ignoring error: " << error_details;
393 return;
394 }
395 QUIC_DLOG(ERROR) << "Handling error: " << error_details;
396
397 state_ = State::kUnrecoverableFailure;
398
399 if (error_details_.empty()) {
400 error_details_ = error_details;
401 } else {
402 error_details_ = absl::StrCat(error_details_, "; ", error_details);
403 }
404 }
405
406 // static
StateToString(State state)407 std::string TlsChloExtractor::StateToString(State state) {
408 switch (state) {
409 case State::kInitial:
410 return "Initial";
411 case State::kParsedFullSinglePacketChlo:
412 return "ParsedFullSinglePacketChlo";
413 case State::kParsedFullMultiPacketChlo:
414 return "ParsedFullMultiPacketChlo";
415 case State::kParsedPartialChloFragment:
416 return "ParsedPartialChloFragment";
417 case State::kUnrecoverableFailure:
418 return "UnrecoverableFailure";
419 }
420 return absl::StrCat("Unknown(", static_cast<int>(state), ")");
421 }
422
operator <<(std::ostream & os,const TlsChloExtractor::State & state)423 std::ostream& operator<<(std::ostream& os,
424 const TlsChloExtractor::State& state) {
425 os << TlsChloExtractor::StateToString(state);
426 return os;
427 }
428
429 } // namespace quic
430