QUIC - Cleanup changes found while sync'ing with internal code.
[chromium-blink-merge.git] / net / quic / crypto / quic_crypto_server_config.cc
blob52ff70908942f92f46c0045c89b854d75c33f4c1
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/crypto/quic_crypto_server_config.h"
7 #include <stdlib.h>
8 #include <algorithm>
10 #include "base/stl_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "crypto/hkdf.h"
13 #include "crypto/secure_hash.h"
14 #include "net/base/net_util.h"
15 #include "net/quic/crypto/aes_128_gcm_12_decrypter.h"
16 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
17 #include "net/quic/crypto/cert_compressor.h"
18 #include "net/quic/crypto/channel_id.h"
19 #include "net/quic/crypto/crypto_framer.h"
20 #include "net/quic/crypto/crypto_server_config_protobuf.h"
21 #include "net/quic/crypto/crypto_utils.h"
22 #include "net/quic/crypto/curve25519_key_exchange.h"
23 #include "net/quic/crypto/ephemeral_key_source.h"
24 #include "net/quic/crypto/key_exchange.h"
25 #include "net/quic/crypto/local_strike_register_client.h"
26 #include "net/quic/crypto/p256_key_exchange.h"
27 #include "net/quic/crypto/proof_source.h"
28 #include "net/quic/crypto/quic_decrypter.h"
29 #include "net/quic/crypto/quic_encrypter.h"
30 #include "net/quic/crypto/quic_random.h"
31 #include "net/quic/crypto/source_address_token.h"
32 #include "net/quic/crypto/strike_register.h"
33 #include "net/quic/crypto/strike_register_client.h"
34 #include "net/quic/quic_clock.h"
35 #include "net/quic/quic_protocol.h"
36 #include "net/quic/quic_socket_address_coder.h"
37 #include "net/quic/quic_utils.h"
39 using base::StringPiece;
40 using crypto::SecureHash;
41 using std::map;
42 using std::string;
43 using std::vector;
45 namespace net {
47 // ClientHelloInfo contains information about a client hello message that is
48 // only kept for as long as it's being processed.
49 struct ClientHelloInfo {
50 ClientHelloInfo(const IPEndPoint& in_client_ip, QuicWallTime in_now)
51 : client_ip(in_client_ip),
52 now(in_now),
53 valid_source_address_token(false),
54 client_nonce_well_formed(false),
55 unique(false) {}
57 // Inputs to EvaluateClientHello.
58 const IPEndPoint client_ip;
59 const QuicWallTime now;
61 // Outputs from EvaluateClientHello.
62 bool valid_source_address_token;
63 bool client_nonce_well_formed;
64 bool unique;
65 StringPiece sni;
66 StringPiece client_nonce;
67 StringPiece server_nonce;
70 struct ValidateClientHelloResultCallback::Result {
71 Result(const CryptoHandshakeMessage& in_client_hello,
72 IPEndPoint in_client_ip,
73 QuicWallTime in_now)
74 : client_hello(in_client_hello),
75 info(in_client_ip, in_now),
76 error_code(QUIC_NO_ERROR) {
79 CryptoHandshakeMessage client_hello;
80 ClientHelloInfo info;
81 QuicErrorCode error_code;
82 string error_details;
85 class ValidateClientHelloHelper {
86 public:
87 ValidateClientHelloHelper(ValidateClientHelloResultCallback::Result* result,
88 ValidateClientHelloResultCallback* done_cb)
89 : result_(result), done_cb_(done_cb) {
92 ~ValidateClientHelloHelper() {
93 LOG_IF(DFATAL, done_cb_ != NULL)
94 << "Deleting ValidateClientHelloHelper with a pending callback.";
97 void ValidationComplete(QuicErrorCode error_code, const char* error_details) {
98 result_->error_code = error_code;
99 result_->error_details = error_details;
100 done_cb_->Run(result_);
101 DetachCallback();
104 void StartedAsyncCallback() {
105 DetachCallback();
108 private:
109 void DetachCallback() {
110 LOG_IF(DFATAL, done_cb_ == NULL) << "Callback already detached.";
111 done_cb_ = NULL;
114 ValidateClientHelloResultCallback::Result* result_;
115 ValidateClientHelloResultCallback* done_cb_;
117 DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloHelper);
120 class VerifyNonceIsValidAndUniqueCallback
121 : public StrikeRegisterClient::ResultCallback {
122 public:
123 VerifyNonceIsValidAndUniqueCallback(
124 ValidateClientHelloResultCallback::Result* result,
125 ValidateClientHelloResultCallback* done_cb)
126 : result_(result), done_cb_(done_cb) {
129 protected:
130 virtual void RunImpl(bool nonce_is_valid_and_unique) OVERRIDE {
131 DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique;
132 result_->info.unique = nonce_is_valid_and_unique;
133 done_cb_->Run(result_);
136 private:
137 ValidateClientHelloResultCallback::Result* result_;
138 ValidateClientHelloResultCallback* done_cb_;
140 DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback);
143 // static
144 const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
146 PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {
149 PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {
152 ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {
155 ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {
158 void ValidateClientHelloResultCallback::Run(const Result* result) {
159 RunImpl(result->client_hello, *result);
160 delete result;
161 delete this;
164 QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
165 : expiry_time(QuicWallTime::Zero()),
166 channel_id_enabled(false),
167 p256(false) {}
169 QuicCryptoServerConfig::QuicCryptoServerConfig(
170 StringPiece source_address_token_secret,
171 QuicRandom* rand)
172 : replay_protection_(true),
173 configs_lock_(),
174 primary_config_(NULL),
175 next_config_promotion_time_(QuicWallTime::Zero()),
176 server_nonce_strike_register_lock_(),
177 strike_register_no_startup_period_(false),
178 strike_register_max_entries_(1 << 10),
179 strike_register_window_secs_(600),
180 source_address_token_future_secs_(3600),
181 source_address_token_lifetime_secs_(86400),
182 server_nonce_strike_register_max_entries_(1 << 10),
183 server_nonce_strike_register_window_secs_(120) {
184 crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
185 "QUIC source address token key",
186 CryptoSecretBoxer::GetKeySize(),
187 0 /* no fixed IV needed */);
188 source_address_token_boxer_.SetKey(hkdf.server_write_key());
190 // Generate a random key and orbit for server nonces.
191 rand->RandBytes(server_nonce_orbit_, sizeof(server_nonce_orbit_));
192 const size_t key_size = server_nonce_boxer_.GetKeySize();
193 scoped_ptr<uint8[]> key_bytes(new uint8[key_size]);
194 rand->RandBytes(key_bytes.get(), key_size);
196 server_nonce_boxer_.SetKey(
197 StringPiece(reinterpret_cast<char*>(key_bytes.get()), key_size));
200 QuicCryptoServerConfig::~QuicCryptoServerConfig() {
201 primary_config_ = NULL;
204 // static
205 QuicServerConfigProtobuf* QuicCryptoServerConfig::GenerateConfig(
206 QuicRandom* rand,
207 const QuicClock* clock,
208 const ConfigOptions& options) {
209 CryptoHandshakeMessage msg;
211 const string curve25519_private_key =
212 Curve25519KeyExchange::NewPrivateKey(rand);
213 scoped_ptr<Curve25519KeyExchange> curve25519(
214 Curve25519KeyExchange::New(curve25519_private_key));
215 StringPiece curve25519_public_value = curve25519->public_value();
217 string encoded_public_values;
218 // First three bytes encode the length of the public value.
219 encoded_public_values.push_back(curve25519_public_value.size());
220 encoded_public_values.push_back(curve25519_public_value.size() >> 8);
221 encoded_public_values.push_back(curve25519_public_value.size() >> 16);
222 encoded_public_values.append(curve25519_public_value.data(),
223 curve25519_public_value.size());
225 string p256_private_key;
226 if (options.p256) {
227 p256_private_key = P256KeyExchange::NewPrivateKey();
228 scoped_ptr<P256KeyExchange> p256(P256KeyExchange::New(p256_private_key));
229 StringPiece p256_public_value = p256->public_value();
231 encoded_public_values.push_back(p256_public_value.size());
232 encoded_public_values.push_back(p256_public_value.size() >> 8);
233 encoded_public_values.push_back(p256_public_value.size() >> 16);
234 encoded_public_values.append(p256_public_value.data(),
235 p256_public_value.size());
238 msg.set_tag(kSCFG);
239 if (options.p256) {
240 msg.SetTaglist(kKEXS, kC255, kP256, 0);
241 } else {
242 msg.SetTaglist(kKEXS, kC255, 0);
244 msg.SetTaglist(kAEAD, kAESG, 0);
245 // TODO(rch): Remove once we remove QUIC_VERSION_12.
246 msg.SetValue(kVERS, static_cast<uint16>(0));
247 msg.SetStringPiece(kPUBS, encoded_public_values);
249 if (options.expiry_time.IsZero()) {
250 const QuicWallTime now = clock->WallNow();
251 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds(
252 60 * 60 * 24 * 180 /* 180 days, ~six months */));
253 const uint64 expiry_seconds = expiry.ToUNIXSeconds();
254 msg.SetValue(kEXPY, expiry_seconds);
255 } else {
256 msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds());
259 char orbit_bytes[kOrbitSize];
260 if (options.orbit.size() == sizeof(orbit_bytes)) {
261 memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes));
262 } else {
263 DCHECK(options.orbit.empty());
264 rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
266 msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes)));
268 if (options.channel_id_enabled) {
269 msg.SetTaglist(kPDMD, kCHID, 0);
272 if (options.id.empty()) {
273 // We need to ensure that the SCID changes whenever the server config does
274 // thus we make it a hash of the rest of the server config.
275 scoped_ptr<QuicData> serialized(
276 CryptoFramer::ConstructHandshakeMessage(msg));
277 scoped_ptr<SecureHash> hash(SecureHash::Create(SecureHash::SHA256));
278 hash->Update(serialized->data(), serialized->length());
280 char scid_bytes[16];
281 hash->Finish(scid_bytes, sizeof(scid_bytes));
282 msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes)));
283 } else {
284 msg.SetStringPiece(kSCID, options.id);
286 // Don't put new tags below this point. The SCID generation should hash over
287 // everything but itself and so extra tags should be added prior to the
288 // preceeding if block.
290 scoped_ptr<QuicData> serialized(CryptoFramer::ConstructHandshakeMessage(msg));
292 scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf);
293 config->set_config(serialized->AsStringPiece());
294 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key();
295 curve25519_key->set_tag(kC255);
296 curve25519_key->set_private_key(curve25519_private_key);
298 if (options.p256) {
299 QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key();
300 p256_key->set_tag(kP256);
301 p256_key->set_private_key(p256_private_key);
304 return config.release();
307 CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
308 QuicServerConfigProtobuf* protobuf,
309 const QuicWallTime now) {
310 scoped_ptr<CryptoHandshakeMessage> msg(
311 CryptoFramer::ParseMessage(protobuf->config()));
313 if (!msg.get()) {
314 LOG(WARNING) << "Failed to parse server config message";
315 return NULL;
318 scoped_refptr<Config> config(ParseConfigProtobuf(protobuf));
319 if (!config.get()) {
320 LOG(WARNING) << "Failed to parse server config message";
321 return NULL;
325 base::AutoLock locked(configs_lock_);
326 if (configs_.find(config->id) != configs_.end()) {
327 LOG(WARNING) << "Failed to add config because another with the same "
328 "server config id already exists: "
329 << base::HexEncode(config->id.data(), config->id.size());
330 return NULL;
333 configs_[config->id] = config;
334 SelectNewPrimaryConfig(now);
335 DCHECK(primary_config_.get());
336 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
339 return msg.release();
342 CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig(
343 QuicRandom* rand,
344 const QuicClock* clock,
345 const ConfigOptions& options) {
346 scoped_ptr<QuicServerConfigProtobuf> config(
347 GenerateConfig(rand, clock, options));
348 return AddConfig(config.get(), clock->WallNow());
351 bool QuicCryptoServerConfig::SetConfigs(
352 const vector<QuicServerConfigProtobuf*>& protobufs,
353 const QuicWallTime now) {
354 vector<scoped_refptr<Config> > parsed_configs;
355 bool ok = true;
357 for (vector<QuicServerConfigProtobuf*>::const_iterator i = protobufs.begin();
358 i != protobufs.end(); ++i) {
359 scoped_refptr<Config> config(ParseConfigProtobuf(*i));
360 if (!config.get()) {
361 ok = false;
362 break;
365 parsed_configs.push_back(config);
368 if (parsed_configs.empty()) {
369 LOG(WARNING) << "New config list is empty.";
370 ok = false;
373 if (!ok) {
374 LOG(WARNING) << "Rejecting QUIC configs because of above errors";
375 } else {
376 VLOG(1) << "Updating configs:";
378 base::AutoLock locked(configs_lock_);
379 ConfigMap new_configs;
381 for (vector<scoped_refptr<Config> >::const_iterator i =
382 parsed_configs.begin();
383 i != parsed_configs.end(); ++i) {
384 scoped_refptr<Config> config = *i;
385 ConfigMap::iterator it = configs_.find(config->id);
386 if (it != configs_.end()) {
387 VLOG(1)
388 << "Keeping scid: " << base::HexEncode(
389 config->id.data(), config->id.size())
390 << " orbit: " << base::HexEncode(
391 reinterpret_cast<const char *>(config->orbit), kOrbitSize)
392 << " new primary_time " << config->primary_time.ToUNIXSeconds()
393 << " old primary_time " << it->second->primary_time.ToUNIXSeconds()
394 << " new priority " << config->priority
395 << " old priority " << it->second->priority;
396 // Update primary_time and priority.
397 it->second->primary_time = config->primary_time;
398 it->second->priority = config->priority;
399 new_configs.insert(*it);
400 } else {
401 VLOG(1) << "Adding scid: " << base::HexEncode(
402 config->id.data(), config->id.size())
403 << " orbit: " << base::HexEncode(
404 reinterpret_cast<const char *>(config->orbit), kOrbitSize)
405 << " primary_time " << config->primary_time.ToUNIXSeconds()
406 << " priority " << config->priority;
407 new_configs.insert(make_pair(config->id, config));
411 configs_.swap(new_configs);
412 SelectNewPrimaryConfig(now);
413 DCHECK(primary_config_);
414 DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
417 return ok;
420 void QuicCryptoServerConfig::GetConfigIds(vector<string>* scids) const {
421 base::AutoLock locked(configs_lock_);
422 for (ConfigMap::const_iterator it = configs_.begin();
423 it != configs_.end(); ++it) {
424 scids->push_back(it->first);
428 void QuicCryptoServerConfig::ValidateClientHello(
429 const CryptoHandshakeMessage& client_hello,
430 IPEndPoint client_ip,
431 const QuicClock* clock,
432 ValidateClientHelloResultCallback* done_cb) const {
433 const QuicWallTime now(clock->WallNow());
435 ValidateClientHelloResultCallback::Result* result =
436 new ValidateClientHelloResultCallback::Result(
437 client_hello, client_ip, now);
439 uint8 primary_orbit[kOrbitSize];
441 base::AutoLock locked(configs_lock_);
443 if (!primary_config_.get()) {
444 result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
445 result->error_details = "No configurations loaded";
446 } else {
447 if (!next_config_promotion_time_.IsZero() &&
448 next_config_promotion_time_.IsAfter(now)) {
449 SelectNewPrimaryConfig(now);
450 DCHECK(primary_config_);
451 DCHECK(configs_.find(primary_config_->id)->second == primary_config_);
454 memcpy(primary_orbit, primary_config_->orbit, sizeof(primary_orbit));
458 if (result->error_code == QUIC_NO_ERROR) {
459 EvaluateClientHello(primary_orbit, result, done_cb);
460 } else {
461 done_cb->Run(result);
465 QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
466 const ValidateClientHelloResultCallback::Result& validate_chlo_result,
467 QuicConnectionId connection_id,
468 IPEndPoint client_address,
469 QuicVersion version,
470 const QuicVersionVector& supported_versions,
471 const QuicClock* clock,
472 QuicRandom* rand,
473 QuicCryptoNegotiatedParameters *params,
474 CryptoHandshakeMessage* out,
475 string* error_details) const {
476 DCHECK(error_details);
478 const CryptoHandshakeMessage& client_hello =
479 validate_chlo_result.client_hello;
480 const ClientHelloInfo& info = validate_chlo_result.info;
482 // If the client's preferred version is not the version we are currently
483 // speaking, then the client went through a version negotiation. In this
484 // case, we need to make sure that we actually do not support this version
485 // and that it wasn't a downgrade attack.
486 QuicTag client_version_tag;
487 // TODO(rch): Make this check mandatory when we remove QUIC_VERSION_12.
488 if (client_hello.GetUint32(kVER, &client_version_tag) == QUIC_NO_ERROR) {
489 QuicVersion client_version = QuicTagToQuicVersion(client_version_tag);
490 if (client_version != version) {
491 // Just because client_version is a valid version enum doesn't mean that
492 // this server actually supports that version, so we check to see if
493 // it's actually in the supported versions list.
494 for (size_t i = 0; i < supported_versions.size(); ++i) {
495 if (client_version == supported_versions[i]) {
496 *error_details = "Downgrade attack detected";
497 return QUIC_VERSION_NEGOTIATION_MISMATCH;
503 StringPiece requested_scid;
504 client_hello.GetStringPiece(kSCID, &requested_scid);
505 const QuicWallTime now(clock->WallNow());
507 scoped_refptr<Config> requested_config;
508 scoped_refptr<Config> primary_config;
510 base::AutoLock locked(configs_lock_);
512 if (!primary_config_.get()) {
513 *error_details = "No configurations loaded";
514 return QUIC_CRYPTO_INTERNAL_ERROR;
517 if (!next_config_promotion_time_.IsZero() &&
518 next_config_promotion_time_.IsAfter(now)) {
519 SelectNewPrimaryConfig(now);
520 DCHECK(primary_config_);
521 DCHECK(configs_.find(primary_config_->id)->second == primary_config_);
524 primary_config = primary_config_;
526 if (!requested_scid.empty()) {
527 ConfigMap::const_iterator it = configs_.find(requested_scid.as_string());
528 if (it != configs_.end()) {
529 // We'll use the config that the client requested in order to do
530 // key-agreement. Otherwise we'll give it a copy of |primary_config_|
531 // to use.
532 requested_config = it->second;
537 if (validate_chlo_result.error_code != QUIC_NO_ERROR) {
538 *error_details = validate_chlo_result.error_details;
539 return validate_chlo_result.error_code;
542 out->Clear();
544 if (!info.valid_source_address_token ||
545 !info.client_nonce_well_formed ||
546 !info.unique ||
547 !requested_config.get()) {
548 BuildRejection(primary_config.get(), client_hello, info, rand, out);
549 return QUIC_NO_ERROR;
552 const QuicTag* their_aeads;
553 const QuicTag* their_key_exchanges;
554 size_t num_their_aeads, num_their_key_exchanges;
555 if (client_hello.GetTaglist(kAEAD, &their_aeads,
556 &num_their_aeads) != QUIC_NO_ERROR ||
557 client_hello.GetTaglist(kKEXS, &their_key_exchanges,
558 &num_their_key_exchanges) != QUIC_NO_ERROR ||
559 num_their_aeads != 1 ||
560 num_their_key_exchanges != 1) {
561 *error_details = "Missing or invalid AEAD or KEXS";
562 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
565 size_t key_exchange_index;
566 if (!QuicUtils::FindMutualTag(requested_config->aead, their_aeads,
567 num_their_aeads, QuicUtils::LOCAL_PRIORITY,
568 &params->aead, NULL) ||
569 !QuicUtils::FindMutualTag(
570 requested_config->kexs, their_key_exchanges, num_their_key_exchanges,
571 QuicUtils::LOCAL_PRIORITY, &params->key_exchange,
572 &key_exchange_index)) {
573 *error_details = "Unsupported AEAD or KEXS";
574 return QUIC_CRYPTO_NO_SUPPORT;
577 StringPiece public_value;
578 if (!client_hello.GetStringPiece(kPUBS, &public_value)) {
579 *error_details = "Missing public value";
580 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
583 const KeyExchange* key_exchange =
584 requested_config->key_exchanges[key_exchange_index];
585 if (!key_exchange->CalculateSharedKey(public_value,
586 &params->initial_premaster_secret)) {
587 *error_details = "Invalid public value";
588 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
591 if (!info.sni.empty()) {
592 scoped_ptr<char[]> sni_tmp(new char[info.sni.length() + 1]);
593 memcpy(sni_tmp.get(), info.sni.data(), info.sni.length());
594 sni_tmp[info.sni.length()] = 0;
595 params->sni = CryptoUtils::NormalizeHostname(sni_tmp.get());
598 string hkdf_suffix;
599 const QuicData& client_hello_serialized = client_hello.GetSerialized();
600 hkdf_suffix.reserve(sizeof(connection_id) + client_hello_serialized.length() +
601 requested_config->serialized.size());
602 hkdf_suffix.append(reinterpret_cast<char*>(&connection_id),
603 sizeof(connection_id));
604 hkdf_suffix.append(client_hello_serialized.data(),
605 client_hello_serialized.length());
606 hkdf_suffix.append(requested_config->serialized);
608 StringPiece cetv_ciphertext;
609 if (requested_config->channel_id_enabled &&
610 client_hello.GetStringPiece(kCETV, &cetv_ciphertext)) {
611 CryptoHandshakeMessage client_hello_copy(client_hello);
612 client_hello_copy.Erase(kCETV);
613 client_hello_copy.Erase(kPAD);
615 const QuicData& client_hello_serialized = client_hello_copy.GetSerialized();
616 string hkdf_input;
617 hkdf_input.append(QuicCryptoConfig::kCETVLabel,
618 strlen(QuicCryptoConfig::kCETVLabel) + 1);
619 hkdf_input.append(reinterpret_cast<char*>(&connection_id),
620 sizeof(connection_id));
621 hkdf_input.append(client_hello_serialized.data(),
622 client_hello_serialized.length());
623 hkdf_input.append(requested_config->serialized);
625 CrypterPair crypters;
626 if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead,
627 info.client_nonce, info.server_nonce,
628 hkdf_input, CryptoUtils::SERVER, &crypters)) {
629 *error_details = "Symmetric key setup failed";
630 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
633 scoped_ptr<QuicData> cetv_plaintext(crypters.decrypter->DecryptPacket(
634 0 /* sequence number */, StringPiece() /* associated data */,
635 cetv_ciphertext));
636 if (!cetv_plaintext.get()) {
637 *error_details = "CETV decryption failure";
638 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
641 scoped_ptr<CryptoHandshakeMessage> cetv(CryptoFramer::ParseMessage(
642 cetv_plaintext->AsStringPiece()));
643 if (!cetv.get()) {
644 *error_details = "CETV parse error";
645 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
648 StringPiece key, signature;
649 if (cetv->GetStringPiece(kCIDK, &key) &&
650 cetv->GetStringPiece(kCIDS, &signature)) {
651 if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) {
652 *error_details = "ChannelID signature failure";
653 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
656 params->channel_id = key.as_string();
660 string hkdf_input;
661 size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
662 hkdf_input.reserve(label_len + hkdf_suffix.size());
663 hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
664 hkdf_input.append(hkdf_suffix);
666 if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead,
667 info.client_nonce, info.server_nonce, hkdf_input,
668 CryptoUtils::SERVER,
669 &params->initial_crypters)) {
670 *error_details = "Symmetric key setup failed";
671 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
674 string forward_secure_public_value;
675 if (ephemeral_key_source_.get()) {
676 params->forward_secure_premaster_secret =
677 ephemeral_key_source_->CalculateForwardSecureKey(
678 key_exchange, rand, clock->ApproximateNow(), public_value,
679 &forward_secure_public_value);
680 } else {
681 scoped_ptr<KeyExchange> forward_secure_key_exchange(
682 key_exchange->NewKeyPair(rand));
683 forward_secure_public_value =
684 forward_secure_key_exchange->public_value().as_string();
685 if (!forward_secure_key_exchange->CalculateSharedKey(
686 public_value, &params->forward_secure_premaster_secret)) {
687 *error_details = "Invalid public value";
688 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
692 string forward_secure_hkdf_input;
693 label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
694 forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size());
695 forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel,
696 label_len);
697 forward_secure_hkdf_input.append(hkdf_suffix);
699 if (!CryptoUtils::DeriveKeys(
700 params->forward_secure_premaster_secret, params->aead,
701 info.client_nonce, info.server_nonce, forward_secure_hkdf_input,
702 CryptoUtils::SERVER, &params->forward_secure_crypters)) {
703 *error_details = "Symmetric key setup failed";
704 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
707 out->set_tag(kSHLO);
708 QuicTagVector supported_version_tags;
709 for (size_t i = 0; i < supported_versions.size(); ++i) {
710 supported_version_tags.push_back
711 (QuicVersionToQuicTag(supported_versions[i]));
713 out->SetVector(kVER, supported_version_tags);
714 out->SetStringPiece(kSourceAddressTokenTag,
715 NewSourceAddressToken(client_address, rand, info.now));
716 QuicSocketAddressCoder address_coder(client_address);
717 out->SetStringPiece(kCADR, address_coder.Encode());
718 out->SetStringPiece(kPUBS, forward_secure_public_value);
719 return QUIC_NO_ERROR;
722 // ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
723 // Config's based on their primary_time.
724 // static
725 bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
726 const scoped_refptr<Config>& a,
727 const scoped_refptr<Config>& b) {
728 if (a->primary_time.IsBefore(b->primary_time) ||
729 b->primary_time.IsBefore(a->primary_time)) {
730 // Primary times differ.
731 return a->primary_time.IsBefore(b->primary_time);
732 } else if (a->priority != b->priority) {
733 // Primary times are equal, sort backwards by priority.
734 return a->priority < b->priority;
735 } else {
736 // Primary times and priorities are equal, sort by config id.
737 return a->id < b->id;
741 void QuicCryptoServerConfig::SelectNewPrimaryConfig(
742 const QuicWallTime now) const {
743 vector<scoped_refptr<Config> > configs;
744 configs.reserve(configs_.size());
746 for (ConfigMap::const_iterator it = configs_.begin();
747 it != configs_.end(); ++it) {
748 // TODO(avd) Exclude expired configs?
749 configs.push_back(it->second);
752 if (configs.empty()) {
753 if (primary_config_.get()) {
754 LOG(DFATAL) << "No valid QUIC server config. Keeping the current config.";
755 } else {
756 LOG(DFATAL) << "No valid QUIC server config.";
758 return;
761 std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan);
763 Config* best_candidate = configs[0];
765 for (size_t i = 0; i < configs.size(); ++i) {
766 const scoped_refptr<Config> config(configs[i]);
767 if (!config->primary_time.IsAfter(now)) {
768 if (config->primary_time.IsAfter(best_candidate->primary_time)) {
769 best_candidate = config;
771 continue;
774 // This is the first config with a primary_time in the future. Thus the
775 // previous Config should be the primary and this one should determine the
776 // next_config_promotion_time_.
777 scoped_refptr<Config> new_primary(best_candidate);
778 if (i == 0) {
779 // We need the primary_time of the next config.
780 if (configs.size() > 1) {
781 next_config_promotion_time_ = configs[1]->primary_time;
782 } else {
783 next_config_promotion_time_ = QuicWallTime::Zero();
785 } else {
786 next_config_promotion_time_ = config->primary_time;
789 if (primary_config_.get()) {
790 primary_config_->is_primary = false;
792 primary_config_ = new_primary;
793 new_primary->is_primary = true;
794 DVLOG(1) << "New primary config. orbit: "
795 << base::HexEncode(
796 reinterpret_cast<const char*>(primary_config_->orbit),
797 kOrbitSize);
798 if (primary_config_changed_cb_.get() != NULL) {
799 primary_config_changed_cb_->Run(primary_config_->id);
802 return;
805 // All config's primary times are in the past. We should make the most recent
806 // and highest priority candidate primary.
807 scoped_refptr<Config> new_primary(best_candidate);
808 if (primary_config_.get()) {
809 primary_config_->is_primary = false;
811 primary_config_ = new_primary;
812 new_primary->is_primary = true;
813 DVLOG(1) << "New primary config. orbit: "
814 << base::HexEncode(
815 reinterpret_cast<const char*>(primary_config_->orbit),
816 kOrbitSize);
817 next_config_promotion_time_ = QuicWallTime::Zero();
818 if (primary_config_changed_cb_.get() != NULL) {
819 primary_config_changed_cb_->Run(primary_config_->id);
823 void QuicCryptoServerConfig::EvaluateClientHello(
824 const uint8* primary_orbit,
825 ValidateClientHelloResultCallback::Result* client_hello_state,
826 ValidateClientHelloResultCallback* done_cb) const {
827 ValidateClientHelloHelper helper(client_hello_state, done_cb);
829 const CryptoHandshakeMessage& client_hello =
830 client_hello_state->client_hello;
831 ClientHelloInfo* info = &(client_hello_state->info);
833 if (client_hello.size() < kClientHelloMinimumSizeOld) {
834 helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
835 "Client hello too small");
836 return;
839 if (client_hello.GetStringPiece(kSNI, &info->sni) &&
840 !CryptoUtils::IsValidSNI(info->sni)) {
841 helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
842 "Invalid SNI name");
843 return;
846 StringPiece srct;
847 if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct) &&
848 ValidateSourceAddressToken(srct, info->client_ip, info->now)) {
849 info->valid_source_address_token = true;
850 } else {
851 // No valid source address token.
852 helper.ValidationComplete(QUIC_NO_ERROR, "");
853 return;
856 if (client_hello.GetStringPiece(kNONC, &info->client_nonce) &&
857 info->client_nonce.size() == kNonceSize) {
858 info->client_nonce_well_formed = true;
859 } else {
860 // Invalid client nonce.
861 DVLOG(1) << "Invalid client nonce.";
862 helper.ValidationComplete(QUIC_NO_ERROR, "");
863 return;
866 if (!replay_protection_) {
867 info->unique = true;
868 DVLOG(1) << "No replay protection.";
869 helper.ValidationComplete(QUIC_NO_ERROR, "");
870 return;
873 client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
874 if (!info->server_nonce.empty()) {
875 // If the server nonce is present, use it to establish uniqueness.
876 info->unique = ValidateServerNonce(info->server_nonce, info->now);
877 DVLOG(1) << "Using server nonce, unique: " << info->unique;
878 helper.ValidationComplete(QUIC_NO_ERROR, "");
879 return;
882 // Use the client nonce to establish uniqueness.
883 StrikeRegisterClient* strike_register_client;
885 base::AutoLock locked(strike_register_client_lock_);
887 if (strike_register_client_.get() == NULL) {
888 strike_register_client_.reset(new LocalStrikeRegisterClient(
889 strike_register_max_entries_,
890 static_cast<uint32>(info->now.ToUNIXSeconds()),
891 strike_register_window_secs_,
892 primary_orbit,
893 strike_register_no_startup_period_ ?
894 StrikeRegister::NO_STARTUP_PERIOD_NEEDED :
895 StrikeRegister::DENY_REQUESTS_AT_STARTUP));
897 strike_register_client = strike_register_client_.get();
900 strike_register_client->VerifyNonceIsValidAndUnique(
901 info->client_nonce,
902 info->now,
903 new VerifyNonceIsValidAndUniqueCallback(client_hello_state, done_cb));
904 helper.StartedAsyncCallback();
907 void QuicCryptoServerConfig::BuildRejection(
908 const scoped_refptr<Config>& config,
909 const CryptoHandshakeMessage& client_hello,
910 const ClientHelloInfo& info,
911 QuicRandom* rand,
912 CryptoHandshakeMessage* out) const {
913 out->set_tag(kREJ);
914 out->SetStringPiece(kSCFG, config->serialized);
915 out->SetStringPiece(kSourceAddressTokenTag,
916 NewSourceAddressToken(info.client_ip, rand, info.now));
917 if (replay_protection_) {
918 out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now));
921 // The client may have requested a certificate chain.
922 const QuicTag* their_proof_demands;
923 size_t num_their_proof_demands;
925 if (proof_source_.get() == NULL ||
926 client_hello.GetTaglist(kPDMD, &their_proof_demands,
927 &num_their_proof_demands) !=
928 QUIC_NO_ERROR) {
929 return;
932 bool x509_supported = false, x509_ecdsa_supported = false;
933 for (size_t i = 0; i < num_their_proof_demands; i++) {
934 switch (their_proof_demands[i]) {
935 case kX509:
936 x509_supported = true;
937 x509_ecdsa_supported = true;
938 break;
939 case kX59R:
940 x509_supported = true;
941 break;
945 if (!x509_supported) {
946 return;
949 const vector<string>* certs;
950 string signature;
951 if (!proof_source_->GetProof(info.sni.as_string(), config->serialized,
952 x509_ecdsa_supported, &certs, &signature)) {
953 return;
956 StringPiece their_common_set_hashes;
957 StringPiece their_cached_cert_hashes;
958 client_hello.GetStringPiece(kCCS, &their_common_set_hashes);
959 client_hello.GetStringPiece(kCCRT, &their_cached_cert_hashes);
961 const string compressed = CertCompressor::CompressChain(
962 *certs, their_common_set_hashes, their_cached_cert_hashes,
963 config->common_cert_sets);
965 // kREJOverheadBytes is a very rough estimate of how much of a REJ
966 // message is taken up by things other than the certificates.
967 // STK: 56 bytes
968 // SNO: 56 bytes
969 // SCFG
970 // SCID: 16 bytes
971 // PUBS: 38 bytes
972 const size_t kREJOverheadBytes = 166;
973 // kMultiplier is the multiple of the CHLO message size that a REJ message
974 // must stay under when the client doesn't present a valid source-address
975 // token.
976 const size_t kMultiplier = 2;
977 // max_unverified_size is the number of bytes that the certificate chain
978 // and signature can consume before we will demand a valid source-address
979 // token.
980 const size_t max_unverified_size =
981 client_hello.size() * kMultiplier - kREJOverheadBytes;
982 COMPILE_ASSERT(kClientHelloMinimumSizeOld * kMultiplier >= kREJOverheadBytes,
983 overhead_calculation_may_underflow);
984 if (info.valid_source_address_token ||
985 signature.size() + compressed.size() < max_unverified_size) {
986 out->SetStringPiece(kCertificateTag, compressed);
987 out->SetStringPiece(kPROF, signature);
991 scoped_refptr<QuicCryptoServerConfig::Config>
992 QuicCryptoServerConfig::ParseConfigProtobuf(
993 QuicServerConfigProtobuf* protobuf) {
994 scoped_ptr<CryptoHandshakeMessage> msg(
995 CryptoFramer::ParseMessage(protobuf->config()));
997 if (msg->tag() != kSCFG) {
998 LOG(WARNING) << "Server config message has tag " << msg->tag()
999 << " expected " << kSCFG;
1000 return NULL;
1003 scoped_refptr<Config> config(new Config);
1004 config->serialized = protobuf->config();
1006 if (protobuf->has_primary_time()) {
1007 config->primary_time =
1008 QuicWallTime::FromUNIXSeconds(protobuf->primary_time());
1011 config->priority = protobuf->priority();
1013 StringPiece scid;
1014 if (!msg->GetStringPiece(kSCID, &scid)) {
1015 LOG(WARNING) << "Server config message is missing SCID";
1016 return NULL;
1018 config->id = scid.as_string();
1020 const QuicTag* aead_tags;
1021 size_t aead_len;
1022 if (msg->GetTaglist(kAEAD, &aead_tags, &aead_len) != QUIC_NO_ERROR) {
1023 LOG(WARNING) << "Server config message is missing AEAD";
1024 return NULL;
1026 config->aead = vector<QuicTag>(aead_tags, aead_tags + aead_len);
1028 const QuicTag* kexs_tags;
1029 size_t kexs_len;
1030 if (msg->GetTaglist(kKEXS, &kexs_tags, &kexs_len) != QUIC_NO_ERROR) {
1031 LOG(WARNING) << "Server config message is missing KEXS";
1032 return NULL;
1035 StringPiece orbit;
1036 if (!msg->GetStringPiece(kORBT, &orbit)) {
1037 LOG(WARNING) << "Server config message is missing OBIT";
1038 return NULL;
1041 if (orbit.size() != kOrbitSize) {
1042 LOG(WARNING) << "Orbit value in server config is the wrong length."
1043 " Got " << orbit.size() << " want " << kOrbitSize;
1044 return NULL;
1046 COMPILE_ASSERT(sizeof(config->orbit) == kOrbitSize, orbit_incorrect_size);
1047 memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
1050 StrikeRegisterClient* strike_register_client;
1052 base::AutoLock locked(strike_register_client_lock_);
1053 strike_register_client = strike_register_client_.get();
1056 if (strike_register_client != NULL &&
1057 !strike_register_client->IsKnownOrbit(orbit)) {
1058 LOG(WARNING)
1059 << "Rejecting server config with orbit that the strike register "
1060 "client doesn't know about.";
1061 return NULL;
1065 if (kexs_len != protobuf->key_size()) {
1066 LOG(WARNING) << "Server config has " << kexs_len
1067 << " key exchange methods configured, but "
1068 << protobuf->key_size() << " private keys";
1069 return NULL;
1072 const QuicTag* proof_demand_tags;
1073 size_t num_proof_demand_tags;
1074 if (msg->GetTaglist(kPDMD, &proof_demand_tags, &num_proof_demand_tags) ==
1075 QUIC_NO_ERROR) {
1076 for (size_t i = 0; i < num_proof_demand_tags; i++) {
1077 if (proof_demand_tags[i] == kCHID) {
1078 config->channel_id_enabled = true;
1079 break;
1084 for (size_t i = 0; i < kexs_len; i++) {
1085 const QuicTag tag = kexs_tags[i];
1086 string private_key;
1088 config->kexs.push_back(tag);
1090 for (size_t j = 0; j < protobuf->key_size(); j++) {
1091 const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i);
1092 if (key.tag() == tag) {
1093 private_key = key.private_key();
1094 break;
1098 if (private_key.empty()) {
1099 LOG(WARNING) << "Server config contains key exchange method without "
1100 "corresponding private key: " << tag;
1101 return NULL;
1104 scoped_ptr<KeyExchange> ka;
1105 switch (tag) {
1106 case kC255:
1107 ka.reset(Curve25519KeyExchange::New(private_key));
1108 if (!ka.get()) {
1109 LOG(WARNING) << "Server config contained an invalid curve25519"
1110 " private key.";
1111 return NULL;
1113 break;
1114 case kP256:
1115 ka.reset(P256KeyExchange::New(private_key));
1116 if (!ka.get()) {
1117 LOG(WARNING) << "Server config contained an invalid P-256"
1118 " private key.";
1119 return NULL;
1121 break;
1122 default:
1123 LOG(WARNING) << "Server config message contains unknown key exchange "
1124 "method: " << tag;
1125 return NULL;
1128 for (vector<KeyExchange*>::const_iterator i = config->key_exchanges.begin();
1129 i != config->key_exchanges.end(); ++i) {
1130 if ((*i)->tag() == tag) {
1131 LOG(WARNING) << "Duplicate key exchange in config: " << tag;
1132 return NULL;
1136 config->key_exchanges.push_back(ka.release());
1139 return config;
1142 void QuicCryptoServerConfig::SetProofSource(ProofSource* proof_source) {
1143 proof_source_.reset(proof_source);
1146 void QuicCryptoServerConfig::SetEphemeralKeySource(
1147 EphemeralKeySource* ephemeral_key_source) {
1148 ephemeral_key_source_.reset(ephemeral_key_source);
1151 void QuicCryptoServerConfig::SetStrikeRegisterClient(
1152 StrikeRegisterClient* strike_register_client) {
1153 base::AutoLock locker(strike_register_client_lock_);
1154 DCHECK(!strike_register_client_.get());
1155 strike_register_client_.reset(strike_register_client);
1158 void QuicCryptoServerConfig::set_replay_protection(bool on) {
1159 replay_protection_ = on;
1162 void QuicCryptoServerConfig::set_strike_register_no_startup_period() {
1163 base::AutoLock locker(strike_register_client_lock_);
1164 DCHECK(!strike_register_client_.get());
1165 strike_register_no_startup_period_ = true;
1168 void QuicCryptoServerConfig::set_strike_register_max_entries(
1169 uint32 max_entries) {
1170 base::AutoLock locker(strike_register_client_lock_);
1171 DCHECK(!strike_register_client_.get());
1172 strike_register_max_entries_ = max_entries;
1175 void QuicCryptoServerConfig::set_strike_register_window_secs(
1176 uint32 window_secs) {
1177 base::AutoLock locker(strike_register_client_lock_);
1178 DCHECK(!strike_register_client_.get());
1179 strike_register_window_secs_ = window_secs;
1182 void QuicCryptoServerConfig::set_source_address_token_future_secs(
1183 uint32 future_secs) {
1184 source_address_token_future_secs_ = future_secs;
1187 void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
1188 uint32 lifetime_secs) {
1189 source_address_token_lifetime_secs_ = lifetime_secs;
1192 void QuicCryptoServerConfig::set_server_nonce_strike_register_max_entries(
1193 uint32 max_entries) {
1194 DCHECK(!server_nonce_strike_register_.get());
1195 server_nonce_strike_register_max_entries_ = max_entries;
1198 void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs(
1199 uint32 window_secs) {
1200 DCHECK(!server_nonce_strike_register_.get());
1201 server_nonce_strike_register_window_secs_ = window_secs;
1204 void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
1205 PrimaryConfigChangedCallback* cb) {
1206 base::AutoLock locked(configs_lock_);
1207 primary_config_changed_cb_.reset(cb);
1210 string QuicCryptoServerConfig::NewSourceAddressToken(
1211 const IPEndPoint& ip,
1212 QuicRandom* rand,
1213 QuicWallTime now) const {
1214 SourceAddressToken source_address_token;
1215 source_address_token.set_ip(IPAddressToPackedString(ip.address()));
1216 source_address_token.set_timestamp(now.ToUNIXSeconds());
1218 return source_address_token_boxer_.Box(
1219 rand, source_address_token.SerializeAsString());
1222 bool QuicCryptoServerConfig::ValidateSourceAddressToken(
1223 StringPiece token,
1224 const IPEndPoint& ip,
1225 QuicWallTime now) const {
1226 string storage;
1227 StringPiece plaintext;
1228 if (!source_address_token_boxer_.Unbox(token, &storage, &plaintext)) {
1229 return false;
1232 SourceAddressToken source_address_token;
1233 if (!source_address_token.ParseFromArray(plaintext.data(),
1234 plaintext.size())) {
1235 return false;
1238 if (source_address_token.ip() != IPAddressToPackedString(ip.address())) {
1239 // It's for a different IP address.
1240 return false;
1243 const QuicWallTime timestamp(
1244 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
1245 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
1247 if (now.IsBefore(timestamp) &&
1248 delta.ToSeconds() > source_address_token_future_secs_) {
1249 return false;
1252 if (now.IsAfter(timestamp) &&
1253 delta.ToSeconds() > source_address_token_lifetime_secs_) {
1254 return false;
1257 return true;
1260 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server
1261 // nonce.
1262 static const size_t kServerNoncePlaintextSize =
1263 4 /* timestamp */ + 20 /* random bytes */;
1265 string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand,
1266 QuicWallTime now) const {
1267 const uint32 timestamp = static_cast<uint32>(now.ToUNIXSeconds());
1269 uint8 server_nonce[kServerNoncePlaintextSize];
1270 COMPILE_ASSERT(sizeof(server_nonce) > sizeof(timestamp), nonce_too_small);
1271 server_nonce[0] = static_cast<uint8>(timestamp >> 24);
1272 server_nonce[1] = static_cast<uint8>(timestamp >> 16);
1273 server_nonce[2] = static_cast<uint8>(timestamp >> 8);
1274 server_nonce[3] = static_cast<uint8>(timestamp);
1275 rand->RandBytes(&server_nonce[sizeof(timestamp)],
1276 sizeof(server_nonce) - sizeof(timestamp));
1278 return server_nonce_boxer_.Box(
1279 rand,
1280 StringPiece(reinterpret_cast<char*>(server_nonce), sizeof(server_nonce)));
1283 bool QuicCryptoServerConfig::ValidateServerNonce(StringPiece token,
1284 QuicWallTime now) const {
1285 string storage;
1286 StringPiece plaintext;
1287 if (!server_nonce_boxer_.Unbox(token, &storage, &plaintext)) {
1288 return false;
1291 // plaintext contains:
1292 // uint32 timestamp
1293 // uint8[20] random bytes
1295 if (plaintext.size() != kServerNoncePlaintextSize) {
1296 // This should never happen because the value decrypted correctly.
1297 LOG(DFATAL) << "Seemingly valid server nonce had incorrect length.";
1298 return false;
1301 uint8 server_nonce[32];
1302 memcpy(server_nonce, plaintext.data(), 4);
1303 memcpy(server_nonce + 4, server_nonce_orbit_, sizeof(server_nonce_orbit_));
1304 memcpy(server_nonce + 4 + sizeof(server_nonce_orbit_), plaintext.data() + 4,
1305 20);
1306 COMPILE_ASSERT(4 + sizeof(server_nonce_orbit_) + 20 == sizeof(server_nonce),
1307 bad_nonce_buffer_length);
1309 bool is_unique;
1311 base::AutoLock auto_lock(server_nonce_strike_register_lock_);
1312 if (server_nonce_strike_register_.get() == NULL) {
1313 server_nonce_strike_register_.reset(new StrikeRegister(
1314 server_nonce_strike_register_max_entries_,
1315 static_cast<uint32>(now.ToUNIXSeconds()),
1316 server_nonce_strike_register_window_secs_, server_nonce_orbit_,
1317 StrikeRegister::NO_STARTUP_PERIOD_NEEDED));
1319 is_unique = server_nonce_strike_register_->Insert(
1320 server_nonce, static_cast<uint32>(now.ToUNIXSeconds()));
1323 return is_unique;
1326 QuicCryptoServerConfig::Config::Config()
1327 : channel_id_enabled(false),
1328 is_primary(false),
1329 primary_time(QuicWallTime::Zero()),
1330 priority(0) {}
1332 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); }
1334 } // namespace net