OLD | NEW |
| (Empty) |
1 // 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/quic/quic_crypto_client_stream.h" | |
6 | |
7 #include <memory> | |
8 #include <vector> | |
9 | |
10 #include "base/metrics/histogram_macros.h" | |
11 #include "base/metrics/sparse_histogram.h" | |
12 #include "base/strings/stringprintf.h" | |
13 #include "net/quic/crypto/crypto_protocol.h" | |
14 #include "net/quic/crypto/crypto_utils.h" | |
15 #include "net/quic/crypto/null_encrypter.h" | |
16 #include "net/quic/quic_flags.h" | |
17 #include "net/quic/quic_protocol.h" | |
18 #include "net/quic/quic_session.h" | |
19 #include "net/quic/quic_utils.h" | |
20 | |
21 using std::string; | |
22 using std::vector; | |
23 | |
24 namespace net { | |
25 | |
26 namespace { | |
27 | |
28 void AppendFixed(CryptoHandshakeMessage* message) { | |
29 if (FLAGS_quic_deprecate_kfixd) { | |
30 return; | |
31 } | |
32 vector<QuicTag> tags; | |
33 tags.push_back(kFIXD); | |
34 | |
35 const QuicTag* received_tags; | |
36 size_t received_tags_length; | |
37 QuicErrorCode error = | |
38 message->GetTaglist(kCOPT, &received_tags, &received_tags_length); | |
39 if (error == QUIC_NO_ERROR) { | |
40 for (size_t i = 0; i < received_tags_length; ++i) { | |
41 tags.push_back(received_tags[i]); | |
42 } | |
43 } | |
44 message->SetVector(kCOPT, tags); | |
45 } | |
46 | |
47 } // namespace | |
48 | |
49 QuicCryptoClientStreamBase::QuicCryptoClientStreamBase(QuicSession* session) | |
50 : QuicCryptoStream(session) {} | |
51 | |
52 QuicCryptoClientStream::ChannelIDSourceCallbackImpl:: | |
53 ChannelIDSourceCallbackImpl(QuicCryptoClientStream* stream) | |
54 : stream_(stream) {} | |
55 | |
56 QuicCryptoClientStream::ChannelIDSourceCallbackImpl:: | |
57 ~ChannelIDSourceCallbackImpl() {} | |
58 | |
59 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Run( | |
60 std::unique_ptr<ChannelIDKey>* channel_id_key) { | |
61 if (stream_ == nullptr) { | |
62 return; | |
63 } | |
64 | |
65 stream_->channel_id_key_.reset(channel_id_key->release()); | |
66 stream_->channel_id_source_callback_run_ = true; | |
67 stream_->channel_id_source_callback_ = nullptr; | |
68 stream_->DoHandshakeLoop(nullptr); | |
69 | |
70 // The ChannelIDSource owns this object and will delete it when this method | |
71 // returns. | |
72 } | |
73 | |
74 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Cancel() { | |
75 stream_ = nullptr; | |
76 } | |
77 | |
78 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl( | |
79 QuicCryptoClientStream* stream) | |
80 : stream_(stream) {} | |
81 | |
82 QuicCryptoClientStream::ProofVerifierCallbackImpl:: | |
83 ~ProofVerifierCallbackImpl() {} | |
84 | |
85 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run( | |
86 bool ok, | |
87 const string& error_details, | |
88 std::unique_ptr<ProofVerifyDetails>* details) { | |
89 if (stream_ == nullptr) { | |
90 return; | |
91 } | |
92 | |
93 stream_->verify_ok_ = ok; | |
94 stream_->verify_error_details_ = error_details; | |
95 stream_->verify_details_.reset(details->release()); | |
96 stream_->proof_verify_callback_ = nullptr; | |
97 stream_->DoHandshakeLoop(nullptr); | |
98 | |
99 // The ProofVerifier owns this object and will delete it when this method | |
100 // returns. | |
101 } | |
102 | |
103 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() { | |
104 stream_ = nullptr; | |
105 } | |
106 | |
107 QuicCryptoClientStream::QuicCryptoClientStream( | |
108 const QuicServerId& server_id, | |
109 QuicSession* session, | |
110 ProofVerifyContext* verify_context, | |
111 QuicCryptoClientConfig* crypto_config, | |
112 ProofHandler* proof_handler) | |
113 : QuicCryptoClientStreamBase(session), | |
114 next_state_(STATE_IDLE), | |
115 num_client_hellos_(0), | |
116 crypto_config_(crypto_config), | |
117 server_id_(server_id), | |
118 generation_counter_(0), | |
119 channel_id_sent_(false), | |
120 channel_id_source_callback_run_(false), | |
121 channel_id_source_callback_(nullptr), | |
122 verify_context_(verify_context), | |
123 proof_verify_callback_(nullptr), | |
124 proof_handler_(proof_handler), | |
125 stateless_reject_received_(false), | |
126 num_scup_messages_received_(0) { | |
127 DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective()); | |
128 } | |
129 | |
130 QuicCryptoClientStream::~QuicCryptoClientStream() { | |
131 if (channel_id_source_callback_) { | |
132 channel_id_source_callback_->Cancel(); | |
133 } | |
134 if (proof_verify_callback_) { | |
135 proof_verify_callback_->Cancel(); | |
136 } | |
137 } | |
138 | |
139 void QuicCryptoClientStream::OnHandshakeMessage( | |
140 const CryptoHandshakeMessage& message) { | |
141 QuicCryptoClientStreamBase::OnHandshakeMessage(message); | |
142 | |
143 if (message.tag() == kSCUP) { | |
144 if (!handshake_confirmed()) { | |
145 CloseConnectionWithDetails(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, | |
146 "Early SCUP disallowed"); | |
147 return; | |
148 } | |
149 | |
150 // |message| is an update from the server, so we treat it differently from a | |
151 // handshake message. | |
152 HandleServerConfigUpdateMessage(message); | |
153 num_scup_messages_received_++; | |
154 return; | |
155 } | |
156 | |
157 // Do not process handshake messages after the handshake is confirmed. | |
158 if (handshake_confirmed()) { | |
159 CloseConnectionWithDetails(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, | |
160 "Unexpected handshake message"); | |
161 return; | |
162 } | |
163 | |
164 DoHandshakeLoop(&message); | |
165 } | |
166 | |
167 void QuicCryptoClientStream::CryptoConnect() { | |
168 next_state_ = STATE_INITIALIZE; | |
169 DoHandshakeLoop(nullptr); | |
170 } | |
171 | |
172 int QuicCryptoClientStream::num_sent_client_hellos() const { | |
173 return num_client_hellos_; | |
174 } | |
175 | |
176 int QuicCryptoClientStream::num_scup_messages_received() const { | |
177 return num_scup_messages_received_; | |
178 } | |
179 | |
180 // Used in Chromium, but not in the server. | |
181 bool QuicCryptoClientStream::WasChannelIDSent() const { | |
182 return channel_id_sent_; | |
183 } | |
184 | |
185 bool QuicCryptoClientStream::WasChannelIDSourceCallbackRun() const { | |
186 return channel_id_source_callback_run_; | |
187 } | |
188 | |
189 void QuicCryptoClientStream::HandleServerConfigUpdateMessage( | |
190 const CryptoHandshakeMessage& server_config_update) { | |
191 DCHECK(server_config_update.tag() == kSCUP); | |
192 string error_details; | |
193 QuicCryptoClientConfig::CachedState* cached = | |
194 crypto_config_->LookupOrCreate(server_id_); | |
195 QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate( | |
196 server_config_update, session()->connection()->clock()->WallNow(), | |
197 session()->connection()->version(), cached->chlo_hash(), cached, | |
198 &crypto_negotiated_params_, &error_details); | |
199 | |
200 if (error != QUIC_NO_ERROR) { | |
201 CloseConnectionWithDetails( | |
202 error, "Server config update invalid: " + error_details); | |
203 return; | |
204 } | |
205 | |
206 DCHECK(handshake_confirmed()); | |
207 if (proof_verify_callback_) { | |
208 proof_verify_callback_->Cancel(); | |
209 } | |
210 next_state_ = STATE_INITIALIZE_SCUP; | |
211 DoHandshakeLoop(nullptr); | |
212 } | |
213 | |
214 void QuicCryptoClientStream::DoHandshakeLoop(const CryptoHandshakeMessage* in) { | |
215 QuicCryptoClientConfig::CachedState* cached = | |
216 crypto_config_->LookupOrCreate(server_id_); | |
217 | |
218 QuicAsyncStatus rv = QUIC_SUCCESS; | |
219 do { | |
220 CHECK_NE(STATE_NONE, next_state_); | |
221 const State state = next_state_; | |
222 next_state_ = STATE_IDLE; | |
223 rv = QUIC_SUCCESS; | |
224 switch (state) { | |
225 case STATE_INITIALIZE: | |
226 DoInitialize(cached); | |
227 break; | |
228 case STATE_SEND_CHLO: | |
229 DoSendCHLO(cached); | |
230 return; // return waiting to hear from server. | |
231 case STATE_RECV_REJ: | |
232 DoReceiveREJ(in, cached); | |
233 break; | |
234 case STATE_VERIFY_PROOF: | |
235 rv = DoVerifyProof(cached); | |
236 break; | |
237 case STATE_VERIFY_PROOF_COMPLETE: | |
238 DoVerifyProofComplete(cached); | |
239 break; | |
240 case STATE_GET_CHANNEL_ID: | |
241 rv = DoGetChannelID(cached); | |
242 break; | |
243 case STATE_GET_CHANNEL_ID_COMPLETE: | |
244 DoGetChannelIDComplete(); | |
245 break; | |
246 case STATE_RECV_SHLO: | |
247 DoReceiveSHLO(in, cached); | |
248 break; | |
249 case STATE_IDLE: | |
250 // This means that the peer sent us a message that we weren't expecting. | |
251 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, | |
252 "Handshake in idle state"); | |
253 return; | |
254 case STATE_INITIALIZE_SCUP: | |
255 DoInitializeServerConfigUpdate(cached); | |
256 break; | |
257 case STATE_NONE: | |
258 NOTREACHED(); | |
259 return; // We are done. | |
260 } | |
261 } while (rv != QUIC_PENDING && next_state_ != STATE_NONE); | |
262 } | |
263 | |
264 void QuicCryptoClientStream::DoInitialize( | |
265 QuicCryptoClientConfig::CachedState* cached) { | |
266 if (!cached->IsEmpty() && !cached->signature().empty()) { | |
267 // Note that we verify the proof even if the cached proof is valid. | |
268 // This allows us to respond to CA trust changes or certificate | |
269 // expiration because it may have been a while since we last verified | |
270 // the proof. | |
271 DCHECK(crypto_config_->proof_verifier()); | |
272 // Track proof verification time when cached server config is used. | |
273 proof_verify_start_time_ = base::TimeTicks::Now(); | |
274 chlo_hash_ = cached->chlo_hash(); | |
275 // If the cached state needs to be verified, do it now. | |
276 next_state_ = STATE_VERIFY_PROOF; | |
277 } else { | |
278 next_state_ = STATE_GET_CHANNEL_ID; | |
279 } | |
280 } | |
281 | |
282 void QuicCryptoClientStream::DoSendCHLO( | |
283 QuicCryptoClientConfig::CachedState* cached) { | |
284 if (stateless_reject_received_) { | |
285 // If we've gotten to this point, we've sent at least one hello | |
286 // and received a stateless reject in response. We cannot | |
287 // continue to send hellos because the server has abandoned state | |
288 // for this connection. Abandon further handshakes. | |
289 next_state_ = STATE_NONE; | |
290 if (session()->connection()->connected()) { | |
291 session()->connection()->CloseConnection( | |
292 QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject received", | |
293 ConnectionCloseBehavior::SILENT_CLOSE); | |
294 } | |
295 return; | |
296 } | |
297 | |
298 // Send the client hello in plaintext. | |
299 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); | |
300 encryption_established_ = false; | |
301 if (num_client_hellos_ > kMaxClientHellos) { | |
302 CloseConnectionWithDetails( | |
303 QUIC_CRYPTO_TOO_MANY_REJECTS, | |
304 base::StringPrintf("More than %u rejects", kMaxClientHellos).c_str()); | |
305 return; | |
306 } | |
307 num_client_hellos_++; | |
308 | |
309 CryptoHandshakeMessage out; | |
310 DCHECK(session() != nullptr); | |
311 DCHECK(session()->config() != nullptr); | |
312 // Send all the options, regardless of whether we're sending an | |
313 // inchoate or subsequent hello. | |
314 session()->config()->ToHandshakeMessage(&out); | |
315 | |
316 // This call and function should be removed when | |
317 // FLAGS_quic_deprecate_kfixd is removed. | |
318 AppendFixed(&out); | |
319 | |
320 // Send a local timestamp to the server. | |
321 out.SetValue(kCTIM, | |
322 session()->connection()->clock()->WallNow().ToUNIXSeconds()); | |
323 | |
324 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { | |
325 crypto_config_->FillInchoateClientHello( | |
326 server_id_, session()->connection()->supported_versions().front(), | |
327 cached, session()->connection()->random_generator(), | |
328 /* demand_x509_proof= */ true, &crypto_negotiated_params_, &out); | |
329 // Pad the inchoate client hello to fill up a packet. | |
330 const QuicByteCount kFramingOverhead = 50; // A rough estimate. | |
331 const QuicByteCount max_packet_size = | |
332 session()->connection()->max_packet_length(); | |
333 if (max_packet_size <= kFramingOverhead) { | |
334 DLOG(DFATAL) << "max_packet_length (" << max_packet_size | |
335 << ") has no room for framing overhead."; | |
336 CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, | |
337 "max_packet_size too smalll"); | |
338 return; | |
339 } | |
340 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) { | |
341 DLOG(DFATAL) << "Client hello won't fit in a single packet."; | |
342 CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "CHLO too large"); | |
343 return; | |
344 } | |
345 out.set_minimum_size( | |
346 static_cast<size_t>(max_packet_size - kFramingOverhead)); | |
347 next_state_ = STATE_RECV_REJ; | |
348 CryptoUtils::HashHandshakeMessage(out, &chlo_hash_); | |
349 SendHandshakeMessage(out); | |
350 return; | |
351 } | |
352 | |
353 // If the server nonce is empty, copy over the server nonce from a previous | |
354 // SREJ, if there is one. | |
355 if (FLAGS_enable_quic_stateless_reject_support && | |
356 crypto_negotiated_params_.server_nonce.empty() && | |
357 cached->has_server_nonce()) { | |
358 crypto_negotiated_params_.server_nonce = cached->GetNextServerNonce(); | |
359 DCHECK(!crypto_negotiated_params_.server_nonce.empty()); | |
360 } | |
361 | |
362 string error_details; | |
363 QuicErrorCode error = crypto_config_->FillClientHello( | |
364 server_id_, session()->connection()->connection_id(), | |
365 session()->connection()->version(), | |
366 session()->connection()->supported_versions().front(), cached, | |
367 session()->connection()->clock()->WallNow(), | |
368 session()->connection()->random_generator(), channel_id_key_.get(), | |
369 &crypto_negotiated_params_, &out, &error_details); | |
370 if (error != QUIC_NO_ERROR) { | |
371 // Flush the cached config so that, if it's bad, the server has a | |
372 // chance to send us another in the future. | |
373 cached->InvalidateServerConfig(); | |
374 CloseConnectionWithDetails(error, error_details); | |
375 return; | |
376 } | |
377 CryptoUtils::HashHandshakeMessage(out, &chlo_hash_); | |
378 channel_id_sent_ = (channel_id_key_.get() != nullptr); | |
379 if (cached->proof_verify_details()) { | |
380 proof_handler_->OnProofVerifyDetailsAvailable( | |
381 *cached->proof_verify_details()); | |
382 } | |
383 next_state_ = STATE_RECV_SHLO; | |
384 SendHandshakeMessage(out); | |
385 // Be prepared to decrypt with the new server write key. | |
386 session()->connection()->SetAlternativeDecrypter( | |
387 ENCRYPTION_INITIAL, | |
388 crypto_negotiated_params_.initial_crypters.decrypter.release(), | |
389 true /* latch once used */); | |
390 // Send subsequent packets under encryption on the assumption that the | |
391 // server will accept the handshake. | |
392 session()->connection()->SetEncrypter( | |
393 ENCRYPTION_INITIAL, | |
394 crypto_negotiated_params_.initial_crypters.encrypter.release()); | |
395 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); | |
396 | |
397 // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and | |
398 // ENCRYPTION_FIRST_ESTABLSIHED | |
399 encryption_established_ = true; | |
400 session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED); | |
401 } | |
402 | |
403 void QuicCryptoClientStream::DoReceiveREJ( | |
404 const CryptoHandshakeMessage* in, | |
405 QuicCryptoClientConfig::CachedState* cached) { | |
406 // We sent a dummy CHLO because we didn't have enough information to | |
407 // perform a handshake, or we sent a full hello that the server | |
408 // rejected. Here we hope to have a REJ that contains the information | |
409 // that we need. | |
410 if ((in->tag() != kREJ) && (in->tag() != kSREJ)) { | |
411 next_state_ = STATE_NONE; | |
412 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, | |
413 "Expected REJ"); | |
414 return; | |
415 } | |
416 | |
417 const uint32_t* reject_reasons; | |
418 size_t num_reject_reasons; | |
419 static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync"); | |
420 if (in->GetTaglist(kRREJ, &reject_reasons, &num_reject_reasons) == | |
421 QUIC_NO_ERROR) { | |
422 uint32_t packed_error = 0; | |
423 for (size_t i = 0; i < num_reject_reasons; ++i) { | |
424 // HANDSHAKE_OK is 0 and don't report that as error. | |
425 if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) { | |
426 continue; | |
427 } | |
428 HandshakeFailureReason reason = | |
429 static_cast<HandshakeFailureReason>(reject_reasons[i]); | |
430 packed_error |= 1 << (reason - 1); | |
431 } | |
432 DVLOG(1) << "Reasons for rejection: " << packed_error; | |
433 if (num_client_hellos_ == kMaxClientHellos) { | |
434 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.TooMany", | |
435 packed_error); | |
436 } | |
437 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure", | |
438 packed_error); | |
439 } | |
440 | |
441 stateless_reject_received_ = in->tag() == kSREJ; | |
442 string error_details; | |
443 QuicErrorCode error = crypto_config_->ProcessRejection( | |
444 *in, session()->connection()->clock()->WallNow(), | |
445 session()->connection()->version(), chlo_hash_, cached, | |
446 &crypto_negotiated_params_, &error_details); | |
447 | |
448 if (error != QUIC_NO_ERROR) { | |
449 next_state_ = STATE_NONE; | |
450 CloseConnectionWithDetails(error, error_details); | |
451 return; | |
452 } | |
453 if (!cached->proof_valid()) { | |
454 if (!cached->signature().empty()) { | |
455 // Note that we only verify the proof if the cached proof is not | |
456 // valid. If the cached proof is valid here, someone else must have | |
457 // just added the server config to the cache and verified the proof, | |
458 // so we can assume no CA trust changes or certificate expiration | |
459 // has happened since then. | |
460 next_state_ = STATE_VERIFY_PROOF; | |
461 return; | |
462 } | |
463 } | |
464 next_state_ = STATE_GET_CHANNEL_ID; | |
465 } | |
466 | |
467 QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof( | |
468 QuicCryptoClientConfig::CachedState* cached) { | |
469 ProofVerifier* verifier = crypto_config_->proof_verifier(); | |
470 DCHECK(verifier); | |
471 next_state_ = STATE_VERIFY_PROOF_COMPLETE; | |
472 generation_counter_ = cached->generation_counter(); | |
473 | |
474 ProofVerifierCallbackImpl* proof_verify_callback = | |
475 new ProofVerifierCallbackImpl(this); | |
476 | |
477 verify_ok_ = false; | |
478 | |
479 QuicAsyncStatus status = verifier->VerifyProof( | |
480 server_id_.host(), server_id_.port(), cached->server_config(), | |
481 session()->connection()->version(), chlo_hash_, cached->certs(), | |
482 cached->cert_sct(), cached->signature(), verify_context_.get(), | |
483 &verify_error_details_, &verify_details_, | |
484 std::unique_ptr<ProofVerifierCallback>(proof_verify_callback)); | |
485 | |
486 switch (status) { | |
487 case QUIC_PENDING: | |
488 proof_verify_callback_ = proof_verify_callback; | |
489 DVLOG(1) << "Doing VerifyProof"; | |
490 break; | |
491 case QUIC_FAILURE: | |
492 break; | |
493 case QUIC_SUCCESS: | |
494 verify_ok_ = true; | |
495 break; | |
496 } | |
497 return status; | |
498 } | |
499 | |
500 void QuicCryptoClientStream::DoVerifyProofComplete( | |
501 QuicCryptoClientConfig::CachedState* cached) { | |
502 if (!proof_verify_start_time_.is_null()) { | |
503 UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.CachedServerConfig", | |
504 base::TimeTicks::Now() - proof_verify_start_time_); | |
505 } | |
506 if (!verify_ok_) { | |
507 if (verify_details_.get()) { | |
508 proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_); | |
509 } | |
510 if (num_client_hellos_ == 0) { | |
511 cached->Clear(); | |
512 next_state_ = STATE_INITIALIZE; | |
513 return; | |
514 } | |
515 next_state_ = STATE_NONE; | |
516 UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed", | |
517 handshake_confirmed()); | |
518 CloseConnectionWithDetails(QUIC_PROOF_INVALID, | |
519 "Proof invalid: " + verify_error_details_); | |
520 return; | |
521 } | |
522 | |
523 // Check if generation_counter has changed between STATE_VERIFY_PROOF and | |
524 // STATE_VERIFY_PROOF_COMPLETE state changes. | |
525 if (generation_counter_ != cached->generation_counter()) { | |
526 next_state_ = STATE_VERIFY_PROOF; | |
527 } else { | |
528 SetCachedProofValid(cached); | |
529 cached->SetProofVerifyDetails(verify_details_.release()); | |
530 if (!handshake_confirmed()) { | |
531 next_state_ = STATE_GET_CHANNEL_ID; | |
532 } else { | |
533 // TODO: Enable Expect-Staple. https://crbug.com/631101 | |
534 next_state_ = STATE_NONE; | |
535 } | |
536 } | |
537 } | |
538 | |
539 QuicAsyncStatus QuicCryptoClientStream::DoGetChannelID( | |
540 QuicCryptoClientConfig::CachedState* cached) { | |
541 next_state_ = STATE_GET_CHANNEL_ID_COMPLETE; | |
542 channel_id_key_.reset(); | |
543 if (!RequiresChannelID(cached)) { | |
544 next_state_ = STATE_SEND_CHLO; | |
545 return QUIC_SUCCESS; | |
546 } | |
547 | |
548 ChannelIDSourceCallbackImpl* channel_id_source_callback = | |
549 new ChannelIDSourceCallbackImpl(this); | |
550 QuicAsyncStatus status = crypto_config_->channel_id_source()->GetChannelIDKey( | |
551 server_id_.host(), &channel_id_key_, channel_id_source_callback); | |
552 | |
553 switch (status) { | |
554 case QUIC_PENDING: | |
555 channel_id_source_callback_ = channel_id_source_callback; | |
556 DVLOG(1) << "Looking up channel ID"; | |
557 break; | |
558 case QUIC_FAILURE: | |
559 next_state_ = STATE_NONE; | |
560 delete channel_id_source_callback; | |
561 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE, | |
562 "Channel ID lookup failed"); | |
563 break; | |
564 case QUIC_SUCCESS: | |
565 delete channel_id_source_callback; | |
566 break; | |
567 } | |
568 return status; | |
569 } | |
570 | |
571 void QuicCryptoClientStream::DoGetChannelIDComplete() { | |
572 if (!channel_id_key_.get()) { | |
573 next_state_ = STATE_NONE; | |
574 CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE, | |
575 "Channel ID lookup failed"); | |
576 return; | |
577 } | |
578 next_state_ = STATE_SEND_CHLO; | |
579 } | |
580 | |
581 void QuicCryptoClientStream::DoReceiveSHLO( | |
582 const CryptoHandshakeMessage* in, | |
583 QuicCryptoClientConfig::CachedState* cached) { | |
584 next_state_ = STATE_NONE; | |
585 // We sent a CHLO that we expected to be accepted and now we're | |
586 // hoping for a SHLO from the server to confirm that. First check | |
587 // to see whether the response was a reject, and if so, move on to | |
588 // the reject-processing state. | |
589 if ((in->tag() == kREJ) || (in->tag() == kSREJ)) { | |
590 // alternative_decrypter will be nullptr if the original alternative | |
591 // decrypter latched and became the primary decrypter. That happens | |
592 // if we received a message encrypted with the INITIAL key. | |
593 if (session()->connection()->alternative_decrypter() == nullptr) { | |
594 // The rejection was sent encrypted! | |
595 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, | |
596 "encrypted REJ message"); | |
597 return; | |
598 } | |
599 next_state_ = STATE_RECV_REJ; | |
600 return; | |
601 } | |
602 | |
603 if (in->tag() != kSHLO) { | |
604 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, | |
605 "Expected SHLO or REJ"); | |
606 return; | |
607 } | |
608 | |
609 // alternative_decrypter will be nullptr if the original alternative | |
610 // decrypter latched and became the primary decrypter. That happens | |
611 // if we received a message encrypted with the INITIAL key. | |
612 if (session()->connection()->alternative_decrypter() != nullptr) { | |
613 // The server hello was sent without encryption. | |
614 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, | |
615 "unencrypted SHLO message"); | |
616 return; | |
617 } | |
618 | |
619 string error_details; | |
620 QuicErrorCode error = crypto_config_->ProcessServerHello( | |
621 *in, session()->connection()->connection_id(), | |
622 session()->connection()->version(), | |
623 session()->connection()->server_supported_versions(), cached, | |
624 &crypto_negotiated_params_, &error_details); | |
625 | |
626 if (error != QUIC_NO_ERROR) { | |
627 CloseConnectionWithDetails(error, "Server hello invalid: " + error_details); | |
628 return; | |
629 } | |
630 error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details); | |
631 if (error != QUIC_NO_ERROR) { | |
632 CloseConnectionWithDetails(error, "Server hello invalid: " + error_details); | |
633 return; | |
634 } | |
635 session()->OnConfigNegotiated(); | |
636 | |
637 CrypterPair* crypters = &crypto_negotiated_params_.forward_secure_crypters; | |
638 // TODO(agl): we don't currently latch this decrypter because the idea | |
639 // has been floated that the server shouldn't send packets encrypted | |
640 // with the FORWARD_SECURE key until it receives a FORWARD_SECURE | |
641 // packet from the client. | |
642 session()->connection()->SetAlternativeDecrypter( | |
643 ENCRYPTION_FORWARD_SECURE, crypters->decrypter.release(), | |
644 false /* don't latch */); | |
645 session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE, | |
646 crypters->encrypter.release()); | |
647 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); | |
648 | |
649 handshake_confirmed_ = true; | |
650 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); | |
651 session()->connection()->OnHandshakeComplete(); | |
652 } | |
653 | |
654 void QuicCryptoClientStream::DoInitializeServerConfigUpdate( | |
655 QuicCryptoClientConfig::CachedState* cached) { | |
656 bool update_ignored = false; | |
657 if (!cached->IsEmpty() && !cached->signature().empty()) { | |
658 // Note that we verify the proof even if the cached proof is valid. | |
659 DCHECK(crypto_config_->proof_verifier()); | |
660 next_state_ = STATE_VERIFY_PROOF; | |
661 } else { | |
662 update_ignored = true; | |
663 next_state_ = STATE_NONE; | |
664 } | |
665 UMA_HISTOGRAM_COUNTS("Net.QuicNumServerConfig.UpdateMessagesIgnored", | |
666 update_ignored); | |
667 } | |
668 | |
669 void QuicCryptoClientStream::SetCachedProofValid( | |
670 QuicCryptoClientConfig::CachedState* cached) { | |
671 cached->SetProofValid(); | |
672 proof_handler_->OnProofValid(*cached); | |
673 } | |
674 | |
675 bool QuicCryptoClientStream::RequiresChannelID( | |
676 QuicCryptoClientConfig::CachedState* cached) { | |
677 if (server_id_.privacy_mode() == PRIVACY_MODE_ENABLED || | |
678 !crypto_config_->channel_id_source()) { | |
679 return false; | |
680 } | |
681 const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); | |
682 if (!scfg) { // scfg may be null then we send an inchoate CHLO. | |
683 return false; | |
684 } | |
685 const QuicTag* their_proof_demands; | |
686 size_t num_their_proof_demands; | |
687 if (scfg->GetTaglist(kPDMD, &their_proof_demands, &num_their_proof_demands) != | |
688 QUIC_NO_ERROR) { | |
689 return false; | |
690 } | |
691 for (size_t i = 0; i < num_their_proof_demands; i++) { | |
692 if (their_proof_demands[i] == kCHID) { | |
693 return true; | |
694 } | |
695 } | |
696 return false; | |
697 } | |
698 | |
699 } // namespace net | |
OLD | NEW |