diff --git a/src/net/cert/internal/system_trust_store.cc b/src/net/cert/internal/system_trust_store.cc index 646ea2f321..76c10cb216 100644 --- a/src/net/cert/internal/system_trust_store.cc +++ b/src/net/cert/internal/system_trust_store.cc @@ -15,12 +15,17 @@ #include #endif +#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/no_destructor.h" +#include "base/strings/string_split.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "build/build_config.h" @@ -263,6 +268,143 @@ std::unique_ptr CreateSslSystemTrustStore() { return std::make_unique(); } +#elif defined(OS_LINUX) || defined(OS_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 +}; + +// certFileEnv is 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"; + +// certDirEnv is 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 StaticUnixSystemCerts { + public: + StaticUnixSystemCerts() { + 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.data(), file.size())) { + 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.data(), file.size())) { + 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"; + } + } + + TrustStoreInMemory* system_trust_store() { return &system_trust_store_; } + + private: + bool AddCertificatesFromBytes(const char* data, size_t length) { + auto certs = X509Certificate::CreateCertificateListFromBytes( + data, length, X509Certificate::FORMAT_AUTO); + bool certs_ok = false; + for (const auto& cert : certs) { + CertErrors errors; + auto parsed = ParsedCertificate::Create( + bssl::UpRef(cert->cert_buffer()), + x509_util::DefaultParseCertificateOptions(), &errors); + if (parsed) { + if (!system_trust_store_.Contains(parsed.get())) { + system_trust_store_.AddTrustAnchor(parsed); + } + certs_ok = true; + } else { + LOG(ERROR) << errors.ToDebugString(); + } + } + return certs_ok; + } + + TrustStoreInMemory system_trust_store_; +}; + +base::LazyInstance::Leaky g_root_certs_static_unix = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +class SystemTrustStoreStaticUnix : public BaseSystemTrustStore { + public: + SystemTrustStoreStaticUnix() { + trust_store_.AddTrustStore( + g_root_certs_static_unix.Get().system_trust_store()); + } + + bool UsesSystemTrustStore() const override { return true; } + + bool IsKnownRoot(const ParsedCertificate* trust_anchor) const override { + return g_root_certs_static_unix.Get().system_trust_store()->Contains( + trust_anchor); + } +}; + +std::unique_ptr CreateSslSystemTrustStore() { + return std::make_unique(); +} + #else std::unique_ptr CreateSslSystemTrustStore() {