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

[email protected]

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194634 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/net.gyp b/net/net.gyp
index 3ba59da..ed191da4 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 @@
   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 @@
 }
 
 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 @@
 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 @@
     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 @@
     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::ProcessRejection(
     const string& server_hostname,
     const CryptoHandshakeMessage& rej,
+    QuicCryptoNegotiatedParameters* out_params,
     string* error_details) {
   CachedState* cached;
 
@@ -631,6 +640,12 @@
     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 @@
     //
     // 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 @@
 }
 
 // static
-QuicServerConfigProtobuf* QuicCryptoServerConfig::ConfigForTesting(
+QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig(
     QuicRandom* rand,
     const QuicClock* clock,
     const CryptoHandshakeMessage& extra_tags)  {
@@ -722,6 +738,10 @@
   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 @@
     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 @@
   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 @@
     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 @@
   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 @@
     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 @@
   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 @@
   }
 
   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 @@
                     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 @@
 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 @@
 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 QuicEncrypter;
 class QuicRandom;
 class QuicServerConfigProtobuf;
+class StrikeRegister;
 
 namespace test {
 class QuicCryptoServerConfigPeer;
@@ -221,6 +223,7 @@
   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 @@
 };
 
 // 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 @@
 
     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 @@
     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 @@
 
   // 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 @@
                                 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 @@
  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 @@
   // 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 @@
   // 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 @@
   // 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 @@
     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 @@
   // 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 @@
   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..f24dcbea5 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -57,11 +57,14 @@
 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 b6ae58bf..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 @@
   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::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 @@
   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 @@
   //   <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..5e1e80f69 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -23,14 +23,10 @@
     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 @@
       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 cdda3111..2bf6e78 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -36,6 +36,7 @@
                     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 @@
   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 1ca0080d..6d265416 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -30,7 +30,9 @@
   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 @@
   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::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 63a4f44d..aa43b6d1 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 @@
   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 @@
     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 @@
         }
         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 @@
         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 @@
       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 fb67ee4a..2ad122c7 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 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 @@
   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 @@
   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 @@
       : 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 @@
   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 d1c21ff9..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 @@
       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 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 @@
 
   // 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 @@
               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 @@
   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 @@
   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 @@
   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 @@
     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 @@
   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 48e647fe..b3f11cb 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -220,6 +220,8 @@
   // 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 b5f57e57..2517bac 100644
--- a/net/quic/quic_reliable_client_stream_test.cc
+++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -42,6 +42,8 @@
   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 @@
 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 @@
 }
 
 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 @@
       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 @@
   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 @@
   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 @@
   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 @@
   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..ac46977f 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -73,6 +73,7 @@
     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 @@
   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 @@
   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 @@
 }
 
 // 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 @@
   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 @@
 
 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 153ddd45..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 @@
 
 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 1ed81f52..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 @@
   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 @@
       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 @@
   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 @@
   // 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 a3e18dc5..6fdf11e 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -16,9 +16,11 @@
 
 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 18bd63b0..f51aeeaf 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -26,7 +26,9 @@
 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 @@
   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..e88a21ee 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -34,8 +34,13 @@
   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 @@
   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 @@
   class EpollServer;
 }
 
+namespace net {
+
+class QuicConfig;
+class QuicCryptoServerConfig;
 class QuicSession;
 
-namespace net {
 namespace tools {
 
 namespace test {
@@ -46,14 +49,16 @@
 }  // 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 @@
 
   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 @@
   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 7b45b97e..8020c333 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 @@
 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 6f761ae3..4e1743a6 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 @@
     : 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 @@
 
   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 813510cf9..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 @@
   // 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 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;