| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/component_updater/pki_metadata_component_installer.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/barrier_closure.h" |
| #include "base/base64.h" |
| #include "base/check.h" |
| #include "base/containers/flat_map.h" |
| #include "base/containers/span.h" |
| #include "base/containers/to_vector.h" |
| #include "base/feature_list.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/no_destructor.h" |
| #include "base/notreached.h" |
| #include "base/sequence_checker.h" |
| #include "base/task/thread_pool.h" |
| #include "base/threading/scoped_blocking_call.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "chrome/browser/browser_features.h" |
| #include "chrome/browser/net/key_pinning.pb.h" |
| #include "chrome/browser/net/system_network_context_manager.h" |
| #include "content/public/browser/network_service_instance.h" |
| #include "net/base/hash_value.h" |
| #include "net/cert/root_store_proto_lite/root_store.pb.h" |
| #include "net/net_buildflags.h" |
| #include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h" |
| #include "services/network/public/cpp/network_service_buildflags.h" |
| #include "services/network/public/mojom/key_pinning.mojom.h" |
| #include "services/network/public/mojom/network_service.mojom.h" |
| |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| #include "components/certificate_transparency/certificate_transparency.pb.h" |
| #include "components/certificate_transparency/certificate_transparency_config.pb.h" |
| #include "components/certificate_transparency/ct_known_logs.h" |
| #include "services/network/public/mojom/ct_log_info.mojom.h" |
| #endif |
| |
| #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) |
| #include "mojo/public/cpp/base/big_buffer.h" |
| #include "mojo/public/cpp/base/proto_wrapper.h" |
| #include "mojo/public/cpp/base/proto_wrapper_passkeys.h" |
| #include "net/cert/internal/trust_store_chrome.h" |
| #endif |
| |
| #if BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST) |
| #include "net/http/transport_security_state.h" |
| #endif |
| |
| namespace { |
| |
| // This is the last version of CT log lists that this version of Chrome will |
| // accept. If a list is delivered with a compatibility version higher than this, |
| // it will be ignored (though the emergency disable flag will still be followed |
| // if it is set). This should never be decreased since that will cause CT |
| // enforcement to eventually stop. This should also only be increased if Chrome |
| // is compatible with the version it is being incremented to. |
| const uint64_t kMaxSupportedCTCompatibilityVersion = 3; |
| |
| // This is the last version of key pins lists that this version of Chrome will |
| // accept. If a list is delivered with a compatibility version higher than this, |
| // it will be ignored. This should never be decreased since that will cause key |
| // pinning enforcement to eventually stop. This should also only be increased if |
| // Chrome is compatible with the version it is being incremented to. |
| const uint64_t kMaxSupportedKPCompatibilityVersion = 1; |
| |
| // The SHA256 of the SubjectPublicKeyInfo used to sign the extension. |
| // The extension id is: efniojlnjndmcbiieegkicadnoecjjef |
| const uint8_t kPKIMetadataPublicKeySHA256[32] = { |
| 0x45, 0xd8, 0xe9, 0xbd, 0x9d, 0x3c, 0x21, 0x88, 0x44, 0x6a, 0x82, |
| 0x03, 0xde, 0x42, 0x99, 0x45, 0x66, 0x25, 0xfe, 0xb3, 0xd1, 0xf8, |
| 0x11, 0x65, 0xb4, 0x6f, 0xd3, 0x1b, 0x21, 0x89, 0xbe, 0x9c}; |
| |
| const base::FilePath::CharType kCTConfigProtoFileName[] = |
| FILE_PATH_LITERAL("ct_config.pb"); |
| |
| const base::FilePath::CharType kKPConfigProtoFileName[] = |
| FILE_PATH_LITERAL("kp_pinslist.pb"); |
| |
| #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) |
| const base::FilePath::CharType kCRSProtoFileName[] = |
| FILE_PATH_LITERAL("crs.pb"); |
| constexpr char kChromeRootStoreProto[] = "chrome_root_store.RootStore"; |
| #endif |
| |
| std::string LoadBinaryProtoFromDisk(const base::FilePath& pb_path) { |
| std::string result; |
| if (pb_path.empty()) { |
| return result; |
| } |
| |
| base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, |
| base::BlockingType::WILL_BLOCK); |
| |
| if (!base::ReadFileToString(pb_path, &result)) { |
| result.clear(); |
| } |
| return result; |
| } |
| |
| // Ideally we'd use EnumTraits for this method, but the conversion is only done |
| // once here so it's not worth it. |
| network::mojom::CTLogInfo::LogType ProtoLogTypeToLogType( |
| ::chrome_browser_certificate_transparency::CTLog_LogType log_type) { |
| switch (log_type) { |
| case ::chrome_browser_certificate_transparency::CTLog::LOG_TYPE_UNSPECIFIED: |
| return network::mojom::CTLogInfo::LogType::kUnspecified; |
| case ::chrome_browser_certificate_transparency::CTLog::RFC6962: |
| return network::mojom::CTLogInfo::LogType::kRFC6962; |
| case ::chrome_browser_certificate_transparency::CTLog::STATIC_CT_API: |
| return network::mojom::CTLogInfo::LogType::kStaticCTAPI; |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| // Converts a protobuf repeated bytes array to an array of uint8_t arrays. |
| std::vector<std::vector<uint8_t>> BytesArrayFromProtoBytes( |
| const google::protobuf::RepeatedPtrField<std::string>& proto_bytes) { |
| std::vector<std::vector<uint8_t>> bytes; |
| bytes.reserve(proto_bytes.size()); |
| std::ranges::transform( |
| proto_bytes, std::back_inserter(bytes), [](const std::string& element) { |
| const auto bytes = base::as_byte_span(element); |
| return std::vector<uint8_t>(bytes.begin(), bytes.end()); |
| }); |
| return bytes; |
| } |
| |
| // Converts a protobuf repeated bytes array to an array of SHA256HashValues. |
| // Elements in `proto_bytes` that are not 32 bytes long are silently ignored. |
| std::vector<net::SHA256HashValue> SHA256HashValueArrayFromProtoBytes( |
| const google::protobuf::RepeatedPtrField<std::string>& proto_bytes) { |
| std::vector<net::SHA256HashValue> hashes; |
| hashes.reserve(proto_bytes.size()); |
| for (const auto& proto_hash : proto_bytes) { |
| if (proto_hash.size() == crypto::hash::kSha256Size) { |
| base::span(hashes.emplace_back()) |
| .copy_from(base::as_byte_span(proto_hash)); |
| } |
| } |
| return hashes; |
| } |
| |
| } // namespace |
| |
| namespace component_updater { |
| |
| // PKIMetadataComponentInstallerService: |
| |
| // static |
| PKIMetadataComponentInstallerService* |
| PKIMetadataComponentInstallerService::GetInstance() { |
| static base::NoDestructor<PKIMetadataComponentInstallerService> instance; |
| return instance.get(); |
| } |
| |
| PKIMetadataComponentInstallerService::PKIMetadataComponentInstallerService() = |
| default; |
| |
| void PKIMetadataComponentInstallerService::ConfigureChromeRootStore() { |
| #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()}, |
| base::BindOnce( |
| [](const base::FilePath& pb_path) |
| -> std::optional<mojo_base::ProtoWrapper> { |
| std::string file_contents = LoadBinaryProtoFromDisk(pb_path); |
| if (file_contents.size()) { |
| return mojo_base::ProtoWrapper( |
| base::as_byte_span(file_contents), kChromeRootStoreProto, |
| mojo_base::ProtoWrapperBytes::GetPassKey()); |
| } |
| return std::nullopt; |
| }, |
| install_dir_.Append(kCRSProtoFileName)), |
| base::BindOnce( |
| &PKIMetadataComponentInstallerService::UpdateChromeRootStoreOnUI, |
| weak_factory_.GetWeakPtr())); |
| #endif |
| } |
| |
| #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED) |
| void PKIMetadataComponentInstallerService::UpdateChromeRootStoreOnUI( |
| std::optional<mojo_base::ProtoWrapper> chrome_root_store) { |
| if (chrome_root_store.has_value()) { |
| UpdateTrustAnchorIDs(chrome_root_store.value()); |
| content::GetCertVerifierServiceFactory()->UpdateChromeRootStore( |
| std::move(chrome_root_store.value()), |
| base::BindOnce(&PKIMetadataComponentInstallerService:: |
| NotifyChromeRootStoreConfigured, |
| weak_factory_.GetWeakPtr())); |
| } |
| } |
| void PKIMetadataComponentInstallerService::UpdateTrustAnchorIDs( |
| const mojo_base::ProtoWrapper& chrome_root_store) { |
| std::vector<std::vector<uint8_t>> trust_anchor_ids; |
| auto message = chrome_root_store.As<chrome_root_store::RootStore>(); |
| if (!message.has_value()) { |
| LOG(ERROR) << "error parsing proto for Chrome Root Store"; |
| return; |
| } |
| if (message->version_major() <= net::CompiledChromeRootStoreVersion()) { |
| return; |
| } |
| for (const auto& anchor : message->trust_anchors()) { |
| if (anchor.has_trust_anchor_id()) { |
| trust_anchor_ids.emplace_back( |
| base::ToVector(base::as_byte_span(anchor.trust_anchor_id()))); |
| } |
| } |
| for (const auto& additional_cert : message->additional_certs()) { |
| if (additional_cert.has_trust_anchor_id() && |
| additional_cert.tls_trust_anchor()) { |
| trust_anchor_ids.emplace_back(base::ToVector( |
| base::as_byte_span(additional_cert.trust_anchor_id()))); |
| } |
| } |
| SystemNetworkContextManager* network_context_manager = |
| SystemNetworkContextManager::GetInstance(); |
| CHECK(network_context_manager); |
| network_context_manager->UpdateTrustAnchorIDs(std::move(trust_anchor_ids)); |
| } |
| |
| void PKIMetadataComponentInstallerService::NotifyChromeRootStoreConfigured() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| for (Observer& observer : observers_) { |
| observer.OnChromeRootStoreConfigured(); |
| } |
| } |
| |
| bool PKIMetadataComponentInstallerService::WriteCRSDataForTesting( |
| const base::FilePath& path, |
| const std::string& contents) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| install_dir_ = path; |
| return base::WriteFile(path.Append(kCRSProtoFileName), contents); |
| } |
| #endif |
| |
| void PKIMetadataComponentInstallerService::ReconfigureAfterNetworkRestart() { |
| // Runs on UI thread. |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (install_dir_.empty()) { |
| return; |
| } |
| if (base::FeatureList::IsEnabled( |
| features::kCertificateTransparencyAskBeforeEnabling)) { |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()}, |
| base::BindOnce(&LoadBinaryProtoFromDisk, |
| install_dir_.Append(kCTConfigProtoFileName)), |
| base::BindOnce(&PKIMetadataComponentInstallerService:: |
| UpdateNetworkServiceCTListOnUI, |
| weak_factory_.GetWeakPtr())); |
| } |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()}, |
| base::BindOnce(&LoadBinaryProtoFromDisk, |
| install_dir_.Append(kKPConfigProtoFileName)), |
| base::BindOnce( |
| &PKIMetadataComponentInstallerService::UpdateNetworkServiceKPListOnUI, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void PKIMetadataComponentInstallerService::OnComponentReady( |
| base::FilePath install_dir) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| install_dir_ = install_dir; |
| ReconfigureAfterNetworkRestart(); |
| ConfigureChromeRootStore(); |
| } |
| |
| bool PKIMetadataComponentInstallerService::WriteCTDataForTesting( |
| const base::FilePath& path, |
| const std::string& contents) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| install_dir_ = path; |
| return base::WriteFile(path.Append(kCTConfigProtoFileName), contents); |
| } |
| |
| void PKIMetadataComponentInstallerService::AddObserver(Observer* observer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| observers_.AddObserver(observer); |
| } |
| |
| void PKIMetadataComponentInstallerService::RemoveObserver(Observer* observer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| observers_.RemoveObserver(observer); |
| } |
| |
| void PKIMetadataComponentInstallerService::UpdateNetworkServiceCTListOnUI( |
| const std::string& ct_config_bytes) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| #if BUILDFLAG(IS_CT_SUPPORTED) |
| if (ct_config_bytes.empty()) { |
| // LoadBinaryProtoFromDisk returns an empty string if it fails to find |
| // the file on disk or fails to read. An empty string is valid proto, |
| // continuing to process such an empty string will result in stomping |
| // on the default disqualified certs in the CT list allowing |
| // disqualified certs to be trusted. Treat empty string as invalid proto |
| // instead. |
| return; |
| } |
| |
| auto proto = |
| std::make_unique<chrome_browser_certificate_transparency::CTConfig>(); |
| if (!proto->ParseFromString(ct_config_bytes)) { |
| return; |
| } |
| |
| network::mojom::NetworkService* network_service = |
| content::GetNetworkService(); |
| |
| if (proto->disable_ct_enforcement()) { |
| // TODO(crbug.com/41392053): The disable_ct_enforcement kill switch is |
| // used in both the network service and cert verifier service. Finish |
| // refactoring so that it is only sent to cert verifier service. |
| base::RepeatingClosure done_callback = BarrierClosure( |
| /*num_closures=*/2, |
| base::BindOnce( |
| &PKIMetadataComponentInstallerService::NotifyCTLogListConfigured, |
| weak_factory_.GetWeakPtr())); |
| content::GetCertVerifierServiceFactory()->DisableCtEnforcement( |
| done_callback); |
| network_service->SetCtEnforcementEnabled(false, done_callback); |
| return; |
| } |
| |
| if (proto->log_list().compatibility_version() > |
| kMaxSupportedCTCompatibilityVersion) { |
| return; |
| } |
| |
| base::Time proto_timestamp = |
| base::Time::UnixEpoch() + |
| base::Seconds(proto->log_list().timestamp().seconds()) + |
| base::Nanoseconds(proto->log_list().timestamp().nanos()); |
| // Do not update the CT log list with the component data if it's older than |
| // the built in list. |
| if (proto_timestamp < certificate_transparency::GetLogListTimestamp()) { |
| return; |
| } |
| |
| // TODO(crbug.com/41392053): Log info needs to be sent to both network |
| // service and cert verifier service. Finish refactoring so that it is only |
| // sent to cert verifier service. |
| std::vector<network::mojom::CTLogInfoPtr> log_list_mojo; |
| std::vector<network::mojom::CTLogInfoPtr> log_list_mojo_clone_network_service; |
| |
| // The log list shipped via component updater is a single message of CTLogList |
| // type, as defined in |
| // components/certificate_transparency/certificate_transparency.proto, the |
| // included logs are of the CTLog type, but include only the information |
| // required by Chrome to enforce its CT policy. Non Chrome used fields are |
| // left unset. |
| for (const auto& log : proto->log_list().logs()) { |
| std::string decoded_id; |
| if (!base::Base64Decode(log.log_id(), &decoded_id)) { |
| continue; |
| } |
| std::string decoded_key; |
| if (!base::Base64Decode(log.key(), &decoded_key)) { |
| continue; |
| } |
| network::mojom::CTLogInfoPtr log_ptr = network::mojom::CTLogInfo::New(); |
| log_ptr->id = std::move(decoded_id); |
| log_ptr->name = log.description(); |
| log_ptr->public_key = std::move(decoded_key); |
| // Operator history is ordered in inverse chronological order, so the 0th |
| // element will be the current operator. |
| if (!log.operator_history().empty()) { |
| log_ptr->current_operator = log.operator_history().Get(0).name(); |
| if (log.operator_history().size() > 1) { |
| // The protobuffer includes operator history in reverse chronological |
| // order, but we need it in chronological order, so we iterate in |
| // reverse (and ignoring the current operator). |
| for (auto it = log.operator_history().rbegin(); |
| it != log.operator_history().rend() - 1; ++it) { |
| network::mojom::PreviousOperatorEntryPtr previous_operator = |
| network::mojom::PreviousOperatorEntry::New(); |
| previous_operator->name = it->name(); |
| // We use the next element's start time as the current element end |
| // time. |
| base::Time end_time = |
| base::Time::UnixEpoch() + |
| base::Seconds((it + 1)->operator_start().seconds()) + |
| base::Nanoseconds((it + 1)->operator_start().nanos()); |
| previous_operator->end_time = end_time; |
| log_ptr->previous_operators.push_back(std::move(previous_operator)); |
| } |
| } |
| } |
| |
| // State history is ordered in inverse chronological order, so the 0th |
| // element will be the current state. |
| if (!log.state().empty()) { |
| const auto& state = log.state().Get(0); |
| if (state.current_state() == |
| chrome_browser_certificate_transparency::CTLog_CurrentState_RETIRED) { |
| // If the log was RETIRED, record the timestamp at which it was. |
| // Note: RETIRED is a terminal state for the log, so other states do not |
| // need to be checked, because once RETIRED, the state will never |
| // change. |
| base::Time retired_since = |
| base::Time::UnixEpoch() + |
| base::Seconds(log.state()[0].state_start().seconds()) + |
| base::Nanoseconds(log.state()[0].state_start().nanos()); |
| log_ptr->disqualified_at = retired_since; |
| } |
| } |
| |
| log_ptr->mmd = base::Seconds(log.mmd_secs()); |
| log_ptr->log_type = ProtoLogTypeToLogType(log.log_type()); |
| log_list_mojo_clone_network_service.push_back(log_ptr.Clone()); |
| log_list_mojo.push_back(std::move(log_ptr)); |
| } |
| |
| // We need to wait for both CT log list updates and the popular SCT list |
| // update. |
| base::RepeatingClosure done_callback = BarrierClosure( |
| /*num_closures=*/3, |
| base::BindOnce( |
| &PKIMetadataComponentInstallerService::NotifyCTLogListConfigured, |
| weak_factory_.GetWeakPtr())); |
| content::GetCertVerifierServiceFactory()->UpdateCtLogList( |
| std::move(log_list_mojo), proto_timestamp, done_callback); |
| network_service->UpdateCtLogList( |
| std::move(log_list_mojo_clone_network_service), done_callback); |
| |
| // Send the updated popular SCTs list to the network service, if available. |
| // TODO(crbug.com/41286522): should this also be vector<SHA256HashValue>? |
| std::vector<std::vector<uint8_t>> popular_scts = |
| BytesArrayFromProtoBytes(proto->popular_scts()); |
| network_service->UpdateCtKnownPopularSCTs(std::move(popular_scts), |
| done_callback); |
| #endif // BUILDFLAG(IS_CT_SUPPORTED) |
| } |
| |
| void PKIMetadataComponentInstallerService::UpdateNetworkServiceKPListOnUI( |
| const std::string& kp_config_bytes) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| auto proto = std::make_unique<chrome_browser_key_pinning::PinList>(); |
| if (!proto->ParseFromString(kp_config_bytes)) { |
| return; |
| } |
| network::mojom::NetworkService* network_service = |
| content::GetNetworkService(); |
| |
| if (proto->compatibility_version() > kMaxSupportedKPCompatibilityVersion) { |
| return; |
| } |
| |
| base::Time proto_timestamp = base::Time::UnixEpoch() + |
| base::Seconds(proto->timestamp().seconds()) + |
| base::Nanoseconds(proto->timestamp().nanos()); |
| |
| #if BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST) |
| // Do not update the pins list with the component data if it's older than the |
| // built in list. |
| if (proto_timestamp < |
| net::TransportSecurityState::GetBuiltInPinsListTimestamp()) { |
| return; |
| } |
| #endif // BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST) |
| |
| network::mojom::PinListPtr pinlist_ptr = network::mojom::PinList::New(); |
| |
| for (const auto& pinset : proto->pinsets()) { |
| network::mojom::PinSetPtr pinset_ptr = network::mojom::PinSet::New(); |
| pinset_ptr->name = pinset.name(); |
| pinset_ptr->static_spki_hashes = |
| SHA256HashValueArrayFromProtoBytes(pinset.static_spki_hashes_sha256()); |
| pinset_ptr->bad_static_spki_hashes = SHA256HashValueArrayFromProtoBytes( |
| pinset.bad_static_spki_hashes_sha256()); |
| pinlist_ptr->pinsets.push_back(std::move(pinset_ptr)); |
| } |
| |
| for (const auto& info : proto->host_pins()) { |
| network::mojom::PinSetInfoPtr pininfo_ptr = |
| network::mojom::PinSetInfo::New(); |
| pininfo_ptr->hostname = info.hostname(); |
| pininfo_ptr->pinset_name = info.pinset_name(); |
| pininfo_ptr->include_subdomains = info.include_subdomains(); |
| pinlist_ptr->host_pins.push_back(std::move(pininfo_ptr)); |
| } |
| |
| network_service->UpdateKeyPinsList(std::move(pinlist_ptr), proto_timestamp); |
| } |
| |
| void PKIMetadataComponentInstallerService::NotifyCTLogListConfigured() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| for (Observer& observer : observers_) { |
| observer.OnCTLogListConfigured(); |
| } |
| } |
| |
| // PKIMetadataComponentInstallerPolicy: |
| |
| PKIMetadataComponentInstallerPolicy::PKIMetadataComponentInstallerPolicy() = |
| default; |
| |
| PKIMetadataComponentInstallerPolicy::~PKIMetadataComponentInstallerPolicy() = |
| default; |
| |
| // static |
| std::vector<std::vector<uint8_t>> |
| PKIMetadataComponentInstallerPolicy::BytesArrayFromProtoBytesForTesting( |
| const google::protobuf::RepeatedPtrField<std::string>& proto_bytes) { |
| return BytesArrayFromProtoBytes(proto_bytes); |
| } |
| |
| // static |
| std::vector<net::SHA256HashValue> PKIMetadataComponentInstallerPolicy:: |
| SHA256HashValueArrayFromProtoBytesForTesting( |
| const google::protobuf::RepeatedPtrField<std::string>& proto_bytes) { |
| return SHA256HashValueArrayFromProtoBytes(proto_bytes); |
| } |
| |
| bool PKIMetadataComponentInstallerPolicy:: |
| SupportsGroupPolicyEnabledComponentUpdates() const { |
| return true; |
| } |
| |
| bool PKIMetadataComponentInstallerPolicy::RequiresNetworkEncryption() const { |
| return false; |
| } |
| |
| update_client::CrxInstaller::Result |
| PKIMetadataComponentInstallerPolicy::OnCustomInstall( |
| const base::Value::Dict& /* manifest */, |
| const base::FilePath& /* install_dir */) { |
| return update_client::CrxInstaller::Result(0); // Nothing custom here. |
| } |
| |
| void PKIMetadataComponentInstallerPolicy::OnCustomUninstall() {} |
| |
| void PKIMetadataComponentInstallerPolicy::ComponentReady( |
| const base::Version& version, |
| const base::FilePath& install_dir, |
| base::Value::Dict /* manifest */) { |
| PKIMetadataComponentInstallerService::GetInstance()->OnComponentReady( |
| install_dir); |
| } |
| |
| // Called during startup and installation before ComponentReady(). |
| bool PKIMetadataComponentInstallerPolicy::VerifyInstallation( |
| const base::Value::Dict& /* manifest */, |
| const base::FilePath& install_dir) const { |
| if (!base::PathExists(install_dir)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| base::FilePath PKIMetadataComponentInstallerPolicy::GetRelativeInstallDir() |
| const { |
| return base::FilePath(FILE_PATH_LITERAL("PKIMetadata")); |
| } |
| |
| void PKIMetadataComponentInstallerPolicy::GetHash( |
| std::vector<uint8_t>* hash) const { |
| hash->assign(std::begin(kPKIMetadataPublicKeySHA256), |
| std::end(kPKIMetadataPublicKeySHA256)); |
| } |
| |
| std::string PKIMetadataComponentInstallerPolicy::GetName() const { |
| return "PKI Metadata"; |
| } |
| |
| update_client::InstallerAttributes |
| PKIMetadataComponentInstallerPolicy::GetInstallerAttributes() const { |
| return update_client::InstallerAttributes(); |
| } |
| |
| void MaybeRegisterPKIMetadataComponent(ComponentUpdateService* cus) { |
| auto installer = base::MakeRefCounted<ComponentInstaller>( |
| std::make_unique<PKIMetadataComponentInstallerPolicy>()); |
| installer->Register(cus, base::OnceClosure()); |
| } |
| |
| } // namespace component_updater |