blob: b5e7af2baee115797a98e2c6aa75d5c210608818 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/cert/internal/system_trust_store.h"
#include <memory>
#include <optional>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "crypto/crypto_buildflags.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#include "third_party/boringssl/src/pki/cert_errors.h"
#include "third_party/boringssl/src/pki/parsed_certificate.h"
#include "third_party/boringssl/src/pki/trust_store_collection.h"
#include "third_party/boringssl/src/pki/trust_store_in_memory.h"
#if BUILDFLAG(USE_NSS_CERTS)
#include "net/cert/internal/trust_store_nss.h"
#elif BUILDFLAG(IS_MAC)
#include <Security/Security.h>
#include "net/base/features.h"
#include "net/cert/internal/trust_store_mac.h"
#include "net/cert/x509_util_apple.h"
#elif BUILDFLAG(IS_FUCHSIA)
#include "third_party/boringssl/src/include/openssl/pool.h"
#elif BUILDFLAG(IS_WIN)
#include "net/cert/internal/trust_store_win.h"
#elif BUILDFLAG(IS_ANDROID)
#include "net/cert/internal/trust_store_android.h"
#endif
#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
#include "net/cert/internal/trust_store_chrome.h"
#endif // CHROME_ROOT_STORE_SUPPORTED
#if BUILDFLAG(IS_CHROMEOS)
#include "base/system/sys_info.h"
#endif
namespace net {
#if BUILDFLAG(IS_CHROMEOS)
namespace internal {
class PemFileCertStore {
public:
explicit PemFileCertStore(std::string_view file_name) {
// This will block on the cert verifier service thread, so the effect will
// just be to block any cert verifications (interactions with the cert
// verifier service are async mojo calls, so it shouldn't block the browser
// UI). There would be no benefit to moving this to a worker thread, since
// all cert verifications would still need to block on loading of the roots
// to complete.
base::ScopedAllowBlocking allow_blocking;
std::optional<std::vector<uint8_t>> certs_file =
base::ReadFileToBytes(base::FilePath(file_name));
if (!certs_file) {
return;
}
trust_store_ = std::make_unique<bssl::TrustStoreInMemory>();
CertificateList certs = X509Certificate::CreateCertificateListFromBytes(
*certs_file, X509Certificate::FORMAT_AUTO);
for (const auto& cert : certs) {
bssl::CertErrors errors;
auto parsed = bssl::ParsedCertificate::Create(
bssl::UpRef(cert->cert_buffer()),
x509_util::DefaultParseCertificateOptions(), &errors);
if (!parsed) {
LOG(ERROR) << file_name << ": " << errors.ToDebugString();
continue;
}
trust_store_->AddTrustAnchor(std::move(parsed));
}
}
bssl::TrustStoreInMemory* trust_store() { return trust_store_.get(); }
private:
std::unique_ptr<bssl::TrustStoreInMemory> trust_store_;
};
} // namespace internal
namespace {
// On ChromeOS look for a PEM file of root CA certs to trust which may be
// present on test images.
bssl::TrustStoreInMemory* GetChromeOSTestTrustStore() {
constexpr char kCrosTestRootCertsFile[] = "/etc/fake_root_ca_certs.pem";
static base::NoDestructor<internal::PemFileCertStore> cros_test_roots{
kCrosTestRootCertsFile};
return cros_test_roots->trust_store();
}
} // namespace
#endif
#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
class SystemTrustStoreChromeWithUnOwnedSystemStore : public SystemTrustStore {
public:
// Creates a SystemTrustStore that gets publicly trusted roots from
// |trust_store_chrome| and local trust settings from |trust_store_system|,
// if non-null. Does not take ownership of |trust_store_system|, which must
// outlive this object.
explicit SystemTrustStoreChromeWithUnOwnedSystemStore(
std::unique_ptr<TrustStoreChrome> trust_store_chrome,
net::PlatformTrustStore* trust_store_system)
: trust_store_chrome_(std::move(trust_store_chrome)),
platform_trust_store_(trust_store_system) {
#if BUILDFLAG(IS_CHROMEOS)
if (GetChromeOSTestTrustStore()) {
// The fake_root_ca_certs.pem file is only intended for testing purposes,
// crash if it is present on a ChromeOS device in a non-test image.
base::SysInfo::CrashIfChromeOSNonTestImage();
trust_store_collection_.AddTrustStore(GetChromeOSTestTrustStore());
non_crs_trust_store_collection_.AddTrustStore(
GetChromeOSTestTrustStore());
}
#endif
if (trust_store_system) {
trust_store_collection_.AddTrustStore(trust_store_system);
non_crs_trust_store_collection_.AddTrustStore(trust_store_system);
}
trust_store_collection_.AddTrustStore(trust_store_chrome_.get());
}
bssl::TrustStore* GetTrustStore() override {
return &trust_store_collection_;
}
// IsKnownRoot returns true if the given trust anchor is a standard one (as
// opposed to a user-installed root)
bool IsKnownRoot(const bssl::ParsedCertificate* trust_anchor) const override {
return trust_store_chrome_->Contains(trust_anchor);
}
bool IsLocallyTrustedRoot(
const bssl::ParsedCertificate* trust_anchor) override {
return non_crs_trust_store_collection_.GetTrust(trust_anchor)
.IsTrustAnchor();
}
int64_t chrome_root_store_version() const override {
return trust_store_chrome_->version();
}
base::span<const ChromeRootCertConstraints> GetChromeRootConstraints(
const bssl::ParsedCertificate* cert) const override {
return trust_store_chrome_->GetConstraintsForCert(cert);
}
bssl::TrustStore* eutl_trust_store() override {
return trust_store_chrome_->eutl_trust_store();
}
net::PlatformTrustStore* GetPlatformTrustStore() override {
return platform_trust_store_;
}
private:
std::unique_ptr<TrustStoreChrome> trust_store_chrome_;
bssl::TrustStoreCollection trust_store_collection_;
bssl::TrustStoreCollection non_crs_trust_store_collection_;
net::PlatformTrustStore* platform_trust_store_;
};
std::unique_ptr<SystemTrustStore> CreateChromeOnlySystemTrustStore(
std::unique_ptr<TrustStoreChrome> chrome_root) {
return std::make_unique<SystemTrustStoreChromeWithUnOwnedSystemStore>(
std::move(chrome_root), /*trust_store_system=*/nullptr);
}
class SystemTrustStoreChrome
: public SystemTrustStoreChromeWithUnOwnedSystemStore {
public:
// Creates a SystemTrustStore that gets publicly trusted roots from
// |trust_store_chrome| and local trust settings from |trust_store_system|.
explicit SystemTrustStoreChrome(
std::unique_ptr<TrustStoreChrome> trust_store_chrome,
std::unique_ptr<net::PlatformTrustStore> trust_store_system)
: SystemTrustStoreChromeWithUnOwnedSystemStore(
std::move(trust_store_chrome),
trust_store_system.get()),
trust_store_system_(std::move(trust_store_system)) {}
private:
std::unique_ptr<net::PlatformTrustStore> trust_store_system_;
};
std::unique_ptr<SystemTrustStore> CreateSystemTrustStoreChromeForTesting(
std::unique_ptr<TrustStoreChrome> trust_store_chrome,
std::unique_ptr<net::PlatformTrustStore> trust_store_system) {
return std::make_unique<SystemTrustStoreChrome>(
std::move(trust_store_chrome), std::move(trust_store_system));
}
#endif // CHROME_ROOT_STORE_SUPPORTED
#if BUILDFLAG(USE_NSS_CERTS)
std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStoreChromeRoot(
std::unique_ptr<TrustStoreChrome> chrome_root) {
return std::make_unique<SystemTrustStoreChrome>(
std::move(chrome_root), std::make_unique<TrustStoreNSS>(
TrustStoreNSS::UseTrustFromAllUserSlots()));
}
#elif BUILDFLAG(IS_MAC)
namespace {
TrustStoreMac* GetGlobalTrustStoreMacForCRS() {
constexpr TrustStoreMac::TrustImplType kDefaultMacTrustImplForCRS =
TrustStoreMac::TrustImplType::kDomainCacheFullCerts;
static base::NoDestructor<TrustStoreMac> static_trust_store_mac(
kSecPolicyAppleSSL, kDefaultMacTrustImplForCRS);
return static_trust_store_mac.get();
}
void InitializeTrustCacheForCRSOnWorkerThread() {
GetGlobalTrustStoreMacForCRS()->InitializeTrustCache();
}
} // namespace
std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStoreChromeRoot(
std::unique_ptr<TrustStoreChrome> chrome_root) {
return std::make_unique<SystemTrustStoreChromeWithUnOwnedSystemStore>(
std::move(chrome_root), GetGlobalTrustStoreMacForCRS());
}
void InitializeTrustStoreMacCache() {
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(&InitializeTrustCacheForCRSOnWorkerThread));
}
#elif BUILDFLAG(IS_FUCHSIA)
namespace {
constexpr char kRootCertsFileFuchsia[] = "/config/ssl/cert.pem";
class FuchsiaSystemCerts {
public:
FuchsiaSystemCerts() {
base::FilePath filename(kRootCertsFileFuchsia);
std::string certs_file;
if (!base::ReadFileToString(filename, &certs_file)) {
LOG(ERROR) << "Can't load root certificates from " << filename;
return;
}
CertificateList certs = X509Certificate::CreateCertificateListFromBytes(
base::as_byte_span(certs_file), X509Certificate::FORMAT_AUTO);
for (const auto& cert : certs) {
bssl::CertErrors errors;
auto parsed = bssl::ParsedCertificate::Create(
bssl::UpRef(cert->cert_buffer()),
x509_util::DefaultParseCertificateOptions(), &errors);
CHECK(parsed) << errors.ToDebugString();
system_trust_store_.AddTrustAnchor(std::move(parsed));
}
}
bssl::TrustStoreInMemory* system_trust_store() {
return &system_trust_store_;
}
private:
bssl::TrustStoreInMemory system_trust_store_;
};
FuchsiaSystemCerts& GetFuchsiaRootCerts() {
static base::NoDestructor<FuchsiaSystemCerts> certs;
return *certs;
}
} // namespace
class SystemTrustStoreFuchsia : public SystemTrustStore {
public:
SystemTrustStoreFuchsia() = default;
bssl::TrustStore* GetTrustStore() override {
return GetFuchsiaRootCerts().system_trust_store();
}
bool IsKnownRoot(const bssl::ParsedCertificate* trust_anchor) const override {
return GetFuchsiaRootCerts().system_trust_store()->Contains(trust_anchor);
}
};
std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() {
return std::make_unique<SystemTrustStoreFuchsia>();
}
#elif BUILDFLAG(IS_WIN)
namespace {
TrustStoreWin* GetGlobalTrustStoreWinForCRS() {
static base::NoDestructor<TrustStoreWin> static_trust_store_win;
return static_trust_store_win.get();
}
void InitializeTrustStoreForCRSOnWorkerThread() {
GetGlobalTrustStoreWinForCRS()->InitializeStores();
}
} // namespace
std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStoreChromeRoot(
std::unique_ptr<TrustStoreChrome> chrome_root) {
return std::make_unique<SystemTrustStoreChromeWithUnOwnedSystemStore>(
std::move(chrome_root), GetGlobalTrustStoreWinForCRS());
}
// We do this in a separate thread as loading the Windows Cert Stores can cause
// quite a bit of I/O. See crbug.com/1399974 for more context.
void InitializeTrustStoreWinSystem() {
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(&InitializeTrustStoreForCRSOnWorkerThread));
}
#elif BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
namespace {
TrustStoreAndroid* GetGlobalTrustStoreAndroidForCRS() {
static base::NoDestructor<TrustStoreAndroid> static_trust_store_android;
return static_trust_store_android.get();
}
void InitializeTrustStoreForCRSOnWorkerThread() {
GetGlobalTrustStoreAndroidForCRS()->Initialize();
}
} // namespace
std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStoreChromeRoot(
std::unique_ptr<TrustStoreChrome> chrome_root) {
return std::make_unique<SystemTrustStoreChromeWithUnOwnedSystemStore>(
std::move(chrome_root), GetGlobalTrustStoreAndroidForCRS());
}
void InitializeTrustStoreAndroid() {
// Start observing DB change before the Trust Store is initialized so we don't
// accidentally miss any changes. See https://crrev.com/c/4226436 for context.
//
// This call is safe here because we're the only callers of
// ObserveCertDBChanges on the singleton TrustStoreAndroid.
GetGlobalTrustStoreAndroidForCRS()->ObserveCertDBChanges();
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(&InitializeTrustStoreForCRSOnWorkerThread));
}
#else
void InitializeTrustStoreAndroid() {}
#endif // CHROME_ROOT_STORE_SUPPORTED
#endif
} // namespace net