Home | History | Annotate | Download | only in ssl
      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.
      4 
      5 #include "net/ssl/client_cert_store_chromeos.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback.h"
      9 #include "base/file_util.h"
     10 #include "base/run_loop.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "crypto/nss_util.h"
     13 #include "crypto/nss_util_internal.h"
     14 #include "net/cert/nss_cert_database.h"
     15 #include "net/ssl/client_cert_store_unittest-inl.h"
     16 
     17 namespace net {
     18 
     19 class ClientCertStoreChromeOSTestDelegate {
     20  public:
     21   ClientCertStoreChromeOSTestDelegate()
     22       : store_("usernamehash",
     23                ClientCertStoreChromeOS::PasswordDelegateFactory()) {
     24     store_.InitForTesting(
     25         crypto::ScopedPK11Slot(crypto::GetPublicNSSKeySlot()),
     26         crypto::ScopedPK11Slot(crypto::GetPrivateNSSKeySlot()));
     27   }
     28 
     29   bool SelectClientCerts(const CertificateList& input_certs,
     30                          const SSLCertRequestInfo& cert_request_info,
     31                          CertificateList* selected_certs) {
     32     return store_.SelectClientCertsForTesting(
     33         input_certs, cert_request_info, selected_certs);
     34   }
     35 
     36  private:
     37   ClientCertStoreChromeOS store_;
     38 };
     39 
     40 class ClientCertStoreChromeOSTest : public ::testing::Test {
     41  public:
     42   scoped_refptr<X509Certificate> ImportCertForUser(
     43       const std::string& username_hash,
     44       const std::string& filename,
     45       const std::string& password) {
     46     crypto::ScopedPK11Slot slot(
     47         crypto::GetPublicSlotForChromeOSUser(username_hash));
     48     EXPECT_TRUE(slot.get());
     49     if (!slot.get())
     50       return NULL;
     51 
     52     net::CertificateList cert_list;
     53 
     54     base::FilePath p12_path = GetTestCertsDirectory().AppendASCII(filename);
     55     std::string p12_data;
     56     if (!base::ReadFileToString(p12_path, &p12_data)) {
     57       EXPECT_TRUE(false);
     58       return NULL;
     59     }
     60 
     61     scoped_refptr<net::CryptoModule> module(
     62         net::CryptoModule::CreateFromHandle(slot.get()));
     63     int rv = NSSCertDatabase::GetInstance()->ImportFromPKCS12(
     64         module.get(), p12_data, base::UTF8ToUTF16(password), false, &cert_list);
     65 
     66     EXPECT_EQ(0, rv);
     67     EXPECT_EQ(1U, cert_list.size());
     68     if (rv || cert_list.size() != 1)
     69       return NULL;
     70 
     71     return cert_list[0];
     72   }
     73 };
     74 
     75 // TODO(mattm): Do better testing of cert_authorities matching below. Update
     76 // net/data/ssl/scripts/generate-client-certificates.sh so that it actually
     77 // saves the .p12 files, and regenerate them.
     78 
     79 TEST_F(ClientCertStoreChromeOSTest, WaitForNSSInit) {
     80   crypto::ScopedTestNSSChromeOSUser user("scopeduser");
     81   ASSERT_TRUE(user.constructed_successfully());
     82   ClientCertStoreChromeOS store(
     83       user.username_hash(), ClientCertStoreChromeOS::PasswordDelegateFactory());
     84   scoped_refptr<X509Certificate> cert_1(
     85       ImportCertForUser(user.username_hash(), "client.p12", "12345"));
     86   scoped_refptr<X509Certificate> cert_2(
     87       ImportCertForUser(user.username_hash(), "websocket_client_cert.p12", ""));
     88 
     89   std::vector<std::string> authority_1(
     90       1,
     91       std::string(reinterpret_cast<const char*>(kAuthority1DN),
     92                   sizeof(kAuthority1DN)));
     93   scoped_refptr<SSLCertRequestInfo> request_1(new SSLCertRequestInfo());
     94   request_1->cert_authorities = authority_1;
     95 
     96   scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
     97 
     98   base::RunLoop run_loop_1;
     99   base::RunLoop run_loop_all;
    100   store.GetClientCerts(
    101       *request_1, &request_1->client_certs, run_loop_1.QuitClosure());
    102   store.GetClientCerts(
    103       *request_all, &request_all->client_certs, run_loop_all.QuitClosure());
    104 
    105   // Callbacks won't be run until nss_util init finishes for the user.
    106   user.FinishInit();
    107 
    108   run_loop_1.Run();
    109   run_loop_all.Run();
    110 
    111   ASSERT_EQ(0u, request_1->client_certs.size());
    112   ASSERT_EQ(2u, request_all->client_certs.size());
    113 }
    114 
    115 TEST_F(ClientCertStoreChromeOSTest, NSSAlreadyInitialized) {
    116   crypto::ScopedTestNSSChromeOSUser user("scopeduser");
    117   ASSERT_TRUE(user.constructed_successfully());
    118   user.FinishInit();
    119 
    120   ClientCertStoreChromeOS store(
    121       user.username_hash(), ClientCertStoreChromeOS::PasswordDelegateFactory());
    122   scoped_refptr<X509Certificate> cert_1(
    123       ImportCertForUser(user.username_hash(), "client.p12", "12345"));
    124   scoped_refptr<X509Certificate> cert_2(
    125       ImportCertForUser(user.username_hash(), "websocket_client_cert.p12", ""));
    126 
    127   std::vector<std::string> authority_1(
    128       1,
    129       std::string(reinterpret_cast<const char*>(kAuthority1DN),
    130                   sizeof(kAuthority1DN)));
    131   scoped_refptr<SSLCertRequestInfo> request_1(new SSLCertRequestInfo());
    132   request_1->cert_authorities = authority_1;
    133 
    134   scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
    135 
    136   base::RunLoop run_loop_1;
    137   base::RunLoop run_loop_all;
    138   store.GetClientCerts(
    139       *request_1, &request_1->client_certs, run_loop_1.QuitClosure());
    140   store.GetClientCerts(
    141       *request_all, &request_all->client_certs, run_loop_all.QuitClosure());
    142 
    143   run_loop_1.Run();
    144   run_loop_all.Run();
    145 
    146   ASSERT_EQ(0u, request_1->client_certs.size());
    147   ASSERT_EQ(2u, request_all->client_certs.size());
    148 }
    149 
    150 TEST_F(ClientCertStoreChromeOSTest, TwoUsers) {
    151   crypto::ScopedTestNSSChromeOSUser user1("scopeduser1");
    152   ASSERT_TRUE(user1.constructed_successfully());
    153   crypto::ScopedTestNSSChromeOSUser user2("scopeduser2");
    154   ASSERT_TRUE(user2.constructed_successfully());
    155   ClientCertStoreChromeOS store1(
    156       user1.username_hash(),
    157       ClientCertStoreChromeOS::PasswordDelegateFactory());
    158   ClientCertStoreChromeOS store2(
    159       user2.username_hash(),
    160       ClientCertStoreChromeOS::PasswordDelegateFactory());
    161   scoped_refptr<X509Certificate> cert_1(
    162       ImportCertForUser(user1.username_hash(), "client.p12", "12345"));
    163   scoped_refptr<X509Certificate> cert_2(ImportCertForUser(
    164       user2.username_hash(), "websocket_client_cert.p12", ""));
    165 
    166   scoped_refptr<SSLCertRequestInfo> request_1(new SSLCertRequestInfo());
    167   scoped_refptr<SSLCertRequestInfo> request_2(new SSLCertRequestInfo());
    168 
    169   base::RunLoop run_loop_1;
    170   base::RunLoop run_loop_2;
    171   store1.GetClientCerts(
    172       *request_1, &request_1->client_certs, run_loop_1.QuitClosure());
    173   store2.GetClientCerts(
    174       *request_2, &request_2->client_certs, run_loop_2.QuitClosure());
    175 
    176   // Callbacks won't be run until nss_util init finishes for the user.
    177   user1.FinishInit();
    178   user2.FinishInit();
    179 
    180   run_loop_1.Run();
    181   run_loop_2.Run();
    182 
    183   ASSERT_EQ(1u, request_1->client_certs.size());
    184   EXPECT_TRUE(cert_1->Equals(request_1->client_certs[0]));
    185   // TODO(mattm): Request for second user will have zero results due to
    186   // crbug.com/315285.  Update the test once that is fixed.
    187 }
    188 
    189 }  // namespace net
    190