| Index: net/quic/quic_crypto_client_stream.cc
|
| ===================================================================
|
| --- net/quic/quic_crypto_client_stream.cc (revision 280648)
|
| +++ net/quic/quic_crypto_client_stream.cc (working copy)
|
| @@ -4,17 +4,40 @@
|
|
|
| #include "net/quic/quic_crypto_client_stream.h"
|
|
|
| -#include "net/quic/crypto/channel_id.h"
|
| #include "net/quic/crypto/crypto_protocol.h"
|
| #include "net/quic/crypto/crypto_utils.h"
|
| #include "net/quic/crypto/null_encrypter.h"
|
| -#include "net/quic/crypto/proof_verifier.h"
|
| #include "net/quic/quic_client_session_base.h"
|
| #include "net/quic/quic_protocol.h"
|
| #include "net/quic/quic_session.h"
|
|
|
| namespace net {
|
|
|
| +QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
|
| +ChannelIDSourceCallbackImpl(QuicCryptoClientStream* stream)
|
| + : stream_(stream) {}
|
| +
|
| +QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
|
| +~ChannelIDSourceCallbackImpl() {}
|
| +
|
| +void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Run(
|
| + scoped_ptr<ChannelIDKey>* channel_id_key) {
|
| + if (stream_ == NULL) {
|
| + return;
|
| + }
|
| +
|
| + stream_->channel_id_key_.reset(channel_id_key->release());
|
| + stream_->channel_id_source_callback_ = NULL;
|
| + stream_->DoHandshakeLoop(NULL);
|
| +
|
| + // The ChannelIDSource owns this object and will delete it when this method
|
| + // returns.
|
| +}
|
| +
|
| +void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Cancel() {
|
| + stream_ = NULL;
|
| +}
|
| +
|
| QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
|
| QuicCryptoClientStream* stream)
|
| : stream_(stream) {}
|
| @@ -55,11 +78,15 @@
|
| crypto_config_(crypto_config),
|
| server_id_(server_id),
|
| generation_counter_(0),
|
| - proof_verify_callback_(NULL),
|
| - verify_context_(verify_context) {
|
| + channel_id_source_callback_(NULL),
|
| + verify_context_(verify_context),
|
| + proof_verify_callback_(NULL) {
|
| }
|
|
|
| QuicCryptoClientStream::~QuicCryptoClientStream() {
|
| + if (channel_id_source_callback_) {
|
| + channel_id_source_callback_->Cancel();
|
| + }
|
| if (proof_verify_callback_) {
|
| proof_verify_callback_->Cancel();
|
| }
|
| @@ -106,13 +133,13 @@
|
| next_state_ = STATE_IDLE;
|
| switch (state) {
|
| case STATE_INITIALIZE: {
|
| - if (!cached->IsEmpty() && !cached->signature().empty() &&
|
| - server_id_.is_https()) {
|
| + if (!cached->IsEmpty() && !cached->proof_valid() &&
|
| + !cached->signature().empty() && server_id_.is_https()) {
|
| DCHECK(crypto_config_->proof_verifier());
|
| // If the cached state needs to be verified, do it now.
|
| next_state_ = STATE_VERIFY_PROOF;
|
| } else {
|
| - next_state_ = STATE_SEND_CHLO;
|
| + next_state_ = STATE_GET_CHANNEL_ID;
|
| }
|
| break;
|
| }
|
| @@ -152,35 +179,6 @@
|
| return;
|
| }
|
| session()->config()->ToHandshakeMessage(&out);
|
| -
|
| - scoped_ptr<ChannelIDKey> channel_id_key;
|
| - bool do_channel_id = false;
|
| - if (crypto_config_->channel_id_source()) {
|
| - const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
|
| - DCHECK(scfg);
|
| - const QuicTag* their_proof_demands;
|
| - size_t num_their_proof_demands;
|
| - if (scfg->GetTaglist(kPDMD, &their_proof_demands,
|
| - &num_their_proof_demands) == QUIC_NO_ERROR) {
|
| - for (size_t i = 0; i < num_their_proof_demands; i++) {
|
| - if (their_proof_demands[i] == kCHID) {
|
| - do_channel_id = true;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - if (do_channel_id) {
|
| - QuicAsyncStatus status =
|
| - crypto_config_->channel_id_source()->GetChannelIDKey(
|
| - server_id_.host(), &channel_id_key, NULL);
|
| - if (status != QUIC_SUCCESS) {
|
| - CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
|
| - "Channel ID lookup failed");
|
| - return;
|
| - }
|
| - }
|
| -
|
| error = crypto_config_->FillClientHello(
|
| server_id_,
|
| session()->connection()->connection_id(),
|
| @@ -188,7 +186,7 @@
|
| cached,
|
| session()->connection()->clock()->WallNow(),
|
| session()->connection()->random_generator(),
|
| - channel_id_key.get(),
|
| + channel_id_key_.get(),
|
| &crypto_negotiated_params_,
|
| &out,
|
| &error_details);
|
| @@ -254,7 +252,7 @@
|
| break;
|
| }
|
| }
|
| - next_state_ = STATE_SEND_CHLO;
|
| + next_state_ = STATE_GET_CHANNEL_ID;
|
| break;
|
| case STATE_VERIFY_PROOF: {
|
| ProofVerifier* verifier = crypto_config_->proof_verifier();
|
| @@ -306,9 +304,48 @@
|
| } 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;
|
| + channel_id_key_.reset();
|
| + if (!RequiresChannelID(cached)) {
|
| next_state_ = STATE_SEND_CHLO;
|
| + break;
|
| }
|
| +
|
| + ChannelIDSourceCallbackImpl* channel_id_source_callback =
|
| + new ChannelIDSourceCallbackImpl(this);
|
| + QuicAsyncStatus status =
|
| + crypto_config_->channel_id_source()->GetChannelIDKey(
|
| + server_id_.host(), &channel_id_key_,
|
| + channel_id_source_callback);
|
| +
|
| + switch (status) {
|
| + case QUIC_PENDING:
|
| + channel_id_source_callback_ = channel_id_source_callback;
|
| + DVLOG(1) << "Looking up channel ID";
|
| + return;
|
| + case QUIC_FAILURE:
|
| + delete channel_id_source_callback;
|
| + CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
|
| + "Channel ID lookup failed");
|
| + return;
|
| + case QUIC_SUCCESS:
|
| + delete channel_id_source_callback;
|
| + break;
|
| + }
|
| break;
|
| + }
|
| + case STATE_GET_CHANNEL_ID_COMPLETE:
|
| + if (!channel_id_key_) {
|
| + CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
|
| + "Channel ID lookup failed");
|
| + return;
|
| + }
|
| + 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.
|
| @@ -390,6 +427,31 @@
|
| client_session()->OnProofValid(*cached);
|
| }
|
|
|
| +bool QuicCryptoClientStream::RequiresChannelID(
|
| + QuicCryptoClientConfig::CachedState* cached) {
|
| + if (!server_id_.is_https() ||
|
| + server_id_.privacy_mode() == PRIVACY_MODE_ENABLED ||
|
| + !crypto_config_->channel_id_source()) {
|
| + return false;
|
| + }
|
| + const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
|
| + if (!scfg) { // scfg may be null when we send an inchoate CHLO.
|
| + return false;
|
| + }
|
| + const QuicTag* their_proof_demands;
|
| + size_t num_their_proof_demands;
|
| + if (scfg->GetTaglist(kPDMD, &their_proof_demands,
|
| + &num_their_proof_demands) != QUIC_NO_ERROR) {
|
| + return false;
|
| + }
|
| + for (size_t i = 0; i < num_their_proof_demands; i++) {
|
| + if (their_proof_demands[i] == kCHID) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| QuicClientSessionBase* QuicCryptoClientStream::client_session() {
|
| return reinterpret_cast<QuicClientSessionBase*>(session());
|
| }
|
|
|