blob: 72769372318fa2b37f7d84effd21d248adace847 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2012 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/quic_crypto_client_handshaker.h"
6
7#include <memory>
vasilvv872e7a32019-03-12 16:42:44 -07008#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -05009
10#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
11#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
12#include "net/third_party/quiche/src/quic/core/quic_session.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_client_stats.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
dmcardlecf0bfcf2019-12-13 08:08:21 -080016#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017
18namespace quic {
19
QUICHE teama6ef0a62019-03-07 20:34:33 -050020QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::
21 ProofVerifierCallbackImpl(QuicCryptoClientHandshaker* parent)
22 : parent_(parent) {}
23
24QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::
25 ~ProofVerifierCallbackImpl() {}
26
27void QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::Run(
28 bool ok,
vasilvvc48c8712019-03-11 13:38:16 -070029 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -050030 std::unique_ptr<ProofVerifyDetails>* details) {
31 if (parent_ == nullptr) {
32 return;
33 }
34
35 parent_->verify_ok_ = ok;
36 parent_->verify_error_details_ = error_details;
37 parent_->verify_details_ = std::move(*details);
38 parent_->proof_verify_callback_ = nullptr;
39 parent_->DoHandshakeLoop(nullptr);
40
41 // The ProofVerifier owns this object and will delete it when this method
42 // returns.
43}
44
45void QuicCryptoClientHandshaker::ProofVerifierCallbackImpl::Cancel() {
46 parent_ = nullptr;
47}
48
49QuicCryptoClientHandshaker::QuicCryptoClientHandshaker(
50 const QuicServerId& server_id,
51 QuicCryptoClientStream* stream,
52 QuicSession* session,
53 std::unique_ptr<ProofVerifyContext> verify_context,
54 QuicCryptoClientConfig* crypto_config,
55 QuicCryptoClientStream::ProofHandler* proof_handler)
56 : QuicCryptoHandshaker(stream, session),
57 stream_(stream),
58 session_(session),
fayangd58736d2019-11-27 13:35:31 -080059 delegate_(session),
QUICHE teama6ef0a62019-03-07 20:34:33 -050060 next_state_(STATE_IDLE),
61 num_client_hellos_(0),
62 crypto_config_(crypto_config),
63 server_id_(server_id),
64 generation_counter_(0),
QUICHE teama6ef0a62019-03-07 20:34:33 -050065 verify_context_(std::move(verify_context)),
66 proof_verify_callback_(nullptr),
67 proof_handler_(proof_handler),
68 verify_ok_(false),
QUICHE teama6ef0a62019-03-07 20:34:33 -050069 proof_verify_start_time_(QuicTime::Zero()),
70 num_scup_messages_received_(0),
71 encryption_established_(false),
fayang685367a2020-01-14 10:40:15 -080072 one_rtt_keys_available_(false),
QUICHE teama6ef0a62019-03-07 20:34:33 -050073 crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) {}
74
75QuicCryptoClientHandshaker::~QuicCryptoClientHandshaker() {
QUICHE teama6ef0a62019-03-07 20:34:33 -050076 if (proof_verify_callback_) {
77 proof_verify_callback_->Cancel();
78 }
79}
80
81void QuicCryptoClientHandshaker::OnHandshakeMessage(
82 const CryptoHandshakeMessage& message) {
83 QuicCryptoHandshaker::OnHandshakeMessage(message);
84 if (message.tag() == kSCUP) {
fayang685367a2020-01-14 10:40:15 -080085 if (!one_rtt_keys_available()) {
renjietang87df0d02020-02-13 11:53:52 -080086 stream_->OnUnrecoverableError(
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE,
88 "Early SCUP disallowed");
89 return;
90 }
91
92 // |message| is an update from the server, so we treat it differently from a
93 // handshake message.
94 HandleServerConfigUpdateMessage(message);
95 num_scup_messages_received_++;
96 return;
97 }
98
99 // Do not process handshake messages after the handshake is confirmed.
fayang685367a2020-01-14 10:40:15 -0800100 if (one_rtt_keys_available()) {
renjietang87df0d02020-02-13 11:53:52 -0800101 stream_->OnUnrecoverableError(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
102 "Unexpected handshake message");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500103 return;
104 }
105
106 DoHandshakeLoop(&message);
107}
108
109bool QuicCryptoClientHandshaker::CryptoConnect() {
110 next_state_ = STATE_INITIALIZE;
111 DoHandshakeLoop(nullptr);
112 return session()->connection()->connected();
113}
114
115int QuicCryptoClientHandshaker::num_sent_client_hellos() const {
116 return num_client_hellos_;
117}
118
nharper02703962019-11-07 12:23:13 -0800119bool QuicCryptoClientHandshaker::IsResumption() const {
fayang685367a2020-01-14 10:40:15 -0800120 QUIC_BUG_IF(!one_rtt_keys_available_);
nharper02703962019-11-07 12:23:13 -0800121 // While 0-RTT handshakes could be considered to be like resumption, QUIC
122 // Crypto doesn't have the same notion of a resumption like TLS does.
123 return false;
124}
125
nharper4084fc92020-02-10 14:43:35 -0800126bool QuicCryptoClientHandshaker::EarlyDataAccepted() const {
127 QUIC_BUG_IF(!one_rtt_keys_available_);
128 return num_client_hellos_ == 1;
129}
130
131bool QuicCryptoClientHandshaker::ReceivedInchoateReject() const {
132 QUIC_BUG_IF(!one_rtt_keys_available_);
nharpera485aa92020-02-14 14:09:42 -0800133 return num_client_hellos_ >= 3;
nharper4084fc92020-02-10 14:43:35 -0800134}
135
QUICHE teama6ef0a62019-03-07 20:34:33 -0500136int QuicCryptoClientHandshaker::num_scup_messages_received() const {
137 return num_scup_messages_received_;
138}
139
vasilvvc48c8712019-03-11 13:38:16 -0700140std::string QuicCryptoClientHandshaker::chlo_hash() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500141 return chlo_hash_;
142}
143
144bool QuicCryptoClientHandshaker::encryption_established() const {
145 return encryption_established_;
146}
147
fayang685367a2020-01-14 10:40:15 -0800148bool QuicCryptoClientHandshaker::one_rtt_keys_available() const {
149 return one_rtt_keys_available_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500150}
151
152const QuicCryptoNegotiatedParameters&
153QuicCryptoClientHandshaker::crypto_negotiated_params() const {
154 return *crypto_negotiated_params_;
155}
156
157CryptoMessageParser* QuicCryptoClientHandshaker::crypto_message_parser() {
158 return QuicCryptoHandshaker::crypto_message_parser();
159}
160
fayang9a863cf2020-01-16 14:12:11 -0800161HandshakeState QuicCryptoClientHandshaker::GetHandshakeState() const {
162 return one_rtt_keys_available() ? HANDSHAKE_COMPLETE : HANDSHAKE_START;
163}
164
fayang01062942020-01-22 07:23:23 -0800165void QuicCryptoClientHandshaker::OnHandshakeDoneReceived() {
166 DCHECK(false);
167}
168
nharper486a8a92019-08-28 16:25:10 -0700169size_t QuicCryptoClientHandshaker::BufferSizeLimitForLevel(
170 EncryptionLevel level) const {
171 return QuicCryptoHandshaker::BufferSizeLimitForLevel(level);
172}
173
fayangb35c9f62020-05-21 08:48:53 -0700174void QuicCryptoClientHandshaker::OnConnectionClosed(
175 QuicErrorCode /*error*/,
176 ConnectionCloseSource /*source*/) {
177 next_state_ = STATE_CONNECTION_CLOSED;
178}
179
QUICHE teama6ef0a62019-03-07 20:34:33 -0500180void QuicCryptoClientHandshaker::HandleServerConfigUpdateMessage(
181 const CryptoHandshakeMessage& server_config_update) {
182 DCHECK(server_config_update.tag() == kSCUP);
vasilvvc48c8712019-03-11 13:38:16 -0700183 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184 QuicCryptoClientConfig::CachedState* cached =
185 crypto_config_->LookupOrCreate(server_id_);
186 QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
187 server_config_update, session()->connection()->clock()->WallNow(),
renjietangd1d00852019-09-06 10:43:12 -0700188 session()->transport_version(), chlo_hash_, cached,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500189 crypto_negotiated_params_, &error_details);
190
191 if (error != QUIC_NO_ERROR) {
renjietang87df0d02020-02-13 11:53:52 -0800192 stream_->OnUnrecoverableError(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500193 error, "Server config update invalid: " + error_details);
194 return;
195 }
196
fayang685367a2020-01-14 10:40:15 -0800197 DCHECK(one_rtt_keys_available());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500198 if (proof_verify_callback_) {
199 proof_verify_callback_->Cancel();
200 }
201 next_state_ = STATE_INITIALIZE_SCUP;
202 DoHandshakeLoop(nullptr);
203}
204
205void QuicCryptoClientHandshaker::DoHandshakeLoop(
206 const CryptoHandshakeMessage* in) {
207 QuicCryptoClientConfig::CachedState* cached =
208 crypto_config_->LookupOrCreate(server_id_);
209
210 QuicAsyncStatus rv = QUIC_SUCCESS;
211 do {
212 CHECK_NE(STATE_NONE, next_state_);
213 const State state = next_state_;
214 next_state_ = STATE_IDLE;
215 rv = QUIC_SUCCESS;
216 switch (state) {
217 case STATE_INITIALIZE:
218 DoInitialize(cached);
219 break;
220 case STATE_SEND_CHLO:
221 DoSendCHLO(cached);
222 return; // return waiting to hear from server.
223 case STATE_RECV_REJ:
224 DoReceiveREJ(in, cached);
225 break;
226 case STATE_VERIFY_PROOF:
227 rv = DoVerifyProof(cached);
228 break;
229 case STATE_VERIFY_PROOF_COMPLETE:
230 DoVerifyProofComplete(cached);
231 break;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500232 case STATE_RECV_SHLO:
233 DoReceiveSHLO(in, cached);
234 break;
235 case STATE_IDLE:
236 // This means that the peer sent us a message that we weren't expecting.
renjietang87df0d02020-02-13 11:53:52 -0800237 stream_->OnUnrecoverableError(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
238 "Handshake in idle state");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500239 return;
240 case STATE_INITIALIZE_SCUP:
241 DoInitializeServerConfigUpdate(cached);
242 break;
243 case STATE_NONE:
244 QUIC_NOTREACHED();
fayangb35c9f62020-05-21 08:48:53 -0700245 return;
246 case STATE_CONNECTION_CLOSED:
247 rv = QUIC_FAILURE;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500248 return; // We are done.
249 }
250 } while (rv != QUIC_PENDING && next_state_ != STATE_NONE);
251}
252
253void QuicCryptoClientHandshaker::DoInitialize(
254 QuicCryptoClientConfig::CachedState* cached) {
255 if (!cached->IsEmpty() && !cached->signature().empty()) {
256 // Note that we verify the proof even if the cached proof is valid.
257 // This allows us to respond to CA trust changes or certificate
258 // expiration because it may have been a while since we last verified
259 // the proof.
260 DCHECK(crypto_config_->proof_verifier());
261 // Track proof verification time when cached server config is used.
262 proof_verify_start_time_ = session()->connection()->clock()->Now();
263 chlo_hash_ = cached->chlo_hash();
264 // If the cached state needs to be verified, do it now.
265 next_state_ = STATE_VERIFY_PROOF;
266 } else {
nharper6153bc72019-05-08 12:04:34 -0700267 next_state_ = STATE_SEND_CHLO;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500268 }
269}
270
271void QuicCryptoClientHandshaker::DoSendCHLO(
272 QuicCryptoClientConfig::CachedState* cached) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500273 // Send the client hello in plaintext.
QUICHE team6987b4a2019-03-15 16:23:04 -0700274 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500275 encryption_established_ = false;
QUICHE team8b353f32019-04-09 13:49:10 -0700276 if (num_client_hellos_ >= QuicCryptoClientStream::kMaxClientHellos) {
renjietang87df0d02020-02-13 11:53:52 -0800277 stream_->OnUnrecoverableError(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500278 QUIC_CRYPTO_TOO_MANY_REJECTS,
dmcardlecf0bfcf2019-12-13 08:08:21 -0800279 quiche::QuicheStrCat("More than ",
280 QuicCryptoClientStream::kMaxClientHellos,
281 " rejects"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500282 return;
283 }
284 num_client_hellos_++;
285
286 CryptoHandshakeMessage out;
287 DCHECK(session() != nullptr);
288 DCHECK(session()->config() != nullptr);
289 // Send all the options, regardless of whether we're sending an
290 // inchoate or subsequent hello.
fkastenholzd3a1de92019-05-15 07:00:07 -0700291 session()->config()->ToHandshakeMessage(&out, session()->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500292
renjietang1b5d1e12020-06-23 17:45:20 -0700293 if (!cached->IsComplete(session()->connection()->clock()->WallNow()) ||
294 session()->config()->HasClientRequestedIndependentOption(
295 kQNZR, session()->perspective())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500296 crypto_config_->FillInchoateClientHello(
297 server_id_, session()->supported_versions().front(), cached,
298 session()->connection()->random_generator(),
299 /* demand_x509_proof= */ true, crypto_negotiated_params_, &out);
300 // Pad the inchoate client hello to fill up a packet.
301 const QuicByteCount kFramingOverhead = 50; // A rough estimate.
302 const QuicByteCount max_packet_size =
303 session()->connection()->max_packet_length();
304 if (max_packet_size <= kFramingOverhead) {
305 QUIC_DLOG(DFATAL) << "max_packet_length (" << max_packet_size
306 << ") has no room for framing overhead.";
renjietang87df0d02020-02-13 11:53:52 -0800307 stream_->OnUnrecoverableError(QUIC_INTERNAL_ERROR,
308 "max_packet_size too smalll");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500309 return;
310 }
311 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
312 QUIC_DLOG(DFATAL) << "Client hello won't fit in a single packet.";
renjietang87df0d02020-02-13 11:53:52 -0800313 stream_->OnUnrecoverableError(QUIC_INTERNAL_ERROR, "CHLO too large");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500314 return;
315 }
316 next_state_ = STATE_RECV_REJ;
QUICHE team84910bd2019-03-15 07:03:40 -0700317 chlo_hash_ = CryptoUtils::HashHandshakeMessage(out, Perspective::IS_CLIENT);
nharper3907ac22019-09-25 15:32:28 -0700318 session()->connection()->set_fully_pad_crypto_handshake_packets(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500319 crypto_config_->pad_inchoate_hello());
320 SendHandshakeMessage(out);
321 return;
322 }
323
vasilvvc48c8712019-03-11 13:38:16 -0700324 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500325 QuicErrorCode error = crypto_config_->FillClientHello(
326 server_id_, session()->connection()->connection_id(),
nharperc1bbfe62019-09-27 16:48:40 -0700327 session()->supported_versions().front(),
328 session()->connection()->version(), cached,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500329 session()->connection()->clock()->WallNow(),
nharper6153bc72019-05-08 12:04:34 -0700330 session()->connection()->random_generator(), crypto_negotiated_params_,
331 &out, &error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500332 if (error != QUIC_NO_ERROR) {
333 // Flush the cached config so that, if it's bad, the server has a
334 // chance to send us another in the future.
335 cached->InvalidateServerConfig();
renjietang87df0d02020-02-13 11:53:52 -0800336 stream_->OnUnrecoverableError(error, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500337 return;
338 }
QUICHE team84910bd2019-03-15 07:03:40 -0700339 chlo_hash_ = CryptoUtils::HashHandshakeMessage(out, Perspective::IS_CLIENT);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500340 if (cached->proof_verify_details()) {
341 proof_handler_->OnProofVerifyDetailsAvailable(
342 *cached->proof_verify_details());
343 }
344 next_state_ = STATE_RECV_SHLO;
nharper3907ac22019-09-25 15:32:28 -0700345 session()->connection()->set_fully_pad_crypto_handshake_packets(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500346 crypto_config_->pad_full_hello());
347 SendHandshakeMessage(out);
348 // Be prepared to decrypt with the new server write key.
fayang3f7bcbe2020-02-10 11:08:47 -0800349 delegate_->OnNewEncryptionKeyAvailable(
350 ENCRYPTION_ZERO_RTT,
351 std::move(crypto_negotiated_params_->initial_crypters.encrypter));
352 delegate_->OnNewDecryptionKeyAvailable(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500353 ENCRYPTION_ZERO_RTT,
fayangd96ecda2020-02-03 08:45:18 -0800354 std::move(crypto_negotiated_params_->initial_crypters.decrypter),
355 /*set_alternative_decrypter=*/true,
fayang3f7bcbe2020-02-10 11:08:47 -0800356 /*latch_once_used=*/true);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500357 encryption_established_ = true;
fayangd96ecda2020-02-03 08:45:18 -0800358 delegate_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500359}
360
361void QuicCryptoClientHandshaker::DoReceiveREJ(
362 const CryptoHandshakeMessage* in,
363 QuicCryptoClientConfig::CachedState* cached) {
364 // We sent a dummy CHLO because we didn't have enough information to
365 // perform a handshake, or we sent a full hello that the server
366 // rejected. Here we hope to have a REJ that contains the information
367 // that we need.
wub0a4b9c52019-05-28 13:18:58 -0700368 if (in->tag() != kREJ) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500369 next_state_ = STATE_NONE;
renjietang87df0d02020-02-13 11:53:52 -0800370 stream_->OnUnrecoverableError(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
371 "Expected REJ");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500372 return;
373 }
374
375 QuicTagVector reject_reasons;
376 static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
377 if (in->GetTaglist(kRREJ, &reject_reasons) == QUIC_NO_ERROR) {
378 uint32_t packed_error = 0;
379 for (size_t i = 0; i < reject_reasons.size(); ++i) {
380 // HANDSHAKE_OK is 0 and don't report that as error.
381 if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
382 continue;
383 }
384 HandshakeFailureReason reason =
385 static_cast<HandshakeFailureReason>(reject_reasons[i]);
386 packed_error |= 1 << (reason - 1);
387 }
bnc5de87052019-05-03 14:21:53 -0700388 QUIC_DVLOG(1) << "Reasons for rejection: " << packed_error;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500389 if (num_client_hellos_ == QuicCryptoClientStream::kMaxClientHellos) {
390 QuicClientSparseHistogram("QuicClientHelloRejectReasons.TooMany",
391 packed_error);
392 }
393 QuicClientSparseHistogram("QuicClientHelloRejectReasons.Secure",
394 packed_error);
395 }
396
397 // Receipt of a REJ message means that the server received the CHLO
398 // so we can cancel and retransmissions.
fayangd96ecda2020-02-03 08:45:18 -0800399 delegate_->NeuterUnencryptedData();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500400
vasilvvc48c8712019-03-11 13:38:16 -0700401 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500402 QuicErrorCode error = crypto_config_->ProcessRejection(
403 *in, session()->connection()->clock()->WallNow(),
renjietangd1d00852019-09-06 10:43:12 -0700404 session()->transport_version(), chlo_hash_, cached,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500405 crypto_negotiated_params_, &error_details);
406
407 if (error != QUIC_NO_ERROR) {
408 next_state_ = STATE_NONE;
renjietang87df0d02020-02-13 11:53:52 -0800409 stream_->OnUnrecoverableError(error, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500410 return;
411 }
412 if (!cached->proof_valid()) {
413 if (!cached->signature().empty()) {
414 // Note that we only verify the proof if the cached proof is not
415 // valid. If the cached proof is valid here, someone else must have
416 // just added the server config to the cache and verified the proof,
417 // so we can assume no CA trust changes or certificate expiration
418 // has happened since then.
419 next_state_ = STATE_VERIFY_PROOF;
420 return;
421 }
422 }
nharper6153bc72019-05-08 12:04:34 -0700423 next_state_ = STATE_SEND_CHLO;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500424}
425
426QuicAsyncStatus QuicCryptoClientHandshaker::DoVerifyProof(
427 QuicCryptoClientConfig::CachedState* cached) {
428 ProofVerifier* verifier = crypto_config_->proof_verifier();
429 DCHECK(verifier);
430 next_state_ = STATE_VERIFY_PROOF_COMPLETE;
431 generation_counter_ = cached->generation_counter();
432
433 ProofVerifierCallbackImpl* proof_verify_callback =
434 new ProofVerifierCallbackImpl(this);
435
436 verify_ok_ = false;
437
438 QuicAsyncStatus status = verifier->VerifyProof(
439 server_id_.host(), server_id_.port(), cached->server_config(),
renjietangd1d00852019-09-06 10:43:12 -0700440 session()->transport_version(), chlo_hash_, cached->certs(),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500441 cached->cert_sct(), cached->signature(), verify_context_.get(),
442 &verify_error_details_, &verify_details_,
443 std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
444
445 switch (status) {
446 case QUIC_PENDING:
447 proof_verify_callback_ = proof_verify_callback;
448 QUIC_DVLOG(1) << "Doing VerifyProof";
449 break;
450 case QUIC_FAILURE:
451 break;
452 case QUIC_SUCCESS:
453 verify_ok_ = true;
454 break;
455 }
456 return status;
457}
458
459void QuicCryptoClientHandshaker::DoVerifyProofComplete(
460 QuicCryptoClientConfig::CachedState* cached) {
461 if (proof_verify_start_time_.IsInitialized()) {
462 QUIC_CLIENT_HISTOGRAM_TIMES(
463 "QuicSession.VerifyProofTime.CachedServerConfig",
464 (session()->connection()->clock()->Now() - proof_verify_start_time_),
465 QuicTime::Delta::FromMilliseconds(1), QuicTime::Delta::FromSeconds(10),
466 50, "");
467 }
468 if (!verify_ok_) {
469 if (verify_details_) {
470 proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_);
471 }
472 if (num_client_hellos_ == 0) {
473 cached->Clear();
474 next_state_ = STATE_INITIALIZE;
475 return;
476 }
477 next_state_ = STATE_NONE;
478 QUIC_CLIENT_HISTOGRAM_BOOL("QuicVerifyProofFailed.HandshakeConfirmed",
fayang685367a2020-01-14 10:40:15 -0800479 one_rtt_keys_available(), "");
renjietang87df0d02020-02-13 11:53:52 -0800480 stream_->OnUnrecoverableError(QUIC_PROOF_INVALID,
481 "Proof invalid: " + verify_error_details_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500482 return;
483 }
484
485 // Check if generation_counter has changed between STATE_VERIFY_PROOF and
486 // STATE_VERIFY_PROOF_COMPLETE state changes.
487 if (generation_counter_ != cached->generation_counter()) {
488 next_state_ = STATE_VERIFY_PROOF;
489 } else {
490 SetCachedProofValid(cached);
491 cached->SetProofVerifyDetails(verify_details_.release());
fayang685367a2020-01-14 10:40:15 -0800492 if (!one_rtt_keys_available()) {
nharper6153bc72019-05-08 12:04:34 -0700493 next_state_ = STATE_SEND_CHLO;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500494 } else {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500495 next_state_ = STATE_NONE;
496 }
497 }
498}
499
QUICHE teama6ef0a62019-03-07 20:34:33 -0500500void QuicCryptoClientHandshaker::DoReceiveSHLO(
501 const CryptoHandshakeMessage* in,
502 QuicCryptoClientConfig::CachedState* cached) {
503 next_state_ = STATE_NONE;
504 // We sent a CHLO that we expected to be accepted and now we're
505 // hoping for a SHLO from the server to confirm that. First check
506 // to see whether the response was a reject, and if so, move on to
507 // the reject-processing state.
wub0a4b9c52019-05-28 13:18:58 -0700508 if (in->tag() == kREJ) {
zhongyi546cc452019-04-12 15:27:49 -0700509 // A reject message must be sent in ENCRYPTION_INITIAL.
510 if (session()->connection()->last_decrypted_level() != ENCRYPTION_INITIAL) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500511 // The rejection was sent encrypted!
renjietang87df0d02020-02-13 11:53:52 -0800512 stream_->OnUnrecoverableError(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
513 "encrypted REJ message");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500514 return;
515 }
516 next_state_ = STATE_RECV_REJ;
517 return;
518 }
519
520 if (in->tag() != kSHLO) {
renjietang87df0d02020-02-13 11:53:52 -0800521 stream_->OnUnrecoverableError(
rch90756152020-01-10 15:09:04 -0800522 QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
523 quiche::QuicheStrCat("Expected SHLO or REJ. Received: ",
524 QuicTagToString(in->tag())));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500525 return;
526 }
527
zhongyi546cc452019-04-12 15:27:49 -0700528 if (session()->connection()->last_decrypted_level() == ENCRYPTION_INITIAL) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500529 // The server hello was sent without encryption.
renjietang87df0d02020-02-13 11:53:52 -0800530 stream_->OnUnrecoverableError(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
531 "unencrypted SHLO message");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500532 return;
533 }
534
vasilvvc48c8712019-03-11 13:38:16 -0700535 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500536 QuicErrorCode error = crypto_config_->ProcessServerHello(
537 *in, session()->connection()->connection_id(),
538 session()->connection()->version(),
539 session()->connection()->server_supported_versions(), cached,
540 crypto_negotiated_params_, &error_details);
541
542 if (error != QUIC_NO_ERROR) {
renjietang87df0d02020-02-13 11:53:52 -0800543 stream_->OnUnrecoverableError(error,
544 "Server hello invalid: " + error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500545 return;
546 }
547 error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
548 if (error != QUIC_NO_ERROR) {
renjietang87df0d02020-02-13 11:53:52 -0800549 stream_->OnUnrecoverableError(error,
550 "Server hello invalid: " + error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500551 return;
552 }
553 session()->OnConfigNegotiated();
554
555 CrypterPair* crypters = &crypto_negotiated_params_->forward_secure_crypters;
556 // TODO(agl): we don't currently latch this decrypter because the idea
557 // has been floated that the server shouldn't send packets encrypted
558 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
559 // packet from the client.
fayang3f7bcbe2020-02-10 11:08:47 -0800560 delegate_->OnNewEncryptionKeyAvailable(ENCRYPTION_FORWARD_SECURE,
561 std::move(crypters->encrypter));
562 delegate_->OnNewDecryptionKeyAvailable(ENCRYPTION_FORWARD_SECURE,
563 std::move(crypters->decrypter),
564 /*set_alternative_decrypter=*/true,
565 /*latch_once_used=*/false);
fayang685367a2020-01-14 10:40:15 -0800566 one_rtt_keys_available_ = true;
fayangd96ecda2020-02-03 08:45:18 -0800567 delegate_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
568 delegate_->DiscardOldEncryptionKey(ENCRYPTION_INITIAL);
569 delegate_->NeuterHandshakeData();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500570}
571
572void QuicCryptoClientHandshaker::DoInitializeServerConfigUpdate(
573 QuicCryptoClientConfig::CachedState* cached) {
574 bool update_ignored = false;
575 if (!cached->IsEmpty() && !cached->signature().empty()) {
576 // Note that we verify the proof even if the cached proof is valid.
577 DCHECK(crypto_config_->proof_verifier());
578 next_state_ = STATE_VERIFY_PROOF;
579 } else {
580 update_ignored = true;
581 next_state_ = STATE_NONE;
582 }
583 QUIC_CLIENT_HISTOGRAM_COUNTS("QuicNumServerConfig.UpdateMessagesIgnored",
584 update_ignored, 1, 1000000, 50, "");
585}
586
587void QuicCryptoClientHandshaker::SetCachedProofValid(
588 QuicCryptoClientConfig::CachedState* cached) {
589 cached->SetProofValid();
590 proof_handler_->OnProofValid(*cached);
591}
592
QUICHE teama6ef0a62019-03-07 20:34:33 -0500593} // namespace quic