123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/cert/nss_cert_database_chromeos.h"
- #include <memory>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/run_loop.h"
- #include "crypto/nss_util_internal.h"
- #include "crypto/scoped_test_nss_chromeos_user.h"
- #include "crypto/scoped_test_nss_db.h"
- #include "net/cert/cert_database.h"
- #include "net/cert/x509_util_nss.h"
- #include "net/test/cert_test_util.h"
- #include "net/test/test_data_directory.h"
- #include "net/test/test_with_task_environment.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace net {
- namespace {
- bool IsCertInCertificateList(const X509Certificate* cert,
- const ScopedCERTCertificateList& cert_list) {
- for (const auto& other : cert_list) {
- if (x509_util::IsSameCertificate(other.get(), cert))
- return true;
- }
- return false;
- }
- bool IsCertInCertificateList(CERTCertificate* cert,
- const ScopedCERTCertificateList& cert_list) {
- for (const auto& other : cert_list) {
- if (x509_util::IsSameCertificate(other.get(), cert))
- return true;
- }
- return false;
- }
- void SwapCertLists(ScopedCERTCertificateList* destination,
- ScopedCERTCertificateList source) {
- ASSERT_TRUE(destination);
- destination->swap(source);
- }
- } // namespace
- class NSSCertDatabaseChromeOSTest : public TestWithTaskEnvironment,
- public CertDatabase::Observer {
- public:
- NSSCertDatabaseChromeOSTest() : user_1_("user1"), user_2_("user2") {}
- void SetUp() override {
- // Initialize nss_util slots.
- ASSERT_TRUE(user_1_.constructed_successfully());
- ASSERT_TRUE(user_2_.constructed_successfully());
- user_1_.FinishInit();
- user_2_.FinishInit();
- // Create NSSCertDatabaseChromeOS for each user.
- db_1_ = std::make_unique<NSSCertDatabaseChromeOS>(
- crypto::GetPublicSlotForChromeOSUser(user_1_.username_hash()),
- crypto::GetPrivateSlotForChromeOSUser(
- user_1_.username_hash(),
- base::OnceCallback<void(crypto::ScopedPK11Slot)>()));
- db_1_->SetSystemSlot(
- crypto::ScopedPK11Slot(PK11_ReferenceSlot(system_db_.slot())));
- db_2_ = std::make_unique<NSSCertDatabaseChromeOS>(
- crypto::GetPublicSlotForChromeOSUser(user_2_.username_hash()),
- crypto::GetPrivateSlotForChromeOSUser(
- user_2_.username_hash(),
- base::OnceCallback<void(crypto::ScopedPK11Slot)>()));
- // Add observer to CertDatabase for checking that notifications from
- // NSSCertDatabaseChromeOS are proxied to the CertDatabase.
- CertDatabase::GetInstance()->AddObserver(this);
- observer_added_ = true;
- }
- void TearDown() override {
- if (observer_added_)
- CertDatabase::GetInstance()->RemoveObserver(this);
- }
- // CertDatabase::Observer:
- void OnCertDBChanged() override { db_changed_count_++; }
- protected:
- bool observer_added_ = false;
- int db_changed_count_ = 0;
- crypto::ScopedTestNSSChromeOSUser user_1_;
- crypto::ScopedTestNSSChromeOSUser user_2_;
- crypto::ScopedTestNSSDB system_db_;
- std::unique_ptr<NSSCertDatabaseChromeOS> db_1_;
- std::unique_ptr<NSSCertDatabaseChromeOS> db_2_;
- };
- // Test that ListModules() on each user includes that user's NSS software slot,
- // and does not include the software slot of the other user. (Does not check the
- // private slot, since it is the same as the public slot in tests.)
- TEST_F(NSSCertDatabaseChromeOSTest, ListModules) {
- std::vector<crypto::ScopedPK11Slot> modules_1;
- std::vector<crypto::ScopedPK11Slot> modules_2;
- db_1_->ListModules(&modules_1, false /* need_rw */);
- db_2_->ListModules(&modules_2, false /* need_rw */);
- bool found_1 = false;
- for (std::vector<crypto::ScopedPK11Slot>::iterator it = modules_1.begin();
- it != modules_1.end(); ++it) {
- EXPECT_NE(db_2_->GetPublicSlot().get(), (*it).get());
- if ((*it).get() == db_1_->GetPublicSlot().get())
- found_1 = true;
- }
- EXPECT_TRUE(found_1);
- bool found_2 = false;
- for (std::vector<crypto::ScopedPK11Slot>::iterator it = modules_2.begin();
- it != modules_2.end(); ++it) {
- EXPECT_NE(db_1_->GetPublicSlot().get(), (*it).get());
- if ((*it).get() == db_2_->GetPublicSlot().get())
- found_2 = true;
- }
- EXPECT_TRUE(found_2);
- }
- // Test that ImportCACerts imports the cert to the correct slot, and that
- // ListCerts includes the added cert for the correct user, and does not include
- // it for the other user.
- TEST_F(NSSCertDatabaseChromeOSTest, ImportCACerts) {
- // Load test certs from disk.
- ScopedCERTCertificateList certs_1 = CreateCERTCertificateListFromFile(
- GetTestCertsDirectory(), "root_ca_cert.pem",
- X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(1U, certs_1.size());
- ScopedCERTCertificateList certs_2 = CreateCERTCertificateListFromFile(
- GetTestCertsDirectory(), "2048-rsa-root.pem",
- X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(1U, certs_2.size());
- // Import one cert for each user.
- NSSCertDatabase::ImportCertFailureList failed;
- EXPECT_TRUE(
- db_1_->ImportCACerts(certs_1, NSSCertDatabase::TRUSTED_SSL, &failed));
- EXPECT_EQ(0U, failed.size());
- failed.clear();
- EXPECT_TRUE(
- db_2_->ImportCACerts(certs_2, NSSCertDatabase::TRUSTED_SSL, &failed));
- EXPECT_EQ(0U, failed.size());
- // Get cert list for each user.
- ScopedCERTCertificateList user_1_certlist;
- ScopedCERTCertificateList user_2_certlist;
- db_1_->ListCerts(
- base::BindOnce(&SwapCertLists, base::Unretained(&user_1_certlist)));
- db_2_->ListCerts(
- base::BindOnce(&SwapCertLists, base::Unretained(&user_2_certlist)));
- // Run the message loop so the observer notifications get processed and
- // lookups are completed.
- RunUntilIdle();
- // Should have gotten two OnCertDBChanged notifications.
- ASSERT_EQ(2, db_changed_count_);
- EXPECT_TRUE(IsCertInCertificateList(certs_1[0].get(), user_1_certlist));
- EXPECT_FALSE(IsCertInCertificateList(certs_1[0].get(), user_2_certlist));
- EXPECT_TRUE(IsCertInCertificateList(certs_2[0].get(), user_2_certlist));
- EXPECT_FALSE(IsCertInCertificateList(certs_2[0].get(), user_1_certlist));
- }
- // Test that ImportServerCerts imports the cert to the correct slot, and that
- // ListCerts includes the added cert for the correct user, and does not include
- // it for the other user.
- TEST_F(NSSCertDatabaseChromeOSTest, ImportServerCert) {
- // Load test certs from disk.
- ScopedCERTCertificateList certs_1 = CreateCERTCertificateListFromFile(
- GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(1U, certs_1.size());
- ScopedCERTCertificateList certs_2 = CreateCERTCertificateListFromFile(
- GetTestCertsDirectory(), "2048-rsa-ee-by-2048-rsa-intermediate.pem",
- X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(1U, certs_2.size());
- // Import one cert for each user.
- NSSCertDatabase::ImportCertFailureList failed;
- EXPECT_TRUE(
- db_1_->ImportServerCert(certs_1, NSSCertDatabase::TRUSTED_SSL, &failed));
- EXPECT_EQ(0U, failed.size());
- failed.clear();
- EXPECT_TRUE(
- db_2_->ImportServerCert(certs_2, NSSCertDatabase::TRUSTED_SSL, &failed));
- EXPECT_EQ(0U, failed.size());
- // Get cert list for each user.
- ScopedCERTCertificateList user_1_certlist;
- ScopedCERTCertificateList user_2_certlist;
- db_1_->ListCerts(
- base::BindOnce(&SwapCertLists, base::Unretained(&user_1_certlist)));
- db_2_->ListCerts(
- base::BindOnce(&SwapCertLists, base::Unretained(&user_2_certlist)));
- // Run the message loop so the observer notifications get processed and
- // lookups are completed.
- RunUntilIdle();
- // TODO(mattm): ImportServerCert doesn't actually cause any observers to
- // fire. Is that correct?
- EXPECT_EQ(0, db_changed_count_);
- EXPECT_TRUE(IsCertInCertificateList(certs_1[0].get(), user_1_certlist));
- EXPECT_FALSE(IsCertInCertificateList(certs_1[0].get(), user_2_certlist));
- EXPECT_TRUE(IsCertInCertificateList(certs_2[0].get(), user_2_certlist));
- EXPECT_FALSE(IsCertInCertificateList(certs_2[0].get(), user_1_certlist));
- }
- // Tests that There is no crash if the database is deleted while ListCerts
- // is being processed on the worker pool.
- TEST_F(NSSCertDatabaseChromeOSTest, NoCrashIfShutdownBeforeDoneOnWorkerPool) {
- ScopedCERTCertificateList certlist;
- db_1_->ListCerts(base::BindOnce(&SwapCertLists, base::Unretained(&certlist)));
- EXPECT_EQ(0U, certlist.size());
- db_1_.reset();
- RunUntilIdle();
- EXPECT_LT(0U, certlist.size());
- }
- TEST_F(NSSCertDatabaseChromeOSTest, ListCertsReadsSystemSlot) {
- scoped_refptr<X509Certificate> cert_1(
- ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
- "client_1.pem",
- "client_1.pk8",
- db_1_->GetPublicSlot().get()));
- scoped_refptr<X509Certificate> cert_2(
- ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
- "client_2.pem",
- "client_2.pk8",
- db_1_->GetSystemSlot().get()));
- ScopedCERTCertificateList certs;
- db_1_->ListCerts(base::BindOnce(&SwapCertLists, base::Unretained(&certs)));
- RunUntilIdle();
- EXPECT_TRUE(IsCertInCertificateList(cert_1.get(), certs));
- EXPECT_TRUE(IsCertInCertificateList(cert_2.get(), certs));
- }
- TEST_F(NSSCertDatabaseChromeOSTest, ListCertsDoesNotCrossReadSystemSlot) {
- scoped_refptr<X509Certificate> cert_1(
- ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
- "client_1.pem",
- "client_1.pk8",
- db_2_->GetPublicSlot().get()));
- scoped_refptr<X509Certificate> cert_2(
- ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
- "client_2.pem",
- "client_2.pk8",
- system_db_.slot()));
- ScopedCERTCertificateList certs;
- db_2_->ListCerts(base::BindOnce(&SwapCertLists, base::Unretained(&certs)));
- RunUntilIdle();
- EXPECT_TRUE(IsCertInCertificateList(cert_1.get(), certs));
- EXPECT_FALSE(IsCertInCertificateList(cert_2.get(), certs));
- }
- TEST_F(NSSCertDatabaseChromeOSTest, SetCertTrustCertIsAlreadyOnPublicSlot) {
- // Import a certificate onto the public slot (and safety check that it ended
- // up there).
- ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
- GetTestCertsDirectory(), "root_ca_cert.pem",
- X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(1U, certs.size());
- NSSCertDatabase::ImportCertFailureList failed;
- EXPECT_TRUE(
- db_1_->ImportCACerts(certs, NSSCertDatabase::TRUST_DEFAULT, &failed));
- EXPECT_EQ(0U, failed.size());
- ASSERT_TRUE(NSSCertDatabase::IsCertificateOnSlot(
- certs[0].get(), db_1_->GetPublicSlot().get()));
- // Check that trust settings modification works.
- EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT,
- db_1_->GetCertTrust(certs[0].get(), CA_CERT));
- EXPECT_TRUE(db_1_->SetCertTrust(certs[0].get(), CA_CERT,
- NSSCertDatabase::TRUSTED_SSL));
- EXPECT_EQ(NSSCertDatabase::TRUSTED_SSL,
- db_1_->GetCertTrust(certs[0].get(), CA_CERT));
- }
- TEST_F(NSSCertDatabaseChromeOSTest, SetCertTrustCertIsOnlyOnOtherSlot) {
- crypto::ScopedTestNSSDB other_slot;
- // Import a certificate onto a slot known by NSS which is not the
- // NSSCertDatabase's public slot.
- ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
- GetTestCertsDirectory(), "root_ca_cert.pem",
- X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(1U, certs.size());
- ASSERT_EQ(SECSuccess, PK11_ImportCert(other_slot.slot(), certs[0].get(),
- CK_INVALID_HANDLE, "cert0",
- PR_FALSE /* includeTrust (unused) */));
- ASSERT_FALSE(NSSCertDatabase::IsCertificateOnSlot(
- certs[0].get(), db_1_->GetPublicSlot().get()));
- // Check that trust settings modification works.
- EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT,
- db_1_->GetCertTrust(certs[0].get(), CA_CERT));
- EXPECT_TRUE(db_1_->SetCertTrust(certs[0].get(), CA_CERT,
- NSSCertDatabase::TRUSTED_SSL));
- EXPECT_EQ(NSSCertDatabase::TRUSTED_SSL,
- db_1_->GetCertTrust(certs[0].get(), CA_CERT));
- // Check that the certificate has been put onto the public slot as a side
- // effect of changing trust.
- EXPECT_TRUE(NSSCertDatabase::IsCertificateOnSlot(
- certs[0].get(), db_1_->GetPublicSlot().get()));
- }
- TEST_F(NSSCertDatabaseChromeOSTest, SetCertTrustPublicSlotIsSystemSlot) {
- // Create a NSSCertDatabase with |public_slot|==|system_slot|.
- NSSCertDatabaseChromeOS test_db_for_system_slot(
- /*public_slot=*/crypto::ScopedPK11Slot(
- PK11_ReferenceSlot(system_db_.slot())),
- /*private_slot=*/{});
- test_db_for_system_slot.SetSystemSlot(
- crypto::ScopedPK11Slot(PK11_ReferenceSlot(system_db_.slot())));
- // Import a certificate onto a slot known by NSS which is not the
- // NSSCertDatabase's public slot.
- crypto::ScopedTestNSSDB other_slot;
- ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
- GetTestCertsDirectory(), "root_ca_cert.pem",
- X509Certificate::FORMAT_AUTO);
- ASSERT_EQ(1U, certs.size());
- ASSERT_EQ(SECSuccess, PK11_ImportCert(other_slot.slot(), certs[0].get(),
- CK_INVALID_HANDLE, "cert0",
- PR_FALSE /* includeTrust (unused) */));
- ASSERT_FALSE(NSSCertDatabase::IsCertificateOnSlot(
- certs[0].get(), test_db_for_system_slot.GetPublicSlot().get()));
- // Changing trust through |test_db_for_system_slot| should fail and not do
- // anything, because the database is not allowed to put the certificate onto
- // its public slot (because it is also the system slot).
- EXPECT_FALSE(test_db_for_system_slot.SetCertTrust(
- certs[0].get(), CA_CERT, NSSCertDatabase::TRUSTED_SSL));
- EXPECT_FALSE(NSSCertDatabase::IsCertificateOnSlot(
- certs[0].get(), test_db_for_system_slot.GetPublicSlot().get()));
- }
- } // namespace net
|