Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Gaurav Kashyap and committed by
Bjorn Andersson
1d45a1cd 8e6854ef

+226
+214
drivers/firmware/qcom/qcom_scm.c
··· 1282 1282 } 1283 1283 EXPORT_SYMBOL_GPL(qcom_scm_ice_set_key); 1284 1284 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 + 1285 1499 /** 1286 1500 * qcom_scm_hdcp_available() - Check if secure environment supports HDCP. 1287 1501 *
+4
drivers/firmware/qcom/qcom_scm.h
··· 128 128 #define QCOM_SCM_SVC_ES 0x10 /* Enterprise Security */ 129 129 #define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03 130 130 #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 131 135 132 136 #define QCOM_SCM_SVC_HDCP 0x11 133 137 #define QCOM_SCM_HDCP_INVOKE 0x01
+8
include/linux/firmware/qcom/qcom_scm.h
··· 105 105 int qcom_scm_ice_invalidate_key(u32 index); 106 106 int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, 107 107 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); 108 116 109 117 bool qcom_scm_hdcp_available(void); 110 118 int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);