From 3e8cceb73080bc5c5a6b1e210678b753270a8030 Mon Sep 17 00:00:00 2001 From: Barani Muthukumaran Date: Thu, 2 Jan 2020 12:01:34 -0800 Subject: [PATCH] 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 Signed-off-by: Gaurav Kashyap Signed-off-by: Barani Muthukumaran Signed-off-by: Eric Biggers --- block/keyslot-manager.c | 38 +++++++++++++++++++++++++++++++++ include/linux/keyslot-manager.h | 12 +++++++++++ 2 files changed, 50 insertions(+) diff --git a/block/keyslot-manager.c b/block/keyslot-manager.c index 52f94a5a9680..8209db5ab1e1 100644 --- a/block/keyslot-manager.c +++ b/block/keyslot-manager.c @@ -425,3 +425,41 @@ void keyslot_manager_destroy(struct keyslot_manager *ksm) } } 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); diff --git a/include/linux/keyslot-manager.h b/include/linux/keyslot-manager.h index fbc423fe5cd5..17dfcaf208fb 100644 --- a/include/linux/keyslot-manager.h +++ b/include/linux/keyslot-manager.h @@ -18,6 +18,9 @@ struct keyslot_manager; * The key is provided so that e.g. dm layers can evict * keys from the devices that they map over. * 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 * 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, const struct blk_crypto_key *key, 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, @@ -57,4 +64,9 @@ void *keyslot_manager_private(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 */