| 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.h" | 7 #include "base/metrics/histogram.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 14 matching lines...) Expand all Loading... |
| 25 using std::find; | 25 using std::find; |
| 26 using std::make_pair; | 26 using std::make_pair; |
| 27 using std::map; | 27 using std::map; |
| 28 using std::string; | 28 using std::string; |
| 29 using std::vector; | 29 using std::vector; |
| 30 | 30 |
| 31 namespace net { | 31 namespace net { |
| 32 | 32 |
| 33 namespace { | 33 namespace { |
| 34 | 34 |
| 35 enum ServerConfigState { | 35 // Tracks the reason (the state of the server config) for sending inchoate |
| 36 // WARNING: Do not change the numerical values of any of server config state. | 36 // ClientHello to the server. |
| 37 // Do not remove deprecated server config states - just comment them as | 37 void RecordInchoateClientHelloReason( |
| 38 // deprecated. | 38 QuicCryptoClientConfig::CachedState::ServerConfigState state) { |
| 39 SERVER_CONFIG_EMPTY = 0, | 39 UMA_HISTOGRAM_ENUMERATION( |
| 40 SERVER_CONFIG_INVALID = 1, | 40 "Net.QuicInchoateClientHelloReason", state, |
| 41 SERVER_CONFIG_CORRUPTED = 2, | 41 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT); |
| 42 SERVER_CONFIG_EXPIRED = 3, | 42 } |
| 43 SERVER_CONFIG_INVALID_EXPIRY = 4, | |
| 44 | 43 |
| 45 // NOTE: Add new server config states only immediately above this line. Make | 44 // Tracks the state of the QUIC server information loaded from the disk cache. |
| 46 // sure to update the QuicServerConfigState enum in | 45 void RecordDiskCacheServerConfigState( |
| 47 // tools/metrics/histograms/histograms.xml accordingly. | 46 QuicCryptoClientConfig::CachedState::ServerConfigState state) { |
| 48 SERVER_CONFIG_COUNT | 47 UMA_HISTOGRAM_ENUMERATION( |
| 49 }; | 48 "Net.QuicServerInfo.DiskCacheState", state, |
| 50 | 49 QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT); |
| 51 void RecordServerConfigState(ServerConfigState server_config_state) { | |
| 52 UMA_HISTOGRAM_ENUMERATION("Net.QuicClientHelloServerConfigState", | |
| 53 server_config_state, SERVER_CONFIG_COUNT); | |
| 54 } | 50 } |
| 55 | 51 |
| 56 } // namespace | 52 } // namespace |
| 57 | 53 |
| 58 QuicCryptoClientConfig::QuicCryptoClientConfig() | 54 QuicCryptoClientConfig::QuicCryptoClientConfig() |
| 59 : disable_ecdsa_(false) { | 55 : disable_ecdsa_(false) { |
| 60 SetDefaults(); | 56 SetDefaults(); |
| 61 } | 57 } |
| 62 | 58 |
| 63 QuicCryptoClientConfig::~QuicCryptoClientConfig() { | 59 QuicCryptoClientConfig::~QuicCryptoClientConfig() { |
| 64 STLDeleteValues(&cached_states_); | 60 STLDeleteValues(&cached_states_); |
| 65 } | 61 } |
| 66 | 62 |
| 67 QuicCryptoClientConfig::CachedState::CachedState() | 63 QuicCryptoClientConfig::CachedState::CachedState() |
| 68 : server_config_valid_(false), | 64 : server_config_valid_(false), |
| 69 generation_counter_(0) {} | 65 generation_counter_(0) {} |
| 70 | 66 |
| 71 QuicCryptoClientConfig::CachedState::~CachedState() {} | 67 QuicCryptoClientConfig::CachedState::~CachedState() {} |
| 72 | 68 |
| 73 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const { | 69 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const { |
| 74 if (server_config_.empty()) { | 70 if (server_config_.empty()) { |
| 75 RecordServerConfigState(SERVER_CONFIG_EMPTY); | 71 RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY); |
| 76 return false; | 72 return false; |
| 77 } | 73 } |
| 78 | 74 |
| 79 if (!server_config_valid_) { | 75 if (!server_config_valid_) { |
| 80 RecordServerConfigState(SERVER_CONFIG_INVALID); | 76 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID); |
| 81 return false; | 77 return false; |
| 82 } | 78 } |
| 83 | 79 |
| 84 const CryptoHandshakeMessage* scfg = GetServerConfig(); | 80 const CryptoHandshakeMessage* scfg = GetServerConfig(); |
| 85 if (!scfg) { | 81 if (!scfg) { |
| 86 // Should be impossible short of cache corruption. | 82 // Should be impossible short of cache corruption. |
| 87 DCHECK(false); | 83 DCHECK(false); |
| 88 RecordServerConfigState(SERVER_CONFIG_CORRUPTED); | 84 RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED); |
| 89 return false; | 85 return false; |
| 90 } | 86 } |
| 91 | 87 |
| 92 uint64 expiry_seconds; | 88 uint64 expiry_seconds; |
| 93 if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { | 89 if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { |
| 94 RecordServerConfigState(SERVER_CONFIG_INVALID_EXPIRY); | 90 RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID_EXPIRY); |
| 95 return false; | 91 return false; |
| 96 } | 92 } |
| 97 if (now.ToUNIXSeconds() >= expiry_seconds) { | 93 if (now.ToUNIXSeconds() >= expiry_seconds) { |
| 98 UMA_HISTOGRAM_CUSTOM_TIMES( | 94 UMA_HISTOGRAM_CUSTOM_TIMES( |
| 99 "Net.QuicClientHelloServerConfig.InvalidDuration", | 95 "Net.QuicClientHelloServerConfig.InvalidDuration", |
| 100 base::TimeDelta::FromSeconds(now.ToUNIXSeconds() - expiry_seconds), | 96 base::TimeDelta::FromSeconds(now.ToUNIXSeconds() - expiry_seconds), |
| 101 base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50); | 97 base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50); |
| 102 RecordServerConfigState(SERVER_CONFIG_EXPIRED); | 98 RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED); |
| 103 return false; | 99 return false; |
| 104 } | 100 } |
| 105 | 101 |
| 106 return true; | 102 return true; |
| 107 } | 103 } |
| 108 | 104 |
| 109 bool QuicCryptoClientConfig::CachedState::IsEmpty() const { | 105 bool QuicCryptoClientConfig::CachedState::IsEmpty() const { |
| 110 return server_config_.empty(); | 106 return server_config_.empty(); |
| 111 } | 107 } |
| 112 | 108 |
| 113 const CryptoHandshakeMessage* | 109 const CryptoHandshakeMessage* |
| 114 QuicCryptoClientConfig::CachedState::GetServerConfig() const { | 110 QuicCryptoClientConfig::CachedState::GetServerConfig() const { |
| 115 if (server_config_.empty()) { | 111 if (server_config_.empty()) { |
| 116 return nullptr; | 112 return nullptr; |
| 117 } | 113 } |
| 118 | 114 |
| 119 if (!scfg_.get()) { | 115 if (!scfg_.get()) { |
| 120 scfg_.reset(CryptoFramer::ParseMessage(server_config_)); | 116 scfg_.reset(CryptoFramer::ParseMessage(server_config_)); |
| 121 DCHECK(scfg_.get()); | 117 DCHECK(scfg_.get()); |
| 122 } | 118 } |
| 123 return scfg_.get(); | 119 return scfg_.get(); |
| 124 } | 120 } |
| 125 | 121 |
| 126 QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig( | 122 QuicCryptoClientConfig::CachedState::ServerConfigState |
| 123 QuicCryptoClientConfig::CachedState::SetServerConfig( |
| 127 StringPiece server_config, QuicWallTime now, string* error_details) { | 124 StringPiece server_config, QuicWallTime now, string* error_details) { |
| 128 const bool matches_existing = server_config == server_config_; | 125 const bool matches_existing = server_config == server_config_; |
| 129 | 126 |
| 130 // Even if the new server config matches the existing one, we still wish to | 127 // Even if the new server config matches the existing one, we still wish to |
| 131 // reject it if it has expired. | 128 // reject it if it has expired. |
| 132 scoped_ptr<CryptoHandshakeMessage> new_scfg_storage; | 129 scoped_ptr<CryptoHandshakeMessage> new_scfg_storage; |
| 133 const CryptoHandshakeMessage* new_scfg; | 130 const CryptoHandshakeMessage* new_scfg; |
| 134 | 131 |
| 135 if (!matches_existing) { | 132 if (!matches_existing) { |
| 136 new_scfg_storage.reset(CryptoFramer::ParseMessage(server_config)); | 133 new_scfg_storage.reset(CryptoFramer::ParseMessage(server_config)); |
| 137 new_scfg = new_scfg_storage.get(); | 134 new_scfg = new_scfg_storage.get(); |
| 138 } else { | 135 } else { |
| 139 new_scfg = GetServerConfig(); | 136 new_scfg = GetServerConfig(); |
| 140 } | 137 } |
| 141 | 138 |
| 142 if (!new_scfg) { | 139 if (!new_scfg) { |
| 143 *error_details = "SCFG invalid"; | 140 *error_details = "SCFG invalid"; |
| 144 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 141 return SERVER_CONFIG_INVALID; |
| 145 } | 142 } |
| 146 | 143 |
| 147 uint64 expiry_seconds; | 144 uint64 expiry_seconds; |
| 148 if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { | 145 if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { |
| 149 *error_details = "SCFG missing EXPY"; | 146 *error_details = "SCFG missing EXPY"; |
| 150 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; | 147 return SERVER_CONFIG_INVALID_EXPIRY; |
| 151 } | 148 } |
| 152 | 149 |
| 153 if (now.ToUNIXSeconds() >= expiry_seconds) { | 150 if (now.ToUNIXSeconds() >= expiry_seconds) { |
| 154 *error_details = "SCFG has expired"; | 151 *error_details = "SCFG has expired"; |
| 155 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED; | 152 return SERVER_CONFIG_EXPIRED; |
| 156 } | 153 } |
| 157 | 154 |
| 158 if (!matches_existing) { | 155 if (!matches_existing) { |
| 159 server_config_ = server_config.as_string(); | 156 server_config_ = server_config.as_string(); |
| 160 SetProofInvalid(); | 157 SetProofInvalid(); |
| 161 scfg_.reset(new_scfg_storage.release()); | 158 scfg_.reset(new_scfg_storage.release()); |
| 162 } | 159 } |
| 163 return QUIC_NO_ERROR; | 160 return SERVER_CONFIG_VALID; |
| 164 } | 161 } |
| 165 | 162 |
| 166 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() { | 163 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() { |
| 167 server_config_.clear(); | 164 server_config_.clear(); |
| 168 scfg_.reset(); | 165 scfg_.reset(); |
| 169 SetProofInvalid(); | 166 SetProofInvalid(); |
| 170 } | 167 } |
| 171 | 168 |
| 172 void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs, | 169 void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs, |
| 173 StringPiece signature) { | 170 StringPiece signature) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 | 218 |
| 222 bool QuicCryptoClientConfig::CachedState::Initialize( | 219 bool QuicCryptoClientConfig::CachedState::Initialize( |
| 223 StringPiece server_config, | 220 StringPiece server_config, |
| 224 StringPiece source_address_token, | 221 StringPiece source_address_token, |
| 225 const vector<string>& certs, | 222 const vector<string>& certs, |
| 226 StringPiece signature, | 223 StringPiece signature, |
| 227 QuicWallTime now) { | 224 QuicWallTime now) { |
| 228 DCHECK(server_config_.empty()); | 225 DCHECK(server_config_.empty()); |
| 229 | 226 |
| 230 if (server_config.empty()) { | 227 if (server_config.empty()) { |
| 228 RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY); |
| 231 return false; | 229 return false; |
| 232 } | 230 } |
| 233 | 231 |
| 234 string error_details; | 232 string error_details; |
| 235 QuicErrorCode error = SetServerConfig(server_config, now, | 233 ServerConfigState state = SetServerConfig(server_config, now, |
| 236 &error_details); | 234 &error_details); |
| 237 if (error != QUIC_NO_ERROR) { | 235 RecordDiskCacheServerConfigState(state); |
| 236 if (state != SERVER_CONFIG_VALID) { |
| 238 DVLOG(1) << "SetServerConfig failed with " << error_details; | 237 DVLOG(1) << "SetServerConfig failed with " << error_details; |
| 239 return false; | 238 return false; |
| 240 } | 239 } |
| 241 | 240 |
| 242 signature.CopyToString(&server_config_sig_); | 241 signature.CopyToString(&server_config_sig_); |
| 243 source_address_token.CopyToString(&source_address_token_); | 242 source_address_token.CopyToString(&source_address_token_); |
| 244 certs_ = certs; | 243 certs_ = certs; |
| 245 return true; | 244 return true; |
| 246 } | 245 } |
| 247 | 246 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 | 317 |
| 319 QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate( | 318 QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate( |
| 320 const QuicServerId& server_id) { | 319 const QuicServerId& server_id) { |
| 321 CachedStateMap::const_iterator it = cached_states_.find(server_id); | 320 CachedStateMap::const_iterator it = cached_states_.find(server_id); |
| 322 if (it != cached_states_.end()) { | 321 if (it != cached_states_.end()) { |
| 323 return it->second; | 322 return it->second; |
| 324 } | 323 } |
| 325 | 324 |
| 326 CachedState* cached = new CachedState; | 325 CachedState* cached = new CachedState; |
| 327 cached_states_.insert(make_pair(server_id, cached)); | 326 cached_states_.insert(make_pair(server_id, cached)); |
| 328 PopulateFromCanonicalConfig(server_id, cached); | 327 bool cache_populated = PopulateFromCanonicalConfig(server_id, cached); |
| 328 UMA_HISTOGRAM_BOOLEAN( |
| 329 "Net.QuicCryptoClientConfig.PopulatedFromCanonicalConfig", |
| 330 cache_populated); |
| 329 return cached; | 331 return cached; |
| 330 } | 332 } |
| 331 | 333 |
| 332 void QuicCryptoClientConfig::ClearCachedStates() { | 334 void QuicCryptoClientConfig::ClearCachedStates() { |
| 333 for (CachedStateMap::const_iterator it = cached_states_.begin(); | 335 for (CachedStateMap::const_iterator it = cached_states_.begin(); |
| 334 it != cached_states_.end(); ++it) { | 336 it != cached_states_.end(); ++it) { |
| 335 it->second->Clear(); | 337 it->second->Clear(); |
| 336 } | 338 } |
| 337 } | 339 } |
| 338 | 340 |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 CachedState* cached, | 586 CachedState* cached, |
| 585 string* error_details) { | 587 string* error_details) { |
| 586 DCHECK(error_details != nullptr); | 588 DCHECK(error_details != nullptr); |
| 587 | 589 |
| 588 StringPiece scfg; | 590 StringPiece scfg; |
| 589 if (!message.GetStringPiece(kSCFG, &scfg)) { | 591 if (!message.GetStringPiece(kSCFG, &scfg)) { |
| 590 *error_details = "Missing SCFG"; | 592 *error_details = "Missing SCFG"; |
| 591 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 593 return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; |
| 592 } | 594 } |
| 593 | 595 |
| 594 QuicErrorCode error = cached->SetServerConfig(scfg, now, error_details); | 596 CachedState::ServerConfigState state = cached->SetServerConfig( |
| 595 if (error != QUIC_NO_ERROR) { | 597 scfg, now, error_details); |
| 596 return error; | 598 if (state == CachedState::SERVER_CONFIG_EXPIRED) { |
| 599 return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED; |
| 600 } |
| 601 // TODO(rtenneti): Return more specific error code than returning |
| 602 // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER. |
| 603 if (state != CachedState::SERVER_CONFIG_VALID) { |
| 604 return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; |
| 597 } | 605 } |
| 598 | 606 |
| 599 StringPiece token; | 607 StringPiece token; |
| 600 if (message.GetStringPiece(kSourceAddressTokenTag, &token)) { | 608 if (message.GetStringPiece(kSourceAddressTokenTag, &token)) { |
| 601 cached->set_source_address_token(token); | 609 cached->set_source_address_token(token); |
| 602 } | 610 } |
| 603 | 611 |
| 604 StringPiece proof, cert_bytes; | 612 StringPiece proof, cert_bytes; |
| 605 bool has_proof = message.GetStringPiece(kPROF, &proof); | 613 bool has_proof = message.GetStringPiece(kPROF, &proof); |
| 606 bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes); | 614 bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes); |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 822 if (pos != aead.end()) { | 830 if (pos != aead.end()) { |
| 823 aead.erase(pos); | 831 aead.erase(pos); |
| 824 aead.insert(aead.begin(), kAESG); | 832 aead.insert(aead.begin(), kAESG); |
| 825 } | 833 } |
| 826 } | 834 } |
| 827 | 835 |
| 828 void QuicCryptoClientConfig::DisableEcdsa() { | 836 void QuicCryptoClientConfig::DisableEcdsa() { |
| 829 disable_ecdsa_ = true; | 837 disable_ecdsa_ = true; |
| 830 } | 838 } |
| 831 | 839 |
| 832 void QuicCryptoClientConfig::PopulateFromCanonicalConfig( | 840 bool QuicCryptoClientConfig::PopulateFromCanonicalConfig( |
| 833 const QuicServerId& server_id, | 841 const QuicServerId& server_id, |
| 834 CachedState* server_state) { | 842 CachedState* server_state) { |
| 835 DCHECK(server_state->IsEmpty()); | 843 DCHECK(server_state->IsEmpty()); |
| 836 size_t i = 0; | 844 size_t i = 0; |
| 837 for (; i < canonical_suffixes_.size(); ++i) { | 845 for (; i < canonical_suffixes_.size(); ++i) { |
| 838 if (EndsWith(server_id.host(), canonical_suffixes_[i], false)) { | 846 if (EndsWith(server_id.host(), canonical_suffixes_[i], false)) { |
| 839 break; | 847 break; |
| 840 } | 848 } |
| 841 } | 849 } |
| 842 if (i == canonical_suffixes_.size()) | 850 if (i == canonical_suffixes_.size()) |
| 843 return; | 851 return false; |
| 844 | 852 |
| 845 QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(), | 853 QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(), |
| 846 server_id.is_https(), | 854 server_id.is_https(), |
| 847 server_id.privacy_mode()); | 855 server_id.privacy_mode()); |
| 848 if (!ContainsKey(canonical_server_map_, suffix_server_id)) { | 856 if (!ContainsKey(canonical_server_map_, suffix_server_id)) { |
| 849 // This is the first host we've seen which matches the suffix, so make it | 857 // This is the first host we've seen which matches the suffix, so make it |
| 850 // canonical. | 858 // canonical. |
| 851 canonical_server_map_[suffix_server_id] = server_id; | 859 canonical_server_map_[suffix_server_id] = server_id; |
| 852 return; | 860 return false; |
| 853 } | 861 } |
| 854 | 862 |
| 855 const QuicServerId& canonical_server_id = | 863 const QuicServerId& canonical_server_id = |
| 856 canonical_server_map_[suffix_server_id]; | 864 canonical_server_map_[suffix_server_id]; |
| 857 CachedState* canonical_state = cached_states_[canonical_server_id]; | 865 CachedState* canonical_state = cached_states_[canonical_server_id]; |
| 858 if (!canonical_state->proof_valid()) { | 866 if (!canonical_state->proof_valid()) { |
| 859 return; | 867 return false; |
| 860 } | 868 } |
| 861 | 869 |
| 862 // Update canonical version to point at the "most recent" entry. | 870 // Update canonical version to point at the "most recent" entry. |
| 863 canonical_server_map_[suffix_server_id] = server_id; | 871 canonical_server_map_[suffix_server_id] = server_id; |
| 864 | 872 |
| 865 server_state->InitializeFrom(*canonical_state); | 873 server_state->InitializeFrom(*canonical_state); |
| 874 return true; |
| 866 } | 875 } |
| 867 | 876 |
| 868 } // namespace net | 877 } // namespace net |
| OLD | NEW |