OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/quic/quic_crypto_client_stream.h" | 5 #include "net/quic/quic_crypto_client_stream.h" |
6 | 6 |
7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
8 #include "base/profiler/scoped_tracker.h" | 8 #include "base/profiler/scoped_tracker.h" |
9 #include "net/quic/crypto/crypto_protocol.h" | 9 #include "net/quic/crypto/crypto_protocol.h" |
10 #include "net/quic/crypto/crypto_utils.h" | 10 #include "net/quic/crypto/crypto_utils.h" |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 : QuicCryptoStream(session), | 80 : QuicCryptoStream(session), |
81 next_state_(STATE_IDLE), | 81 next_state_(STATE_IDLE), |
82 num_client_hellos_(0), | 82 num_client_hellos_(0), |
83 crypto_config_(crypto_config), | 83 crypto_config_(crypto_config), |
84 server_id_(server_id), | 84 server_id_(server_id), |
85 generation_counter_(0), | 85 generation_counter_(0), |
86 channel_id_sent_(false), | 86 channel_id_sent_(false), |
87 channel_id_source_callback_run_(false), | 87 channel_id_source_callback_run_(false), |
88 channel_id_source_callback_(nullptr), | 88 channel_id_source_callback_(nullptr), |
89 verify_context_(verify_context), | 89 verify_context_(verify_context), |
90 proof_verify_callback_(nullptr) { | 90 proof_verify_callback_(nullptr), |
| 91 stateless_reject_received_(false) { |
91 DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective()); | 92 DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective()); |
92 } | 93 } |
93 | 94 |
94 QuicCryptoClientStream::~QuicCryptoClientStream() { | 95 QuicCryptoClientStream::~QuicCryptoClientStream() { |
95 if (channel_id_source_callback_) { | 96 if (channel_id_source_callback_) { |
96 channel_id_source_callback_->Cancel(); | 97 channel_id_source_callback_->Cancel(); |
97 } | 98 } |
98 if (proof_verify_callback_) { | 99 if (proof_verify_callback_) { |
99 proof_verify_callback_->Cancel(); | 100 proof_verify_callback_->Cancel(); |
100 } | 101 } |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 // If the cached state needs to be verified, do it now. | 240 // If the cached state needs to be verified, do it now. |
240 next_state_ = STATE_VERIFY_PROOF; | 241 next_state_ = STATE_VERIFY_PROOF; |
241 } else { | 242 } else { |
242 next_state_ = STATE_GET_CHANNEL_ID; | 243 next_state_ = STATE_GET_CHANNEL_ID; |
243 } | 244 } |
244 } | 245 } |
245 | 246 |
246 void QuicCryptoClientStream::DoSendCHLO( | 247 void QuicCryptoClientStream::DoSendCHLO( |
247 const CryptoHandshakeMessage* in, | 248 const CryptoHandshakeMessage* in, |
248 QuicCryptoClientConfig::CachedState* cached) { | 249 QuicCryptoClientConfig::CachedState* cached) { |
| 250 if (stateless_reject_received_) { |
| 251 // If we've gotten to this point, we've sent at least one hello |
| 252 // and received a stateless reject in response. We cannot |
| 253 // continue to send hellos because the server has abandoned state |
| 254 // for this connection. Abandon further handshakes. |
| 255 next_state_ = STATE_NONE; |
| 256 if (session()->connection()->connected()) { |
| 257 session()->connection()->CloseConnection( |
| 258 QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, false); |
| 259 } |
| 260 return; |
| 261 } |
| 262 |
249 // Send the client hello in plaintext. | 263 // Send the client hello in plaintext. |
250 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); | 264 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); |
251 if (num_client_hellos_ > kMaxClientHellos) { | 265 if (num_client_hellos_ > kMaxClientHellos) { |
252 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); | 266 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); |
253 return; | 267 return; |
254 } | 268 } |
255 num_client_hellos_++; | 269 num_client_hellos_++; |
256 | 270 |
257 CryptoHandshakeMessage out; | 271 CryptoHandshakeMessage out; |
| 272 DCHECK(session() != nullptr); |
| 273 DCHECK(session()->config() != nullptr); |
| 274 // Send all the options, regardless of whether we're sending an |
| 275 // inchoate or subsequent hello. |
| 276 session()->config()->ToHandshakeMessage(&out); |
258 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { | 277 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { |
259 crypto_config_->FillInchoateClientHello( | 278 crypto_config_->FillInchoateClientHello( |
260 server_id_, | 279 server_id_, |
261 session()->connection()->supported_versions().front(), | 280 session()->connection()->supported_versions().front(), |
262 cached, &crypto_negotiated_params_, &out); | 281 cached, &crypto_negotiated_params_, &out); |
263 // Pad the inchoate client hello to fill up a packet. | 282 // Pad the inchoate client hello to fill up a packet. |
264 const QuicByteCount kFramingOverhead = 50; // A rough estimate. | 283 const QuicByteCount kFramingOverhead = 50; // A rough estimate. |
265 const QuicByteCount max_packet_size = | 284 const QuicByteCount max_packet_size = |
266 session()->connection()->max_packet_length(); | 285 session()->connection()->max_packet_length(); |
267 if (max_packet_size <= kFramingOverhead) { | 286 if (max_packet_size <= kFramingOverhead) { |
268 DLOG(DFATAL) << "max_packet_length (" << max_packet_size | 287 DLOG(DFATAL) << "max_packet_length (" << max_packet_size |
269 << ") has no room for framing overhead."; | 288 << ") has no room for framing overhead."; |
270 CloseConnection(QUIC_INTERNAL_ERROR); | 289 CloseConnection(QUIC_INTERNAL_ERROR); |
271 return; | 290 return; |
272 } | 291 } |
273 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) { | 292 if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) { |
274 DLOG(DFATAL) << "Client hello won't fit in a single packet."; | 293 DLOG(DFATAL) << "Client hello won't fit in a single packet."; |
275 CloseConnection(QUIC_INTERNAL_ERROR); | 294 CloseConnection(QUIC_INTERNAL_ERROR); |
276 return; | 295 return; |
277 } | 296 } |
278 out.set_minimum_size( | 297 out.set_minimum_size( |
279 static_cast<size_t>(max_packet_size - kFramingOverhead)); | 298 static_cast<size_t>(max_packet_size - kFramingOverhead)); |
280 next_state_ = STATE_RECV_REJ; | 299 next_state_ = STATE_RECV_REJ; |
281 SendHandshakeMessage(out); | 300 SendHandshakeMessage(out); |
282 return; | 301 return; |
283 } | 302 } |
284 | 303 |
285 session()->config()->ToHandshakeMessage(&out); | |
286 string error_details; | 304 string error_details; |
287 QuicErrorCode error = crypto_config_->FillClientHello( | 305 QuicErrorCode error = crypto_config_->FillClientHello( |
288 server_id_, | 306 server_id_, |
289 session()->connection()->connection_id(), | 307 session()->connection()->connection_id(), |
290 session()->connection()->supported_versions().front(), | 308 session()->connection()->supported_versions().front(), |
291 cached, | 309 cached, |
292 session()->connection()->clock()->WallNow(), | 310 session()->connection()->clock()->WallNow(), |
293 session()->connection()->random_generator(), | 311 session()->connection()->random_generator(), |
294 channel_id_key_.get(), | 312 channel_id_key_.get(), |
295 &crypto_negotiated_params_, | 313 &crypto_negotiated_params_, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 QuicCryptoClientConfig::CachedState* cached) { | 355 QuicCryptoClientConfig::CachedState* cached) { |
338 // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed. | 356 // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed. |
339 tracked_objects::ScopedTracker tracking_profile( | 357 tracked_objects::ScopedTracker tracking_profile( |
340 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 358 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
341 "422516 QuicCryptoClientStream::DoReceiveREJ")); | 359 "422516 QuicCryptoClientStream::DoReceiveREJ")); |
342 | 360 |
343 // We sent a dummy CHLO because we didn't have enough information to | 361 // We sent a dummy CHLO because we didn't have enough information to |
344 // perform a handshake, or we sent a full hello that the server | 362 // perform a handshake, or we sent a full hello that the server |
345 // rejected. Here we hope to have a REJ that contains the information | 363 // rejected. Here we hope to have a REJ that contains the information |
346 // that we need. | 364 // that we need. |
347 if (in->tag() != kREJ) { | 365 if ((in->tag() != kREJ) && (in->tag() != kSREJ)) { |
348 next_state_ = STATE_NONE; | 366 next_state_ = STATE_NONE; |
349 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, | 367 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
350 "Expected REJ"); | 368 "Expected REJ"); |
351 return; | 369 return; |
352 } | 370 } |
| 371 stateless_reject_received_ = in->tag() == kSREJ; |
353 string error_details; | 372 string error_details; |
354 QuicErrorCode error = crypto_config_->ProcessRejection( | 373 QuicErrorCode error = crypto_config_->ProcessRejection( |
355 *in, session()->connection()->clock()->WallNow(), cached, | 374 *in, session()->connection()->clock()->WallNow(), cached, |
356 server_id_.is_https(), &crypto_negotiated_params_, &error_details); | 375 server_id_.is_https(), &crypto_negotiated_params_, &error_details); |
| 376 |
357 if (error != QUIC_NO_ERROR) { | 377 if (error != QUIC_NO_ERROR) { |
358 next_state_ = STATE_NONE; | 378 next_state_ = STATE_NONE; |
359 CloseConnectionWithDetails(error, error_details); | 379 CloseConnectionWithDetails(error, error_details); |
360 return; | 380 return; |
361 } | 381 } |
362 if (!cached->proof_valid()) { | 382 if (!cached->proof_valid()) { |
363 if (!server_id_.is_https()) { | 383 if (!server_id_.is_https()) { |
364 // We don't check the certificates for insecure QUIC connections. | 384 // We don't check the certificates for insecure QUIC connections. |
365 SetCachedProofValid(cached); | 385 SetCachedProofValid(cached); |
366 } else if (!cached->signature().empty()) { | 386 } else if (!cached->signature().empty()) { |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 "Channel ID lookup failed"); | 504 "Channel ID lookup failed"); |
485 return; | 505 return; |
486 } | 506 } |
487 next_state_ = STATE_SEND_CHLO; | 507 next_state_ = STATE_SEND_CHLO; |
488 } | 508 } |
489 | 509 |
490 void QuicCryptoClientStream::DoReceiveSHLO( | 510 void QuicCryptoClientStream::DoReceiveSHLO( |
491 const CryptoHandshakeMessage* in, | 511 const CryptoHandshakeMessage* in, |
492 QuicCryptoClientConfig::CachedState* cached) { | 512 QuicCryptoClientConfig::CachedState* cached) { |
493 next_state_ = STATE_NONE; | 513 next_state_ = STATE_NONE; |
494 // We sent a CHLO that we expected to be accepted and now we're hoping | 514 // We sent a CHLO that we expected to be accepted and now we're |
495 // for a SHLO from the server to confirm that. | 515 // hoping for a SHLO from the server to confirm that. First check |
496 if (in->tag() == kREJ) { | 516 // to see whether the response was a reject, and if so, move on to |
| 517 // the reject-processing state. |
| 518 if ((in->tag() == kREJ) || (in->tag() == kSREJ)) { |
497 // alternative_decrypter will be nullptr if the original alternative | 519 // alternative_decrypter will be nullptr if the original alternative |
498 // decrypter latched and became the primary decrypter. That happens | 520 // decrypter latched and became the primary decrypter. That happens |
499 // if we received a message encrypted with the INITIAL key. | 521 // if we received a message encrypted with the INITIAL key. |
500 if (session()->connection()->alternative_decrypter() == nullptr) { | 522 if (session()->connection()->alternative_decrypter() == nullptr) { |
501 // The rejection was sent encrypted! | 523 // The rejection was sent encrypted! |
502 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, | 524 CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT, |
503 "encrypted REJ message"); | 525 "encrypted REJ message"); |
504 return; | 526 return; |
505 } | 527 } |
506 next_state_ = STATE_RECV_REJ; | 528 next_state_ = STATE_RECV_REJ; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 } | 628 } |
607 } | 629 } |
608 return false; | 630 return false; |
609 } | 631 } |
610 | 632 |
611 QuicClientSessionBase* QuicCryptoClientStream::client_session() { | 633 QuicClientSessionBase* QuicCryptoClientStream::client_session() { |
612 return reinterpret_cast<QuicClientSessionBase*>(session()); | 634 return reinterpret_cast<QuicClientSessionBase*>(session()); |
613 } | 635 } |
614 | 636 |
615 } // namespace net | 637 } // namespace net |
OLD | NEW |