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_persister.h" | 5 #include "net/http/transport_security_persister.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <memory> | 8 #include <memory> |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
13 #include "base/files/file_util.h" | 13 #include "base/files/file_util.h" |
14 #include "base/files/scoped_temp_dir.h" | 14 #include "base/files/scoped_temp_dir.h" |
15 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
16 #include "base/run_loop.h" | 16 #include "base/run_loop.h" |
| 17 #include "base/test/scoped_feature_list.h" |
17 #include "base/threading/thread_task_runner_handle.h" | 18 #include "base/threading/thread_task_runner_handle.h" |
18 #include "net/http/transport_security_state.h" | 19 #include "net/http/transport_security_state.h" |
19 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
20 | 21 |
21 namespace net { | 22 namespace net { |
22 | 23 |
23 namespace { | 24 namespace { |
24 | 25 |
25 const char kReportUri[] = "http://www.example.test/report"; | 26 const char kReportUri[] = "http://www.example.test/report"; |
26 | 27 |
(...skipping 14 matching lines...) Expand all Loading... |
41 &state_, temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get(), | 42 &state_, temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get(), |
42 false)); | 43 false)); |
43 } | 44 } |
44 | 45 |
45 protected: | 46 protected: |
46 base::ScopedTempDir temp_dir_; | 47 base::ScopedTempDir temp_dir_; |
47 TransportSecurityState state_; | 48 TransportSecurityState state_; |
48 std::unique_ptr<TransportSecurityPersister> persister_; | 49 std::unique_ptr<TransportSecurityPersister> persister_; |
49 }; | 50 }; |
50 | 51 |
| 52 // Tests that LoadEntries() clears existing non-static entries. |
| 53 TEST_F(TransportSecurityPersisterTest, LoadEntriesClearsExistingState) { |
| 54 base::test::ScopedFeatureList feature_list; |
| 55 feature_list.InitAndEnableFeature( |
| 56 TransportSecurityState::kDynamicExpectCTFeature); |
| 57 std::string output; |
| 58 bool dirty; |
| 59 |
| 60 TransportSecurityState::STSState sts_state; |
| 61 TransportSecurityState::PKPState pkp_state; |
| 62 TransportSecurityState::ExpectCTState expect_ct_state; |
| 63 const base::Time current_time(base::Time::Now()); |
| 64 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); |
| 65 static const char kYahooDomain[] = "yahoo.com"; |
| 66 |
| 67 EXPECT_FALSE(state_.GetDynamicSTSState(kYahooDomain, &sts_state)); |
| 68 EXPECT_FALSE(state_.GetDynamicPKPState(kYahooDomain, &pkp_state)); |
| 69 |
| 70 state_.AddHSTS(kYahooDomain, expiry, false /* include subdomains */); |
| 71 HashValue spki(HASH_VALUE_SHA256); |
| 72 memset(spki.data(), 0, spki.size()); |
| 73 HashValueVector dynamic_spki_hashes; |
| 74 dynamic_spki_hashes.push_back(spki); |
| 75 state_.AddHPKP(kYahooDomain, expiry, false, dynamic_spki_hashes, GURL()); |
| 76 state_.AddExpectCT(kYahooDomain, expiry, true /* enforce */, GURL()); |
| 77 |
| 78 EXPECT_TRUE(state_.GetDynamicSTSState(kYahooDomain, &sts_state)); |
| 79 EXPECT_TRUE(state_.GetDynamicPKPState(kYahooDomain, &pkp_state)); |
| 80 EXPECT_TRUE(state_.GetDynamicExpectCTState(kYahooDomain, &expect_ct_state)); |
| 81 |
| 82 EXPECT_TRUE(persister_->LoadEntries("{}", &dirty)); |
| 83 EXPECT_FALSE(dirty); |
| 84 |
| 85 EXPECT_FALSE(state_.GetDynamicSTSState(kYahooDomain, &sts_state)); |
| 86 EXPECT_FALSE(state_.GetDynamicPKPState(kYahooDomain, &pkp_state)); |
| 87 EXPECT_FALSE(state_.GetDynamicExpectCTState(kYahooDomain, &expect_ct_state)); |
| 88 } |
| 89 |
51 TEST_F(TransportSecurityPersisterTest, SerializeData1) { | 90 TEST_F(TransportSecurityPersisterTest, SerializeData1) { |
52 std::string output; | 91 std::string output; |
53 bool dirty; | 92 bool dirty; |
54 | 93 |
55 EXPECT_TRUE(persister_->SerializeData(&output)); | 94 EXPECT_TRUE(persister_->SerializeData(&output)); |
56 EXPECT_TRUE(persister_->LoadEntries(output, &dirty)); | 95 EXPECT_TRUE(persister_->LoadEntries(output, &dirty)); |
57 EXPECT_FALSE(dirty); | 96 EXPECT_FALSE(dirty); |
58 } | 97 } |
59 | 98 |
60 TEST_F(TransportSecurityPersisterTest, SerializeData2) { | 99 TEST_F(TransportSecurityPersisterTest, SerializeData2) { |
(...skipping 25 matching lines...) Expand all Loading... |
86 EXPECT_TRUE(state_.GetDynamicSTSState("foo.bar.yahoo.com", &sts_state)); | 125 EXPECT_TRUE(state_.GetDynamicSTSState("foo.bar.yahoo.com", &sts_state)); |
87 EXPECT_EQ(sts_state.upgrade_mode, | 126 EXPECT_EQ(sts_state.upgrade_mode, |
88 TransportSecurityState::STSState::MODE_FORCE_HTTPS); | 127 TransportSecurityState::STSState::MODE_FORCE_HTTPS); |
89 EXPECT_TRUE(state_.GetDynamicSTSState("foo.bar.baz.yahoo.com", &sts_state)); | 128 EXPECT_TRUE(state_.GetDynamicSTSState("foo.bar.baz.yahoo.com", &sts_state)); |
90 EXPECT_EQ(sts_state.upgrade_mode, | 129 EXPECT_EQ(sts_state.upgrade_mode, |
91 TransportSecurityState::STSState::MODE_FORCE_HTTPS); | 130 TransportSecurityState::STSState::MODE_FORCE_HTTPS); |
92 EXPECT_FALSE(state_.GetStaticDomainState("com", &sts_state, &pkp_state)); | 131 EXPECT_FALSE(state_.GetStaticDomainState("com", &sts_state, &pkp_state)); |
93 } | 132 } |
94 | 133 |
95 TEST_F(TransportSecurityPersisterTest, SerializeData3) { | 134 TEST_F(TransportSecurityPersisterTest, SerializeData3) { |
| 135 base::test::ScopedFeatureList feature_list; |
| 136 feature_list.InitAndEnableFeature( |
| 137 TransportSecurityState::kDynamicExpectCTFeature); |
96 const GURL report_uri(kReportUri); | 138 const GURL report_uri(kReportUri); |
97 // Add an entry. | 139 // Add an entry. |
98 HashValue fp1(HASH_VALUE_SHA256); | 140 HashValue fp1(HASH_VALUE_SHA256); |
99 memset(fp1.data(), 0, fp1.size()); | 141 memset(fp1.data(), 0, fp1.size()); |
100 HashValue fp2(HASH_VALUE_SHA256); | 142 HashValue fp2(HASH_VALUE_SHA256); |
101 memset(fp2.data(), 1, fp2.size()); | 143 memset(fp2.data(), 1, fp2.size()); |
102 base::Time expiry = | 144 base::Time expiry = |
103 base::Time::Now() + base::TimeDelta::FromSeconds(1000); | 145 base::Time::Now() + base::TimeDelta::FromSeconds(1000); |
104 HashValueVector dynamic_spki_hashes; | 146 HashValueVector dynamic_spki_hashes; |
105 dynamic_spki_hashes.push_back(fp1); | 147 dynamic_spki_hashes.push_back(fp1); |
106 dynamic_spki_hashes.push_back(fp2); | 148 dynamic_spki_hashes.push_back(fp2); |
107 bool include_subdomains = false; | 149 bool include_subdomains = false; |
108 state_.AddHSTS("www.example.com", expiry, include_subdomains); | 150 state_.AddHSTS("www.example.com", expiry, include_subdomains); |
109 state_.AddHPKP("www.example.com", expiry, include_subdomains, | 151 state_.AddHPKP("www.example.com", expiry, include_subdomains, |
110 dynamic_spki_hashes, report_uri); | 152 dynamic_spki_hashes, report_uri); |
| 153 state_.AddExpectCT("www.example.com", expiry, true /* enforce */, GURL()); |
111 | 154 |
112 // Add another entry. | 155 // Add another entry. |
113 memset(fp1.data(), 2, fp1.size()); | 156 memset(fp1.data(), 2, fp1.size()); |
114 memset(fp2.data(), 3, fp2.size()); | 157 memset(fp2.data(), 3, fp2.size()); |
115 expiry = | 158 expiry = |
116 base::Time::Now() + base::TimeDelta::FromSeconds(3000); | 159 base::Time::Now() + base::TimeDelta::FromSeconds(3000); |
117 dynamic_spki_hashes.push_back(fp1); | 160 dynamic_spki_hashes.push_back(fp1); |
118 dynamic_spki_hashes.push_back(fp2); | 161 dynamic_spki_hashes.push_back(fp2); |
119 state_.AddHSTS("www.example.net", expiry, include_subdomains); | 162 state_.AddHSTS("www.example.net", expiry, include_subdomains); |
120 state_.AddHPKP("www.example.net", expiry, include_subdomains, | 163 state_.AddHPKP("www.example.net", expiry, include_subdomains, |
121 dynamic_spki_hashes, report_uri); | 164 dynamic_spki_hashes, report_uri); |
| 165 state_.AddExpectCT("www.example.net", expiry, false /* enforce */, |
| 166 report_uri); |
122 | 167 |
123 // Save a copy of everything. | 168 // Save a copy of everything. |
124 std::set<std::string> sts_saved; | 169 std::set<std::string> sts_saved; |
125 TransportSecurityState::STSStateIterator sts_iter(state_); | 170 TransportSecurityState::STSStateIterator sts_iter(state_); |
126 while (sts_iter.HasNext()) { | 171 while (sts_iter.HasNext()) { |
127 sts_saved.insert(sts_iter.hostname()); | 172 sts_saved.insert(sts_iter.hostname()); |
128 sts_iter.Advance(); | 173 sts_iter.Advance(); |
129 } | 174 } |
130 | 175 |
131 std::set<std::string> pkp_saved; | 176 std::set<std::string> pkp_saved; |
132 TransportSecurityState::PKPStateIterator pkp_iter(state_); | 177 TransportSecurityState::PKPStateIterator pkp_iter(state_); |
133 while (pkp_iter.HasNext()) { | 178 while (pkp_iter.HasNext()) { |
134 pkp_saved.insert(pkp_iter.hostname()); | 179 pkp_saved.insert(pkp_iter.hostname()); |
135 pkp_iter.Advance(); | 180 pkp_iter.Advance(); |
136 } | 181 } |
137 | 182 |
| 183 std::set<std::string> expect_ct_saved; |
| 184 TransportSecurityState::ExpectCTStateIterator expect_ct_iter(state_); |
| 185 while (expect_ct_iter.HasNext()) { |
| 186 expect_ct_saved.insert(expect_ct_iter.hostname()); |
| 187 expect_ct_iter.Advance(); |
| 188 } |
| 189 |
138 std::string serialized; | 190 std::string serialized; |
139 EXPECT_TRUE(persister_->SerializeData(&serialized)); | 191 EXPECT_TRUE(persister_->SerializeData(&serialized)); |
140 | 192 |
141 // Persist the data to the file. For the test to be fast and not flaky, we | 193 // Persist the data to the file. For the test to be fast and not flaky, we |
142 // just do it directly rather than call persister_->StateIsDirty. (That uses | 194 // just do it directly rather than call persister_->StateIsDirty. (That uses |
143 // ImportantFileWriter, which has an asynchronous commit interval rather | 195 // ImportantFileWriter, which has an asynchronous commit interval rather |
144 // than block.) Use a different basename just for cleanliness. | 196 // than block.) Use a different basename just for cleanliness. |
145 base::FilePath path = | 197 base::FilePath path = |
146 temp_dir_.GetPath().AppendASCII("TransportSecurityPersisterTest"); | 198 temp_dir_.GetPath().AppendASCII("TransportSecurityPersisterTest"); |
147 EXPECT_EQ(static_cast<int>(serialized.size()), | 199 EXPECT_EQ(static_cast<int>(serialized.size()), |
(...skipping 16 matching lines...) Expand all Loading... |
164 } | 216 } |
165 EXPECT_EQ(count, sts_saved.size()); | 217 EXPECT_EQ(count, sts_saved.size()); |
166 | 218 |
167 count = 0; | 219 count = 0; |
168 TransportSecurityState::PKPStateIterator pkp_iter2(state_); | 220 TransportSecurityState::PKPStateIterator pkp_iter2(state_); |
169 while (pkp_iter2.HasNext()) { | 221 while (pkp_iter2.HasNext()) { |
170 count++; | 222 count++; |
171 pkp_iter2.Advance(); | 223 pkp_iter2.Advance(); |
172 } | 224 } |
173 EXPECT_EQ(count, pkp_saved.size()); | 225 EXPECT_EQ(count, pkp_saved.size()); |
| 226 |
| 227 count = 0; |
| 228 TransportSecurityState::ExpectCTStateIterator expect_ct_iter2(state_); |
| 229 while (expect_ct_iter2.HasNext()) { |
| 230 count++; |
| 231 expect_ct_iter2.Advance(); |
| 232 } |
| 233 EXPECT_EQ(count, expect_ct_saved.size()); |
174 } | 234 } |
175 | 235 |
176 TEST_F(TransportSecurityPersisterTest, SerializeDataOld) { | 236 TEST_F(TransportSecurityPersisterTest, SerializeDataOld) { |
177 // This is an old-style piece of transport state JSON, which has no creation | 237 // This is an old-style piece of transport state JSON, which has no creation |
178 // date. | 238 // date. |
179 std::string output = | 239 std::string output = |
180 "{ " | 240 "{ " |
181 "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {" | 241 "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {" |
182 "\"expiry\": 1266815027.983453, " | 242 "\"expiry\": 1266815027.983453, " |
183 "\"include_subdomains\": false, " | 243 "\"include_subdomains\": false, " |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 | 284 |
225 TransportSecurityState::PKPState new_pkp_state; | 285 TransportSecurityState::PKPState new_pkp_state; |
226 EXPECT_TRUE(state_.GetDynamicPKPState(kTestDomain, &new_pkp_state)); | 286 EXPECT_TRUE(state_.GetDynamicPKPState(kTestDomain, &new_pkp_state)); |
227 EXPECT_EQ(1u, new_pkp_state.spki_hashes.size()); | 287 EXPECT_EQ(1u, new_pkp_state.spki_hashes.size()); |
228 EXPECT_EQ(sha256.tag, new_pkp_state.spki_hashes[0].tag); | 288 EXPECT_EQ(sha256.tag, new_pkp_state.spki_hashes[0].tag); |
229 EXPECT_EQ(0, memcmp(new_pkp_state.spki_hashes[0].data(), sha256.data(), | 289 EXPECT_EQ(0, memcmp(new_pkp_state.spki_hashes[0].data(), sha256.data(), |
230 sha256.size())); | 290 sha256.size())); |
231 EXPECT_EQ(report_uri, new_pkp_state.report_uri); | 291 EXPECT_EQ(report_uri, new_pkp_state.report_uri); |
232 } | 292 } |
233 | 293 |
| 294 // Tests that dynamic Expect-CT state is serialized and deserialized correctly. |
| 295 TEST_F(TransportSecurityPersisterTest, ExpectCT) { |
| 296 base::test::ScopedFeatureList feature_list; |
| 297 feature_list.InitAndEnableFeature( |
| 298 TransportSecurityState::kDynamicExpectCTFeature); |
| 299 const GURL report_uri(kReportUri); |
| 300 TransportSecurityState::ExpectCTState expect_ct_state; |
| 301 static const char kTestDomain[] = "example.test"; |
| 302 |
| 303 EXPECT_FALSE(state_.GetDynamicExpectCTState(kTestDomain, &expect_ct_state)); |
| 304 |
| 305 const base::Time current_time(base::Time::Now()); |
| 306 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); |
| 307 state_.AddExpectCT(kTestDomain, expiry, true /* enforce */, GURL()); |
| 308 std::string serialized; |
| 309 EXPECT_TRUE(persister_->SerializeData(&serialized)); |
| 310 bool dirty; |
| 311 // LoadEntries() clears existing dynamic data before loading entries from |
| 312 // |serialized|. |
| 313 EXPECT_TRUE(persister_->LoadEntries(serialized, &dirty)); |
| 314 |
| 315 TransportSecurityState::ExpectCTState new_expect_ct_state; |
| 316 EXPECT_TRUE( |
| 317 state_.GetDynamicExpectCTState(kTestDomain, &new_expect_ct_state)); |
| 318 EXPECT_TRUE(new_expect_ct_state.enforce); |
| 319 EXPECT_TRUE(new_expect_ct_state.report_uri.is_empty()); |
| 320 EXPECT_EQ(expiry, new_expect_ct_state.expiry); |
| 321 |
| 322 // Update the state for the domain and check that it is |
| 323 // serialized/deserialized correctly. |
| 324 state_.AddExpectCT(kTestDomain, expiry, false /* enforce */, report_uri); |
| 325 EXPECT_TRUE(persister_->SerializeData(&serialized)); |
| 326 EXPECT_TRUE(persister_->LoadEntries(serialized, &dirty)); |
| 327 EXPECT_TRUE( |
| 328 state_.GetDynamicExpectCTState(kTestDomain, &new_expect_ct_state)); |
| 329 EXPECT_FALSE(new_expect_ct_state.enforce); |
| 330 EXPECT_EQ(report_uri, new_expect_ct_state.report_uri); |
| 331 EXPECT_EQ(expiry, new_expect_ct_state.expiry); |
| 332 } |
| 333 |
| 334 // Tests that dynamic Expect-CT state is serialized and deserialized correctly |
| 335 // when there is also PKP and STS data present. |
| 336 TEST_F(TransportSecurityPersisterTest, ExpectCTWithSTSAndPKPDataPresent) { |
| 337 base::test::ScopedFeatureList feature_list; |
| 338 feature_list.InitAndEnableFeature( |
| 339 TransportSecurityState::kDynamicExpectCTFeature); |
| 340 const GURL report_uri(kReportUri); |
| 341 TransportSecurityState::ExpectCTState expect_ct_state; |
| 342 static const char kTestDomain[] = "example.test"; |
| 343 |
| 344 EXPECT_FALSE(state_.GetDynamicExpectCTState(kTestDomain, &expect_ct_state)); |
| 345 |
| 346 const base::Time current_time(base::Time::Now()); |
| 347 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); |
| 348 state_.AddHSTS(kTestDomain, expiry, false /* include subdomains */); |
| 349 state_.AddExpectCT(kTestDomain, expiry, true /* enforce */, GURL()); |
| 350 HashValue spki_hash(HASH_VALUE_SHA256); |
| 351 memset(spki_hash.data(), 0, spki_hash.size()); |
| 352 HashValueVector dynamic_spki_hashes; |
| 353 dynamic_spki_hashes.push_back(spki_hash); |
| 354 state_.AddHPKP(kTestDomain, expiry, false /* include subdomains */, |
| 355 dynamic_spki_hashes, GURL()); |
| 356 |
| 357 std::string serialized; |
| 358 EXPECT_TRUE(persister_->SerializeData(&serialized)); |
| 359 bool dirty; |
| 360 // LoadEntries() clears existing dynamic data before loading entries from |
| 361 // |serialized|. |
| 362 EXPECT_TRUE(persister_->LoadEntries(serialized, &dirty)); |
| 363 |
| 364 TransportSecurityState::ExpectCTState new_expect_ct_state; |
| 365 EXPECT_TRUE( |
| 366 state_.GetDynamicExpectCTState(kTestDomain, &new_expect_ct_state)); |
| 367 EXPECT_TRUE(new_expect_ct_state.enforce); |
| 368 EXPECT_TRUE(new_expect_ct_state.report_uri.is_empty()); |
| 369 EXPECT_EQ(expiry, new_expect_ct_state.expiry); |
| 370 // Check that STS and PKP state are loaded properly as well. |
| 371 TransportSecurityState::STSState sts_state; |
| 372 EXPECT_TRUE(state_.GetDynamicSTSState(kTestDomain, &sts_state)); |
| 373 EXPECT_EQ(sts_state.upgrade_mode, |
| 374 TransportSecurityState::STSState::MODE_FORCE_HTTPS); |
| 375 TransportSecurityState::PKPState pkp_state; |
| 376 EXPECT_TRUE(state_.GetDynamicPKPState(kTestDomain, &pkp_state)); |
| 377 EXPECT_EQ(1u, pkp_state.spki_hashes.size()); |
| 378 EXPECT_EQ(0, memcmp(pkp_state.spki_hashes[0].data(), spki_hash.data(), |
| 379 spki_hash.size())); |
| 380 } |
| 381 |
| 382 // Tests that Expect-CT state is not serialized and persisted when the feature |
| 383 // is disabled. |
| 384 TEST_F(TransportSecurityPersisterTest, ExpectCTDisabled) { |
| 385 base::test::ScopedFeatureList feature_list; |
| 386 feature_list.InitAndDisableFeature( |
| 387 TransportSecurityState::kDynamicExpectCTFeature); |
| 388 const GURL report_uri(kReportUri); |
| 389 TransportSecurityState::ExpectCTState expect_ct_state; |
| 390 static const char kTestDomain[] = "example.test"; |
| 391 |
| 392 EXPECT_FALSE(state_.GetDynamicExpectCTState(kTestDomain, &expect_ct_state)); |
| 393 |
| 394 const base::Time current_time(base::Time::Now()); |
| 395 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); |
| 396 state_.AddExpectCT(kTestDomain, expiry, true /* enforce */, GURL()); |
| 397 std::string serialized; |
| 398 EXPECT_TRUE(persister_->SerializeData(&serialized)); |
| 399 bool dirty; |
| 400 EXPECT_TRUE(persister_->LoadEntries(serialized, &dirty)); |
| 401 |
| 402 TransportSecurityState::ExpectCTState new_expect_ct_state; |
| 403 EXPECT_FALSE( |
| 404 state_.GetDynamicExpectCTState(kTestDomain, &new_expect_ct_state)); |
| 405 } |
| 406 |
234 } // namespace | 407 } // namespace |
235 | 408 |
236 } // namespace net | 409 } // namespace net |
OLD | NEW |