// Copyright 2019 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_ASH_ATTESTATION_MACHINE_CERTIFICATE_UPLOADER_IMPL_H_
#define CHROME_BROWSER_ASH_ATTESTATION_MACHINE_CERTIFICATE_UPLOADER_IMPL_H_
#include <optional>
#include <string>
#include <utility>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/ash/attestation/machine_certificate_uploader.h"
#include "chromeos/ash/components/dbus/attestation/interface.pb.h"
#include "chromeos/ash/components/dbus/constants/attestation_constants.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
namespace ash {
namespace attestation {
class AttestationFlow;
// A class which uploads enterprise machine certificates.
class MachineCertificateUploaderImpl : public MachineCertificateUploader {
public:
explicit MachineCertificateUploaderImpl(
policy::CloudPolicyClient* policy_client);
// A constructor which allows custom AttestationFlow implementations. Useful
// for testing.
MachineCertificateUploaderImpl(policy::CloudPolicyClient* policy_client,
AttestationFlow* attestation_flow);
MachineCertificateUploaderImpl(const MachineCertificateUploaderImpl&) =
delete;
MachineCertificateUploaderImpl& operator=(
const MachineCertificateUploaderImpl&) = delete;
~MachineCertificateUploaderImpl() override;
// Sets the retry limit in number of tries; useful in testing.
void set_retry_limit_for_testing(int limit) { retry_limit_ = limit; }
// Sets the retry delay; useful in testing.
void set_retry_delay_for_testing(base::TimeDelta retry_delay) {
retry_delay_ = std::move(retry_delay);
}
using UploadCallback =
base::OnceCallback<void(bool /*certificate_uploaded*/)>;
// Checks if the machine certificate has been uploaded, and if not, do so.
// A certificate will be obtained if needed.
void UploadCertificateIfNeeded(UploadCallback callback) override;
// Refreshes a fresh machine certificate and uploads it.
void RefreshAndUploadCertificate(UploadCallback callback) override;
// Non-blocking wait for a certificate to be uploaded. Calls the |callback|
// immediately if the certificate was already uploaded or wait for the next
// attempt to do so.
void WaitForUploadComplete(UploadCallback callback) override;
private:
// Starts certificate obtention and upload.
void Start();
// Gets a new certificate for the Enterprise Machine Key (EMK).
void GetNewCertificate();
// Called when `GetKeyInfo()` returned to check the existing certificate.
// There are 3 cases by the status replied from attestation service:
// 1. If the existing EMK is found, calls `CheckCertificateExpiry()`.
// 2. If the key does not exist, calls `GetNewCertificate()`.
// 3. Otherwise, there is an error and `Reschedule()` is called to retry.
void OnGetExistingCertificate(const ::attestation::GetKeyInfoReply& reply);
// Checks if any certificate in the given `reply` is expired and, if so, gets
// a new one. If not renewing, calls `CheckIfUploaded()`.
void CheckCertificateExpiry(const ::attestation::GetKeyInfoReply& reply);
// Uploads a machine certificate to the policy server.
void UploadCertificate(const std::string& pem_certificate_chain);
// Checks if a certificate in `reply` has already been uploaded and, if not,
// upload.
void CheckIfUploaded(const ::attestation::GetKeyInfoReply& reply);
// Called when a certificate upload operation completes.
void OnUploadComplete(policy::CloudPolicyClient::Result result);
// Marks a key as uploaded in the payload proto.
void MarkAsUploaded(const ::attestation::GetKeyInfoReply& reply);
// Handles failure of getting a certificate.
void HandleGetCertificateFailure(AttestationStatus status);
// Reschedules a policy check (i.e. a call to Start) for a later time.
// TODO(dkrahn): A better solution would be to wait for a dbus signal which
// indicates the system is ready to process this task. See crbug.com/256845.
void Reschedule();
void RunCallbacks(bool status);
raw_ptr<policy::CloudPolicyClient, DanglingUntriaged> policy_client_ =
nullptr;
std::unique_ptr<AttestationFlow> default_attestation_flow_;
raw_ptr<AttestationFlow> attestation_flow_ = nullptr;
bool refresh_certificate_ = false;
std::vector<UploadCallback> callbacks_;
int num_retries_ = 0;
int retry_limit_ = 0;
base::TimeDelta retry_delay_;
std::optional<bool> certificate_uploaded_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate the weak pointers before any other members are destroyed.
base::WeakPtrFactory<MachineCertificateUploaderImpl> weak_factory_{this};
};
} // namespace attestation
} // namespace ash
#endif // CHROME_BROWSER_ASH_ATTESTATION_MACHINE_CERTIFICATE_UPLOADER_IMPL_H_