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