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

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

Issue 2747173005: Store dynamic Expect-CT state (Closed)
Patch Set: clear dynamic Expect-CT data when needed Created 3 years, 8 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 #include <algorithm> 7 #include <algorithm>
8 #include <memory> 8 #include <memory>
9 #include <utility> 9 #include <utility>
10 #include <vector> 10 #include <vector>
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 49
50 // Points to the active transport security state source. 50 // Points to the active transport security state source.
51 const TransportSecurityStateSource* g_hsts_source = &kHSTSSource; 51 const TransportSecurityStateSource* g_hsts_source = &kHSTSSource;
52 52
53 // Override for ShouldRequireCT() for unit tests. Possible values: 53 // Override for ShouldRequireCT() for unit tests. Possible values:
54 // -1: Unless a delegate says otherwise, do not require CT. 54 // -1: Unless a delegate says otherwise, do not require CT.
55 // 0: Use the default implementation (e.g. production) 55 // 0: Use the default implementation (e.g. production)
56 // 1: Unless a delegate says otherwise, require CT. 56 // 1: Unless a delegate says otherwise, require CT.
57 int g_ct_required_for_testing = 0; 57 int g_ct_required_for_testing = 0;
58 58
59 bool IsDynamicExpectCTEnabled() {
60 return base::FeatureList::IsEnabled(
61 TransportSecurityState::kDynamicExpectCTFeature);
62 }
63
59 // LessThan comparator for use with std::binary_search() in determining 64 // LessThan comparator for use with std::binary_search() in determining
60 // whether a SHA-256 HashValue appears within a sorted array of 65 // whether a SHA-256 HashValue appears within a sorted array of
61 // SHA256HashValues. 66 // SHA256HashValues.
62 struct SHA256ToHashValueComparator { 67 struct SHA256ToHashValueComparator {
63 bool operator()(const SHA256HashValue& lhs, const HashValue& rhs) const { 68 bool operator()(const SHA256HashValue& lhs, const HashValue& rhs) const {
64 DCHECK_EQ(HASH_VALUE_SHA256, rhs.tag); 69 DCHECK_EQ(HASH_VALUE_SHA256, rhs.tag);
65 return memcmp(lhs.data, rhs.data(), rhs.size()) < 0; 70 return memcmp(lhs.data, rhs.data(), rhs.size()) < 0;
66 } 71 }
67 72
68 bool operator()(const HashValue& lhs, const SHA256HashValue& rhs) const { 73 bool operator()(const HashValue& lhs, const SHA256HashValue& rhs) const {
(...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after
719 report.Set("validated-certificate-chain", 724 report.Set("validated-certificate-chain",
720 GetPEMEncodedChainAsList(ssl_info.cert.get())); 725 GetPEMEncodedChainAsList(ssl_info.cert.get()));
721 726
722 if (!base::JSONWriter::Write(report, out_serialized_report)) 727 if (!base::JSONWriter::Write(report, out_serialized_report))
723 return false; 728 return false;
724 return true; 729 return true;
725 } 730 }
726 731
727 } // namespace 732 } // namespace
728 733
734 // static
735 const base::Feature TransportSecurityState::kDynamicExpectCTFeature{
736 "DynamicExpectCT", base::FEATURE_DISABLED_BY_DEFAULT};
737
729 void SetTransportSecurityStateSourceForTesting( 738 void SetTransportSecurityStateSourceForTesting(
730 const TransportSecurityStateSource* source) { 739 const TransportSecurityStateSource* source) {
731 g_hsts_source = source ? source : &kHSTSSource; 740 g_hsts_source = source ? source : &kHSTSSource;
732 } 741 }
733 742
734 TransportSecurityState::TransportSecurityState() 743 TransportSecurityState::TransportSecurityState()
735 : enable_static_pins_(true), 744 : enable_static_pins_(true),
736 enable_static_expect_ct_(true), 745 enable_static_expect_ct_(true),
737 enable_static_expect_staple_(true), 746 enable_static_expect_staple_(true),
738 enable_pkp_bypass_for_local_trust_anchors_(true), 747 enable_pkp_bypass_for_local_trust_anchors_(true),
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
981 PKPState pkp_state; 990 PKPState pkp_state;
982 pkp_state.last_observed = last_observed; 991 pkp_state.last_observed = last_observed;
983 pkp_state.expiry = expiry; 992 pkp_state.expiry = expiry;
984 pkp_state.include_subdomains = include_subdomains; 993 pkp_state.include_subdomains = include_subdomains;
985 pkp_state.spki_hashes = hashes; 994 pkp_state.spki_hashes = hashes;
986 pkp_state.report_uri = report_uri; 995 pkp_state.report_uri = report_uri;
987 996
988 EnablePKPHost(host, pkp_state); 997 EnablePKPHost(host, pkp_state);
989 } 998 }
990 999
1000 void TransportSecurityState::AddExpectCTInternal(
1001 const std::string& host,
1002 const base::Time& last_observed,
1003 const base::Time& expiry,
1004 bool enforce,
1005 const GURL& report_uri) {
1006 DCHECK(CalledOnValidThread());
1007
1008 ExpectCTState expect_ct_state;
1009 expect_ct_state.last_observed = last_observed;
1010 expect_ct_state.expiry = expiry;
1011 expect_ct_state.enforce = enforce;
1012 expect_ct_state.report_uri = report_uri;
1013
1014 EnableExpectCTHost(host, expect_ct_state);
1015 }
1016
991 void TransportSecurityState:: 1017 void TransportSecurityState::
992 SetEnablePublicKeyPinningBypassForLocalTrustAnchors(bool value) { 1018 SetEnablePublicKeyPinningBypassForLocalTrustAnchors(bool value) {
993 enable_pkp_bypass_for_local_trust_anchors_ = value; 1019 enable_pkp_bypass_for_local_trust_anchors_ = value;
994 } 1020 }
995 1021
996 void TransportSecurityState::EnableSTSHost(const std::string& host, 1022 void TransportSecurityState::EnableSTSHost(const std::string& host,
997 const STSState& state) { 1023 const STSState& state) {
998 DCHECK(CalledOnValidThread()); 1024 DCHECK(CalledOnValidThread());
999 1025
1000 const std::string canonicalized_host = CanonicalizeHost(host); 1026 const std::string canonicalized_host = CanonicalizeHost(host);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1036 1062
1037 enabled_pkp_hosts_[HashHost(canonicalized_host)] = pkp_state; 1063 enabled_pkp_hosts_[HashHost(canonicalized_host)] = pkp_state;
1038 } else { 1064 } else {
1039 const std::string hashed_host = HashHost(canonicalized_host); 1065 const std::string hashed_host = HashHost(canonicalized_host);
1040 enabled_pkp_hosts_.erase(hashed_host); 1066 enabled_pkp_hosts_.erase(hashed_host);
1041 } 1067 }
1042 1068
1043 DirtyNotify(); 1069 DirtyNotify();
1044 } 1070 }
1045 1071
1072 void TransportSecurityState::EnableExpectCTHost(const std::string& host,
1073 const ExpectCTState& state) {
1074 DCHECK(CalledOnValidThread());
1075 if (!IsDynamicExpectCTEnabled())
1076 return;
1077
1078 const std::string canonicalized_host = CanonicalizeHost(host);
1079 if (canonicalized_host.empty())
1080 return;
1081
1082 // Only store new state when Expect-CT is explicitly enabled. If it is
1083 // disabled, remove the state from the enabled hosts.
1084 if (state.enforce || !state.report_uri.is_empty()) {
1085 ExpectCTState expect_ct_state(state);
1086 // No need to store this value since it is redundant. (|canonicalized_host|
1087 // is the map key.)
1088 expect_ct_state.domain.clear();
1089
1090 enabled_expect_ct_hosts_[HashHost(canonicalized_host)] = expect_ct_state;
1091 } else {
1092 const std::string hashed_host = HashHost(canonicalized_host);
1093 enabled_expect_ct_hosts_.erase(hashed_host);
1094 }
1095
1096 DirtyNotify();
1097 }
1098
1046 TransportSecurityState::PKPStatus 1099 TransportSecurityState::PKPStatus
1047 TransportSecurityState::CheckPinsAndMaybeSendReport( 1100 TransportSecurityState::CheckPinsAndMaybeSendReport(
1048 const HostPortPair& host_port_pair, 1101 const HostPortPair& host_port_pair,
1049 bool is_issued_by_known_root, 1102 bool is_issued_by_known_root,
1050 const TransportSecurityState::PKPState& pkp_state, 1103 const TransportSecurityState::PKPState& pkp_state,
1051 const HashValueVector& hashes, 1104 const HashValueVector& hashes,
1052 const X509Certificate* served_certificate_chain, 1105 const X509Certificate* served_certificate_chain,
1053 const X509Certificate* validated_certificate_chain, 1106 const X509Certificate* validated_certificate_chain,
1054 const TransportSecurityState::PublicKeyPinReportStatus report_status, 1107 const TransportSecurityState::PublicKeyPinReportStatus report_status,
1055 std::string* failure_log) { 1108 std::string* failure_log) {
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1157 enabled_sts_hosts_.erase(sts_interator); 1210 enabled_sts_hosts_.erase(sts_interator);
1158 deleted = true; 1211 deleted = true;
1159 } 1212 }
1160 1213
1161 PKPStateMap::iterator pkp_iterator = enabled_pkp_hosts_.find(hashed_host); 1214 PKPStateMap::iterator pkp_iterator = enabled_pkp_hosts_.find(hashed_host);
1162 if (pkp_iterator != enabled_pkp_hosts_.end()) { 1215 if (pkp_iterator != enabled_pkp_hosts_.end()) {
1163 enabled_pkp_hosts_.erase(pkp_iterator); 1216 enabled_pkp_hosts_.erase(pkp_iterator);
1164 deleted = true; 1217 deleted = true;
1165 } 1218 }
1166 1219
1220 ExpectCTStateMap::iterator expect_ct_iterator =
1221 enabled_expect_ct_hosts_.find(hashed_host);
1222 if (expect_ct_iterator != enabled_expect_ct_hosts_.end()) {
1223 enabled_expect_ct_hosts_.erase(expect_ct_iterator);
1224 deleted = true;
1225 }
1226
1167 if (deleted) 1227 if (deleted)
1168 DirtyNotify(); 1228 DirtyNotify();
1169 return deleted; 1229 return deleted;
1170 } 1230 }
1171 1231
1172 void TransportSecurityState::ClearDynamicData() { 1232 void TransportSecurityState::ClearDynamicData() {
1173 DCHECK(CalledOnValidThread()); 1233 DCHECK(CalledOnValidThread());
1174 enabled_sts_hosts_.clear(); 1234 enabled_sts_hosts_.clear();
1175 enabled_pkp_hosts_.clear(); 1235 enabled_pkp_hosts_.clear();
1236 enabled_expect_ct_hosts_.clear();
1176 } 1237 }
1177 1238
1178 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) { 1239 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
1179 DCHECK(CalledOnValidThread()); 1240 DCHECK(CalledOnValidThread());
1180 1241
1181 bool dirtied = false; 1242 bool dirtied = false;
1182 STSStateMap::iterator sts_iterator = enabled_sts_hosts_.begin(); 1243 STSStateMap::iterator sts_iterator = enabled_sts_hosts_.begin();
1183 while (sts_iterator != enabled_sts_hosts_.end()) { 1244 while (sts_iterator != enabled_sts_hosts_.end()) {
1184 if (sts_iterator->second.last_observed >= time) { 1245 if (sts_iterator->second.last_observed >= time) {
1185 dirtied = true; 1246 dirtied = true;
1186 enabled_sts_hosts_.erase(sts_iterator++); 1247 enabled_sts_hosts_.erase(sts_iterator++);
1187 continue; 1248 continue;
1188 } 1249 }
1189 1250
1190 ++sts_iterator; 1251 ++sts_iterator;
1191 } 1252 }
1192 1253
1193 PKPStateMap::iterator pkp_iterator = enabled_pkp_hosts_.begin(); 1254 PKPStateMap::iterator pkp_iterator = enabled_pkp_hosts_.begin();
1194 while (pkp_iterator != enabled_pkp_hosts_.end()) { 1255 while (pkp_iterator != enabled_pkp_hosts_.end()) {
1195 if (pkp_iterator->second.last_observed >= time) { 1256 if (pkp_iterator->second.last_observed >= time) {
1196 dirtied = true; 1257 dirtied = true;
1197 enabled_pkp_hosts_.erase(pkp_iterator++); 1258 enabled_pkp_hosts_.erase(pkp_iterator++);
1198 continue; 1259 continue;
1199 } 1260 }
1200 1261
1201 ++pkp_iterator; 1262 ++pkp_iterator;
1202 } 1263 }
1203 1264
1265 ExpectCTStateMap::iterator expect_ct_iterator =
1266 enabled_expect_ct_hosts_.begin();
1267 while (expect_ct_iterator != enabled_expect_ct_hosts_.end()) {
1268 if (expect_ct_iterator->second.last_observed >= time) {
1269 dirtied = true;
1270 enabled_expect_ct_hosts_.erase(expect_ct_iterator++);
1271 continue;
1272 }
1273
1274 ++expect_ct_iterator;
1275 }
1276
1204 if (dirtied) 1277 if (dirtied)
1205 DirtyNotify(); 1278 DirtyNotify();
1206 } 1279 }
1207 1280
1208 TransportSecurityState::~TransportSecurityState() { 1281 TransportSecurityState::~TransportSecurityState() {
1209 DCHECK(CalledOnValidThread()); 1282 DCHECK(CalledOnValidThread());
1210 } 1283 }
1211 1284
1212 void TransportSecurityState::DirtyNotify() { 1285 void TransportSecurityState::DirtyNotify() {
1213 DCHECK(CalledOnValidThread()); 1286 DCHECK(CalledOnValidThread());
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1272 void TransportSecurityState::AddHPKP(const std::string& host, 1345 void TransportSecurityState::AddHPKP(const std::string& host,
1273 const base::Time& expiry, 1346 const base::Time& expiry,
1274 bool include_subdomains, 1347 bool include_subdomains,
1275 const HashValueVector& hashes, 1348 const HashValueVector& hashes,
1276 const GURL& report_uri) { 1349 const GURL& report_uri) {
1277 DCHECK(CalledOnValidThread()); 1350 DCHECK(CalledOnValidThread());
1278 AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes, 1351 AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes,
1279 report_uri); 1352 report_uri);
1280 } 1353 }
1281 1354
1355 void TransportSecurityState::AddExpectCT(const std::string& host,
1356 const base::Time& expiry,
1357 bool enforce,
1358 const GURL& report_uri) {
1359 DCHECK(CalledOnValidThread());
1360 AddExpectCTInternal(host, base::Time::Now(), expiry, enforce, report_uri);
1361 }
1362
1282 bool TransportSecurityState::ProcessHPKPReportOnlyHeader( 1363 bool TransportSecurityState::ProcessHPKPReportOnlyHeader(
1283 const std::string& value, 1364 const std::string& value,
1284 const HostPortPair& host_port_pair, 1365 const HostPortPair& host_port_pair,
1285 const SSLInfo& ssl_info) { 1366 const SSLInfo& ssl_info) {
1286 DCHECK(CalledOnValidThread()); 1367 DCHECK(CalledOnValidThread());
1287 1368
1288 base::Time now = base::Time::Now(); 1369 base::Time now = base::Time::Now();
1289 bool include_subdomains; 1370 bool include_subdomains;
1290 HashValueVector spki_hashes; 1371 HashValueVector spki_hashes;
1291 GURL report_uri; 1372 GURL report_uri;
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
1564 return true; 1645 return true;
1565 } 1646 }
1566 1647
1567 break; 1648 break;
1568 } 1649 }
1569 } 1650 }
1570 1651
1571 return false; 1652 return false;
1572 } 1653 }
1573 1654
1655 bool TransportSecurityState::GetDynamicExpectCTState(const std::string& host,
1656 ExpectCTState* result) {
1657 DCHECK(CalledOnValidThread());
1658
1659 const std::string canonicalized_host = CanonicalizeHost(host);
1660 if (canonicalized_host.empty())
1661 return false;
1662
1663 base::Time current_time(base::Time::Now());
1664 ExpectCTStateMap::iterator j =
1665 enabled_expect_ct_hosts_.find(HashHost(canonicalized_host));
1666 if (j == enabled_expect_ct_hosts_.end())
1667 return false;
1668 // If the entry is invalid, drop it.
1669 if (current_time > j->second.expiry) {
1670 enabled_expect_ct_hosts_.erase(j);
1671 DirtyNotify();
1672 return false;
1673 }
1674
1675 *result = j->second;
1676 return true;
1677 }
1678
1574 void TransportSecurityState::AddOrUpdateEnabledSTSHosts( 1679 void TransportSecurityState::AddOrUpdateEnabledSTSHosts(
1575 const std::string& hashed_host, 1680 const std::string& hashed_host,
1576 const STSState& state) { 1681 const STSState& state) {
1577 DCHECK(CalledOnValidThread()); 1682 DCHECK(CalledOnValidThread());
1578 DCHECK(state.ShouldUpgradeToSSL()); 1683 DCHECK(state.ShouldUpgradeToSSL());
1579 enabled_sts_hosts_[hashed_host] = state; 1684 enabled_sts_hosts_[hashed_host] = state;
1580 } 1685 }
1581 1686
1582 void TransportSecurityState::AddOrUpdateEnabledPKPHosts( 1687 void TransportSecurityState::AddOrUpdateEnabledPKPHosts(
1583 const std::string& hashed_host, 1688 const std::string& hashed_host,
1584 const PKPState& state) { 1689 const PKPState& state) {
1585 DCHECK(CalledOnValidThread()); 1690 DCHECK(CalledOnValidThread());
1586 DCHECK(state.HasPublicKeyPins()); 1691 DCHECK(state.HasPublicKeyPins());
1587 enabled_pkp_hosts_[hashed_host] = state; 1692 enabled_pkp_hosts_[hashed_host] = state;
1588 } 1693 }
1589 1694
1695 void TransportSecurityState::AddOrUpdateEnabledExpectCTHosts(
1696 const std::string& hashed_host,
1697 const ExpectCTState& state) {
1698 DCHECK(CalledOnValidThread());
1699 DCHECK(state.enforce || !state.report_uri.is_empty());
1700 enabled_expect_ct_hosts_[hashed_host] = state;
1701 }
1702
1590 TransportSecurityState::STSState::STSState() 1703 TransportSecurityState::STSState::STSState()
1591 : upgrade_mode(MODE_DEFAULT), include_subdomains(false) { 1704 : upgrade_mode(MODE_DEFAULT), include_subdomains(false) {
1592 } 1705 }
1593 1706
1594 TransportSecurityState::STSState::~STSState() { 1707 TransportSecurityState::STSState::~STSState() {
1595 } 1708 }
1596 1709
1597 bool TransportSecurityState::STSState::ShouldUpgradeToSSL() const { 1710 bool TransportSecurityState::STSState::ShouldUpgradeToSSL() const {
1598 return upgrade_mode == MODE_FORCE_HTTPS; 1711 return upgrade_mode == MODE_FORCE_HTTPS;
1599 } 1712 }
1600 1713
1601 TransportSecurityState::STSStateIterator::STSStateIterator( 1714 TransportSecurityState::STSStateIterator::STSStateIterator(
1602 const TransportSecurityState& state) 1715 const TransportSecurityState& state)
1603 : iterator_(state.enabled_sts_hosts_.begin()), 1716 : iterator_(state.enabled_sts_hosts_.begin()),
1604 end_(state.enabled_sts_hosts_.end()) { 1717 end_(state.enabled_sts_hosts_.end()) {
1605 } 1718 }
1606 1719
1607 TransportSecurityState::STSStateIterator::~STSStateIterator() { 1720 TransportSecurityState::STSStateIterator::~STSStateIterator() {
1608 } 1721 }
1609 1722
1610 TransportSecurityState::PKPState::PKPState() : include_subdomains(false) { 1723 TransportSecurityState::PKPState::PKPState() : include_subdomains(false) {
1611 } 1724 }
1612 1725
1613 TransportSecurityState::PKPState::PKPState(const PKPState& other) = default; 1726 TransportSecurityState::PKPState::PKPState(const PKPState& other) = default;
1614 1727
1615 TransportSecurityState::PKPState::~PKPState() { 1728 TransportSecurityState::PKPState::~PKPState() {
1616 } 1729 }
1617 1730
1618 TransportSecurityState::ExpectCTState::ExpectCTState() {} 1731 TransportSecurityState::ExpectCTState::ExpectCTState() : enforce(false) {}
1619 1732
1620 TransportSecurityState::ExpectCTState::~ExpectCTState() {} 1733 TransportSecurityState::ExpectCTState::~ExpectCTState() {}
1621 1734
1735 TransportSecurityState::ExpectCTStateIterator::ExpectCTStateIterator(
1736 const TransportSecurityState& state)
1737 : iterator_(state.enabled_expect_ct_hosts_.begin()),
1738 end_(state.enabled_expect_ct_hosts_.end()) {
1739 DCHECK(state.CalledOnValidThread());
1740 }
1741
1742 TransportSecurityState::ExpectCTStateIterator::~ExpectCTStateIterator() {}
1743
1622 TransportSecurityState::ExpectStapleState::ExpectStapleState() 1744 TransportSecurityState::ExpectStapleState::ExpectStapleState()
1623 : include_subdomains(false) {} 1745 : include_subdomains(false) {}
1624 1746
1625 TransportSecurityState::ExpectStapleState::~ExpectStapleState() {} 1747 TransportSecurityState::ExpectStapleState::~ExpectStapleState() {}
1626 1748
1627 bool TransportSecurityState::PKPState::CheckPublicKeyPins( 1749 bool TransportSecurityState::PKPState::CheckPublicKeyPins(
1628 const HashValueVector& hashes, 1750 const HashValueVector& hashes,
1629 std::string* failure_log) const { 1751 std::string* failure_log) const {
1630 // Validate that hashes is not empty. By the time this code is called (in 1752 // Validate that hashes is not empty. By the time this code is called (in
1631 // production), that should never happen, but it's good to be defensive. 1753 // production), that should never happen, but it's good to be defensive.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1666 TransportSecurityState::PKPStateIterator::PKPStateIterator( 1788 TransportSecurityState::PKPStateIterator::PKPStateIterator(
1667 const TransportSecurityState& state) 1789 const TransportSecurityState& state)
1668 : iterator_(state.enabled_pkp_hosts_.begin()), 1790 : iterator_(state.enabled_pkp_hosts_.begin()),
1669 end_(state.enabled_pkp_hosts_.end()) { 1791 end_(state.enabled_pkp_hosts_.end()) {
1670 } 1792 }
1671 1793
1672 TransportSecurityState::PKPStateIterator::~PKPStateIterator() { 1794 TransportSecurityState::PKPStateIterator::~PKPStateIterator() {
1673 } 1795 }
1674 1796
1675 } // namespace 1797 } // 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