blob: 932d537b16d11350ee77e588de0751e927d3d7c9 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2017 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/core/tls_client_handshaker.h"
6
dschinazi35e749e2019-04-09 09:36:04 -07007#include <cstring>
vasilvv872e7a32019-03-12 16:42:44 -07008#include <string>
9
QUICHE teama6ef0a62019-03-07 20:34:33 -050010#include "third_party/boringssl/src/include/openssl/ssl.h"
11#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
12#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
13#include "net/third_party/quiche/src/quic/core/quic_session.h"
dschinazi35e749e2019-04-09 09:36:04 -070014#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050015
16namespace quic {
17
18TlsClientHandshaker::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
19 TlsClientHandshaker* parent)
20 : parent_(parent) {}
21
22TlsClientHandshaker::ProofVerifierCallbackImpl::~ProofVerifierCallbackImpl() {}
23
24void TlsClientHandshaker::ProofVerifierCallbackImpl::Run(
25 bool ok,
vasilvvc48c8712019-03-11 13:38:16 -070026 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -050027 std::unique_ptr<ProofVerifyDetails>* details) {
28 if (parent_ == nullptr) {
29 return;
30 }
31
32 parent_->verify_details_ = std::move(*details);
33 parent_->verify_result_ = ok ? ssl_verify_ok : ssl_verify_invalid;
34 parent_->state_ = STATE_HANDSHAKE_RUNNING;
35 parent_->proof_verify_callback_ = nullptr;
36 parent_->AdvanceHandshake();
37}
38
39void TlsClientHandshaker::ProofVerifierCallbackImpl::Cancel() {
40 parent_ = nullptr;
41}
42
43TlsClientHandshaker::TlsClientHandshaker(
44 QuicCryptoStream* stream,
45 QuicSession* session,
46 const QuicServerId& server_id,
47 ProofVerifier* proof_verifier,
48 SSL_CTX* ssl_ctx,
49 std::unique_ptr<ProofVerifyContext> verify_context,
vasilvvc48c8712019-03-11 13:38:16 -070050 const std::string& user_agent_id)
QUICHE teama6ef0a62019-03-07 20:34:33 -050051 : TlsHandshaker(stream, session, ssl_ctx),
52 server_id_(server_id),
53 proof_verifier_(proof_verifier),
54 verify_context_(std::move(verify_context)),
55 user_agent_id_(user_agent_id),
56 crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {}
57
58TlsClientHandshaker::~TlsClientHandshaker() {
59 if (proof_verify_callback_) {
60 proof_verify_callback_->Cancel();
61 }
62}
63
64// static
65bssl::UniquePtr<SSL_CTX> TlsClientHandshaker::CreateSslCtx() {
66 return TlsHandshaker::CreateSslCtx();
67}
68
69bool TlsClientHandshaker::CryptoConnect() {
70 CrypterPair crypters;
71 CryptoUtils::CreateTlsInitialCrypters(
72 Perspective::IS_CLIENT, session()->connection()->transport_version(),
73 session()->connection_id(), &crypters);
QUICHE team6987b4a2019-03-15 16:23:04 -070074 session()->connection()->SetEncrypter(ENCRYPTION_INITIAL,
QUICHE teama6ef0a62019-03-07 20:34:33 -050075 std::move(crypters.encrypter));
zhongyi546cc452019-04-12 15:27:49 -070076 session()->connection()->InstallDecrypter(ENCRYPTION_INITIAL,
77 std::move(crypters.decrypter));
QUICHE teama6ef0a62019-03-07 20:34:33 -050078 state_ = STATE_HANDSHAKE_RUNNING;
79 // Configure certificate verification.
80 // TODO(nharper): This only verifies certs on initial connection, not on
81 // resumption. Chromium has this callback be a no-op and verifies the
82 // certificate after the connection is complete. We need to re-verify on
83 // resumption in case of expiration or revocation/distrust.
84 SSL_set_custom_verify(ssl(), SSL_VERIFY_PEER, &VerifyCallback);
85
86 // Configure the SSL to be a client.
87 SSL_set_connect_state(ssl());
88 if (SSL_set_tlsext_host_name(ssl(), server_id_.host().c_str()) != 1) {
89 return false;
90 }
91
dschinazi35e749e2019-04-09 09:36:04 -070092 std::string alpn_string =
93 AlpnForVersion(session()->supported_versions().front());
94 if (alpn_string.length() > std::numeric_limits<uint8_t>::max()) {
95 QUIC_BUG << "ALPN too long: '" << alpn_string << "'";
96 CloseConnection(QUIC_HANDSHAKE_FAILED, "ALPN too long");
97 return false;
98 }
99 const uint8_t alpn_length = alpn_string.length();
100 // SSL_set_alpn_protos expects a sequence of one-byte-length-prefixed strings
101 // so we copy alpn_string to a new buffer that has the length in alpn[0].
102 uint8_t alpn[std::numeric_limits<uint8_t>::max() + 1];
103 alpn[0] = alpn_length;
104 memcpy(reinterpret_cast<char*>(alpn + 1), alpn_string.data(), alpn_length);
105 if (SSL_set_alpn_protos(ssl(), alpn,
106 static_cast<unsigned>(alpn_length) + 1) != 0) {
107 QUIC_BUG << "Failed to set ALPN: '" << alpn_string << "'";
108 CloseConnection(QUIC_HANDSHAKE_FAILED, "Failed to set ALPN");
109 return false;
110 }
111 QUIC_DLOG(INFO) << "Client using ALPN: '" << alpn_string << "'";
112
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113 // Set the Transport Parameters to send in the ClientHello
114 if (!SetTransportParameters()) {
115 CloseConnection(QUIC_HANDSHAKE_FAILED,
116 "Failed to set Transport Parameters");
117 return false;
118 }
119
120 // Start the handshake.
121 AdvanceHandshake();
122 return session()->connection()->connected();
123}
124
125bool TlsClientHandshaker::SetTransportParameters() {
126 TransportParameters params;
127 params.perspective = Perspective::IS_CLIENT;
128 params.version =
129 CreateQuicVersionLabel(session()->supported_versions().front());
130
131 if (!session()->config()->FillTransportParameters(&params)) {
132 return false;
133 }
134 params.google_quic_params->SetStringPiece(kUAID, user_agent_id_);
135
136 std::vector<uint8_t> param_bytes;
137 return SerializeTransportParameters(params, &param_bytes) &&
138 SSL_set_quic_transport_params(ssl(), param_bytes.data(),
139 param_bytes.size()) == 1;
140}
141
142bool TlsClientHandshaker::ProcessTransportParameters(
vasilvvc48c8712019-03-11 13:38:16 -0700143 std::string* error_details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500144 TransportParameters params;
145 const uint8_t* param_bytes;
146 size_t param_bytes_len;
147 SSL_get_peer_quic_transport_params(ssl(), &param_bytes, &param_bytes_len);
148 if (param_bytes_len == 0 ||
149 !ParseTransportParameters(param_bytes, param_bytes_len,
150 Perspective::IS_SERVER, &params)) {
151 *error_details = "Unable to parse Transport Parameters";
152 return false;
153 }
154
155 if (params.version !=
156 CreateQuicVersionLabel(session()->connection()->version())) {
157 *error_details = "Version mismatch detected";
158 return false;
159 }
160 if (CryptoUtils::ValidateServerHelloVersions(
161 params.supported_versions,
162 session()->connection()->server_supported_versions(),
163 error_details) != QUIC_NO_ERROR ||
164 session()->config()->ProcessTransportParameters(
165 params, SERVER, error_details) != QUIC_NO_ERROR) {
dschinazid1967a22019-04-03 16:11:32 -0700166 DCHECK(!error_details->empty());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500167 return false;
168 }
169
170 session()->OnConfigNegotiated();
171 return true;
172}
173
174int TlsClientHandshaker::num_sent_client_hellos() const {
175 // TODO(nharper): Return a sensible value here.
176 return 0;
177}
178
179int TlsClientHandshaker::num_scup_messages_received() const {
180 // SCUP messages aren't sent or received when using the TLS handshake.
181 return 0;
182}
183
184bool TlsClientHandshaker::WasChannelIDSent() const {
185 // Channel ID is not used with TLS in QUIC.
186 return false;
187}
188
189bool TlsClientHandshaker::WasChannelIDSourceCallbackRun() const {
190 // Channel ID is not used with TLS in QUIC.
191 return false;
192}
193
vasilvvc48c8712019-03-11 13:38:16 -0700194std::string TlsClientHandshaker::chlo_hash() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500195 return "";
196}
197
198bool TlsClientHandshaker::encryption_established() const {
199 return encryption_established_;
200}
201
202bool TlsClientHandshaker::handshake_confirmed() const {
203 return handshake_confirmed_;
204}
205
206const QuicCryptoNegotiatedParameters&
207TlsClientHandshaker::crypto_negotiated_params() const {
208 return *crypto_negotiated_params_;
209}
210
211CryptoMessageParser* TlsClientHandshaker::crypto_message_parser() {
212 return TlsHandshaker::crypto_message_parser();
213}
214
215void TlsClientHandshaker::AdvanceHandshake() {
216 if (state_ == STATE_CONNECTION_CLOSED) {
217 QUIC_LOG(INFO)
218 << "TlsClientHandshaker received message after connection closed";
219 return;
220 }
221 if (state_ == STATE_IDLE) {
222 CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failed");
223 return;
224 }
225 if (state_ == STATE_HANDSHAKE_COMPLETE) {
226 // TODO(nharper): Handle post-handshake messages.
227 return;
228 }
229
230 QUIC_LOG(INFO) << "TlsClientHandshaker: continuing handshake";
231 int rv = SSL_do_handshake(ssl());
232 if (rv == 1) {
233 FinishHandshake();
234 return;
235 }
236 int ssl_error = SSL_get_error(ssl(), rv);
237 bool should_close = true;
238 switch (state_) {
239 case STATE_HANDSHAKE_RUNNING:
240 should_close = ssl_error != SSL_ERROR_WANT_READ;
241 break;
242 case STATE_CERT_VERIFY_PENDING:
243 should_close = ssl_error != SSL_ERROR_WANT_CERTIFICATE_VERIFY;
244 break;
245 default:
246 should_close = true;
247 }
248 if (should_close && state_ != STATE_CONNECTION_CLOSED) {
249 // TODO(nharper): Surface error details from the error queue when ssl_error
250 // is SSL_ERROR_SSL.
251 QUIC_LOG(WARNING) << "SSL_do_handshake failed; closing connection";
252 CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failed");
253 }
254}
255
256void TlsClientHandshaker::CloseConnection(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700257 const std::string& reason_phrase) {
dschinazid1967a22019-04-03 16:11:32 -0700258 DCHECK(!reason_phrase.empty());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500259 state_ = STATE_CONNECTION_CLOSED;
260 stream()->CloseConnectionWithDetails(error, reason_phrase);
261}
262
263void TlsClientHandshaker::FinishHandshake() {
264 QUIC_LOG(INFO) << "Client: handshake finished";
265 state_ = STATE_HANDSHAKE_COMPLETE;
266
vasilvvc48c8712019-03-11 13:38:16 -0700267 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500268 if (!ProcessTransportParameters(&error_details)) {
dschinazid1967a22019-04-03 16:11:32 -0700269 DCHECK(!error_details.empty());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500270 CloseConnection(QUIC_HANDSHAKE_FAILED, error_details);
271 return;
272 }
273
dschinazi35e749e2019-04-09 09:36:04 -0700274 const uint8_t* alpn_data = nullptr;
275 unsigned alpn_length = 0;
276 SSL_get0_alpn_selected(ssl(), &alpn_data, &alpn_length);
277 // TODO(b/130164908) Act on ALPN.
278 if (alpn_length != 0) {
279 std::string received_alpn_string(reinterpret_cast<const char*>(alpn_data),
280 alpn_length);
281 std::string sent_alpn_string =
282 AlpnForVersion(session()->supported_versions().front());
283 if (received_alpn_string != sent_alpn_string) {
284 QUIC_LOG(ERROR) << "Client: received mismatched ALPN '"
285 << received_alpn_string << "', expected '"
286 << sent_alpn_string << "'";
287 CloseConnection(QUIC_HANDSHAKE_FAILED, "Mismatched ALPN");
288 return;
289 }
290 QUIC_DLOG(INFO) << "Client: server selected ALPN: '" << received_alpn_string
291 << "'";
292 } else {
293 QUIC_DLOG(INFO) << "Client: server did not select ALPN";
294 }
295
QUICHE teama6ef0a62019-03-07 20:34:33 -0500296 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
297 session()->NeuterUnencryptedData();
298 encryption_established_ = true;
299 handshake_confirmed_ = true;
300}
301
302// static
303TlsClientHandshaker* TlsClientHandshaker::HandshakerFromSsl(SSL* ssl) {
304 return static_cast<TlsClientHandshaker*>(
305 TlsHandshaker::HandshakerFromSsl(ssl));
306}
307
308// static
309enum ssl_verify_result_t TlsClientHandshaker::VerifyCallback(
310 SSL* ssl,
311 uint8_t* out_alert) {
312 return HandshakerFromSsl(ssl)->VerifyCert(out_alert);
313}
314
315enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) {
316 if (verify_result_ != ssl_verify_retry ||
317 state_ == STATE_CERT_VERIFY_PENDING) {
318 enum ssl_verify_result_t result = verify_result_;
319 verify_result_ = ssl_verify_retry;
320 return result;
321 }
322 const STACK_OF(CRYPTO_BUFFER)* cert_chain = SSL_get0_peer_certificates(ssl());
323 if (cert_chain == nullptr) {
324 *out_alert = SSL_AD_INTERNAL_ERROR;
325 return ssl_verify_invalid;
326 }
327 // TODO(nharper): Pass the CRYPTO_BUFFERs into the QUIC stack to avoid copies.
vasilvvc48c8712019-03-11 13:38:16 -0700328 std::vector<std::string> certs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500329 for (CRYPTO_BUFFER* cert : cert_chain) {
330 certs.push_back(
vasilvvc48c8712019-03-11 13:38:16 -0700331 std::string(reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)),
332 CRYPTO_BUFFER_len(cert)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500333 }
334
335 ProofVerifierCallbackImpl* proof_verify_callback =
336 new ProofVerifierCallbackImpl(this);
337
338 QuicAsyncStatus verify_result = proof_verifier_->VerifyCertChain(
339 server_id_.host(), certs, verify_context_.get(),
340 &cert_verify_error_details_, &verify_details_,
341 std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
342 switch (verify_result) {
343 case QUIC_SUCCESS:
344 return ssl_verify_ok;
345 case QUIC_PENDING:
346 proof_verify_callback_ = proof_verify_callback;
347 state_ = STATE_CERT_VERIFY_PENDING;
348 return ssl_verify_retry;
349 case QUIC_FAILURE:
350 default:
351 QUIC_LOG(INFO) << "Cert chain verification failed: "
352 << cert_verify_error_details_;
353 return ssl_verify_invalid;
354 }
355}
356
357} // namespace quic