From b78cb721e87dd0a88c99463f50751e0fc2255ed9 Mon Sep 17 00:00:00 2001 From: Gaurav Kashyap Date: Sun, 28 Jun 2020 13:19:18 -0700 Subject: [PATCH] soc: qcom: crypto-qti-hwkm: add wrapped raw secret Add support to derive raw secret using HWKM instead of using a plaintext value from the exported key. This raw secret that is derived using HWKM is used to derive the key identifier in fscrypt and also the filenames encryption key. Change-Id: Id1401555a2d01354753cbe708eb23dc091d2589f Signed-off-by: Gaurav Kashyap --- drivers/scsi/ufs/ufshcd-crypto-qti.c | 20 +++- drivers/soc/qcom/crypto-qti-common.c | 16 ++- drivers/soc/qcom/crypto-qti-hwkm.c | 145 ++++++++++++++++++++++++- drivers/soc/qcom/crypto-qti-platform.h | 15 +++ drivers/soc/qcom/crypto-qti-tz.c | 11 ++ include/linux/crypto-qti-common.h | 6 +- 6 files changed, 201 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd-crypto-qti.c b/drivers/scsi/ufs/ufshcd-crypto-qti.c index 6a447f16a163..a7f629d7c943 100644 --- a/drivers/scsi/ufs/ufshcd-crypto-qti.c +++ b/drivers/scsi/ufs/ufshcd-crypto-qti.c @@ -147,8 +147,24 @@ static int ufshcd_crypto_qti_derive_raw_secret(struct keyslot_manager *ksm, u8 *secret, unsigned int secret_size) { - return crypto_qti_derive_raw_secret(wrapped_key, wrapped_key_size, - secret, secret_size); + int err = 0; + struct ufs_hba *hba = keyslot_manager_private(ksm); + + pm_runtime_get_sync(hba->dev); + err = ufshcd_hold(hba, false); + if (err) { + pr_err("%s: failed to enable clocks, err %d\n", __func__, err); + return err; + } + + err = crypto_qti_derive_raw_secret(hba->crypto_vops->priv, + wrapped_key, wrapped_key_size, + secret, secret_size); + + ufshcd_release(hba); + pm_runtime_put_sync(hba->dev); + + return err; } static const struct keyslot_mgmt_ll_ops ufshcd_crypto_qti_ksm_ops = { diff --git a/drivers/soc/qcom/crypto-qti-common.c b/drivers/soc/qcom/crypto-qti-common.c index 649dc1d0a29b..ee4cb2dda82a 100644 --- a/drivers/soc/qcom/crypto-qti-common.c +++ b/drivers/soc/qcom/crypto-qti-common.c @@ -443,11 +443,19 @@ int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot) } EXPORT_SYMBOL(crypto_qti_keyslot_evict); -int crypto_qti_derive_raw_secret(const u8 *wrapped_key, +int crypto_qti_derive_raw_secret(void *priv_data, + const u8 *wrapped_key, unsigned int wrapped_key_size, u8 *secret, unsigned int secret_size) { int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } if (wrapped_key_size <= RAW_SECRET_SIZE) { pr_err("%s: Invalid wrapped_key_size: %u\n", @@ -461,9 +469,9 @@ int crypto_qti_derive_raw_secret(const u8 *wrapped_key, return err; } - memcpy(secret, wrapped_key, secret_size); - - return err; + return crypto_qti_derive_raw_secret_platform(ice_entry, + wrapped_key, wrapped_key_size, + secret, secret_size); } EXPORT_SYMBOL(crypto_qti_derive_raw_secret); diff --git a/drivers/soc/qcom/crypto-qti-hwkm.c b/drivers/soc/qcom/crypto-qti-hwkm.c index e8fe8350adc9..92e33ee31c2f 100644 --- a/drivers/soc/qcom/crypto-qti-hwkm.c +++ b/drivers/soc/qcom/crypto-qti-hwkm.c @@ -17,11 +17,14 @@ #define TPKEY_SLOT_ICEMEM_SLAVE 0x92 #define KEYMANAGER_ICE_MAP_SLOT(slot) ((slot * 2) + 10) #define GP_KEYSLOT 140 +#define RAW_SECRET_KEYSLOT 141 #define QTI_HWKM_INIT_DONE 0x1 #define SLOT_EMPTY_ERROR 0x1000 #define INLINECRYPT_CTX "inline encryption key" +#define RAW_SECRET_CTX "raw secret" #define BYTE_ORDER_VAL 8 +#define KEY_WRAPPED_SIZE 68 union crypto_cfg { __le32 regval[2]; @@ -98,7 +101,7 @@ int crypto_qti_program_key(struct crypto_vops_qti_entry *ice_entry, } //Failsafe, clear GP_KEYSLOT incase it is not empty for any reason - err_clear = crypto_qti_hwkm_evict_slot(GP_KEYSLOT, true); + err_clear = crypto_qti_hwkm_evict_slot(GP_KEYSLOT, false); if (err_clear && (err_clear != SLOT_EMPTY_ERROR)) { pr_err("%s: Error clearing ICE slot %d, err %d\n", __func__, GP_KEYSLOT, err_clear); @@ -110,9 +113,16 @@ int crypto_qti_program_key(struct crypto_vops_qti_entry *ice_entry, cmd_unwrap.op = KEY_UNWRAP_IMPORT; cmd_unwrap.unwrap.dks = GP_KEYSLOT; cmd_unwrap.unwrap.kwk = TPKEY_SLOT_ICEMEM_SLAVE; - cmd_unwrap.unwrap.sz = (key->size) - RAW_SECRET_SIZE; - memcpy(cmd_unwrap.unwrap.wkb, (key->raw) + RAW_SECRET_SIZE, - cmd_unwrap.unwrap.sz); + if ((key->size) == KEY_WRAPPED_SIZE) { + cmd_unwrap.unwrap.sz = key->size; + memcpy(cmd_unwrap.unwrap.wkb, key->raw, + cmd_unwrap.unwrap.sz); + } else { + cmd_unwrap.unwrap.sz = (key->size) - RAW_SECRET_SIZE; + memcpy(cmd_unwrap.unwrap.wkb, (key->raw) + RAW_SECRET_SIZE, + cmd_unwrap.unwrap.sz); + } + err_program = qti_hwkm_handle_cmd(&cmd_unwrap, &rsp_unwrap); if (err_program) { pr_err("%s: Error with key unwrap %d\n", __func__, @@ -214,5 +224,132 @@ void crypto_qti_disable_platform(struct crypto_vops_qti_entry *ice_entry) } EXPORT_SYMBOL(crypto_qti_disable_platform); +int crypto_qti_derive_raw_secret_platform( + struct crypto_vops_qti_entry *ice_entry, + const u8 *wrapped_key, + unsigned int wrapped_key_size, u8 *secret, + unsigned int secret_size) +{ + int err_program = 0; + int err_clear = 0; + struct hwkm_cmd cmd_unwrap; + struct hwkm_cmd cmd_kdf; + struct hwkm_cmd cmd_read; + struct hwkm_rsp rsp_unwrap; + struct hwkm_rsp rsp_kdf; + struct hwkm_rsp rsp_read; + + struct hwkm_key_policy policy_kdf = { + .security_lvl = SW_KEY, + .hw_destination = ICEMEM_SLAVE, + .key_type = GENERIC_KEY, + .enc_allowed = true, + .dec_allowed = true, + .alg_allowed = AES256_CBC, + .km_by_nsec_allowed = true, + }; + struct hwkm_bsve bsve_kdf = { + .enabled = true, + .km_swc_en = true, + .km_child_key_policy_en = true, + }; + + if (wrapped_key_size != KEY_WRAPPED_SIZE) { + memcpy(secret, wrapped_key, secret_size); + return 0; + } + + err_program = qti_hwkm_clocks(true); + if (err_program) { + pr_err("%s: Error enabling clocks %d\n", __func__, + err_program); + return err_program; + } + + if ((ice_entry->flags & QTI_HWKM_INIT_DONE) != QTI_HWKM_INIT_DONE) { + err_program = qti_hwkm_init(); + if (err_program) { + pr_err("%s: Error with HWKM init %d\n", __func__, + err_program); + qti_hwkm_clocks(false); + return -EINVAL; + } + ice_entry->flags |= QTI_HWKM_INIT_DONE; + } + + //Failsafe, clear GP_KEYSLOT incase it is not empty for any reason + err_clear = crypto_qti_hwkm_evict_slot(GP_KEYSLOT, false); + if (err_clear && (err_clear != SLOT_EMPTY_ERROR)) { + pr_err("%s: Error clearing GP slot %d, err %d\n", + __func__, GP_KEYSLOT, err_clear); + qti_hwkm_clocks(false); + return -EINVAL; + } + + /* Unwrap keyblob into a non ICE slot using TP key */ + cmd_unwrap.op = KEY_UNWRAP_IMPORT; + cmd_unwrap.unwrap.dks = GP_KEYSLOT; + cmd_unwrap.unwrap.kwk = TPKEY_SLOT_ICEMEM_SLAVE; + cmd_unwrap.unwrap.sz = wrapped_key_size; + memcpy(cmd_unwrap.unwrap.wkb, wrapped_key, + cmd_unwrap.unwrap.sz); + + err_program = qti_hwkm_handle_cmd(&cmd_unwrap, &rsp_unwrap); + if (err_program) { + pr_err("%s: Error with key unwrap %d\n", __func__, + err_program); + qti_hwkm_clocks(false); + return -EINVAL; + } + + //Failsafe, clear RAW_SECRET_KEYSLOT incase it is not empty + err_clear = crypto_qti_hwkm_evict_slot(RAW_SECRET_KEYSLOT, false); + if (err_clear && (err_clear != SLOT_EMPTY_ERROR)) { + pr_err("%s: Error clearing raw secret slot %d, err %d\n", + __func__, RAW_SECRET_KEYSLOT, err_clear); + qti_hwkm_clocks(false); + return -EINVAL; + } + + /* Derive a 512-bit key which will be the key to encrypt/decrypt data */ + cmd_kdf.op = SYSTEM_KDF; + cmd_kdf.kdf.dks = RAW_SECRET_KEYSLOT; + cmd_kdf.kdf.kdk = GP_KEYSLOT; + cmd_kdf.kdf.policy = policy_kdf; + cmd_kdf.kdf.bsve = bsve_kdf; + cmd_kdf.kdf.sz = round_up(strlen(RAW_SECRET_CTX), BYTE_ORDER_VAL); + memset(cmd_kdf.kdf.ctx, 0, HWKM_MAX_CTX_SIZE); + memcpy(cmd_kdf.kdf.ctx, RAW_SECRET_CTX, strlen(RAW_SECRET_CTX)); + + err_program = qti_hwkm_handle_cmd(&cmd_kdf, &rsp_kdf); + if (err_program) { + pr_err("%s: Error deriving secret %d, slot %d\n", __func__, + err_program, RAW_SECRET_KEYSLOT); + err_program = -EINVAL; + } + + //Read the KDF key for raw secret + cmd_read.op = KEY_SLOT_RDWR; + cmd_read.rdwr.slot = RAW_SECRET_KEYSLOT; + cmd_read.rdwr.is_write = false; + err_program = qti_hwkm_handle_cmd(&cmd_read, &rsp_read); + if (err_program) { + pr_err("%s: Error with key read %d\n", __func__, err_program); + err_program = -EINVAL; + } + memcpy(secret, rsp_read.rdwr.key, rsp_read.rdwr.sz); + + err_clear = crypto_qti_hwkm_evict_slot(GP_KEYSLOT, false); + if (err_clear) + pr_err("%s: GP slot clear %d\n", __func__, err_clear); + err_clear = crypto_qti_hwkm_evict_slot(RAW_SECRET_KEYSLOT, false); + if (err_clear) + pr_err("%s: raw secret slot clear %d\n", __func__, err_clear); + + qti_hwkm_clocks(false); + return err_program; +} +EXPORT_SYMBOL(crypto_qti_derive_raw_secret_platform); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Crypto HWKM library for storage encryption"); diff --git a/drivers/soc/qcom/crypto-qti-platform.h b/drivers/soc/qcom/crypto-qti-platform.h index 02e1067b9a5f..cb4570f9f5de 100644 --- a/drivers/soc/qcom/crypto-qti-platform.h +++ b/drivers/soc/qcom/crypto-qti-platform.h @@ -18,6 +18,12 @@ int crypto_qti_program_key(struct crypto_vops_qti_entry *ice_entry, unsigned int data_unit_mask, int capid); int crypto_qti_invalidate_key(struct crypto_vops_qti_entry *ice_entry, unsigned int slot); +int crypto_qti_derive_raw_secret_platform( + struct crypto_vops_qti_entry *ice_entry, + const u8 *wrapped_key, + unsigned int wrapped_key_size, u8 *secret, + unsigned int secret_size); + #if IS_ENABLED(CONFIG_QTI_HW_KEY_MANAGER) void crypto_qti_disable_platform(struct crypto_vops_qti_entry *ice_entry); #else @@ -39,6 +45,15 @@ static inline int crypto_qti_invalidate_key( { return -EOPNOTSUPP; } +static inline int crypto_qti_derive_raw_secret_platform( + struct crypto_vops_qti_entry *ice_entry, + const u8 *wrapped_key, + unsigned int wrapped_key_size, u8 *secret, + unsigned int secret_size) +{ + return -EOPNOTSUPP; +} + static inline void crypto_qti_disable_platform( struct crypto_vops_qti_entry *ice_entry) {} diff --git a/drivers/soc/qcom/crypto-qti-tz.c b/drivers/soc/qcom/crypto-qti-tz.c index 622a32189022..5a675210db52 100644 --- a/drivers/soc/qcom/crypto-qti-tz.c +++ b/drivers/soc/qcom/crypto-qti-tz.c @@ -58,5 +58,16 @@ int crypto_qti_invalidate_key(struct crypto_vops_qti_entry *ice_entry, } EXPORT_SYMBOL(crypto_qti_invalidate_key); +int crypto_qti_derive_raw_secret_platform( + struct crypto_vops_qti_entry *ice_entry, + const u8 *wrapped_key, + unsigned int wrapped_key_size, u8 *secret, + unsigned int secret_size) +{ + memcpy(secret, wrapped_key, secret_size); + return 0; +} +EXPORT_SYMBOL(crypto_qti_derive_raw_secret_platform); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Crypto TZ library for storage encryption"); diff --git a/include/linux/crypto-qti-common.h b/include/linux/crypto-qti-common.h index 40606854edc6..56ea368a50fa 100644 --- a/include/linux/crypto-qti-common.h +++ b/include/linux/crypto-qti-common.h @@ -35,7 +35,8 @@ int crypto_qti_keyslot_program(void *priv_data, unsigned int slot, u8 data_unit_mask, int capid); int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot); -int crypto_qti_derive_raw_secret(const u8 *wrapped_key, +int crypto_qti_derive_raw_secret(void *priv_data, + const u8 *wrapped_key, unsigned int wrapped_key_size, u8 *secret, unsigned int secret_size); @@ -74,7 +75,8 @@ static inline int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot) { return -EOPNOTSUPP; } -static inline int crypto_qti_derive_raw_secret(const u8 *wrapped_key, +static inline int crypto_qti_derive_raw_secret(void *priv_data, + const u8 *wrapped_key, unsigned int wrapped_key_size, u8 *secret, unsigned int secret_size)