| 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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 } | 55 } |
| 56 | 56 |
| 57 std::string HashHost(const std::string& canonicalized_host) { | 57 std::string HashHost(const std::string& canonicalized_host) { |
| 58 char hashed[crypto::kSHA256Length]; | 58 char hashed[crypto::kSHA256Length]; |
| 59 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); | 59 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); |
| 60 return std::string(hashed, sizeof(hashed)); | 60 return std::string(hashed, sizeof(hashed)); |
| 61 } | 61 } |
| 62 | 62 |
| 63 // Returns true if the intersection of |a| and |b| is not empty. If either | 63 // Returns true if the intersection of |a| and |b| is not empty. If either |
| 64 // |a| or |b| is empty, returns false. | 64 // |a| or |b| is empty, returns false. |
| 65 bool HashesIntersect(const HashValueVector& a, | 65 bool HashesIntersect(const HashValueVector& a, const HashValueVector& b) { |
| 66 const HashValueVector& b) { | |
| 67 for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) { | 66 for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) { |
| 68 HashValueVector::const_iterator j = | 67 HashValueVector::const_iterator j = |
| 69 std::find_if(b.begin(), b.end(), HashValuesEqual(*i)); | 68 std::find_if(b.begin(), b.end(), HashValuesEqual(*i)); |
| 70 if (j != b.end()) | 69 if (j != b.end()) |
| 71 return true; | 70 return true; |
| 72 } | 71 } |
| 73 return false; | 72 return false; |
| 74 } | 73 } |
| 75 | 74 |
| 76 bool AddHash(const char* sha1_hash, | 75 bool AddHash(const char* sha1_hash, HashValueVector* out) { |
| 77 HashValueVector* out) { | |
| 78 HashValue hash(HASH_VALUE_SHA1); | 76 HashValue hash(HASH_VALUE_SHA1); |
| 79 memcpy(hash.data(), sha1_hash, hash.size()); | 77 memcpy(hash.data(), sha1_hash, hash.size()); |
| 80 out->push_back(hash); | 78 out->push_back(hash); |
| 81 return true; | 79 return true; |
| 82 } | 80 } |
| 83 | 81 |
| 84 } // namespace | 82 } // namespace |
| 85 | 83 |
| 86 TransportSecurityState::TransportSecurityState() | 84 TransportSecurityState::TransportSecurityState() : delegate_(NULL) { |
| 87 : delegate_(NULL) { | |
| 88 DCHECK(CalledOnValidThread()); | 85 DCHECK(CalledOnValidThread()); |
| 89 } | 86 } |
| 90 | 87 |
| 91 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) | 88 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) |
| 92 : iterator_(state.enabled_hosts_.begin()), | 89 : iterator_(state.enabled_hosts_.begin()), |
| 93 end_(state.enabled_hosts_.end()) { | 90 end_(state.enabled_hosts_.end()) { |
| 94 } | 91 } |
| 95 | 92 |
| 96 TransportSecurityState::Iterator::~Iterator() {} | 93 TransportSecurityState::Iterator::~Iterator() { |
| 94 } |
| 97 | 95 |
| 98 void TransportSecurityState::SetDelegate( | 96 void TransportSecurityState::SetDelegate( |
| 99 TransportSecurityState::Delegate* delegate) { | 97 TransportSecurityState::Delegate* delegate) { |
| 100 DCHECK(CalledOnValidThread()); | 98 DCHECK(CalledOnValidThread()); |
| 101 delegate_ = delegate; | 99 delegate_ = delegate; |
| 102 } | 100 } |
| 103 | 101 |
| 104 void TransportSecurityState::EnableHost(const std::string& host, | 102 void TransportSecurityState::EnableHost(const std::string& host, |
| 105 const DomainState& state) { | 103 const DomainState& state) { |
| 106 DCHECK(CalledOnValidThread()); | 104 DCHECK(CalledOnValidThread()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 118 DirtyNotify(); | 116 DirtyNotify(); |
| 119 } | 117 } |
| 120 | 118 |
| 121 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { | 119 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { |
| 122 DCHECK(CalledOnValidThread()); | 120 DCHECK(CalledOnValidThread()); |
| 123 | 121 |
| 124 const std::string canonicalized_host = CanonicalizeHost(host); | 122 const std::string canonicalized_host = CanonicalizeHost(host); |
| 125 if (canonicalized_host.empty()) | 123 if (canonicalized_host.empty()) |
| 126 return false; | 124 return false; |
| 127 | 125 |
| 128 DomainStateMap::iterator i = enabled_hosts_.find( | 126 DomainStateMap::iterator i = |
| 129 HashHost(canonicalized_host)); | 127 enabled_hosts_.find(HashHost(canonicalized_host)); |
| 130 if (i != enabled_hosts_.end()) { | 128 if (i != enabled_hosts_.end()) { |
| 131 enabled_hosts_.erase(i); | 129 enabled_hosts_.erase(i); |
| 132 DirtyNotify(); | 130 DirtyNotify(); |
| 133 return true; | 131 return true; |
| 134 } | 132 } |
| 135 return false; | 133 return false; |
| 136 } | 134 } |
| 137 | 135 |
| 138 bool TransportSecurityState::GetDomainState(const std::string& host, | 136 bool TransportSecurityState::GetDomainState(const std::string& host, |
| 139 bool sni_enabled, | 137 bool sni_enabled, |
| 140 DomainState* result) { | 138 DomainState* result) { |
| 141 DCHECK(CalledOnValidThread()); | 139 DCHECK(CalledOnValidThread()); |
| 142 | 140 |
| 143 DomainState state; | 141 DomainState state; |
| 144 const std::string canonicalized_host = CanonicalizeHost(host); | 142 const std::string canonicalized_host = CanonicalizeHost(host); |
| 145 if (canonicalized_host.empty()) | 143 if (canonicalized_host.empty()) |
| 146 return false; | 144 return false; |
| 147 | 145 |
| 148 bool has_preload = GetStaticDomainState(canonicalized_host, sni_enabled, | 146 bool has_preload = |
| 149 &state); | 147 GetStaticDomainState(canonicalized_host, sni_enabled, &state); |
| 150 std::string canonicalized_preload = CanonicalizeHost(state.domain); | 148 std::string canonicalized_preload = CanonicalizeHost(state.domain); |
| 151 GetDynamicDomainState(host, &state); | 149 GetDynamicDomainState(host, &state); |
| 152 | 150 |
| 153 base::Time current_time(base::Time::Now()); | 151 base::Time current_time(base::Time::Now()); |
| 154 | 152 |
| 155 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { | 153 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
| 156 std::string host_sub_chunk(&canonicalized_host[i], | 154 std::string host_sub_chunk(&canonicalized_host[i], |
| 157 canonicalized_host.size() - i); | 155 canonicalized_host.size() - i); |
| 158 // Exact match of a preload always wins. | 156 // Exact match of a preload always wins. |
| 159 if (has_preload && host_sub_chunk == canonicalized_preload) { | 157 if (has_preload && host_sub_chunk == canonicalized_preload) { |
| 160 *result = state; | 158 *result = state; |
| 161 return true; | 159 return true; |
| 162 } | 160 } |
| 163 | 161 |
| 164 DomainStateMap::iterator j = | 162 DomainStateMap::iterator j = enabled_hosts_.find(HashHost(host_sub_chunk)); |
| 165 enabled_hosts_.find(HashHost(host_sub_chunk)); | |
| 166 if (j == enabled_hosts_.end()) | 163 if (j == enabled_hosts_.end()) |
| 167 continue; | 164 continue; |
| 168 | 165 |
| 169 if (current_time > j->second.upgrade_expiry && | 166 if (current_time > j->second.upgrade_expiry && |
| 170 current_time > j->second.dynamic_spki_hashes_expiry) { | 167 current_time > j->second.dynamic_spki_hashes_expiry) { |
| 171 enabled_hosts_.erase(j); | 168 enabled_hosts_.erase(j); |
| 172 DirtyNotify(); | 169 DirtyNotify(); |
| 173 continue; | 170 continue; |
| 174 } | 171 } |
| 175 | 172 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 return new_host; | 255 return new_host; |
| 259 } | 256 } |
| 260 | 257 |
| 261 // |ReportUMAOnPinFailure| uses these to report which domain was associated | 258 // |ReportUMAOnPinFailure| uses these to report which domain was associated |
| 262 // with the public key pinning failure. | 259 // with the public key pinning failure. |
| 263 // | 260 // |
| 264 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new | 261 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new |
| 265 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS). | 262 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS). |
| 266 enum SecondLevelDomainName { | 263 enum SecondLevelDomainName { |
| 267 DOMAIN_NOT_PINNED, | 264 DOMAIN_NOT_PINNED, |
| 268 | |
| 269 DOMAIN_GOOGLE_COM, | 265 DOMAIN_GOOGLE_COM, |
| 270 DOMAIN_ANDROID_COM, | 266 DOMAIN_ANDROID_COM, |
| 271 DOMAIN_GOOGLE_ANALYTICS_COM, | 267 DOMAIN_GOOGLE_ANALYTICS_COM, |
| 272 DOMAIN_GOOGLEPLEX_COM, | 268 DOMAIN_GOOGLEPLEX_COM, |
| 273 DOMAIN_YTIMG_COM, | 269 DOMAIN_YTIMG_COM, |
| 274 DOMAIN_GOOGLEUSERCONTENT_COM, | 270 DOMAIN_GOOGLEUSERCONTENT_COM, |
| 275 DOMAIN_YOUTUBE_COM, | 271 DOMAIN_YOUTUBE_COM, |
| 276 DOMAIN_GOOGLEAPIS_COM, | 272 DOMAIN_GOOGLEAPIS_COM, |
| 277 DOMAIN_GOOGLEADSERVICES_COM, | 273 DOMAIN_GOOGLEADSERVICES_COM, |
| 278 DOMAIN_GOOGLECODE_COM, | 274 DOMAIN_GOOGLECODE_COM, |
| 279 DOMAIN_APPSPOT_COM, | 275 DOMAIN_APPSPOT_COM, |
| 280 DOMAIN_GOOGLESYNDICATION_COM, | 276 DOMAIN_GOOGLESYNDICATION_COM, |
| 281 DOMAIN_DOUBLECLICK_NET, | 277 DOMAIN_DOUBLECLICK_NET, |
| 282 DOMAIN_GSTATIC_COM, | 278 DOMAIN_GSTATIC_COM, |
| 283 DOMAIN_GMAIL_COM, | 279 DOMAIN_GMAIL_COM, |
| 284 DOMAIN_GOOGLEMAIL_COM, | 280 DOMAIN_GOOGLEMAIL_COM, |
| 285 DOMAIN_GOOGLEGROUPS_COM, | 281 DOMAIN_GOOGLEGROUPS_COM, |
| 286 | |
| 287 DOMAIN_TORPROJECT_ORG, | 282 DOMAIN_TORPROJECT_ORG, |
| 288 | |
| 289 DOMAIN_TWITTER_COM, | 283 DOMAIN_TWITTER_COM, |
| 290 DOMAIN_TWIMG_COM, | 284 DOMAIN_TWIMG_COM, |
| 291 | |
| 292 DOMAIN_AKAMAIHD_NET, | 285 DOMAIN_AKAMAIHD_NET, |
| 293 | |
| 294 DOMAIN_TOR2WEB_ORG, | 286 DOMAIN_TOR2WEB_ORG, |
| 295 | |
| 296 DOMAIN_YOUTU_BE, | 287 DOMAIN_YOUTU_BE, |
| 297 DOMAIN_GOOGLECOMMERCE_COM, | 288 DOMAIN_GOOGLECOMMERCE_COM, |
| 298 DOMAIN_URCHIN_COM, | 289 DOMAIN_URCHIN_COM, |
| 299 DOMAIN_GOO_GL, | 290 DOMAIN_GOO_GL, |
| 300 DOMAIN_G_CO, | 291 DOMAIN_G_CO, |
| 301 DOMAIN_GOOGLE_AC, | 292 DOMAIN_GOOGLE_AC, |
| 302 DOMAIN_GOOGLE_AD, | 293 DOMAIN_GOOGLE_AD, |
| 303 DOMAIN_GOOGLE_AE, | 294 DOMAIN_GOOGLE_AE, |
| 304 DOMAIN_GOOGLE_AF, | 295 DOMAIN_GOOGLE_AF, |
| 305 DOMAIN_GOOGLE_AG, | 296 DOMAIN_GOOGLE_AG, |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 DOMAIN_GOOGLE_TM, | 499 DOMAIN_GOOGLE_TM, |
| 509 DOMAIN_GOOGLE_TN, | 500 DOMAIN_GOOGLE_TN, |
| 510 DOMAIN_GOOGLE_TO, | 501 DOMAIN_GOOGLE_TO, |
| 511 DOMAIN_GOOGLE_TP, | 502 DOMAIN_GOOGLE_TP, |
| 512 DOMAIN_GOOGLE_TT, | 503 DOMAIN_GOOGLE_TT, |
| 513 DOMAIN_GOOGLE_US, | 504 DOMAIN_GOOGLE_US, |
| 514 DOMAIN_GOOGLE_UZ, | 505 DOMAIN_GOOGLE_UZ, |
| 515 DOMAIN_GOOGLE_VG, | 506 DOMAIN_GOOGLE_VG, |
| 516 DOMAIN_GOOGLE_VU, | 507 DOMAIN_GOOGLE_VU, |
| 517 DOMAIN_GOOGLE_WS, | 508 DOMAIN_GOOGLE_WS, |
| 518 | |
| 519 DOMAIN_CHROMIUM_ORG, | 509 DOMAIN_CHROMIUM_ORG, |
| 520 | |
| 521 DOMAIN_CRYPTO_CAT, | 510 DOMAIN_CRYPTO_CAT, |
| 522 DOMAIN_LAVABIT_COM, | 511 DOMAIN_LAVABIT_COM, |
| 523 | |
| 524 DOMAIN_GOOGLETAGMANAGER_COM, | 512 DOMAIN_GOOGLETAGMANAGER_COM, |
| 525 DOMAIN_GOOGLETAGSERVICES_COM, | 513 DOMAIN_GOOGLETAGSERVICES_COM, |
| 526 | 514 |
| 527 // Boundary value for UMA_HISTOGRAM_ENUMERATION: | 515 // Boundary value for UMA_HISTOGRAM_ENUMERATION: |
| 528 DOMAIN_NUM_EVENTS | 516 DOMAIN_NUM_EVENTS |
| 529 }; | 517 }; |
| 530 | 518 |
| 531 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site. | 519 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site. |
| 532 // The validated certificate chain for the site must not include any of | 520 // The validated certificate chain for the site must not include any of |
| 533 // |excluded_hashes| and must include one or more of |required_hashes|. | 521 // |excluded_hashes| and must include one or more of |required_hashes|. |
| 534 struct PublicKeyPins { | 522 struct PublicKeyPins { |
| 535 const char* const* required_hashes; | 523 const char* const* required_hashes; |
| 536 const char* const* excluded_hashes; | 524 const char* const* excluded_hashes; |
| 537 }; | 525 }; |
| 538 | 526 |
| 539 struct HSTSPreload { | 527 struct HSTSPreload { |
| 540 uint8 length; | 528 uint8 length; |
| 541 bool include_subdomains; | 529 bool include_subdomains; |
| 542 char dns_name[38]; | 530 char dns_name[38]; |
| 543 bool https_required; | 531 bool https_required; |
| 544 PublicKeyPins pins; | 532 PublicKeyPins pins; |
| 545 SecondLevelDomainName second_level_domain_name; | 533 SecondLevelDomainName second_level_domain_name; |
| 546 }; | 534 }; |
| 547 | 535 |
| 548 static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries, | 536 static bool HasPreload(const struct HSTSPreload* entries, |
| 549 const std::string& canonicalized_host, size_t i, | 537 size_t num_entries, |
| 550 TransportSecurityState::DomainState* out, bool* ret) { | 538 const std::string& canonicalized_host, |
| 539 size_t i, |
| 540 TransportSecurityState::DomainState* out, |
| 541 bool* ret) { |
| 551 for (size_t j = 0; j < num_entries; j++) { | 542 for (size_t j = 0; j < num_entries; j++) { |
| 552 if (entries[j].length == canonicalized_host.size() - i && | 543 if (entries[j].length == canonicalized_host.size() - i && |
| 553 memcmp(entries[j].dns_name, &canonicalized_host[i], | 544 memcmp(entries[j].dns_name, |
| 545 &canonicalized_host[i], |
| 554 entries[j].length) == 0) { | 546 entries[j].length) == 0) { |
| 555 if (!entries[j].include_subdomains && i != 0) { | 547 if (!entries[j].include_subdomains && i != 0) { |
| 556 *ret = false; | 548 *ret = false; |
| 557 } else { | 549 } else { |
| 558 out->sts_include_subdomains = entries[j].include_subdomains; | 550 out->sts_include_subdomains = entries[j].include_subdomains; |
| 559 out->pkp_include_subdomains = entries[j].include_subdomains; | 551 out->pkp_include_subdomains = entries[j].include_subdomains; |
| 560 *ret = true; | 552 *ret = true; |
| 561 if (!entries[j].https_required) | 553 if (!entries[j].https_required) |
| 562 out->upgrade_mode = TransportSecurityState::DomainState::MODE_DEFAULT; | 554 out->upgrade_mode = TransportSecurityState::DomainState::MODE_DEFAULT; |
| 563 if (entries[j].pins.required_hashes) { | 555 if (entries[j].pins.required_hashes) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 634 | 626 |
| 635 bool TransportSecurityState::AddHPKPHeader(const std::string& host, | 627 bool TransportSecurityState::AddHPKPHeader(const std::string& host, |
| 636 const std::string& value, | 628 const std::string& value, |
| 637 const SSLInfo& ssl_info) { | 629 const SSLInfo& ssl_info) { |
| 638 DCHECK(CalledOnValidThread()); | 630 DCHECK(CalledOnValidThread()); |
| 639 | 631 |
| 640 base::Time now = base::Time::Now(); | 632 base::Time now = base::Time::Now(); |
| 641 base::TimeDelta max_age; | 633 base::TimeDelta max_age; |
| 642 TransportSecurityState::DomainState domain_state; | 634 TransportSecurityState::DomainState domain_state; |
| 643 GetDynamicDomainState(host, &domain_state); | 635 GetDynamicDomainState(host, &domain_state); |
| 644 if (ParseHPKPHeader(value, ssl_info.public_key_hashes, | 636 if (ParseHPKPHeader(value, |
| 645 &max_age, &domain_state.pkp_include_subdomains, | 637 ssl_info.public_key_hashes, |
| 638 &max_age, |
| 639 &domain_state.pkp_include_subdomains, |
| 646 &domain_state.dynamic_spki_hashes)) { | 640 &domain_state.dynamic_spki_hashes)) { |
| 647 // TODO(palmer): http://crbug.com/243865 handle max-age == 0. | 641 // TODO(palmer): http://crbug.com/243865 handle max-age == 0. |
| 648 domain_state.pkp_observed = now; | 642 domain_state.pkp_observed = now; |
| 649 domain_state.dynamic_spki_hashes_expiry = now + max_age; | 643 domain_state.dynamic_spki_hashes_expiry = now + max_age; |
| 650 EnableHost(host, domain_state); | 644 EnableHost(host, domain_state); |
| 651 return true; | 645 return true; |
| 652 } | 646 } |
| 653 return false; | 647 return false; |
| 654 } | 648 } |
| 655 | 649 |
| 656 bool TransportSecurityState::AddHSTS(const std::string& host, | 650 bool TransportSecurityState::AddHSTS(const std::string& host, |
| 657 const base::Time& expiry, | 651 const base::Time& expiry, |
| 658 bool include_subdomains) { | 652 bool include_subdomains) { |
| 659 DCHECK(CalledOnValidThread()); | 653 DCHECK(CalledOnValidThread()); |
| 660 | 654 |
| 661 // Copy-and-modify the existing DomainState for this host (if any). | 655 // Copy-and-modify the existing DomainState for this host (if any). |
| 662 TransportSecurityState::DomainState domain_state; | 656 TransportSecurityState::DomainState domain_state; |
| 663 const std::string canonicalized_host = CanonicalizeHost(host); | 657 const std::string canonicalized_host = CanonicalizeHost(host); |
| 664 const std::string hashed_host = HashHost(canonicalized_host); | 658 const std::string hashed_host = HashHost(canonicalized_host); |
| 665 DomainStateMap::const_iterator i = enabled_hosts_.find( | 659 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); |
| 666 hashed_host); | |
| 667 if (i != enabled_hosts_.end()) | 660 if (i != enabled_hosts_.end()) |
| 668 domain_state = i->second; | 661 domain_state = i->second; |
| 669 | 662 |
| 670 domain_state.sts_observed = base::Time::Now(); | 663 domain_state.sts_observed = base::Time::Now(); |
| 671 domain_state.sts_include_subdomains = include_subdomains; | 664 domain_state.sts_include_subdomains = include_subdomains; |
| 672 domain_state.upgrade_expiry = expiry; | 665 domain_state.upgrade_expiry = expiry; |
| 673 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; | 666 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; |
| 674 EnableHost(host, domain_state); | 667 EnableHost(host, domain_state); |
| 675 return true; | 668 return true; |
| 676 } | 669 } |
| 677 | 670 |
| 678 bool TransportSecurityState::AddHPKP(const std::string& host, | 671 bool TransportSecurityState::AddHPKP(const std::string& host, |
| 679 const base::Time& expiry, | 672 const base::Time& expiry, |
| 680 bool include_subdomains, | 673 bool include_subdomains, |
| 681 const HashValueVector& hashes) { | 674 const HashValueVector& hashes) { |
| 682 DCHECK(CalledOnValidThread()); | 675 DCHECK(CalledOnValidThread()); |
| 683 | 676 |
| 684 // Copy-and-modify the existing DomainState for this host (if any). | 677 // Copy-and-modify the existing DomainState for this host (if any). |
| 685 TransportSecurityState::DomainState domain_state; | 678 TransportSecurityState::DomainState domain_state; |
| 686 const std::string canonicalized_host = CanonicalizeHost(host); | 679 const std::string canonicalized_host = CanonicalizeHost(host); |
| 687 const std::string hashed_host = HashHost(canonicalized_host); | 680 const std::string hashed_host = HashHost(canonicalized_host); |
| 688 DomainStateMap::const_iterator i = enabled_hosts_.find( | 681 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); |
| 689 hashed_host); | |
| 690 if (i != enabled_hosts_.end()) | 682 if (i != enabled_hosts_.end()) |
| 691 domain_state = i->second; | 683 domain_state = i->second; |
| 692 | 684 |
| 693 domain_state.pkp_observed = base::Time::Now(); | 685 domain_state.pkp_observed = base::Time::Now(); |
| 694 domain_state.pkp_include_subdomains = include_subdomains; | 686 domain_state.pkp_include_subdomains = include_subdomains; |
| 695 domain_state.dynamic_spki_hashes_expiry = expiry; | 687 domain_state.dynamic_spki_hashes_expiry = expiry; |
| 696 domain_state.dynamic_spki_hashes = hashes; | 688 domain_state.dynamic_spki_hashes = hashes; |
| 697 EnableHost(host, domain_state); | 689 EnableHost(host, domain_state); |
| 698 return true; | 690 return true; |
| 699 } | 691 } |
| 700 | 692 |
| 701 // static | 693 // static |
| 702 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host, | 694 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host, |
| 703 bool sni_enabled) { | 695 bool sni_enabled) { |
| 704 std::string canonicalized_host = CanonicalizeHost(host); | 696 std::string canonicalized_host = CanonicalizeHost(host); |
| 705 const struct HSTSPreload* entry = | 697 const struct HSTSPreload* entry = |
| 706 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); | 698 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); |
| 707 | 699 |
| 708 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) | 700 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) |
| 709 return true; | 701 return true; |
| 710 | 702 |
| 711 if (sni_enabled) { | 703 if (sni_enabled) { |
| 712 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, | 704 entry = GetHSTSPreload( |
| 713 kNumPreloadedSNISTS); | 705 canonicalized_host, kPreloadedSNISTS, kNumPreloadedSNISTS); |
| 714 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) | 706 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) |
| 715 return true; | 707 return true; |
| 716 } | 708 } |
| 717 | 709 |
| 718 return false; | 710 return false; |
| 719 } | 711 } |
| 720 | 712 |
| 721 // static | 713 // static |
| 722 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { | 714 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { |
| 723 std::string canonicalized_host = CanonicalizeHost(host); | 715 std::string canonicalized_host = CanonicalizeHost(host); |
| 724 | 716 |
| 725 const struct HSTSPreload* entry = | 717 const struct HSTSPreload* entry = |
| 726 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); | 718 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); |
| 727 | 719 |
| 728 if (!entry) { | 720 if (!entry) { |
| 729 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, | 721 entry = GetHSTSPreload( |
| 730 kNumPreloadedSNISTS); | 722 canonicalized_host, kPreloadedSNISTS, kNumPreloadedSNISTS); |
| 731 } | 723 } |
| 732 | 724 |
| 733 if (!entry) { | 725 if (!entry) { |
| 734 // We don't care to report pin failures for dynamic pins. | 726 // We don't care to report pin failures for dynamic pins. |
| 735 return; | 727 return; |
| 736 } | 728 } |
| 737 | 729 |
| 738 DCHECK(entry); | 730 DCHECK(entry); |
| 739 DCHECK(entry->pins.required_hashes); | 731 DCHECK(entry->pins.required_hashes); |
| 740 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED); | 732 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED); |
| 741 | 733 |
| 742 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", | 734 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", |
| 743 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); | 735 entry->second_level_domain_name, |
| 736 DOMAIN_NUM_EVENTS); |
| 744 } | 737 } |
| 745 | 738 |
| 746 // static | 739 // static |
| 747 bool TransportSecurityState::IsBuildTimely() { | 740 bool TransportSecurityState::IsBuildTimely() { |
| 748 const base::Time build_time = base::GetBuildTime(); | 741 const base::Time build_time = base::GetBuildTime(); |
| 749 // We consider built-in information to be timely for 10 weeks. | 742 // We consider built-in information to be timely for 10 weeks. |
| 750 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; | 743 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; |
| 751 } | 744 } |
| 752 | 745 |
| 753 bool TransportSecurityState::GetStaticDomainState( | 746 bool TransportSecurityState::GetStaticDomainState( |
| 754 const std::string& canonicalized_host, | 747 const std::string& canonicalized_host, |
| 755 bool sni_enabled, | 748 bool sni_enabled, |
| 756 DomainState* out) { | 749 DomainState* out) { |
| 757 DCHECK(CalledOnValidThread()); | 750 DCHECK(CalledOnValidThread()); |
| 758 | 751 |
| 759 out->upgrade_mode = DomainState::MODE_FORCE_HTTPS; | 752 out->upgrade_mode = DomainState::MODE_FORCE_HTTPS; |
| 760 out->sts_include_subdomains = false; | 753 out->sts_include_subdomains = false; |
| 761 out->pkp_include_subdomains = false; | 754 out->pkp_include_subdomains = false; |
| 762 | 755 |
| 763 const bool is_build_timely = IsBuildTimely(); | 756 const bool is_build_timely = IsBuildTimely(); |
| 764 | 757 |
| 765 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { | 758 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
| 766 std::string host_sub_chunk(&canonicalized_host[i], | 759 std::string host_sub_chunk(&canonicalized_host[i], |
| 767 canonicalized_host.size() - i); | 760 canonicalized_host.size() - i); |
| 768 out->domain = DNSDomainToString(host_sub_chunk); | 761 out->domain = DNSDomainToString(host_sub_chunk); |
| 769 bool ret; | 762 bool ret; |
| 770 if (is_build_timely && | 763 if (is_build_timely && HasPreload(kPreloadedSTS, |
| 771 HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out, | 764 kNumPreloadedSTS, |
| 772 &ret)) { | 765 canonicalized_host, |
| 766 i, |
| 767 out, |
| 768 &ret)) { |
| 773 return ret; | 769 return ret; |
| 774 } | 770 } |
| 775 if (sni_enabled && | 771 if (sni_enabled && is_build_timely && HasPreload(kPreloadedSNISTS, |
| 776 is_build_timely && | 772 kNumPreloadedSNISTS, |
| 777 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i, | 773 canonicalized_host, |
| 778 out, &ret)) { | 774 i, |
| 775 out, |
| 776 &ret)) { |
| 779 return ret; | 777 return ret; |
| 780 } | 778 } |
| 781 } | 779 } |
| 782 | 780 |
| 783 return false; | 781 return false; |
| 784 } | 782 } |
| 785 | 783 |
| 786 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, | 784 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, |
| 787 DomainState* result) { | 785 DomainState* result) { |
| 788 DCHECK(CalledOnValidThread()); | 786 DCHECK(CalledOnValidThread()); |
| 789 | 787 |
| 790 DomainState state; | 788 DomainState state; |
| 791 const std::string canonicalized_host = CanonicalizeHost(host); | 789 const std::string canonicalized_host = CanonicalizeHost(host); |
| 792 if (canonicalized_host.empty()) | 790 if (canonicalized_host.empty()) |
| 793 return false; | 791 return false; |
| 794 | 792 |
| 795 base::Time current_time(base::Time::Now()); | 793 base::Time current_time(base::Time::Now()); |
| 796 | 794 |
| 797 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { | 795 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
| 798 std::string host_sub_chunk(&canonicalized_host[i], | 796 std::string host_sub_chunk(&canonicalized_host[i], |
| 799 canonicalized_host.size() - i); | 797 canonicalized_host.size() - i); |
| 800 DomainStateMap::iterator j = | 798 DomainStateMap::iterator j = enabled_hosts_.find(HashHost(host_sub_chunk)); |
| 801 enabled_hosts_.find(HashHost(host_sub_chunk)); | |
| 802 if (j == enabled_hosts_.end()) | 799 if (j == enabled_hosts_.end()) |
| 803 continue; | 800 continue; |
| 804 | 801 |
| 805 if (current_time > j->second.upgrade_expiry && | 802 if (current_time > j->second.upgrade_expiry && |
| 806 current_time > j->second.dynamic_spki_hashes_expiry) { | 803 current_time > j->second.dynamic_spki_hashes_expiry) { |
| 807 enabled_hosts_.erase(j); | 804 enabled_hosts_.erase(j); |
| 808 DirtyNotify(); | 805 DirtyNotify(); |
| 809 continue; | 806 continue; |
| 810 } | 807 } |
| 811 | 808 |
| 812 state = j->second; | 809 state = j->second; |
| 813 state.domain = DNSDomainToString(host_sub_chunk); | 810 state.domain = DNSDomainToString(host_sub_chunk); |
| 814 | 811 |
| 815 // Succeed if we matched the domain exactly or if subdomain matches are | 812 // Succeed if we matched the domain exactly or if subdomain matches are |
| 816 // allowed. | 813 // allowed. |
| 817 if (i == 0 || j->second.sts_include_subdomains || | 814 if (i == 0 || j->second.sts_include_subdomains || |
| 818 j->second.pkp_include_subdomains) { | 815 j->second.pkp_include_subdomains) { |
| 819 *result = state; | 816 *result = state; |
| 820 return true; | 817 return true; |
| 821 } | 818 } |
| 822 | 819 |
| 823 return false; | 820 return false; |
| 824 } | 821 } |
| 825 | 822 |
| 826 return false; | 823 return false; |
| 827 } | 824 } |
| 828 | 825 |
| 829 | |
| 830 void TransportSecurityState::AddOrUpdateEnabledHosts( | 826 void TransportSecurityState::AddOrUpdateEnabledHosts( |
| 831 const std::string& hashed_host, const DomainState& state) { | 827 const std::string& hashed_host, |
| 828 const DomainState& state) { |
| 832 DCHECK(CalledOnValidThread()); | 829 DCHECK(CalledOnValidThread()); |
| 833 enabled_hosts_[hashed_host] = state; | 830 enabled_hosts_[hashed_host] = state; |
| 834 } | 831 } |
| 835 | 832 |
| 836 TransportSecurityState::DomainState::DomainState() | 833 TransportSecurityState::DomainState::DomainState() |
| 837 : upgrade_mode(MODE_DEFAULT), | 834 : upgrade_mode(MODE_DEFAULT), |
| 838 sts_include_subdomains(false), | 835 sts_include_subdomains(false), |
| 839 pkp_include_subdomains(false) { | 836 pkp_include_subdomains(false) { |
| 840 base::Time now(base::Time::Now()); | 837 base::Time now(base::Time::Now()); |
| 841 sts_observed = now; | 838 sts_observed = now; |
| 842 pkp_observed = now; | 839 pkp_observed = now; |
| 843 } | 840 } |
| 844 | 841 |
| 845 TransportSecurityState::DomainState::~DomainState() { | 842 TransportSecurityState::DomainState::~DomainState() { |
| 846 } | 843 } |
| 847 | 844 |
| 848 bool TransportSecurityState::DomainState::CheckPublicKeyPins( | 845 bool TransportSecurityState::DomainState::CheckPublicKeyPins( |
| 849 const HashValueVector& hashes, std::string* failure_log) const { | 846 const HashValueVector& hashes, |
| 847 std::string* failure_log) const { |
| 850 // Validate that hashes is not empty. By the time this code is called (in | 848 // Validate that hashes is not empty. By the time this code is called (in |
| 851 // production), that should never happen, but it's good to be defensive. | 849 // production), that should never happen, but it's good to be defensive. |
| 852 // And, hashes *can* be empty in some test scenarios. | 850 // And, hashes *can* be empty in some test scenarios. |
| 853 if (hashes.empty()) { | 851 if (hashes.empty()) { |
| 854 *failure_log = "Rejecting empty public key chain for public-key-pinned " | 852 *failure_log = |
| 855 "domains: " + domain; | 853 "Rejecting empty public key chain for public-key-pinned " |
| 854 "domains: " + |
| 855 domain; |
| 856 return false; | 856 return false; |
| 857 } | 857 } |
| 858 | 858 |
| 859 if (HashesIntersect(bad_static_spki_hashes, hashes)) { | 859 if (HashesIntersect(bad_static_spki_hashes, hashes)) { |
| 860 *failure_log = "Rejecting public key chain for domain " + domain + | 860 *failure_log = "Rejecting public key chain for domain " + domain + |
| 861 ". Validated chain: " + HashesToBase64String(hashes) + | 861 ". Validated chain: " + HashesToBase64String(hashes) + |
| 862 ", matches one or more bad hashes: " + | 862 ", matches one or more bad hashes: " + |
| 863 HashesToBase64String(bad_static_spki_hashes); | 863 HashesToBase64String(bad_static_spki_hashes); |
| 864 return false; | 864 return false; |
| 865 } | 865 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 882 | 882 |
| 883 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const { | 883 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const { |
| 884 return upgrade_mode == MODE_FORCE_HTTPS; | 884 return upgrade_mode == MODE_FORCE_HTTPS; |
| 885 } | 885 } |
| 886 | 886 |
| 887 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const { | 887 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const { |
| 888 return true; | 888 return true; |
| 889 } | 889 } |
| 890 | 890 |
| 891 bool TransportSecurityState::DomainState::HasPublicKeyPins() const { | 891 bool TransportSecurityState::DomainState::HasPublicKeyPins() const { |
| 892 return static_spki_hashes.size() > 0 || | 892 return static_spki_hashes.size() > 0 || bad_static_spki_hashes.size() > 0 || |
| 893 bad_static_spki_hashes.size() > 0 || | |
| 894 dynamic_spki_hashes.size() > 0; | 893 dynamic_spki_hashes.size() > 0; |
| 895 } | 894 } |
| 896 | 895 |
| 897 } // namespace | 896 } // namespace |
| OLD | NEW |