blob: 7618b6e1d73352867f14ea7b3af4f67a45a55ad2 [file] [log] [blame]
// Copyright 2024 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_WEBAUTHN_GPM_ENCLAVE_TRANSACTION_H_
#define CHROME_BROWSER_WEBAUTHN_GPM_ENCLAVE_TRANSACTION_H_
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/webauthn/enclave_manager.h"
namespace device {
enum class FidoRequestType : uint8_t;
}
namespace device::enclave {
struct ClaimedPIN;
struct CredentialRequest;
enum class PINValidationResult : int;
} // namespace device::enclave
namespace signin {
class PrimaryAccountAccessTokenFetcher;
}
namespace webauthn {
class PasskeyModel;
}
namespace sync_pb {
class WebauthnCredentialSpecifics;
}
// EnclaveUserVerificationMethod enumerates the possible ways that user
// verification will be performed for an enclave transaction.
enum class EnclaveUserVerificationMethod {
// No user verification will be performed. The user acknowledged the operation
// in browser UI.
kUserPresenceOnly,
// The user will enter a GPM PIN.
kPIN,
// User verification is satisfied because the user performed account recovery.
kImplicit,
// The operating system will perform user verification and allow signing
// with the UV key.
kUVKeyWithSystemUI,
// The device is in a state waiting for an OS UV key to be created, which can
// be done when a UV request is required.
kDeferredUVKeyWithSystemUI,
// Chrome will show user verification UI for the operating system, which will
// then allow signing
// with the UV key.
kUVKeyWithChromeUI,
// A 'silent' request. No user verification is performed, and the user did not
// explicitly acknowledge the operation in browser UI either. This is only
// used for passkey upgrades (i.e. registration with mediation=conditional).
kNoUserVerificationAndNoUserPresence,
// The request cannot be satisfied.
kUnsatisfiable,
};
// GPMEnclaveTransaction encapsulates a single request (MakeCredential or
// GetAssertion) made to the enclave authenticator.
class GPMEnclaveTransaction {
public:
// Dispatches a CredentialRequest instance to the EnclaveAuthenticator.
using EnclaveRequestCallback = base::RepeatingCallback<void(
std::unique_ptr<device::enclave::CredentialRequest>)>;
class Delegate {
public:
// Invoked when transaction encounters an error. This is useful for updating
// UI.
virtual void HandleEnclaveTransactionError() = 0;
// Invoked to build UVKeyOptions for the request. This is only invoked for
// requests that perform UV.
virtual void BuildUVKeyOptions(EnclaveManager::UVKeyOptions& options) = 0;
// Invoked with the result of the PIN claim of the transaction if PIN UV was
// performed.
virtual void HandlePINValidationResult(
device::enclave::PINValidationResult result) = 0;
// Invoked after a successful MakeCredential request.
virtual void OnPasskeyCreated(
const sync_pb::WebauthnCredentialSpecifics& passkey) = 0;
// Returns the UV method to be used for the transaction.
virtual EnclaveUserVerificationMethod GetUvMethod() = 0;
};
// `delegate`, `model` and `enclave_manager` must be non-null and outlive the
// transaction. If `uv_method` is `kPIN` `pin` must be non-null.
// `selected_credential_id` must be non-null iff `request_type` is
// `kGetAssertion`.
GPMEnclaveTransaction(
Delegate* delegate,
webauthn::PasskeyModel* model,
device::FidoRequestType request_type,
std::string rp_id,
EnclaveManager* enclave_manager,
std::optional<std::string> pin,
std::optional<std::vector<uint8_t>> selected_credential_id,
EnclaveRequestCallback enclave_request_callback);
~GPMEnclaveTransaction();
// Dispatches the request to the enclave authenticator.
void Start();
private:
// Called when the UI has reached a state where it needs to do an enclave
// operation, and an OAuth token for the enclave has been fetched.
void MaybeHashPinAndStartEnclaveTransaction(std::optional<std::string> token);
// Called when the UI has reached a state where it needs to do an enclave
// operation, an OAuth token for the enclave has been fetched, and any PIN
// hashing has been completed.
void StartEnclaveTransaction(std::optional<std::string> token,
std::unique_ptr<device::enclave::ClaimedPIN>);
void HandlePINValidationResult(device::enclave::PINValidationResult result);
void OnPasskeyCreated(sync_pb::WebauthnCredentialSpecifics passkey);
void OnPasskeyEncryptedBlobUpdated(const std::string& credential_id,
const std::string& encrypted_data);
raw_ptr<Delegate> delegate_;
raw_ptr<webauthn::PasskeyModel> passkey_model_;
device::FidoRequestType request_type_;
std::string rp_id_;
raw_ptr<EnclaveManager> enclave_manager_;
std::optional<std::string> pin_;
std::optional<std::vector<uint8_t>> selected_credential_id_;
EnclaveRequestCallback enclave_request_callback_;
// Taken when attempting to create a deferred UV key. Released on destruction.
std::unique_ptr<EnclaveManager::UvKeyCreationLock> uv_key_lock_;
// The pending request to fetch an OAuth token for the enclave request.
std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher>
access_token_fetcher_;
base::WeakPtrFactory<GPMEnclaveTransaction> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_WEBAUTHN_GPM_ENCLAVE_TRANSACTION_H_