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 28a6db8569195660a55a34639065e3fa56d75bc8..f1f09092952b9e89163f6cf7ad980822ba277f5c 100644 |
--- a/net/quic/quic_crypto_client_stream.cc |
+++ b/net/quic/quic_crypto_client_stream.cc |
@@ -87,7 +87,8 @@ QuicCryptoClientStream::QuicCryptoClientStream( |
channel_id_source_callback_run_(false), |
channel_id_source_callback_(nullptr), |
verify_context_(verify_context), |
- proof_verify_callback_(nullptr) { |
+ proof_verify_callback_(nullptr), |
+ stateless_reject_received_(false) { |
DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective()); |
} |
@@ -246,6 +247,19 @@ void QuicCryptoClientStream::DoInitialize( |
void QuicCryptoClientStream::DoSendCHLO( |
const CryptoHandshakeMessage* in, |
QuicCryptoClientConfig::CachedState* cached) { |
+ if (stateless_reject_received_) { |
+ // If we've gotten to this point, we've sent at least one hello |
+ // and received a stateless reject in response. We cannot |
+ // continue to send hellos because the server has abandoned state |
+ // for this connection. Abandon further handshakes. |
+ next_state_ = STATE_NONE; |
+ if (session()->connection()->connected()) { |
+ session()->connection()->CloseConnection( |
+ QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, false); |
+ } |
+ return; |
+ } |
+ |
// Send the client hello in plaintext. |
session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE); |
if (num_client_hellos_ > kMaxClientHellos) { |
@@ -255,6 +269,11 @@ void QuicCryptoClientStream::DoSendCHLO( |
num_client_hellos_++; |
CryptoHandshakeMessage out; |
+ DCHECK(session() != nullptr); |
+ DCHECK(session()->config() != nullptr); |
+ // Send all the options, regardless of whether we're sending an |
+ // inchoate or subsequent hello. |
+ session()->config()->ToHandshakeMessage(&out); |
if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { |
crypto_config_->FillInchoateClientHello( |
server_id_, |
@@ -282,7 +301,6 @@ void QuicCryptoClientStream::DoSendCHLO( |
return; |
} |
- session()->config()->ToHandshakeMessage(&out); |
string error_details; |
QuicErrorCode error = crypto_config_->FillClientHello( |
server_id_, |
@@ -344,16 +362,18 @@ void QuicCryptoClientStream::DoReceiveREJ( |
// 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) { |
+ if ((in->tag() != kREJ) && (in->tag() != kSREJ)) { |
next_state_ = STATE_NONE; |
CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
"Expected REJ"); |
return; |
} |
+ stateless_reject_received_ = in->tag() == kSREJ; |
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); |
@@ -491,9 +511,11 @@ 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) { |
+ // We sent a CHLO that we expected to be accepted and now we're |
+ // hoping for a SHLO from the server to confirm that. First check |
+ // to see whether the response was a reject, and if so, move on to |
+ // the reject-processing state. |
+ if ((in->tag() == kREJ) || (in->tag() == kSREJ)) { |
// alternative_decrypter will be nullptr if the original alternative |
// decrypter latched and became the primary decrypter. That happens |
// if we received a message encrypted with the INITIAL key. |