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 |