| // Copyright 2017 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/internal/system_trust_store.h" |
| |
| #if defined(USE_NSS_CERTS) |
| #include <cert.h> |
| #include <pk11pub.h> |
| #elif defined(OS_MACOSX) && !defined(OS_IOS) |
| #include <Security/Security.h> |
| #endif |
| |
| #include <memory> |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "build/build_config.h" |
| #include "net/cert/internal/cert_errors.h" |
| #include "net/cert/internal/parsed_certificate.h" |
| #include "net/cert/internal/trust_store_collection.h" |
| #include "net/cert/internal/trust_store_in_memory.h" |
| #include "net/cert/test_root_certs.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/cert/x509_util.h" |
| #include "starboard/types.h" |
| |
| #if defined(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 defined(OS_MACOSX) && !defined(OS_IOS) |
| #include "net/cert/internal/trust_store_mac.h" |
| #include "net/cert/known_roots_mac.h" |
| #include "net/cert/x509_util_mac.h" |
| #elif defined(OS_FUCHSIA) |
| #include "third_party/boringssl/src/include/openssl/pool.h" |
| #elif defined(STARBOARD) |
| #include "net/cert/internal/trust_store_in_memory_starboard.h" |
| #endif |
| |
| namespace net { |
| |
| namespace { |
| |
| // Abstract implementation of SystemTrustStore to be used as a base class. |
| // Handles the addition of additional trust anchors. |
| class BaseSystemTrustStore : public SystemTrustStore { |
| public: |
| BaseSystemTrustStore() { |
| trust_store_.AddTrustStore(&additional_trust_store_); |
| } |
| |
| void AddTrustAnchor( |
| const scoped_refptr<ParsedCertificate>& trust_anchor) override { |
| additional_trust_store_.AddTrustAnchor(trust_anchor); |
| } |
| |
| TrustStore* GetTrustStore() override { return &trust_store_; } |
| |
| bool IsAdditionalTrustAnchor( |
| const ParsedCertificate* trust_anchor) const override { |
| return additional_trust_store_.Contains(trust_anchor); |
| } |
| |
| protected: |
| TrustStoreCollection trust_store_; |
| TrustStoreInMemory additional_trust_store_; |
| }; |
| |
| } // namespace |
| |
| #if defined(USE_NSS_CERTS) |
| namespace { |
| |
| class SystemTrustStoreNSS : public BaseSystemTrustStore { |
| public: |
| explicit SystemTrustStoreNSS() : trust_store_nss_(trustSSL) { |
| trust_store_.AddTrustStore(&trust_store_nss_); |
| } |
| |
| 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); |
| } |
| |
| private: |
| TrustStoreNSS trust_store_nss_; |
| }; |
| |
| } // namespace |
| |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<SystemTrustStoreNSS>(); |
| } |
| |
| #elif defined(OS_MACOSX) && !defined(OS_IOS) |
| |
| class SystemTrustStoreMac : public BaseSystemTrustStore { |
| public: |
| explicit SystemTrustStoreMac() : trust_store_mac_(kSecPolicyAppleSSL) { |
| InitializeKnownRoots(); |
| trust_store_.AddTrustStore(&trust_store_mac_); |
| |
| // When running in test mode, also layer in the test-only root certificates. |
| // |
| // Note that this integration requires TestRootCerts::HasInstance() to be |
| // true by the time SystemTrustStoreMac is created - a limitation which is |
| // acceptable for the test-only code that consumes this. |
| if (TestRootCerts::HasInstance()) { |
| trust_store_.AddTrustStore( |
| TestRootCerts::GetInstance()->test_trust_store()); |
| } |
| } |
| |
| 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 { |
| der::Input bytes = trust_anchor->der_cert(); |
| base::ScopedCFTypeRef<SecCertificateRef> cert_ref = |
| x509_util::CreateSecCertificateFromBytes(bytes.UnsafeData(), |
| bytes.Length()); |
| if (!cert_ref) |
| return false; |
| |
| return net::IsKnownRoot(cert_ref); |
| } |
| |
| private: |
| TrustStoreMac trust_store_mac_; |
| }; |
| |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<SystemTrustStoreMac>(); |
| } |
| |
| #elif defined(OS_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( |
| certs_file.data(), certs_file.length(), 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 BaseSystemTrustStore { |
| public: |
| SystemTrustStoreFuchsia() { |
| trust_store_.AddTrustStore(g_root_certs_fuchsia.Get().system_trust_store()); |
| if (TestRootCerts::HasInstance()) { |
| trust_store_.AddTrustStore( |
| TestRootCerts::GetInstance()->test_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 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 system certificate stores but Cobalt ships with a |
| // set of trusted CA certificates that can be used for validations. |
| class SystemTrustStoreStarboard : public BaseSystemTrustStore { |
| public: |
| SystemTrustStoreStarboard() { |
| trust_store_.AddTrustStore( |
| g_root_certs_starboard.Get().system_trust_store()); |
| if (TestRootCerts::HasInstance()) { |
| trust_store_.AddTrustStore( |
| TestRootCerts::GetInstance()->test_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 |
| |
| class DummySystemTrustStore : public BaseSystemTrustStore { |
| public: |
| bool UsesSystemTrustStore() const override { return false; } |
| |
| bool IsKnownRoot(const ParsedCertificate* trust_anchor) const override { |
| return false; |
| } |
| }; |
| |
| std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStore() { |
| return std::make_unique<DummySystemTrustStore>(); |
| } |
| |
| #endif |
| |
| } // namespace net |