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"
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
;
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
),
53 valid_source_address_token(false),
54 client_nonce_well_formed(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
;
66 StringPiece client_nonce
;
67 StringPiece server_nonce
;
70 struct ValidateClientHelloResultCallback::Result
{
71 Result(const CryptoHandshakeMessage
& in_client_hello
,
72 IPEndPoint in_client_ip
,
74 : client_hello(in_client_hello
),
75 info(in_client_ip
, in_now
),
76 error_code(QUIC_NO_ERROR
) {
79 CryptoHandshakeMessage client_hello
;
81 QuicErrorCode error_code
;
85 class ValidateClientHelloHelper
{
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_
);
104 void StartedAsyncCallback() {
109 void DetachCallback() {
110 LOG_IF(DFATAL
, done_cb_
== NULL
) << "Callback already detached.";
114 ValidateClientHelloResultCallback::Result
* result_
;
115 ValidateClientHelloResultCallback
* done_cb_
;
117 DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloHelper
);
120 class VerifyNonceIsValidAndUniqueCallback
121 : public StrikeRegisterClient::ResultCallback
{
123 VerifyNonceIsValidAndUniqueCallback(
124 ValidateClientHelloResultCallback::Result
* result
,
125 ValidateClientHelloResultCallback
* done_cb
)
126 : result_(result
), done_cb_(done_cb
) {
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_
);
137 ValidateClientHelloResultCallback::Result
* result_
;
138 ValidateClientHelloResultCallback
* done_cb_
;
140 DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback
);
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
);
164 QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
165 : expiry_time(QuicWallTime::Zero()),
166 channel_id_enabled(false),
169 QuicCryptoServerConfig::QuicCryptoServerConfig(
170 StringPiece source_address_token_secret
,
172 : replay_protection_(true),
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
;
205 QuicServerConfigProtobuf
* QuicCryptoServerConfig::GenerateConfig(
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
;
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());
240 msg
.SetTaglist(kKEXS
, kC255
, kP256
, 0);
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
);
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
));
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());
281 hash
->Finish(scid_bytes
, sizeof(scid_bytes
));
282 msg
.SetStringPiece(kSCID
, StringPiece(scid_bytes
, sizeof(scid_bytes
)));
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
);
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()));
314 LOG(WARNING
) << "Failed to parse server config message";
318 scoped_refptr
<Config
> config(ParseConfigProtobuf(protobuf
));
320 LOG(WARNING
) << "Failed to parse server config message";
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());
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(
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
;
357 for (vector
<QuicServerConfigProtobuf
*>::const_iterator i
= protobufs
.begin();
358 i
!= protobufs
.end(); ++i
) {
359 scoped_refptr
<Config
> config(ParseConfigProtobuf(*i
));
365 parsed_configs
.push_back(config
);
368 if (parsed_configs
.empty()) {
369 LOG(WARNING
) << "New config list is empty.";
374 LOG(WARNING
) << "Rejecting QUIC configs because of above errors";
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()) {
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
);
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_
);
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";
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
);
461 done_cb
->Run(result
);
465 QuicErrorCode
QuicCryptoServerConfig::ProcessClientHello(
466 const ValidateClientHelloResultCallback::Result
& validate_chlo_result
,
467 QuicConnectionId connection_id
,
468 IPEndPoint client_address
,
470 const QuicVersionVector
& supported_versions
,
471 const QuicClock
* clock
,
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_|
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
;
544 if (!info
.valid_source_address_token
||
545 !info
.client_nonce_well_formed
||
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 ¶ms
->aead
, NULL
) ||
569 !QuicUtils::FindMutualTag(
570 requested_config
->kexs
, their_key_exchanges
, num_their_key_exchanges
,
571 QuicUtils::LOCAL_PRIORITY
, ¶ms
->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 ¶ms
->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());
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();
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 */,
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()));
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();
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
,
669 ¶ms
->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
);
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
, ¶ms
->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
,
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
, ¶ms
->forward_secure_crypters
)) {
703 *error_details
= "Symmetric key setup failed";
704 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
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.
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
;
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.";
756 LOG(DFATAL
) << "No valid QUIC server config.";
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
;
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
);
779 // We need the primary_time of the next config.
780 if (configs
.size() > 1) {
781 next_config_promotion_time_
= configs
[1]->primary_time
;
783 next_config_promotion_time_
= QuicWallTime::Zero();
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: "
796 reinterpret_cast<const char*>(primary_config_
->orbit
),
798 if (primary_config_changed_cb_
.get() != NULL
) {
799 primary_config_changed_cb_
->Run(primary_config_
->id
);
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: "
815 reinterpret_cast<const char*>(primary_config_
->orbit
),
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");
839 if (client_hello
.GetStringPiece(kSNI
, &info
->sni
) &&
840 !CryptoUtils::IsValidSNI(info
->sni
)) {
841 helper
.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
,
847 if (client_hello
.GetStringPiece(kSourceAddressTokenTag
, &srct
) &&
848 ValidateSourceAddressToken(srct
, info
->client_ip
, info
->now
)) {
849 info
->valid_source_address_token
= true;
851 // No valid source address token.
852 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
856 if (client_hello
.GetStringPiece(kNONC
, &info
->client_nonce
) &&
857 info
->client_nonce
.size() == kNonceSize
) {
858 info
->client_nonce_well_formed
= true;
860 // Invalid client nonce.
861 DVLOG(1) << "Invalid client nonce.";
862 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
866 if (!replay_protection_
) {
868 DVLOG(1) << "No replay protection.";
869 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
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
, "");
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_
,
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(
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
,
912 CryptoHandshakeMessage
* out
) const {
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
) !=
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
]) {
936 x509_supported
= true;
937 x509_ecdsa_supported
= true;
940 x509_supported
= true;
945 if (!x509_supported
) {
949 const vector
<string
>* certs
;
951 if (!proof_source_
->GetProof(info
.sni
.as_string(), config
->serialized
,
952 x509_ecdsa_supported
, &certs
, &signature
)) {
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.
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
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
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
;
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();
1014 if (!msg
->GetStringPiece(kSCID
, &scid
)) {
1015 LOG(WARNING
) << "Server config message is missing SCID";
1018 config
->id
= scid
.as_string();
1020 const QuicTag
* aead_tags
;
1022 if (msg
->GetTaglist(kAEAD
, &aead_tags
, &aead_len
) != QUIC_NO_ERROR
) {
1023 LOG(WARNING
) << "Server config message is missing AEAD";
1026 config
->aead
= vector
<QuicTag
>(aead_tags
, aead_tags
+ aead_len
);
1028 const QuicTag
* kexs_tags
;
1030 if (msg
->GetTaglist(kKEXS
, &kexs_tags
, &kexs_len
) != QUIC_NO_ERROR
) {
1031 LOG(WARNING
) << "Server config message is missing KEXS";
1036 if (!msg
->GetStringPiece(kORBT
, &orbit
)) {
1037 LOG(WARNING
) << "Server config message is missing OBIT";
1041 if (orbit
.size() != kOrbitSize
) {
1042 LOG(WARNING
) << "Orbit value in server config is the wrong length."
1043 " Got " << orbit
.size() << " want " << kOrbitSize
;
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
)) {
1059 << "Rejecting server config with orbit that the strike register "
1060 "client doesn't know about.";
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";
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
) ==
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;
1084 for (size_t i
= 0; i
< kexs_len
; i
++) {
1085 const QuicTag tag
= kexs_tags
[i
];
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();
1098 if (private_key
.empty()) {
1099 LOG(WARNING
) << "Server config contains key exchange method without "
1100 "corresponding private key: " << tag
;
1104 scoped_ptr
<KeyExchange
> ka
;
1107 ka
.reset(Curve25519KeyExchange::New(private_key
));
1109 LOG(WARNING
) << "Server config contained an invalid curve25519"
1115 ka
.reset(P256KeyExchange::New(private_key
));
1117 LOG(WARNING
) << "Server config contained an invalid P-256"
1123 LOG(WARNING
) << "Server config message contains unknown key exchange "
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
;
1136 config
->key_exchanges
.push_back(ka
.release());
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
,
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(
1224 const IPEndPoint
& ip
,
1225 QuicWallTime now
) const {
1227 StringPiece plaintext
;
1228 if (!source_address_token_boxer_
.Unbox(token
, &storage
, &plaintext
)) {
1232 SourceAddressToken source_address_token
;
1233 if (!source_address_token
.ParseFromArray(plaintext
.data(),
1234 plaintext
.size())) {
1238 if (source_address_token
.ip() != IPAddressToPackedString(ip
.address())) {
1239 // It's for a different IP address.
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_
) {
1252 if (now
.IsAfter(timestamp
) &&
1253 delta
.ToSeconds() > source_address_token_lifetime_secs_
) {
1260 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server
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(
1280 StringPiece(reinterpret_cast<char*>(server_nonce
), sizeof(server_nonce
)));
1283 bool QuicCryptoServerConfig::ValidateServerNonce(StringPiece token
,
1284 QuicWallTime now
) const {
1286 StringPiece plaintext
;
1287 if (!server_nonce_boxer_
.Unbox(token
, &storage
, &plaintext
)) {
1291 // plaintext contains:
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.";
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,
1306 COMPILE_ASSERT(4 + sizeof(server_nonce_orbit_
) + 20 == sizeof(server_nonce
),
1307 bad_nonce_buffer_length
);
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()));
1326 QuicCryptoServerConfig::Config::Config()
1327 : channel_id_enabled(false),
1329 primary_time(QuicWallTime::Zero()),
1332 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges
); }