Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(730)

Side by Side Diff: net/http/transport_security_state.cc

Issue 433123003: Centralize the logic for checking public key pins (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: final fixes? Hah! Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698