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