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:
Eric Biggers
2022-12-16 22:52:12 +00:00
parent 35f067ef8d
commit 3918b39c3e
6 changed files with 66 additions and 43 deletions

View File

@@ -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/>`_.

View File

@@ -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)

View File

@@ -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

View File

@@ -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,

View File

@@ -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);

View File

@@ -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)