Index: net/quic/quic_crypto_client_stream.cc |
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc |
index 40e4d45901c531d6fd711e3d1067a3b4cda7d953..94a7c14402ad8c9e98d08a1f4f9925edec9a6fc6 100644 |
--- a/net/quic/quic_crypto_client_stream.cc |
+++ b/net/quic/quic_crypto_client_stream.cc |
@@ -156,6 +156,13 @@ void QuicCryptoClientStream::HandleServerConfigUpdateMessage( |
error, "Server config update invalid: " + error_details); |
return; |
} |
+ |
+ DCHECK(handshake_confirmed()); |
+ if (proof_verify_callback_) { |
+ proof_verify_callback_->Cancel(); |
+ } |
+ next_state_ = STATE_INITIALIZE_SCUP; |
+ DoProofVeifyLoop(); |
} |
// kMaxClientHellos is the maximum number of times that we'll send a client |
@@ -308,57 +315,17 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
next_state_ = STATE_GET_CHANNEL_ID; |
break; |
case STATE_VERIFY_PROOF: { |
- ProofVerifier* verifier = crypto_config_->proof_verifier(); |
- DCHECK(verifier); |
- next_state_ = STATE_VERIFY_PROOF_COMPLETE; |
- generation_counter_ = cached->generation_counter(); |
- |
- ProofVerifierCallbackImpl* proof_verify_callback = |
- new ProofVerifierCallbackImpl(this); |
- |
- verify_ok_ = false; |
- |
- QuicAsyncStatus status = verifier->VerifyProof( |
- server_id_.host(), |
- cached->server_config(), |
- cached->certs(), |
- cached->signature(), |
- verify_context_.get(), |
- &verify_error_details_, |
- &verify_details_, |
- proof_verify_callback); |
- |
- switch (status) { |
- case QUIC_PENDING: |
- proof_verify_callback_ = proof_verify_callback; |
- DVLOG(1) << "Doing VerifyProof"; |
- return; |
- case QUIC_FAILURE: |
- delete proof_verify_callback; |
- break; |
- case QUIC_SUCCESS: |
- delete proof_verify_callback; |
- verify_ok_ = true; |
- break; |
+ DCHECK(!handshake_confirmed()); |
+ if (QUIC_PENDING == DoVerifyProof(cached)) { |
+ return; |
} |
break; |
} |
case STATE_VERIFY_PROOF_COMPLETE: |
- if (!verify_ok_) { |
- client_session()->OnProofVerifyDetailsAvailable(*verify_details_); |
- CloseConnectionWithDetails( |
- QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_); |
+ DCHECK(!handshake_confirmed()); |
+ if (QUIC_NO_ERROR != DoVerifyProofComplete(cached)) { |
return; |
} |
- // Check if generation_counter has changed between STATE_VERIFY_PROOF |
- // and STATE_VERIFY_PROOF_COMPLETE state changes. |
- if (generation_counter_ != cached->generation_counter()) { |
- next_state_ = STATE_VERIFY_PROOF; |
- } else { |
- SetCachedProofValid(cached); |
- cached->SetProofVerifyDetails(verify_details_.release()); |
- next_state_ = STATE_GET_CHANNEL_ID; |
- } |
break; |
case STATE_GET_CHANNEL_ID: { |
next_state_ = STATE_GET_CHANNEL_ID_COMPLETE; |
@@ -471,8 +438,129 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
// This means that the peer sent us a message that we weren't expecting. |
CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); |
return; |
+ case STATE_INITIALIZE_SCUP: |
+ case STATE_VERIFY_PROOF_SCUP: |
+ case STATE_VERIFY_PROOF_COMPLETE_SCUP: |
+ NOTREACHED(); |
+ return; |
+ } |
+ } |
+} |
+ |
+void QuicCryptoClientStream::DoProofVeifyLoop() { |
+ QuicCryptoClientConfig::CachedState* cached = |
+ crypto_config_->LookupOrCreate(server_id_); |
+ for (;;) { |
+ const State state = next_state_; |
+ next_state_ = STATE_IDLE; |
+ switch (state) { |
+ case STATE_INITIALIZE_SCUP: { |
+ if (!server_id_.is_https()) { |
+ // We don't check the certificates for insecure QUIC connections. |
+ SetCachedProofValid(cached); |
+ } else { |
+ if (!cached->IsEmpty() && !cached->signature().empty()) { |
+ // Note that we verify the proof even if the cached proof is valid. |
+ // This allows us to respond to CA trust changes or certificate |
+ // expiration because it may have been a while since we last |
+ // verified the proof. |
+ DCHECK(crypto_config_->proof_verifier()); |
+ // If the cached state needs to be verified, do it now. |
+ next_state_ = STATE_VERIFY_PROOF_SCUP; |
+ } |
+ } |
+ break; |
+ } |
+ case STATE_VERIFY_PROOF_SCUP: { |
+ if (QUIC_PENDING == DoVerifyProof(cached)) { |
+ return; |
+ } |
+ break; |
+ } |
+ case STATE_VERIFY_PROOF_COMPLETE_SCUP: { |
+ if (QUIC_NO_ERROR != DoVerifyProofComplete(cached)) { |
+ return; |
+ } |
+ break; |
+ } |
+ case STATE_IDLE: |
+ return; // We are done. |
+ default: |
+ NOTREACHED(); |
+ return; |
+ |
+ } |
+ } |
+} |
+ |
+QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof( |
+ QuicCryptoClientConfig::CachedState* cached) { |
+ ProofVerifier* verifier = crypto_config_->proof_verifier(); |
+ DCHECK(verifier); |
+ if (handshake_confirmed()) { |
+ next_state_ = STATE_VERIFY_PROOF_COMPLETE_SCUP; |
+ } else { |
+ next_state_ = STATE_VERIFY_PROOF_COMPLETE; |
Ryan Hamilton
2014/09/15 22:37:56
Since we have to conditionally set next_state_ in
ramant (doing other things)
2014/09/16 21:06:32
Done.
|
+ } |
+ generation_counter_ = cached->generation_counter(); |
+ |
+ ProofVerifierCallbackImpl* proof_verify_callback = |
+ new ProofVerifierCallbackImpl(this); |
+ |
+ verify_ok_ = false; |
+ |
+ QuicAsyncStatus status = verifier->VerifyProof( |
+ server_id_.host(), |
+ cached->server_config(), |
+ cached->certs(), |
+ cached->signature(), |
+ verify_context_.get(), |
+ &verify_error_details_, |
+ &verify_details_, |
+ proof_verify_callback); |
+ |
+ switch (status) { |
+ case QUIC_PENDING: |
+ proof_verify_callback_ = proof_verify_callback; |
+ DVLOG(1) << "Doing VerifyProof"; |
+ break; |
+ case QUIC_FAILURE: |
+ delete proof_verify_callback; |
+ break; |
+ case QUIC_SUCCESS: |
+ delete proof_verify_callback; |
+ verify_ok_ = true; |
+ break; |
+ } |
+ return status; |
+} |
+ |
+QuicErrorCode QuicCryptoClientStream::DoVerifyProofComplete( |
+ QuicCryptoClientConfig::CachedState* cached) { |
+ if (!verify_ok_) { |
+ client_session()->OnProofVerifyDetailsAvailable(*verify_details_); |
+ CloseConnectionWithDetails( |
+ QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_); |
+ return QUIC_PROOF_INVALID; |
Ryan Hamilton
2014/09/15 22:37:56
possibly add a histogram here when the handshake h
ramant (doing other things)
2014/09/16 21:06:32
Done.
|
+ } |
+ |
+ // Check if generation_counter has changed between STATE_VERIFY_PROOF (or |
+ // STATE_VERIFY_PROOF_SCUP) and STATE_VERIFY_PROOF_COMPLETE (or |
+ // STATE_VERIFY_PROOF_COMPLETE_SCUP) state changes. |
+ if (generation_counter_ != cached->generation_counter()) { |
+ if (handshake_confirmed()) { |
+ next_state_ = STATE_VERIFY_PROOF_SCUP; |
+ } else { |
+ next_state_ = STATE_VERIFY_PROOF; |
+ } |
+ } else { |
+ SetCachedProofValid(cached); |
+ cached->SetProofVerifyDetails(verify_details_.release()); |
+ if (!handshake_confirmed()) { |
+ next_state_ = STATE_GET_CHANNEL_ID; |
} |
} |
+ return QUIC_NO_ERROR; |
} |
void QuicCryptoClientStream::SetCachedProofValid( |