summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-17 17:57:01 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-17 17:57:01 +0000
commitef95114d4d73b9f561e09c4f7688b5f7c18330ba (patch)
treed8d77e0efffa6b3a0a2c392b42e94c7cf36253c9
parentf467442c9e0db18557ee0e1a5060bd25827f9ed9 (diff)
downloadchromium_src-ef95114d4d73b9f561e09c4f7688b5f7c18330ba.zip
chromium_src-ef95114d4d73b9f561e09c4f7688b5f7c18330ba.tar.gz
chromium_src-ef95114d4d73b9f561e09c4f7688b5f7c18330ba.tar.bz2
Land Recent QUIC Changes
QUIC crypto: move config objects. Currently the client and server configs are setup and torn-down for each connection. Since they are supposed to be per-client and per-server objects, this change makes them parameters that are passed into the connection Merge internal change: 44269387 QUIC crypto steps 6 and 7: per-server strike register. This change adds a per-server strike-register that allows the server to complete 0-RTT connections if the client has enough information cached. Due to the fact that the per-server and per-client objects (QuicCryptoServerConfig and QuicCryptoClientConfig) are currently setup and torn down for each connection, there's no tests in this change for a 0-RTT handshake because we can't do one yet. The next change will move these objects into the right place so that 0-RTT handshakes can be tested. This change also reminded me why I had a server nonce: without it the server cannot terminate any connections if the strike-register fails. So the server nonce is firmly back. Merge internal change: 44228897 R=rch@chromium.org Review URL: https://codereview.chromium.org/13976007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194634 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/net.gyp2
-rw-r--r--net/quic/crypto/crypto_handshake.cc134
-rw-r--r--net/quic/crypto/crypto_handshake.h51
-rw-r--r--net/quic/crypto/crypto_handshake_test.cc2
-rw-r--r--net/quic/crypto/crypto_protocol.h3
-rw-r--r--net/quic/crypto/crypto_utils.cc16
-rw-r--r--net/quic/crypto/crypto_utils.h18
-rw-r--r--net/quic/quic_client_session.cc14
-rw-r--r--net/quic/quic_client_session.h4
-rw-r--r--net/quic/quic_client_session_test.cc6
-rw-r--r--net/quic/quic_config.cc135
-rw-r--r--net/quic/quic_config.h66
-rw-r--r--net/quic/quic_connection.cc3
-rw-r--r--net/quic/quic_crypto_client_stream.cc52
-rw-r--r--net/quic/quic_crypto_client_stream.h18
-rw-r--r--net/quic/quic_crypto_client_stream_factory.h5
-rw-r--r--net/quic/quic_crypto_client_stream_test.cc6
-rw-r--r--net/quic/quic_crypto_server_stream.cc34
-rw-r--r--net/quic/quic_crypto_server_stream.h12
-rw-r--r--net/quic/quic_crypto_server_stream_test.cc8
-rw-r--r--net/quic/quic_crypto_stream.cc124
-rw-r--r--net/quic/quic_crypto_stream.h48
-rw-r--r--net/quic/quic_http_stream_test.cc6
-rw-r--r--net/quic/quic_protocol.h2
-rw-r--r--net/quic/quic_reliable_client_stream_test.cc2
-rw-r--r--net/quic/quic_stream_factory.cc29
-rw-r--r--net/quic/quic_stream_factory.h19
-rw-r--r--net/quic/quic_utils.cc1
-rw-r--r--net/quic/test_tools/crypto_test_utils.cc38
-rw-r--r--net/quic/test_tools/crypto_test_utils.h12
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream.cc9
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream.h6
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream_factory.cc7
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream_factory.h5
-rw-r--r--net/tools/quic/quic_client.cc12
-rw-r--r--net/tools/quic/quic_client.h7
-rw-r--r--net/tools/quic/quic_client_session.cc6
-rw-r--r--net/tools/quic/quic_client_session.h4
-rw-r--r--net/tools/quic/quic_client_session_test.cc2
-rw-r--r--net/tools/quic/quic_dispatcher.cc10
-rw-r--r--net/tools/quic/quic_dispatcher.h15
-rw-r--r--net/tools/quic/quic_dispatcher_test.cc2
-rw-r--r--net/tools/quic/quic_reliable_client_stream_test.cc5
-rw-r--r--net/tools/quic/quic_server.cc26
-rw-r--r--net/tools/quic/quic_server.h10
-rw-r--r--net/tools/quic/quic_server_session.cc9
-rw-r--r--net/tools/quic/quic_server_session.h7
47 files changed, 680 insertions, 332 deletions
diff --git a/net/net.gyp b/net/net.gyp
index 3ba59da..ed191da 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -734,6 +734,8 @@
'quic/quic_blocked_writer_interface.h',
'quic/quic_client_session.cc',
'quic/quic_client_session.h',
+ 'quic/quic_config.cc',
+ 'quic/quic_config.h',
'quic/quic_crypto_client_stream.cc',
'quic/quic_crypto_client_stream.h',
'quic/quic_crypto_client_stream_factory.h',
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index 18840b4..1d9b01b 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -23,6 +23,8 @@
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/crypto/quic_random.h"
+#include "net/quic/crypto/strike_register.h"
+#include "net/quic/quic_clock.h"
#include "net/quic/quic_protocol.h"
using base::StringPiece;
@@ -419,10 +421,6 @@ const string& QuicCryptoClientConfig::CachedState::source_address_token()
return source_address_token_;
}
-const string& QuicCryptoClientConfig::CachedState::orbit() const {
- return orbit_;
-}
-
void QuicCryptoClientConfig::CachedState::set_source_address_token(
StringPiece token) {
source_address_token_ = token.as_string();
@@ -443,7 +441,7 @@ void QuicCryptoClientConfig::SetDefaults() {
}
const QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::Lookup(
- const string& server_hostname) {
+ const string& server_hostname) const {
map<string, CachedState*>::const_iterator it =
cached_states_.find(server_hostname);
if (it == cached_states_.end()) {
@@ -455,7 +453,7 @@ const QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::Lookup(
void QuicCryptoClientConfig::FillInchoateClientHello(
const string& server_hostname,
const CachedState* cached,
- CryptoHandshakeMessage* out) {
+ CryptoHandshakeMessage* out) const {
out->set_tag(kCHLO);
// Server name indication.
@@ -480,7 +478,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
QuicRandom* rand,
QuicCryptoNegotiatedParameters* out_params,
CryptoHandshakeMessage* out,
- string* error_details) {
+ string* error_details) const {
FillInchoateClientHello(server_hostname, cached, out);
const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
@@ -552,8 +550,18 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
+ StringPiece orbit;
+ if (!scfg->GetStringPiece(kORBT, &orbit) ||
+ orbit.size() != kOrbitSize) {
+ if (error_details) {
+ *error_details = "SCFG missing OBIT";
+ }
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ }
+
string nonce;
- CryptoUtils::GenerateNonce(clock, rand, cached->orbit(), &nonce);
+ CryptoUtils::GenerateNonce(clock->NowAsDeltaSinceUnixEpoch(), rand, orbit,
+ &nonce);
out->SetStringPiece(kNONC, nonce);
scoped_ptr<KeyExchange> key_exchange;
@@ -599,6 +607,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
const string& server_hostname,
const CryptoHandshakeMessage& rej,
+ QuicCryptoNegotiatedParameters* out_params,
string* error_details) {
CachedState* cached;
@@ -631,6 +640,12 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
cached->set_source_address_token(token);
}
+ StringPiece nonce;
+ if (rej.GetStringPiece(kNONC, &nonce) &&
+ nonce.size() == kNonceSize) {
+ out_params->server_nonce = nonce.as_string();
+ }
+
return QUIC_NO_ERROR;
}
@@ -666,7 +681,8 @@ QuicCryptoServerConfig::QuicCryptoServerConfig(
//
// TODO(agl): switch to an encrypter with a larger nonce space (i.e.
// Salsa20+Poly1305).
- : source_address_token_encrypter_(new Aes128GcmEncrypter),
+ : strike_register_lock_(),
+ source_address_token_encrypter_(new Aes128GcmEncrypter),
source_address_token_decrypter_(new Aes128GcmDecrypter) {
crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
"QUIC source address token key",
@@ -681,7 +697,7 @@ QuicCryptoServerConfig::~QuicCryptoServerConfig() {
}
// static
-QuicServerConfigProtobuf* QuicCryptoServerConfig::ConfigForTesting(
+QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
const CryptoHandshakeMessage& extra_tags) {
@@ -722,6 +738,10 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::ConfigForTesting(
rand->RandBytes(scid_bytes, sizeof(scid_bytes));
msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes)));
+ char orbit_bytes[kOrbitSize];
+ rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
+ msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes)));
+
scoped_ptr<QuicData> serialized(
CryptoFramer::ConstructHandshakeMessage(msg));
@@ -778,6 +798,20 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
return NULL;
}
+ StringPiece orbit;
+ if (!msg->GetStringPiece(kORBT, &orbit)) {
+ LOG(WARNING) << "Server config message is missing OBIT";
+ return NULL;
+ }
+
+ if (orbit.size() != kOrbitSize) {
+ LOG(WARNING) << "Orbit value in server config is the wrong length."
+ " Got " << orbit.size() << " want " << kOrbitSize;
+ return NULL;
+ }
+ COMPILE_ASSERT(sizeof(config->orbit) == kOrbitSize, orbit_incorrect_size);
+ memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
+
if (kexs_len != protobuf->key_size()) {
LOG(WARNING) << "Server config has "
<< kexs_len
@@ -866,11 +900,11 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
return msg.release();
}
-CryptoHandshakeMessage* QuicCryptoServerConfig::AddTestingConfig(
+CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
const CryptoHandshakeMessage& extra_tags) {
- scoped_ptr<QuicServerConfigProtobuf> config(ConfigForTesting(
+ scoped_ptr<QuicServerConfigProtobuf> config(DefaultConfig(
rand, clock, extra_tags));
return AddConfig(config.get());
}
@@ -881,12 +915,18 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
const IPEndPoint& client_ip,
QuicTime::Delta now_since_unix_epoch,
QuicRandom* rand,
+ QuicCryptoNegotiatedParameters *params,
CryptoHandshakeMessage* out,
- QuicCryptoNegotiatedParameters *out_params,
- string* error_details) {
+ string* error_details) const {
CHECK(!configs_.empty());
// FIXME(agl): we should use the client's SCID, not just the active config.
- const Config* config(configs_[active_config_]);
+ map<ServerConfigID, Config*>::const_iterator it =
+ configs_.find(active_config_);
+ if (it == configs_.end()) {
+ *error_details = "No valid server config loaded";
+ return QUIC_CRYPTO_INTERNAL_ERROR;
+ }
+ const Config* const config(it->second);
bool valid_source_address_token = false;
StringPiece srct;
@@ -898,10 +938,42 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
const string fresh_source_address_token =
NewSourceAddressToken(client_ip, rand, now_since_unix_epoch);
+ // If we previously sent a REJ to this client then we may have stored a
+ // server nonce in |params|. In which case, we know that the connection
+ // is unique because the server nonce will be mixed into the key generation.
+ bool unique_by_server_nonce = !params->server_nonce.empty();
+ // If we can't ensure uniqueness by a server nonce, then we will try and use
+ // the strike register.
+ bool unique_by_strike_register = false;
+
+ StringPiece client_nonce;
+ bool client_nonce_well_formed = false;
+ if (client_hello.GetStringPiece(kNONC, &client_nonce) &&
+ client_nonce.size() == kNonceSize) {
+ client_nonce_well_formed = true;
+ if (!unique_by_server_nonce) {
+ base::AutoLock auto_lock(strike_register_lock_);
+
+ if (strike_register_.get() == NULL) {
+ strike_register_.reset(new StrikeRegister(
+ // TODO(agl): these magic numbers should come from config.
+ 1024 /* max entries */,
+ static_cast<uint32>(now_since_unix_epoch.ToSeconds()),
+ 600 /* window secs */, config->orbit));
+ }
+ unique_by_strike_register = strike_register_->Insert(
+ reinterpret_cast<const uint8*>(client_nonce.data()),
+ static_cast<uint32>(now_since_unix_epoch.ToSeconds()));
+ }
+ }
+
StringPiece scid;
if (!client_hello.GetStringPiece(kSCID, &scid) ||
scid.as_string() != config->id ||
- !valid_source_address_token) {
+ !valid_source_address_token ||
+ !client_nonce_well_formed ||
+ (!unique_by_strike_register &&
+ !unique_by_server_nonce)) {
// If the client didn't provide a server config ID, or gave the wrong one,
// then the handshake cannot possibly complete. We reject the handshake and
// give the client enough information to do better next time.
@@ -909,6 +981,14 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
out->set_tag(kREJ);
out->SetStringPiece(kSCFG, config->serialized);
out->SetStringPiece(kSRCT, fresh_source_address_token);
+ if (params->server_nonce.empty()) {
+ CryptoUtils::GenerateNonce(
+ now_since_unix_epoch, rand,
+ StringPiece(reinterpret_cast<const char*>(config->orbit),
+ sizeof(config->orbit)),
+ &params->server_nonce);
+ }
+ out->SetStringPiece(kNONC, params->server_nonce);
return QUIC_NO_ERROR;
}
@@ -931,12 +1011,12 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
if (!CryptoUtils::FindMutualTag(config->aead,
their_aeads, num_their_aeads,
CryptoUtils::LOCAL_PRIORITY,
- &out_params->aead,
+ &params->aead,
NULL) ||
!CryptoUtils::FindMutualTag(config->kexs,
their_key_exchanges, num_their_key_exchanges,
CryptoUtils::LOCAL_PRIORITY,
- &out_params->key_exchange,
+ &params->key_exchange,
&key_exchange_index)) {
if (error_details) {
*error_details = "Unsupported AEAD or KEXS";
@@ -953,22 +1033,14 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
}
if (!config->key_exchanges[key_exchange_index]->CalculateSharedKey(
- public_value, &out_params->premaster_secret)) {
+ public_value, &params->premaster_secret)) {
if (error_details) {
*error_details = "Invalid public value";
}
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
- out_params->server_config_id = scid.as_string();
-
- StringPiece client_nonce;
- if (!client_hello.GetStringPiece(kNONC, &client_nonce)) {
- if (error_details) {
- *error_details = "Invalid nonce";
- }
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
+ params->server_config_id = scid.as_string();
string hkdf_input(kLabel, arraysize(kLabel));
hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid));
@@ -978,7 +1050,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
client_hello_serialized.length());
hkdf_input.append(config->serialized);
- CryptoUtils::DeriveKeys(out_params, client_nonce, hkdf_input,
+ CryptoUtils::DeriveKeys(params, client_nonce, hkdf_input,
CryptoUtils::SERVER);
out->set_tag(kSHLO);
@@ -989,7 +1061,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
string QuicCryptoServerConfig::NewSourceAddressToken(
const IPEndPoint& ip,
QuicRandom* rand,
- QuicTime::Delta now_since_epoch) {
+ QuicTime::Delta now_since_epoch) const {
SourceAddressToken source_address_token;
source_address_token.set_ip(ip.ToString());
source_address_token.set_timestamp(now_since_epoch.ToSeconds());
@@ -1020,7 +1092,7 @@ string QuicCryptoServerConfig::NewSourceAddressToken(
bool QuicCryptoServerConfig::ValidateSourceAddressToken(
StringPiece token,
const IPEndPoint& ip,
- QuicTime::Delta now_since_epoch) {
+ QuicTime::Delta now_since_epoch) const {
char nonce[12];
DCHECK_EQ(sizeof(nonce),
source_address_token_encrypter_->GetNoncePrefixSize() +
diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h
index fa6efd3..c597b74 100644
--- a/net/quic/crypto/crypto_handshake.h
+++ b/net/quic/crypto/crypto_handshake.h
@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_piece.h"
+#include "base/synchronization/lock.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
#include "net/quic/crypto/crypto_protocol.h"
@@ -24,6 +25,7 @@ class QuicDecrypter;
class QuicEncrypter;
class QuicRandom;
class QuicServerConfigProtobuf;
+class StrikeRegister;
namespace test {
class QuicCryptoServerConfigPeer;
@@ -221,6 +223,7 @@ struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters {
scoped_ptr<QuicEncrypter> encrypter;
scoped_ptr<QuicDecrypter> decrypter;
std::string server_config_id;
+ std::string server_nonce;
};
// QuicCryptoConfig contains common configuration between clients and servers.
@@ -242,7 +245,8 @@ class NET_EXPORT_PRIVATE QuicCryptoConfig {
};
// QuicCryptoClientConfig contains crypto-related configuration settings for a
-// client.
+// client. Note that this object isn't thread-safe. It's designed to be used on
+// a single thread at a time.
class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
public:
// A CachedState contains the information that the client needs in order to
@@ -269,7 +273,6 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
const std::string& server_config() const;
const std::string& source_address_token() const;
- const std::string& orbit() const;
void set_source_address_token(base::StringPiece token);
@@ -277,7 +280,6 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
std::string server_config_id_; // An opaque id from the server.
std::string server_config_; // A serialized handshake message.
std::string source_address_token_; // An opaque proof of IP ownership.
- std::string orbit_; // An opaque server-id used in nonce generation.
// scfg contains the cached, parsed value of |server_config|.
mutable scoped_ptr<CryptoHandshakeMessage> scfg_;
@@ -291,14 +293,14 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
// Lookup returns a CachedState for the given hostname, or NULL if no
// information is known.
- const CachedState* Lookup(const std::string& server_hostname);
+ const CachedState* Lookup(const std::string& server_hostname) const;
// FillInchoateClientHello sets |out| to be a CHLO message that elicits a
// source-address token or SCFG from a server. If |cached| is non-NULL, the
// source-address token will be taken from it.
void FillInchoateClientHello(const std::string& server_hostname,
const CachedState* cached,
- CryptoHandshakeMessage* out);
+ CryptoHandshakeMessage* out) const;
// FillClientHello sets |out| to be a CHLO message based on the configuration
// of this object. This object must have cached enough information about
@@ -315,13 +317,16 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
QuicRandom* rand,
QuicCryptoNegotiatedParameters* out_params,
CryptoHandshakeMessage* out,
- std::string* error_details);
+ std::string* error_details) const;
// ProcessRejection processes a REJ message from a server and updates the
// cached information about that server. After this, |is_complete| may return
- // true for that server's CachedState.
+ // true for that server's CachedState. If the rejection message contains
+ // state about a future handshake (i.e. an nonce value from the server), then
+ // it will be saved in |out_params|.
QuicErrorCode ProcessRejection(const std::string& server_hostname,
const CryptoHandshakeMessage& rej,
+ QuicCryptoNegotiatedParameters* out_params,
std::string* error_details);
// ProcessServerHello processes the message in |server_hello|, writes the
@@ -348,7 +353,7 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
public:
// |source_address_token_secret|: secret key material used for encrypting and
// decrypting source address tokens. It can be of any length as it is fed
- // into a KDF before use.
+ // into a KDF before use. In tests, use TESTING.
explicit QuicCryptoServerConfig(
base::StringPiece source_address_token_secret);
~QuicCryptoServerConfig();
@@ -356,10 +361,10 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// TESTING is a magic parameter for passing to the constructor in tests.
static const char TESTING[];
- // ConfigForTesting generates a QuicServerConfigProtobuf protobuf suitable
+ // DefaultConfig generates a QuicServerConfigProtobuf protobuf suitable
// for using in tests. |extra_tags| contains additional key/value pairs that
// will be inserted into the config.
- static QuicServerConfigProtobuf* ConfigForTesting(
+ static QuicServerConfigProtobuf* DefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
const CryptoHandshakeMessage& extra_tags);
@@ -369,9 +374,9 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// takes ownership of the CryptoHandshakeMessage.
CryptoHandshakeMessage* AddConfig(QuicServerConfigProtobuf* protobuf);
- // AddTestingConfig creates a test config and then calls AddConfig to add it.
- // Any tags in |extra_tags| will be copied into the config.
- CryptoHandshakeMessage* AddTestingConfig(
+ // AddDefaultConfig creates a config and then calls AddConfig to
+ // add it. Any tags in |extra_tags| will be copied into the config.
+ CryptoHandshakeMessage* AddDefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
const CryptoHandshakeMessage& extra_tags);
@@ -389,17 +394,19 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// now_since_epoch: the current time, as a delta since the unix epoch,
// which is used to validate client nonces.
// rand: an entropy source
+ // params: the state of the handshake. This may be updated with a server
+ // nonce when we send a rejection. After a successful handshake, this will
+ // contain the state of the connection.
// out: the resulting handshake message (either REJ or SHLO)
- // out_params: the state of the handshake
// error_details: used to store a string describing any error.
QuicErrorCode ProcessClientHello(const CryptoHandshakeMessage& client_hello,
QuicGuid guid,
const IPEndPoint& client_ip,
QuicTime::Delta now_since_epoch,
QuicRandom* rand,
+ QuicCryptoNegotiatedParameters* params,
CryptoHandshakeMessage* out,
- QuicCryptoNegotiatedParameters* out_params,
- std::string* error_details);
+ std::string* error_details) const;
private:
friend class test::QuicCryptoServerConfigPeer;
@@ -415,6 +422,9 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
std::string serialized;
// id contains the SCID of this server config.
std::string id;
+ // orbit contains the orbit value for this config: an opaque identifier
+ // used to identify clusters of server frontends.
+ unsigned char orbit[kOrbitSize];
// key_exchanges contains key exchange objects with the private keys
// already loaded. The values correspond, one-to-one, with the tags in
@@ -432,19 +442,24 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// IP address.
std::string NewSourceAddressToken(const IPEndPoint& ip,
QuicRandom* rand,
- QuicTime::Delta now_since_epoch);
+ QuicTime::Delta now_since_epoch) const;
// ValidateSourceAddressToken returns true if the source address token in
// |token| is a valid and timely token for the IP address |ip| given that the
// current time is |now|.
bool ValidateSourceAddressToken(base::StringPiece token,
const IPEndPoint& ip,
- QuicTime::Delta now_since_epoch);
+ QuicTime::Delta now_since_epoch) const;
std::map<ServerConfigID, Config*> configs_;
ServerConfigID active_config_;
+ mutable base::Lock strike_register_lock_;
+ // strike_register_ contains a data structure that keeps track of previously
+ // observed client nonces in order to prevent replay attacks.
+ mutable scoped_ptr<StrikeRegister> strike_register_;
+
// These members are used to encrypt and decrypt the source address tokens
// that we receive from and send to clients.
scoped_ptr<QuicEncrypter> source_address_token_encrypter_;
diff --git a/net/quic/crypto/crypto_handshake_test.cc b/net/quic/crypto/crypto_handshake_test.cc
index 5909cd9..154e364 100644
--- a/net/quic/crypto/crypto_handshake_test.cc
+++ b/net/quic/crypto/crypto_handshake_test.cc
@@ -45,7 +45,7 @@ TEST(QuicCryptoServerConfigTest, ServerConfig) {
CryptoHandshakeMessage extra_tags;
scoped_ptr<CryptoHandshakeMessage>(
- server.AddTestingConfig(QuicRandom::GetInstance(), &clock, extra_tags));
+ server.AddDefaultConfig(QuicRandom::GetInstance(), &clock, extra_tags));
}
TEST(QuicCryptoServerConfigTest, SourceAddressTokens) {
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 0b84a98..f24dcbe 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -57,11 +57,14 @@ const CryptoTag kSNI = MAKE_TAG('S', 'N', 'I', '\0'); // Server name
const CryptoTag kPUBS = MAKE_TAG('P', 'U', 'B', 'S'); // Public key values
const CryptoTag kSCID = MAKE_TAG('S', 'C', 'I', 'D'); // Server config id
const CryptoTag kSRCT = MAKE_TAG('S', 'R', 'C', 'T'); // Source-address token
+const CryptoTag kORBT = MAKE_TAG('O', 'B', 'I', 'T'); // Server orbit.
const size_t kMaxEntries = 16; // Max number of entries in a message.
const size_t kNonceSize = 32; // Size in bytes of the connection nonce.
+const size_t kOrbitSize = 8; // Number of bytes in an orbit value.
+
} // namespace net
#endif // NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
diff --git a/net/quic/crypto/crypto_utils.cc b/net/quic/crypto/crypto_utils.cc
index b6ae58b..6e52898 100644
--- a/net/quic/crypto/crypto_utils.cc
+++ b/net/quic/crypto/crypto_utils.cc
@@ -10,7 +10,7 @@
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_clock.h"
+#include "net/quic/quic_time.h"
using base::StringPiece;
using std::string;
@@ -64,14 +64,13 @@ bool CryptoUtils::FindMutualTag(const CryptoTagVector& our_tags_vector,
return false;
}
-void CryptoUtils::GenerateNonce(const QuicClock* clock,
+void CryptoUtils::GenerateNonce(QuicTime::Delta now,
QuicRandom* random_generator,
- const string& orbit,
+ StringPiece orbit,
string* nonce) {
// a 4-byte timestamp + 28 random bytes.
nonce->reserve(kNonceSize);
nonce->resize(kNonceSize);
- QuicTime::Delta now = clock->NowAsDeltaSinceUnixEpoch();
uint32 gmt_unix_time = now.ToSeconds();
memcpy(&(*nonce)[0], &gmt_unix_time, sizeof(gmt_unix_time));
@@ -85,7 +84,7 @@ void CryptoUtils::GenerateNonce(const QuicClock* clock,
}
void CryptoUtils::DeriveKeys(QuicCryptoNegotiatedParameters* params,
- StringPiece nonce,
+ StringPiece client_nonce,
const string& hkdf_input,
Perspective perspective) {
params->encrypter.reset(QuicEncrypter::Create(params->aead));
@@ -93,6 +92,13 @@ void CryptoUtils::DeriveKeys(QuicCryptoNegotiatedParameters* params,
size_t key_bytes = params->encrypter->GetKeySize();
size_t nonce_prefix_bytes = params->encrypter->GetNoncePrefixSize();
+ StringPiece nonce = client_nonce;
+ string nonce_storage;
+ if (!params->server_nonce.empty()) {
+ nonce_storage = client_nonce.as_string() + params->server_nonce;
+ nonce = nonce_storage;
+ }
+
crypto::HKDF hkdf(params->premaster_secret, nonce,
hkdf_input, key_bytes, nonce_prefix_bytes);
if (perspective == SERVER) {
diff --git a/net/quic/crypto/crypto_utils.h b/net/quic/crypto/crypto_utils.h
index 442830b..4ad4149 100644
--- a/net/quic/crypto/crypto_utils.h
+++ b/net/quic/crypto/crypto_utils.h
@@ -16,7 +16,7 @@
namespace net {
-class QuicClock;
+class QuicTime;
class QuicRandom;
struct QuicCryptoNegotiatedParameters;
@@ -51,17 +51,19 @@ class NET_EXPORT_PRIVATE CryptoUtils {
// <4 bytes> current time
// <8 bytes> |orbit| (or random if |orbit| is empty)
// <20 bytes> random
- static void GenerateNonce(const QuicClock* clock,
+ static void GenerateNonce(QuicTime::Delta now,
QuicRandom* random_generator,
- const std::string& orbit,
+ base::StringPiece orbit,
std::string* nonce);
- // DeriveKeys populates the |encrypter| and |decrypter| members of |params|
- // given the contents of |premaster_secret|, |nonce| and |hkdf_input|.
- // |perspective| controls whether the server's keys are assigned to
- // |encrypter| or |decrypter|.
+ // DeriveKeys populates |params->encrypter| and |params->decrypter| given the
+ // contents of |params->premaster_secret|, |client_nonce|,
+ // |params->server_nonce| and |hkdf_input|. |perspective| controls whether
+ // the server's keys are assigned to |encrypter| or |decrypter|.
+ // |params->server_nonce| is optional and, if non-empty, is mixed into the
+ // key derivation.
static void DeriveKeys(QuicCryptoNegotiatedParameters* params,
- base::StringPiece nonce,
+ base::StringPiece client_nonce,
const std::string& hkdf_input,
Perspective perspective);
};
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 7bd4078..5e1e80f 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -23,14 +23,10 @@ QuicClientSession::QuicClientSession(
QuicStreamFactory* stream_factory,
QuicCryptoClientStreamFactory* crypto_client_stream_factory,
const string& server_hostname,
+ QuicCryptoClientConfig* crypto_config,
NetLog* net_log)
: QuicSession(connection, false),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
- ALLOW_THIS_IN_INITIALIZER_LIST(crypto_stream_(
- crypto_client_stream_factory ?
- crypto_client_stream_factory->CreateQuicCryptoClientStream(
- this, server_hostname) :
- new QuicCryptoClientStream(this, server_hostname))),
stream_factory_(stream_factory),
socket_(socket),
read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
@@ -38,6 +34,14 @@ QuicClientSession::QuicClientSession(
num_total_streams_(0),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
logger_(net_log_) {
+ config_.SetDefaults();
+ crypto_stream_.reset(
+ crypto_client_stream_factory ?
+ crypto_client_stream_factory->CreateQuicCryptoClientStream(
+ server_hostname, config_, this, crypto_config) :
+ new QuicCryptoClientStream(
+ server_hostname, config_, this, crypto_config));
+
connection->set_debug_visitor(&logger_);
// TODO(rch): pass in full host port proxy pair
net_log_.BeginEvent(
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index cdda311..2bf6e78 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -36,6 +36,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicSession {
QuicStreamFactory* stream_factory,
QuicCryptoClientStreamFactory* crypto_client_stream_factory,
const std::string& server_hostname,
+ QuicCryptoClientConfig* crypto_config,
NetLog* net_log);
virtual ~QuicClientSession();
@@ -70,6 +71,9 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicSession {
void OnReadComplete(int result);
base::WeakPtrFactory<QuicClientSession> weak_factory_;
+ // config_ contains non-crypto configuration options negotiated in the crypto
+ // handshake.
+ QuicConfig config_;
scoped_ptr<QuicCryptoClientStream> crypto_stream_;
QuicStreamFactory* stream_factory_;
scoped_ptr<DatagramClientSocket> socket_;
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 1ca0080..6d26541 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -30,7 +30,9 @@ class QuicClientSessionTest : public ::testing::Test {
QuicClientSessionTest()
: guid_(1),
connection_(new PacketSavingConnection(guid_, IPEndPoint(), false)),
- session_(connection_, NULL, NULL, NULL, kServerHostname, &net_log_) {
+ session_(connection_, NULL, NULL, NULL, kServerHostname,
+ &crypto_config_, &net_log_) {
+ crypto_config_.SetDefaults();
}
void CompleteCryptoHandshake() {
@@ -49,6 +51,8 @@ class QuicClientSessionTest : public ::testing::Test {
MockRandom random_;
QuicConnectionVisitorInterface* visitor_;
TestCompletionCallback callback_;
+ QuicConfig* config_;
+ QuicCryptoClientConfig crypto_config_;
};
TEST_F(QuicClientSessionTest, CryptoConnect) {
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc
new file mode 100644
index 0000000..f16f06f
--- /dev/null
+++ b/net/quic/quic_config.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_config.h"
+
+using std::string;
+
+namespace net {
+
+QuicNegotiatedParameters::QuicNegotiatedParameters()
+ : idle_connection_state_lifetime(QuicTime::Delta::Zero()),
+ keepalive_timeout(QuicTime::Delta::Zero()) {
+}
+
+QuicConfig::QuicConfig()
+ : idle_connection_state_lifetime_(QuicTime::Delta::Zero()),
+ keepalive_timeout_(QuicTime::Delta::Zero()) {
+}
+
+QuicConfig::~QuicConfig() {
+}
+
+void QuicConfig::SetDefaults() {
+ idle_connection_state_lifetime_ = QuicTime::Delta::FromSeconds(300);
+ keepalive_timeout_ = QuicTime::Delta::Zero();
+ congestion_control_.clear();
+ congestion_control_.push_back(kQBIC);
+}
+
+bool QuicConfig::SetFromHandshakeMessage(const CryptoHandshakeMessage& scfg) {
+ const CryptoTag* cgst;
+ size_t num_cgst;
+ QuicErrorCode error;
+
+ error = scfg.GetTaglist(kCGST, &cgst, &num_cgst);
+ if (error != QUIC_NO_ERROR) {
+ return false;
+ }
+
+ congestion_control_.assign(cgst, cgst + num_cgst);
+
+ uint32 idle;
+ error = scfg.GetUint32(kICSL, &idle);
+ if (error != QUIC_NO_ERROR) {
+ return false;
+ }
+ idle_connection_state_lifetime_ = QuicTime::Delta::FromSeconds(idle);
+
+ keepalive_timeout_ = QuicTime::Delta::Zero();
+
+ uint32 keepalive;
+ error = scfg.GetUint32(kKATO, &keepalive);
+ // KATO is optional.
+ if (error == QUIC_NO_ERROR) {
+ keepalive_timeout_ = QuicTime::Delta::FromSeconds(keepalive);
+ }
+
+ return true;
+}
+
+void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+ out->SetValue(
+ kICSL, static_cast<uint32>(idle_connection_state_lifetime_.ToSeconds()));
+ out->SetValue(kKATO, static_cast<uint32>(keepalive_timeout_.ToSeconds()));
+ out->SetVector(kCGST, congestion_control_);
+}
+
+QuicErrorCode QuicConfig::ProcessFinalPeerHandshake(
+ const CryptoHandshakeMessage& msg,
+ CryptoUtils::Priority priority,
+ QuicNegotiatedParameters* out_params,
+ string* error_details) const {
+ const CryptoTag* their_congestion_controls;
+ size_t num_their_congestion_controls;
+ QuicErrorCode error;
+
+ error = msg.GetTaglist(kCGST, &their_congestion_controls,
+ &num_their_congestion_controls);
+ if (error != QUIC_NO_ERROR) {
+ if (error_details) {
+ *error_details = "Missing CGST";
+ }
+ return error;
+ }
+
+ if (!CryptoUtils::FindMutualTag(congestion_control_,
+ their_congestion_controls,
+ num_their_congestion_controls,
+ priority,
+ &out_params->congestion_control,
+ NULL)) {
+ if (error_details) {
+ *error_details = "Unsuported CGST";
+ }
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP;
+ }
+
+ uint32 idle;
+ error = msg.GetUint32(kICSL, &idle);
+ if (error != QUIC_NO_ERROR) {
+ if (error_details) {
+ *error_details = "Missing ICSL";
+ }
+ return error;
+ }
+
+ out_params->idle_connection_state_lifetime = QuicTime::Delta::FromSeconds(
+ std::min(static_cast<uint32>(idle_connection_state_lifetime_.ToSeconds()),
+ idle));
+
+ uint32 keepalive;
+ error = msg.GetUint32(kKATO, &keepalive);
+ switch (error) {
+ case QUIC_NO_ERROR:
+ out_params->keepalive_timeout = QuicTime::Delta::FromSeconds(
+ std::min(static_cast<uint32>(keepalive_timeout_.ToSeconds()),
+ keepalive));
+ break;
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ // KATO is optional.
+ out_params->keepalive_timeout = QuicTime::Delta::Zero();
+ break;
+ default:
+ if (error_details) {
+ *error_details = "Bad KATO";
+ }
+ return error;
+ }
+
+ return QUIC_NO_ERROR;
+}
+
+} // namespace net
+
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h
new file mode 100644
index 0000000..17441d7
--- /dev/null
+++ b/net/quic/quic_config.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_CONFIG_H_
+#define NET_QUIC_QUIC_CONFIG_H_
+
+#include <string>
+
+#include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/crypto/crypto_utils.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+// QuicNegotiatedParameters contains non-crypto parameters that are agreed upon
+// during the crypto handshake.
+class NET_EXPORT_PRIVATE QuicNegotiatedParameters {
+ public:
+ QuicNegotiatedParameters();
+
+ CryptoTag congestion_control;
+ QuicTime::Delta idle_connection_state_lifetime;
+ QuicTime::Delta keepalive_timeout;
+};
+
+// QuicConfig contains non-crypto configuration options that are negotiated in
+// the crypto handshake.
+class NET_EXPORT_PRIVATE QuicConfig {
+ public:
+ QuicConfig();
+ ~QuicConfig();
+
+ // SetDefaults sets the members to sensible, default values.
+ void SetDefaults();
+
+ // SetFromMessage extracts the non-crypto configuration from |msg| and sets
+ // the members of this object to match. This is expected to be called in the
+ // case of a server which is loading a server config. The server config
+ // contains the non-crypto parameters and so the server will need to keep its
+ // QuicConfig in sync with the server config that it'll be sending to
+ // clients.
+ bool SetFromHandshakeMessage(const CryptoHandshakeMessage& scfg);
+
+ // ToHandshakeMessage serializes the settings in this object as a series of
+ // tags /value pairs and adds them to |out|.
+ void ToHandshakeMessage(CryptoHandshakeMessage* out) const;
+
+ QuicErrorCode ProcessFinalPeerHandshake(
+ const CryptoHandshakeMessage& peer_handshake,
+ CryptoUtils::Priority priority,
+ QuicNegotiatedParameters* out_params,
+ std::string* error_details) const;
+
+ private:
+ // Congestion control feedback type.
+ CryptoTagVector congestion_control_;
+ // Idle connection state lifetime
+ QuicTime::Delta idle_connection_state_lifetime_;
+ // Keepalive timeout, or 0 to turn off keepalive probes
+ QuicTime::Delta keepalive_timeout_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CONFIG_H_
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 6449ee1..efb3e96 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -1162,7 +1162,8 @@ void QuicConnection::SendConnectionClose(QuicErrorCode error) {
void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
const string& details) {
DLOG(INFO) << ENDPOINT << "Force closing with error "
- << QuicUtils::ErrorToString(error) << " (" << error << ")";
+ << QuicUtils::ErrorToString(error) << " (" << error << ") "
+ << details;
QuicConnectionCloseFrame frame;
frame.error_code = error;
frame.error_details = details;
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 63a4f44..aa43b6d 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
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index fb67ee4..2ad122c 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -8,10 +8,12 @@
#include <string>
#include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/quic_config.h"
#include "net/quic/quic_crypto_stream.h"
namespace net {
+class QuicConfig;
class QuicSession;
namespace test {
@@ -20,7 +22,10 @@ class CryptoTestUtils;
class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
public:
- QuicCryptoClientStream(QuicSession* session, const string& server_hostname);
+ QuicCryptoClientStream(const string& server_hostname,
+ const QuicConfig& config,
+ QuicSession* session,
+ QuicCryptoClientConfig* crypto_config);
virtual ~QuicCryptoClientStream();
// CryptoFramerVisitorInterface implementation
@@ -50,13 +55,20 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
void DoHandshakeLoop(const CryptoHandshakeMessage* in);
State next_state_;
+ // num_client_hellos_ contains the number of client hello messages that this
+ // connection has sent.
+ int num_client_hellos_;
- QuicConfig config_;
- QuicCryptoClientConfig crypto_config_;
+ const QuicConfig& config_;
+ QuicCryptoClientConfig* const crypto_config_;
QuicNegotiatedParameters negotiated_params_;
QuicCryptoNegotiatedParameters crypto_negotiated_params_;
+ // decrypter_pushed_ is true if we have installed a QuicDecrypter in the
+ // connection. We need to track this because, in the event of a handshake
+ // failure, we have to remove any previous decrypters as they will have the
+ // wrong keys.
bool decrypter_pushed_;
// Client's connection nonce (4-byte timestamp + 28 random bytes)
diff --git a/net/quic/quic_crypto_client_stream_factory.h b/net/quic/quic_crypto_client_stream_factory.h
index abfcbb4..4d0eb1e 100644
--- a/net/quic/quic_crypto_client_stream_factory.h
+++ b/net/quic/quic_crypto_client_stream_factory.h
@@ -21,7 +21,10 @@ class NET_EXPORT QuicCryptoClientStreamFactory {
virtual ~QuicCryptoClientStreamFactory() {}
virtual QuicCryptoClientStream* CreateQuicCryptoClientStream(
- QuicSession* session, const std::string& server_hostname) = 0;
+ const string& server_hostname,
+ const QuicConfig& config,
+ QuicSession* session,
+ QuicCryptoClientConfig* crypto_config) = 0;
};
} // namespace net
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 251a8ef..d8d2392 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -66,7 +66,9 @@ class QuicCryptoClientStreamTest : public ::testing::Test {
: addr_(),
connection_(new PacketSavingConnection(1, addr_, true)),
session_(connection_, true),
- stream_(&session_, kServerHostname) {
+ stream_(kServerHostname, config_, &session_, &crypto_config_) {
+ config_.SetDefaults();
+ crypto_config_.SetDefaults();
}
void CompleteCryptoHandshake() {
@@ -85,6 +87,8 @@ class QuicCryptoClientStreamTest : public ::testing::Test {
QuicCryptoClientStream stream_;
CryptoHandshakeMessage message_;
scoped_ptr<QuicData> message_data_;
+ QuicConfig config_;
+ QuicCryptoClientConfig crypto_config_;
};
TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index d1c21ff..a0104e4 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -6,37 +6,19 @@
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_utils.h"
+#include "net/quic/quic_config.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_session.h"
namespace net {
-QuicCryptoServerStream::QuicCryptoServerStream(QuicSession* session)
+QuicCryptoServerStream::QuicCryptoServerStream(
+ const QuicConfig& config,
+ const QuicCryptoServerConfig& crypto_config,
+ QuicSession* session)
: QuicCryptoStream(session),
- // TODO(agl): use real secret.
- crypto_config_("secret") {
- config_.SetDefaults();
- // Use hardcoded crypto parameters for now.
- CryptoHandshakeMessage extra_tags;
- config_.ToHandshakeMessage(&extra_tags);
-
- // TODO(agl): AddTestingConfig generates a new, random config. In the future
- // this will be replaced with a real source of configs.
- scoped_ptr<CryptoHandshakeMessage> scfg(
- crypto_config_.AddTestingConfig(session->connection()->random_generator(),
- session->connection()->clock(),
- extra_tags));
- // If we were using the same config in many servers then we would have to
- // parse a QuicConfig from config_tags here.
-
- // Our non-crypto configuration is also expressed in the SCFG because it's
- // signed. Thus |config_| needs to be consistent with that.
- if (!config_.SetFromHandshakeMessage(*scfg)) {
- // TODO(agl): when we aren't generating testing configs then this can be a
- // CHECK at startup time.
- LOG(WARNING) << "SCFG could not be parsed by QuicConfig.";
- DCHECK(false);
- }
+ config_(config),
+ crypto_config_(crypto_config) {
}
QuicCryptoServerStream::~QuicCryptoServerStream() {
@@ -62,7 +44,7 @@ void QuicCryptoServerStream::OnHandshakeMessage(
session()->connection()->peer_address(),
session()->connection()->clock()->NowAsDeltaSinceUnixEpoch(),
session()->connection()->random_generator(),
- &reply, &crypto_negotiated_params_, &error_details);
+ &crypto_negotiated_params_, &reply, &error_details);
if (reply.tag() == kSHLO) {
// If we are returning a SHLO then we accepted the handshake.
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index 7841172..3e4264a 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -8,10 +8,14 @@
#include <string>
#include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/quic_config.h"
#include "net/quic/quic_crypto_stream.h"
namespace net {
+class CryptoHandshakeMessage;
+class QuicCryptoServerConfig;
+class QuicNegotiatedParameters;
class QuicSession;
namespace test {
@@ -20,6 +24,9 @@ class CryptoTestUtils;
class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
public:
+ QuicCryptoServerStream(const QuicConfig& config,
+ const QuicCryptoServerConfig& crypto_config,
+ QuicSession* session);
explicit QuicCryptoServerStream(QuicSession* session);
virtual ~QuicCryptoServerStream();
@@ -35,10 +42,9 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
// config_ contains non-crypto parameters that are negotiated in the crypto
// handshake.
- QuicConfig config_;
+ const QuicConfig& config_;
// crypto_config_ contains crypto parameters for the handshake.
- QuicCryptoServerConfig crypto_config_;
- std::string server_nonce_;
+ const QuicCryptoServerConfig& crypto_config_;
QuicNegotiatedParameters negotiated_params_;
QuicCryptoNegotiatedParameters crypto_negotiated_params_;
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 173122d8..b567f85 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -71,7 +71,11 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
ip_ : IPAddressNumber(), 1),
connection_(new PacketSavingConnection(guid_, addr_, true)),
session_(connection_, true),
- stream_(&session_) {
+ crypto_config_(QuicCryptoServerConfig::TESTING),
+ stream_(config_, crypto_config_, &session_) {
+ CryptoTestUtils::SetupCryptoServerConfigForTest(
+ connection_->clock(), connection_->random_generator(), &config_,
+ &crypto_config_);
}
void ConstructHandshakeMessage() {
@@ -89,6 +93,8 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
IPEndPoint addr_;
PacketSavingConnection* connection_;
TestSession session_;
+ QuicConfig config_;
+ QuicCryptoServerConfig crypto_config_;
QuicCryptoServerStream stream_;
CryptoHandshakeMessage message_;
scoped_ptr<QuicData> message_data_;
diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc
index f033af8..9167e6f 100644
--- a/net/quic/quic_crypto_stream.cc
+++ b/net/quic/quic_crypto_stream.cc
@@ -61,128 +61,4 @@ void QuicCryptoStream::SendHandshakeMessage(
WriteData(string(data.data(), data.length()), false);
}
-QuicNegotiatedParameters::QuicNegotiatedParameters()
- : idle_connection_state_lifetime(QuicTime::Delta::Zero()),
- keepalive_timeout(QuicTime::Delta::Zero()) {
-}
-
-QuicConfig::QuicConfig()
- : idle_connection_state_lifetime_(QuicTime::Delta::Zero()),
- keepalive_timeout_(QuicTime::Delta::Zero()) {
-}
-
-QuicConfig::~QuicConfig() {
-}
-
-void QuicConfig::SetDefaults() {
- idle_connection_state_lifetime_ = QuicTime::Delta::FromSeconds(300);
- keepalive_timeout_ = QuicTime::Delta::Zero();
- congestion_control_.clear();
- congestion_control_.push_back(kQBIC);
-}
-
-bool QuicConfig::SetFromHandshakeMessage(const CryptoHandshakeMessage& scfg) {
- const CryptoTag* cgst;
- size_t num_cgst;
- QuicErrorCode error;
-
- error = scfg.GetTaglist(kCGST, &cgst, &num_cgst);
- if (error != QUIC_NO_ERROR) {
- return false;
- }
-
- congestion_control_.assign(cgst, cgst + num_cgst);
-
- uint32 idle;
- error = scfg.GetUint32(kICSL, &idle);
- if (error != QUIC_NO_ERROR) {
- return false;
- }
-
- idle_connection_state_lifetime_ = QuicTime::Delta::FromSeconds(idle);
-
- keepalive_timeout_ = QuicTime::Delta::Zero();
-
- uint32 keepalive;
- error = scfg.GetUint32(kKATO, &keepalive);
- // KATO is optional.
- if (error == QUIC_NO_ERROR) {
- keepalive_timeout_ = QuicTime::Delta::FromSeconds(keepalive);
- }
-
- return true;
-}
-
-void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
- out->SetValue(
- kICSL, static_cast<uint32>(idle_connection_state_lifetime_.ToSeconds()));
- out->SetValue(kKATO, static_cast<uint32>(keepalive_timeout_.ToSeconds()));
- out->SetVector(kCGST, congestion_control_);
-}
-
-QuicErrorCode QuicConfig::ProcessFinalPeerHandshake(
- const CryptoHandshakeMessage& msg,
- CryptoUtils::Priority priority,
- QuicNegotiatedParameters* out_params,
- string* error_details) const {
- const CryptoTag* their_congestion_controls;
- size_t num_their_congestion_controls;
- QuicErrorCode error;
-
- error = msg.GetTaglist(kCGST, &their_congestion_controls,
- &num_their_congestion_controls);
- if (error != QUIC_NO_ERROR) {
- if (error_details) {
- *error_details = "Missing CGST";
- }
- return error;
- }
-
- if (!CryptoUtils::FindMutualTag(congestion_control_,
- their_congestion_controls,
- num_their_congestion_controls,
- priority,
- &out_params->congestion_control,
- NULL)) {
- if (error_details) {
- *error_details = "Unsuported CGST";
- }
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP;
- }
-
- uint32 idle;
- error = msg.GetUint32(kICSL, &idle);
- if (error != QUIC_NO_ERROR) {
- if (error_details) {
- *error_details = "Missing ICSL";
- }
- return error;
- }
-
- out_params->idle_connection_state_lifetime = QuicTime::Delta::FromSeconds(
- std::min(static_cast<uint32>(idle_connection_state_lifetime_.ToSeconds()),
- idle));
-
- uint32 keepalive;
- error = msg.GetUint32(kKATO, &keepalive);
- switch (error) {
- case QUIC_NO_ERROR:
- out_params->keepalive_timeout = QuicTime::Delta::FromSeconds(
- std::min(static_cast<uint32>(keepalive_timeout_.ToSeconds()),
- keepalive));
- break;
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- // KATO is optional.
- out_params->keepalive_timeout = QuicTime::Delta::Zero();
- break;
- default:
- if (error_details) {
- *error_details = "Bad KATO";
- }
- return error;
- }
-
- return QUIC_NO_ERROR;
-}
-
} // namespace net
diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h
index 43667c0..b43cb38 100644
--- a/net/quic/quic_crypto_stream.h
+++ b/net/quic/quic_crypto_stream.h
@@ -58,54 +58,6 @@ class NET_EXPORT_PRIVATE QuicCryptoStream
DISALLOW_COPY_AND_ASSIGN(QuicCryptoStream);
};
-// QuicNegotiatedParameters contains non-crypto parameters that are agreed upon
-// during the crypto handshake.
-class NET_EXPORT_PRIVATE QuicNegotiatedParameters {
- public:
- QuicNegotiatedParameters();
-
- CryptoTag congestion_control;
- QuicTime::Delta idle_connection_state_lifetime;
- QuicTime::Delta keepalive_timeout;
-};
-
-// QuicConfig contains non-crypto configuration options that are negotiated in
-// the crypto handshake.
-class NET_EXPORT_PRIVATE QuicConfig {
- public:
- QuicConfig();
- ~QuicConfig();
-
- // SetDefaults sets the members to sensible, default values.
- void SetDefaults();
-
- // SetFromMessage extracts the non-crypto configuration from |msg| and sets
- // the members of this object to match. This is expected to be called in the
- // case of a server which is loading a server config. The server config
- // contains the non-crypto parameters and so the server will need to keep its
- // QuicConfig in sync with the server config that it'll be sending to
- // clients.
- bool SetFromHandshakeMessage(const CryptoHandshakeMessage& scfg);
-
- // ToHandshakeMessage serializes the settings in this object as a series of
- // tags /value pairs and adds them to |out|.
- void ToHandshakeMessage(CryptoHandshakeMessage* out) const;
-
- QuicErrorCode ProcessFinalPeerHandshake(
- const CryptoHandshakeMessage& peer_handshake,
- CryptoUtils::Priority priority,
- QuicNegotiatedParameters* out_params,
- string* error_details) const;
-
- private:
- // Congestion control feedback type.
- CryptoTagVector congestion_control_;
- // Idle connection state lifetime
- QuicTime::Delta idle_connection_state_lifetime_;
- // Keepalive timeout, or 0 to turn off keepalive probes
- QuicTime::Delta keepalive_timeout_;
-};
-
} // namespace net
#endif // NET_QUIC_QUIC_CRYPTO_STREAM_H_
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 1370ced..e5bcdcc 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -180,9 +180,11 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
connection_->set_visitor(&visitor_);
connection_->SetSendAlgorithm(send_algorithm_);
connection_->SetReceiveAlgorithm(receive_algorithm_);
+ crypto_config_.SetDefaults();
session_.reset(new QuicClientSession(connection_, socket, NULL,
&crypto_client_stream_factory_,
- "www.google.com", NULL));
+ "www.google.com", &crypto_config_,
+ NULL));
session_->GetCryptoStream()->CryptoConnect();
EXPECT_TRUE(session_->IsCryptoHandshakeComplete());
QuicReliableClientStream* stream =
@@ -267,6 +269,8 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
testing::StrictMock<MockConnectionVisitor> visitor_;
scoped_ptr<QuicHttpStream> stream_;
scoped_ptr<QuicClientSession> session_;
+ QuicConfig* config_;
+ QuicCryptoClientConfig crypto_config_;
TestCompletionCallback callback_;
HttpRequestInfo request_;
HttpRequestHeaders headers_;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 48e647f..b3f11cb 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -220,6 +220,8 @@ enum QuicErrorCode {
// There was no intersection between the crypto primitives supported by the
// peer and ourselves.
QUIC_CRYPTO_NO_SUPPORT,
+ // The server rejected our client hello messages too many times.
+ QUIC_CRYPTO_TOO_MANY_REJECTS,
// No error. Used as bound while iterating.
QUIC_LAST_ERROR,
diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc
index b5f57e5..2517bac 100644
--- a/net/quic/quic_reliable_client_stream_test.cc
+++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -42,6 +42,8 @@ class QuicReliableClientStreamTest : public ::testing::Test {
testing::StrictMock<MockDelegate> delegate_;
MockSession session_;
QuicReliableClientStream stream_;
+ QuicConfig config_;
+ QuicCryptoClientConfig crypto_config_;
};
TEST_F(QuicReliableClientStreamTest, TerminateFromPeer) {
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 4bb6449..fe25c50 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -198,8 +198,8 @@ scoped_ptr<QuicHttpStream> QuicStreamRequest::ReleaseStream() {
int QuicStreamFactory::Job::DoConnect() {
io_state_ = STATE_CONNECT_COMPLETE;
- session_ = factory_->CreateSession(host_port_proxy_pair_.first.host(),
- address_list_, net_log_);
+ session_ = factory_->CreateSession(host_port_proxy_pair_, address_list_,
+ net_log_);
session_->StartReading();
int rv = session_->CryptoConnect(
base::Bind(&QuicStreamFactory::Job::OnIOComplete,
@@ -360,7 +360,7 @@ bool QuicStreamFactory::HasActiveSession(
}
QuicClientSession* QuicStreamFactory::CreateSession(
- const std::string& host,
+ const HostPortProxyPair& host_port_proxy_pair,
const AddressList& address_list,
const BoundNetLog& net_log) {
QuicGuid guid = random_generator_->RandUint64();
@@ -377,10 +377,16 @@ QuicClientSession* QuicStreamFactory::CreateSession(
clock_.get(), random_generator_, socket);
QuicConnection* connection = new QuicConnection(guid, addr, helper, false);
+
+ QuicCryptoClientConfig* crypto_config =
+ GetOrCreateCryptoConfig(host_port_proxy_pair);
+ DCHECK(crypto_config);
+
QuicClientSession* session =
new QuicClientSession(connection, socket, this,
- quic_crypto_client_stream_factory_, host,
- net_log.net_log());
+ quic_crypto_client_stream_factory_,
+ host_port_proxy_pair.first.host(),
+ crypto_config, net_log.net_log());
all_sessions_.insert(session); // owning pointer
return session;
}
@@ -398,5 +404,18 @@ void QuicStreamFactory::ActivateSession(
session_aliases_[session].insert(host_port_proxy_pair);
}
+QuicCryptoClientConfig* QuicStreamFactory::GetOrCreateCryptoConfig(
+ const HostPortProxyPair& host_port_proxy_pair) {
+ QuicCryptoClientConfig* crypto_config;
+ if (ContainsKey(all_crypto_configs_, host_port_proxy_pair)) {
+ crypto_config = all_crypto_configs_[host_port_proxy_pair];
+ DCHECK(crypto_config);
+ } else {
+ crypto_config = new QuicCryptoClientConfig();
+ crypto_config->SetDefaults();
+ all_crypto_configs_[host_port_proxy_pair] = crypto_config;
+ }
+ return crypto_config;
+}
} // namespace net
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 48f4da0..629b835 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -14,6 +14,8 @@
#include "net/base/host_port_pair.h"
#include "net/base/net_log.h"
#include "net/proxy/proxy_server.h"
+#include "net/quic/quic_config.h"
+#include "net/quic/quic_crypto_stream.h"
#include "net/quic/quic_http_stream.h"
#include "net/quic/quic_protocol.h"
@@ -106,6 +108,7 @@ class NET_EXPORT_PRIVATE QuicStreamFactory {
typedef std::set<HostPortProxyPair> AliasSet;
typedef std::map<QuicClientSession*, AliasSet> SessionAliasMap;
typedef std::set<QuicClientSession*> SessionSet;
+ typedef std::map<HostPortProxyPair, QuicCryptoClientConfig*> CryptoConfigMap;
typedef std::map<HostPortProxyPair, Job*> JobMap;
typedef std::map<QuicStreamRequest*, Job*> RequestMap;
typedef std::set<QuicStreamRequest*> RequestSet;
@@ -114,12 +117,16 @@ class NET_EXPORT_PRIVATE QuicStreamFactory {
void OnJobComplete(Job* job, int rv);
bool HasActiveSession(const HostPortProxyPair& host_port_proxy_pair);
bool HasActiveJob(const HostPortProxyPair& host_port_proxy_pair);
- QuicClientSession* CreateSession(const std::string& host,
- const AddressList& address_list,
- const BoundNetLog& net_log);
+ QuicClientSession* CreateSession(
+ const HostPortProxyPair& host_port_proxy_pair,
+ const AddressList& address_list,
+ const BoundNetLog& net_log);
void ActivateSession(const HostPortProxyPair& host_port_proxy_pair,
QuicClientSession* session);
+ QuicCryptoClientConfig* GetOrCreateCryptoConfig(
+ const HostPortProxyPair& host_port_proxy_pair);
+
HostResolver* host_resolver_;
ClientSocketFactory* client_socket_factory_;
QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory_;
@@ -133,6 +140,12 @@ class NET_EXPORT_PRIVATE QuicStreamFactory {
SessionMap active_sessions_;
SessionAliasMap session_aliases_;
+ // Contains owning pointers to QuicCryptoClientConfig. QuicCryptoClientConfig
+ // contains configuration and cached state about servers.
+ // TODO(rtenneti): Persist all_crypto_configs_ to disk and decide when to
+ // clear the data in the map.
+ CryptoConfigMap all_crypto_configs_;
+
JobMap active_jobs_;
JobRequestsMap job_requests_map_;
RequestMap active_requests_;
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 616e809..ac46977 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -73,6 +73,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_PEER_GOING_AWAY);
RETURN_STRING_LITERAL(QUIC_CRYPTO_TAGS_OUT_OF_ORDER);
RETURN_STRING_LITERAL(QUIC_CRYPTO_TOO_MANY_ENTRIES);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_TOO_MANY_REJECTS);
RETURN_STRING_LITERAL(QUIC_CRYPTO_INVALID_VALUE_LENGTH)
RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
RETURN_STRING_LITERAL(QUIC_CRYPTO_INTERNAL_ERROR);
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 5086044..c2d5988 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -5,8 +5,11 @@
#include "net/quic/test_tools/crypto_test_utils.h"
#include "base/strings/string_piece.h"
+#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/crypto/quic_random.h"
+#include "net/quic/quic_clock.h"
#include "net/quic/quic_crypto_client_stream.h"
#include "net/quic/quic_crypto_server_stream.h"
#include "net/quic/quic_crypto_stream.h"
@@ -75,7 +78,15 @@ void CryptoTestUtils::HandshakeWithFakeServer(
PacketSavingConnection* server_conn =
new PacketSavingConnection(guid, addr, true);
TestSession server_session(server_conn, true);
- QuicCryptoServerStream server(&server_session);
+
+ QuicConfig config;
+ QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING);
+ SetupCryptoServerConfigForTest(
+ server_session.connection()->clock(),
+ server_session.connection()->random_generator(),
+ &config, &crypto_config);
+
+ QuicCryptoServerStream server(config, crypto_config, &server_session);
// The client's handshake must have been started already.
CHECK_NE(0u, client_conn->packets_.size());
@@ -96,7 +107,13 @@ void CryptoTestUtils::HandshakeWithFakeClient(
PacketSavingConnection* client_conn =
new PacketSavingConnection(guid, addr, false);
TestSession client_session(client_conn, true);
- QuicCryptoClientStream client(&client_session, "test.example.com");
+ QuicConfig config;
+ QuicCryptoClientConfig crypto_config;
+
+ config.SetDefaults();
+ crypto_config.SetDefaults();
+ QuicCryptoClientStream client("test.example.com", config, &client_session,
+ &crypto_config);
CHECK(client.CryptoConnect());
CHECK_EQ(1u, client_conn->packets_.size());
@@ -107,6 +124,23 @@ void CryptoTestUtils::HandshakeWithFakeClient(
}
// static
+void CryptoTestUtils::SetupCryptoServerConfigForTest(
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicConfig* config,
+ QuicCryptoServerConfig* crypto_config) {
+ config->SetDefaults();
+ CryptoHandshakeMessage extra_tags;
+ config->ToHandshakeMessage(&extra_tags);
+
+ scoped_ptr<CryptoHandshakeMessage> scfg(
+ crypto_config->AddDefaultConfig(rand, clock, extra_tags));
+ if (!config->SetFromHandshakeMessage(*scfg)) {
+ CHECK(false) << "Crypto config could not be parsed by QuicConfig.";
+ }
+}
+
+// static
string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message,
CryptoTag tag) {
CryptoTagValueMap::const_iterator it = message.tag_value_map().find(tag);
diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h
index 5ece1db..73ff480 100644
--- a/net/quic/test_tools/crypto_test_utils.h
+++ b/net/quic/test_tools/crypto_test_utils.h
@@ -14,8 +14,12 @@
namespace net {
+class QuicClock;
+class QuicConfig;
class QuicCryptoClientStream;
+class QuicCryptoServerConfig;
class QuicCryptoServerStream;
+class QuicRandom;
namespace test {
@@ -29,6 +33,14 @@ class CryptoTestUtils {
static void HandshakeWithFakeClient(PacketSavingConnection* server_conn,
QuicCryptoServerStream* server);
+ // SetupCryptoServerConfigForTest configures |config| and |crypto_config|
+ // with sensible defaults for testing.
+ static void SetupCryptoServerConfigForTest(
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicConfig* config,
+ QuicCryptoServerConfig* crypto_config);
+
// Returns the value for the tag |tag| in the tag value map of |message|.
static std::string GetValueForTag(const CryptoHandshakeMessage& message,
CryptoTag tag);
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc
index 5f2d06b..c63d0f0 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -6,9 +6,12 @@
namespace net {
-MockCryptoClientStream::MockCryptoClientStream(QuicSession* session,
- const string& server_hostname)
- : QuicCryptoClientStream(session, server_hostname) {
+MockCryptoClientStream::MockCryptoClientStream(
+ const string& server_hostname,
+ const QuicConfig& config,
+ QuicSession* session,
+ QuicCryptoClientConfig* crypto_config)
+ : QuicCryptoClientStream(server_hostname, config, session, crypto_config) {
}
MockCryptoClientStream::~MockCryptoClientStream() {
diff --git a/net/quic/test_tools/mock_crypto_client_stream.h b/net/quic/test_tools/mock_crypto_client_stream.h
index a115e15..2d9fdc3 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.h
+++ b/net/quic/test_tools/mock_crypto_client_stream.h
@@ -15,8 +15,10 @@ namespace net {
class MockCryptoClientStream : public QuicCryptoClientStream {
public:
- MockCryptoClientStream(QuicSession* session,
- const std::string& server_hostname);
+ MockCryptoClientStream(const string& server_hostname,
+ const QuicConfig& config,
+ QuicSession* session,
+ QuicCryptoClientConfig* crypto_config);
virtual ~MockCryptoClientStream();
// CryptoFramerVisitorInterface implementation.
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.cc b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
index 153ddd4..f774328 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
@@ -14,9 +14,12 @@ namespace net {
QuicCryptoClientStream*
MockCryptoClientStreamFactory::CreateQuicCryptoClientStream(
+ const string& server_hostname,
+ const QuicConfig& config,
QuicSession* session,
- const string& server_hostname) {
- return new MockCryptoClientStream(session, server_hostname);
+ QuicCryptoClientConfig* crypto_config) {
+ return new MockCryptoClientStream(server_hostname, config, session,
+ crypto_config);
}
} // namespace net
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.h b/net/quic/test_tools/mock_crypto_client_stream_factory.h
index 1ed81f5..445e766 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.h
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.h
@@ -18,7 +18,10 @@ class MockCryptoClientStreamFactory : public QuicCryptoClientStreamFactory {
virtual ~MockCryptoClientStreamFactory() {}
virtual QuicCryptoClientStream* CreateQuicCryptoClientStream(
- QuicSession* session, const std::string& server_hostname) OVERRIDE;
+ const string& server_hostname,
+ const QuicConfig& config,
+ QuicSession* session,
+ QuicCryptoClientConfig* crypto_config) OVERRIDE;
};
} // namespace net
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index 8acb85a..e258c13 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -39,6 +39,8 @@ QuicClient::QuicClient(IPEndPoint server_address,
packets_dropped_(0),
overflow_supported_(false) {
epoll_server_.set_timeout_in_us(50 * 1000);
+ config_.SetDefaults();
+ crypto_config_.SetDefaults();
}
QuicClient::~QuicClient() {
@@ -129,9 +131,13 @@ bool QuicClient::StartConnect() {
DCHECK(!connected() && initialized_);
QuicGuid guid = QuicRandom::GetInstance()->RandUint64();
- session_.reset(new QuicClientSession(server_hostname_, new QuicConnection(
- guid, server_address_,
- new QuicEpollConnectionHelper(fd_, &epoll_server_), false)));
+ session_.reset(new QuicClientSession(
+ server_hostname_,
+ config_,
+ new QuicConnection(guid, server_address_,
+ new QuicEpollConnectionHelper(fd_, &epoll_server_),
+ false),
+ &crypto_config_));
return session_->CryptoConnect();
}
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index 1328a5e..fa3e014 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -13,6 +13,8 @@
#include "base/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/ip_endpoint.h"
+#include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/quic_config.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
#include "net/tools/flip_server/epoll_server.h"
@@ -141,6 +143,11 @@ class QuicClient : public EpollCallbackInterface {
// because the socket would otherwise overflow.
bool overflow_supported_;
+ // config_ and crypto_config_ contain configuration and cached state about
+ // servers.
+ QuicConfig config_;
+ QuicCryptoClientConfig crypto_config_;
+
DISALLOW_COPY_AND_ASSIGN(QuicClient);
};
diff --git a/net/tools/quic/quic_client_session.cc b/net/tools/quic/quic_client_session.cc
index a3e18dc..6fdf11e 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -16,9 +16,11 @@ namespace tools {
QuicClientSession::QuicClientSession(
const string& server_hostname,
- QuicConnection* connection)
+ const QuicConfig& config,
+ QuicConnection* connection,
+ QuicCryptoClientConfig* crypto_config)
: QuicSession(connection, false),
- crypto_stream_(this, server_hostname) {
+ crypto_stream_(server_hostname, config, this, crypto_config) {
}
QuicClientSession::~QuicClientSession() {
diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h
index 18bd63b..f51aeea 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -26,7 +26,9 @@ class QuicReliableClientStream;
class QuicClientSession : public QuicSession {
public:
QuicClientSession(const std::string& server_hostname,
- QuicConnection* connection);
+ const QuicConfig& config,
+ QuicConnection* connection,
+ QuicCryptoClientConfig* crypto_config);
virtual ~QuicClientSession();
// QuicSession methods:
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index c107f5e..39543db 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -28,7 +28,7 @@ class QuicClientSessionTest : public ::testing::Test {
QuicClientSessionTest()
: guid_(1),
connection_(new PacketSavingConnection(guid_, IPEndPoint(), false)),
- session_(kServerHostname, connection_) {
+ session_(kServerHostname, config_, connection_, &crypto_config_) {
config_.SetDefaults();
crypto_config_.SetDefaults();
}
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 9b5ab84..e88a21e 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -34,8 +34,13 @@ class DeleteSessionsAlarm : public EpollAlarm {
QuicDispatcher* dispatcher_;
};
-QuicDispatcher::QuicDispatcher(int fd, EpollServer* epoll_server)
- : time_wait_list_manager_(
+QuicDispatcher::QuicDispatcher(const QuicConfig& config,
+ const QuicCryptoServerConfig& crypto_config,
+ int fd,
+ EpollServer* epoll_server)
+ : config_(config),
+ crypto_config_(crypto_config),
+ time_wait_list_manager_(
new QuicTimeWaitListManager(this, epoll_server)),
delete_sessions_alarm_(new DeleteSessionsAlarm(this)),
epoll_server_(epoll_server),
@@ -177,6 +182,7 @@ QuicSession* QuicDispatcher::CreateQuicSession(
QuicConnectionHelperInterface* helper =
new QuicEpollConnectionHelper(this, epoll_server);
return new QuicServerSession(
+ config_, crypto_config_,
new QuicConnection(guid, client_address, helper, true), this);
}
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index 6142e8b..b683677 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -36,9 +36,12 @@ namespace gfe2 {
class EpollServer;
}
+namespace net {
+
+class QuicConfig;
+class QuicCryptoServerConfig;
class QuicSession;
-namespace net {
namespace tools {
namespace test {
@@ -46,14 +49,16 @@ class QuicDispatcherPeer;
} // namespace test
class DeleteSessionsAlarm;
-
class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
public:
typedef BlockedList<QuicBlockedWriterInterface*> WriteBlockedList;
// Due to the way delete_sessions_closure_ is registered, the Dispatcher
// must live until epoll_server Shutdown.
- QuicDispatcher(int fd, EpollServer* epoll_server);
+ QuicDispatcher(const QuicConfig& config,
+ const QuicCryptoServerConfig& crypto_config,
+ int fd,
+ EpollServer* epoll_server);
virtual ~QuicDispatcher();
// QuicPacketWriter
@@ -98,6 +103,10 @@ class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
WriteBlockedList* write_blocked_list() { return &write_blocked_list_; }
+ protected:
+ const QuicConfig& config_;
+ const QuicCryptoServerConfig& crypto_config_;
+
private:
friend class net::tools::test::QuicDispatcherPeer;
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 52a22dc..e0824bb 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -50,7 +50,7 @@ class TestDispatcher : public QuicDispatcher {
explicit TestDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
EpollServer* eps)
- : QuicDispatcher(1, eps) {}
+ : QuicDispatcher(config, crypto_config, 1, eps) {}
MOCK_METHOD4(CreateQuicSession, QuicSession*(
QuicGuid guid,
diff --git a/net/tools/quic/quic_reliable_client_stream_test.cc b/net/tools/quic/quic_reliable_client_stream_test.cc
index 7b45b97..8020c33 100644
--- a/net/tools/quic/quic_reliable_client_stream_test.cc
+++ b/net/tools/quic/quic_reliable_client_stream_test.cc
@@ -25,8 +25,9 @@ namespace {
class QuicClientStreamTest : public ::testing::Test {
public:
QuicClientStreamTest()
- : session_("localhost",
- new MockConnection(1, IPEndPoint(), 0, &eps_, false)),
+ : session_("localhost", config_,
+ new MockConnection(1, IPEndPoint(), 0, &eps_, false),
+ &crypto_config_),
body_("hello world") {
config_.SetDefaults();
crypto_config_.SetDefaults();
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index 6f761ae..4e1743a 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -12,6 +12,10 @@
#include <sys/socket.h>
#include "net/base/ip_endpoint.h"
+#include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/crypto/quic_random.h"
+#include "net/quic/quic_clock.h"
+#include "net/quic/quic_crypto_stream.h"
#include "net/quic/quic_data_reader.h"
#include "net/quic/quic_protocol.h"
#include "net/tools/quic/quic_in_memory_cache.h"
@@ -25,6 +29,7 @@
const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
const int kNumPacketsPerReadCall = 5; // Arbitrary
+static const char kSourceAddressTokenSecret[] = "secret";
namespace net {
namespace tools {
@@ -33,10 +38,26 @@ QuicServer::QuicServer()
: port_(0),
packets_dropped_(0),
overflow_supported_(false),
- use_recvmmsg_(false) {
+ use_recvmmsg_(false),
+ crypto_config_(kSourceAddressTokenSecret) {
epoll_server_.set_timeout_in_us(50 * 1000);
// Initialize the in memory cache now.
QuicInMemoryCache::GetInstance();
+
+ // Use hardcoded crypto parameters for now.
+ config_.SetDefaults();
+ CryptoHandshakeMessage extra_tags;
+ config_.ToHandshakeMessage(&extra_tags);
+ QuicEpollClock clock(&epoll_server_);
+
+ scoped_ptr<CryptoHandshakeMessage> scfg(
+ crypto_config_.AddDefaultConfig(QuicRandom::GetInstance(), &clock,
+ extra_tags));
+ // If we were using the same config in many servers then we would have to
+ // parse a QuicConfig from config_tags here.
+ if (!config_.SetFromHandshakeMessage(*scfg)) {
+ CHECK(false) << "Crypto config could not be parsed by QuicConfig.";
+ }
}
QuicServer::~QuicServer() {
@@ -109,7 +130,8 @@ bool QuicServer::Listen(const IPEndPoint& address) {
epoll_server_.RegisterFD(fd_, this, kEpollFlags);
- dispatcher_.reset(new QuicDispatcher(fd_, &epoll_server_));
+ dispatcher_.reset(new QuicDispatcher(config_, crypto_config_, fd_,
+ &epoll_server_));
return true;
}
diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h
index 813510c..28ea551 100644
--- a/net/tools/quic/quic_server.h
+++ b/net/tools/quic/quic_server.h
@@ -10,11 +10,15 @@
#include "base/memory/scoped_ptr.h"
#include "net/base/ip_endpoint.h"
+#include "net/quic/quic_config.h"
#include "net/quic/quic_framer.h"
#include "net/tools/flip_server/epoll_server.h"
#include "net/tools/quic/quic_dispatcher.h"
namespace net {
+
+class QuicCryptoServerConfig;
+
namespace tools {
class QuicDispatcher;
@@ -82,6 +86,12 @@ class QuicServer : public EpollCallbackInterface {
// If true, use recvmmsg for reading.
bool use_recvmmsg_;
+ // config_ contains non-crypto parameters that are negotiated in the crypto
+ // handshake.
+ QuicConfig config_;
+ // crypto_config_ contains crypto parameters for the handshake.
+ QuicCryptoServerConfig crypto_config_;
+
DISALLOW_COPY_AND_ASSIGN(QuicServer);
};
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index fc84f75..f692332 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -11,10 +11,13 @@
namespace net {
namespace tools {
-QuicServerSession::QuicServerSession(QuicConnection* connection,
- QuicSessionOwner* owner)
+QuicServerSession::QuicServerSession(
+ const QuicConfig& config,
+ const QuicCryptoServerConfig& crypto_config,
+ QuicConnection* connection,
+ QuicSessionOwner* owner)
: QuicSession(connection, true),
- crypto_stream_(this),
+ crypto_stream_(config, crypto_config, this),
owner_(owner) {
}
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index 91a0704..be92871a 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -17,7 +17,9 @@
namespace net {
+class QuicConfig;
class QuicConnection;
+class QuicCryptoServerConfig;
class ReliableQuicStream;
namespace tools {
@@ -34,7 +36,10 @@ class QuicSessionOwner {
class QuicServerSession : public QuicSession {
public:
- QuicServerSession(QuicConnection *connection, QuicSessionOwner* owner);
+ QuicServerSession(const QuicConfig& config,
+ const QuicCryptoServerConfig& crypto_config,
+ QuicConnection* connection,
+ QuicSessionOwner* owner);
// Override the base class to notify the owner of the connection close.
virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE;