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 |