blob: d9e67dbb0692a7d0d96b2cc78eedf2fbe7d02453 [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_);
133 return num_client_hellos_ == 3;
134}
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
QUICHE teama6ef0a62019-03-07 20:34:33 -0500174void QuicCryptoClientHandshaker::HandleServerConfigUpdateMessage(
175 const CryptoHandshakeMessage& server_config_update) {
176 DCHECK(server_config_update.tag() == kSCUP);
vasilvvc48c8712019-03-11 13:38:16 -0700177 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500178 QuicCryptoClientConfig::CachedState* cached =
179 crypto_config_->LookupOrCreate(server_id_);
180 QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
181 server_config_update, session()->connection()->clock()->WallNow(),
renjietangd1d00852019-09-06 10:43:12 -0700182 session()->transport_version(), chlo_hash_, cached,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500183 crypto_negotiated_params_, &error_details);
184
185 if (error != QUIC_NO_ERROR) {
renjietang87df0d02020-02-13 11:53:52 -0800186 stream_->OnUnrecoverableError(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500187 error, "Server config update invalid: " + error_details);
188 return;
189 }
190
fayang685367a2020-01-14 10:40:15 -0800191 DCHECK(one_rtt_keys_available());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500192 if (proof_verify_callback_) {
193 proof_verify_callback_->Cancel();
194 }
195 next_state_ = STATE_INITIALIZE_SCUP;
196 DoHandshakeLoop(nullptr);
197}
198
199void QuicCryptoClientHandshaker::DoHandshakeLoop(
200 const CryptoHandshakeMessage* in) {
201 QuicCryptoClientConfig::CachedState* cached =
202 crypto_config_->LookupOrCreate(server_id_);
203
204 QuicAsyncStatus rv = QUIC_SUCCESS;
205 do {
206 CHECK_NE(STATE_NONE, next_state_);
207 const State state = next_state_;
208 next_state_ = STATE_IDLE;
209 rv = QUIC_SUCCESS;
210 switch (state) {
211 case STATE_INITIALIZE:
212 DoInitialize(cached);
213 break;
214 case STATE_SEND_CHLO:
215 DoSendCHLO(cached);
216 return; // return waiting to hear from server.
217 case STATE_RECV_REJ:
218 DoReceiveREJ(in, cached);
219 break;
220 case STATE_VERIFY_PROOF:
221 rv = DoVerifyProof(cached);
222 break;
223 case STATE_VERIFY_PROOF_COMPLETE:
224 DoVerifyProofComplete(cached);
225 break;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500226 case STATE_RECV_SHLO:
227 DoReceiveSHLO(in, cached);
228 break;
229 case STATE_IDLE:
230 // This means that the peer sent us a message that we weren't expecting.
renjietang87df0d02020-02-13 11:53:52 -0800231 stream_->OnUnrecoverableError(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
232 "Handshake in idle state");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500233 return;
234 case STATE_INITIALIZE_SCUP:
235 DoInitializeServerConfigUpdate(cached);
236 break;
237 case STATE_NONE:
238 QUIC_NOTREACHED();
239 return; // We are done.
240 }
241 } while (rv != QUIC_PENDING && next_state_ != STATE_NONE);
242}
243
244void QuicCryptoClientHandshaker::DoInitialize(
245 QuicCryptoClientConfig::CachedState* cached) {
246 if (!cached->IsEmpty() && !cached->signature().empty()) {
247 // Note that we verify the proof even if the cached proof is valid.
248 // This allows us to respond to CA trust changes or certificate
249 // expiration because it may have been a while since we last verified
250 // the proof.
251 DCHECK(crypto_config_->proof_verifier());
252 // Track proof verification time when cached server config is used.
253 proof_verify_start_time_ = session()->connection()->clock()->Now();
254 chlo_hash_ = cached->chlo_hash();
255 // If the cached state needs to be verified, do it now.
256 next_state_ = STATE_VERIFY_PROOF;
257 } else {
nharper6153bc72019-05-08 12:04:34 -0700258 next_state_ = STATE_SEND_CHLO;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500259 }
260}
261
262void QuicCryptoClientHandshaker::DoSendCHLO(
263 QuicCryptoClientConfig::CachedState* cached) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500264 // Send the client hello in plaintext.
QUICHE team6987b4a2019-03-15 16:23:04 -0700265 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500266 encryption_established_ = false;
QUICHE team8b353f32019-04-09 13:49:10 -0700267 if (num_client_hellos_ >= QuicCryptoClientStream::kMaxClientHellos) {
renjietang87df0d02020-02-13 11:53:52 -0800268 stream_->OnUnrecoverableError(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500269 QUIC_CRYPTO_TOO_MANY_REJECTS,
dmcardlecf0bfcf2019-12-13 08:08:21 -0800270 quiche::QuicheStrCat("More than ",
271 QuicCryptoClientStream::kMaxClientHellos,
272 " rejects"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500273 return;
274 }
275 num_client_hellos_++;
276
277 CryptoHandshakeMessage out;
278 DCHECK(session() != nullptr);
279 DCHECK(session()->config() != nullptr);
280 // Send all the options, regardless of whether we're sending an
281 // inchoate or subsequent hello.
fkastenholzd3a1de92019-05-15 07:00:07 -0700282 session()->config()->ToHandshakeMessage(&out, session()->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500283
284 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
285 crypto_config_->FillInchoateClientHello(
286 server_id_, session()->supported_versions().front(), cached,
287 session()->connection()->random_generator(),
288 /* demand_x509_proof= */ true, crypto_negotiated_params_, &out);
289 // Pad the inchoate client hello to fill up a packet.
290 const QuicByteCount kFramingOverhead = 50; // A rough estimate.
291 const QuicByteCount max_packet_size =
292 session()->connection()->max_packet_length();
293 if (max_packet_size <= kFramingOverhead) {
294 QUIC_DLOG(DFATAL) << "max_packet_length (" << max_packet_size
295 << ") has no room for framing overhead.";
renjietang87df0d02020-02-13 11:53:52 -0800296 stream_->OnUnrecoverableError(QUIC_INTERNAL_ERROR,
297 "max_packet_size too smalll");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500298 return;
299 }
300 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
301 QUIC_DLOG(DFATAL) << "Client hello won't fit in a single packet.";
renjietang87df0d02020-02-13 11:53:52 -0800302 stream_->OnUnrecoverableError(QUIC_INTERNAL_ERROR, "CHLO too large");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500303 return;
304 }
305 next_state_ = STATE_RECV_REJ;
QUICHE team84910bd2019-03-15 07:03:40 -0700306 chlo_hash_ = CryptoUtils::HashHandshakeMessage(out, Perspective::IS_CLIENT);
nharper3907ac22019-09-25 15:32:28 -0700307 session()->connection()->set_fully_pad_crypto_handshake_packets(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500308 crypto_config_->pad_inchoate_hello());
309 SendHandshakeMessage(out);
310 return;
311 }
312
vasilvvc48c8712019-03-11 13:38:16 -0700313 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500314 QuicErrorCode error = crypto_config_->FillClientHello(
315 server_id_, session()->connection()->connection_id(),
nharperc1bbfe62019-09-27 16:48:40 -0700316 session()->supported_versions().front(),
317 session()->connection()->version(), cached,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500318 session()->connection()->clock()->WallNow(),
nharper6153bc72019-05-08 12:04:34 -0700319 session()->connection()->random_generator(), crypto_negotiated_params_,
320 &out, &error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500321 if (error != QUIC_NO_ERROR) {
322 // Flush the cached config so that, if it's bad, the server has a
323 // chance to send us another in the future.
324 cached->InvalidateServerConfig();
renjietang87df0d02020-02-13 11:53:52 -0800325 stream_->OnUnrecoverableError(error, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500326 return;
327 }
QUICHE team84910bd2019-03-15 07:03:40 -0700328 chlo_hash_ = CryptoUtils::HashHandshakeMessage(out, Perspective::IS_CLIENT);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500329 if (cached->proof_verify_details()) {
330 proof_handler_->OnProofVerifyDetailsAvailable(
331 *cached->proof_verify_details());
332 }
333 next_state_ = STATE_RECV_SHLO;
nharper3907ac22019-09-25 15:32:28 -0700334 session()->connection()->set_fully_pad_crypto_handshake_packets(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500335 crypto_config_->pad_full_hello());
336 SendHandshakeMessage(out);
337 // Be prepared to decrypt with the new server write key.
fayang3f7bcbe2020-02-10 11:08:47 -0800338 delegate_->OnNewEncryptionKeyAvailable(
339 ENCRYPTION_ZERO_RTT,
340 std::move(crypto_negotiated_params_->initial_crypters.encrypter));
341 delegate_->OnNewDecryptionKeyAvailable(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500342 ENCRYPTION_ZERO_RTT,
fayangd96ecda2020-02-03 08:45:18 -0800343 std::move(crypto_negotiated_params_->initial_crypters.decrypter),
344 /*set_alternative_decrypter=*/true,
fayang3f7bcbe2020-02-10 11:08:47 -0800345 /*latch_once_used=*/true);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500346 encryption_established_ = true;
fayangd96ecda2020-02-03 08:45:18 -0800347 delegate_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500348}
349
350void QuicCryptoClientHandshaker::DoReceiveREJ(
351 const CryptoHandshakeMessage* in,
352 QuicCryptoClientConfig::CachedState* cached) {
353 // We sent a dummy CHLO because we didn't have enough information to
354 // perform a handshake, or we sent a full hello that the server
355 // rejected. Here we hope to have a REJ that contains the information
356 // that we need.
wub0a4b9c52019-05-28 13:18:58 -0700357 if (in->tag() != kREJ) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500358 next_state_ = STATE_NONE;
renjietang87df0d02020-02-13 11:53:52 -0800359 stream_->OnUnrecoverableError(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
360 "Expected REJ");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500361 return;
362 }
363
364 QuicTagVector reject_reasons;
365 static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
366 if (in->GetTaglist(kRREJ, &reject_reasons) == QUIC_NO_ERROR) {
367 uint32_t packed_error = 0;
368 for (size_t i = 0; i < reject_reasons.size(); ++i) {
369 // HANDSHAKE_OK is 0 and don't report that as error.
370 if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
371 continue;
372 }
373 HandshakeFailureReason reason =
374 static_cast<HandshakeFailureReason>(reject_reasons[i]);
375 packed_error |= 1 << (reason - 1);
376 }
bnc5de87052019-05-03 14:21:53 -0700377 QUIC_DVLOG(1) << "Reasons for rejection: " << packed_error;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500378 if (num_client_hellos_ == QuicCryptoClientStream::kMaxClientHellos) {
379 QuicClientSparseHistogram("QuicClientHelloRejectReasons.TooMany",
380 packed_error);
381 }
382 QuicClientSparseHistogram("QuicClientHelloRejectReasons.Secure",
383 packed_error);
384 }
385
386 // Receipt of a REJ message means that the server received the CHLO
387 // so we can cancel and retransmissions.
fayangd96ecda2020-02-03 08:45:18 -0800388 delegate_->NeuterUnencryptedData();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500389
vasilvvc48c8712019-03-11 13:38:16 -0700390 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500391 QuicErrorCode error = crypto_config_->ProcessRejection(
392 *in, session()->connection()->clock()->WallNow(),
renjietangd1d00852019-09-06 10:43:12 -0700393 session()->transport_version(), chlo_hash_, cached,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394 crypto_negotiated_params_, &error_details);
395
396 if (error != QUIC_NO_ERROR) {
397 next_state_ = STATE_NONE;
renjietang87df0d02020-02-13 11:53:52 -0800398 stream_->OnUnrecoverableError(error, error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500399 return;
400 }
401 if (!cached->proof_valid()) {
402 if (!cached->signature().empty()) {
403 // Note that we only verify the proof if the cached proof is not
404 // valid. If the cached proof is valid here, someone else must have
405 // just added the server config to the cache and verified the proof,
406 // so we can assume no CA trust changes or certificate expiration
407 // has happened since then.
408 next_state_ = STATE_VERIFY_PROOF;
409 return;
410 }
411 }
nharper6153bc72019-05-08 12:04:34 -0700412 next_state_ = STATE_SEND_CHLO;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500413}
414
415QuicAsyncStatus QuicCryptoClientHandshaker::DoVerifyProof(
416 QuicCryptoClientConfig::CachedState* cached) {
417 ProofVerifier* verifier = crypto_config_->proof_verifier();
418 DCHECK(verifier);
419 next_state_ = STATE_VERIFY_PROOF_COMPLETE;
420 generation_counter_ = cached->generation_counter();
421
422 ProofVerifierCallbackImpl* proof_verify_callback =
423 new ProofVerifierCallbackImpl(this);
424
425 verify_ok_ = false;
426
427 QuicAsyncStatus status = verifier->VerifyProof(
428 server_id_.host(), server_id_.port(), cached->server_config(),
renjietangd1d00852019-09-06 10:43:12 -0700429 session()->transport_version(), chlo_hash_, cached->certs(),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500430 cached->cert_sct(), cached->signature(), verify_context_.get(),
431 &verify_error_details_, &verify_details_,
432 std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
433
434 switch (status) {
435 case QUIC_PENDING:
436 proof_verify_callback_ = proof_verify_callback;
437 QUIC_DVLOG(1) << "Doing VerifyProof";
438 break;
439 case QUIC_FAILURE:
440 break;
441 case QUIC_SUCCESS:
442 verify_ok_ = true;
443 break;
444 }
445 return status;
446}
447
448void QuicCryptoClientHandshaker::DoVerifyProofComplete(
449 QuicCryptoClientConfig::CachedState* cached) {
450 if (proof_verify_start_time_.IsInitialized()) {
451 QUIC_CLIENT_HISTOGRAM_TIMES(
452 "QuicSession.VerifyProofTime.CachedServerConfig",
453 (session()->connection()->clock()->Now() - proof_verify_start_time_),
454 QuicTime::Delta::FromMilliseconds(1), QuicTime::Delta::FromSeconds(10),
455 50, "");
456 }
457 if (!verify_ok_) {
458 if (verify_details_) {
459 proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_);
460 }
461 if (num_client_hellos_ == 0) {
462 cached->Clear();
463 next_state_ = STATE_INITIALIZE;
464 return;
465 }
466 next_state_ = STATE_NONE;
467 QUIC_CLIENT_HISTOGRAM_BOOL("QuicVerifyProofFailed.HandshakeConfirmed",
fayang685367a2020-01-14 10:40:15 -0800468 one_rtt_keys_available(), "");
renjietang87df0d02020-02-13 11:53:52 -0800469 stream_->OnUnrecoverableError(QUIC_PROOF_INVALID,
470 "Proof invalid: " + verify_error_details_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500471 return;
472 }
473
474 // Check if generation_counter has changed between STATE_VERIFY_PROOF and
475 // STATE_VERIFY_PROOF_COMPLETE state changes.
476 if (generation_counter_ != cached->generation_counter()) {
477 next_state_ = STATE_VERIFY_PROOF;
478 } else {
479 SetCachedProofValid(cached);
480 cached->SetProofVerifyDetails(verify_details_.release());
fayang685367a2020-01-14 10:40:15 -0800481 if (!one_rtt_keys_available()) {
nharper6153bc72019-05-08 12:04:34 -0700482 next_state_ = STATE_SEND_CHLO;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500483 } else {
484 // TODO: Enable Expect-Staple. https://crbug.com/631101
485 next_state_ = STATE_NONE;
486 }
487 }
488}
489
QUICHE teama6ef0a62019-03-07 20:34:33 -0500490void QuicCryptoClientHandshaker::DoReceiveSHLO(
491 const CryptoHandshakeMessage* in,
492 QuicCryptoClientConfig::CachedState* cached) {
493 next_state_ = STATE_NONE;
494 // We sent a CHLO that we expected to be accepted and now we're
495 // hoping for a SHLO from the server to confirm that. First check
496 // to see whether the response was a reject, and if so, move on to
497 // the reject-processing state.
wub0a4b9c52019-05-28 13:18:58 -0700498 if (in->tag() == kREJ) {
zhongyi546cc452019-04-12 15:27:49 -0700499 // A reject message must be sent in ENCRYPTION_INITIAL.
500 if (session()->connection()->last_decrypted_level() != ENCRYPTION_INITIAL) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500501 // The rejection was sent encrypted!
renjietang87df0d02020-02-13 11:53:52 -0800502 stream_->OnUnrecoverableError(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
503 "encrypted REJ message");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500504 return;
505 }
506 next_state_ = STATE_RECV_REJ;
507 return;
508 }
509
510 if (in->tag() != kSHLO) {
renjietang87df0d02020-02-13 11:53:52 -0800511 stream_->OnUnrecoverableError(
rch90756152020-01-10 15:09:04 -0800512 QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
513 quiche::QuicheStrCat("Expected SHLO or REJ. Received: ",
514 QuicTagToString(in->tag())));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500515 return;
516 }
517
zhongyi546cc452019-04-12 15:27:49 -0700518 if (session()->connection()->last_decrypted_level() == ENCRYPTION_INITIAL) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500519 // The server hello was sent without encryption.
renjietang87df0d02020-02-13 11:53:52 -0800520 stream_->OnUnrecoverableError(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
521 "unencrypted SHLO message");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500522 return;
523 }
524
vasilvvc48c8712019-03-11 13:38:16 -0700525 std::string error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500526 QuicErrorCode error = crypto_config_->ProcessServerHello(
527 *in, session()->connection()->connection_id(),
528 session()->connection()->version(),
529 session()->connection()->server_supported_versions(), cached,
530 crypto_negotiated_params_, &error_details);
531
532 if (error != QUIC_NO_ERROR) {
renjietang87df0d02020-02-13 11:53:52 -0800533 stream_->OnUnrecoverableError(error,
534 "Server hello invalid: " + error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500535 return;
536 }
537 error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
538 if (error != QUIC_NO_ERROR) {
renjietang87df0d02020-02-13 11:53:52 -0800539 stream_->OnUnrecoverableError(error,
540 "Server hello invalid: " + error_details);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500541 return;
542 }
543 session()->OnConfigNegotiated();
544
545 CrypterPair* crypters = &crypto_negotiated_params_->forward_secure_crypters;
546 // TODO(agl): we don't currently latch this decrypter because the idea
547 // has been floated that the server shouldn't send packets encrypted
548 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
549 // packet from the client.
fayang3f7bcbe2020-02-10 11:08:47 -0800550 delegate_->OnNewEncryptionKeyAvailable(ENCRYPTION_FORWARD_SECURE,
551 std::move(crypters->encrypter));
552 delegate_->OnNewDecryptionKeyAvailable(ENCRYPTION_FORWARD_SECURE,
553 std::move(crypters->decrypter),
554 /*set_alternative_decrypter=*/true,
555 /*latch_once_used=*/false);
fayang685367a2020-01-14 10:40:15 -0800556 one_rtt_keys_available_ = true;
fayangd96ecda2020-02-03 08:45:18 -0800557 delegate_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
558 delegate_->DiscardOldEncryptionKey(ENCRYPTION_INITIAL);
559 delegate_->NeuterHandshakeData();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500560}
561
562void QuicCryptoClientHandshaker::DoInitializeServerConfigUpdate(
563 QuicCryptoClientConfig::CachedState* cached) {
564 bool update_ignored = false;
565 if (!cached->IsEmpty() && !cached->signature().empty()) {
566 // Note that we verify the proof even if the cached proof is valid.
567 DCHECK(crypto_config_->proof_verifier());
568 next_state_ = STATE_VERIFY_PROOF;
569 } else {
570 update_ignored = true;
571 next_state_ = STATE_NONE;
572 }
573 QUIC_CLIENT_HISTOGRAM_COUNTS("QuicNumServerConfig.UpdateMessagesIgnored",
574 update_ignored, 1, 1000000, 50, "");
575}
576
577void QuicCryptoClientHandshaker::SetCachedProofValid(
578 QuicCryptoClientConfig::CachedState* cached) {
579 cached->SetProofValid();
580 proof_handler_->OnProofValid(*cached);
581}
582
QUICHE teama6ef0a62019-03-07 20:34:33 -0500583} // namespace quic