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 0 /* no subkey secret */);
59 return hkdf
.server_write_key().as_string();
64 // ClientHelloInfo contains information about a client hello message that is
65 // only kept for as long as it's being processed.
66 struct ClientHelloInfo
{
67 ClientHelloInfo(const IPEndPoint
& in_client_ip
, QuicWallTime in_now
)
68 : client_ip(in_client_ip
),
70 valid_source_address_token(false),
71 client_nonce_well_formed(false),
74 // Inputs to EvaluateClientHello.
75 const IPEndPoint client_ip
;
76 const QuicWallTime now
;
78 // Outputs from EvaluateClientHello.
79 bool valid_source_address_token
;
80 bool client_nonce_well_formed
;
83 StringPiece client_nonce
;
84 StringPiece server_nonce
;
85 StringPiece user_agent_id
;
87 // Errors from EvaluateClientHello.
88 vector
<uint32
> reject_reasons
;
89 COMPILE_ASSERT(sizeof(QuicTag
) == sizeof(uint32
), header_out_of_sync
);
92 struct ValidateClientHelloResultCallback::Result
{
93 Result(const CryptoHandshakeMessage
& in_client_hello
,
94 IPEndPoint in_client_ip
,
96 : client_hello(in_client_hello
),
97 info(in_client_ip
, in_now
),
98 error_code(QUIC_NO_ERROR
) {
101 CryptoHandshakeMessage client_hello
;
102 ClientHelloInfo info
;
103 QuicErrorCode error_code
;
104 string error_details
;
107 class ValidateClientHelloHelper
{
109 ValidateClientHelloHelper(ValidateClientHelloResultCallback::Result
* result
,
110 ValidateClientHelloResultCallback
* done_cb
)
111 : result_(result
), done_cb_(done_cb
) {
114 ~ValidateClientHelloHelper() {
115 LOG_IF(DFATAL
, done_cb_
!= NULL
)
116 << "Deleting ValidateClientHelloHelper with a pending callback.";
119 void ValidationComplete(QuicErrorCode error_code
, const char* error_details
) {
120 result_
->error_code
= error_code
;
121 result_
->error_details
= error_details
;
122 done_cb_
->Run(result_
);
126 void StartedAsyncCallback() {
131 void DetachCallback() {
132 LOG_IF(DFATAL
, done_cb_
== NULL
) << "Callback already detached.";
136 ValidateClientHelloResultCallback::Result
* result_
;
137 ValidateClientHelloResultCallback
* done_cb_
;
139 DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloHelper
);
142 class VerifyNonceIsValidAndUniqueCallback
143 : public StrikeRegisterClient::ResultCallback
{
145 VerifyNonceIsValidAndUniqueCallback(
146 ValidateClientHelloResultCallback::Result
* result
,
147 ValidateClientHelloResultCallback
* done_cb
)
148 : result_(result
), done_cb_(done_cb
) {
152 virtual void RunImpl(bool nonce_is_valid_and_unique
,
153 InsertStatus nonce_error
) OVERRIDE
{
154 DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique
155 << " nonce_error: " << nonce_error
;
156 result_
->info
.unique
= nonce_is_valid_and_unique
;
157 if (!nonce_is_valid_and_unique
) {
158 HandshakeFailureReason client_nonce_error
;
159 switch (nonce_error
) {
160 case NONCE_INVALID_FAILURE
:
161 client_nonce_error
= CLIENT_NONCE_INVALID_FAILURE
;
163 case NONCE_NOT_UNIQUE_FAILURE
:
164 client_nonce_error
= CLIENT_NONCE_NOT_UNIQUE_FAILURE
;
166 case NONCE_INVALID_ORBIT_FAILURE
:
167 client_nonce_error
= CLIENT_NONCE_INVALID_ORBIT_FAILURE
;
169 case NONCE_INVALID_TIME_FAILURE
:
170 client_nonce_error
= CLIENT_NONCE_INVALID_TIME_FAILURE
;
172 case STRIKE_REGISTER_TIMEOUT
:
173 client_nonce_error
= CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT
;
175 case STRIKE_REGISTER_FAILURE
:
176 client_nonce_error
= CLIENT_NONCE_STRIKE_REGISTER_FAILURE
;
178 case NONCE_UNKNOWN_FAILURE
:
179 client_nonce_error
= CLIENT_NONCE_UNKNOWN_FAILURE
;
183 LOG(DFATAL
) << "Unexpected client nonce error: " << nonce_error
;
184 client_nonce_error
= CLIENT_NONCE_UNKNOWN_FAILURE
;
187 result_
->info
.reject_reasons
.push_back(client_nonce_error
);
189 done_cb_
->Run(result_
);
193 ValidateClientHelloResultCallback::Result
* result_
;
194 ValidateClientHelloResultCallback
* done_cb_
;
196 DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback
);
200 const char QuicCryptoServerConfig::TESTING
[] = "secret string for testing";
202 PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {
205 PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {
208 ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {
211 ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {
214 void ValidateClientHelloResultCallback::Run(const Result
* result
) {
215 RunImpl(result
->client_hello
, *result
);
220 QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
221 : expiry_time(QuicWallTime::Zero()),
222 channel_id_enabled(false),
225 QuicCryptoServerConfig::QuicCryptoServerConfig(
226 StringPiece source_address_token_secret
,
228 : replay_protection_(true),
230 primary_config_(NULL
),
231 next_config_promotion_time_(QuicWallTime::Zero()),
232 server_nonce_strike_register_lock_(),
233 strike_register_no_startup_period_(false),
234 strike_register_max_entries_(1 << 10),
235 strike_register_window_secs_(600),
236 source_address_token_future_secs_(3600),
237 source_address_token_lifetime_secs_(86400),
238 server_nonce_strike_register_max_entries_(1 << 10),
239 server_nonce_strike_register_window_secs_(120) {
240 default_source_address_token_boxer_
.SetKey(
241 DeriveSourceAddressTokenKey(source_address_token_secret
));
243 // Generate a random key and orbit for server nonces.
244 rand
->RandBytes(server_nonce_orbit_
, sizeof(server_nonce_orbit_
));
245 const size_t key_size
= server_nonce_boxer_
.GetKeySize();
246 scoped_ptr
<uint8
[]> key_bytes(new uint8
[key_size
]);
247 rand
->RandBytes(key_bytes
.get(), key_size
);
249 server_nonce_boxer_
.SetKey(
250 StringPiece(reinterpret_cast<char*>(key_bytes
.get()), key_size
));
253 QuicCryptoServerConfig::~QuicCryptoServerConfig() {
254 primary_config_
= NULL
;
258 QuicServerConfigProtobuf
* QuicCryptoServerConfig::GenerateConfig(
260 const QuicClock
* clock
,
261 const ConfigOptions
& options
) {
262 CryptoHandshakeMessage msg
;
264 const string curve25519_private_key
=
265 Curve25519KeyExchange::NewPrivateKey(rand
);
266 scoped_ptr
<Curve25519KeyExchange
> curve25519(
267 Curve25519KeyExchange::New(curve25519_private_key
));
268 StringPiece curve25519_public_value
= curve25519
->public_value();
270 string encoded_public_values
;
271 // First three bytes encode the length of the public value.
272 encoded_public_values
.push_back(curve25519_public_value
.size());
273 encoded_public_values
.push_back(curve25519_public_value
.size() >> 8);
274 encoded_public_values
.push_back(curve25519_public_value
.size() >> 16);
275 encoded_public_values
.append(curve25519_public_value
.data(),
276 curve25519_public_value
.size());
278 string p256_private_key
;
280 p256_private_key
= P256KeyExchange::NewPrivateKey();
281 scoped_ptr
<P256KeyExchange
> p256(P256KeyExchange::New(p256_private_key
));
282 StringPiece p256_public_value
= p256
->public_value();
284 encoded_public_values
.push_back(p256_public_value
.size());
285 encoded_public_values
.push_back(p256_public_value
.size() >> 8);
286 encoded_public_values
.push_back(p256_public_value
.size() >> 16);
287 encoded_public_values
.append(p256_public_value
.data(),
288 p256_public_value
.size());
293 msg
.SetTaglist(kKEXS
, kC255
, kP256
, 0);
295 msg
.SetTaglist(kKEXS
, kC255
, 0);
297 if (ChaCha20Poly1305Encrypter::IsSupported()) {
298 msg
.SetTaglist(kAEAD
, kAESG
, kCC12
, 0);
300 msg
.SetTaglist(kAEAD
, kAESG
, 0);
302 msg
.SetStringPiece(kPUBS
, encoded_public_values
);
304 if (options
.expiry_time
.IsZero()) {
305 const QuicWallTime now
= clock
->WallNow();
306 const QuicWallTime expiry
= now
.Add(QuicTime::Delta::FromSeconds(
307 60 * 60 * 24 * 180 /* 180 days, ~six months */));
308 const uint64 expiry_seconds
= expiry
.ToUNIXSeconds();
309 msg
.SetValue(kEXPY
, expiry_seconds
);
311 msg
.SetValue(kEXPY
, options
.expiry_time
.ToUNIXSeconds());
314 char orbit_bytes
[kOrbitSize
];
315 if (options
.orbit
.size() == sizeof(orbit_bytes
)) {
316 memcpy(orbit_bytes
, options
.orbit
.data(), sizeof(orbit_bytes
));
318 DCHECK(options
.orbit
.empty());
319 rand
->RandBytes(orbit_bytes
, sizeof(orbit_bytes
));
321 msg
.SetStringPiece(kORBT
, StringPiece(orbit_bytes
, sizeof(orbit_bytes
)));
323 if (options
.channel_id_enabled
) {
324 msg
.SetTaglist(kPDMD
, kCHID
, 0);
327 if (options
.id
.empty()) {
328 // We need to ensure that the SCID changes whenever the server config does
329 // thus we make it a hash of the rest of the server config.
330 scoped_ptr
<QuicData
> serialized(
331 CryptoFramer::ConstructHandshakeMessage(msg
));
332 scoped_ptr
<SecureHash
> hash(SecureHash::Create(SecureHash::SHA256
));
333 hash
->Update(serialized
->data(), serialized
->length());
336 hash
->Finish(scid_bytes
, sizeof(scid_bytes
));
337 msg
.SetStringPiece(kSCID
, StringPiece(scid_bytes
, sizeof(scid_bytes
)));
339 msg
.SetStringPiece(kSCID
, options
.id
);
341 // Don't put new tags below this point. The SCID generation should hash over
342 // everything but itself and so extra tags should be added prior to the
343 // preceeding if block.
345 scoped_ptr
<QuicData
> serialized(CryptoFramer::ConstructHandshakeMessage(msg
));
347 scoped_ptr
<QuicServerConfigProtobuf
> config(new QuicServerConfigProtobuf
);
348 config
->set_config(serialized
->AsStringPiece());
349 QuicServerConfigProtobuf::PrivateKey
* curve25519_key
= config
->add_key();
350 curve25519_key
->set_tag(kC255
);
351 curve25519_key
->set_private_key(curve25519_private_key
);
354 QuicServerConfigProtobuf::PrivateKey
* p256_key
= config
->add_key();
355 p256_key
->set_tag(kP256
);
356 p256_key
->set_private_key(p256_private_key
);
359 return config
.release();
362 CryptoHandshakeMessage
* QuicCryptoServerConfig::AddConfig(
363 QuicServerConfigProtobuf
* protobuf
,
364 const QuicWallTime now
) {
365 scoped_ptr
<CryptoHandshakeMessage
> msg(
366 CryptoFramer::ParseMessage(protobuf
->config()));
369 LOG(WARNING
) << "Failed to parse server config message";
373 scoped_refptr
<Config
> config(ParseConfigProtobuf(protobuf
));
375 LOG(WARNING
) << "Failed to parse server config message";
380 base::AutoLock
locked(configs_lock_
);
381 if (configs_
.find(config
->id
) != configs_
.end()) {
382 LOG(WARNING
) << "Failed to add config because another with the same "
383 "server config id already exists: "
384 << base::HexEncode(config
->id
.data(), config
->id
.size());
388 configs_
[config
->id
] = config
;
389 SelectNewPrimaryConfig(now
);
390 DCHECK(primary_config_
.get());
391 DCHECK_EQ(configs_
.find(primary_config_
->id
)->second
, primary_config_
);
394 return msg
.release();
397 CryptoHandshakeMessage
* QuicCryptoServerConfig::AddDefaultConfig(
399 const QuicClock
* clock
,
400 const ConfigOptions
& options
) {
401 scoped_ptr
<QuicServerConfigProtobuf
> config(
402 GenerateConfig(rand
, clock
, options
));
403 return AddConfig(config
.get(), clock
->WallNow());
406 bool QuicCryptoServerConfig::SetConfigs(
407 const vector
<QuicServerConfigProtobuf
*>& protobufs
,
408 const QuicWallTime now
) {
409 vector
<scoped_refptr
<Config
> > parsed_configs
;
412 for (vector
<QuicServerConfigProtobuf
*>::const_iterator i
= protobufs
.begin();
413 i
!= protobufs
.end(); ++i
) {
414 scoped_refptr
<Config
> config(ParseConfigProtobuf(*i
));
420 parsed_configs
.push_back(config
);
423 if (parsed_configs
.empty()) {
424 LOG(WARNING
) << "New config list is empty.";
429 LOG(WARNING
) << "Rejecting QUIC configs because of above errors";
431 VLOG(1) << "Updating configs:";
433 base::AutoLock
locked(configs_lock_
);
434 ConfigMap new_configs
;
436 for (vector
<scoped_refptr
<Config
> >::const_iterator i
=
437 parsed_configs
.begin();
438 i
!= parsed_configs
.end(); ++i
) {
439 scoped_refptr
<Config
> config
= *i
;
441 ConfigMap::iterator it
= configs_
.find(config
->id
);
442 if (it
!= configs_
.end()) {
444 << "Keeping scid: " << base::HexEncode(
445 config
->id
.data(), config
->id
.size())
446 << " orbit: " << base::HexEncode(
447 reinterpret_cast<const char *>(config
->orbit
), kOrbitSize
)
448 << " new primary_time " << config
->primary_time
.ToUNIXSeconds()
449 << " old primary_time " << it
->second
->primary_time
.ToUNIXSeconds()
450 << " new priority " << config
->priority
451 << " old priority " << it
->second
->priority
;
452 // Update primary_time and priority.
453 it
->second
->primary_time
= config
->primary_time
;
454 it
->second
->priority
= config
->priority
;
455 new_configs
.insert(*it
);
457 VLOG(1) << "Adding scid: " << base::HexEncode(
458 config
->id
.data(), config
->id
.size())
459 << " orbit: " << base::HexEncode(
460 reinterpret_cast<const char *>(config
->orbit
), kOrbitSize
)
461 << " primary_time " << config
->primary_time
.ToUNIXSeconds()
462 << " priority " << config
->priority
;
463 new_configs
.insert(make_pair(config
->id
, config
));
467 configs_
.swap(new_configs
);
468 SelectNewPrimaryConfig(now
);
469 DCHECK(primary_config_
.get());
470 DCHECK_EQ(configs_
.find(primary_config_
->id
)->second
, primary_config_
);
476 void QuicCryptoServerConfig::GetConfigIds(vector
<string
>* scids
) const {
477 base::AutoLock
locked(configs_lock_
);
478 for (ConfigMap::const_iterator it
= configs_
.begin();
479 it
!= configs_
.end(); ++it
) {
480 scids
->push_back(it
->first
);
484 void QuicCryptoServerConfig::ValidateClientHello(
485 const CryptoHandshakeMessage
& client_hello
,
486 IPEndPoint client_ip
,
487 const QuicClock
* clock
,
488 ValidateClientHelloResultCallback
* done_cb
) const {
489 const QuicWallTime
now(clock
->WallNow());
491 ValidateClientHelloResultCallback::Result
* result
=
492 new ValidateClientHelloResultCallback::Result(
493 client_hello
, client_ip
, now
);
495 StringPiece requested_scid
;
496 client_hello
.GetStringPiece(kSCID
, &requested_scid
);
498 uint8 primary_orbit
[kOrbitSize
];
499 scoped_refptr
<Config
> requested_config
;
501 base::AutoLock
locked(configs_lock_
);
503 if (!primary_config_
.get()) {
504 result
->error_code
= QUIC_CRYPTO_INTERNAL_ERROR
;
505 result
->error_details
= "No configurations loaded";
507 if (!next_config_promotion_time_
.IsZero() &&
508 next_config_promotion_time_
.IsAfter(now
)) {
509 SelectNewPrimaryConfig(now
);
510 DCHECK(primary_config_
.get());
511 DCHECK_EQ(configs_
.find(primary_config_
->id
)->second
, primary_config_
);
514 memcpy(primary_orbit
, primary_config_
->orbit
, sizeof(primary_orbit
));
517 requested_config
= GetConfigWithScid(requested_scid
);
520 if (result
->error_code
== QUIC_NO_ERROR
) {
521 EvaluateClientHello(primary_orbit
, requested_config
, result
, done_cb
);
523 done_cb
->Run(result
);
527 QuicErrorCode
QuicCryptoServerConfig::ProcessClientHello(
528 const ValidateClientHelloResultCallback::Result
& validate_chlo_result
,
529 QuicConnectionId connection_id
,
530 IPEndPoint client_address
,
532 const QuicVersionVector
& supported_versions
,
533 const QuicClock
* clock
,
535 QuicCryptoNegotiatedParameters
*params
,
536 CryptoHandshakeMessage
* out
,
537 string
* error_details
) const {
538 DCHECK(error_details
);
540 const CryptoHandshakeMessage
& client_hello
=
541 validate_chlo_result
.client_hello
;
542 const ClientHelloInfo
& info
= validate_chlo_result
.info
;
544 // If the client's preferred version is not the version we are currently
545 // speaking, then the client went through a version negotiation. In this
546 // case, we need to make sure that we actually do not support this version
547 // and that it wasn't a downgrade attack.
548 QuicTag client_version_tag
;
549 if (client_hello
.GetUint32(kVER
, &client_version_tag
) != QUIC_NO_ERROR
) {
550 *error_details
= "client hello missing version list";
551 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
553 QuicVersion client_version
= QuicTagToQuicVersion(client_version_tag
);
554 if (client_version
!= version
) {
555 // Just because client_version is a valid version enum doesn't mean that
556 // this server actually supports that version, so we check to see if
557 // it's actually in the supported versions list.
558 for (size_t i
= 0; i
< supported_versions
.size(); ++i
) {
559 if (client_version
== supported_versions
[i
]) {
560 *error_details
= "Downgrade attack detected";
561 return QUIC_VERSION_NEGOTIATION_MISMATCH
;
566 StringPiece requested_scid
;
567 client_hello
.GetStringPiece(kSCID
, &requested_scid
);
568 const QuicWallTime
now(clock
->WallNow());
570 scoped_refptr
<Config
> requested_config
;
571 scoped_refptr
<Config
> primary_config
;
573 base::AutoLock
locked(configs_lock_
);
575 if (!primary_config_
.get()) {
576 *error_details
= "No configurations loaded";
577 return QUIC_CRYPTO_INTERNAL_ERROR
;
580 if (!next_config_promotion_time_
.IsZero() &&
581 next_config_promotion_time_
.IsAfter(now
)) {
582 SelectNewPrimaryConfig(now
);
583 DCHECK(primary_config_
.get());
584 DCHECK_EQ(configs_
.find(primary_config_
->id
)->second
, primary_config_
);
587 // We'll use the config that the client requested in order to do
588 // key-agreement. Otherwise we'll give it a copy of |primary_config_|
590 primary_config
= primary_config_
;
592 requested_config
= GetConfigWithScid(requested_scid
);
595 if (validate_chlo_result
.error_code
!= QUIC_NO_ERROR
) {
596 *error_details
= validate_chlo_result
.error_details
;
597 return validate_chlo_result
.error_code
;
602 if (!info
.valid_source_address_token
||
603 !info
.client_nonce_well_formed
||
605 !requested_config
.get()) {
607 *primary_config
.get(), client_hello
, info
, rand
, params
, out
);
608 return QUIC_NO_ERROR
;
611 const QuicTag
* their_aeads
;
612 const QuicTag
* their_key_exchanges
;
613 size_t num_their_aeads
, num_their_key_exchanges
;
614 if (client_hello
.GetTaglist(kAEAD
, &their_aeads
,
615 &num_their_aeads
) != QUIC_NO_ERROR
||
616 client_hello
.GetTaglist(kKEXS
, &their_key_exchanges
,
617 &num_their_key_exchanges
) != QUIC_NO_ERROR
||
618 num_their_aeads
!= 1 ||
619 num_their_key_exchanges
!= 1) {
620 *error_details
= "Missing or invalid AEAD or KEXS";
621 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
624 size_t key_exchange_index
;
625 if (!QuicUtils::FindMutualTag(requested_config
->aead
, their_aeads
,
626 num_their_aeads
, QuicUtils::LOCAL_PRIORITY
,
627 ¶ms
->aead
, NULL
) ||
628 !QuicUtils::FindMutualTag(
629 requested_config
->kexs
, their_key_exchanges
, num_their_key_exchanges
,
630 QuicUtils::LOCAL_PRIORITY
, ¶ms
->key_exchange
,
631 &key_exchange_index
)) {
632 *error_details
= "Unsupported AEAD or KEXS";
633 return QUIC_CRYPTO_NO_SUPPORT
;
636 StringPiece public_value
;
637 if (!client_hello
.GetStringPiece(kPUBS
, &public_value
)) {
638 *error_details
= "Missing public value";
639 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
642 const KeyExchange
* key_exchange
=
643 requested_config
->key_exchanges
[key_exchange_index
];
644 if (!key_exchange
->CalculateSharedKey(public_value
,
645 ¶ms
->initial_premaster_secret
)) {
646 *error_details
= "Invalid public value";
647 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
650 if (!info
.sni
.empty()) {
651 scoped_ptr
<char[]> sni_tmp(new char[info
.sni
.length() + 1]);
652 memcpy(sni_tmp
.get(), info
.sni
.data(), info
.sni
.length());
653 sni_tmp
[info
.sni
.length()] = 0;
654 params
->sni
= CryptoUtils::NormalizeHostname(sni_tmp
.get());
658 const QuicData
& client_hello_serialized
= client_hello
.GetSerialized();
659 hkdf_suffix
.reserve(sizeof(connection_id
) + client_hello_serialized
.length() +
660 requested_config
->serialized
.size());
661 hkdf_suffix
.append(reinterpret_cast<char*>(&connection_id
),
662 sizeof(connection_id
));
663 hkdf_suffix
.append(client_hello_serialized
.data(),
664 client_hello_serialized
.length());
665 hkdf_suffix
.append(requested_config
->serialized
);
667 StringPiece cetv_ciphertext
;
668 if (requested_config
->channel_id_enabled
&&
669 client_hello
.GetStringPiece(kCETV
, &cetv_ciphertext
)) {
670 CryptoHandshakeMessage
client_hello_copy(client_hello
);
671 client_hello_copy
.Erase(kCETV
);
672 client_hello_copy
.Erase(kPAD
);
674 const QuicData
& client_hello_serialized
= client_hello_copy
.GetSerialized();
676 hkdf_input
.append(QuicCryptoConfig::kCETVLabel
,
677 strlen(QuicCryptoConfig::kCETVLabel
) + 1);
678 hkdf_input
.append(reinterpret_cast<char*>(&connection_id
),
679 sizeof(connection_id
));
680 hkdf_input
.append(client_hello_serialized
.data(),
681 client_hello_serialized
.length());
682 hkdf_input
.append(requested_config
->serialized
);
684 CrypterPair crypters
;
685 if (!CryptoUtils::DeriveKeys(params
->initial_premaster_secret
, params
->aead
,
686 info
.client_nonce
, info
.server_nonce
,
687 hkdf_input
, CryptoUtils::SERVER
, &crypters
,
688 NULL
/* subkey secret */)) {
689 *error_details
= "Symmetric key setup failed";
690 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
693 scoped_ptr
<QuicData
> cetv_plaintext(crypters
.decrypter
->DecryptPacket(
694 0 /* sequence number */, StringPiece() /* associated data */,
696 if (!cetv_plaintext
.get()) {
697 *error_details
= "CETV decryption failure";
698 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
701 scoped_ptr
<CryptoHandshakeMessage
> cetv(CryptoFramer::ParseMessage(
702 cetv_plaintext
->AsStringPiece()));
704 *error_details
= "CETV parse error";
705 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
708 StringPiece key
, signature
;
709 if (cetv
->GetStringPiece(kCIDK
, &key
) &&
710 cetv
->GetStringPiece(kCIDS
, &signature
)) {
711 if (!ChannelIDVerifier::Verify(key
, hkdf_input
, signature
)) {
712 *error_details
= "ChannelID signature failure";
713 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
716 params
->channel_id
= key
.as_string();
721 size_t label_len
= strlen(QuicCryptoConfig::kInitialLabel
) + 1;
722 hkdf_input
.reserve(label_len
+ hkdf_suffix
.size());
723 hkdf_input
.append(QuicCryptoConfig::kInitialLabel
, label_len
);
724 hkdf_input
.append(hkdf_suffix
);
726 if (!CryptoUtils::DeriveKeys(params
->initial_premaster_secret
, params
->aead
,
727 info
.client_nonce
, info
.server_nonce
, hkdf_input
,
729 ¶ms
->initial_crypters
,
730 NULL
/* subkey secret */)) {
731 *error_details
= "Symmetric key setup failed";
732 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
735 string forward_secure_public_value
;
736 if (ephemeral_key_source_
.get()) {
737 params
->forward_secure_premaster_secret
=
738 ephemeral_key_source_
->CalculateForwardSecureKey(
739 key_exchange
, rand
, clock
->ApproximateNow(), public_value
,
740 &forward_secure_public_value
);
742 scoped_ptr
<KeyExchange
> forward_secure_key_exchange(
743 key_exchange
->NewKeyPair(rand
));
744 forward_secure_public_value
=
745 forward_secure_key_exchange
->public_value().as_string();
746 if (!forward_secure_key_exchange
->CalculateSharedKey(
747 public_value
, ¶ms
->forward_secure_premaster_secret
)) {
748 *error_details
= "Invalid public value";
749 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
;
753 string forward_secure_hkdf_input
;
754 label_len
= strlen(QuicCryptoConfig::kForwardSecureLabel
) + 1;
755 forward_secure_hkdf_input
.reserve(label_len
+ hkdf_suffix
.size());
756 forward_secure_hkdf_input
.append(QuicCryptoConfig::kForwardSecureLabel
,
758 forward_secure_hkdf_input
.append(hkdf_suffix
);
760 if (!CryptoUtils::DeriveKeys(
761 params
->forward_secure_premaster_secret
, params
->aead
,
762 info
.client_nonce
, info
.server_nonce
, forward_secure_hkdf_input
,
763 CryptoUtils::SERVER
, ¶ms
->forward_secure_crypters
,
764 ¶ms
->subkey_secret
)) {
765 *error_details
= "Symmetric key setup failed";
766 return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED
;
770 QuicTagVector supported_version_tags
;
771 for (size_t i
= 0; i
< supported_versions
.size(); ++i
) {
772 supported_version_tags
.push_back
773 (QuicVersionToQuicTag(supported_versions
[i
]));
775 out
->SetVector(kVER
, supported_version_tags
);
777 kSourceAddressTokenTag
,
778 NewSourceAddressToken(
779 *requested_config
.get(), client_address
, rand
, info
.now
, NULL
));
780 QuicSocketAddressCoder
address_coder(client_address
);
781 out
->SetStringPiece(kCADR
, address_coder
.Encode());
782 out
->SetStringPiece(kPUBS
, forward_secure_public_value
);
784 return QUIC_NO_ERROR
;
787 scoped_refptr
<QuicCryptoServerConfig::Config
>
788 QuicCryptoServerConfig::GetConfigWithScid(StringPiece requested_scid
) const {
789 // In Chromium, we will dead lock if the lock is held by the current thread.
790 // Chromium doesn't have AssertReaderHeld API call.
791 // configs_lock_.AssertReaderHeld();
793 if (!requested_scid
.empty()) {
794 ConfigMap::const_iterator it
= configs_
.find(requested_scid
.as_string());
795 if (it
!= configs_
.end()) {
796 // We'll use the config that the client requested in order to do
798 return scoped_refptr
<Config
>(it
->second
);
802 return scoped_refptr
<Config
>();
805 // ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
806 // Config's based on their primary_time.
808 bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
809 const scoped_refptr
<Config
>& a
,
810 const scoped_refptr
<Config
>& b
) {
811 if (a
->primary_time
.IsBefore(b
->primary_time
) ||
812 b
->primary_time
.IsBefore(a
->primary_time
)) {
813 // Primary times differ.
814 return a
->primary_time
.IsBefore(b
->primary_time
);
815 } else if (a
->priority
!= b
->priority
) {
816 // Primary times are equal, sort backwards by priority.
817 return a
->priority
< b
->priority
;
819 // Primary times and priorities are equal, sort by config id.
820 return a
->id
< b
->id
;
824 void QuicCryptoServerConfig::SelectNewPrimaryConfig(
825 const QuicWallTime now
) const {
826 vector
<scoped_refptr
<Config
> > configs
;
827 configs
.reserve(configs_
.size());
829 for (ConfigMap::const_iterator it
= configs_
.begin();
830 it
!= configs_
.end(); ++it
) {
831 // TODO(avd) Exclude expired configs?
832 configs
.push_back(it
->second
);
835 if (configs
.empty()) {
836 if (primary_config_
.get()) {
837 LOG(DFATAL
) << "No valid QUIC server config. Keeping the current config.";
839 LOG(DFATAL
) << "No valid QUIC server config.";
844 sort(configs
.begin(), configs
.end(), ConfigPrimaryTimeLessThan
);
846 Config
* best_candidate
= configs
[0].get();
848 for (size_t i
= 0; i
< configs
.size(); ++i
) {
849 const scoped_refptr
<Config
> config(configs
[i
]);
850 if (!config
->primary_time
.IsAfter(now
)) {
851 if (config
->primary_time
.IsAfter(best_candidate
->primary_time
)) {
852 best_candidate
= config
.get();
857 // This is the first config with a primary_time in the future. Thus the
858 // previous Config should be the primary and this one should determine the
859 // next_config_promotion_time_.
860 scoped_refptr
<Config
> new_primary(best_candidate
);
862 // We need the primary_time of the next config.
863 if (configs
.size() > 1) {
864 next_config_promotion_time_
= configs
[1]->primary_time
;
866 next_config_promotion_time_
= QuicWallTime::Zero();
869 next_config_promotion_time_
= config
->primary_time
;
872 if (primary_config_
.get()) {
873 primary_config_
->is_primary
= false;
875 primary_config_
= new_primary
;
876 new_primary
->is_primary
= true;
877 DVLOG(1) << "New primary config. orbit: "
879 reinterpret_cast<const char*>(primary_config_
->orbit
),
881 if (primary_config_changed_cb_
.get() != NULL
) {
882 primary_config_changed_cb_
->Run(primary_config_
->id
);
888 // All config's primary times are in the past. We should make the most recent
889 // and highest priority candidate primary.
890 scoped_refptr
<Config
> new_primary(best_candidate
);
891 if (primary_config_
.get()) {
892 primary_config_
->is_primary
= false;
894 primary_config_
= new_primary
;
895 new_primary
->is_primary
= true;
896 DVLOG(1) << "New primary config. orbit: "
898 reinterpret_cast<const char*>(primary_config_
->orbit
),
900 << " scid: " << base::HexEncode(primary_config_
->id
.data(),
901 primary_config_
->id
.size());
902 next_config_promotion_time_
= QuicWallTime::Zero();
903 if (primary_config_changed_cb_
.get() != NULL
) {
904 primary_config_changed_cb_
->Run(primary_config_
->id
);
908 void QuicCryptoServerConfig::EvaluateClientHello(
909 const uint8
* primary_orbit
,
910 scoped_refptr
<Config
> requested_config
,
911 ValidateClientHelloResultCallback::Result
* client_hello_state
,
912 ValidateClientHelloResultCallback
* done_cb
) const {
913 ValidateClientHelloHelper
helper(client_hello_state
, done_cb
);
915 const CryptoHandshakeMessage
& client_hello
=
916 client_hello_state
->client_hello
;
917 ClientHelloInfo
* info
= &(client_hello_state
->info
);
919 if (client_hello
.size() < kClientHelloMinimumSize
) {
920 helper
.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH
,
921 "Client hello too small");
925 if (client_hello
.GetStringPiece(kSNI
, &info
->sni
) &&
926 !CryptoUtils::IsValidSNI(info
->sni
)) {
927 helper
.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER
,
932 client_hello
.GetStringPiece(kUAID
, &info
->user_agent_id
);
934 if (!requested_config
.get()) {
935 StringPiece requested_scid
;
936 if (client_hello
.GetStringPiece(kSCID
, &requested_scid
)) {
937 info
->reject_reasons
.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE
);
939 info
->reject_reasons
.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE
);
941 // No server config with the requested ID.
942 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
946 HandshakeFailureReason source_address_token_error
;
948 if (client_hello
.GetStringPiece(kSourceAddressTokenTag
, &srct
)) {
949 source_address_token_error
= ValidateSourceAddressToken(
950 *requested_config
.get(), srct
, info
->client_ip
, info
->now
);
951 info
->valid_source_address_token
=
952 (source_address_token_error
== HANDSHAKE_OK
);
954 source_address_token_error
= SOURCE_ADDRESS_TOKEN_INVALID_FAILURE
;
957 bool found_error
= false;
958 if (source_address_token_error
!= HANDSHAKE_OK
) {
959 info
->reject_reasons
.push_back(source_address_token_error
);
960 // No valid source address token.
961 if (FLAGS_use_early_return_when_verifying_chlo
) {
962 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
968 if (client_hello
.GetStringPiece(kNONC
, &info
->client_nonce
) &&
969 info
->client_nonce
.size() == kNonceSize
) {
970 info
->client_nonce_well_formed
= true;
972 info
->reject_reasons
.push_back(CLIENT_NONCE_INVALID_FAILURE
);
973 // Invalid client nonce.
974 DVLOG(1) << "Invalid client nonce.";
975 if (FLAGS_use_early_return_when_verifying_chlo
) {
976 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
982 if (!replay_protection_
) {
986 DVLOG(1) << "No replay protection.";
987 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
991 client_hello
.GetStringPiece(kServerNonceTag
, &info
->server_nonce
);
992 if (!info
->server_nonce
.empty()) {
993 // If the server nonce is present, use it to establish uniqueness.
994 HandshakeFailureReason server_nonce_error
=
995 ValidateServerNonce(info
->server_nonce
, info
->now
);
996 if (server_nonce_error
== HANDSHAKE_OK
) {
999 info
->reject_reasons
.push_back(server_nonce_error
);
1000 info
->unique
= false;
1002 DVLOG(1) << "Using server nonce, unique: " << info
->unique
;
1003 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
1007 // We want to contact strike register only if there are no errors because it
1008 // is a RPC call and is expensive.
1010 helper
.ValidationComplete(QUIC_NO_ERROR
, "");
1014 // Use the client nonce to establish uniqueness.
1015 StrikeRegisterClient
* strike_register_client
;
1017 base::AutoLock
locked(strike_register_client_lock_
);
1019 if (strike_register_client_
.get() == NULL
) {
1020 strike_register_client_
.reset(new LocalStrikeRegisterClient(
1021 strike_register_max_entries_
,
1022 static_cast<uint32
>(info
->now
.ToUNIXSeconds()),
1023 strike_register_window_secs_
,
1025 strike_register_no_startup_period_
?
1026 StrikeRegister::NO_STARTUP_PERIOD_NEEDED
:
1027 StrikeRegister::DENY_REQUESTS_AT_STARTUP
));
1029 strike_register_client
= strike_register_client_
.get();
1032 strike_register_client
->VerifyNonceIsValidAndUnique(
1035 new VerifyNonceIsValidAndUniqueCallback(client_hello_state
, done_cb
));
1036 helper
.StartedAsyncCallback();
1039 bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
1040 const IPEndPoint
& client_ip
,
1041 const QuicClock
* clock
,
1043 const QuicCryptoNegotiatedParameters
& params
,
1044 const CachedNetworkParameters
* cached_network_params
,
1045 CryptoHandshakeMessage
* out
) const {
1046 base::AutoLock
locked(configs_lock_
);
1047 out
->set_tag(kSCUP
);
1048 out
->SetStringPiece(kSCFG
, primary_config_
->serialized
);
1049 out
->SetStringPiece(kSourceAddressTokenTag
,
1050 NewSourceAddressToken(*primary_config_
.get(),
1054 cached_network_params
));
1056 if (proof_source_
== NULL
) {
1057 // Insecure QUIC, can send SCFG without proof.
1061 const vector
<string
>* certs
;
1063 if (!proof_source_
->GetProof(params
.sni
, primary_config_
->serialized
,
1064 params
.x509_ecdsa_supported
, &certs
,
1066 DVLOG(1) << "Server: failed to get proof.";
1070 const string compressed
= CertCompressor::CompressChain(
1071 *certs
, params
.client_common_set_hashes
, params
.client_cached_cert_hashes
,
1072 primary_config_
->common_cert_sets
);
1074 out
->SetStringPiece(kCertificateTag
, compressed
);
1075 out
->SetStringPiece(kPROF
, signature
);
1079 void QuicCryptoServerConfig::BuildRejection(
1080 const Config
& config
,
1081 const CryptoHandshakeMessage
& client_hello
,
1082 const ClientHelloInfo
& info
,
1084 QuicCryptoNegotiatedParameters
*params
,
1085 CryptoHandshakeMessage
* out
) const {
1087 out
->SetStringPiece(kSCFG
, config
.serialized
);
1088 out
->SetStringPiece(kSourceAddressTokenTag
,
1089 NewSourceAddressToken(
1095 if (replay_protection_
) {
1096 out
->SetStringPiece(kServerNonceTag
, NewServerNonce(rand
, info
.now
));
1099 if (FLAGS_send_quic_crypto_reject_reason
) {
1100 // Send client the reject reason for debugging purposes.
1101 DCHECK_LT(0u, info
.reject_reasons
.size());
1102 out
->SetVector(kRREJ
, info
.reject_reasons
);
1105 // The client may have requested a certificate chain.
1106 const QuicTag
* their_proof_demands
;
1107 size_t num_their_proof_demands
;
1109 if (proof_source_
.get() == NULL
||
1110 client_hello
.GetTaglist(kPDMD
, &their_proof_demands
,
1111 &num_their_proof_demands
) !=
1116 bool x509_supported
= false;
1117 for (size_t i
= 0; i
< num_their_proof_demands
; i
++) {
1118 switch (their_proof_demands
[i
]) {
1120 x509_supported
= true;
1121 params
->x509_ecdsa_supported
= true;
1124 x509_supported
= true;
1129 if (!x509_supported
) {
1133 const vector
<string
>* certs
;
1135 if (!proof_source_
->GetProof(info
.sni
.as_string(), config
.serialized
,
1136 params
->x509_ecdsa_supported
, &certs
,
1141 StringPiece client_common_set_hashes
;
1142 if (client_hello
.GetStringPiece(kCCS
, &client_common_set_hashes
)) {
1143 params
->client_common_set_hashes
= client_common_set_hashes
.as_string();
1146 StringPiece client_cached_cert_hashes
;
1147 if (client_hello
.GetStringPiece(kCCRT
, &client_cached_cert_hashes
)) {
1148 params
->client_cached_cert_hashes
= client_cached_cert_hashes
.as_string();
1151 const string compressed
= CertCompressor::CompressChain(
1152 *certs
, params
->client_common_set_hashes
,
1153 params
->client_cached_cert_hashes
, config
.common_cert_sets
);
1155 // kREJOverheadBytes is a very rough estimate of how much of a REJ
1156 // message is taken up by things other than the certificates.
1162 const size_t kREJOverheadBytes
= 166;
1163 // kMultiplier is the multiple of the CHLO message size that a REJ message
1164 // must stay under when the client doesn't present a valid source-address
1166 const size_t kMultiplier
= 2;
1167 // max_unverified_size is the number of bytes that the certificate chain
1168 // and signature can consume before we will demand a valid source-address
1170 const size_t max_unverified_size
=
1171 client_hello
.size() * kMultiplier
- kREJOverheadBytes
;
1172 COMPILE_ASSERT(kClientHelloMinimumSize
* kMultiplier
>= kREJOverheadBytes
,
1173 overhead_calculation_may_underflow
);
1174 if (info
.valid_source_address_token
||
1175 signature
.size() + compressed
.size() < max_unverified_size
) {
1176 out
->SetStringPiece(kCertificateTag
, compressed
);
1177 out
->SetStringPiece(kPROF
, signature
);
1181 scoped_refptr
<QuicCryptoServerConfig::Config
>
1182 QuicCryptoServerConfig::ParseConfigProtobuf(
1183 QuicServerConfigProtobuf
* protobuf
) {
1184 scoped_ptr
<CryptoHandshakeMessage
> msg(
1185 CryptoFramer::ParseMessage(protobuf
->config()));
1187 if (msg
->tag() != kSCFG
) {
1188 LOG(WARNING
) << "Server config message has tag " << msg
->tag()
1189 << " expected " << kSCFG
;
1193 scoped_refptr
<Config
> config(new Config
);
1194 config
->serialized
= protobuf
->config();
1196 if (!protobuf
->has_source_address_token_secret_override()) {
1197 // Use the default boxer.
1198 config
->source_address_token_boxer
= &default_source_address_token_boxer_
;
1200 // Create override boxer instance.
1201 CryptoSecretBoxer
* boxer
= new CryptoSecretBoxer
;
1202 boxer
->SetKey(DeriveSourceAddressTokenKey(
1203 protobuf
->source_address_token_secret_override()));
1204 config
->source_address_token_boxer_storage
.reset(boxer
);
1205 config
->source_address_token_boxer
= boxer
;
1208 if (protobuf
->has_primary_time()) {
1209 config
->primary_time
=
1210 QuicWallTime::FromUNIXSeconds(protobuf
->primary_time());
1213 config
->priority
= protobuf
->priority();
1216 if (!msg
->GetStringPiece(kSCID
, &scid
)) {
1217 LOG(WARNING
) << "Server config message is missing SCID";
1220 config
->id
= scid
.as_string();
1222 const QuicTag
* aead_tags
;
1224 if (msg
->GetTaglist(kAEAD
, &aead_tags
, &aead_len
) != QUIC_NO_ERROR
) {
1225 LOG(WARNING
) << "Server config message is missing AEAD";
1228 config
->aead
= vector
<QuicTag
>(aead_tags
, aead_tags
+ aead_len
);
1230 const QuicTag
* kexs_tags
;
1232 if (msg
->GetTaglist(kKEXS
, &kexs_tags
, &kexs_len
) != QUIC_NO_ERROR
) {
1233 LOG(WARNING
) << "Server config message is missing KEXS";
1238 if (!msg
->GetStringPiece(kORBT
, &orbit
)) {
1239 LOG(WARNING
) << "Server config message is missing ORBT";
1243 if (orbit
.size() != kOrbitSize
) {
1244 LOG(WARNING
) << "Orbit value in server config is the wrong length."
1245 " Got " << orbit
.size() << " want " << kOrbitSize
;
1248 COMPILE_ASSERT(sizeof(config
->orbit
) == kOrbitSize
, orbit_incorrect_size
);
1249 memcpy(config
->orbit
, orbit
.data(), sizeof(config
->orbit
));
1252 StrikeRegisterClient
* strike_register_client
;
1254 base::AutoLock
locked(strike_register_client_lock_
);
1255 strike_register_client
= strike_register_client_
.get();
1258 if (strike_register_client
!= NULL
&&
1259 !strike_register_client
->IsKnownOrbit(orbit
)) {
1261 << "Rejecting server config with orbit that the strike register "
1262 "client doesn't know about.";
1267 if (kexs_len
!= protobuf
->key_size()) {
1268 LOG(WARNING
) << "Server config has " << kexs_len
1269 << " key exchange methods configured, but "
1270 << protobuf
->key_size() << " private keys";
1274 const QuicTag
* proof_demand_tags
;
1275 size_t num_proof_demand_tags
;
1276 if (msg
->GetTaglist(kPDMD
, &proof_demand_tags
, &num_proof_demand_tags
) ==
1278 for (size_t i
= 0; i
< num_proof_demand_tags
; i
++) {
1279 if (proof_demand_tags
[i
] == kCHID
) {
1280 config
->channel_id_enabled
= true;
1286 for (size_t i
= 0; i
< kexs_len
; i
++) {
1287 const QuicTag tag
= kexs_tags
[i
];
1290 config
->kexs
.push_back(tag
);
1292 for (size_t j
= 0; j
< protobuf
->key_size(); j
++) {
1293 const QuicServerConfigProtobuf::PrivateKey
& key
= protobuf
->key(i
);
1294 if (key
.tag() == tag
) {
1295 private_key
= key
.private_key();
1300 if (private_key
.empty()) {
1301 LOG(WARNING
) << "Server config contains key exchange method without "
1302 "corresponding private key: " << tag
;
1306 scoped_ptr
<KeyExchange
> ka
;
1309 ka
.reset(Curve25519KeyExchange::New(private_key
));
1311 LOG(WARNING
) << "Server config contained an invalid curve25519"
1317 ka
.reset(P256KeyExchange::New(private_key
));
1319 LOG(WARNING
) << "Server config contained an invalid P-256"
1325 LOG(WARNING
) << "Server config message contains unknown key exchange "
1330 for (vector
<KeyExchange
*>::const_iterator i
= config
->key_exchanges
.begin();
1331 i
!= config
->key_exchanges
.end(); ++i
) {
1332 if ((*i
)->tag() == tag
) {
1333 LOG(WARNING
) << "Duplicate key exchange in config: " << tag
;
1338 config
->key_exchanges
.push_back(ka
.release());
1344 void QuicCryptoServerConfig::SetProofSource(ProofSource
* proof_source
) {
1345 proof_source_
.reset(proof_source
);
1348 void QuicCryptoServerConfig::SetEphemeralKeySource(
1349 EphemeralKeySource
* ephemeral_key_source
) {
1350 ephemeral_key_source_
.reset(ephemeral_key_source
);
1353 void QuicCryptoServerConfig::SetStrikeRegisterClient(
1354 StrikeRegisterClient
* strike_register_client
) {
1355 base::AutoLock
locker(strike_register_client_lock_
);
1356 DCHECK(!strike_register_client_
.get());
1357 strike_register_client_
.reset(strike_register_client
);
1360 void QuicCryptoServerConfig::set_replay_protection(bool on
) {
1361 replay_protection_
= on
;
1364 void QuicCryptoServerConfig::set_strike_register_no_startup_period() {
1365 base::AutoLock
locker(strike_register_client_lock_
);
1366 DCHECK(!strike_register_client_
.get());
1367 strike_register_no_startup_period_
= true;
1370 void QuicCryptoServerConfig::set_strike_register_max_entries(
1371 uint32 max_entries
) {
1372 base::AutoLock
locker(strike_register_client_lock_
);
1373 DCHECK(!strike_register_client_
.get());
1374 strike_register_max_entries_
= max_entries
;
1377 void QuicCryptoServerConfig::set_strike_register_window_secs(
1378 uint32 window_secs
) {
1379 base::AutoLock
locker(strike_register_client_lock_
);
1380 DCHECK(!strike_register_client_
.get());
1381 strike_register_window_secs_
= window_secs
;
1384 void QuicCryptoServerConfig::set_source_address_token_future_secs(
1385 uint32 future_secs
) {
1386 source_address_token_future_secs_
= future_secs
;
1389 void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
1390 uint32 lifetime_secs
) {
1391 source_address_token_lifetime_secs_
= lifetime_secs
;
1394 void QuicCryptoServerConfig::set_server_nonce_strike_register_max_entries(
1395 uint32 max_entries
) {
1396 DCHECK(!server_nonce_strike_register_
.get());
1397 server_nonce_strike_register_max_entries_
= max_entries
;
1400 void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs(
1401 uint32 window_secs
) {
1402 DCHECK(!server_nonce_strike_register_
.get());
1403 server_nonce_strike_register_window_secs_
= window_secs
;
1406 void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
1407 PrimaryConfigChangedCallback
* cb
) {
1408 base::AutoLock
locked(configs_lock_
);
1409 primary_config_changed_cb_
.reset(cb
);
1412 string
QuicCryptoServerConfig::NewSourceAddressToken(
1413 const Config
& config
,
1414 const IPEndPoint
& ip
,
1417 const CachedNetworkParameters
* cached_network_params
) const {
1418 IPAddressNumber ip_address
= ip
.address();
1419 if (ip
.GetSockAddrFamily() == AF_INET
) {
1420 ip_address
= ConvertIPv4NumberToIPv6Number(ip_address
);
1422 SourceAddressToken source_address_token
;
1423 source_address_token
.set_ip(IPAddressToPackedString(ip_address
));
1424 source_address_token
.set_timestamp(now
.ToUNIXSeconds());
1425 if (cached_network_params
!= NULL
) {
1426 source_address_token
.set_cached_network_parameters(*cached_network_params
);
1429 return config
.source_address_token_boxer
->Box(
1430 rand
, source_address_token
.SerializeAsString());
1433 HandshakeFailureReason
QuicCryptoServerConfig::ValidateSourceAddressToken(
1434 const Config
& config
,
1436 const IPEndPoint
& ip
,
1437 QuicWallTime now
) const {
1439 StringPiece plaintext
;
1440 if (!config
.source_address_token_boxer
->Unbox(token
, &storage
, &plaintext
)) {
1441 return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE
;
1444 SourceAddressToken source_address_token
;
1445 if (!source_address_token
.ParseFromArray(plaintext
.data(),
1446 plaintext
.size())) {
1447 return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE
;
1450 IPAddressNumber ip_address
= ip
.address();
1451 if (ip
.GetSockAddrFamily() == AF_INET
) {
1452 ip_address
= ConvertIPv4NumberToIPv6Number(ip_address
);
1454 if (source_address_token
.ip() != IPAddressToPackedString(ip_address
)) {
1455 // It's for a different IP address.
1456 return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE
;
1459 const QuicWallTime
timestamp(
1460 QuicWallTime::FromUNIXSeconds(source_address_token
.timestamp()));
1461 const QuicTime::Delta
delta(now
.AbsoluteDifference(timestamp
));
1463 if (now
.IsBefore(timestamp
) &&
1464 delta
.ToSeconds() > source_address_token_future_secs_
) {
1465 return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE
;
1468 if (now
.IsAfter(timestamp
) &&
1469 delta
.ToSeconds() > source_address_token_lifetime_secs_
) {
1470 return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE
;
1473 return HANDSHAKE_OK
;
1476 // kServerNoncePlaintextSize is the number of bytes in an unencrypted server
1478 static const size_t kServerNoncePlaintextSize
=
1479 4 /* timestamp */ + 20 /* random bytes */;
1481 string
QuicCryptoServerConfig::NewServerNonce(QuicRandom
* rand
,
1482 QuicWallTime now
) const {
1483 const uint32 timestamp
= static_cast<uint32
>(now
.ToUNIXSeconds());
1485 uint8 server_nonce
[kServerNoncePlaintextSize
];
1486 COMPILE_ASSERT(sizeof(server_nonce
) > sizeof(timestamp
), nonce_too_small
);
1487 server_nonce
[0] = static_cast<uint8
>(timestamp
>> 24);
1488 server_nonce
[1] = static_cast<uint8
>(timestamp
>> 16);
1489 server_nonce
[2] = static_cast<uint8
>(timestamp
>> 8);
1490 server_nonce
[3] = static_cast<uint8
>(timestamp
);
1491 rand
->RandBytes(&server_nonce
[sizeof(timestamp
)],
1492 sizeof(server_nonce
) - sizeof(timestamp
));
1494 return server_nonce_boxer_
.Box(
1496 StringPiece(reinterpret_cast<char*>(server_nonce
), sizeof(server_nonce
)));
1499 HandshakeFailureReason
QuicCryptoServerConfig::ValidateServerNonce(
1501 QuicWallTime now
) const {
1503 StringPiece plaintext
;
1504 if (!server_nonce_boxer_
.Unbox(token
, &storage
, &plaintext
)) {
1505 return SERVER_NONCE_DECRYPTION_FAILURE
;
1508 // plaintext contains:
1510 // uint8[20] random bytes
1512 if (plaintext
.size() != kServerNoncePlaintextSize
) {
1513 // This should never happen because the value decrypted correctly.
1514 LOG(DFATAL
) << "Seemingly valid server nonce had incorrect length.";
1515 return SERVER_NONCE_INVALID_FAILURE
;
1518 uint8 server_nonce
[32];
1519 memcpy(server_nonce
, plaintext
.data(), 4);
1520 memcpy(server_nonce
+ 4, server_nonce_orbit_
, sizeof(server_nonce_orbit_
));
1521 memcpy(server_nonce
+ 4 + sizeof(server_nonce_orbit_
), plaintext
.data() + 4,
1523 COMPILE_ASSERT(4 + sizeof(server_nonce_orbit_
) + 20 == sizeof(server_nonce
),
1524 bad_nonce_buffer_length
);
1526 InsertStatus nonce_error
;
1528 base::AutoLock
auto_lock(server_nonce_strike_register_lock_
);
1529 if (server_nonce_strike_register_
.get() == NULL
) {
1530 server_nonce_strike_register_
.reset(new StrikeRegister(
1531 server_nonce_strike_register_max_entries_
,
1532 static_cast<uint32
>(now
.ToUNIXSeconds()),
1533 server_nonce_strike_register_window_secs_
, server_nonce_orbit_
,
1534 StrikeRegister::NO_STARTUP_PERIOD_NEEDED
));
1536 nonce_error
= server_nonce_strike_register_
->Insert(
1537 server_nonce
, static_cast<uint32
>(now
.ToUNIXSeconds()));
1540 switch (nonce_error
) {
1542 return HANDSHAKE_OK
;
1543 case NONCE_INVALID_FAILURE
:
1544 case NONCE_INVALID_ORBIT_FAILURE
:
1545 return SERVER_NONCE_INVALID_FAILURE
;
1546 case NONCE_NOT_UNIQUE_FAILURE
:
1547 return SERVER_NONCE_NOT_UNIQUE_FAILURE
;
1548 case NONCE_INVALID_TIME_FAILURE
:
1549 return SERVER_NONCE_INVALID_TIME_FAILURE
;
1550 case NONCE_UNKNOWN_FAILURE
:
1551 case STRIKE_REGISTER_TIMEOUT
:
1552 case STRIKE_REGISTER_FAILURE
:
1554 LOG(DFATAL
) << "Unexpected server nonce error: " << nonce_error
;
1555 return SERVER_NONCE_NOT_UNIQUE_FAILURE
;
1559 QuicCryptoServerConfig::Config::Config()
1560 : channel_id_enabled(false),
1562 primary_time(QuicWallTime::Zero()),
1564 source_address_token_boxer(NULL
) {}
1566 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges
); }