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/file_util.h"
12 #include "base/files/file_path.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"
18 using net::TransportSecurityPersister
;
19 using net::TransportSecurityState
;
21 class TransportSecurityPersisterTest
: public testing::Test
{
23 TransportSecurityPersisterTest() {
26 virtual ~TransportSecurityPersisterTest() {
27 base::MessageLoopForIO::current()->RunUntilIdle();
30 virtual void SetUp() OVERRIDE
{
31 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
32 persister_
.reset(new TransportSecurityPersister(
35 base::MessageLoopForIO::current()->message_loop_proxy(),
40 base::ScopedTempDir temp_dir_
;
41 TransportSecurityState state_
;
42 scoped_ptr
<TransportSecurityPersister
> persister_
;
45 TEST_F(TransportSecurityPersisterTest
, SerializeData1
) {
49 EXPECT_TRUE(persister_
->SerializeData(&output
));
50 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
54 TEST_F(TransportSecurityPersisterTest
, SerializeData2
) {
55 TransportSecurityState::DomainState domain_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";
60 EXPECT_FALSE(state_
.GetDomainState(kYahooDomain
, true, &domain_state
));
62 bool include_subdomains
= true;
63 state_
.AddHSTS(kYahooDomain
, expiry
, include_subdomains
);
67 EXPECT_TRUE(persister_
->SerializeData(&output
));
68 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
70 EXPECT_TRUE(state_
.GetDomainState(kYahooDomain
, true, &domain_state
));
71 EXPECT_EQ(domain_state
.upgrade_mode
,
72 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
);
73 EXPECT_TRUE(state_
.GetDomainState("foo.yahoo.com", true, &domain_state
));
74 EXPECT_EQ(domain_state
.upgrade_mode
,
75 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
);
76 EXPECT_TRUE(state_
.GetDomainState("foo.bar.yahoo.com", true, &domain_state
));
77 EXPECT_EQ(domain_state
.upgrade_mode
,
78 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
);
79 EXPECT_TRUE(state_
.GetDomainState("foo.bar.baz.yahoo.com", true,
81 EXPECT_EQ(domain_state
.upgrade_mode
,
82 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
);
83 EXPECT_FALSE(state_
.GetDomainState("com", true, &domain_state
));
86 TEST_F(TransportSecurityPersisterTest
, SerializeData3
) {
88 net::HashValue
fp1(net::HASH_VALUE_SHA1
);
89 memset(fp1
.data(), 0, fp1
.size());
90 net::HashValue
fp2(net::HASH_VALUE_SHA1
);
91 memset(fp2
.data(), 1, fp2
.size());
93 base::Time::Now() + base::TimeDelta::FromSeconds(1000);
94 net::HashValueVector dynamic_spki_hashes
;
95 dynamic_spki_hashes
.push_back(fp1
);
96 dynamic_spki_hashes
.push_back(fp2
);
97 bool include_subdomains
= false;
98 state_
.AddHSTS("www.example.com", expiry
, include_subdomains
);
99 state_
.AddHPKP("www.example.com", expiry
, include_subdomains
,
100 dynamic_spki_hashes
);
102 // Add another entry.
103 memset(fp1
.data(), 2, fp1
.size());
104 memset(fp2
.data(), 3, fp2
.size());
106 base::Time::Now() + base::TimeDelta::FromSeconds(3000);
107 dynamic_spki_hashes
.push_back(fp1
);
108 dynamic_spki_hashes
.push_back(fp2
);
109 state_
.AddHSTS("www.example.net", expiry
, include_subdomains
);
110 state_
.AddHPKP("www.example.net", expiry
, include_subdomains
,
111 dynamic_spki_hashes
);
113 // Save a copy of everything.
114 std::map
<std::string
, TransportSecurityState::DomainState
> saved
;
115 TransportSecurityState::Iterator
i(state_
);
116 while (i
.HasNext()) {
117 saved
[i
.hostname()] = i
.domain_state();
121 std::string serialized
;
122 EXPECT_TRUE(persister_
->SerializeData(&serialized
));
124 // Persist the data to the file. For the test to be fast and not flaky, we
125 // just do it directly rather than call persister_->StateIsDirty. (That uses
126 // ImportantFileWriter, which has an asynchronous commit interval rather
127 // than block.) Use a different basename just for cleanliness.
128 base::FilePath path
=
129 temp_dir_
.path().AppendASCII("TransportSecurityPersisterTest");
130 EXPECT_TRUE(base::WriteFile(path
, serialized
.c_str(), serialized
.size()));
132 // Read the data back.
133 std::string persisted
;
134 EXPECT_TRUE(base::ReadFileToString(path
, &persisted
));
135 EXPECT_EQ(persisted
, serialized
);
137 EXPECT_TRUE(persister_
->LoadEntries(persisted
, &dirty
));
140 // Check that states are the same as saved.
142 TransportSecurityState::Iterator
j(state_
);
143 while (j
.HasNext()) {
147 EXPECT_EQ(count
, saved
.size());
150 TEST_F(TransportSecurityPersisterTest
, SerializeDataOld
) {
151 // This is an old-style piece of transport state JSON, which has no creation
155 "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {"
156 "\"expiry\": 1266815027.983453, "
157 "\"include_subdomains\": false, "
158 "\"mode\": \"strict\" "
162 EXPECT_TRUE(persister_
->LoadEntries(output
, &dirty
));
166 TEST_F(TransportSecurityPersisterTest
, PublicKeyHashes
) {
167 TransportSecurityState::DomainState domain_state
;
168 static const char kTestDomain
[] = "example.com";
169 EXPECT_FALSE(state_
.GetDomainState(kTestDomain
, false, &domain_state
));
170 net::HashValueVector hashes
;
171 EXPECT_FALSE(domain_state
.CheckPublicKeyPins(hashes
));
173 net::HashValue
sha1(net::HASH_VALUE_SHA1
);
174 memset(sha1
.data(), '1', sha1
.size());
175 domain_state
.dynamic_spki_hashes
.push_back(sha1
);
177 EXPECT_FALSE(domain_state
.CheckPublicKeyPins(hashes
));
179 hashes
.push_back(sha1
);
180 EXPECT_TRUE(domain_state
.CheckPublicKeyPins(hashes
));
182 hashes
[0].data()[0] = '2';
183 EXPECT_FALSE(domain_state
.CheckPublicKeyPins(hashes
));
185 const base::Time
current_time(base::Time::Now());
186 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
187 bool include_subdomains
= false;
188 state_
.AddHSTS(kTestDomain
, expiry
, include_subdomains
);
189 state_
.AddHPKP(kTestDomain
, expiry
, include_subdomains
,
190 domain_state
.dynamic_spki_hashes
);
192 EXPECT_TRUE(persister_
->SerializeData(&ser
));
194 EXPECT_TRUE(persister_
->LoadEntries(ser
, &dirty
));
195 EXPECT_TRUE(state_
.GetDomainState(kTestDomain
, false, &domain_state
));
196 EXPECT_EQ(1u, domain_state
.dynamic_spki_hashes
.size());
197 EXPECT_EQ(sha1
.tag
, domain_state
.dynamic_spki_hashes
[0].tag
);
198 EXPECT_EQ(0, memcmp(domain_state
.dynamic_spki_hashes
[0].data(), sha1
.data(),