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

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: fewer friends 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
« no previous file with comments | « net/http/transport_security_state.h ('k') | net/http/transport_security_state_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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:
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).
138 // * the server actually has public key pins.
139 //
140 // TODO(rsleevi): http://crbug.com/391032 - Only disable static HPKP if the
141 // build is not timely.
142 if (!is_issued_by_known_root || !IsBuildTimely() ||
143 !HasPublicKeyPins(host, sni_available)) {
144 return true;
133 } 145 }
134 146
135 return false; 147 bool pins_are_valid = CheckPublicKeyPinsImpl(
148 host, sni_available, public_key_hashes, pinning_failure_log);
149 if (!pins_are_valid) {
150 LOG(ERROR) << *pinning_failure_log;
151 ReportUMAOnPinFailure(host);
152 }
153
154 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid);
155 return pins_are_valid;
136 } 156 }
137 157
138 bool TransportSecurityState::HasPublicKeyPins(const std::string& host, 158 bool TransportSecurityState::HasPublicKeyPins(const std::string& host,
139 bool sni_enabled) { 159 bool sni_enabled) {
140 DomainState dynamic_state; 160 DomainState dynamic_state;
141 if (GetDynamicDomainState(host, &dynamic_state)) 161 if (GetDynamicDomainState(host, &dynamic_state))
142 return dynamic_state.HasPublicKeyPins(); 162 return dynamic_state.HasPublicKeyPins();
143 163
144 DomainState static_state; 164 DomainState static_state;
145 if (GetStaticDomainState(host, sni_enabled, &static_state)) { 165 if (GetStaticDomainState(host, sni_enabled, &static_state)) {
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 562
543 struct HSTSPreload { 563 struct HSTSPreload {
544 uint8 length; 564 uint8 length;
545 bool include_subdomains; 565 bool include_subdomains;
546 char dns_name[38]; 566 char dns_name[38];
547 bool https_required; 567 bool https_required;
548 PublicKeyPins pins; 568 PublicKeyPins pins;
549 SecondLevelDomainName second_level_domain_name; 569 SecondLevelDomainName second_level_domain_name;
550 }; 570 };
551 571
552 static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries, 572 static bool HasPreload(const struct HSTSPreload* entries,
553 const std::string& canonicalized_host, size_t i, 573 size_t num_entries,
554 TransportSecurityState::DomainState* out, bool* ret) { 574 const std::string& canonicalized_host,
575 size_t i,
576 bool enable_static_pins,
577 TransportSecurityState::DomainState* out,
578 bool* ret) {
555 for (size_t j = 0; j < num_entries; j++) { 579 for (size_t j = 0; j < num_entries; j++) {
556 if (entries[j].length == canonicalized_host.size() - i && 580 if (entries[j].length == canonicalized_host.size() - i &&
557 memcmp(entries[j].dns_name, &canonicalized_host[i], 581 memcmp(entries[j].dns_name, &canonicalized_host[i],
558 entries[j].length) == 0) { 582 entries[j].length) == 0) {
559 if (!entries[j].include_subdomains && i != 0) { 583 if (!entries[j].include_subdomains && i != 0) {
560 *ret = false; 584 *ret = false;
561 } else { 585 } else {
562 out->sts.include_subdomains = entries[j].include_subdomains; 586 out->sts.include_subdomains = entries[j].include_subdomains;
563 out->sts.last_observed = base::GetBuildTime(); 587 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; 588 *ret = true;
567 out->sts.upgrade_mode = 589 out->sts.upgrade_mode =
568 TransportSecurityState::DomainState::MODE_FORCE_HTTPS; 590 TransportSecurityState::DomainState::MODE_FORCE_HTTPS;
569 if (!entries[j].https_required) 591 if (!entries[j].https_required)
570 out->sts.upgrade_mode = 592 out->sts.upgrade_mode =
571 TransportSecurityState::DomainState::MODE_DEFAULT; 593 TransportSecurityState::DomainState::MODE_DEFAULT;
572 if (entries[j].pins.required_hashes) { 594
573 const char* const* sha1_hash = entries[j].pins.required_hashes; 595 if (enable_static_pins) {
574 while (*sha1_hash) { 596 out->pkp.include_subdomains = entries[j].include_subdomains;
575 AddHash(*sha1_hash, &out->pkp.spki_hashes); 597 out->pkp.last_observed = base::GetBuildTime();
576 sha1_hash++; 598 if (entries[j].pins.required_hashes) {
599 const char* const* sha1_hash = entries[j].pins.required_hashes;
600 while (*sha1_hash) {
601 AddHash(*sha1_hash, &out->pkp.spki_hashes);
602 sha1_hash++;
603 }
577 } 604 }
578 } 605 if (entries[j].pins.excluded_hashes) {
579 if (entries[j].pins.excluded_hashes) { 606 const char* const* sha1_hash = entries[j].pins.excluded_hashes;
580 const char* const* sha1_hash = entries[j].pins.excluded_hashes; 607 while (*sha1_hash) {
581 while (*sha1_hash) { 608 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes);
582 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes); 609 sha1_hash++;
583 sha1_hash++; 610 }
584 } 611 }
585 } 612 }
586 } 613 }
587 return true; 614 return true;
588 } 615 }
589 } 616 }
590 return false; 617 return false;
591 } 618 }
592 619
593 #include "net/http/transport_security_state_static.h" 620 #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); 783 entry->second_level_domain_name, DOMAIN_NUM_EVENTS);
757 } 784 }
758 785
759 // static 786 // static
760 bool TransportSecurityState::IsBuildTimely() { 787 bool TransportSecurityState::IsBuildTimely() {
761 const base::Time build_time = base::GetBuildTime(); 788 const base::Time build_time = base::GetBuildTime();
762 // We consider built-in information to be timely for 10 weeks. 789 // We consider built-in information to be timely for 10 weeks.
763 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; 790 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
764 } 791 }
765 792
793 bool TransportSecurityState::CheckPublicKeyPinsImpl(
794 const std::string& host,
795 bool sni_enabled,
796 const HashValueVector& hashes,
797 std::string* failure_log) {
798 DomainState dynamic_state;
799 if (GetDynamicDomainState(host, &dynamic_state))
800 return dynamic_state.CheckPublicKeyPins(hashes, failure_log);
801
802 DomainState static_state;
803 if (GetStaticDomainState(host, sni_enabled, &static_state))
804 return static_state.CheckPublicKeyPins(hashes, failure_log);
805
806 // HasPublicKeyPins should have returned true in order for this method
807 // to have been called, so if we fall through to here, it's an error.
808 return false;
809 }
810
766 bool TransportSecurityState::GetStaticDomainState(const std::string& host, 811 bool TransportSecurityState::GetStaticDomainState(const std::string& host,
767 bool sni_enabled, 812 bool sni_enabled,
768 DomainState* out) const { 813 DomainState* out) const {
769 DCHECK(CalledOnValidThread()); 814 DCHECK(CalledOnValidThread());
770 815
771 const std::string canonicalized_host = CanonicalizeHost(host); 816 const std::string canonicalized_host = CanonicalizeHost(host);
772 817
773 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS; 818 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
774 out->sts.include_subdomains = false; 819 out->sts.include_subdomains = false;
775 out->pkp.include_subdomains = false; 820 out->pkp.include_subdomains = false;
776 821
777 const bool is_build_timely = IsBuildTimely(); 822 const bool is_build_timely = IsBuildTimely();
778 823
779 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 824 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
780 std::string host_sub_chunk(&canonicalized_host[i], 825 std::string host_sub_chunk(&canonicalized_host[i],
781 canonicalized_host.size() - i); 826 canonicalized_host.size() - i);
782 out->domain = DNSDomainToString(host_sub_chunk); 827 out->domain = DNSDomainToString(host_sub_chunk);
783 bool ret; 828 bool ret;
784 if (is_build_timely && 829 if (is_build_timely && HasPreload(kPreloadedSTS,
785 HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out, 830 kNumPreloadedSTS,
786 &ret)) { 831 canonicalized_host,
832 i,
833 enable_static_pins_,
834 out,
835 &ret)) {
787 return ret; 836 return ret;
788 } 837 }
789 if (sni_enabled && 838 if (sni_enabled && is_build_timely && HasPreload(kPreloadedSNISTS,
790 is_build_timely && 839 kNumPreloadedSNISTS,
791 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i, 840 canonicalized_host,
792 out, &ret)) { 841 i,
842 enable_static_pins_,
843 out,
844 &ret)) {
793 return ret; 845 return ret;
794 } 846 }
795 } 847 }
796 848
797 return false; 849 return false;
798 } 850 }
799 851
800 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, 852 bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
801 DomainState* result) { 853 DomainState* result) {
802 DCHECK(CalledOnValidThread()); 854 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; 953 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0;
902 } 954 }
903 955
904 TransportSecurityState::DomainState::PKPState::PKPState() { 956 TransportSecurityState::DomainState::PKPState::PKPState() {
905 } 957 }
906 958
907 TransportSecurityState::DomainState::PKPState::~PKPState() { 959 TransportSecurityState::DomainState::PKPState::~PKPState() {
908 } 960 }
909 961
910 } // namespace 962 } // namespace
OLDNEW
« no previous file with comments | « net/http/transport_security_state.h ('k') | net/http/transport_security_state_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698