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."; | |
stevenjb
2014/01/23 18:17:42
nit: align
tbarzic
2014/01/23 19:18:37
Done.
| |
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_->SetCryptoTaskRunner(message_loop_.message_loop_proxy()); | |
60 } | |
61 | |
62 virtual void TearDown() { | |
63 cert_loader_->RemoveObserver(this); | |
64 CertLoader::Shutdown(); | |
65 } | |
66 | |
67 protected: | |
68 // CertLoader::Observer: | |
69 // The test keeps count of times the observer method was called. | |
70 virtual void OnCertificatesLoaded(const net::CertificateList& cert_list, | |
71 bool initial_load) OVERRIDE { | |
72 new_certificates_loaded_events_count_++; | |
73 } | |
74 | |
75 // Checks if the number of |OnCertificatesLoaded| calls observed since the | |
76 // last call to this method equals |value|. | |
77 bool NewCertificatesLoadedEventsCountEquals(size_t value) { | |
78 bool result = value == new_certificates_loaded_events_count_; | |
79 new_certificates_loaded_events_count_ = 0; | |
80 return result; | |
81 } | |
82 | |
83 // Finishes initialization for the |user| and returns a user's NSS database | |
84 // instance. | |
85 scoped_ptr<net::NSSCertDatabaseChromeOS> FinishUserInitAndGetDatabase( | |
86 crypto::ScopedTestNSSChromeOSUser* user) { | |
87 scoped_ptr<net::NSSCertDatabaseChromeOS> database; | |
88 if (!user->constructed_successfully()) | |
89 return database.Pass(); | |
90 | |
91 user->FinishInit(); | |
92 | |
93 crypto::ScopedPK11Slot private_slot( | |
94 crypto::GetPrivateSlotForChromeOSUser( | |
95 user->username_hash(), | |
96 base::Bind(&NotReachedPrivateSlotCallback))); | |
97 if (!private_slot) | |
98 return database.Pass(); | |
99 | |
100 database.reset(new net::NSSCertDatabaseChromeOS( | |
101 crypto::GetPublicSlotForChromeOSUser(user->username_hash()), | |
102 private_slot.Pass())); | |
103 return database.Pass(); | |
104 } | |
105 | |
106 int GetDbPrivateSlotId(net::NSSCertDatabase* db) { | |
107 return static_cast<int>(PK11_GetSlotID(db->GetPrivateSlot().get())); | |
108 } | |
109 | |
110 bool ImportCACerts(const std::string& cert_file, | |
111 net::NSSCertDatabase* database, | |
112 net::CertificateList* imported_certs) { | |
113 if (!database || !imported_certs) | |
114 return false; | |
115 | |
116 // Add a certificate to the user's db. | |
117 *imported_certs = net::CreateCertificateListFromFile( | |
118 net::GetTestCertsDirectory(), | |
119 cert_file, | |
120 net::X509Certificate::FORMAT_AUTO); | |
121 | |
122 net::NSSCertDatabase::ImportCertFailureList failed; | |
123 bool success = database->ImportCACerts( | |
124 *imported_certs, net::NSSCertDatabase::TRUSTED_SSL, &failed); | |
125 success = success && failed.empty(); | |
126 | |
127 if (!success) | |
128 imported_certs->clear(); | |
129 return success; | |
130 } | |
131 | |
132 bool ImportClientCertAndKey(const std::string& pkcs12_file, | |
133 net::NSSCertDatabase* database, | |
134 net::CertificateList* imported_certs) { | |
135 std::string pkcs12_data; | |
136 base::FilePath pkcs12_file_path = | |
137 net::GetTestCertsDirectory().Append(pkcs12_file); | |
138 if (!base::ReadFileToString(pkcs12_file_path, &pkcs12_data)) | |
139 return false; | |
140 | |
141 net::CertificateList client_cert_list; | |
142 scoped_refptr<net::CryptoModule> module(net::CryptoModule::CreateFromHandle( | |
143 database->GetPrivateSlot().get())); | |
144 return net::OK == | |
145 database->ImportFromPKCS12(module, pkcs12_data, base::string16(), false, | |
146 imported_certs); | |
147 } | |
148 | |
149 CertLoader* cert_loader_; | |
150 | |
151 // The user is primary as the one whose certificates CertLoader handles, it | |
152 // has nothing to do with crypto::InitializeNSSForChromeOSUser is_primary_user | |
153 // parameter (which is irrelevant for these tests). | |
154 crypto::ScopedTestNSSChromeOSUser primary_user_; | |
155 scoped_ptr<net::NSSCertDatabaseChromeOS> primary_db_; | |
156 | |
157 base::MessageLoop message_loop_; | |
158 | |
159 private: | |
160 size_t new_certificates_loaded_events_count_; | |
161 }; | |
162 | |
163 TEST_F(CertLoaderTest, Basic) { | |
164 EXPECT_FALSE(cert_loader_->CertificatesLoading()); | |
165 EXPECT_FALSE(cert_loader_->certificates_loaded()); | |
166 EXPECT_FALSE(cert_loader_->is_hardware_backed()); | |
167 | |
168 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
169 ASSERT_TRUE(primary_db_); | |
170 | |
171 cert_loader_->StartWithNSSDB(primary_db_.get()); | |
172 | |
173 EXPECT_FALSE(cert_loader_->certificates_loaded()); | |
174 EXPECT_TRUE(cert_loader_->CertificatesLoading()); | |
175 EXPECT_TRUE(cert_loader_->cert_list().empty()); | |
176 | |
177 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
178 base::RunLoop().RunUntilIdle(); | |
179 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
180 | |
181 EXPECT_TRUE(cert_loader_->certificates_loaded()); | |
182 EXPECT_FALSE(cert_loader_->CertificatesLoading()); | |
183 EXPECT_FALSE(cert_loader_->is_hardware_backed()); | |
184 EXPECT_EQ(GetDbPrivateSlotId(primary_db_.get()), | |
185 cert_loader_->tpm_token_slot_id()); | |
186 | |
187 // Default CA cert roots should get loaded. | |
188 EXPECT_FALSE(cert_loader_->cert_list().empty()); | |
189 } | |
190 | |
191 TEST_F(CertLoaderTest, CertLoaderUpdatesCertListOnNewCert) { | |
192 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
193 ASSERT_TRUE(primary_db_); | |
194 | |
195 cert_loader_->StartWithNSSDB(primary_db_.get()); | |
196 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
197 base::RunLoop().RunUntilIdle(); | |
198 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
199 | |
200 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
201 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
202 | |
203 net::CertificateList certs; | |
204 ASSERT_TRUE(ImportCACerts("root_ca_cert.pem", primary_db_.get(), &certs)); | |
205 ASSERT_EQ(1U, certs.size()); | |
206 | |
207 // Certs are loaded asynchronously, so the new cert should not yet be in the | |
208 // cert list. | |
209 EXPECT_FALSE(IsCertInCertificateList(certs[0], cert_loader_->cert_list())); | |
210 | |
211 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
212 base::RunLoop().RunUntilIdle(); | |
213 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
214 | |
215 // The certificate list should be updated now, as the message loop's been run. | |
216 EXPECT_TRUE(IsCertInCertificateList(certs[0], cert_loader_->cert_list())); | |
217 } | |
218 | |
219 TEST_F(CertLoaderTest, CertLoaderNoUpdateOnSecondaryDbChanges) { | |
220 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
221 ASSERT_TRUE(primary_db_); | |
222 cert_loader_->StartWithNSSDB(primary_db_.get()); | |
223 | |
224 crypto::ScopedTestNSSChromeOSUser secondary_user("secondary"); | |
225 scoped_ptr<net::NSSCertDatabaseChromeOS> secondary_db = | |
226 FinishUserInitAndGetDatabase(&secondary_user); | |
227 ASSERT_TRUE(secondary_db); | |
228 | |
229 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
230 base::RunLoop().RunUntilIdle(); | |
231 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
232 | |
233 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
234 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
235 | |
236 net::CertificateList certs; | |
237 ASSERT_TRUE(ImportCACerts("root_ca_cert.pem", secondary_db.get(), &certs)); | |
238 ASSERT_EQ(1U, certs.size()); | |
239 | |
240 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
241 base::RunLoop().RunUntilIdle(); | |
242 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
243 | |
244 EXPECT_FALSE(IsCertInCertificateList(certs[0], cert_loader_->cert_list())); | |
245 } | |
246 | |
247 TEST_F(CertLoaderTest, ClientLoaderUpdateOnNewClientCert) { | |
248 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
249 ASSERT_TRUE(primary_db_); | |
250 cert_loader_->StartWithNSSDB(primary_db_.get()); | |
251 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
252 base::RunLoop().RunUntilIdle(); | |
253 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
254 | |
255 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
256 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
257 | |
258 net::CertificateList client_certs; | |
259 ASSERT_TRUE(ImportClientCertAndKey("websocket_client_cert.p12", | |
260 primary_db_.get(), | |
261 &client_certs)); | |
262 ASSERT_EQ(1U, client_certs.size()); | |
263 | |
264 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
265 base::RunLoop().RunUntilIdle(); | |
266 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
267 | |
268 EXPECT_TRUE(IsCertInCertificateList(client_certs[0], | |
269 cert_loader_->cert_list())); | |
270 } | |
271 | |
272 TEST_F(CertLoaderTest, CertLoaderNoUpdateOnNewClientCertInSecondaryDb) { | |
273 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
274 ASSERT_TRUE(primary_db_); | |
275 cert_loader_->StartWithNSSDB(primary_db_.get()); | |
276 | |
277 crypto::ScopedTestNSSChromeOSUser secondary_user("secondary"); | |
278 scoped_ptr<net::NSSCertDatabaseChromeOS> secondary_db = | |
279 FinishUserInitAndGetDatabase(&secondary_user); | |
280 ASSERT_TRUE(secondary_db); | |
281 | |
282 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
283 base::RunLoop().RunUntilIdle(); | |
284 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
285 | |
286 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
287 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
288 | |
289 net::CertificateList client_certs; | |
290 ASSERT_TRUE(ImportClientCertAndKey("websocket_client_cert.p12", | |
291 secondary_db.get(), | |
292 &client_certs)); | |
293 ASSERT_EQ(1U, client_certs.size()); | |
294 | |
295 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
296 base::RunLoop().RunUntilIdle(); | |
297 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
298 | |
299 EXPECT_FALSE( | |
300 IsCertInCertificateList(client_certs[0], cert_loader_->cert_list())); | |
301 } | |
302 | |
303 TEST_F(CertLoaderTest, UpdatedOnCertRemoval) { | |
304 primary_db_ = FinishUserInitAndGetDatabase(&primary_user_); | |
305 ASSERT_TRUE(primary_db_); | |
306 cert_loader_->StartWithNSSDB(primary_db_.get()); | |
307 | |
308 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
309 base::RunLoop().RunUntilIdle(); | |
310 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
311 | |
312 ASSERT_TRUE(cert_loader_->certificates_loaded()); | |
313 ASSERT_FALSE(cert_loader_->cert_list().empty()); | |
314 | |
315 net::CertificateList client_certs; | |
316 ASSERT_TRUE(ImportClientCertAndKey("websocket_client_cert.p12", | |
317 primary_db_.get(), | |
318 &client_certs)); | |
319 ASSERT_EQ(1U, client_certs.size()); | |
320 base::RunLoop().RunUntilIdle(); | |
321 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
322 ASSERT_TRUE(IsCertInCertificateList(client_certs[0], | |
323 cert_loader_->cert_list())); | |
324 | |
325 primary_db_->DeleteCertAndKey(client_certs[0]); | |
326 | |
327 ASSERT_TRUE(NewCertificatesLoadedEventsCountEquals(0U)); | |
328 base::RunLoop().RunUntilIdle(); | |
329 EXPECT_TRUE(NewCertificatesLoadedEventsCountEquals(1U)); | |
330 | |
331 ASSERT_FALSE(IsCertInCertificateList(client_certs[0], | |
332 cert_loader_->cert_list())); | |
333 } | |
334 | |
335 } // namespace | |
336 } // namespace chromeos | |
OLD | NEW |