ANDROID: update "block: add basic hardware-wrapped key support" to v7
The hardware-wrapped key support in this branch is based on my patch "[RFC PATCH v3 1/3] block: add basic hardware-wrapped key support" (https://lore.kernel.org/all/20211021181608.54127-2-ebiggers@kernel.org). I've since made several updates to that patch and it is now at v7. This commit brings in the updates from v3 to v7. The main change is making blk_crypto_derive_sw_secret() operate on a struct block_device, and adding blk_crypto_hw_wrapped_keys_compatible(). This aligns with changes upstream in v6.1 and v6.2 that removed block-layer internal structures from the API that blk-crypto exposes to upper layers. There's also a slight change in prototype for ->derive_sw_secret, so a couple out-of-tree drivers will need to be updated, but people maintaining out-of-tree drivers know what they are dealing with anyway. Bug: 160883801 Link: https://lore.kernel.org/r/20221216203636.81491-2-ebiggers@kernel.org Change-Id: I0f285c11c2764064cd4a9d6eac0089099a9601ed Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
@@ -388,8 +388,8 @@ such as in file-based encryption. Key wrapping is a commonly used technique.)
|
||||
The key which wraps (encrypts) hardware-wrapped keys is a hardware-internal key
|
||||
that is never exposed to software; it is either a persistent key (a "long-term
|
||||
wrapping key") or a per-boot key (an "ephemeral wrapping key"). The long-term
|
||||
wrapped form of the key is what is initially unlocked, but it is discarded as
|
||||
soon as it is converted into an ephemerally-wrapped key. In-use
|
||||
wrapped form of the key is what is initially unlocked, but it is erased from
|
||||
memory as soon as it is converted into an ephemerally-wrapped key. In-use
|
||||
hardware-wrapped keys are always ephemerally-wrapped, not long-term wrapped.
|
||||
|
||||
As inline encryption hardware can only be used to encrypt/decrypt data on-disk,
|
||||
@@ -442,8 +442,8 @@ The components are:
|
||||
for cryptographic applications that require up to a 256-bit security strength.
|
||||
Some use cases (e.g. full-disk encryption) won't require the software secret.
|
||||
|
||||
Example: in the case of fscrypt, the fscrypt master key (the key used to unlock
|
||||
a particular set of encrypted directories) is made hardware-wrapped. The inline
|
||||
Example: in the case of fscrypt, the fscrypt master key (the key that protects a
|
||||
particular set of encrypted directories) is made hardware-wrapped. The inline
|
||||
encryption key is used as the file contents encryption key, while the software
|
||||
secret (rather than the master key directly) is used to key fscrypt's KDF
|
||||
(HKDF-SHA512) to derive other subkeys such as filenames encryption keys.
|
||||
@@ -512,5 +512,6 @@ the hardware RNG and its use to generate the key, as well as the testing of the
|
||||
"import" mode as that should cover all parts other than the key generation.
|
||||
|
||||
For an example of a test that verifies the ciphertext written to disk in the
|
||||
"import" mode, see `Android's vts_kernel_encryption_test
|
||||
"import" mode, see the fscrypt hardware-wrapped key tests in xfstests, or
|
||||
`Android's vts_kernel_encryption_test
|
||||
<https://android.googlesource.com/platform/test/vts-testcase/kernel/+/refs/heads/master/encryption/>`_.
|
||||
|
||||
@@ -540,7 +540,7 @@ static int blk_crypto_fallback_init(void)
|
||||
if (blk_crypto_fallback_inited)
|
||||
return 0;
|
||||
|
||||
prandom_bytes(blank_key, BLK_CRYPTO_MAX_STANDARD_KEY_SIZE);
|
||||
prandom_bytes(blank_key, sizeof(blank_key));
|
||||
|
||||
err = bioset_init(&crypto_bio_split, 64, 0, 0);
|
||||
if (err)
|
||||
|
||||
@@ -466,42 +466,60 @@ bool blk_crypto_register(struct blk_crypto_profile *profile,
|
||||
EXPORT_SYMBOL_GPL(blk_crypto_register);
|
||||
|
||||
/**
|
||||
* blk_crypto_derive_sw_secret() - Derive software secret from hardware-wrapped
|
||||
* key
|
||||
* @profile: the crypto profile of the device the key will be used on
|
||||
* @wrapped_key: the hardware-wrapped key
|
||||
* @wrapped_key_size: size of @wrapped_key in bytes
|
||||
* blk_crypto_derive_sw_secret() - Derive software secret from wrapped key
|
||||
* @bdev: a block device whose hardware-wrapped keys implementation is
|
||||
* compatible (blk_crypto_hw_wrapped_keys_compatible()) with all block
|
||||
* devices on which the key will be used.
|
||||
* @eph_key: the hardware-wrapped key in ephemerally-wrapped form
|
||||
* @eph_key_size: size of @eph_key in bytes
|
||||
* @sw_secret: (output) the software secret
|
||||
*
|
||||
* Given a hardware-wrapped key, ask the hardware to derive the secret which
|
||||
* software can use for cryptographic tasks other than inline encryption. This
|
||||
* secret is guaranteed to be cryptographically isolated from the inline
|
||||
* encryption key, i.e. derived with a different KDF context.
|
||||
* Given a hardware-wrapped key in ephemerally-wrapped form (the same form that
|
||||
* it is used for I/O), ask the hardware to derive the secret which software can
|
||||
* use for cryptographic tasks other than inline encryption. This secret is
|
||||
* guaranteed to be cryptographically isolated from the inline encryption key,
|
||||
* i.e. derived with a different KDF context.
|
||||
*
|
||||
* Return: 0 on success, -EOPNOTSUPP if the given @profile doesn't support
|
||||
* hardware-wrapped keys (or is NULL), -EBADMSG if the key isn't a valid
|
||||
* Return: 0 on success, -EOPNOTSUPP if the block device doesn't support
|
||||
* hardware-wrapped keys, -EBADMSG if the key isn't a valid
|
||||
* hardware-wrapped key, or another -errno code.
|
||||
*/
|
||||
int blk_crypto_derive_sw_secret(struct blk_crypto_profile *profile,
|
||||
const u8 *wrapped_key,
|
||||
unsigned int wrapped_key_size,
|
||||
int blk_crypto_derive_sw_secret(struct block_device *bdev,
|
||||
const u8 *eph_key, size_t eph_key_size,
|
||||
u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
|
||||
{
|
||||
int err = -EOPNOTSUPP;
|
||||
struct blk_crypto_profile *profile =
|
||||
bdev_get_queue(bdev)->crypto_profile;
|
||||
int err;
|
||||
|
||||
if (profile &&
|
||||
(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) &&
|
||||
profile->ll_ops.derive_sw_secret) {
|
||||
blk_crypto_hw_enter(profile);
|
||||
err = profile->ll_ops.derive_sw_secret(profile, wrapped_key,
|
||||
wrapped_key_size,
|
||||
sw_secret);
|
||||
blk_crypto_hw_exit(profile);
|
||||
}
|
||||
if (!profile)
|
||||
return -EOPNOTSUPP;
|
||||
if (!(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED))
|
||||
return -EOPNOTSUPP;
|
||||
if (!profile->ll_ops.derive_sw_secret)
|
||||
return -EOPNOTSUPP;
|
||||
blk_crypto_hw_enter(profile);
|
||||
err = profile->ll_ops.derive_sw_secret(profile, eph_key, eph_key_size,
|
||||
sw_secret);
|
||||
blk_crypto_hw_exit(profile);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_crypto_derive_sw_secret);
|
||||
|
||||
/**
|
||||
* blk_crypto_hw_wrapped_keys_compatible() - Check HW-wrapped key compatibility
|
||||
* @bdev1: the first block device
|
||||
* @bdev2: the second block device
|
||||
*
|
||||
* Return: true if HW-wrapped keys used on @bdev1 can also be used on @bdev2.
|
||||
*/
|
||||
bool blk_crypto_hw_wrapped_keys_compatible(struct block_device *bdev1,
|
||||
struct block_device *bdev2)
|
||||
{
|
||||
return bdev_get_queue(bdev1)->crypto_profile ==
|
||||
bdev_get_queue(bdev2)->crypto_profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* blk_crypto_intersect_capabilities() - restrict supported crypto capabilities
|
||||
* by child device
|
||||
|
||||
@@ -72,7 +72,10 @@ static int __init bio_crypt_ctx_init(void)
|
||||
/* This is assumed in various places. */
|
||||
BUILD_BUG_ON(BLK_ENCRYPTION_MODE_INVALID != 0);
|
||||
|
||||
/* Sanity check that no algorithm exceeds the defined limits. */
|
||||
/*
|
||||
* Validate the crypto mode properties. This ideally would be done with
|
||||
* static assertions, but boot-time checks are the next best thing.
|
||||
*/
|
||||
for (i = 0; i < BLK_ENCRYPTION_MODE_MAX; i++) {
|
||||
BUG_ON(blk_crypto_modes[i].keysize >
|
||||
BLK_CRYPTO_MAX_STANDARD_KEY_SIZE);
|
||||
@@ -328,7 +331,7 @@ int __blk_crypto_rq_bio_prep(struct request *rq, struct bio *bio,
|
||||
* zeroizing both blk_key and raw_key when done with them.
|
||||
*/
|
||||
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
|
||||
const u8 *raw_key, unsigned int raw_key_size,
|
||||
const u8 *raw_key, size_t raw_key_size,
|
||||
enum blk_crypto_key_type key_type,
|
||||
enum blk_crypto_mode_num crypto_mode,
|
||||
unsigned int dun_bytes,
|
||||
|
||||
@@ -60,7 +60,7 @@ struct blk_crypto_ll_ops {
|
||||
|
||||
/**
|
||||
* @derive_sw_secret: Derive the software secret from a hardware-wrapped
|
||||
* key.
|
||||
* key in ephemerally-wrapped form.
|
||||
*
|
||||
* This only needs to be implemented if BLK_CRYPTO_KEY_TYPE_HW_WRAPPED
|
||||
* is supported.
|
||||
@@ -69,8 +69,7 @@ struct blk_crypto_ll_ops {
|
||||
* -errno code on other errors.
|
||||
*/
|
||||
int (*derive_sw_secret)(struct blk_crypto_profile *profile,
|
||||
const u8 *wrapped_key,
|
||||
unsigned int wrapped_key_size,
|
||||
const u8 *eph_key, size_t eph_key_size,
|
||||
u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
|
||||
};
|
||||
|
||||
@@ -100,7 +99,7 @@ struct blk_crypto_profile {
|
||||
unsigned int max_dun_bytes_supported;
|
||||
|
||||
/**
|
||||
* @key_types_supported: Supported types of keys --
|
||||
* @key_types_supported: A bitmask of the supported key types:
|
||||
* BLK_CRYPTO_KEY_TYPE_STANDARD and/or BLK_CRYPTO_KEY_TYPE_HW_WRAPPED.
|
||||
*/
|
||||
unsigned int key_types_supported;
|
||||
@@ -163,11 +162,6 @@ void blk_crypto_reprogram_all_keys(struct blk_crypto_profile *profile);
|
||||
|
||||
void blk_crypto_profile_destroy(struct blk_crypto_profile *profile);
|
||||
|
||||
int blk_crypto_derive_sw_secret(struct blk_crypto_profile *profile,
|
||||
const u8 *wrapped_key,
|
||||
unsigned int wrapped_key_size,
|
||||
u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
|
||||
|
||||
void blk_crypto_intersect_capabilities(struct blk_crypto_profile *parent,
|
||||
const struct blk_crypto_profile *child);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ enum blk_crypto_mode_num {
|
||||
};
|
||||
|
||||
/*
|
||||
* Supported types of keys. Must be bit-flags due to their use in
|
||||
* Supported types of keys. Must be bitflags due to their use in
|
||||
* blk_crypto_profile::key_types_supported.
|
||||
*/
|
||||
enum blk_crypto_key_type {
|
||||
@@ -141,7 +141,7 @@ bool bio_crypt_dun_is_contiguous(const struct bio_crypt_ctx *bc,
|
||||
const u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]);
|
||||
|
||||
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
|
||||
const u8 *raw_key, unsigned int raw_key_size,
|
||||
const u8 *raw_key, size_t raw_key_size,
|
||||
enum blk_crypto_key_type key_type,
|
||||
enum blk_crypto_mode_num crypto_mode,
|
||||
unsigned int dun_bytes,
|
||||
@@ -158,6 +158,13 @@ bool blk_crypto_config_supported_natively(struct block_device *bdev,
|
||||
bool blk_crypto_config_supported(struct block_device *bdev,
|
||||
const struct blk_crypto_config *cfg);
|
||||
|
||||
int blk_crypto_derive_sw_secret(struct block_device *bdev,
|
||||
const u8 *eph_key, size_t eph_key_size,
|
||||
u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
|
||||
|
||||
bool blk_crypto_hw_wrapped_keys_compatible(struct block_device *bdev1,
|
||||
struct block_device *bdev2);
|
||||
|
||||
#else /* CONFIG_BLK_INLINE_ENCRYPTION */
|
||||
|
||||
static inline bool bio_has_crypt_ctx(struct bio *bio)
|
||||
|
||||
Reference in New Issue
Block a user