// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_LACROS_CERT_CERT_DB_INITIALIZER_IMPL_H_
#define CHROME_BROWSER_LACROS_CERT_CERT_DB_INITIALIZER_IMPL_H_
#include <optional>
#include "base/callback_list.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/lacros/cert/cert_db_initializer.h"
#include "chrome/browser/lacros/cert/cert_db_initializer_io_impl.h"
#include "chromeos/crosapi/mojom/cert_database.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "components/keyed_service/core/keyed_service.h"
#include "crypto/scoped_nss_types.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/cert/cert_database.h"
class Profile;
// Initializes the certificate database in Lacros-Chrome for the specified
// profile. This object should only be accessed on the UI thread, and requires
// the Mojo CertDatabase interface to be available on the `LacrosService`.
//
// On Lacros-Chrome, how a database is initialized depends on which profile is
// being used as well as the device capabilities.
//
// - For devices with a dedicated TPM, for the main profile the public slot will
// be in the current user's cryptohome (a path is provided by Ash) and the
// private slot will be on the TPM (its slot id is provided by Ash).
//
// - For devices with a dedicated TPM, Ash may also indicate that Lacros should
// use the system slot stored on the TPM. If indicated, the main profile will
// attempt to load the system slot (its slot id is provided by Ash). In case
// of failure, the profile won't have access to certificates from the system
// slot (it will log an error, but won't crash).
//
// - Devices without a dedicated TPM are currently not fully
// supported. For the main profile the public slot be in the current user's
// cryptohome (a path is provided by Ash), the private slot will be set to a
// read-only slot that does not support modification or permanent objects.
// TODO(b/197082753): Make the private slot reference the public slot (same as
// in Ash).
//
// - For all devices, secondary profiles will be initialized with both
// public and private slots set to read-only slots that do not
// support modification or permanent objects.
//
// - If Ash provides a path/TPM slot, and Lacros is unable to load
// it, Lacros will intentionally crash, to avoid ignoring
// settings from Ash.
//
// - If Ash does not provide a path, this is an unexpected/invalid
// state, but Lacros will fail into read-only mode.
class CertDbInitializerImpl : public CertDbInitializer,
public KeyedService,
public crosapi::mojom::AshCertDatabaseObserver {
public:
explicit CertDbInitializerImpl(Profile* profile);
~CertDbInitializerImpl() override;
// Starts the initialization. For the main profile the database will be
// initialized based on the information provided by Ash. Secondary profiles
// will get a read-only database without any user certificates.
void Start();
// CertDbInitializer
base::CallbackListSubscription WaitUntilReady(
base::OnceClosure callback) override;
NssCertDatabaseGetter CreateNssCertDatabaseGetterForIOThread() override;
// Called when there's a change in certificate database in Ash.
// Forwards the notification to the CertDatabase.
void OnCertsChangedInAsh(
crosapi::mojom::CertDatabaseChangeType change_type) override;
private:
void InitializeForMainProfile();
// Initializes a read-only cert database. It only has access to the built-in
// certs and doesn't allow any modifications.
void InitializeReadOnlyCertDb();
// Queries Ash-Chrome for the user and system slots to use for the profile.
// Should only be called after the software database has been loaded.
void DidLoadSoftwareNssDb();
// Receives information for initializing the main cert database and forwards
// it to `cert_db_initializer_io_`.
void OnCertDbInfoReceived(
crosapi::mojom::GetCertDatabaseInfoResultPtr cert_db_info);
// A part of the legacy initialization flow. Triggers legacy initialization in
// `cert_db_initializer_io_`.
void OnLegacyCertDbInfoReceived(
crosapi::mojom::GetCertDatabaseInfoResultPtr cert_db_info);
// Receives the signal that initialization is finished and notifies observers
// about that.
void OnCertDbInitializationFinished();
// This class is a `KeyedService` based on the `Profile`. An instance is
// created together with a new profile and never outlives it.`
raw_ptr<Profile> profile_ = nullptr;
bool is_ready_ = false;
base::OnceClosureList callbacks_;
// Created on the UI thread, but after that, initialized, accessed, and
// destroyed exclusively on the IO thread. It is safe to pass unretained
// pointers to this object into IO thread tasks because the earliest it can be
// destroyed is in the following task posted from the destructor.
std::unique_ptr<CertDbInitializerIOImpl> cert_db_initializer_io_;
// Receives mojo messages from ash-chrome (under Streaming mode).
mojo::Receiver<crosapi::mojom::AshCertDatabaseObserver> receiver_{this};
base::WeakPtrFactory<CertDbInitializerImpl> weak_factory_{this};
};
#endif // CHROME_BROWSER_LACROS_CERT_CERT_DB_INITIALIZER_IMPL_H_