10f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
20f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
30f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// found in the LICENSE file.
40f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
50f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/quic_crypto_client_config.h"
60f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/metrics/histogram.h"
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/metrics/sparse_histogram.h"
90f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/stl_util.h"
10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/strings/string_util.h"
110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/cert_compressor.h"
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "net/quic/crypto/chacha20_poly1305_encrypter.h"
130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/channel_id.h"
140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/common_cert_set.h"
150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/crypto_framer.h"
160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/crypto_utils.h"
170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/curve25519_key_exchange.h"
180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/key_exchange.h"
190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/p256_key_exchange.h"
200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/proof_verifier.h"
210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/crypto/quic_encrypter.h"
220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "net/quic/quic_utils.h"
230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)using base::StringPiece;
25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochusing std::find;
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using std::make_pair;
270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)using std::map;
280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)using std::string;
290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)using std::vector;
300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace net {
320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace {
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)enum ServerConfigState {
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // WARNING: Do not change the numerical values of any of server config state.
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Do not remove deprecated server config states - just comment them as
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // deprecated.
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SERVER_CONFIG_EMPTY = 0,
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SERVER_CONFIG_INVALID = 1,
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SERVER_CONFIG_CORRUPTED = 2,
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SERVER_CONFIG_EXPIRED = 3,
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SERVER_CONFIG_INVALID_EXPIRY = 4,
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // NOTE: Add new server config states only immediately above this line. Make
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // sure to update the QuicServerConfigState enum in
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // tools/metrics/histograms/histograms.xml accordingly.
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SERVER_CONFIG_COUNT
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void RecordServerConfigState(ServerConfigState server_config_state) {
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.QuicClientHelloServerConfigState",
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            server_config_state, SERVER_CONFIG_COUNT);
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
58effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochQuicCryptoClientConfig::QuicCryptoClientConfig()
59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    : disable_ecdsa_(false) {}
600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicCryptoClientConfig::~QuicCryptoClientConfig() {
620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  STLDeleteValues(&cached_states_);
630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicCryptoClientConfig::CachedState::CachedState()
660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    : server_config_valid_(false),
670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      generation_counter_(0) {}
680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicCryptoClientConfig::CachedState::~CachedState() {}
700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (server_config_.empty()) {
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RecordServerConfigState(SERVER_CONFIG_EMPTY);
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!server_config_valid_) {
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RecordServerConfigState(SERVER_CONFIG_INVALID);
790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return false;
800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const CryptoHandshakeMessage* scfg = GetServerConfig();
830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!scfg) {
840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // Should be impossible short of cache corruption.
850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    DCHECK(false);
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RecordServerConfigState(SERVER_CONFIG_CORRUPTED);
870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return false;
880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  uint64 expiry_seconds;
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RecordServerConfigState(SERVER_CONFIG_INVALID_EXPIRY);
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (now.ToUNIXSeconds() >= expiry_seconds) {
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES(
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Net.QuicClientHelloServerConfig.InvalidDuration",
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::TimeDelta::FromSeconds(now.ToUNIXSeconds() - expiry_seconds),
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50);
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RecordServerConfigState(SERVER_CONFIG_EXPIRED);
1010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return false;
1020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return true;
1050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return server_config_.empty();
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const CryptoHandshakeMessage*
1120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicCryptoClientConfig::CachedState::GetServerConfig() const {
1130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (server_config_.empty()) {
1140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return NULL;
1150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!scfg_.get()) {
1180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    scfg_.reset(CryptoFramer::ParseMessage(server_config_));
1190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    DCHECK(scfg_.get());
1200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return scfg_.get();
1220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig(
1250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    StringPiece server_config, QuicWallTime now, string* error_details) {
1260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const bool matches_existing = server_config == server_config_;
1270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Even if the new server config matches the existing one, we still wish to
1290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // reject it if it has expired.
1300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  scoped_ptr<CryptoHandshakeMessage> new_scfg_storage;
1310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const CryptoHandshakeMessage* new_scfg;
1320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!matches_existing) {
1340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    new_scfg_storage.reset(CryptoFramer::ParseMessage(server_config));
1350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    new_scfg = new_scfg_storage.get();
1360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
1370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    new_scfg = GetServerConfig();
1380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!new_scfg) {
1410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "SCFG invalid";
1420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
1430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  uint64 expiry_seconds;
1460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
1470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "SCFG missing EXPY";
1480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
1490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (now.ToUNIXSeconds() >= expiry_seconds) {
1520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "SCFG has expired";
1530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
1540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!matches_existing) {
1570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    server_config_ = server_config.as_string();
1580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    SetProofInvalid();
1590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    scfg_.reset(new_scfg_storage.release());
1600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return QUIC_NO_ERROR;
1620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
1650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  server_config_.clear();
1660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  scfg_.reset();
1670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  SetProofInvalid();
1680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
1710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                                   StringPiece signature) {
1720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  bool has_changed =
1730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      signature != server_config_sig_ || certs_.size() != certs.size();
1740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!has_changed) {
1760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    for (size_t i = 0; i < certs_.size(); i++) {
1770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if (certs_[i] != certs[i]) {
1780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        has_changed = true;
1790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break;
1800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
1810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
1820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!has_changed) {
1850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
1860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // If the proof has changed then it needs to be revalidated.
1890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  SetProofInvalid();
1900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  certs_ = certs;
1910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  server_config_sig_ = signature.as_string();
1920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid QuicCryptoClientConfig::CachedState::Clear() {
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  server_config_.clear();
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  source_address_token_.clear();
1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  certs_.clear();
1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  server_config_sig_.clear();
1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  server_config_valid_ = false;
2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  proof_verify_details_.reset();
2015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scfg_.reset();
2025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ++generation_counter_;
2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::CachedState::ClearProof() {
2060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  SetProofInvalid();
2070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  certs_.clear();
2080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  server_config_sig_.clear();
2090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::CachedState::SetProofValid() {
2120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  server_config_valid_ = true;
2130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
2160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  server_config_valid_ = false;
2170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ++generation_counter_;
2180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool QuicCryptoClientConfig::CachedState::Initialize(
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    StringPiece server_config,
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    StringPiece source_address_token,
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const vector<string>& certs,
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    StringPiece signature,
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    QuicWallTime now) {
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(server_config_.empty());
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (server_config.empty()) {
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  string error_details;
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  QuicErrorCode error = SetServerConfig(server_config, now,
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                        &error_details);
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (error != QUIC_NO_ERROR) {
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DVLOG(1) << "SetServerConfig failed with " << error_details;
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  signature.CopyToString(&server_config_sig_);
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  source_address_token.CopyToString(&source_address_token_);
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  certs_ = certs;
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const string& QuicCryptoClientConfig::CachedState::server_config() const {
2470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return server_config_;
2480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const string&
2510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicCryptoClientConfig::CachedState::source_address_token() const {
2520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return source_address_token_;
2530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const vector<string>& QuicCryptoClientConfig::CachedState::certs() const {
2560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return certs_;
2570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const string& QuicCryptoClientConfig::CachedState::signature() const {
2600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return server_config_sig_;
2610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool QuicCryptoClientConfig::CachedState::proof_valid() const {
2640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return server_config_valid_;
2650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)uint64 QuicCryptoClientConfig::CachedState::generation_counter() const {
2680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return generation_counter_;
2690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const ProofVerifyDetails*
2720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicCryptoClientConfig::CachedState::proof_verify_details() const {
2730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return proof_verify_details_.get();
2740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::CachedState::set_source_address_token(
2770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    StringPiece token) {
2780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  source_address_token_ = token.as_string();
2790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
2820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    ProofVerifyDetails* details) {
2830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  proof_verify_details_.reset(details);
2840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::CachedState::InitializeFrom(
2870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const QuicCryptoClientConfig::CachedState& other) {
2880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(server_config_.empty());
2890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(!server_config_valid_);
2900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  server_config_ = other.server_config_;
2910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  source_address_token_ = other.source_address_token_;
2920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  certs_ = other.certs_;
2930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  server_config_sig_ = other.server_config_sig_;
2940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  server_config_valid_ = other.server_config_valid_;
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (other.proof_verify_details_.get() != NULL) {
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    proof_verify_details_.reset(other.proof_verify_details_->Clone());
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ++generation_counter_;
2990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
3000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::SetDefaults() {
3020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Key exchange methods.
3030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  kexs.resize(2);
3040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  kexs[0] = kC255;
3050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  kexs[1] = kP256;
3060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
307effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Authenticated encryption algorithms. Prefer ChaCha20 by default.
308effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  aead.clear();
309effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (ChaCha20Poly1305Encrypter::IsSupported()) {
310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    aead.push_back(kCC12);
311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  aead.push_back(kAESG);
313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  disable_ecdsa_ = false;
3150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
3160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate(
318e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const QuicServerId& server_id) {
319e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  CachedStateMap::const_iterator it = cached_states_.find(server_id);
3200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (it != cached_states_.end()) {
3210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return it->second;
3220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  CachedState* cached = new CachedState;
325e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  cached_states_.insert(make_pair(server_id, cached));
326e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  PopulateFromCanonicalConfig(server_id, cached);
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return cached;
3280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
3290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid QuicCryptoClientConfig::ClearCachedStates() {
3310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (CachedStateMap::const_iterator it = cached_states_.begin();
3320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       it != cached_states_.end(); ++it) {
3335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    it->second->Clear();
3340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
3350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
3360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::FillInchoateClientHello(
338e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const QuicServerId& server_id,
339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const QuicVersion preferred_version,
3400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const CachedState* cached,
3410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    QuicCryptoNegotiatedParameters* out_params,
3420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CryptoHandshakeMessage* out) const {
3430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out->set_tag(kCHLO);
3440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out->set_minimum_size(kClientHelloMinimumSize);
3450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Server name indication. We only send SNI if it's a valid domain name, as
3470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // per the spec.
348e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (CryptoUtils::IsValidSNI(server_id.host())) {
349e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    out->SetStringPiece(kSNI, server_id.host());
3500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  out->SetValue(kVER, QuicVersionToQuicTag(preferred_version));
3520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
35346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!user_agent_id_.empty()) {
35446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    out->SetStringPiece(kUAID, user_agent_id_);
35546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
35646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!cached->source_address_token().empty()) {
3580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
3590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
361e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (server_id.is_https()) {
362effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (disable_ecdsa_) {
3630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      out->SetTaglist(kPDMD, kX59R, 0);
3640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    } else {
3650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      out->SetTaglist(kPDMD, kX509, 0);
3660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
3670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (common_cert_sets) {
3700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
3710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const vector<string>& certs = cached->certs();
3740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
3750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // client config is being used for multiple connections, another connection
3760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // doesn't update the cached certificates and cause us to be unable to
3770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // process the server's compressed certificate chain.
3780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out_params->cached_certs = certs;
3790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!certs.empty()) {
3800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    vector<uint64> hashes;
3810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    hashes.reserve(certs.size());
3820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    for (vector<string>::const_iterator i = certs.begin();
3830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)         i != certs.end(); ++i) {
3840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      hashes.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
3850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
3860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    out->SetVector(kCCRT, hashes);
3870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
3890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicErrorCode QuicCryptoClientConfig::FillClientHello(
391e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const QuicServerId& server_id,
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    QuicConnectionId connection_id,
393f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const QuicVersion preferred_version,
3940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const CachedState* cached,
3950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    QuicWallTime now,
3960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    QuicRandom* rand,
397f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ChannelIDKey* channel_id_key,
3980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    QuicCryptoNegotiatedParameters* out_params,
3990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CryptoHandshakeMessage* out,
4000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    string* error_details) const {
4010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(error_details != NULL);
4020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
403e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  FillInchoateClientHello(server_id, preferred_version, cached,
404f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          out_params, out);
4050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
4070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!scfg) {
4080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // This should never happen as our caller should have checked
4090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // cached->IsComplete() before calling this function.
4100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Handshake not ready";
4110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_CRYPTO_INTERNAL_ERROR;
4120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  StringPiece scid;
4150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!scfg->GetStringPiece(kSCID, &scid)) {
4160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "SCFG missing SCID";
4170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
4180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out->SetStringPiece(kSCID, scid);
4200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const QuicTag* their_aeads;
4220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const QuicTag* their_key_exchanges;
4230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  size_t num_their_aeads, num_their_key_exchanges;
4240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (scfg->GetTaglist(kAEAD, &their_aeads,
4250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                       &num_their_aeads) != QUIC_NO_ERROR ||
4260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      scfg->GetTaglist(kKEXS, &their_key_exchanges,
4270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                       &num_their_key_exchanges) != QUIC_NO_ERROR) {
4280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Missing AEAD or KEXS";
4290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
4300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
432effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // AEAD: the work loads on the client and server are symmetric. Since the
433effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // client is more likely to be CPU-constrained, break the tie by favoring
434effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // the client's preference.
435effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Key exchange: the client does more work than the server, so favor the
436effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // client's preference.
4370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  size_t key_exchange_index;
4380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!QuicUtils::FindMutualTag(
439effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          aead, their_aeads, num_their_aeads, QuicUtils::LOCAL_PRIORITY,
4400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          &out_params->aead, NULL) ||
4410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      !QuicUtils::FindMutualTag(
4420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          kexs, their_key_exchanges, num_their_key_exchanges,
443effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          QuicUtils::LOCAL_PRIORITY, &out_params->key_exchange,
4440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          &key_exchange_index)) {
4450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Unsupported AEAD or KEXS";
4460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_CRYPTO_NO_SUPPORT;
4470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out->SetTaglist(kAEAD, out_params->aead, 0);
4490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out->SetTaglist(kKEXS, out_params->key_exchange, 0);
4500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  StringPiece public_value;
4520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) !=
4530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          QUIC_NO_ERROR) {
4540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Missing public value";
4550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
4560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  StringPiece orbit;
4590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) {
4600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "SCFG missing OBIT";
4610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
4620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce);
4650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out->SetStringPiece(kNONC, out_params->client_nonce);
4660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!out_params->server_nonce.empty()) {
4670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    out->SetStringPiece(kServerNonceTag, out_params->server_nonce);
4680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  switch (out_params->key_exchange) {
4710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    case kC255:
4720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      out_params->client_key_exchange.reset(Curve25519KeyExchange::New(
4730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          Curve25519KeyExchange::NewPrivateKey(rand)));
4740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      break;
4750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    case kP256:
4760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      out_params->client_key_exchange.reset(P256KeyExchange::New(
4770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          P256KeyExchange::NewPrivateKey()));
4780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      break;
4790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    default:
4800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      DCHECK(false);
4810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      *error_details = "Configured to support an unknown key exchange";
4820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return QUIC_CRYPTO_INTERNAL_ERROR;
4830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!out_params->client_key_exchange->CalculateSharedKey(
4860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          public_value, &out_params->initial_premaster_secret)) {
4870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Key exchange failure";
4880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
4890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value());
4910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
492f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (channel_id_key) {
4930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // In order to calculate the encryption key for the CETV block we need to
4940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // serialise the client hello as it currently is (i.e. without the CETV
4950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // block). For this, the client hello is serialized without padding.
4960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const size_t orig_min_size = out->minimum_size();
4970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    out->set_minimum_size(0);
4980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CryptoHandshakeMessage cetv;
5000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    cetv.set_tag(kCETV);
5010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    string hkdf_input;
5030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const QuicData& client_hello_serialized = out->GetSerialized();
5040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    hkdf_input.append(QuicCryptoConfig::kCETVLabel,
5050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                      strlen(QuicCryptoConfig::kCETVLabel) + 1);
506a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    hkdf_input.append(reinterpret_cast<char*>(&connection_id),
507a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                      sizeof(connection_id));
5080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    hkdf_input.append(client_hello_serialized.data(),
5090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                      client_hello_serialized.length());
5100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    hkdf_input.append(cached->server_config());
5110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
512cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    string key = channel_id_key->SerializeKey();
513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    string signature;
514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!channel_id_key->Sign(hkdf_input, &signature)) {
5150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      *error_details = "Channel ID signature failed";
5160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return QUIC_INVALID_CHANNEL_ID_SIGNATURE;
5170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
5180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    cetv.SetStringPiece(kCIDK, key);
5200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    cetv.SetStringPiece(kCIDS, signature);
5210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CrypterPair crypters;
5230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (!CryptoUtils::DeriveKeys(out_params->initial_premaster_secret,
5240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                 out_params->aead, out_params->client_nonce,
5250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                 out_params->server_nonce, hkdf_input,
5265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                 CryptoUtils::CLIENT, &crypters,
5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                 NULL /* subkey secret */)) {
5280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      *error_details = "Symmetric key setup failed";
5290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
5300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
5310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const QuicData& cetv_plaintext = cetv.GetSerialized();
5330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    scoped_ptr<QuicData> cetv_ciphertext(crypters.encrypter->EncryptPacket(
5340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        0 /* sequence number */,
5350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        StringPiece() /* associated data */,
5360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        cetv_plaintext.AsStringPiece()));
5370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (!cetv_ciphertext.get()) {
5380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      *error_details = "Packet encryption failed";
5390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return QUIC_ENCRYPTION_FAILURE;
5400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
5410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    out->SetStringPiece(kCETV, cetv_ciphertext->AsStringPiece());
5430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    out->MarkDirty();
5440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    out->set_minimum_size(orig_min_size);
5460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
5470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
548f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Derive the symmetric keys and set up the encrypters and decrypters.
549f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Set the following members of out_params:
550f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  //   out_params->hkdf_input_suffix
551f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  //   out_params->initial_crypters
5520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out_params->hkdf_input_suffix.clear();
553a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&connection_id),
554a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                       sizeof(connection_id));
5550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const QuicData& client_hello_serialized = out->GetSerialized();
5560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out_params->hkdf_input_suffix.append(client_hello_serialized.data(),
5570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                       client_hello_serialized.length());
5580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  out_params->hkdf_input_suffix.append(cached->server_config());
5590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  string hkdf_input;
5610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
5620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
5630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
5640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  hkdf_input.append(out_params->hkdf_input_suffix);
5650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!CryptoUtils::DeriveKeys(
5670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)           out_params->initial_premaster_secret, out_params->aead,
5680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)           out_params->client_nonce, out_params->server_nonce, hkdf_input,
5695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           CryptoUtils::CLIENT, &out_params->initial_crypters,
5705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           NULL /* subkey secret */)) {
5710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Symmetric key setup failed";
5720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
5730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
5740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return QUIC_NO_ERROR;
5760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
5770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
578116680a4aac90f2aa7413d9095a592090648e557Ben MurdochQuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig(
579116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const CryptoHandshakeMessage& message,
5800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    QuicWallTime now,
581116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const vector<string>& cached_certs,
5820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CachedState* cached,
5830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    string* error_details) {
5840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(error_details != NULL);
5850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  StringPiece scfg;
587116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!message.GetStringPiece(kSCFG, &scfg)) {
5880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Missing SCFG";
5890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
5900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
5910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  QuicErrorCode error = cached->SetServerConfig(scfg, now, error_details);
5930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (error != QUIC_NO_ERROR) {
5940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return error;
5950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
5960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  StringPiece token;
598116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (message.GetStringPiece(kSourceAddressTokenTag, &token)) {
5990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    cached->set_source_address_token(token);
6000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
6010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  StringPiece proof, cert_bytes;
603116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool has_proof = message.GetStringPiece(kPROF, &proof);
604116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes);
6050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (has_proof && has_cert) {
6060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    vector<string> certs;
607116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!CertCompressor::DecompressChain(cert_bytes, cached_certs,
6080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                         common_cert_sets, &certs)) {
6090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      *error_details = "Certificate data invalid";
6100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
6110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
6120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    cached->SetProof(certs, proof);
6140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
6156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (proof_verifier() != NULL) {
6166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // Secure QUIC: clear existing proof as we have been sent a new SCFG
6176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // without matching proof/certs.
6186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      cached->ClearProof();
6196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
6206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
6210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (has_proof && !has_cert) {
6220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      *error_details = "Certificate missing";
6230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
6240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
6250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (!has_proof && has_cert) {
6270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      *error_details = "Proof missing";
6280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
6290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
6300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
6310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
632116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return QUIC_NO_ERROR;
633116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
634116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
635116680a4aac90f2aa7413d9095a592090648e557Ben MurdochQuicErrorCode QuicCryptoClientConfig::ProcessRejection(
636116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const CryptoHandshakeMessage& rej,
637116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QuicWallTime now,
638116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CachedState* cached,
6395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool is_https,
640116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QuicCryptoNegotiatedParameters* out_params,
641116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    string* error_details) {
642116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(error_details != NULL);
643116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
644116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (rej.tag() != kREJ) {
645116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    *error_details = "Message is not REJ";
646116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return QUIC_CRYPTO_INTERNAL_ERROR;
647116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
648116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
649116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  QuicErrorCode error = CacheNewServerConfig(rej, now, out_params->cached_certs,
650116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                             cached, error_details);
651116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (error != QUIC_NO_ERROR) {
652116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return error;
653116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
654116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
655116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  StringPiece nonce;
656116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
657116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    out_params->server_nonce = nonce.as_string();
658116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
659116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
660116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const uint32* reject_reasons;
6616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  size_t num_reject_reasons;
662116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  COMPILE_ASSERT(sizeof(QuicTag) == sizeof(uint32), header_out_of_sync);
6636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (rej.GetTaglist(kRREJ, &reject_reasons,
6646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                     &num_reject_reasons) == QUIC_NO_ERROR) {
665116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    uint32 packed_error = 0;
6666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    for (size_t i = 0; i < num_reject_reasons; ++i) {
667116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // HANDSHAKE_OK is 0 and don't report that as error.
668116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
669116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        continue;
670116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
671116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      HandshakeFailureReason reason =
672116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          static_cast<HandshakeFailureReason>(reject_reasons[i]);
673116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      packed_error |= 1 << (reason - 1);
6746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
675116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DVLOG(1) << "Reasons for rejection: " << packed_error;
6765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (is_https) {
6775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
6785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                  packed_error);
6795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
6805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Insecure",
6815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                  packed_error);
6825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
6836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
6846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
6850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return QUIC_NO_ERROR;
6860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
6870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
6890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const CryptoHandshakeMessage& server_hello,
690a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    QuicConnectionId connection_id,
691f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const QuicVersionVector& negotiated_versions,
6920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CachedState* cached,
6930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    QuicCryptoNegotiatedParameters* out_params,
6940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    string* error_details) {
6950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(error_details != NULL);
6960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (server_hello.tag() != kSHLO) {
6980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Bad tag";
6990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
7000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
7010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
702f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const QuicTag* supported_version_tags;
703f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  size_t num_supported_versions;
704a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
705f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (server_hello.GetTaglist(kVER, &supported_version_tags,
706a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                              &num_supported_versions) != QUIC_NO_ERROR) {
707a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *error_details = "server hello missing version list";
708a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
709a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
710a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!negotiated_versions.empty()) {
711a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool mismatch = num_supported_versions != negotiated_versions.size();
712a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (size_t i = 0; i < num_supported_versions && !mismatch; ++i) {
713a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      mismatch = QuicTagToQuicVersion(supported_version_tags[i]) !=
714a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          negotiated_versions[i];
715a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
716a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // The server sent a list of supported versions, and the connection
717a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // reports that there was a version negotiation during the handshake.
718f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Ensure that these two lists are identical.
719a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (mismatch) {
720a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *error_details = "Downgrade attack detected";
721a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return QUIC_VERSION_NEGOTIATION_MISMATCH;
722f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
723f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
724f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Learn about updated source address tokens.
7260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  StringPiece token;
7270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (server_hello.GetStringPiece(kSourceAddressTokenTag, &token)) {
7280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    cached->set_source_address_token(token);
7290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
7300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
7310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // TODO(agl):
7320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  //   learn about updated SCFGs.
7330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
7340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  StringPiece public_value;
7350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!server_hello.GetStringPiece(kPUBS, &public_value)) {
7360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "server hello missing forward secure public value";
7370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
7380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
7390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
7400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!out_params->client_key_exchange->CalculateSharedKey(
7410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          public_value, &out_params->forward_secure_premaster_secret)) {
7420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Key exchange failure";
7430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
7440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
7450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
7460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  string hkdf_input;
7470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
7480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
7490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len);
7500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  hkdf_input.append(out_params->hkdf_input_suffix);
7510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
7520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!CryptoUtils::DeriveKeys(
7530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)           out_params->forward_secure_premaster_secret, out_params->aead,
7540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)           out_params->client_nonce, out_params->server_nonce, hkdf_input,
7555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           CryptoUtils::CLIENT, &out_params->forward_secure_crypters,
7565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           &out_params->subkey_secret)) {
7570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *error_details = "Symmetric key setup failed";
7580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
7590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
7600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
7610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return QUIC_NO_ERROR;
7620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
7630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
764116680a4aac90f2aa7413d9095a592090648e557Ben MurdochQuicErrorCode QuicCryptoClientConfig::ProcessServerConfigUpdate(
765116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const CryptoHandshakeMessage& server_config_update,
766116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QuicWallTime now,
767116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CachedState* cached,
768116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QuicCryptoNegotiatedParameters* out_params,
769116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    string* error_details) {
770116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(error_details != NULL);
771116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
772116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (server_config_update.tag() != kSCUP) {
773116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    *error_details = "ServerConfigUpdate must have kSCUP tag.";
774116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
775116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
776116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
777116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return CacheNewServerConfig(server_config_update, now,
778116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                              out_params->cached_certs, cached, error_details);
779116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
780116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
7810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
7820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return proof_verifier_.get();
7830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
7840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
7850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier* verifier) {
7860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  proof_verifier_.reset(verifier);
7870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
7880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
789cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const {
790cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return channel_id_source_.get();
7910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
7920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
793cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource* source) {
794cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  channel_id_source_.reset(source);
7950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
7960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
7970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicCryptoClientConfig::InitializeFrom(
798e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const QuicServerId& server_id,
799e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const QuicServerId& canonical_server_id,
8000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    QuicCryptoClientConfig* canonical_crypto_config) {
8010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  CachedState* canonical_cached =
802e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      canonical_crypto_config->LookupOrCreate(canonical_server_id);
8030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!canonical_cached->proof_valid()) {
8040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
8050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
806e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  CachedState* cached = LookupOrCreate(server_id);
8070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  cached->InitializeFrom(*canonical_cached);
8080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
8090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
810effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid QuicCryptoClientConfig::AddCanonicalSuffix(const string& suffix) {
811effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  canoncial_suffixes_.push_back(suffix);
812effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
813effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
814effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid QuicCryptoClientConfig::PreferAesGcm() {
815effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(!aead.empty());
816effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (aead.size() <= 1) {
817effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
818effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
819effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  QuicTagVector::iterator pos = find(aead.begin(), aead.end(), kAESG);
820effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (pos != aead.end()) {
821effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    aead.erase(pos);
822effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    aead.insert(aead.begin(), kAESG);
823effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
824effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
825effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
826effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid QuicCryptoClientConfig::DisableEcdsa() {
827effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  disable_ecdsa_ = true;
828effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
829effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
830effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid QuicCryptoClientConfig::PopulateFromCanonicalConfig(
831e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const QuicServerId& server_id,
832effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    CachedState* server_state) {
833effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(server_state->IsEmpty());
834c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  size_t i = 0;
835effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (; i < canoncial_suffixes_.size(); ++i) {
836e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (EndsWith(server_id.host(), canoncial_suffixes_[i], false)) {
837effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
838effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
839effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
840effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (i == canoncial_suffixes_.size())
841effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
842effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
843e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  QuicServerId suffix_server_id(canoncial_suffixes_[i], server_id.port(),
844e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                server_id.is_https(),
845e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                server_id.privacy_mode());
846e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (!ContainsKey(canonical_server_map_, suffix_server_id)) {
847effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // This is the first host we've seen which matches the suffix, so make it
848effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // canonical.
849e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    canonical_server_map_[suffix_server_id] = server_id;
850effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
851effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
852effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
853e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  const QuicServerId& canonical_server_id =
854e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      canonical_server_map_[suffix_server_id];
855e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  CachedState* canonical_state = cached_states_[canonical_server_id];
856effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!canonical_state->proof_valid()) {
857effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
858effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
859effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
860effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Update canonical version to point at the "most recent" entry.
861e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  canonical_server_map_[suffix_server_id] = server_id;
862effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
863effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  server_state->InitializeFrom(*canonical_state);
864effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
865effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
8660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}  // namespace net
867