• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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