linux-arm-msm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/10] Add wrapped key support for Qualcomm ICE
@ 2021-12-06 22:57 Gaurav Kashyap
  2021-12-06 22:57 ` [PATCH 01/10] soc: qcom: new common library for ICE functionality Gaurav Kashyap
                   ` (10 more replies)
  0 siblings, 11 replies; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

These patches add support to Qualcomm ICE for hardware
wrapped keys and are made on top of Eric Bigger's set of changes to
support wrapped keys.
Found here: https://lore.kernel.org/linux-block/20210916174928.65529-1-ebiggers@kernel.org).
Explanation and use of hardware-wrapped-keys can be found here:
Documentation/block/inline-encryption.rst

The first patch however is not related to wrapped keys. It is
for moving ICE functionality into a shared library which both ufs and
sdhci can use. The patch for sdhc-msm will be uploaded later.

Wrapped keys are supported in Qualcomm's ICE engine using
a proprietary hardware module known as Hardware Key Manager (HWKM).
The patches are revolved around that and testing for them
can be done only on a HWKM supported Qualcomm device.

Testing:
Test platform: SM8350 HDK/MTP
Engineering trustzone image (based on sm8350) is required to test
this feature. This is because of version changes of HWKM.
HWKM version 2 and moving forward has a lot of restrictions on the
key management due to which the launched SM8350 solution (based on v1)
cannot be used and some modifications are required in trustzone.

The ideal scenario is to test by mounting initramfs on an upstream
kernel and then using the fscrypt tool to setup directories with
encryption policies. Testing and development for that is still under way.

All the SCM calls however were individually tested from UFS by invoking
a test API on bootup which is not part of these patchsets.

Gaurav Kashyap (10):
  soc: qcom: new common library for ICE functionality
  scsi: ufs: qcom: move ICE functionality to common library
  qcom_scm: scm call for deriving a software secret
  soc: qcom: add HWKM library for storage encryption
  scsi: ufs: prepare to support wrapped keys
  soc: qcom: add wrapped key support for ICE
  qcom_scm: scm call for create, prepare and import keys
  scsi: ufs: add support for generate, import and prepare keys
  soc: qcom: support for generate, import and prepare key
  arm64: dts: qcom: sm8350: add ice and hwkm mappings

 arch/arm64/boot/dts/qcom/sm8350.dtsi |   5 +-
 drivers/firmware/qcom_scm.c          | 286 +++++++++++++++++++
 drivers/firmware/qcom_scm.h          |   4 +
 drivers/scsi/ufs/Kconfig             |   1 +
 drivers/scsi/ufs/ufs-qcom-ice.c      | 227 +++++----------
 drivers/scsi/ufs/ufs-qcom.c          |   4 +
 drivers/scsi/ufs/ufs-qcom.h          |  22 +-
 drivers/scsi/ufs/ufshcd-crypto.c     |  96 ++++++-
 drivers/scsi/ufs/ufshcd.h            |  20 +-
 drivers/soc/qcom/Kconfig             |   7 +
 drivers/soc/qcom/Makefile            |   1 +
 drivers/soc/qcom/qti-ice-common.c    | 402 +++++++++++++++++++++++++++
 drivers/soc/qcom/qti-ice-hwkm.c      | 111 ++++++++
 drivers/soc/qcom/qti-ice-regs.h      | 264 ++++++++++++++++++
 include/linux/qcom_scm.h             |  30 +-
 include/linux/qti-ice-common.h       |  40 +++
 16 files changed, 1345 insertions(+), 175 deletions(-)
 create mode 100644 drivers/soc/qcom/qti-ice-common.c
 create mode 100644 drivers/soc/qcom/qti-ice-hwkm.c
 create mode 100644 drivers/soc/qcom/qti-ice-regs.h
 create mode 100644 include/linux/qti-ice-common.h

-- 
2.17.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 01/10] soc: qcom: new common library for ICE functionality
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2021-12-07  0:24   ` Randy Dunlap
  2021-12-14  0:20   ` Eric Biggers
  2021-12-06 22:57 ` [PATCH 02/10] scsi: ufs: qcom: move ICE functionality to common library Gaurav Kashyap
                   ` (9 subsequent siblings)
  10 siblings, 2 replies; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

Add a new library which congregates all the ICE
functionality so that all storage controllers containing
ICE can utilize it.

Currently, ufs and sdhci-msm have their own support for
ICE, this common library allows code to be shared.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/soc/qcom/Kconfig          |   7 ++
 drivers/soc/qcom/Makefile         |   1 +
 drivers/soc/qcom/qti-ice-common.c | 199 ++++++++++++++++++++++++++++++
 drivers/soc/qcom/qti-ice-regs.h   | 145 ++++++++++++++++++++++
 include/linux/qti-ice-common.h    |  24 ++++
 5 files changed, 376 insertions(+)
 create mode 100644 drivers/soc/qcom/qti-ice-common.c
 create mode 100644 drivers/soc/qcom/qti-ice-regs.h
 create mode 100644 include/linux/qti-ice-common.h

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 79b568f82a1c..a900f5ab6263 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -209,4 +209,11 @@ config QCOM_APR
 	  application processor and QDSP6. APR is
 	  used by audio driver to configure QDSP6
 	  ASM, ADM and AFE modules.
+
+config QTI_ICE_COMMON
+	tristate "QTI common ICE functionality"
+	depends on ARCH_QCOM
+	help
+	  Enable the common ICE library that can be used
+	  by UFS and EMMC drivers for ICE functionality.
 endmenu
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index ad675a6593d0..57840b19b7ee 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
 obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
 obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
 obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) +=	kryo-l2-accessors.o
+obj-$(CONFIG_QTI_ICE_COMMON) += qti-ice-common.o
diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c
new file mode 100644
index 000000000000..0c5b529201c5
--- /dev/null
+++ b/drivers/soc/qcom/qti-ice-common.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common ICE library for storage encryption.
+ *
+ * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved.
+ */
+
+#include <linux/qti-ice-common.h>
+#include <linux/module.h>
+#include <linux/qcom_scm.h>
+#include <linux/delay.h>
+#include "qti-ice-regs.h"
+
+#define QTI_ICE_MAX_BIST_CHECK_COUNT    100
+#define QTI_AES_256_XTS_KEY_RAW_SIZE	64
+
+static bool qti_ice_supported(const struct ice_mmio_data *mmio)
+{
+	u32 regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_VERSION);
+	int major = regval >> 24;
+	int minor = (regval >> 16) & 0xFF;
+	int step = regval & 0xFFFF;
+
+	/* For now this driver only supports ICE version 3 and higher. */
+	if (major < 3) {
+		pr_warn("Unsupported ICE version: v%d.%d.%d\n",
+			 major, minor, step);
+		return false;
+	}
+
+	pr_info("Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n",
+		 major, minor, step);
+
+	/* If fuses are blown, ICE might not work in the standard way. */
+	regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_FUSE_SETTING);
+	if (regval & (QTI_ICE_FUSE_SETTING_MASK |
+		      QTI_ICE_FORCE_HW_KEY0_SETTING_MASK |
+		      QTI_ICE_FORCE_HW_KEY1_SETTING_MASK)) {
+		pr_warn("Fuses are blown; ICE is unusable!\n");
+		return false;
+	}
+	return true;
+}
+
+/**
+ * qti_ice_init() - Initialize ICE functionality
+ * @ice_mmio_data: contains ICE register mapping for i/o
+ *
+ * Initialize ICE by checking the version for ICE support and
+ * also checking the fuses blown.
+ *
+ * Return: 0 on success; -EINVAL on failure.
+ */
+int qti_ice_init(const struct ice_mmio_data *mmio)
+{
+	if (!qti_ice_supported(mmio))
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qti_ice_init);
+
+static void qti_ice_low_power_and_optimization_enable(
+				const struct ice_mmio_data *mmio)
+{
+	u32 regval = qti_ice_readl(mmio->ice_mmio,
+				   QTI_ICE_REGS_ADVANCED_CONTROL);
+
+	/* Enable low power mode sequence
+	 * [0]-0,[1]-0,[2]-0,[3]-7,[4]-0,[5]-0,[6]-0,[7]-0,
+	 * Enable CONFIG_CLK_GATING, STREAM2_CLK_GATING and STREAM1_CLK_GATING
+	 */
+	regval |= 0x7000;
+	/* Optimization enable sequence*/
+	regval |= 0xD807100;
+	qti_ice_writel(mmio->ice_mmio, regval, QTI_ICE_REGS_ADVANCED_CONTROL);
+	/* Memory barrier - to ensure write completion before next transaction */
+	wmb();
+}
+
+static int qti_ice_wait_bist_status(const struct ice_mmio_data *mmio)
+{
+	int count;
+	u32 regval;
+
+	for (count = 0; count < QTI_ICE_MAX_BIST_CHECK_COUNT; count++) {
+		regval = qti_ice_readl(mmio->ice_mmio,
+				       QTI_ICE_REGS_BIST_STATUS);
+		if (!(regval & QTI_ICE_BIST_STATUS_MASK))
+			break;
+		udelay(50);
+	}
+
+	if (regval) {
+		pr_err("%s: wait bist status failed, reg %d\n",
+			__func__, regval);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+/**
+ * qti_ice_enable() - Enable ICE functionality
+ * @ice_mmio_data: contains ICE register mapping for i/o
+ *
+ * Performs two operations two enable ICE functionality.
+ * 1. Enable low power mode and optimization.
+ * 2. Wait for and check if BIST has completed.
+ *
+ * Return: 0 on success; err on failure.
+ */
+int qti_ice_enable(const struct ice_mmio_data *mmio)
+{
+	qti_ice_low_power_and_optimization_enable(mmio);
+	return qti_ice_wait_bist_status(mmio);
+}
+EXPORT_SYMBOL_GPL(qti_ice_enable);
+
+/**
+ * qti_ice_resume() - Resume ICE functionality
+ * @ice_mmio_data: contains ICE register mapping for i/o
+ *
+ * This is called from storage controller after suspend.
+ * It must be ensured that BIST is complete before resuming.
+ *
+ * Return: 0 on success; err on failure.
+ */
+int qti_ice_resume(const struct ice_mmio_data *mmio)
+{
+	return qti_ice_wait_bist_status(mmio);
+}
+EXPORT_SYMBOL_GPL(qti_ice_resume);
+
+/**
+ * qti_ice_keyslot_program() - Program a key to an ICE slot
+ * @ice_mmio_data: contains ICE register mapping for i/o
+ * @crypto_key: key to be program, this can be wrapped or raw
+ * @crypto_key_size: size of the key to be programmed
+ * @slot: the keyslot at which the key should be programmed.
+ * @data_unit_mask: mask for the dun which is part of the
+ *                  crypto configuration.
+ * @capid: capability index indicating the algorithm for the
+ *         crypto configuration
+ *
+ * Program the passed in key to a slot in ICE.
+ * The key that is passed in can either be a raw key or wrapped.
+ * In both cases, due to access control of ICE for Qualcomm chipsets,
+ * a scm call is used to program the key into ICE from trustzone.
+ * Trustzone can differentiate between raw and wrapped keys.
+ *
+ * Return: 0 on success; err on failure.
+ */
+int qti_ice_keyslot_program(const struct ice_mmio_data *mmio,
+			    const u8 *crypto_key, unsigned int crypto_key_size,
+			    unsigned int slot, u8 data_unit_mask, int capid)
+{
+	int err = 0;
+	int i = 0;
+	union {
+		u8 bytes[QTI_AES_256_XTS_KEY_RAW_SIZE];
+		u32 words[QTI_AES_256_XTS_KEY_RAW_SIZE / sizeof(u32)];
+	} key;
+
+	memcpy(key.bytes, crypto_key, crypto_key_size);
+	/*
+	 * The SCM call byte-swaps the 32-bit words of the key.  So we have to
+	 * do the same, in order for the final key be correct.
+	 */
+	for (i = 0; i < ARRAY_SIZE(key.words); i++)
+		__cpu_to_be32s(&key.words[i]);
+
+	err = qcom_scm_ice_set_key(slot, key.bytes,
+				   QTI_AES_256_XTS_KEY_RAW_SIZE,
+				   capid, data_unit_mask);
+	if (err)
+		pr_err("%s:SCM call Error: 0x%x slot %d\n",
+			__func__, err, slot);
+
+	memzero_explicit(&key, sizeof(key));
+	return err;
+}
+EXPORT_SYMBOL_GPL(qti_ice_keyslot_program);
+
+/**
+ * qti_ice_keyslot_evict() - Evict a key from a keyslot
+ * @slot: keyslot from which key needs to be evicted.
+ *
+ * Make a scm call into trustzone to evict an ICE key
+ * from its keyslot.
+ *
+ * Return: 0 on success; err on failure.
+ */
+int qti_ice_keyslot_evict(unsigned int slot)
+{
+	return qcom_scm_ice_invalidate_key(slot);
+}
+EXPORT_SYMBOL_GPL(qti_ice_keyslot_evict);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/qti-ice-regs.h b/drivers/soc/qcom/qti-ice-regs.h
new file mode 100644
index 000000000000..582b73fd60fc
--- /dev/null
+++ b/drivers/soc/qcom/qti-ice-regs.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved.
+ */
+
+#ifndef _QTI_INLINE_CRYPTO_ENGINE_REGS_H_
+#define _QTI_INLINE_CRYPTO_ENGINE_REGS_H_
+
+#include <linux/io.h>
+
+/* QTI ICE Registers from SWI */
+#define QTI_ICE_REGS_CONTROL			        0x0000
+#define QTI_ICE_REGS_RESET				0x0004
+#define QTI_ICE_REGS_VERSION			        0x0008
+#define QTI_ICE_REGS_FUSE_SETTING			0x0010
+#define QTI_ICE_REGS_PARAMETERS_1			0x0014
+#define QTI_ICE_REGS_PARAMETERS_2			0x0018
+#define QTI_ICE_REGS_PARAMETERS_3			0x001C
+#define QTI_ICE_REGS_PARAMETERS_4			0x0020
+#define QTI_ICE_REGS_PARAMETERS_5			0x0024
+
+/* Register bits for ICE version */
+#define QTI_ICE_CORE_STEP_REV_MASK			0xFFFF
+#define QTI_ICE_CORE_STEP_REV				0 /* bit 15-0 */
+#define QTI_ICE_CORE_MAJOR_REV_MASK			0xFF000000
+#define QTI_ICE_CORE_MAJOR_REV				24 /* bit 31-24 */
+#define QTI_ICE_CORE_MINOR_REV_MASK			0xFF0000
+#define QTI_ICE_CORE_MINOR_REV				16 /* bit 23-16 */
+
+#define QTI_ICE_BIST_STATUS_MASK			(0xF0000000)	/* bits 28-31 */
+
+#define QTI_ICE_FUSE_SETTING_MASK			0x1
+#define QTI_ICE_FORCE_HW_KEY0_SETTING_MASK		0x2
+#define QTI_ICE_FORCE_HW_KEY1_SETTING_MASK		0x4
+
+/* QTI ICE v3.X only */
+#define QTI_ICE_INVALID_CCFG_ERR_STTS			0x0030
+#define QTI_ICE_GENERAL_ERR_STTS			0x0040
+#define QTI_ICE_GENERAL_ERR_MASK			0x0044
+#define QTI_ICE_REGS_NON_SEC_IRQ_CLR			0x0048
+#define QTI_ICE_REGS_STREAM1_ERROR_SYNDROME1		0x0050
+#define QTI_ICE_REGS_STREAM1_ERROR_SYNDROME2		0x0054
+#define QTI_ICE_REGS_STREAM2_ERROR_SYNDROME1		0x0058
+#define QTI_ICE_REGS_STREAM2_ERROR_SYNDROME2		0x005C
+#define QTI_ICE_REGS_STREAM1_BIST_ERROR_VEC		0x0060
+#define QTI_ICE_REGS_STREAM2_BIST_ERROR_VEC		0x0064
+#define QTI_ICE_REGS_STREAM1_BIST_FINISH_VEC		0x0068
+#define QTI_ICE_REGS_STREAM2_BIST_FINISH_VEC		0x006C
+#define QTI_ICE_REGS_BIST_STATUS			0x0070
+#define QTI_ICE_REGS_BYPASS_STATUS			0x0074
+#define QTI_ICE_REGS_ADVANCED_CONTROL			0x1000
+#define QTI_ICE_REGS_ENDIAN_SWAP			0x1004
+#define QTI_ICE_REGS_TEST_BUS_CONTROL			0x1010
+#define QTI_ICE_REGS_TEST_BUS_REG			0x1014
+#define QTI_ICE_REGS_STREAM1_COUNTERS1			0x1100
+#define QTI_ICE_REGS_STREAM1_COUNTERS2			0x1104
+#define QTI_ICE_REGS_STREAM1_COUNTERS3			0x1108
+#define QTI_ICE_REGS_STREAM1_COUNTERS4			0x110C
+#define QTI_ICE_REGS_STREAM1_COUNTERS5_MSB		0x1110
+#define QTI_ICE_REGS_STREAM1_COUNTERS5_LSB		0x1114
+#define QTI_ICE_REGS_STREAM1_COUNTERS6_MSB		0x1118
+#define QTI_ICE_REGS_STREAM1_COUNTERS6_LSB		0x111C
+#define QTI_ICE_REGS_STREAM1_COUNTERS7_MSB		0x1120
+#define QTI_ICE_REGS_STREAM1_COUNTERS7_LSB		0x1124
+#define QTI_ICE_REGS_STREAM1_COUNTERS8_MSB		0x1128
+#define QTI_ICE_REGS_STREAM1_COUNTERS8_LSB		0x112C
+#define QTI_ICE_REGS_STREAM1_COUNTERS9_MSB		0x1130
+#define QTI_ICE_REGS_STREAM1_COUNTERS9_LSB		0x1134
+#define QTI_ICE_REGS_STREAM2_COUNTERS1			0x1200
+#define QTI_ICE_REGS_STREAM2_COUNTERS2			0x1204
+#define QTI_ICE_REGS_STREAM2_COUNTERS3			0x1208
+#define QTI_ICE_REGS_STREAM2_COUNTERS4			0x120C
+#define QTI_ICE_REGS_STREAM2_COUNTERS5_MSB		0x1210
+#define QTI_ICE_REGS_STREAM2_COUNTERS5_LSB		0x1214
+#define QTI_ICE_REGS_STREAM2_COUNTERS6_MSB		0x1218
+#define QTI_ICE_REGS_STREAM2_COUNTERS6_LSB		0x121C
+#define QTI_ICE_REGS_STREAM2_COUNTERS7_MSB		0x1220
+#define QTI_ICE_REGS_STREAM2_COUNTERS7_LSB		0x1224
+#define QTI_ICE_REGS_STREAM2_COUNTERS8_MSB		0x1228
+#define QTI_ICE_REGS_STREAM2_COUNTERS8_LSB		0x122C
+#define QTI_ICE_REGS_STREAM2_COUNTERS9_MSB		0x1230
+#define QTI_ICE_REGS_STREAM2_COUNTERS9_LSB		0x1234
+
+#define QTI_ICE_STREAM1_PREMATURE_LBA_CHANGE		(1L << 0)
+#define QTI_ICE_STREAM2_PREMATURE_LBA_CHANGE		(1L << 1)
+#define QTI_ICE_STREAM1_NOT_EXPECTED_LBO		(1L << 2)
+#define QTI_ICE_STREAM2_NOT_EXPECTED_LBO		(1L << 3)
+#define QTI_ICE_STREAM1_NOT_EXPECTED_DUN		(1L << 4)
+#define QTI_ICE_STREAM2_NOT_EXPECTED_DUN		(1L << 5)
+#define QTI_ICE_STREAM1_NOT_EXPECTED_DUS		(1L << 6)
+#define QTI_ICE_STREAM2_NOT_EXPECTED_DUS		(1L << 7)
+#define QTI_ICE_STREAM1_NOT_EXPECTED_DBO		(1L << 8)
+#define QTI_ICE_STREAM2_NOT_EXPECTED_DBO		(1L << 9)
+#define QTI_ICE_STREAM1_NOT_EXPECTED_ENC_SEL		(1L << 10)
+#define QTI_ICE_STREAM2_NOT_EXPECTED_ENC_SEL		(1L << 11)
+#define QTI_ICE_STREAM1_NOT_EXPECTED_CONF_IDX		(1L << 12)
+#define QTI_ICE_STREAM2_NOT_EXPECTED_CONF_IDX		(1L << 13)
+#define QTI_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS		(1L << 14)
+#define QTI_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS		(1L << 15)
+
+#define QTI_ICE_NON_SEC_IRQ_MASK				\
+			(QTI_ICE_STREAM1_PREMATURE_LBA_CHANGE |	\
+			 QTI_ICE_STREAM2_PREMATURE_LBA_CHANGE |	\
+			 QTI_ICE_STREAM1_NOT_EXPECTED_LBO |	\
+			 QTI_ICE_STREAM2_NOT_EXPECTED_LBO |	\
+			 QTI_ICE_STREAM1_NOT_EXPECTED_DUN |	\
+			 QTI_ICE_STREAM2_NOT_EXPECTED_DUN |	\
+			 QTI_ICE_STREAM2_NOT_EXPECTED_DUS |	\
+			 QTI_ICE_STREAM1_NOT_EXPECTED_DBO |	\
+			 QTI_ICE_STREAM2_NOT_EXPECTED_DBO |	\
+			 QTI_ICE_STREAM1_NOT_EXPECTED_ENC_SEL |	\
+			 QTI_ICE_STREAM2_NOT_EXPECTED_ENC_SEL |	\
+			 QTI_ICE_STREAM1_NOT_EXPECTED_CONF_IDX |\
+			 QTI_ICE_STREAM1_NOT_EXPECTED_NEW_TRNS |\
+			 QTI_ICE_STREAM2_NOT_EXPECTED_NEW_TRNS)
+
+/* QTI ICE registers from secure side */
+#define QTI_ICE_TEST_BUS_REG_SECURE_INTR		(1L << 28)
+#define QTI_ICE_TEST_BUS_REG_NON_SECURE_INTR		(1L << 2)
+
+#define QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16			0x4040
+#define QTI_ICE_LUT_KEYS_CRYPTOCFG_R_17			0x4044
+#define QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET		0x80
+
+#define QTI_ICE_LUT_KEYS_QTI_ICE_SEC_IRQ_STTS		0x6200
+#define QTI_ICE_LUT_KEYS_QTI_ICE_SEC_IRQ_MASK		0x6204
+#define QTI_ICE_LUT_KEYS_QTI_ICE_SEC_IRQ_CLR		0x6208
+
+#define QTI_ICE_STREAM1_PARTIALLY_SET_KEY_USED		(1L << 0)
+#define QTI_ICE_STREAM2_PARTIALLY_SET_KEY_USED		(1L << 1)
+#define QTI_ICE_QTIC_DBG_OPEN_EVENT			(1L << 30)
+#define QTI_ICE_KEYS_RAM_RESET_COMPLETED		(1L << 31)
+
+#define QTI_ICE_SEC_IRQ_MASK					\
+			(QTI_ICE_STREAM1_PARTIALLY_SET_KEY_USED |\
+			 QTI_ICE_STREAM2_PARTIALLY_SET_KEY_USED |\
+			 QTI_ICE_QTIC_DBG_OPEN_EVENT |		\
+			 QTI_ICE_KEYS_RAM_RESET_COMPLETED)
+
+#define qti_ice_writel(mmio, val, reg)		\
+	writel_relaxed((val), mmio + (reg))
+#define qti_ice_readl(mmio, reg)		\
+	readl_relaxed(mmio + (reg))
+
+#endif /* _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ */
diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h
new file mode 100644
index 000000000000..5a7c6fa99dc1
--- /dev/null
+++ b/include/linux/qti-ice-common.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved.
+ */
+
+#ifndef _QTI_ICE_COMMON_H
+#define _QTI_ICE_COMMON_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+struct ice_mmio_data {
+	void __iomem *ice_mmio;
+};
+
+int qti_ice_init(const struct ice_mmio_data *mmio);
+int qti_ice_enable(const struct ice_mmio_data *mmio);
+int qti_ice_resume(const struct ice_mmio_data *mmio);
+int qti_ice_keyslot_program(const struct ice_mmio_data *mmio,
+			    const u8 *key, unsigned int key_size,
+			    unsigned int slot, u8 data_unit_mask, int capid);
+int qti_ice_keyslot_evict(unsigned int slot);
+
+#endif /* _QTI_ICE_COMMON_H */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 02/10] scsi: ufs: qcom: move ICE functionality to common library
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
  2021-12-06 22:57 ` [PATCH 01/10] soc: qcom: new common library for ICE functionality Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2021-12-14  0:40   ` Eric Biggers
  2021-12-06 22:57 ` [PATCH 03/10] qcom_scm: scm call for deriving a software secret Gaurav Kashyap
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

Remove the ICE support in UFS and use the shared library
for crypto functionality.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/scsi/ufs/Kconfig        |   1 +
 drivers/scsi/ufs/ufs-qcom-ice.c | 169 +++-----------------------------
 drivers/scsi/ufs/ufs-qcom.h     |   3 +-
 3 files changed, 15 insertions(+), 158 deletions(-)

diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 432df76e6318..622a4c3fbf70 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -101,6 +101,7 @@ config SCSI_UFS_QCOM
 	tristate "QCOM specific hooks to UFS controller platform driver"
 	depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM
 	select QCOM_SCM if SCSI_UFS_CRYPTO
+	select QTI_ICE_COMMON if SCSI_UFS_CRYPTO
 	select RESET_CONTROLLER
 	help
 	  This selects the QCOM specific additions to UFSHCD platform driver.
diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index bbb0ad7590ec..3826643bf537 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -8,90 +8,11 @@
 
 #include <linux/platform_device.h>
 #include <linux/qcom_scm.h>
+#include <linux/qti-ice-common.h>
 
 #include "ufshcd-crypto.h"
 #include "ufs-qcom.h"
 
-#define AES_256_XTS_KEY_SIZE			64
-
-/* QCOM ICE registers */
-
-#define QCOM_ICE_REG_CONTROL			0x0000
-#define QCOM_ICE_REG_RESET			0x0004
-#define QCOM_ICE_REG_VERSION			0x0008
-#define QCOM_ICE_REG_FUSE_SETTING		0x0010
-#define QCOM_ICE_REG_PARAMETERS_1		0x0014
-#define QCOM_ICE_REG_PARAMETERS_2		0x0018
-#define QCOM_ICE_REG_PARAMETERS_3		0x001C
-#define QCOM_ICE_REG_PARAMETERS_4		0x0020
-#define QCOM_ICE_REG_PARAMETERS_5		0x0024
-
-/* QCOM ICE v3.X only */
-#define QCOM_ICE_GENERAL_ERR_STTS		0x0040
-#define QCOM_ICE_INVALID_CCFG_ERR_STTS		0x0030
-#define QCOM_ICE_GENERAL_ERR_MASK		0x0044
-
-/* QCOM ICE v2.X only */
-#define QCOM_ICE_REG_NON_SEC_IRQ_STTS		0x0040
-#define QCOM_ICE_REG_NON_SEC_IRQ_MASK		0x0044
-
-#define QCOM_ICE_REG_NON_SEC_IRQ_CLR		0x0048
-#define QCOM_ICE_REG_STREAM1_ERROR_SYNDROME1	0x0050
-#define QCOM_ICE_REG_STREAM1_ERROR_SYNDROME2	0x0054
-#define QCOM_ICE_REG_STREAM2_ERROR_SYNDROME1	0x0058
-#define QCOM_ICE_REG_STREAM2_ERROR_SYNDROME2	0x005C
-#define QCOM_ICE_REG_STREAM1_BIST_ERROR_VEC	0x0060
-#define QCOM_ICE_REG_STREAM2_BIST_ERROR_VEC	0x0064
-#define QCOM_ICE_REG_STREAM1_BIST_FINISH_VEC	0x0068
-#define QCOM_ICE_REG_STREAM2_BIST_FINISH_VEC	0x006C
-#define QCOM_ICE_REG_BIST_STATUS		0x0070
-#define QCOM_ICE_REG_BYPASS_STATUS		0x0074
-#define QCOM_ICE_REG_ADVANCED_CONTROL		0x1000
-#define QCOM_ICE_REG_ENDIAN_SWAP		0x1004
-#define QCOM_ICE_REG_TEST_BUS_CONTROL		0x1010
-#define QCOM_ICE_REG_TEST_BUS_REG		0x1014
-
-/* BIST ("built-in self-test"?) status flags */
-#define QCOM_ICE_BIST_STATUS_MASK		0xF0000000
-
-#define QCOM_ICE_FUSE_SETTING_MASK		0x1
-#define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK	0x2
-#define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK	0x4
-
-#define qcom_ice_writel(host, val, reg)	\
-	writel((val), (host)->ice_mmio + (reg))
-#define qcom_ice_readl(host, reg)	\
-	readl((host)->ice_mmio + (reg))
-
-static bool qcom_ice_supported(struct ufs_qcom_host *host)
-{
-	struct device *dev = host->hba->dev;
-	u32 regval = qcom_ice_readl(host, QCOM_ICE_REG_VERSION);
-	int major = regval >> 24;
-	int minor = (regval >> 16) & 0xFF;
-	int step = regval & 0xFFFF;
-
-	/* For now this driver only supports ICE version 3. */
-	if (major != 3) {
-		dev_warn(dev, "Unsupported ICE version: v%d.%d.%d\n",
-			 major, minor, step);
-		return false;
-	}
-
-	dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n",
-		 major, minor, step);
-
-	/* If fuses are blown, ICE might not work in the standard way. */
-	regval = qcom_ice_readl(host, QCOM_ICE_REG_FUSE_SETTING);
-	if (regval & (QCOM_ICE_FUSE_SETTING_MASK |
-		      QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK |
-		      QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK)) {
-		dev_warn(dev, "Fuses are blown; ICE is unusable!\n");
-		return false;
-	}
-	return true;
-}
-
 int ufs_qcom_ice_init(struct ufs_qcom_host *host)
 {
 	struct ufs_hba *hba = host->hba;
@@ -115,14 +36,14 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host)
 		goto disable;
 	}
 
-	host->ice_mmio = devm_ioremap_resource(dev, res);
-	if (IS_ERR(host->ice_mmio)) {
-		err = PTR_ERR(host->ice_mmio);
+	host->ice_data.ice_mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(host->ice_data.ice_mmio)) {
+		err = PTR_ERR(host->ice_data.ice_mmio);
 		dev_err(dev, "Failed to map ICE registers; err=%d\n", err);
 		return err;
 	}
 
-	if (!qcom_ice_supported(host))
+	if (qti_ice_init(&host->ice_data))
 		goto disable;
 
 	return 0;
@@ -133,71 +54,21 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host)
 	return 0;
 }
 
-static void qcom_ice_low_power_mode_enable(struct ufs_qcom_host *host)
-{
-	u32 regval;
-
-	regval = qcom_ice_readl(host, QCOM_ICE_REG_ADVANCED_CONTROL);
-	/*
-	 * Enable low power mode sequence
-	 * [0]-0, [1]-0, [2]-0, [3]-E, [4]-0, [5]-0, [6]-0, [7]-0
-	 */
-	regval |= 0x7000;
-	qcom_ice_writel(host, regval, QCOM_ICE_REG_ADVANCED_CONTROL);
-}
-
-static void qcom_ice_optimization_enable(struct ufs_qcom_host *host)
-{
-	u32 regval;
-
-	/* ICE Optimizations Enable Sequence */
-	regval = qcom_ice_readl(host, QCOM_ICE_REG_ADVANCED_CONTROL);
-	regval |= 0xD807100;
-	/* ICE HPG requires delay before writing */
-	udelay(5);
-	qcom_ice_writel(host, regval, QCOM_ICE_REG_ADVANCED_CONTROL);
-	udelay(5);
-}
 
 int ufs_qcom_ice_enable(struct ufs_qcom_host *host)
 {
 	if (!(host->hba->caps & UFSHCD_CAP_CRYPTO))
 		return 0;
-	qcom_ice_low_power_mode_enable(host);
-	qcom_ice_optimization_enable(host);
-	return ufs_qcom_ice_resume(host);
-}
 
-/* Poll until all BIST bits are reset */
-static int qcom_ice_wait_bist_status(struct ufs_qcom_host *host)
-{
-	int count;
-	u32 reg;
-
-	for (count = 0; count < 100; count++) {
-		reg = qcom_ice_readl(host, QCOM_ICE_REG_BIST_STATUS);
-		if (!(reg & QCOM_ICE_BIST_STATUS_MASK))
-			break;
-		udelay(50);
-	}
-	if (reg)
-		return -ETIMEDOUT;
-	return 0;
+	return qti_ice_enable(&host->ice_data);
 }
 
 int ufs_qcom_ice_resume(struct ufs_qcom_host *host)
 {
-	int err;
-
 	if (!(host->hba->caps & UFSHCD_CAP_CRYPTO))
 		return 0;
 
-	err = qcom_ice_wait_bist_status(host);
-	if (err) {
-		dev_err(host->hba->dev, "BIST status error (%d)\n", err);
-		return err;
-	}
-	return 0;
+	return qti_ice_resume(&host->ice_data);
 }
 
 /*
@@ -208,15 +79,10 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba,
 			     const union ufs_crypto_cfg_entry *cfg, int slot)
 {
 	union ufs_crypto_cap_entry cap;
-	union {
-		u8 bytes[AES_256_XTS_KEY_SIZE];
-		u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)];
-	} key;
-	int i;
-	int err;
+	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
 
 	if (!(cfg->config_enable & UFS_CRYPTO_CONFIGURATION_ENABLE))
-		return qcom_scm_ice_invalidate_key(slot);
+		return qti_ice_keyslot_evict(slot);
 
 	/* Only AES-256-XTS has been tested so far. */
 	cap = hba->crypto_cap_array[cfg->crypto_cap_idx];
@@ -228,18 +94,7 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba,
 		return -EINVAL;
 	}
 
-	memcpy(key.bytes, cfg->crypto_key, AES_256_XTS_KEY_SIZE);
-
-	/*
-	 * The SCM call byte-swaps the 32-bit words of the key.  So we have to
-	 * do the same, in order for the final key be correct.
-	 */
-	for (i = 0; i < ARRAY_SIZE(key.words); i++)
-		__cpu_to_be32s(&key.words[i]);
-
-	err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE,
-				   QCOM_SCM_ICE_CIPHER_AES_256_XTS,
-				   cfg->data_unit_size);
-	memzero_explicit(&key, sizeof(key));
-	return err;
+	return qti_ice_keyslot_program(&host->ice_data, cfg->crypto_key,
+				       UFS_CRYPTO_KEY_SIZE_256, slot,
+				       cfg->data_unit_size, cfg->crypto_cap_idx);
 }
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 8208e3a3ef59..8efacc0d7888 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -7,6 +7,7 @@
 
 #include <linux/reset-controller.h>
 #include <linux/reset.h>
+#include <linux/qti-ice-common.h>
 
 #define MAX_UFS_QCOM_HOSTS	1
 #define MAX_U32                 (~(u32)0)
@@ -206,7 +207,7 @@ struct ufs_qcom_host {
 	bool is_dev_ref_clk_enabled;
 	struct ufs_hw_version hw_ver;
 #ifdef CONFIG_SCSI_UFS_CRYPTO
-	void __iomem *ice_mmio;
+	struct ice_mmio_data ice_data;
 #endif
 
 	u32 dev_ref_clk_en_mask;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 03/10] qcom_scm: scm call for deriving a software secret
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
  2021-12-06 22:57 ` [PATCH 01/10] soc: qcom: new common library for ICE functionality Gaurav Kashyap
  2021-12-06 22:57 ` [PATCH 02/10] scsi: ufs: qcom: move ICE functionality to common library Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2021-12-14  0:53   ` Eric Biggers
  2021-12-06 22:57 ` [PATCH 04/10] soc: qcom: add HWKM library for storage encryption Gaurav Kashyap
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

Storage encryption requires fscrypt deriving a sw secret from
the keys inserted into the linux keyring. For non-wrapped keys,
this can be directly done as keys are in the clear.

However, when keys are hardware wrapped, it can be unwrapped
by HWKM which is accessible only from  Qualcomm Trustzone.
Hence, it also makes sense that the software secret is also derived
there and returned to the linux kernel for wrapped keys. This can be
invoked by using the crypto profile APIs provided by the block layer.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/firmware/qcom_scm.c | 73 +++++++++++++++++++++++++++++++++++++
 drivers/firmware/qcom_scm.h |  1 +
 include/linux/qcom_scm.h    |  6 +++
 3 files changed, 80 insertions(+)

diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 2ee97bab7440..4a7703846788 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1062,6 +1062,79 @@ int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
 }
 EXPORT_SYMBOL(qcom_scm_ice_set_key);
 
+/**
+ * qcom_scm_derive_sw_secret() - Derive SW secret from wrapped encryption key
+ * @wrapped_key: the wrapped key used for inline encryption
+ * @wrapped_key_size: size of the wrapped key
+ * @sw_secret: the secret to be derived which is at most the secret size
+ * @secret_size: maximum size of the secret that is derived
+ *
+ * Derive a SW secret to be used for inline encryption using Qualcomm ICE.
+ *
+ * For wrapped keys, the key needs to be unwrapped, in order to derive a
+ * SW secret, which can be done only by the secure EE. So, it makes sense
+ * for the secure EE to derive the sw secret and return to the kernel when
+ * wrapped keys are used.
+ *
+ * For more information on sw secret, please refer to "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 *wrapped_key, u32 wrapped_key_size,
+			      u8 *sw_secret, u32 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_RO,
+					 QCOM_SCM_VAL, QCOM_SCM_RW,
+					 QCOM_SCM_VAL),
+		.args[1] = wrapped_key_size,
+		.args[3] = secret_size,
+		.owner = ARM_SMCCC_OWNER_SIP,
+	};
+
+	void *keybuf, *secretbuf;
+	dma_addr_t key_phys, secret_phys;
+	int ret;
+
+	/*
+	 * Like qcom_scm_ice_set_key(), we use dma_alloc_coherent() to properly
+	 * get a physical address, while guaranteeing that we can zeroize the
+	 * key material later using memzero_explicit().
+	 *
+	 */
+	keybuf = dma_alloc_coherent(__scm->dev, wrapped_key_size, &key_phys,
+				    GFP_KERNEL);
+	if (!keybuf)
+		return -ENOMEM;
+	secretbuf = dma_alloc_coherent(__scm->dev, secret_size, &secret_phys,
+				    GFP_KERNEL);
+	if (!secretbuf) {
+		ret = -ENOMEM;
+		goto bail_keybuf;
+	}
+
+	memcpy(keybuf, wrapped_key, wrapped_key_size);
+	desc.args[0] = key_phys;
+	desc.args[2] = secret_phys;
+
+	ret = qcom_scm_call(__scm->dev, &desc, NULL);
+	if (!ret)
+		memcpy(sw_secret, secretbuf, secret_size);
+
+	memzero_explicit(secretbuf, secret_size);
+	dma_free_coherent(__scm->dev, secret_size, secretbuf, secret_phys);
+
+bail_keybuf:
+	memzero_explicit(keybuf, wrapped_key_size);
+	dma_free_coherent(__scm->dev, wrapped_key_size, keybuf, key_phys);
+
+	return ret;
+}
+EXPORT_SYMBOL(qcom_scm_derive_sw_secret);
+
 /**
  * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
  *
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index d92156ceb3ac..08bb2a4c80db 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -110,6 +110,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
 #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_SVC_HDCP		0x11
 #define QCOM_SCM_HDCP_INVOKE		0x01
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index c0475d1c9885..ccd764bdc357 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -103,6 +103,9 @@ extern int qcom_scm_ice_invalidate_key(u32 index);
 extern int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
 				enum qcom_scm_ice_cipher cipher,
 				u32 data_unit_size);
+extern int qcom_scm_derive_sw_secret(const u8 *wrapped_key,
+				     u32 wrapped_key_size, u8 *sw_secret,
+				     u32 secret_size);
 
 extern bool qcom_scm_hdcp_available(void);
 extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
@@ -169,6 +172,9 @@ static inline int qcom_scm_ice_invalidate_key(u32 index) { return -ENODEV; }
 static inline int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
 				       enum qcom_scm_ice_cipher cipher,
 				       u32 data_unit_size) { return -ENODEV; }
+static inline int qcom_scm_derive_sw_secret(const u8 *wrapped_key,
+					u32 wrapped_key_size, u8 *sw_secret,
+					u32 secret_size) { return -ENODEV; }
 
 static inline bool qcom_scm_hdcp_available(void) { return false; }
 static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 04/10] soc: qcom: add HWKM library for storage encryption
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
                   ` (2 preceding siblings ...)
  2021-12-06 22:57 ` [PATCH 03/10] qcom_scm: scm call for deriving a software secret Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2021-12-14  1:08   ` Eric Biggers
  2021-12-06 22:57 ` [PATCH 05/10] scsi: ufs: prepare to support wrapped keys Gaurav Kashyap
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

Wrapped keys should utilize hardware to protect the keys
used for storage encryption. Qualcomm's Inline Crypto Engine
supports a hardware block called Hardware Key Manager (HWKM)
for key management.

Although most of the interactions to this hardware block happens
via a secure execution environment, some initializations for the
slave present in ICE can be done from the kernel.

This can also be a placeholder for when the hardware provides more
capabilities to be accessed from the linux kernel in the future.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/soc/qcom/Makefile       |   2 +-
 drivers/soc/qcom/qti-ice-hwkm.c | 111 +++++++++++++++++++++++++++++
 drivers/soc/qcom/qti-ice-regs.h | 119 ++++++++++++++++++++++++++++++++
 include/linux/qti-ice-common.h  |   1 +
 4 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 drivers/soc/qcom/qti-ice-hwkm.c

diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 57840b19b7ee..e73fefb4f533 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -26,4 +26,4 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
 obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
 obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
 obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) +=	kryo-l2-accessors.o
-obj-$(CONFIG_QTI_ICE_COMMON) += qti-ice-common.o
+obj-$(CONFIG_QTI_ICE_COMMON) += qti-ice-common.o qti-ice-hwkm.o
diff --git a/drivers/soc/qcom/qti-ice-hwkm.c b/drivers/soc/qcom/qti-ice-hwkm.c
new file mode 100644
index 000000000000..3be6b350cd88
--- /dev/null
+++ b/drivers/soc/qcom/qti-ice-hwkm.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HWKM ICE library for storage encryption.
+ *
+ * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved.
+ */
+
+#include <linux/qti-ice-common.h>
+#include "qti-ice-regs.h"
+
+static int qti_ice_hwkm_bist_status(const struct ice_mmio_data *mmio, int version)
+{
+	if (!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
+			(version == 1) ? BIST_DONE_V1 : BIST_DONE_V2) ||
+	!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
+			(version == 1) ? CRYPTO_LIB_BIST_DONE_V1 :
+			CRYPTO_LIB_BIST_DONE_V2) ||
+	!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
+			(version == 1) ? BOOT_CMD_LIST1_DONE_V1 :
+			BOOT_CMD_LIST1_DONE_V2) ||
+	!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
+			(version == 1) ? BOOT_CMD_LIST0_DONE_V1 :
+			BOOT_CMD_LIST0_DONE_V2) ||
+	!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
+			(version == 1) ? KT_CLEAR_DONE_V1 :
+			KT_CLEAR_DONE_V2))
+		return -EINVAL;
+	return 0;
+}
+
+static void qti_ice_hwkm_configure_ice_registers(
+				const struct ice_mmio_data *mmio)
+{
+	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
+			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_0);
+	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
+			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_1);
+	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
+			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_2);
+	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
+			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_3);
+	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
+			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_4);
+}
+
+static int qti_ice_hwkm_init_sequence(const struct ice_mmio_data *mmio,
+				      int version)
+{
+	u32 val = 0;
+
+	/*
+	 * Put ICE in standard mode, ICE defaults to legacy mode.
+	 * Legacy mode - ICE HWKM slave not supported.
+	 * Standard mode - ICE HWKM slave supported.
+	 *
+	 * Depending on the version of HWKM, it is controlled by different
+	 * registers in ICE.
+	 */
+	if (version >= 2) {
+		val = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_CONTROL);
+		val = val & 0xFFFFFFFE;
+		qti_ice_writel(mmio->ice_mmio, val, QTI_ICE_REGS_CONTROL);
+	} else {
+		qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0x7,
+				    QTI_HWKM_ICE_RG_TZ_KM_CTL);
+	}
+
+	/* Check BIST status */
+	if (qti_ice_hwkm_bist_status(mmio, version))
+		return -EINVAL;
+
+	/*
+	 * Give register bank of the HWKM slave access to read and modify
+	 * the keyslots in ICE HWKM slave. Without this, trustzone will not
+	 * be able to program keys into ICE.
+	 */
+	qti_ice_hwkm_configure_ice_registers(mmio);
+
+	/* Disable CRC check */
+	qti_ice_hwkm_clearb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_CTL,
+			    CRC_CHECK_EN);
+
+	/* Set RSP_FIFO_FULL bit */
+	qti_ice_hwkm_setb(mmio->ice_hwkm_mmio,
+			QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS, RSP_FIFO_FULL);
+
+	return 0;
+}
+
+/**
+ * qti_ice_hwkm_init() - Initialize ICE HWKM hardware
+ * @ice_mmio_data: contains ICE register mapping for i/o
+ * @version: version of hwkm hardware
+ *
+ * Perform HWKM initialization in the ICE slave by going
+ * through the slave initialization routine.The registers
+ * can vary slightly based on the version.
+ *
+ * Return: 0 on success; err on failure.
+ */
+
+int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version)
+{
+	if (!mmio->ice_hwkm_mmio)
+		return -EINVAL;
+
+	return qti_ice_hwkm_init_sequence(mmio, version);
+}
+EXPORT_SYMBOL_GPL(qti_ice_hwkm_init);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/qti-ice-regs.h b/drivers/soc/qcom/qti-ice-regs.h
index 582b73fd60fc..256c6feb9072 100644
--- a/drivers/soc/qcom/qti-ice-regs.h
+++ b/drivers/soc/qcom/qti-ice-regs.h
@@ -137,9 +137,128 @@
 			 QTI_ICE_QTIC_DBG_OPEN_EVENT |		\
 			 QTI_ICE_KEYS_RAM_RESET_COMPLETED)
 
+/* Read/write macros for ICE address space */
 #define qti_ice_writel(mmio, val, reg)		\
 	writel_relaxed((val), mmio + (reg))
 #define qti_ice_readl(mmio, reg)		\
 	readl_relaxed(mmio + (reg))
 
+/* Registers for ICE HWKM Slave */
+
+#define HWKM_VERSION_STEP_REV_MASK			0xFFFF
+#define HWKM_VERSION_STEP_REV				0 /* bit 15-0 */
+#define HWKM_VERSION_MAJOR_REV_MASK			0xFF000000
+#define HWKM_VERSION_MAJOR_REV				24 /* bit 31-24 */
+#define HWKM_VERSION_MINOR_REV_MASK			0xFF0000
+#define HWKM_VERSION_MINOR_REV				16 /* bit 23-16 */
+
+/* QTI HWKM ICE slave config and status registers */
+
+#define QTI_HWKM_ICE_RG_IPCAT_VERSION			0x0000
+#define QTI_HWKM_ICE_RG_KEY_POLICY_VERSION		0x0004
+#define QTI_HWKM_ICE_RG_SHARED_STATUS			0x0008
+#define QTI_HWKM_ICE_RG_KEYTABLE_SIZE			0x000C
+
+#define QTI_HWKM_ICE_RG_TZ_KM_CTL			0x1000
+#define QTI_HWKM_ICE_RG_TZ_KM_STATUS			0x1004
+#define QTI_HWKM_ICE_RG_TZ_KM_STATUS_IRQ_MASK		0x1008
+#define QTI_HWKM_ICE_RG_TZ_KM_BOOT_STAGE_OTP		0x100C
+#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_CTL			0x1010
+#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_WRITE		0x1014
+#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_READ		0x1018
+#define QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL		0x101C
+#define QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_STATUS		0x1020
+#define QTI_HWKM_ICE_RG_TZ_KM_COMMON_IRQ_ROUTING	0x1024
+
+/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_CTL */
+#define CRC_CHECK_EN					0
+#define KEYTABLE_HW_WR_ACCESS_EN			1
+#define KEYTABLE_HW_RD_ACCESS_EN			2
+#define BOOT_INIT0_DISABLE				3
+#define BOOT_INIT1_DISABLE				4
+#define ICE_LEGACY_MODE_EN_OTP				5
+
+/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_STATUS for v2 and above*/
+#define KT_CLEAR_DONE_V2				0
+#define BOOT_CMD_LIST0_DONE_V2				1
+#define BOOT_CMD_LIST1_DONE_V2				2
+#define LAST_ACTIVITY_BANK_V2				3
+#define CRYPTO_LIB_BIST_ERROR_V2			6
+#define CRYPTO_LIB_BIST_DONE_V2				7
+#define BIST_ERROR_V2					8
+#define BIST_DONE_V2					9
+#define LAST_ACTIVITY_BANK_MASK_V2			0x38
+
+/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_STATUS for v1*/
+#define KT_CLEAR_DONE_V1				0
+#define BOOT_CMD_LIST0_DONE_V1				1
+#define BOOT_CMD_LIST1_DONE_V1				2
+#define KEYTABLE_KEY_POLICY_V1				3
+#define KEYTABLE_INTEGRITY_ERROR_V1			4
+#define KEYTABLE_KEY_SLOT_ERROR_V1			5
+#define KEYTABLE_KEY_SLOT_NOT_EVEN_ERROR_V1		6
+#define KEYTABLE_KEY_SLOT_OUT_OF_RANGE_V1		7
+#define KEYTABLE_KEY_SIZE_ERROR_V1			8
+#define KEYTABLE_OPERATION_ERROR_V1			9
+#define LAST_ACTIVITY_BANK_V1				10
+#define CRYPTO_LIB_BIST_ERROR_V1			13
+#define CRYPTO_LIB_BIST_DONE_V1				14
+#define BIST_ERROR_V1					15
+#define BIST_DONE_V1					16
+
+/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_TPKEY_RECEIVE_CTL */
+#define TPKEY_EN					8
+
+/* QTI HWKM ICE slave register bank 0 */
+#define QTI_HWKM_ICE_RG_BANK0_BANKN_CTL			0x2000
+#define QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS		0x2004
+#define QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS		0x2008
+#define QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_MASK		0x200C
+#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESR			0x2010
+#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESR_IRQ_MASK	0x2014
+#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESYNR		0x2018
+
+/* QTI HWKM access control registers for Bank 0 */
+#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_0		0x5000
+#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_1		0x5004
+#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_2		0x5008
+#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_3		0x500C
+#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_4		0x5010
+
+/* QTI_HWKM_ICE_RG_BANKN_IRQ_STATUS */
+#define ARB_GRAN_WINNER					0
+#define CMD_DONE_BIT					1
+#define RSP_FIFO_NOT_EMPTY				2
+#define RSP_FIFO_FULL					3
+#define RSP_FIFO_UNDERFLOW				4
+#define CMD_FIFO_UNDERFLOW				5
+
+/* Read/write macros for ICE HWKM address space */
+
+#define qti_ice_hwkm_readl(hwkm_mmio, reg)		\
+	(readl_relaxed(hwkm_mmio + (reg)))
+#define qti_ice_hwkm_writel(hwkm_mmio, val, reg)	\
+	(writel_relaxed((val), hwkm_mmio + (reg)))
+#define qti_ice_hwkm_setb(hwkm_mmio, reg, nr) {		\
+	u32 val = qti_ice_hwkm_readl(hwkm_mmio, reg);	\
+	val |= (0x1 << nr);				\
+	qti_ice_hwkm_writel(hwkm_mmio, val, reg);	\
+}
+#define qti_ice_hwkm_clearb(hwkm_mmio, reg, nr) {	\
+	u32 val = qti_ice_hwkm_readl(hwkm_mmio, reg);	\
+	val &= ~(0x1 << nr);				\
+	qti_ice_hwkm_writel(hwkm_mmio, val, reg);	\
+}
+
+static inline bool qti_ice_hwkm_testb(void __iomem *ice_hwkm_mmio,
+				      u32 reg, u8 nr)
+{
+	u32 val = qti_ice_hwkm_readl(ice_hwkm_mmio, reg);
+
+	val = (val >> nr) & 0x1;
+	if (val == 0)
+		return false;
+	return true;
+}
+
 #endif /* _QTI_INLINE_CRYPTO_ENGINE_REGS_H_ */
diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h
index 5a7c6fa99dc1..51dfe3c12092 100644
--- a/include/linux/qti-ice-common.h
+++ b/include/linux/qti-ice-common.h
@@ -20,5 +20,6 @@ int qti_ice_keyslot_program(const struct ice_mmio_data *mmio,
 			    const u8 *key, unsigned int key_size,
 			    unsigned int slot, u8 data_unit_mask, int capid);
 int qti_ice_keyslot_evict(unsigned int slot);
+int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version);
 
 #endif /* _QTI_ICE_COMMON_H */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 05/10] scsi: ufs: prepare to support wrapped keys
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
                   ` (3 preceding siblings ...)
  2021-12-06 22:57 ` [PATCH 04/10] soc: qcom: add HWKM library for storage encryption Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2021-12-14  1:26   ` Eric Biggers
  2021-12-06 22:57 ` [PATCH 06/10] soc: qcom: add wrapped key support for ICE Gaurav Kashyap
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

Adds support in ufshcd-core for wrapped keys.
1. Change program key vop to support wrapped key sizes by
   using blk_crypto_key directly instead of using ufs_crypto_cfg
   which is not suitable for wrapped keys.
2. Add derive_sw_secret vop and derive_sw_secret crypto_profile op.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/scsi/ufs/ufshcd-crypto.c | 52 +++++++++++++++++++++++++-------
 drivers/scsi/ufs/ufshcd.h        |  9 +++++-
 2 files changed, 49 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c
index 0ed82741f981..9d68621a0eb4 100644
--- a/drivers/scsi/ufs/ufshcd-crypto.c
+++ b/drivers/scsi/ufs/ufshcd-crypto.c
@@ -18,16 +18,23 @@ static const struct ufs_crypto_alg_entry {
 };
 
 static int ufshcd_program_key(struct ufs_hba *hba,
+			      const struct blk_crypto_key *key,
 			      const union ufs_crypto_cfg_entry *cfg, int slot)
 {
 	int i;
 	u32 slot_offset = hba->crypto_cfg_register + slot * sizeof(*cfg);
 	int err = 0;
+	bool evict = false;
 
 	ufshcd_hold(hba, false);
 
 	if (hba->vops && hba->vops->program_key) {
-		err = hba->vops->program_key(hba, cfg, slot);
+		if (!(cfg->config_enable & UFS_CRYPTO_CONFIGURATION_ENABLE))
+			evict = true;
+		err = hba->vops->program_key(hba, key, slot,
+					     cfg->data_unit_size,
+					     cfg->crypto_cap_idx,
+					     evict);
 		goto out;
 	}
 
@@ -80,16 +87,18 @@ static int ufshcd_crypto_keyslot_program(struct blk_crypto_profile *profile,
 	cfg.crypto_cap_idx = cap_idx;
 	cfg.config_enable = UFS_CRYPTO_CONFIGURATION_ENABLE;
 
-	if (ccap_array[cap_idx].algorithm_id == UFS_CRYPTO_ALG_AES_XTS) {
-		/* In XTS mode, the blk_crypto_key's size is already doubled */
-		memcpy(cfg.crypto_key, key->raw, key->size/2);
-		memcpy(cfg.crypto_key + UFS_CRYPTO_KEY_MAX_SIZE/2,
-		       key->raw + key->size/2, key->size/2);
-	} else {
-		memcpy(cfg.crypto_key, key->raw, key->size);
+	if (key->crypto_cfg.key_type != BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) {
+		if (ccap_array[cap_idx].algorithm_id == UFS_CRYPTO_ALG_AES_XTS) {
+			/* In XTS mode, the blk_crypto_key's size is already doubled */
+			memcpy(cfg.crypto_key, key->raw, key->size/2);
+			memcpy(cfg.crypto_key + UFS_CRYPTO_KEY_MAX_SIZE/2,
+			       key->raw + key->size/2, key->size/2);
+		} else {
+			memcpy(cfg.crypto_key, key->raw, key->size);
+		}
 	}
 
-	err = ufshcd_program_key(hba, &cfg, slot);
+	err = ufshcd_program_key(hba, key, &cfg, slot);
 
 	memzero_explicit(&cfg, sizeof(cfg));
 	return err;
@@ -103,7 +112,7 @@ static int ufshcd_clear_keyslot(struct ufs_hba *hba, int slot)
 	 */
 	union ufs_crypto_cfg_entry cfg = {};
 
-	return ufshcd_program_key(hba, &cfg, slot);
+	return ufshcd_program_key(hba, NULL, &cfg, slot);
 }
 
 static int ufshcd_crypto_keyslot_evict(struct blk_crypto_profile *profile,
@@ -126,9 +135,25 @@ bool ufshcd_crypto_enable(struct ufs_hba *hba)
 	return true;
 }
 
+static int ufshcd_crypto_derive_sw_secret(struct blk_crypto_profile *profile,
+				const u8 *wrapped_key,
+				unsigned int wrapped_key_size,
+				u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
+{
+	struct ufs_hba *hba =
+		container_of(profile, struct ufs_hba, crypto_profile);
+
+	if (hba->vops && hba->vops->derive_secret)
+		return  hba->vops->derive_secret(hba, wrapped_key,
+						 wrapped_key_size, sw_secret);
+
+	return -EOPNOTSUPP;
+}
+
 static const struct blk_crypto_ll_ops ufshcd_crypto_ops = {
 	.keyslot_program	= ufshcd_crypto_keyslot_program,
 	.keyslot_evict		= ufshcd_crypto_keyslot_evict,
+	.derive_sw_secret	= ufshcd_crypto_derive_sw_secret,
 };
 
 static enum blk_crypto_mode_num
@@ -190,7 +215,12 @@ int ufshcd_hba_init_crypto_capabilities(struct ufs_hba *hba)
 	hba->crypto_profile.ll_ops = ufshcd_crypto_ops;
 	/* UFS only supports 8 bytes for any DUN */
 	hba->crypto_profile.max_dun_bytes_supported = 8;
-	hba->crypto_profile.key_types_supported = BLK_CRYPTO_KEY_TYPE_STANDARD;
+	if (hba->hw_wrapped_keys_supported)
+		hba->crypto_profile.key_types_supported =
+				BLK_CRYPTO_KEY_TYPE_HW_WRAPPED;
+	else
+		hba->crypto_profile.key_types_supported =
+				BLK_CRYPTO_KEY_TYPE_STANDARD;
 	hba->crypto_profile.dev = hba->dev;
 
 	/*
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index df5439b12208..095c2d660aa7 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -320,6 +320,7 @@ struct ufs_pwr_mode_info {
  * @device_reset: called to issue a reset pulse on the UFS device
  * @program_key: program or evict an inline encryption key
  * @event_notify: called to notify important events
+ * @derive_secret: derive sw secret from wrapped inline encryption key
  */
 struct ufs_hba_variant_ops {
 	const char *name;
@@ -353,9 +354,14 @@ struct ufs_hba_variant_ops {
 					struct devfreq_dev_profile *profile,
 					void *data);
 	int	(*program_key)(struct ufs_hba *hba,
-			       const union ufs_crypto_cfg_entry *cfg, int slot);
+			       const struct blk_crypto_key *crypto_key,
+			       int slot, u8 data_unit_size, int capid,
+			       bool evict);
 	void	(*event_notify)(struct ufs_hba *hba,
 				enum ufs_event_type evt, void *data);
+	int	(*derive_secret)(struct ufs_hba *hba, const u8 *wrapped_key,
+				 unsigned int wrapped_key_size,
+				 u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
 };
 
 /* clock gating state  */
@@ -906,6 +912,7 @@ struct ufs_hba {
 	union ufs_crypto_cap_entry *crypto_cap_array;
 	u32 crypto_cfg_register;
 	struct blk_crypto_profile crypto_profile;
+	bool hw_wrapped_keys_supported;
 #endif
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_root;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 06/10] soc: qcom: add wrapped key support for ICE
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
                   ` (4 preceding siblings ...)
  2021-12-06 22:57 ` [PATCH 05/10] scsi: ufs: prepare to support wrapped keys Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2021-12-14  1:46   ` Eric Biggers
  2021-12-06 22:57 ` [PATCH 07/10] qcom_scm: scm call for create, prepare and import keys Gaurav Kashyap
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

Add support for wrapped keys in ufs and common ICE library.
Qualcomm's ICE solution uses a hardware block called Hardware
Key Manager (HWKM) to handle wrapped keys.

This patch adds the following changes to support this.
1. Link to HWKM library for initialization.
2. Most of the key management is done from Trustzone via scm calls.
   Added calls to this from the ICE library.
3. Added support for this framework in ufs qcom.
4. Added support for deriving SW secret as it cannot be done in
   linux kernel for wrapped keys.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/scsi/ufs/ufs-qcom-ice.c   |  48 +++++++--
 drivers/scsi/ufs/ufs-qcom.c       |   1 +
 drivers/scsi/ufs/ufs-qcom.h       |   7 +-
 drivers/soc/qcom/qti-ice-common.c | 158 +++++++++++++++++++++++++++---
 include/linux/qti-ice-common.h    |  11 ++-
 5 files changed, 198 insertions(+), 27 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index 3826643bf537..c8305aab6714 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -43,6 +43,24 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host)
 		return err;
 	}
 
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice_hwkm");
+	if (!res) {
+		dev_warn(dev, "ICE HWKM registers not found\n");
+		host->ice_data.hw_wrapped_keys_supported = false;
+		goto init;
+	}
+
+	host->ice_data.ice_hwkm_mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(host->ice_data.ice_hwkm_mmio)) {
+		err = PTR_ERR(host->ice_data.ice_hwkm_mmio);
+		dev_err(dev, "Failed to map HWKM registers; err=%d\n", err);
+		return err;
+	}
+	host->ice_data.hw_wrapped_keys_supported = true;
+
+init:
+	hba->hw_wrapped_keys_supported =
+				host->ice_data.hw_wrapped_keys_supported;
 	if (qti_ice_init(&host->ice_data))
 		goto disable;
 
@@ -54,7 +72,6 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host)
 	return 0;
 }
 
-
 int ufs_qcom_ice_enable(struct ufs_qcom_host *host)
 {
 	if (!(host->hba->caps & UFSHCD_CAP_CRYPTO))
@@ -76,16 +93,17 @@ int ufs_qcom_ice_resume(struct ufs_qcom_host *host)
  * vendor-specific SCM calls for this; it doesn't support the standard way.
  */
 int ufs_qcom_ice_program_key(struct ufs_hba *hba,
-			     const union ufs_crypto_cfg_entry *cfg, int slot)
+			     const struct blk_crypto_key *key, int slot,
+			     u8 data_unit_size, int capid, bool evict)
 {
 	union ufs_crypto_cap_entry cap;
 	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
 
-	if (!(cfg->config_enable & UFS_CRYPTO_CONFIGURATION_ENABLE))
-		return qti_ice_keyslot_evict(slot);
+	if (evict)
+		return qti_ice_keyslot_evict(&host->ice_data, slot);
 
 	/* Only AES-256-XTS has been tested so far. */
-	cap = hba->crypto_cap_array[cfg->crypto_cap_idx];
+	cap = hba->crypto_cap_array[capid];
 	if (cap.algorithm_id != UFS_CRYPTO_ALG_AES_XTS ||
 	    cap.key_size != UFS_CRYPTO_KEY_SIZE_256) {
 		dev_err_ratelimited(hba->dev,
@@ -94,7 +112,21 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba,
 		return -EINVAL;
 	}
 
-	return qti_ice_keyslot_program(&host->ice_data, cfg->crypto_key,
-				       UFS_CRYPTO_KEY_SIZE_256, slot,
-				       cfg->data_unit_size, cfg->crypto_cap_idx);
+	return qti_ice_keyslot_program(&host->ice_data, key, slot,
+				       data_unit_size, capid);
+}
+
+/*
+ * Derive a SW secret from the wrapped key to be used in fscrypt. The key
+ * is unwrapped in QTI and a SW key is then derived.
+ */
+int ufs_qcom_ice_derive_sw_secret(struct ufs_hba *hba, const u8 *wrapped_key,
+				  unsigned int wrapped_key_size,
+				  u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
+{
+	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+	return qti_ice_derive_sw_secret(&host->ice_data,
+					wrapped_key, wrapped_key_size,
+					sw_secret);
 }
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 9d9770f1db4f..9f85332fbe64 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1495,6 +1495,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
 	.device_reset		= ufs_qcom_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,
+	.derive_secret		= ufs_qcom_ice_derive_sw_secret,
 };
 
 /**
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 8efacc0d7888..e7da3d1dc3c7 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -253,7 +253,12 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host);
 int ufs_qcom_ice_enable(struct ufs_qcom_host *host);
 int ufs_qcom_ice_resume(struct ufs_qcom_host *host);
 int ufs_qcom_ice_program_key(struct ufs_hba *hba,
-			     const union ufs_crypto_cfg_entry *cfg, int slot);
+			     const struct blk_crypto_key *key,
+			     int slot, u8 data_unit_size, int capid,
+			     bool evict);
+int ufs_qcom_ice_derive_sw_secret(struct ufs_hba *hba, const u8 *wrapped_key,
+				  unsigned int wrapped_key_size,
+				  u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
 #else
 static inline int ufs_qcom_ice_init(struct ufs_qcom_host *host)
 {
diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c
index 0c5b529201c5..76703afa4834 100644
--- a/drivers/soc/qcom/qti-ice-common.c
+++ b/drivers/soc/qcom/qti-ice-common.c
@@ -14,6 +14,23 @@
 #define QTI_ICE_MAX_BIST_CHECK_COUNT    100
 #define QTI_AES_256_XTS_KEY_RAW_SIZE	64
 
+/*
+ * ICE resets during power collapse and HWKM has to be
+ * reconfigured which can be kept track with this flag.
+ */
+static bool qti_hwkm_init_done;
+static int hwkm_version;
+
+union crypto_cfg {
+	__le32 regval;
+	struct {
+		u8 dusize;
+		u8 capidx;
+		u8 reserved;
+		u8 cfge;
+	};
+};
+
 static bool qti_ice_supported(const struct ice_mmio_data *mmio)
 {
 	u32 regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_VERSION);
@@ -28,6 +45,11 @@ static bool qti_ice_supported(const struct ice_mmio_data *mmio)
 		return false;
 	}
 
+	if ((major >= 4) || ((major == 3) && (minor == 2) && (step >= 1)))
+		hwkm_version = 2;
+	else
+		hwkm_version = 1;
+
 	pr_info("Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n",
 		 major, minor, step);
 
@@ -131,6 +153,58 @@ int qti_ice_resume(const struct ice_mmio_data *mmio)
 }
 EXPORT_SYMBOL_GPL(qti_ice_resume);
 
+static int qti_ice_program_wrapped_key(const struct ice_mmio_data *mmio,
+				       const struct blk_crypto_key *crypto_key,
+				       unsigned int slot, u8 data_unit_mask,
+				       int capid)
+{
+	int err = 0;
+	union crypto_cfg cfg;
+
+	/*
+	 * HWKM slave in ICE should be initialized before the first
+	 * time we perform ICE HWKM related operations. This is because
+	 * ICE by default comes up in legacy mode where HWKM operations
+	 * won't work.
+	 */
+	if (!qti_hwkm_init_done) {
+		err = qti_ice_hwkm_init(mmio, hwkm_version);
+		if (err) {
+			pr_err("%s: Error initializing hwkm, err = %d",
+							__func__, err);
+			return -EINVAL;
+		}
+		qti_hwkm_init_done = true;
+	}
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.dusize = data_unit_mask;
+	cfg.capidx = capid;
+	cfg.cfge = 0x80;
+
+	/* Make sure CFGE is cleared */
+	qti_ice_writel(mmio->ice_mmio, 0x0, (QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 +
+				QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET*slot));
+	/* Memory barrier - to ensure write completion before next transaction */
+	wmb();
+
+	/* Call trustzone to program the wrapped key using hwkm */
+	err =  qcom_scm_ice_set_key(slot, crypto_key->raw, crypto_key->size,
+				    capid, data_unit_mask);
+	if (err)
+		pr_err("%s:SCM call Error: 0x%x slot %d\n",
+					__func__, err, slot);
+
+	/* Make sure CFGE is enabled after programming the key */
+	qti_ice_writel(mmio->ice_mmio, cfg.regval,
+			(QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 +
+			 QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET*slot));
+	/* Memory barrier - to ensure write completion before next transaction */
+	wmb();
+
+	return err;
+}
+
 /**
  * qti_ice_keyslot_program() - Program a key to an ICE slot
  * @ice_mmio_data: contains ICE register mapping for i/o
@@ -151,7 +225,7 @@ EXPORT_SYMBOL_GPL(qti_ice_resume);
  * Return: 0 on success; err on failure.
  */
 int qti_ice_keyslot_program(const struct ice_mmio_data *mmio,
-			    const u8 *crypto_key, unsigned int crypto_key_size,
+			    const struct blk_crypto_key *crypto_key,
 			    unsigned int slot, u8 data_unit_mask, int capid)
 {
 	int err = 0;
@@ -161,22 +235,28 @@ int qti_ice_keyslot_program(const struct ice_mmio_data *mmio,
 		u32 words[QTI_AES_256_XTS_KEY_RAW_SIZE / sizeof(u32)];
 	} key;
 
-	memcpy(key.bytes, crypto_key, crypto_key_size);
-	/*
-	 * The SCM call byte-swaps the 32-bit words of the key.  So we have to
-	 * do the same, in order for the final key be correct.
-	 */
-	for (i = 0; i < ARRAY_SIZE(key.words); i++)
-		__cpu_to_be32s(&key.words[i]);
+	if (crypto_key->crypto_cfg.key_type == BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) {
+		if (!mmio->hw_wrapped_keys_supported)
+			return -EINVAL;
+		err = qti_ice_program_wrapped_key(mmio, crypto_key, slot,
+						  data_unit_mask, capid);
+	} else {
+		memcpy(key.bytes, crypto_key->raw, crypto_key->size);
+		/*
+		 * The SCM call byte-swaps the 32-bit words of the key.  So we have to
+		 * do the same, in order for the final key be correct.
+		 */
+		for (i = 0; i < ARRAY_SIZE(key.words); i++)
+			__cpu_to_be32s(&key.words[i]);
 
-	err = qcom_scm_ice_set_key(slot, key.bytes,
-				   QTI_AES_256_XTS_KEY_RAW_SIZE,
-				   capid, data_unit_mask);
-	if (err)
-		pr_err("%s:SCM call Error: 0x%x slot %d\n",
-			__func__, err, slot);
+		err = qcom_scm_ice_set_key(slot, key.bytes,
+			QTI_AES_256_XTS_KEY_RAW_SIZE, capid, data_unit_mask);
+		if (err)
+			pr_err("%s:SCM call Error: 0x%x slot %d\n",
+							__func__, err, slot);
+		memzero_explicit(&key, sizeof(key));
+	}
 
-	memzero_explicit(&key, sizeof(key));
 	return err;
 }
 EXPORT_SYMBOL_GPL(qti_ice_keyslot_program);
@@ -190,10 +270,56 @@ EXPORT_SYMBOL_GPL(qti_ice_keyslot_program);
  *
  * Return: 0 on success; err on failure.
  */
-int qti_ice_keyslot_evict(unsigned int slot)
+int qti_ice_keyslot_evict(const struct ice_mmio_data *mmio, unsigned int slot)
 {
+	/*
+	 * Ignore calls to evict key when wrapped keys are supported and
+	 * hwkm init is not yet done. This is to avoid the clearing all slots
+	 * call that comes from ufs during ufs reset. HWKM slave in ICE takes
+	 * care of zeroing out the keytable on reset.
+	 */
+	if (mmio->hw_wrapped_keys_supported && !qti_hwkm_init_done)
+		return 0;
 	return qcom_scm_ice_invalidate_key(slot);
 }
 EXPORT_SYMBOL_GPL(qti_ice_keyslot_evict);
 
+/**
+ * qti_ice_derive_sw_secret() - Derive SW secret from wrapped key
+ * @wrapped_key: wrapped key from which secret should be derived
+ * @wrapped_key_size: size of the wrapped key
+ * @sw_secret: secret to be returned, which is atmost BLK_CRYPTO_SW_SECRET_SIZE
+ *
+ * Make a scm call into trustzone to derive a sw secret from the
+ * given wrapped key.
+ *
+ * Return: 0 on success; err on failure.
+ */
+int qti_ice_derive_sw_secret(const struct ice_mmio_data *mmio,
+			     const u8 *wrapped_key,
+			     unsigned int wrapped_key_size,
+			     u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
+{
+	int err = 0;
+
+	/*
+	 * HWKM slave in ICE should be initialized before the first
+	 * time we perform ICE HWKM related operations. This is because
+	 * ICE by default comes up in legacy mode where HWKM operations
+	 * won't work.
+	 */
+	if (!qti_hwkm_init_done) {
+		err = qti_ice_hwkm_init(mmio, qti_hwkm_version);
+		if (err) {
+			pr_err("%s: Error initializing hwkm, err = %d",
+							__func__, err);
+			return -EINVAL;
+		}
+		qti_hwkm_init_done = true;
+	}
+	return qcom_scm_derive_sw_secret(wrapped_key, wrapped_key_size,
+					 sw_secret, BLK_CRYPTO_SW_SECRET_SIZE);
+}
+EXPORT_SYMBOL_GPL(qti_ice_derive_sw_secret);
+
 MODULE_LICENSE("GPL v2");
diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h
index 51dfe3c12092..e329afeba113 100644
--- a/include/linux/qti-ice-common.h
+++ b/include/linux/qti-ice-common.h
@@ -8,18 +8,25 @@
 
 #include <linux/types.h>
 #include <linux/device.h>
+#include <linux/blk-crypto.h>
 
 struct ice_mmio_data {
 	void __iomem *ice_mmio;
+	void __iomem *ice_hwkm_mmio;
+	bool hw_wrapped_keys_supported;
 };
 
 int qti_ice_init(const struct ice_mmio_data *mmio);
 int qti_ice_enable(const struct ice_mmio_data *mmio);
 int qti_ice_resume(const struct ice_mmio_data *mmio);
 int qti_ice_keyslot_program(const struct ice_mmio_data *mmio,
-			    const u8 *key, unsigned int key_size,
+			    const struct blk_crypto_key *crypto_key,
 			    unsigned int slot, u8 data_unit_mask, int capid);
-int qti_ice_keyslot_evict(unsigned int slot);
+int qti_ice_keyslot_evict(const struct ice_mmio_data *mmio, unsigned int slot);
 int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version);
+int qti_ice_derive_sw_secret(const struct ice_mmio_data *mmio,
+			     const u8 *wrapped_key,
+			     unsigned int wrapped_key_size,
+			     u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
 
 #endif /* _QTI_ICE_COMMON_H */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 07/10] qcom_scm: scm call for create, prepare and import keys
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
                   ` (5 preceding siblings ...)
  2021-12-06 22:57 ` [PATCH 06/10] soc: qcom: add wrapped key support for ICE Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2021-12-14  1:50   ` Eric Biggers
  2021-12-06 22:57 ` [PATCH 08/10] scsi: ufs: add support for generate, import and prepare keys Gaurav Kashyap
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

Storage encryption has two IOCTLs for creating, importing
and preparing keys for encryption. For wrapped keys, these
IOCTLs need to interface with the secure environment, which
require these SCM calls.

generate_key: This is used to generate and return a longterm
              wrapped key. Trustzone achieves this by generating
	      a key and then wrapping it using hwkm, returning
	      a wrapped keyblob.
import_key:   The functionality is similar to generate, but here,
              a raw key is imported into hwkm and a longterm wrapped
	      keyblob is returned.
prepare_key:  The longterm wrapped key from import or generate
              is made further secure by rewrapping it with a per-boot
	      ephemeral wrapped key before installing it to the linux
	      kernel for programming to ICE.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/firmware/qcom_scm.c | 213 ++++++++++++++++++++++++++++++++++++
 drivers/firmware/qcom_scm.h |   3 +
 include/linux/qcom_scm.h    |  24 +++-
 3 files changed, 239 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 4a7703846788..cca5c1ac5666 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1135,6 +1135,219 @@ int qcom_scm_derive_sw_secret(const u8 *wrapped_key, u32 wrapped_key_size,
 }
 EXPORT_SYMBOL(qcom_scm_derive_sw_secret);
 
+/**
+ * qcom_scm_generate_ice_key() - Generate a wrapped key for encryption.
+ * @longterm_wrapped_key: the wrapped key returned after key generation
+ * @longterm_wrapped_key_size: size of the wrapped key to be returned.
+ *
+ * Qualcomm wrapped keys need to be generated in a trusted environment.
+ * A generate key  IOCTL call is used to achieve this. These are longterm
+ * in nature as they need to be generated and wrapped only once per
+ * requirement.
+ *
+ * This SCM calls adds support for the generate key IOCTL to interface
+ * with the secure environment to generate and return a wrapped key..
+ *
+ * Return: 0 on success; -errno on failure.
+ */
+int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key,
+			    u32 longterm_wrapped_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),
+		.args[1] = longterm_wrapped_key_size,
+		.owner = ARM_SMCCC_OWNER_SIP,
+	};
+
+	void *longterm_wrapped_keybuf;
+	dma_addr_t longterm_wrapped_key_phys;
+	int ret;
+
+	/*
+	 * Like qcom_scm_ice_set_key(), we use dma_alloc_coherent() to properly
+	 * get a physical address, while guaranteeing that we can zeroize the
+	 * key material later using memzero_explicit().
+	 *
+	 */
+	longterm_wrapped_keybuf = dma_alloc_coherent(__scm->dev,
+				  longterm_wrapped_key_size,
+				  &longterm_wrapped_key_phys, GFP_KERNEL);
+	if (!longterm_wrapped_keybuf)
+		return -ENOMEM;
+
+	desc.args[0] = longterm_wrapped_key_phys;
+
+	ret = qcom_scm_call(__scm->dev, &desc, NULL);
+	memcpy(longterm_wrapped_key, longterm_wrapped_keybuf,
+	       longterm_wrapped_key_size);
+
+	memzero_explicit(longterm_wrapped_keybuf, longterm_wrapped_key_size);
+	dma_free_coherent(__scm->dev, longterm_wrapped_key_size,
+			  longterm_wrapped_keybuf, longterm_wrapped_key_phys);
+
+	return ret;
+}
+EXPORT_SYMBOL(qcom_scm_generate_ice_key);
+
+/**
+ * qcom_scm_prepare_ice_key() - Get per boot ephemeral wrapped key
+ * @longterm_wrapped_key: the wrapped key
+ * @longterm_wrapped_key_size: size of the wrapped key
+ * @ephemeral_wrapped_key: ephemeral wrapped key to be returned
+ * @ephemeral_wrapped_key_size: size of the ephemeral wrapped key
+ *
+ * Qualcomm wrapped keys (longterm keys) are rewrapped with a per-boot
+ * ephemeral key for added protection. These are ephemeral in nature as
+ * they are valid only for that boot. A create key IOCTL is used to
+ * achieve this. These are the keys that are installed into the kernel
+ * to be then unwrapped and programmed into ICE.
+ *
+ * This SCM call adds support for the create key IOCTL to interface
+ * with the secure environment to rewrap the wrapped key with an
+ * ephemeral wrapping key.
+ *
+ * Return: 0 on success; -errno on failure.
+ */
+int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
+			     u32 longterm_wrapped_key_size,
+			     u8 *ephemeral_wrapped_key,
+			     u32 ephemeral_wrapped_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),
+		.args[1] = longterm_wrapped_key_size,
+		.args[3] = ephemeral_wrapped_key_size,
+		.owner = ARM_SMCCC_OWNER_SIP,
+	};
+
+	void *longterm_wrapped_keybuf, *ephemeral_wrapped_keybuf;
+	dma_addr_t longterm_wrapped_key_phys, ephemeral_wrapped_key_phys;
+	int ret;
+
+	/*
+	 * Like qcom_scm_ice_set_key(), we use dma_alloc_coherent() to properly
+	 * get a physical address, while guaranteeing that we can zeroize the
+	 * key material later using memzero_explicit().
+	 *
+	 */
+	longterm_wrapped_keybuf = dma_alloc_coherent(__scm->dev,
+				  longterm_wrapped_key_size,
+				  &longterm_wrapped_key_phys, GFP_KERNEL);
+	if (!longterm_wrapped_keybuf)
+		return -ENOMEM;
+	ephemeral_wrapped_keybuf = dma_alloc_coherent(__scm->dev,
+				   ephemeral_wrapped_key_size,
+				   &ephemeral_wrapped_key_phys, GFP_KERNEL);
+	if (!ephemeral_wrapped_keybuf) {
+		ret = -ENOMEM;
+		goto bail_keybuf;
+	}
+
+	memcpy(longterm_wrapped_keybuf, longterm_wrapped_key,
+	       longterm_wrapped_key_size);
+	desc.args[0] = longterm_wrapped_key_phys;
+	desc.args[2] = ephemeral_wrapped_key_phys;
+
+	ret = qcom_scm_call(__scm->dev, &desc, NULL);
+	if (!ret)
+		memcpy(ephemeral_wrapped_key, ephemeral_wrapped_keybuf,
+		       ephemeral_wrapped_key_size);
+
+	memzero_explicit(ephemeral_wrapped_keybuf, ephemeral_wrapped_key_size);
+	dma_free_coherent(__scm->dev, ephemeral_wrapped_key_size,
+			  ephemeral_wrapped_keybuf,
+			  ephemeral_wrapped_key_phys);
+
+bail_keybuf:
+	memzero_explicit(longterm_wrapped_keybuf, longterm_wrapped_key_size);
+	dma_free_coherent(__scm->dev, longterm_wrapped_key_size,
+			  longterm_wrapped_keybuf, longterm_wrapped_key_phys);
+
+	return ret;
+}
+EXPORT_SYMBOL(qcom_scm_prepare_ice_key);
+
+/**
+ * qcom_scm_import_ice_key() - Import a wrapped key for encryption
+ * @imported_key: the raw key that is imported
+ * @imported_key_size: size of the key to be imported
+ * @longterm_wrapped_key: the wrapped key to be returned
+ * @longterm_wrapped_key_size: size of the wrapped key
+ *
+ * Conceptually, this is very similar to generate, the difference being,
+ * here we want to import a raw key and return a longterm wrapped key
+ * from it. THe same create key IOCTL is used to achieve this.
+ *
+ * This SCM call adds support for the create key IOCTL to interface with
+ * the secure environment to import a raw key and generate a longterm
+ * wrapped key.
+ *
+ * Return: 0 on success; -errno on failure.
+ */
+int qcom_scm_import_ice_key(const u8 *imported_key, u32 imported_key_size,
+			    u8 *longterm_wrapped_key,
+			    u32 longterm_wrapped_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),
+		.args[1] = imported_key_size,
+		.args[3] = longterm_wrapped_key_size,
+		.owner = ARM_SMCCC_OWNER_SIP,
+	};
+
+	void *imported_keybuf, *longterm_wrapped_keybuf;
+	dma_addr_t imported_key_phys, longterm_wrapped_key_phys;
+	int ret;
+	/*
+	 * Like qcom_scm_ice_set_key(), we use dma_alloc_coherent() to properly
+	 * get a physical address, while guaranteeing that we can zeroize the
+	 * key material later using memzero_explicit().
+	 *
+	 */
+	imported_keybuf = dma_alloc_coherent(__scm->dev, imported_key_size,
+			  &imported_key_phys, GFP_KERNEL);
+	if (!imported_keybuf)
+		return -ENOMEM;
+	longterm_wrapped_keybuf = dma_alloc_coherent(__scm->dev,
+				  longterm_wrapped_key_size,
+				  &longterm_wrapped_key_phys, GFP_KERNEL);
+	if (!longterm_wrapped_keybuf) {
+		ret = -ENOMEM;
+		goto bail_keybuf;
+	}
+
+	memcpy(imported_keybuf, imported_key, imported_key_size);
+	desc.args[0] = imported_key_phys;
+	desc.args[2] = longterm_wrapped_key_phys;
+
+	ret = qcom_scm_call(__scm->dev, &desc, NULL);
+	if (!ret)
+		memcpy(longterm_wrapped_key, longterm_wrapped_keybuf,
+		       longterm_wrapped_key_size);
+
+	memzero_explicit(longterm_wrapped_keybuf, longterm_wrapped_key_size);
+	dma_free_coherent(__scm->dev, longterm_wrapped_key_size,
+			  longterm_wrapped_keybuf, longterm_wrapped_key_phys);
+bail_keybuf:
+	memzero_explicit(imported_keybuf, imported_key_size);
+	dma_free_coherent(__scm->dev, imported_key_size, imported_keybuf,
+			  imported_key_phys);
+
+	return ret;
+}
+EXPORT_SYMBOL(qcom_scm_import_ice_key);
+
 /**
  * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
  *
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index 08bb2a4c80db..efd0ede1fb37 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -111,6 +111,9 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
 #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	0xA
 
 #define QCOM_SCM_SVC_HDCP		0x11
 #define QCOM_SCM_HDCP_INVOKE		0x01
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index ccd764bdc357..865e4b4392a1 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -106,6 +106,16 @@ extern int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
 extern int qcom_scm_derive_sw_secret(const u8 *wrapped_key,
 				     u32 wrapped_key_size, u8 *sw_secret,
 				     u32 secret_size);
+extern int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key,
+				     u32 longterm_wrapped_key_size);
+extern int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
+				    u32 longterm_wrapped_key_size,
+				    u8 *ephemeral_wrapped_key,
+				    u32 ephemeral_wrapped_key_size);
+extern int qcom_scm_import_ice_key(const u8 *imported_key,
+				   u32 imported_key_size,
+				   u8 *longterm_wrapped_key,
+				   u32 longterm_wrapped_key_size);
 
 extern bool qcom_scm_hdcp_available(void);
 extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
@@ -175,7 +185,19 @@ static inline int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
 static inline int qcom_scm_derive_sw_secret(const u8 *wrapped_key,
 					u32 wrapped_key_size, u8 *sw_secret,
 					u32 secret_size) { return -ENODEV; }
-
+static inline int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key,
+				     u32 longterm_wrapped_key_size)
+		{ return -ENODEV; }
+static inline int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
+				    u32 longterm_wrapped_key_size,
+				    u8 *ephemeral_wrapped_key,
+				    u32 ephemeral_wrapped_key_size)
+		{ return -ENODEV; }
+static inline int qcom_scm_import_ice_key(const u8 *imported_key,
+				   u32 imported_key_size,
+				   u8 *longterm_wrapped_key,
+				   u32 longterm_wrapped_key_size)
+		{ return -ENODEV; }
 static inline bool qcom_scm_hdcp_available(void) { return false; }
 static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
 		u32 *resp) { return -ENODEV; }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 08/10] scsi: ufs: add support for generate, import and prepare keys
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
                   ` (6 preceding siblings ...)
  2021-12-06 22:57 ` [PATCH 07/10] qcom_scm: scm call for create, prepare and import keys Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2021-12-14  1:53   ` Eric Biggers
  2021-12-06 22:57 ` [PATCH 09/10] soc: qcom: support for generate, import and prepare key Gaurav Kashyap
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

This patch contains two changes in UFS for wrapped keys.
1. Implements the blk_crypto_profile ops for generate, import
   and prepare key apis.
2. Adds UFS vops for generate, import and prepare keys so
   that vendors can hooks to them.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/scsi/ufs/ufshcd-crypto.c | 50 ++++++++++++++++++++++++++++++--
 drivers/scsi/ufs/ufshcd.h        | 11 +++++++
 2 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c
index 9d68621a0eb4..2bea9b924f77 100644
--- a/drivers/scsi/ufs/ufshcd-crypto.c
+++ b/drivers/scsi/ufs/ufshcd-crypto.c
@@ -136,9 +136,9 @@ bool ufshcd_crypto_enable(struct ufs_hba *hba)
 }
 
 static int ufshcd_crypto_derive_sw_secret(struct blk_crypto_profile *profile,
-				const u8 *wrapped_key,
-				unsigned int wrapped_key_size,
-				u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
+					  const u8 *wrapped_key,
+					  unsigned int wrapped_key_size,
+					  u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
 {
 	struct ufs_hba *hba =
 		container_of(profile, struct ufs_hba, crypto_profile);
@@ -146,6 +146,47 @@ static int ufshcd_crypto_derive_sw_secret(struct blk_crypto_profile *profile,
 	if (hba->vops && hba->vops->derive_secret)
 		return  hba->vops->derive_secret(hba, wrapped_key,
 						 wrapped_key_size, sw_secret);
+	return 0;
+}
+
+static int ufshcd_crypto_generate_key(struct blk_crypto_profile *profile,
+		u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+	struct ufs_hba *hba =
+		container_of(profile, struct ufs_hba, crypto_profile);
+
+	if (hba->vops && hba->vops->generate_key)
+		return  hba->vops->generate_key(longterm_wrapped_key);
+
+	return -EOPNOTSUPP;
+}
+
+static int ufshcd_crypto_prepare_key(struct blk_crypto_profile *profile,
+		const u8 *longterm_wrapped_key,
+		size_t longterm_wrapped_key_size,
+		u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+	struct ufs_hba *hba =
+		container_of(profile, struct ufs_hba, crypto_profile);
+
+	if (hba->vops && hba->vops->prepare_key)
+		return  hba->vops->prepare_key(longterm_wrapped_key,
+			longterm_wrapped_key_size, ephemerally_wrapped_key);
+
+	return -EOPNOTSUPP;
+}
+
+static int ufshcd_crypto_import_key(struct blk_crypto_profile *profile,
+		const u8 *imported_key,
+		size_t imported_key_size,
+		u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+	struct ufs_hba *hba =
+		container_of(profile, struct ufs_hba, crypto_profile);
+
+	if (hba->vops && hba->vops->import_key)
+		return  hba->vops->import_key(imported_key,
+			imported_key_size, longterm_wrapped_key);
 
 	return -EOPNOTSUPP;
 }
@@ -154,6 +195,9 @@ static const struct blk_crypto_ll_ops ufshcd_crypto_ops = {
 	.keyslot_program	= ufshcd_crypto_keyslot_program,
 	.keyslot_evict		= ufshcd_crypto_keyslot_evict,
 	.derive_sw_secret	= ufshcd_crypto_derive_sw_secret,
+	.generate_key		= ufshcd_crypto_generate_key,
+	.prepare_key		= ufshcd_crypto_prepare_key,
+	.import_key		= ufshcd_crypto_import_key,
 };
 
 static enum blk_crypto_mode_num
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 095c2d660aa7..88cd21dec0d9 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -321,6 +321,10 @@ struct ufs_pwr_mode_info {
  * @program_key: program or evict an inline encryption key
  * @event_notify: called to notify important events
  * @derive_secret: derive sw secret from wrapped inline encryption key
+ * @generate_key: generate a longterm wrapped key for inline encryption
+ * @prepare_key: prepare the longterm wrapped key for inline encryption
+ *               by rewrapping with a ephemeral wrapping key.
+ * @import_key: import a raw key and return a longterm wrapped key.
  */
 struct ufs_hba_variant_ops {
 	const char *name;
@@ -362,6 +366,13 @@ struct ufs_hba_variant_ops {
 	int	(*derive_secret)(struct ufs_hba *hba, const u8 *wrapped_key,
 				 unsigned int wrapped_key_size,
 				 u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
+	int	(*generate_key)(u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
+	int	(*prepare_key)(const u8 *longterm_wrapped_key,
+			       unsigned int longterm_wrapped_key_size,
+			       u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
+	int	(*import_key)(const u8 *imported_key,
+			       unsigned int imported_key_size,
+			       u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
 };
 
 /* clock gating state  */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 09/10] soc: qcom: support for generate, import and prepare key
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
                   ` (7 preceding siblings ...)
  2021-12-06 22:57 ` [PATCH 08/10] scsi: ufs: add support for generate, import and prepare keys Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2021-12-14  2:04   ` Eric Biggers
  2021-12-06 22:57 ` [PATCH 10/10] arm64: dts: qcom: sm8350: add ice and hwkm mappings Gaurav Kashyap
  2022-01-06 19:47 ` [PATCH 00/10] Add wrapped key support for Qualcomm ICE Eric Biggers
  10 siblings, 1 reply; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

Implements the vops for generate, prepare and import key
apis and hooks it up the scm calls defined for them.
Key management has to be done from Qualcomm Trustzone as only
it can interface with HWKM.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/scsi/ufs/ufs-qcom-ice.c   | 22 ++++++++
 drivers/scsi/ufs/ufs-qcom.c       |  3 ++
 drivers/scsi/ufs/ufs-qcom.h       | 12 +++++
 drivers/soc/qcom/qti-ice-common.c | 89 ++++++++++++++++++++++++++++---
 include/linux/qti-ice-common.h    |  8 +++
 5 files changed, 128 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index c8305aab6714..7f0485553d75 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -130,3 +130,25 @@ int ufs_qcom_ice_derive_sw_secret(struct ufs_hba *hba, const u8 *wrapped_key,
 					wrapped_key, wrapped_key_size,
 					sw_secret);
 }
+
+int ufs_qcom_ice_generate_key(
+	u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+	return qti_ice_generate_key(longterm_wrapped_key);
+}
+
+int ufs_qcom_ice_prepare_key(const u8 *longterm_wrapped_key,
+		unsigned int longterm_wrapped_key_size,
+		u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+	return qti_ice_prepare_key(longterm_wrapped_key, longterm_wrapped_key_size,
+				   ephemerally_wrapped_key);
+}
+
+int ufs_qcom_ice_import_key(const u8 *imported_key,
+		unsigned int imported_key_size,
+		u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+	return qti_ice_import_key(imported_key, imported_key_size,
+				   longterm_wrapped_key);
+}
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 9f85332fbe64..cbd472844065 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1496,6 +1496,9 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,
 	.derive_secret		= ufs_qcom_ice_derive_sw_secret,
+	.generate_key		= ufs_qcom_ice_generate_key,
+	.prepare_key		= ufs_qcom_ice_prepare_key,
+	.import_key		= ufs_qcom_ice_import_key,
 };
 
 /**
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index e7da3d1dc3c7..1f8ed9adb28f 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -259,6 +259,14 @@ int ufs_qcom_ice_program_key(struct ufs_hba *hba,
 int ufs_qcom_ice_derive_sw_secret(struct ufs_hba *hba, const u8 *wrapped_key,
 				  unsigned int wrapped_key_size,
 				  u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
+int ufs_qcom_ice_generate_key(
+		u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
+int ufs_qcom_ice_prepare_key(const u8 *longterm_wrapped_key,
+		unsigned int longterm_wrapped_key_size,
+		u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
+int ufs_qcom_ice_import_key(const u8 *imported_key,
+		unsigned int imported_key_size,
+		u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
 #else
 static inline int ufs_qcom_ice_init(struct ufs_qcom_host *host)
 {
@@ -273,6 +281,10 @@ static inline int ufs_qcom_ice_resume(struct ufs_qcom_host *host)
 	return 0;
 }
 #define ufs_qcom_ice_program_key NULL
+#define ufs_qcom_ice_derive_sw_secret NULL
+#define ufs_qcom_ice_generate_key NULL
+#define ufs_qcom_ice_prepare_key NULL
+#define ufs_qcom_ice_import_key NULL
 #endif /* !CONFIG_SCSI_UFS_CRYPTO */
 
 #endif /* UFS_QCOM_H_ */
diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c
index 76703afa4834..cc035f1a1d42 100644
--- a/drivers/soc/qcom/qti-ice-common.c
+++ b/drivers/soc/qcom/qti-ice-common.c
@@ -13,13 +13,21 @@
 
 #define QTI_ICE_MAX_BIST_CHECK_COUNT    100
 #define QTI_AES_256_XTS_KEY_RAW_SIZE	64
+#define QTI_HWKM_WRAPPED_KEY_SIZE_V1	68
+#define QTI_HWKM_WRAPPED_KEY_SIZE_V2	100
 
 /*
  * ICE resets during power collapse and HWKM has to be
  * reconfigured which can be kept track with this flag.
  */
 static bool qti_hwkm_init_done;
-static int hwkm_version;
+static int qti_hwkm_version;
+
+/*
+ * Size of the wrapped key returned by HWKM, which varies with
+ * hwkm version
+ */
+static unsigned int qti_hwkm_wrapped_key_size;
 
 union crypto_cfg {
 	__le32 regval;
@@ -45,10 +53,13 @@ static bool qti_ice_supported(const struct ice_mmio_data *mmio)
 		return false;
 	}
 
-	if ((major >= 4) || ((major == 3) && (minor == 2) && (step >= 1)))
-		hwkm_version = 2;
-	else
-		hwkm_version = 1;
+	if ((major >= 4) || ((major == 3) && (minor == 2) && (step >= 1))) {
+		qti_hwkm_wrapped_key_size = QTI_HWKM_WRAPPED_KEY_SIZE_V2;
+		qti_hwkm_version = 2;
+	} else {
+		qti_hwkm_wrapped_key_size = QTI_HWKM_WRAPPED_KEY_SIZE_V1;
+		qti_hwkm_version = 1;
+	}
 
 	pr_info("Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n",
 		 major, minor, step);
@@ -168,7 +179,7 @@ static int qti_ice_program_wrapped_key(const struct ice_mmio_data *mmio,
 	 * won't work.
 	 */
 	if (!qti_hwkm_init_done) {
-		err = qti_ice_hwkm_init(mmio, hwkm_version);
+		err = qti_ice_hwkm_init(mmio, qti_hwkm_version);
 		if (err) {
 			pr_err("%s: Error initializing hwkm, err = %d",
 							__func__, err);
@@ -322,4 +333,70 @@ int qti_ice_derive_sw_secret(const struct ice_mmio_data *mmio,
 }
 EXPORT_SYMBOL_GPL(qti_ice_derive_sw_secret);
 
+/**
+ * qti_ice_generate_key() - Generate a wrapped key for inline encryption
+ * @longterm_wrapped_key: wrapped key that is generated, which is at most
+ *                        BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE in size.
+ *
+ * Make a scm call into trustzone to generate a wrapped key for storage
+ * encryption using hwkm.
+ *
+ * Return: 0 on success; err on failure.
+ */
+int qti_ice_generate_key(
+		u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+	return qcom_scm_generate_ice_key(longterm_wrapped_key,
+			       qti_hwkm_wrapped_key_size);
+}
+EXPORT_SYMBOL_GPL(qti_ice_generate_key);
+
+/**
+ * qti_ice_prepare_key() - Prepare a longterm wrapped key for inline encryption
+ * @longterm_wrapped_key: wrapped key that is generated,
+ * @longterm_wrapped_key_size: size of the longterm wrapped_key
+ * @ephemerally_wrapped_key: wrapped key returned which has been wrapped with
+ *                           a per-boot ephemeral key, size of which is at most
+ *                           BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE
+ *
+ * Make a scm call into trustzone to prepare a wrapped key for storage
+ * encryption by rewrapping the longterm wrapped key with a per boot ephemeral
+ * key using hwkm.
+ *
+ * Return: 0 on success; err on failure.
+ */
+int qti_ice_prepare_key(const u8 *longterm_wrapped_key,
+		unsigned int longterm_wrapped_key_size,
+		u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+	return qcom_scm_prepare_ice_key(longterm_wrapped_key,
+				    longterm_wrapped_key_size,
+				    ephemerally_wrapped_key,
+				    qti_hwkm_wrapped_key_size);
+}
+EXPORT_SYMBOL_GPL(qti_ice_prepare_key);
+
+/**
+ * qti_ice_import_key() - Importa raw key for inline encryption
+ * @imported_key: raw key that has to be imported
+ * @imported_key_size: size of the imported key
+ * @longterm_wrapped_key: longterm wrapped key returned which has been wrapped
+ *                        after imporint the raw key using hwkm.
+ *
+ * Make a scm call into trustzone to import a raw key for storage encryption
+ * and generating a longterm wrapped key using hwkm.
+ *
+ * Return: 0 on success; err on failure.
+ */
+int qti_ice_import_key(const u8 *imported_key,
+		unsigned int imported_key_size,
+		u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+	return qcom_scm_import_ice_key(imported_key,
+				    imported_key_size,
+				    longterm_wrapped_key,
+				    qti_hwkm_wrapped_key_size);
+}
+EXPORT_SYMBOL_GPL(qti_ice_import_key);
+
 MODULE_LICENSE("GPL v2");
diff --git a/include/linux/qti-ice-common.h b/include/linux/qti-ice-common.h
index e329afeba113..cae5275ee1d9 100644
--- a/include/linux/qti-ice-common.h
+++ b/include/linux/qti-ice-common.h
@@ -28,5 +28,13 @@ int qti_ice_derive_sw_secret(const struct ice_mmio_data *mmio,
 			     const u8 *wrapped_key,
 			     unsigned int wrapped_key_size,
 			     u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
+int qti_ice_generate_key(
+		u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
+int qti_ice_prepare_key(const u8 *longterm_wrapped_key,
+		unsigned int longterm_wrapped_key_size,
+		u8 ephemerally_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
+int qti_ice_import_key(const u8 *imported_key,
+		unsigned int imported__key_size,
+		u8 longterm_wrapped_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE]);
 
 #endif /* _QTI_ICE_COMMON_H */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 10/10] arm64: dts: qcom: sm8350: add ice and hwkm mappings
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
                   ` (8 preceding siblings ...)
  2021-12-06 22:57 ` [PATCH 09/10] soc: qcom: support for generate, import and prepare key Gaurav Kashyap
@ 2021-12-06 22:57 ` Gaurav Kashyap
  2022-01-06 19:47 ` [PATCH 00/10] Add wrapped key support for Qualcomm ICE Eric Biggers
  10 siblings, 0 replies; 24+ messages in thread
From: Gaurav Kashyap @ 2021-12-06 22:57 UTC (permalink / raw)
  To: linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg, Gaurav Kashyap

Add register mappings for ICE (Inline Crypto Engine) and
HWKM (Hardware Key Manager) slave, which are both part
of the UFS controller for sm8350.

These are required for inline storage encryption using
hardware wrapped key.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 arch/arm64/boot/dts/qcom/sm8350.dtsi | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi
index e91cd8a5e535..8e15524731b3 100644
--- a/arch/arm64/boot/dts/qcom/sm8350.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi
@@ -1019,7 +1019,10 @@
 		ufs_mem_hc: ufshc@1d84000 {
 			compatible = "qcom,sm8350-ufshc", "qcom,ufshc",
 				     "jedec,ufs-2.0";
-			reg = <0 0x01d84000 0 0x3000>;
+			reg = <0 0x01d84000 0 0x3000>,
+			      <0 0x01d88000 0 0x8000>,
+			      <0 0x01d90000 0 0x9000>;
+			reg-names = "ufs_mem", "ice", "ice_hwkm";
 			interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>;
 			phys = <&ufs_mem_phy_lanes>;
 			phy-names = "ufsphy";
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH 01/10] soc: qcom: new common library for ICE functionality
  2021-12-06 22:57 ` [PATCH 01/10] soc: qcom: new common library for ICE functionality Gaurav Kashyap
@ 2021-12-07  0:24   ` Randy Dunlap
  2021-12-14  0:20   ` Eric Biggers
  1 sibling, 0 replies; 24+ messages in thread
From: Randy Dunlap @ 2021-12-07  0:24 UTC (permalink / raw)
  To: Gaurav Kashyap, linux-scsi, linux-arm-msm
  Cc: linux-mmc, linux-block, linux-fscrypt, thara.gopinath,
	quic_neersoni, dineshg

Hi,

Since I have no idea what "ICE" means in this context:

On 12/6/21 14:57, Gaurav Kashyap wrote:
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 79b568f82a1c..a900f5ab6263 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -209,4 +209,11 @@ config QCOM_APR
>  	  application processor and QDSP6. APR is
>  	  used by audio driver to configure QDSP6
>  	  ASM, ADM and AFE modules.
> +
> +config QTI_ICE_COMMON
> +	tristate "QTI common ICE functionality"

please do something like (just an example!):

	tristate "QTI common ICE (internal compiler error) functionality"

> +	depends on ARCH_QCOM
> +	help
> +	  Enable the common ICE library that can be used
> +	  by UFS and EMMC drivers for ICE functionality.
>  endmenu

thanks.
-- 
~Randy

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 01/10] soc: qcom: new common library for ICE functionality
  2021-12-06 22:57 ` [PATCH 01/10] soc: qcom: new common library for ICE functionality Gaurav Kashyap
  2021-12-07  0:24   ` Randy Dunlap
@ 2021-12-14  0:20   ` Eric Biggers
  1 sibling, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2021-12-14  0:20 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

On Mon, Dec 06, 2021 at 02:57:16PM -0800, Gaurav Kashyap wrote:
> Add a new library which congregates all the ICE
> functionality so that all storage controllers containing
> ICE can utilize it.

In commit messages and comments, please spell out "Inline Crypto Engine (ICE)"
the first time it appears, so that people know what ICE means.

> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 79b568f82a1c..a900f5ab6263 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -209,4 +209,11 @@ config QCOM_APR
>  	  application processor and QDSP6. APR is
>  	  used by audio driver to configure QDSP6
>  	  ASM, ADM and AFE modules.
> +
> +config QTI_ICE_COMMON
> +	tristate "QTI common ICE functionality"

Since this is a library, it shouldn't be user-selectable, but rather just be
selected by the other options that need it.  Putting a string after "tristate"
makes it user-selectable; the string is the prompt string.  The line should just
be "tristate", without a string afterwards.

> diff --git a/drivers/soc/qcom/qti-ice-common.c b/drivers/soc/qcom/qti-ice-common.c
> new file mode 100644
> index 000000000000..0c5b529201c5
> --- /dev/null
> +++ b/drivers/soc/qcom/qti-ice-common.c
> @@ -0,0 +1,199 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Common ICE library for storage encryption.
> + *
> + * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved.
> + */
> +
> +#include <linux/qti-ice-common.h>
> +#include <linux/module.h>
> +#include <linux/qcom_scm.h>
> +#include <linux/delay.h>
> +#include "qti-ice-regs.h"
> +
> +#define QTI_ICE_MAX_BIST_CHECK_COUNT    100
> +#define QTI_AES_256_XTS_KEY_RAW_SIZE	64
> +
> +static bool qti_ice_supported(const struct ice_mmio_data *mmio)
> +{
> +	u32 regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_VERSION);
> +	int major = regval >> 24;
> +	int minor = (regval >> 16) & 0xFF;
> +	int step = regval & 0xFFFF;
> +
> +	/* For now this driver only supports ICE version 3 and higher. */
> +	if (major < 3) {
> +		pr_warn("Unsupported ICE version: v%d.%d.%d\n",
> +			 major, minor, step);
> +		return false;
> +	}

For log messages associated with a device, the dev_*() functions should be used
instead of pr_*().  How about including the relevant 'struct device *' in the
struct ice_mmio_data?

This comment applies to everywhere in qti-ice-common that is logging anything.

> +/**
> + * qti_ice_init() - Initialize ICE functionality
> + * @ice_mmio_data: contains ICE register mapping for i/o
> + *
> + * Initialize ICE by checking the version for ICE support and
> + * also checking the fuses blown.
> + *
> + * Return: 0 on success; -EINVAL on failure.
> + */
> +int qti_ice_init(const struct ice_mmio_data *mmio)
> +{
> +	if (!qti_ice_supported(mmio))
> +		return -EINVAL;
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(qti_ice_init);

Be more specific about what "failure" means here.  It means that the driver
doesn't support the ICE hardware, right?  -ENODEV would be a more appropriate
error code for this.  -EINVAL is a very generic error.

> +static void qti_ice_low_power_and_optimization_enable(
> +				const struct ice_mmio_data *mmio)
> +{
> +	u32 regval = qti_ice_readl(mmio->ice_mmio,
> +				   QTI_ICE_REGS_ADVANCED_CONTROL);
> +
> +	/* Enable low power mode sequence
> +	 * [0]-0,[1]-0,[2]-0,[3]-7,[4]-0,[5]-0,[6]-0,[7]-0,
> +	 * Enable CONFIG_CLK_GATING, STREAM2_CLK_GATING and STREAM1_CLK_GATING
> +	 */
> +	regval |= 0x7000;
> +	/* Optimization enable sequence*/
> +	regval |= 0xD807100;
> +	qti_ice_writel(mmio->ice_mmio, regval, QTI_ICE_REGS_ADVANCED_CONTROL);
> +	/* Memory barrier - to ensure write completion before next transaction */
> +	wmb();
> +}

This part changed slightly from the original code in
drivers/scsi/ufs/ufs-qcom-ice.c and drivers/mmc/host/sdhci-msm.c.  What is the
reason for these changes?  To be fair, I can't properly explain this part of the
original code; I just did what some existing ICE code was doing.  But if it
wasn't the correct or best way, it would be super useful to understand *why*
this different version is really the correct/best way.

Also note that the line "regval |= 0x7000;" is redundant.

> +static int qti_ice_wait_bist_status(const struct ice_mmio_data *mmio)
> +{
> +	int count;
> +	u32 regval;
> +
> +	for (count = 0; count < QTI_ICE_MAX_BIST_CHECK_COUNT; count++) {
> +		regval = qti_ice_readl(mmio->ice_mmio,
> +				       QTI_ICE_REGS_BIST_STATUS);
> +		if (!(regval & QTI_ICE_BIST_STATUS_MASK))
> +			break;
> +		udelay(50);
> +	}
> +
> +	if (regval) {
> +		pr_err("%s: wait bist status failed, reg %d\n",
> +			__func__, regval);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}

The copy of this in drivers/mmc/host/sdhci-msm.c is a bit nicer in that it uses
the readl_poll_timeout() helper function, and it has a longer comment explaining
it.  So I think you should use that version rather than the UFS version.

> +/**
> + * qti_ice_keyslot_program() - Program a key to an ICE slot
> + * @ice_mmio_data: contains ICE register mapping for i/o
> + * @crypto_key: key to be program, this can be wrapped or raw
> + * @crypto_key_size: size of the key to be programmed
> + * @slot: the keyslot at which the key should be programmed.
> + * @data_unit_mask: mask for the dun which is part of the
> + *                  crypto configuration.
> + * @capid: capability index indicating the algorithm for the
> + *         crypto configuration
> + *
> + * Program the passed in key to a slot in ICE.
> + * The key that is passed in can either be a raw key or wrapped.
> + * In both cases, due to access control of ICE for Qualcomm chipsets,
> + * a scm call is used to program the key into ICE from trustzone.
> + * Trustzone can differentiate between raw and wrapped keys.

How does TrustZone differentiate between raw and wrapped keys?  I thought you
had mentioned that only one is supported at a time on a particular SoC.

> +int qti_ice_keyslot_program(const struct ice_mmio_data *mmio,
> +			    const u8 *crypto_key, unsigned int crypto_key_size,
> +			    unsigned int slot, u8 data_unit_mask, int capid)
> +{
> +	int err = 0;
> +	int i = 0;
> +	union {
> +		u8 bytes[QTI_AES_256_XTS_KEY_RAW_SIZE];
> +		u32 words[QTI_AES_256_XTS_KEY_RAW_SIZE / sizeof(u32)];
> +	} key;
> +
> +	memcpy(key.bytes, crypto_key, crypto_key_size);

This is assuming that wrapped keys aren't longer than raw AES-256-XTS keys,
which isn't necessarily true.

> +#define qti_ice_writel(mmio, val, reg)		\
> +	writel_relaxed((val), mmio + (reg))
> +#define qti_ice_readl(mmio, reg)		\
> +	readl_relaxed(mmio + (reg))

Previously, writel() and readl() were used instead of writel_relaxed() and
readl_relaxed().  What is the reason for this change?  My understanding is that
the *_relaxed() functions are harder to use correctly, so they shouldn't be used
unless it's been carefully thought through and the extra performance is needed.

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 02/10] scsi: ufs: qcom: move ICE functionality to common library
  2021-12-06 22:57 ` [PATCH 02/10] scsi: ufs: qcom: move ICE functionality to common library Gaurav Kashyap
@ 2021-12-14  0:40   ` Eric Biggers
  0 siblings, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2021-12-14  0:40 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

On Mon, Dec 06, 2021 at 02:57:17PM -0800, Gaurav Kashyap wrote:
> Remove the ICE support in UFS and use the shared library
> for crypto functionality.
> 
> Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>

Can you reword this to make it clear that this patch isn't removing ICE support
from the UFS driver, but rather just refactoring how it is implemented?

Also please make sure to clearly describe any changes in behavior, or else
reorder the patchset so that no behavior is changed until after the conversion.
There are some behavior changes that I pointed out on the previous patch.

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 03/10] qcom_scm: scm call for deriving a software secret
  2021-12-06 22:57 ` [PATCH 03/10] qcom_scm: scm call for deriving a software secret Gaurav Kashyap
@ 2021-12-14  0:53   ` Eric Biggers
  0 siblings, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2021-12-14  0:53 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

On Mon, Dec 06, 2021 at 02:57:18PM -0800, Gaurav Kashyap wrote:
> Storage encryption requires fscrypt deriving a sw secret from

As I mentioned on the previous version of this patchset, I think mentions of
"fscrypt" should generally be avoided at the driver level.  Drivers don't know
or care who is using block layer functionality.  It's better to think of the
sw_secret support as simply one of the requirements for hardware-wrapped keys,
alongside the other ones such as support for import_key, prepare_key, etc.

> +/**
> + * qcom_scm_derive_sw_secret() - Derive SW secret from wrapped encryption key
> + * @wrapped_key: the wrapped key used for inline encryption
> + * @wrapped_key_size: size of the wrapped key
> + * @sw_secret: the secret to be derived which is at most the secret size
> + * @secret_size: maximum size of the secret that is derived
> + *
> + * Derive a SW secret to be used for inline encryption using Qualcomm ICE.

The SW secret isn't used for inline encryption.  It's actually the opposite; the
SW secret is used only for tasks that can't use inline encryption.

> + * For wrapped keys, the key needs to be unwrapped, in order to derive a
> + * SW secret, which can be done only by the secure EE. So, it makes sense
> + * for the secure EE to derive the sw secret and return to the kernel when
> + * wrapped keys are used.

The second sentence above seems to be saying the same as the first.

> + * Return: 0 on success; -errno on failure.
> + */
> +int qcom_scm_derive_sw_secret(const u8 *wrapped_key, u32 wrapped_key_size,
> +			      u8 *sw_secret, u32 secret_size)

Is @secret_size really the "maximum size of the secret that is derived"?  That
would imply that a shorter secret might be derived.  But if the return value is
0 on success, then there is no way for callers to know what length was derived.

Can't the semantics be "derive exactly secret_size bytes"?  That would make much
more sense.

> diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
> index c0475d1c9885..ccd764bdc357 100644
> --- a/include/linux/qcom_scm.h
> +++ b/include/linux/qcom_scm.h
> @@ -103,6 +103,9 @@ extern int qcom_scm_ice_invalidate_key(u32 index);
>  extern int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
>  				enum qcom_scm_ice_cipher cipher,
>  				u32 data_unit_size);
> +extern int qcom_scm_derive_sw_secret(const u8 *wrapped_key,
> +				     u32 wrapped_key_size, u8 *sw_secret,
> +				     u32 secret_size);
>  
>  extern bool qcom_scm_hdcp_available(void);
>  extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
> @@ -169,6 +172,9 @@ static inline int qcom_scm_ice_invalidate_key(u32 index) { return -ENODEV; }
>  static inline int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
>  				       enum qcom_scm_ice_cipher cipher,
>  				       u32 data_unit_size) { return -ENODEV; }
> +static inline int qcom_scm_derive_sw_secret(const u8 *wrapped_key,
> +					u32 wrapped_key_size, u8 *sw_secret,
> +					u32 secret_size) { return -ENODEV; }
>  
>  static inline bool qcom_scm_hdcp_available(void) { return false; }
>  static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,

These "return -ENODEV" stubs don't exist in the latest kernel.  Can you make
sure that you've developing on top of the latest kernel?  It looks like you
based this patchset on top of my patchset
https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/log/?h=wrapped-keys-v2.
But I had already sent out a newer version of it, based on v5.16-rc1:
https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/log/?h=wrapped-keys-v4.
So please make sure you're using the most recent version.

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 04/10] soc: qcom: add HWKM library for storage encryption
  2021-12-06 22:57 ` [PATCH 04/10] soc: qcom: add HWKM library for storage encryption Gaurav Kashyap
@ 2021-12-14  1:08   ` Eric Biggers
  0 siblings, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2021-12-14  1:08 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

On Mon, Dec 06, 2021 at 02:57:19PM -0800, Gaurav Kashyap wrote:
> Wrapped keys should utilize hardware to protect the keys
> used for storage encryption. Qualcomm's Inline Crypto Engine

"should utilize" => "utilize"?

> supports a hardware block called Hardware Key Manager (HWKM)
> for key management.
> 
> Although most of the interactions to this hardware block happens
> via a secure execution environment, some initializations for the
> slave present in ICE can be done from the kernel.
> 
> This can also be a placeholder for when the hardware provides more
> capabilities to be accessed from the linux kernel in the future.
> 

This commit message doesn't explain what this commit actually does.  Can you
make that clearer?

> diff --git a/drivers/soc/qcom/qti-ice-hwkm.c b/drivers/soc/qcom/qti-ice-hwkm.c
> new file mode 100644
> index 000000000000..3be6b350cd88
> --- /dev/null
> +++ b/drivers/soc/qcom/qti-ice-hwkm.c
> @@ -0,0 +1,111 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * HWKM ICE library for storage encryption.
> + *
> + * Copyright (c) 2021, Qualcomm Innovation Center. All rights reserved.
> + */
> +
> +#include <linux/qti-ice-common.h>
> +#include "qti-ice-regs.h"
> +
> +static int qti_ice_hwkm_bist_status(const struct ice_mmio_data *mmio, int version)
> +{
> +	if (!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
> +			(version == 1) ? BIST_DONE_V1 : BIST_DONE_V2) ||
> +	!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
> +			(version == 1) ? CRYPTO_LIB_BIST_DONE_V1 :
> +			CRYPTO_LIB_BIST_DONE_V2) ||
> +	!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
> +			(version == 1) ? BOOT_CMD_LIST1_DONE_V1 :
> +			BOOT_CMD_LIST1_DONE_V2) ||
> +	!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
> +			(version == 1) ? BOOT_CMD_LIST0_DONE_V1 :
> +			BOOT_CMD_LIST0_DONE_V2) ||
> +	!qti_ice_hwkm_testb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_STATUS,
> +			(version == 1) ? KT_CLEAR_DONE_V1 :
> +			KT_CLEAR_DONE_V2))
> +		return -EINVAL;
> +	return 0;
> +}

Long "if" statements are hard to read.  It would be more readable to have a
separate "if" and "return -EINVAL" for each of these checks.

> +static void qti_ice_hwkm_configure_ice_registers(
> +				const struct ice_mmio_data *mmio)
> +{
> +	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
> +			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_0);
> +	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
> +			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_1);
> +	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
> +			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_2);
> +	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
> +			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_3);
> +	qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0xffffffff,
> +			    QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_4);
> +}
> +
> +static int qti_ice_hwkm_init_sequence(const struct ice_mmio_data *mmio,
> +				      int version)
> +{
> +	u32 val = 0;
> +
> +	/*
> +	 * Put ICE in standard mode, ICE defaults to legacy mode.
> +	 * Legacy mode - ICE HWKM slave not supported.
> +	 * Standard mode - ICE HWKM slave supported.
> +	 *
> +	 * Depending on the version of HWKM, it is controlled by different
> +	 * registers in ICE.
> +	 */
> +	if (version >= 2) {
> +		val = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_CONTROL);
> +		val = val & 0xFFFFFFFE;
> +		qti_ice_writel(mmio->ice_mmio, val, QTI_ICE_REGS_CONTROL);
> +	} else {
> +		qti_ice_hwkm_writel(mmio->ice_hwkm_mmio, 0x7,
> +				    QTI_HWKM_ICE_RG_TZ_KM_CTL);
> +	}

So to use wrapped keys, ICE needs to be in "standard mode", and to use standard
keys it needs to be in "legacy mode"?  That's confusing.  It would be helpful to
explain this more clearly in a comment.

> +
> +	/* Check BIST status */
> +	if (qti_ice_hwkm_bist_status(mmio, version))
> +		return -EINVAL;

Please spell out what BIST stands for.  It's "Built-In Self Test", right?

> +
> +	/*
> +	 * Give register bank of the HWKM slave access to read and modify
> +	 * the keyslots in ICE HWKM slave. Without this, trustzone will not
> +	 * be able to program keys into ICE.
> +	 */
> +	qti_ice_hwkm_configure_ice_registers(mmio);
> +
> +	/* Disable CRC check */
> +	qti_ice_hwkm_clearb(mmio->ice_hwkm_mmio, QTI_HWKM_ICE_RG_TZ_KM_CTL,
> +			    CRC_CHECK_EN);
> +
> +	/* Set RSP_FIFO_FULL bit */
> +	qti_ice_hwkm_setb(mmio->ice_hwkm_mmio,
> +			QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS, RSP_FIFO_FULL);

Please expand on comments as much as possible, so that people can understand not
just what the code is doing but why it is doing it.  E.g., why does the CRC
check need to be disabled, and why does the RSP_FIFO_FULL bit need to be set?

> +/**
> + * qti_ice_hwkm_init() - Initialize ICE HWKM hardware
> + * @ice_mmio_data: contains ICE register mapping for i/o
> + * @version: version of hwkm hardware
> + *
> + * Perform HWKM initialization in the ICE slave by going
> + * through the slave initialization routine.The registers
> + * can vary slightly based on the version.
> + *
> + * Return: 0 on success; err on failure.
> + */
> +
> +int qti_ice_hwkm_init(const struct ice_mmio_data *mmio, int version)
> +{
> +	if (!mmio->ice_hwkm_mmio)
> +		return -EINVAL;
> +
> +	return qti_ice_hwkm_init_sequence(mmio, version);
> +}
> +EXPORT_SYMBOL_GPL(qti_ice_hwkm_init);

This function is only called from within the same kernel module, so it doesn't
need to be an exported symbol.

> +MODULE_LICENSE("GPL v2");

The main source file for this module (qti-ice-common.c) already has a
MODULE_LICENSE, so there shouldn't be a duplicate one here.  MODULE_LICENSE is
for the whole module, not for individual source files.

> +
> +#define qti_ice_hwkm_readl(hwkm_mmio, reg)		\
> +	(readl_relaxed(hwkm_mmio + (reg)))
> +#define qti_ice_hwkm_writel(hwkm_mmio, val, reg)	\
> +	(writel_relaxed((val), hwkm_mmio + (reg)))

Why readl_relaxed() and writel_relaxed(), instead of readl() and writel()?

> +static inline bool qti_ice_hwkm_testb(void __iomem *ice_hwkm_mmio,
> +				      u32 reg, u8 nr)
> +{
> +	u32 val = qti_ice_hwkm_readl(ice_hwkm_mmio, reg);
> +
> +	val = (val >> nr) & 0x1;
> +	if (val == 0)
> +		return false;
> +	return true;
> +}

This is unnecessarily verbose.  It could be just:

	return qti_ice_hwkm_readl(ice_hwkm_mmio, reg) & (1U << nr);

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 05/10] scsi: ufs: prepare to support wrapped keys
  2021-12-06 22:57 ` [PATCH 05/10] scsi: ufs: prepare to support wrapped keys Gaurav Kashyap
@ 2021-12-14  1:26   ` Eric Biggers
  0 siblings, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2021-12-14  1:26 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

On Mon, Dec 06, 2021 at 02:57:20PM -0800, Gaurav Kashyap wrote:
> Adds support in ufshcd-core for wrapped keys.
> 1. Change program key vop to support wrapped key sizes by
>    using blk_crypto_key directly instead of using ufs_crypto_cfg
>    which is not suitable for wrapped keys.
> 2. Add derive_sw_secret vop and derive_sw_secret crypto_profile op.
> 
> Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
> ---
>  drivers/scsi/ufs/ufshcd-crypto.c | 52 +++++++++++++++++++++++++-------
>  drivers/scsi/ufs/ufshcd.h        |  9 +++++-
>  2 files changed, 49 insertions(+), 12 deletions(-)

There will be a build error if the patch series is applied just up to here,
since this patch changes the prototype of ufs_hba_variant_ops::program_key but
doesn't update ufs_qcom which implements it.

Every intermediate step needs to be buildable, and that's more important than
keeping changes to different drivers separate.

So I recommend having one patch that does the program_key change, in both
ufshcd-crypto.c and ufs-qcom-ice.c.

Adding derive_sw_secret should be a separate patch, and maybe should be combined
with the other new methods.

> diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c
> index 0ed82741f981..9d68621a0eb4 100644
> --- a/drivers/scsi/ufs/ufshcd-crypto.c
> +++ b/drivers/scsi/ufs/ufshcd-crypto.c
> @@ -18,16 +18,23 @@ static const struct ufs_crypto_alg_entry {
>  };
>  
>  static int ufshcd_program_key(struct ufs_hba *hba,
> +			      const struct blk_crypto_key *key,
>  			      const union ufs_crypto_cfg_entry *cfg, int slot)
>  {
>  	int i;
>  	u32 slot_offset = hba->crypto_cfg_register + slot * sizeof(*cfg);
>  	int err = 0;
> +	bool evict = false;
>  
>  	ufshcd_hold(hba, false);
>  
>  	if (hba->vops && hba->vops->program_key) {
> -		err = hba->vops->program_key(hba, cfg, slot);
> +		if (!(cfg->config_enable & UFS_CRYPTO_CONFIGURATION_ENABLE))
> +			evict = true;
> +		err = hba->vops->program_key(hba, key, slot,
> +					     cfg->data_unit_size,
> +					     cfg->crypto_cap_idx,
> +					     evict);
>  		goto out;
>  	}

This is a little weird because here we've already gone through the trouble of
creating a 'union ufs_crypto_cfg_entry', only to throw it away in the
->program_key case and just use the original blk_crypto_key instead.

I think that this should be refactored a bit to make it so that a
'ufs_crypto_cfg_entry' is only be initialized if program_key is not implemented.

Also, note that 'struct blk_crypto_key' includes the data unit size.  So there's
no need to pass the data unit size as a separate argument to program_key.

> +static int ufshcd_crypto_derive_sw_secret(struct blk_crypto_profile *profile,
> +				const u8 *wrapped_key,
> +				unsigned int wrapped_key_size,
> +				u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
> +{
> +	struct ufs_hba *hba =
> +		container_of(profile, struct ufs_hba, crypto_profile);
> +
> +	if (hba->vops && hba->vops->derive_secret)
> +		return  hba->vops->derive_secret(hba, wrapped_key,
> +						 wrapped_key_size, sw_secret);

There's a weird double space here.

> @@ -190,7 +215,12 @@ int ufshcd_hba_init_crypto_capabilities(struct ufs_hba *hba)
>  	hba->crypto_profile.ll_ops = ufshcd_crypto_ops;
>  	/* UFS only supports 8 bytes for any DUN */
>  	hba->crypto_profile.max_dun_bytes_supported = 8;
> -	hba->crypto_profile.key_types_supported = BLK_CRYPTO_KEY_TYPE_STANDARD;
> +	if (hba->hw_wrapped_keys_supported)
> +		hba->crypto_profile.key_types_supported =
> +				BLK_CRYPTO_KEY_TYPE_HW_WRAPPED;
> +	else
> +		hba->crypto_profile.key_types_supported =
> +				BLK_CRYPTO_KEY_TYPE_STANDARD;

"hw_wrapped_keys_supported" is confusing because it doesn't just mean that
wrapped keys are supported, but also that standard keys are *not* supported.
"use_hw_wrapped_keys" would be clearer.

However, given that wrapped keys aren't specified by the UFS standard, I think
this better belongs as a bit in hba->quirks, like
UFSHCD_QUIRK_USES_WRAPPED_CRYPTO_KEYS.

> +	int	(*derive_secret)(struct ufs_hba *hba, const u8 *wrapped_key,
> +				 unsigned int wrapped_key_size,
> +				 u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);

This probably should be called derive_sw_secret, not just derive_secret.

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 06/10] soc: qcom: add wrapped key support for ICE
  2021-12-06 22:57 ` [PATCH 06/10] soc: qcom: add wrapped key support for ICE Gaurav Kashyap
@ 2021-12-14  1:46   ` Eric Biggers
  0 siblings, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2021-12-14  1:46 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

On Mon, Dec 06, 2021 at 02:57:21PM -0800, Gaurav Kashyap wrote:
> Add support for wrapped keys in ufs and common ICE library.
> Qualcomm's ICE solution uses a hardware block called Hardware
> Key Manager (HWKM) to handle wrapped keys.
> 
> This patch adds the following changes to support this.
> 1. Link to HWKM library for initialization.
> 2. Most of the key management is done from Trustzone via scm calls.
>    Added calls to this from the ICE library.
> 3. Added support for this framework in ufs qcom.
> 4. Added support for deriving SW secret as it cannot be done in
>    linux kernel for wrapped keys.
> 
> Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
> ---
>  drivers/scsi/ufs/ufs-qcom-ice.c   |  48 +++++++--
>  drivers/scsi/ufs/ufs-qcom.c       |   1 +
>  drivers/scsi/ufs/ufs-qcom.h       |   7 +-
>  drivers/soc/qcom/qti-ice-common.c | 158 +++++++++++++++++++++++++++---
>  include/linux/qti-ice-common.h    |  11 ++-
>  5 files changed, 198 insertions(+), 27 deletions(-)

If possible, the qti-ice-common changes should be a separate patch that goes
before the ufs-qcom changes.  Are there interdependencies that make this
impossible?  I see the prototype change in qti_ice_keyslot_evict() (see below),
but that could be avoided by using the right prototype from the beginning.

> diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
> index 3826643bf537..c8305aab6714 100644
> --- a/drivers/scsi/ufs/ufs-qcom-ice.c
> +++ b/drivers/scsi/ufs/ufs-qcom-ice.c
> @@ -43,6 +43,24 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *host)
>  		return err;
>  	}
>  
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice_hwkm");
> +	if (!res) {
> +		dev_warn(dev, "ICE HWKM registers not found\n");
> +		host->ice_data.hw_wrapped_keys_supported = false;
> +		goto init;
> +	}

I don't think a warning is appropriate here, as this is expected behavior on
SoCs that support standard keys rather than wrapped keys.

> +	host->ice_data.ice_hwkm_mmio = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(host->ice_data.ice_hwkm_mmio)) {
> +		err = PTR_ERR(host->ice_data.ice_hwkm_mmio);
> +		dev_err(dev, "Failed to map HWKM registers; err=%d\n", err);
> +		return err;
> +	}
> +	host->ice_data.hw_wrapped_keys_supported = true;

Similar to what I suggested on the previous patch: "hw_wrapped_keys_supported"
should be called something like "using_hw_wrapped_keys", since it means that
standard keys are *not* supported, not just that wrapped keys are supported.

>  int ufs_qcom_ice_program_key(struct ufs_hba *hba,
> -			     const union ufs_crypto_cfg_entry *cfg, int slot)
> +			     const struct blk_crypto_key *key, int slot,
> +			     u8 data_unit_size, int capid, bool evict)
>  {
>  	union ufs_crypto_cap_entry cap;
>  	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
>  
> -	if (!(cfg->config_enable & UFS_CRYPTO_CONFIGURATION_ENABLE))
> -		return qti_ice_keyslot_evict(slot);
> +	if (evict)
> +		return qti_ice_keyslot_evict(&host->ice_data, slot);

It probably would be easier if qti_ice_keyslot_evict() took the ice_data
parameter from the beginning.  Then its prototype wouldn't need to change
halfway through the patch series.

>  static bool qti_ice_supported(const struct ice_mmio_data *mmio)
>  {
>  	u32 regval = qti_ice_readl(mmio->ice_mmio, QTI_ICE_REGS_VERSION);
> @@ -28,6 +45,11 @@ static bool qti_ice_supported(const struct ice_mmio_data *mmio)
>  		return false;
>  	}
>  
> +	if ((major >= 4) || ((major == 3) && (minor == 2) && (step >= 1)))
> +		hwkm_version = 2;
> +	else
> +		hwkm_version = 1;

Is this trying to check whether the ICE version is greater than or equal to
3.2.1?  If so, this isn't quite correct, as it doesn't handle 3.X correctly
where X is greater than 2.

> +	/*
> +	 * HWKM slave in ICE should be initialized before the first
> +	 * time we perform ICE HWKM related operations. This is because
> +	 * ICE by default comes up in legacy mode where HWKM operations
> +	 * won't work.
> +	 */
> +	if (!qti_hwkm_init_done) {
> +		err = qti_ice_hwkm_init(mmio, hwkm_version);
> +		if (err) {
> +			pr_err("%s: Error initializing hwkm, err = %d",
> +							__func__, err);
> +			return -EINVAL;
> +		}
> +		qti_hwkm_init_done = true;
> +	}

This code is duplicated in two places.  Can it be consolidated into a helper
function?  Also, "should be initialized" => "must be initialized"?

> +
> +	memset(&cfg, 0, sizeof(cfg));
> +	cfg.dusize = data_unit_mask;
> +	cfg.capidx = capid;
> +	cfg.cfge = 0x80;
> +
> +	/* Make sure CFGE is cleared */
> +	qti_ice_writel(mmio->ice_mmio, 0x0, (QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 +
> +				QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET*slot));
> +	/* Memory barrier - to ensure write completion before next transaction */
> +	wmb();

Is this memory barrier necessary only because writel_relaxed() is being used?
Using writel() would probably be a better idea, as I've mentioned elsewhere.

Also, what does a "transaction" mean in this context?

> +
> +	/* Call trustzone to program the wrapped key using hwkm */
> +	err =  qcom_scm_ice_set_key(slot, crypto_key->raw, crypto_key->size,
> +				    capid, data_unit_mask);

There's a weird double space here.

> +	if (err)
> +		pr_err("%s:SCM call Error: 0x%x slot %d\n",
> +					__func__, err, slot);
> +
> +	/* Make sure CFGE is enabled after programming the key */
> +	qti_ice_writel(mmio->ice_mmio, cfg.regval,
> +			(QTI_ICE_LUT_KEYS_CRYPTOCFG_R_16 +
> +			 QTI_ICE_LUT_KEYS_CRYPTOCFG_OFFSET*slot));

Shouln't CFGE not be set on failure?

> +int qti_ice_keyslot_evict(const struct ice_mmio_data *mmio, unsigned int slot)
>  {
> +	/*
> +	 * Ignore calls to evict key when wrapped keys are supported and
> +	 * hwkm init is not yet done. This is to avoid the clearing all slots
> +	 * call that comes from ufs during ufs reset. HWKM slave in ICE takes
> +	 * care of zeroing out the keytable on reset.
> +	 */
> +	if (mmio->hw_wrapped_keys_supported && !qti_hwkm_init_done)
> +		return 0;

I guess this is reasonable.  (The alternative would be to not clear the keyslots
in the first place.)  But this is going to be used by MMC too, so the comment
should be worded in a generic way and not be tied to UFS.

> +/**
> + * qti_ice_derive_sw_secret() - Derive SW secret from wrapped key
> + * @wrapped_key: wrapped key from which secret should be derived
> + * @wrapped_key_size: size of the wrapped key
> + * @sw_secret: secret to be returned, which is atmost BLK_CRYPTO_SW_SECRET_SIZE

The resulting sw_secret needs to be *exactly* BLK_CRYPTO_SW_SECRET_SIZE bytes,
not "at most" that many bytes.

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 07/10] qcom_scm: scm call for create, prepare and import keys
  2021-12-06 22:57 ` [PATCH 07/10] qcom_scm: scm call for create, prepare and import keys Gaurav Kashyap
@ 2021-12-14  1:50   ` Eric Biggers
  0 siblings, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2021-12-14  1:50 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

On Mon, Dec 06, 2021 at 02:57:22PM -0800, Gaurav Kashyap wrote:
> +/**
> + * qcom_scm_generate_ice_key() - Generate a wrapped key for encryption.
> + * @longterm_wrapped_key: the wrapped key returned after key generation
> + * @longterm_wrapped_key_size: size of the wrapped key to be returned.
> + *
> + * Qualcomm wrapped keys need to be generated in a trusted environment.
> + * A generate key  IOCTL call is used to achieve this. These are longterm
> + * in nature as they need to be generated and wrapped only once per
> + * requirement.
> + *
> + * This SCM calls adds support for the generate key IOCTL to interface
> + * with the secure environment to generate and return a wrapped key..
> + *
> + * Return: 0 on success; -errno on failure.
> + */
> +int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key,
> +			    u32 longterm_wrapped_key_size)

Isn't longterm_wrapped_key_size really a maximum size?  How does this function
indicate the size of the resulting key?

> +/**
> + * qcom_scm_prepare_ice_key() - Get per boot ephemeral wrapped key
> + * @longterm_wrapped_key: the wrapped key
> + * @longterm_wrapped_key_size: size of the wrapped key
> + * @ephemeral_wrapped_key: ephemeral wrapped key to be returned
> + * @ephemeral_wrapped_key_size: size of the ephemeral wrapped key
> + *
> + * Qualcomm wrapped keys (longterm keys) are rewrapped with a per-boot
> + * ephemeral key for added protection. These are ephemeral in nature as
> + * they are valid only for that boot. A create key IOCTL is used to
> + * achieve this. These are the keys that are installed into the kernel
> + * to be then unwrapped and programmed into ICE.
> + *
> + * This SCM call adds support for the create key IOCTL to interface
> + * with the secure environment to rewrap the wrapped key with an
> + * ephemeral wrapping key.
> + *
> + * Return: 0 on success; -errno on failure.
> + */
> +int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
> +			     u32 longterm_wrapped_key_size,
> +			     u8 *ephemeral_wrapped_key,
> +			     u32 ephemeral_wrapped_key_size)

Similarly here.  Isn't ephemeral_wrapped_key_size really a maximum size?  How
does this function indicate the size of the resulting ephemeral wrapped key?

> +/**
> + * qcom_scm_import_ice_key() - Import a wrapped key for encryption
> + * @imported_key: the raw key that is imported
> + * @imported_key_size: size of the key to be imported

imported_key and imported_key_size should be called raw_key and raw_key_size.

> + * @longterm_wrapped_key: the wrapped key to be returned
> + * @longterm_wrapped_key_size: size of the wrapped key
> + *
> + * Conceptually, this is very similar to generate, the difference being,
> + * here we want to import a raw key and return a longterm wrapped key
> + * from it. THe same create key IOCTL is used to achieve this.
> + *
> + * This SCM call adds support for the create key IOCTL to interface with
> + * the secure environment to import a raw key and generate a longterm
> + * wrapped key.
> + *
> + * Return: 0 on success; -errno on failure.
> + */
> +int qcom_scm_import_ice_key(const u8 *imported_key, u32 imported_key_size,
> +			    u8 *longterm_wrapped_key,
> +			    u32 longterm_wrapped_key_size)

And likewise, isn't longterm_wrapped_key_size really a maximum size?  How does
this function indicate the size of the resulting key?

> diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
> index 08bb2a4c80db..efd0ede1fb37 100644
> --- a/drivers/firmware/qcom_scm.h
> +++ b/drivers/firmware/qcom_scm.h
> @@ -111,6 +111,9 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
>  #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	0xA

Writing "0xA" here looks weird.  It should be "0x0A" to match the others.

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 08/10] scsi: ufs: add support for generate, import and prepare keys
  2021-12-06 22:57 ` [PATCH 08/10] scsi: ufs: add support for generate, import and prepare keys Gaurav Kashyap
@ 2021-12-14  1:53   ` Eric Biggers
  0 siblings, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2021-12-14  1:53 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

On Mon, Dec 06, 2021 at 02:57:23PM -0800, Gaurav Kashyap wrote:
> This patch contains two changes in UFS for wrapped keys.
> 1. Implements the blk_crypto_profile ops for generate, import
>    and prepare key apis.
> 2. Adds UFS vops for generate, import and prepare keys so
>    that vendors can hooks to them.
> 
> Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>

When adding things to ufs_hba_variant_ops, it would helpful to explain why they
belong there.  It's because this stuff isn't part of the UFS standard, right?

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 09/10] soc: qcom: support for generate, import and prepare key
  2021-12-06 22:57 ` [PATCH 09/10] soc: qcom: support for generate, import and prepare key Gaurav Kashyap
@ 2021-12-14  2:04   ` Eric Biggers
  0 siblings, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2021-12-14  2:04 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

On Mon, Dec 06, 2021 at 02:57:24PM -0800, Gaurav Kashyap wrote:
> Implements the vops for generate, prepare and import key
> apis and hooks it up the scm calls defined for them.
> Key management has to be done from Qualcomm Trustzone as only
> it can interface with HWKM.
> 
> Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
> ---
>  drivers/scsi/ufs/ufs-qcom-ice.c   | 22 ++++++++
>  drivers/scsi/ufs/ufs-qcom.c       |  3 ++
>  drivers/scsi/ufs/ufs-qcom.h       | 12 +++++
>  drivers/soc/qcom/qti-ice-common.c | 89 ++++++++++++++++++++++++++++---
>  include/linux/qti-ice-common.h    |  8 +++
>  5 files changed, 128 insertions(+), 6 deletions(-)

Similarly to patch 6, it would be preferable to change qti-ice-common in a
separate patch that precedes the ufs-qcom changes, if it's possible.

If this is starting to result in too many patches, you might consider combining
the patches that add generate/import/prepare with the patches that add
derive_sw_secret.  Splitting up patches between subsystems (when possible) is
more important than splitting up the wrapped key feature itself, IMO.

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 00/10] Add wrapped key support for Qualcomm ICE
  2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
                   ` (9 preceding siblings ...)
  2021-12-06 22:57 ` [PATCH 10/10] arm64: dts: qcom: sm8350: add ice and hwkm mappings Gaurav Kashyap
@ 2022-01-06 19:47 ` Eric Biggers
  2022-01-06 21:14   ` Gaurav Kashyap
  10 siblings, 1 reply; 24+ messages in thread
From: Eric Biggers @ 2022-01-06 19:47 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, quic_neersoni, dineshg

Hi Gaurav,

On Mon, Dec 06, 2021 at 02:57:15PM -0800, Gaurav Kashyap wrote:
> Testing:
> Test platform: SM8350 HDK/MTP
> Engineering trustzone image (based on sm8350) is required to test
> this feature. This is because of version changes of HWKM.
> HWKM version 2 and moving forward has a lot of restrictions on the
> key management due to which the launched SM8350 solution (based on v1)
> cannot be used and some modifications are required in trustzone.

I've been trying to test this patchset on a SM8350 HDK using the TrustZone image
you provided, but it's not completely working yet.

This is the kernel branch I'm using:
https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/log/?h=wip-wrapped-keys.
It has my v4 patchset with your patchset rebased on top of it, some qcom_scm.c
fixes I had to make (see below), and some extra logging messages.

This is how I'm building and booting a kernel on the board:
https://github.com/ebiggers/fscryptctl/blob/wip-wrapped-keys/scripts/sm8350-buildkernel.sh

And this is the test script I'm running:
https://github.com/ebiggers/fscryptctl/blob/wip-wrapped-keys/scripts/wrappedkey-test.sh.
It imports or generates a hardware-wrapped key, then tries to set up a directory
on an ext4 filesystem that is encrypted with that key.   This uses new
'fscryptctl' commands to access the new blk-crypto ioctls; the version of
'fscryptctl' on the branch the scripts are on has all the needed changes.

QCOM_SCM_ES_IMPORT_ICE_KEY, QCOM_SCM_ES_GENERATE_ICE_KEY,
QCOM_SCM_ES_PREPARE_ICE_KEY, all seem to work.  However,
QCOM_SCM_ES_DERIVE_SW_SECRET doesn't work; it always returns -EINVAL.

For example:

Importing hardware-wrapped key
[  187.606109] blk-crypto: entering BLKCRYPTOCREATEKEY
[  187.611648] calling QCOM_SCM_ES_IMPORT_ICE_KEY; raw_key=5858585858585858585858585858585858585858585858585858585858585858
[  187.628180] QCOM_SCM_ES_IMPORT_ICE_KEY succeeded; longterm_wrapped_key=fab51aa07fb6c2bf2fea60a8120e8d35a9e53865b594e0fb6279e7951a34864591f1c1c4e26f9421039377c1ac311ff9241a0152030000000000000000000000
[  187.646433] blk-crypto: exiting BLKCRYPTOCREATEKEY; ret=0
Preparing hardware-wrapped key
[  187.653129] blk-crypto: entering BLKCRYPTOPREPAREKEY
[  187.660356] calling QCOM_SCM_ES_PREPARE_ICE_KEY; longterm_wrapped_key=fab51aa07fb6c2bf2fea60a8120e8d35a9e53865b594e0fb6279e7951a34864591f1c1c4e26f9421039377c1ac311ff9241a0152030000000000000000000000
[  187.680420] QCOM_SCM_ES_PREPARE_ICE_KEY succeeded; ephemeral_wrapped_key=1fbf5d501854858d6faaf52c9d22bebc576012e40485ba75e7d19e88f74b3400eb1a8836e28232939e990df6007659b1241a0152030000000000000000000000
[  187.698791] blk-crypto: exiting BLKCRYPTOPREPAREKEY; ret=0
Adding hardware-wrapped key
[  187.705515] calling blk_crypto_derive_sw_secret(); wrapped_key_size=68
[  187.714075] in qti_ice_derive_sw_secret()
[  187.718212] calling qti_ice_hwkm_init()
[  187.722157] calling qti_ice_hwkm_init_sequence(version=1)
[  187.727715] setting standard mode
[  187.731134] checking BIST status
[  187.734464] configuring ICE registers
[  187.738230] disabling CRC check
[  187.741479] setting RSP_FIFO_FULL bit
[  187.745247] calling qcom_scm_derive_sw_secret()
[  187.749920] calling QCOM_SCM_ES_DERIVE_SW_SECRET; wrapped_key=1fbf5d501854858d6faaf52c9d22bebc576012e40485ba75e7d19e88f74b3400eb1a8836e28232939e990df6007659b1241a0152030000000000000000000000, secret_size=32
[  187.768834] QCOM_SCM_ES_DERIVE_SW_SECRET failed with error -22
[  187.774838] blk_crypto_derive_sw_secret() returned -22
error: adding key to /mnt: Invalid argument


You can see that the wrapped_key being passed to QCOM_SCM_ES_DERIVE_SW_SECRET
matches the ephemeral_wrapped_key that was returned earlier by
QCOM_SCM_ES_PREPARE_ICE_KEY, and that secret_size is 32.  So the arguments are
as expected.  However, QCOM_SCM_ES_DERIVE_SW_SECRET still fails.

This still occurs if QCOM_SCM_ES_GENERATE_ICE_KEY is used instead of
QCOM_SCM_ES_IMPORT_ICE_KEY.

Have you tested that QCOM_SCM_ES_DERIVE_SW_SECRET is working properly?

For reference, these are the fixes I had to apply to qcom_scm.c to get things
working until that point.  This included fixing the direction of the first
arguments to the SCM calls, and fixing the return values.  Note, I also tested
leaving QCOM_SCM_ES_DERIVE_SW_SECRET using QCOM_SCM_RO instead of QCOM_SCM_RW,
but the result was still the same --- it still returned -EINVAL.

diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index d57f52015640..002b57a1473d 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1087,7 +1087,7 @@ int qcom_scm_derive_sw_secret(const u8 *wrapped_key, u32 wrapped_key_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_RO,
+		.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW,
 					 QCOM_SCM_VAL, QCOM_SCM_RW,
 					 QCOM_SCM_VAL),
 		.args[1] = wrapped_key_size,
@@ -1148,7 +1148,7 @@ EXPORT_SYMBOL(qcom_scm_derive_sw_secret);
  * This SCM calls adds support for the generate key IOCTL to interface
  * with the secure environment to generate and return a wrapped key..
  *
- * Return: 0 on success; -errno on failure.
+ * Return: size of the resulting key on success; -errno on failure.
  */
 int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key,
 			    u32 longterm_wrapped_key_size)
@@ -1188,7 +1188,7 @@ int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key,
 	dma_free_coherent(__scm->dev, longterm_wrapped_key_size,
 			  longterm_wrapped_keybuf, longterm_wrapped_key_phys);
 
-	return ret;
+	return ret ?: longterm_wrapped_key_size;
 }
 EXPORT_SYMBOL(qcom_scm_generate_ice_key);
 
@@ -1209,7 +1209,7 @@ EXPORT_SYMBOL(qcom_scm_generate_ice_key);
  * with the secure environment to rewrap the wrapped key with an
  * ephemeral wrapping key.
  *
- * Return: 0 on success; -errno on failure.
+ * Return: size of the resulting key on success; -errno on failure.
  */
 int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
 			     u32 longterm_wrapped_key_size,
@@ -1219,7 +1219,7 @@ int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
 	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,
+		.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW,
 					 QCOM_SCM_VAL, QCOM_SCM_RW,
 					 QCOM_SCM_VAL),
 		.args[1] = longterm_wrapped_key_size,
@@ -1270,7 +1270,7 @@ int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
 	dma_free_coherent(__scm->dev, longterm_wrapped_key_size,
 			  longterm_wrapped_keybuf, longterm_wrapped_key_phys);
 
-	return ret;
+	return ret ?: ephemeral_wrapped_key_size;
 }
 EXPORT_SYMBOL(qcom_scm_prepare_ice_key);
 
@@ -1289,7 +1289,7 @@ EXPORT_SYMBOL(qcom_scm_prepare_ice_key);
  * the secure environment to import a raw key and generate a longterm
  * wrapped key.
  *
- * Return: 0 on success; -errno on failure.
+ * Return: size of the resulting key on success; -errno on failure.
  */
 int qcom_scm_import_ice_key(const u8 *imported_key, u32 imported_key_size,
 			    u8 *longterm_wrapped_key,
@@ -1298,7 +1298,7 @@ int qcom_scm_import_ice_key(const u8 *imported_key, u32 imported_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,
+		.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW,
 					 QCOM_SCM_VAL, QCOM_SCM_RW,
 					 QCOM_SCM_VAL),
 		.args[1] = imported_key_size,
@@ -1344,7 +1344,7 @@ int qcom_scm_import_ice_key(const u8 *imported_key, u32 imported_key_size,
 	dma_free_coherent(__scm->dev, imported_key_size, imported_keybuf,
 			  imported_key_phys);
 
-	return ret;
+	return ret ?: longterm_wrapped_key_size;
 }
 EXPORT_SYMBOL(qcom_scm_import_ice_key);

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* RE: [PATCH 00/10] Add wrapped key support for Qualcomm ICE
  2022-01-06 19:47 ` [PATCH 00/10] Add wrapped key support for Qualcomm ICE Eric Biggers
@ 2022-01-06 21:14   ` Gaurav Kashyap
  2022-01-27  0:51     ` Eric Biggers
  0 siblings, 1 reply; 24+ messages in thread
From: Gaurav Kashyap @ 2022-01-06 21:14 UTC (permalink / raw)
  To: Eric Biggers, Gaurav Kashyap (QUIC)
  Cc: linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, Neeraj Soni (QUIC),
	Dinesh Garg

Hey Eric

Have you tested that QCOM_SCM_ES_DERIVE_SW_SECRET is working properly?

- You will need updated trustzone build for that (as I was missing a minor detail in the original one pertaining to SW secret) , please request again on the same ticket for the updated build.
- I have reminded the people in Qualcomm too to provide you the build.
- Note that with the new build you should be using the correct directions, i.e QCOM_SCM_RO where intended

Warm Regards
Gaurav Kashyap

-----Original Message-----
From: Eric Biggers <ebiggers@kernel.org> 
Sent: Thursday, January 6, 2022 11:48 AM
To: Gaurav Kashyap (QUIC) <quic_gaurkash@quicinc.com>
Cc: linux-scsi@vger.kernel.org; linux-arm-msm@vger.kernel.org; linux-mmc@vger.kernel.org; linux-block@vger.kernel.org; linux-fscrypt@vger.kernel.org; thara.gopinath@linaro.org; Neeraj Soni (QUIC) <quic_neersoni@quicinc.com>; Dinesh Garg <dineshg@quicinc.com>
Subject: Re: [PATCH 00/10] Add wrapped key support for Qualcomm ICE

WARNING: This email originated from outside of Qualcomm. Please be wary of any links or attachments, and do not enable macros.

Hi Gaurav,

On Mon, Dec 06, 2021 at 02:57:15PM -0800, Gaurav Kashyap wrote:
> Testing:
> Test platform: SM8350 HDK/MTP
> Engineering trustzone image (based on sm8350) is required to test this 
> feature. This is because of version changes of HWKM.
> HWKM version 2 and moving forward has a lot of restrictions on the key 
> management due to which the launched SM8350 solution (based on v1) 
> cannot be used and some modifications are required in trustzone.

I've been trying to test this patchset on a SM8350 HDK using the TrustZone image you provided, but it's not completely working yet.

This is the kernel branch I'm using:
https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/log/?h=wip-wrapped-keys.
It has my v4 patchset with your patchset rebased on top of it, some qcom_scm.c fixes I had to make (see below), and some extra logging messages.

This is how I'm building and booting a kernel on the board:
https://github.com/ebiggers/fscryptctl/blob/wip-wrapped-keys/scripts/sm8350-buildkernel.sh

And this is the test script I'm running:
https://github.com/ebiggers/fscryptctl/blob/wip-wrapped-keys/scripts/wrappedkey-test.sh.
It imports or generates a hardware-wrapped key, then tries to set up a directory
on an ext4 filesystem that is encrypted with that key.   This uses new
'fscryptctl' commands to access the new blk-crypto ioctls; the version of 'fscryptctl' on the branch the scripts are on has all the needed changes.

QCOM_SCM_ES_IMPORT_ICE_KEY, QCOM_SCM_ES_GENERATE_ICE_KEY, QCOM_SCM_ES_PREPARE_ICE_KEY, all seem to work.  However, QCOM_SCM_ES_DERIVE_SW_SECRET doesn't work; it always returns -EINVAL.

For example:

Importing hardware-wrapped key
[  187.606109] blk-crypto: entering BLKCRYPTOCREATEKEY [  187.611648] calling QCOM_SCM_ES_IMPORT_ICE_KEY; raw_key=5858585858585858585858585858585858585858585858585858585858585858
[  187.628180] QCOM_SCM_ES_IMPORT_ICE_KEY succeeded; longterm_wrapped_key=fab51aa07fb6c2bf2fea60a8120e8d35a9e53865b594e0fb6279e7951a34864591f1c1c4e26f9421039377c1ac311ff9241a0152030000000000000000000000
[  187.646433] blk-crypto: exiting BLKCRYPTOCREATEKEY; ret=0 Preparing hardware-wrapped key [  187.653129] blk-crypto: entering BLKCRYPTOPREPAREKEY [  187.660356] calling QCOM_SCM_ES_PREPARE_ICE_KEY; longterm_wrapped_key=fab51aa07fb6c2bf2fea60a8120e8d35a9e53865b594e0fb6279e7951a34864591f1c1c4e26f9421039377c1ac311ff9241a0152030000000000000000000000
[  187.680420] QCOM_SCM_ES_PREPARE_ICE_KEY succeeded; ephemeral_wrapped_key=1fbf5d501854858d6faaf52c9d22bebc576012e40485ba75e7d19e88f74b3400eb1a8836e28232939e990df6007659b1241a0152030000000000000000000000
[  187.698791] blk-crypto: exiting BLKCRYPTOPREPAREKEY; ret=0 Adding hardware-wrapped key [  187.705515] calling blk_crypto_derive_sw_secret(); wrapped_key_size=68 [  187.714075] in qti_ice_derive_sw_secret() [  187.718212] calling qti_ice_hwkm_init() [  187.722157] calling qti_ice_hwkm_init_sequence(version=1)
[  187.727715] setting standard mode
[  187.731134] checking BIST status
[  187.734464] configuring ICE registers [  187.738230] disabling CRC check [  187.741479] setting RSP_FIFO_FULL bit [  187.745247] calling qcom_scm_derive_sw_secret() [  187.749920] calling QCOM_SCM_ES_DERIVE_SW_SECRET; wrapped_key=1fbf5d501854858d6faaf52c9d22bebc576012e40485ba75e7d19e88f74b3400eb1a8836e28232939e990df6007659b1241a0152030000000000000000000000, secret_size=32 [  187.768834] QCOM_SCM_ES_DERIVE_SW_SECRET failed with error -22 [  187.774838] blk_crypto_derive_sw_secret() returned -22
error: adding key to /mnt: Invalid argument


You can see that the wrapped_key being passed to QCOM_SCM_ES_DERIVE_SW_SECRET matches the ephemeral_wrapped_key that was returned earlier by QCOM_SCM_ES_PREPARE_ICE_KEY, and that secret_size is 32.  So the arguments are as expected.  However, QCOM_SCM_ES_DERIVE_SW_SECRET still fails.

This still occurs if QCOM_SCM_ES_GENERATE_ICE_KEY is used instead of QCOM_SCM_ES_IMPORT_ICE_KEY.

Have you tested that QCOM_SCM_ES_DERIVE_SW_SECRET is working properly?

For reference, these are the fixes I had to apply to qcom_scm.c to get things working until that point.  This included fixing the direction of the first arguments to the SCM calls, and fixing the return values.  Note, I also tested leaving QCOM_SCM_ES_DERIVE_SW_SECRET using QCOM_SCM_RO instead of QCOM_SCM_RW, but the result was still the same --- it still returned -EINVAL.

diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index d57f52015640..002b57a1473d 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1087,7 +1087,7 @@ int qcom_scm_derive_sw_secret(const u8 *wrapped_key, u32 wrapped_key_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_RO,
+               .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW,
                                         QCOM_SCM_VAL, QCOM_SCM_RW,
                                         QCOM_SCM_VAL),
                .args[1] = wrapped_key_size, @@ -1148,7 +1148,7 @@ EXPORT_SYMBOL(qcom_scm_derive_sw_secret);
  * This SCM calls adds support for the generate key IOCTL to interface
  * with the secure environment to generate and return a wrapped key..
  *
- * Return: 0 on success; -errno on failure.
+ * Return: size of the resulting key on success; -errno on failure.
  */
 int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key,
                            u32 longterm_wrapped_key_size) @@ -1188,7 +1188,7 @@ int qcom_scm_generate_ice_key(u8 *longterm_wrapped_key,
        dma_free_coherent(__scm->dev, longterm_wrapped_key_size,
                          longterm_wrapped_keybuf, longterm_wrapped_key_phys);

-       return ret;
+       return ret ?: longterm_wrapped_key_size;
 }
 EXPORT_SYMBOL(qcom_scm_generate_ice_key);

@@ -1209,7 +1209,7 @@ EXPORT_SYMBOL(qcom_scm_generate_ice_key);
  * with the secure environment to rewrap the wrapped key with an
  * ephemeral wrapping key.
  *
- * Return: 0 on success; -errno on failure.
+ * Return: size of the resulting key on success; -errno on failure.
  */
 int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
                             u32 longterm_wrapped_key_size, @@ -1219,7 +1219,7 @@ int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
        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,
+               .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW,
                                         QCOM_SCM_VAL, QCOM_SCM_RW,
                                         QCOM_SCM_VAL),
                .args[1] = longterm_wrapped_key_size, @@ -1270,7 +1270,7 @@ int qcom_scm_prepare_ice_key(const u8 *longterm_wrapped_key,
        dma_free_coherent(__scm->dev, longterm_wrapped_key_size,
                          longterm_wrapped_keybuf, longterm_wrapped_key_phys);

-       return ret;
+       return ret ?: ephemeral_wrapped_key_size;
 }
 EXPORT_SYMBOL(qcom_scm_prepare_ice_key);

@@ -1289,7 +1289,7 @@ EXPORT_SYMBOL(qcom_scm_prepare_ice_key);
  * the secure environment to import a raw key and generate a longterm
  * wrapped key.
  *
- * Return: 0 on success; -errno on failure.
+ * Return: size of the resulting key on success; -errno on failure.
  */
 int qcom_scm_import_ice_key(const u8 *imported_key, u32 imported_key_size,
                            u8 *longterm_wrapped_key, @@ -1298,7 +1298,7 @@ int qcom_scm_import_ice_key(const u8 *imported_key, u32 imported_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,
+               .arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW,
                                         QCOM_SCM_VAL, QCOM_SCM_RW,
                                         QCOM_SCM_VAL),
                .args[1] = imported_key_size, @@ -1344,7 +1344,7 @@ int qcom_scm_import_ice_key(const u8 *imported_key, u32 imported_key_size,
        dma_free_coherent(__scm->dev, imported_key_size, imported_keybuf,
                          imported_key_phys);

-       return ret;
+       return ret ?: longterm_wrapped_key_size;
 }
 EXPORT_SYMBOL(qcom_scm_import_ice_key);

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 00/10] Add wrapped key support for Qualcomm ICE
  2022-01-06 21:14   ` Gaurav Kashyap
@ 2022-01-27  0:51     ` Eric Biggers
  0 siblings, 0 replies; 24+ messages in thread
From: Eric Biggers @ 2022-01-27  0:51 UTC (permalink / raw)
  To: Gaurav Kashyap
  Cc: Gaurav Kashyap (QUIC),
	linux-scsi, linux-arm-msm, linux-mmc, linux-block, linux-fscrypt,
	thara.gopinath, Neeraj Soni (QUIC),
	Dinesh Garg

Hi Gaurav,

On Thu, Jan 06, 2022 at 09:14:22PM +0000, Gaurav Kashyap wrote:
> Hey Eric
> 
> > Have you tested that QCOM_SCM_ES_DERIVE_SW_SECRET is working properly?
> 
> - You will need updated trustzone build for that (as I was missing a minor detail in the original one pertaining to SW secret) , please request again on the same ticket for the updated build.
> - I have reminded the people in Qualcomm too to provide you the build.
> - Note that with the new build you should be using the correct directions, i.e QCOM_SCM_RO where intended
> 
> Warm Regards
> Gaurav Kashyap
> 

I verified that the latest TrustZone build is working; thanks for the help!

Note, these are the branches I'm using for now:

  * Kernel patches: https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/log/?h=wip-wrapped-keys
  * fscryptctl tool and test scripts: https://github.com/ebiggers/fscryptctl/tree/wip-wrapped-keys

The kernel branch is based on v5.17-rc1.  I haven't changed your patches from
your latest series other than rebasing them and adding a fix
"qcom_scm: fix return values" on top.

Note that v5.16-rc5 and later have a bug where the UFS controller on SM8350
isn't recognized.  Therefore, my branch contains a fix from Bjorn Andersson for
that bug, which I applied from the mailing list.

One oddity I noticed is that if I import the same raw key twice, the long-term
wrapped key blob is the same.  This implies that the key encryption algorithm
used by the Qualcomm hardware is deterministic, which is unexpected.  I would
expect the wrapped key to contain a random nonce.  Do you know why deterministic
encryption is used?  This probably isn't much of a problem, but it's unexpected.

Besides that, I think the next steps are for you to address the comments I've
left on this series, and for me to get started on adding ciphertext verification
tests for this to xfstests (alongside the other fscrypt ciphertext verification
tests that are already there) so that we can prove this feature is actually
encrypting the data as intended.

- Eric

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2022-01-27  0:51 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-06 22:57 [PATCH 00/10] Add wrapped key support for Qualcomm ICE Gaurav Kashyap
2021-12-06 22:57 ` [PATCH 01/10] soc: qcom: new common library for ICE functionality Gaurav Kashyap
2021-12-07  0:24   ` Randy Dunlap
2021-12-14  0:20   ` Eric Biggers
2021-12-06 22:57 ` [PATCH 02/10] scsi: ufs: qcom: move ICE functionality to common library Gaurav Kashyap
2021-12-14  0:40   ` Eric Biggers
2021-12-06 22:57 ` [PATCH 03/10] qcom_scm: scm call for deriving a software secret Gaurav Kashyap
2021-12-14  0:53   ` Eric Biggers
2021-12-06 22:57 ` [PATCH 04/10] soc: qcom: add HWKM library for storage encryption Gaurav Kashyap
2021-12-14  1:08   ` Eric Biggers
2021-12-06 22:57 ` [PATCH 05/10] scsi: ufs: prepare to support wrapped keys Gaurav Kashyap
2021-12-14  1:26   ` Eric Biggers
2021-12-06 22:57 ` [PATCH 06/10] soc: qcom: add wrapped key support for ICE Gaurav Kashyap
2021-12-14  1:46   ` Eric Biggers
2021-12-06 22:57 ` [PATCH 07/10] qcom_scm: scm call for create, prepare and import keys Gaurav Kashyap
2021-12-14  1:50   ` Eric Biggers
2021-12-06 22:57 ` [PATCH 08/10] scsi: ufs: add support for generate, import and prepare keys Gaurav Kashyap
2021-12-14  1:53   ` Eric Biggers
2021-12-06 22:57 ` [PATCH 09/10] soc: qcom: support for generate, import and prepare key Gaurav Kashyap
2021-12-14  2:04   ` Eric Biggers
2021-12-06 22:57 ` [PATCH 10/10] arm64: dts: qcom: sm8350: add ice and hwkm mappings Gaurav Kashyap
2022-01-06 19:47 ` [PATCH 00/10] Add wrapped key support for Qualcomm ICE Eric Biggers
2022-01-06 21:14   ` Gaurav Kashyap
2022-01-27  0:51     ` Eric Biggers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).