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 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 void TearDown() override
{
82 CertDatabase::GetInstance()->RemoveObserver(this);
85 // CertDatabase::Observer:
86 void OnCertAdded(const X509Certificate
* cert
) override
{
87 added_
.push_back(cert
? cert
->os_cert_handle() : NULL
);
90 void OnCertRemoved(const X509Certificate
* cert
) override
{}
92 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].get(), user_1_certlist
));
174 EXPECT_FALSE(IsCertInCertificateList(certs_1
[0].get(), user_2_certlist
));
176 EXPECT_TRUE(IsCertInCertificateList(certs_2
[0].get(), user_2_certlist
));
177 EXPECT_FALSE(IsCertInCertificateList(certs_2
[0].get(), 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].get(), user_1_certlist_async
));
201 IsCertInCertificateList(certs_1
[0].get(), user_2_certlist_async
));
203 EXPECT_TRUE(IsCertInCertificateList(certs_2
[0].get(), user_2_certlist_async
));
205 IsCertInCertificateList(certs_2
[0].get(), user_1_certlist_async
));
208 // Test that ImportServerCerts imports the cert to the correct slot, and that
209 // ListCerts includes the added cert for the correct user, and does not include
210 // it for the other user.
211 TEST_F(NSSCertDatabaseChromeOSTest
, ImportServerCert
) {
212 // Load test certs from disk.
213 CertificateList certs_1
= CreateCertificateListFromFile(
214 GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO
);
215 ASSERT_EQ(1U, certs_1
.size());
217 CertificateList certs_2
=
218 CreateCertificateListFromFile(GetTestCertsDirectory(),
219 "2048-rsa-ee-by-2048-rsa-intermediate.pem",
220 X509Certificate::FORMAT_AUTO
);
221 ASSERT_EQ(1U, certs_2
.size());
223 // Import one cert for each user.
224 NSSCertDatabase::ImportCertFailureList failed
;
226 db_1_
->ImportServerCert(certs_1
, NSSCertDatabase::TRUSTED_SSL
, &failed
));
227 EXPECT_EQ(0U, failed
.size());
230 db_2_
->ImportServerCert(certs_2
, NSSCertDatabase::TRUSTED_SSL
, &failed
));
231 EXPECT_EQ(0U, failed
.size());
233 // Get cert list for each user.
234 CertificateList user_1_certlist
;
235 CertificateList user_2_certlist
;
236 db_1_
->ListCertsSync(&user_1_certlist
);
237 db_2_
->ListCertsSync(&user_2_certlist
);
239 // Check that the imported certs only shows up in the list for the user that
241 EXPECT_TRUE(IsCertInCertificateList(certs_1
[0].get(), user_1_certlist
));
242 EXPECT_FALSE(IsCertInCertificateList(certs_1
[0].get(), user_2_certlist
));
244 EXPECT_TRUE(IsCertInCertificateList(certs_2
[0].get(), user_2_certlist
));
245 EXPECT_FALSE(IsCertInCertificateList(certs_2
[0].get(), user_1_certlist
));
247 // Run the message loop so the observer notifications get processed.
248 base::RunLoop().RunUntilIdle();
249 // TODO(mattm): ImportServerCert doesn't actually cause any observers to
250 // fire. Is that correct?
251 EXPECT_EQ(0U, added_ca_
.size());
252 EXPECT_EQ(0U, added_
.size());
254 // Tests that the new certs are loaded by async ListCerts method.
255 CertificateList user_1_certlist_async
;
256 CertificateList user_2_certlist_async
;
258 base::Bind(&SwapCertLists
, base::Unretained(&user_1_certlist_async
)));
260 base::Bind(&SwapCertLists
, base::Unretained(&user_2_certlist_async
)));
262 base::RunLoop().RunUntilIdle();
264 EXPECT_TRUE(IsCertInCertificateList(certs_1
[0].get(), user_1_certlist_async
));
266 IsCertInCertificateList(certs_1
[0].get(), user_2_certlist_async
));
268 EXPECT_TRUE(IsCertInCertificateList(certs_2
[0].get(), user_2_certlist_async
));
270 IsCertInCertificateList(certs_2
[0].get(), user_1_certlist_async
));
273 // Tests that There is no crash if the database is deleted while ListCerts
274 // is being processed on the worker pool.
275 TEST_F(NSSCertDatabaseChromeOSTest
, NoCrashIfShutdownBeforeDoneOnWorkerPool
) {
276 CertificateList certlist
;
277 db_1_
->ListCerts(base::Bind(&SwapCertLists
, base::Unretained(&certlist
)));
278 EXPECT_EQ(0U, certlist
.size());
282 base::RunLoop().RunUntilIdle();
284 EXPECT_LT(0U, certlist
.size());
287 TEST_F(NSSCertDatabaseChromeOSTest
, ListCertsReadsSystemSlot
) {
288 scoped_refptr
<X509Certificate
> cert_1(
289 ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
292 db_1_
->GetPublicSlot().get()));
294 scoped_refptr
<X509Certificate
> cert_2(
295 ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
298 db_1_
->GetSystemSlot().get()));
299 CertificateList certs
;
300 db_1_
->ListCertsSync(&certs
);
301 EXPECT_TRUE(IsCertInCertificateList(cert_1
.get(), certs
));
302 EXPECT_TRUE(IsCertInCertificateList(cert_2
.get(), certs
));
305 TEST_F(NSSCertDatabaseChromeOSTest
, ListCertsDoesNotCrossReadSystemSlot
) {
306 scoped_refptr
<X509Certificate
> cert_1(
307 ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
310 db_2_
->GetPublicSlot().get()));
312 scoped_refptr
<X509Certificate
> cert_2(
313 ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
317 CertificateList certs
;
318 db_2_
->ListCertsSync(&certs
);
319 EXPECT_TRUE(IsCertInCertificateList(cert_1
.get(), certs
));
320 EXPECT_FALSE(IsCertInCertificateList(cert_2
.get(), certs
));