diff --git a/net/cert/internal/trust_store_in_memory_starboard.cc b/net/cert/internal/trust_store_in_memory_starboard.cc index 1bc400f5ce53..4d546c5996dc 100644 --- a/net/cert/internal/trust_store_in_memory_starboard.cc +++ b/net/cert/internal/trust_store_in_memory_starboard.cc @@ -16,51 +16,30 @@ #include -#include "base/files/file.h" #include "base/files/file_path.h" -#include "base/path_service.h" +#include "base/files/file_util.h" #include "base/logging.h" +#include "base/notreached.h" +#include "base/path_service.h" #include "base/time/time.h" -#include "net/cert/pki/cert_errors.h" #include "net/cert/pem.h" +#include "net/cert/pki/cert_errors.h" #include "net/cert/x509_certificate.h" #include "net/cert/x509_util.h" #include "starboard/common/string.h" #include "starboard/configuration_constants.h" -#include "starboard/directory.h" -#include "starboard/file.h" #include "starboard/string.h" -#include "third_party/boringssl/src/include/openssl/digest.h" -#include "third_party/boringssl/src/include/openssl/sha.h" #include "third_party/boringssl/src/include/openssl/x509.h" namespace net { namespace { -// PEM encoded DER cert is usually around or less than 2000 bytes long. -const short kCertBufferSize = 8 * 1024; // Each certificate file name is 8 bit hash + ".0" suffix. const short kCertFileNameLength = 10; const char kCertificateHeader[] = "CERTIFICATE"; const char kSSLDirName[] = "ssl"; const char kCertsDirName[] = "certs"; -// Essentially an X509_NAME_hash without using X509_NAME. We did not use the -// boringSSL function directly because net does not store certs with X509 -// struct anymore and converting binary certs to X509_NAME is slightly -// expensive. -unsigned long CertNameHash(const void* data, size_t length) { - unsigned long ret = 0; - unsigned char md[SHA_DIGEST_LENGTH]; - if (!EVP_Digest(data, length, md, NULL, EVP_sha1(), NULL)) - return 0; - - ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) | - ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L)) & - 0xffffffffL; - return ret; -} - base::FilePath GetCertificateDirPath() { base::FilePath cert_path; base::PathService::Get(base::DIR_EXE, &cert_path); @@ -68,9 +47,9 @@ base::FilePath GetCertificateDirPath() { return std::move(cert_path); } -std::unordered_set GetCertNamesOnDisk() { - DIR* sb_certs_directory = - opendir(GetCertificateDirPath().value().c_str()); +std::vector> GetAllCertsOnDisk() { + base::FilePath cert_dir_path = GetCertificateDirPath(); + DIR* sb_certs_directory = opendir(cert_dir_path.value().c_str()); if (!sb_certs_directory) { // Unit tests, for example, do not use production certificates. #if defined(STARBOARD_BUILD_TYPE_QA) || defined(STARBOARD_BUILD_TYPE_GOLD) @@ -79,9 +58,10 @@ std::unordered_set GetCertNamesOnDisk() { DLOG(WARNING) << "ssl/certs directory is not valid, no root certificates" " will be loaded"; #endif - return std::unordered_set(); + return {}; } - std::unordered_set trusted_certs_on_disk; + + std::vector> certs; std::vector dir_entry(kSbFileMaxName); struct dirent dirent_buffer; @@ -99,90 +79,51 @@ std::unordered_set GetCertNamesOnDisk() { if (strlen(dir_entry.data()) != kCertFileNameLength) { continue; } - trusted_certs_on_disk.emplace(dir_entry.data()); + + base::FilePath cert_path = cert_dir_path.Append(dir_entry.data()); + std::string cert_buffer; + CHECK(base::ReadFileToString(cert_path, &cert_buffer)) + << "ssl/certs/" << cert_path.value() << " failed to open."; + PEMTokenizer pem_tokenizer(cert_buffer, {kCertificateHeader}); + CHECK(pem_tokenizer.GetNext()) << "Failed to parse PEM from cert file: " + << cert_path.value(); + std::string decoded(pem_tokenizer.data()); + CHECK(!pem_tokenizer.GetNext()) << "Multiple certificates found in " + << cert_path.value(); + auto crypto_buffer = x509_util::CreateCryptoBuffer(decoded); + CHECK(crypto_buffer) << "Failed to create crypto buffer for " + << cert_path.value(); + CertErrors errors; + auto parsed = ParsedCertificate::Create( + std::move(crypto_buffer), x509_util::DefaultParseCertificateOptions(), + &errors); + CHECK(parsed) << "Failed to parse certificate " << cert_path.value() + << ": " << errors.ToDebugString(); + certs.push_back(parsed); } closedir(sb_certs_directory); - return std::move(trusted_certs_on_disk); + return certs; } } // namespace -std::shared_ptr TrustStoreInMemoryStarboard::TryLoadCert( - const base::StringPiece& cert_name) const { - auto hash = CertNameHash(cert_name.data(), cert_name.length()); - char cert_file_name[256]; - snprintf(cert_file_name, 256, "%08lx.%d", hash, 0); - - if (trusted_cert_names_on_disk_.find(cert_file_name) == - trusted_cert_names_on_disk_.end()) { - // The requested certificate is not found. - return nullptr; +TrustStoreInMemoryStarboard::TrustStoreInMemoryStarboard() { + for (const auto& cert : GetAllCertsOnDisk()) { + underlying_trust_store_.AddTrustAnchor(cert); } - - char cert_buffer[kCertBufferSize]; - base::FilePath cert_path = GetCertificateDirPath().Append(cert_file_name); - base::File cert_file(cert_path, base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ); - // The file was in certs directory when we iterated the directory at startup, - // opening it should not fail. - if (!cert_file.IsValid()) { - NOTREACHED() << "ssl/certs/" << cert_path << " failed to open."; - return nullptr; - } - int cert_size = cert_file.ReadAtCurrentPos(cert_buffer, kCertBufferSize); - PEMTokenizer pem_tokenizer(base::StringPiece(cert_buffer, cert_size), - {kCertificateHeader}); - pem_tokenizer.GetNext(); - std::string decoded(pem_tokenizer.data()); - DCHECK(!pem_tokenizer.GetNext()); - auto crypto_buffer = x509_util::CreateCryptoBuffer(decoded); - CertErrors errors; - auto parsed = ParsedCertificate::Create( - std::move(crypto_buffer), - x509_util::DefaultParseCertificateOptions(), &errors); - CHECK(parsed) << errors.ToDebugString(); - return parsed; } -TrustStoreInMemoryStarboard::TrustStoreInMemoryStarboard() - : trusted_cert_names_on_disk_(std::move(GetCertNamesOnDisk())) {} - TrustStoreInMemoryStarboard::~TrustStoreInMemoryStarboard() = default; void TrustStoreInMemoryStarboard::SyncGetIssuersOf( const ParsedCertificate* cert, ParsedCertificateList* issuers) { - DCHECK(issuers); - DCHECK(issuers->empty()); - base::AutoLock scoped_lock(load_mutex_); - // Look up the request certificate first in the trust store in memory. underlying_trust_store_.SyncGetIssuersOf(cert, issuers); - if (issuers->empty()) { - // If the requested certificate is not found, compute certificate hash name - // and see if the certificate is stored on disk. - auto parsed_cert = TryLoadCert(cert->normalized_issuer().AsStringView()); - if (parsed_cert.get()) { - issuers->push_back(parsed_cert); - underlying_trust_store_.AddTrustAnchor(parsed_cert); - } - } } -CertificateTrust TrustStoreInMemoryStarboard::GetTrust(const ParsedCertificate* cert, - base::SupportsUserData* debug_data) { - base::AutoLock scoped_lock(load_mutex_); - // Loop up the request certificate first in the trust store in memory. - CertificateTrust trust = underlying_trust_store_.GetTrust(cert, debug_data); - if (trust.HasUnspecifiedTrust()) { - // If the requested certificate is not found, compute certificate hash name - // and see if the certificate is stored on disk. - auto parsed_cert = TryLoadCert(cert->normalized_subject().AsStringView()); - if (parsed_cert.get()) { - trust = CertificateTrust::ForTrustAnchor(); - const_cast(this) - ->underlying_trust_store_.AddTrustAnchor(parsed_cert); - } - } - return trust; +CertificateTrust TrustStoreInMemoryStarboard::GetTrust( + const ParsedCertificate* cert, + base::SupportsUserData* debug_data) { + return underlying_trust_store_.GetTrust(cert, debug_data); } } // namespace net - diff --git a/net/cert/internal/trust_store_in_memory_starboard.h b/net/cert/internal/trust_store_in_memory_starboard.h index d8cb1d292834..169847e5a819 100644 --- a/net/cert/internal/trust_store_in_memory_starboard.h +++ b/net/cert/internal/trust_store_in_memory_starboard.h @@ -15,15 +15,12 @@ #ifndef NET_CERT_INTERNAL_TRUST_STORE_IN_MEMORY_STARBOARD_H_ #define NET_CERT_INTERNAL_TRUST_STORE_IN_MEMORY_STARBOARD_H_ -#include - #include "base/strings/string_piece.h" -#include "base/synchronization/lock.h" #include "net/cert/pki/trust_store_in_memory.h" namespace net { -// Wrapper around TrustStoreInMemory to lazily load trusted root certificates. +// Wrapper around TrustStoreInMemory to eagerly load trusted root certificates. class NET_EXPORT TrustStoreInMemoryStarboard : public TrustStore { public: TrustStoreInMemoryStarboard(); @@ -33,12 +30,11 @@ class NET_EXPORT TrustStoreInMemoryStarboard : public TrustStore { void SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) override; CertificateTrust GetTrust(const ParsedCertificate* cert, - base::SupportsUserData* debug_data) override; + base::SupportsUserData* debug_data) override; // Returns true if the trust store contains the given ParsedCertificate // (matches by DER). bool Contains(const ParsedCertificate* cert) const { - base::AutoLock scoped_lock(load_mutex_); return underlying_trust_store_.Contains(cert); } @@ -48,22 +44,8 @@ class NET_EXPORT TrustStoreInMemoryStarboard : public TrustStore { delete; TrustStoreInMemory underlying_trust_store_; - - // Given a certificate's canonical name, try to load this cert from trusted - // certs on disk if it is found. - std::shared_ptr TryLoadCert( - const base::StringPiece& cert_name) const; - - // The memory trust store can be accessed by multiple threads, in Chromium, - // the synchronization issue is solved by initializing trust store at startup - // and passing constant reference to consumers. Cobalt loads certs lazily and - // therefore guards the underlying_trust_store_ with mutex. - mutable base::Lock load_mutex_; - - const std::unordered_set trusted_cert_names_on_disk_; }; } // namespace net #endif // NET_CERT_INTERNAL_TRUST_STORE_IN_MEMORY_STARBOARD_H_ -