chromium/chromeos/ash/components/dbus/attestation/attestation_client.h

// 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 CHROMEOS_ASH_COMPONENTS_DBUS_ATTESTATION_ATTESTATION_CLIENT_H_
#define CHROMEOS_ASH_COMPONENTS_DBUS_ATTESTATION_ATTESTATION_CLIENT_H_

#include <deque>
#include <vector>

#include "base/component_export.h"
#include "base/functional/callback.h"
#include "base/time/time.h"
#include "chromeos/ash/components/dbus/attestation/interface.pb.h"
#include "chromeos/dbus/common/dbus_callback.h"

namespace dbus {
class Bus;
}

namespace ash {

// AttestationClient is used to communicate with the org.chromium.Attestation
// service. All method should be called from the origin thread (UI thread) which
// initializes the DBusThreadManager instance.
class COMPONENT_EXPORT(ASH_DBUS_ATTESTATION) AttestationClient {
 public:
  using GetKeyInfoCallback =
      base::OnceCallback<void(const ::attestation::GetKeyInfoReply&)>;
  using GetEndorsementInfoCallback =
      base::OnceCallback<void(const ::attestation::GetEndorsementInfoReply&)>;
  using GetAttestationKeyInfoCallback = base::OnceCallback<void(
      const ::attestation::GetAttestationKeyInfoReply&)>;
  using ActivateAttestationKeyCallback = base::OnceCallback<void(
      const ::attestation::ActivateAttestationKeyReply&)>;
  using CreateCertifiableKeyCallback =
      base::OnceCallback<void(const ::attestation::CreateCertifiableKeyReply&)>;
  using DecryptCallback =
      base::OnceCallback<void(const ::attestation::DecryptReply&)>;
  using SignCallback =
      base::OnceCallback<void(const ::attestation::SignReply&)>;
  using RegisterKeyWithChapsTokenCallback = base::OnceCallback<void(
      const ::attestation::RegisterKeyWithChapsTokenReply&)>;
  using GetEnrollmentPreparationsCallback = base::OnceCallback<void(
      const ::attestation::GetEnrollmentPreparationsReply&)>;
  using GetFeaturesCallback =
      base::OnceCallback<void(const ::attestation::GetFeaturesReply&)>;
  using GetStatusCallback =
      base::OnceCallback<void(const ::attestation::GetStatusReply&)>;
  using VerifyCallback =
      base::OnceCallback<void(const ::attestation::VerifyReply&)>;
  using CreateEnrollRequestCallback =
      base::OnceCallback<void(const ::attestation::CreateEnrollRequestReply&)>;
  using FinishEnrollCallback =
      base::OnceCallback<void(const ::attestation::FinishEnrollReply&)>;
  using CreateCertificateRequestCallback = base::OnceCallback<void(
      const ::attestation::CreateCertificateRequestReply&)>;
  using FinishCertificateRequestCallback = base::OnceCallback<void(
      const ::attestation::FinishCertificateRequestReply&)>;
  using EnrollCallback =
      base::OnceCallback<void(const ::attestation::EnrollReply&)>;
  using GetCertificateCallback =
      base::OnceCallback<void(const ::attestation::GetCertificateReply&)>;
  using SignEnterpriseChallengeCallback = base::OnceCallback<void(
      const ::attestation::SignEnterpriseChallengeReply&)>;
  using SignSimpleChallengeCallback =
      base::OnceCallback<void(const ::attestation::SignSimpleChallengeReply&)>;
  using SetKeyPayloadCallback =
      base::OnceCallback<void(const ::attestation::SetKeyPayloadReply&)>;
  using DeleteKeysCallback =
      base::OnceCallback<void(const ::attestation::DeleteKeysReply&)>;
  using ResetIdentityCallback =
      base::OnceCallback<void(const ::attestation::ResetIdentityReply&)>;
  using GetEnrollmentIdCallback =
      base::OnceCallback<void(const ::attestation::GetEnrollmentIdReply&)>;
  using GetCertifiedNvIndexCallback =
      base::OnceCallback<void(const ::attestation::GetCertifiedNvIndexReply&)>;

  // Interface with testing functionality. Accessed through GetTestInterface(),
  // only implemented in the fake implementation.
  class TestInterface {
   public:
    // Sets the preparation status to |is_prepared|. If no injected sequence by
    // |ConfigureEnrollmentPreparationsSequence| the enrollment preparations
    // always returns |is_prepared|.
    virtual void ConfigureEnrollmentPreparations(bool is_prepared) = 0;
    // Injects |sequence| of enrollment preparations. Once injected, the
    // returned enrollment preparations status will be the element popped from
    // the |sequence| one-by-one until all the elements are consumed.
    virtual void ConfigureEnrollmentPreparationsSequence(
        std::deque<bool> sequence) = 0;
    // Injects a bad status to `GetEnrollmentPreparations()` calls. By design,
    // this only accepts bad status so |STATUS_SUCCESS| is seen as an illegal
    // input and abort the program. To recover the fake behavior to successful
    // calls, call ConfigureEnrollmentPreparations(Sequence)?.
    virtual void ConfigureEnrollmentPreparationsStatus(
        ::attestation::AttestationStatus status) = 0;

    // Gets the mutable |GetFeaturesReply| that is returned when queried.
    virtual ::attestation::GetFeaturesReply* mutable_features_reply() = 0;

    // Gets the mutable |GetStatusReply| that is returned when queried.
    virtual ::attestation::GetStatusReply* mutable_status_reply() = 0;

    // Allowlists |request| so the certificate requests that comes in afterwards
    // will get a fake certificate. If any alias of |request| has been
    // allowlisted this functions performs no-ops.
    virtual void AllowlistCertificateRequest(
        const ::attestation::GetCertificateRequest& request) = 0;

    // Gets the history of `DeleteKeys()` requests.
    virtual const std::vector<::attestation::DeleteKeysRequest>&
    delete_keys_history() const = 0;

    // Clears the request history of `DeleteKeys()`.
    virtual void ClearDeleteKeysHistory() = 0;

    // Sets returned enrollment ids, when ignoring/not ignoring cache,
    // respectively.
    virtual void set_enrollment_id_ignore_cache(const std::string& id) = 0;
    virtual void set_cached_enrollment_id(const std::string& id) = 0;
    // Sets the returned status of `GetEnrollmentId()` to be D-Bus error for
    // `count` times to emulate D-Bus late availability.
    virtual void set_enrollment_id_dbus_error_count(int count) = 0;

    // Gets the reply to the key info query as a fake database.
    virtual ::attestation::GetKeyInfoReply* GetMutableKeyInfoReply(
        const std::string& username,
        const std::string& label) = 0;
    // Sets the returned status of `GetKeyInfo()` to be D-Bus error for
    // `count` times to emulate D-Bus late availability.
    virtual void set_key_info_dbus_error_count(int count) = 0;
    // Gets the remaining count of `GetKeyInfo()` replying D-Bus error.
    virtual int key_info_dbus_error_count() const = 0;

    // Verifies if `signed_data` is signed against `challenge`.
    virtual bool VerifySimpleChallengeResponse(
        const std::string& challenge,
        const ::attestation::SignedData& signed_data) = 0;

    // Sets the status code returned by `SignSimpleChallenge()`.
    virtual void set_sign_simple_challenge_status(
        ::attestation::AttestationStatus status) = 0;
    // Allowlists the key used to sign simple challenge.
    virtual void AllowlistSignSimpleChallengeKey(const std::string& username,
                                                 const std::string& label) = 0;

    // Sets the status code returned by `Sign()`.
    virtual void set_sign_status(::attestation::AttestationStatus status) = 0;

    // Sets the status code returned by `RegisterKeyWithChapsToken()`.
    virtual void set_register_key_status(
        ::attestation::AttestationStatus status) = 0;
    // Allowlists the key allowed to be registered to the key store.
    virtual void AllowlistRegisterKey(const std::string& username,
                                      const std::string& label) = 0;

    // Sets the status code returned by `SignEnterpriseChallenge()`.
    virtual void set_sign_enterprise_challenge_status(
        ::attestation::AttestationStatus status) = 0;
    // Allowlists the key used to sign enterprise challenge. Note that
    // `include_signed_public_key` and `challenge` are ignored for key
    // comparison because they are are part of the key but the inputs for
    // signature generation.
    virtual void AllowlistSignEnterpriseChallengeKey(
        const ::attestation::SignEnterpriseChallengeRequest& request) = 0;
    // Signs the enterprise `challenge` with this class the same way the
    // enterprise challenge is signed.
    virtual std::string GetEnterpriseChallengeFakeSignature(
        const std::string& challenge,
        bool include_spkac) const = 0;
    // Sets the delay to the time we reply to `SignEnterpriseChallenge()`.
    virtual void set_sign_enterprise_challenge_delay(
        const base::TimeDelta& delay) = 0;

    // Sets the allowed ACA type for the legacy attestation flow. The enroll
    // request can be created/finished only if the ACA type matches the set ACA
    // type. By default, it is default ACA.
    virtual void set_aca_type_for_legacy_flow(
        ::attestation::ACAType aca_type) = 0;

    // Sets the status code returned by `CreateEnrollRequestRequest()`.
    virtual void set_enroll_request_status(
        ::attestation::AttestationStatus status) = 0;
    // Gets the fake enroll request when the status is configured to be good.
    virtual std::string GetFakePcaEnrollRequest() const = 0;
    // Gets the fake enroll response that is accepted by `FinishEnroll()`.
    virtual std::string GetFakePcaEnrollResponse() const = 0;

    // Allowlists the request that has `username`, `request_origin`, `profile`,
    // and `key_type`, so the certificate requests that comes in afterwards will
    // be successfully created.
    virtual void AllowlistLegacyCreateCertificateRequest(
        const std::string& username,
        const std::string& request_origin,
        ::attestation::CertificateProfile profile,
        ::attestation::KeyType key_type) = 0;
    // Sets the status code returned by `CreateCertificateRequest()`.
    virtual void set_cert_request_status(
        ::attestation::AttestationStatus status) = 0;
    // Gets the fake certificate request when the status is configured to be
    // good.
    virtual std::string GetFakePcaCertRequest() const = 0;
    // Gets the fake enroll response that is accepted by
    // `FinishCertificateRequest()`.
    virtual std::string GetFakePcaCertResponse() const = 0;
    // Gets the fake certificate that is returned by
    // successful `FinishCertificateRequest()`.
    virtual std::string GetFakeCertificate() const = 0;
    // Sets the status code returned by `DeleteKeys()`.
    virtual void set_delete_keys_status(
        ::attestation::AttestationStatus status) = 0;
  };

  // Not copyable or movable.
  AttestationClient(const AttestationClient&) = delete;
  AttestationClient& operator=(const AttestationClient&) = delete;
  AttestationClient(AttestationClient&&) = delete;
  AttestationClient& operator=(AttestationClient&&) = delete;

  // Creates and initializes the global instance. |bus| must not be null.
  static void Initialize(dbus::Bus* bus);

  // Creates and initializes a fake global instance if not already created.
  static void InitializeFake();

  // Destroys the global instance.
  static void Shutdown();

  // Returns the global instance which may be null if not initialized.
  static AttestationClient* Get();

  // Checks if |reply| indicates the attestation service is prepared with any
  // ACA.
  static bool IsAttestationPrepared(
      const ::attestation::GetEnrollmentPreparationsReply& reply);

  // Gets the verified access server type from command-line arguments.
  static ::attestation::VAType GetVerifiedAccessServerType();

  // Attestation daemon D-Bus method calls. See org.chromium.Attestation.xml and
  // the corresponding protobuf definitions in Chromium OS code for the
  // documentation of the methods and request/ messages.

  virtual void GetKeyInfo(const ::attestation::GetKeyInfoRequest& request,
                          GetKeyInfoCallback callback) = 0;

  virtual void GetEndorsementInfo(
      const ::attestation::GetEndorsementInfoRequest& request,
      GetEndorsementInfoCallback callback) = 0;

  virtual void GetAttestationKeyInfo(
      const ::attestation::GetAttestationKeyInfoRequest& request,
      GetAttestationKeyInfoCallback callback) = 0;

  virtual void ActivateAttestationKey(
      const ::attestation::ActivateAttestationKeyRequest& request,
      ActivateAttestationKeyCallback callback) = 0;

  virtual void CreateCertifiableKey(
      const ::attestation::CreateCertifiableKeyRequest& request,
      CreateCertifiableKeyCallback callback) = 0;

  virtual void Decrypt(const ::attestation::DecryptRequest& request,
                       DecryptCallback callback) = 0;

  virtual void Sign(const ::attestation::SignRequest& request,
                    SignCallback callback) = 0;

  virtual void RegisterKeyWithChapsToken(
      const ::attestation::RegisterKeyWithChapsTokenRequest& request,
      RegisterKeyWithChapsTokenCallback callback) = 0;

  virtual void GetEnrollmentPreparations(
      const ::attestation::GetEnrollmentPreparationsRequest& request,
      GetEnrollmentPreparationsCallback callback) = 0;

  virtual void GetFeatures(const ::attestation::GetFeaturesRequest& request,
                           GetFeaturesCallback callback) = 0;

  virtual void GetStatus(const ::attestation::GetStatusRequest& request,
                         GetStatusCallback callback) = 0;

  virtual void Verify(const ::attestation::VerifyRequest& request,
                      VerifyCallback callback) = 0;

  virtual void CreateEnrollRequest(
      const ::attestation::CreateEnrollRequestRequest& request,
      CreateEnrollRequestCallback callback) = 0;

  virtual void FinishEnroll(const ::attestation::FinishEnrollRequest& request,
                            FinishEnrollCallback callback) = 0;

  virtual void CreateCertificateRequest(
      const ::attestation::CreateCertificateRequestRequest& request,
      CreateCertificateRequestCallback callback) = 0;

  virtual void FinishCertificateRequest(
      const ::attestation::FinishCertificateRequestRequest& request,
      FinishCertificateRequestCallback callback) = 0;

  virtual void Enroll(const ::attestation::EnrollRequest& request,
                      EnrollCallback callback) = 0;

  virtual void GetCertificate(
      const ::attestation::GetCertificateRequest& request,
      GetCertificateCallback callback) = 0;

  virtual void SignEnterpriseChallenge(
      const ::attestation::SignEnterpriseChallengeRequest& request,
      SignEnterpriseChallengeCallback callback) = 0;

  virtual void SignSimpleChallenge(
      const ::attestation::SignSimpleChallengeRequest& request,
      SignSimpleChallengeCallback callback) = 0;

  virtual void SetKeyPayload(const ::attestation::SetKeyPayloadRequest& request,
                             SetKeyPayloadCallback callback) = 0;

  virtual void DeleteKeys(const ::attestation::DeleteKeysRequest& request,
                          DeleteKeysCallback callback) = 0;

  virtual void ResetIdentity(const ::attestation::ResetIdentityRequest& request,
                             ResetIdentityCallback callback) = 0;

  virtual void GetEnrollmentId(
      const ::attestation::GetEnrollmentIdRequest& request,
      GetEnrollmentIdCallback callback) = 0;

  virtual void GetCertifiedNvIndex(
      const ::attestation::GetCertifiedNvIndexRequest& request,
      GetCertifiedNvIndexCallback callback) = 0;

  // Runs the callback as soon as the service becomes available.
  virtual void WaitForServiceToBeAvailable(
      chromeos::WaitForServiceToBeAvailableCallback callback) = 0;

  // Returns an interface for testing (fake only), or returns nullptr.
  virtual TestInterface* GetTestInterface() = 0;

 protected:
  // Initialize/Shutdown should be used instead.
  AttestationClient();
  virtual ~AttestationClient();
};

}  // namespace ash

#endif  // CHROMEOS_ASH_COMPONENTS_DBUS_ATTESTATION_ATTESTATION_CLIENT_H_