blob: ddccd93e00a0e2a8147a7561b58565553c1315fb [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
vasilvv872e7a32019-03-12 16:42:44 -07007#include <string>
8
QUICHE teama6ef0a62019-03-07 20:34:33 -05009#include "third_party/boringssl/src/include/openssl/ssl.h"
10#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
11#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
12#include "net/third_party/quiche/src/quic/core/quic_session.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050013
14namespace quic {
15
16TlsClientHandshaker::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
17 TlsClientHandshaker* parent)
18 : parent_(parent) {}
19
20TlsClientHandshaker::ProofVerifierCallbackImpl::~ProofVerifierCallbackImpl() {}
21
22void TlsClientHandshaker::ProofVerifierCallbackImpl::Run(
23 bool ok,
vasilvvc48c8712019-03-11 13:38:16 -070024 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -050025 std::unique_ptr<ProofVerifyDetails>* details) {
26 if (parent_ == nullptr) {
27 return;
28 }
29
30 parent_->verify_details_ = std::move(*details);
31 parent_->verify_result_ = ok ? ssl_verify_ok : ssl_verify_invalid;
32 parent_->state_ = STATE_HANDSHAKE_RUNNING;
33 parent_->proof_verify_callback_ = nullptr;
34 parent_->AdvanceHandshake();
35}
36
37void TlsClientHandshaker::ProofVerifierCallbackImpl::Cancel() {
38 parent_ = nullptr;
39}
40
41TlsClientHandshaker::TlsClientHandshaker(
42 QuicCryptoStream* stream,
43 QuicSession* session,
44 const QuicServerId& server_id,
45 ProofVerifier* proof_verifier,
46 SSL_CTX* ssl_ctx,
47 std::unique_ptr<ProofVerifyContext> verify_context,
vasilvvc48c8712019-03-11 13:38:16 -070048 const std::string& user_agent_id)
QUICHE teama6ef0a62019-03-07 20:34:33 -050049 : TlsHandshaker(stream, session, ssl_ctx),
50 server_id_(server_id),
51 proof_verifier_(proof_verifier),
52 verify_context_(std::move(verify_context)),
53 user_agent_id_(user_agent_id),
54 crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {}
55
56TlsClientHandshaker::~TlsClientHandshaker() {
57 if (proof_verify_callback_) {
58 proof_verify_callback_->Cancel();
59 }
60}
61
62// static
63bssl::UniquePtr<SSL_CTX> TlsClientHandshaker::CreateSslCtx() {
64 return TlsHandshaker::CreateSslCtx();
65}
66
67bool TlsClientHandshaker::CryptoConnect() {
68 CrypterPair crypters;
69 CryptoUtils::CreateTlsInitialCrypters(
70 Perspective::IS_CLIENT, session()->connection()->transport_version(),
71 session()->connection_id(), &crypters);
72 session()->connection()->SetEncrypter(ENCRYPTION_NONE,
73 std::move(crypters.encrypter));
74 session()->connection()->SetDecrypter(ENCRYPTION_NONE,
75 std::move(crypters.decrypter));
76 state_ = STATE_HANDSHAKE_RUNNING;
77 // Configure certificate verification.
78 // TODO(nharper): This only verifies certs on initial connection, not on
79 // resumption. Chromium has this callback be a no-op and verifies the
80 // certificate after the connection is complete. We need to re-verify on
81 // resumption in case of expiration or revocation/distrust.
82 SSL_set_custom_verify(ssl(), SSL_VERIFY_PEER, &VerifyCallback);
83
84 // Configure the SSL to be a client.
85 SSL_set_connect_state(ssl());
86 if (SSL_set_tlsext_host_name(ssl(), server_id_.host().c_str()) != 1) {
87 return false;
88 }
89
90 // Set the Transport Parameters to send in the ClientHello
91 if (!SetTransportParameters()) {
92 CloseConnection(QUIC_HANDSHAKE_FAILED,
93 "Failed to set Transport Parameters");
94 return false;
95 }
96
97 // Start the handshake.
98 AdvanceHandshake();
99 return session()->connection()->connected();
100}
101
102bool TlsClientHandshaker::SetTransportParameters() {
103 TransportParameters params;
104 params.perspective = Perspective::IS_CLIENT;
105 params.version =
106 CreateQuicVersionLabel(session()->supported_versions().front());
107
108 if (!session()->config()->FillTransportParameters(&params)) {
109 return false;
110 }
111 params.google_quic_params->SetStringPiece(kUAID, user_agent_id_);
112
113 std::vector<uint8_t> param_bytes;
114 return SerializeTransportParameters(params, &param_bytes) &&
115 SSL_set_quic_transport_params(ssl(), param_bytes.data(),
116 param_bytes.size()) == 1;
117}
118
119bool TlsClientHandshaker::ProcessTransportParameters(
vasilvvc48c8712019-03-11 13:38:16 -0700120 std::string* error_details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500121 TransportParameters params;
122 const uint8_t* param_bytes;
123 size_t param_bytes_len;
124 SSL_get_peer_quic_transport_params(ssl(), &param_bytes, &param_bytes_len);
125 if (param_bytes_len == 0 ||
126 !ParseTransportParameters(param_bytes, param_bytes_len,
127 Perspective::IS_SERVER, &params)) {
128 *error_details = "Unable to parse Transport Parameters";
129 return false;
130 }
131
132 if (params.version !=
133 CreateQuicVersionLabel(session()->connection()->version())) {
134 *error_details = "Version mismatch detected";
135 return false;
136 }
137 if (CryptoUtils::ValidateServerHelloVersions(
138 params.supported_versions,
139 session()->connection()->server_supported_versions(),
140 error_details) != QUIC_NO_ERROR ||
141 session()->config()->ProcessTransportParameters(
142 params, SERVER, error_details) != QUIC_NO_ERROR) {
143 return false;
144 }
145
146 session()->OnConfigNegotiated();
147 return true;
148}
149
150int TlsClientHandshaker::num_sent_client_hellos() const {
151 // TODO(nharper): Return a sensible value here.
152 return 0;
153}
154
155int TlsClientHandshaker::num_scup_messages_received() const {
156 // SCUP messages aren't sent or received when using the TLS handshake.
157 return 0;
158}
159
160bool TlsClientHandshaker::WasChannelIDSent() const {
161 // Channel ID is not used with TLS in QUIC.
162 return false;
163}
164
165bool TlsClientHandshaker::WasChannelIDSourceCallbackRun() const {
166 // Channel ID is not used with TLS in QUIC.
167 return false;
168}
169
vasilvvc48c8712019-03-11 13:38:16 -0700170std::string TlsClientHandshaker::chlo_hash() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500171 return "";
172}
173
174bool TlsClientHandshaker::encryption_established() const {
175 return encryption_established_;
176}
177
178bool TlsClientHandshaker::handshake_confirmed() const {
179 return handshake_confirmed_;
180}
181
182const QuicCryptoNegotiatedParameters&
183TlsClientHandshaker::crypto_negotiated_params() const {
184 return *crypto_negotiated_params_;
185}
186
187CryptoMessageParser* TlsClientHandshaker::crypto_message_parser() {
188 return TlsHandshaker::crypto_message_parser();
189}
190
191void TlsClientHandshaker::AdvanceHandshake() {
192 if (state_ == STATE_CONNECTION_CLOSED) {
193 QUIC_LOG(INFO)
194 << "TlsClientHandshaker received message after connection closed";
195 return;
196 }
197 if (state_ == STATE_IDLE) {
198 CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failed");
199 return;
200 }
201 if (state_ == STATE_HANDSHAKE_COMPLETE) {
202 // TODO(nharper): Handle post-handshake messages.
203 return;
204 }
205
206 QUIC_LOG(INFO) << "TlsClientHandshaker: continuing handshake";
207 int rv = SSL_do_handshake(ssl());
208 if (rv == 1) {
209 FinishHandshake();
210 return;
211 }
212 int ssl_error = SSL_get_error(ssl(), rv);
213 bool should_close = true;
214 switch (state_) {
215 case STATE_HANDSHAKE_RUNNING:
216 should_close = ssl_error != SSL_ERROR_WANT_READ;
217 break;
218 case STATE_CERT_VERIFY_PENDING:
219 should_close = ssl_error != SSL_ERROR_WANT_CERTIFICATE_VERIFY;
220 break;
221 default:
222 should_close = true;
223 }
224 if (should_close && state_ != STATE_CONNECTION_CLOSED) {
225 // TODO(nharper): Surface error details from the error queue when ssl_error
226 // is SSL_ERROR_SSL.
227 QUIC_LOG(WARNING) << "SSL_do_handshake failed; closing connection";
228 CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failed");
229 }
230}
231
232void TlsClientHandshaker::CloseConnection(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700233 const std::string& reason_phrase) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500234 state_ = STATE_CONNECTION_CLOSED;
235 stream()->CloseConnectionWithDetails(error, reason_phrase);
236}
237
238void TlsClientHandshaker::FinishHandshake() {
239 QUIC_LOG(INFO) << "Client: handshake finished";
240 state_ = STATE_HANDSHAKE_COMPLETE;
241
vasilvvc48c8712019-03-11 13:38:16 -0700242 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500243 if (!ProcessTransportParameters(&error_details)) {
244 CloseConnection(QUIC_HANDSHAKE_FAILED, error_details);
245 return;
246 }
247
248 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
249 session()->NeuterUnencryptedData();
250 encryption_established_ = true;
251 handshake_confirmed_ = true;
252}
253
254// static
255TlsClientHandshaker* TlsClientHandshaker::HandshakerFromSsl(SSL* ssl) {
256 return static_cast<TlsClientHandshaker*>(
257 TlsHandshaker::HandshakerFromSsl(ssl));
258}
259
260// static
261enum ssl_verify_result_t TlsClientHandshaker::VerifyCallback(
262 SSL* ssl,
263 uint8_t* out_alert) {
264 return HandshakerFromSsl(ssl)->VerifyCert(out_alert);
265}
266
267enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) {
268 if (verify_result_ != ssl_verify_retry ||
269 state_ == STATE_CERT_VERIFY_PENDING) {
270 enum ssl_verify_result_t result = verify_result_;
271 verify_result_ = ssl_verify_retry;
272 return result;
273 }
274 const STACK_OF(CRYPTO_BUFFER)* cert_chain = SSL_get0_peer_certificates(ssl());
275 if (cert_chain == nullptr) {
276 *out_alert = SSL_AD_INTERNAL_ERROR;
277 return ssl_verify_invalid;
278 }
279 // TODO(nharper): Pass the CRYPTO_BUFFERs into the QUIC stack to avoid copies.
vasilvvc48c8712019-03-11 13:38:16 -0700280 std::vector<std::string> certs;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500281 for (CRYPTO_BUFFER* cert : cert_chain) {
282 certs.push_back(
vasilvvc48c8712019-03-11 13:38:16 -0700283 std::string(reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)),
284 CRYPTO_BUFFER_len(cert)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500285 }
286
287 ProofVerifierCallbackImpl* proof_verify_callback =
288 new ProofVerifierCallbackImpl(this);
289
290 QuicAsyncStatus verify_result = proof_verifier_->VerifyCertChain(
291 server_id_.host(), certs, verify_context_.get(),
292 &cert_verify_error_details_, &verify_details_,
293 std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
294 switch (verify_result) {
295 case QUIC_SUCCESS:
296 return ssl_verify_ok;
297 case QUIC_PENDING:
298 proof_verify_callback_ = proof_verify_callback;
299 state_ = STATE_CERT_VERIFY_PENDING;
300 return ssl_verify_retry;
301 case QUIC_FAILURE:
302 default:
303 QUIC_LOG(INFO) << "Cert chain verification failed: "
304 << cert_verify_error_details_;
305 return ssl_verify_invalid;
306 }
307}
308
309} // namespace quic