diff mbox

[U-Boot] imx: imx7 Support for Manufacturing Protection

Message ID 1454496994-5523-1-git-send-email-raul.casas@nxp.com
State Changes Requested
Delegated to: Stefano Babic
Headers show

Commit Message

Ulises Cardenas Feb. 3, 2016, 10:56 a.m. UTC
i.MX7 has an a protection feature for Manufacturing process.
This feature uses assymetric encryption to sign and verify
authenticated software handled between parties. This command
is enables the use of such feature.

The private key is unique and generated once per device.
And it is stored in secure memory and only accessible by CAAM.
Therefore, the public key generation and signature functions
are the only functions available for the user.

Command usage:
mfgprot 0 - prints out the public key for the device.
mfgprot 1 - signs and prints out a sample data.

This is only a working example for the signature function, and
is intended to be used as a canvas for user-specific cases.

Signed-off-by: Ulises Cardenas <raul.casas@nxp.com>
---

 arch/arm/imx-common/Makefile      |   1 +
 arch/arm/imx-common/cmd_mfgprot.c |  91 ++++++++++++
 drivers/crypto/fsl/Makefile       |   4 +
 drivers/crypto/fsl/fsl_mfgprot.c  | 286 ++++++++++++++++++++++++++++++++++++++
 include/fsl_sec.h                 |  12 ++
 5 files changed, 394 insertions(+)
 create mode 100644 arch/arm/imx-common/cmd_mfgprot.c
 create mode 100644 drivers/crypto/fsl/fsl_mfgprot.c

Comments

Fabio Estevam Feb. 5, 2016, 7:04 p.m. UTC | #1
On Wed, Feb 3, 2016 at 8:56 AM, Ulises Cardenas <raul.casas@nxp.com> wrote:

> +/**
> +* generate_mppubk() - Generates a Public for Manufacturing Protection
> +*
> +* Returns zero on success,and negative on error.
> +*/
> +static int genenerate_mppubk(void)
> +{
> +       int ret = 0;
> +
> +       ret = gen_mppubk();
> +
> +       return ret;
> +}

You could simply remove 'ret' and do a return gen_mppubk(); directly,
but maybe you don't even need genenerate_mppubk() and could use
gen_mppubk() directly instead?

> +
> +/**
> +* generate_mpsign() - Example of Signature command  for Manufacturing Protection
> +*
> +* Returns zero on success,and negative on error.
> +*/
> +static int generate_mpsign(void)
> +{
> +       int ret = 0;
> +
> +       ret = sign_mppubk();
> +
> +       return ret;
> +}

Ditto.
diff mbox

Patch

diff --git a/arch/arm/imx-common/Makefile b/arch/arm/imx-common/Makefile
index e7190c3..8563150 100644
--- a/arch/arm/imx-common/Makefile
+++ b/arch/arm/imx-common/Makefile
@@ -22,6 +22,7 @@  ifeq ($(SOC),$(filter $(SOC),mx7))
 obj-y 	+= cpu.o
 obj-$(CONFIG_SYS_I2C_MXC) += i2c-mxv7.o
 obj-$(CONFIG_SYSCOUNTER_TIMER) += syscounter.o
+obj-$(CONFIG_CMD_MFGPROT) += cmd_mfgprot.o
 endif
 ifeq ($(SOC),$(filter $(SOC),mx6 mx7))
 obj-y 	+= cache.o init.o
diff --git a/arch/arm/imx-common/cmd_mfgprot.c b/arch/arm/imx-common/cmd_mfgprot.c
new file mode 100644
index 0000000..88f2b12
--- /dev/null
+++ b/arch/arm/imx-common/cmd_mfgprot.c
@@ -0,0 +1,91 @@ 
+/*
+ * Copyright 2016 NXP Semiconductors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Command for manufacturing protection
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <linux/compiler.h>
+#include <fsl_sec.h>
+#include <asm/arch/clock.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+* generate_mppubk() - Generates a Public for Manufacturing Protection
+*
+* Returns zero on success,and negative on error.
+*/
+static int genenerate_mppubk(void)
+{
+	int ret = 0;
+
+	ret = gen_mppubk();
+
+	return ret;
+}
+
+/**
+* generate_mpsign() - Example of Signature command  for Manufacturing Protection
+*
+* Returns zero on success,and negative on error.
+*/
+static int generate_mpsign(void)
+{
+	int ret = 0;
+
+	ret = sign_mppubk();
+
+	return ret;
+}
+
+/**
+ * do_mfgprot() - Handle the "mfgprogt" command-line command
+ * @cmdtp:  Command data struct pointer
+ * @flag:   Command flag
+ * @argc:   Command-line argument count
+ * @argv:   Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ */
+static int do_mfgprot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	uint32_t sel;
+	int ret = 0;
+
+	u32 jr_size = 4;
+	u32 out_jr_size = sec_in32(CONFIG_SYS_FSL_JR0_ADDR + 0x102c);
+	if (out_jr_size != jr_size) {
+		hab_caam_clock_enable(1);
+		sec_init();
+	}
+
+	sel = simple_strtoul(argv[1], NULL, 10);
+	switch (sel) {
+	case 0:
+		ret = genenerate_mppubk();
+		break;
+	case 1:
+		ret = generate_mpsign();
+		break;
+	}
+	return ret;
+}
+
+/***************************************************/
+static char mfgprot_help_text[] =
+	"mp 0: prints out the public key for MP\n"
+	"mp 1: prints out an exmple signature for MP\n";
+
+U_BOOT_CMD(
+	mfgprot, 2, 1, do_mfgprot,
+	"Manufacturing Protection\n",
+	mfgprot_help_text
+);
diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile
index fd736cf..6d6903b 100644
--- a/drivers/crypto/fsl/Makefile
+++ b/drivers/crypto/fsl/Makefile
@@ -8,3 +8,7 @@  obj-y += sec.o
 obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o
 obj-$(CONFIG_CMD_BLOB)$(CONFIG_CMD_DEKBLOB) += fsl_blob.o
 obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o
+
+ifdef CONFIG_MX7
+obj-$(CONFIG_CMD_MFGPROT) += fsl_mfgprot.o
+endif
diff --git a/drivers/crypto/fsl/fsl_mfgprot.c b/drivers/crypto/fsl/fsl_mfgprot.c
new file mode 100644
index 0000000..967dbc4
--- /dev/null
+++ b/drivers/crypto/fsl/fsl_mfgprot.c
@@ -0,0 +1,286 @@ 
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <fsl_sec.h>
+#include <asm-generic/errno.h>
+#include "jobdesc.h"
+#include "desc.h"
+#include "jr.h"
+
+
+/** Job Descriptor Header command - add length in words */
+#define HAB_ENG_CAAM_CMD_JOBHDR			0xB0800000UL
+#define HAB_ENG_CAAM_CMD_JOBHDR_START_SHIFT	16 /**< START INDEX field */
+#define HAB_ENG_CAAM_CMD_JOBHDR_START_WIDTH	6 /**< START INDEX field */
+
+#define HAB_MASK(LBL)	\
+	((((uint32_t)1 << (LBL##_WIDTH)) - 1) << (LBL##_SHIFT))
+
+#define HAB_INSERT_BITS(val, LBL)	\
+	(((uint32_t)(val) << LBL##_SHIFT) & HAB_MASK(LBL))
+
+/** @name MPPUBK protocol data block
+ *  @{
+ */
+#define HAB_ENG_CAAM_MPPUBK_SGF		(1UL<<31)	/**< Message SG flag */
+#define HAB_ENG_CAAM_MPPUBK_CSEL_SHIFT	17		/**< Curve selection */
+#define HAB_ENG_CAAM_MPPUBK_CSEL_WIDTH	4		/**< Curve selection */
+#define HAB_ENG_CAAM_MPPUBK_CSEL_P256	0x3		/**< P-256 */
+#define HAB_ENG_CAAM_MPPUBK_CSEL_P384	0x4		/**< P-384 */
+#define HAB_ENG_CAAM_MPPUBK_CSEL_P521	0x5		/**< P-521 */
+
+/** Size of MFG descriptor */
+#define MFG_PUBK_DSC_WORDS 4
+#define MFG_SIGN_DSC_WORDS 8
+
+/** Size of MFG protocol data block */
+#define MFG_PUBK_PDB_WORDS 2
+#define MFG_SIGN_PDB_WORDS 6
+
+/** Security level index in #mfg_curve */
+#define MFG_SEC_LVL_256 0
+#define MFG_SEC_LVL_384 1
+#define MFG_SEC_LVL_521 2
+
+/** PROTOCOL MPPubKGen command */
+#define HAB_ENG_CAAM_CMD_PROTOCOL_MPPUBK	0x86140000UL
+#define HAB_ENG_CAAM_CMD_PROTOCOL_MPSIGN	0x86150000UL
+
+#define HAB_ENG_MFG_PUBK_BYTES	64
+#define HAB_ENG_MFG_SIGN_BYTES	4
+#define HAB_ENG_MFG_PRVK_BYTES	32
+#define HAB_MES_RESP_DGST_BYTES	32
+
+void mfg_build_sign_dsc(u32 *dsc_ptr, u8 *m, u8 *dgst, u8 *c, u8 *d)
+{
+	u32 *dsc = dsc_ptr;
+	*dsc++ = (HAB_ENG_CAAM_CMD_JOBHDR
+		  | HAB_INSERT_BITS(
+				MFG_SIGN_PDB_WORDS + 1,
+				HAB_ENG_CAAM_CMD_JOBHDR_START)
+		  | MFG_SIGN_DSC_WORDS);
+
+	/*** MFG PubK PDB ***/
+	/* Curve */
+	*dsc++ = HAB_INSERT_BITS(HAB_ENG_CAAM_MPPUBK_CSEL_P256,
+				 HAB_ENG_CAAM_MPPUBK_CSEL);
+	/* Message Pointer */
+	*dsc++ = (dma_addr_t)m;
+
+	/* mes-resp Pointer */
+	*dsc++ = (dma_addr_t)dgst;
+
+	/* C Pointer */
+	*dsc++ = (dma_addr_t)c;
+
+	/* d Pointer */
+	*dsc++ = (dma_addr_t)d;
+
+	/* Message Size */
+	*dsc++ = HAB_ENG_MFG_SIGN_BYTES;
+
+	/* MP PubK generate key command */
+	*dsc = HAB_ENG_CAAM_CMD_PROTOCOL_MPSIGN;
+}
+
+void mfg_build_pubk_dsc(u32 *dsc_ptr, u8 *dst)
+{
+	u32 *dsc = dsc_ptr;
+	*dsc++ = (HAB_ENG_CAAM_CMD_JOBHDR
+		 | HAB_INSERT_BITS(
+			MFG_PUBK_PDB_WORDS + 1,
+			HAB_ENG_CAAM_CMD_JOBHDR_START)
+		 | MFG_PUBK_DSC_WORDS);
+
+	/*** MFG PubK PDB ***/
+	/* Curve */
+	*dsc++ = HAB_INSERT_BITS(HAB_ENG_CAAM_MPPUBK_CSEL_P256,
+				 HAB_ENG_CAAM_MPPUBK_CSEL);
+	/* Message Pointer */
+	*dsc++ = (dma_addr_t)dst;
+
+	/* MP PubK generate key command */
+	*dsc = HAB_ENG_CAAM_CMD_PROTOCOL_MPPUBK;
+}
+
+int gen_mppubk(void)
+{
+	int ret;
+	int size, i;
+
+	u32 *dsc;
+	uint32_t dst_addr;
+	u8 *dst;
+
+	/****************************************************************
+	 * Allocation & Initialization
+	 ****************************************************************/
+	ret = 0;
+
+	/* Memory addresses for output */
+	dst_addr = 0x80100000;
+	dst = map_sysmem(dst_addr, HAB_ENG_MFG_PUBK_BYTES);
+	memset(dst, 0, HAB_ENG_MFG_PUBK_BYTES);
+
+	/****************************************************************
+	 * Job Descriptor initialization
+	 ****************************************************************/
+	dsc = memalign(ARCH_DMA_MINALIGN,
+			sizeof(uint32_t) * MFG_PUBK_DSC_WORDS);
+	if (!dsc) {
+		debug("Not enough memory for descriptor allocation\n");
+		return -ENOMEM;
+	}
+
+	mfg_build_pubk_dsc(dsc, dst);
+
+	size = roundup(sizeof(uint32_t) * MFG_PUBK_DSC_WORDS,
+			ARCH_DMA_MINALIGN);
+	flush_dcache_range((unsigned long)dsc, (unsigned long)dsc + size);
+
+	size = roundup(HAB_ENG_MFG_PUBK_BYTES, ARCH_DMA_MINALIGN);
+	flush_dcache_range((unsigned long)dst, (unsigned long)dst + size);
+
+	/****************************************************************
+	 * Execute Job Descriptor
+	 ****************************************************************/
+	puts("\nGenerating Manufacturing Protection Public Key\n");
+
+	ret = run_descriptor_jr(dsc);
+	if (ret) {
+		debug("Error in public key generation %d\n", ret);
+	   goto err;
+	}
+
+	size = roundup(HAB_ENG_MFG_PUBK_BYTES, ARCH_DMA_MINALIGN);
+	invalidate_dcache_range((unsigned long)dst, (unsigned long)dst+size);
+
+	/****************************************************************
+	 * Output results
+	 ****************************************************************/
+	puts("Public key:\n");
+	for (i = 0; i < HAB_ENG_MFG_PUBK_BYTES; i++)
+		printf("%02X", ((u8 *)dst)[i]);
+	printf("\n");
+
+err:
+	free(dsc);
+	return ret;
+}
+
+int sign_mppubk(void)
+{
+	int ret;
+	int size, i;
+	int data_size;
+
+	uint32_t dgst_addr, c_addr, d_addr;
+	u32 *dsc;
+	u8 *m, *dgst, *c, *d;
+
+	/****************************************************************
+	 * Allocation & Initialization
+	 ****************************************************************/
+	ret = 0;
+
+	/* Data to be signed */
+	data_size = 4;
+	m = memalign(ARCH_DMA_MINALIGN, data_size);
+	memset(m, 0, data_size);
+	m[0] = 0x42;
+	m[1] = 0x45;
+	m[2] = 0x45;
+	m[3] = 0x46;
+
+	/* Memory addresses for output */
+	dgst_addr = 0x80100000;
+	c_addr = 0x80101000;
+	d_addr = 0x80102000;
+
+	dgst = map_sysmem(dgst_addr, HAB_MES_RESP_DGST_BYTES);
+	c = map_sysmem(c_addr, HAB_ENG_MFG_PRVK_BYTES);
+	d = map_sysmem(d_addr, HAB_ENG_MFG_PRVK_BYTES);
+
+	memset(dgst, 0, HAB_MES_RESP_DGST_BYTES);
+	memset(d, 0, HAB_ENG_MFG_PRVK_BYTES);
+	memset(c, 0, HAB_ENG_MFG_PRVK_BYTES);
+
+	/****************************************************************
+	 * Job Descriptor initialization
+	 ****************************************************************/
+	dsc = memalign(ARCH_DMA_MINALIGN,
+			sizeof(uint32_t) * MFG_SIGN_DSC_WORDS);
+	if (!dsc) {
+		debug("Not enough memory for descriptor allocation\n");
+		return -ENOMEM;
+	}
+
+	mfg_build_sign_dsc(dsc, m, dgst, c, d);
+
+	size = roundup(sizeof(uint32_t) * MFG_SIGN_DSC_WORDS,
+			ARCH_DMA_MINALIGN);
+	flush_dcache_range((unsigned long)dsc, (unsigned long)dsc + size);
+
+	size = roundup(data_size, ARCH_DMA_MINALIGN);
+	flush_dcache_range((unsigned long)m, (unsigned long)m + size);
+
+	size = roundup(HAB_MES_RESP_DGST_BYTES, ARCH_DMA_MINALIGN);
+	flush_dcache_range((unsigned long)dgst, (unsigned long)dgst + size);
+
+	size = roundup(HAB_ENG_MFG_PRVK_BYTES, ARCH_DMA_MINALIGN);
+	flush_dcache_range((unsigned long)c, (unsigned long)c + size);
+	flush_dcache_range((unsigned long)d, (unsigned long)d + size);
+
+	/****************************************************************
+	 * Execute Job Descriptor
+	 ****************************************************************/
+	puts("\nSiging message with Manufacturing Protection Public Key\n");
+
+	ret = run_descriptor_jr(dsc);
+	if (ret) {
+		debug("Error in public key generation %d\n", ret);
+	   goto err;
+	}
+
+	size = roundup(HAB_MES_RESP_DGST_BYTES, ARCH_DMA_MINALIGN);
+	invalidate_dcache_range((unsigned long)dgst, (unsigned long)dgst+size);
+
+	size = roundup(HAB_ENG_MFG_PRVK_BYTES, ARCH_DMA_MINALIGN);
+	invalidate_dcache_range((unsigned long)c, (unsigned long)c+size);
+	invalidate_dcache_range((unsigned long)d, (unsigned long)d+size);
+
+	/****************************************************************
+	 * Output results
+	 ****************************************************************/
+	puts("Message: ");
+	for (i = 0; i < data_size; i++)
+		printf("%02X ", ((uint8_t *)m)[i]);
+	printf("\n");
+
+	puts("Message Representative Digest(SHA-256):\n");
+	for (i = 0; i < HAB_MES_RESP_DGST_BYTES; i++)
+		printf("%02X", ((uint8_t *)dgst)[i]);
+	printf("\n");
+
+	puts("Signature:\n");
+	puts("D:\n");
+	for (i = 0; i < HAB_ENG_MFG_PRVK_BYTES; i++)
+		printf("%02X", ((uint8_t *)c)[i]);
+	printf("\n");
+
+	puts("d:\n");
+	for (i = 0; i < HAB_ENG_MFG_PRVK_BYTES; i++)
+		printf("%02X", ((uint8_t *)d)[i]);
+	printf("\n");
+
+err:
+	free(dsc);
+	return ret;
+}
diff --git a/include/fsl_sec.h b/include/fsl_sec.h
index 2ddced3..3b22651 100644
--- a/include/fsl_sec.h
+++ b/include/fsl_sec.h
@@ -284,6 +284,18 @@  int sec_init(void);
  */
 int blob_dek(const u8 *src, u8 *dst, u8 len);
 
+/*
+ * gen_mpubk:
+ * Generates example of public key for manufacturing protection
+ */
+int gen_mppubk(void);
+
+/*
+ * sign_mpubk:
+ * Generates example of manufacturing protection signature of
+ * sample data.
+ */
+int sign_mppubk(void);
 #endif
 
 #endif /* __FSL_SEC_H */