| // 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 "base/memory/ptr_util.h" |
| #include "build/build_config.h" |
| #include "crypto/crypto_buildflags.h" |
| |
| #if BUILDFLAG(USE_NSS_CERTS) |
| #include "net/cert/internal/system_trust_store_nss.h" |
| #endif // BUILDFLAG(USE_NSS_CERTS) |
| |
| #if BUILDFLAG(USE_NSS_CERTS) |
| #include <cert.h> |
| #include <pk11pub.h> |
| #elif BUILDFLAG(IS_MAC) |
| #include <Security/Security.h> |
| #endif |
| |
| #include <memory> |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "base/no_destructor.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "build/build_config.h" |
| #include "net/cert/pki/cert_errors.h" |
| #include "net/cert/pki/parsed_certificate.h" |
| #include "net/cert/pki/trust_store_collection.h" |
| #include "net/cert/pki/trust_store_in_memory.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/cert/x509_util.h" |
| |
| #if BUILDFLAG(USE_NSS_CERTS) |
| #include "crypto/nss_util.h" |
| #include "net/cert/internal/trust_store_nss.h" |
| #include "net/cert/known_roots_nss.h" |
| #include "net/cert/scoped_nss_types.h" |
| #elif BUILDFLAG(IS_MAC) |
| #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 "base/lazy_instance.h" |
| #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" |
| #elif defined(STARBOARD) |
| #include "base/lazy_instance.h" |
| #include "net/cert/internal/trust_store_in_memory_starboard.h" |
| #include "net/cert/test_root_certs.h" |
| #endif |
| #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) |
| #include "net/cert/internal/trust_store_chrome.h" |
| #endif // CHROME_ROOT_STORE_SUPPORTED |
| |
| namespace net { |
| |
| namespace { |
| |
| class DummySystemTrustStore : public SystemTrustStore { |
| public: |
| TrustStore* GetTrustStore() override { return &trust_store_; } |
| |
| bool UsesSystemTrustStore() const override { return false; } |
| |
| bool IsKnownRoot(const ParsedCertificate* trust_anchor) const override { |
| return false; |
| } |
| |
| #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) |
| int64_t chrome_root_store_version() override { return 0; } |
| #endif |
| |
| private: |
| TrustStoreCollection trust_store_; |
| }; |
| |
| } // namespace |
| |
| #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|. |
| // Does not take ownership of |trust_store_system|, which must outlive this |
| // object. |
| explicit SystemTrustStoreChromeWithUnOwnedSystemStore( |
| std::unique_ptr<TrustStoreChrome> trust_store_chrome, |
| TrustStore* trust_store_system) |
| : trust_store_chrome_(std::move(trust_store_chrome)) { |
| trust_store_collection_.AddTrustStore(trust_store_system); |
| trust_store_collection_.AddTrustStore(trust_store_chrome_.get()); |
| } |
| |
| TrustStore* GetTrustStore() override { return &trust_store_collection_; } |
| |
| bool UsesSystemTrustStore() const override { return true; } |
| |
| // IsKnownRoot returns true if the given trust anchor is a standard one (as |
| // opposed to a user-installed root) |
| bool IsKnownRoot(const ParsedCertificate* trust_anchor) const override { |
| return trust_store_chrome_->Contains(trust_anchor); |
| } |
| |
| int64_t chrome_root_store_version() override { |
| return trust_store_chrome_->version(); |
| } |
| |
| private: |
| std::unique_ptr<TrustStoreChrome> trust_store_chrome_; |
| TrustStoreCollection trust_store_collection_; |
| }; |
| |
| 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<TrustStore> 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<TrustStore> trust_store_system_; |
| }; |
| |
| std::unique_ptr<SystemTrustStore> CreateSystemTrustStoreChromeForTesting( |
| std::unique_ptr<TrustStoreChrome> trust_store_chrome, |
| std::unique_ptr<TrustStore> 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) |
| namespace { |
| |
| class SystemTrustStoreNSS : public SystemTrustStore { |
| public: |
| explicit SystemTrustStoreNSS(std::unique_ptr<TrustStoreNSS> trust_store_nss) |
| : trust_store_nss_(std::move(trust_store_nss)) {} |
| |
| TrustStore* GetTrustStore() override { return trust_store_nss_.get(); } |
| |
| bool UsesSystemTrustStore() const override { return true; } |
| |
| // IsKnownRoot returns true if the given trust anchor is a standard one (as |
| // opposed to a user-installed root) |
| bool IsKnownRoot(const ParsedCertificate* trust_anchor) const override { |
| // TODO(eroman): The overall approach of IsKnownRoot() is inefficient -- it |
| // requires searching for the trust anchor by DER in NSS, however path |
| // building already had a handle to it. |
| SECItem der_cert; |
| der_cert.data = const_cast<uint8_t*>(trust_anchor->der_cert().UnsafeData()); |
| der_cert.len = trust_anchor->der_cert().Length(); |
| der_cert.type = siDERCertBuffer; |
| ScopedCERTCertificate nss_cert( |
| CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), &der_cert)); |
| if (!nss_cert) |
| return false; |
| |
| if (!net::IsKnownRoot(nss_cert.get())) |
| return false; |
| |
| return trust_anchor->der_cert() == |
| der::Input(nss_cert->derCert.data, nss_cert->derCert.len); |
| } |
| |
| #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) |
| int64_t chrome_root_store_version() override { return 0; } |
| #endif |
| |
| private: |
| std::unique_ptr<TrustStoreNSS> trust_store_nss_; |
| }; |
| |
| } // namespace |
| |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<SystemTrustStoreNSS>(std::make_unique<TrustStoreNSS>( |
| TrustStoreNSS::kUseSystemTrust, |
| TrustStoreNSS::UseTrustFromAllUserSlots())); |
| } |
| |
| #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) |
| 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::kIgnoreSystemTrust, |
| TrustStoreNSS::UseTrustFromAllUserSlots())); |
| } |
| |
| std::unique_ptr<SystemTrustStore> |
| CreateSslSystemTrustStoreChromeRootWithUserSlotRestriction( |
| std::unique_ptr<TrustStoreChrome> chrome_root, |
| crypto::ScopedPK11Slot user_slot_restriction) { |
| return std::make_unique<SystemTrustStoreChrome>( |
| std::move(chrome_root), |
| std::make_unique<TrustStoreNSS>(TrustStoreNSS::kIgnoreSystemTrust, |
| std::move(user_slot_restriction))); |
| } |
| |
| #endif // CHROME_ROOT_STORE_SUPPORTED |
| |
| std::unique_ptr<SystemTrustStore> |
| CreateSslSystemTrustStoreNSSWithUserSlotRestriction( |
| crypto::ScopedPK11Slot user_slot_restriction) { |
| return std::make_unique<SystemTrustStoreNSS>(std::make_unique<TrustStoreNSS>( |
| TrustStoreNSS::kUseSystemTrust, std::move(user_slot_restriction))); |
| } |
| |
| #elif BUILDFLAG(IS_MAC) |
| |
| // Using the Builtin Verifier w/o the Chrome Root Store is unsupported on |
| // Mac. |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<DummySystemTrustStore>(); |
| } |
| |
| 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_bytes(base::make_span(certs_file)), |
| X509Certificate::FORMAT_AUTO); |
| |
| for (const auto& cert : certs) { |
| CertErrors errors; |
| auto parsed = ParsedCertificate::Create( |
| bssl::UpRef(cert->cert_buffer()), |
| x509_util::DefaultParseCertificateOptions(), &errors); |
| CHECK(parsed) << errors.ToDebugString(); |
| system_trust_store_.AddTrustAnchor(parsed); |
| } |
| } |
| |
| TrustStoreInMemory* system_trust_store() { return &system_trust_store_; } |
| |
| private: |
| TrustStoreInMemory system_trust_store_; |
| }; |
| |
| base::LazyInstance<FuchsiaSystemCerts>::Leaky g_root_certs_fuchsia = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| } // namespace |
| |
| class SystemTrustStoreFuchsia : public SystemTrustStore { |
| public: |
| SystemTrustStoreFuchsia() = default; |
| |
| TrustStore* GetTrustStore() override { |
| return g_root_certs_fuchsia.Get().system_trust_store(); |
| } |
| |
| bool UsesSystemTrustStore() const override { return true; } |
| |
| bool IsKnownRoot(const ParsedCertificate* trust_anchor) const override { |
| return g_root_certs_fuchsia.Get().system_trust_store()->Contains( |
| trust_anchor); |
| } |
| }; |
| |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<SystemTrustStoreFuchsia>(); |
| } |
| |
| #elif BUILDFLAG(IS_WIN) |
| |
| // Using the Builtin Verifier w/o the Chrome Root Store is unsupported on |
| // Windows. |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<DummySystemTrustStore>(); |
| } |
| |
| 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) |
| |
| // Using the Builtin Verifier w/o the Chrome Root Store is unsupported on |
| // Android. |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<DummySystemTrustStore>(); |
| } |
| |
| #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 |
| |
| #elif defined(STARBOARD) |
| |
| namespace { |
| |
| class StarboardSystemCerts { |
| public: |
| StarboardSystemCerts() {} |
| |
| TrustStoreInMemoryStarboard* system_trust_store() { |
| return &system_trust_store_; |
| } |
| |
| private: |
| TrustStoreInMemoryStarboard system_trust_store_; |
| }; |
| |
| base::LazyInstance<StarboardSystemCerts>::Leaky g_root_certs_starboard = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| } // namespace |
| |
| // Starboard does not use OS certificate stores, instead Cobalt ships with a |
| // set of trusted CA certificates to be used for validations. |
| class SystemTrustStoreStarboard : public SystemTrustStore { |
| public: |
| SystemTrustStoreStarboard() = default; |
| |
| TrustStore* GetTrustStore() override { |
| if (TestRootCerts::HasInstance()) { |
| return TestRootCerts::GetInstance()->test_trust_store(); |
| } |
| return g_root_certs_starboard.Get().system_trust_store(); |
| } |
| |
| bool UsesSystemTrustStore() const override { return true; } |
| |
| bool IsKnownRoot(const ParsedCertificate* trust_anchor) const override { |
| return g_root_certs_starboard.Get().system_trust_store()->Contains( |
| trust_anchor); |
| } |
| }; |
| |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<SystemTrustStoreStarboard>(); |
| } |
| |
| #else |
| |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<DummySystemTrustStore>(); |
| } |
| |
| #endif |
| |
| std::unique_ptr<SystemTrustStore> CreateEmptySystemTrustStore() { |
| return std::make_unique<DummySystemTrustStore>(); |
| } |
| |
| } // namespace net |