OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 "chromeos/cert_loader.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/file_util.h" | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "base/message_loop/message_loop.h" | |
11 #include "base/run_loop.h" | |
12 #include "crypto/nss_util.h" | |
13 #include "crypto/nss_util_internal.h" | |
14 #include "net/base/net_errors.h" | |
15 #include "net/base/test_data_directory.h" | |
16 #include "net/cert/nss_cert_database_chromeos.h" | |
17 #include "net/cert/x509_certificate.h" | |
18 #include "net/test/cert_test_util.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 namespace chromeos { | |
22 namespace { | |
23 | |
24 bool IsCertInCertificateList(const net::X509Certificate* cert, | |
25 const net::CertificateList& cert_list) { | |
26 for (net::CertificateList::const_iterator it = cert_list.begin(); | |
27 it != cert_list.end(); | |
28 ++it) { | |
29 if (net::X509Certificate::IsSameOSCert((*it)->os_cert_handle(), | |
30 cert->os_cert_handle())) | |
31 return true; | |
32 } | |
33 return false; | |
34 } | |
35 | |
36 void NotReachedPrivateSlotCallback(crypto::ScopedPK11Slot slot) { | |
37 ASSERT_FALSE(true) << "GetPrivateSlotForChromeOSUser callback called even " | |
38 << "though the private slot had been initialized."; | |
39 } | |
40 | |
41 class CertLoaderTest : public testing::Test, | |
42 public CertLoader::Observer { | |
43 public: | |
44 CertLoaderTest() : cert_loader_(NULL), | |
45 primary_user_("primary"), | |
46 new_certificates_loaded_events_count_(0U) { | |
47 } | |
48 | |
49 virtual ~CertLoaderTest() {} | |
50 | |
51 virtual void SetUp() OVERRIDE { | |
52 ASSERT_TRUE(primary_user_.constructed_successfully()); | |
53 ASSERT_TRUE( | |
54 crypto::GetPublicSlotForChromeOSUser(primary_user_.username_hash())); | |
55 | |
56 CertLoader::Initialize(); | |
57 cert_loader_ = CertLoader::Get(); | |
58 cert_loader_->AddObserver(this); | |
59 cert_loader_->SetSlowTaskRunnerForTest(message_loop_.message_loop_proxy()); | |
60 cert_loader_->SetCryptoTaskRunner(message_loop_.message_loop_proxy()); | |
61 } | |
62 | |
63 virtual void TearDown() { | |
64 cert_loader_->RemoveObserver(this); | |
65 CertLoader::Shutdown(); | |
66 } | |
67 | |
68 protected: | |
69 // CertLoader::Observer: | |
70 // The test keeps count of times the observer method was called. | |
71 virtual void OnCertificatesLoaded(const net::CertificateList& cert_list, | |
72 bool initial_load) OVERRIDE { | |
73 new_certificates_loaded_events_count_++; | |
74 } | |
75 | |
76 // Checks if the number of |OnCertificatesLoaded| calls observed since the | |
77 // last call to this method equals |value|. | |
78 bool NewCertificatesLoadedEventsCountEquals(size_t value) { | |
79 bool result = value == new_certificates_loaded_events_count_; | |
80 new_certificates_loaded_events_count_ = 0; | |
81 return result; | |
82 } | |
83 | |
84 // Finishes initialization for the |user| and returns a user's NSS database | |
85 // instance. | |
86 scoped_ptr<net::NSSCertDatabaseChromeOS> FinishUserInitAndGetDatabase( | |
87 crypto::ScopedTestNSSChromeOSUser* user) { | |
88 scoped_ptr<net::NSSCertDatabaseChromeOS> database; | |
89 if (!user->constructed_successfully()) | |
90 return database.Pass(); | |
91 | |
92 user->FinishInit(); | |
93 | |
94 crypto::ScopedPK11Slot private_slot( | |
95 crypto::GetPrivateSlotForChromeOSUser( | |
96 user->username_hash(), | |
97 base::Bind(&NotReachedPrivateSlotCallback))); | |
98 if (!private_slot) | |
99 return database.Pass(); | |
100 | |
101 database.reset(new net::NSSCertDatabaseChromeOS( | |
mattm
2014/01/23 01:45:55
(Creating database objects for the unittest is fin
tbarzic
2014/01/23 04:45:28
ack
| |
102 crypto::GetPublicSlotForChromeOSUser(user->username_hash()), | |
103 private_slot.Pass())); | |
104 return database.Pass(); | |
105 } | |
106 | |
107 int GetDbPrivateSlotId(net::NSSCertDatabase* db) { | |
108 return static_cast<int>(PK11_GetSlotID(db->GetPrivateSlot().get())); | |
109 } | |
110 | |
111 bool ImportCACerts(const std::string& cert_file, | |
112 net::NSSCertDatabase* database, | |
113 net::CertificateList* imported_certs) { | |
114 if (!database || !imported_certs) | |
115 return false; | |
116 | |
117 // Add a certificate to the user's db. | |
118 *imported_certs = net::CreateCertificateListFromFile( | |
119 net::GetTestCertsDirectory(), | |
120 cert_file, | |
121 net::X509Certificate::FORMAT_AUTO); | |
122 | |
123 net::NSSCertDatabase::ImportCertFailureList failed; | |
124 bool success = database->ImportCACerts( | |
125 *imported_certs, net::NSSCertDatabase::TRUSTED_SSL, &failed); | |
126 success = success && failed.empty(); | |
127 | |
128 if (!success) | |
129 imported_certs->clear(); | |
130 return success; | |
131 } | |
132 | |
133 bool ImportClientCertAndKey(const std::string& pkcs12_file, | |
134 net::NSSCertDatabase* database, | |
135 net::CertificateList* imported_certs) { | |
136 std::string pkcs12_data; | |
137 base::FilePath pkcs12_file_path = | |
138 net::GetTestCertsDirectory().Append(pkcs12_file); | |
139 if (!base::ReadFileToString(pkcs12_file_path, &pkcs12_data)) | |
140 return false; | |
141 | |
142 net::CertificateList client_cert_list; | |
143 scoped_refptr<net::CryptoModule> module(net::CryptoModule::CreateFromHandle( | |
144 database->GetPrivateSlot().get())); | |
145 return net::OK == | |
146 database->ImportFromPKCS12(module, pkcs12_data, base::string16(), false, | |
147 imported_certs); | |
148 } | |
149 | |
150 CertLoader* cert_loader_; | |
151 | |
152 // The user is primary as the one whose certificates CertLoader handles, it | |
153 // has nothing to do with crypto::InitializeNSSForChromeOSUser is_primary_user | |
154 // parameter (which is irrelevant for these tests). | |
155 crypto::ScopedTestNSSChromeOSUser primary_user_; | |
156 scoped_ptr<net::NSSCertDatabaseChromeOS> primary_db_; | |
157 | |
158 base::MessageLoop message_loop_; | |
159 | |
160 private: | |
161 size_t new_certificates_loaded_events_count_; | |
162 }; | |
163 | |
164 TEST_F(CertLoaderTest, Basic) { | |
165 EXPECT_FALSE(cert_loader_->CertificatesLoading()); | |
166 EXPECT_FALSE(cert_loader_->certificates_loaded()); | |
167 EXPECT_FALSE(cert_loader_->is_hardware_backed()); | |
168 | |
169 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
170 ASSERT_TRUE(primary_db_); | |
171 | |
172 cert_loader_->StartWithUser(primary_user_.username_hash()); | |
173 | |
174 EXPECT_FALSE(cert_loader_->certificates_loaded()); | |
175 EXPECT_TRUE(cert_loader_->CertificatesLoading()); | |
176 EXPECT_TRUE(cert_loader_->cert_list().empty()); | |
177 | |
178 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
179 base::RunLoop().RunUntilIdle(); | |
180 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
181 | |
182 EXPECT_TRUE(cert_loader_->certificates_loaded()); | |
183 EXPECT_FALSE(cert_loader_->CertificatesLoading()); | |
184 EXPECT_FALSE(cert_loader_->is_hardware_backed()); | |
185 EXPECT_EQ(GetDbPrivateSlotId(primary_db_.get()), | |
186 cert_loader_->tpm_token_slot_id()); | |
187 | |
188 // Default CA cert roots should get loaded. | |
189 EXPECT_FALSE(cert_loader_->cert_list().empty()); | |
190 } | |
191 | |
192 TEST_F(CertLoaderTest, CertLoaderInitBeforePrivateSlot) { | |
193 cert_loader_->StartWithUser(primary_user_.username_hash()); | |
194 | |
195 EXPECT_FALSE(cert_loader_->certificates_loaded()); | |
196 EXPECT_TRUE(cert_loader_->CertificatesLoading()); | |
197 EXPECT_TRUE(cert_loader_->cert_list().empty()); | |
198 // Database should not be set yet, as the private slot hasn't bee initialized. | |
199 EXPECT_EQ(-1, cert_loader_->tpm_token_slot_id()); | |
200 | |
201 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
202 ASSERT_TRUE(primary_db_); | |
203 | |
204 EXPECT_FALSE(cert_loader_->certificates_loaded()); | |
205 EXPECT_TRUE(cert_loader_->CertificatesLoading()); | |
206 EXPECT_TRUE(cert_loader_->cert_list().empty()); | |
207 | |
208 // Certificate loading should be called asynchronously after the db is loaded. | |
209 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
210 base::RunLoop().RunUntilIdle(); | |
211 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
212 | |
213 // Default CA cert roots should get loaded. | |
214 EXPECT_FALSE(cert_loader_->cert_list().empty()); | |
215 } | |
216 | |
217 TEST_F(CertLoaderTest, CertLoaderUpdatesCertListOnNewCert) { | |
218 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
219 ASSERT_TRUE(primary_db_); | |
220 | |
221 cert_loader_->StartWithUser(primary_user_.username_hash()); | |
222 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
223 base::RunLoop().RunUntilIdle(); | |
224 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
225 | |
226 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
227 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
228 | |
229 net::CertificateList certs; | |
230 ASSERT_TRUE(ImportCACerts("root_ca_cert.pem", primary_db_.get(), &certs)); | |
231 ASSERT_EQ(1U, certs.size()); | |
232 | |
233 // Certs are loaded asynchronously, so the new cert should not yet be in the | |
234 // cert list. | |
235 EXPECT_FALSE(IsCertInCertificateList(certs[0], cert_loader_->cert_list())); | |
236 | |
237 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
238 base::RunLoop().RunUntilIdle(); | |
239 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
240 | |
241 // The certificate list should be updated now, as the message loop's been run. | |
242 EXPECT_TRUE(IsCertInCertificateList(certs[0], cert_loader_->cert_list())); | |
243 } | |
244 | |
245 TEST_F(CertLoaderTest, CertLoaderNoUpdateOnSecondaryDbChanges) { | |
246 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
247 ASSERT_TRUE(primary_db_); | |
248 cert_loader_->StartWithUser(primary_user_.username_hash()); | |
249 | |
250 crypto::ScopedTestNSSChromeOSUser secondary_user("secondary"); | |
251 scoped_ptr<net::NSSCertDatabaseChromeOS> secondary_db = | |
252 FinishUserInitAndGetDatabase(&secondary_user); | |
253 ASSERT_TRUE(secondary_db); | |
254 | |
255 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
256 base::RunLoop().RunUntilIdle(); | |
257 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
258 | |
259 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
260 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
261 | |
262 net::CertificateList certs; | |
263 ASSERT_TRUE(ImportCACerts("root_ca_cert.pem", secondary_db.get(), &certs)); | |
264 ASSERT_EQ(1U, certs.size()); | |
265 | |
266 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
267 base::RunLoop().RunUntilIdle(); | |
268 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
269 | |
270 EXPECT_FALSE(IsCertInCertificateList(certs[0], cert_loader_->cert_list())); | |
271 } | |
272 | |
273 TEST_F(CertLoaderTest, ClientLoaderUpdateOnNewClientCert) { | |
274 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
275 ASSERT_TRUE(primary_db_); | |
276 cert_loader_->StartWithUser(primary_user_.username_hash()); | |
277 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
278 base::RunLoop().RunUntilIdle(); | |
279 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
280 | |
281 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
282 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
283 | |
284 net::CertificateList client_certs; | |
285 ASSERT_TRUE(ImportClientCertAndKey("websocket_client_cert.p12", | |
286 primary_db_.get(), | |
287 &client_certs)); | |
288 ASSERT_EQ(1U, client_certs.size()); | |
289 | |
290 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
291 base::RunLoop().RunUntilIdle(); | |
292 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
293 | |
294 EXPECT_TRUE(IsCertInCertificateList(client_certs[0], | |
295 cert_loader_->cert_list())); | |
296 EXPECT_TRUE(cert_loader_->IsCertificateInPrivateSlot(*client_certs[0])); | |
297 } | |
298 | |
299 TEST_F(CertLoaderTest, CertLoaderNoUpdateOnNewClientCertInSecondaryDb) { | |
300 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
301 ASSERT_TRUE(primary_db_); | |
302 cert_loader_->StartWithUser(primary_user_.username_hash()); | |
303 | |
304 crypto::ScopedTestNSSChromeOSUser secondary_user("secondary"); | |
305 scoped_ptr<net::NSSCertDatabaseChromeOS> secondary_db = | |
306 FinishUserInitAndGetDatabase(&secondary_user); | |
307 ASSERT_TRUE(secondary_db); | |
308 | |
309 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
310 base::RunLoop().RunUntilIdle(); | |
311 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
312 | |
313 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
314 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
315 | |
316 net::CertificateList client_certs; | |
317 ASSERT_TRUE(ImportClientCertAndKey("websocket_client_cert.p12", | |
318 secondary_db.get(), | |
319 &client_certs)); | |
320 ASSERT_EQ(1U, client_certs.size()); | |
321 | |
322 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
323 base::RunLoop().RunUntilIdle(); | |
324 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
325 | |
326 EXPECT_FALSE( | |
327 IsCertInCertificateList(client_certs[0], cert_loader_->cert_list())); | |
328 EXPECT_FALSE(cert_loader_->IsCertificateInPrivateSlot(*client_certs[0])); | |
329 } | |
330 | |
331 TEST_F(CertLoaderTest, UpdatedOnCertRemoval) { | |
332 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
333 ASSERT_TRUE(primary_db_); | |
334 cert_loader_->StartWithUser(primary_user_.username_hash()); | |
335 | |
336 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
337 base::RunLoop().RunUntilIdle(); | |
338 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
339 | |
340 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
341 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
342 | |
343 net::CertificateList client_certs; | |
344 ASSERT_TRUE(ImportClientCertAndKey("websocket_client_cert.p12", | |
345 primary_db_.get(), | |
346 &client_certs)); | |
347 ASSERT_EQ(1U, client_certs.size()); | |
348 base::RunLoop().RunUntilIdle(); | |
349 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
350 ASSERT_TRUE(IsCertInCertificateList(client_certs[0], | |
351 cert_loader_->cert_list())); | |
352 | |
353 primary_db_->DeleteCertAndKey(client_certs[0]); | |
354 | |
355 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
356 base::RunLoop().RunUntilIdle(); | |
357 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
358 | |
359 ASSERT_FALSE(IsCertInCertificateList(client_certs[0], | |
360 cert_loader_->cert_list())); | |
361 } | |
362 | |
363 } // namespace | |
364 } // namespace chromeos | |
OLD | NEW |