OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/net/transport_security_persister.h" | |
6 | |
7 #include <map> | |
8 #include <string> | |
9 #include <vector> | |
10 | |
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" | |
17 | |
18 using net::TransportSecurityState; | |
19 | |
20 class TransportSecurityPersisterTest : public testing::Test { | |
21 public: | |
22 TransportSecurityPersisterTest() | |
23 : message_loop_(base::MessageLoop::TYPE_IO) { | |
24 } | |
25 | |
26 virtual ~TransportSecurityPersisterTest() { | |
27 message_loop_.RunUntilIdle(); | |
28 } | |
29 | |
30 virtual void SetUp() OVERRIDE { | |
31 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
32 persister_.reset(new TransportSecurityPersister( | |
33 &state_, temp_dir_.path(), message_loop_.message_loop_proxy(), false)); | |
34 } | |
35 | |
36 protected: | |
37 // Ordering is important here. If member variables are not destroyed in the | |
38 // right order, then DCHECKs will fail all over the place. | |
39 base::MessageLoop message_loop_; | |
40 | |
41 base::ScopedTempDir temp_dir_; | |
42 TransportSecurityState state_; | |
43 scoped_ptr<TransportSecurityPersister> persister_; | |
44 }; | |
45 | |
46 TEST_F(TransportSecurityPersisterTest, SerializeData1) { | |
47 std::string output; | |
48 bool dirty; | |
49 | |
50 EXPECT_TRUE(persister_->SerializeData(&output)); | |
51 EXPECT_TRUE(persister_->LoadEntries(output, &dirty)); | |
52 EXPECT_FALSE(dirty); | |
53 } | |
54 | |
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"; | |
60 | |
61 EXPECT_FALSE(state_.GetDomainState(kYahooDomain, true, &domain_state)); | |
62 | |
63 bool include_subdomains = true; | |
64 state_.AddHSTS(kYahooDomain, expiry, include_subdomains); | |
65 | |
66 std::string output; | |
67 bool dirty; | |
68 EXPECT_TRUE(persister_->SerializeData(&output)); | |
69 EXPECT_TRUE(persister_->LoadEntries(output, &dirty)); | |
70 | |
71 EXPECT_TRUE(state_.GetDomainState(kYahooDomain, true, &domain_state)); | |
72 EXPECT_EQ(domain_state.upgrade_mode, | |
73 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | |
74 EXPECT_TRUE(state_.GetDomainState("foo.yahoo.com", true, &domain_state)); | |
75 EXPECT_EQ(domain_state.upgrade_mode, | |
76 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | |
77 EXPECT_TRUE(state_.GetDomainState("foo.bar.yahoo.com", true, &domain_state)); | |
78 EXPECT_EQ(domain_state.upgrade_mode, | |
79 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | |
80 EXPECT_TRUE(state_.GetDomainState("foo.bar.baz.yahoo.com", true, | |
81 &domain_state)); | |
82 EXPECT_EQ(domain_state.upgrade_mode, | |
83 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | |
84 EXPECT_FALSE(state_.GetDomainState("com", true, &domain_state)); | |
85 } | |
86 | |
87 TEST_F(TransportSecurityPersisterTest, SerializeData3) { | |
88 // Add an entry. | |
89 net::HashValue fp1(net::HASH_VALUE_SHA1); | |
90 memset(fp1.data(), 0, fp1.size()); | |
91 net::HashValue fp2(net::HASH_VALUE_SHA1); | |
92 memset(fp2.data(), 1, fp2.size()); | |
93 base::Time expiry = | |
94 base::Time::Now() + base::TimeDelta::FromSeconds(1000); | |
95 net::HashValueVector dynamic_spki_hashes; | |
96 dynamic_spki_hashes.push_back(fp1); | |
97 dynamic_spki_hashes.push_back(fp2); | |
98 bool include_subdomains = false; | |
99 state_.AddHSTS("www.example.com", expiry, include_subdomains); | |
100 state_.AddHPKP("www.example.com", expiry, include_subdomains, | |
101 dynamic_spki_hashes); | |
102 | |
103 // Add another entry. | |
104 memset(fp1.data(), 2, fp1.size()); | |
105 memset(fp2.data(), 3, fp2.size()); | |
106 expiry = | |
107 base::Time::Now() + base::TimeDelta::FromSeconds(3000); | |
108 dynamic_spki_hashes.push_back(fp1); | |
109 dynamic_spki_hashes.push_back(fp2); | |
110 state_.AddHSTS("www.example.net", expiry, include_subdomains); | |
111 state_.AddHPKP("www.example.net", expiry, include_subdomains, | |
112 dynamic_spki_hashes); | |
113 | |
114 // Save a copy of everything. | |
115 std::map<std::string, TransportSecurityState::DomainState> saved; | |
116 TransportSecurityState::Iterator i(state_); | |
117 while (i.HasNext()) { | |
118 saved[i.hostname()] = i.domain_state(); | |
119 i.Advance(); | |
120 } | |
121 | |
122 std::string serialized; | |
123 EXPECT_TRUE(persister_->SerializeData(&serialized)); | |
124 | |
125 // Persist the data to the file. For the test to be fast and not flaky, we | |
126 // just do it directly rather than call persister_->StateIsDirty. (That uses | |
127 // ImportantFileWriter, which has an asynchronous commit interval rather | |
128 // than block.) Use a different basename just for cleanliness. | |
129 base::FilePath path = | |
130 temp_dir_.path().AppendASCII("TransportSecurityPersisterTest"); | |
131 EXPECT_TRUE(file_util::WriteFile(path, serialized.c_str(), | |
132 serialized.size())); | |
133 | |
134 // Read the data back. | |
135 std::string persisted; | |
136 EXPECT_TRUE(base::ReadFileToString(path, &persisted)); | |
137 EXPECT_EQ(persisted, serialized); | |
138 bool dirty; | |
139 EXPECT_TRUE(persister_->LoadEntries(persisted, &dirty)); | |
140 EXPECT_FALSE(dirty); | |
141 | |
142 // Check that states are the same as saved. | |
143 size_t count = 0; | |
144 TransportSecurityState::Iterator j(state_); | |
145 while (j.HasNext()) { | |
146 count++; | |
147 j.Advance(); | |
148 } | |
149 EXPECT_EQ(count, saved.size()); | |
150 } | |
151 | |
152 TEST_F(TransportSecurityPersisterTest, SerializeDataOld) { | |
153 // This is an old-style piece of transport state JSON, which has no creation | |
154 // date. | |
155 std::string output = | |
156 "{ " | |
157 "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {" | |
158 "\"expiry\": 1266815027.983453, " | |
159 "\"include_subdomains\": false, " | |
160 "\"mode\": \"strict\" " | |
161 "}" | |
162 "}"; | |
163 bool dirty; | |
164 EXPECT_TRUE(persister_->LoadEntries(output, &dirty)); | |
165 EXPECT_TRUE(dirty); | |
166 } | |
167 | |
168 TEST_F(TransportSecurityPersisterTest, PublicKeyHashes) { | |
169 TransportSecurityState::DomainState domain_state; | |
170 static const char kTestDomain[] = "example.com"; | |
171 EXPECT_FALSE(state_.GetDomainState(kTestDomain, false, &domain_state)); | |
172 net::HashValueVector hashes; | |
173 EXPECT_FALSE(domain_state.CheckPublicKeyPins(hashes)); | |
174 | |
175 net::HashValue sha1(net::HASH_VALUE_SHA1); | |
176 memset(sha1.data(), '1', sha1.size()); | |
177 domain_state.dynamic_spki_hashes.push_back(sha1); | |
178 | |
179 EXPECT_FALSE(domain_state.CheckPublicKeyPins(hashes)); | |
180 | |
181 hashes.push_back(sha1); | |
182 EXPECT_TRUE(domain_state.CheckPublicKeyPins(hashes)); | |
183 | |
184 hashes[0].data()[0] = '2'; | |
185 EXPECT_FALSE(domain_state.CheckPublicKeyPins(hashes)); | |
186 | |
187 const base::Time current_time(base::Time::Now()); | |
188 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | |
189 bool include_subdomains = false; | |
190 state_.AddHSTS(kTestDomain, expiry, include_subdomains); | |
191 state_.AddHPKP(kTestDomain, expiry, include_subdomains, | |
192 domain_state.dynamic_spki_hashes); | |
193 std::string ser; | |
194 EXPECT_TRUE(persister_->SerializeData(&ser)); | |
195 bool dirty; | |
196 EXPECT_TRUE(persister_->LoadEntries(ser, &dirty)); | |
197 EXPECT_TRUE(state_.GetDomainState(kTestDomain, false, &domain_state)); | |
198 EXPECT_EQ(1u, domain_state.dynamic_spki_hashes.size()); | |
199 EXPECT_EQ(sha1.tag, domain_state.dynamic_spki_hashes[0].tag); | |
200 EXPECT_EQ(0, memcmp(domain_state.dynamic_spki_hashes[0].data(), sha1.data(), | |
201 sha1.size())); | |
202 } | |
OLD | NEW |