Skip to content

Commit 1d45a1c

Browse files
quic-gaurkashandersson
authored andcommitted
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>
1 parent 8e6854e commit 1d45a1c

File tree

3 files changed

+226
-0
lines changed

3 files changed

+226
-0
lines changed

drivers/firmware/qcom/qcom_scm.c

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,220 @@ int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
12821282
}
12831283
EXPORT_SYMBOL_GPL(qcom_scm_ice_set_key);
12841284

1285+
bool qcom_scm_has_wrapped_key_support(void)
1286+
{
1287+
return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
1288+
QCOM_SCM_ES_DERIVE_SW_SECRET) &&
1289+
__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
1290+
QCOM_SCM_ES_GENERATE_ICE_KEY) &&
1291+
__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
1292+
QCOM_SCM_ES_PREPARE_ICE_KEY) &&
1293+
__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
1294+
QCOM_SCM_ES_IMPORT_ICE_KEY);
1295+
}
1296+
EXPORT_SYMBOL_GPL(qcom_scm_has_wrapped_key_support);
1297+
1298+
/**
1299+
* qcom_scm_derive_sw_secret() - Derive software secret from wrapped key
1300+
* @eph_key: an ephemerally-wrapped key
1301+
* @eph_key_size: size of @eph_key in bytes
1302+
* @sw_secret: output buffer for the software secret
1303+
* @sw_secret_size: size of the software secret to derive in bytes
1304+
*
1305+
* Derive a software secret from an ephemerally-wrapped key for software crypto
1306+
* operations. This is done by calling into the secure execution environment,
1307+
* which then calls into the hardware to unwrap and derive the secret.
1308+
*
1309+
* For more information on sw_secret, see the "Hardware-wrapped keys" section of
1310+
* Documentation/block/inline-encryption.rst.
1311+
*
1312+
* Return: 0 on success; -errno on failure.
1313+
*/
1314+
int qcom_scm_derive_sw_secret(const u8 *eph_key, size_t eph_key_size,
1315+
u8 *sw_secret, size_t sw_secret_size)
1316+
{
1317+
struct qcom_scm_desc desc = {
1318+
.svc = QCOM_SCM_SVC_ES,
1319+
.cmd = QCOM_SCM_ES_DERIVE_SW_SECRET,
1320+
.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL,
1321+
QCOM_SCM_RW, QCOM_SCM_VAL),
1322+
.owner = ARM_SMCCC_OWNER_SIP,
1323+
};
1324+
int ret;
1325+
1326+
void *eph_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
1327+
eph_key_size,
1328+
GFP_KERNEL);
1329+
if (!eph_key_buf)
1330+
return -ENOMEM;
1331+
1332+
void *sw_secret_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
1333+
sw_secret_size,
1334+
GFP_KERNEL);
1335+
if (!sw_secret_buf)
1336+
return -ENOMEM;
1337+
1338+
memcpy(eph_key_buf, eph_key, eph_key_size);
1339+
desc.args[0] = qcom_tzmem_to_phys(eph_key_buf);
1340+
desc.args[1] = eph_key_size;
1341+
desc.args[2] = qcom_tzmem_to_phys(sw_secret_buf);
1342+
desc.args[3] = sw_secret_size;
1343+
1344+
ret = qcom_scm_call(__scm->dev, &desc, NULL);
1345+
if (!ret)
1346+
memcpy(sw_secret, sw_secret_buf, sw_secret_size);
1347+
1348+
memzero_explicit(eph_key_buf, eph_key_size);
1349+
memzero_explicit(sw_secret_buf, sw_secret_size);
1350+
return ret;
1351+
}
1352+
EXPORT_SYMBOL_GPL(qcom_scm_derive_sw_secret);
1353+
1354+
/**
1355+
* qcom_scm_generate_ice_key() - Generate a wrapped key for storage encryption
1356+
* @lt_key: output buffer for the long-term wrapped key
1357+
* @lt_key_size: size of @lt_key in bytes. Must be the exact wrapped key size
1358+
* used by the SoC.
1359+
*
1360+
* Generate a key using the built-in HW module in the SoC. The resulting key is
1361+
* returned wrapped with the platform-specific Key Encryption Key.
1362+
*
1363+
* Return: 0 on success; -errno on failure.
1364+
*/
1365+
int qcom_scm_generate_ice_key(u8 *lt_key, size_t lt_key_size)
1366+
{
1367+
struct qcom_scm_desc desc = {
1368+
.svc = QCOM_SCM_SVC_ES,
1369+
.cmd = QCOM_SCM_ES_GENERATE_ICE_KEY,
1370+
.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL),
1371+
.owner = ARM_SMCCC_OWNER_SIP,
1372+
};
1373+
int ret;
1374+
1375+
void *lt_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
1376+
lt_key_size,
1377+
GFP_KERNEL);
1378+
if (!lt_key_buf)
1379+
return -ENOMEM;
1380+
1381+
desc.args[0] = qcom_tzmem_to_phys(lt_key_buf);
1382+
desc.args[1] = lt_key_size;
1383+
1384+
ret = qcom_scm_call(__scm->dev, &desc, NULL);
1385+
if (!ret)
1386+
memcpy(lt_key, lt_key_buf, lt_key_size);
1387+
1388+
memzero_explicit(lt_key_buf, lt_key_size);
1389+
return ret;
1390+
}
1391+
EXPORT_SYMBOL_GPL(qcom_scm_generate_ice_key);
1392+
1393+
/**
1394+
* qcom_scm_prepare_ice_key() - Re-wrap a key with the per-boot ephemeral key
1395+
* @lt_key: a long-term wrapped key
1396+
* @lt_key_size: size of @lt_key in bytes
1397+
* @eph_key: output buffer for the ephemerally-wrapped key
1398+
* @eph_key_size: size of @eph_key in bytes. Must be the exact wrapped key size
1399+
* used by the SoC.
1400+
*
1401+
* Given a long-term wrapped key, re-wrap it with the per-boot ephemeral key for
1402+
* added protection. The resulting key will only be valid for the current boot.
1403+
*
1404+
* Return: 0 on success; -errno on failure.
1405+
*/
1406+
int qcom_scm_prepare_ice_key(const u8 *lt_key, size_t lt_key_size,
1407+
u8 *eph_key, size_t eph_key_size)
1408+
{
1409+
struct qcom_scm_desc desc = {
1410+
.svc = QCOM_SCM_SVC_ES,
1411+
.cmd = QCOM_SCM_ES_PREPARE_ICE_KEY,
1412+
.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, QCOM_SCM_VAL,
1413+
QCOM_SCM_RW, QCOM_SCM_VAL),
1414+
.owner = ARM_SMCCC_OWNER_SIP,
1415+
};
1416+
int ret;
1417+
1418+
void *lt_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
1419+
lt_key_size,
1420+
GFP_KERNEL);
1421+
if (!lt_key_buf)
1422+
return -ENOMEM;
1423+
1424+
void *eph_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
1425+
eph_key_size,
1426+
GFP_KERNEL);
1427+
if (!eph_key_buf)
1428+
return -ENOMEM;
1429+
1430+
memcpy(lt_key_buf, lt_key, lt_key_size);
1431+
desc.args[0] = qcom_tzmem_to_phys(lt_key_buf);
1432+
desc.args[1] = lt_key_size;
1433+
desc.args[2] = qcom_tzmem_to_phys(eph_key_buf);
1434+
desc.args[3] = eph_key_size;
1435+
1436+
ret = qcom_scm_call(__scm->dev, &desc, NULL);
1437+
if (!ret)
1438+
memcpy(eph_key, eph_key_buf, eph_key_size);
1439+
1440+
memzero_explicit(lt_key_buf, lt_key_size);
1441+
memzero_explicit(eph_key_buf, eph_key_size);
1442+
return ret;
1443+
}
1444+
EXPORT_SYMBOL_GPL(qcom_scm_prepare_ice_key);
1445+
1446+
/**
1447+
* qcom_scm_import_ice_key() - Import key for storage encryption
1448+
* @raw_key: the raw key to import
1449+
* @raw_key_size: size of @raw_key in bytes
1450+
* @lt_key: output buffer for the long-term wrapped key
1451+
* @lt_key_size: size of @lt_key in bytes. Must be the exact wrapped key size
1452+
* used by the SoC.
1453+
*
1454+
* Import a raw key and return a long-term wrapped key. Uses the SoC's HWKM to
1455+
* wrap the raw key using the platform-specific Key Encryption Key.
1456+
*
1457+
* Return: 0 on success; -errno on failure.
1458+
*/
1459+
int qcom_scm_import_ice_key(const u8 *raw_key, size_t raw_key_size,
1460+
u8 *lt_key, size_t lt_key_size)
1461+
{
1462+
struct qcom_scm_desc desc = {
1463+
.svc = QCOM_SCM_SVC_ES,
1464+
.cmd = QCOM_SCM_ES_IMPORT_ICE_KEY,
1465+
.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, QCOM_SCM_VAL,
1466+
QCOM_SCM_RW, QCOM_SCM_VAL),
1467+
.owner = ARM_SMCCC_OWNER_SIP,
1468+
};
1469+
int ret;
1470+
1471+
void *raw_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
1472+
raw_key_size,
1473+
GFP_KERNEL);
1474+
if (!raw_key_buf)
1475+
return -ENOMEM;
1476+
1477+
void *lt_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
1478+
lt_key_size,
1479+
GFP_KERNEL);
1480+
if (!lt_key_buf)
1481+
return -ENOMEM;
1482+
1483+
memcpy(raw_key_buf, raw_key, raw_key_size);
1484+
desc.args[0] = qcom_tzmem_to_phys(raw_key_buf);
1485+
desc.args[1] = raw_key_size;
1486+
desc.args[2] = qcom_tzmem_to_phys(lt_key_buf);
1487+
desc.args[3] = lt_key_size;
1488+
1489+
ret = qcom_scm_call(__scm->dev, &desc, NULL);
1490+
if (!ret)
1491+
memcpy(lt_key, lt_key_buf, lt_key_size);
1492+
1493+
memzero_explicit(raw_key_buf, raw_key_size);
1494+
memzero_explicit(lt_key_buf, lt_key_size);
1495+
return ret;
1496+
}
1497+
EXPORT_SYMBOL_GPL(qcom_scm_import_ice_key);
1498+
12851499
/**
12861500
* qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
12871501
*

drivers/firmware/qcom/qcom_scm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void);
128128
#define QCOM_SCM_SVC_ES 0x10 /* Enterprise Security */
129129
#define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03
130130
#define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04
131+
#define QCOM_SCM_ES_DERIVE_SW_SECRET 0x07
132+
#define QCOM_SCM_ES_GENERATE_ICE_KEY 0x08
133+
#define QCOM_SCM_ES_PREPARE_ICE_KEY 0x09
134+
#define QCOM_SCM_ES_IMPORT_ICE_KEY 0x0a
131135

132136
#define QCOM_SCM_SVC_HDCP 0x11
133137
#define QCOM_SCM_HDCP_INVOKE 0x01

include/linux/firmware/qcom/qcom_scm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ bool qcom_scm_ice_available(void);
105105
int qcom_scm_ice_invalidate_key(u32 index);
106106
int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
107107
enum qcom_scm_ice_cipher cipher, u32 data_unit_size);
108+
bool qcom_scm_has_wrapped_key_support(void);
109+
int qcom_scm_derive_sw_secret(const u8 *eph_key, size_t eph_key_size,
110+
u8 *sw_secret, size_t sw_secret_size);
111+
int qcom_scm_generate_ice_key(u8 *lt_key, size_t lt_key_size);
112+
int qcom_scm_prepare_ice_key(const u8 *lt_key, size_t lt_key_size,
113+
u8 *eph_key, size_t eph_key_size);
114+
int qcom_scm_import_ice_key(const u8 *raw_key, size_t raw_key_size,
115+
u8 *lt_key, size_t lt_key_size);
108116

109117
bool qcom_scm_hdcp_available(void);
110118
int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);

0 commit comments

Comments
 (0)