mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-11-01 09:13:37 +00:00
firmware: qcom: scm: add calls for wrapped key support
Add helper functions for the SCM calls required to support
hardware-wrapped inline storage encryption keys. These SCM calls manage
wrapped keys via Qualcomm's Hardware Key Manager (HWKM), which can only
be accessed from TrustZone.
QCOM_SCM_ES_GENERATE_ICE_KEY and QCOM_SCM_ES_IMPORT_ICE_KEY create a new
long-term wrapped key, with the former making the hardware generate the
key and the latter importing a raw key. QCOM_SCM_ES_PREPARE_ICE_KEY
converts the key to ephemerally-wrapped form so that it can be used for
inline storage encryption. These are planned to be wired up to new
ioctls via the blk-crypto framework; see the proposed documentation for
the hardware-wrapped keys feature for more information.
Similarly there's also QCOM_SCM_ES_DERIVE_SW_SECRET which derives a
"software secret" from an ephemerally-wrapped key and will be wired up
to the corresponding operation in the blk_crypto_profile.
These will all be used by the ICE driver in drivers/soc/qcom/ice.c.
[EB: merged related patches, fixed error handling, fixed naming, fixed
docs for size parameters, fixed qcom_scm_has_wrapped_key_support(),
improved comments, improved commit message.]
Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Link: https://lore.kernel.org/r/20241213041958.202565-9-ebiggers@kernel.org
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
This commit is contained in:
parent
8e6854efd4
commit
1d45a1cd9f
3 changed files with 226 additions and 0 deletions
|
|
@ -1282,6 +1282,220 @@ int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_ice_set_key);
|
||||
|
||||
bool qcom_scm_has_wrapped_key_support(void)
|
||||
{
|
||||
return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
|
||||
QCOM_SCM_ES_DERIVE_SW_SECRET) &&
|
||||
__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
|
||||
QCOM_SCM_ES_GENERATE_ICE_KEY) &&
|
||||
__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
|
||||
QCOM_SCM_ES_PREPARE_ICE_KEY) &&
|
||||
__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
|
||||
QCOM_SCM_ES_IMPORT_ICE_KEY);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_has_wrapped_key_support);
|
||||
|
||||
/**
|
||||
* qcom_scm_derive_sw_secret() - Derive software secret from wrapped key
|
||||
* @eph_key: an ephemerally-wrapped key
|
||||
* @eph_key_size: size of @eph_key in bytes
|
||||
* @sw_secret: output buffer for the software secret
|
||||
* @sw_secret_size: size of the software secret to derive in bytes
|
||||
*
|
||||
* Derive a software secret from an ephemerally-wrapped key for software crypto
|
||||
* operations. This is done by calling into the secure execution environment,
|
||||
* which then calls into the hardware to unwrap and derive the secret.
|
||||
*
|
||||
* For more information on sw_secret, see the "Hardware-wrapped keys" section of
|
||||
* Documentation/block/inline-encryption.rst.
|
||||
*
|
||||
* Return: 0 on success; -errno on failure.
|
||||
*/
|
||||
int qcom_scm_derive_sw_secret(const u8 *eph_key, size_t eph_key_size,
|
||||
u8 *sw_secret, size_t sw_secret_size)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_ES,
|
||||
.cmd = QCOM_SCM_ES_DERIVE_SW_SECRET,
|
||||
.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL,
|
||||
QCOM_SCM_RW, QCOM_SCM_VAL),
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
int ret;
|
||||
|
||||
void *eph_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
eph_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!eph_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
void *sw_secret_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
sw_secret_size,
|
||||
GFP_KERNEL);
|
||||
if (!sw_secret_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(eph_key_buf, eph_key, eph_key_size);
|
||||
desc.args[0] = qcom_tzmem_to_phys(eph_key_buf);
|
||||
desc.args[1] = eph_key_size;
|
||||
desc.args[2] = qcom_tzmem_to_phys(sw_secret_buf);
|
||||
desc.args[3] = sw_secret_size;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
if (!ret)
|
||||
memcpy(sw_secret, sw_secret_buf, sw_secret_size);
|
||||
|
||||
memzero_explicit(eph_key_buf, eph_key_size);
|
||||
memzero_explicit(sw_secret_buf, sw_secret_size);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_derive_sw_secret);
|
||||
|
||||
/**
|
||||
* qcom_scm_generate_ice_key() - Generate a wrapped key for storage encryption
|
||||
* @lt_key: output buffer for the long-term wrapped key
|
||||
* @lt_key_size: size of @lt_key in bytes. Must be the exact wrapped key size
|
||||
* used by the SoC.
|
||||
*
|
||||
* Generate a key using the built-in HW module in the SoC. The resulting key is
|
||||
* returned wrapped with the platform-specific Key Encryption Key.
|
||||
*
|
||||
* Return: 0 on success; -errno on failure.
|
||||
*/
|
||||
int qcom_scm_generate_ice_key(u8 *lt_key, size_t lt_key_size)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_ES,
|
||||
.cmd = QCOM_SCM_ES_GENERATE_ICE_KEY,
|
||||
.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL),
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
int ret;
|
||||
|
||||
void *lt_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
lt_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!lt_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
desc.args[0] = qcom_tzmem_to_phys(lt_key_buf);
|
||||
desc.args[1] = lt_key_size;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
if (!ret)
|
||||
memcpy(lt_key, lt_key_buf, lt_key_size);
|
||||
|
||||
memzero_explicit(lt_key_buf, lt_key_size);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_generate_ice_key);
|
||||
|
||||
/**
|
||||
* qcom_scm_prepare_ice_key() - Re-wrap a key with the per-boot ephemeral key
|
||||
* @lt_key: a long-term wrapped key
|
||||
* @lt_key_size: size of @lt_key in bytes
|
||||
* @eph_key: output buffer for the ephemerally-wrapped key
|
||||
* @eph_key_size: size of @eph_key in bytes. Must be the exact wrapped key size
|
||||
* used by the SoC.
|
||||
*
|
||||
* Given a long-term wrapped key, re-wrap it with the per-boot ephemeral key for
|
||||
* added protection. The resulting key will only be valid for the current boot.
|
||||
*
|
||||
* Return: 0 on success; -errno on failure.
|
||||
*/
|
||||
int qcom_scm_prepare_ice_key(const u8 *lt_key, size_t lt_key_size,
|
||||
u8 *eph_key, size_t eph_key_size)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_ES,
|
||||
.cmd = QCOM_SCM_ES_PREPARE_ICE_KEY,
|
||||
.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, QCOM_SCM_VAL,
|
||||
QCOM_SCM_RW, QCOM_SCM_VAL),
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
int ret;
|
||||
|
||||
void *lt_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
lt_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!lt_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
void *eph_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
eph_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!eph_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(lt_key_buf, lt_key, lt_key_size);
|
||||
desc.args[0] = qcom_tzmem_to_phys(lt_key_buf);
|
||||
desc.args[1] = lt_key_size;
|
||||
desc.args[2] = qcom_tzmem_to_phys(eph_key_buf);
|
||||
desc.args[3] = eph_key_size;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
if (!ret)
|
||||
memcpy(eph_key, eph_key_buf, eph_key_size);
|
||||
|
||||
memzero_explicit(lt_key_buf, lt_key_size);
|
||||
memzero_explicit(eph_key_buf, eph_key_size);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_prepare_ice_key);
|
||||
|
||||
/**
|
||||
* qcom_scm_import_ice_key() - Import key for storage encryption
|
||||
* @raw_key: the raw key to import
|
||||
* @raw_key_size: size of @raw_key in bytes
|
||||
* @lt_key: output buffer for the long-term wrapped key
|
||||
* @lt_key_size: size of @lt_key in bytes. Must be the exact wrapped key size
|
||||
* used by the SoC.
|
||||
*
|
||||
* Import a raw key and return a long-term wrapped key. Uses the SoC's HWKM to
|
||||
* wrap the raw key using the platform-specific Key Encryption Key.
|
||||
*
|
||||
* Return: 0 on success; -errno on failure.
|
||||
*/
|
||||
int qcom_scm_import_ice_key(const u8 *raw_key, size_t raw_key_size,
|
||||
u8 *lt_key, size_t lt_key_size)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_ES,
|
||||
.cmd = QCOM_SCM_ES_IMPORT_ICE_KEY,
|
||||
.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, QCOM_SCM_VAL,
|
||||
QCOM_SCM_RW, QCOM_SCM_VAL),
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
int ret;
|
||||
|
||||
void *raw_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
raw_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!raw_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
void *lt_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
lt_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!lt_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(raw_key_buf, raw_key, raw_key_size);
|
||||
desc.args[0] = qcom_tzmem_to_phys(raw_key_buf);
|
||||
desc.args[1] = raw_key_size;
|
||||
desc.args[2] = qcom_tzmem_to_phys(lt_key_buf);
|
||||
desc.args[3] = lt_key_size;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
if (!ret)
|
||||
memcpy(lt_key, lt_key_buf, lt_key_size);
|
||||
|
||||
memzero_explicit(raw_key_buf, raw_key_size);
|
||||
memzero_explicit(lt_key_buf, lt_key_size);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_import_ice_key);
|
||||
|
||||
/**
|
||||
* qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -128,6 +128,10 @@ struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void);
|
|||
#define QCOM_SCM_SVC_ES 0x10 /* Enterprise Security */
|
||||
#define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03
|
||||
#define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04
|
||||
#define QCOM_SCM_ES_DERIVE_SW_SECRET 0x07
|
||||
#define QCOM_SCM_ES_GENERATE_ICE_KEY 0x08
|
||||
#define QCOM_SCM_ES_PREPARE_ICE_KEY 0x09
|
||||
#define QCOM_SCM_ES_IMPORT_ICE_KEY 0x0a
|
||||
|
||||
#define QCOM_SCM_SVC_HDCP 0x11
|
||||
#define QCOM_SCM_HDCP_INVOKE 0x01
|
||||
|
|
|
|||
|
|
@ -105,6 +105,14 @@ bool qcom_scm_ice_available(void);
|
|||
int qcom_scm_ice_invalidate_key(u32 index);
|
||||
int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
|
||||
enum qcom_scm_ice_cipher cipher, u32 data_unit_size);
|
||||
bool qcom_scm_has_wrapped_key_support(void);
|
||||
int qcom_scm_derive_sw_secret(const u8 *eph_key, size_t eph_key_size,
|
||||
u8 *sw_secret, size_t sw_secret_size);
|
||||
int qcom_scm_generate_ice_key(u8 *lt_key, size_t lt_key_size);
|
||||
int qcom_scm_prepare_ice_key(const u8 *lt_key, size_t lt_key_size,
|
||||
u8 *eph_key, size_t eph_key_size);
|
||||
int qcom_scm_import_ice_key(const u8 *raw_key, size_t raw_key_size,
|
||||
u8 *lt_key, size_t lt_key_size);
|
||||
|
||||
bool qcom_scm_hdcp_available(void);
|
||||
int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue