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 674a441e7971a0b62e9c6ee49486139a489cfcbf..f0ec9130f3cd926de064c3a545a840b80ad208d1 100644 |
--- a/net/quic/quic_crypto_client_stream.cc |
+++ b/net/quic/quic_crypto_client_stream.cc |
@@ -4,6 +4,8 @@ |
#include "net/quic/quic_crypto_client_stream.h" |
+#include "net/base/completion_callback.h" |
+#include "net/base/net_errors.h" |
#include "net/quic/crypto/crypto_protocol.h" |
#include "net/quic/crypto/crypto_utils.h" |
#include "net/quic/crypto/null_encrypter.h" |
@@ -18,10 +20,12 @@ QuicCryptoClientStream::QuicCryptoClientStream( |
QuicSession* session, |
QuicCryptoClientConfig* crypto_config) |
: QuicCryptoStream(session), |
+ weak_factory_(this), |
next_state_(STATE_IDLE), |
num_client_hellos_(0), |
crypto_config_(crypto_config), |
- server_hostname_(server_hostname) { |
+ server_hostname_(server_hostname), |
+ generation_counter_(0) { |
} |
QuicCryptoClientStream::~QuicCryptoClientStream() { |
@@ -29,12 +33,12 @@ QuicCryptoClientStream::~QuicCryptoClientStream() { |
void QuicCryptoClientStream::OnHandshakeMessage( |
const CryptoHandshakeMessage& message) { |
- DoHandshakeLoop(&message); |
+ DoHandshakeLoop(&message, OK); |
} |
bool QuicCryptoClientStream::CryptoConnect() { |
next_state_ = STATE_SEND_CHLO; |
- DoHandshakeLoop(NULL); |
+ DoHandshakeLoop(NULL, OK); |
return true; |
} |
@@ -50,7 +54,8 @@ int QuicCryptoClientStream::num_sent_client_hellos() const { |
static const int kMaxClientHellos = 3; |
void QuicCryptoClientStream::DoHandshakeLoop( |
- const CryptoHandshakeMessage* in) { |
+ const CryptoHandshakeMessage* in, |
+ int result) { |
CryptoHandshakeMessage out; |
QuicErrorCode error; |
string error_details; |
@@ -66,6 +71,8 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
next_state_ = STATE_IDLE; |
switch (state) { |
case STATE_SEND_CHLO: { |
+ // Send the subsequent client hello in plaintext. |
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); |
if (num_client_hellos_ > kMaxClientHellos) { |
CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); |
return; |
@@ -122,6 +129,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
return; |
} |
case STATE_RECV_REJ: |
+ DCHECK_EQ(OK, result); |
// We sent a dummy CHLO because we didn't have enough information to |
// perform a handshake, or we sent a full hello that the server |
// rejected. Here we hope to have a REJ that contains the information |
@@ -139,30 +147,54 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
return; |
} |
if (!cached->proof_valid()) { |
- const ProofVerifier* verifier = crypto_config_->proof_verifier(); |
+ ProofVerifier* verifier = session()->proof_verifier(); |
if (!verifier) { |
// If no verifier is set then we don't check the certificates. |
cached->SetProofValid(); |
} else if (!cached->signature().empty()) { |
- // TODO(rtenneti): In Chromium, we will need to make VerifyProof() |
- // asynchronous. |
- if (!verifier->VerifyProof(server_hostname_, |
- cached->server_config(), |
- cached->certs(), |
- cached->signature(), |
- &error_details)) { |
- CloseConnectionWithDetails(QUIC_PROOF_INVALID, |
- "Proof invalid: " + error_details); |
- return; |
- } |
- cached->SetProofValid(); |
+ next_state_ = STATE_VERIFY_PROOF; |
+ continue; |
} |
} |
- // Send the subsequent client hello in plaintext. |
- session()->connection()->SetDefaultEncryptionLevel( |
- ENCRYPTION_NONE); |
next_state_ = STATE_SEND_CHLO; |
break; |
+ case STATE_VERIFY_PROOF: { |
+ ProofVerifier* verifier = session()->proof_verifier(); |
+ DCHECK(verifier); |
+ next_state_ = STATE_VERIFY_PROOF_COMPLETED; |
+ generation_counter_ = cached->generation_counter(); |
+ result = verifier->VerifyProof( |
+ server_hostname_, |
+ cached->server_config(), |
+ cached->certs(), |
+ cached->signature(), |
+ &error_details_, |
+ base::Bind(&QuicCryptoClientStream::OnVerifyProofComplete, |
+ weak_factory_.GetWeakPtr())); |
+ if (result == ERR_IO_PENDING) { |
+ DVLOG(1) << "Doing VerifyProof"; |
+ return; |
+ } |
+ break; |
+ } |
+ case STATE_VERIFY_PROOF_COMPLETED: { |
+ if (result != OK) { |
+ CloseConnectionWithDetails( |
+ QUIC_PROOF_INVALID, "Proof invalid: " + error_details_); |
+ return; |
+ } |
+ ProofVerifier* verifier = session()->proof_verifier(); |
+ DCHECK(verifier); |
+ // Check if generation_counter has changed between STATE_VERIFY_PROOF |
+ // and STATE_VERIFY_PROOF_COMPLETED state changes. |
+ if (generation_counter_ != cached->generation_counter()) { |
+ next_state_ = STATE_VERIFY_PROOF; |
+ continue; |
+ } |
+ cached->SetProofValid(); |
+ next_state_ = STATE_SEND_CHLO; |
+ break; |
+ } |
case STATE_RECV_SHLO: { |
// We sent a CHLO that we expected to be accepted and now we're hoping |
// for a SHLO from the server to confirm that. |
@@ -232,4 +264,10 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
} |
} |
+void QuicCryptoClientStream::OnVerifyProofComplete(int result) { |
+ DCHECK_EQ(STATE_VERIFY_PROOF_COMPLETED, next_state_); |
+ DVLOG(1) << "VerifyProof completed: " << result; |
+ DoHandshakeLoop(NULL, result); |
+} |
+ |
} // namespace net |