blob: 6056f7675e849259dffeb2571fe9f4d9b6715198 [file] [log] [blame]
[email protected]69295ba2014-01-28 06:17:001// Copyright 2014 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 "chromeos/cert_loader.h"
6
avi6e1a22d2015-12-21 03:43:207#include <stddef.h>
dcheng0a6e80c2016-04-08 18:37:388
9#include <memory>
dcheng7df85ba2015-12-31 04:56:3910#include <utility>
avi6e1a22d2015-12-21 03:43:2011
[email protected]69295ba2014-01-28 06:17:0012#include "base/bind.h"
thestigb44bd352014-09-10 01:47:0613#include "base/files/file_util.h"
fdoray37b8327d2017-02-28 02:42:1414#include "base/message_loop/message_loop.h"
[email protected]69295ba2014-01-28 06:17:0015#include "base/run_loop.h"
[email protected]16dad0962014-03-18 01:29:1116#include "crypto/scoped_nss_types.h"
pneubeck6fd7d482015-01-10 10:07:3817#include "crypto/scoped_test_nss_db.h"
[email protected]69295ba2014-01-28 06:17:0018#include "net/cert/nss_cert_database_chromeos.h"
19#include "net/cert/x509_certificate.h"
20#include "net/test/cert_test_util.h"
rsleevia69c79a2016-06-22 03:28:4321#include "net/test/test_data_directory.h"
[email protected]69295ba2014-01-28 06:17:0022#include "testing/gtest/include/gtest/gtest.h"
23
24namespace chromeos {
25namespace {
26
27bool IsCertInCertificateList(const net::X509Certificate* cert,
28 const net::CertificateList& cert_list) {
29 for (net::CertificateList::const_iterator it = cert_list.begin();
30 it != cert_list.end();
31 ++it) {
32 if (net::X509Certificate::IsSameOSCert((*it)->os_cert_handle(),
33 cert->os_cert_handle())) {
34 return true;
35 }
36 }
37 return false;
38}
39
pneubeck6fd7d482015-01-10 10:07:3840class TestNSSCertDatabase : public net::NSSCertDatabaseChromeOS {
41 public:
42 TestNSSCertDatabase(crypto::ScopedPK11Slot public_slot,
43 crypto::ScopedPK11Slot private_slot)
dcheng7df85ba2015-12-31 04:56:3944 : NSSCertDatabaseChromeOS(std::move(public_slot),
45 std::move(private_slot)) {}
pneubeck6fd7d482015-01-10 10:07:3846 ~TestNSSCertDatabase() override {}
47
48 void NotifyOfCertAdded(const net::X509Certificate* cert) {
mattmfd05a1f2017-02-18 06:18:4449 NSSCertDatabaseChromeOS::NotifyObserversCertDBChanged();
pneubeck6fd7d482015-01-10 10:07:3850 }
51};
[email protected]69295ba2014-01-28 06:17:0052
53class CertLoaderTest : public testing::Test,
54 public CertLoader::Observer {
55 public:
pneubeck6fd7d482015-01-10 10:07:3856 CertLoaderTest()
57 : cert_loader_(nullptr), certificates_loaded_events_count_(0U) {}
[email protected]69295ba2014-01-28 06:17:0058
pneubeck6fd7d482015-01-10 10:07:3859 ~CertLoaderTest() override {}
[email protected]69295ba2014-01-28 06:17:0060
pneubeck6fd7d482015-01-10 10:07:3861 void SetUp() override {
62 ASSERT_TRUE(primary_db_.is_open());
[email protected]69295ba2014-01-28 06:17:0063
64 CertLoader::Initialize();
65 cert_loader_ = CertLoader::Get();
66 cert_loader_->AddObserver(this);
[email protected]69295ba2014-01-28 06:17:0067 }
68
pneubeck6fd7d482015-01-10 10:07:3869 void TearDown() override {
[email protected]69295ba2014-01-28 06:17:0070 cert_loader_->RemoveObserver(this);
71 CertLoader::Shutdown();
72 }
73
74 protected:
pneubeck6fd7d482015-01-10 10:07:3875 void StartCertLoaderWithPrimaryDB() {
76 CreateCertDatabase(&primary_db_, &primary_certdb_);
77 cert_loader_->StartWithNSSDB(primary_certdb_.get());
[email protected]69295ba2014-01-28 06:17:0078
79 base::RunLoop().RunUntilIdle();
80 GetAndResetCertificatesLoadedEventsCount();
81 }
82
83 // CertLoader::Observer:
84 // The test keeps count of times the observer method was called.
pneubeck6fd7d482015-01-10 10:07:3885 void OnCertificatesLoaded(const net::CertificateList& cert_list,
86 bool initial_load) override {
[email protected]69295ba2014-01-28 06:17:0087 EXPECT_TRUE(certificates_loaded_events_count_ == 0 || !initial_load);
88 certificates_loaded_events_count_++;
89 }
90
91 // Returns the number of |OnCertificatesLoaded| calls observed since the
92 // last call to this method equals |value|.
93 size_t GetAndResetCertificatesLoadedEventsCount() {
94 size_t result = certificates_loaded_events_count_;
95 certificates_loaded_events_count_ = 0;
96 return result;
97 }
98
pneubeck6fd7d482015-01-10 10:07:3899 void CreateCertDatabase(crypto::ScopedTestNSSDB* db,
dcheng0a6e80c2016-04-08 18:37:38100 std::unique_ptr<TestNSSCertDatabase>* certdb) {
pneubeck6fd7d482015-01-10 10:07:38101 ASSERT_TRUE(db->is_open());
[email protected]69295ba2014-01-28 06:17:00102
pneubeck6fd7d482015-01-10 10:07:38103 certdb->reset(new TestNSSCertDatabase(
104 crypto::ScopedPK11Slot(PK11_ReferenceSlot(db->slot())),
105 crypto::ScopedPK11Slot(PK11_ReferenceSlot(db->slot()))));
fdoray37b8327d2017-02-28 02:42:14106 (*certdb)->SetSlowTaskRunnerForTest(message_loop_.task_runner());
[email protected]69295ba2014-01-28 06:17:00107 }
108
109 void ImportCACert(const std::string& cert_file,
110 net::NSSCertDatabase* database,
111 net::CertificateList* imported_certs) {
112 ASSERT_TRUE(database);
113 ASSERT_TRUE(imported_certs);
114
[email protected]69295ba2014-01-28 06:17:00115 *imported_certs = net::CreateCertificateListFromFile(
116 net::GetTestCertsDirectory(),
117 cert_file,
118 net::X509Certificate::FORMAT_AUTO);
119 ASSERT_EQ(1U, imported_certs->size());
120
121 net::NSSCertDatabase::ImportCertFailureList failed;
122 ASSERT_TRUE(database->ImportCACerts(*imported_certs,
123 net::NSSCertDatabase::TRUST_DEFAULT,
124 &failed));
125 ASSERT_TRUE(failed.empty());
126 }
127
pneubeck6fd7d482015-01-10 10:07:38128 scoped_refptr<net::X509Certificate> ImportClientCertAndKey(
129 TestNSSCertDatabase* database) {
130 // Import a client cert signed by that CA.
131 scoped_refptr<net::X509Certificate> client_cert(
132 net::ImportClientCertAndKeyFromFile(net::GetTestCertsDirectory(),
133 "client_1.pem", "client_1.pk8",
134 database->GetPrivateSlot().get()));
135 database->NotifyOfCertAdded(client_cert.get());
136 return client_cert;
[email protected]69295ba2014-01-28 06:17:00137 }
138
139 CertLoader* cert_loader_;
140
141 // The user is primary as the one whose certificates CertLoader handles, it
142 // has nothing to do with crypto::InitializeNSSForChromeOSUser is_primary_user
143 // parameter (which is irrelevant for these tests).
pneubeck6fd7d482015-01-10 10:07:38144 crypto::ScopedTestNSSDB primary_db_;
dcheng0a6e80c2016-04-08 18:37:38145 std::unique_ptr<TestNSSCertDatabase> primary_certdb_;
[email protected]69295ba2014-01-28 06:17:00146
fdoray37b8327d2017-02-28 02:42:14147 base::MessageLoop message_loop_;
[email protected]69295ba2014-01-28 06:17:00148
149 private:
150 size_t certificates_loaded_events_count_;
151};
152
pneubeck6fd7d482015-01-10 10:07:38153} // namespace
154
[email protected]69295ba2014-01-28 06:17:00155TEST_F(CertLoaderTest, Basic) {
156 EXPECT_FALSE(cert_loader_->CertificatesLoading());
157 EXPECT_FALSE(cert_loader_->certificates_loaded());
[email protected]69295ba2014-01-28 06:17:00158
pneubeck6fd7d482015-01-10 10:07:38159 CreateCertDatabase(&primary_db_, &primary_certdb_);
160 cert_loader_->StartWithNSSDB(primary_certdb_.get());
[email protected]69295ba2014-01-28 06:17:00161
162 EXPECT_FALSE(cert_loader_->certificates_loaded());
163 EXPECT_TRUE(cert_loader_->CertificatesLoading());
164 EXPECT_TRUE(cert_loader_->cert_list().empty());
165
166 ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
167 base::RunLoop().RunUntilIdle();
168 EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
169
170 EXPECT_TRUE(cert_loader_->certificates_loaded());
171 EXPECT_FALSE(cert_loader_->CertificatesLoading());
[email protected]69295ba2014-01-28 06:17:00172
173 // Default CA cert roots should get loaded.
174 EXPECT_FALSE(cert_loader_->cert_list().empty());
175}
176
177TEST_F(CertLoaderTest, CertLoaderUpdatesCertListOnNewCert) {
pneubeck6fd7d482015-01-10 10:07:38178 StartCertLoaderWithPrimaryDB();
[email protected]69295ba2014-01-28 06:17:00179
180 net::CertificateList certs;
pneubeck6fd7d482015-01-10 10:07:38181 ImportCACert("root_ca_cert.pem", primary_certdb_.get(), &certs);
[email protected]69295ba2014-01-28 06:17:00182
183 // Certs are loaded asynchronously, so the new cert should not yet be in the
184 // cert list.
dcheng5adf8d22014-09-11 00:53:37185 EXPECT_FALSE(
186 IsCertInCertificateList(certs[0].get(), cert_loader_->cert_list()));
[email protected]69295ba2014-01-28 06:17:00187
188 ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
189 base::RunLoop().RunUntilIdle();
190 EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
191
192 // The certificate list should be updated now, as the message loop's been run.
dcheng5adf8d22014-09-11 00:53:37193 EXPECT_TRUE(
194 IsCertInCertificateList(certs[0].get(), cert_loader_->cert_list()));
pneubeckad2f2162014-11-06 10:56:19195
196 EXPECT_FALSE(cert_loader_->IsCertificateHardwareBacked(certs[0].get()));
[email protected]69295ba2014-01-28 06:17:00197}
198
199TEST_F(CertLoaderTest, CertLoaderNoUpdateOnSecondaryDbChanges) {
pneubeck6fd7d482015-01-10 10:07:38200 crypto::ScopedTestNSSDB secondary_db;
dcheng0a6e80c2016-04-08 18:37:38201 std::unique_ptr<TestNSSCertDatabase> secondary_certdb;
[email protected]69295ba2014-01-28 06:17:00202
pneubeck6fd7d482015-01-10 10:07:38203 StartCertLoaderWithPrimaryDB();
204 CreateCertDatabase(&secondary_db, &secondary_certdb);
[email protected]69295ba2014-01-28 06:17:00205
206 net::CertificateList certs;
pneubeck6fd7d482015-01-10 10:07:38207 ImportCACert("root_ca_cert.pem", secondary_certdb.get(), &certs);
[email protected]69295ba2014-01-28 06:17:00208
209 base::RunLoop().RunUntilIdle();
210
dcheng5adf8d22014-09-11 00:53:37211 EXPECT_FALSE(
212 IsCertInCertificateList(certs[0].get(), cert_loader_->cert_list()));
[email protected]69295ba2014-01-28 06:17:00213}
214
215TEST_F(CertLoaderTest, ClientLoaderUpdateOnNewClientCert) {
pneubeck6fd7d482015-01-10 10:07:38216 StartCertLoaderWithPrimaryDB();
[email protected]69295ba2014-01-28 06:17:00217
pneubeck6fd7d482015-01-10 10:07:38218 scoped_refptr<net::X509Certificate> cert(
219 ImportClientCertAndKey(primary_certdb_.get()));
[email protected]69295ba2014-01-28 06:17:00220
221 ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
222 base::RunLoop().RunUntilIdle();
223 EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
224
pneubeck6fd7d482015-01-10 10:07:38225 EXPECT_TRUE(IsCertInCertificateList(cert.get(), cert_loader_->cert_list()));
[email protected]69295ba2014-01-28 06:17:00226}
227
228TEST_F(CertLoaderTest, CertLoaderNoUpdateOnNewClientCertInSecondaryDb) {
pneubeck6fd7d482015-01-10 10:07:38229 crypto::ScopedTestNSSDB secondary_db;
dcheng0a6e80c2016-04-08 18:37:38230 std::unique_ptr<TestNSSCertDatabase> secondary_certdb;
[email protected]69295ba2014-01-28 06:17:00231
pneubeck6fd7d482015-01-10 10:07:38232 StartCertLoaderWithPrimaryDB();
233 CreateCertDatabase(&secondary_db, &secondary_certdb);
[email protected]69295ba2014-01-28 06:17:00234
pneubeck6fd7d482015-01-10 10:07:38235 scoped_refptr<net::X509Certificate> cert(
236 ImportClientCertAndKey(secondary_certdb.get()));
[email protected]69295ba2014-01-28 06:17:00237
238 base::RunLoop().RunUntilIdle();
239
pneubeck6fd7d482015-01-10 10:07:38240 EXPECT_FALSE(IsCertInCertificateList(cert.get(), cert_loader_->cert_list()));
[email protected]69295ba2014-01-28 06:17:00241}
242
243TEST_F(CertLoaderTest, UpdatedOnCertRemoval) {
pneubeck6fd7d482015-01-10 10:07:38244 StartCertLoaderWithPrimaryDB();
[email protected]69295ba2014-01-28 06:17:00245
pneubeck6fd7d482015-01-10 10:07:38246 scoped_refptr<net::X509Certificate> cert(
247 ImportClientCertAndKey(primary_certdb_.get()));
[email protected]69295ba2014-01-28 06:17:00248
249 base::RunLoop().RunUntilIdle();
250
251 ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
pneubeck6fd7d482015-01-10 10:07:38252 ASSERT_TRUE(IsCertInCertificateList(cert.get(), cert_loader_->cert_list()));
[email protected]69295ba2014-01-28 06:17:00253
pneubeck6fd7d482015-01-10 10:07:38254 primary_certdb_->DeleteCertAndKey(cert.get());
[email protected]69295ba2014-01-28 06:17:00255
256 ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
257 base::RunLoop().RunUntilIdle();
258 EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
259
pneubeck6fd7d482015-01-10 10:07:38260 ASSERT_FALSE(IsCertInCertificateList(cert.get(), cert_loader_->cert_list()));
[email protected]69295ba2014-01-28 06:17:00261}
262
263TEST_F(CertLoaderTest, UpdatedOnCACertTrustChange) {
pneubeck6fd7d482015-01-10 10:07:38264 StartCertLoaderWithPrimaryDB();
[email protected]69295ba2014-01-28 06:17:00265
266 net::CertificateList certs;
pneubeck6fd7d482015-01-10 10:07:38267 ImportCACert("root_ca_cert.pem", primary_certdb_.get(), &certs);
[email protected]69295ba2014-01-28 06:17:00268
269 base::RunLoop().RunUntilIdle();
270 ASSERT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
dcheng5adf8d22014-09-11 00:53:37271 ASSERT_TRUE(
272 IsCertInCertificateList(certs[0].get(), cert_loader_->cert_list()));
[email protected]69295ba2014-01-28 06:17:00273
274 // The value that should have been set by |ImportCACert|.
275 ASSERT_EQ(net::NSSCertDatabase::TRUST_DEFAULT,
pneubeck6fd7d482015-01-10 10:07:38276 primary_certdb_->GetCertTrust(certs[0].get(), net::CA_CERT));
277 ASSERT_TRUE(primary_certdb_->SetCertTrust(certs[0].get(), net::CA_CERT,
278 net::NSSCertDatabase::TRUSTED_SSL));
[email protected]69295ba2014-01-28 06:17:00279
280 // Cert trust change should trigger certificate reload in cert_loader_.
281 ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
282 base::RunLoop().RunUntilIdle();
283 EXPECT_EQ(1U, GetAndResetCertificatesLoadedEventsCount());
284}
285
[email protected]69295ba2014-01-28 06:17:00286} // namespace chromeos