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 63a4f44d0347a660a3c8683dad32794fef2fa416..aa43b6d1df74107681003b1c68163c1457eb78ff 100644 |
--- a/net/quic/quic_crypto_client_stream.cc |
+++ b/net/quic/quic_crypto_client_stream.cc |
@@ -11,14 +11,18 @@ |
namespace net { |
-QuicCryptoClientStream::QuicCryptoClientStream(QuicSession* session, |
- const string& server_hostname) |
+QuicCryptoClientStream::QuicCryptoClientStream( |
+ const string& server_hostname, |
+ const QuicConfig& config, |
+ QuicSession* session, |
+ QuicCryptoClientConfig* crypto_config) |
: QuicCryptoStream(session), |
next_state_(STATE_IDLE), |
+ num_client_hellos_(0), |
+ config_(config), |
+ crypto_config_(crypto_config), |
decrypter_pushed_(false), |
server_hostname_(server_hostname) { |
- config_.SetDefaults(); |
- crypto_config_.SetDefaults(); |
} |
QuicCryptoClientStream::~QuicCryptoClientStream() { |
@@ -45,6 +49,13 @@ QuicCryptoClientStream::crypto_negotiated_params() const { |
return crypto_negotiated_params_; |
} |
+// kMaxClientHellos is the maximum number of times that we'll send a client |
+// hello. The value 3 accounts for: |
+// * One failure due to an incorrect or missing source-address token. |
+// * One failure due the server's certificate chain being unavailible and the |
+// server being unwilling to send it without a valid source-address token. |
+static const int kMaxClientHellos = 3; |
+ |
void QuicCryptoClientStream::DoHandshakeLoop( |
const CryptoHandshakeMessage* in) { |
CryptoHandshakeMessage out; |
@@ -60,11 +71,17 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
next_state_ = STATE_IDLE; |
switch (state) { |
case STATE_SEND_CHLO: { |
+ if (num_client_hellos_ > kMaxClientHellos) { |
+ CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); |
+ return; |
+ } |
+ num_client_hellos_++; |
+ |
const QuicCryptoClientConfig::CachedState* cached = |
- crypto_config_.Lookup(server_hostname_); |
+ crypto_config_->Lookup(server_hostname_); |
if (!cached || !cached->is_complete()) { |
- crypto_config_.FillInchoateClientHello(server_hostname_, cached, |
- &out); |
+ crypto_config_->FillInchoateClientHello(server_hostname_, cached, |
+ &out); |
next_state_ = STATE_RECV_REJ; |
DLOG(INFO) << "Client Sending: " << out.DebugString(); |
SendHandshakeMessage(out); |
@@ -72,7 +89,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
} |
const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); |
config_.ToHandshakeMessage(&out); |
- error = crypto_config_.FillClientHello( |
+ error = crypto_config_->FillClientHello( |
server_hostname_, |
session()->connection()->guid(), |
cached, |
@@ -102,16 +119,18 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
return; |
} |
case STATE_RECV_REJ: |
- // We sent a dummy CHLO because we don't have enough information to |
- // perform a handshake. Here we hope to have a REJ that contains the |
- // information that we need. |
+ // 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) { |
CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
"Expected REJ"); |
return; |
} |
- error = crypto_config_.ProcessRejection(server_hostname_, *in, |
- &error_details); |
+ error = crypto_config_->ProcessRejection(server_hostname_, *in, |
+ &crypto_negotiated_params_, |
+ &error_details); |
if (error != QUIC_NO_ERROR) { |
CloseConnectionWithDetails(error, error_details); |
return; |
@@ -126,10 +145,13 @@ void QuicCryptoClientStream::DoHandshakeLoop( |
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) { |
+ next_state_ = STATE_RECV_REJ; |
+ break; |
+ } |
if (in->tag() != kSHLO) { |
- // TODO(agl): in the future we would attempt the handshake again. |
CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
- "Expected SHLO"); |
+ "Expected SHLO or REJ"); |
return; |
} |
// Receiving SHLO implies the server must have processed our full |