Change type of drag-drop window to popup
[chromium-blink-merge.git] / net / ssl / client_cert_store_chromeos_unittest.cc
blob33601efe5b34398f88a4736531a561f9f9416122
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/ssl/client_cert_store_chromeos.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/file_util.h"
12 #include "base/run_loop.h"
13 #include "crypto/nss_util_internal.h"
14 #include "crypto/rsa_private_key.h"
15 #include "crypto/scoped_test_nss_chromeos_user.h"
16 #include "crypto/scoped_test_system_nss_key_slot.h"
17 #include "net/base/test_data_directory.h"
18 #include "net/cert/x509_certificate.h"
19 #include "net/ssl/client_cert_store_unittest-inl.h"
20 #include "net/test/cert_test_util.h"
22 namespace net {
24 namespace {
26 enum ReadFromSlot {
27 READ_FROM_SLOT_USER,
28 READ_FROM_SLOT_SYSTEM
31 enum SystemSlotAvailability {
32 SYSTEM_SLOT_AVAILABILITY_ENABLED,
33 SYSTEM_SLOT_AVAILABILITY_DISABLED
36 } // namespace
38 // Define a delegate to be used for instantiating the parameterized test set
39 // ClientCertStoreTest.
40 template <ReadFromSlot read_from,
41 SystemSlotAvailability system_slot_availability>
42 class ClientCertStoreChromeOSTestDelegate {
43 public:
44 ClientCertStoreChromeOSTestDelegate()
45 : user_("scopeduser"),
46 store_(system_slot_availability == SYSTEM_SLOT_AVAILABILITY_ENABLED,
47 user_.username_hash(),
48 ClientCertStoreChromeOS::PasswordDelegateFactory()) {
49 // Defer futher initialization and checks to SelectClientCerts, because the
50 // constructor doesn't allow us to return an initialization result. Could be
51 // cleaned up by adding an Init() function.
54 // Called by the ClientCertStoreTest tests.
55 // |inpurt_certs| contains certificates to select from. Because
56 // ClientCertStoreChromeOS filters also for the right slot, we have to import
57 // the certs at first.
58 // Since the certs are imported, the store can be tested by using its public
59 // interface (GetClientCerts), which will read the certs from NSS.
60 bool SelectClientCerts(const CertificateList& input_certs,
61 const SSLCertRequestInfo& cert_request_info,
62 CertificateList* selected_certs) {
63 if (!user_.constructed_successfully()) {
64 LOG(ERROR) << "Scoped test user DB could not be constructed.";
65 return false;
67 user_.FinishInit();
69 crypto::ScopedPK11Slot slot;
70 switch (read_from) {
71 case READ_FROM_SLOT_USER:
72 slot = crypto::GetPublicSlotForChromeOSUser(user_.username_hash());
73 break;
74 case READ_FROM_SLOT_SYSTEM:
75 slot.reset(PK11_ReferenceSlot(system_db_.slot()));
76 break;
77 default:
78 CHECK(false);
80 if (!slot) {
81 LOG(ERROR) << "Could not get the NSS key slot";
82 return false;
85 // Only user certs are considered for the cert request, which means that the
86 // private key must be known to NSS. Import all private keys for certs that
87 // are used througout the test.
88 if (!ImportSensitiveKeyFromFile(
89 GetTestCertsDirectory(), "client_1.pk8", slot.get()) ||
90 !ImportSensitiveKeyFromFile(
91 GetTestCertsDirectory(), "client_2.pk8", slot.get())) {
92 return false;
95 for (CertificateList::const_iterator it = input_certs.begin();
96 it != input_certs.end();
97 ++it) {
98 if (!ImportClientCertToSlot(*it, slot.get()))
99 return false;
101 base::RunLoop run_loop;
102 store_.GetClientCerts(
103 cert_request_info, selected_certs, run_loop.QuitClosure());
104 run_loop.Run();
105 return true;
108 private:
109 crypto::ScopedTestNSSChromeOSUser user_;
110 crypto::ScopedTestSystemNSSKeySlot system_db_;
111 ClientCertStoreChromeOS store_;
114 // ClientCertStoreChromeOS derives from ClientCertStoreNSS and delegates the
115 // filtering by issuer to that base class.
116 // To verify that this delegation is functional, run the same filtering tests as
117 // for the other implementations. These tests are defined in
118 // client_cert_store_unittest-inl.h and are instantiated for each platform.
120 // In this case, all requested certs are read from the user's slot and the
121 // system slot is not enabled in the store.
122 typedef ClientCertStoreChromeOSTestDelegate<READ_FROM_SLOT_USER,
123 SYSTEM_SLOT_AVAILABILITY_DISABLED>
124 DelegateReadUserDisableSystem;
125 INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS_ReadUserDisableSystem,
126 ClientCertStoreTest,
127 DelegateReadUserDisableSystem);
129 // In this case, all requested certs are read from the user's slot and the
130 // system slot is enabled in the store.
131 typedef ClientCertStoreChromeOSTestDelegate<READ_FROM_SLOT_USER,
132 SYSTEM_SLOT_AVAILABILITY_ENABLED>
133 DelegateReadUserEnableSystem;
134 INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS_ReadUserEnableSystem,
135 ClientCertStoreTest,
136 DelegateReadUserEnableSystem);
138 // In this case, all requested certs are read from the system slot, therefore
139 // the system slot is enabled in the store.
140 typedef ClientCertStoreChromeOSTestDelegate<READ_FROM_SLOT_SYSTEM,
141 SYSTEM_SLOT_AVAILABILITY_ENABLED>
142 DelegateReadSystem;
143 INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS_ReadSystem,
144 ClientCertStoreTest,
145 DelegateReadSystem);
147 class ClientCertStoreChromeOSTest : public ::testing::Test {
148 public:
149 scoped_refptr<X509Certificate> ImportCertForUser(
150 const std::string& username_hash,
151 const std::string& cert_filename,
152 const std::string& key_filename) {
153 crypto::ScopedPK11Slot slot(
154 crypto::GetPublicSlotForChromeOSUser(username_hash));
155 if (!slot) {
156 LOG(ERROR) << "No slot for user " << username_hash;
157 return NULL;
160 return ImportClientCertAndKeyFromFile(
161 GetTestCertsDirectory(), cert_filename, key_filename, slot.get());
166 // Ensure that cert requests, that are started before the user's NSS DB is
167 // initialized, will wait for the initialization and succeed afterwards.
168 TEST_F(ClientCertStoreChromeOSTest, RequestWaitsForNSSInitAndSucceeds) {
169 crypto::ScopedTestNSSChromeOSUser user("scopeduser");
170 ASSERT_TRUE(user.constructed_successfully());
172 crypto::ScopedTestSystemNSSKeySlot system_slot;
174 ClientCertStoreChromeOS store(
175 true /* use system slot */,
176 user.username_hash(),
177 ClientCertStoreChromeOS::PasswordDelegateFactory());
178 scoped_refptr<X509Certificate> cert_1(
179 ImportCertForUser(user.username_hash(), "client_1.pem", "client_1.pk8"));
180 ASSERT_TRUE(cert_1);
182 // Request any client certificate, which is expected to match client_1.
183 scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
185 base::RunLoop run_loop;
186 store.GetClientCerts(
187 *request_all, &request_all->client_certs, run_loop.QuitClosure());
190 base::RunLoop run_loop_inner;
191 run_loop_inner.RunUntilIdle();
192 // GetClientCerts should wait for the initialization of the user's DB to
193 // finish.
194 ASSERT_EQ(0u, request_all->client_certs.size());
196 // This should trigger the GetClientCerts operation to finish and to call
197 // back.
198 user.FinishInit();
200 run_loop.Run();
202 ASSERT_EQ(1u, request_all->client_certs.size());
205 // Ensure that cert requests, that are started after the user's NSS DB was
206 // initialized, will succeed.
207 TEST_F(ClientCertStoreChromeOSTest, RequestsAfterNSSInitSucceed) {
208 crypto::ScopedTestNSSChromeOSUser user("scopeduser");
209 ASSERT_TRUE(user.constructed_successfully());
210 user.FinishInit();
212 crypto::ScopedTestSystemNSSKeySlot system_slot;
214 ClientCertStoreChromeOS store(
215 true /* use system slot */,
216 user.username_hash(),
217 ClientCertStoreChromeOS::PasswordDelegateFactory());
218 scoped_refptr<X509Certificate> cert_1(
219 ImportCertForUser(user.username_hash(), "client_1.pem", "client_1.pk8"));
220 ASSERT_TRUE(cert_1);
222 scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
224 base::RunLoop run_loop;
225 store.GetClientCerts(
226 *request_all, &request_all->client_certs, run_loop.QuitClosure());
227 run_loop.Run();
229 ASSERT_EQ(1u, request_all->client_certs.size());
232 // This verifies that a request in the context of User1 doesn't see certificates
233 // of User2, and the other way round. We check both directions, to ensure that
234 // the behavior doesn't depend on initialization order of the DBs, for example.
235 TEST_F(ClientCertStoreChromeOSTest, RequestDoesCrossReadOtherUserDB) {
236 crypto::ScopedTestNSSChromeOSUser user1("scopeduser1");
237 ASSERT_TRUE(user1.constructed_successfully());
238 crypto::ScopedTestNSSChromeOSUser user2("scopeduser2");
239 ASSERT_TRUE(user2.constructed_successfully());
241 user1.FinishInit();
242 user2.FinishInit();
244 crypto::ScopedTestSystemNSSKeySlot system_slot;
246 ClientCertStoreChromeOS store1(
247 true /* use system slot */,
248 user1.username_hash(),
249 ClientCertStoreChromeOS::PasswordDelegateFactory());
250 ClientCertStoreChromeOS store2(
251 true /* use system slot */,
252 user2.username_hash(),
253 ClientCertStoreChromeOS::PasswordDelegateFactory());
255 scoped_refptr<X509Certificate> cert_1(
256 ImportCertForUser(user1.username_hash(), "client_1.pem", "client_1.pk8"));
257 ASSERT_TRUE(cert_1);
258 scoped_refptr<X509Certificate> cert_2(
259 ImportCertForUser(user2.username_hash(), "client_2.pem", "client_2.pk8"));
260 ASSERT_TRUE(cert_2);
262 scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
264 base::RunLoop run_loop_1;
265 base::RunLoop run_loop_2;
267 CertificateList selected_certs1, selected_certs2;
268 store1.GetClientCerts(
269 *request_all, &selected_certs1, run_loop_1.QuitClosure());
270 store2.GetClientCerts(
271 *request_all, &selected_certs2, run_loop_2.QuitClosure());
273 run_loop_1.Run();
274 run_loop_2.Run();
276 // store1 should only return certs of user1, namely cert_1.
277 ASSERT_EQ(1u, selected_certs1.size());
278 EXPECT_TRUE(cert_1->Equals(selected_certs1[0]));
280 // store2 should only return certs of user2, namely cert_2.
281 ASSERT_EQ(1u, selected_certs2.size());
282 EXPECT_TRUE(cert_2->Equals(selected_certs2[0]));
285 // This verifies that a request in the context of User1 doesn't see certificates
286 // of the system store if the system store is disabled.
287 TEST_F(ClientCertStoreChromeOSTest, RequestDoesCrossReadSystemDB) {
288 crypto::ScopedTestNSSChromeOSUser user1("scopeduser1");
289 ASSERT_TRUE(user1.constructed_successfully());
291 user1.FinishInit();
293 crypto::ScopedTestSystemNSSKeySlot system_slot;
295 ClientCertStoreChromeOS store(
296 false /* do not use system slot */,
297 user1.username_hash(),
298 ClientCertStoreChromeOS::PasswordDelegateFactory());
300 scoped_refptr<X509Certificate> cert_1(
301 ImportCertForUser(user1.username_hash(), "client_1.pem", "client_1.pk8"));
302 ASSERT_TRUE(cert_1);
303 scoped_refptr<X509Certificate> cert_2(
304 ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
305 "client_2.pem",
306 "client_2.pk8",
307 system_slot.slot()));
308 ASSERT_TRUE(cert_2);
310 scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
312 base::RunLoop run_loop;
314 CertificateList selected_certs;
315 store.GetClientCerts(*request_all, &selected_certs, run_loop.QuitClosure());
317 run_loop.Run();
319 // store should only return certs of the user, namely cert_1.
320 ASSERT_EQ(1u, selected_certs.size());
321 EXPECT_TRUE(cert_1->Equals(selected_certs[0]));
324 } // namespace net