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_handshake.h" | 5 #include "net/quic/crypto/crypto_handshake.h" |
6 | 6 |
7 #include <ctype.h> | 7 #include <ctype.h> |
8 | 8 |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
12 #include "base/strings/string_split.h" | 12 #include "base/strings/string_split.h" |
13 #include "crypto/hkdf.h" | |
14 #include "crypto/secure_hash.h" | 13 #include "crypto/secure_hash.h" |
15 #include "net/base/net_util.h" | 14 #include "net/base/net_util.h" |
16 #include "net/quic/crypto/aes_128_gcm_decrypter.h" | |
17 #include "net/quic/crypto/aes_128_gcm_encrypter.h" | |
18 #include "net/quic/crypto/crypto_framer.h" | 15 #include "net/quic/crypto/crypto_framer.h" |
19 #include "net/quic/crypto/crypto_utils.h" | 16 #include "net/quic/crypto/crypto_utils.h" |
20 #include "net/quic/crypto/curve25519_key_exchange.h" | 17 #include "net/quic/crypto/curve25519_key_exchange.h" |
21 #include "net/quic/crypto/key_exchange.h" | 18 #include "net/quic/crypto/key_exchange.h" |
22 #include "net/quic/crypto/p256_key_exchange.h" | 19 #include "net/quic/crypto/p256_key_exchange.h" |
23 #include "net/quic/crypto/quic_decrypter.h" | 20 #include "net/quic/crypto/quic_decrypter.h" |
24 #include "net/quic/crypto/quic_encrypter.h" | 21 #include "net/quic/crypto/quic_encrypter.h" |
25 #include "net/quic/crypto/quic_random.h" | 22 #include "net/quic/crypto/quic_random.h" |
26 #include "net/quic/crypto/strike_register.h" | |
27 #include "net/quic/quic_clock.h" | 23 #include "net/quic/quic_clock.h" |
28 #include "net/quic/quic_protocol.h" | 24 #include "net/quic/quic_protocol.h" |
29 | 25 |
30 using base::StringPiece; | 26 using base::StringPiece; |
31 using crypto::SecureHash; | 27 using crypto::SecureHash; |
32 using std::map; | 28 using std::map; |
33 using std::string; | 29 using std::string; |
34 using std::vector; | 30 using std::vector; |
35 | 31 |
36 namespace net { | 32 namespace net { |
37 | 33 |
38 // kVersion contains the one (and, for the moment, only) version number that we | |
39 // implement. | |
40 static const uint16 kVersion = 0; | |
41 | |
42 // kLabel is constant that is used in key derivation to tie the resulting key | |
43 // to this protocol. | |
44 static const char kLabel[] = "QUIC key expansion"; | |
45 | |
46 using crypto::SecureHash; | |
47 | |
48 QuicServerConfigProtobuf::QuicServerConfigProtobuf() { | |
49 } | |
50 | |
51 QuicServerConfigProtobuf::~QuicServerConfigProtobuf() { | |
52 STLDeleteElements(&keys_); | |
53 } | |
54 | |
55 CryptoHandshakeMessage::CryptoHandshakeMessage() : tag_(0) {} | 34 CryptoHandshakeMessage::CryptoHandshakeMessage() : tag_(0) {} |
56 | 35 |
57 CryptoHandshakeMessage::CryptoHandshakeMessage( | 36 CryptoHandshakeMessage::CryptoHandshakeMessage( |
58 const CryptoHandshakeMessage& other) | 37 const CryptoHandshakeMessage& other) |
59 : tag_(other.tag_), | 38 : tag_(other.tag_), |
60 tag_value_map_(other.tag_value_map_) { | 39 tag_value_map_(other.tag_value_map_) { |
61 // Don't copy serialized_. scoped_ptr doesn't have a copy constructor. | 40 // Don't copy serialized_. scoped_ptr doesn't have a copy constructor. |
62 // The new object can reconstruct serialized_ lazily. | 41 // The new object can reconstruct serialized_ lazily. |
63 } | 42 } |
64 | 43 |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 if (it->second.size() == 4) { | 256 if (it->second.size() == 4) { |
278 uint32 value; | 257 uint32 value; |
279 memcpy(&value, it->second.data(), sizeof(value)); | 258 memcpy(&value, it->second.data(), sizeof(value)); |
280 ret += base::UintToString(value); | 259 ret += base::UintToString(value); |
281 done = true; | 260 done = true; |
282 } | 261 } |
283 break; | 262 break; |
284 case kKEXS: | 263 case kKEXS: |
285 case kAEAD: | 264 case kAEAD: |
286 case kCGST: | 265 case kCGST: |
| 266 case kPDMD: |
287 // tag lists | 267 // tag lists |
288 if (it->second.size() % sizeof(CryptoTag) == 0) { | 268 if (it->second.size() % sizeof(CryptoTag) == 0) { |
289 for (size_t j = 0; j < it->second.size(); j += sizeof(CryptoTag)) { | 269 for (size_t j = 0; j < it->second.size(); j += sizeof(CryptoTag)) { |
290 CryptoTag tag; | 270 CryptoTag tag; |
291 memcpy(&tag, it->second.data() + j, sizeof(tag)); | 271 memcpy(&tag, it->second.data() + j, sizeof(tag)); |
292 if (j > 0) { | 272 if (j > 0) { |
293 ret += ","; | 273 ret += ","; |
294 } | 274 } |
295 ret += TagToString(tag); | 275 ret += TagToString(tag); |
296 } | 276 } |
(...skipping 20 matching lines...) Expand all Loading... |
317 // then just use hex. | 297 // then just use hex. |
318 ret += base::HexEncode(it->second.data(), it->second.size()); | 298 ret += base::HexEncode(it->second.data(), it->second.size()); |
319 } | 299 } |
320 ret += "\n"; | 300 ret += "\n"; |
321 } | 301 } |
322 --indent; | 302 --indent; |
323 ret += string(2 * indent, ' ') + ">"; | 303 ret += string(2 * indent, ' ') + ">"; |
324 return ret; | 304 return ret; |
325 } | 305 } |
326 | 306 |
327 SourceAddressToken::SourceAddressToken() { | |
328 } | |
329 | |
330 SourceAddressToken::~SourceAddressToken() { | |
331 } | |
332 | |
333 string SourceAddressToken::SerializeAsString() const { | |
334 return ip_ + " " + base::Int64ToString(timestamp_); | |
335 } | |
336 | |
337 bool SourceAddressToken::ParseFromArray(unsigned char* plaintext, | |
338 size_t plaintext_length) { | |
339 string data(reinterpret_cast<const char*>(plaintext), plaintext_length); | |
340 std::vector<std::string> results; | |
341 base::SplitString(data, ' ', &results); | |
342 if (results.size() < 2) { | |
343 return false; | |
344 } | |
345 | |
346 int64 timestamp; | |
347 if (!base::StringToInt64(results[1], ×tamp)) { | |
348 return false; | |
349 } | |
350 | |
351 ip_ = results[0]; | |
352 timestamp_ = timestamp; | |
353 return true; | |
354 } | |
355 | |
356 QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters() | 307 QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters() |
357 : version(0), | 308 : version(0), |
358 key_exchange(0), | 309 key_exchange(0), |
359 aead(0) { | 310 aead(0) { |
360 } | 311 } |
361 | 312 |
362 QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() { | 313 QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() { |
363 } | 314 } |
364 | 315 |
365 | 316 |
| 317 // static |
| 318 const char QuicCryptoConfig::kLabel[] = "QUIC key expansion"; |
| 319 |
366 QuicCryptoConfig::QuicCryptoConfig() | 320 QuicCryptoConfig::QuicCryptoConfig() |
367 : version(0) { | 321 : version(0) { |
368 } | 322 } |
369 | 323 |
370 QuicCryptoConfig::~QuicCryptoConfig() { | 324 QuicCryptoConfig::~QuicCryptoConfig() { |
371 } | 325 } |
372 | 326 |
373 | 327 |
374 QuicCryptoClientConfig::QuicCryptoClientConfig() { | 328 QuicCryptoClientConfig::QuicCryptoClientConfig() { |
375 } | 329 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 return source_address_token_; | 375 return source_address_token_; |
422 } | 376 } |
423 | 377 |
424 void QuicCryptoClientConfig::CachedState::set_source_address_token( | 378 void QuicCryptoClientConfig::CachedState::set_source_address_token( |
425 StringPiece token) { | 379 StringPiece token) { |
426 source_address_token_ = token.as_string(); | 380 source_address_token_ = token.as_string(); |
427 } | 381 } |
428 | 382 |
429 void QuicCryptoClientConfig::SetDefaults() { | 383 void QuicCryptoClientConfig::SetDefaults() { |
430 // Version must be 0. | 384 // Version must be 0. |
431 version = kVersion; | 385 version = QuicCryptoConfig::CONFIG_VERSION; |
432 | 386 |
433 // Key exchange methods. | 387 // Key exchange methods. |
434 kexs.resize(2); | 388 kexs.resize(2); |
435 kexs[0] = kC255; | 389 kexs[0] = kC255; |
436 kexs[1] = kP256; | 390 kexs[1] = kP256; |
437 | 391 |
438 // Authenticated encryption algorithms. | 392 // Authenticated encryption algorithms. |
439 aead.resize(1); | 393 aead.resize(1); |
440 aead[0] = kAESG; | 394 aead[0] = kAESG; |
441 } | 395 } |
(...skipping 19 matching lines...) Expand all Loading... |
461 IPAddressNumber ip; | 415 IPAddressNumber ip; |
462 if (!server_hostname.empty() && | 416 if (!server_hostname.empty() && |
463 !ParseIPLiteralToNumber(server_hostname, &ip)) { | 417 !ParseIPLiteralToNumber(server_hostname, &ip)) { |
464 out->SetStringPiece(kSNI, server_hostname); | 418 out->SetStringPiece(kSNI, server_hostname); |
465 } | 419 } |
466 out->SetValue(kVERS, version); | 420 out->SetValue(kVERS, version); |
467 | 421 |
468 if (cached && !cached->source_address_token().empty()) { | 422 if (cached && !cached->source_address_token().empty()) { |
469 out->SetStringPiece(kSRCT, cached->source_address_token()); | 423 out->SetStringPiece(kSRCT, cached->source_address_token()); |
470 } | 424 } |
| 425 |
| 426 out->SetTaglist(kPDMD, kX509, 0); |
471 } | 427 } |
472 | 428 |
473 QuicErrorCode QuicCryptoClientConfig::FillClientHello( | 429 QuicErrorCode QuicCryptoClientConfig::FillClientHello( |
474 const string& server_hostname, | 430 const string& server_hostname, |
475 QuicGuid guid, | 431 QuicGuid guid, |
476 const CachedState* cached, | 432 const CachedState* cached, |
477 const QuicClock* clock, | 433 const QuicClock* clock, |
478 QuicRandom* rand, | 434 QuicRandom* rand, |
479 QuicCryptoNegotiatedParameters* out_params, | 435 QuicCryptoNegotiatedParameters* out_params, |
480 CryptoHandshakeMessage* out, | 436 CryptoHandshakeMessage* out, |
481 string* error_details) const { | 437 string* error_details) const { |
| 438 DCHECK(error_details != NULL); |
| 439 |
482 FillInchoateClientHello(server_hostname, cached, out); | 440 FillInchoateClientHello(server_hostname, cached, out); |
483 | 441 |
484 const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); | 442 const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); |
485 if (!scfg) { | 443 if (!scfg) { |
486 // This should never happen as our caller should have checked | 444 // This should never happen as our caller should have checked |
487 // cached->is_complete() before calling this function. | 445 // cached->is_complete() before calling this function. |
488 if (error_details) { | 446 *error_details = "Handshake not ready"; |
489 *error_details = "Handshake not ready"; | |
490 } | |
491 return QUIC_CRYPTO_INTERNAL_ERROR; | 447 return QUIC_CRYPTO_INTERNAL_ERROR; |
492 } | 448 } |
493 | 449 |
494 StringPiece scid; | 450 StringPiece scid; |
495 if (!scfg->GetStringPiece(kSCID, &scid)) { | 451 if (!scfg->GetStringPiece(kSCID, &scid)) { |
496 if (error_details) { | 452 *error_details = "SCFG missing SCID"; |
497 *error_details = "SCFG missing SCID"; | |
498 } | |
499 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 453 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
500 } | 454 } |
501 out->SetStringPiece(kSCID, scid); | 455 out->SetStringPiece(kSCID, scid); |
502 | 456 |
503 // Calculate the mutual algorithms that the connection is going to use. | 457 // Calculate the mutual algorithms that the connection is going to use. |
504 if (scfg->GetUint16(kVERS, &out_params->version) != QUIC_NO_ERROR || | 458 if (scfg->GetUint16(kVERS, &out_params->version) != QUIC_NO_ERROR || |
505 out_params->version != kVersion) { | 459 out_params->version != QuicCryptoConfig::CONFIG_VERSION) { |
506 if (error_details) { | 460 *error_details = "Bad version"; |
507 *error_details = "Bad version"; | 461 return QUIC_CRYPTO_VERSION_NOT_SUPPORTED; |
508 } | |
509 return QUIC_VERSION_NOT_SUPPORTED; | |
510 } | 462 } |
511 | 463 |
512 const CryptoTag* their_aeads; | 464 const CryptoTag* their_aeads; |
513 const CryptoTag* their_key_exchanges; | 465 const CryptoTag* their_key_exchanges; |
514 size_t num_their_aeads, num_their_key_exchanges; | 466 size_t num_their_aeads, num_their_key_exchanges; |
515 if (scfg->GetTaglist(kAEAD, &their_aeads, | 467 if (scfg->GetTaglist(kAEAD, &their_aeads, |
516 &num_their_aeads) != QUIC_NO_ERROR || | 468 &num_their_aeads) != QUIC_NO_ERROR || |
517 scfg->GetTaglist(kKEXS, &their_key_exchanges, | 469 scfg->GetTaglist(kKEXS, &their_key_exchanges, |
518 &num_their_key_exchanges) != QUIC_NO_ERROR) { | 470 &num_their_key_exchanges) != QUIC_NO_ERROR) { |
519 if (error_details) { | 471 *error_details = "Missing AEAD or KEXS"; |
520 *error_details = "Missing AEAD or KEXS"; | |
521 } | |
522 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 472 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
523 } | 473 } |
524 | 474 |
525 size_t key_exchange_index; | 475 size_t key_exchange_index; |
526 if (!CryptoUtils::FindMutualTag(aead, | 476 if (!CryptoUtils::FindMutualTag(aead, |
527 their_aeads, num_their_aeads, | 477 their_aeads, num_their_aeads, |
528 CryptoUtils::PEER_PRIORITY, | 478 CryptoUtils::PEER_PRIORITY, |
529 &out_params->aead, | 479 &out_params->aead, |
530 NULL) || | 480 NULL) || |
531 !CryptoUtils::FindMutualTag(kexs, | 481 !CryptoUtils::FindMutualTag(kexs, |
532 their_key_exchanges, num_their_key_exchanges, | 482 their_key_exchanges, num_their_key_exchanges, |
533 CryptoUtils::PEER_PRIORITY, | 483 CryptoUtils::PEER_PRIORITY, |
534 &out_params->key_exchange, | 484 &out_params->key_exchange, |
535 &key_exchange_index)) { | 485 &key_exchange_index)) { |
536 if (error_details) { | 486 *error_details = "Unsupported AEAD or KEXS"; |
537 *error_details = "Unsupported AEAD or KEXS"; | |
538 } | |
539 return QUIC_CRYPTO_NO_SUPPORT; | 487 return QUIC_CRYPTO_NO_SUPPORT; |
540 } | 488 } |
541 out->SetTaglist(kAEAD, out_params->aead, 0); | 489 out->SetTaglist(kAEAD, out_params->aead, 0); |
542 out->SetTaglist(kKEXS, out_params->key_exchange, 0); | 490 out->SetTaglist(kKEXS, out_params->key_exchange, 0); |
543 | 491 |
544 StringPiece public_value; | 492 StringPiece public_value; |
545 if (scfg->GetNthValue16(kPUBS, key_exchange_index, &public_value) != | 493 if (scfg->GetNthValue16(kPUBS, key_exchange_index, &public_value) != |
546 QUIC_NO_ERROR) { | 494 QUIC_NO_ERROR) { |
547 if (error_details) { | 495 *error_details = "Missing public value"; |
548 *error_details = "Missing public value"; | |
549 } | |
550 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 496 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
551 } | 497 } |
552 | 498 |
553 StringPiece orbit; | 499 StringPiece orbit; |
554 if (!scfg->GetStringPiece(kORBT, &orbit) || | 500 if (!scfg->GetStringPiece(kORBT, &orbit) || |
555 orbit.size() != kOrbitSize) { | 501 orbit.size() != kOrbitSize) { |
556 if (error_details) { | 502 *error_details = "SCFG missing OBIT"; |
557 *error_details = "SCFG missing OBIT"; | |
558 } | |
559 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 503 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
560 } | 504 } |
561 | 505 |
562 string nonce; | 506 string nonce; |
563 CryptoUtils::GenerateNonce(clock->NowAsDeltaSinceUnixEpoch(), rand, orbit, | 507 CryptoUtils::GenerateNonce(clock->NowAsDeltaSinceUnixEpoch(), rand, orbit, |
564 &nonce); | 508 &nonce); |
565 out->SetStringPiece(kNONC, nonce); | 509 out->SetStringPiece(kNONC, nonce); |
566 | 510 |
567 scoped_ptr<KeyExchange> key_exchange; | 511 scoped_ptr<KeyExchange> key_exchange; |
568 switch (out_params->key_exchange) { | 512 switch (out_params->key_exchange) { |
569 case kC255: | 513 case kC255: |
570 key_exchange.reset(Curve25519KeyExchange::New( | 514 key_exchange.reset(Curve25519KeyExchange::New( |
571 Curve25519KeyExchange::NewPrivateKey(rand))); | 515 Curve25519KeyExchange::NewPrivateKey(rand))); |
572 break; | 516 break; |
573 case kP256: | 517 case kP256: |
574 key_exchange.reset(P256KeyExchange::New( | 518 key_exchange.reset(P256KeyExchange::New( |
575 P256KeyExchange::NewPrivateKey())); | 519 P256KeyExchange::NewPrivateKey())); |
576 break; | 520 break; |
577 default: | 521 default: |
578 DCHECK(false); | 522 DCHECK(false); |
579 if (error_details) { | 523 *error_details = "Configured to support an unknown key exchange"; |
580 *error_details = "Configured to support an unknown key exchange"; | |
581 } | |
582 return QUIC_CRYPTO_INTERNAL_ERROR; | 524 return QUIC_CRYPTO_INTERNAL_ERROR; |
583 } | 525 } |
584 | 526 |
585 if (!key_exchange->CalculateSharedKey(public_value, | 527 if (!key_exchange->CalculateSharedKey(public_value, |
586 &out_params->premaster_secret)) { | 528 &out_params->premaster_secret)) { |
587 if (error_details) { | 529 *error_details = "Key exchange failure"; |
588 *error_details = "Key exchange failure"; | |
589 } | |
590 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 530 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
591 } | 531 } |
592 out->SetStringPiece(kPUBS, key_exchange->public_value()); | 532 out->SetStringPiece(kPUBS, key_exchange->public_value()); |
593 | 533 |
594 string hkdf_input(kLabel, arraysize(kLabel)); | 534 string hkdf_input(QuicCryptoConfig::kLabel, |
| 535 strlen(QuicCryptoConfig::kLabel) + 1); |
595 hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid)); | 536 hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid)); |
596 | 537 |
597 const QuicData& client_hello_serialized = out->GetSerialized(); | 538 const QuicData& client_hello_serialized = out->GetSerialized(); |
598 hkdf_input.append(client_hello_serialized.data(), | 539 hkdf_input.append(client_hello_serialized.data(), |
599 client_hello_serialized.length()); | 540 client_hello_serialized.length()); |
600 hkdf_input.append(cached->server_config()); | 541 hkdf_input.append(cached->server_config()); |
601 | 542 |
602 CryptoUtils::DeriveKeys(out_params, nonce, hkdf_input, CryptoUtils::CLIENT); | 543 CryptoUtils::DeriveKeys(out_params, nonce, hkdf_input, CryptoUtils::CLIENT); |
603 | 544 |
604 return QUIC_NO_ERROR; | 545 return QUIC_NO_ERROR; |
605 } | 546 } |
606 | 547 |
607 QuicErrorCode QuicCryptoClientConfig::ProcessRejection( | 548 QuicErrorCode QuicCryptoClientConfig::ProcessRejection( |
608 const string& server_hostname, | 549 const string& server_hostname, |
609 const CryptoHandshakeMessage& rej, | 550 const CryptoHandshakeMessage& rej, |
610 QuicCryptoNegotiatedParameters* out_params, | 551 QuicCryptoNegotiatedParameters* out_params, |
611 string* error_details) { | 552 string* error_details) { |
| 553 DCHECK(error_details != NULL); |
| 554 |
612 CachedState* cached; | 555 CachedState* cached; |
613 | |
614 map<string, CachedState*>::const_iterator it = | 556 map<string, CachedState*>::const_iterator it = |
615 cached_states_.find(server_hostname); | 557 cached_states_.find(server_hostname); |
616 if (it == cached_states_.end()) { | 558 if (it == cached_states_.end()) { |
617 cached = new CachedState; | 559 cached = new CachedState; |
618 cached_states_[server_hostname] = cached; | 560 cached_states_[server_hostname] = cached; |
619 } else { | 561 } else { |
620 cached = it->second; | 562 cached = it->second; |
621 } | 563 } |
622 | 564 |
623 StringPiece scfg; | 565 StringPiece scfg; |
624 if (!rej.GetStringPiece(kSCFG, &scfg)) { | 566 if (!rej.GetStringPiece(kSCFG, &scfg)) { |
625 if (error_details) { | 567 *error_details = "Missing SCFG"; |
626 *error_details = "Missing SCFG"; | |
627 } | |
628 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 568 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
629 } | 569 } |
630 | 570 |
631 if (!cached->SetServerConfig(scfg)) { | 571 if (!cached->SetServerConfig(scfg)) { |
632 if (error_details) { | 572 *error_details = "Invalid SCFG"; |
633 *error_details = "Invalid SCFG"; | |
634 } | |
635 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 573 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
636 } | 574 } |
637 | 575 |
638 StringPiece token; | 576 StringPiece token; |
639 if (rej.GetStringPiece(kSRCT, &token)) { | 577 if (rej.GetStringPiece(kSRCT, &token)) { |
640 cached->set_source_address_token(token); | 578 cached->set_source_address_token(token); |
641 } | 579 } |
642 | 580 |
643 StringPiece nonce; | 581 StringPiece nonce; |
644 if (rej.GetStringPiece(kNONC, &nonce) && | 582 if (rej.GetStringPiece(kNONC, &nonce) && |
645 nonce.size() == kNonceSize) { | 583 nonce.size() == kNonceSize) { |
646 out_params->server_nonce = nonce.as_string(); | 584 out_params->server_nonce = nonce.as_string(); |
647 } | 585 } |
648 | 586 |
649 return QUIC_NO_ERROR; | 587 return QUIC_NO_ERROR; |
650 } | 588 } |
651 | 589 |
652 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( | 590 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( |
653 const CryptoHandshakeMessage& server_hello, | 591 const CryptoHandshakeMessage& server_hello, |
654 const string& nonce, | 592 const string& nonce, |
655 QuicCryptoNegotiatedParameters* out_params, | 593 QuicCryptoNegotiatedParameters* out_params, |
656 string* error_details) { | 594 string* error_details) { |
| 595 DCHECK(error_details != NULL); |
| 596 |
657 if (server_hello.tag() != kSHLO) { | 597 if (server_hello.tag() != kSHLO) { |
658 *error_details = "Bad tag"; | 598 *error_details = "Bad tag"; |
659 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE; | 599 return QUIC_INVALID_CRYPTO_MESSAGE_TYPE; |
660 } | 600 } |
661 | 601 |
662 // TODO(agl): | 602 // TODO(agl): |
663 // learn about updated SCFGs. | 603 // learn about updated SCFGs. |
664 // read ephemeral public value for forward-secret keys. | 604 // read ephemeral public value for forward-secret keys. |
665 | 605 |
666 return QUIC_NO_ERROR; | 606 return QUIC_NO_ERROR; |
667 } | 607 } |
668 | 608 |
669 // static | |
670 const char QuicCryptoServerConfig::TESTING[] = "secret string for testing"; | |
671 | |
672 QuicCryptoServerConfig::QuicCryptoServerConfig( | |
673 StringPiece source_address_token_secret) | |
674 // AES-GCM is used to encrypt and authenticate source address tokens. The | |
675 // full, 96-bit nonce is used but we must ensure that an attacker cannot | |
676 // obtain two source address tokens with the same nonce. This occurs with | |
677 // probability 0.5 after 2**48 values. We assume that obtaining 2**48 | |
678 // source address tokens is not possible: at a rate of 10M packets per | |
679 // second, it would still take the attacker a year to obtain the needed | |
680 // number of packets. | |
681 // | |
682 // TODO(agl): switch to an encrypter with a larger nonce space (i.e. | |
683 // Salsa20+Poly1305). | |
684 : strike_register_lock_(), | |
685 source_address_token_encrypter_(new Aes128GcmEncrypter), | |
686 source_address_token_decrypter_(new Aes128GcmDecrypter) { | |
687 crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */, | |
688 "QUIC source address token key", | |
689 source_address_token_encrypter_->GetKeySize(), | |
690 0 /* no fixed IV needed */); | |
691 source_address_token_encrypter_->SetKey(hkdf.server_write_key()); | |
692 source_address_token_decrypter_->SetKey(hkdf.server_write_key()); | |
693 } | |
694 | |
695 QuicCryptoServerConfig::~QuicCryptoServerConfig() { | |
696 STLDeleteValues(&configs_); | |
697 } | |
698 | |
699 // static | |
700 QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig( | |
701 QuicRandom* rand, | |
702 const QuicClock* clock, | |
703 const CryptoHandshakeMessage& extra_tags) { | |
704 CryptoHandshakeMessage msg; | |
705 | |
706 const string curve25519_private_key = | |
707 Curve25519KeyExchange::NewPrivateKey(rand); | |
708 scoped_ptr<Curve25519KeyExchange> curve25519( | |
709 Curve25519KeyExchange::New(curve25519_private_key)); | |
710 StringPiece curve25519_public_value = curve25519->public_value(); | |
711 | |
712 const string p256_private_key = | |
713 P256KeyExchange::NewPrivateKey(); | |
714 scoped_ptr<P256KeyExchange> p256( | |
715 P256KeyExchange::New(p256_private_key)); | |
716 StringPiece p256_public_value = p256->public_value(); | |
717 | |
718 string encoded_public_values; | |
719 // First two bytes encode the length of the public value. | |
720 encoded_public_values.push_back(curve25519_public_value.size()); | |
721 encoded_public_values.push_back(curve25519_public_value.size() >> 8); | |
722 encoded_public_values.append(curve25519_public_value.data(), | |
723 curve25519_public_value.size()); | |
724 encoded_public_values.push_back(p256_public_value.size()); | |
725 encoded_public_values.push_back(p256_public_value.size() >> 8); | |
726 encoded_public_values.append(p256_public_value.data(), | |
727 p256_public_value.size()); | |
728 | |
729 msg.set_tag(kSCFG); | |
730 msg.SetTaglist(kKEXS, kC255, kP256, 0); | |
731 msg.SetTaglist(kAEAD, kAESG, 0); | |
732 msg.SetValue(kVERS, static_cast<uint16>(0)); | |
733 msg.SetStringPiece(kPUBS, encoded_public_values); | |
734 msg.Insert(extra_tags.tag_value_map().begin(), | |
735 extra_tags.tag_value_map().end()); | |
736 | |
737 char scid_bytes[16]; | |
738 rand->RandBytes(scid_bytes, sizeof(scid_bytes)); | |
739 msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes))); | |
740 | |
741 char orbit_bytes[kOrbitSize]; | |
742 rand->RandBytes(orbit_bytes, sizeof(orbit_bytes)); | |
743 msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes))); | |
744 | |
745 scoped_ptr<QuicData> serialized( | |
746 CryptoFramer::ConstructHandshakeMessage(msg)); | |
747 | |
748 scoped_ptr<QuicServerConfigProtobuf> config(new QuicServerConfigProtobuf); | |
749 config->set_config(serialized->AsStringPiece()); | |
750 QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key(); | |
751 curve25519_key->set_tag(kC255); | |
752 curve25519_key->set_private_key(curve25519_private_key); | |
753 QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key(); | |
754 p256_key->set_tag(kP256); | |
755 p256_key->set_private_key(p256_private_key); | |
756 | |
757 return config.release(); | |
758 } | |
759 | |
760 CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( | |
761 QuicServerConfigProtobuf* protobuf) { | |
762 scoped_ptr<CryptoHandshakeMessage> msg( | |
763 CryptoFramer::ParseMessage(protobuf->config())); | |
764 | |
765 if (!msg.get()) { | |
766 LOG(WARNING) << "Failed to parse server config message"; | |
767 return NULL; | |
768 } | |
769 if (msg->tag() != kSCFG) { | |
770 LOG(WARNING) << "Server config message has tag " | |
771 << msg->tag() << " expected " | |
772 << kSCFG; | |
773 return NULL; | |
774 } | |
775 | |
776 scoped_ptr<Config> config(new Config); | |
777 config->serialized = protobuf->config(); | |
778 | |
779 StringPiece scid; | |
780 if (!msg->GetStringPiece(kSCID, &scid)) { | |
781 LOG(WARNING) << "Server config message is missing SCID"; | |
782 return NULL; | |
783 } | |
784 config->id = scid.as_string(); | |
785 | |
786 const CryptoTag* aead_tags; | |
787 size_t aead_len; | |
788 if (msg->GetTaglist(kAEAD, &aead_tags, &aead_len) != QUIC_NO_ERROR) { | |
789 LOG(WARNING) << "Server config message is missing AEAD"; | |
790 return NULL; | |
791 } | |
792 config->aead = vector<CryptoTag>(aead_tags, aead_tags + aead_len); | |
793 | |
794 const CryptoTag* kexs_tags; | |
795 size_t kexs_len; | |
796 if (msg->GetTaglist(kKEXS, &kexs_tags, &kexs_len) != QUIC_NO_ERROR) { | |
797 LOG(WARNING) << "Server config message is missing KEXS"; | |
798 return NULL; | |
799 } | |
800 | |
801 StringPiece orbit; | |
802 if (!msg->GetStringPiece(kORBT, &orbit)) { | |
803 LOG(WARNING) << "Server config message is missing OBIT"; | |
804 return NULL; | |
805 } | |
806 | |
807 if (orbit.size() != kOrbitSize) { | |
808 LOG(WARNING) << "Orbit value in server config is the wrong length." | |
809 " Got " << orbit.size() << " want " << kOrbitSize; | |
810 return NULL; | |
811 } | |
812 COMPILE_ASSERT(sizeof(config->orbit) == kOrbitSize, orbit_incorrect_size); | |
813 memcpy(config->orbit, orbit.data(), sizeof(config->orbit)); | |
814 | |
815 if (kexs_len != protobuf->key_size()) { | |
816 LOG(WARNING) << "Server config has " | |
817 << kexs_len | |
818 << " key exchange methods configured, but " | |
819 << protobuf->key_size() | |
820 << " private keys"; | |
821 return NULL; | |
822 } | |
823 | |
824 for (size_t i = 0; i < kexs_len; i++) { | |
825 const CryptoTag tag = kexs_tags[i]; | |
826 string private_key; | |
827 | |
828 config->kexs.push_back(tag); | |
829 | |
830 for (size_t j = 0; j < protobuf->key_size(); j++) { | |
831 const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i); | |
832 if (key.tag() == tag) { | |
833 private_key = key.private_key(); | |
834 break; | |
835 } | |
836 } | |
837 | |
838 if (private_key.empty()) { | |
839 LOG(WARNING) << "Server config contains key exchange method without " | |
840 "corresponding private key: " | |
841 << tag; | |
842 return NULL; | |
843 } | |
844 | |
845 scoped_ptr<KeyExchange> ka; | |
846 switch (tag) { | |
847 case kC255: | |
848 ka.reset(Curve25519KeyExchange::New(private_key)); | |
849 if (!ka.get()) { | |
850 LOG(WARNING) << "Server config contained an invalid curve25519" | |
851 " private key."; | |
852 return NULL; | |
853 } | |
854 break; | |
855 case kP256: | |
856 ka.reset(P256KeyExchange::New(private_key)); | |
857 if (!ka.get()) { | |
858 LOG(WARNING) << "Server config contained an invalid P-256" | |
859 " private key."; | |
860 return NULL; | |
861 } | |
862 break; | |
863 default: | |
864 LOG(WARNING) << "Server config message contains unknown key exchange " | |
865 "method: " | |
866 << tag; | |
867 return NULL; | |
868 } | |
869 | |
870 for (vector<KeyExchange*>::const_iterator i = config->key_exchanges.begin(); | |
871 i != config->key_exchanges.end(); ++i) { | |
872 if ((*i)->tag() == tag) { | |
873 LOG(WARNING) << "Duplicate key exchange in config: " << tag; | |
874 return NULL; | |
875 } | |
876 } | |
877 | |
878 config->key_exchanges.push_back(ka.release()); | |
879 } | |
880 | |
881 if (msg->GetUint16(kVERS, &config->version) != QUIC_NO_ERROR) { | |
882 LOG(WARNING) << "Server config message is missing version"; | |
883 return NULL; | |
884 } | |
885 | |
886 if (config->version != kVersion) { | |
887 LOG(WARNING) << "Server config specifies an unsupported version"; | |
888 return NULL; | |
889 } | |
890 | |
891 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256)); | |
892 sha256->Update(protobuf->config().data(), protobuf->config().size()); | |
893 char id_bytes[16]; | |
894 sha256->Finish(id_bytes, sizeof(id_bytes)); | |
895 const string id(id_bytes, sizeof(id_bytes)); | |
896 | |
897 configs_[id] = config.release(); | |
898 active_config_ = id; | |
899 | |
900 return msg.release(); | |
901 } | |
902 | |
903 CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig( | |
904 QuicRandom* rand, | |
905 const QuicClock* clock, | |
906 const CryptoHandshakeMessage& extra_tags) { | |
907 scoped_ptr<QuicServerConfigProtobuf> config(DefaultConfig( | |
908 rand, clock, extra_tags)); | |
909 return AddConfig(config.get()); | |
910 } | |
911 | |
912 QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( | |
913 const CryptoHandshakeMessage& client_hello, | |
914 QuicGuid guid, | |
915 const IPEndPoint& client_ip, | |
916 QuicTime::Delta now_since_unix_epoch, | |
917 QuicRandom* rand, | |
918 QuicCryptoNegotiatedParameters *params, | |
919 CryptoHandshakeMessage* out, | |
920 string* error_details) const { | |
921 CHECK(!configs_.empty()); | |
922 // FIXME(agl): we should use the client's SCID, not just the active config. | |
923 map<ServerConfigID, Config*>::const_iterator it = | |
924 configs_.find(active_config_); | |
925 if (it == configs_.end()) { | |
926 *error_details = "No valid server config loaded"; | |
927 return QUIC_CRYPTO_INTERNAL_ERROR; | |
928 } | |
929 const Config* const config(it->second); | |
930 | |
931 bool valid_source_address_token = false; | |
932 StringPiece srct; | |
933 if (client_hello.GetStringPiece(kSRCT, &srct) && | |
934 ValidateSourceAddressToken(srct, client_ip, now_since_unix_epoch)) { | |
935 valid_source_address_token = true; | |
936 } | |
937 | |
938 const string fresh_source_address_token = | |
939 NewSourceAddressToken(client_ip, rand, now_since_unix_epoch); | |
940 | |
941 // If we previously sent a REJ to this client then we may have stored a | |
942 // server nonce in |params|. In which case, we know that the connection | |
943 // is unique because the server nonce will be mixed into the key generation. | |
944 bool unique_by_server_nonce = !params->server_nonce.empty(); | |
945 // If we can't ensure uniqueness by a server nonce, then we will try and use | |
946 // the strike register. | |
947 bool unique_by_strike_register = false; | |
948 | |
949 StringPiece client_nonce; | |
950 bool client_nonce_well_formed = false; | |
951 if (client_hello.GetStringPiece(kNONC, &client_nonce) && | |
952 client_nonce.size() == kNonceSize) { | |
953 client_nonce_well_formed = true; | |
954 if (!unique_by_server_nonce) { | |
955 base::AutoLock auto_lock(strike_register_lock_); | |
956 | |
957 if (strike_register_.get() == NULL) { | |
958 strike_register_.reset(new StrikeRegister( | |
959 // TODO(agl): these magic numbers should come from config. | |
960 1024 /* max entries */, | |
961 static_cast<uint32>(now_since_unix_epoch.ToSeconds()), | |
962 600 /* window secs */, config->orbit)); | |
963 } | |
964 unique_by_strike_register = strike_register_->Insert( | |
965 reinterpret_cast<const uint8*>(client_nonce.data()), | |
966 static_cast<uint32>(now_since_unix_epoch.ToSeconds())); | |
967 } | |
968 } | |
969 | |
970 StringPiece scid; | |
971 if (!client_hello.GetStringPiece(kSCID, &scid) || | |
972 scid.as_string() != config->id || | |
973 !valid_source_address_token || | |
974 !client_nonce_well_formed || | |
975 (!unique_by_strike_register && | |
976 !unique_by_server_nonce)) { | |
977 // If the client didn't provide a server config ID, or gave the wrong one, | |
978 // then the handshake cannot possibly complete. We reject the handshake and | |
979 // give the client enough information to do better next time. | |
980 out->Clear(); | |
981 out->set_tag(kREJ); | |
982 out->SetStringPiece(kSCFG, config->serialized); | |
983 out->SetStringPiece(kSRCT, fresh_source_address_token); | |
984 if (params->server_nonce.empty()) { | |
985 CryptoUtils::GenerateNonce( | |
986 now_since_unix_epoch, rand, | |
987 StringPiece(reinterpret_cast<const char*>(config->orbit), | |
988 sizeof(config->orbit)), | |
989 ¶ms->server_nonce); | |
990 } | |
991 out->SetStringPiece(kNONC, params->server_nonce); | |
992 return QUIC_NO_ERROR; | |
993 } | |
994 | |
995 const CryptoTag* their_aeads; | |
996 const CryptoTag* their_key_exchanges; | |
997 size_t num_their_aeads, num_their_key_exchanges; | |
998 if (client_hello.GetTaglist(kAEAD, &their_aeads, | |
999 &num_their_aeads) != QUIC_NO_ERROR || | |
1000 client_hello.GetTaglist(kKEXS, &their_key_exchanges, | |
1001 &num_their_key_exchanges) != QUIC_NO_ERROR || | |
1002 num_their_aeads != 1 || | |
1003 num_their_key_exchanges != 1) { | |
1004 if (error_details) { | |
1005 *error_details = "Missing or invalid AEAD or KEXS"; | |
1006 } | |
1007 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
1008 } | |
1009 | |
1010 size_t key_exchange_index; | |
1011 if (!CryptoUtils::FindMutualTag(config->aead, | |
1012 their_aeads, num_their_aeads, | |
1013 CryptoUtils::LOCAL_PRIORITY, | |
1014 ¶ms->aead, | |
1015 NULL) || | |
1016 !CryptoUtils::FindMutualTag(config->kexs, | |
1017 their_key_exchanges, num_their_key_exchanges, | |
1018 CryptoUtils::LOCAL_PRIORITY, | |
1019 ¶ms->key_exchange, | |
1020 &key_exchange_index)) { | |
1021 if (error_details) { | |
1022 *error_details = "Unsupported AEAD or KEXS"; | |
1023 } | |
1024 return QUIC_CRYPTO_NO_SUPPORT; | |
1025 } | |
1026 | |
1027 StringPiece public_value; | |
1028 if (!client_hello.GetStringPiece(kPUBS, &public_value)) { | |
1029 if (error_details) { | |
1030 *error_details = "Missing public value"; | |
1031 } | |
1032 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
1033 } | |
1034 | |
1035 if (!config->key_exchanges[key_exchange_index]->CalculateSharedKey( | |
1036 public_value, ¶ms->premaster_secret)) { | |
1037 if (error_details) { | |
1038 *error_details = "Invalid public value"; | |
1039 } | |
1040 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | |
1041 } | |
1042 | |
1043 params->server_config_id = scid.as_string(); | |
1044 | |
1045 string hkdf_input(kLabel, arraysize(kLabel)); | |
1046 hkdf_input.append(reinterpret_cast<char*>(&guid), sizeof(guid)); | |
1047 | |
1048 const QuicData& client_hello_serialized = client_hello.GetSerialized(); | |
1049 hkdf_input.append(client_hello_serialized.data(), | |
1050 client_hello_serialized.length()); | |
1051 hkdf_input.append(config->serialized); | |
1052 | |
1053 CryptoUtils::DeriveKeys(params, client_nonce, hkdf_input, | |
1054 CryptoUtils::SERVER); | |
1055 | |
1056 out->set_tag(kSHLO); | |
1057 out->SetStringPiece(kSRCT, fresh_source_address_token); | |
1058 return QUIC_NO_ERROR; | |
1059 } | |
1060 | |
1061 string QuicCryptoServerConfig::NewSourceAddressToken( | |
1062 const IPEndPoint& ip, | |
1063 QuicRandom* rand, | |
1064 QuicTime::Delta now_since_epoch) const { | |
1065 SourceAddressToken source_address_token; | |
1066 source_address_token.set_ip(ip.ToString()); | |
1067 source_address_token.set_timestamp(now_since_epoch.ToSeconds()); | |
1068 | |
1069 string plaintext = source_address_token.SerializeAsString(); | |
1070 char nonce[12]; | |
1071 DCHECK_EQ(sizeof(nonce), | |
1072 source_address_token_encrypter_->GetNoncePrefixSize() + | |
1073 sizeof(QuicPacketSequenceNumber)); | |
1074 rand->RandBytes(nonce, sizeof(nonce)); | |
1075 | |
1076 size_t ciphertext_size = | |
1077 source_address_token_encrypter_->GetCiphertextSize(plaintext.size()); | |
1078 string result; | |
1079 result.resize(sizeof(nonce) + ciphertext_size); | |
1080 memcpy(&result[0], &nonce, sizeof(nonce)); | |
1081 | |
1082 if (!source_address_token_encrypter_->Encrypt( | |
1083 StringPiece(nonce, sizeof(nonce)), StringPiece(), plaintext, | |
1084 reinterpret_cast<unsigned char*>(&result[sizeof(nonce)]))) { | |
1085 DCHECK(false); | |
1086 return string(); | |
1087 } | |
1088 | |
1089 return result; | |
1090 } | |
1091 | |
1092 bool QuicCryptoServerConfig::ValidateSourceAddressToken( | |
1093 StringPiece token, | |
1094 const IPEndPoint& ip, | |
1095 QuicTime::Delta now_since_epoch) const { | |
1096 char nonce[12]; | |
1097 DCHECK_EQ(sizeof(nonce), | |
1098 source_address_token_encrypter_->GetNoncePrefixSize() + | |
1099 sizeof(QuicPacketSequenceNumber)); | |
1100 | |
1101 if (token.size() <= sizeof(nonce)) { | |
1102 return false; | |
1103 } | |
1104 memcpy(&nonce, token.data(), sizeof(nonce)); | |
1105 token.remove_prefix(sizeof(nonce)); | |
1106 | |
1107 unsigned char plaintext_stack[128]; | |
1108 scoped_ptr<unsigned char[]> plaintext_heap; | |
1109 unsigned char* plaintext; | |
1110 if (token.size() <= sizeof(plaintext_stack)) { | |
1111 plaintext = plaintext_stack; | |
1112 } else { | |
1113 plaintext_heap.reset(new unsigned char[token.size()]); | |
1114 plaintext = plaintext_heap.get(); | |
1115 } | |
1116 size_t plaintext_length; | |
1117 | |
1118 if (!source_address_token_decrypter_->Decrypt( | |
1119 StringPiece(nonce, sizeof(nonce)), StringPiece(), token, | |
1120 plaintext, &plaintext_length)) { | |
1121 return false; | |
1122 } | |
1123 | |
1124 SourceAddressToken source_address_token; | |
1125 if (!source_address_token.ParseFromArray(plaintext, plaintext_length)) { | |
1126 return false; | |
1127 } | |
1128 | |
1129 if (source_address_token.ip() != ip.ToString()) { | |
1130 // It's for a different IP address. | |
1131 return false; | |
1132 } | |
1133 | |
1134 const QuicTime::Delta delta(now_since_epoch.Subtract( | |
1135 QuicTime::Delta::FromSeconds(source_address_token.timestamp()))); | |
1136 const int64 delta_secs = delta.ToSeconds(); | |
1137 | |
1138 // TODO(agl): consider whether and how these magic values should be moved to | |
1139 // a config. | |
1140 if (delta_secs < -3600) { | |
1141 // We only allow timestamps to be from an hour in the future. | |
1142 return false; | |
1143 } | |
1144 | |
1145 if (delta_secs > 86400) { | |
1146 // We allow one day into the past. | |
1147 return false; | |
1148 } | |
1149 | |
1150 return true; | |
1151 } | |
1152 | |
1153 QuicCryptoServerConfig::Config::Config() { | |
1154 } | |
1155 | |
1156 QuicCryptoServerConfig::Config::~Config() { | |
1157 STLDeleteElements(&key_exchanges); | |
1158 } | |
1159 | |
1160 } // namespace net | 609 } // namespace net |
OLD | NEW |