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 |