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 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 607 return NULL; | 607 return NULL; |
| 608 } | 608 } |
| 609 | 609 |
| 610 bool TransportSecurityState::AddHSTSHeader(const std::string& host, | 610 bool TransportSecurityState::AddHSTSHeader(const std::string& host, |
| 611 const std::string& value) { | 611 const std::string& value) { |
| 612 DCHECK(CalledOnValidThread()); | 612 DCHECK(CalledOnValidThread()); |
| 613 | 613 |
| 614 base::Time now = base::Time::Now(); | 614 base::Time now = base::Time::Now(); |
| 615 base::TimeDelta max_age; | 615 base::TimeDelta max_age; |
| 616 TransportSecurityState::DomainState domain_state; | 616 TransportSecurityState::DomainState domain_state; |
| 617 //GetDomainState(host, true /* SNI enabled */, &domain_state); | |
|
Ryan Sleevi
2013/12/27 00:21:06
Remove
palmer
2014/01/03 22:43:44
Done.
| |
| 617 GetDynamicDomainState(host, &domain_state); | 618 GetDynamicDomainState(host, &domain_state); |
| 618 if (ParseHSTSHeader(value, &max_age, &domain_state.sts_include_subdomains)) { | 619 if (ParseHSTSHeader(value, &max_age, &domain_state.sts_include_subdomains)) { |
| 619 // Handle max-age == 0 | 620 // Handle max-age == 0 |
| 620 if (max_age.InSeconds() == 0) | 621 if (max_age.InSeconds() == 0) |
| 621 domain_state.upgrade_mode = DomainState::MODE_DEFAULT; | 622 domain_state.upgrade_mode = DomainState::MODE_DEFAULT; |
| 622 else | 623 else |
| 623 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; | 624 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; |
| 624 domain_state.sts_observed = now; | 625 domain_state.sts_observed = now; |
| 625 domain_state.upgrade_expiry = now + max_age; | 626 domain_state.upgrade_expiry = now + max_age; |
| 626 EnableHost(host, domain_state); | 627 EnableHost(host, domain_state); |
| 627 return true; | 628 return true; |
| 628 } | 629 } |
| 629 return false; | 630 return false; |
| 630 } | 631 } |
| 631 | 632 |
| 632 bool TransportSecurityState::AddHPKPHeader(const std::string& host, | 633 bool TransportSecurityState::AddHPKPHeader(const std::string& host, |
| 633 const std::string& value, | 634 const std::string& value, |
| 634 const SSLInfo& ssl_info) { | 635 const SSLInfo& ssl_info) { |
| 635 DCHECK(CalledOnValidThread()); | 636 DCHECK(CalledOnValidThread()); |
| 636 | 637 |
| 637 base::Time now = base::Time::Now(); | 638 base::Time now = base::Time::Now(); |
| 638 base::TimeDelta max_age; | 639 base::TimeDelta max_age; |
| 639 TransportSecurityState::DomainState domain_state; | 640 TransportSecurityState::DomainState domain_state; |
| 641 //GetDomainState(host, true /* SNI enabled */, &domain_state); | |
|
Ryan Sleevi
2013/12/27 00:21:06
Remove
palmer
2014/01/03 22:43:44
Done.
| |
| 640 GetDynamicDomainState(host, &domain_state); | 642 GetDynamicDomainState(host, &domain_state); |
| 641 if (ParseHPKPHeader(value, ssl_info.public_key_hashes, | 643 if (ParseHPKPHeader(value, ssl_info.public_key_hashes, |
| 642 &max_age, &domain_state.pkp_include_subdomains, | 644 &max_age, &domain_state.pkp_include_subdomains, |
| 643 &domain_state.dynamic_spki_hashes)) { | 645 &domain_state.dynamic_spki_hashes)) { |
| 644 // TODO(palmer): http://crbug.com/243865 handle max-age == 0. | 646 // TODO(palmer): http://crbug.com/243865 handle max-age == 0. |
| 645 domain_state.pkp_observed = now; | 647 domain_state.pkp_observed = now; |
| 646 domain_state.dynamic_spki_hashes_expiry = now + max_age; | 648 domain_state.dynamic_spki_hashes_expiry = now + max_age; |
| 647 EnableHost(host, domain_state); | 649 EnableHost(host, domain_state); |
| 648 return true; | 650 return true; |
| 649 } | 651 } |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 846 const HashValueVector& hashes) const { | 848 const HashValueVector& hashes) const { |
| 847 // Validate that hashes is not empty. By the time this code is called (in | 849 // Validate that hashes is not empty. By the time this code is called (in |
| 848 // production), that should never happen, but it's good to be defensive. | 850 // production), that should never happen, but it's good to be defensive. |
| 849 // And, hashes *can* be empty in some test scenarios. | 851 // And, hashes *can* be empty in some test scenarios. |
| 850 if (hashes.empty()) { | 852 if (hashes.empty()) { |
| 851 LOG(ERROR) << "Rejecting empty public key chain for public-key-pinned " | 853 LOG(ERROR) << "Rejecting empty public key chain for public-key-pinned " |
| 852 "domain " << domain; | 854 "domain " << domain; |
| 853 return false; | 855 return false; |
| 854 } | 856 } |
| 855 | 857 |
| 856 if (HashesIntersect(bad_static_spki_hashes, hashes)) { | 858 // If there is a static entry, check its pins (if any). |this| may have |
| 859 // been loaded via GetDynamicDomainState (only), and hence we would | |
| 860 // erroneously ignore static key pins if we did not do this check. | |
| 861 // See crbug.com/29386. | |
|
Ryan Sleevi
2013/12/27 00:21:06
Avoid pronouns in comments.
// TODO(palmer): Stat
palmer
2014/01/03 22:43:44
Done.
| |
| 862 // | |
| 863 // This is a terrible hack and should be resolved with a proper refactor | |
| 864 // in the very near future (as of Dec 2013). TODO(palmer). | |
|
Ryan Sleevi
2013/12/27 00:21:06
note: remove this bit.
palmer
2014/01/03 22:43:44
Done.
| |
| 865 HashValueVector restored_static_hashes; | |
| 866 HashValueVector restored_bad_static_hashes; | |
| 867 DomainState restored_static_state; | |
| 868 bool did_restore_static_state = false; | |
|
Ryan Sleevi
2013/12/27 00:21:06
The naming here is a bit confusing, because you're
| |
| 869 if (IsBuildTimely()) { | |
|
Ryan Sleevi
2013/12/27 00:21:06
if (TransportSecurityState::IsBuildTimely()) - you
palmer
2014/01/03 22:43:44
<spiderman>...and I'm just sitting here, compiling
| |
| 870 std::string canonicalized_host = CanonicalizeHost(domain); | |
| 871 | |
| 872 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { | |
| 873 std::string host_sub_chunk(&canonicalized_host[i], | |
|
Ryan Sleevi
2013/12/27 00:21:06
This duplicates significant portions of GetStaticD
palmer
2014/01/03 22:43:44
Done.
| |
| 874 canonicalized_host.size() - i); | |
| 875 restored_static_state.domain = DNSDomainToString(host_sub_chunk); | |
| 876 if (HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, | |
| 877 &restored_static_state, &did_restore_static_state)) { | |
| 878 break; | |
| 879 } | |
| 880 if (HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, | |
| 881 i, &restored_static_state, &did_restore_static_state)) { | |
|
Ryan Sleevi
2013/12/27 00:21:06
You're unconditionally checking against SNI hosts.
palmer
2014/01/03 22:43:44
Handled this by getting rid of that code.
| |
| 882 break; | |
| 883 } | |
| 884 } | |
| 885 } | |
| 886 if (did_restore_static_state) { | |
| 887 restored_bad_static_hashes = restored_static_state.bad_static_spki_hashes; | |
| 888 restored_static_hashes = restored_static_state.static_spki_hashes; | |
| 889 } | |
| 890 | |
| 891 if (HashesIntersect(restored_bad_static_hashes, hashes) || | |
| 892 HashesIntersect(bad_static_spki_hashes, hashes)) { | |
| 857 LOG(ERROR) << "Rejecting public key chain for domain " << domain | 893 LOG(ERROR) << "Rejecting public key chain for domain " << domain |
| 858 << ". Validated chain: " << HashesToBase64String(hashes) | 894 << ". Validated chain: " << HashesToBase64String(hashes) |
| 859 << ", matches one or more bad hashes: " | 895 << ", matches one or more bad hashes: " |
| 860 << HashesToBase64String(bad_static_spki_hashes); | 896 << HashesToBase64String(bad_static_spki_hashes) << |
| 897 ", " << HashesToBase64String(restored_bad_static_hashes); | |
| 861 return false; | 898 return false; |
| 862 } | 899 } |
| 863 | 900 |
| 864 // If there are no pins, then any valid chain is acceptable. | 901 // If there are no pins, then any valid chain is acceptable. |
| 865 if (dynamic_spki_hashes.empty() && static_spki_hashes.empty()) | 902 if (dynamic_spki_hashes.empty() && static_spki_hashes.empty() && |
| 903 restored_static_hashes.empty()) { | |
| 866 return true; | 904 return true; |
| 905 } | |
| 867 | 906 |
| 868 if (HashesIntersect(dynamic_spki_hashes, hashes) || | 907 if (HashesIntersect(dynamic_spki_hashes, hashes) || |
| 869 HashesIntersect(static_spki_hashes, hashes)) { | 908 HashesIntersect(static_spki_hashes, hashes) || |
| 909 HashesIntersect(restored_static_hashes, hashes)) { | |
| 870 return true; | 910 return true; |
| 871 } | 911 } |
| 872 | 912 |
| 873 LOG(ERROR) << "Rejecting public key chain for domain " << domain | 913 LOG(ERROR) << "Rejecting public key chain for domain " << domain |
| 874 << ". Validated chain: " << HashesToBase64String(hashes) | 914 << ". Validated chain: " << HashesToBase64String(hashes) |
| 875 << ", expected: " << HashesToBase64String(dynamic_spki_hashes) | 915 << ", expected: " << HashesToBase64String(dynamic_spki_hashes) |
| 876 << " or: " << HashesToBase64String(static_spki_hashes); | 916 << " or: " << HashesToBase64String(static_spki_hashes) |
| 917 << " or: " << HashesToBase64String(restored_static_hashes); | |
| 877 return false; | 918 return false; |
| 878 } | 919 } |
| 879 | 920 |
| 880 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const { | 921 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const { |
| 881 return upgrade_mode == MODE_FORCE_HTTPS; | 922 return upgrade_mode == MODE_FORCE_HTTPS; |
| 882 } | 923 } |
| 883 | 924 |
| 884 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const { | 925 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const { |
| 885 return true; | 926 return true; |
| 886 } | 927 } |
| 887 | 928 |
| 888 bool TransportSecurityState::DomainState::HasPublicKeyPins() const { | 929 bool TransportSecurityState::DomainState::HasPublicKeyPins() const { |
| 889 return static_spki_hashes.size() > 0 || | 930 return static_spki_hashes.size() > 0 || |
| 890 bad_static_spki_hashes.size() > 0 || | 931 bad_static_spki_hashes.size() > 0 || |
| 891 dynamic_spki_hashes.size() > 0; | 932 dynamic_spki_hashes.size() > 0; |
| 892 } | 933 } |
| 893 | 934 |
| 894 } // namespace | 935 } // namespace |
| OLD | NEW |