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
3 // found in the LICENSE file.
5 #include "net/http/transport_security_persister.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/message_loop/message_loop.h"
15 #include "net/http/transport_security_state.h"
16 #include "testing/gtest/include/gtest/gtest.h"
22 const char kReportUri
[] = "http://www.example.test/report";
24 class TransportSecurityPersisterTest
: public testing::Test
{
26 TransportSecurityPersisterTest() {
29 ~TransportSecurityPersisterTest() override
{
30 base::MessageLoopForIO::current()->RunUntilIdle();
33 void SetUp() override
{
34 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
35 persister_
.reset(new TransportSecurityPersister(
36 &state_
, temp_dir_
.path(),
37 base::MessageLoopForIO::current()->task_runner(), false));
41 base::ScopedTempDir temp_dir_
;
42 TransportSecurityState state_
;
43 scoped_ptr
<TransportSecurityPersister
> persister_
;
46 TEST_F(TransportSecurityPersisterTest
, SerializeData1
) {
50 EXPECT_TRUE(persister_
->SerializeData(&output
));
51 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
55 TEST_F(TransportSecurityPersisterTest
, SerializeData2
) {
56 TransportSecurityState::STSState sts_state
;
57 TransportSecurityState::PKPState pkp_state
;
58 const base::Time
current_time(base::Time::Now());
59 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
60 static const char kYahooDomain
[] = "yahoo.com";
63 state_
.GetStaticDomainState(kYahooDomain
, &sts_state
, &pkp_state
));
64 EXPECT_FALSE(state_
.GetDynamicSTSState(kYahooDomain
, &sts_state
));
65 EXPECT_FALSE(state_
.GetDynamicPKPState(kYahooDomain
, &pkp_state
));
67 bool include_subdomains
= true;
68 state_
.AddHSTS(kYahooDomain
, expiry
, include_subdomains
);
72 EXPECT_TRUE(persister_
->SerializeData(&output
));
73 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
75 EXPECT_TRUE(state_
.GetDynamicSTSState(kYahooDomain
, &sts_state
));
76 EXPECT_EQ(sts_state
.upgrade_mode
,
77 TransportSecurityState::STSState::MODE_FORCE_HTTPS
);
78 EXPECT_TRUE(state_
.GetDynamicSTSState("foo.yahoo.com", &sts_state
));
79 EXPECT_EQ(sts_state
.upgrade_mode
,
80 TransportSecurityState::STSState::MODE_FORCE_HTTPS
);
81 EXPECT_TRUE(state_
.GetDynamicSTSState("foo.bar.yahoo.com", &sts_state
));
82 EXPECT_EQ(sts_state
.upgrade_mode
,
83 TransportSecurityState::STSState::MODE_FORCE_HTTPS
);
84 EXPECT_TRUE(state_
.GetDynamicSTSState("foo.bar.baz.yahoo.com", &sts_state
));
85 EXPECT_EQ(sts_state
.upgrade_mode
,
86 TransportSecurityState::STSState::MODE_FORCE_HTTPS
);
87 EXPECT_FALSE(state_
.GetStaticDomainState("com", &sts_state
, &pkp_state
));
90 TEST_F(TransportSecurityPersisterTest
, SerializeData3
) {
91 const GURL
report_uri(kReportUri
);
93 HashValue
fp1(HASH_VALUE_SHA1
);
94 memset(fp1
.data(), 0, fp1
.size());
95 HashValue
fp2(HASH_VALUE_SHA1
);
96 memset(fp2
.data(), 1, fp2
.size());
98 base::Time::Now() + base::TimeDelta::FromSeconds(1000);
99 HashValueVector dynamic_spki_hashes
;
100 dynamic_spki_hashes
.push_back(fp1
);
101 dynamic_spki_hashes
.push_back(fp2
);
102 bool include_subdomains
= false;
103 state_
.AddHSTS("www.example.com", expiry
, include_subdomains
);
104 state_
.AddHPKP("www.example.com", expiry
, include_subdomains
,
105 dynamic_spki_hashes
, report_uri
);
107 // Add another entry.
108 memset(fp1
.data(), 2, fp1
.size());
109 memset(fp2
.data(), 3, fp2
.size());
111 base::Time::Now() + base::TimeDelta::FromSeconds(3000);
112 dynamic_spki_hashes
.push_back(fp1
);
113 dynamic_spki_hashes
.push_back(fp2
);
114 state_
.AddHSTS("www.example.net", expiry
, include_subdomains
);
115 state_
.AddHPKP("www.example.net", expiry
, include_subdomains
,
116 dynamic_spki_hashes
, report_uri
);
118 // Save a copy of everything.
119 std::set
<std::string
> sts_saved
;
120 TransportSecurityState::STSStateIterator
sts_iter(state_
);
121 while (sts_iter
.HasNext()) {
122 sts_saved
.insert(sts_iter
.hostname());
126 std::set
<std::string
> pkp_saved
;
127 TransportSecurityState::PKPStateIterator
pkp_iter(state_
);
128 while (pkp_iter
.HasNext()) {
129 pkp_saved
.insert(pkp_iter
.hostname());
133 std::string serialized
;
134 EXPECT_TRUE(persister_
->SerializeData(&serialized
));
136 // Persist the data to the file. For the test to be fast and not flaky, we
137 // just do it directly rather than call persister_->StateIsDirty. (That uses
138 // ImportantFileWriter, which has an asynchronous commit interval rather
139 // than block.) Use a different basename just for cleanliness.
140 base::FilePath path
=
141 temp_dir_
.path().AppendASCII("TransportSecurityPersisterTest");
142 EXPECT_TRUE(base::WriteFile(path
, serialized
.c_str(), serialized
.size()));
144 // Read the data back.
145 std::string persisted
;
146 EXPECT_TRUE(base::ReadFileToString(path
, &persisted
));
147 EXPECT_EQ(persisted
, serialized
);
149 EXPECT_TRUE(persister_
->LoadEntries(persisted
, &dirty
));
152 // Check that states are the same as saved.
154 TransportSecurityState::STSStateIterator
sts_iter2(state_
);
155 while (sts_iter2
.HasNext()) {
159 EXPECT_EQ(count
, sts_saved
.size());
162 TransportSecurityState::PKPStateIterator
pkp_iter2(state_
);
163 while (pkp_iter2
.HasNext()) {
167 EXPECT_EQ(count
, pkp_saved
.size());
170 TEST_F(TransportSecurityPersisterTest
, SerializeDataOld
) {
171 // This is an old-style piece of transport state JSON, which has no creation
175 "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {"
176 "\"expiry\": 1266815027.983453, "
177 "\"include_subdomains\": false, "
178 "\"mode\": \"strict\" "
182 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
186 TEST_F(TransportSecurityPersisterTest
, PublicKeyPins
) {
187 const GURL
report_uri(kReportUri
);
188 TransportSecurityState::PKPState pkp_state
;
189 static const char kTestDomain
[] = "example.com";
191 EXPECT_FALSE(state_
.GetDynamicPKPState(kTestDomain
, &pkp_state
));
192 HashValueVector hashes
;
193 std::string failure_log
;
194 EXPECT_FALSE(pkp_state
.CheckPublicKeyPins(hashes
, &failure_log
));
196 HashValue
sha1(HASH_VALUE_SHA1
);
197 memset(sha1
.data(), '1', sha1
.size());
198 pkp_state
.spki_hashes
.push_back(sha1
);
200 EXPECT_FALSE(pkp_state
.CheckPublicKeyPins(hashes
, &failure_log
));
202 hashes
.push_back(sha1
);
203 EXPECT_TRUE(pkp_state
.CheckPublicKeyPins(hashes
, &failure_log
));
205 hashes
[0].data()[0] = '2';
206 EXPECT_FALSE(pkp_state
.CheckPublicKeyPins(hashes
, &failure_log
));
208 const base::Time
current_time(base::Time::Now());
209 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
210 bool include_subdomains
= false;
211 state_
.AddHSTS(kTestDomain
, expiry
, include_subdomains
);
212 state_
.AddHPKP(kTestDomain
, expiry
, include_subdomains
, pkp_state
.spki_hashes
,
214 std::string serialized
;
215 EXPECT_TRUE(persister_
->SerializeData(&serialized
));
217 EXPECT_TRUE(persister_
->LoadEntries(serialized
, &dirty
));
219 TransportSecurityState::PKPState new_pkp_state
;
220 EXPECT_TRUE(state_
.GetDynamicPKPState(kTestDomain
, &new_pkp_state
));
221 EXPECT_EQ(1u, new_pkp_state
.spki_hashes
.size());
222 EXPECT_EQ(sha1
.tag
, new_pkp_state
.spki_hashes
[0].tag
);
224 0, memcmp(new_pkp_state
.spki_hashes
[0].data(), sha1
.data(), sha1
.size()));
225 EXPECT_EQ(report_uri
, new_pkp_state
.report_uri
);