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

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

Issue 826423009: Treat HSTS and HPKP state independently. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rsleevi comments Created 5 years, 11 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
« 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 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 160
161 return false; 161 return false;
162 } 162 }
163 163
164 void TransportSecurityState::SetDelegate( 164 void TransportSecurityState::SetDelegate(
165 TransportSecurityState::Delegate* delegate) { 165 TransportSecurityState::Delegate* delegate) {
166 DCHECK(CalledOnValidThread()); 166 DCHECK(CalledOnValidThread());
167 delegate_ = delegate; 167 delegate_ = delegate;
168 } 168 }
169 169
170 void TransportSecurityState::AddHSTSInternal(
171 const std::string& host,
172 TransportSecurityState::DomainState::UpgradeMode upgrade_mode,
173 const base::Time& expiry,
174 bool include_subdomains) {
175 DCHECK(CalledOnValidThread());
176
177 // Copy-and-modify the existing DomainState for this host (if any).
178 DomainState domain_state;
179 const std::string canonicalized_host = CanonicalizeHost(host);
180 const std::string hashed_host = HashHost(canonicalized_host);
181 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host);
182 if (i != enabled_hosts_.end())
183 domain_state = i->second;
184
185 domain_state.sts.last_observed = base::Time::Now();
186 domain_state.sts.include_subdomains = include_subdomains;
187 domain_state.sts.expiry = expiry;
188 domain_state.sts.upgrade_mode = upgrade_mode;
189 EnableHost(host, domain_state);
190 }
191
192 void TransportSecurityState::AddHPKPInternal(const std::string& host,
193 const base::Time& last_observed,
194 const base::Time& expiry,
195 bool include_subdomains,
196 const HashValueVector& hashes) {
197 DCHECK(CalledOnValidThread());
198
199 // Copy-and-modify the existing DomainState for this host (if any).
200 DomainState domain_state;
201 const std::string canonicalized_host = CanonicalizeHost(host);
202 const std::string hashed_host = HashHost(canonicalized_host);
203 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host);
204 if (i != enabled_hosts_.end())
205 domain_state = i->second;
206
207 domain_state.pkp.last_observed = last_observed;
208 domain_state.pkp.expiry = expiry;
209 domain_state.pkp.include_subdomains = include_subdomains;
210 domain_state.pkp.spki_hashes = hashes;
211 EnableHost(host, domain_state);
212 }
213
170 void TransportSecurityState::EnableHost(const std::string& host, 214 void TransportSecurityState::EnableHost(const std::string& host,
171 const DomainState& state) { 215 const DomainState& state) {
172 DCHECK(CalledOnValidThread()); 216 DCHECK(CalledOnValidThread());
173 217
174 const std::string canonicalized_host = CanonicalizeHost(host); 218 const std::string canonicalized_host = CanonicalizeHost(host);
175 if (canonicalized_host.empty()) 219 if (canonicalized_host.empty())
176 return; 220 return;
177 221
178 DomainState state_copy(state); 222 DomainState state_copy(state);
179 // No need to store this value since it is redundant. (|canonicalized_host| 223 // No need to store this value since it is redundant. (|canonicalized_host|
180 // is the map key.) 224 // is the map key.)
181 state_copy.domain.clear(); 225 state_copy.sts.domain.clear();
226 state_copy.pkp.domain.clear();
182 227
183 enabled_hosts_[HashHost(canonicalized_host)] = state_copy; 228 enabled_hosts_[HashHost(canonicalized_host)] = state_copy;
184 DirtyNotify(); 229 DirtyNotify();
185 } 230 }
186 231
187 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { 232 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) {
188 DCHECK(CalledOnValidThread()); 233 DCHECK(CalledOnValidThread());
189 234
190 const std::string canonicalized_host = CanonicalizeHost(host); 235 const std::string canonicalized_host = CanonicalizeHost(host);
191 if (canonicalized_host.empty()) 236 if (canonicalized_host.empty())
(...skipping 13 matching lines...) Expand all
205 DCHECK(CalledOnValidThread()); 250 DCHECK(CalledOnValidThread());
206 enabled_hosts_.clear(); 251 enabled_hosts_.clear();
207 } 252 }
208 253
209 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) { 254 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
210 DCHECK(CalledOnValidThread()); 255 DCHECK(CalledOnValidThread());
211 256
212 bool dirtied = false; 257 bool dirtied = false;
213 DomainStateMap::iterator i = enabled_hosts_.begin(); 258 DomainStateMap::iterator i = enabled_hosts_.begin();
214 while (i != enabled_hosts_.end()) { 259 while (i != enabled_hosts_.end()) {
215 if (i->second.sts.last_observed >= time && 260 // Clear STS and PKP state independently.
216 i->second.pkp.last_observed >= time) { 261 if (i->second.sts.last_observed >= time) {
262 dirtied = true;
263 i->second.sts.upgrade_mode = DomainState::MODE_DEFAULT;
264 }
265 if (i->second.pkp.last_observed >= time) {
266 dirtied = true;
267 i->second.pkp.spki_hashes.clear();
268 i->second.pkp.expiry = base::Time();
269 }
270
271 // If both are now invalid, drop the entry altogether.
272 if (!i->second.ShouldUpgradeToSSL() && !i->second.HasPublicKeyPins()) {
217 dirtied = true; 273 dirtied = true;
218 enabled_hosts_.erase(i++); 274 enabled_hosts_.erase(i++);
219 continue; 275 continue;
220 } 276 }
221 277
222 if (i->second.sts.last_observed >= time) {
223 dirtied = true;
224 i->second.sts.upgrade_mode = DomainState::MODE_DEFAULT;
225 } else if (i->second.pkp.last_observed >= time) {
226 dirtied = true;
227 i->second.pkp.spki_hashes.clear();
228 i->second.pkp.expiry = base::Time();
229 }
230 ++i; 278 ++i;
231 } 279 }
232 280
233 if (dirtied) 281 if (dirtied)
234 DirtyNotify(); 282 DirtyNotify();
235 } 283 }
236 284
237 TransportSecurityState::~TransportSecurityState() { 285 TransportSecurityState::~TransportSecurityState() {
238 DCHECK(CalledOnValidThread()); 286 DCHECK(CalledOnValidThread());
239 } 287 }
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after
614 662
615 return found; 663 return found;
616 } 664 }
617 665
618 bool TransportSecurityState::AddHSTSHeader(const std::string& host, 666 bool TransportSecurityState::AddHSTSHeader(const std::string& host,
619 const std::string& value) { 667 const std::string& value) {
620 DCHECK(CalledOnValidThread()); 668 DCHECK(CalledOnValidThread());
621 669
622 base::Time now = base::Time::Now(); 670 base::Time now = base::Time::Now();
623 base::TimeDelta max_age; 671 base::TimeDelta max_age;
624 TransportSecurityState::DomainState domain_state; 672 bool include_subdomains;
625 GetDynamicDomainState(host, &domain_state); 673 if (!ParseHSTSHeader(value, &max_age, &include_subdomains)) {
626 if (ParseHSTSHeader(value, &max_age, &domain_state.sts.include_subdomains)) { 674 return false;
627 // Handle max-age == 0.
628 if (max_age.InSeconds() == 0)
629 domain_state.sts.upgrade_mode = DomainState::MODE_DEFAULT;
630 else
631 domain_state.sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
632 domain_state.sts.last_observed = now;
633 domain_state.sts.expiry = now + max_age;
634 EnableHost(host, domain_state);
635 return true;
636 } 675 }
637 return false; 676
677 // Handle max-age == 0.
678 DomainState::UpgradeMode upgrade_mode;
679 if (max_age.InSeconds() == 0) {
680 upgrade_mode = DomainState::MODE_DEFAULT;
681 } else {
682 upgrade_mode = DomainState::MODE_FORCE_HTTPS;
683 }
684
685 AddHSTSInternal(host, upgrade_mode, now + max_age, include_subdomains);
686 return true;
638 } 687 }
639 688
640 bool TransportSecurityState::AddHPKPHeader(const std::string& host, 689 bool TransportSecurityState::AddHPKPHeader(const std::string& host,
641 const std::string& value, 690 const std::string& value,
642 const SSLInfo& ssl_info) { 691 const SSLInfo& ssl_info) {
643 DCHECK(CalledOnValidThread()); 692 DCHECK(CalledOnValidThread());
644 693
645 base::Time now = base::Time::Now(); 694 base::Time now = base::Time::Now();
646 base::TimeDelta max_age; 695 base::TimeDelta max_age;
647 TransportSecurityState::DomainState domain_state; 696 bool include_subdomains;
648 GetDynamicDomainState(host, &domain_state); 697 HashValueVector spki_hashes;
649 if (ParseHPKPHeader(value, 698 if (!ParseHPKPHeader(value, ssl_info.public_key_hashes, &max_age,
650 ssl_info.public_key_hashes, 699 &include_subdomains, &spki_hashes)) {
651 &max_age, 700 return false;
652 &domain_state.pkp.include_subdomains,
653 &domain_state.pkp.spki_hashes)) {
654 // Handle max-age == 0.
655 if (max_age.InSeconds() == 0)
656 domain_state.pkp.spki_hashes.clear();
657 domain_state.pkp.last_observed = now;
658 domain_state.pkp.expiry = now + max_age;
659 EnableHost(host, domain_state);
660 return true;
661 } 701 }
662 return false; 702 // Handle max-age == 0.
703 if (max_age.InSeconds() == 0)
704 spki_hashes.clear();
705 AddHPKPInternal(host, now, now + max_age, include_subdomains, spki_hashes);
706 return true;
663 } 707 }
664 708
665 bool TransportSecurityState::AddHSTS(const std::string& host, 709 void TransportSecurityState::AddHSTS(const std::string& host,
666 const base::Time& expiry, 710 const base::Time& expiry,
667 bool include_subdomains) { 711 bool include_subdomains) {
668 DCHECK(CalledOnValidThread()); 712 DCHECK(CalledOnValidThread());
669 713 AddHSTSInternal(host, DomainState::MODE_FORCE_HTTPS, expiry,
670 // Copy-and-modify the existing DomainState for this host (if any). 714 include_subdomains);
671 TransportSecurityState::DomainState domain_state;
672 const std::string canonicalized_host = CanonicalizeHost(host);
673 const std::string hashed_host = HashHost(canonicalized_host);
674 DomainStateMap::const_iterator i = enabled_hosts_.find(
675 hashed_host);
676 if (i != enabled_hosts_.end())
677 domain_state = i->second;
678
679 domain_state.sts.last_observed = base::Time::Now();
680 domain_state.sts.include_subdomains = include_subdomains;
681 domain_state.sts.expiry = expiry;
682 domain_state.sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
683 EnableHost(host, domain_state);
684 return true;
685 } 715 }
686 716
687 bool TransportSecurityState::AddHPKP(const std::string& host, 717 void TransportSecurityState::AddHPKP(const std::string& host,
688 const base::Time& expiry, 718 const base::Time& expiry,
689 bool include_subdomains, 719 bool include_subdomains,
690 const HashValueVector& hashes) { 720 const HashValueVector& hashes) {
691 DCHECK(CalledOnValidThread()); 721 DCHECK(CalledOnValidThread());
692 722 AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes);
693 // Copy-and-modify the existing DomainState for this host (if any).
694 TransportSecurityState::DomainState domain_state;
695 const std::string canonicalized_host = CanonicalizeHost(host);
696 const std::string hashed_host = HashHost(canonicalized_host);
697 DomainStateMap::const_iterator i = enabled_hosts_.find(
698 hashed_host);
699 if (i != enabled_hosts_.end())
700 domain_state = i->second;
701
702 domain_state.pkp.last_observed = base::Time::Now();
703 domain_state.pkp.include_subdomains = include_subdomains;
704 domain_state.pkp.expiry = expiry;
705 domain_state.pkp.spki_hashes = hashes;
706 EnableHost(host, domain_state);
707 return true;
708 } 723 }
709 724
710 // static 725 // static
711 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) { 726 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) {
712 PreloadResult result; 727 PreloadResult result;
713 return DecodeHSTSPreload(host, &result) && result.has_pins && 728 return DecodeHSTSPreload(host, &result) && result.has_pins &&
714 kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts; 729 kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts;
715 } 730 }
716 731
717 // static 732 // static
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 out->sts.include_subdomains = false; 784 out->sts.include_subdomains = false;
770 out->pkp.include_subdomains = false; 785 out->pkp.include_subdomains = false;
771 786
772 if (!IsBuildTimely()) 787 if (!IsBuildTimely())
773 return false; 788 return false;
774 789
775 PreloadResult result; 790 PreloadResult result;
776 if (!DecodeHSTSPreload(host, &result)) 791 if (!DecodeHSTSPreload(host, &result))
777 return false; 792 return false;
778 793
779 out->domain = host.substr(result.hostname_offset); 794 out->sts.domain = host.substr(result.hostname_offset);
795 out->pkp.domain = out->sts.domain;
780 out->sts.include_subdomains = result.sts_include_subdomains; 796 out->sts.include_subdomains = result.sts_include_subdomains;
781 out->sts.last_observed = base::GetBuildTime(); 797 out->sts.last_observed = base::GetBuildTime();
782 out->sts.upgrade_mode = 798 out->sts.upgrade_mode =
783 TransportSecurityState::DomainState::MODE_DEFAULT; 799 TransportSecurityState::DomainState::MODE_DEFAULT;
784 if (result.force_https) { 800 if (result.force_https) {
785 out->sts.upgrade_mode = 801 out->sts.upgrade_mode =
786 TransportSecurityState::DomainState::MODE_FORCE_HTTPS; 802 TransportSecurityState::DomainState::MODE_FORCE_HTTPS;
787 } 803 }
788 804
789 if (enable_static_pins_ && result.has_pins) { 805 if (enable_static_pins_ && result.has_pins) {
(...skipping 27 matching lines...) Expand all
817 DomainState* result) { 833 DomainState* result) {
818 DCHECK(CalledOnValidThread()); 834 DCHECK(CalledOnValidThread());
819 835
820 DomainState state; 836 DomainState state;
821 const std::string canonicalized_host = CanonicalizeHost(host); 837 const std::string canonicalized_host = CanonicalizeHost(host);
822 if (canonicalized_host.empty()) 838 if (canonicalized_host.empty())
823 return false; 839 return false;
824 840
825 base::Time current_time(base::Time::Now()); 841 base::Time current_time(base::Time::Now());
826 842
843 bool found_sts = false;
844 bool found_pkp = false;
827 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 845 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
828 std::string host_sub_chunk(&canonicalized_host[i], 846 std::string host_sub_chunk(&canonicalized_host[i],
829 canonicalized_host.size() - i); 847 canonicalized_host.size() - i);
830 DomainStateMap::iterator j = 848 DomainStateMap::iterator j =
831 enabled_hosts_.find(HashHost(host_sub_chunk)); 849 enabled_hosts_.find(HashHost(host_sub_chunk));
832 if (j == enabled_hosts_.end()) 850 if (j == enabled_hosts_.end())
833 continue; 851 continue;
834 852
853 // If both halves of the entry are invalid, drop it.
835 if (current_time > j->second.sts.expiry && 854 if (current_time > j->second.sts.expiry &&
836 current_time > j->second.pkp.expiry) { 855 current_time > j->second.pkp.expiry) {
837 enabled_hosts_.erase(j); 856 enabled_hosts_.erase(j);
838 DirtyNotify(); 857 DirtyNotify();
839 continue; 858 continue;
840 } 859 }
841 860
842 state = j->second; 861 // If this is the most specific STS match, add it to the result.
843 state.domain = DNSDomainToString(host_sub_chunk); 862 if (!found_sts && (i == 0 || j->second.sts.include_subdomains) &&
844 863 current_time <= j->second.sts.expiry &&
845 // Succeed if we matched the domain exactly or if subdomain matches are 864 j->second.ShouldUpgradeToSSL()) {
846 // allowed. 865 found_sts = true;
847 if (i == 0 || j->second.sts.include_subdomains || 866 state.sts = j->second.sts;
848 j->second.pkp.include_subdomains) { 867 state.sts.domain = DNSDomainToString(host_sub_chunk);
849 *result = state;
850 return true;
851 } 868 }
852 869
853 return false; 870 // If this is the most specific PKP match, add it to the result.
871 if (!found_pkp && (i == 0 || j->second.pkp.include_subdomains) &&
872 current_time <= j->second.pkp.expiry && j->second.HasPublicKeyPins()) {
873 found_pkp = true;
874 state.pkp = j->second.pkp;
875 state.pkp.domain = DNSDomainToString(host_sub_chunk);
876 }
877
878 if (found_sts && found_pkp)
879 break;
854 } 880 }
855 881
856 return false; 882 if (!found_sts && !found_pkp)
883 return false;
884
885 *result = state;
886 return true;
857 } 887 }
858 888
859 void TransportSecurityState::AddOrUpdateEnabledHosts( 889 void TransportSecurityState::AddOrUpdateEnabledHosts(
860 const std::string& hashed_host, const DomainState& state) { 890 const std::string& hashed_host, const DomainState& state) {
861 DCHECK(CalledOnValidThread()); 891 DCHECK(CalledOnValidThread());
862 enabled_hosts_[hashed_host] = state; 892 enabled_hosts_[hashed_host] = state;
863 } 893 }
864 894
865 TransportSecurityState::DomainState::DomainState() { 895 TransportSecurityState::DomainState::DomainState() {
866 sts.upgrade_mode = MODE_DEFAULT; 896 sts.upgrade_mode = MODE_DEFAULT;
867 sts.include_subdomains = false; 897 sts.include_subdomains = false;
868 pkp.include_subdomains = false; 898 pkp.include_subdomains = false;
869 } 899 }
870 900
871 TransportSecurityState::DomainState::~DomainState() { 901 TransportSecurityState::DomainState::~DomainState() {
872 } 902 }
873 903
874 bool TransportSecurityState::DomainState::CheckPublicKeyPins( 904 bool TransportSecurityState::DomainState::CheckPublicKeyPins(
875 const HashValueVector& hashes, std::string* failure_log) const { 905 const HashValueVector& hashes, std::string* failure_log) const {
876 // Validate that hashes is not empty. By the time this code is called (in 906 // Validate that hashes is not empty. By the time this code is called (in
877 // production), that should never happen, but it's good to be defensive. 907 // production), that should never happen, but it's good to be defensive.
878 // And, hashes *can* be empty in some test scenarios. 908 // And, hashes *can* be empty in some test scenarios.
879 if (hashes.empty()) { 909 if (hashes.empty()) {
880 failure_log->append( 910 failure_log->append(
881 "Rejecting empty public key chain for public-key-pinned domains: " + 911 "Rejecting empty public key chain for public-key-pinned domains: " +
882 domain); 912 pkp.domain);
883 return false; 913 return false;
884 } 914 }
885 915
886 if (HashesIntersect(pkp.bad_spki_hashes, hashes)) { 916 if (HashesIntersect(pkp.bad_spki_hashes, hashes)) {
887 failure_log->append("Rejecting public key chain for domain " + domain + 917 failure_log->append("Rejecting public key chain for domain " + pkp.domain +
888 ". Validated chain: " + HashesToBase64String(hashes) + 918 ". Validated chain: " + HashesToBase64String(hashes) +
889 ", matches one or more bad hashes: " + 919 ", matches one or more bad hashes: " +
890 HashesToBase64String(pkp.bad_spki_hashes)); 920 HashesToBase64String(pkp.bad_spki_hashes));
891 return false; 921 return false;
892 } 922 }
893 923
894 // If there are no pins, then any valid chain is acceptable. 924 // If there are no pins, then any valid chain is acceptable.
895 if (pkp.spki_hashes.empty()) 925 if (pkp.spki_hashes.empty())
896 return true; 926 return true;
897 927
898 if (HashesIntersect(pkp.spki_hashes, hashes)) { 928 if (HashesIntersect(pkp.spki_hashes, hashes)) {
899 return true; 929 return true;
900 } 930 }
901 931
902 failure_log->append("Rejecting public key chain for domain " + domain + 932 failure_log->append("Rejecting public key chain for domain " + pkp.domain +
903 ". Validated chain: " + HashesToBase64String(hashes) + 933 ". Validated chain: " + HashesToBase64String(hashes) +
904 ", expected: " + HashesToBase64String(pkp.spki_hashes)); 934 ", expected: " + HashesToBase64String(pkp.spki_hashes));
905 return false; 935 return false;
906 } 936 }
907 937
908 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const { 938 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
909 return sts.upgrade_mode == MODE_FORCE_HTTPS; 939 return sts.upgrade_mode == MODE_FORCE_HTTPS;
910 } 940 }
911 941
912 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const { 942 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
943 // Both HSTS and HPKP cause fatal SSL errors, so enable this on the presense
944 // of either. (If neither is active, no DomainState will be returned.)
913 return true; 945 return true;
914 } 946 }
915 947
916 bool TransportSecurityState::DomainState::HasPublicKeyPins() const { 948 bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
917 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0; 949 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0;
918 } 950 }
919 951
952 TransportSecurityState::DomainState::STSState::STSState() {
953 }
954
955 TransportSecurityState::DomainState::STSState::~STSState() {
956 }
957
920 TransportSecurityState::DomainState::PKPState::PKPState() { 958 TransportSecurityState::DomainState::PKPState::PKPState() {
921 } 959 }
922 960
923 TransportSecurityState::DomainState::PKPState::~PKPState() { 961 TransportSecurityState::DomainState::PKPState::~PKPState() {
924 } 962 }
925 963
926 } // namespace 964 } // 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