| 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 |