ANDROID: block: add KSM op to derive software secret from wrapped key

Some inline encryption hardware supports protecting the keys in hardware
and only exposing wrapped keys to software.  To use this capability,
userspace must provide a hardware-wrapped key rather than a raw key.

However, users of inline encryption in the kernel won't necessarily use
the user-specified key directly for inline encryption.  E.g. with
fscrypt with IV_INO_LBLK_64 policies, each user-provided key is used to
derive a file contents encryption key, filenames encryption key, and key
identifier.  Since inline encryption can only be used with file
contents, if the user were to provide a wrapped key there would
(naively) be no way to encrypt filenames or derive the key identifier.

This problem is solved by designing the hardware to internally use the
unwrapped key as input to a KDF from which multiple cryptographically
isolated keys can be derived, including both the inline crypto key (not
exposed to software) and a secret that *is* exposed to software.

Add a function to the keyslot manager to allow upper layers to request
this software secret from a hardware-wrapped key.

Bug: 147209885

Change-Id: Iffb05b297b7ba3f3e865e798e4bb73aef4e6ba19
Co-developed-by: Gaurav Kashyap <gaurkash@codeaurora.org>
Signed-off-by: Gaurav Kashyap <gaurkash@codeaurora.org>
Signed-off-by: Barani Muthukumaran <bmuthuku@codeaurora.org>
Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
Barani Muthukumaran 2020-01-02 12:01:34 -08:00 committed by Todd Kjos
parent e25d82c5a0
commit 3e8cceb730
2 changed files with 50 additions and 0 deletions

View File

@ -425,3 +425,41 @@ void keyslot_manager_destroy(struct keyslot_manager *ksm)
} }
} }
EXPORT_SYMBOL_GPL(keyslot_manager_destroy); EXPORT_SYMBOL_GPL(keyslot_manager_destroy);
/**
* keyslot_manager_derive_raw_secret() - Derive software secret from wrapped key
* @ksm: The keyslot manager
* @wrapped_key: The wrapped key
* @wrapped_key_size: Size of the wrapped key in bytes
* @secret: (output) the software secret
* @secret_size: (output) the number of secret bytes to derive
*
* Given a hardware-wrapped key, ask the hardware to derive a secret which
* software can use for cryptographic tasks other than inline encryption. The
* derived secret is guaranteed to be cryptographically isolated from the key
* with which any inline encryption with this wrapped key would actually be
* done. I.e., both will be derived from the unwrapped key.
*
* Return: 0 on success, -EOPNOTSUPP if hardware-wrapped keys are unsupported,
* or another -errno code.
*/
int keyslot_manager_derive_raw_secret(struct keyslot_manager *ksm,
const u8 *wrapped_key,
unsigned int wrapped_key_size,
u8 *secret, unsigned int secret_size)
{
int err;
down_write(&ksm->lock);
if (ksm->ksm_ll_ops.derive_raw_secret) {
err = ksm->ksm_ll_ops.derive_raw_secret(ksm, wrapped_key,
wrapped_key_size,
secret, secret_size);
} else {
err = -EOPNOTSUPP;
}
up_write(&ksm->lock);
return err;
}
EXPORT_SYMBOL_GPL(keyslot_manager_derive_raw_secret);

View File

@ -18,6 +18,9 @@ struct keyslot_manager;
* The key is provided so that e.g. dm layers can evict * The key is provided so that e.g. dm layers can evict
* keys from the devices that they map over. * keys from the devices that they map over.
* Returns 0 on success, -errno otherwise. * Returns 0 on success, -errno otherwise.
* @derive_raw_secret: (Optional) Derive a software secret from a
* hardware-wrapped key. Returns 0 on success, -EOPNOTSUPP
* if unsupported on the hardware, or another -errno code.
* *
* This structure should be provided by storage device drivers when they set up * This structure should be provided by storage device drivers when they set up
* a keyslot manager - this structure holds the function ptrs that the keyslot * a keyslot manager - this structure holds the function ptrs that the keyslot
@ -30,6 +33,10 @@ struct keyslot_mgmt_ll_ops {
int (*keyslot_evict)(struct keyslot_manager *ksm, int (*keyslot_evict)(struct keyslot_manager *ksm,
const struct blk_crypto_key *key, const struct blk_crypto_key *key,
unsigned int slot); unsigned int slot);
int (*derive_raw_secret)(struct keyslot_manager *ksm,
const u8 *wrapped_key,
unsigned int wrapped_key_size,
u8 *secret, unsigned int secret_size);
}; };
struct keyslot_manager *keyslot_manager_create(unsigned int num_slots, struct keyslot_manager *keyslot_manager_create(unsigned int num_slots,
@ -57,4 +64,9 @@ void *keyslot_manager_private(struct keyslot_manager *ksm);
void keyslot_manager_destroy(struct keyslot_manager *ksm); void keyslot_manager_destroy(struct keyslot_manager *ksm);
int keyslot_manager_derive_raw_secret(struct keyslot_manager *ksm,
const u8 *wrapped_key,
unsigned int wrapped_key_size,
u8 *secret, unsigned int secret_size);
#endif /* __LINUX_KEYSLOT_MANAGER_H */ #endif /* __LINUX_KEYSLOT_MANAGER_H */