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(
36 base::MessageLoopForIO::current()->message_loop_proxy(),
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::DomainState domain_state
;
57 const base::Time
current_time(base::Time::Now());
58 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
59 static const char kYahooDomain
[] = "yahoo.com";
61 EXPECT_FALSE(state_
.GetStaticDomainState(kYahooDomain
, &domain_state
));
62 EXPECT_FALSE(state_
.GetDynamicDomainState(kYahooDomain
, &domain_state
));
64 bool include_subdomains
= true;
65 state_
.AddHSTS(kYahooDomain
, expiry
, include_subdomains
);
69 EXPECT_TRUE(persister_
->SerializeData(&output
));
70 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
72 EXPECT_TRUE(state_
.GetDynamicDomainState(kYahooDomain
, &domain_state
));
73 EXPECT_EQ(domain_state
.sts
.upgrade_mode
,
74 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
);
75 EXPECT_TRUE(state_
.GetDynamicDomainState("foo.yahoo.com", &domain_state
));
76 EXPECT_EQ(domain_state
.sts
.upgrade_mode
,
77 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
);
78 EXPECT_TRUE(state_
.GetDynamicDomainState("foo.bar.yahoo.com", &domain_state
));
79 EXPECT_EQ(domain_state
.sts
.upgrade_mode
,
80 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
);
82 state_
.GetDynamicDomainState("foo.bar.baz.yahoo.com", &domain_state
));
83 EXPECT_EQ(domain_state
.sts
.upgrade_mode
,
84 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
);
85 EXPECT_FALSE(state_
.GetStaticDomainState("com", &domain_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::map
<std::string
, TransportSecurityState::DomainState
> saved
;
117 TransportSecurityState::Iterator
i(state_
);
118 while (i
.HasNext()) {
119 saved
[i
.hostname()] = i
.domain_state();
123 std::string serialized
;
124 EXPECT_TRUE(persister_
->SerializeData(&serialized
));
126 // Persist the data to the file. For the test to be fast and not flaky, we
127 // just do it directly rather than call persister_->StateIsDirty. (That uses
128 // ImportantFileWriter, which has an asynchronous commit interval rather
129 // than block.) Use a different basename just for cleanliness.
130 base::FilePath path
=
131 temp_dir_
.path().AppendASCII("TransportSecurityPersisterTest");
132 EXPECT_TRUE(base::WriteFile(path
, serialized
.c_str(), serialized
.size()));
134 // Read the data back.
135 std::string persisted
;
136 EXPECT_TRUE(base::ReadFileToString(path
, &persisted
));
137 EXPECT_EQ(persisted
, serialized
);
139 EXPECT_TRUE(persister_
->LoadEntries(persisted
, &dirty
));
142 // Check that states are the same as saved.
144 TransportSecurityState::Iterator
j(state_
);
145 while (j
.HasNext()) {
149 EXPECT_EQ(count
, saved
.size());
152 TEST_F(TransportSecurityPersisterTest
, SerializeDataOld
) {
153 // This is an old-style piece of transport state JSON, which has no creation
157 "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {"
158 "\"expiry\": 1266815027.983453, "
159 "\"include_subdomains\": false, "
160 "\"mode\": \"strict\" "
164 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
168 TEST_F(TransportSecurityPersisterTest
, PublicKeyHashes
) {
169 TransportSecurityState::DomainState domain_state
;
170 static const char kTestDomain
[] = "example.com";
171 EXPECT_FALSE(state_
.GetDynamicDomainState(kTestDomain
, &domain_state
));
172 HashValueVector hashes
;
173 std::string failure_log
;
174 EXPECT_FALSE(domain_state
.CheckPublicKeyPins(hashes
, &failure_log
));
176 HashValue
sha1(HASH_VALUE_SHA1
);
177 memset(sha1
.data(), '1', sha1
.size());
178 domain_state
.pkp
.spki_hashes
.push_back(sha1
);
180 EXPECT_FALSE(domain_state
.CheckPublicKeyPins(hashes
, &failure_log
));
182 hashes
.push_back(sha1
);
183 EXPECT_TRUE(domain_state
.CheckPublicKeyPins(hashes
, &failure_log
));
185 hashes
[0].data()[0] = '2';
186 EXPECT_FALSE(domain_state
.CheckPublicKeyPins(hashes
, &failure_log
));
188 const base::Time
current_time(base::Time::Now());
189 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
190 bool include_subdomains
= false;
191 state_
.AddHSTS(kTestDomain
, expiry
, include_subdomains
);
193 kTestDomain
, expiry
, include_subdomains
, domain_state
.pkp
.spki_hashes
);
194 std::string serialized
;
195 EXPECT_TRUE(persister_
->SerializeData(&serialized
));
197 EXPECT_TRUE(persister_
->LoadEntries(serialized
, &dirty
));
199 TransportSecurityState::DomainState new_domain_state
;
200 EXPECT_TRUE(state_
.GetDynamicDomainState(kTestDomain
, &new_domain_state
));
201 EXPECT_EQ(1u, new_domain_state
.pkp
.spki_hashes
.size());
202 EXPECT_EQ(sha1
.tag
, new_domain_state
.pkp
.spki_hashes
[0].tag
);
204 memcmp(new_domain_state
.pkp
.spki_hashes
[0].data(),