Chromium Code Reviews| 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 HashValueVector* out) { | 77 HashValueVector* out) { |
| 78 HashValue hash(HASH_VALUE_SHA1); | 78 HashValue hash(HASH_VALUE_SHA1); |
| 79 memcpy(hash.data(), sha1_hash, hash.size()); | 79 memcpy(hash.data(), sha1_hash, hash.size()); |
| 80 out->push_back(hash); | 80 out->push_back(hash); |
| 81 return true; | 81 return true; |
| 82 } | 82 } |
| 83 | 83 |
| 84 } // namespace | 84 } // namespace |
| 85 | 85 |
| 86 TransportSecurityState::TransportSecurityState() | 86 TransportSecurityState::TransportSecurityState() |
| 87 : delegate_(NULL) { | 87 : delegate_(NULL), enable_static_pins_(true) { |
| 88 // Static pinning is only enabled for official builds to make sure that | |
| 89 // others don't end up with pins that cannot be easily updated. | |
| 90 #if !defined(OFFICIAL_BUILD) || defined(OS_ANDROID) || defined(OS_IOS) | |
| 91 enable_static_pins_ = false; | |
| 92 #endif | |
| 88 DCHECK(CalledOnValidThread()); | 93 DCHECK(CalledOnValidThread()); |
| 89 } | 94 } |
| 90 | 95 |
| 91 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) | 96 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) |
| 92 : iterator_(state.enabled_hosts_.begin()), | 97 : iterator_(state.enabled_hosts_.begin()), |
| 93 end_(state.enabled_hosts_.end()) { | 98 end_(state.enabled_hosts_.end()) { |
| 94 } | 99 } |
| 95 | 100 |
| 96 TransportSecurityState::Iterator::~Iterator() {} | 101 TransportSecurityState::Iterator::~Iterator() {} |
| 97 | 102 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 111 | 116 |
| 112 DomainState static_state; | 117 DomainState static_state; |
| 113 if (GetStaticDomainState(host, sni_enabled, &static_state) && | 118 if (GetStaticDomainState(host, sni_enabled, &static_state) && |
| 114 static_state.ShouldUpgradeToSSL()) { | 119 static_state.ShouldUpgradeToSSL()) { |
| 115 return true; | 120 return true; |
| 116 } | 121 } |
| 117 | 122 |
| 118 return false; | 123 return false; |
| 119 } | 124 } |
| 120 | 125 |
| 121 bool TransportSecurityState::CheckPublicKeyPins(const std::string& host, | 126 bool TransportSecurityState::CheckPublicKeyPins( |
| 122 bool sni_enabled, | 127 const std::string& host, |
| 123 const HashValueVector& hashes, | 128 bool sni_available, |
| 124 std::string* failure_log) { | 129 bool is_issued_by_known_root, |
| 125 DomainState dynamic_state; | 130 const HashValueVector& public_key_hashes, |
| 126 if (GetDynamicDomainState(host, &dynamic_state)) | 131 std::string* pinning_failure_log) { |
| 127 return dynamic_state.CheckPublicKeyPins(hashes, failure_log); | 132 // Perform pin validation if, and only if, all these conditions obtain: |
|
wtc
2014/08/08 15:36:59
I think this comment block should be moved or copi
Ryan Hamilton
2014/08/08 16:21:42
I had a comment very similar to this on the Verify
| |
| 128 | 133 // |
| 129 DomainState static_state; | 134 // * the server's certificate chain chains up to a known root (i.e. not a |
| 130 if (GetStaticDomainState(host, sni_enabled, &static_state) && | 135 // user-installed trust anchor); and |
| 131 static_state.CheckPublicKeyPins(hashes, failure_log)) { | 136 // * the build is recent (very old builds should fail open so that users |
| 132 return true; | 137 // have some chance to recover). |
|
wtc
2014/08/08 15:36:59
You should document the third condition: HasPublic
Ryan Hamilton
2014/08/08 16:21:42
Done.
| |
| 138 // | |
| 139 if (!is_issued_by_known_root || !IsBuildTimely() || | |
| 140 !HasPublicKeyPins(host, sni_available)) { | |
| 141 return true; | |
| 133 } | 142 } |
| 134 | 143 |
| 135 return false; | 144 bool pins_are_valid = CheckPublicKeyPinsImpl( |
| 145 host, sni_available, public_key_hashes, pinning_failure_log); | |
| 146 if (!pins_are_valid) { | |
| 147 LOG(ERROR) << *pinning_failure_log; | |
| 148 ReportUMAOnPinFailure(host); | |
| 149 } | |
| 150 | |
| 151 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid); | |
| 152 return pins_are_valid; | |
| 136 } | 153 } |
| 137 | 154 |
| 138 bool TransportSecurityState::HasPublicKeyPins(const std::string& host, | 155 bool TransportSecurityState::HasPublicKeyPins(const std::string& host, |
| 139 bool sni_enabled) { | 156 bool sni_enabled) { |
| 140 DomainState dynamic_state; | 157 DomainState dynamic_state; |
| 141 if (GetDynamicDomainState(host, &dynamic_state)) | 158 if (GetDynamicDomainState(host, &dynamic_state)) |
| 142 return dynamic_state.HasPublicKeyPins(); | 159 return dynamic_state.HasPublicKeyPins(); |
| 143 | 160 |
| 144 DomainState static_state; | 161 DomainState static_state; |
| 145 if (GetStaticDomainState(host, sni_enabled, &static_state)) { | 162 if (GetStaticDomainState(host, sni_enabled, &static_state)) { |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 542 | 559 |
| 543 struct HSTSPreload { | 560 struct HSTSPreload { |
| 544 uint8 length; | 561 uint8 length; |
| 545 bool include_subdomains; | 562 bool include_subdomains; |
| 546 char dns_name[38]; | 563 char dns_name[38]; |
| 547 bool https_required; | 564 bool https_required; |
| 548 PublicKeyPins pins; | 565 PublicKeyPins pins; |
| 549 SecondLevelDomainName second_level_domain_name; | 566 SecondLevelDomainName second_level_domain_name; |
| 550 }; | 567 }; |
| 551 | 568 |
| 552 static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries, | 569 static bool HasPreload(const struct HSTSPreload* entries, |
| 553 const std::string& canonicalized_host, size_t i, | 570 size_t num_entries, |
| 554 TransportSecurityState::DomainState* out, bool* ret) { | 571 const std::string& canonicalized_host, |
| 572 size_t i, | |
| 573 bool enable_static_pins, | |
| 574 TransportSecurityState::DomainState* out, | |
| 575 bool* ret) { | |
| 555 for (size_t j = 0; j < num_entries; j++) { | 576 for (size_t j = 0; j < num_entries; j++) { |
| 556 if (entries[j].length == canonicalized_host.size() - i && | 577 if (entries[j].length == canonicalized_host.size() - i && |
| 557 memcmp(entries[j].dns_name, &canonicalized_host[i], | 578 memcmp(entries[j].dns_name, &canonicalized_host[i], |
| 558 entries[j].length) == 0) { | 579 entries[j].length) == 0) { |
| 559 if (!entries[j].include_subdomains && i != 0) { | 580 if (!entries[j].include_subdomains && i != 0) { |
| 560 *ret = false; | 581 *ret = false; |
| 561 } else { | 582 } else { |
| 562 out->sts.include_subdomains = entries[j].include_subdomains; | 583 out->sts.include_subdomains = entries[j].include_subdomains; |
| 563 out->sts.last_observed = base::GetBuildTime(); | 584 out->sts.last_observed = base::GetBuildTime(); |
| 564 out->pkp.include_subdomains = entries[j].include_subdomains; | |
| 565 out->pkp.last_observed = base::GetBuildTime(); | |
| 566 *ret = true; | 585 *ret = true; |
| 567 out->sts.upgrade_mode = | 586 out->sts.upgrade_mode = |
| 568 TransportSecurityState::DomainState::MODE_FORCE_HTTPS; | 587 TransportSecurityState::DomainState::MODE_FORCE_HTTPS; |
| 569 if (!entries[j].https_required) | 588 if (!entries[j].https_required) |
| 570 out->sts.upgrade_mode = | 589 out->sts.upgrade_mode = |
| 571 TransportSecurityState::DomainState::MODE_DEFAULT; | 590 TransportSecurityState::DomainState::MODE_DEFAULT; |
| 572 if (entries[j].pins.required_hashes) { | 591 |
| 573 const char* const* sha1_hash = entries[j].pins.required_hashes; | 592 if (enable_static_pins) { |
| 574 while (*sha1_hash) { | 593 out->pkp.include_subdomains = entries[j].include_subdomains; |
| 575 AddHash(*sha1_hash, &out->pkp.spki_hashes); | 594 out->pkp.last_observed = base::GetBuildTime(); |
| 576 sha1_hash++; | 595 if (entries[j].pins.required_hashes) { |
| 596 const char* const* sha1_hash = entries[j].pins.required_hashes; | |
| 597 while (*sha1_hash) { | |
| 598 AddHash(*sha1_hash, &out->pkp.spki_hashes); | |
| 599 sha1_hash++; | |
| 600 } | |
| 577 } | 601 } |
| 578 } | 602 if (entries[j].pins.excluded_hashes) { |
| 579 if (entries[j].pins.excluded_hashes) { | 603 const char* const* sha1_hash = entries[j].pins.excluded_hashes; |
| 580 const char* const* sha1_hash = entries[j].pins.excluded_hashes; | 604 while (*sha1_hash) { |
| 581 while (*sha1_hash) { | 605 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes); |
| 582 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes); | 606 sha1_hash++; |
| 583 sha1_hash++; | 607 } |
| 584 } | 608 } |
| 585 } | 609 } |
| 586 } | 610 } |
| 587 return true; | 611 return true; |
| 588 } | 612 } |
| 589 } | 613 } |
| 590 return false; | 614 return false; |
| 591 } | 615 } |
| 592 | 616 |
| 593 #include "net/http/transport_security_state_static.h" | 617 #include "net/http/transport_security_state_static.h" |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); | 780 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); |
| 757 } | 781 } |
| 758 | 782 |
| 759 // static | 783 // static |
| 760 bool TransportSecurityState::IsBuildTimely() { | 784 bool TransportSecurityState::IsBuildTimely() { |
| 761 const base::Time build_time = base::GetBuildTime(); | 785 const base::Time build_time = base::GetBuildTime(); |
| 762 // We consider built-in information to be timely for 10 weeks. | 786 // We consider built-in information to be timely for 10 weeks. |
| 763 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; | 787 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; |
| 764 } | 788 } |
| 765 | 789 |
| 790 bool TransportSecurityState::CheckPublicKeyPinsImpl( | |
| 791 const std::string& host, | |
| 792 bool sni_enabled, | |
| 793 const HashValueVector& hashes, | |
| 794 std::string* failure_log) { | |
| 795 DomainState dynamic_state; | |
| 796 if (GetDynamicDomainState(host, &dynamic_state)) | |
| 797 return dynamic_state.CheckPublicKeyPins(hashes, failure_log); | |
| 798 | |
| 799 DomainState static_state; | |
| 800 if (GetStaticDomainState(host, sni_enabled, &static_state)) | |
| 801 return static_state.CheckPublicKeyPins(hashes, failure_log); | |
| 802 | |
| 803 // HasPublicKeyPins should have returned true in order for this method | |
| 804 // to have been called, so if we fall through to here, it's an error. | |
| 805 return false; | |
| 806 } | |
| 807 | |
| 766 bool TransportSecurityState::GetStaticDomainState(const std::string& host, | 808 bool TransportSecurityState::GetStaticDomainState(const std::string& host, |
| 767 bool sni_enabled, | 809 bool sni_enabled, |
| 768 DomainState* out) const { | 810 DomainState* out) const { |
| 769 DCHECK(CalledOnValidThread()); | 811 DCHECK(CalledOnValidThread()); |
| 770 | 812 |
| 771 const std::string canonicalized_host = CanonicalizeHost(host); | 813 const std::string canonicalized_host = CanonicalizeHost(host); |
| 772 | 814 |
| 773 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS; | 815 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS; |
| 774 out->sts.include_subdomains = false; | 816 out->sts.include_subdomains = false; |
| 775 out->pkp.include_subdomains = false; | 817 out->pkp.include_subdomains = false; |
| 776 | 818 |
| 777 const bool is_build_timely = IsBuildTimely(); | 819 const bool is_build_timely = IsBuildTimely(); |
| 778 | 820 |
| 779 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { | 821 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
| 780 std::string host_sub_chunk(&canonicalized_host[i], | 822 std::string host_sub_chunk(&canonicalized_host[i], |
| 781 canonicalized_host.size() - i); | 823 canonicalized_host.size() - i); |
| 782 out->domain = DNSDomainToString(host_sub_chunk); | 824 out->domain = DNSDomainToString(host_sub_chunk); |
| 783 bool ret; | 825 bool ret; |
| 784 if (is_build_timely && | 826 if (is_build_timely && HasPreload(kPreloadedSTS, |
| 785 HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out, | 827 kNumPreloadedSTS, |
| 786 &ret)) { | 828 canonicalized_host, |
| 829 i, | |
| 830 enable_static_pins_, | |
| 831 out, | |
| 832 &ret)) { | |
| 787 return ret; | 833 return ret; |
| 788 } | 834 } |
| 789 if (sni_enabled && | 835 if (sni_enabled && is_build_timely && HasPreload(kPreloadedSNISTS, |
| 790 is_build_timely && | 836 kNumPreloadedSNISTS, |
| 791 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i, | 837 canonicalized_host, |
| 792 out, &ret)) { | 838 i, |
| 839 enable_static_pins_, | |
| 840 out, | |
| 841 &ret)) { | |
| 793 return ret; | 842 return ret; |
| 794 } | 843 } |
| 795 } | 844 } |
| 796 | 845 |
| 797 return false; | 846 return false; |
| 798 } | 847 } |
| 799 | 848 |
| 800 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, | 849 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, |
| 801 DomainState* result) { | 850 DomainState* result) { |
| 802 DCHECK(CalledOnValidThread()); | 851 DCHECK(CalledOnValidThread()); |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 901 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0; | 950 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0; |
| 902 } | 951 } |
| 903 | 952 |
| 904 TransportSecurityState::DomainState::PKPState::PKPState() { | 953 TransportSecurityState::DomainState::PKPState::PKPState() { |
| 905 } | 954 } |
| 906 | 955 |
| 907 TransportSecurityState::DomainState::PKPState::~PKPState() { | 956 TransportSecurityState::DomainState::PKPState::~PKPState() { |
| 908 } | 957 } |
| 909 | 958 |
| 910 } // namespace | 959 } // namespace |
| OLD | NEW |