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/chacha20_poly1305_encrypter.h"
19 #include "net/quic/crypto/channel_id.h"
20 #include "net/quic/crypto/crypto_framer.h"
21 #include "net/quic/crypto/crypto_server_config_protobuf.h"
22 #include "net/quic/crypto/crypto_utils.h"
23 #include "net/quic/crypto/curve25519_key_exchange.h"
24 #include "net/quic/crypto/ephemeral_key_source.h"
25 #include "net/quic/crypto/key_exchange.h"
26 #include "net/quic/crypto/local_strike_register_client.h"
27 #include "net/quic/crypto/p256_key_exchange.h"
28 #include "net/quic/crypto/proof_source.h"
29 #include "net/quic/crypto/quic_decrypter.h"
30 #include "net/quic/crypto/quic_encrypter.h"
31 #include "net/quic/crypto/quic_random.h"
32 #include "net/quic/crypto/source_address_token.h"
33 #include "net/quic/crypto/strike_register.h"
34 #include "net/quic/crypto/strike_register_client.h"
35 #include "net/quic/quic_clock.h"
36 #include "net/quic/quic_flags.h"
37 #include "net/quic/quic_protocol.h"
38 #include "net/quic/quic_socket_address_coder.h"
39 #include "net/quic/quic_utils.h"
41 using base::StringPiece
;
42 using crypto::SecureHash
;
52 string
DeriveSourceAddressTokenKey(StringPiece source_address_token_secret
) {
53 crypto::HKDF
hkdf(source_address_token_secret
,
54 StringPiece() /* no salt */,
55 "QUIC source address token key",
56 CryptoSecretBoxer::GetKeySize(),
57 0 /* no fixed IV needed */);
58 return hkdf
.server_write_key().as_string();
63 // ClientHelloInfo contains information about a client hello message that is
64 // only kept for as long as it's being processed.
65 struct ClientHelloInfo
{
66 ClientHelloInfo(const IPEndPoint
& in_client_ip
, QuicWallTime in_now
)
67 : client_ip(in_client_ip
),
69 valid_source_address_token(false),
70 client_nonce_well_formed(false),
73 // Inputs to EvaluateClientHello.
74 const IPEndPoint client_ip
;
75 const QuicWallTime now
;
77 // Outputs from EvaluateClientHello.
78 bool valid_source_address_token
;
79 bool client_nonce_well_formed
;
82 StringPiece client_nonce
;
83 StringPiece server_nonce
;
84 StringPiece user_agent_id
;
86 // Errors from EvaluateClientHello.
87 vector
<uint32
> reject_reasons
;
88 COMPILE_ASSERT(sizeof(QuicTag
) == sizeof(uint32
), header_out_of_sync
);
91 struct ValidateClientHelloResultCallback::Result
{
92 Result(const CryptoHandshakeMessage
& in_client_hello
,
93 IPEndPoint in_client_ip
,
95 : client_hello(in_client_hello
),
96 info(in_client_ip
, in_now
),
97 error_code(QUIC_NO_ERROR
) {
100 CryptoHandshakeMessage client_hello
;
101 ClientHelloInfo info
;
102 QuicErrorCode error_code
;
103 string error_details
;
106 class ValidateClientHelloHelper
{
108 ValidateClientHelloHelper(ValidateClientHelloResultCallback::Result
* result
,
109 ValidateClientHelloResultCallback
* done_cb
)
110 : result_(result
), done_cb_(done_cb
) {
113 ~ValidateClientHelloHelper() {
114 LOG_IF(DFATAL
, done_cb_
!= NULL
)
115 << "Deleting ValidateClientHelloHelper with a pending callback.";
118 void ValidationComplete(QuicErrorCode error_code
, const char* error_details
) {
119 result_
->error_code
= error_code
;
120 result_
->error_details
= error_details
;
121 done_cb_
->Run(result_
);
125 void StartedAsyncCallback() {
130 void DetachCallback() {
131 LOG_IF(DFATAL
, done_cb_
== NULL
) << "Callback already detached.";
135 ValidateClientHelloResultCallback::Result
* result_
;
136 ValidateClientHelloResultCallback
* done_cb_
;
138 DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloHelper
);
141 class VerifyNonceIsValidAndUniqueCallback
142 : public StrikeRegisterClient::ResultCallback
{
144 VerifyNonceIsValidAndUniqueCallback(
145 ValidateClientHelloResultCallback::Result
* result
,
146 ValidateClientHelloResultCallback
* done_cb
)
147 : result_(result
), done_cb_(done_cb
) {
151 virtual void RunImpl(bool nonce_is_valid_and_unique
) OVERRIDE
{
152 DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique
;
153 result_
->info
.unique
= nonce_is_valid_and_unique
;
154 // TODO(rtenneti): Implement capturing of error from strike register.
155 // Temporarily treat them as CLIENT_NONCE_INVALID_FAILURE.
156 if (!nonce_is_valid_and_unique
) {
157 result_
->info
.reject_reasons
.push_back(CLIENT_NONCE_INVALID_FAILURE
);
159 done_cb_
->Run(result_
);
163 ValidateClientHelloResultCallback::Result
* result_
;
164 ValidateClientHelloResultCallback
* done_cb_
;
166 DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback
);
170 const char QuicCryptoServerConfig::TESTING
[] = "secret string for testing";
172 PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {
175 PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {
178 ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {
181 ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {
184 void ValidateClientHelloResultCallback::Run(const Result
* result
) {
185 RunImpl(result
->client_hello
, *result
);
190 QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
191 : expiry_time(QuicWallTime::Zero()),
192 channel_id_enabled(false),
195 QuicCryptoServerConfig::QuicCryptoServerConfig(
196 StringPiece source_address_token_secret
,
198 : replay_protection_(true),
200 primary_config_(NULL
),
201 next_config_promotion_time_(QuicWallTime::Zero()),
202 server_nonce_strike_register_lock_(),
203 strike_register_no_startup_period_(false),
204 strike_register_max_entries_(1 << 10),
205 strike_register_window_secs_(600),
206 source_address_token_future_secs_(3600),
207 source_address_token_lifetime_secs_(86400),
208 server_nonce_strike_register_max_entries_(1 << 10),
209 server_nonce_strike_register_window_secs_(120) {
210 default_source_address_token_boxer_
.SetKey(
211 DeriveSourceAddressTokenKey(source_address_token_secret
));
213 // Generate a random key and orbit for server nonces.
214 rand
->RandBytes(server_nonce_orbit_
, sizeof(server_nonce_orbit_
));
215 const size_t key_size
= server_nonce_boxer_
.GetKeySize();
216 scoped_ptr
<uint8
[]> key_bytes(new uint8
[key_size
]);
217 rand
->RandBytes(key_bytes
.get(), key_size
);
219 server_nonce_boxer_
.SetKey(
220 StringPiece(reinterpret_cast<char*>(key_bytes
.get()), key_size
));
223 QuicCryptoServerConfig::~QuicCryptoServerConfig() {
224 primary_config_
= NULL
;
228 QuicServerConfigProtobuf
* QuicCryptoServerConfig::GenerateConfig(
230 const QuicClock
* clock
,
231 const ConfigOptions
& options
) {
232 CryptoHandshakeMessage msg
;
234 const string curve25519_private_key
=
235 Curve25519KeyExchange::NewPrivateKey(rand
);
236 scoped_ptr
<Curve25519KeyExchange
> curve25519(
237 Curve25519KeyExchange::New(curve25519_private_key
));
238 StringPiece curve25519_public_value
= curve25519
->public_value();
240 string encoded_public_values
;
241 // First three bytes encode the length of the public value.
242 encoded_public_values
.push_back(curve25519_public_value
.size());
243 encoded_public_values
.push_back(curve25519_public_value
.size() >> 8);
244 encoded_public_values
.push_back(curve25519_public_value
.size() >> 16);
245 encoded_public_values
.append(curve25519_public_value
.data(),
246 curve25519_public_value
.size());
248 string p256_private_key
;
250 p256_private_key
= P256KeyExchange::NewPrivateKey();
251 scoped_ptr
<P256KeyExchange
> p256(P256KeyExchange::New(p256_private_key
));
252 StringPiece p256_public_value
= p256
->public_value();
254 encoded_public_values
.push_back(p256_public_value
.size());
255 encoded_public_values
.push_back(p256_public_value
.size() >> 8);
256 encoded_public_values
.push_back(p256_public_value
.size() >> 16);
257 encoded_public_values
.append(p256_public_value
.data(),
258 p256_public_value
.size());
263 msg
.SetTaglist(kKEXS
, kC255
, kP256
, 0);
265 msg
.SetTaglist(kKEXS
, kC255
, 0);
267 if (ChaCha20Poly1305Encrypter::IsSupported()) {
268 msg
.SetTaglist(kAEAD
, kAESG
, kCC12
, 0);
270 msg
.SetTaglist(kAEAD
, kAESG
, 0);
272 msg
.SetStringPiece(kPUBS
, encoded_public_values
);
274 if (options
.expiry_time
.IsZero()) {
275 const QuicWallTime now
= clock
->WallNow();
276 const QuicWallTime expiry
= now
.Add(QuicTime::Delta::FromSeconds(
277 60 * 60 * 24 * 180 /* 180 days, ~six months */));
278 const uint64 expiry_seconds
= expiry
.ToUNIXSeconds();
279 msg
.SetValue(kEXPY
, expiry_seconds
);
281 msg
.SetValue(kEXPY
, options
.expiry_time
.ToUNIXSeconds());
284 char orbit_bytes
[kOrbitSize
];
285 if (options
.orbit
.size() == sizeof(orbit_bytes
)) {
286 memcpy(orbit_bytes
, options
.orbit
.data(), sizeof(orbit_bytes
));
288 DCHECK(options
.orbit
.empty());
289 rand
->RandBytes(orbit_bytes
, sizeof(orbit_bytes
));
291 msg
.SetStringPiece(kORBT
, StringPiece(orbit_bytes
, sizeof(orbit_bytes
)));
293 if (options
.channel_id_enabled
) {
294 msg
.SetTaglist(kPDMD
, kCHID
, 0);
297 if (options
.id
.empty()) {
298 // We need to ensure that the SCID changes whenever the server config does
299 // thus we make it a hash of the rest of the server config.
300 scoped_ptr
<QuicData
> serialized(
301 CryptoFramer::ConstructHandshakeMessage(msg
));
302 scoped_ptr
<SecureHash
> hash(SecureHash::Create(SecureHash::SHA256
));
303 hash
->Update(serialized
->data(), serialized
->length());
306 hash
->Finish(scid_bytes
, sizeof(scid_bytes
));
307 msg
.SetStringPiece(kSCID
, StringPiece(scid_bytes
, sizeof(scid_bytes
)));
309 msg
.SetStringPiece(kSCID
, options
.id
);
311 // Don't put new tags below this point. The SCID generation should hash over
312 // everything but itself and so extra tags should be added prior to the
313 // preceeding if block.
315 scoped_ptr
<QuicData
> serialized(CryptoFramer::ConstructHandshakeMessage(msg
));
317 scoped_ptr
<QuicServerConfigProtobuf
> config(new QuicServerConfigProtobuf
);
318 config
->set_config(serialized
->AsStringPiece());
319 QuicServerConfigProtobuf::PrivateKey
* curve25519_key
= config
->add_key();
320 curve25519_key
->set_tag(kC255
);
321 curve25519_key
->set_private_key(curve25519_private_key
);
324 QuicServerConfigProtobuf::PrivateKey
* p256_key
= config
->add_key();
325 p256_key
->set_tag(kP256
);
326 p256_key
->set_private_key(p256_private_key
);
329 return config
.release();
332 CryptoHandshakeMessage
* QuicCryptoServerConfig::AddConfig(
333 QuicServerConfigProtobuf
* protobuf
,
334 const QuicWallTime now
) {
335 scoped_ptr
<CryptoHandshakeMessage
> msg(
336 CryptoFramer::ParseMessage(protobuf
->config()));
339 LOG(WARNING
) << "Failed to parse server config message";
343 scoped_refptr
<Config
> config(ParseConfigProtobuf(protobuf
));
345 LOG(WARNING
) << "Failed to parse server config message";
350 base::AutoLock
locked(configs_lock_
);
351 if (configs_
.find(config
->id
) != configs_
.end()) {
352 LOG(WARNING
) << "Failed to add config because another with the same "
353 "server config id already exists: "
354 << base::HexEncode(config
->id
.data(), config
->id
.size());
358 configs_
[config
->id
] = config
;
359 SelectNewPrimaryConfig(now
);
360 DCHECK(primary_config_
.get());
361 DCHECK_EQ(configs_
.find(primary_config_
->id
)->second
, primary_config_
);
364 return msg
.release();
367 CryptoHandshakeMessage
* QuicCryptoServerConfig::AddDefaultConfig(
369 const QuicClock
* clock
,
370 const ConfigOptions
& options
) {
371 scoped_ptr
<QuicServerConfigProtobuf
> config(
372 GenerateConfig(rand
, clock
, options
));
373 return AddConfig(config
.get(), clock
->WallNow());
376 bool QuicCryptoServerConfig::SetConfigs(
377 const vector
<QuicServerConfigProtobuf
*>& protobufs
,
378 const QuicWallTime now
) {
379 vector
<scoped_refptr
<Config
> > parsed_configs
;
382 for (vector
<QuicServerConfigProtobuf
*>::const_iterator i
= protobufs
.begin();
383 i
!= protobufs
.end(); ++i
) {
384 scoped_refptr
<Config
> config(ParseConfigProtobuf(*i
));
390 parsed_configs
.push_back(config
);
393 if (parsed_configs
.empty()) {
394 LOG(WARNING
) << "New config list is empty.";
399 LOG(WARNING
) << "Rejecting QUIC configs because of above errors";
401 VLOG(1) << "Updating configs:";
403 base::AutoLock
locked(configs_lock_
);
404 ConfigMap new_configs
;
406 for (vector
<scoped_refptr
<Config
> >::const_iterator i
=
407 parsed_configs
.begin();
408 i
!= parsed_configs
.end(); ++i
) {
409 scoped_refptr
<Config
> config
= *i
;
411 ConfigMap::iterator it
= configs_
.find(config
->id
);
412 if (it
!= configs_
.end()) {
414 << "Keeping scid: " << base::HexEncode(
415 config
->id
.data(), config
->id
.size())
416 << " orbit: " << base::HexEncode(
417 reinterpret_cast<const char *>(config
->orbit
), kOrbitSize
)
418 << " new primary_time " << config
->primary_time
.ToUNIXSeconds()
419 << " old primary_time " << it
->second
->primary_time
.ToUNIXSeconds()
420 << " new priority " << config
->priority
421 << " old priority " << it
->second
->priority
;
422 // Update primary_time and priority.
423 it
->second
->primary_time
= config
->primary_time
;
424 it
->second
->priority
= config
->priority
;
425 new_configs
.insert(*it
);
427 VLOG(1) << "Adding scid: " << base::HexEncode(
428 config
->id
.data(), config
->id
.size())
429 << " orbit: " << base::HexEncode(
430 reinterpret_cast<const char *>(config
->orbit
), kOrbitSize
)
431 << " primary_time " << config
->primary_time
.ToUNIXSeconds()
432 << " priority " << config
->priority
;
433 new_configs
.insert(make_pair(config
->id
, config
));
437 configs_
.swap(new_configs
);
438 SelectNewPrimaryConfig(now
);
439 DCHECK(primary_config_
);
440 DCHECK_EQ(configs_
.find(primary_config_
->id
)->second
, primary_config_
);
446 void QuicCryptoServerConfig::GetConfigIds(vector
<string
>* scids
) const {
447 base::AutoLock
locked(configs_lock_
);
448 for (ConfigMap::const_iterator it
= configs_
.begin();
449 it
!= configs_
.end(); ++it
) {
450 scids
->push_back(it
->first
);
454 void QuicCryptoServerConfig::ValidateClientHello(
455 const CryptoHandshakeMessage
& client_hello
,
456 IPEndPoint client_ip
,
457 const QuicClock
* clock
,
458 ValidateClientHelloResultCallback
* done_cb
) const {
459 const QuicWallTime
now(clock
->WallNow());
461 ValidateClientHelloResultCallback::Result
* result
=
462 new ValidateClientHelloResultCallback::Result(
463 client_hello
, client_ip
, now
);
465 StringPiece requested_scid
;
466 client_hello
.GetStringPiece(kSCID
, &requested_scid
);
468 uint8 primary_orbit
[kOrbitSize
];
469 scoped_refptr
<Config
> requested_config
;
471 base::AutoLock
locked(configs_lock_
);
473 if (!primary_config_
.get()) {
474 result
->error_code
= QUIC_CRYPTO_INTERNAL_ERROR
;
475 result
->error_details
= "No configurations loaded";
477 if (!next_config_promotion_time_
.IsZero() &&
478 next_config_promotion_time_
.IsAfter(now
)) {
479 SelectNewPrimaryConfig(now
);
480 DCHECK(primary_config_
);
481 DCHECK(configs_
.find(primary_config_
->id
)->second
== primary_config_
);
484 memcpy(primary_orbit
, primary_config_
->orbit
, sizeof(primary_orbit
));
487 requested_config
= GetConfigWithScid(requested_scid
);
490 if (result
->error_code
== QUIC_NO_ERROR
) {
491 EvaluateClientHello(primary_orbit
, requested_config
, result
, done_cb
);
493 done_cb
->Run(result
);
497 QuicErrorCode
QuicCryptoServerConfig::ProcessClientHello(
498 const ValidateClientHelloResultCallback::Result
& validate_chlo_result
,
499 QuicConnectionId connection_id
,
500 IPEndPoint client_address
,
502 const QuicVersionVector
& supported_versions
,
503 const QuicClock
* clock
,
505 QuicCryptoNegotiatedParameters
*params
,
506 CryptoHandshakeMessage
* out
,
507 string
* error_details
) const {
508 DCHECK(error_details
);
510 const CryptoHandshakeMessage
& client_hello
=
511 validate_chlo_result
.client_hello
;
512 const ClientHelloInfo
& info
= validate_chlo_result
.info
;
514 // If the client's preferred version is not the version we are currently
515 // speaking, then the client went through a version negotiation. In this
516 // case, we need to make sure that we actually do not support this version
517 // and that it wasn't a downgrade attack.
518 QuicTag client_version_tag
;
519 if (client_hello
.GetUint32(kVER
, &client_version_tag
) != QUIC_NO_ERROR
) {
520 *error_details
= "client hello missing version list";
521 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
523 QuicVersion client_version
= QuicTagToQuicVersion(client_version_tag
);
524 if (client_version
!= version
) {
525 // Just because client_version is a valid version enum doesn't mean that
526 // this server actually supports that version, so we check to see if
527 // it's actually in the supported versions list.
528 for (size_t i
= 0; i
< supported_versions
.size(); ++i
) {
529 if (client_version
== supported_versions
[i
]) {
530 *error_details
= "Downgrade attack detected";
531 return QUIC_VERSION_NEGOTIATION_MISMATCH
;
536 StringPiece requested_scid
;
537 client_hello
.GetStringPiece(kSCID
, &requested_scid
);
538 const QuicWallTime
now(clock
->WallNow());
540 scoped_refptr
<Config
> requested_config
;
541 scoped_refptr
<Config
> primary_config
;
543 base::AutoLock
locked(configs_lock_
);
545 if (!primary_config_
.get()) {
546 *error_details
= "No configurations loaded";
547 return QUIC_CRYPTO_INTERNAL_ERROR
;
550 if (!next_config_promotion_time_
.IsZero() &&
551 next_config_promotion_time_
.IsAfter(now
)) {
552 SelectNewPrimaryConfig(now
);
553 DCHECK(primary_config_
);
554 DCHECK(configs_
.find(primary_config_
->id
)->second
== primary_config_
);
557 // We'll use the config that the client requested in order to do
558 // key-agreement. Otherwise we'll give it a copy of |primary_config_|
560 primary_config
= primary_config_
;
562 requested_config
= GetConfigWithScid(requested_scid
);
565 if (validate_chlo_result
.error_code
!= QUIC_NO_ERROR
) {
566 *error_details
= validate_chlo_result
.error_details
;
567 return validate_chlo_result
.error_code
;
572 if (!info
.valid_source_address_token
||
573 !info
.client_nonce_well_formed
||
575 !requested_config
.get()) {
576 BuildRejection(*primary_config
, client_hello
, info
, rand
, out
);
577 return QUIC_NO_ERROR
;
580 const QuicTag
* their_aeads
;
581 const QuicTag
* their_key_exchanges
;
582 size_t num_their_aeads
, num_their_key_exchanges
;
583 if (client_hello
.GetTaglist(kAEAD
, &their_aeads
,
584 &num_their_aeads
) != QUIC_NO_ERROR
||
585 client_hello
.GetTaglist(kKEXS
, &their_key_exchanges
,
586 &num_their_key_exchanges
) != QUIC_NO_ERROR
||
587 num_their_aeads
!= 1 ||
588 num_their_key_exchanges
!= 1) {
589 *error_details
= "Missing or invalid AEAD or KEXS";
590 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
593 size_t key_exchange_index
;
594 if (!QuicUtils::FindMutualTag(requested_config
->aead
, their_aeads
,
595 num_their_aeads
, QuicUtils::LOCAL_PRIORITY
,
596 ¶ms
->aead
, NULL
) ||
597 !QuicUtils::FindMutualTag(
598 requested_config
->kexs
, their_key_exchanges
, num_their_key_exchanges
,
599 QuicUtils::LOCAL_PRIORITY
, ¶ms
->key_exchange
,
600 &key_exchange_index
)) {
601 *error_details
= "Unsupported AEAD or KEXS";
602 return QUIC_CRYPTO_NO_SUPPORT
;
605 StringPiece public_value
;
606 if (!client_hello
.GetStringPiece(kPUBS
, &public_value
)) {
607 *error_details
= "Missing public value";
608 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
611 const KeyExchange
* key_exchange
=
612 requested_config
->key_exchanges
[key_exchange_index
];
613 if (!key_exchange
->CalculateSharedKey(public_value
,
614 ¶ms
->initial_premaster_secret
)) {
615 *error_details
= "Invalid public value";
616 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
619 if (!info
.sni
.empty()) {
620 scoped_ptr
<char[]> sni_tmp(new char[info
.sni
.length() + 1]);
621 memcpy(sni_tmp
.get(), info
.sni
.data(), info
.sni
.length());
622 sni_tmp
[info
.sni
.length()] = 0;
623 params
->sni
= CryptoUtils::NormalizeHostname(sni_tmp
.get());
627 const QuicData
& client_hello_serialized
= client_hello
.GetSerialized();
628 hkdf_suffix
.reserve(sizeof(connection_id
) + client_hello_serialized
.length() +
629 requested_config
->serialized
.size());
630 hkdf_suffix
.append(reinterpret_cast<char*>(&connection_id
),
631 sizeof(connection_id
));
632 hkdf_suffix
.append(client_hello_serialized
.data(),
633 client_hello_serialized
.length());
634 hkdf_suffix
.append(requested_config
->serialized
);
636 StringPiece cetv_ciphertext
;
637 if (requested_config
->channel_id_enabled
&&
638 client_hello
.GetStringPiece(kCETV
, &cetv_ciphertext
)) {
639 CryptoHandshakeMessage
client_hello_copy(client_hello
);
640 client_hello_copy
.Erase(kCETV
);
641 client_hello_copy
.Erase(kPAD
);
643 const QuicData
& client_hello_serialized
= client_hello_copy
.GetSerialized();
645 hkdf_input
.append(QuicCryptoConfig::kCETVLabel
,
646 strlen(QuicCryptoConfig::kCETVLabel
) + 1);
647 hkdf_input
.append(reinterpret_cast<char*>(&connection_id
),
648 sizeof(connection_id
));
649 hkdf_input
.append(client_hello_serialized
.data(),
650 client_hello_serialized
.length());
651 hkdf_input
.append(requested_config
->serialized
);
653 CrypterPair crypters
;
654 if (!CryptoUtils::DeriveKeys(params
->initial_premaster_secret
, params
->aead
,
655 info
.client_nonce
, info
.server_nonce
,
656 hkdf_input
, CryptoUtils::SERVER
, &crypters
)) {
657 *error_details
= "Symmetric key setup failed";
658 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
661 scoped_ptr
<QuicData
> cetv_plaintext(crypters
.decrypter
->DecryptPacket(
662 0 /* sequence number */, StringPiece() /* associated data */,
664 if (!cetv_plaintext
.get()) {
665 *error_details
= "CETV decryption failure";
666 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
669 scoped_ptr
<CryptoHandshakeMessage
> cetv(CryptoFramer::ParseMessage(
670 cetv_plaintext
->AsStringPiece()));
672 *error_details
= "CETV parse error";
673 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
676 StringPiece key
, signature
;
677 if (cetv
->GetStringPiece(kCIDK
, &key
) &&
678 cetv
->GetStringPiece(kCIDS
, &signature
)) {
679 if (!ChannelIDVerifier::Verify(key
, hkdf_input
, signature
)) {
680 *error_details
= "ChannelID signature failure";
681 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
684 params
->channel_id
= key
.as_string();
689 size_t label_len
= strlen(QuicCryptoConfig::kInitialLabel
) + 1;
690 hkdf_input
.reserve(label_len
+ hkdf_suffix
.size());
691 hkdf_input
.append(QuicCryptoConfig::kInitialLabel
, label_len
);
692 hkdf_input
.append(hkdf_suffix
);
694 if (!CryptoUtils::DeriveKeys(params
->initial_premaster_secret
, params
->aead
,
695 info
.client_nonce
, info
.server_nonce
, hkdf_input
,
697 ¶ms
->initial_crypters
)) {
698 *error_details
= "Symmetric key setup failed";
699 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
702 string forward_secure_public_value
;
703 if (ephemeral_key_source_
.get()) {
704 params
->forward_secure_premaster_secret
=
705 ephemeral_key_source_
->CalculateForwardSecureKey(
706 key_exchange
, rand
, clock
->ApproximateNow(), public_value
,
707 &forward_secure_public_value
);
709 scoped_ptr
<KeyExchange
> forward_secure_key_exchange(
710 key_exchange
->NewKeyPair(rand
));
711 forward_secure_public_value
=
712 forward_secure_key_exchange
->public_value().as_string();
713 if (!forward_secure_key_exchange
->CalculateSharedKey(
714 public_value
, ¶ms
->forward_secure_premaster_secret
)) {
715 *error_details
= "Invalid public value";
716 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
720 string forward_secure_hkdf_input
;
721 label_len
= strlen(QuicCryptoConfig::kForwardSecureLabel
) + 1;
722 forward_secure_hkdf_input
.reserve(label_len
+ hkdf_suffix
.size());
723 forward_secure_hkdf_input
.append(QuicCryptoConfig::kForwardSecureLabel
,
725 forward_secure_hkdf_input
.append(hkdf_suffix
);
727 if (!CryptoUtils::DeriveKeys(
728 params
->forward_secure_premaster_secret
, params
->aead
,
729 info
.client_nonce
, info
.server_nonce
, forward_secure_hkdf_input
,
730 CryptoUtils::SERVER
, ¶ms
->forward_secure_crypters
)) {
731 *error_details
= "Symmetric key setup failed";
732 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
736 QuicTagVector supported_version_tags
;
737 for (size_t i
= 0; i
< supported_versions
.size(); ++i
) {
738 supported_version_tags
.push_back
739 (QuicVersionToQuicTag(supported_versions
[i
]));
741 out
->SetVector(kVER
, supported_version_tags
);
742 out
->SetStringPiece(kSourceAddressTokenTag
,
743 NewSourceAddressToken(
745 client_address
, rand
,
747 QuicSocketAddressCoder
address_coder(client_address
);
748 out
->SetStringPiece(kCADR
, address_coder
.Encode());
749 out
->SetStringPiece(kPUBS
, forward_secure_public_value
);
751 return QUIC_NO_ERROR
;
754 scoped_refptr
<QuicCryptoServerConfig::Config
>
755 QuicCryptoServerConfig::GetConfigWithScid(StringPiece requested_scid
) const {
756 // In Chromium, we will dead lock if the lock is held by the current thread.
757 // Chromium doesn't have AssertReaderHeld API call.
758 // configs_lock_.AssertReaderHeld();
760 if (!requested_scid
.empty()) {
761 ConfigMap::const_iterator it
= configs_
.find(requested_scid
.as_string());
762 if (it
!= configs_
.end()) {
763 // We'll use the config that the client requested in order to do
765 return scoped_refptr
<Config
>(it
->second
);
769 return scoped_refptr
<Config
>();
772 // ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
773 // Config's based on their primary_time.
775 bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
776 const scoped_refptr
<Config
>& a
,
777 const scoped_refptr
<Config
>& b
) {
778 if (a
->primary_time
.IsBefore(b
->primary_time
) ||
779 b
->primary_time
.IsBefore(a
->primary_time
)) {
780 // Primary times differ.
781 return a
->primary_time
.IsBefore(b
->primary_time
);
782 } else if (a
->priority
!= b
->priority
) {
783 // Primary times are equal, sort backwards by priority.
784 return a
->priority
< b
->priority
;
786 // Primary times and priorities are equal, sort by config id.
787 return a
->id
< b
->id
;
791 void QuicCryptoServerConfig::SelectNewPrimaryConfig(
792 const QuicWallTime now
) const {
793 vector
<scoped_refptr
<Config
> > configs
;
794 configs
.reserve(configs_
.size());
796 for (ConfigMap::const_iterator it
= configs_
.begin();
797 it
!= configs_
.end(); ++it
) {
798 // TODO(avd) Exclude expired configs?
799 configs
.push_back(it
->second
);
802 if (configs
.empty()) {
803 if (primary_config_
.get()) {
804 LOG(DFATAL
) << "No valid QUIC server config. Keeping the current config.";
806 LOG(DFATAL
) << "No valid QUIC server config.";
811 sort(configs
.begin(), configs
.end(), ConfigPrimaryTimeLessThan
);
813 Config
* best_candidate
= configs
[0];
815 for (size_t i
= 0; i
< configs
.size(); ++i
) {
816 const scoped_refptr
<Config
> config(configs
[i
]);
817 if (!config
->primary_time
.IsAfter(now
)) {
818 if (config
->primary_time
.IsAfter(best_candidate
->primary_time
)) {
819 best_candidate
= config
;
824 // This is the first config with a primary_time in the future. Thus the
825 // previous Config should be the primary and this one should determine the
826 // next_config_promotion_time_.
827 scoped_refptr
<Config
> new_primary(best_candidate
);
829 // We need the primary_time of the next config.
830 if (configs
.size() > 1) {
831 next_config_promotion_time_
= configs
[1]->primary_time
;
833 next_config_promotion_time_
= QuicWallTime::Zero();
836 next_config_promotion_time_
= config
->primary_time
;
839 if (primary_config_
.get()) {
840 primary_config_
->is_primary
= false;
842 primary_config_
= new_primary
;
843 new_primary
->is_primary
= true;
844 DVLOG(1) << "New primary config. orbit: "
846 reinterpret_cast<const char*>(primary_config_
->orbit
),
848 if (primary_config_changed_cb_
.get() != NULL
) {
849 primary_config_changed_cb_
->Run(primary_config_
->id
);
855 // All config's primary times are in the past. We should make the most recent
856 // and highest priority candidate primary.
857 scoped_refptr
<Config
> new_primary(best_candidate
);
858 if (primary_config_
.get()) {
859 primary_config_
->is_primary
= false;
861 primary_config_
= new_primary
;
862 new_primary
->is_primary
= true;
863 DVLOG(1) << "New primary config. orbit: "
865 reinterpret_cast<const char*>(primary_config_
->orbit
),
867 << " scid: " << base::HexEncode(primary_config_
->id
.data(),
868 primary_config_
->id
.size());
869 next_config_promotion_time_
= QuicWallTime::Zero();
870 if (primary_config_changed_cb_
.get() != NULL
) {
871 primary_config_changed_cb_
->Run(primary_config_
->id
);
875 void QuicCryptoServerConfig::EvaluateClientHello(
876 const uint8
* primary_orbit
,
877 scoped_refptr
<Config
> requested_config
,
878 ValidateClientHelloResultCallback::Result
* client_hello_state
,
879 ValidateClientHelloResultCallback
* done_cb
) const {
880 ValidateClientHelloHelper
helper(client_hello_state
, done_cb
);
882 const CryptoHandshakeMessage
& client_hello
=
883 client_hello_state
->client_hello
;
884 ClientHelloInfo
* info
= &(client_hello_state
->info
);
886 if (client_hello
.size() < kClientHelloMinimumSize
) {
887 helper
.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH
,
888 "Client hello too small");
892 if (client_hello
.GetStringPiece(kSNI
, &info
->sni
) &&
893 !CryptoUtils::IsValidSNI(info
->sni
)) {
894 helper
.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
,
899 client_hello
.GetStringPiece(kUAID
, &info
->user_agent_id
);
901 if (!requested_config
.get()) {
902 StringPiece requested_scid
;
903 if (client_hello
.GetStringPiece(kSCID
, &requested_scid
)) {
904 info
->reject_reasons
.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE
);
906 info
->reject_reasons
.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE
);
908 // No server config with the requested ID.
909 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
913 HandshakeFailureReason source_address_token_error
;
915 if (client_hello
.GetStringPiece(kSourceAddressTokenTag
, &srct
)) {
916 source_address_token_error
=
917 ValidateSourceAddressToken(*requested_config
,
921 info
->valid_source_address_token
=
922 (source_address_token_error
== HANDSHAKE_OK
);
924 source_address_token_error
= SOURCE_ADDRESS_TOKEN_INVALID_FAILURE
;
927 bool found_error
= false;
928 if (source_address_token_error
!= HANDSHAKE_OK
) {
929 info
->reject_reasons
.push_back(source_address_token_error
);
930 // No valid source address token.
931 if (FLAGS_use_early_return_when_verifying_chlo
) {
932 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
938 if (client_hello
.GetStringPiece(kNONC
, &info
->client_nonce
) &&
939 info
->client_nonce
.size() == kNonceSize
) {
940 info
->client_nonce_well_formed
= true;
942 info
->reject_reasons
.push_back(CLIENT_NONCE_INVALID_FAILURE
);
943 // Invalid client nonce.
944 DVLOG(1) << "Invalid client nonce.";
945 if (FLAGS_use_early_return_when_verifying_chlo
) {
946 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
952 if (!replay_protection_
) {
956 DVLOG(1) << "No replay protection.";
957 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
961 client_hello
.GetStringPiece(kServerNonceTag
, &info
->server_nonce
);
962 if (!info
->server_nonce
.empty()) {
963 // If the server nonce is present, use it to establish uniqueness.
964 HandshakeFailureReason server_nonce_error
=
965 ValidateServerNonce(info
->server_nonce
, info
->now
);
966 if (server_nonce_error
== HANDSHAKE_OK
) {
969 info
->reject_reasons
.push_back(server_nonce_error
);
970 info
->unique
= false;
972 DVLOG(1) << "Using server nonce, unique: " << info
->unique
;
973 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
977 // We want to contact strike register only if there are no errors because it
978 // is a RPC call and is expensive.
980 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
984 // Use the client nonce to establish uniqueness.
985 StrikeRegisterClient
* strike_register_client
;
987 base::AutoLock
locked(strike_register_client_lock_
);
989 if (strike_register_client_
.get() == NULL
) {
990 strike_register_client_
.reset(new LocalStrikeRegisterClient(
991 strike_register_max_entries_
,
992 static_cast<uint32
>(info
->now
.ToUNIXSeconds()),
993 strike_register_window_secs_
,
995 strike_register_no_startup_period_
?
996 StrikeRegister::NO_STARTUP_PERIOD_NEEDED
:
997 StrikeRegister::DENY_REQUESTS_AT_STARTUP
));
999 strike_register_client
= strike_register_client_
.get();
1002 strike_register_client
->VerifyNonceIsValidAndUnique(
1005 new VerifyNonceIsValidAndUniqueCallback(client_hello_state
, done_cb
));
1006 helper
.StartedAsyncCallback();
1009 void QuicCryptoServerConfig::BuildRejection(
1010 const Config
& config
,
1011 const CryptoHandshakeMessage
& client_hello
,
1012 const ClientHelloInfo
& info
,
1014 CryptoHandshakeMessage
* out
) const {
1016 out
->SetStringPiece(kSCFG
, config
.serialized
);
1017 out
->SetStringPiece(kSourceAddressTokenTag
,
1018 NewSourceAddressToken(
1023 if (replay_protection_
) {
1024 out
->SetStringPiece(kServerNonceTag
, NewServerNonce(rand
, info
.now
));
1027 if (FLAGS_send_quic_crypto_reject_reason
) {
1028 // Send client the reject reason for debugging purposes.
1029 DCHECK_LT(0u, info
.reject_reasons
.size());
1030 out
->SetVector(kRREJ
, info
.reject_reasons
);
1033 // The client may have requested a certificate chain.
1034 const QuicTag
* their_proof_demands
;
1035 size_t num_their_proof_demands
;
1037 if (proof_source_
.get() == NULL
||
1038 client_hello
.GetTaglist(kPDMD
, &their_proof_demands
,
1039 &num_their_proof_demands
) !=
1044 bool x509_supported
= false, x509_ecdsa_supported
= false;
1045 for (size_t i
= 0; i
< num_their_proof_demands
; i
++) {
1046 switch (their_proof_demands
[i
]) {
1048 x509_supported
= true;
1049 x509_ecdsa_supported
= true;
1052 x509_supported
= true;
1057 if (!x509_supported
) {
1061 const vector
<string
>* certs
;
1063 if (!proof_source_
->GetProof(info
.sni
.as_string(), config
.serialized
,
1064 x509_ecdsa_supported
, &certs
, &signature
)) {
1068 StringPiece their_common_set_hashes
;
1069 StringPiece their_cached_cert_hashes
;
1070 client_hello
.GetStringPiece(kCCS
, &their_common_set_hashes
);
1071 client_hello
.GetStringPiece(kCCRT
, &their_cached_cert_hashes
);
1073 const string compressed
= CertCompressor::CompressChain(
1074 *certs
, their_common_set_hashes
, their_cached_cert_hashes
,
1075 config
.common_cert_sets
);
1077 // kREJOverheadBytes is a very rough estimate of how much of a REJ
1078 // message is taken up by things other than the certificates.
1084 const size_t kREJOverheadBytes
= 166;
1085 // kMultiplier is the multiple of the CHLO message size that a REJ message
1086 // must stay under when the client doesn't present a valid source-address
1088 const size_t kMultiplier
= 2;
1089 // max_unverified_size is the number of bytes that the certificate chain
1090 // and signature can consume before we will demand a valid source-address
1092 const size_t max_unverified_size
=
1093 client_hello
.size() * kMultiplier
- kREJOverheadBytes
;
1094 COMPILE_ASSERT(kClientHelloMinimumSize
* kMultiplier
>= kREJOverheadBytes
,
1095 overhead_calculation_may_underflow
);
1096 if (info
.valid_source_address_token
||
1097 signature
.size() + compressed
.size() < max_unverified_size
) {
1098 out
->SetStringPiece(kCertificateTag
, compressed
);
1099 out
->SetStringPiece(kPROF
, signature
);
1103 scoped_refptr
<QuicCryptoServerConfig::Config
>
1104 QuicCryptoServerConfig::ParseConfigProtobuf(
1105 QuicServerConfigProtobuf
* protobuf
) {
1106 scoped_ptr
<CryptoHandshakeMessage
> msg(
1107 CryptoFramer::ParseMessage(protobuf
->config()));
1109 if (msg
->tag() != kSCFG
) {
1110 LOG(WARNING
) << "Server config message has tag " << msg
->tag()
1111 << " expected " << kSCFG
;
1115 scoped_refptr
<Config
> config(new Config
);
1116 config
->serialized
= protobuf
->config();
1118 if (!protobuf
->has_source_address_token_secret_override()) {
1119 // Use the default boxer.
1120 config
->source_address_token_boxer
= &default_source_address_token_boxer_
;
1122 // Create override boxer instance.
1123 CryptoSecretBoxer
* boxer
= new CryptoSecretBoxer
;
1124 boxer
->SetKey(DeriveSourceAddressTokenKey(
1125 protobuf
->source_address_token_secret_override()));
1126 config
->source_address_token_boxer_storage
.reset(boxer
);
1127 config
->source_address_token_boxer
= boxer
;
1130 if (protobuf
->has_primary_time()) {
1131 config
->primary_time
=
1132 QuicWallTime::FromUNIXSeconds(protobuf
->primary_time());
1135 config
->priority
= protobuf
->priority();
1138 if (!msg
->GetStringPiece(kSCID
, &scid
)) {
1139 LOG(WARNING
) << "Server config message is missing SCID";
1142 config
->id
= scid
.as_string();
1144 const QuicTag
* aead_tags
;
1146 if (msg
->GetTaglist(kAEAD
, &aead_tags
, &aead_len
) != QUIC_NO_ERROR
) {
1147 LOG(WARNING
) << "Server config message is missing AEAD";
1150 config
->aead
= vector
<QuicTag
>(aead_tags
, aead_tags
+ aead_len
);
1152 const QuicTag
* kexs_tags
;
1154 if (msg
->GetTaglist(kKEXS
, &kexs_tags
, &kexs_len
) != QUIC_NO_ERROR
) {
1155 LOG(WARNING
) << "Server config message is missing KEXS";
1160 if (!msg
->GetStringPiece(kORBT
, &orbit
)) {
1161 LOG(WARNING
) << "Server config message is missing ORBT";
1165 if (orbit
.size() != kOrbitSize
) {
1166 LOG(WARNING
) << "Orbit value in server config is the wrong length."
1167 " Got " << orbit
.size() << " want " << kOrbitSize
;
1170 COMPILE_ASSERT(sizeof(config
->orbit
) == kOrbitSize
, orbit_incorrect_size
);
1171 memcpy(config
->orbit
, orbit
.data(), sizeof(config
->orbit
));
1174 StrikeRegisterClient
* strike_register_client
;
1176 base::AutoLock
locked(strike_register_client_lock_
);
1177 strike_register_client
= strike_register_client_
.get();
1180 if (strike_register_client
!= NULL
&&
1181 !strike_register_client
->IsKnownOrbit(orbit
)) {
1183 << "Rejecting server config with orbit that the strike register "
1184 "client doesn't know about.";
1189 if (kexs_len
!= protobuf
->key_size()) {
1190 LOG(WARNING
) << "Server config has " << kexs_len
1191 << " key exchange methods configured, but "
1192 << protobuf
->key_size() << " private keys";
1196 const QuicTag
* proof_demand_tags
;
1197 size_t num_proof_demand_tags
;
1198 if (msg
->GetTaglist(kPDMD
, &proof_demand_tags
, &num_proof_demand_tags
) ==
1200 for (size_t i
= 0; i
< num_proof_demand_tags
; i
++) {
1201 if (proof_demand_tags
[i
] == kCHID
) {
1202 config
->channel_id_enabled
= true;
1208 for (size_t i
= 0; i
< kexs_len
; i
++) {
1209 const QuicTag tag
= kexs_tags
[i
];
1212 config
->kexs
.push_back(tag
);
1214 for (size_t j
= 0; j
< protobuf
->key_size(); j
++) {
1215 const QuicServerConfigProtobuf::PrivateKey
& key
= protobuf
->key(i
);
1216 if (key
.tag() == tag
) {
1217 private_key
= key
.private_key();
1222 if (private_key
.empty()) {
1223 LOG(WARNING
) << "Server config contains key exchange method without "
1224 "corresponding private key: " << tag
;
1228 scoped_ptr
<KeyExchange
> ka
;
1231 ka
.reset(Curve25519KeyExchange::New(private_key
));
1233 LOG(WARNING
) << "Server config contained an invalid curve25519"
1239 ka
.reset(P256KeyExchange::New(private_key
));
1241 LOG(WARNING
) << "Server config contained an invalid P-256"
1247 LOG(WARNING
) << "Server config message contains unknown key exchange "
1252 for (vector
<KeyExchange
*>::const_iterator i
= config
->key_exchanges
.begin();
1253 i
!= config
->key_exchanges
.end(); ++i
) {
1254 if ((*i
)->tag() == tag
) {
1255 LOG(WARNING
) << "Duplicate key exchange in config: " << tag
;
1260 config
->key_exchanges
.push_back(ka
.release());
1266 void QuicCryptoServerConfig::SetProofSource(ProofSource
* proof_source
) {
1267 proof_source_
.reset(proof_source
);
1270 void QuicCryptoServerConfig::SetEphemeralKeySource(
1271 EphemeralKeySource
* ephemeral_key_source
) {
1272 ephemeral_key_source_
.reset(ephemeral_key_source
);
1275 void QuicCryptoServerConfig::SetStrikeRegisterClient(
1276 StrikeRegisterClient
* strike_register_client
) {
1277 base::AutoLock
locker(strike_register_client_lock_
);
1278 DCHECK(!strike_register_client_
.get());
1279 strike_register_client_
.reset(strike_register_client
);
1282 void QuicCryptoServerConfig::set_replay_protection(bool on
) {
1283 replay_protection_
= on
;
1286 void QuicCryptoServerConfig::set_strike_register_no_startup_period() {
1287 base::AutoLock
locker(strike_register_client_lock_
);
1288 DCHECK(!strike_register_client_
.get());
1289 strike_register_no_startup_period_
= true;
1292 void QuicCryptoServerConfig::set_strike_register_max_entries(
1293 uint32 max_entries
) {
1294 base::AutoLock
locker(strike_register_client_lock_
);
1295 DCHECK(!strike_register_client_
.get());
1296 strike_register_max_entries_
= max_entries
;
1299 void QuicCryptoServerConfig::set_strike_register_window_secs(
1300 uint32 window_secs
) {
1301 base::AutoLock
locker(strike_register_client_lock_
);
1302 DCHECK(!strike_register_client_
.get());
1303 strike_register_window_secs_
= window_secs
;
1306 void QuicCryptoServerConfig::set_source_address_token_future_secs(
1307 uint32 future_secs
) {
1308 source_address_token_future_secs_
= future_secs
;
1311 void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
1312 uint32 lifetime_secs
) {
1313 source_address_token_lifetime_secs_
= lifetime_secs
;
1316 void QuicCryptoServerConfig::set_server_nonce_strike_register_max_entries(
1317 uint32 max_entries
) {
1318 DCHECK(!server_nonce_strike_register_
.get());
1319 server_nonce_strike_register_max_entries_
= max_entries
;
1322 void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs(
1323 uint32 window_secs
) {
1324 DCHECK(!server_nonce_strike_register_
.get());
1325 server_nonce_strike_register_window_secs_
= window_secs
;
1328 void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
1329 PrimaryConfigChangedCallback
* cb
) {
1330 base::AutoLock
locked(configs_lock_
);
1331 primary_config_changed_cb_
.reset(cb
);
1334 string
QuicCryptoServerConfig::NewSourceAddressToken(const Config
& config
,
1335 const IPEndPoint
& ip
,
1337 QuicWallTime now
) const {
1338 SourceAddressToken source_address_token
;
1339 IPAddressNumber ip_address
= ip
.address();
1340 if (ip
.GetSockAddrFamily() == AF_INET
) {
1341 ip_address
= ConvertIPv4NumberToIPv6Number(ip_address
);
1343 source_address_token
.set_ip(IPAddressToPackedString(ip_address
));
1344 source_address_token
.set_timestamp(now
.ToUNIXSeconds());
1346 return config
.source_address_token_boxer
->Box(
1347 rand
, source_address_token
.SerializeAsString());
1350 HandshakeFailureReason
QuicCryptoServerConfig::ValidateSourceAddressToken(
1351 const Config
& config
,
1353 const IPEndPoint
& ip
,
1354 QuicWallTime now
) const {
1356 StringPiece plaintext
;
1357 if (!config
.source_address_token_boxer
->Unbox(token
, &storage
, &plaintext
)) {
1358 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE
;
1361 SourceAddressToken source_address_token
;
1362 if (!source_address_token
.ParseFromArray(plaintext
.data(),
1363 plaintext
.size())) {
1364 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE
;
1367 IPAddressNumber ip_address
= ip
.address();
1368 if (ip
.GetSockAddrFamily() == AF_INET
) {
1369 ip_address
= ConvertIPv4NumberToIPv6Number(ip_address
);
1371 if (source_address_token
.ip() != IPAddressToPackedString(ip_address
)) {
1372 // It's for a different IP address.
1373 return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE
;
1376 const QuicWallTime
timestamp(
1377 QuicWallTime::FromUNIXSeconds(source_address_token
.timestamp()));
1378 const QuicTime::Delta
delta(now
.AbsoluteDifference(timestamp
));
1380 if (now
.IsBefore(timestamp
) &&
1381 delta
.ToSeconds() > source_address_token_future_secs_
) {
1382 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE
;
1385 if (now
.IsAfter(timestamp
) &&
1386 delta
.ToSeconds() > source_address_token_lifetime_secs_
) {
1387 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE
;
1390 return HANDSHAKE_OK
;
1393 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server
1395 static const size_t kServerNoncePlaintextSize
=
1396 4 /* timestamp */ + 20 /* random bytes */;
1398 string
QuicCryptoServerConfig::NewServerNonce(QuicRandom
* rand
,
1399 QuicWallTime now
) const {
1400 const uint32 timestamp
= static_cast<uint32
>(now
.ToUNIXSeconds());
1402 uint8 server_nonce
[kServerNoncePlaintextSize
];
1403 COMPILE_ASSERT(sizeof(server_nonce
) > sizeof(timestamp
), nonce_too_small
);
1404 server_nonce
[0] = static_cast<uint8
>(timestamp
>> 24);
1405 server_nonce
[1] = static_cast<uint8
>(timestamp
>> 16);
1406 server_nonce
[2] = static_cast<uint8
>(timestamp
>> 8);
1407 server_nonce
[3] = static_cast<uint8
>(timestamp
);
1408 rand
->RandBytes(&server_nonce
[sizeof(timestamp
)],
1409 sizeof(server_nonce
) - sizeof(timestamp
));
1411 return server_nonce_boxer_
.Box(
1413 StringPiece(reinterpret_cast<char*>(server_nonce
), sizeof(server_nonce
)));
1416 HandshakeFailureReason
QuicCryptoServerConfig::ValidateServerNonce(
1418 QuicWallTime now
) const {
1420 StringPiece plaintext
;
1421 if (!server_nonce_boxer_
.Unbox(token
, &storage
, &plaintext
)) {
1422 return SERVER_NONCE_DECRYPTION_FAILURE
;
1425 // plaintext contains:
1427 // uint8[20] random bytes
1429 if (plaintext
.size() != kServerNoncePlaintextSize
) {
1430 // This should never happen because the value decrypted correctly.
1431 LOG(DFATAL
) << "Seemingly valid server nonce had incorrect length.";
1432 return SERVER_NONCE_INVALID_FAILURE
;
1435 uint8 server_nonce
[32];
1436 memcpy(server_nonce
, plaintext
.data(), 4);
1437 memcpy(server_nonce
+ 4, server_nonce_orbit_
, sizeof(server_nonce_orbit_
));
1438 memcpy(server_nonce
+ 4 + sizeof(server_nonce_orbit_
), plaintext
.data() + 4,
1440 COMPILE_ASSERT(4 + sizeof(server_nonce_orbit_
) + 20 == sizeof(server_nonce
),
1441 bad_nonce_buffer_length
);
1445 base::AutoLock
auto_lock(server_nonce_strike_register_lock_
);
1446 if (server_nonce_strike_register_
.get() == NULL
) {
1447 server_nonce_strike_register_
.reset(new StrikeRegister(
1448 server_nonce_strike_register_max_entries_
,
1449 static_cast<uint32
>(now
.ToUNIXSeconds()),
1450 server_nonce_strike_register_window_secs_
, server_nonce_orbit_
,
1451 StrikeRegister::NO_STARTUP_PERIOD_NEEDED
));
1453 is_unique
= server_nonce_strike_register_
->Insert(
1454 server_nonce
, static_cast<uint32
>(now
.ToUNIXSeconds()));
1457 return is_unique
? HANDSHAKE_OK
: SERVER_NONCE_NOT_UNIQUE_FAILURE
;
1460 QuicCryptoServerConfig::Config::Config()
1461 : channel_id_enabled(false),
1463 primary_time(QuicWallTime::Zero()),
1465 source_address_token_boxer(NULL
) {}
1467 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges
); }