| Index: net/quic/crypto/crypto_handshake.cc
|
| diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
|
| index 1d9b01b809f06d3c018d88ba7f726bb0a743c309..59ecd425e7972d4894428f718519d40422535c49 100644
|
| --- a/net/quic/crypto/crypto_handshake.cc
|
| +++ b/net/quic/crypto/crypto_handshake.cc
|
| @@ -10,11 +10,8 @@
|
| #include "base/stl_util.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_split.h"
|
| -#include "crypto/hkdf.h"
|
| #include "crypto/secure_hash.h"
|
| #include "net/base/net_util.h"
|
| -#include "net/quic/crypto/aes_128_gcm_decrypter.h"
|
| -#include "net/quic/crypto/aes_128_gcm_encrypter.h"
|
| #include "net/quic/crypto/crypto_framer.h"
|
| #include "net/quic/crypto/crypto_utils.h"
|
| #include "net/quic/crypto/curve25519_key_exchange.h"
|
| @@ -23,7 +20,6 @@
|
| #include "net/quic/crypto/quic_decrypter.h"
|
| #include "net/quic/crypto/quic_encrypter.h"
|
| #include "net/quic/crypto/quic_random.h"
|
| -#include "net/quic/crypto/strike_register.h"
|
| #include "net/quic/quic_clock.h"
|
| #include "net/quic/quic_protocol.h"
|
|
|
| @@ -35,23 +31,6 @@ using std::vector;
|
|
|
| namespace net {
|
|
|
| -// kVersion contains the one (and, for the moment, only) version number that we
|
| -// implement.
|
| -static const uint16 kVersion = 0;
|
| -
|
| -// kLabel is constant that is used in key derivation to tie the resulting key
|
| -// to this protocol.
|
| -static const char kLabel[] = "QUIC key expansion";
|
| -
|
| -using crypto::SecureHash;
|
| -
|
| -QuicServerConfigProtobuf::QuicServerConfigProtobuf() {
|
| -}
|
| -
|
| -QuicServerConfigProtobuf::~QuicServerConfigProtobuf() {
|
| - STLDeleteElements(&keys_);
|
| -}
|
| -
|
| CryptoHandshakeMessage::CryptoHandshakeMessage() : tag_(0) {}
|
|
|
| CryptoHandshakeMessage::CryptoHandshakeMessage(
|
| @@ -284,6 +263,7 @@ string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
|
| case kKEXS:
|
| case kAEAD:
|
| case kCGST:
|
| + case kPDMD:
|
| // tag lists
|
| if (it->second.size() % sizeof(CryptoTag) == 0) {
|
| for (size_t j = 0; j < it->second.size(); j += sizeof(CryptoTag)) {
|
| @@ -324,35 +304,6 @@ string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
|
| return ret;
|
| }
|
|
|
| -SourceAddressToken::SourceAddressToken() {
|
| -}
|
| -
|
| -SourceAddressToken::~SourceAddressToken() {
|
| -}
|
| -
|
| -string SourceAddressToken::SerializeAsString() const {
|
| - return ip_ + " " + base::Int64ToString(timestamp_);
|
| -}
|
| -
|
| -bool SourceAddressToken::ParseFromArray(unsigned char* plaintext,
|
| - size_t plaintext_length) {
|
| - string data(reinterpret_cast<const char*>(plaintext), plaintext_length);
|
| - std::vector<std::string> results;
|
| - base::SplitString(data, ' ', &results);
|
| - if (results.size() < 2) {
|
| - return false;
|
| - }
|
| -
|
| - int64 timestamp;
|
| - if (!base::StringToInt64(results[1], ×tamp)) {
|
| - return false;
|
| - }
|
| -
|
| - ip_ = results[0];
|
| - timestamp_ = timestamp;
|
| - return true;
|
| -}
|
| -
|
| QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
|
| : version(0),
|
| key_exchange(0),
|
| @@ -363,6 +314,9 @@ QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {
|
| }
|
|
|
|
|
| +// static
|
| +const char QuicCryptoConfig::kLabel[] = "QUIC key expansion";
|
| +
|
| QuicCryptoConfig::QuicCryptoConfig()
|
| : version(0) {
|
| }
|
| @@ -428,7 +382,7 @@ void QuicCryptoClientConfig::CachedState::set_source_address_token(
|
|
|
| void QuicCryptoClientConfig::SetDefaults() {
|
| // Version must be 0.
|
| - version = kVersion;
|
| + version = QuicCryptoConfig::CONFIG_VERSION;
|
|
|
| // Key exchange methods.
|
| kexs.resize(2);
|
| @@ -468,6 +422,8 @@ void QuicCryptoClientConfig::FillInchoateClientHello(
|
| if (cached && !cached->source_address_token().empty()) {
|
| out->SetStringPiece(kSRCT, cached->source_address_token());
|
| }
|
| +
|
| + out->SetTaglist(kPDMD, kX509, 0);
|
| }
|
|
|
| QuicErrorCode QuicCryptoClientConfig::FillClientHello(
|
| @@ -479,34 +435,30 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
|
| QuicCryptoNegotiatedParameters* out_params,
|
| CryptoHandshakeMessage* out,
|
| string* error_details) const {
|
| + DCHECK(error_details != NULL);
|
| +
|
| FillInchoateClientHello(server_hostname, cached, out);
|
|
|
| const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
|
| if (!scfg) {
|
| // This should never happen as our caller should have checked
|
| // cached->is_complete() before calling this function.
|
| - if (error_details) {
|
| - *error_details = "Handshake not ready";
|
| - }
|
| + *error_details = "Handshake not ready";
|
| return QUIC_CRYPTO_INTERNAL_ERROR;
|
| }
|
|
|
| StringPiece scid;
|
| if (!scfg->GetStringPiece(kSCID, &scid)) {
|
| - if (error_details) {
|
| - *error_details = "SCFG missing SCID";
|
| - }
|
| + *error_details = "SCFG missing SCID";
|
| return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
|
| }
|
| out->SetStringPiece(kSCID, scid);
|
|
|
| // Calculate the mutual algorithms that the connection is going to use.
|
| if (scfg->GetUint16(kVERS, &out_params->version) != QUIC_NO_ERROR ||
|
| - out_params->version != kVersion) {
|
| - if (error_details) {
|
| - *error_details = "Bad version";
|
| - }
|
| - return QUIC_VERSION_NOT_SUPPORTED;
|
| + out_params->version != QuicCryptoConfig::CONFIG_VERSION) {
|
| + *error_details = "Bad version";
|
| + return QUIC_CRYPTO_VERSION_NOT_SUPPORTED;
|
| }
|
|
|
| const CryptoTag* their_aeads;
|
| @@ -516,9 +468,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
|
| &num_their_aeads) != QUIC_NO_ERROR ||
|
| scfg->GetTaglist(kKEXS, &their_key_exchanges,
|
| &num_their_key_exchanges) != QUIC_NO_ERROR) {
|
| - if (error_details) {
|
| - *error_details = "Missing AEAD or KEXS";
|
| - }
|
| + *error_details = "Missing AEAD or KEXS";
|
| return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
|
| }
|
|
|
| @@ -533,9 +483,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
|
| CryptoUtils::PEER_PRIORITY,
|
| &out_params->key_exchange,
|
| &key_exchange_index)) {
|
| - if (error_details) {
|
| - *error_details = "Unsupported AEAD or KEXS";
|
| - }
|
| + *error_details = "Unsupported AEAD or KEXS";
|
| return QUIC_CRYPTO_NO_SUPPORT;
|
| }
|
| out->SetTaglist(kAEAD, out_params->aead, 0);
|
| @@ -544,18 +492,14 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
|
| StringPiece public_value;
|
| if (scfg->GetNthValue16(kPUBS, key_exchange_index, &public_value) !=
|
| QUIC_NO_ERROR) {
|
| - if (error_details) {
|
| - *error_details = "Missing public value";
|
| - }
|
| + *error_details = "Missing public value";
|
| return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
|
| }
|
|
|
| StringPiece orbit;
|
| if (!scfg->GetStringPiece(kORBT, &orbit) ||
|
| orbit.size() != kOrbitSize) {
|
| - if (error_details) {
|
| - *error_details = "SCFG missing OBIT";
|
| - }
|
| + *error_details = "SCFG missing OBIT";
|
| return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
|
| }
|
|
|
| @@ -576,22 +520,19 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
|
| break;
|
| default:
|
| DCHECK(false);
|
| - if (error_details) {
|
| - *error_details = "Configured to support an unknown key exchange";
|
| - }
|
| + *error_details = "Configured to support an unknown key exchange";
|
| return QUIC_CRYPTO_INTERNAL_ERROR;
|
| }
|
|
|
| if (!key_exchange->CalculateSharedKey(public_value,
|
| &out_params->premaster_secret)) {
|
| - if (error_details) {
|
| - *error_details = "Key exchange failure";
|
| - }
|
| + *error_details = "Key exchange failure";
|
| return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
|
| }
|
| out->SetStringPiece(kPUBS, key_exchange->public_value());
|
|
|
| - string hkdf_input(kLabel, arraysize(kLabel));
|
| + string hkdf_input(QuicCryptoConfig::kLabel,
|
| + strlen(QuicCryptoConfig::kLabel) + 1);
|
| hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid));
|
|
|
| const QuicData& client_hello_serialized = out->GetSerialized();
|
| @@ -609,8 +550,9 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
|
| const CryptoHandshakeMessage& rej,
|
| QuicCryptoNegotiatedParameters* out_params,
|
| string* error_details) {
|
| - CachedState* cached;
|
| + DCHECK(error_details != NULL);
|
|
|
| + CachedState* cached;
|
| map<string, CachedState*>::const_iterator it =
|
| cached_states_.find(server_hostname);
|
| if (it == cached_states_.end()) {
|
| @@ -622,16 +564,12 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
|
|
|
| StringPiece scfg;
|
| if (!rej.GetStringPiece(kSCFG, &scfg)) {
|
| - if (error_details) {
|
| - *error_details = "Missing SCFG";
|
| - }
|
| + *error_details = "Missing SCFG";
|
| return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
|
| }
|
|
|
| if (!cached->SetServerConfig(scfg)) {
|
| - if (error_details) {
|
| - *error_details = "Invalid SCFG";
|
| - }
|
| + *error_details = "Invalid SCFG";
|
| return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
|
| }
|
|
|
| @@ -654,6 +592,8 @@ QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
|
| const string& nonce,
|
| QuicCryptoNegotiatedParameters* out_params,
|
| string* error_details) {
|
| + DCHECK(error_details != NULL);
|
| +
|
| if (server_hello.tag() != kSHLO) {
|
| *error_details = "Bad tag";
|
| return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
|
| @@ -666,495 +606,4 @@ QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
|
| return QUIC_NO_ERROR;
|
| }
|
|
|
| -// static
|
| -const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
|
| -
|
| -QuicCryptoServerConfig::QuicCryptoServerConfig(
|
| - StringPiece source_address_token_secret)
|
| - // AES-GCM is used to encrypt and authenticate source address tokens. The
|
| - // full, 96-bit nonce is used but we must ensure that an attacker cannot
|
| - // obtain two source address tokens with the same nonce. This occurs with
|
| - // probability 0.5 after 2**48 values. We assume that obtaining 2**48
|
| - // source address tokens is not possible: at a rate of 10M packets per
|
| - // second, it would still take the attacker a year to obtain the needed
|
| - // number of packets.
|
| - //
|
| - // TODO(agl): switch to an encrypter with a larger nonce space (i.e.
|
| - // Salsa20+Poly1305).
|
| - : strike_register_lock_(),
|
| - source_address_token_encrypter_(new Aes128GcmEncrypter),
|
| - source_address_token_decrypter_(new Aes128GcmDecrypter) {
|
| - crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
|
| - "QUIC source address token key",
|
| - source_address_token_encrypter_->GetKeySize(),
|
| - 0 /* no fixed IV needed */);
|
| - source_address_token_encrypter_->SetKey(hkdf.server_write_key());
|
| - source_address_token_decrypter_->SetKey(hkdf.server_write_key());
|
| -}
|
| -
|
| -QuicCryptoServerConfig::~QuicCryptoServerConfig() {
|
| - STLDeleteValues(&configs_);
|
| -}
|
| -
|
| -// static
|
| -QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig(
|
| - QuicRandom* rand,
|
| - const QuicClock* clock,
|
| - const CryptoHandshakeMessage& extra_tags) {
|
| - CryptoHandshakeMessage msg;
|
| -
|
| - const string curve25519_private_key =
|
| - Curve25519KeyExchange::NewPrivateKey(rand);
|
| - scoped_ptr<Curve25519KeyExchange> curve25519(
|
| - Curve25519KeyExchange::New(curve25519_private_key));
|
| - StringPiece curve25519_public_value = curve25519->public_value();
|
| -
|
| - const string p256_private_key =
|
| - P256KeyExchange::NewPrivateKey();
|
| - scoped_ptr<P256KeyExchange> p256(
|
| - P256KeyExchange::New(p256_private_key));
|
| - StringPiece p256_public_value = p256->public_value();
|
| -
|
| - string encoded_public_values;
|
| - // First two bytes encode the length of the public value.
|
| - encoded_public_values.push_back(curve25519_public_value.size());
|
| - encoded_public_values.push_back(curve25519_public_value.size() >> 8);
|
| - encoded_public_values.append(curve25519_public_value.data(),
|
| - curve25519_public_value.size());
|
| - encoded_public_values.push_back(p256_public_value.size());
|
| - encoded_public_values.push_back(p256_public_value.size() >> 8);
|
| - encoded_public_values.append(p256_public_value.data(),
|
| - p256_public_value.size());
|
| -
|
| - msg.set_tag(kSCFG);
|
| - msg.SetTaglist(kKEXS, kC255, kP256, 0);
|
| - msg.SetTaglist(kAEAD, kAESG, 0);
|
| - msg.SetValue(kVERS, static_cast<uint16>(0));
|
| - msg.SetStringPiece(kPUBS, encoded_public_values);
|
| - msg.Insert(extra_tags.tag_value_map().begin(),
|
| - extra_tags.tag_value_map().end());
|
| -
|
| - char scid_bytes[16];
|
| - rand->RandBytes(scid_bytes, sizeof(scid_bytes));
|
| - msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes)));
|
| -
|
| - char orbit_bytes[kOrbitSize];
|
| - rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
|
| - msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes)));
|
| -
|
| - scoped_ptr<QuicData> serialized(
|
| - CryptoFramer::ConstructHandshakeMessage(msg));
|
| -
|
| - scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf);
|
| - config->set_config(serialized->AsStringPiece());
|
| - QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key();
|
| - curve25519_key->set_tag(kC255);
|
| - curve25519_key->set_private_key(curve25519_private_key);
|
| - QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key();
|
| - p256_key->set_tag(kP256);
|
| - p256_key->set_private_key(p256_private_key);
|
| -
|
| - return config.release();
|
| -}
|
| -
|
| -CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
|
| - QuicServerConfigProtobuf* protobuf) {
|
| - scoped_ptr<CryptoHandshakeMessage> msg(
|
| - CryptoFramer::ParseMessage(protobuf->config()));
|
| -
|
| - if (!msg.get()) {
|
| - LOG(WARNING) << "Failed to parse server config message";
|
| - return NULL;
|
| - }
|
| - if (msg->tag() != kSCFG) {
|
| - LOG(WARNING) << "Server config message has tag "
|
| - << msg->tag() << " expected "
|
| - << kSCFG;
|
| - return NULL;
|
| - }
|
| -
|
| - scoped_ptr<Config> config(new Config);
|
| - config->serialized = protobuf->config();
|
| -
|
| - StringPiece scid;
|
| - if (!msg->GetStringPiece(kSCID, &scid)) {
|
| - LOG(WARNING) << "Server config message is missing SCID";
|
| - return NULL;
|
| - }
|
| - config->id = scid.as_string();
|
| -
|
| - const CryptoTag* aead_tags;
|
| - size_t aead_len;
|
| - if (msg->GetTaglist(kAEAD, &aead_tags, &aead_len) != QUIC_NO_ERROR) {
|
| - LOG(WARNING) << "Server config message is missing AEAD";
|
| - return NULL;
|
| - }
|
| - config->aead = vector<CryptoTag>(aead_tags, aead_tags + aead_len);
|
| -
|
| - const CryptoTag* kexs_tags;
|
| - size_t kexs_len;
|
| - if (msg->GetTaglist(kKEXS, &kexs_tags, &kexs_len) != QUIC_NO_ERROR) {
|
| - LOG(WARNING) << "Server config message is missing KEXS";
|
| - return NULL;
|
| - }
|
| -
|
| - StringPiece orbit;
|
| - if (!msg->GetStringPiece(kORBT, &orbit)) {
|
| - LOG(WARNING) << "Server config message is missing OBIT";
|
| - return NULL;
|
| - }
|
| -
|
| - if (orbit.size() != kOrbitSize) {
|
| - LOG(WARNING) << "Orbit value in server config is the wrong length."
|
| - " Got " << orbit.size() << " want " << kOrbitSize;
|
| - return NULL;
|
| - }
|
| - COMPILE_ASSERT(sizeof(config->orbit) == kOrbitSize, orbit_incorrect_size);
|
| - memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
|
| -
|
| - if (kexs_len != protobuf->key_size()) {
|
| - LOG(WARNING) << "Server config has "
|
| - << kexs_len
|
| - << " key exchange methods configured, but "
|
| - << protobuf->key_size()
|
| - << " private keys";
|
| - return NULL;
|
| - }
|
| -
|
| - for (size_t i = 0; i < kexs_len; i++) {
|
| - const CryptoTag tag = kexs_tags[i];
|
| - string private_key;
|
| -
|
| - config->kexs.push_back(tag);
|
| -
|
| - for (size_t j = 0; j < protobuf->key_size(); j++) {
|
| - const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i);
|
| - if (key.tag() == tag) {
|
| - private_key = key.private_key();
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (private_key.empty()) {
|
| - LOG(WARNING) << "Server config contains key exchange method without "
|
| - "corresponding private key: "
|
| - << tag;
|
| - return NULL;
|
| - }
|
| -
|
| - scoped_ptr<KeyExchange> ka;
|
| - switch (tag) {
|
| - case kC255:
|
| - ka.reset(Curve25519KeyExchange::New(private_key));
|
| - if (!ka.get()) {
|
| - LOG(WARNING) << "Server config contained an invalid curve25519"
|
| - " private key.";
|
| - return NULL;
|
| - }
|
| - break;
|
| - case kP256:
|
| - ka.reset(P256KeyExchange::New(private_key));
|
| - if (!ka.get()) {
|
| - LOG(WARNING) << "Server config contained an invalid P-256"
|
| - " private key.";
|
| - return NULL;
|
| - }
|
| - break;
|
| - default:
|
| - LOG(WARNING) << "Server config message contains unknown key exchange "
|
| - "method: "
|
| - << tag;
|
| - return NULL;
|
| - }
|
| -
|
| - for (vector<KeyExchange*>::const_iterator i = config->key_exchanges.begin();
|
| - i != config->key_exchanges.end(); ++i) {
|
| - if ((*i)->tag() == tag) {
|
| - LOG(WARNING) << "Duplicate key exchange in config: " << tag;
|
| - return NULL;
|
| - }
|
| - }
|
| -
|
| - config->key_exchanges.push_back(ka.release());
|
| - }
|
| -
|
| - if (msg->GetUint16(kVERS, &config->version) != QUIC_NO_ERROR) {
|
| - LOG(WARNING) << "Server config message is missing version";
|
| - return NULL;
|
| - }
|
| -
|
| - if (config->version != kVersion) {
|
| - LOG(WARNING) << "Server config specifies an unsupported version";
|
| - return NULL;
|
| - }
|
| -
|
| - scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256));
|
| - sha256->Update(protobuf->config().data(), protobuf->config().size());
|
| - char id_bytes[16];
|
| - sha256->Finish(id_bytes, sizeof(id_bytes));
|
| - const string id(id_bytes, sizeof(id_bytes));
|
| -
|
| - configs_[id] = config.release();
|
| - active_config_ = id;
|
| -
|
| - return msg.release();
|
| -}
|
| -
|
| -CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig(
|
| - QuicRandom* rand,
|
| - const QuicClock* clock,
|
| - const CryptoHandshakeMessage& extra_tags) {
|
| - scoped_ptr<QuicServerConfigProtobuf> config(DefaultConfig(
|
| - rand, clock, extra_tags));
|
| - return AddConfig(config.get());
|
| -}
|
| -
|
| -QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
|
| - const CryptoHandshakeMessage& client_hello,
|
| - QuicGuid guid,
|
| - const IPEndPoint& client_ip,
|
| - QuicTime::Delta now_since_unix_epoch,
|
| - QuicRandom* rand,
|
| - QuicCryptoNegotiatedParameters *params,
|
| - CryptoHandshakeMessage* out,
|
| - string* error_details) const {
|
| - CHECK(!configs_.empty());
|
| - // FIXME(agl): we should use the client's SCID, not just the active config.
|
| - map<ServerConfigID, Config*>::const_iterator it =
|
| - configs_.find(active_config_);
|
| - if (it == configs_.end()) {
|
| - *error_details = "No valid server config loaded";
|
| - return QUIC_CRYPTO_INTERNAL_ERROR;
|
| - }
|
| - const Config* const config(it->second);
|
| -
|
| - bool valid_source_address_token = false;
|
| - StringPiece srct;
|
| - if (client_hello.GetStringPiece(kSRCT, &srct) &&
|
| - ValidateSourceAddressToken(srct, client_ip, now_since_unix_epoch)) {
|
| - valid_source_address_token = true;
|
| - }
|
| -
|
| - const string fresh_source_address_token =
|
| - NewSourceAddressToken(client_ip, rand, now_since_unix_epoch);
|
| -
|
| - // If we previously sent a REJ to this client then we may have stored a
|
| - // server nonce in |params|. In which case, we know that the connection
|
| - // is unique because the server nonce will be mixed into the key generation.
|
| - bool unique_by_server_nonce = !params->server_nonce.empty();
|
| - // If we can't ensure uniqueness by a server nonce, then we will try and use
|
| - // the strike register.
|
| - bool unique_by_strike_register = false;
|
| -
|
| - StringPiece client_nonce;
|
| - bool client_nonce_well_formed = false;
|
| - if (client_hello.GetStringPiece(kNONC, &client_nonce) &&
|
| - client_nonce.size() == kNonceSize) {
|
| - client_nonce_well_formed = true;
|
| - if (!unique_by_server_nonce) {
|
| - base::AutoLock auto_lock(strike_register_lock_);
|
| -
|
| - if (strike_register_.get() == NULL) {
|
| - strike_register_.reset(new StrikeRegister(
|
| - // TODO(agl): these magic numbers should come from config.
|
| - 1024 /* max entries */,
|
| - static_cast<uint32>(now_since_unix_epoch.ToSeconds()),
|
| - 600 /* window secs */, config->orbit));
|
| - }
|
| - unique_by_strike_register = strike_register_->Insert(
|
| - reinterpret_cast<const uint8*>(client_nonce.data()),
|
| - static_cast<uint32>(now_since_unix_epoch.ToSeconds()));
|
| - }
|
| - }
|
| -
|
| - StringPiece scid;
|
| - if (!client_hello.GetStringPiece(kSCID, &scid) ||
|
| - scid.as_string() != config->id ||
|
| - !valid_source_address_token ||
|
| - !client_nonce_well_formed ||
|
| - (!unique_by_strike_register &&
|
| - !unique_by_server_nonce)) {
|
| - // If the client didn't provide a server config ID, or gave the wrong one,
|
| - // then the handshake cannot possibly complete. We reject the handshake and
|
| - // give the client enough information to do better next time.
|
| - out->Clear();
|
| - out->set_tag(kREJ);
|
| - out->SetStringPiece(kSCFG, config->serialized);
|
| - out->SetStringPiece(kSRCT, fresh_source_address_token);
|
| - if (params->server_nonce.empty()) {
|
| - CryptoUtils::GenerateNonce(
|
| - now_since_unix_epoch, rand,
|
| - StringPiece(reinterpret_cast<const char*>(config->orbit),
|
| - sizeof(config->orbit)),
|
| - ¶ms->server_nonce);
|
| - }
|
| - out->SetStringPiece(kNONC, params->server_nonce);
|
| - return QUIC_NO_ERROR;
|
| - }
|
| -
|
| - const CryptoTag* their_aeads;
|
| - const CryptoTag* their_key_exchanges;
|
| - size_t num_their_aeads, num_their_key_exchanges;
|
| - if (client_hello.GetTaglist(kAEAD, &their_aeads,
|
| - &num_their_aeads) != QUIC_NO_ERROR ||
|
| - client_hello.GetTaglist(kKEXS, &their_key_exchanges,
|
| - &num_their_key_exchanges) != QUIC_NO_ERROR ||
|
| - num_their_aeads != 1 ||
|
| - num_their_key_exchanges != 1) {
|
| - if (error_details) {
|
| - *error_details = "Missing or invalid AEAD or KEXS";
|
| - }
|
| - return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
|
| - }
|
| -
|
| - size_t key_exchange_index;
|
| - if (!CryptoUtils::FindMutualTag(config->aead,
|
| - their_aeads, num_their_aeads,
|
| - CryptoUtils::LOCAL_PRIORITY,
|
| - ¶ms->aead,
|
| - NULL) ||
|
| - !CryptoUtils::FindMutualTag(config->kexs,
|
| - their_key_exchanges, num_their_key_exchanges,
|
| - CryptoUtils::LOCAL_PRIORITY,
|
| - ¶ms->key_exchange,
|
| - &key_exchange_index)) {
|
| - if (error_details) {
|
| - *error_details = "Unsupported AEAD or KEXS";
|
| - }
|
| - return QUIC_CRYPTO_NO_SUPPORT;
|
| - }
|
| -
|
| - StringPiece public_value;
|
| - if (!client_hello.GetStringPiece(kPUBS, &public_value)) {
|
| - if (error_details) {
|
| - *error_details = "Missing public value";
|
| - }
|
| - return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
|
| - }
|
| -
|
| - if (!config->key_exchanges[key_exchange_index]->CalculateSharedKey(
|
| - public_value, ¶ms->premaster_secret)) {
|
| - if (error_details) {
|
| - *error_details = "Invalid public value";
|
| - }
|
| - return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
|
| - }
|
| -
|
| - params->server_config_id = scid.as_string();
|
| -
|
| - string hkdf_input(kLabel, arraysize(kLabel));
|
| - hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid));
|
| -
|
| - const QuicData& client_hello_serialized = client_hello.GetSerialized();
|
| - hkdf_input.append(client_hello_serialized.data(),
|
| - client_hello_serialized.length());
|
| - hkdf_input.append(config->serialized);
|
| -
|
| - CryptoUtils::DeriveKeys(params, client_nonce, hkdf_input,
|
| - CryptoUtils::SERVER);
|
| -
|
| - out->set_tag(kSHLO);
|
| - out->SetStringPiece(kSRCT, fresh_source_address_token);
|
| - return QUIC_NO_ERROR;
|
| -}
|
| -
|
| -string QuicCryptoServerConfig::NewSourceAddressToken(
|
| - const IPEndPoint& ip,
|
| - QuicRandom* rand,
|
| - QuicTime::Delta now_since_epoch) const {
|
| - SourceAddressToken source_address_token;
|
| - source_address_token.set_ip(ip.ToString());
|
| - source_address_token.set_timestamp(now_since_epoch.ToSeconds());
|
| -
|
| - string plaintext = source_address_token.SerializeAsString();
|
| - char nonce[12];
|
| - DCHECK_EQ(sizeof(nonce),
|
| - source_address_token_encrypter_->GetNoncePrefixSize() +
|
| - sizeof(QuicPacketSequenceNumber));
|
| - rand->RandBytes(nonce, sizeof(nonce));
|
| -
|
| - size_t ciphertext_size =
|
| - source_address_token_encrypter_->GetCiphertextSize(plaintext.size());
|
| - string result;
|
| - result.resize(sizeof(nonce) + ciphertext_size);
|
| - memcpy(&result[0], &nonce, sizeof(nonce));
|
| -
|
| - if (!source_address_token_encrypter_->Encrypt(
|
| - StringPiece(nonce, sizeof(nonce)), StringPiece(), plaintext,
|
| - reinterpret_cast<unsigned char*>(&result[sizeof(nonce)]))) {
|
| - DCHECK(false);
|
| - return string();
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -bool QuicCryptoServerConfig::ValidateSourceAddressToken(
|
| - StringPiece token,
|
| - const IPEndPoint& ip,
|
| - QuicTime::Delta now_since_epoch) const {
|
| - char nonce[12];
|
| - DCHECK_EQ(sizeof(nonce),
|
| - source_address_token_encrypter_->GetNoncePrefixSize() +
|
| - sizeof(QuicPacketSequenceNumber));
|
| -
|
| - if (token.size() <= sizeof(nonce)) {
|
| - return false;
|
| - }
|
| - memcpy(&nonce, token.data(), sizeof(nonce));
|
| - token.remove_prefix(sizeof(nonce));
|
| -
|
| - unsigned char plaintext_stack[128];
|
| - scoped_ptr<unsigned char[]> plaintext_heap;
|
| - unsigned char* plaintext;
|
| - if (token.size() <= sizeof(plaintext_stack)) {
|
| - plaintext = plaintext_stack;
|
| - } else {
|
| - plaintext_heap.reset(new unsigned char[token.size()]);
|
| - plaintext = plaintext_heap.get();
|
| - }
|
| - size_t plaintext_length;
|
| -
|
| - if (!source_address_token_decrypter_->Decrypt(
|
| - StringPiece(nonce, sizeof(nonce)), StringPiece(), token,
|
| - plaintext, &plaintext_length)) {
|
| - return false;
|
| - }
|
| -
|
| - SourceAddressToken source_address_token;
|
| - if (!source_address_token.ParseFromArray(plaintext, plaintext_length)) {
|
| - return false;
|
| - }
|
| -
|
| - if (source_address_token.ip() != ip.ToString()) {
|
| - // It's for a different IP address.
|
| - return false;
|
| - }
|
| -
|
| - const QuicTime::Delta delta(now_since_epoch.Subtract(
|
| - QuicTime::Delta::FromSeconds(source_address_token.timestamp())));
|
| - const int64 delta_secs = delta.ToSeconds();
|
| -
|
| - // TODO(agl): consider whether and how these magic values should be moved to
|
| - // a config.
|
| - if (delta_secs < -3600) {
|
| - // We only allow timestamps to be from an hour in the future.
|
| - return false;
|
| - }
|
| -
|
| - if (delta_secs > 86400) {
|
| - // We allow one day into the past.
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -QuicCryptoServerConfig::Config::Config() {
|
| -}
|
| -
|
| -QuicCryptoServerConfig::Config::~Config() {
|
| - STLDeleteElements(&key_exchanges);
|
| -}
|
| -
|
| } // namespace net
|
|
|