OLD | NEW |
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/http/transport_security_state.h" | 5 #include "net/http/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) |
(...skipping 27 matching lines...) Expand all Loading... |
38 #include "url/gurl.h" | 38 #include "url/gurl.h" |
39 | 39 |
40 #if defined(USE_OPENSSL) | 40 #if defined(USE_OPENSSL) |
41 #include "crypto/openssl_util.h" | 41 #include "crypto/openssl_util.h" |
42 #endif | 42 #endif |
43 | 43 |
44 namespace net { | 44 namespace net { |
45 | 45 |
46 namespace { | 46 namespace { |
47 | 47 |
| 48 #include "net/http/transport_security_state_static.h" |
| 49 |
48 std::string HashesToBase64String(const HashValueVector& hashes) { | 50 std::string HashesToBase64String(const HashValueVector& hashes) { |
49 std::string str; | 51 std::string str; |
50 for (size_t i = 0; i != hashes.size(); ++i) { | 52 for (size_t i = 0; i != hashes.size(); ++i) { |
51 if (i != 0) | 53 if (i != 0) |
52 str += ","; | 54 str += ","; |
53 str += hashes[i].ToString(); | 55 str += hashes[i].ToString(); |
54 } | 56 } |
55 return str; | 57 return str; |
56 } | 58 } |
57 | 59 |
(...skipping 17 matching lines...) Expand all Loading... |
75 } | 77 } |
76 | 78 |
77 bool AddHash(const char* sha1_hash, | 79 bool AddHash(const char* sha1_hash, |
78 HashValueVector* out) { | 80 HashValueVector* out) { |
79 HashValue hash(HASH_VALUE_SHA1); | 81 HashValue hash(HASH_VALUE_SHA1); |
80 memcpy(hash.data(), sha1_hash, hash.size()); | 82 memcpy(hash.data(), sha1_hash, hash.size()); |
81 out->push_back(hash); | 83 out->push_back(hash); |
82 return true; | 84 return true; |
83 } | 85 } |
84 | 86 |
85 } // namespace | 87 // Converts |hostname| from dotted form ("www.google.com") to the form |
86 | 88 // used in DNS: "\x03www\x06google\x03com", lowercases that, and returns |
87 TransportSecurityState::TransportSecurityState() | 89 // the result. |
88 : delegate_(NULL), enable_static_pins_(true) { | 90 std::string CanonicalizeHost(const std::string& host) { |
89 // Static pinning is only enabled for official builds to make sure that | |
90 // others don't end up with pins that cannot be easily updated. | |
91 #if !defined(OFFICIAL_BUILD) || defined(OS_ANDROID) || defined(OS_IOS) | |
92 enable_static_pins_ = false; | |
93 #endif | |
94 DCHECK(CalledOnValidThread()); | |
95 } | |
96 | |
97 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) | |
98 : iterator_(state.enabled_hosts_.begin()), | |
99 end_(state.enabled_hosts_.end()) { | |
100 } | |
101 | |
102 TransportSecurityState::Iterator::~Iterator() {} | |
103 | |
104 bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host) { | |
105 DomainState state; | |
106 if (GetStaticDomainState(host, &state)) | |
107 return true; | |
108 return GetDynamicDomainState(host, &state); | |
109 } | |
110 | |
111 bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host) { | |
112 DomainState dynamic_state; | |
113 if (GetDynamicDomainState(host, &dynamic_state)) | |
114 return dynamic_state.ShouldUpgradeToSSL(); | |
115 | |
116 DomainState static_state; | |
117 if (GetStaticDomainState(host, &static_state) && | |
118 static_state.ShouldUpgradeToSSL()) { | |
119 return true; | |
120 } | |
121 | |
122 return false; | |
123 } | |
124 | |
125 bool TransportSecurityState::CheckPublicKeyPins( | |
126 const std::string& host, | |
127 bool is_issued_by_known_root, | |
128 const HashValueVector& public_key_hashes, | |
129 std::string* pinning_failure_log) { | |
130 // Perform pin validation if, and only if, all these conditions obtain: | |
131 // | |
132 // * the server's certificate chain chains up to a known root (i.e. not a | |
133 // user-installed trust anchor); and | |
134 // * the server actually has public key pins. | |
135 if (!is_issued_by_known_root || !HasPublicKeyPins(host)) { | |
136 return true; | |
137 } | |
138 | |
139 bool pins_are_valid = CheckPublicKeyPinsImpl( | |
140 host, public_key_hashes, pinning_failure_log); | |
141 if (!pins_are_valid) { | |
142 LOG(ERROR) << *pinning_failure_log; | |
143 ReportUMAOnPinFailure(host); | |
144 } | |
145 | |
146 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid); | |
147 return pins_are_valid; | |
148 } | |
149 | |
150 bool TransportSecurityState::HasPublicKeyPins(const std::string& host) { | |
151 DomainState dynamic_state; | |
152 if (GetDynamicDomainState(host, &dynamic_state)) | |
153 return dynamic_state.HasPublicKeyPins(); | |
154 | |
155 DomainState static_state; | |
156 if (GetStaticDomainState(host, &static_state)) { | |
157 if (static_state.HasPublicKeyPins()) | |
158 return true; | |
159 } | |
160 | |
161 return false; | |
162 } | |
163 | |
164 void TransportSecurityState::SetDelegate( | |
165 TransportSecurityState::Delegate* delegate) { | |
166 DCHECK(CalledOnValidThread()); | |
167 delegate_ = delegate; | |
168 } | |
169 | |
170 void TransportSecurityState::AddHSTSInternal( | |
171 const std::string& host, | |
172 TransportSecurityState::DomainState::UpgradeMode upgrade_mode, | |
173 const base::Time& expiry, | |
174 bool include_subdomains) { | |
175 DCHECK(CalledOnValidThread()); | |
176 | |
177 // Copy-and-modify the existing DomainState for this host (if any). | |
178 DomainState domain_state; | |
179 const std::string canonicalized_host = CanonicalizeHost(host); | |
180 const std::string hashed_host = HashHost(canonicalized_host); | |
181 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); | |
182 if (i != enabled_hosts_.end()) | |
183 domain_state = i->second; | |
184 | |
185 domain_state.sts.last_observed = base::Time::Now(); | |
186 domain_state.sts.include_subdomains = include_subdomains; | |
187 domain_state.sts.expiry = expiry; | |
188 domain_state.sts.upgrade_mode = upgrade_mode; | |
189 EnableHost(host, domain_state); | |
190 } | |
191 | |
192 void TransportSecurityState::AddHPKPInternal(const std::string& host, | |
193 const base::Time& last_observed, | |
194 const base::Time& expiry, | |
195 bool include_subdomains, | |
196 const HashValueVector& hashes) { | |
197 DCHECK(CalledOnValidThread()); | |
198 | |
199 // Copy-and-modify the existing DomainState for this host (if any). | |
200 DomainState domain_state; | |
201 const std::string canonicalized_host = CanonicalizeHost(host); | |
202 const std::string hashed_host = HashHost(canonicalized_host); | |
203 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); | |
204 if (i != enabled_hosts_.end()) | |
205 domain_state = i->second; | |
206 | |
207 domain_state.pkp.last_observed = last_observed; | |
208 domain_state.pkp.expiry = expiry; | |
209 domain_state.pkp.include_subdomains = include_subdomains; | |
210 domain_state.pkp.spki_hashes = hashes; | |
211 EnableHost(host, domain_state); | |
212 } | |
213 | |
214 void TransportSecurityState::EnableHost(const std::string& host, | |
215 const DomainState& state) { | |
216 DCHECK(CalledOnValidThread()); | |
217 | |
218 const std::string canonicalized_host = CanonicalizeHost(host); | |
219 if (canonicalized_host.empty()) | |
220 return; | |
221 | |
222 DomainState state_copy(state); | |
223 // No need to store this value since it is redundant. (|canonicalized_host| | |
224 // is the map key.) | |
225 state_copy.sts.domain.clear(); | |
226 state_copy.pkp.domain.clear(); | |
227 | |
228 enabled_hosts_[HashHost(canonicalized_host)] = state_copy; | |
229 DirtyNotify(); | |
230 } | |
231 | |
232 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { | |
233 DCHECK(CalledOnValidThread()); | |
234 | |
235 const std::string canonicalized_host = CanonicalizeHost(host); | |
236 if (canonicalized_host.empty()) | |
237 return false; | |
238 | |
239 DomainStateMap::iterator i = enabled_hosts_.find( | |
240 HashHost(canonicalized_host)); | |
241 if (i != enabled_hosts_.end()) { | |
242 enabled_hosts_.erase(i); | |
243 DirtyNotify(); | |
244 return true; | |
245 } | |
246 return false; | |
247 } | |
248 | |
249 void TransportSecurityState::ClearDynamicData() { | |
250 DCHECK(CalledOnValidThread()); | |
251 enabled_hosts_.clear(); | |
252 } | |
253 | |
254 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) { | |
255 DCHECK(CalledOnValidThread()); | |
256 | |
257 bool dirtied = false; | |
258 DomainStateMap::iterator i = enabled_hosts_.begin(); | |
259 while (i != enabled_hosts_.end()) { | |
260 // Clear STS and PKP state independently. | |
261 if (i->second.sts.last_observed >= time) { | |
262 dirtied = true; | |
263 i->second.sts.upgrade_mode = DomainState::MODE_DEFAULT; | |
264 } | |
265 if (i->second.pkp.last_observed >= time) { | |
266 dirtied = true; | |
267 i->second.pkp.spki_hashes.clear(); | |
268 i->second.pkp.expiry = base::Time(); | |
269 } | |
270 | |
271 // If both are now invalid, drop the entry altogether. | |
272 if (!i->second.ShouldUpgradeToSSL() && !i->second.HasPublicKeyPins()) { | |
273 dirtied = true; | |
274 enabled_hosts_.erase(i++); | |
275 continue; | |
276 } | |
277 | |
278 ++i; | |
279 } | |
280 | |
281 if (dirtied) | |
282 DirtyNotify(); | |
283 } | |
284 | |
285 TransportSecurityState::~TransportSecurityState() { | |
286 DCHECK(CalledOnValidThread()); | |
287 } | |
288 | |
289 void TransportSecurityState::DirtyNotify() { | |
290 DCHECK(CalledOnValidThread()); | |
291 | |
292 if (delegate_) | |
293 delegate_->StateIsDirty(this); | |
294 } | |
295 | |
296 // static | |
297 std::string TransportSecurityState::CanonicalizeHost(const std::string& host) { | |
298 // We cannot perform the operations as detailed in the spec here as |host| | 91 // We cannot perform the operations as detailed in the spec here as |host| |
299 // has already undergone IDN processing before it reached us. Thus, we check | 92 // has already undergone IDN processing before it reached us. Thus, we check |
300 // that there are no invalid characters in the host and lowercase the result. | 93 // that there are no invalid characters in the host and lowercase the result. |
301 | |
302 std::string new_host; | 94 std::string new_host; |
303 if (!DNSDomainFromDot(host, &new_host)) { | 95 if (!DNSDomainFromDot(host, &new_host)) { |
304 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole | 96 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole |
305 // name is >255 bytes. However, search terms can have those properties. | 97 // name is >255 bytes. However, search terms can have those properties. |
306 return std::string(); | 98 return std::string(); |
307 } | 99 } |
308 | 100 |
309 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) { | 101 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) { |
310 const unsigned label_length = static_cast<unsigned>(new_host[i]); | 102 const unsigned label_length = static_cast<unsigned>(new_host[i]); |
311 if (!label_length) | 103 if (!label_length) |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 | 239 |
448 current = &tree_[offset]; | 240 current = &tree_[offset]; |
449 } | 241 } |
450 } | 242 } |
451 | 243 |
452 private: | 244 private: |
453 const uint8* const tree_; | 245 const uint8* const tree_; |
454 const size_t tree_bytes_; | 246 const size_t tree_bytes_; |
455 }; | 247 }; |
456 | 248 |
457 #include "net/http/transport_security_state_static.h" | |
458 | |
459 // PreloadResult is the result of resolving a specific name in the preloaded | 249 // PreloadResult is the result of resolving a specific name in the preloaded |
460 // data. | 250 // data. |
461 struct PreloadResult { | 251 struct PreloadResult { |
462 uint32 pinset_id; | 252 uint32 pinset_id; |
463 uint32 domain_id; | 253 uint32 domain_id; |
464 // hostname_offset contains the number of bytes from the start of the given | 254 // hostname_offset contains the number of bytes from the start of the given |
465 // hostname where the name of the matching entry starts. | 255 // hostname where the name of the matching entry starts. |
466 size_t hostname_offset; | 256 size_t hostname_offset; |
467 bool sts_include_subdomains; | 257 bool sts_include_subdomains; |
468 bool pkp_include_subdomains; | 258 bool pkp_include_subdomains; |
(...skipping 19 matching lines...) Expand all Loading... |
488 // In the dispatch table, the zero character represents the "end of string" | 278 // In the dispatch table, the zero character represents the "end of string" |
489 // (which is the *beginning* of a hostname since we process it backwards). The | 279 // (which is the *beginning* of a hostname since we process it backwards). The |
490 // value in that case is special -- rather than an offset to another trie node, | 280 // value in that case is special -- rather than an offset to another trie node, |
491 // it contains the HSTS information: whether subdomains are included, pinsets | 281 // it contains the HSTS information: whether subdomains are included, pinsets |
492 // etc. If an "end of string" matches a period in the hostname then the | 282 // etc. If an "end of string" matches a period in the hostname then the |
493 // information is remembered because, if no more specific node is found, then | 283 // information is remembered because, if no more specific node is found, then |
494 // that information applies to the hostname. | 284 // that information applies to the hostname. |
495 // | 285 // |
496 // Dispatch tables are always given in order, but the "end of string" (zero) | 286 // Dispatch tables are always given in order, but the "end of string" (zero) |
497 // value always comes before an entry for '.'. | 287 // value always comes before an entry for '.'. |
498 bool DecodeHSTSPreloadRaw(const std::string& hostname, | 288 bool DecodeHSTSPreloadRaw(const std::string& search_hostname, |
499 bool* out_found, | 289 bool* out_found, |
500 PreloadResult* out) { | 290 PreloadResult* out) { |
501 HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree)); | 291 HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree)); |
502 BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits); | 292 BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits); |
503 size_t bit_offset = kHSTSRootPosition; | 293 size_t bit_offset = kHSTSRootPosition; |
504 static const char kEndOfString = 0; | 294 static const char kEndOfString = 0; |
505 static const char kEndOfTable = 127; | 295 static const char kEndOfTable = 127; |
506 | 296 |
507 *out_found = false; | 297 *out_found = false; |
508 | 298 |
| 299 // Ensure that |search_hostname| is a valid hostname before |
| 300 // processing. |
| 301 if (CanonicalizeHost(search_hostname).empty()) { |
| 302 return true; |
| 303 } |
| 304 |
| 305 // Normalize any trailing '.' used for DNS suffix searches. |
| 306 std::string hostname = search_hostname; |
| 307 size_t found = hostname.find_last_not_of('.'); |
| 308 if (found != std::string::npos) { |
| 309 hostname.erase(found + 1); |
| 310 } else { |
| 311 hostname.clear(); |
| 312 } |
| 313 |
| 314 // |hostname| has already undergone IDN conversion, so should be |
| 315 // entirely A-Labels. The preload data is entirely normalized to |
| 316 // lower case. |
| 317 base::StringToLowerASCII(&hostname); |
| 318 |
509 if (hostname.empty()) { | 319 if (hostname.empty()) { |
510 return true; | 320 return true; |
511 } | 321 } |
| 322 |
512 // hostname_offset contains one more than the index of the current character | 323 // hostname_offset contains one more than the index of the current character |
513 // in the hostname that is being considered. It's one greater so that we can | 324 // in the hostname that is being considered. It's one greater so that we can |
514 // represent the position just before the beginning (with zero). | 325 // represent the position just before the beginning (with zero). |
515 size_t hostname_offset = hostname.size(); | 326 size_t hostname_offset = hostname.size(); |
516 | 327 |
517 for (;;) { | 328 for (;;) { |
518 // Seek to the desired location. | 329 // Seek to the desired location. |
519 if (!reader.Seek(bit_offset)) { | 330 if (!reader.Seek(bit_offset)) { |
520 return false; | 331 return false; |
521 } | 332 } |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
656 bool found; | 467 bool found; |
657 if (!DecodeHSTSPreloadRaw(hostname, &found, out)) { | 468 if (!DecodeHSTSPreloadRaw(hostname, &found, out)) { |
658 DCHECK(false) << "Internal error in DecodeHSTSPreloadRaw for hostname " | 469 DCHECK(false) << "Internal error in DecodeHSTSPreloadRaw for hostname " |
659 << hostname; | 470 << hostname; |
660 return false; | 471 return false; |
661 } | 472 } |
662 | 473 |
663 return found; | 474 return found; |
664 } | 475 } |
665 | 476 |
| 477 } // namespace |
| 478 |
| 479 TransportSecurityState::TransportSecurityState() |
| 480 : delegate_(NULL), enable_static_pins_(true) { |
| 481 // Static pinning is only enabled for official builds to make sure that |
| 482 // others don't end up with pins that cannot be easily updated. |
| 483 #if !defined(OFFICIAL_BUILD) || defined(OS_ANDROID) || defined(OS_IOS) |
| 484 enable_static_pins_ = false; |
| 485 #endif |
| 486 DCHECK(CalledOnValidThread()); |
| 487 } |
| 488 |
| 489 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) |
| 490 : iterator_(state.enabled_hosts_.begin()), |
| 491 end_(state.enabled_hosts_.end()) { |
| 492 } |
| 493 |
| 494 TransportSecurityState::Iterator::~Iterator() { |
| 495 } |
| 496 |
| 497 bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host) { |
| 498 DomainState state; |
| 499 if (GetStaticDomainState(host, &state)) |
| 500 return true; |
| 501 return GetDynamicDomainState(host, &state); |
| 502 } |
| 503 |
| 504 bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host) { |
| 505 DomainState dynamic_state; |
| 506 if (GetDynamicDomainState(host, &dynamic_state)) |
| 507 return dynamic_state.ShouldUpgradeToSSL(); |
| 508 |
| 509 DomainState static_state; |
| 510 if (GetStaticDomainState(host, &static_state) && |
| 511 static_state.ShouldUpgradeToSSL()) { |
| 512 return true; |
| 513 } |
| 514 |
| 515 return false; |
| 516 } |
| 517 |
| 518 bool TransportSecurityState::CheckPublicKeyPins( |
| 519 const std::string& host, |
| 520 bool is_issued_by_known_root, |
| 521 const HashValueVector& public_key_hashes, |
| 522 std::string* pinning_failure_log) { |
| 523 // Perform pin validation if, and only if, all these conditions obtain: |
| 524 // |
| 525 // * the server's certificate chain chains up to a known root (i.e. not a |
| 526 // user-installed trust anchor); and |
| 527 // * the server actually has public key pins. |
| 528 if (!is_issued_by_known_root || !HasPublicKeyPins(host)) { |
| 529 return true; |
| 530 } |
| 531 |
| 532 bool pins_are_valid = |
| 533 CheckPublicKeyPinsImpl(host, public_key_hashes, pinning_failure_log); |
| 534 if (!pins_are_valid) { |
| 535 LOG(ERROR) << *pinning_failure_log; |
| 536 ReportUMAOnPinFailure(host); |
| 537 } |
| 538 |
| 539 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid); |
| 540 return pins_are_valid; |
| 541 } |
| 542 |
| 543 bool TransportSecurityState::HasPublicKeyPins(const std::string& host) { |
| 544 DomainState dynamic_state; |
| 545 if (GetDynamicDomainState(host, &dynamic_state)) |
| 546 return dynamic_state.HasPublicKeyPins(); |
| 547 |
| 548 DomainState static_state; |
| 549 if (GetStaticDomainState(host, &static_state)) { |
| 550 if (static_state.HasPublicKeyPins()) |
| 551 return true; |
| 552 } |
| 553 |
| 554 return false; |
| 555 } |
| 556 |
| 557 void TransportSecurityState::SetDelegate( |
| 558 TransportSecurityState::Delegate* delegate) { |
| 559 DCHECK(CalledOnValidThread()); |
| 560 delegate_ = delegate; |
| 561 } |
| 562 |
| 563 void TransportSecurityState::AddHSTSInternal( |
| 564 const std::string& host, |
| 565 TransportSecurityState::DomainState::UpgradeMode upgrade_mode, |
| 566 const base::Time& expiry, |
| 567 bool include_subdomains) { |
| 568 DCHECK(CalledOnValidThread()); |
| 569 |
| 570 // Copy-and-modify the existing DomainState for this host (if any). |
| 571 DomainState domain_state; |
| 572 const std::string canonicalized_host = CanonicalizeHost(host); |
| 573 const std::string hashed_host = HashHost(canonicalized_host); |
| 574 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); |
| 575 if (i != enabled_hosts_.end()) |
| 576 domain_state = i->second; |
| 577 |
| 578 domain_state.sts.last_observed = base::Time::Now(); |
| 579 domain_state.sts.include_subdomains = include_subdomains; |
| 580 domain_state.sts.expiry = expiry; |
| 581 domain_state.sts.upgrade_mode = upgrade_mode; |
| 582 EnableHost(host, domain_state); |
| 583 } |
| 584 |
| 585 void TransportSecurityState::AddHPKPInternal(const std::string& host, |
| 586 const base::Time& last_observed, |
| 587 const base::Time& expiry, |
| 588 bool include_subdomains, |
| 589 const HashValueVector& hashes) { |
| 590 DCHECK(CalledOnValidThread()); |
| 591 |
| 592 // Copy-and-modify the existing DomainState for this host (if any). |
| 593 DomainState domain_state; |
| 594 const std::string canonicalized_host = CanonicalizeHost(host); |
| 595 const std::string hashed_host = HashHost(canonicalized_host); |
| 596 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); |
| 597 if (i != enabled_hosts_.end()) |
| 598 domain_state = i->second; |
| 599 |
| 600 domain_state.pkp.last_observed = last_observed; |
| 601 domain_state.pkp.expiry = expiry; |
| 602 domain_state.pkp.include_subdomains = include_subdomains; |
| 603 domain_state.pkp.spki_hashes = hashes; |
| 604 EnableHost(host, domain_state); |
| 605 } |
| 606 |
| 607 void TransportSecurityState::EnableHost(const std::string& host, |
| 608 const DomainState& state) { |
| 609 DCHECK(CalledOnValidThread()); |
| 610 |
| 611 const std::string canonicalized_host = CanonicalizeHost(host); |
| 612 if (canonicalized_host.empty()) |
| 613 return; |
| 614 |
| 615 DomainState state_copy(state); |
| 616 // No need to store this value since it is redundant. (|canonicalized_host| |
| 617 // is the map key.) |
| 618 state_copy.sts.domain.clear(); |
| 619 state_copy.pkp.domain.clear(); |
| 620 |
| 621 enabled_hosts_[HashHost(canonicalized_host)] = state_copy; |
| 622 DirtyNotify(); |
| 623 } |
| 624 |
| 625 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { |
| 626 DCHECK(CalledOnValidThread()); |
| 627 |
| 628 const std::string canonicalized_host = CanonicalizeHost(host); |
| 629 if (canonicalized_host.empty()) |
| 630 return false; |
| 631 |
| 632 DomainStateMap::iterator i = |
| 633 enabled_hosts_.find(HashHost(canonicalized_host)); |
| 634 if (i != enabled_hosts_.end()) { |
| 635 enabled_hosts_.erase(i); |
| 636 DirtyNotify(); |
| 637 return true; |
| 638 } |
| 639 return false; |
| 640 } |
| 641 |
| 642 void TransportSecurityState::ClearDynamicData() { |
| 643 DCHECK(CalledOnValidThread()); |
| 644 enabled_hosts_.clear(); |
| 645 } |
| 646 |
| 647 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) { |
| 648 DCHECK(CalledOnValidThread()); |
| 649 |
| 650 bool dirtied = false; |
| 651 DomainStateMap::iterator i = enabled_hosts_.begin(); |
| 652 while (i != enabled_hosts_.end()) { |
| 653 // Clear STS and PKP state independently. |
| 654 if (i->second.sts.last_observed >= time) { |
| 655 dirtied = true; |
| 656 i->second.sts.upgrade_mode = DomainState::MODE_DEFAULT; |
| 657 } |
| 658 if (i->second.pkp.last_observed >= time) { |
| 659 dirtied = true; |
| 660 i->second.pkp.spki_hashes.clear(); |
| 661 i->second.pkp.expiry = base::Time(); |
| 662 } |
| 663 |
| 664 // If both are now invalid, drop the entry altogether. |
| 665 if (!i->second.ShouldUpgradeToSSL() && !i->second.HasPublicKeyPins()) { |
| 666 dirtied = true; |
| 667 enabled_hosts_.erase(i++); |
| 668 continue; |
| 669 } |
| 670 |
| 671 ++i; |
| 672 } |
| 673 |
| 674 if (dirtied) |
| 675 DirtyNotify(); |
| 676 } |
| 677 |
| 678 TransportSecurityState::~TransportSecurityState() { |
| 679 DCHECK(CalledOnValidThread()); |
| 680 } |
| 681 |
| 682 void TransportSecurityState::DirtyNotify() { |
| 683 DCHECK(CalledOnValidThread()); |
| 684 |
| 685 if (delegate_) |
| 686 delegate_->StateIsDirty(this); |
| 687 } |
| 688 |
666 bool TransportSecurityState::AddHSTSHeader(const std::string& host, | 689 bool TransportSecurityState::AddHSTSHeader(const std::string& host, |
667 const std::string& value) { | 690 const std::string& value) { |
668 DCHECK(CalledOnValidThread()); | 691 DCHECK(CalledOnValidThread()); |
669 | 692 |
670 base::Time now = base::Time::Now(); | 693 base::Time now = base::Time::Now(); |
671 base::TimeDelta max_age; | 694 base::TimeDelta max_age; |
672 bool include_subdomains; | 695 bool include_subdomains; |
673 if (!ParseHSTSHeader(value, &max_age, &include_subdomains)) { | 696 if (!ParseHSTSHeader(value, &max_age, &include_subdomains)) { |
674 return false; | 697 return false; |
675 } | 698 } |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
970 TransportSecurityState::DomainState::STSState::~STSState() { | 993 TransportSecurityState::DomainState::STSState::~STSState() { |
971 } | 994 } |
972 | 995 |
973 TransportSecurityState::DomainState::PKPState::PKPState() { | 996 TransportSecurityState::DomainState::PKPState::PKPState() { |
974 } | 997 } |
975 | 998 |
976 TransportSecurityState::DomainState::PKPState::~PKPState() { | 999 TransportSecurityState::DomainState::PKPState::~PKPState() { |
977 } | 1000 } |
978 | 1001 |
979 } // namespace | 1002 } // namespace |
OLD | NEW |