| 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 |