diff --git a/src/net/cert/internal/system_trust_store.cc b/src/net/cert/internal/system_trust_store.cc index 9a344eaf0d..629c38ea78 100644 --- a/src/net/cert/internal/system_trust_store.cc +++ b/src/net/cert/internal/system_trust_store.cc @@ -4,15 +4,19 @@ #include "net/cert/internal/system_trust_store.h" +#include #include #include #include +#include "base/environment.h" +#include "base/files/file_enumerator.h" #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/strings/string_split.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "base/threading/thread_restrictions.h" @@ -39,8 +43,8 @@ #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 BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) +#include "base/lazy_instance.h" #endif #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) @@ -317,6 +321,147 @@ std::unique_ptr CreateSslSystemTrustStore() { return std::make_unique(); } +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) + +namespace { + +// Copied from https://golang.org/src/crypto/x509/root_linux.go +// Possible certificate files; stop after finding one. +constexpr std::array kStaticRootCertFiles = { + "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. + "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6 + "/etc/ssl/ca-bundle.pem", // OpenSUSE + "/etc/pki/tls/cacert.pem", // OpenELEC + "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7 + "/etc/ssl/cert.pem", // Alpine Linux +}; + +// Possible directories with certificate files; stop after successfully +// reading at least one file from a directory. +constexpr std::array kStaticRootCertDirs = { + "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139 + "/etc/pki/tls/certs", // Fedora/RHEL + "/system/etc/security/cacerts", // Android +}; + +// The environment variable which identifies where to locate the SSL +// certificate file. If set this overrides the system default. +constexpr char kStaticCertFileEnv[] = "SSL_CERT_FILE"; + +// The environment variable which identifies which directory to check for SSL +// certificate files. If set this overrides the system default. It is a colon +// separated list of directories. +// See https://www.openssl.org/docs/man1.0.2/man1/c_rehash.html. +constexpr char kStaticCertDirsEnv[] = "SSL_CERT_DIR"; + +class TrustStoreUnix : public PlatformTrustStore { + public: + TrustStoreUnix() { + auto env = base::Environment::Create(); + std::string env_value; + + std::vector cert_filenames(kStaticRootCertFiles.begin(), + kStaticRootCertFiles.end()); + if (env->GetVar(kStaticCertFileEnv, &env_value) && !env_value.empty()) { + cert_filenames = {env_value}; + } + + bool cert_file_ok = false; + for (const auto& filename : cert_filenames) { + std::string file; + if (!base::ReadFileToString(base::FilePath(filename), &file)) + continue; + if (AddCertificatesFromBytes(file, trust_store_)) { + cert_file_ok = true; + break; + } + } + + std::vector cert_dirnames(kStaticRootCertDirs.begin(), + kStaticRootCertDirs.end()); + if (env->GetVar(kStaticCertDirsEnv, &env_value) && !env_value.empty()) { + cert_dirnames = base::SplitString(env_value, ":", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + } + + bool cert_dir_ok = false; + for (const auto& dir : cert_dirnames) { + base::FileEnumerator e(base::FilePath(dir), + /*recursive=*/true, base::FileEnumerator::FILES); + for (auto filename = e.Next(); !filename.empty(); filename = e.Next()) { + std::string file; + if (!base::ReadFileToString(filename, &file)) { + continue; + } + if (AddCertificatesFromBytes(file, trust_store_)) { + cert_dir_ok = true; + } + } + if (cert_dir_ok) + break; + } + + if (!cert_file_ok && !cert_dir_ok) { + LOG(ERROR) << "No CA certificates were found. Try using environment " + "variable SSL_CERT_FILE or SSL_CERT_DIR"; + } + } + + TrustStoreUnix(const TrustStoreUnix&) = delete; + TrustStoreUnix& operator=(const TrustStoreUnix&) = delete; + + // bssl::CertIssuerSource implementation: + void SyncGetIssuersOf(const bssl::ParsedCertificate* cert, + bssl::ParsedCertificateList* issuers) override { + trust_store_.SyncGetIssuersOf(cert, issuers); + } + + // bssl::TrustStore implementation: + bssl::CertificateTrust GetTrust( + const bssl::ParsedCertificate* cert) override { + return trust_store_.GetTrust(cert); + } + + // net::PlatformTrustStore implementation: + std::vector GetAllUserAddedCerts() + override { + return {}; + } + + private: + static bool AddCertificatesFromBytes(std::string_view data, + bssl::TrustStoreInMemory& store) { + auto certs = X509Certificate::CreateCertificateListFromBytes( + base::as_bytes(base::make_span(data)), X509Certificate::FORMAT_AUTO); + bool certs_ok = false; + for (const auto& cert : certs) { + bssl::CertErrors errors; + auto parsed = bssl::ParsedCertificate::Create( + bssl::UpRef(cert->cert_buffer()), + x509_util::DefaultParseCertificateOptions(), &errors); + if (parsed) { + if (!store.Contains(parsed.get())) { + store.AddTrustAnchor(parsed); + } + certs_ok = true; + } else { + LOG(ERROR) << errors.ToDebugString(); + } + } + return certs_ok; + } + + bssl::TrustStoreInMemory trust_store_; +}; + +} // namespace + +std::unique_ptr CreateSslSystemTrustStoreChromeRoot( + std::unique_ptr chrome_root) { + return std::make_unique( + std::move(chrome_root), std::make_unique()); +} + #elif BUILDFLAG(IS_WIN) namespace {