Chromium Code Reviews| 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 "net/base/completion_callback.h" | 7 #include "net/base/completion_callback.h" |
| 8 #include "net/base/net_errors.h" | 8 #include "net/base/net_errors.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" |
| 11 #include "net/quic/crypto/null_encrypter.h" | 11 #include "net/quic/crypto/null_encrypter.h" |
| 12 #include "net/quic/crypto/proof_verifier.h" | 12 #include "net/quic/crypto/proof_verifier.h" |
| 13 #include "net/quic/crypto/proof_verifier_chromium.h" | |
| 13 #include "net/quic/quic_protocol.h" | 14 #include "net/quic/quic_protocol.h" |
| 14 #include "net/quic/quic_session.h" | 15 #include "net/quic/quic_session.h" |
| 15 #include "net/ssl/ssl_connection_status_flags.h" | 16 #include "net/ssl/ssl_connection_status_flags.h" |
| 16 #include "net/ssl/ssl_info.h" | 17 #include "net/ssl/ssl_info.h" |
| 17 | 18 |
| 18 namespace net { | 19 namespace net { |
| 19 | 20 |
| 21 // ProofVerifierCallbackClientStream is passed as the callback method to | |
| 22 // VerifyProof. The ProofVerifier calls this class with the result of proof | |
| 23 // verification when verification is performed asynchronously. | |
| 24 class ProofVerifierCallbackClientStream : public ProofVerifierCallback { | |
|
Ryan Hamilton
2013/07/23 18:40:50
This code can land in google3, right? (It will ju
agl
2013/07/23 21:04:57
Right.
| |
| 25 public: | |
| 26 explicit ProofVerifierCallbackClientStream(QuicCryptoClientStream* stream) | |
| 27 : stream_(stream) {} | |
| 28 | |
| 29 // ProofVerifierCallback interface. | |
| 30 virtual void Run(bool ok, | |
| 31 string* error_details, | |
| 32 ProofVerifyDetails* details) OVERRIDE { | |
| 33 if (stream_ == NULL) { | |
| 34 delete details; | |
| 35 return; | |
| 36 } | |
| 37 | |
| 38 stream_->verify_ok_ = ok; | |
| 39 stream_->verify_error_details_ = *error_details; | |
| 40 stream_->verify_details_.reset(details); | |
| 41 stream_->proof_verify_callback_ = NULL; | |
| 42 stream_->DoHandshakeLoop(NULL); | |
| 43 | |
| 44 // The ProofVerifier owns this object and will delete it when this method | |
| 45 // returns. | |
| 46 } | |
| 47 | |
| 48 // Cancel causes any future callbacks to be ignored. It must be called on the | |
| 49 // same thread as the callback will be made on. | |
| 50 void Cancel() { | |
| 51 stream_ = NULL; | |
| 52 } | |
| 53 | |
| 54 private: | |
| 55 QuicCryptoClientStream* stream_; | |
| 56 }; | |
| 57 | |
| 20 QuicCryptoClientStream::QuicCryptoClientStream( | 58 QuicCryptoClientStream::QuicCryptoClientStream( |
| 21 const string& server_hostname, | 59 const string& server_hostname, |
| 22 QuicSession* session, | 60 QuicSession* session, |
| 23 QuicCryptoClientConfig* crypto_config) | 61 QuicCryptoClientConfig* crypto_config) |
| 24 : QuicCryptoStream(session), | 62 : QuicCryptoStream(session), |
| 25 weak_factory_(this), | |
| 26 next_state_(STATE_IDLE), | 63 next_state_(STATE_IDLE), |
| 27 num_client_hellos_(0), | 64 num_client_hellos_(0), |
| 28 crypto_config_(crypto_config), | 65 crypto_config_(crypto_config), |
| 29 server_hostname_(server_hostname), | 66 server_hostname_(server_hostname), |
| 30 generation_counter_(0) { | 67 generation_counter_(0), |
| 68 proof_verify_callback_(NULL) { | |
| 31 } | 69 } |
| 32 | 70 |
| 33 QuicCryptoClientStream::~QuicCryptoClientStream() { | 71 QuicCryptoClientStream::~QuicCryptoClientStream() { |
| 72 if (proof_verify_callback_) { | |
| 73 proof_verify_callback_->Cancel(); | |
| 74 } | |
| 34 } | 75 } |
| 35 | 76 |
| 36 void QuicCryptoClientStream::OnHandshakeMessage( | 77 void QuicCryptoClientStream::OnHandshakeMessage( |
| 37 const CryptoHandshakeMessage& message) { | 78 const CryptoHandshakeMessage& message) { |
| 38 DoHandshakeLoop(&message, OK); | 79 DoHandshakeLoop(&message); |
| 39 } | 80 } |
| 40 | 81 |
| 41 bool QuicCryptoClientStream::CryptoConnect() { | 82 bool QuicCryptoClientStream::CryptoConnect() { |
| 42 next_state_ = STATE_SEND_CHLO; | 83 next_state_ = STATE_SEND_CHLO; |
| 43 DoHandshakeLoop(NULL, OK); | 84 DoHandshakeLoop(NULL); |
| 44 return true; | 85 return true; |
| 45 } | 86 } |
| 46 | 87 |
| 47 int QuicCryptoClientStream::num_sent_client_hellos() const { | 88 int QuicCryptoClientStream::num_sent_client_hellos() const { |
| 48 return num_client_hellos_; | 89 return num_client_hellos_; |
| 49 } | 90 } |
| 50 | 91 |
| 51 bool QuicCryptoClientStream::GetSSLInfo(SSLInfo* ssl_info) { | 92 bool QuicCryptoClientStream::GetSSLInfo(SSLInfo* ssl_info) { |
| 52 ssl_info->Reset(); | 93 ssl_info->Reset(); |
| 53 QuicCryptoClientConfig::CachedState* cached = | 94 QuicCryptoClientConfig::CachedState* cached = |
| 54 crypto_config_->LookupOrCreate(server_hostname_); | 95 crypto_config_->LookupOrCreate(server_hostname_); |
| 55 DCHECK(cached); | 96 DCHECK(cached); |
| 56 if (!cached) { | 97 if (!cached) { |
| 57 return false; | 98 return false; |
| 58 } | 99 } |
| 59 const CertVerifyResult* cert_verify_result = | 100 const CertVerifyResult* cert_verify_result = |
| 60 cached->cert_verify_result(); | 101 &(reinterpret_cast<const ProofVerifyDetailsChromium*>( |
| 102 cached->proof_verify_details()))->cert_verify_result; | |
| 61 | 103 |
| 62 ssl_info->cert_status = cert_verify_result->cert_status; | 104 ssl_info->cert_status = cert_verify_result->cert_status; |
| 63 ssl_info->cert = cert_verify_result->verified_cert; | 105 ssl_info->cert = cert_verify_result->verified_cert; |
| 64 | 106 |
| 65 // TODO(rtenneti): Figure out what to set for the following. | 107 // TODO(rtenneti): Figure out what to set for the following. |
| 66 // Temporarily hard coded cipher_suite as 0xc031 to represent | 108 // Temporarily hard coded cipher_suite as 0xc031 to represent |
| 67 // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (from | 109 // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (from |
| 68 // net/ssl/ssl_cipher_suite_names.cc) and encryption as 256. | 110 // net/ssl/ssl_cipher_suite_names.cc) and encryption as 256. |
| 69 int cipher_suite = 0xc02f; | 111 int cipher_suite = 0xc02f; |
| 70 int ssl_connection_status = 0; | 112 int ssl_connection_status = 0; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 88 } | 130 } |
| 89 | 131 |
| 90 // kMaxClientHellos is the maximum number of times that we'll send a client | 132 // kMaxClientHellos is the maximum number of times that we'll send a client |
| 91 // hello. The value 3 accounts for: | 133 // hello. The value 3 accounts for: |
| 92 // * One failure due to an incorrect or missing source-address token. | 134 // * One failure due to an incorrect or missing source-address token. |
| 93 // * One failure due the server's certificate chain being unavailible and the | 135 // * One failure due the server's certificate chain being unavailible and the |
| 94 // server being unwilling to send it without a valid source-address token. | 136 // server being unwilling to send it without a valid source-address token. |
| 95 static const int kMaxClientHellos = 3; | 137 static const int kMaxClientHellos = 3; |
| 96 | 138 |
| 97 void QuicCryptoClientStream::DoHandshakeLoop( | 139 void QuicCryptoClientStream::DoHandshakeLoop( |
| 98 const CryptoHandshakeMessage* in, | 140 const CryptoHandshakeMessage* in) { |
| 99 int result) { | |
| 100 CryptoHandshakeMessage out; | 141 CryptoHandshakeMessage out; |
| 101 QuicErrorCode error; | 142 QuicErrorCode error; |
| 102 string error_details; | 143 string error_details; |
| 103 QuicCryptoClientConfig::CachedState* cached = | 144 QuicCryptoClientConfig::CachedState* cached = |
| 104 crypto_config_->LookupOrCreate(server_hostname_); | 145 crypto_config_->LookupOrCreate(server_hostname_); |
| 105 | 146 |
| 106 if (in != NULL) { | 147 if (in != NULL) { |
| 107 DVLOG(1) << "Client received: " << in->DebugString(); | 148 DVLOG(1) << "Client received: " << in->DebugString(); |
| 108 } | 149 } |
| 109 | 150 |
| 110 for (;;) { | 151 for (;;) { |
| 111 const State state = next_state_; | 152 const State state = next_state_; |
| 112 next_state_ = STATE_IDLE; | 153 next_state_ = STATE_IDLE; |
| 113 switch (state) { | 154 switch (state) { |
| 114 case STATE_SEND_CHLO: { | 155 case STATE_SEND_CHLO: { |
| 115 DCHECK_EQ(OK, result); | |
| 116 // Send the client hello in plaintext. | 156 // Send the client hello in plaintext. |
| 117 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); | 157 session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); |
| 118 if (num_client_hellos_ > kMaxClientHellos) { | 158 if (num_client_hellos_ > kMaxClientHellos) { |
| 119 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); | 159 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); |
| 120 return; | 160 return; |
| 121 } | 161 } |
| 122 num_client_hellos_++; | 162 num_client_hellos_++; |
| 123 | 163 |
| 124 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { | 164 if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { |
| 125 crypto_config_->FillInchoateClientHello( | 165 crypto_config_->FillInchoateClientHello( |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 164 encryption_established_ = true; | 204 encryption_established_ = true; |
| 165 session()->OnCryptoHandshakeEvent( | 205 session()->OnCryptoHandshakeEvent( |
| 166 QuicSession::ENCRYPTION_FIRST_ESTABLISHED); | 206 QuicSession::ENCRYPTION_FIRST_ESTABLISHED); |
| 167 } else { | 207 } else { |
| 168 session()->OnCryptoHandshakeEvent( | 208 session()->OnCryptoHandshakeEvent( |
| 169 QuicSession::ENCRYPTION_REESTABLISHED); | 209 QuicSession::ENCRYPTION_REESTABLISHED); |
| 170 } | 210 } |
| 171 return; | 211 return; |
| 172 } | 212 } |
| 173 case STATE_RECV_REJ: | 213 case STATE_RECV_REJ: |
| 174 DCHECK_EQ(OK, result); | |
| 175 // We sent a dummy CHLO because we didn't have enough information to | 214 // We sent a dummy CHLO because we didn't have enough information to |
| 176 // perform a handshake, or we sent a full hello that the server | 215 // perform a handshake, or we sent a full hello that the server |
| 177 // rejected. Here we hope to have a REJ that contains the information | 216 // rejected. Here we hope to have a REJ that contains the information |
| 178 // that we need. | 217 // that we need. |
| 179 if (in->tag() != kREJ) { | 218 if (in->tag() != kREJ) { |
| 180 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, | 219 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
| 181 "Expected REJ"); | 220 "Expected REJ"); |
| 182 return; | 221 return; |
| 183 } | 222 } |
| 184 error = crypto_config_->ProcessRejection( | 223 error = crypto_config_->ProcessRejection( |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 198 break; | 237 break; |
| 199 } | 238 } |
| 200 } | 239 } |
| 201 next_state_ = STATE_SEND_CHLO; | 240 next_state_ = STATE_SEND_CHLO; |
| 202 break; | 241 break; |
| 203 case STATE_VERIFY_PROOF: { | 242 case STATE_VERIFY_PROOF: { |
| 204 ProofVerifier* verifier = crypto_config_->proof_verifier(); | 243 ProofVerifier* verifier = crypto_config_->proof_verifier(); |
| 205 DCHECK(verifier); | 244 DCHECK(verifier); |
| 206 next_state_ = STATE_VERIFY_PROOF_COMPLETE; | 245 next_state_ = STATE_VERIFY_PROOF_COMPLETE; |
| 207 generation_counter_ = cached->generation_counter(); | 246 generation_counter_ = cached->generation_counter(); |
| 208 result = verifier->VerifyProof( | 247 |
| 248 ProofVerifierCallbackClientStream* proof_verify_callback = new | |
| 249 ProofVerifierCallbackClientStream(this); | |
| 250 | |
| 251 verify_ok_ = false; | |
| 252 | |
| 253 ProofVerifier::Status status = verifier->VerifyProof( | |
| 209 server_hostname_, | 254 server_hostname_, |
| 210 cached->server_config(), | 255 cached->server_config(), |
| 211 cached->certs(), | 256 cached->certs(), |
| 212 cached->signature(), | 257 cached->signature(), |
| 213 &error_details_, | 258 &error_details, |
| 214 &cert_verify_result_, | 259 &verify_details_, |
| 215 base::Bind(&QuicCryptoClientStream::OnVerifyProofComplete, | 260 proof_verify_callback); |
| 216 weak_factory_.GetWeakPtr())); | 261 |
| 217 if (result == ERR_IO_PENDING) { | 262 switch (status) { |
| 218 DVLOG(1) << "Doing VerifyProof"; | 263 case ProofVerifier::PENDING: |
| 219 return; | 264 proof_verify_callback_ = proof_verify_callback; |
| 265 DVLOG(1) << "Doing VerifyProof"; | |
| 266 return; | |
| 267 case ProofVerifier::ERROR: | |
| 268 CloseConnectionWithDetails( | |
| 269 QUIC_PROOF_INVALID, "Proof invalid: " + error_details); | |
| 270 return; | |
| 271 case ProofVerifier::OK: | |
| 272 verify_ok_ = true; | |
| 273 break; | |
| 220 } | 274 } |
| 221 break; | 275 break; |
| 222 } | 276 } |
| 223 case STATE_VERIFY_PROOF_COMPLETE: | 277 case STATE_VERIFY_PROOF_COMPLETE: |
| 224 if (result != OK) { | 278 if (!verify_ok_) { |
| 225 CloseConnectionWithDetails( | 279 CloseConnectionWithDetails( |
| 226 QUIC_PROOF_INVALID, "Proof invalid: " + error_details_); | 280 QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_); |
| 227 return; | 281 return; |
| 228 } | 282 } |
| 229 // Check if generation_counter has changed between STATE_VERIFY_PROOF | 283 // Check if generation_counter has changed between STATE_VERIFY_PROOF |
| 230 // and STATE_VERIFY_PROOF_COMPLETE state changes. | 284 // and STATE_VERIFY_PROOF_COMPLETE state changes. |
| 231 if (generation_counter_ != cached->generation_counter()) { | 285 if (generation_counter_ != cached->generation_counter()) { |
| 232 next_state_ = STATE_VERIFY_PROOF; | 286 next_state_ = STATE_VERIFY_PROOF; |
| 233 } else { | 287 } else { |
| 234 cached->SetProofValid(); | 288 cached->SetProofValid(); |
| 235 cached->SetCertVerifyResult(cert_verify_result_); | 289 cached->SetProofVerifyDetails(verify_details_.release()); |
| 236 next_state_ = STATE_SEND_CHLO; | 290 next_state_ = STATE_SEND_CHLO; |
| 237 } | 291 } |
| 238 break; | 292 break; |
| 239 case STATE_RECV_SHLO: { | 293 case STATE_RECV_SHLO: { |
| 240 // We sent a CHLO that we expected to be accepted and now we're hoping | 294 // We sent a CHLO that we expected to be accepted and now we're hoping |
| 241 // for a SHLO from the server to confirm that. | 295 // for a SHLO from the server to confirm that. |
| 242 if (in->tag() == kREJ) { | 296 if (in->tag() == kREJ) { |
| 243 // alternative_decrypter will be NULL if the original alternative | 297 // alternative_decrypter will be NULL if the original alternative |
| 244 // decrypter latched and became the primary decrypter. That happens | 298 // decrypter latched and became the primary decrypter. That happens |
| 245 // if we received a message encrypted with the INITIAL key. | 299 // if we received a message encrypted with the INITIAL key. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 return; | 352 return; |
| 299 } | 353 } |
| 300 case STATE_IDLE: | 354 case STATE_IDLE: |
| 301 // This means that the peer sent us a message that we weren't expecting. | 355 // This means that the peer sent us a message that we weren't expecting. |
| 302 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); | 356 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); |
| 303 return; | 357 return; |
| 304 } | 358 } |
| 305 } | 359 } |
| 306 } | 360 } |
| 307 | 361 |
| 308 void QuicCryptoClientStream::OnVerifyProofComplete(int result) { | |
| 309 DCHECK_EQ(STATE_VERIFY_PROOF_COMPLETE, next_state_); | |
| 310 DVLOG(1) << "VerifyProof completed: " << result; | |
| 311 DoHandshakeLoop(NULL, result); | |
| 312 } | |
| 313 | |
| 314 } // namespace net | 362 } // namespace net |
| OLD | NEW |