OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/quic/crypto/crypto_server_config.h" | 5 #include "net/quic/crypto/crypto_server_config.h" |
6 | 6 |
7 #include "base/stl_util.h" | 7 #include "base/stl_util.h" |
8 #include "crypto/hkdf.h" | 8 #include "crypto/hkdf.h" |
9 #include "crypto/secure_hash.h" | 9 #include "crypto/secure_hash.h" |
10 #include "net/quic/crypto/aes_128_gcm_decrypter.h" | 10 #include "net/quic/crypto/aes_128_gcm_decrypter.h" |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 // obtain two source address tokens with the same nonce. This occurs with | 45 // obtain two source address tokens with the same nonce. This occurs with |
46 // probability 0.5 after 2**48 values. We assume that obtaining 2**48 | 46 // probability 0.5 after 2**48 values. We assume that obtaining 2**48 |
47 // source address tokens is not possible: at a rate of 10M packets per | 47 // source address tokens is not possible: at a rate of 10M packets per |
48 // second, it would still take the attacker a year to obtain the needed | 48 // second, it would still take the attacker a year to obtain the needed |
49 // number of packets. | 49 // number of packets. |
50 // | 50 // |
51 // TODO(agl): switch to an encrypter with a larger nonce space (i.e. | 51 // TODO(agl): switch to an encrypter with a larger nonce space (i.e. |
52 // Salsa20+Poly1305). | 52 // Salsa20+Poly1305). |
53 : strike_register_lock_(), | 53 : strike_register_lock_(), |
54 source_address_token_encrypter_(new Aes128GcmEncrypter), | 54 source_address_token_encrypter_(new Aes128GcmEncrypter), |
55 source_address_token_decrypter_(new Aes128GcmDecrypter) { | 55 source_address_token_decrypter_(new Aes128GcmDecrypter), |
| 56 strike_register_max_entries_(1 << 10), |
| 57 strike_register_window_secs_(600), |
| 58 source_address_token_future_secs_(3600), |
| 59 source_address_token_lifetime_secs_(86400) { |
56 crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */, | 60 crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */, |
57 "QUIC source address token key", | 61 "QUIC source address token key", |
58 source_address_token_encrypter_->GetKeySize(), | 62 source_address_token_encrypter_->GetKeySize(), |
59 0 /* no fixed IV needed */); | 63 0 /* no fixed IV needed */); |
60 source_address_token_encrypter_->SetKey(hkdf.server_write_key()); | 64 source_address_token_encrypter_->SetKey(hkdf.server_write_key()); |
61 source_address_token_decrypter_->SetKey(hkdf.server_write_key()); | 65 source_address_token_decrypter_->SetKey(hkdf.server_write_key()); |
62 } | 66 } |
63 | 67 |
64 QuicCryptoServerConfig::~QuicCryptoServerConfig() { | 68 QuicCryptoServerConfig::~QuicCryptoServerConfig() { |
65 STLDeleteValues(&configs_); | 69 STLDeleteValues(&configs_); |
66 } | 70 } |
67 | 71 |
68 // static | 72 // static |
69 QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig( | 73 QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig( |
70 QuicRandom* rand, | 74 QuicRandom* rand, |
71 const QuicClock* clock, | 75 const QuicClock* clock, |
72 const CryptoHandshakeMessage& extra_tags, | |
73 uint64 expiry_time) { | 76 uint64 expiry_time) { |
74 CryptoHandshakeMessage msg; | 77 CryptoHandshakeMessage msg; |
75 | 78 |
76 const string curve25519_private_key = | 79 const string curve25519_private_key = |
77 Curve25519KeyExchange::NewPrivateKey(rand); | 80 Curve25519KeyExchange::NewPrivateKey(rand); |
78 scoped_ptr<Curve25519KeyExchange> curve25519( | 81 scoped_ptr<Curve25519KeyExchange> curve25519( |
79 Curve25519KeyExchange::New(curve25519_private_key)); | 82 Curve25519KeyExchange::New(curve25519_private_key)); |
80 StringPiece curve25519_public_value = curve25519->public_value(); | 83 StringPiece curve25519_public_value = curve25519->public_value(); |
81 | 84 |
82 const string p256_private_key = P256KeyExchange::NewPrivateKey(); | 85 const string p256_private_key = P256KeyExchange::NewPrivateKey(); |
(...skipping 11 matching lines...) Expand all Loading... |
94 encoded_public_values.push_back(p256_public_value.size() >> 8); | 97 encoded_public_values.push_back(p256_public_value.size() >> 8); |
95 encoded_public_values.push_back(p256_public_value.size() >> 16); | 98 encoded_public_values.push_back(p256_public_value.size() >> 16); |
96 encoded_public_values.append(p256_public_value.data(), | 99 encoded_public_values.append(p256_public_value.data(), |
97 p256_public_value.size()); | 100 p256_public_value.size()); |
98 | 101 |
99 msg.set_tag(kSCFG); | 102 msg.set_tag(kSCFG); |
100 msg.SetTaglist(kKEXS, kC255, kP256, 0); | 103 msg.SetTaglist(kKEXS, kC255, kP256, 0); |
101 msg.SetTaglist(kAEAD, kAESG, 0); | 104 msg.SetTaglist(kAEAD, kAESG, 0); |
102 msg.SetValue(kVERS, static_cast<uint16>(0)); | 105 msg.SetValue(kVERS, static_cast<uint16>(0)); |
103 msg.SetStringPiece(kPUBS, encoded_public_values); | 106 msg.SetStringPiece(kPUBS, encoded_public_values); |
104 msg.Insert(extra_tags.tag_value_map().begin(), | |
105 extra_tags.tag_value_map().end()); | |
106 | 107 |
107 if (expiry_time == 0) { | 108 if (expiry_time == 0) { |
108 const QuicWallTime now = clock->WallNow(); | 109 const QuicWallTime now = clock->WallNow(); |
109 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds( | 110 const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds( |
110 60 * 60 * 24 * 180 /* 180 days, ~six months */)); | 111 60 * 60 * 24 * 180 /* 180 days, ~six months */)); |
111 const uint64 expiry_seconds = expiry.ToUNIXSeconds(); | 112 const uint64 expiry_seconds = expiry.ToUNIXSeconds(); |
112 msg.SetValue(kEXPY, expiry_seconds); | 113 msg.SetValue(kEXPY, expiry_seconds); |
113 } else { | 114 } else { |
114 msg.SetValue(kEXPY, expiry_time); | 115 msg.SetValue(kEXPY, expiry_time); |
115 } | 116 } |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 | 271 |
271 configs_[id] = config.release(); | 272 configs_[id] = config.release(); |
272 active_config_ = id; | 273 active_config_ = id; |
273 | 274 |
274 return msg.release(); | 275 return msg.release(); |
275 } | 276 } |
276 | 277 |
277 CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig( | 278 CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig( |
278 QuicRandom* rand, | 279 QuicRandom* rand, |
279 const QuicClock* clock, | 280 const QuicClock* clock, |
280 const CryptoHandshakeMessage& extra_tags, | |
281 uint64 expiry_time) { | 281 uint64 expiry_time) { |
282 scoped_ptr<QuicServerConfigProtobuf> config(DefaultConfig( | 282 scoped_ptr<QuicServerConfigProtobuf> config( |
283 rand, clock, extra_tags, expiry_time)); | 283 DefaultConfig(rand, clock, expiry_time)); |
284 return AddConfig(config.get()); | 284 return AddConfig(config.get()); |
285 } | 285 } |
286 | 286 |
287 QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( | 287 QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( |
288 const CryptoHandshakeMessage& client_hello, | 288 const CryptoHandshakeMessage& client_hello, |
289 QuicGuid guid, | 289 QuicGuid guid, |
290 const IPEndPoint& client_ip, | 290 const IPEndPoint& client_ip, |
291 const QuicClock* clock, | 291 const QuicClock* clock, |
292 QuicRandom* rand, | 292 QuicRandom* rand, |
293 QuicCryptoNegotiatedParameters *params, | 293 QuicCryptoNegotiatedParameters *params, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 | 327 |
328 StringPiece client_nonce; | 328 StringPiece client_nonce; |
329 bool client_nonce_well_formed = false; | 329 bool client_nonce_well_formed = false; |
330 if (client_hello.GetStringPiece(kNONC, &client_nonce) && | 330 if (client_hello.GetStringPiece(kNONC, &client_nonce) && |
331 client_nonce.size() == kNonceSize) { | 331 client_nonce.size() == kNonceSize) { |
332 client_nonce_well_formed = true; | 332 client_nonce_well_formed = true; |
333 base::AutoLock auto_lock(strike_register_lock_); | 333 base::AutoLock auto_lock(strike_register_lock_); |
334 | 334 |
335 if (strike_register_.get() == NULL) { | 335 if (strike_register_.get() == NULL) { |
336 strike_register_.reset(new StrikeRegister( | 336 strike_register_.reset(new StrikeRegister( |
337 // TODO(agl): these magic numbers should come from config. | 337 strike_register_max_entries_, |
338 1024 /* max entries */, | |
339 static_cast<uint32>(now.ToUNIXSeconds()), | 338 static_cast<uint32>(now.ToUNIXSeconds()), |
340 600 /* window secs */, config->orbit)); | 339 strike_register_window_secs_, |
| 340 config->orbit)); |
341 } | 341 } |
342 unique_by_strike_register = strike_register_->Insert( | 342 unique_by_strike_register = strike_register_->Insert( |
343 reinterpret_cast<const uint8*>(client_nonce.data()), | 343 reinterpret_cast<const uint8*>(client_nonce.data()), |
344 static_cast<uint32>(now.ToUNIXSeconds())); | 344 static_cast<uint32>(now.ToUNIXSeconds())); |
345 } | 345 } |
346 | 346 |
347 StringPiece server_nonce; | 347 StringPiece server_nonce; |
348 client_hello.GetStringPiece(kServerNonceTag, &server_nonce); | 348 client_hello.GetStringPiece(kServerNonceTag, &server_nonce); |
349 const bool server_nonce_matches = server_nonce == params->server_nonce; | 349 const bool server_nonce_matches = server_nonce == params->server_nonce; |
350 | 350 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 break; | 394 break; |
395 } | 395 } |
396 | 396 |
397 StringPiece their_common_set_hashes; | 397 StringPiece their_common_set_hashes; |
398 StringPiece their_cached_cert_hashes; | 398 StringPiece their_cached_cert_hashes; |
399 client_hello.GetStringPiece(kCCS, &their_common_set_hashes); | 399 client_hello.GetStringPiece(kCCS, &their_common_set_hashes); |
400 client_hello.GetStringPiece(kCCRT, &their_cached_cert_hashes); | 400 client_hello.GetStringPiece(kCCRT, &their_cached_cert_hashes); |
401 | 401 |
402 const string compressed = CertCompressor::CompressChain( | 402 const string compressed = CertCompressor::CompressChain( |
403 *certs, their_common_set_hashes, their_cached_cert_hashes, | 403 *certs, their_common_set_hashes, their_cached_cert_hashes, |
404 config->common_cert_set_.get()); | 404 config->common_cert_sets.get()); |
405 | 405 |
406 // kMaxUnverifiedSize is the number of bytes that the certificate chain | 406 // kMaxUnverifiedSize is the number of bytes that the certificate chain |
407 // and signature can consume before we will demand a valid | 407 // and signature can consume before we will demand a valid |
408 // source-address token. | 408 // source-address token. |
409 static const size_t kMaxUnverifiedSize = 400; | 409 static const size_t kMaxUnverifiedSize = 400; |
410 if (valid_source_address_token || | 410 if (valid_source_address_token || |
411 signature.size() + compressed.size() < kMaxUnverifiedSize) { | 411 signature.size() + compressed.size() < kMaxUnverifiedSize) { |
412 out->SetStringPiece(kCertificateTag, compressed); | 412 out->SetStringPiece(kCertificateTag, compressed); |
413 out->SetStringPiece(kPROF, signature); | 413 out->SetStringPiece(kPROF, signature); |
414 } | 414 } |
(...skipping 11 matching lines...) Expand all Loading... |
426 &num_their_aeads) != QUIC_NO_ERROR || | 426 &num_their_aeads) != QUIC_NO_ERROR || |
427 client_hello.GetTaglist(kKEXS, &their_key_exchanges, | 427 client_hello.GetTaglist(kKEXS, &their_key_exchanges, |
428 &num_their_key_exchanges) != QUIC_NO_ERROR || | 428 &num_their_key_exchanges) != QUIC_NO_ERROR || |
429 num_their_aeads != 1 || | 429 num_their_aeads != 1 || |
430 num_their_key_exchanges != 1) { | 430 num_their_key_exchanges != 1) { |
431 *error_details = "Missing or invalid AEAD or KEXS"; | 431 *error_details = "Missing or invalid AEAD or KEXS"; |
432 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 432 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
433 } | 433 } |
434 | 434 |
435 size_t key_exchange_index; | 435 size_t key_exchange_index; |
436 if (!CryptoUtils::FindMutualTag(config->aead, their_aeads, num_their_aeads, | 436 if (!QuicUtils::FindMutualTag(config->aead, their_aeads, num_their_aeads, |
437 CryptoUtils::LOCAL_PRIORITY, ¶ms->aead, | 437 QuicUtils::LOCAL_PRIORITY, ¶ms->aead, |
438 NULL) || | 438 NULL) || |
439 !CryptoUtils::FindMutualTag( | 439 !QuicUtils::FindMutualTag( |
440 config->kexs, their_key_exchanges, num_their_key_exchanges, | 440 config->kexs, their_key_exchanges, num_their_key_exchanges, |
441 CryptoUtils::LOCAL_PRIORITY, ¶ms->key_exchange, | 441 QuicUtils::LOCAL_PRIORITY, ¶ms->key_exchange, |
442 &key_exchange_index)) { | 442 &key_exchange_index)) { |
443 *error_details = "Unsupported AEAD or KEXS"; | 443 *error_details = "Unsupported AEAD or KEXS"; |
444 return QUIC_CRYPTO_NO_SUPPORT; | 444 return QUIC_CRYPTO_NO_SUPPORT; |
445 } | 445 } |
446 | 446 |
447 StringPiece public_value; | 447 StringPiece public_value; |
448 if (!client_hello.GetStringPiece(kPUBS, &public_value)) { | 448 if (!client_hello.GetStringPiece(kPUBS, &public_value)) { |
449 *error_details = "Missing public value"; | 449 *error_details = "Missing public value"; |
450 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 450 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
451 } | 451 } |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 | 516 |
517 void QuicCryptoServerConfig::SetProofSource(ProofSource* proof_source) { | 517 void QuicCryptoServerConfig::SetProofSource(ProofSource* proof_source) { |
518 proof_source_.reset(proof_source); | 518 proof_source_.reset(proof_source); |
519 } | 519 } |
520 | 520 |
521 void QuicCryptoServerConfig::SetEphemeralKeySource( | 521 void QuicCryptoServerConfig::SetEphemeralKeySource( |
522 EphemeralKeySource* ephemeral_key_source) { | 522 EphemeralKeySource* ephemeral_key_source) { |
523 ephemeral_key_source_.reset(ephemeral_key_source); | 523 ephemeral_key_source_.reset(ephemeral_key_source); |
524 } | 524 } |
525 | 525 |
| 526 void QuicCryptoServerConfig::set_strike_register_max_entries( |
| 527 uint32 max_entries) { |
| 528 DCHECK(!strike_register_.get()); |
| 529 strike_register_max_entries_ = max_entries; |
| 530 } |
| 531 |
| 532 void QuicCryptoServerConfig::set_strike_register_window_secs( |
| 533 uint32 window_secs) { |
| 534 DCHECK(!strike_register_.get()); |
| 535 strike_register_window_secs_ = window_secs; |
| 536 } |
| 537 |
| 538 void QuicCryptoServerConfig::set_source_address_token_future_secs( |
| 539 uint32 future_secs) { |
| 540 source_address_token_future_secs_ = future_secs; |
| 541 } |
| 542 |
| 543 void QuicCryptoServerConfig::set_source_address_token_lifetime_secs( |
| 544 uint32 lifetime_secs) { |
| 545 source_address_token_lifetime_secs_ = lifetime_secs; |
| 546 } |
| 547 |
526 string QuicCryptoServerConfig::NewSourceAddressToken( | 548 string QuicCryptoServerConfig::NewSourceAddressToken( |
527 const IPEndPoint& ip, | 549 const IPEndPoint& ip, |
528 QuicRandom* rand, | 550 QuicRandom* rand, |
529 QuicWallTime now) const { | 551 QuicWallTime now) const { |
530 SourceAddressToken source_address_token; | 552 SourceAddressToken source_address_token; |
531 source_address_token.set_ip(ip.ToString()); | 553 source_address_token.set_ip(ip.ToString()); |
532 source_address_token.set_timestamp(now.ToUNIXSeconds()); | 554 source_address_token.set_timestamp(now.ToUNIXSeconds()); |
533 | 555 |
534 string plaintext = source_address_token.SerializeAsString(); | 556 string plaintext = source_address_token.SerializeAsString(); |
535 char nonce[12]; | 557 char nonce[12]; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 | 615 |
594 if (source_address_token.ip() != ip.ToString()) { | 616 if (source_address_token.ip() != ip.ToString()) { |
595 // It's for a different IP address. | 617 // It's for a different IP address. |
596 return false; | 618 return false; |
597 } | 619 } |
598 | 620 |
599 const QuicWallTime timestamp( | 621 const QuicWallTime timestamp( |
600 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp())); | 622 QuicWallTime::FromUNIXSeconds(source_address_token.timestamp())); |
601 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp)); | 623 const QuicTime::Delta delta(now.AbsoluteDifference(timestamp)); |
602 | 624 |
603 // TODO(agl): consider whether and how these magic values should be moved to | 625 if (now.IsBefore(timestamp) && |
604 // a config. | 626 delta.ToSeconds() > source_address_token_future_secs_) { |
605 if (now.IsBefore(timestamp) && delta.ToSeconds() > 3600) { | |
606 // We only allow timestamps to be from an hour in the future. | |
607 return false; | 627 return false; |
608 } | 628 } |
609 | 629 |
610 if (now.IsAfter(timestamp) && delta.ToSeconds() > 86400) { | 630 if (now.IsAfter(timestamp) && |
611 // We allow one day into the past. | 631 delta.ToSeconds() > source_address_token_lifetime_secs_) { |
612 return false; | 632 return false; |
613 } | 633 } |
614 | 634 |
615 return true; | 635 return true; |
616 } | 636 } |
617 | 637 |
618 QuicCryptoServerConfig::Config::Config() {} | 638 QuicCryptoServerConfig::Config::Config() {} |
619 | 639 |
620 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); } | 640 QuicCryptoServerConfig::Config::~Config() { STLDeleteElements(&key_exchanges); } |
621 | 641 |
622 } // namespace net | 642 } // namespace net |
OLD | NEW |