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 class TransportSecurityPersisterTest
: public testing::Test
{
24 TransportSecurityPersisterTest() {
27 ~TransportSecurityPersisterTest() override
{
28 base::MessageLoopForIO::current()->RunUntilIdle();
31 void SetUp() override
{
32 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
33 persister_
.reset(new TransportSecurityPersister(
34 &state_
, temp_dir_
.path(),
35 base::MessageLoopForIO::current()->task_runner(), false));
39 base::ScopedTempDir temp_dir_
;
40 TransportSecurityState state_
;
41 scoped_ptr
<TransportSecurityPersister
> persister_
;
44 TEST_F(TransportSecurityPersisterTest
, SerializeData1
) {
48 EXPECT_TRUE(persister_
->SerializeData(&output
));
49 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
53 TEST_F(TransportSecurityPersisterTest
, SerializeData2
) {
54 TransportSecurityState::STSState sts_state
;
55 TransportSecurityState::PKPState pkp_state
;
56 const base::Time
current_time(base::Time::Now());
57 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
58 static const char kYahooDomain
[] = "yahoo.com";
61 state_
.GetStaticDomainState(kYahooDomain
, &sts_state
, &pkp_state
));
62 EXPECT_FALSE(state_
.GetDynamicSTSState(kYahooDomain
, &sts_state
));
63 EXPECT_FALSE(state_
.GetDynamicPKPState(kYahooDomain
, &pkp_state
));
65 bool include_subdomains
= true;
66 state_
.AddHSTS(kYahooDomain
, expiry
, include_subdomains
);
70 EXPECT_TRUE(persister_
->SerializeData(&output
));
71 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
73 EXPECT_TRUE(state_
.GetDynamicSTSState(kYahooDomain
, &sts_state
));
74 EXPECT_EQ(sts_state
.upgrade_mode
,
75 TransportSecurityState::STSState::MODE_FORCE_HTTPS
);
76 EXPECT_TRUE(state_
.GetDynamicSTSState("foo.yahoo.com", &sts_state
));
77 EXPECT_EQ(sts_state
.upgrade_mode
,
78 TransportSecurityState::STSState::MODE_FORCE_HTTPS
);
79 EXPECT_TRUE(state_
.GetDynamicSTSState("foo.bar.yahoo.com", &sts_state
));
80 EXPECT_EQ(sts_state
.upgrade_mode
,
81 TransportSecurityState::STSState::MODE_FORCE_HTTPS
);
82 EXPECT_TRUE(state_
.GetDynamicSTSState("foo.bar.baz.yahoo.com", &sts_state
));
83 EXPECT_EQ(sts_state
.upgrade_mode
,
84 TransportSecurityState::STSState::MODE_FORCE_HTTPS
);
85 EXPECT_FALSE(state_
.GetStaticDomainState("com", &sts_state
, &pkp_state
));
88 TEST_F(TransportSecurityPersisterTest
, SerializeData3
) {
90 HashValue
fp1(HASH_VALUE_SHA1
);
91 memset(fp1
.data(), 0, fp1
.size());
92 HashValue
fp2(HASH_VALUE_SHA1
);
93 memset(fp2
.data(), 1, fp2
.size());
95 base::Time::Now() + base::TimeDelta::FromSeconds(1000);
96 HashValueVector dynamic_spki_hashes
;
97 dynamic_spki_hashes
.push_back(fp1
);
98 dynamic_spki_hashes
.push_back(fp2
);
99 bool include_subdomains
= false;
100 state_
.AddHSTS("www.example.com", expiry
, include_subdomains
);
101 state_
.AddHPKP("www.example.com", expiry
, include_subdomains
,
102 dynamic_spki_hashes
);
104 // Add another entry.
105 memset(fp1
.data(), 2, fp1
.size());
106 memset(fp2
.data(), 3, fp2
.size());
108 base::Time::Now() + base::TimeDelta::FromSeconds(3000);
109 dynamic_spki_hashes
.push_back(fp1
);
110 dynamic_spki_hashes
.push_back(fp2
);
111 state_
.AddHSTS("www.example.net", expiry
, include_subdomains
);
112 state_
.AddHPKP("www.example.net", expiry
, include_subdomains
,
113 dynamic_spki_hashes
);
115 // Save a copy of everything.
116 std::set
<std::string
> sts_saved
;
117 TransportSecurityState::STSStateIterator
sts_iter(state_
);
118 while (sts_iter
.HasNext()) {
119 sts_saved
.insert(sts_iter
.hostname());
123 std::set
<std::string
> pkp_saved
;
124 TransportSecurityState::PKPStateIterator
pkp_iter(state_
);
125 while (pkp_iter
.HasNext()) {
126 pkp_saved
.insert(pkp_iter
.hostname());
130 std::string serialized
;
131 EXPECT_TRUE(persister_
->SerializeData(&serialized
));
133 // Persist the data to the file. For the test to be fast and not flaky, we
134 // just do it directly rather than call persister_->StateIsDirty. (That uses
135 // ImportantFileWriter, which has an asynchronous commit interval rather
136 // than block.) Use a different basename just for cleanliness.
137 base::FilePath path
=
138 temp_dir_
.path().AppendASCII("TransportSecurityPersisterTest");
139 EXPECT_TRUE(base::WriteFile(path
, serialized
.c_str(), serialized
.size()));
141 // Read the data back.
142 std::string persisted
;
143 EXPECT_TRUE(base::ReadFileToString(path
, &persisted
));
144 EXPECT_EQ(persisted
, serialized
);
146 EXPECT_TRUE(persister_
->LoadEntries(persisted
, &dirty
));
149 // Check that states are the same as saved.
151 TransportSecurityState::STSStateIterator
sts_iter2(state_
);
152 while (sts_iter2
.HasNext()) {
156 EXPECT_EQ(count
, sts_saved
.size());
159 TransportSecurityState::PKPStateIterator
pkp_iter2(state_
);
160 while (pkp_iter2
.HasNext()) {
164 EXPECT_EQ(count
, pkp_saved
.size());
167 TEST_F(TransportSecurityPersisterTest
, SerializeDataOld
) {
168 // This is an old-style piece of transport state JSON, which has no creation
172 "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {"
173 "\"expiry\": 1266815027.983453, "
174 "\"include_subdomains\": false, "
175 "\"mode\": \"strict\" "
179 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
183 TEST_F(TransportSecurityPersisterTest
, PublicKeyHashes
) {
184 TransportSecurityState::PKPState pkp_state
;
185 static const char kTestDomain
[] = "example.com";
186 EXPECT_FALSE(state_
.GetDynamicPKPState(kTestDomain
, &pkp_state
));
187 HashValueVector hashes
;
188 std::string failure_log
;
189 EXPECT_FALSE(pkp_state
.CheckPublicKeyPins(hashes
, &failure_log
));
191 HashValue
sha1(HASH_VALUE_SHA1
);
192 memset(sha1
.data(), '1', sha1
.size());
193 pkp_state
.spki_hashes
.push_back(sha1
);
195 EXPECT_FALSE(pkp_state
.CheckPublicKeyPins(hashes
, &failure_log
));
197 hashes
.push_back(sha1
);
198 EXPECT_TRUE(pkp_state
.CheckPublicKeyPins(hashes
, &failure_log
));
200 hashes
[0].data()[0] = '2';
201 EXPECT_FALSE(pkp_state
.CheckPublicKeyPins(hashes
, &failure_log
));
203 const base::Time
current_time(base::Time::Now());
204 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
205 bool include_subdomains
= false;
206 state_
.AddHSTS(kTestDomain
, expiry
, include_subdomains
);
207 state_
.AddHPKP(kTestDomain
, expiry
, include_subdomains
,
208 pkp_state
.spki_hashes
);
209 std::string serialized
;
210 EXPECT_TRUE(persister_
->SerializeData(&serialized
));
212 EXPECT_TRUE(persister_
->LoadEntries(serialized
, &dirty
));
214 TransportSecurityState::PKPState new_pkp_state
;
215 EXPECT_TRUE(state_
.GetDynamicPKPState(kTestDomain
, &new_pkp_state
));
216 EXPECT_EQ(1u, new_pkp_state
.spki_hashes
.size());
217 EXPECT_EQ(sha1
.tag
, new_pkp_state
.spki_hashes
[0].tag
);
219 0, memcmp(new_pkp_state
.spki_hashes
[0].data(), sha1
.data(), sha1
.size()));