| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/quic_crypto_client_config.h" | 5 #include "net/quic/crypto/quic_crypto_client_config.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
| 8 #include "base/metrics/sparse_histogram.h" | 8 #include "base/metrics/sparse_histogram.h" |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 // Tracks the state of the QUIC server information loaded from the disk cache. | 43 // Tracks the state of the QUIC server information loaded from the disk cache. |
| 44 void RecordDiskCacheServerConfigState( | 44 void RecordDiskCacheServerConfigState( |
| 45 QuicCryptoClientConfig::CachedState::ServerConfigState state) { | 45 QuicCryptoClientConfig::CachedState::ServerConfigState state) { |
| 46 UMA_HISTOGRAM_ENUMERATION( | 46 UMA_HISTOGRAM_ENUMERATION( |
| 47 "Net.QuicServerInfo.DiskCacheState", state, | 47 "Net.QuicServerInfo.DiskCacheState", state, |
| 48 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT); | 48 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT); |
| 49 } | 49 } |
| 50 | 50 |
| 51 } // namespace | 51 } // namespace |
| 52 | 52 |
| 53 QuicCryptoClientConfig::QuicCryptoClientConfig() | 53 QuicCryptoClientConfig::QuicCryptoClientConfig(ProofVerifier* proof_verifier) |
| 54 : disable_ecdsa_(false) { | 54 : proof_verifier_(proof_verifier), |
| 55 disable_ecdsa_(false) { |
| 56 DCHECK(proof_verifier_.get()); |
| 55 SetDefaults(); | 57 SetDefaults(); |
| 56 } | 58 } |
| 57 | 59 |
| 58 QuicCryptoClientConfig::~QuicCryptoClientConfig() { | 60 QuicCryptoClientConfig::~QuicCryptoClientConfig() { |
| 59 STLDeleteValues(&cached_states_); | 61 STLDeleteValues(&cached_states_); |
| 60 } | 62 } |
| 61 | 63 |
| 62 QuicCryptoClientConfig::CachedState::CachedState() | 64 QuicCryptoClientConfig::CachedState::CachedState() |
| 63 : server_config_valid_(false), | 65 : server_config_valid_(false), |
| 64 generation_counter_(0) {} | 66 generation_counter_(0) {} |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 out->SetValue(kVER, QuicVersionToQuicTag(preferred_version)); | 403 out->SetValue(kVER, QuicVersionToQuicTag(preferred_version)); |
| 402 | 404 |
| 403 if (!user_agent_id_.empty()) { | 405 if (!user_agent_id_.empty()) { |
| 404 out->SetStringPiece(kUAID, user_agent_id_); | 406 out->SetStringPiece(kUAID, user_agent_id_); |
| 405 } | 407 } |
| 406 | 408 |
| 407 if (!cached->source_address_token().empty()) { | 409 if (!cached->source_address_token().empty()) { |
| 408 out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token()); | 410 out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token()); |
| 409 } | 411 } |
| 410 | 412 |
| 411 if (server_id.is_https()) { | 413 if (disable_ecdsa_) { |
| 412 if (disable_ecdsa_) { | 414 out->SetTaglist(kPDMD, kX59R, 0); |
| 413 out->SetTaglist(kPDMD, kX59R, 0); | 415 } else { |
| 414 } else { | 416 out->SetTaglist(kPDMD, kX509, 0); |
| 415 out->SetTaglist(kPDMD, kX509, 0); | |
| 416 } | |
| 417 } | 417 } |
| 418 | 418 |
| 419 if (common_cert_sets) { | 419 if (common_cert_sets) { |
| 420 out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes()); | 420 out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes()); |
| 421 } | 421 } |
| 422 | 422 |
| 423 const vector<string>& certs = cached->certs(); | 423 const vector<string>& certs = cached->certs(); |
| 424 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the | 424 // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the |
| 425 // client config is being used for multiple connections, another connection | 425 // client config is being used for multiple connections, another connection |
| 426 // doesn't update the cached certificates and cause us to be unable to | 426 // doesn't update the cached certificates and cause us to be unable to |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 533 } | 533 } |
| 534 | 534 |
| 535 if (!out_params->client_key_exchange->CalculateSharedKey( | 535 if (!out_params->client_key_exchange->CalculateSharedKey( |
| 536 public_value, &out_params->initial_premaster_secret)) { | 536 public_value, &out_params->initial_premaster_secret)) { |
| 537 *error_details = "Key exchange failure"; | 537 *error_details = "Key exchange failure"; |
| 538 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 538 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 539 } | 539 } |
| 540 out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value()); | 540 out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value()); |
| 541 | 541 |
| 542 const vector<string>& certs = cached->certs(); | 542 const vector<string>& certs = cached->certs(); |
| 543 if (preferred_version > QUIC_VERSION_25 && proof_verifier()) { | 543 if (preferred_version > QUIC_VERSION_25) { |
| 544 if (certs.empty()) { | 544 if (certs.empty()) { |
| 545 *error_details = "No certs to calculate XLCT"; | 545 *error_details = "No certs to calculate XLCT"; |
| 546 return QUIC_CRYPTO_INTERNAL_ERROR; | 546 return QUIC_CRYPTO_INTERNAL_ERROR; |
| 547 } | 547 } |
| 548 out->SetValue(kXLCT, CryptoUtils::ComputeLeafCertHash(certs[0])); | 548 out->SetValue(kXLCT, CryptoUtils::ComputeLeafCertHash(certs[0])); |
| 549 } | 549 } |
| 550 | 550 |
| 551 if (channel_id_key) { | 551 if (channel_id_key) { |
| 552 // In order to calculate the encryption key for the CETV block we need to | 552 // In order to calculate the encryption key for the CETV block we need to |
| 553 // serialise the client hello as it currently is (i.e. without the CETV | 553 // serialise the client hello as it currently is (i.e. without the CETV |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 610 // Set the following members of out_params: | 610 // Set the following members of out_params: |
| 611 // out_params->hkdf_input_suffix | 611 // out_params->hkdf_input_suffix |
| 612 // out_params->initial_crypters | 612 // out_params->initial_crypters |
| 613 out_params->hkdf_input_suffix.clear(); | 613 out_params->hkdf_input_suffix.clear(); |
| 614 out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&connection_id), | 614 out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&connection_id), |
| 615 sizeof(connection_id)); | 615 sizeof(connection_id)); |
| 616 const QuicData& client_hello_serialized = out->GetSerialized(); | 616 const QuicData& client_hello_serialized = out->GetSerialized(); |
| 617 out_params->hkdf_input_suffix.append(client_hello_serialized.data(), | 617 out_params->hkdf_input_suffix.append(client_hello_serialized.data(), |
| 618 client_hello_serialized.length()); | 618 client_hello_serialized.length()); |
| 619 out_params->hkdf_input_suffix.append(cached->server_config()); | 619 out_params->hkdf_input_suffix.append(cached->server_config()); |
| 620 if (preferred_version > QUIC_VERSION_25 && proof_verifier()) { | 620 if (preferred_version > QUIC_VERSION_25) { |
| 621 if (certs.empty()) { | 621 if (certs.empty()) { |
| 622 *error_details = "No certs found to include in KDF"; | 622 *error_details = "No certs found to include in KDF"; |
| 623 return QUIC_CRYPTO_INTERNAL_ERROR; | 623 return QUIC_CRYPTO_INTERNAL_ERROR; |
| 624 } | 624 } |
| 625 out_params->hkdf_input_suffix.append(certs[0]); | 625 out_params->hkdf_input_suffix.append(certs[0]); |
| 626 } | 626 } |
| 627 | 627 |
| 628 string hkdf_input; | 628 string hkdf_input; |
| 629 const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; | 629 const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; |
| 630 hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size()); | 630 hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size()); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 if (has_proof && has_cert) { | 679 if (has_proof && has_cert) { |
| 680 vector<string> certs; | 680 vector<string> certs; |
| 681 if (!CertCompressor::DecompressChain(cert_bytes, cached_certs, | 681 if (!CertCompressor::DecompressChain(cert_bytes, cached_certs, |
| 682 common_cert_sets, &certs)) { | 682 common_cert_sets, &certs)) { |
| 683 *error_details = "Certificate data invalid"; | 683 *error_details = "Certificate data invalid"; |
| 684 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 684 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 685 } | 685 } |
| 686 | 686 |
| 687 cached->SetProof(certs, proof); | 687 cached->SetProof(certs, proof); |
| 688 } else { | 688 } else { |
| 689 if (proof_verifier() != nullptr) { | 689 // Secure QUIC: clear existing proof as we have been sent a new SCFG |
| 690 // Secure QUIC: clear existing proof as we have been sent a new SCFG | 690 // without matching proof/certs. |
| 691 // without matching proof/certs. | 691 cached->ClearProof(); |
| 692 cached->ClearProof(); | |
| 693 } | |
| 694 | 692 |
| 695 if (has_proof && !has_cert) { | 693 if (has_proof && !has_cert) { |
| 696 *error_details = "Certificate missing"; | 694 *error_details = "Certificate missing"; |
| 697 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 695 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 698 } | 696 } |
| 699 | 697 |
| 700 if (!has_proof && has_cert) { | 698 if (!has_proof && has_cert) { |
| 701 *error_details = "Proof missing"; | 699 *error_details = "Proof missing"; |
| 702 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 700 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 703 } | 701 } |
| 704 } | 702 } |
| 705 | 703 |
| 706 return QUIC_NO_ERROR; | 704 return QUIC_NO_ERROR; |
| 707 } | 705 } |
| 708 | 706 |
| 709 QuicErrorCode QuicCryptoClientConfig::ProcessRejection( | 707 QuicErrorCode QuicCryptoClientConfig::ProcessRejection( |
| 710 const CryptoHandshakeMessage& rej, | 708 const CryptoHandshakeMessage& rej, |
| 711 QuicWallTime now, | 709 QuicWallTime now, |
| 712 CachedState* cached, | 710 CachedState* cached, |
| 713 bool is_https, | |
| 714 QuicCryptoNegotiatedParameters* out_params, | 711 QuicCryptoNegotiatedParameters* out_params, |
| 715 string* error_details) { | 712 string* error_details) { |
| 716 DCHECK(error_details != nullptr); | 713 DCHECK(error_details != nullptr); |
| 717 | 714 |
| 718 if ((rej.tag() != kREJ) && (rej.tag() != kSREJ)) { | 715 if ((rej.tag() != kREJ) && (rej.tag() != kSREJ)) { |
| 719 *error_details = "Message is not REJ or SREJ"; | 716 *error_details = "Message is not REJ or SREJ"; |
| 720 return QUIC_CRYPTO_INTERNAL_ERROR; | 717 return QUIC_CRYPTO_INTERNAL_ERROR; |
| 721 } | 718 } |
| 722 | 719 |
| 723 QuicErrorCode error = CacheNewServerConfig(rej, now, out_params->cached_certs, | 720 QuicErrorCode error = CacheNewServerConfig(rej, now, out_params->cached_certs, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 740 for (size_t i = 0; i < num_reject_reasons; ++i) { | 737 for (size_t i = 0; i < num_reject_reasons; ++i) { |
| 741 // HANDSHAKE_OK is 0 and don't report that as error. | 738 // HANDSHAKE_OK is 0 and don't report that as error. |
| 742 if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) { | 739 if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) { |
| 743 continue; | 740 continue; |
| 744 } | 741 } |
| 745 HandshakeFailureReason reason = | 742 HandshakeFailureReason reason = |
| 746 static_cast<HandshakeFailureReason>(reject_reasons[i]); | 743 static_cast<HandshakeFailureReason>(reject_reasons[i]); |
| 747 packed_error |= 1 << (reason - 1); | 744 packed_error |= 1 << (reason - 1); |
| 748 } | 745 } |
| 749 DVLOG(1) << "Reasons for rejection: " << packed_error; | 746 DVLOG(1) << "Reasons for rejection: " << packed_error; |
| 750 if (is_https) { | 747 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure", |
| 751 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure", | 748 packed_error); |
| 752 packed_error); | |
| 753 } else { | |
| 754 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Insecure", | |
| 755 packed_error); | |
| 756 } | |
| 757 } | 749 } |
| 758 | 750 |
| 759 if (rej.tag() == kSREJ) { | 751 if (rej.tag() == kSREJ) { |
| 760 QuicConnectionId connection_id; | 752 QuicConnectionId connection_id; |
| 761 if (rej.GetUint64(kRCID, &connection_id) != QUIC_NO_ERROR) { | 753 if (rej.GetUint64(kRCID, &connection_id) != QUIC_NO_ERROR) { |
| 762 *error_details = "Missing kRCID"; | 754 *error_details = "Missing kRCID"; |
| 763 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 755 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
| 764 } | 756 } |
| 765 cached->add_server_designated_connection_id(connection_id); | 757 cached->add_server_designated_connection_id(connection_id); |
| 766 if (!nonce.empty()) { | 758 if (!nonce.empty()) { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 871 } | 863 } |
| 872 | 864 |
| 873 return CacheNewServerConfig(server_config_update, now, | 865 return CacheNewServerConfig(server_config_update, now, |
| 874 out_params->cached_certs, cached, error_details); | 866 out_params->cached_certs, cached, error_details); |
| 875 } | 867 } |
| 876 | 868 |
| 877 ProofVerifier* QuicCryptoClientConfig::proof_verifier() const { | 869 ProofVerifier* QuicCryptoClientConfig::proof_verifier() const { |
| 878 return proof_verifier_.get(); | 870 return proof_verifier_.get(); |
| 879 } | 871 } |
| 880 | 872 |
| 881 void QuicCryptoClientConfig::SetProofVerifier(ProofVerifier* verifier) { | |
| 882 proof_verifier_.reset(verifier); | |
| 883 } | |
| 884 | |
| 885 ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const { | 873 ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const { |
| 886 return channel_id_source_.get(); | 874 return channel_id_source_.get(); |
| 887 } | 875 } |
| 888 | 876 |
| 889 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource* source) { | 877 void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource* source) { |
| 890 channel_id_source_.reset(source); | 878 channel_id_source_.reset(source); |
| 891 } | 879 } |
| 892 | 880 |
| 893 void QuicCryptoClientConfig::InitializeFrom( | 881 void QuicCryptoClientConfig::InitializeFrom( |
| 894 const QuicServerId& server_id, | 882 const QuicServerId& server_id, |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 932 if (base::EndsWith(server_id.host(), canonical_suffixes_[i], | 920 if (base::EndsWith(server_id.host(), canonical_suffixes_[i], |
| 933 base::CompareCase::INSENSITIVE_ASCII)) { | 921 base::CompareCase::INSENSITIVE_ASCII)) { |
| 934 break; | 922 break; |
| 935 } | 923 } |
| 936 } | 924 } |
| 937 if (i == canonical_suffixes_.size()) { | 925 if (i == canonical_suffixes_.size()) { |
| 938 return false; | 926 return false; |
| 939 } | 927 } |
| 940 | 928 |
| 941 QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(), | 929 QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(), |
| 942 server_id.is_https(), | |
| 943 server_id.privacy_mode()); | 930 server_id.privacy_mode()); |
| 944 if (!ContainsKey(canonical_server_map_, suffix_server_id)) { | 931 if (!ContainsKey(canonical_server_map_, suffix_server_id)) { |
| 945 // This is the first host we've seen which matches the suffix, so make it | 932 // This is the first host we've seen which matches the suffix, so make it |
| 946 // canonical. | 933 // canonical. |
| 947 canonical_server_map_[suffix_server_id] = server_id; | 934 canonical_server_map_[suffix_server_id] = server_id; |
| 948 return false; | 935 return false; |
| 949 } | 936 } |
| 950 | 937 |
| 951 const QuicServerId& canonical_server_id = | 938 const QuicServerId& canonical_server_id = |
| 952 canonical_server_map_[suffix_server_id]; | 939 canonical_server_map_[suffix_server_id]; |
| 953 CachedState* canonical_state = cached_states_[canonical_server_id]; | 940 CachedState* canonical_state = cached_states_[canonical_server_id]; |
| 954 if (!canonical_state->proof_valid()) { | 941 if (!canonical_state->proof_valid()) { |
| 955 return false; | 942 return false; |
| 956 } | 943 } |
| 957 | 944 |
| 958 // Update canonical version to point at the "most recent" entry. | 945 // Update canonical version to point at the "most recent" entry. |
| 959 canonical_server_map_[suffix_server_id] = server_id; | 946 canonical_server_map_[suffix_server_id] = server_id; |
| 960 | 947 |
| 961 server_state->InitializeFrom(*canonical_state); | 948 server_state->InitializeFrom(*canonical_state); |
| 962 return true; | 949 return true; |
| 963 } | 950 } |
| 964 | 951 |
| 965 } // namespace net | 952 } // namespace net |
| OLD | NEW |