Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Side by Side Diff: net/base/transport_security_state.cc

Issue 12974003: Improve TransportSecurityState data storage. (Closed) Base URL: https://src.chromium.org/chrome/trunk/src/
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/base/transport_security_state.h ('k') | net/base/transport_security_state_preload.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/base/transport_security_state.h" 5 #include "net/base/transport_security_state.h"
6 6
7 #if defined(USE_OPENSSL) 7 #if defined(USE_OPENSSL)
8 #include <openssl/ecdsa.h> 8 #include <openssl/ecdsa.h>
9 #include <openssl/ssl.h> 9 #include <openssl/ssl.h>
10 #else // !defined(USE_OPENSSL) 10 #else // !defined(USE_OPENSSL)
11 #include <cryptohi.h> 11 #include <cryptohi.h>
12 #include <hasht.h> 12 #include <hasht.h>
13 #include <keyhi.h> 13 #include <keyhi.h>
14 #include <pk11pub.h> 14 #include <pk11pub.h>
15 #include <nspr.h> 15 #include <nspr.h>
16 #endif 16 #endif
17 17
18 #include <algorithm> 18 #include <algorithm>
19 19
20 #include "base/base64.h" 20 #include "base/base64.h"
21 #include "base/build_time.h" 21 #include "base/build_time.h"
22 #include "base/logging.h" 22 #include "base/logging.h"
23 #include "base/memory/scoped_ptr.h" 23 #include "base/memory/scoped_ptr.h"
24 #include "base/metrics/histogram.h" 24 #include "base/metrics/histogram.h"
25 #include "base/sha1.h" 25 #include "base/sha1.h"
26 #include "base/string_number_conversions.h"
27 #include "base/string_util.h" 26 #include "base/string_util.h"
28 #include "base/time.h" 27 #include "base/time.h"
29 #include "base/utf_string_conversions.h"
30 #include "base/values.h"
31 #include "crypto/sha2.h" 28 #include "crypto/sha2.h"
32 #include "googleurl/src/gurl.h" 29 #include "googleurl/src/gurl.h"
33 #include "net/base/dns_util.h" 30 #include "net/base/dns_util.h"
34 #include "net/base/ssl_info.h" 31 #include "net/base/ssl_info.h"
35 #include "net/base/x509_cert_types.h" 32 #include "net/base/transport_security_state_preload.h"
36 #include "net/base/x509_certificate.h" 33 #include "net/base/x509_certificate.h"
37 #include "net/http/http_security_headers.h" 34 #include "net/http/http_security_headers.h"
38 35
39 #if defined(USE_OPENSSL) 36 #if defined(USE_OPENSSL)
40 #include "crypto/openssl_util.h" 37 #include "crypto/openssl_util.h"
41 #endif 38 #endif
42 39
43 namespace net { 40 namespace net {
44 41
45 namespace { 42 namespace {
46 43
47 std::string HashesToBase64String(const HashValueVector& hashes) { 44 std::string HashesToBase64String(const HashValueVector& hashes) {
48 std::string str; 45 std::string str;
49 for (size_t i = 0; i != hashes.size(); ++i) { 46 for (size_t i = 0; i != hashes.size(); ++i) {
50 if (i != 0) 47 if (i != 0)
51 str += ","; 48 str += ",";
52 str += hashes[i].ToString(); 49 str += hashes[i].ToString();
53 } 50 }
54 return str; 51 return str;
55 } 52 }
56 53
57 std::string HashHost(const std::string& canonicalized_host) { 54 std::string HashHost(const std::string& host) {
55 std::string lowercase = StringToLowerASCII(host);
56 std::string old_style_canonicalized_name;
57 if (!DNSDomainFromDot(lowercase, &old_style_canonicalized_name)) {
58 old_style_canonicalized_name.clear();
59 LOG(WARNING) << "Bad DNS name passed to TransportSecurityState";
60 }
61
58 char hashed[crypto::kSHA256Length]; 62 char hashed[crypto::kSHA256Length];
59 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); 63 crypto::SHA256HashString(old_style_canonicalized_name, hashed,
64 sizeof(hashed));
60 return std::string(hashed, sizeof(hashed)); 65 return std::string(hashed, sizeof(hashed));
61 } 66 }
62 67
63 // Returns true if the intersection of |a| and |b| is not empty. If either 68 // Returns true if the intersection of |a| and |b| is not empty. If either
64 // |a| or |b| is empty, returns false. 69 // |a| or |b| is empty, returns false.
65 bool HashesIntersect(const HashValueVector& a, 70 bool HashesIntersect(const HashValueVector& a,
66 const HashValueVector& b) { 71 const HashValueVector& b) {
67 for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) { 72 for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) {
68 HashValueVector::const_iterator j = 73 HashValueVector::const_iterator j =
69 std::find_if(b.begin(), b.end(), HashValuesEqual(*i)); 74 std::find_if(b.begin(), b.end(), HashValuesEqual(*i));
70 if (j != b.end()) 75 if (j != b.end())
71 return true; 76 return true;
72 } 77 }
73 return false; 78 return false;
74 } 79 }
75 80
76 bool AddHash(const char* sha1_hash, 81 // Iterate over ("www.example.com", "example.com", "com")
77 HashValueVector* out) { 82 struct DomainNameIterator {
78 HashValue hash(HASH_VALUE_SHA1); 83 explicit DomainNameIterator(const std::string& host) {
79 memcpy(hash.data(), sha1_hash, hash.size()); 84 name_ = StringToLowerASCII(host);
80 out->push_back(hash); 85 index_ = 0;
86 }
87
88 bool AtEnd() {
89 return index_ == name_.length();
90 }
91
92 // Advance to NUL char, or after the next '.'
93 void Advance() {
94 if (AtEnd())
95 return;
96 for (index_++; name_[index_] != '.' && name_[index_] != 0; ++index_);
97 if (name_[index_] == '.')
98 index_++;
99 }
100
101 std::string GetName() {
102 return name_.substr(index_);
103 }
104
105 bool IsFullHostname() {
106 return index_ == 0;
107 }
108
109 std::string name_; // The full hostname, canonicalized to lowercase
110 size_t index_; // Index into name_
111 };
112
113 // Template functions for maps of DynamicEntries (or subclasses)
114 template <typename T, typename MapType = std::map<std::string, T> >
115 bool GetDynamicEntry(const std::map<std::string, T>& entries,
116 const base::Time& now,
117 const std::string& hashed_host,
118 bool is_full_hostname,
119 T* result_entry) {
120 // Find the entry, and return if relevant and nonexpired
121 typename MapType::const_iterator find_iter = entries.find(hashed_host);
122 if (find_iter == entries.end())
123 return false;
124
125 const T& found_entry = find_iter->second;
126 if ((is_full_hostname || found_entry.include_subdomains_) &&
127 found_entry.expiry_ > now) {
128 *result_entry = found_entry;
129 return true;
130 }
131 return false;
132 }
133
134 template<typename T, typename MapType = std::map<std::string, T> >
135 bool AddDynamicEntry(std::map<std::string, T>& entries,
136 const std::string& hashed_host,
137 const T& new_entry) {
138 typename MapType::iterator find_iter = entries.find(hashed_host);
139 if (find_iter != entries.end()) {
140 // Leave 'created' unchanged
141 T& found_entry = find_iter->second;
142 found_entry.expiry_ = new_entry.expiry_;
143 found_entry.include_subdomains_ = new_entry.include_subdomains_;
144 } else {
145 entries[hashed_host] = new_entry;
146 }
81 return true; 147 return true;
82 } 148 }
83 149
150 template<typename T, typename MapType = std::map<std::string, T> >
151 bool DeleteDynamicEntry(std::map<std::string, T>& entries,
152 const std::string& hashed_host) {
153 typename MapType::iterator find_iter = entries.find(hashed_host);
154 if (find_iter != entries.end()) {
155 entries.erase(find_iter);
156 return true;
157 }
158 return false;
159 }
160
161 template<typename T, typename MapType = std::map<std::string, T> >
162 bool DeleteDynamicEntriesSince(std::map<std::string, T>& entries,
163 const base::Time& time) {
164 typename MapType::iterator iter = entries.begin();
165 bool deleted = false;
166 while (iter != entries.end()) {
167 if (iter->second.created_ >= time) {
168 entries.erase(iter++);
169 deleted = true;
170 } else {
171 iter++;
172 }
173 }
174 return deleted;
175 }
176
84 } // namespace 177 } // namespace
85 178
179
86 TransportSecurityState::TransportSecurityState() 180 TransportSecurityState::TransportSecurityState()
87 : delegate_(NULL) { 181 : delegate_(NULL) {
88 } 182 }
89 183
90 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) 184 TransportSecurityState::~TransportSecurityState() {}
91 : iterator_(state.enabled_hosts_.begin()),
92 end_(state.enabled_hosts_.end()) {
93 }
94
95 TransportSecurityState::Iterator::~Iterator() {}
96 185
97 void TransportSecurityState::SetDelegate( 186 void TransportSecurityState::SetDelegate(
98 TransportSecurityState::Delegate* delegate) { 187 TransportSecurityState::Delegate* delegate) {
99 delegate_ = delegate; 188 delegate_ = delegate;
100 } 189 }
101 190
102 void TransportSecurityState::EnableHost(const std::string& host, 191 void TransportSecurityState::ClearDynamicData() {
103 const DomainState& state) { 192 hsts_entries_.clear();
193 hpkp_entries_.clear();
194 }
195
196 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
104 DCHECK(CalledOnValidThread()); 197 DCHECK(CalledOnValidThread());
105 198 bool deleted_hsts = DeleteDynamicEntriesSince(hsts_entries_, time);
106 const std::string canonicalized_host = CanonicalizeHost(host); 199 bool deleted_hpkp = DeleteDynamicEntriesSince(hpkp_entries_, time);
107 if (canonicalized_host.empty()) 200 if (deleted_hsts || deleted_hpkp)
108 return; 201 StateIsDirty();
109
110 DomainState existing_state;
111
112 // Use the original creation date if we already have this host. (But note
113 // that statically-defined states have no |created| date. Therefore, we do
114 // not bother to search the SNI-only static states.)
115 DomainState state_copy(state);
116 if (GetDomainState(host, false /* sni_enabled */, &existing_state) &&
117 !existing_state.created.is_null()) {
118 state_copy.created = existing_state.created;
119 }
120
121 // No need to store this value since it is redundant. (|canonicalized_host|
122 // is the map key.)
123 state_copy.domain.clear();
124
125 enabled_hosts_[HashHost(canonicalized_host)] = state_copy;
126 DirtyNotify();
127 } 202 }
128 203
129 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { 204 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) {
130 DCHECK(CalledOnValidThread()); 205 DCHECK(CalledOnValidThread());
131 206 bool deleted_hsts = DeleteHSTS(host);
132 const std::string canonicalized_host = CanonicalizeHost(host); 207 bool deleted_hpkp = DeleteHPKP(host);
133 if (canonicalized_host.empty()) 208 if (deleted_hsts || deleted_hpkp)
134 return false; 209 StateIsDirty();
135 210 return deleted_hsts || deleted_hpkp;
136 DomainStateMap::iterator i = enabled_hosts_.find(
137 HashHost(canonicalized_host));
138 if (i != enabled_hosts_.end()) {
139 enabled_hosts_.erase(i);
140 DirtyNotify();
141 return true;
142 }
143 return false;
144 } 211 }
145 212
146 bool TransportSecurityState::GetDomainState(const std::string& host, 213 bool TransportSecurityState::GetDomainState(const std::string& host,
147 bool sni_enabled, 214 bool sni_enabled,
148 DomainState* result) { 215 DomainState* result) const {
149 DCHECK(CalledOnValidThread()); 216 DCHECK(CalledOnValidThread());
150 217 bool found = false;
151 DomainState state; 218 const base::Time now = base::Time::Now();
152 const std::string canonicalized_host = CanonicalizeHost(host); 219 DomainState dynamic_state;
153 if (canonicalized_host.empty()) 220
221 found = GetPreloadDomainState(sni_enabled, now, host, result);
222 found = GetDynamicDomainState(now, host, &dynamic_state) || found;
223
224 // Merge dynamic state into preload state
225 // Currently, HSTS and HPKP are set if either state has them set.
226 // However, if both states have HPKP set, the preload pins take precedence.
227 // This behavior may change (e.g. for the most-recent to take priority).
228 if (!result->should_upgrade_ && dynamic_state.should_upgrade_)
229 result->should_upgrade_ = true;
230 if (!result->has_public_key_pins_ && dynamic_state.has_public_key_pins_) {
231 result->has_public_key_pins_ = true;
232 result->public_key_pins_good_hashes_ =
233 dynamic_state.public_key_pins_good_hashes_;
234 }
235 return found;
236 }
237
238 bool TransportSecurityState::GetDynamicDomainState(const base::Time& now,
239 const std::string& host,
240 DomainState* result) const {
241 HSTSEntry hsts_entry;
242 HPKPEntry hpkp_entry;
243 // Iterate over 'www.example.com", 'example.com", "com"
244 for (DomainNameIterator iter(host); !iter.AtEnd(); iter.Advance()) {
245 std::string hashed_host = HashHost(iter.GetName());
246 bool is_full_hostname = iter.IsFullHostname();
247
248 // Get HSTS data from map
249 if (!result->should_upgrade_ &&
250 GetDynamicEntry(hsts_entries_, now, hashed_host, is_full_hostname,
251 &hsts_entry)) {
252 result->should_upgrade_ = true;
253 }
254
255 // Get HPKP data from map
256 if (!result->has_public_key_pins_ &&
257 GetDynamicEntry(hpkp_entries_, now, hashed_host, is_full_hostname,
258 &hpkp_entry)) {
259 result->has_public_key_pins_ = true;
260 result->public_key_pins_good_hashes_ = hpkp_entry.good_hashes_;
261 }
262
263 // If we've got all possible data, exit early
264 if (result->should_upgrade_ && result->has_public_key_pins_)
265 return true;
266 }
267 return result->should_upgrade_ || result->has_public_key_pins_;
268 }
269
270 bool TransportSecurityState::GetPreloadDomainState(bool sni_enabled,
271 const base::Time& now,
272 const std::string& host,
273 DomainState* result) const {
274 #if defined(PRELOADS_PRESENT)
275 const PreloadEntry* entries = kPreloadedEntries;
276 size_t num_entries = kNumPreloaded;
277
278 if (!IsBuildTimely())
154 return false; 279 return false;
155 280
156 bool has_preload = GetStaticDomainState(canonicalized_host, sni_enabled, 281 for (int count = 0; count < 2; count++) {
157 &state); 282 // If sni_enabled, then scan through SNI entries (if necessary)
158 std::string canonicalized_preload = CanonicalizeHost(state.domain); 283 if (count == 1) {
159 284 if (!sni_enabled)
160 base::Time current_time(base::Time::Now()); 285 break;
161 286 entries = kPreloadedEntriesSNI;
162 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 287 num_entries = kNumPreloadedSNI;
163 std::string host_sub_chunk(&canonicalized_host[i], 288 }
164 canonicalized_host.size() - i); 289
165 // Exact match of a preload always wins. 290 for (DomainNameIterator iter(host); !iter.AtEnd(); iter.Advance()) {
166 if (has_preload && host_sub_chunk == canonicalized_preload) { 291 std::string name = iter.GetName();
167 *result = state; 292 for (size_t index = 0; index < num_entries; index++) {
168 return true; 293 const PreloadEntry& entry = entries[index];
169 } 294
170 295 // If we find a relevant preload entry, populate the
171 DomainStateMap::iterator j = 296 // entire DomainState from it and return
172 enabled_hosts_.find(HashHost(host_sub_chunk)); 297 if (entry.length == name.size() &&
173 if (j == enabled_hosts_.end()) 298 (iter.IsFullHostname() || entry.include_subdomains) &&
174 continue; 299 memcmp(entry.dns_name, name.data(), entry.length) == 0) {
175 300 if (entry.https_required)
176 if (current_time > j->second.upgrade_expiry && 301 result->should_upgrade_ = true;
177 current_time > j->second.dynamic_spki_hashes_expiry) { 302
178 enabled_hosts_.erase(j); 303 if (entry.pins.required_hashes || entry.pins.excluded_hashes)
179 DirtyNotify(); 304 result->has_public_key_pins_ = true;
180 continue; 305 HashValue hash(HASH_VALUE_SHA1);
181 } 306 if (entry.pins.required_hashes) {
182 307 const char* const* sha1_hashes = entry.pins.required_hashes;
183 state = j->second; 308 while (*sha1_hashes) {
184 state.domain = DNSDomainToString(host_sub_chunk); 309 memcpy(hash.data(), *sha1_hashes, hash.size());
185 310 result->public_key_pins_good_hashes_.push_back(hash);
186 // Succeed if we matched the domain exactly or if subdomain matches are 311 sha1_hashes++;
187 // allowed. 312 }
188 if (i == 0 || j->second.include_subdomains) {
189 *result = state;
190 return true;
191 }
192
193 return false;
194 }
195
196 return false;
197 }
198
199 void TransportSecurityState::ClearDynamicData() {
200 enabled_hosts_.clear();
201 }
202
203 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
204 DCHECK(CalledOnValidThread());
205
206 bool dirtied = false;
207
208 DomainStateMap::iterator i = enabled_hosts_.begin();
209 while (i != enabled_hosts_.end()) {
210 if (i->second.created >= time) {
211 dirtied = true;
212 enabled_hosts_.erase(i++);
213 } else {
214 i++;
215 }
216 }
217
218 if (dirtied)
219 DirtyNotify();
220 }
221
222 TransportSecurityState::~TransportSecurityState() {}
223
224 void TransportSecurityState::DirtyNotify() {
225 DCHECK(CalledOnValidThread());
226
227 if (delegate_)
228 delegate_->StateIsDirty(this);
229 }
230
231 // static
232 std::string TransportSecurityState::CanonicalizeHost(const std::string& host) {
233 // We cannot perform the operations as detailed in the spec here as |host|
234 // has already undergone IDN processing before it reached us. Thus, we check
235 // that there are no invalid characters in the host and lowercase the result.
236
237 std::string new_host;
238 if (!DNSDomainFromDot(host, &new_host)) {
239 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
240 // name is >255 bytes. However, search terms can have those properties.
241 return std::string();
242 }
243
244 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) {
245 const unsigned label_length = static_cast<unsigned>(new_host[i]);
246 if (!label_length)
247 break;
248
249 for (size_t j = 0; j < label_length; ++j) {
250 // RFC 3490, 4.1, step 3
251 if (!IsSTD3ASCIIValidCharacter(new_host[i + 1 + j]))
252 return std::string();
253
254 new_host[i + 1 + j] = tolower(new_host[i + 1 + j]);
255 }
256
257 // step 3(b)
258 if (new_host[i + 1] == '-' ||
259 new_host[i + label_length] == '-') {
260 return std::string();
261 }
262 }
263
264 return new_host;
265 }
266
267 // |ReportUMAOnPinFailure| uses these to report which domain was associated
268 // with the public key pinning failure.
269 //
270 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new
271 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS).
272 enum SecondLevelDomainName {
273 DOMAIN_NOT_PINNED,
274
275 DOMAIN_GOOGLE_COM,
276 DOMAIN_ANDROID_COM,
277 DOMAIN_GOOGLE_ANALYTICS_COM,
278 DOMAIN_GOOGLEPLEX_COM,
279 DOMAIN_YTIMG_COM,
280 DOMAIN_GOOGLEUSERCONTENT_COM,
281 DOMAIN_YOUTUBE_COM,
282 DOMAIN_GOOGLEAPIS_COM,
283 DOMAIN_GOOGLEADSERVICES_COM,
284 DOMAIN_GOOGLECODE_COM,
285 DOMAIN_APPSPOT_COM,
286 DOMAIN_GOOGLESYNDICATION_COM,
287 DOMAIN_DOUBLECLICK_NET,
288 DOMAIN_GSTATIC_COM,
289 DOMAIN_GMAIL_COM,
290 DOMAIN_GOOGLEMAIL_COM,
291 DOMAIN_GOOGLEGROUPS_COM,
292
293 DOMAIN_TORPROJECT_ORG,
294
295 DOMAIN_TWITTER_COM,
296 DOMAIN_TWIMG_COM,
297
298 DOMAIN_AKAMAIHD_NET,
299
300 DOMAIN_TOR2WEB_ORG,
301
302 DOMAIN_YOUTU_BE,
303 DOMAIN_GOOGLECOMMERCE_COM,
304 DOMAIN_URCHIN_COM,
305 DOMAIN_GOO_GL,
306 DOMAIN_G_CO,
307 DOMAIN_GOOGLE_AC,
308 DOMAIN_GOOGLE_AD,
309 DOMAIN_GOOGLE_AE,
310 DOMAIN_GOOGLE_AF,
311 DOMAIN_GOOGLE_AG,
312 DOMAIN_GOOGLE_AM,
313 DOMAIN_GOOGLE_AS,
314 DOMAIN_GOOGLE_AT,
315 DOMAIN_GOOGLE_AZ,
316 DOMAIN_GOOGLE_BA,
317 DOMAIN_GOOGLE_BE,
318 DOMAIN_GOOGLE_BF,
319 DOMAIN_GOOGLE_BG,
320 DOMAIN_GOOGLE_BI,
321 DOMAIN_GOOGLE_BJ,
322 DOMAIN_GOOGLE_BS,
323 DOMAIN_GOOGLE_BY,
324 DOMAIN_GOOGLE_CA,
325 DOMAIN_GOOGLE_CAT,
326 DOMAIN_GOOGLE_CC,
327 DOMAIN_GOOGLE_CD,
328 DOMAIN_GOOGLE_CF,
329 DOMAIN_GOOGLE_CG,
330 DOMAIN_GOOGLE_CH,
331 DOMAIN_GOOGLE_CI,
332 DOMAIN_GOOGLE_CL,
333 DOMAIN_GOOGLE_CM,
334 DOMAIN_GOOGLE_CN,
335 DOMAIN_CO_AO,
336 DOMAIN_CO_BW,
337 DOMAIN_CO_CK,
338 DOMAIN_CO_CR,
339 DOMAIN_CO_HU,
340 DOMAIN_CO_ID,
341 DOMAIN_CO_IL,
342 DOMAIN_CO_IM,
343 DOMAIN_CO_IN,
344 DOMAIN_CO_JE,
345 DOMAIN_CO_JP,
346 DOMAIN_CO_KE,
347 DOMAIN_CO_KR,
348 DOMAIN_CO_LS,
349 DOMAIN_CO_MA,
350 DOMAIN_CO_MZ,
351 DOMAIN_CO_NZ,
352 DOMAIN_CO_TH,
353 DOMAIN_CO_TZ,
354 DOMAIN_CO_UG,
355 DOMAIN_CO_UK,
356 DOMAIN_CO_UZ,
357 DOMAIN_CO_VE,
358 DOMAIN_CO_VI,
359 DOMAIN_CO_ZA,
360 DOMAIN_CO_ZM,
361 DOMAIN_CO_ZW,
362 DOMAIN_COM_AF,
363 DOMAIN_COM_AG,
364 DOMAIN_COM_AI,
365 DOMAIN_COM_AR,
366 DOMAIN_COM_AU,
367 DOMAIN_COM_BD,
368 DOMAIN_COM_BH,
369 DOMAIN_COM_BN,
370 DOMAIN_COM_BO,
371 DOMAIN_COM_BR,
372 DOMAIN_COM_BY,
373 DOMAIN_COM_BZ,
374 DOMAIN_COM_CN,
375 DOMAIN_COM_CO,
376 DOMAIN_COM_CU,
377 DOMAIN_COM_CY,
378 DOMAIN_COM_DO,
379 DOMAIN_COM_EC,
380 DOMAIN_COM_EG,
381 DOMAIN_COM_ET,
382 DOMAIN_COM_FJ,
383 DOMAIN_COM_GE,
384 DOMAIN_COM_GH,
385 DOMAIN_COM_GI,
386 DOMAIN_COM_GR,
387 DOMAIN_COM_GT,
388 DOMAIN_COM_HK,
389 DOMAIN_COM_IQ,
390 DOMAIN_COM_JM,
391 DOMAIN_COM_JO,
392 DOMAIN_COM_KH,
393 DOMAIN_COM_KW,
394 DOMAIN_COM_LB,
395 DOMAIN_COM_LY,
396 DOMAIN_COM_MT,
397 DOMAIN_COM_MX,
398 DOMAIN_COM_MY,
399 DOMAIN_COM_NA,
400 DOMAIN_COM_NF,
401 DOMAIN_COM_NG,
402 DOMAIN_COM_NI,
403 DOMAIN_COM_NP,
404 DOMAIN_COM_NR,
405 DOMAIN_COM_OM,
406 DOMAIN_COM_PA,
407 DOMAIN_COM_PE,
408 DOMAIN_COM_PH,
409 DOMAIN_COM_PK,
410 DOMAIN_COM_PL,
411 DOMAIN_COM_PR,
412 DOMAIN_COM_PY,
413 DOMAIN_COM_QA,
414 DOMAIN_COM_RU,
415 DOMAIN_COM_SA,
416 DOMAIN_COM_SB,
417 DOMAIN_COM_SG,
418 DOMAIN_COM_SL,
419 DOMAIN_COM_SV,
420 DOMAIN_COM_TJ,
421 DOMAIN_COM_TN,
422 DOMAIN_COM_TR,
423 DOMAIN_COM_TW,
424 DOMAIN_COM_UA,
425 DOMAIN_COM_UY,
426 DOMAIN_COM_VC,
427 DOMAIN_COM_VE,
428 DOMAIN_COM_VN,
429 DOMAIN_GOOGLE_CV,
430 DOMAIN_GOOGLE_CZ,
431 DOMAIN_GOOGLE_DE,
432 DOMAIN_GOOGLE_DJ,
433 DOMAIN_GOOGLE_DK,
434 DOMAIN_GOOGLE_DM,
435 DOMAIN_GOOGLE_DZ,
436 DOMAIN_GOOGLE_EE,
437 DOMAIN_GOOGLE_ES,
438 DOMAIN_GOOGLE_FI,
439 DOMAIN_GOOGLE_FM,
440 DOMAIN_GOOGLE_FR,
441 DOMAIN_GOOGLE_GA,
442 DOMAIN_GOOGLE_GE,
443 DOMAIN_GOOGLE_GG,
444 DOMAIN_GOOGLE_GL,
445 DOMAIN_GOOGLE_GM,
446 DOMAIN_GOOGLE_GP,
447 DOMAIN_GOOGLE_GR,
448 DOMAIN_GOOGLE_GY,
449 DOMAIN_GOOGLE_HK,
450 DOMAIN_GOOGLE_HN,
451 DOMAIN_GOOGLE_HR,
452 DOMAIN_GOOGLE_HT,
453 DOMAIN_GOOGLE_HU,
454 DOMAIN_GOOGLE_IE,
455 DOMAIN_GOOGLE_IM,
456 DOMAIN_GOOGLE_INFO,
457 DOMAIN_GOOGLE_IQ,
458 DOMAIN_GOOGLE_IS,
459 DOMAIN_GOOGLE_IT,
460 DOMAIN_IT_AO,
461 DOMAIN_GOOGLE_JE,
462 DOMAIN_GOOGLE_JO,
463 DOMAIN_GOOGLE_JOBS,
464 DOMAIN_GOOGLE_JP,
465 DOMAIN_GOOGLE_KG,
466 DOMAIN_GOOGLE_KI,
467 DOMAIN_GOOGLE_KZ,
468 DOMAIN_GOOGLE_LA,
469 DOMAIN_GOOGLE_LI,
470 DOMAIN_GOOGLE_LK,
471 DOMAIN_GOOGLE_LT,
472 DOMAIN_GOOGLE_LU,
473 DOMAIN_GOOGLE_LV,
474 DOMAIN_GOOGLE_MD,
475 DOMAIN_GOOGLE_ME,
476 DOMAIN_GOOGLE_MG,
477 DOMAIN_GOOGLE_MK,
478 DOMAIN_GOOGLE_ML,
479 DOMAIN_GOOGLE_MN,
480 DOMAIN_GOOGLE_MS,
481 DOMAIN_GOOGLE_MU,
482 DOMAIN_GOOGLE_MV,
483 DOMAIN_GOOGLE_MW,
484 DOMAIN_GOOGLE_NE,
485 DOMAIN_NE_JP,
486 DOMAIN_GOOGLE_NET,
487 DOMAIN_GOOGLE_NL,
488 DOMAIN_GOOGLE_NO,
489 DOMAIN_GOOGLE_NR,
490 DOMAIN_GOOGLE_NU,
491 DOMAIN_OFF_AI,
492 DOMAIN_GOOGLE_PK,
493 DOMAIN_GOOGLE_PL,
494 DOMAIN_GOOGLE_PN,
495 DOMAIN_GOOGLE_PS,
496 DOMAIN_GOOGLE_PT,
497 DOMAIN_GOOGLE_RO,
498 DOMAIN_GOOGLE_RS,
499 DOMAIN_GOOGLE_RU,
500 DOMAIN_GOOGLE_RW,
501 DOMAIN_GOOGLE_SC,
502 DOMAIN_GOOGLE_SE,
503 DOMAIN_GOOGLE_SH,
504 DOMAIN_GOOGLE_SI,
505 DOMAIN_GOOGLE_SK,
506 DOMAIN_GOOGLE_SM,
507 DOMAIN_GOOGLE_SN,
508 DOMAIN_GOOGLE_SO,
509 DOMAIN_GOOGLE_ST,
510 DOMAIN_GOOGLE_TD,
511 DOMAIN_GOOGLE_TG,
512 DOMAIN_GOOGLE_TK,
513 DOMAIN_GOOGLE_TL,
514 DOMAIN_GOOGLE_TM,
515 DOMAIN_GOOGLE_TN,
516 DOMAIN_GOOGLE_TO,
517 DOMAIN_GOOGLE_TP,
518 DOMAIN_GOOGLE_TT,
519 DOMAIN_GOOGLE_US,
520 DOMAIN_GOOGLE_UZ,
521 DOMAIN_GOOGLE_VG,
522 DOMAIN_GOOGLE_VU,
523 DOMAIN_GOOGLE_WS,
524
525 DOMAIN_CHROMIUM_ORG,
526
527 DOMAIN_CRYPTO_CAT,
528
529 // Boundary value for UMA_HISTOGRAM_ENUMERATION:
530 DOMAIN_NUM_EVENTS
531 };
532
533 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site.
534 // The validated certificate chain for the site must not include any of
535 // |excluded_hashes| and must include one or more of |required_hashes|.
536 struct PublicKeyPins {
537 const char* const* required_hashes;
538 const char* const* excluded_hashes;
539 };
540
541 struct HSTSPreload {
542 uint8 length;
543 bool include_subdomains;
544 char dns_name[34];
545 bool https_required;
546 PublicKeyPins pins;
547 SecondLevelDomainName second_level_domain_name;
548 };
549
550 static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries,
551 const std::string& canonicalized_host, size_t i,
552 TransportSecurityState::DomainState* out, bool* ret) {
553 for (size_t j = 0; j < num_entries; j++) {
554 if (entries[j].length == canonicalized_host.size() - i &&
555 memcmp(entries[j].dns_name, &canonicalized_host[i],
556 entries[j].length) == 0) {
557 if (!entries[j].include_subdomains && i != 0) {
558 *ret = false;
559 } else {
560 out->include_subdomains = entries[j].include_subdomains;
561 *ret = true;
562 if (!entries[j].https_required)
563 out->upgrade_mode = TransportSecurityState::DomainState::MODE_DEFAULT;
564 if (entries[j].pins.required_hashes) {
565 const char* const* sha1_hash = entries[j].pins.required_hashes;
566 while (*sha1_hash) {
567 AddHash(*sha1_hash, &out->static_spki_hashes);
568 sha1_hash++;
569 } 313 }
570 } 314 if (entry.pins.excluded_hashes) {
571 if (entries[j].pins.excluded_hashes) { 315 const char* const* sha1_hashes = entry.pins.excluded_hashes;
572 const char* const* sha1_hash = entries[j].pins.excluded_hashes; 316 while (*sha1_hashes) {
573 while (*sha1_hash) { 317 memcpy(hash.data(), *sha1_hashes, hash.size());
574 AddHash(*sha1_hash, &out->bad_static_spki_hashes); 318 result->public_key_pins_bad_hashes_.push_back(hash);
575 sha1_hash++; 319 sha1_hashes++;
320 }
576 } 321 }
322
323 if (entry.pins.required_hashes == kGoogleAcceptableCerts)
324 result->is_google_pinned_property_ = true;
325
326 if (entry.second_level_domain_name != DOMAIN_NOT_PINNED) {
327 result->report_uma_on_pin_failure_ = true;
328 result->second_level_domain_name_ = entry.second_level_domain_name;
329 }
330 return true;
577 } 331 }
578 } 332 }
579 return true; 333 }
580 } 334 }
581 } 335 #endif
582 return false; 336 return false;
583 } 337 }
584 338
585 #include "net/base/transport_security_state_static.h" 339 void TransportSecurityState::AddHSTSHeader(const std::string& host,
586
587 // Returns the HSTSPreload entry for the |canonicalized_host| in |entries|,
588 // or NULL if there is none. Prefers exact hostname matches to those that
589 // match only because HSTSPreload.include_subdomains is true.
590 //
591 // |canonicalized_host| should be the hostname as canonicalized by
592 // CanonicalizeHost.
593 static const struct HSTSPreload* GetHSTSPreload(
594 const std::string& canonicalized_host,
595 const struct HSTSPreload* entries,
596 size_t num_entries) {
597 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
598 for (size_t j = 0; j < num_entries; j++) {
599 const struct HSTSPreload* entry = entries + j;
600
601 if (i != 0 && !entry->include_subdomains)
602 continue;
603
604 if (entry->length == canonicalized_host.size() - i &&
605 memcmp(entry->dns_name, &canonicalized_host[i], entry->length) == 0) {
606 return entry;
607 }
608 }
609 }
610
611 return NULL;
612 }
613
614 bool TransportSecurityState::AddHSTSHeader(const std::string& host,
615 const std::string& value) { 340 const std::string& value) {
616 base::Time now = base::Time::Now(); 341 const base::Time now = base::Time::Now();
617 TransportSecurityState::DomainState domain_state; 342 base::TimeDelta max_age;
618 if (ParseHSTSHeader(now, value, &domain_state.upgrade_expiry, 343 bool include_subdomains = false;
619 &domain_state.include_subdomains)) { 344 if (ParseHSTSHeader(value, &max_age, &include_subdomains)) {
620 // Handle max-age == 0 345 if (max_age.InSeconds() == 0)
621 if (now == domain_state.upgrade_expiry) 346 DeleteHSTS(host);
622 domain_state.upgrade_mode = DomainState::MODE_DEFAULT;
623 else 347 else
624 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; 348 AddHSTS(host, now, now + max_age, include_subdomains);
625 domain_state.created = now; 349 }
626 EnableHost(host, domain_state); 350 }
627 return true; 351
628 } 352 void TransportSecurityState::AddHPKPHeader(const std::string& host,
629 return false;
630 }
631
632 bool TransportSecurityState::AddHPKPHeader(const std::string& host,
633 const std::string& value, 353 const std::string& value,
634 const SSLInfo& ssl_info) { 354 const SSLInfo& ssl_info) {
635 base::Time now = base::Time::Now(); 355 const base::Time now = base::Time::Now();
636 TransportSecurityState::DomainState domain_state; 356 base::TimeDelta max_age;
637 if (ParseHPKPHeader(now, value, ssl_info.public_key_hashes, 357 HashValueVector public_key_pin_hashes;
638 &domain_state.dynamic_spki_hashes_expiry, 358 bool include_subdomains = false; // TODO(trevp) PARSE FROM HEADER
639 &domain_state.dynamic_spki_hashes)) { 359 if (ParseHPKPHeader(value, ssl_info.public_key_hashes, &max_age,
640 domain_state.upgrade_mode = DomainState::MODE_DEFAULT; 360 &public_key_pin_hashes)) {
641 domain_state.created = now; 361 if (max_age.InSeconds() == 0) {
642 EnableHost(host, domain_state); 362 DeleteHPKP(host);
643 return true; 363 } else {
644 } 364 AddHPKP(host, now, now + max_age, include_subdomains,
645 return false; 365 public_key_pin_hashes);
366 }
367 }
646 } 368 }
647 369
648 bool TransportSecurityState::AddHSTS(const std::string& host, 370 bool TransportSecurityState::AddHSTS(const std::string& host,
371 const base::Time& created,
649 const base::Time& expiry, 372 const base::Time& expiry,
650 bool include_subdomains) { 373 bool include_subdomains) {
651 // Copy-and-modify the existing DomainState for this host (if any). 374 return AddHSTSHashedHost(HashHost(host), created, expiry,
652 TransportSecurityState::DomainState domain_state; 375 include_subdomains);
653 const std::string canonicalized_host = CanonicalizeHost(host);
654 const std::string hashed_host = HashHost(canonicalized_host);
655 DomainStateMap::const_iterator i = enabled_hosts_.find(
656 hashed_host);
657 if (i != enabled_hosts_.end())
658 domain_state = i->second;
659
660 domain_state.created = base::Time::Now();
661 domain_state.include_subdomains = include_subdomains;
662 domain_state.upgrade_expiry = expiry;
663 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
664 EnableHost(host, domain_state);
665 return true;
666 } 376 }
667 377
668 bool TransportSecurityState::AddHPKP(const std::string& host, 378 bool TransportSecurityState::AddHPKP(const std::string& host,
379 const base::Time& created,
669 const base::Time& expiry, 380 const base::Time& expiry,
670 bool include_subdomains, 381 bool include_subdomains,
671 const HashValueVector& hashes) { 382 const HashValueVector& hashes) {
672 // Copy-and-modify the existing DomainState for this host (if any). 383 return AddHPKPHashedHost(HashHost(host), created, expiry,
673 TransportSecurityState::DomainState domain_state; 384 include_subdomains, hashes);
674 const std::string canonicalized_host = CanonicalizeHost(host); 385 }
675 const std::string hashed_host = HashHost(canonicalized_host); 386
676 DomainStateMap::const_iterator i = enabled_hosts_.find( 387 bool TransportSecurityState::AddHSTSHashedHost(const std::string& hashed_host,
677 hashed_host); 388 const base::Time& created,
678 if (i != enabled_hosts_.end()) 389 const base::Time& expiry,
679 domain_state = i->second; 390 bool include_subdomains) {
680 391
681 domain_state.created = base::Time::Now(); 392 HSTSEntry entry(include_subdomains, created, expiry);
682 domain_state.include_subdomains = include_subdomains; 393 if (AddDynamicEntry(hsts_entries_, hashed_host, entry)) {
683 domain_state.dynamic_spki_hashes_expiry = expiry; 394 StateIsDirty();
684 domain_state.dynamic_spki_hashes = hashes; 395 return true;
685 EnableHost(host, domain_state); 396 }
686 return true; 397 return false;
687 } 398 }
688 399
689 // static 400 bool TransportSecurityState::AddHPKPHashedHost(const std::string& hashed_host,
690 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host, 401 const base::Time& created,
691 bool sni_enabled) { 402 const base::Time& expiry,
692 std::string canonicalized_host = CanonicalizeHost(host); 403 bool include_subdomains,
693 const struct HSTSPreload* entry = 404 const HashValueVector& hashes) {
694 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); 405 if (hashes.empty())
695 406 return false;
696 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) 407 HPKPEntry entry(include_subdomains, created, expiry, hashes);
697 return true; 408 if (AddDynamicEntry(hpkp_entries_, hashed_host, entry)) {
698 409 StateIsDirty();
699 if (sni_enabled) { 410 return true;
700 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, 411 }
701 kNumPreloadedSNISTS); 412 return false;
702 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) 413 }
703 return true; 414
704 } 415 bool TransportSecurityState::DeleteHSTS(const std::string& host) {
705 416 if (DeleteDynamicEntry(hsts_entries_, HashHost(host))) {
706 return false; 417 StateIsDirty();
707 } 418 return true;
708 419 }
709 // static 420 return false;
710 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { 421 }
711 std::string canonicalized_host = CanonicalizeHost(host); 422
712 423 bool TransportSecurityState::DeleteHPKP(const std::string& host) {
713 const struct HSTSPreload* entry = 424 if (DeleteDynamicEntry(hpkp_entries_, HashHost(host))) {
714 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); 425 StateIsDirty();
715 426 return true;
716 if (!entry) { 427 }
717 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, 428 return false;
718 kNumPreloadedSNISTS); 429 }
719 } 430
720 431 const std::map<std::string, TransportSecurityState::HSTSEntry>&
721 if (!entry) { 432 TransportSecurityState::GetHSTSEntries() const {
722 // We don't care to report pin failures for dynamic pins. 433 return hsts_entries_;
723 return; 434 }
724 } 435
725 436 const std::map<std::string, TransportSecurityState::HPKPEntry>&
726 DCHECK(entry); 437 TransportSecurityState::GetHPKPEntries() const {
727 DCHECK(entry->pins.required_hashes); 438 return hpkp_entries_;
728 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED); 439 }
729 440
730 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", 441 void TransportSecurityState::StateIsDirty() {
731 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); 442 if (delegate_)
732 } 443 delegate_->StateIsDirty(this);
733 444 }
734 // static 445
735 bool TransportSecurityState::IsBuildTimely() { 446 bool TransportSecurityState::IsBuildTimely() {
736 const base::Time build_time = base::GetBuildTime(); 447 const base::Time build_time = base::GetBuildTime();
737 // We consider built-in information to be timely for 10 weeks. 448 // We consider built-in information to be timely for 10 weeks.
738 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; 449 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
739 } 450 }
740 451
741 bool TransportSecurityState::GetStaticDomainState( 452 // HSTSEntry and HPKPEntry
742 const std::string& canonicalized_host, 453
743 bool sni_enabled, 454 TransportSecurityState::HSTSEntry::HSTSEntry()
744 DomainState* out) { 455 : include_subdomains_(false),
745 DCHECK(CalledOnValidThread()); 456 created_(),
746 457 expiry_() {
747 out->upgrade_mode = DomainState::MODE_FORCE_HTTPS; 458 }
748 out->include_subdomains = false; 459
749 460 TransportSecurityState::HSTSEntry::~HSTSEntry() {
750 const bool is_build_timely = IsBuildTimely(); 461 }
751 462
752 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 463 TransportSecurityState::HSTSEntry::HSTSEntry(bool include_subdomains,
753 std::string host_sub_chunk(&canonicalized_host[i], 464 const base::Time& created,
754 canonicalized_host.size() - i); 465 const base::Time& expiry)
755 out->domain = DNSDomainToString(host_sub_chunk); 466 : include_subdomains_(include_subdomains),
756 std::string hashed_host(HashHost(host_sub_chunk)); 467 created_(created),
757 if (forced_hosts_.find(hashed_host) != forced_hosts_.end()) { 468 expiry_(expiry) {
758 *out = forced_hosts_[hashed_host]; 469 }
759 out->domain = DNSDomainToString(host_sub_chunk); 470
760 return true; 471 TransportSecurityState::HPKPEntry::HPKPEntry()
761 } 472 : include_subdomains_(false),
762 bool ret; 473 created_(),
763 if (is_build_timely && 474 expiry_(),
764 HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out, 475 good_hashes_() {
765 &ret)) { 476 }
766 return ret; 477
767 } 478 TransportSecurityState::HPKPEntry::~HPKPEntry() {
768 if (sni_enabled && 479 }
769 is_build_timely && 480
770 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i, 481 TransportSecurityState::HPKPEntry::HPKPEntry(
771 out, &ret)) { 482 bool include_subdomains,
772 return ret; 483 const base::Time& created,
773 } 484 const base::Time& expiry,
774 } 485 const HashValueVector& good_hashes)
775 486 : include_subdomains_(include_subdomains),
776 return false; 487 created_(created),
777 } 488 expiry_(expiry),
778 489 good_hashes_(good_hashes) {
779 void TransportSecurityState::AddOrUpdateEnabledHosts( 490 }
780 const std::string& hashed_host, const DomainState& state) { 491
781 enabled_hosts_[hashed_host] = state; 492 // DomainState
782 }
783
784 void TransportSecurityState::AddOrUpdateForcedHosts(
785 const std::string& hashed_host, const DomainState& state) {
786 forced_hosts_[hashed_host] = state;
787 }
788 493
789 TransportSecurityState::DomainState::DomainState() 494 TransportSecurityState::DomainState::DomainState()
790 : upgrade_mode(MODE_FORCE_HTTPS), 495 : should_upgrade_(false),
791 created(base::Time::Now()), 496 has_public_key_pins_(false),
792 include_subdomains(false) { 497 is_google_pinned_property_(false),
498 report_uma_on_pin_failure_(false),
499 public_key_pins_good_hashes_(),
500 public_key_pins_bad_hashes_(),
501 second_level_domain_name_(DOMAIN_NOT_PINNED) {
793 } 502 }
794 503
795 TransportSecurityState::DomainState::~DomainState() { 504 TransportSecurityState::DomainState::~DomainState() {
796 } 505 }
506 bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
507 return has_public_key_pins_;
508 }
797 509
798 bool TransportSecurityState::DomainState::CheckPublicKeyPins( 510 bool TransportSecurityState::DomainState::CheckPublicKeyPins(
799 const HashValueVector& hashes) const { 511 const HashValueVector& hashes) const {
800 // Validate that hashes is not empty. By the time this code is called (in 512 if (HashesIntersect(public_key_pins_bad_hashes_, hashes)) {
801 // production), that should never happen, but it's good to be defensive. 513 LOG(ERROR) << "Rejecting public key chain. Validated chain: "
802 // And, hashes *can* be empty in some test scenarios. 514 << HashesToBase64String(hashes)
803 if (hashes.empty()) { 515 << ", matches one or more bad hashes: "
804 LOG(ERROR) << "Rejecting empty public key chain for public-key-pinned " 516 << HashesToBase64String(public_key_pins_bad_hashes_);
805 "domain " << domain;
806 return false; 517 return false;
807 } 518 }
808 519
809 if (HashesIntersect(bad_static_spki_hashes, hashes)) { 520 // If there are no good pins, then any valid chain is acceptable.
810 LOG(ERROR) << "Rejecting public key chain for domain " << domain 521 // Otherwise, there has to be a match.
811 << ". Validated chain: " << HashesToBase64String(hashes) 522 if (public_key_pins_good_hashes_.empty() ||
812 << ", matches one or more bad hashes: " 523 HashesIntersect(public_key_pins_good_hashes_, hashes)) {
813 << HashesToBase64String(bad_static_spki_hashes); 524 return true;
814 return false; 525 }
815 } 526
816 527 LOG(ERROR) << "Rejecting public key chain. Validated chain: "
817 // If there are no pins, then any valid chain is acceptable. 528 << HashesToBase64String(hashes)
818 if (dynamic_spki_hashes.empty() && static_spki_hashes.empty()) 529 << ", expected: "
819 return true; 530 << HashesToBase64String(public_key_pins_good_hashes_);
820
821 if (HashesIntersect(dynamic_spki_hashes, hashes) ||
822 HashesIntersect(static_spki_hashes, hashes)) {
823 return true;
824 }
825
826 LOG(ERROR) << "Rejecting public key chain for domain " << domain
827 << ". Validated chain: " << HashesToBase64String(hashes)
828 << ", expected: " << HashesToBase64String(dynamic_spki_hashes)
829 << " or: " << HashesToBase64String(static_spki_hashes);
830 return false; 531 return false;
831 } 532 }
832 533
833 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const { 534 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
834 return upgrade_mode == MODE_FORCE_HTTPS; 535 return should_upgrade_;
835 } 536 }
836 537
837 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const { 538 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
838 return true; 539 return should_upgrade_;
839 } 540 }
840 541
841 bool TransportSecurityState::DomainState::Equals( 542 bool TransportSecurityState::DomainState::IsGooglePinnedProperty() const {
842 const DomainState& other) const { 543 return is_google_pinned_property_;
843 // TODO(palmer): Implement this 544 }
844 (void) other; 545
845 return true; 546 void TransportSecurityState::DomainState::ReportUMAOnPinFailure() const {
846 } 547 if (report_uma_on_pin_failure_) {
847 548 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain",
848 bool TransportSecurityState::DomainState::HasPublicKeyPins() const { 549 second_level_domain_name_, DOMAIN_NUM_EVENTS);
849 return static_spki_hashes.size() > 0 || 550 }
850 bad_static_spki_hashes.size() > 0 || 551 }
851 dynamic_spki_hashes.size() > 0; 552
553 const HashValueVector&
554 TransportSecurityState::DomainState::GetPublicKeyPinsGoodHashes() const {
555 return public_key_pins_good_hashes_;
556 }
557
558 const HashValueVector&
559 TransportSecurityState::DomainState::GetPublicKeyPinsBadHashes() const {
560 return public_key_pins_bad_hashes_;
852 } 561 }
853 562
854 } // namespace 563 } // namespace
OLDNEW
« no previous file with comments | « net/base/transport_security_state.h ('k') | net/base/transport_security_state_preload.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698