| // Copyright 2018 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 "chrome/browser/certificate_manager_model.h" |
| |
| #include "base/observer_list.h" |
| #include "base/run_loop.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "build/chromeos_buildflags.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "crypto/scoped_test_nss_db.h" |
| #include "net/cert/nss_cert_database.h" |
| #include "net/cert/scoped_nss_types.h" |
| #include "net/cert/x509_util_nss.h" |
| #include "net/ssl/client_cert_identity_test_util.h" |
| #include "net/test/cert_builder.h" |
| #include "net/test/cert_test_util.h" |
| #include "net/test/test_data_directory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "chrome/browser/ash/certificate_provider/certificate_provider.h" |
| #include "chromeos/components/onc/certificate_scope.h" |
| #include "chromeos/network/policy_certificate_provider.h" |
| #endif |
| |
| namespace { |
| |
| // A fake CertificateManagerModel::Observer that has the ability to execute a |
| // OnceClosure passed to it when |CertificatesRefreshed| is called. |
| class FakeObserver : public CertificateManagerModel::Observer { |
| public: |
| void CertificatesRefreshed() override { |
| if (!run_on_refresh_.is_null()) |
| std::move(run_on_refresh_).Run(); |
| } |
| |
| // Execute |closure| on the next |CertificatesRefreshed| invocation. |
| void RunOnNextRefresh(base::OnceClosure closure) { |
| run_on_refresh_ = std::move(closure); |
| } |
| |
| private: |
| base::OnceClosure run_on_refresh_; |
| }; |
| |
| // Looks up a |CertInfo| in |org_grouping_map| corresponding to |cert|. Returns |
| // nullptr if no such |CertInfo| was found. |
| CertificateManagerModel::CertInfo* GetCertInfoFromOrgGroupingMap( |
| const CertificateManagerModel::OrgGroupingMap& org_grouping_map, |
| CERTCertificate* cert) { |
| for (const auto& org_and_cert_info_list : org_grouping_map) { |
| for (const auto& cert_info : org_and_cert_info_list.second) { |
| if (net::x509_util::IsSameCertificate(cert_info->cert(), cert)) |
| return cert_info.get(); |
| } |
| } |
| return nullptr; |
| } |
| |
| } // namespace |
| |
| class CertificateManagerModelTest : public testing::Test { |
| public: |
| CertificateManagerModelTest() {} |
| |
| CertificateManagerModelTest(const CertificateManagerModelTest&) = delete; |
| CertificateManagerModelTest& operator=(const CertificateManagerModelTest&) = |
| delete; |
| |
| protected: |
| void SetUp() override { |
| ASSERT_TRUE(test_nssdb_.is_open()); |
| |
| nss_cert_db_ = std::make_unique<net::NSSCertDatabase>( |
| crypto::ScopedPK11Slot( |
| PK11_ReferenceSlot(test_nssdb_.slot())) /* public slot */, |
| crypto::ScopedPK11Slot( |
| PK11_ReferenceSlot(test_nssdb_.slot())) /* private slot */); |
| |
| fake_observer_ = std::make_unique<FakeObserver>(); |
| certificate_manager_model_ = std::make_unique<CertificateManagerModel>( |
| GetCertificateManagerModelParams(), fake_observer_.get(), |
| nss_cert_db_.get()); |
| } |
| |
| void TearDown() override { |
| certificate_manager_model_.reset(); |
| nss_cert_db_.reset(); |
| } |
| |
| // Provides the platform-specific |Params| (containing policy/extension |
| // certificate provides on Chrome OS). |
| virtual std::unique_ptr<CertificateManagerModel::Params> |
| GetCertificateManagerModelParams() { |
| return std::make_unique<CertificateManagerModel::Params>(); |
| } |
| |
| protected: |
| // Invoke an explicit Refresh if the refresh is triggered and wait until the |
| // observer has been notified. |
| void WaitForRefresh(bool trigger_refresh) { |
| base::RunLoop run_loop; |
| fake_observer_->RunOnNextRefresh(run_loop.QuitClosure()); |
| if (trigger_refresh) { |
| certificate_manager_model_->Refresh(); |
| } |
| run_loop.Run(); |
| } |
| |
| content::BrowserTaskEnvironment task_environment_; |
| crypto::ScopedTestNSSDB test_nssdb_; |
| std::unique_ptr<net::NSSCertDatabase> nss_cert_db_; |
| std::unique_ptr<FakeObserver> fake_observer_; |
| std::unique_ptr<CertificateManagerModel> certificate_manager_model_; |
| }; |
| |
| // CertificateManagerModel correctly lists CA certificates from the platform NSS |
| // Database. |
| TEST_F(CertificateManagerModelTest, ListsCertsFromPlatform) { |
| net::CertificateList orig_certs = CreateCertificateListFromFile( |
| net::GetTestCertsDirectory(), "websocket_cacert.pem", |
| net::X509Certificate::FORMAT_AUTO); |
| ASSERT_EQ(1U, orig_certs.size()); |
| |
| net::CertBuilder cert_builder(orig_certs[0]->cert_buffer(), nullptr); |
| scoped_refptr<net::X509Certificate> x509_cert = |
| cert_builder.GetX509Certificate(); |
| |
| net::ScopedCERTCertificate cert = |
| net::x509_util::CreateCERTCertificateFromX509Certificate(x509_cert.get()); |
| std::string cert_subject_name = x509_cert->subject().GetDisplayName(); |
| |
| ASSERT_EQ(SECSuccess, |
| PK11_ImportCert(test_nssdb_.slot(), cert.get(), CK_INVALID_HANDLE, |
| "cert", PR_FALSE /* includeTrust (unused) */)); |
| WaitForRefresh(true /*tigger_for_refresh*/); |
| |
| { |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::CA_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, cert.get()); |
| ASSERT_TRUE(cert_info); |
| |
| EXPECT_EQ(net::CertType::CA_CERT, cert_info->type()); |
| EXPECT_EQ(base::UTF8ToUTF16(cert_subject_name), cert_info->name()); |
| EXPECT_TRUE(cert_info->can_be_deleted()); |
| // This platform cert is untrusted because it is self-signed and has no |
| // trust bits. |
| EXPECT_TRUE(cert_info->untrusted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform, |
| cert_info->source()); |
| EXPECT_FALSE(cert_info->web_trust_anchor()); |
| EXPECT_FALSE(cert_info->hardware_backed()); |
| } |
| |
| certificate_manager_model_->SetCertTrust(cert.get(), net::CertType::CA_CERT, |
| net::NSSCertDatabase::TRUSTED_SSL); |
| // Wait for refresh without triggering because observer should be notified by |
| // net::CertDatabase and refresh automatically. |
| WaitForRefresh(false /*tigger_for_refresh*/); |
| { |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::CA_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, cert.get()); |
| ASSERT_TRUE(cert_info); |
| |
| EXPECT_FALSE(cert_info->untrusted()); |
| EXPECT_TRUE(cert_info->web_trust_anchor()); |
| } |
| } |
| |
| // CertificateManagerModel correctly lists client certificates from the platform |
| // NSS Database. |
| TEST_F(CertificateManagerModelTest, ListsClientCertsFromPlatform) { |
| net::ScopedCERTCertificate platform_client_cert; |
| net::ImportClientCertAndKeyFromFile( |
| net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8", |
| test_nssdb_.slot(), &platform_client_cert); |
| |
| WaitForRefresh(true /*tigger_for_refresh*/); |
| |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::USER_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* platform_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, |
| platform_client_cert.get()); |
| ASSERT_TRUE(platform_cert_info); |
| |
| EXPECT_EQ(net::CertType::USER_CERT, platform_cert_info->type()); |
| EXPECT_EQ(u"Client Cert A", platform_cert_info->name()); |
| EXPECT_TRUE(platform_cert_info->can_be_deleted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform, |
| platform_cert_info->source()); |
| EXPECT_FALSE(platform_cert_info->web_trust_anchor()); |
| EXPECT_FALSE(platform_cert_info->hardware_backed()); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| namespace { |
| |
| class FakePolicyCertificateProvider |
| : public chromeos::PolicyCertificateProvider { |
| public: |
| void AddPolicyProvidedCertsObserver(Observer* observer) override { |
| observer_list_.AddObserver(observer); |
| } |
| |
| void RemovePolicyProvidedCertsObserver(Observer* observer) override { |
| observer_list_.RemoveObserver(observer); |
| } |
| |
| net::CertificateList GetAllServerAndAuthorityCertificates( |
| const chromeos::onc::CertificateScope& scope) const override { |
| // The CertificateManagerModel only retrieves profile-wide certificates. |
| EXPECT_EQ(chromeos::onc::CertificateScope::Default(), scope); |
| |
| net::CertificateList merged; |
| merged.insert(merged.end(), web_trusted_certs_.begin(), |
| web_trusted_certs_.end()); |
| merged.insert(merged.end(), not_web_trusted_certs_.begin(), |
| not_web_trusted_certs_.end()); |
| return merged; |
| } |
| |
| net::CertificateList GetAllAuthorityCertificates( |
| const chromeos::onc::CertificateScope& scope) const override { |
| // This function is not called by CertificateManagerModel. |
| NOTREACHED(); |
| return net::CertificateList(); |
| } |
| |
| net::CertificateList GetWebTrustedCertificates( |
| const chromeos::onc::CertificateScope& scope) const override { |
| // The CertificateManagerModel only retrieves profile-wide certificates. |
| EXPECT_EQ(chromeos::onc::CertificateScope::Default(), scope); |
| |
| return web_trusted_certs_; |
| } |
| |
| net::CertificateList GetCertificatesWithoutWebTrust( |
| const chromeos::onc::CertificateScope& scope) const override { |
| // The CertificateManagerModel only retrieves profile-wide certificates. |
| EXPECT_EQ(chromeos::onc::CertificateScope::Default(), scope); |
| |
| return not_web_trusted_certs_; |
| } |
| |
| const std::set<std::string>& GetExtensionIdsWithPolicyCertificates() |
| const override { |
| // This function is not called by CertificateManagerModel. |
| NOTREACHED(); |
| return kNoExtensions; |
| } |
| |
| void SetPolicyProvidedCertificates( |
| const net::CertificateList& web_trusted_certs, |
| const net::CertificateList& not_web_trusted_certs) { |
| web_trusted_certs_ = web_trusted_certs; |
| not_web_trusted_certs_ = not_web_trusted_certs; |
| } |
| |
| void NotifyObservers() { |
| for (auto& observer : observer_list_) |
| observer.OnPolicyProvidedCertsChanged(); |
| } |
| |
| private: |
| base::ObserverList<PolicyCertificateProvider::Observer, |
| true /* check_empty */>::Unchecked observer_list_; |
| net::CertificateList web_trusted_certs_; |
| net::CertificateList not_web_trusted_certs_; |
| const std::set<std::string> kNoExtensions = {}; |
| }; |
| |
| class FakeExtensionCertificateProvider : public chromeos::CertificateProvider { |
| public: |
| FakeExtensionCertificateProvider( |
| const net::CertificateList* extension_client_certificates, |
| const bool* extensions_hang) |
| : extension_client_certificates_(extension_client_certificates), |
| extensions_hang_(extensions_hang) {} |
| |
| void GetCertificates( |
| base::OnceCallback<void(net::ClientCertIdentityList)> callback) override { |
| if (*extensions_hang_) |
| return; |
| |
| std::move(callback).Run(FakeClientCertIdentityListFromCertificateList( |
| *extension_client_certificates_)); |
| } |
| |
| private: |
| const net::CertificateList* extension_client_certificates_; |
| |
| // If *|extensions_hang| is true, the |FakeExtensionCertificateProvider| hangs |
| // - it never calls the callbacks passed to |GetCertificates|. |
| const bool* extensions_hang_; |
| }; |
| |
| // Looks up a |CertInfo| in |org_grouping_map| corresponding to |cert|. Returns |
| // nullptr if no such |CertInfo| was found. |
| CertificateManagerModel::CertInfo* GetCertInfoFromOrgGroupingMap( |
| const CertificateManagerModel::OrgGroupingMap& org_grouping_map, |
| const net::X509Certificate* cert) { |
| for (const auto& org_and_cert_info_list : org_grouping_map) { |
| for (const auto& cert_info : org_and_cert_info_list.second) { |
| if (net::x509_util::IsSameCertificate(cert_info->cert(), cert)) |
| return cert_info.get(); |
| } |
| } |
| return nullptr; |
| } |
| |
| } // namespace |
| |
| class CertificateManagerModelChromeOSTest : public CertificateManagerModelTest { |
| protected: |
| std::unique_ptr<CertificateManagerModel::Params> |
| GetCertificateManagerModelParams() override { |
| auto params = std::make_unique<CertificateManagerModel::Params>(); |
| params->policy_certs_provider = &policy_certs_provider_; |
| params->extension_certificate_provider = |
| std::make_unique<FakeExtensionCertificateProvider>( |
| &extension_client_certs_, &extensions_hang_); |
| return params; |
| } |
| |
| void NotifyPolicyObserversAndWaitForRefresh() { |
| base::RunLoop run_loop; |
| fake_observer_->RunOnNextRefresh(run_loop.QuitClosure()); |
| policy_certs_provider_.NotifyObservers(); |
| run_loop.Run(); |
| } |
| |
| // Provider for policy certificates. In a non-test environment, this would |
| // usually be the UserNetworkConfigurationUpdater. |
| FakePolicyCertificateProvider policy_certs_provider_; |
| |
| // List of certificates that will be returned from the |
| // FakeExtensionCertificateProvider. |
| net::CertificateList extension_client_certs_; |
| // If true, the FakeExtensionCertificateProvider hangs. |
| bool extensions_hang_ = false; |
| }; |
| |
| // CertificateManagerModel correctly lists policy-provided certificates with web |
| // trust. |
| TEST_F(CertificateManagerModelChromeOSTest, ListsWebTrustedCertsFromPolicy) { |
| scoped_refptr<net::X509Certificate> cert = net::ImportCertFromFile( |
| net::GetTestCertsDirectory(), "websocket_cacert.pem"); |
| ASSERT_TRUE(cert.get()); |
| policy_certs_provider_.SetPolicyProvidedCertificates({cert}, {}); |
| |
| NotifyPolicyObserversAndWaitForRefresh(); |
| |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::CA_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, cert.get()); |
| ASSERT_TRUE(cert_info); |
| |
| EXPECT_EQ(net::CertType::CA_CERT, cert_info->type()); |
| EXPECT_EQ(u"pywebsocket", cert_info->name()); |
| EXPECT_FALSE(cert_info->can_be_deleted()); |
| EXPECT_FALSE(cert_info->untrusted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPolicy, |
| cert_info->source()); |
| EXPECT_TRUE(cert_info->web_trust_anchor()); |
| EXPECT_FALSE(cert_info->hardware_backed()); |
| } |
| |
| // CertificateManagerModel correctly lists policy-provided certificates without |
| // web trust. |
| TEST_F(CertificateManagerModelChromeOSTest, ListsNotWebTrustedCertsFromPolicy) { |
| scoped_refptr<net::X509Certificate> cert = net::ImportCertFromFile( |
| net::GetTestCertsDirectory(), "websocket_cacert.pem"); |
| ASSERT_TRUE(cert.get()); |
| policy_certs_provider_.SetPolicyProvidedCertificates({}, {cert}); |
| |
| NotifyPolicyObserversAndWaitForRefresh(); |
| |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::CA_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, cert.get()); |
| ASSERT_TRUE(cert_info); |
| |
| EXPECT_EQ(net::CertType::CA_CERT, cert_info->type()); |
| EXPECT_EQ(u"pywebsocket", cert_info->name()); |
| EXPECT_FALSE(cert_info->can_be_deleted()); |
| EXPECT_FALSE(cert_info->untrusted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPolicy, |
| cert_info->source()); |
| EXPECT_FALSE(cert_info->web_trust_anchor()); |
| EXPECT_FALSE(cert_info->hardware_backed()); |
| } |
| |
| // CertificateManagerModel correctly lists CA certificates that are in the |
| // platform NSS database and provided by policy with web trust. The |
| // policy-provided certificate hides the platform certificate in this case. |
| TEST_F(CertificateManagerModelChromeOSTest, |
| WebTrustedPolicyCertsWinOverPlatformCerts) { |
| net::ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile( |
| net::GetTestCertsDirectory(), "websocket_cacert.pem", |
| net::X509Certificate::FORMAT_AUTO); |
| ASSERT_EQ(1U, certs.size()); |
| CERTCertificate* platform_cert = certs[0].get(); |
| ASSERT_EQ(SECSuccess, PK11_ImportCert(test_nssdb_.slot(), platform_cert, |
| CK_INVALID_HANDLE, "cert", |
| PR_FALSE /* includeTrust (unused) */)); |
| |
| scoped_refptr<net::X509Certificate> policy_cert = net::ImportCertFromFile( |
| net::GetTestCertsDirectory(), "websocket_cacert.pem"); |
| ASSERT_TRUE(policy_cert.get()); |
| policy_certs_provider_.SetPolicyProvidedCertificates({policy_cert}, {}); |
| |
| WaitForRefresh(true /*tigger_for_refresh*/); |
| |
| { |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::CA_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* platform_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, platform_cert); |
| ASSERT_TRUE(platform_cert_info); |
| CertificateManagerModel::CertInfo* policy_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, policy_cert.get()); |
| ASSERT_TRUE(policy_cert_info); |
| |
| EXPECT_EQ(platform_cert_info, policy_cert_info); |
| |
| EXPECT_EQ(net::CertType::CA_CERT, policy_cert_info->type()); |
| EXPECT_EQ(u"pywebsocket", policy_cert_info->name()); |
| EXPECT_FALSE(policy_cert_info->can_be_deleted()); |
| EXPECT_FALSE(policy_cert_info->untrusted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPolicy, |
| policy_cert_info->source()); |
| EXPECT_TRUE(policy_cert_info->web_trust_anchor()); |
| EXPECT_FALSE(policy_cert_info->hardware_backed()); |
| } |
| |
| // Remove the cert from policy-provided certs again. The platform certificate |
| // should be visible afterwards. |
| policy_certs_provider_.SetPolicyProvidedCertificates({}, {}); |
| NotifyPolicyObserversAndWaitForRefresh(); |
| |
| { |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::CA_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* platform_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, platform_cert); |
| ASSERT_TRUE(platform_cert_info); |
| |
| EXPECT_EQ(net::CertType::CA_CERT, platform_cert_info->type()); |
| EXPECT_EQ(u"pywebsocket", platform_cert_info->name()); |
| EXPECT_TRUE(platform_cert_info->can_be_deleted()); |
| EXPECT_TRUE(platform_cert_info->untrusted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform, |
| platform_cert_info->source()); |
| EXPECT_FALSE(platform_cert_info->web_trust_anchor()); |
| EXPECT_FALSE(platform_cert_info->hardware_backed()); |
| } |
| } |
| |
| // CertificateManagerModel correctly lists CA certificates that are in the |
| // platform NSS database and provided by policy without web trust. The platform |
| // certificate hides the policy-provided certificate in this case. |
| TEST_F(CertificateManagerModelChromeOSTest, |
| PlatformCertsWinOverNotWebTrustedCerts) { |
| net::ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile( |
| net::GetTestCertsDirectory(), "websocket_cacert.pem", |
| net::X509Certificate::FORMAT_AUTO); |
| ASSERT_EQ(1U, certs.size()); |
| CERTCertificate* platform_cert = certs[0].get(); |
| ASSERT_EQ(SECSuccess, PK11_ImportCert(test_nssdb_.slot(), platform_cert, |
| CK_INVALID_HANDLE, "cert", |
| PR_FALSE /* includeTrust (unused) */)); |
| |
| scoped_refptr<net::X509Certificate> policy_cert = net::ImportCertFromFile( |
| net::GetTestCertsDirectory(), "websocket_cacert.pem"); |
| ASSERT_TRUE(policy_cert.get()); |
| policy_certs_provider_.SetPolicyProvidedCertificates({}, {policy_cert}); |
| |
| WaitForRefresh(true /*tigger_for_refresh*/); |
| |
| { |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::CA_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* platform_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, platform_cert); |
| ASSERT_TRUE(platform_cert_info); |
| CertificateManagerModel::CertInfo* policy_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, policy_cert.get()); |
| ASSERT_TRUE(policy_cert_info); |
| |
| EXPECT_EQ(platform_cert_info, policy_cert_info); |
| |
| EXPECT_EQ(net::CertType::CA_CERT, platform_cert_info->type()); |
| EXPECT_EQ(u"pywebsocket", platform_cert_info->name()); |
| EXPECT_TRUE(platform_cert_info->can_be_deleted()); |
| EXPECT_TRUE(platform_cert_info->untrusted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform, |
| platform_cert_info->source()); |
| EXPECT_FALSE(platform_cert_info->web_trust_anchor()); |
| EXPECT_FALSE(platform_cert_info->hardware_backed()); |
| } |
| |
| // Remove the certificate from the platform NSS database. The policy-provided |
| // certificate should be visible afterwards. |
| base::RunLoop run_loop; |
| fake_observer_->RunOnNextRefresh(run_loop.QuitClosure()); |
| certificate_manager_model_->Delete(platform_cert); |
| run_loop.Run(); |
| |
| { |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::CA_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* policy_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, policy_cert.get()); |
| ASSERT_TRUE(policy_cert_info); |
| |
| EXPECT_EQ(net::CertType::CA_CERT, policy_cert_info->type()); |
| EXPECT_EQ(u"pywebsocket", policy_cert_info->name()); |
| EXPECT_FALSE(policy_cert_info->can_be_deleted()); |
| EXPECT_FALSE(policy_cert_info->untrusted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPolicy, |
| policy_cert_info->source()); |
| EXPECT_FALSE(policy_cert_info->web_trust_anchor()); |
| EXPECT_FALSE(policy_cert_info->hardware_backed()); |
| } |
| } |
| |
| // When the Extension CertificateProvider hangs (e.g. because an extension is |
| // not responding), policy and platform certificates are still listed. |
| TEST_F(CertificateManagerModelChromeOSTest, |
| PlatformAndPolicyCertsListedWhenExtensionsHang) { |
| extensions_hang_ = true; |
| |
| net::ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile( |
| net::GetTestCertsDirectory(), "websocket_cacert.pem", |
| net::X509Certificate::FORMAT_AUTO); |
| ASSERT_EQ(1U, certs.size()); |
| CERTCertificate* platform_cert = certs[0].get(); |
| ASSERT_EQ(SECSuccess, PK11_ImportCert(test_nssdb_.slot(), platform_cert, |
| CK_INVALID_HANDLE, "cert", |
| PR_FALSE /* includeTrust (unused) */)); |
| |
| scoped_refptr<net::X509Certificate> policy_cert = |
| net::ImportCertFromFile(net::GetTestCertsDirectory(), "root_ca_cert.pem"); |
| ASSERT_TRUE(policy_cert.get()); |
| policy_certs_provider_.SetPolicyProvidedCertificates({policy_cert}, {}); |
| |
| WaitForRefresh(true /*tigger_for_refresh*/); |
| |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::CA_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* platform_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, platform_cert); |
| ASSERT_TRUE(platform_cert_info); |
| CertificateManagerModel::CertInfo* policy_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, policy_cert.get()); |
| ASSERT_TRUE(policy_cert_info); |
| |
| EXPECT_NE(platform_cert_info, policy_cert_info); |
| } |
| |
| // CertificateManagerModel lists client certificates provided by extensions. |
| TEST_F(CertificateManagerModelChromeOSTest, ListsExtensionCerts) { |
| scoped_refptr<net::X509Certificate> extension_cert = |
| net::ImportCertFromFile(net::GetTestCertsDirectory(), "client_1.pem"); |
| ASSERT_TRUE(extension_cert.get()); |
| extension_client_certs_.push_back(extension_cert); |
| |
| WaitForRefresh(true /*tigger_for_refresh*/); |
| |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::USER_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* extension_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, extension_cert.get()); |
| ASSERT_TRUE(extension_cert_info); |
| |
| EXPECT_EQ(net::CertType::USER_CERT, extension_cert_info->type()); |
| EXPECT_EQ(u"Client Cert A (extension provided)", extension_cert_info->name()); |
| EXPECT_FALSE(extension_cert_info->can_be_deleted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kExtension, |
| extension_cert_info->source()); |
| EXPECT_FALSE(extension_cert_info->web_trust_anchor()); |
| EXPECT_FALSE(extension_cert_info->hardware_backed()); |
| } |
| |
| TEST_F(CertificateManagerModelChromeOSTest, |
| PlatformCertsWinOverExtensionCerts) { |
| net::ScopedCERTCertificate platform_client_cert; |
| net::ImportClientCertAndKeyFromFile( |
| net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8", |
| test_nssdb_.slot(), &platform_client_cert); |
| |
| scoped_refptr<net::X509Certificate> extension_cert = |
| net::ImportCertFromFile(net::GetTestCertsDirectory(), "client_1.pem"); |
| ASSERT_TRUE(extension_cert.get()); |
| extension_client_certs_.push_back(extension_cert); |
| |
| WaitForRefresh(true /*tigger_for_refresh*/); |
| |
| { |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::USER_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* platform_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, |
| platform_client_cert.get()); |
| ASSERT_TRUE(platform_cert_info); |
| CertificateManagerModel::CertInfo* extension_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, extension_cert.get()); |
| ASSERT_TRUE(extension_cert_info); |
| |
| EXPECT_EQ(platform_cert_info, extension_cert_info); |
| |
| EXPECT_EQ(net::CertType::USER_CERT, platform_cert_info->type()); |
| EXPECT_EQ(u"Client Cert A", platform_cert_info->name()); |
| EXPECT_TRUE(platform_cert_info->can_be_deleted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kPlatform, |
| platform_cert_info->source()); |
| EXPECT_FALSE(platform_cert_info->web_trust_anchor()); |
| EXPECT_FALSE(platform_cert_info->hardware_backed()); |
| } |
| |
| // Remove the platform client certificate. The extension-provided client |
| // certificate should be visible afterwards. |
| base::RunLoop run_loop; |
| fake_observer_->RunOnNextRefresh(run_loop.QuitClosure()); |
| certificate_manager_model_->Delete(platform_client_cert.get()); |
| run_loop.Run(); |
| |
| { |
| CertificateManagerModel::OrgGroupingMap org_grouping_map; |
| certificate_manager_model_->FilterAndBuildOrgGroupingMap( |
| net::CertType::USER_CERT, &org_grouping_map); |
| CertificateManagerModel::CertInfo* extension_cert_info = |
| GetCertInfoFromOrgGroupingMap(org_grouping_map, extension_cert.get()); |
| ASSERT_TRUE(extension_cert_info); |
| |
| EXPECT_EQ(net::CertType::USER_CERT, extension_cert_info->type()); |
| EXPECT_EQ(u"Client Cert A (extension provided)", |
| extension_cert_info->name()); |
| EXPECT_FALSE(extension_cert_info->can_be_deleted()); |
| EXPECT_EQ(CertificateManagerModel::CertInfo::Source::kExtension, |
| extension_cert_info->source()); |
| EXPECT_FALSE(extension_cert_info->web_trust_anchor()); |
| EXPECT_FALSE(extension_cert_info->hardware_backed()); |
| } |
| } |
| |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |