mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-31 06:09:56 +00:00

Until this point, the kernel can use hardware-wrapped keys to do encryption if userspace provides one -- specifically a key in ephemerally-wrapped form. However, no generic way has been provided for userspace to get such a key in the first place. Getting such a key is a two-step process. First, the key needs to be imported from a raw key or generated by the hardware, producing a key in long-term wrapped form. This happens once in the whole lifetime of the key. Second, the long-term wrapped key needs to be converted into ephemerally-wrapped form. This happens each time the key is "unlocked". In Android, these operations are supported in a generic way through KeyMint, a userspace abstraction layer. However, that method is Android-specific and can't be used on other Linux systems, may rely on proprietary libraries, and also misleads people into supporting KeyMint features like rollback resistance that make sense for other KeyMint keys but don't make sense for hardware-wrapped inline encryption keys. Therefore, this patch provides a generic kernel interface for these operations by introducing new block device ioctls: - BLKCRYPTOIMPORTKEY: convert a raw key to long-term wrapped form. - BLKCRYPTOGENERATEKEY: have the hardware generate a new key, then return it in long-term wrapped form. - BLKCRYPTOPREPAREKEY: convert a key from long-term wrapped form to ephemerally-wrapped form. These ioctls are implemented using new operations in blk_crypto_ll_ops. Signed-off-by: Eric Biggers <ebiggers@google.com> Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> # sm8650 Link: https://lore.kernel.org/r/20250204060041.409950-4-ebiggers@kernel.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
229 lines
7.9 KiB
C
229 lines
7.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright 2019 Google LLC
|
|
*/
|
|
|
|
#ifndef __LINUX_BLK_CRYPTO_PROFILE_H
|
|
#define __LINUX_BLK_CRYPTO_PROFILE_H
|
|
|
|
#include <linux/bio.h>
|
|
#include <linux/blk-crypto.h>
|
|
|
|
struct blk_crypto_profile;
|
|
|
|
/**
|
|
* struct blk_crypto_ll_ops - functions to control inline encryption hardware
|
|
*
|
|
* Low-level operations for controlling inline encryption hardware. This
|
|
* interface must be implemented by storage drivers that support inline
|
|
* encryption. All functions may sleep, are serialized by profile->lock, and
|
|
* are never called while profile->dev (if set) is runtime-suspended.
|
|
*/
|
|
struct blk_crypto_ll_ops {
|
|
|
|
/**
|
|
* @keyslot_program: Program a key into the inline encryption hardware.
|
|
*
|
|
* Program @key into the specified @slot in the inline encryption
|
|
* hardware, overwriting any key that the keyslot may already contain.
|
|
* The keyslot is guaranteed to not be in-use by any I/O.
|
|
*
|
|
* This is required if the device has keyslots. Otherwise (i.e. if the
|
|
* device is a layered device, or if the device is real hardware that
|
|
* simply doesn't have the concept of keyslots) it is never called.
|
|
*
|
|
* Must return 0 on success, or -errno on failure.
|
|
*/
|
|
int (*keyslot_program)(struct blk_crypto_profile *profile,
|
|
const struct blk_crypto_key *key,
|
|
unsigned int slot);
|
|
|
|
/**
|
|
* @keyslot_evict: Evict a key from the inline encryption hardware.
|
|
*
|
|
* If the device has keyslots, this function must evict the key from the
|
|
* specified @slot. The slot will contain @key, but there should be no
|
|
* need for the @key argument to be used as @slot should be sufficient.
|
|
* The keyslot is guaranteed to not be in-use by any I/O.
|
|
*
|
|
* If the device doesn't have keyslots itself, this function must evict
|
|
* @key from any underlying devices. @slot won't be valid in this case.
|
|
*
|
|
* If there are no keyslots and no underlying devices, this function
|
|
* isn't required.
|
|
*
|
|
* Must return 0 on success, or -errno on failure.
|
|
*/
|
|
int (*keyslot_evict)(struct blk_crypto_profile *profile,
|
|
const struct blk_crypto_key *key,
|
|
unsigned int slot);
|
|
|
|
/**
|
|
* @derive_sw_secret: Derive the software secret from a hardware-wrapped
|
|
* key in ephemerally-wrapped form.
|
|
*
|
|
* This only needs to be implemented if BLK_CRYPTO_KEY_TYPE_HW_WRAPPED
|
|
* is supported.
|
|
*
|
|
* Must return 0 on success, -EBADMSG if the key is invalid, or another
|
|
* -errno code on other errors.
|
|
*/
|
|
int (*derive_sw_secret)(struct blk_crypto_profile *profile,
|
|
const u8 *eph_key, size_t eph_key_size,
|
|
u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
|
|
|
|
/**
|
|
* @import_key: Create a hardware-wrapped key by importing a raw key.
|
|
*
|
|
* This only needs to be implemented if BLK_CRYPTO_KEY_TYPE_HW_WRAPPED
|
|
* is supported.
|
|
*
|
|
* On success, must write the new key in long-term wrapped form to
|
|
* @lt_key and return its size in bytes. On failure, must return a
|
|
* -errno value.
|
|
*/
|
|
int (*import_key)(struct blk_crypto_profile *profile,
|
|
const u8 *raw_key, size_t raw_key_size,
|
|
u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
|
|
|
|
/**
|
|
* @generate_key: Generate a hardware-wrapped key.
|
|
*
|
|
* This only needs to be implemented if BLK_CRYPTO_KEY_TYPE_HW_WRAPPED
|
|
* is supported.
|
|
*
|
|
* On success, must write the new key in long-term wrapped form to
|
|
* @lt_key and return its size in bytes. On failure, must return a
|
|
* -errno value.
|
|
*/
|
|
int (*generate_key)(struct blk_crypto_profile *profile,
|
|
u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
|
|
|
|
/**
|
|
* @prepare_key: Prepare a hardware-wrapped key to be used.
|
|
*
|
|
* Prepare a hardware-wrapped key to be used by converting it from
|
|
* long-term wrapped form to ephemerally-wrapped form. This only needs
|
|
* to be implemented if BLK_CRYPTO_KEY_TYPE_HW_WRAPPED is supported.
|
|
*
|
|
* On success, must write the key in ephemerally-wrapped form to
|
|
* @eph_key and return its size in bytes. On failure, must return
|
|
* -EBADMSG if the key is invalid, or another -errno on other error.
|
|
*/
|
|
int (*prepare_key)(struct blk_crypto_profile *profile,
|
|
const u8 *lt_key, size_t lt_key_size,
|
|
u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
|
|
};
|
|
|
|
/**
|
|
* struct blk_crypto_profile - inline encryption profile for a device
|
|
*
|
|
* This struct contains a storage device's inline encryption capabilities (e.g.
|
|
* the supported crypto algorithms), driver-provided functions to control the
|
|
* inline encryption hardware (e.g. programming and evicting keys), and optional
|
|
* device-independent keyslot management data.
|
|
*/
|
|
struct blk_crypto_profile {
|
|
|
|
/* public: Drivers must initialize the following fields. */
|
|
|
|
/**
|
|
* @ll_ops: Driver-provided functions to control the inline encryption
|
|
* hardware, e.g. program and evict keys.
|
|
*/
|
|
struct blk_crypto_ll_ops ll_ops;
|
|
|
|
/**
|
|
* @max_dun_bytes_supported: The maximum number of bytes supported for
|
|
* specifying the data unit number (DUN). Specifically, the range of
|
|
* supported DUNs is 0 through (1 << (8 * max_dun_bytes_supported)) - 1.
|
|
*/
|
|
unsigned int max_dun_bytes_supported;
|
|
|
|
/**
|
|
* @key_types_supported: A bitmask of the supported key types:
|
|
* BLK_CRYPTO_KEY_TYPE_RAW and/or BLK_CRYPTO_KEY_TYPE_HW_WRAPPED.
|
|
*/
|
|
unsigned int key_types_supported;
|
|
|
|
/**
|
|
* @modes_supported: Array of bitmasks that specifies whether each
|
|
* combination of crypto mode and data unit size is supported.
|
|
* Specifically, the i'th bit of modes_supported[crypto_mode] is set if
|
|
* crypto_mode can be used with a data unit size of (1 << i). Note that
|
|
* only data unit sizes that are powers of 2 can be supported.
|
|
*/
|
|
unsigned int modes_supported[BLK_ENCRYPTION_MODE_MAX];
|
|
|
|
/**
|
|
* @dev: An optional device for runtime power management. If the driver
|
|
* provides this device, it will be runtime-resumed before any function
|
|
* in @ll_ops is called and will remain resumed during the call.
|
|
*/
|
|
struct device *dev;
|
|
|
|
/* private: The following fields shouldn't be accessed by drivers. */
|
|
|
|
/* Number of keyslots, or 0 if not applicable */
|
|
unsigned int num_slots;
|
|
|
|
/*
|
|
* Serializes all calls to functions in @ll_ops as well as all changes
|
|
* to @slot_hashtable. This can also be taken in read mode to look up
|
|
* keyslots while ensuring that they can't be changed concurrently.
|
|
*/
|
|
struct rw_semaphore lock;
|
|
struct lock_class_key lockdep_key;
|
|
|
|
/* List of idle slots, with least recently used slot at front */
|
|
wait_queue_head_t idle_slots_wait_queue;
|
|
struct list_head idle_slots;
|
|
spinlock_t idle_slots_lock;
|
|
|
|
/*
|
|
* Hash table which maps struct *blk_crypto_key to keyslots, so that we
|
|
* can find a key's keyslot in O(1) time rather than O(num_slots).
|
|
* Protected by 'lock'.
|
|
*/
|
|
struct hlist_head *slot_hashtable;
|
|
unsigned int log_slot_ht_size;
|
|
|
|
/* Per-keyslot data */
|
|
struct blk_crypto_keyslot *slots;
|
|
};
|
|
|
|
int blk_crypto_profile_init(struct blk_crypto_profile *profile,
|
|
unsigned int num_slots);
|
|
|
|
int devm_blk_crypto_profile_init(struct device *dev,
|
|
struct blk_crypto_profile *profile,
|
|
unsigned int num_slots);
|
|
|
|
unsigned int blk_crypto_keyslot_index(struct blk_crypto_keyslot *slot);
|
|
|
|
void blk_crypto_reprogram_all_keys(struct blk_crypto_profile *profile);
|
|
|
|
void blk_crypto_profile_destroy(struct blk_crypto_profile *profile);
|
|
|
|
int blk_crypto_import_key(struct blk_crypto_profile *profile,
|
|
const u8 *raw_key, size_t raw_key_size,
|
|
u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
|
|
|
|
int blk_crypto_generate_key(struct blk_crypto_profile *profile,
|
|
u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
|
|
|
|
int blk_crypto_prepare_key(struct blk_crypto_profile *profile,
|
|
const u8 *lt_key, size_t lt_key_size,
|
|
u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
|
|
|
|
void blk_crypto_intersect_capabilities(struct blk_crypto_profile *parent,
|
|
const struct blk_crypto_profile *child);
|
|
|
|
bool blk_crypto_has_capabilities(const struct blk_crypto_profile *target,
|
|
const struct blk_crypto_profile *reference);
|
|
|
|
void blk_crypto_update_capabilities(struct blk_crypto_profile *dst,
|
|
const struct blk_crypto_profile *src);
|
|
|
|
#endif /* __LINUX_BLK_CRYPTO_PROFILE_H */
|