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
|
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
|
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
|
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
|
wrapped form of the key is what is initially unlocked, but it is erased from
|
||||||
soon as it is converted into an ephemerally-wrapped key. In-use
|
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.
|
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,
|
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.
|
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.
|
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
|
Example: in the case of fscrypt, the fscrypt master key (the key that protects a
|
||||||
a particular set of encrypted directories) is made hardware-wrapped. The inline
|
particular set of encrypted directories) is made hardware-wrapped. The inline
|
||||||
encryption key is used as the file contents encryption key, while the software
|
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
|
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.
|
(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.
|
"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
|
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/>`_.
|
<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)
|
if (blk_crypto_fallback_inited)
|
||||||
return 0;
|
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);
|
err = bioset_init(&crypto_bio_split, 64, 0, 0);
|
||||||
if (err)
|
if (err)
|
||||||
|
|||||||
@@ -466,42 +466,60 @@ bool blk_crypto_register(struct blk_crypto_profile *profile,
|
|||||||
EXPORT_SYMBOL_GPL(blk_crypto_register);
|
EXPORT_SYMBOL_GPL(blk_crypto_register);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* blk_crypto_derive_sw_secret() - Derive software secret from hardware-wrapped
|
* blk_crypto_derive_sw_secret() - Derive software secret from wrapped key
|
||||||
* key
|
* @bdev: a block device whose hardware-wrapped keys implementation is
|
||||||
* @profile: the crypto profile of the device the key will be used on
|
* compatible (blk_crypto_hw_wrapped_keys_compatible()) with all block
|
||||||
* @wrapped_key: the hardware-wrapped key
|
* devices on which the key will be used.
|
||||||
* @wrapped_key_size: size of @wrapped_key in bytes
|
* @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
|
* @sw_secret: (output) the software secret
|
||||||
*
|
*
|
||||||
* Given a hardware-wrapped key, ask the hardware to derive the secret which
|
* Given a hardware-wrapped key in ephemerally-wrapped form (the same form that
|
||||||
* software can use for cryptographic tasks other than inline encryption. This
|
* it is used for I/O), ask the hardware to derive the secret which software can
|
||||||
* secret is guaranteed to be cryptographically isolated from the inline
|
* use for cryptographic tasks other than inline encryption. This secret is
|
||||||
* encryption key, i.e. derived with a different KDF context.
|
* 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
|
* Return: 0 on success, -EOPNOTSUPP if the block device doesn't support
|
||||||
* hardware-wrapped keys (or is NULL), -EBADMSG if the key isn't a valid
|
* hardware-wrapped keys, -EBADMSG if the key isn't a valid
|
||||||
* hardware-wrapped key, or another -errno code.
|
* hardware-wrapped key, or another -errno code.
|
||||||
*/
|
*/
|
||||||
int blk_crypto_derive_sw_secret(struct blk_crypto_profile *profile,
|
int blk_crypto_derive_sw_secret(struct block_device *bdev,
|
||||||
const u8 *wrapped_key,
|
const u8 *eph_key, size_t eph_key_size,
|
||||||
unsigned int wrapped_key_size,
|
|
||||||
u8 sw_secret[BLK_CRYPTO_SW_SECRET_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 &&
|
if (!profile)
|
||||||
(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) &&
|
return -EOPNOTSUPP;
|
||||||
profile->ll_ops.derive_sw_secret) {
|
if (!(profile->key_types_supported & BLK_CRYPTO_KEY_TYPE_HW_WRAPPED))
|
||||||
blk_crypto_hw_enter(profile);
|
return -EOPNOTSUPP;
|
||||||
err = profile->ll_ops.derive_sw_secret(profile, wrapped_key,
|
if (!profile->ll_ops.derive_sw_secret)
|
||||||
wrapped_key_size,
|
return -EOPNOTSUPP;
|
||||||
sw_secret);
|
blk_crypto_hw_enter(profile);
|
||||||
blk_crypto_hw_exit(profile);
|
err = profile->ll_ops.derive_sw_secret(profile, eph_key, eph_key_size,
|
||||||
}
|
sw_secret);
|
||||||
|
blk_crypto_hw_exit(profile);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(blk_crypto_derive_sw_secret);
|
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
|
* blk_crypto_intersect_capabilities() - restrict supported crypto capabilities
|
||||||
* by child device
|
* by child device
|
||||||
|
|||||||
@@ -72,7 +72,10 @@ static int __init bio_crypt_ctx_init(void)
|
|||||||
/* This is assumed in various places. */
|
/* This is assumed in various places. */
|
||||||
BUILD_BUG_ON(BLK_ENCRYPTION_MODE_INVALID != 0);
|
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++) {
|
for (i = 0; i < BLK_ENCRYPTION_MODE_MAX; i++) {
|
||||||
BUG_ON(blk_crypto_modes[i].keysize >
|
BUG_ON(blk_crypto_modes[i].keysize >
|
||||||
BLK_CRYPTO_MAX_STANDARD_KEY_SIZE);
|
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.
|
* zeroizing both blk_key and raw_key when done with them.
|
||||||
*/
|
*/
|
||||||
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
|
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_key_type key_type,
|
||||||
enum blk_crypto_mode_num crypto_mode,
|
enum blk_crypto_mode_num crypto_mode,
|
||||||
unsigned int dun_bytes,
|
unsigned int dun_bytes,
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ struct blk_crypto_ll_ops {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @derive_sw_secret: Derive the software secret from a hardware-wrapped
|
* @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
|
* This only needs to be implemented if BLK_CRYPTO_KEY_TYPE_HW_WRAPPED
|
||||||
* is supported.
|
* is supported.
|
||||||
@@ -69,8 +69,7 @@ struct blk_crypto_ll_ops {
|
|||||||
* -errno code on other errors.
|
* -errno code on other errors.
|
||||||
*/
|
*/
|
||||||
int (*derive_sw_secret)(struct blk_crypto_profile *profile,
|
int (*derive_sw_secret)(struct blk_crypto_profile *profile,
|
||||||
const u8 *wrapped_key,
|
const u8 *eph_key, size_t eph_key_size,
|
||||||
unsigned int wrapped_key_size,
|
|
||||||
u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
|
u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -100,7 +99,7 @@ struct blk_crypto_profile {
|
|||||||
unsigned int max_dun_bytes_supported;
|
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.
|
* BLK_CRYPTO_KEY_TYPE_STANDARD and/or BLK_CRYPTO_KEY_TYPE_HW_WRAPPED.
|
||||||
*/
|
*/
|
||||||
unsigned int key_types_supported;
|
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);
|
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,
|
void blk_crypto_intersect_capabilities(struct blk_crypto_profile *parent,
|
||||||
const struct blk_crypto_profile *child);
|
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.
|
* blk_crypto_profile::key_types_supported.
|
||||||
*/
|
*/
|
||||||
enum blk_crypto_key_type {
|
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]);
|
const u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]);
|
||||||
|
|
||||||
int blk_crypto_init_key(struct blk_crypto_key *blk_key,
|
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_key_type key_type,
|
||||||
enum blk_crypto_mode_num crypto_mode,
|
enum blk_crypto_mode_num crypto_mode,
|
||||||
unsigned int dun_bytes,
|
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,
|
bool blk_crypto_config_supported(struct block_device *bdev,
|
||||||
const struct blk_crypto_config *cfg);
|
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 */
|
#else /* CONFIG_BLK_INLINE_ENCRYPTION */
|
||||||
|
|
||||||
static inline bool bio_has_crypt_ctx(struct bio *bio)
|
static inline bool bio_has_crypt_ctx(struct bio *bio)
|
||||||
|
|||||||
Reference in New Issue
Block a user