Commit 46f73cea authored by rtenneti's avatar rtenneti Committed by Commit bot

QUIC - minor reorg of QuicCryptoClientStream::DoHandshakeLoop.

Added Do... methods for each state in DoHandshakeLoop (similar to the
conventions that we typically use in our state machines).

DoVerifyProof and DoGetChannelID which could do async operation
return  QuicAsyncStatus.

In DoHandshakeLoop changed "for (;;) {" to be similar to other
do { ...} while loops of other state machines in chromium.

R=rch@chromium.org,agl@chromium.org

Review URL: https://codereview.chromium.org/588443002

Cr-Commit-Position: refs/heads/master@{#297316}
parent f7028cff
...@@ -175,264 +175,40 @@ static const int kMaxClientHellos = 3; ...@@ -175,264 +175,40 @@ static const int kMaxClientHellos = 3;
void QuicCryptoClientStream::DoHandshakeLoop( void QuicCryptoClientStream::DoHandshakeLoop(
const CryptoHandshakeMessage* in) { const CryptoHandshakeMessage* in) {
CryptoHandshakeMessage out;
QuicErrorCode error;
string error_details;
QuicCryptoClientConfig::CachedState* cached = QuicCryptoClientConfig::CachedState* cached =
crypto_config_->LookupOrCreate(server_id_); crypto_config_->LookupOrCreate(server_id_);
for (;;) { QuicAsyncStatus rv = QUIC_SUCCESS;
do {
CHECK_NE(STATE_NONE, next_state_);
const State state = next_state_; const State state = next_state_;
next_state_ = STATE_IDLE; next_state_ = STATE_IDLE;
rv = QUIC_SUCCESS;
switch (state) { switch (state) {
case STATE_INITIALIZE: { case STATE_INITIALIZE:
if (!cached->IsEmpty() && !cached->signature().empty() && DoInitialize(cached);
server_id_.is_https()) {
// 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;
} else {
next_state_ = STATE_GET_CHANNEL_ID;
}
break; break;
} case STATE_SEND_CHLO:
case STATE_SEND_CHLO: { DoSendCHLO(in, cached);
// Send the client hello in plaintext.
session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
if (num_client_hellos_ > kMaxClientHellos) {
CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
return;
}
num_client_hellos_++;
if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
crypto_config_->FillInchoateClientHello(
server_id_,
session()->connection()->supported_versions().front(),
cached, &crypto_negotiated_params_, &out);
// Pad the inchoate client hello to fill up a packet.
const size_t kFramingOverhead = 50; // A rough estimate.
const size_t max_packet_size =
session()->connection()->max_packet_length();
if (max_packet_size <= kFramingOverhead) {
DLOG(DFATAL) << "max_packet_length (" << max_packet_size
<< ") has no room for framing overhead.";
CloseConnection(QUIC_INTERNAL_ERROR);
return;
}
if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
DLOG(DFATAL) << "Client hello won't fit in a single packet.";
CloseConnection(QUIC_INTERNAL_ERROR);
return;
}
out.set_minimum_size(max_packet_size - kFramingOverhead);
next_state_ = STATE_RECV_REJ;
SendHandshakeMessage(out);
return;
}
session()->config()->ToHandshakeMessage(&out);
error = crypto_config_->FillClientHello(
server_id_,
session()->connection()->connection_id(),
session()->connection()->supported_versions().front(),
cached,
session()->connection()->clock()->WallNow(),
session()->connection()->random_generator(),
channel_id_key_.get(),
&crypto_negotiated_params_,
&out,
&error_details);
if (error != QUIC_NO_ERROR) {
// Flush the cached config so that, if it's bad, the server has a
// chance to send us another in the future.
cached->InvalidateServerConfig();
CloseConnectionWithDetails(error, error_details);
return;
}
channel_id_sent_ = (channel_id_key_.get() != NULL);
if (cached->proof_verify_details()) {
client_session()->OnProofVerifyDetailsAvailable(
*cached->proof_verify_details());
}
next_state_ = STATE_RECV_SHLO;
SendHandshakeMessage(out);
// Be prepared to decrypt with the new server write key.
session()->connection()->SetAlternativeDecrypter(
crypto_negotiated_params_.initial_crypters.decrypter.release(),
ENCRYPTION_INITIAL,
true /* latch once used */);
// Send subsequent packets under encryption on the assumption that the
// server will accept the handshake.
session()->connection()->SetEncrypter(
ENCRYPTION_INITIAL,
crypto_negotiated_params_.initial_crypters.encrypter.release());
session()->connection()->SetDefaultEncryptionLevel(
ENCRYPTION_INITIAL);
if (!encryption_established_) {
encryption_established_ = true;
session()->OnCryptoHandshakeEvent(
QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
} else {
session()->OnCryptoHandshakeEvent(
QuicSession::ENCRYPTION_REESTABLISHED);
}
return; return;
}
case STATE_RECV_REJ: case STATE_RECV_REJ:
// We sent a dummy CHLO because we didn't have enough information to DoReceiveREJ(in, cached);
// perform a handshake, or we sent a full hello that the server
// rejected. Here we hope to have a REJ that contains the information
// that we need.
if (in->tag() != kREJ) {
CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
"Expected REJ");
return;
}
error = crypto_config_->ProcessRejection(
*in, session()->connection()->clock()->WallNow(), cached,
server_id_.is_https(), &crypto_negotiated_params_, &error_details);
if (error != QUIC_NO_ERROR) {
CloseConnectionWithDetails(error, error_details);
return;
}
if (!cached->proof_valid()) {
if (!server_id_.is_https()) {
// We don't check the certificates for insecure QUIC connections.
SetCachedProofValid(cached);
} else if (!cached->signature().empty()) {
// Note that we only verify the proof if the cached proof is not
// valid. If the cached proof is valid here, someone else must have
// just added the server config to the cache and verified the proof,
// so we can assume no CA trust changes or certificate expiration
// has happened since then.
next_state_ = STATE_VERIFY_PROOF;
break;
}
}
next_state_ = STATE_GET_CHANNEL_ID;
break; break;
case STATE_VERIFY_PROOF: { case STATE_VERIFY_PROOF:
if (QUIC_PENDING == DoVerifyProof(cached)) { rv = DoVerifyProof(cached);
return;
}
break; break;
}
case STATE_VERIFY_PROOF_COMPLETE: case STATE_VERIFY_PROOF_COMPLETE:
if (QUIC_PROOF_INVALID == DoVerifyProofComplete(cached)) { DoVerifyProofComplete(cached);
return;
}
break; break;
case STATE_GET_CHANNEL_ID: { case STATE_GET_CHANNEL_ID:
next_state_ = STATE_GET_CHANNEL_ID_COMPLETE; rv = DoGetChannelID(cached);
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; break;
}
case STATE_GET_CHANNEL_ID_COMPLETE: case STATE_GET_CHANNEL_ID_COMPLETE:
if (!channel_id_key_.get()) { DoGetChannelIDComplete();
CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE, break;
"Channel ID lookup failed"); case STATE_RECV_SHLO:
return; DoReceiveSHLO(in, cached);
}
next_state_ = STATE_SEND_CHLO;
break; 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.
if (in->tag() == kREJ) {
// alternative_decrypter will be NULL if the original alternative
// decrypter latched and became the primary decrypter. That happens
// if we received a message encrypted with the INITIAL key.
if (session()->connection()->alternative_decrypter() == NULL) {
// The rejection was sent encrypted!
CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
"encrypted REJ message");
return;
}
next_state_ = STATE_RECV_REJ;
break;
}
if (in->tag() != kSHLO) {
CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
"Expected SHLO or REJ");
return;
}
// alternative_decrypter will be NULL if the original alternative
// decrypter latched and became the primary decrypter. That happens
// if we received a message encrypted with the INITIAL key.
if (session()->connection()->alternative_decrypter() != NULL) {
// The server hello was sent without encryption.
CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
"unencrypted SHLO message");
return;
}
error = crypto_config_->ProcessServerHello(
*in, session()->connection()->connection_id(),
session()->connection()->server_supported_versions(),
cached, &crypto_negotiated_params_, &error_details);
if (error != QUIC_NO_ERROR) {
CloseConnectionWithDetails(
error, "Server hello invalid: " + error_details);
return;
}
error =
session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
if (error != QUIC_NO_ERROR) {
CloseConnectionWithDetails(
error, "Server hello invalid: " + error_details);
return;
}
session()->OnConfigNegotiated();
CrypterPair* crypters =
&crypto_negotiated_params_.forward_secure_crypters;
// TODO(agl): we don't currently latch this decrypter because the idea
// has been floated that the server shouldn't send packets encrypted
// with the FORWARD_SECURE key until it receives a FORWARD_SECURE
// packet from the client.
session()->connection()->SetAlternativeDecrypter(
crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
false /* don't latch */);
session()->connection()->SetEncrypter(
ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
session()->connection()->SetDefaultEncryptionLevel(
ENCRYPTION_FORWARD_SECURE);
handshake_confirmed_ = true;
session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
session()->connection()->OnHandshakeComplete();
return;
}
case STATE_IDLE: case STATE_IDLE:
// This means that the peer sent us a message that we weren't expecting. // This means that the peer sent us a message that we weren't expecting.
CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
...@@ -440,29 +216,153 @@ void QuicCryptoClientStream::DoHandshakeLoop( ...@@ -440,29 +216,153 @@ void QuicCryptoClientStream::DoHandshakeLoop(
case STATE_INITIALIZE_SCUP: case STATE_INITIALIZE_SCUP:
DoInitializeServerConfigUpdate(cached); DoInitializeServerConfigUpdate(cached);
break; break;
case STATE_VERIFY_PROOF_DONE: case STATE_NONE:
NOTREACHED();
return; // We are done. return; // We are done.
} }
} } while (rv != QUIC_PENDING && next_state_ != STATE_NONE);
} }
void QuicCryptoClientStream::DoInitializeServerConfigUpdate( void QuicCryptoClientStream::DoInitialize(
QuicCryptoClientConfig::CachedState* cached) { QuicCryptoClientConfig::CachedState* cached) {
bool update_ignored = false; if (!cached->IsEmpty() && !cached->signature().empty() &&
if (!server_id_.is_https()) { server_id_.is_https()) {
// We don't check the certificates for insecure QUIC connections.
SetCachedProofValid(cached);
next_state_ = STATE_VERIFY_PROOF_DONE;
} else if (!cached->IsEmpty() && !cached->signature().empty()) {
// Note that we verify the proof even if the cached proof is valid. // 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()); DCHECK(crypto_config_->proof_verifier());
// If the cached state needs to be verified, do it now.
next_state_ = STATE_VERIFY_PROOF; next_state_ = STATE_VERIFY_PROOF;
} else { } else {
update_ignored = true; next_state_ = STATE_GET_CHANNEL_ID;
next_state_ = STATE_VERIFY_PROOF_DONE;
} }
UMA_HISTOGRAM_BOOLEAN("Net.QuicNumServerConfig.UpdateMessagesIgnored", }
update_ignored);
void QuicCryptoClientStream::DoSendCHLO(
const CryptoHandshakeMessage* in,
QuicCryptoClientConfig::CachedState* cached) {
// Send the client hello in plaintext.
session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
if (num_client_hellos_ > kMaxClientHellos) {
CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
return;
}
num_client_hellos_++;
CryptoHandshakeMessage out;
if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
crypto_config_->FillInchoateClientHello(
server_id_,
session()->connection()->supported_versions().front(),
cached, &crypto_negotiated_params_, &out);
// Pad the inchoate client hello to fill up a packet.
const size_t kFramingOverhead = 50; // A rough estimate.
const size_t max_packet_size =
session()->connection()->max_packet_length();
if (max_packet_size <= kFramingOverhead) {
DLOG(DFATAL) << "max_packet_length (" << max_packet_size
<< ") has no room for framing overhead.";
CloseConnection(QUIC_INTERNAL_ERROR);
return;
}
if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
DLOG(DFATAL) << "Client hello won't fit in a single packet.";
CloseConnection(QUIC_INTERNAL_ERROR);
return;
}
out.set_minimum_size(max_packet_size - kFramingOverhead);
next_state_ = STATE_RECV_REJ;
SendHandshakeMessage(out);
return;
}
session()->config()->ToHandshakeMessage(&out);
string error_details;
QuicErrorCode error = crypto_config_->FillClientHello(
server_id_,
session()->connection()->connection_id(),
session()->connection()->supported_versions().front(),
cached,
session()->connection()->clock()->WallNow(),
session()->connection()->random_generator(),
channel_id_key_.get(),
&crypto_negotiated_params_,
&out,
&error_details);
if (error != QUIC_NO_ERROR) {
// Flush the cached config so that, if it's bad, the server has a
// chance to send us another in the future.
cached->InvalidateServerConfig();
CloseConnectionWithDetails(error, error_details);
return;
}
channel_id_sent_ = (channel_id_key_.get() != NULL);
if (cached->proof_verify_details()) {
client_session()->OnProofVerifyDetailsAvailable(
*cached->proof_verify_details());
}
next_state_ = STATE_RECV_SHLO;
SendHandshakeMessage(out);
// Be prepared to decrypt with the new server write key.
session()->connection()->SetAlternativeDecrypter(
crypto_negotiated_params_.initial_crypters.decrypter.release(),
ENCRYPTION_INITIAL,
true /* latch once used */);
// Send subsequent packets under encryption on the assumption that the
// server will accept the handshake.
session()->connection()->SetEncrypter(
ENCRYPTION_INITIAL,
crypto_negotiated_params_.initial_crypters.encrypter.release());
session()->connection()->SetDefaultEncryptionLevel(
ENCRYPTION_INITIAL);
if (!encryption_established_) {
encryption_established_ = true;
session()->OnCryptoHandshakeEvent(
QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
} else {
session()->OnCryptoHandshakeEvent(
QuicSession::ENCRYPTION_REESTABLISHED);
}
}
void QuicCryptoClientStream::DoReceiveREJ(
const CryptoHandshakeMessage* in,
QuicCryptoClientConfig::CachedState* cached) {
// 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
// that we need.
if (in->tag() != kREJ) {
next_state_ = STATE_NONE;
CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
"Expected REJ");
return;
}
string error_details;
QuicErrorCode error = crypto_config_->ProcessRejection(
*in, session()->connection()->clock()->WallNow(), cached,
server_id_.is_https(), &crypto_negotiated_params_, &error_details);
if (error != QUIC_NO_ERROR) {
next_state_ = STATE_NONE;
CloseConnectionWithDetails(error, error_details);
return;
}
if (!cached->proof_valid()) {
if (!server_id_.is_https()) {
// We don't check the certificates for insecure QUIC connections.
SetCachedProofValid(cached);
} else if (!cached->signature().empty()) {
// Note that we only verify the proof if the cached proof is not
// valid. If the cached proof is valid here, someone else must have
// just added the server config to the cache and verified the proof,
// so we can assume no CA trust changes or certificate expiration
// has happened since then.
next_state_ = STATE_VERIFY_PROOF;
return;
}
}
next_state_ = STATE_GET_CHANNEL_ID;
} }
QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof( QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof(
...@@ -503,15 +403,16 @@ QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof( ...@@ -503,15 +403,16 @@ QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof(
return status; return status;
} }
QuicErrorCode QuicCryptoClientStream::DoVerifyProofComplete( void QuicCryptoClientStream::DoVerifyProofComplete(
QuicCryptoClientConfig::CachedState* cached) { QuicCryptoClientConfig::CachedState* cached) {
if (!verify_ok_) { if (!verify_ok_) {
next_state_ = STATE_NONE;
client_session()->OnProofVerifyDetailsAvailable(*verify_details_); client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed", UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
handshake_confirmed()); handshake_confirmed());
CloseConnectionWithDetails( CloseConnectionWithDetails(
QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_); QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
return QUIC_PROOF_INVALID; return;
} }
// Check if generation_counter has changed between STATE_VERIFY_PROOF and // Check if generation_counter has changed between STATE_VERIFY_PROOF and
...@@ -524,10 +425,143 @@ QuicErrorCode QuicCryptoClientStream::DoVerifyProofComplete( ...@@ -524,10 +425,143 @@ QuicErrorCode QuicCryptoClientStream::DoVerifyProofComplete(
if (!handshake_confirmed()) { if (!handshake_confirmed()) {
next_state_ = STATE_GET_CHANNEL_ID; next_state_ = STATE_GET_CHANNEL_ID;
} else { } else {
next_state_ = STATE_VERIFY_PROOF_DONE; next_state_ = STATE_NONE;
}
}
}
QuicAsyncStatus QuicCryptoClientStream::DoGetChannelID(
QuicCryptoClientConfig::CachedState* cached) {
next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
channel_id_key_.reset();
if (!RequiresChannelID(cached)) {
next_state_ = STATE_SEND_CHLO;
return QUIC_SUCCESS;
}
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";
break;
case QUIC_FAILURE:
next_state_ = STATE_NONE;
delete channel_id_source_callback;
CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
"Channel ID lookup failed");
break;
case QUIC_SUCCESS:
delete channel_id_source_callback;
break;
}
return status;
}
void QuicCryptoClientStream::DoGetChannelIDComplete() {
if (!channel_id_key_.get()) {
next_state_ = STATE_NONE;
CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
"Channel ID lookup failed");
return;
}
next_state_ = STATE_SEND_CHLO;
}
void QuicCryptoClientStream::DoReceiveSHLO(
const CryptoHandshakeMessage* in,
QuicCryptoClientConfig::CachedState* cached) {
next_state_ = STATE_NONE;
// We sent a CHLO that we expected to be accepted and now we're hoping
// for a SHLO from the server to confirm that.
if (in->tag() == kREJ) {
// alternative_decrypter will be NULL if the original alternative
// decrypter latched and became the primary decrypter. That happens
// if we received a message encrypted with the INITIAL key.
if (session()->connection()->alternative_decrypter() == NULL) {
// The rejection was sent encrypted!
CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
"encrypted REJ message");
return;
} }
next_state_ = STATE_RECV_REJ;
return;
}
if (in->tag() != kSHLO) {
CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
"Expected SHLO or REJ");
return;
}
// alternative_decrypter will be NULL if the original alternative
// decrypter latched and became the primary decrypter. That happens
// if we received a message encrypted with the INITIAL key.
if (session()->connection()->alternative_decrypter() != NULL) {
// The server hello was sent without encryption.
CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
"unencrypted SHLO message");
return;
}
string error_details;
QuicErrorCode error = crypto_config_->ProcessServerHello(
*in, session()->connection()->connection_id(),
session()->connection()->server_supported_versions(),
cached, &crypto_negotiated_params_, &error_details);
if (error != QUIC_NO_ERROR) {
CloseConnectionWithDetails(error, "Server hello invalid: " + error_details);
return;
}
error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
if (error != QUIC_NO_ERROR) {
CloseConnectionWithDetails(error, "Server hello invalid: " + error_details);
return;
}
session()->OnConfigNegotiated();
CrypterPair* crypters = &crypto_negotiated_params_.forward_secure_crypters;
// TODO(agl): we don't currently latch this decrypter because the idea
// has been floated that the server shouldn't send packets encrypted
// with the FORWARD_SECURE key until it receives a FORWARD_SECURE
// packet from the client.
session()->connection()->SetAlternativeDecrypter(
crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
false /* don't latch */);
session()->connection()->SetEncrypter(
ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
session()->connection()->SetDefaultEncryptionLevel(
ENCRYPTION_FORWARD_SECURE);
handshake_confirmed_ = true;
session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
session()->connection()->OnHandshakeComplete();
}
void QuicCryptoClientStream::DoInitializeServerConfigUpdate(
QuicCryptoClientConfig::CachedState* cached) {
bool update_ignored = false;
if (!server_id_.is_https()) {
// We don't check the certificates for insecure QUIC connections.
SetCachedProofValid(cached);
next_state_ = STATE_NONE;
} else if (!cached->IsEmpty() && !cached->signature().empty()) {
// Note that we verify the proof even if the cached proof is valid.
DCHECK(crypto_config_->proof_verifier());
next_state_ = STATE_VERIFY_PROOF;
} else {
update_ignored = true;
next_state_ = STATE_NONE;
} }
return QUIC_NO_ERROR; UMA_HISTOGRAM_COUNTS("Net.QuicNumServerConfig.UpdateMessagesIgnored",
update_ignored);
} }
void QuicCryptoClientStream::SetCachedProofValid( void QuicCryptoClientStream::SetCachedProofValid(
......
...@@ -107,7 +107,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { ...@@ -107,7 +107,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
STATE_GET_CHANNEL_ID_COMPLETE, STATE_GET_CHANNEL_ID_COMPLETE,
STATE_RECV_SHLO, STATE_RECV_SHLO,
STATE_INITIALIZE_SCUP, STATE_INITIALIZE_SCUP,
STATE_VERIFY_PROOF_DONE, STATE_NONE,
}; };
// Handles new server config and optional source-address token provided by the // Handles new server config and optional source-address token provided by the
...@@ -119,19 +119,41 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { ...@@ -119,19 +119,41 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
// |in| may be NULL if the call did not result from a received message. // |in| may be NULL if the call did not result from a received message.
void DoHandshakeLoop(const CryptoHandshakeMessage* in); void DoHandshakeLoop(const CryptoHandshakeMessage* in);
// Start the proof verification if |server_id_| is https and |cached| has // Start the handshake process.
// signature. void DoInitialize(QuicCryptoClientConfig::CachedState* cached);
void DoInitializeServerConfigUpdate(
QuicCryptoClientConfig::CachedState* cached);
// Starts the proof verification. Returns the QuicAsyncStatus returned by the // Send either InchoateClientHello or ClientHello message to the server.
// ProofVerifier's VerifyProof. void DoSendCHLO(const CryptoHandshakeMessage* in,
QuicCryptoClientConfig::CachedState* cached);
// Process REJ message from the server.
void DoReceiveREJ(const CryptoHandshakeMessage* in,
QuicCryptoClientConfig::CachedState* cached);
// Start the proof verification process. Returns the QuicAsyncStatus returned
// by the ProofVerifier's VerifyProof.
QuicAsyncStatus DoVerifyProof(QuicCryptoClientConfig::CachedState* cached); QuicAsyncStatus DoVerifyProof(QuicCryptoClientConfig::CachedState* cached);
// If proof is valid then it sets the proof as valid (which persists the // If proof is valid then it sets the proof as valid (which persists the
// server config) and returns QUIC_NO_ERROR. If not, it closes the connection // server config). If not, it closes the connection.
// and returns QUIC_PROOF_INVALID. void DoVerifyProofComplete(QuicCryptoClientConfig::CachedState* cached);
QuicErrorCode DoVerifyProofComplete(
// Start the look up of Channel ID process. Returns either QUIC_SUCCESS if
// RequiresChannelID returns false or QuicAsyncStatus returned by
// GetChannelIDKey.
QuicAsyncStatus DoGetChannelID(QuicCryptoClientConfig::CachedState* cached);
// If there is no channel ID, then close the connection otherwise transtion to
// STATE_SEND_CHLO state.
void DoGetChannelIDComplete();
// Process SHLO message from the server.
void DoReceiveSHLO(const CryptoHandshakeMessage* in,
QuicCryptoClientConfig::CachedState* cached);
// Start the proof verification if |server_id_| is https and |cached| has
// signature.
void DoInitializeServerConfigUpdate(
QuicCryptoClientConfig::CachedState* cached); QuicCryptoClientConfig::CachedState* cached);
// Called to set the proof of |cached| valid. Also invokes the session's // Called to set the proof of |cached| valid. Also invokes the session's
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment