1 // Copyright 2013 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/cert/nss_cert_database_chromeos.h"
8 #include "base/callback.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/run_loop.h"
11 #include "crypto/nss_util_internal.h"
12 #include "crypto/scoped_test_nss_chromeos_user.h"
13 #include "crypto/scoped_test_nss_db.h"
14 #include "net/base/test_data_directory.h"
15 #include "net/cert/cert_database.h"
16 #include "net/test/cert_test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
23 bool IsCertInCertificateList(const X509Certificate
* cert
,
24 const CertificateList
& cert_list
) {
25 for (CertificateList::const_iterator it
= cert_list
.begin();
26 it
!= cert_list
.end();
28 if (X509Certificate::IsSameOSCert((*it
)->os_cert_handle(),
29 cert
->os_cert_handle()))
35 void SwapCertLists(CertificateList
* destination
,
36 scoped_ptr
<CertificateList
> source
) {
37 ASSERT_TRUE(destination
);
40 destination
->swap(*source
);
45 class NSSCertDatabaseChromeOSTest
: public testing::Test
,
46 public CertDatabase::Observer
{
48 NSSCertDatabaseChromeOSTest()
49 : observer_added_(false), user_1_("user1"), user_2_("user2") {}
51 virtual void SetUp() OVERRIDE
{
52 // Initialize nss_util slots.
53 ASSERT_TRUE(user_1_
.constructed_successfully());
54 ASSERT_TRUE(user_2_
.constructed_successfully());
58 // Create NSSCertDatabaseChromeOS for each user.
59 db_1_
.reset(new NSSCertDatabaseChromeOS(
60 crypto::GetPublicSlotForChromeOSUser(user_1_
.username_hash()),
61 crypto::GetPrivateSlotForChromeOSUser(
62 user_1_
.username_hash(),
63 base::Callback
<void(crypto::ScopedPK11Slot
)>())));
64 db_1_
->SetSlowTaskRunnerForTest(base::MessageLoopProxy::current());
66 crypto::ScopedPK11Slot(PK11_ReferenceSlot(system_db_
.slot())));
67 db_2_
.reset(new NSSCertDatabaseChromeOS(
68 crypto::GetPublicSlotForChromeOSUser(user_2_
.username_hash()),
69 crypto::GetPrivateSlotForChromeOSUser(
70 user_2_
.username_hash(),
71 base::Callback
<void(crypto::ScopedPK11Slot
)>())));
72 db_2_
->SetSlowTaskRunnerForTest(base::MessageLoopProxy::current());
74 // Add observer to CertDatabase for checking that notifications from
75 // NSSCertDatabaseChromeOS are proxied to the CertDatabase.
76 CertDatabase::GetInstance()->AddObserver(this);
77 observer_added_
= true;
80 virtual void TearDown() OVERRIDE
{
82 CertDatabase::GetInstance()->RemoveObserver(this);
85 // CertDatabase::Observer:
86 virtual void OnCertAdded(const X509Certificate
* cert
) OVERRIDE
{
87 added_
.push_back(cert
? cert
->os_cert_handle() : NULL
);
90 virtual void OnCertRemoved(const X509Certificate
* cert
) OVERRIDE
{}
92 virtual void OnCACertChanged(const X509Certificate
* cert
) OVERRIDE
{
93 added_ca_
.push_back(cert
? cert
->os_cert_handle() : NULL
);
98 // Certificates that were passed to the CertDatabase observers.
99 std::vector
<CERTCertificate
*> added_ca_
;
100 std::vector
<CERTCertificate
*> added_
;
102 crypto::ScopedTestNSSChromeOSUser user_1_
;
103 crypto::ScopedTestNSSChromeOSUser user_2_
;
104 crypto::ScopedTestNSSDB system_db_
;
105 scoped_ptr
<NSSCertDatabaseChromeOS
> db_1_
;
106 scoped_ptr
<NSSCertDatabaseChromeOS
> db_2_
;
109 // Test that ListModules() on each user includes that user's NSS software slot,
110 // and does not include the software slot of the other user. (Does not check the
111 // private slot, since it is the same as the public slot in tests.)
112 TEST_F(NSSCertDatabaseChromeOSTest
, ListModules
) {
113 CryptoModuleList modules_1
;
114 CryptoModuleList modules_2
;
116 db_1_
->ListModules(&modules_1
, false /* need_rw */);
117 db_2_
->ListModules(&modules_2
, false /* need_rw */);
119 bool found_1
= false;
120 for (CryptoModuleList::iterator it
= modules_1
.begin(); it
!= modules_1
.end();
122 EXPECT_NE(db_2_
->GetPublicSlot().get(), (*it
)->os_module_handle());
123 if ((*it
)->os_module_handle() == db_1_
->GetPublicSlot().get())
126 EXPECT_TRUE(found_1
);
128 bool found_2
= false;
129 for (CryptoModuleList::iterator it
= modules_2
.begin(); it
!= modules_2
.end();
131 EXPECT_NE(db_1_
->GetPublicSlot().get(), (*it
)->os_module_handle());
132 if ((*it
)->os_module_handle() == db_2_
->GetPublicSlot().get())
135 EXPECT_TRUE(found_2
);
138 // Test that ImportCACerts imports the cert to the correct slot, and that
139 // ListCerts includes the added cert for the correct user, and does not include
140 // it for the other user.
141 TEST_F(NSSCertDatabaseChromeOSTest
, ImportCACerts
) {
142 // Load test certs from disk.
143 CertificateList certs_1
=
144 CreateCertificateListFromFile(GetTestCertsDirectory(),
146 X509Certificate::FORMAT_AUTO
);
147 ASSERT_EQ(1U, certs_1
.size());
149 CertificateList certs_2
=
150 CreateCertificateListFromFile(GetTestCertsDirectory(),
152 X509Certificate::FORMAT_AUTO
);
153 ASSERT_EQ(1U, certs_2
.size());
155 // Import one cert for each user.
156 NSSCertDatabase::ImportCertFailureList failed
;
158 db_1_
->ImportCACerts(certs_1
, NSSCertDatabase::TRUSTED_SSL
, &failed
));
159 EXPECT_EQ(0U, failed
.size());
162 db_2_
->ImportCACerts(certs_2
, NSSCertDatabase::TRUSTED_SSL
, &failed
));
163 EXPECT_EQ(0U, failed
.size());
165 // Get cert list for each user.
166 CertificateList user_1_certlist
;
167 CertificateList user_2_certlist
;
168 db_1_
->ListCertsSync(&user_1_certlist
);
169 db_2_
->ListCertsSync(&user_2_certlist
);
171 // Check that the imported certs only shows up in the list for the user that
173 EXPECT_TRUE(IsCertInCertificateList(certs_1
[0], user_1_certlist
));
174 EXPECT_FALSE(IsCertInCertificateList(certs_1
[0], user_2_certlist
));
176 EXPECT_TRUE(IsCertInCertificateList(certs_2
[0], user_2_certlist
));
177 EXPECT_FALSE(IsCertInCertificateList(certs_2
[0], user_1_certlist
));
179 // Run the message loop so the observer notifications get processed.
180 base::RunLoop().RunUntilIdle();
181 // Should have gotten two OnCACertChanged notifications.
182 ASSERT_EQ(2U, added_ca_
.size());
183 // TODO(mattm): make NSSCertDatabase actually pass the cert to the callback,
184 // and enable these checks:
185 // EXPECT_EQ(certs_1[0]->os_cert_handle(), added_ca_[0]);
186 // EXPECT_EQ(certs_2[0]->os_cert_handle(), added_ca_[1]);
187 EXPECT_EQ(0U, added_
.size());
189 // Tests that the new certs are loaded by async ListCerts method.
190 CertificateList user_1_certlist_async
;
191 CertificateList user_2_certlist_async
;
193 base::Bind(&SwapCertLists
, base::Unretained(&user_1_certlist_async
)));
195 base::Bind(&SwapCertLists
, base::Unretained(&user_2_certlist_async
)));
197 base::RunLoop().RunUntilIdle();
199 EXPECT_TRUE(IsCertInCertificateList(certs_1
[0], user_1_certlist_async
));
200 EXPECT_FALSE(IsCertInCertificateList(certs_1
[0], user_2_certlist_async
));
202 EXPECT_TRUE(IsCertInCertificateList(certs_2
[0], user_2_certlist_async
));
203 EXPECT_FALSE(IsCertInCertificateList(certs_2
[0], user_1_certlist_async
));
206 // Test that ImportServerCerts imports the cert to the correct slot, and that
207 // ListCerts includes the added cert for the correct user, and does not include
208 // it for the other user.
209 TEST_F(NSSCertDatabaseChromeOSTest
, ImportServerCert
) {
210 // Load test certs from disk.
211 CertificateList certs_1
= CreateCertificateListFromFile(
212 GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO
);
213 ASSERT_EQ(1U, certs_1
.size());
215 CertificateList certs_2
=
216 CreateCertificateListFromFile(GetTestCertsDirectory(),
217 "2048-rsa-ee-by-2048-rsa-intermediate.pem",
218 X509Certificate::FORMAT_AUTO
);
219 ASSERT_EQ(1U, certs_2
.size());
221 // Import one cert for each user.
222 NSSCertDatabase::ImportCertFailureList failed
;
224 db_1_
->ImportServerCert(certs_1
, NSSCertDatabase::TRUSTED_SSL
, &failed
));
225 EXPECT_EQ(0U, failed
.size());
228 db_2_
->ImportServerCert(certs_2
, NSSCertDatabase::TRUSTED_SSL
, &failed
));
229 EXPECT_EQ(0U, failed
.size());
231 // Get cert list for each user.
232 CertificateList user_1_certlist
;
233 CertificateList user_2_certlist
;
234 db_1_
->ListCertsSync(&user_1_certlist
);
235 db_2_
->ListCertsSync(&user_2_certlist
);
237 // Check that the imported certs only shows up in the list for the user that
239 EXPECT_TRUE(IsCertInCertificateList(certs_1
[0], user_1_certlist
));
240 EXPECT_FALSE(IsCertInCertificateList(certs_1
[0], user_2_certlist
));
242 EXPECT_TRUE(IsCertInCertificateList(certs_2
[0], user_2_certlist
));
243 EXPECT_FALSE(IsCertInCertificateList(certs_2
[0], user_1_certlist
));
245 // Run the message loop so the observer notifications get processed.
246 base::RunLoop().RunUntilIdle();
247 // TODO(mattm): ImportServerCert doesn't actually cause any observers to
248 // fire. Is that correct?
249 EXPECT_EQ(0U, added_ca_
.size());
250 EXPECT_EQ(0U, added_
.size());
252 // Tests that the new certs are loaded by async ListCerts method.
253 CertificateList user_1_certlist_async
;
254 CertificateList user_2_certlist_async
;
256 base::Bind(&SwapCertLists
, base::Unretained(&user_1_certlist_async
)));
258 base::Bind(&SwapCertLists
, base::Unretained(&user_2_certlist_async
)));
260 base::RunLoop().RunUntilIdle();
262 EXPECT_TRUE(IsCertInCertificateList(certs_1
[0], user_1_certlist_async
));
263 EXPECT_FALSE(IsCertInCertificateList(certs_1
[0], user_2_certlist_async
));
265 EXPECT_TRUE(IsCertInCertificateList(certs_2
[0], user_2_certlist_async
));
266 EXPECT_FALSE(IsCertInCertificateList(certs_2
[0], user_1_certlist_async
));
269 // Tests that There is no crash if the database is deleted while ListCerts
270 // is being processed on the worker pool.
271 TEST_F(NSSCertDatabaseChromeOSTest
, NoCrashIfShutdownBeforeDoneOnWorkerPool
) {
272 CertificateList certlist
;
273 db_1_
->ListCerts(base::Bind(&SwapCertLists
, base::Unretained(&certlist
)));
274 EXPECT_EQ(0U, certlist
.size());
278 base::RunLoop().RunUntilIdle();
280 EXPECT_LT(0U, certlist
.size());
283 TEST_F(NSSCertDatabaseChromeOSTest
, ListCertsReadsSystemSlot
) {
284 scoped_refptr
<X509Certificate
> cert_1(
285 ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
288 db_1_
->GetPublicSlot().get()));
290 scoped_refptr
<X509Certificate
> cert_2(
291 ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
294 db_1_
->GetSystemSlot().get()));
295 CertificateList certs
;
296 db_1_
->ListCertsSync(&certs
);
297 EXPECT_TRUE(IsCertInCertificateList(cert_1
.get(), certs
));
298 EXPECT_TRUE(IsCertInCertificateList(cert_2
.get(), certs
));
301 TEST_F(NSSCertDatabaseChromeOSTest
, ListCertsDoesNotCrossReadSystemSlot
) {
302 scoped_refptr
<X509Certificate
> cert_1(
303 ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
306 db_2_
->GetPublicSlot().get()));
308 scoped_refptr
<X509Certificate
> cert_2(
309 ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
313 CertificateList certs
;
314 db_2_
->ListCertsSync(&certs
);
315 EXPECT_TRUE(IsCertInCertificateList(cert_1
.get(), certs
));
316 EXPECT_FALSE(IsCertInCertificateList(cert_2
.get(), certs
));