| 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/core/quic_crypto_server_stream.h" | 5 #include "net/quic/core/quic_crypto_server_stream.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "crypto/secure_hash.h" | 10 #include "crypto/secure_hash.h" |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 const CryptoHandshakeMessage& message = result->client_hello; | 129 const CryptoHandshakeMessage& message = result->client_hello; |
| 130 | 130 |
| 131 // Clear the callback that got us here. | 131 // Clear the callback that got us here. |
| 132 DCHECK(validate_client_hello_cb_ != nullptr); | 132 DCHECK(validate_client_hello_cb_ != nullptr); |
| 133 validate_client_hello_cb_ = nullptr; | 133 validate_client_hello_cb_ = nullptr; |
| 134 | 134 |
| 135 if (use_stateless_rejects_if_peer_supported_) { | 135 if (use_stateless_rejects_if_peer_supported_) { |
| 136 peer_supports_stateless_rejects_ = DoesPeerSupportStatelessRejects(message); | 136 peer_supports_stateless_rejects_ = DoesPeerSupportStatelessRejects(message); |
| 137 } | 137 } |
| 138 | 138 |
| 139 CryptoHandshakeMessage reply; | |
| 140 DiversificationNonce diversification_nonce; | |
| 141 string error_details; | 139 string error_details; |
| 140 std::unique_ptr<CryptoHandshakeMessage> reply(new CryptoHandshakeMessage); |
| 141 std::unique_ptr<DiversificationNonce> diversification_nonce( |
| 142 new DiversificationNonce); |
| 142 QuicErrorCode error = | 143 QuicErrorCode error = |
| 143 ProcessClientHello(result, std::move(details), &reply, | 144 ProcessClientHello(result, std::move(details), reply.get(), |
| 144 &diversification_nonce, &error_details); | 145 diversification_nonce.get(), &error_details); |
| 145 | 146 |
| 147 // Note: this split exists to facilitate a future conversion of |
| 148 // ProcessClientHello to an async signature. |
| 149 FinishProcessingHandshakeMessageAfterProcessClientHello( |
| 150 *result, error, error_details, std::move(reply), |
| 151 std::move(diversification_nonce)); |
| 152 } |
| 153 |
| 154 void QuicCryptoServerStream:: |
| 155 FinishProcessingHandshakeMessageAfterProcessClientHello( |
| 156 const ValidateClientHelloResultCallback::Result& result, |
| 157 QuicErrorCode error, |
| 158 const string& error_details, |
| 159 std::unique_ptr<CryptoHandshakeMessage> reply, |
| 160 std::unique_ptr<DiversificationNonce> diversification_nonce) { |
| 161 const CryptoHandshakeMessage& message = result.client_hello; |
| 146 if (error != QUIC_NO_ERROR) { | 162 if (error != QUIC_NO_ERROR) { |
| 147 CloseConnectionWithDetails(error, error_details); | 163 CloseConnectionWithDetails(error, error_details); |
| 148 return; | 164 return; |
| 149 } | 165 } |
| 150 | 166 |
| 151 if (reply.tag() != kSHLO) { | 167 if (reply->tag() != kSHLO) { |
| 152 if (reply.tag() == kSREJ) { | 168 if (reply->tag() == kSREJ) { |
| 153 DCHECK(use_stateless_rejects_if_peer_supported_); | 169 DCHECK(use_stateless_rejects_if_peer_supported_); |
| 154 DCHECK(peer_supports_stateless_rejects_); | 170 DCHECK(peer_supports_stateless_rejects_); |
| 155 // Before sending the SREJ, cause the connection to save crypto packets | 171 // Before sending the SREJ, cause the connection to save crypto packets |
| 156 // so that they can be added to the time wait list manager and | 172 // so that they can be added to the time wait list manager and |
| 157 // retransmitted. | 173 // retransmitted. |
| 158 session()->connection()->EnableSavingCryptoPackets(); | 174 session()->connection()->EnableSavingCryptoPackets(); |
| 159 } | 175 } |
| 160 SendHandshakeMessage(reply); | 176 SendHandshakeMessage(*reply); |
| 161 | 177 |
| 162 if (reply.tag() == kSREJ) { | 178 if (reply->tag() == kSREJ) { |
| 163 DCHECK(use_stateless_rejects_if_peer_supported_); | 179 DCHECK(use_stateless_rejects_if_peer_supported_); |
| 164 DCHECK(peer_supports_stateless_rejects_); | 180 DCHECK(peer_supports_stateless_rejects_); |
| 165 DCHECK(!handshake_confirmed()); | 181 DCHECK(!handshake_confirmed()); |
| 166 DVLOG(1) << "Closing connection " | 182 DVLOG(1) << "Closing connection " |
| 167 << session()->connection()->connection_id() | 183 << session()->connection()->connection_id() |
| 168 << " because of a stateless reject."; | 184 << " because of a stateless reject."; |
| 169 session()->connection()->CloseConnection( | 185 session()->connection()->CloseConnection( |
| 170 QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject", | 186 QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject", |
| 171 ConnectionCloseBehavior::SILENT_CLOSE); | 187 ConnectionCloseBehavior::SILENT_CLOSE); |
| 172 } | 188 } |
| 173 return; | 189 return; |
| 174 } | 190 } |
| 175 | 191 |
| 176 // If we are returning a SHLO then we accepted the handshake. Now | 192 // If we are returning a SHLO then we accepted the handshake. Now |
| 177 // process the negotiated configuration options as part of the | 193 // process the negotiated configuration options as part of the |
| 178 // session config. | 194 // session config. |
| 179 QuicConfig* config = session()->config(); | 195 QuicConfig* config = session()->config(); |
| 180 OverrideQuicConfigDefaults(config); | 196 OverrideQuicConfigDefaults(config); |
| 181 error = config->ProcessPeerHello(message, CLIENT, &error_details); | 197 string process_error_details; |
| 182 if (error != QUIC_NO_ERROR) { | 198 const QuicErrorCode process_error = |
| 183 CloseConnectionWithDetails(error, error_details); | 199 config->ProcessPeerHello(message, CLIENT, &process_error_details); |
| 200 if (process_error != QUIC_NO_ERROR) { |
| 201 CloseConnectionWithDetails(process_error, process_error_details); |
| 184 return; | 202 return; |
| 185 } | 203 } |
| 186 | 204 |
| 187 session()->OnConfigNegotiated(); | 205 session()->OnConfigNegotiated(); |
| 188 | 206 |
| 189 config->ToHandshakeMessage(&reply); | 207 config->ToHandshakeMessage(reply.get()); |
| 190 | 208 |
| 191 // Receiving a full CHLO implies the client is prepared to decrypt with | 209 // Receiving a full CHLO implies the client is prepared to decrypt with |
| 192 // the new server write key. We can start to encrypt with the new server | 210 // the new server write key. We can start to encrypt with the new server |
| 193 // write key. | 211 // write key. |
| 194 // | 212 // |
| 195 // NOTE: the SHLO will be encrypted with the new server write key. | 213 // NOTE: the SHLO will be encrypted with the new server write key. |
| 196 session()->connection()->SetEncrypter( | 214 session()->connection()->SetEncrypter( |
| 197 ENCRYPTION_INITIAL, | 215 ENCRYPTION_INITIAL, |
| 198 crypto_negotiated_params_.initial_crypters.encrypter.release()); | 216 crypto_negotiated_params_.initial_crypters.encrypter.release()); |
| 199 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); | 217 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); |
| 200 // Set the decrypter immediately so that we no longer accept unencrypted | 218 // Set the decrypter immediately so that we no longer accept unencrypted |
| 201 // packets. | 219 // packets. |
| 202 session()->connection()->SetDecrypter( | 220 session()->connection()->SetDecrypter( |
| 203 ENCRYPTION_INITIAL, | 221 ENCRYPTION_INITIAL, |
| 204 crypto_negotiated_params_.initial_crypters.decrypter.release()); | 222 crypto_negotiated_params_.initial_crypters.decrypter.release()); |
| 205 if (version() > QUIC_VERSION_32) { | 223 if (version() > QUIC_VERSION_32) { |
| 206 session()->connection()->SetDiversificationNonce(diversification_nonce); | 224 session()->connection()->SetDiversificationNonce(*diversification_nonce); |
| 207 } | 225 } |
| 208 | 226 |
| 209 SendHandshakeMessage(reply); | 227 SendHandshakeMessage(*reply); |
| 210 | 228 |
| 211 session()->connection()->SetEncrypter( | 229 session()->connection()->SetEncrypter( |
| 212 ENCRYPTION_FORWARD_SECURE, | 230 ENCRYPTION_FORWARD_SECURE, |
| 213 crypto_negotiated_params_.forward_secure_crypters.encrypter.release()); | 231 crypto_negotiated_params_.forward_secure_crypters.encrypter.release()); |
| 214 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); | 232 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); |
| 215 | 233 |
| 216 session()->connection()->SetAlternativeDecrypter( | 234 session()->connection()->SetAlternativeDecrypter( |
| 217 ENCRYPTION_FORWARD_SECURE, | 235 ENCRYPTION_FORWARD_SECURE, |
| 218 crypto_negotiated_params_.forward_secure_crypters.decrypter.release(), | 236 crypto_negotiated_params_.forward_secure_crypters.decrypter.release(), |
| 219 false /* don't latch */); | 237 false /* don't latch */); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 len--; | 390 len--; |
| 373 if ((*output)[len - 1] == '=') { | 391 if ((*output)[len - 1] == '=') { |
| 374 len--; | 392 len--; |
| 375 } | 393 } |
| 376 output->resize(len); | 394 output->resize(len); |
| 377 } | 395 } |
| 378 } | 396 } |
| 379 return true; | 397 return true; |
| 380 } | 398 } |
| 381 | 399 |
| 400 class QuicCryptoServerStream::ProcessClientHelloCallback |
| 401 : public ProcessClientHelloResultCallback { |
| 402 public: |
| 403 ProcessClientHelloCallback(QuicErrorCode* error, |
| 404 string* error_details, |
| 405 CryptoHandshakeMessage* message, |
| 406 DiversificationNonce* diversification_nonce) |
| 407 : error_(error), |
| 408 error_details_(error_details), |
| 409 message_(message), |
| 410 diversification_nonce_(diversification_nonce) {} |
| 411 |
| 412 void Run( |
| 413 QuicErrorCode error, |
| 414 const string& error_details, |
| 415 std::unique_ptr<CryptoHandshakeMessage> message, |
| 416 std::unique_ptr<DiversificationNonce> diversification_nonce) override { |
| 417 *error_ = error; |
| 418 *error_details_ = error_details; |
| 419 if (message != nullptr) { |
| 420 *message_ = *message; |
| 421 } |
| 422 if (diversification_nonce != nullptr) { |
| 423 *diversification_nonce_ = *diversification_nonce; |
| 424 } |
| 425 // NOTE: copies the message, nonce, and error details. This is a temporary |
| 426 // condition until this codepath is fully asynchronized. |
| 427 // TODO(gredner): Fix this. |
| 428 } |
| 429 |
| 430 private: |
| 431 QuicErrorCode* error_; |
| 432 string* error_details_; |
| 433 CryptoHandshakeMessage* message_; |
| 434 DiversificationNonce* diversification_nonce_; |
| 435 }; |
| 436 |
| 382 QuicErrorCode QuicCryptoServerStream::ProcessClientHello( | 437 QuicErrorCode QuicCryptoServerStream::ProcessClientHello( |
| 383 scoped_refptr<ValidateClientHelloResultCallback::Result> result, | 438 scoped_refptr<ValidateClientHelloResultCallback::Result> result, |
| 384 std::unique_ptr<ProofSource::Details> proof_source_details, | 439 std::unique_ptr<ProofSource::Details> proof_source_details, |
| 385 CryptoHandshakeMessage* reply, | 440 CryptoHandshakeMessage* reply, |
| 386 DiversificationNonce* out_diversification_nonce, | 441 DiversificationNonce* out_diversification_nonce, |
| 387 string* error_details) { | 442 string* error_details) { |
| 388 const CryptoHandshakeMessage& message = result->client_hello; | 443 const CryptoHandshakeMessage& message = result->client_hello; |
| 389 if (!helper_->CanAcceptClientHello( | 444 if (!helper_->CanAcceptClientHello( |
| 390 message, session()->connection()->self_address(), error_details)) { | 445 message, session()->connection()->self_address(), error_details)) { |
| 391 return QUIC_HANDSHAKE_FAILED; | 446 return QUIC_HANDSHAKE_FAILED; |
| 392 } | 447 } |
| 393 | 448 |
| 394 if (!result->info.server_nonce.empty()) { | 449 if (!result->info.server_nonce.empty()) { |
| 395 ++num_handshake_messages_with_server_nonces_; | 450 ++num_handshake_messages_with_server_nonces_; |
| 396 } | 451 } |
| 397 // Store the bandwidth estimate from the client. | 452 // Store the bandwidth estimate from the client. |
| 398 if (result->cached_network_params.bandwidth_estimate_bytes_per_second() > 0) { | 453 if (result->cached_network_params.bandwidth_estimate_bytes_per_second() > 0) { |
| 399 previous_cached_network_params_.reset( | 454 previous_cached_network_params_.reset( |
| 400 new CachedNetworkParameters(result->cached_network_params)); | 455 new CachedNetworkParameters(result->cached_network_params)); |
| 401 } | 456 } |
| 402 previous_source_address_tokens_ = result->info.source_address_tokens; | 457 previous_source_address_tokens_ = result->info.source_address_tokens; |
| 403 | 458 |
| 404 const bool use_stateless_rejects_in_crypto_config = | 459 const bool use_stateless_rejects_in_crypto_config = |
| 405 use_stateless_rejects_if_peer_supported_ && | 460 use_stateless_rejects_if_peer_supported_ && |
| 406 peer_supports_stateless_rejects_; | 461 peer_supports_stateless_rejects_; |
| 407 QuicConnection* connection = session()->connection(); | 462 QuicConnection* connection = session()->connection(); |
| 408 const QuicConnectionId server_designated_connection_id = | 463 const QuicConnectionId server_designated_connection_id = |
| 409 GenerateConnectionIdForReject(use_stateless_rejects_in_crypto_config); | 464 GenerateConnectionIdForReject(use_stateless_rejects_in_crypto_config); |
| 410 return crypto_config_->ProcessClientHello( | 465 |
| 466 QuicErrorCode error = QUIC_NO_ERROR; |
| 467 std::unique_ptr<ProcessClientHelloCallback> cb(new ProcessClientHelloCallback( |
| 468 &error, error_details, reply, out_diversification_nonce)); |
| 469 crypto_config_->ProcessClientHello( |
| 411 result, /*reject_only=*/false, connection->connection_id(), | 470 result, /*reject_only=*/false, connection->connection_id(), |
| 412 connection->self_address().address(), connection->peer_address(), | 471 connection->self_address().address(), connection->peer_address(), |
| 413 version(), connection->supported_versions(), | 472 version(), connection->supported_versions(), |
| 414 use_stateless_rejects_in_crypto_config, server_designated_connection_id, | 473 use_stateless_rejects_in_crypto_config, server_designated_connection_id, |
| 415 connection->clock(), connection->random_generator(), | 474 connection->clock(), connection->random_generator(), |
| 416 compressed_certs_cache_, &crypto_negotiated_params_, &crypto_proof_, | 475 compressed_certs_cache_, &crypto_negotiated_params_, &crypto_proof_, |
| 417 QuicCryptoStream::CryptoMessageFramingOverhead(version()), | 476 QuicCryptoStream::CryptoMessageFramingOverhead(version()), |
| 418 chlo_packet_size_, reply, out_diversification_nonce, error_details); | 477 chlo_packet_size_, std::move(cb)); |
| 478 // NOTE: assumes that ProcessClientHello invokes the callback synchronously. |
| 479 // This is a temporary condition until these codepaths are fully |
| 480 // asynchronized. |
| 481 // TODO(gredner): fix this. |
| 482 |
| 483 return error; |
| 419 } | 484 } |
| 420 | 485 |
| 421 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {} | 486 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {} |
| 422 | 487 |
| 423 QuicCryptoServerStream::ValidateCallback::ValidateCallback( | 488 QuicCryptoServerStream::ValidateCallback::ValidateCallback( |
| 424 QuicCryptoServerStream* parent) | 489 QuicCryptoServerStream* parent) |
| 425 : parent_(parent) {} | 490 : parent_(parent) {} |
| 426 | 491 |
| 427 void QuicCryptoServerStream::ValidateCallback::Cancel() { | 492 void QuicCryptoServerStream::ValidateCallback::Cancel() { |
| 428 parent_ = nullptr; | 493 parent_ = nullptr; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 440 QuicConnectionId QuicCryptoServerStream::GenerateConnectionIdForReject( | 505 QuicConnectionId QuicCryptoServerStream::GenerateConnectionIdForReject( |
| 441 bool use_stateless_rejects) { | 506 bool use_stateless_rejects) { |
| 442 if (!use_stateless_rejects) { | 507 if (!use_stateless_rejects) { |
| 443 return 0; | 508 return 0; |
| 444 } | 509 } |
| 445 return helper_->GenerateConnectionIdForReject( | 510 return helper_->GenerateConnectionIdForReject( |
| 446 session()->connection()->connection_id()); | 511 session()->connection()->connection_id()); |
| 447 } | 512 } |
| 448 | 513 |
| 449 } // namespace net | 514 } // namespace net |
| OLD | NEW |