blob: 060951e316916827bb2cce0985ca834fc2eba476 [file]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_UNEXPORTABLE_KEYS_UNEXPORTABLE_KEY_SERVICE_H_
#define COMPONENTS_UNEXPORTABLE_KEYS_UNEXPORTABLE_KEY_SERVICE_H_
#include "base/component_export.h"
#include "base/containers/span.h"
#include "base/functional/callback_forward.h"
#include "base/time/time.h"
#include "components/unexportable_keys/background_task_priority.h"
#include "components/unexportable_keys/service_error.h"
#include "components/unexportable_keys/unexportable_key_id.h"
#include "crypto/sign.h"
namespace crypto {
struct AttestationStatement;
} // namespace crypto
namespace unexportable_keys {
// Service providing access to `UnexportableSigningKey`s and
// `UnexportableAttestationKey`s.
//
// The service doesn't give clients direct access to the keys. Instead,
// `UnexportableKeyService` returns a key handle, `UnexportableSigningKeyId` (or
// its subclass `UnexportableAttestationKeyId`), that can be passed back to the
// service to perform operations with the key.
//
// To use the same key across several sessions, a client should perform the
// following steps (shown for signing keys, but similar for attestation keys):
//
// 1. Generate a new `UnexportableSigningKey` and obtain its key ID:
//
// UnexportableKeyService& service = GetUnexportableKeyService();
// ServiceErrorOr<UnexportableSigningKeyId> key_id;
// service.GenerateSigningKeySlowlyAsync(
// kAlgorithm, kPriority, [&key_id](auto result) { key_id = result; });
//
// 2. Get a wrapped key for this key and save it to disk:
//
// std::vector<uint8_t> wrapped_key = service.GetWrappedKey(*key_id);
// SaveToDisk(wrapped_key);
//
// 3. After the process restart, restore the same `UnexportableSigningKey` from
// the wrapped key:
//
// UnexportableKeyService& service = GetUnexportableKeyService();
// ServiceErrorOr<UnexportableSigningKeyId> key_id;
// std::vector<uint8_t> wrapped_key = ReadFromDisk();
// service.FromWrappedSigningKeySlowlyAsync(
// wrapped_key, kPriority, [&key_id](auto result) { key_id = result; });
//
// 4. Use obtained key ID to sign data:
//
// service.SignSlowlyAsync(*key_id, kData, kPriority, std::move(callback));
class COMPONENT_EXPORT(UNEXPORTABLE_KEYS) UnexportableKeyService {
public:
UnexportableKeyService() = default;
UnexportableKeyService(const UnexportableKeyService&) = delete;
UnexportableKeyService& operator=(const UnexportableKeyService&) = delete;
virtual ~UnexportableKeyService() = default;
// Generates a new signing key asynchronously and returns an ID of this key.
// Returned `UnexportableSigningKeyId` can be used later to perform key
// operations on this `UnexportableKeyService`.
// The first supported value of `acceptable_algorithms` determines the type of
// the key.
// Invokes `callback` with a `ServiceError` if no supported hardware exists,
// if no value in `acceptable_algorithms` is supported, or if there was an
// error creating the key.
virtual void GenerateSigningKeySlowlyAsync(
base::span<const crypto::sign::SignatureKind> acceptable_algorithms,
BackgroundTaskPriority priority,
base::OnceCallback<void(ServiceErrorOr<UnexportableSigningKeyId>)>
callback) = 0;
// Creates a new signing key from a `wrapped_key` asynchronously and returns
// an ID of this key.
// Returned `UnexportableSigningKeyId` can be used later to perform key
// operations on this `UnexportableKeyService`.
// `wrapped_key` can be read from disk but must have initially resulted from
// calling `GetWrappedKey()` on a previous instance of
// `UnexportableSigningKeyId`. Invokes `callback` with a `ServiceError` if
// `wrapped_key` cannot be imported.
//
// This method is also a supported way of transferring a key between
// `UnexportableKeyService` instances. A key's lifetime is controlled by the
// source `UnexportableKeyService` instance until this method completes in the
// destination service.
virtual void FromWrappedSigningKeySlowlyAsync(
base::span<const uint8_t> wrapped_key,
BackgroundTaskPriority priority,
base::OnceCallback<void(ServiceErrorOr<UnexportableSigningKeyId>)>
callback) = 0;
// Generates a new attestation key asynchronously and returns an ID of this
// key. Returned `UnexportableAttestationKeyId` can be used later to perform
// key operations on this `UnexportableKeyService`. The first supported value
// of `acceptable_algorithms` determines the type of the key. Invokes
// `callback` with a `ServiceError` if no supported hardware exists, if no
// value in `acceptable_algorithms` is supported, or if there was an error
// creating the key.
//
// TODO(crbug.com/501306852): Attestation keys are not really useful yet, but
// a CertifySlowly() API involving them will be added shortly.
virtual void GenerateAttestationKeySlowlyAsync(
base::span<const crypto::sign::SignatureKind> acceptable_algorithms,
BackgroundTaskPriority priority,
base::OnceCallback<void(ServiceErrorOr<UnexportableAttestationKeyId>)>
callback) = 0;
// Creates a new attestation key from a `wrapped_key` asynchronously and
// returns an ID of this key. Returned `UnexportableAttestationKeyId` can be
// used later to perform key operations on this `UnexportableKeyService`.
// `wrapped_key` can be read from disk but must have initially resulted from
// calling `GetWrappedKey()` on a previous instance of
// `UnexportableAttestationKeyId`. Invokes `callback` with a `ServiceError` if
// `wrapped_key` cannot be imported.
//
// TODO(crbug.com/501306852): Attestation keys are not really useful yet, but
// a CertifySlowly() API involving them will be added shortly.
virtual void FromWrappedAttestationKeySlowlyAsync(
base::span<const uint8_t> wrapped_key,
BackgroundTaskPriority priority,
base::OnceCallback<void(ServiceErrorOr<UnexportableAttestationKeyId>)>
callback) = 0;
// Returns all signing keys currently stored by the OS that are have been
// managed by this service.
//
// Invokes `callback` with a `ServiceError` if an error occurs during
// retrieval, or the list of stored keys otherwise.
//
// Note: The intended use case for this method is garbage collecting obsolete
// keys. That is, clients are expected to call this method, and then compare
// the returned keys to the ones present in the client's storage. Keys that
// are returned but no longer recognized by the client should be passed to
// `DeleteKeySlowlyAsync()` soon after.
//
// Note: This method is meaningless on platforms that do not support storing
// keys in the OS, and will return an empty list on those platforms. Here
// clients are not expected to perform garbage collection.
//
// Example usage:
//
// void OnKeys(
// ServiceErrorOr<std::vector<UnexportableSigningKeyId>> maybe_keys) {
// if (!maybe_keys.has_value()) {
// // Handle error.
// return;
// }
//
// UnexportableKeyService& service = GetUnexportableKeyService();
// for (const auto& key : *maybe_keys) {
// if (!MyCodeRecognizesThisKey(key)) {
// // Perform garbage collection.
// service.DeleteKeySlowlyAsync(key, ...);
// }
// }
// }
//
//
// UnexportableKeyService& service = GetUnexportableKeyService();
// service.GetAllKeysForGarbageCollectionSlowlyAsync(
// kPriority,
// base::BindOnce(OnKeys));
virtual void GetAllKeysForGarbageCollectionSlowlyAsync(
BackgroundTaskPriority priority,
base::OnceCallback<void(
ServiceErrorOr<std::vector<UnexportableSigningKeyId>>)> callback) = 0;
// Schedules a new asynchronous signing task.
// Might return a cached result if a task with the same combination of
// `signing_key` and `data` has been completed recently.
// Invokes `callback` with a signature of `data`, or a `ServiceError` if
// `key_id` is not found or an error occurs during signing.
// `key_id` must have resulted from calling `GenerateSigningKeySlowlyAsync()`
// or `FromWrappedSigningKeySlowlyAsync()`.
virtual void SignSlowlyAsync(
UnexportableSigningKeyId key_id,
base::span<const uint8_t> data,
BackgroundTaskPriority priority,
base::OnceCallback<void(ServiceErrorOr<std::vector<uint8_t>>)>
callback) = 0;
// Asynchronously certifies `signing_key_id` with `attestation_key_id` and
// `challenge`.
// Invokes `callback` with either:
// - attestation statement if the certification was successful, or
// - `ServiceError` if the keys are not found or if there was a certification
// error.
virtual void CertifySlowlyAsync(
UnexportableAttestationKeyId attestation_key_id,
UnexportableSigningKeyId signing_key_id,
base::span<const uint8_t> challenge,
BackgroundTaskPriority priority,
base::OnceCallback<void(ServiceErrorOr<crypto::AttestationStatement>)>
callback) = 0;
// Deletes a collection of keys.
//
// Invokes `callback` with the number of deleted keys or a `ServiceError` if
// an error occurs during deletion.
//
// The entries in `key_ids` must have resulted from calling
// `GenerateSigningKeySlowlyAsync()` or `FromWrappedSigningKeySlowlyAsync()`.
//
// Assuming the entries in `key_ids` were found, they are invalidated
// immediately and should not be used again.
//
// Note: On platforms like macOS this will delete the keys from the OS, and
// thus future calls to `FromWrappedSigningKeySlowlyAsync()` with the same
// wrapped keys will fail.
virtual void DeleteKeysSlowlyAsync(
base::span<const UnexportableSigningKeyId> key_ids,
BackgroundTaskPriority priority,
base::OnceCallback<void(ServiceErrorOr<size_t>)> callback) = 0;
// Deletes all keys.
//
// This will remove all keys from the in-memory cache synchronously, cancel
// **all** outstanding key operation requests, and schedule an asynchronous
// deletion task. This will invoke `callback` with a `ServiceError` if an
// error occurs during deletion and the number of deleted keys otherwise.
// Furthermore, the background task is scheduled with the highest priority,
// ensuring that it is completed as soon as possible.
//
// Note: On platforms like macOS this will delete all keys from the OS, and
// thus future calls to `FromWrappedSigningKeySlowlyAsync()` will fail.
virtual void DeleteAllKeysSlowlyAsync(
base::OnceCallback<void(ServiceErrorOr<size_t>)> callback) = 0;
// Returns an SPKI that contains the public key of a key that `key_id` refers
// to.
// Returns a `ServiceError` if `key_id` is not found.
// `key_id` must have resulted from calling `GenerateSigningKeySlowlyAsync()`
// or `FromWrappedSigningKeySlowlyAsync()`
virtual ServiceErrorOr<std::vector<uint8_t>> GetSubjectPublicKeyInfo(
UnexportableSigningKeyId key_id) const = 0;
// Returns the encrypted private key of a key that `key_id` refers to. It is
// encrypted to a key that is kept in hardware and the unencrypted private key
// never exists in the CPU's memory.
// Returns a `ServiceError` if `key_id` is not found.
// `key_id` must have resulted from calling `GenerateSigningKeySlowlyAsync()`
// or `FromWrappedSigningKeySlowlyAsync()`
virtual ServiceErrorOr<std::vector<uint8_t>> GetWrappedKey(
UnexportableSigningKeyId key_id) const = 0;
// Returns the algorithm of a key that `key_id` refers to.
// Returns a `ServiceError` if `key_id` is not found.
// `key_id` must have resulted from calling `GenerateSigningKeySlowlyAsync()`
// or `FromWrappedSigningKeySlowlyAsync()`
virtual ServiceErrorOr<crypto::sign::SignatureKind> GetAlgorithm(
UnexportableSigningKeyId key_id) const = 0;
// Returns the tag of a key that `key_id` refers to.
// Returns a `ServiceError` if `key_id` is not found, or if the key does not
// support stateful operations.
virtual ServiceErrorOr<std::string> GetKeyTag(
UnexportableSigningKeyId key_id) const = 0;
// Returns the time a key that `key_id` refers to was created.
// Returns a `ServiceError` if `key_id` is not found, or if the key does not
// support stateful operations.
virtual ServiceErrorOr<base::Time> GetCreationTime(
UnexportableSigningKeyId key_id) const = 0;
};
} // namespace unexportable_keys
#endif // COMPONENTS_UNEXPORTABLE_KEYS_UNEXPORTABLE_KEY_SERVICE_H_