| Index: net/ssl/client_cert_store_chromeos_unittest.cc
|
| diff --git a/net/ssl/client_cert_store_chromeos_unittest.cc b/net/ssl/client_cert_store_chromeos_unittest.cc
|
| index f6a07ff6568248787920682d80533f85f341cd62..ca2c049408837685d0f67fd2e98139dac105e531 100644
|
| --- a/net/ssl/client_cert_store_chromeos_unittest.cc
|
| +++ b/net/ssl/client_cert_store_chromeos_unittest.cc
|
| @@ -6,14 +6,11 @@
|
|
|
| #include <string>
|
|
|
| -#include "base/bind.h"
|
| #include "base/callback.h"
|
| -#include "base/files/file_util.h"
|
| +#include "base/message_loop/message_loop.h"
|
| #include "base/run_loop.h"
|
| -#include "crypto/nss_util_internal.h"
|
| #include "crypto/rsa_private_key.h"
|
| -#include "crypto/scoped_test_nss_chromeos_user.h"
|
| -#include "crypto/scoped_test_system_nss_key_slot.h"
|
| +#include "crypto/scoped_test_nss_db.h"
|
| #include "net/base/test_data_directory.h"
|
| #include "net/cert/x509_certificate.h"
|
| #include "net/ssl/client_cert_store_unittest-inl.h"
|
| @@ -23,29 +20,57 @@ namespace net {
|
|
|
| namespace {
|
|
|
| -enum ReadFromSlot {
|
| - READ_FROM_SLOT_USER,
|
| - READ_FROM_SLOT_SYSTEM
|
| -};
|
| +class TestCertFilter : public net::ClientCertStoreChromeOS::CertFilter {
|
| + public:
|
| + explicit TestCertFilter(bool init_finished)
|
| + : init_finished_(init_finished), init_called_(false) {}
|
| +
|
| + ~TestCertFilter() override {}
|
| +
|
| + bool Init(const base::Closure& callback) override {
|
| + init_called_ = true;
|
| + if (init_finished_)
|
| + return true;
|
| + pending_callback_ = callback;
|
| + return false;
|
| + }
|
|
|
| -enum SystemSlotAvailability {
|
| - SYSTEM_SLOT_AVAILABILITY_ENABLED,
|
| - SYSTEM_SLOT_AVAILABILITY_DISABLED
|
| + bool IsCertAllowed(
|
| + const scoped_refptr<net::X509Certificate>& cert) const override {
|
| + if (not_allowed_cert_.get() && cert->Equals(not_allowed_cert_.get()))
|
| + return false;
|
| + return true;
|
| + }
|
| +
|
| + bool init_called() { return init_called_; }
|
| +
|
| + void FinishInit() {
|
| + init_finished_ = true;
|
| + base::MessageLoop::current()->PostTask(FROM_HERE, pending_callback_);
|
| + pending_callback_.Reset();
|
| + }
|
| +
|
| + void SetNotAllowedCert(scoped_refptr<X509Certificate> cert) {
|
| + not_allowed_cert_ = cert;
|
| + }
|
| +
|
| + private:
|
| + bool init_finished_;
|
| + bool init_called_;
|
| + base::Closure pending_callback_;
|
| + scoped_refptr<X509Certificate> not_allowed_cert_;
|
| };
|
|
|
| } // namespace
|
|
|
| // Define a delegate to be used for instantiating the parameterized test set
|
| // ClientCertStoreTest.
|
| -template <ReadFromSlot read_from,
|
| - SystemSlotAvailability system_slot_availability>
|
| class ClientCertStoreChromeOSTestDelegate {
|
| public:
|
| ClientCertStoreChromeOSTestDelegate()
|
| - : user_("scopeduser"),
|
| - store_(system_slot_availability == SYSTEM_SLOT_AVAILABILITY_ENABLED,
|
| - user_.username_hash(),
|
| - ClientCertStoreChromeOS::PasswordDelegateFactory()) {
|
| + : store_(
|
| + make_scoped_ptr(new TestCertFilter(true /* init synchronously */)),
|
| + ClientCertStoreChromeOS::PasswordDelegateFactory()) {
|
| // Defer futher initialization and checks to SelectClientCerts, because the
|
| // constructor doesn't allow us to return an initialization result. Could be
|
| // cleaned up by adding an Init() function.
|
| @@ -60,25 +85,8 @@ class ClientCertStoreChromeOSTestDelegate {
|
| bool SelectClientCerts(const CertificateList& input_certs,
|
| const SSLCertRequestInfo& cert_request_info,
|
| CertificateList* selected_certs) {
|
| - if (!user_.constructed_successfully()) {
|
| - LOG(ERROR) << "Scoped test user DB could not be constructed.";
|
| - return false;
|
| - }
|
| - user_.FinishInit();
|
| -
|
| - crypto::ScopedPK11Slot slot;
|
| - switch (read_from) {
|
| - case READ_FROM_SLOT_USER:
|
| - slot = crypto::GetPublicSlotForChromeOSUser(user_.username_hash());
|
| - break;
|
| - case READ_FROM_SLOT_SYSTEM:
|
| - slot.reset(PK11_ReferenceSlot(system_db_.slot()));
|
| - break;
|
| - default:
|
| - CHECK(false);
|
| - }
|
| - if (!slot) {
|
| - LOG(ERROR) << "Could not get the NSS key slot";
|
| + if (!test_db_.is_open()) {
|
| + LOG(ERROR) << "NSS DB could not be constructed.";
|
| return false;
|
| }
|
|
|
| @@ -86,16 +94,16 @@ class ClientCertStoreChromeOSTestDelegate {
|
| // private key must be known to NSS. Import all private keys for certs that
|
| // are used througout the test.
|
| if (!ImportSensitiveKeyFromFile(
|
| - GetTestCertsDirectory(), "client_1.pk8", slot.get()) ||
|
| + GetTestCertsDirectory(), "client_1.pk8", test_db_.slot()) ||
|
| !ImportSensitiveKeyFromFile(
|
| - GetTestCertsDirectory(), "client_2.pk8", slot.get())) {
|
| + GetTestCertsDirectory(), "client_2.pk8", test_db_.slot())) {
|
| return false;
|
| }
|
|
|
| for (CertificateList::const_iterator it = input_certs.begin();
|
| it != input_certs.end();
|
| ++it) {
|
| - if (!ImportClientCertToSlot(*it, slot.get()))
|
| + if (!ImportClientCertToSlot(*it, test_db_.slot()))
|
| return false;
|
| }
|
| base::RunLoop run_loop;
|
| @@ -106,8 +114,7 @@ class ClientCertStoreChromeOSTestDelegate {
|
| }
|
|
|
| private:
|
| - crypto::ScopedTestNSSChromeOSUser user_;
|
| - crypto::ScopedTestSystemNSSKeySlot system_db_;
|
| + crypto::ScopedTestNSSDB test_db_;
|
| ClientCertStoreChromeOS store_;
|
| };
|
|
|
| @@ -116,67 +123,35 @@ class ClientCertStoreChromeOSTestDelegate {
|
| // To verify that this delegation is functional, run the same filtering tests as
|
| // for the other implementations. These tests are defined in
|
| // client_cert_store_unittest-inl.h and are instantiated for each platform.
|
| -
|
| -// In this case, all requested certs are read from the user's slot and the
|
| -// system slot is not enabled in the store.
|
| -typedef ClientCertStoreChromeOSTestDelegate<READ_FROM_SLOT_USER,
|
| - SYSTEM_SLOT_AVAILABILITY_DISABLED>
|
| - DelegateReadUserDisableSystem;
|
| -INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS_ReadUserDisableSystem,
|
| +INSTANTIATE_TYPED_TEST_CASE_P(ClientCertStoreTestChromeOS,
|
| ClientCertStoreTest,
|
| - DelegateReadUserDisableSystem);
|
| -
|
| -// In this case, all requested certs are read from the user's slot and the
|
| -// system slot is enabled in the store.
|
| -typedef ClientCertStoreChromeOSTestDelegate<READ_FROM_SLOT_USER,
|
| - SYSTEM_SLOT_AVAILABILITY_ENABLED>
|
| - DelegateReadUserEnableSystem;
|
| -INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS_ReadUserEnableSystem,
|
| - ClientCertStoreTest,
|
| - DelegateReadUserEnableSystem);
|
| -
|
| -// In this case, all requested certs are read from the system slot, therefore
|
| -// the system slot is enabled in the store.
|
| -typedef ClientCertStoreChromeOSTestDelegate<READ_FROM_SLOT_SYSTEM,
|
| - SYSTEM_SLOT_AVAILABILITY_ENABLED>
|
| - DelegateReadSystem;
|
| -INSTANTIATE_TYPED_TEST_CASE_P(ChromeOS_ReadSystem,
|
| - ClientCertStoreTest,
|
| - DelegateReadSystem);
|
| + ClientCertStoreChromeOSTestDelegate);
|
|
|
| class ClientCertStoreChromeOSTest : public ::testing::Test {
|
| public:
|
| - scoped_refptr<X509Certificate> ImportCertForUser(
|
| - const std::string& username_hash,
|
| + scoped_refptr<X509Certificate> ImportCertToSlot(
|
| const std::string& cert_filename,
|
| - const std::string& key_filename) {
|
| - crypto::ScopedPK11Slot slot(
|
| - crypto::GetPublicSlotForChromeOSUser(username_hash));
|
| - if (!slot) {
|
| - LOG(ERROR) << "No slot for user " << username_hash;
|
| - return NULL;
|
| - }
|
| -
|
| + const std::string& key_filename,
|
| + PK11SlotInfo* slot) {
|
| return ImportClientCertAndKeyFromFile(
|
| - GetTestCertsDirectory(), cert_filename, key_filename, slot.get());
|
| + GetTestCertsDirectory(), cert_filename, key_filename, slot);
|
| }
|
| -
|
| };
|
|
|
| -// Ensure that cert requests, that are started before the user's NSS DB is
|
| -// initialized, will wait for the initialization and succeed afterwards.
|
| +// Ensure that cert requests, that are started before the filter is initialized,
|
| +// will wait for the initialization and succeed afterwards.
|
| TEST_F(ClientCertStoreChromeOSTest, RequestWaitsForNSSInitAndSucceeds) {
|
| - crypto::ScopedTestNSSChromeOSUser user("scopeduser");
|
| - ASSERT_TRUE(user.constructed_successfully());
|
| -
|
| - crypto::ScopedTestSystemNSSKeySlot system_slot;
|
| + crypto::ScopedTestNSSDB test_db;
|
| + ASSERT_TRUE(test_db.is_open());
|
|
|
| + TestCertFilter* cert_filter =
|
| + new TestCertFilter(false /* init asynchronously */);
|
| ClientCertStoreChromeOS store(
|
| - true /* use system slot */,
|
| - user.username_hash(),
|
| + make_scoped_ptr(cert_filter),
|
| ClientCertStoreChromeOS::PasswordDelegateFactory());
|
| +
|
| scoped_refptr<X509Certificate> cert_1(
|
| - ImportCertForUser(user.username_hash(), "client_1.pem", "client_1.pk8"));
|
| + ImportCertToSlot("client_1.pem", "client_1.pk8", test_db.slot()));
|
| ASSERT_TRUE(cert_1.get());
|
|
|
| // Request any client certificate, which is expected to match client_1.
|
| @@ -189,34 +164,29 @@ TEST_F(ClientCertStoreChromeOSTest, RequestWaitsForNSSInitAndSucceeds) {
|
| {
|
| base::RunLoop run_loop_inner;
|
| run_loop_inner.RunUntilIdle();
|
| - // GetClientCerts should wait for the initialization of the user's DB to
|
| + // GetClientCerts should wait for the initialization of the filter to
|
| // finish.
|
| ASSERT_EQ(0u, request_all->client_certs.size());
|
| + EXPECT_TRUE(cert_filter->init_called());
|
| }
|
| - // This should trigger the GetClientCerts operation to finish and to call
|
| - // back.
|
| - user.FinishInit();
|
| -
|
| + cert_filter->FinishInit();
|
| run_loop.Run();
|
|
|
| ASSERT_EQ(1u, request_all->client_certs.size());
|
| }
|
|
|
| -// Ensure that cert requests, that are started after the user's NSS DB was
|
| -// initialized, will succeed.
|
| +// Ensure that cert requests, that are started after the filter was initialized,
|
| +// will succeed.
|
| TEST_F(ClientCertStoreChromeOSTest, RequestsAfterNSSInitSucceed) {
|
| - crypto::ScopedTestNSSChromeOSUser user("scopeduser");
|
| - ASSERT_TRUE(user.constructed_successfully());
|
| - user.FinishInit();
|
| -
|
| - crypto::ScopedTestSystemNSSKeySlot system_slot;
|
| + crypto::ScopedTestNSSDB test_db;
|
| + ASSERT_TRUE(test_db.is_open());
|
|
|
| ClientCertStoreChromeOS store(
|
| - true /* use system slot */,
|
| - user.username_hash(),
|
| + make_scoped_ptr(new TestCertFilter(true /* init synchronously */)),
|
| ClientCertStoreChromeOS::PasswordDelegateFactory());
|
| +
|
| scoped_refptr<X509Certificate> cert_1(
|
| - ImportCertForUser(user.username_hash(), "client_1.pem", "client_1.pk8"));
|
| + ImportCertToSlot("client_1.pem", "client_1.pk8", test_db.slot()));
|
| ASSERT_TRUE(cert_1.get());
|
|
|
| scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
|
| @@ -229,96 +199,46 @@ TEST_F(ClientCertStoreChromeOSTest, RequestsAfterNSSInitSucceed) {
|
| ASSERT_EQ(1u, request_all->client_certs.size());
|
| }
|
|
|
| -// This verifies that a request in the context of User1 doesn't see certificates
|
| -// of User2, and the other way round. We check both directions, to ensure that
|
| -// the behavior doesn't depend on initialization order of the DBs, for example.
|
| -TEST_F(ClientCertStoreChromeOSTest, RequestDoesCrossReadOtherUserDB) {
|
| - crypto::ScopedTestNSSChromeOSUser user1("scopeduser1");
|
| - ASSERT_TRUE(user1.constructed_successfully());
|
| - crypto::ScopedTestNSSChromeOSUser user2("scopeduser2");
|
| - ASSERT_TRUE(user2.constructed_successfully());
|
| -
|
| - user1.FinishInit();
|
| - user2.FinishInit();
|
| -
|
| - crypto::ScopedTestSystemNSSKeySlot system_slot;
|
| -
|
| - ClientCertStoreChromeOS store1(
|
| - true /* use system slot */,
|
| - user1.username_hash(),
|
| - ClientCertStoreChromeOS::PasswordDelegateFactory());
|
| - ClientCertStoreChromeOS store2(
|
| - true /* use system slot */,
|
| - user2.username_hash(),
|
| - ClientCertStoreChromeOS::PasswordDelegateFactory());
|
| -
|
| - scoped_refptr<X509Certificate> cert_1(
|
| - ImportCertForUser(user1.username_hash(), "client_1.pem", "client_1.pk8"));
|
| - ASSERT_TRUE(cert_1.get());
|
| - scoped_refptr<X509Certificate> cert_2(
|
| - ImportCertForUser(user2.username_hash(), "client_2.pem", "client_2.pk8"));
|
| - ASSERT_TRUE(cert_2.get());
|
| -
|
| - scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
|
| -
|
| - base::RunLoop run_loop_1;
|
| - base::RunLoop run_loop_2;
|
| -
|
| - CertificateList selected_certs1, selected_certs2;
|
| - store1.GetClientCerts(
|
| - *request_all, &selected_certs1, run_loop_1.QuitClosure());
|
| - store2.GetClientCerts(
|
| - *request_all, &selected_certs2, run_loop_2.QuitClosure());
|
| -
|
| - run_loop_1.Run();
|
| - run_loop_2.Run();
|
| -
|
| - // store1 should only return certs of user1, namely cert_1.
|
| - ASSERT_EQ(1u, selected_certs1.size());
|
| - EXPECT_TRUE(cert_1->Equals(selected_certs1[0].get()));
|
| -
|
| - // store2 should only return certs of user2, namely cert_2.
|
| - ASSERT_EQ(1u, selected_certs2.size());
|
| - EXPECT_TRUE(cert_2->Equals(selected_certs2[0].get()));
|
| -}
|
| -
|
| -// This verifies that a request in the context of User1 doesn't see certificates
|
| -// of the system store if the system store is disabled.
|
| -TEST_F(ClientCertStoreChromeOSTest, RequestDoesCrossReadSystemDB) {
|
| - crypto::ScopedTestNSSChromeOSUser user1("scopeduser1");
|
| - ASSERT_TRUE(user1.constructed_successfully());
|
| -
|
| - user1.FinishInit();
|
| -
|
| - crypto::ScopedTestSystemNSSKeySlot system_slot;
|
| +TEST_F(ClientCertStoreChromeOSTest, Filter) {
|
| + crypto::ScopedTestNSSDB test_db;
|
| + ASSERT_TRUE(test_db.is_open());
|
|
|
| + TestCertFilter* cert_filter =
|
| + new TestCertFilter(true /* init synchronously */);
|
| ClientCertStoreChromeOS store(
|
| - false /* do not use system slot */,
|
| - user1.username_hash(),
|
| + make_scoped_ptr(cert_filter),
|
| ClientCertStoreChromeOS::PasswordDelegateFactory());
|
|
|
| scoped_refptr<X509Certificate> cert_1(
|
| - ImportCertForUser(user1.username_hash(), "client_1.pem", "client_1.pk8"));
|
| + ImportCertToSlot("client_1.pem", "client_1.pk8", test_db.slot()));
|
| ASSERT_TRUE(cert_1.get());
|
| scoped_refptr<X509Certificate> cert_2(
|
| - ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
|
| - "client_2.pem",
|
| - "client_2.pk8",
|
| - system_slot.slot()));
|
| + ImportCertToSlot("client_2.pem", "client_2.pk8", test_db.slot()));
|
| ASSERT_TRUE(cert_2.get());
|
|
|
| scoped_refptr<SSLCertRequestInfo> request_all(new SSLCertRequestInfo());
|
|
|
| - base::RunLoop run_loop;
|
| + {
|
| + base::RunLoop run_loop;
|
| + cert_filter->SetNotAllowedCert(cert_2);
|
| + CertificateList selected_certs;
|
| + store.GetClientCerts(*request_all, &selected_certs, run_loop.QuitClosure());
|
| + run_loop.Run();
|
|
|
| - CertificateList selected_certs;
|
| - store.GetClientCerts(*request_all, &selected_certs, run_loop.QuitClosure());
|
| + ASSERT_EQ(1u, selected_certs.size());
|
| + EXPECT_TRUE(cert_1->Equals(selected_certs[0].get()));
|
| + }
|
|
|
| - run_loop.Run();
|
| + {
|
| + base::RunLoop run_loop;
|
| + cert_filter->SetNotAllowedCert(cert_1);
|
| + CertificateList selected_certs;
|
| + store.GetClientCerts(*request_all, &selected_certs, run_loop.QuitClosure());
|
| + run_loop.Run();
|
|
|
| - // store should only return certs of the user, namely cert_1.
|
| - ASSERT_EQ(1u, selected_certs.size());
|
| - EXPECT_TRUE(cert_1->Equals(selected_certs[0].get()));
|
| + ASSERT_EQ(1u, selected_certs.size());
|
| + EXPECT_TRUE(cert_2->Equals(selected_certs[0].get()));
|
| + }
|
| }
|
|
|
| } // namespace net
|
|
|