Home | History | Annotate | Download | only in crypto
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/quic/crypto/quic_crypto_client_config.h"
      6 
      7 #include "base/stl_util.h"
      8 #include "net/quic/crypto/cert_compressor.h"
      9 #include "net/quic/crypto/channel_id.h"
     10 #include "net/quic/crypto/common_cert_set.h"
     11 #include "net/quic/crypto/crypto_framer.h"
     12 #include "net/quic/crypto/crypto_utils.h"
     13 #include "net/quic/crypto/curve25519_key_exchange.h"
     14 #include "net/quic/crypto/key_exchange.h"
     15 #include "net/quic/crypto/p256_key_exchange.h"
     16 #include "net/quic/crypto/proof_verifier.h"
     17 #include "net/quic/crypto/quic_encrypter.h"
     18 #include "net/quic/quic_utils.h"
     19 
     20 #if defined(OS_WIN)
     21 #include "base/win/windows_version.h"
     22 #endif
     23 
     24 using base::StringPiece;
     25 using std::map;
     26 using std::string;
     27 using std::vector;
     28 
     29 namespace net {
     30 
     31 QuicCryptoClientConfig::QuicCryptoClientConfig() {}
     32 
     33 QuicCryptoClientConfig::~QuicCryptoClientConfig() {
     34   STLDeleteValues(&cached_states_);
     35 }
     36 
     37 QuicCryptoClientConfig::CachedState::CachedState()
     38     : server_config_valid_(false),
     39       generation_counter_(0) {}
     40 
     41 QuicCryptoClientConfig::CachedState::~CachedState() {}
     42 
     43 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
     44   if (server_config_.empty() || !server_config_valid_) {
     45     return false;
     46   }
     47 
     48   const CryptoHandshakeMessage* scfg = GetServerConfig();
     49   if (!scfg) {
     50     // Should be impossible short of cache corruption.
     51     DCHECK(false);
     52     return false;
     53   }
     54 
     55   uint64 expiry_seconds;
     56   if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR ||
     57       now.ToUNIXSeconds() >= expiry_seconds) {
     58     return false;
     59   }
     60 
     61   return true;
     62 }
     63 
     64 const CryptoHandshakeMessage*
     65 QuicCryptoClientConfig::CachedState::GetServerConfig() const {
     66   if (server_config_.empty()) {
     67     return NULL;
     68   }
     69 
     70   if (!scfg_.get()) {
     71     scfg_.reset(CryptoFramer::ParseMessage(server_config_));
     72     DCHECK(scfg_.get());
     73   }
     74   return scfg_.get();
     75 }
     76 
     77 QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig(
     78     StringPiece server_config, QuicWallTime now, string* error_details) {
     79   const bool matches_existing = server_config == server_config_;
     80 
     81   // Even if the new server config matches the existing one, we still wish to
     82   // reject it if it has expired.
     83   scoped_ptr<CryptoHandshakeMessage> new_scfg_storage;
     84   const CryptoHandshakeMessage* new_scfg;
     85 
     86   if (!matches_existing) {
     87     new_scfg_storage.reset(CryptoFramer::ParseMessage(server_config));
     88     new_scfg = new_scfg_storage.get();
     89   } else {
     90     new_scfg = GetServerConfig();
     91   }
     92 
     93   if (!new_scfg) {
     94     *error_details = "SCFG invalid";
     95     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
     96   }
     97 
     98   uint64 expiry_seconds;
     99   if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
    100     *error_details = "SCFG missing EXPY";
    101     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    102   }
    103 
    104   if (now.ToUNIXSeconds() >= expiry_seconds) {
    105     *error_details = "SCFG has expired";
    106     return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
    107   }
    108 
    109   if (!matches_existing) {
    110     server_config_ = server_config.as_string();
    111     SetProofInvalid();
    112     scfg_.reset(new_scfg_storage.release());
    113   }
    114   return QUIC_NO_ERROR;
    115 }
    116 
    117 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
    118   server_config_.clear();
    119   scfg_.reset();
    120   SetProofInvalid();
    121 }
    122 
    123 void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
    124                                                    StringPiece signature) {
    125   bool has_changed =
    126       signature != server_config_sig_ || certs_.size() != certs.size();
    127 
    128   if (!has_changed) {
    129     for (size_t i = 0; i < certs_.size(); i++) {
    130       if (certs_[i] != certs[i]) {
    131         has_changed = true;
    132         break;
    133       }
    134     }
    135   }
    136 
    137   if (!has_changed) {
    138     return;
    139   }
    140 
    141   // If the proof has changed then it needs to be revalidated.
    142   SetProofInvalid();
    143   certs_ = certs;
    144   server_config_sig_ = signature.as_string();
    145 }
    146 
    147 void QuicCryptoClientConfig::CachedState::ClearProof() {
    148   SetProofInvalid();
    149   certs_.clear();
    150   server_config_sig_.clear();
    151 }
    152 
    153 void QuicCryptoClientConfig::CachedState::SetProofValid() {
    154   server_config_valid_ = true;
    155 }
    156 
    157 void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
    158   server_config_valid_ = false;
    159   ++generation_counter_;
    160 }
    161 
    162 const string& QuicCryptoClientConfig::CachedState::server_config() const {
    163   return server_config_;
    164 }
    165 
    166 const string&
    167 QuicCryptoClientConfig::CachedState::source_address_token() const {
    168   return source_address_token_;
    169 }
    170 
    171 const vector<string>& QuicCryptoClientConfig::CachedState::certs() const {
    172   return certs_;
    173 }
    174 
    175 const string& QuicCryptoClientConfig::CachedState::signature() const {
    176   return server_config_sig_;
    177 }
    178 
    179 bool QuicCryptoClientConfig::CachedState::proof_valid() const {
    180   return server_config_valid_;
    181 }
    182 
    183 uint64 QuicCryptoClientConfig::CachedState::generation_counter() const {
    184   return generation_counter_;
    185 }
    186 
    187 const ProofVerifyDetails*
    188 QuicCryptoClientConfig::CachedState::proof_verify_details() const {
    189   return proof_verify_details_.get();
    190 }
    191 
    192 void QuicCryptoClientConfig::CachedState::set_source_address_token(
    193     StringPiece token) {
    194   source_address_token_ = token.as_string();
    195 }
    196 
    197 void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
    198     ProofVerifyDetails* details) {
    199   proof_verify_details_.reset(details);
    200 }
    201 
    202 void QuicCryptoClientConfig::CachedState::InitializeFrom(
    203     const QuicCryptoClientConfig::CachedState& other) {
    204   DCHECK(server_config_.empty());
    205   DCHECK(!server_config_valid_);
    206   server_config_ = other.server_config_;
    207   source_address_token_ = other.source_address_token_;
    208   certs_ = other.certs_;
    209   server_config_sig_ = other.server_config_sig_;
    210   server_config_valid_ = other.server_config_valid_;
    211 }
    212 
    213 void QuicCryptoClientConfig::SetDefaults() {
    214   // Key exchange methods.
    215   kexs.resize(2);
    216   kexs[0] = kC255;
    217   kexs[1] = kP256;
    218 
    219   // Authenticated encryption algorithms.
    220   aead.resize(1);
    221   aead[0] = kAESG;
    222 }
    223 
    224 QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate(
    225     const string& server_hostname) {
    226   map<string, CachedState*>::const_iterator it =
    227       cached_states_.find(server_hostname);
    228   if (it != cached_states_.end()) {
    229     return it->second;
    230   }
    231 
    232   CachedState* cached = new CachedState;
    233   cached_states_.insert(make_pair(server_hostname, cached));
    234   return cached;
    235 }
    236 
    237 void QuicCryptoClientConfig::FillInchoateClientHello(
    238     const string& server_hostname,
    239     const QuicVersion preferred_version,
    240     const CachedState* cached,
    241     QuicCryptoNegotiatedParameters* out_params,
    242     CryptoHandshakeMessage* out) const {
    243   out->set_tag(kCHLO);
    244   out->set_minimum_size(kClientHelloMinimumSize);
    245 
    246   // Server name indication. We only send SNI if it's a valid domain name, as
    247   // per the spec.
    248   if (CryptoUtils::IsValidSNI(server_hostname)) {
    249     out->SetStringPiece(kSNI, server_hostname);
    250   }
    251   // TODO(rch): Remove once we remove QUIC_VERSION_12.
    252   out->SetValue(kVERS, static_cast<uint16>(0));
    253   out->SetValue(kVER, QuicVersionToQuicTag(preferred_version));
    254 
    255   if (!cached->source_address_token().empty()) {
    256     out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
    257   }
    258 
    259   if (proof_verifier_.get()) {
    260     // Don't request ECDSA proofs on platforms that do not support ECDSA
    261     // certificates.
    262     bool disableECDSA = false;
    263 #if defined(OS_WIN)
    264     if (base::win::GetVersion() < base::win::VERSION_VISTA)
    265       disableECDSA = true;
    266 #endif
    267     if (disableECDSA) {
    268       out->SetTaglist(kPDMD, kX59R, 0);
    269     } else {
    270       out->SetTaglist(kPDMD, kX509, 0);
    271     }
    272   }
    273 
    274   if (common_cert_sets) {
    275     out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
    276   }
    277 
    278   const vector<string>& certs = cached->certs();
    279   // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
    280   // client config is being used for multiple connections, another connection
    281   // doesn't update the cached certificates and cause us to be unable to
    282   // process the server's compressed certificate chain.
    283   out_params->cached_certs = certs;
    284   if (!certs.empty()) {
    285     vector<uint64> hashes;
    286     hashes.reserve(certs.size());
    287     for (vector<string>::const_iterator i = certs.begin();
    288          i != certs.end(); ++i) {
    289       hashes.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
    290     }
    291     out->SetVector(kCCRT, hashes);
    292   }
    293 }
    294 
    295 QuicErrorCode QuicCryptoClientConfig::FillClientHello(
    296     const string& server_hostname,
    297     QuicGuid guid,
    298     const QuicVersion preferred_version,
    299     const CachedState* cached,
    300     QuicWallTime now,
    301     QuicRandom* rand,
    302     QuicCryptoNegotiatedParameters* out_params,
    303     CryptoHandshakeMessage* out,
    304     string* error_details) const {
    305   DCHECK(error_details != NULL);
    306 
    307   FillInchoateClientHello(server_hostname, preferred_version, cached,
    308                           out_params, out);
    309 
    310   const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
    311   if (!scfg) {
    312     // This should never happen as our caller should have checked
    313     // cached->IsComplete() before calling this function.
    314     *error_details = "Handshake not ready";
    315     return QUIC_CRYPTO_INTERNAL_ERROR;
    316   }
    317 
    318   StringPiece scid;
    319   if (!scfg->GetStringPiece(kSCID, &scid)) {
    320     *error_details = "SCFG missing SCID";
    321     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    322   }
    323   out->SetStringPiece(kSCID, scid);
    324 
    325   const QuicTag* their_aeads;
    326   const QuicTag* their_key_exchanges;
    327   size_t num_their_aeads, num_their_key_exchanges;
    328   if (scfg->GetTaglist(kAEAD, &their_aeads,
    329                        &num_their_aeads) != QUIC_NO_ERROR ||
    330       scfg->GetTaglist(kKEXS, &their_key_exchanges,
    331                        &num_their_key_exchanges) != QUIC_NO_ERROR) {
    332     *error_details = "Missing AEAD or KEXS";
    333     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    334   }
    335 
    336   size_t key_exchange_index;
    337   if (!QuicUtils::FindMutualTag(
    338           aead, their_aeads, num_their_aeads, QuicUtils::PEER_PRIORITY,
    339           &out_params->aead, NULL) ||
    340       !QuicUtils::FindMutualTag(
    341           kexs, their_key_exchanges, num_their_key_exchanges,
    342           QuicUtils::PEER_PRIORITY, &out_params->key_exchange,
    343           &key_exchange_index)) {
    344     *error_details = "Unsupported AEAD or KEXS";
    345     return QUIC_CRYPTO_NO_SUPPORT;
    346   }
    347   out->SetTaglist(kAEAD, out_params->aead, 0);
    348   out->SetTaglist(kKEXS, out_params->key_exchange, 0);
    349 
    350   StringPiece public_value;
    351   if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) !=
    352           QUIC_NO_ERROR) {
    353     *error_details = "Missing public value";
    354     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    355   }
    356 
    357   StringPiece orbit;
    358   if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) {
    359     *error_details = "SCFG missing OBIT";
    360     return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
    361   }
    362 
    363   CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce);
    364   out->SetStringPiece(kNONC, out_params->client_nonce);
    365   if (!out_params->server_nonce.empty()) {
    366     out->SetStringPiece(kServerNonceTag, out_params->server_nonce);
    367   }
    368 
    369   switch (out_params->key_exchange) {
    370     case kC255:
    371       out_params->client_key_exchange.reset(Curve25519KeyExchange::New(
    372           Curve25519KeyExchange::NewPrivateKey(rand)));
    373       break;
    374     case kP256:
    375       out_params->client_key_exchange.reset(P256KeyExchange::New(
    376           P256KeyExchange::NewPrivateKey()));
    377       break;
    378     default:
    379       DCHECK(false);
    380       *error_details = "Configured to support an unknown key exchange";
    381       return QUIC_CRYPTO_INTERNAL_ERROR;
    382   }
    383 
    384   if (!out_params->client_key_exchange->CalculateSharedKey(
    385           public_value, &out_params->initial_premaster_secret)) {
    386     *error_details = "Key exchange failure";
    387     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    388   }
    389   out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value());
    390 
    391   bool do_channel_id = false;
    392   if (channel_id_signer_.get()) {
    393     const QuicTag* their_proof_demands;
    394     size_t num_their_proof_demands;
    395     if (scfg->GetTaglist(kPDMD, &their_proof_demands,
    396                          &num_their_proof_demands) == QUIC_NO_ERROR) {
    397       for (size_t i = 0; i < num_their_proof_demands; i++) {
    398         if (their_proof_demands[i] == kCHID) {
    399           do_channel_id = true;
    400           break;
    401         }
    402       }
    403     }
    404   }
    405 
    406   if (do_channel_id) {
    407     // In order to calculate the encryption key for the CETV block we need to
    408     // serialise the client hello as it currently is (i.e. without the CETV
    409     // block). For this, the client hello is serialized without padding.
    410     const size_t orig_min_size = out->minimum_size();
    411     out->set_minimum_size(0);
    412 
    413     CryptoHandshakeMessage cetv;
    414     cetv.set_tag(kCETV);
    415 
    416     string hkdf_input;
    417     const QuicData& client_hello_serialized = out->GetSerialized();
    418     hkdf_input.append(QuicCryptoConfig::kCETVLabel,
    419                       strlen(QuicCryptoConfig::kCETVLabel) + 1);
    420     hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid));
    421     hkdf_input.append(client_hello_serialized.data(),
    422                       client_hello_serialized.length());
    423     hkdf_input.append(cached->server_config());
    424 
    425     string key, signature;
    426     if (!channel_id_signer_->Sign(server_hostname, hkdf_input,
    427                                   &key, &signature)) {
    428       *error_details = "Channel ID signature failed";
    429       return QUIC_INVALID_CHANNEL_ID_SIGNATURE;
    430     }
    431 
    432     cetv.SetStringPiece(kCIDK, key);
    433     cetv.SetStringPiece(kCIDS, signature);
    434 
    435     CrypterPair crypters;
    436     if (!CryptoUtils::DeriveKeys(out_params->initial_premaster_secret,
    437                                  out_params->aead, out_params->client_nonce,
    438                                  out_params->server_nonce, hkdf_input,
    439                                  CryptoUtils::CLIENT, &crypters)) {
    440       *error_details = "Symmetric key setup failed";
    441       return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
    442     }
    443 
    444     const QuicData& cetv_plaintext = cetv.GetSerialized();
    445     scoped_ptr<QuicData> cetv_ciphertext(crypters.encrypter->EncryptPacket(
    446         0 /* sequence number */,
    447         StringPiece() /* associated data */,
    448         cetv_plaintext.AsStringPiece()));
    449     if (!cetv_ciphertext.get()) {
    450       *error_details = "Packet encryption failed";
    451       return QUIC_ENCRYPTION_FAILURE;
    452     }
    453 
    454     out->SetStringPiece(kCETV, cetv_ciphertext->AsStringPiece());
    455     out->MarkDirty();
    456 
    457     out->set_minimum_size(orig_min_size);
    458   }
    459 
    460   out_params->hkdf_input_suffix.clear();
    461   out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&guid),
    462                                        sizeof(guid));
    463   const QuicData& client_hello_serialized = out->GetSerialized();
    464   out_params->hkdf_input_suffix.append(client_hello_serialized.data(),
    465                                        client_hello_serialized.length());
    466   out_params->hkdf_input_suffix.append(cached->server_config());
    467 
    468   string hkdf_input;
    469   const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
    470   hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
    471   hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
    472   hkdf_input.append(out_params->hkdf_input_suffix);
    473 
    474   if (!CryptoUtils::DeriveKeys(
    475            out_params->initial_premaster_secret, out_params->aead,
    476            out_params->client_nonce, out_params->server_nonce, hkdf_input,
    477            CryptoUtils::CLIENT, &out_params->initial_crypters)) {
    478     *error_details = "Symmetric key setup failed";
    479     return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
    480   }
    481 
    482   return QUIC_NO_ERROR;
    483 }
    484 
    485 QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
    486     const CryptoHandshakeMessage& rej,
    487     QuicWallTime now,
    488     CachedState* cached,
    489     QuicCryptoNegotiatedParameters* out_params,
    490     string* error_details) {
    491   DCHECK(error_details != NULL);
    492 
    493   if (rej.tag() != kREJ) {
    494     *error_details = "Message is not REJ";
    495     return QUIC_CRYPTO_INTERNAL_ERROR;
    496   }
    497 
    498   StringPiece scfg;
    499   if (!rej.GetStringPiece(kSCFG, &scfg)) {
    500     *error_details = "Missing SCFG";
    501     return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
    502   }
    503 
    504   QuicErrorCode error = cached->SetServerConfig(scfg, now, error_details);
    505   if (error != QUIC_NO_ERROR) {
    506     return error;
    507   }
    508 
    509   StringPiece token;
    510   if (rej.GetStringPiece(kSourceAddressTokenTag, &token)) {
    511     cached->set_source_address_token(token);
    512   }
    513 
    514   StringPiece nonce;
    515   if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
    516     out_params->server_nonce = nonce.as_string();
    517   }
    518 
    519   StringPiece proof, cert_bytes;
    520   bool has_proof = rej.GetStringPiece(kPROF, &proof);
    521   bool has_cert = rej.GetStringPiece(kCertificateTag, &cert_bytes);
    522   if (has_proof && has_cert) {
    523     vector<string> certs;
    524     if (!CertCompressor::DecompressChain(cert_bytes, out_params->cached_certs,
    525                                          common_cert_sets, &certs)) {
    526       *error_details = "Certificate data invalid";
    527       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    528     }
    529 
    530     cached->SetProof(certs, proof);
    531   } else {
    532     cached->ClearProof();
    533     if (has_proof && !has_cert) {
    534       *error_details = "Certificate missing";
    535       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    536     }
    537 
    538     if (!has_proof && has_cert) {
    539       *error_details = "Proof missing";
    540       return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    541     }
    542   }
    543 
    544   return QUIC_NO_ERROR;
    545 }
    546 
    547 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
    548     const CryptoHandshakeMessage& server_hello,
    549     QuicGuid guid,
    550     const QuicVersionVector& negotiated_versions,
    551     CachedState* cached,
    552     QuicCryptoNegotiatedParameters* out_params,
    553     string* error_details) {
    554   DCHECK(error_details != NULL);
    555 
    556   if (server_hello.tag() != kSHLO) {
    557     *error_details = "Bad tag";
    558     return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
    559   }
    560 
    561   const QuicTag* supported_version_tags;
    562   size_t num_supported_versions;
    563   // TODO(rch): Once QUIC_VERSION_12 is removed, then make it a failure
    564   // if the server does not have a version list.
    565   if (server_hello.GetTaglist(kVER, &supported_version_tags,
    566                               &num_supported_versions) == QUIC_NO_ERROR) {
    567     if (!negotiated_versions.empty()) {
    568       bool mismatch = num_supported_versions != negotiated_versions.size();
    569       for (size_t i = 0; i < num_supported_versions && !mismatch; ++i) {
    570         mismatch = QuicTagToQuicVersion(supported_version_tags[i]) !=
    571             negotiated_versions[i];
    572       }
    573       // The server sent a list of supported versions, and the connection
    574       // reports that there was a version negotiation during the handshake.
    575       // Ensure that these two lists are identical.
    576       if (mismatch) {
    577         *error_details = "Downgrade attack detected";
    578         return QUIC_VERSION_NEGOTIATION_MISMATCH;
    579       }
    580     }
    581   }
    582 
    583   // Learn about updated source address tokens.
    584   StringPiece token;
    585   if (server_hello.GetStringPiece(kSourceAddressTokenTag, &token)) {
    586     cached->set_source_address_token(token);
    587   }
    588 
    589   // TODO(agl):
    590   //   learn about updated SCFGs.
    591 
    592   StringPiece public_value;
    593   if (!server_hello.GetStringPiece(kPUBS, &public_value)) {
    594     *error_details = "server hello missing forward secure public value";
    595     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    596   }
    597 
    598   if (!out_params->client_key_exchange->CalculateSharedKey(
    599           public_value, &out_params->forward_secure_premaster_secret)) {
    600     *error_details = "Key exchange failure";
    601     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
    602   }
    603 
    604   string hkdf_input;
    605   const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
    606   hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
    607   hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len);
    608   hkdf_input.append(out_params->hkdf_input_suffix);
    609 
    610   if (!CryptoUtils::DeriveKeys(
    611            out_params->forward_secure_premaster_secret, out_params->aead,
    612            out_params->client_nonce, out_params->server_nonce, hkdf_input,
    613            CryptoUtils::CLIENT, &out_params->forward_secure_crypters)) {
    614     *error_details = "Symmetric key setup failed";
    615     return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
    616   }
    617 
    618   return QUIC_NO_ERROR;
    619 }
    620 
    621 ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
    622   return proof_verifier_.get();
    623 }
    624 
    625 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier* verifier) {
    626   proof_verifier_.reset(verifier);
    627 }
    628 
    629 ChannelIDSigner* QuicCryptoClientConfig::channel_id_signer() const {
    630   return channel_id_signer_.get();
    631 }
    632 
    633 void QuicCryptoClientConfig::SetChannelIDSigner(ChannelIDSigner* signer) {
    634   channel_id_signer_.reset(signer);
    635 }
    636 
    637 void QuicCryptoClientConfig::InitializeFrom(
    638     const std::string& server_hostname,
    639     const std::string& canonical_server_hostname,
    640     QuicCryptoClientConfig* canonical_crypto_config) {
    641   CachedState* canonical_cached =
    642       canonical_crypto_config->LookupOrCreate(canonical_server_hostname);
    643   if (!canonical_cached->proof_valid()) {
    644     return;
    645   }
    646   CachedState* cached = LookupOrCreate(server_hostname);
    647   cached->InitializeFrom(*canonical_cached);
    648 }
    649 
    650 }  // namespace net
    651