[U-Boot] [PATCH 5/5] Added command for validation of images in case of secure boot

Ruchika Gupta ruchika.gupta at freescale.com
Thu Mar 28 11:46:35 CET 2013


        1. Default environment will be used for secure boot flow
           which can't be edited or saved.
        2. Command for secure boot is predefined in the default
           environment which will run on autoboot (and autoboot is
           the only option allowed in case of secure boot) and it
           looks like this:
           #define CONFIG_SECBOOT \
            "setenv bs_hdraddr 0xe8e00000;"                 \
            "esbc_validate $bs_hdraddr;"                    \
            "source $img_addr;"                             \
            "esbc_halt;"
           #endif
        3. esbc_validate command is meant for validating header and
           signature of images (Boot Script and ESBC uboot client).
           SHA-256 and RSA operations are performed using SEC block in HW.
           This command works on both high-end (P4080) and
           low-end (P1010) platforms.
           Command usage:
           esbc_validate img_hdr_addr [pub_key_hash]
        4. Boot Script can contain esbc_validate commands and bootm command.
           Uboot source command used in default secure boot command will
           run the bootscript.
        5. ESBC uboot client can be linux. Additionally, rootfs and device
           tree blob can also be signed.
        6. In the event of header or signature failure in validation,
           ITS and ITF bits determine further course of action.
        7. In case of soft failure, appropriate error is dumped on console
           and next esbc_validate command is executed.
        8. In case of hard failure, SoC is issued RESET REQUEST after
           dumping error on the console.
        9. Command esbc_halt added to ensure either bootm executes
           after validation of images or core should just spin.

Signed-off-by: Kuldip Giroh <kuldip.giroh at freescale.com>
Signed-off-by: Ruchika Gupta <ruchika.gupta at freescale.com>
---
Based upon git://git.denx.de/u-boot.git branch master

 arch/powerpc/cpu/mpc85xx/Makefile            |    2 +
 arch/powerpc/cpu/mpc85xx/cmd_esbc_validate.c |   54 +++
 arch/powerpc/cpu/mpc85xx/cpu_init.c          |   17 +
 arch/powerpc/cpu/mpc85xx/fsl_sfp_snvs.c      |  163 ++++++++
 arch/powerpc/cpu/mpc85xx/fsl_validate.c      |  543 ++++++++++++++++++++++++++
 arch/powerpc/include/asm/fsl_secure_boot.h   |   68 ++++-
 arch/powerpc/include/asm/fsl_sfp_snvs.h      |   42 ++
 arch/powerpc/include/asm/immap_85xx.h        |   55 +++
 8 files changed, 943 insertions(+), 1 deletions(-)
 create mode 100644 arch/powerpc/cpu/mpc85xx/cmd_esbc_validate.c
 create mode 100644 arch/powerpc/cpu/mpc85xx/fsl_sfp_snvs.c
 create mode 100644 arch/powerpc/cpu/mpc85xx/fsl_validate.c
 create mode 100644 arch/powerpc/include/asm/fsl_sfp_snvs.h

diff --git a/arch/powerpc/cpu/mpc85xx/Makefile b/arch/powerpc/cpu/mpc85xx/Makefile
index 6776c85..66b7b67 100644
--- a/arch/powerpc/cpu/mpc85xx/Makefile
+++ b/arch/powerpc/cpu/mpc85xx/Makefile
@@ -109,6 +109,8 @@ COBJS-$(CONFIG_QE)	+= qe_io.o
 COBJS-$(CONFIG_CPM2)	+= serial_scc.o
 COBJS-$(CONFIG_SYS_FSL_QORIQ_CHASSIS1) += fsl_corenet_serdes.o
 COBJS-$(CONFIG_SYS_FSL_QORIQ_CHASSIS2) += fsl_corenet2_serdes.o
+COBJS-$(CONFIG_SECURE_BOOT) += fsl_sfp_snvs.o
+COBJS-$(CONFIG_CMD_ESBC_VALIDATE) += cmd_esbc_validate.o fsl_validate.o
 
 # SoC specific SERDES support
 COBJS-$(CONFIG_MPC8536) += mpc8536_serdes.o
diff --git a/arch/powerpc/cpu/mpc85xx/cmd_esbc_validate.c b/arch/powerpc/cpu/mpc85xx/cmd_esbc_validate.c
new file mode 100644
index 0000000..a95f04e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/cmd_esbc_validate.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <command.h>
+#include <common.h>
+#include <asm/fsl_validate.h>
+
+static int do_esbc_validate(cmd_tbl_t *cmdtp, int flag, int argc,
+				char * const argv[])
+{
+	if (argc < 2)
+		return cmd_usage(cmdtp);
+
+	return fsl_secboot_validate(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+	esbc_validate,	3,	0,	do_esbc_validate,
+	"Validates signature of a given image using RSA verification"
+	"algorithm as part of Freescale Secure Boot Process",
+	"<hdr_addr> <hash_val>"
+);
+
+static int do_esbc_halt(cmd_tbl_t *cmdtp, int flag, int argc,
+				char * const argv[])
+{
+	printf("Core is entering spin loop.\n");
+	while (1);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	esbc_halt,	1,	0,	do_esbc_halt,
+	"Put the core in spin loop if control reaches to uboot"
+	"from bootscript",
+	""
+);
diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c
index de9d916..41d7bf8 100644
--- a/arch/powerpc/cpu/mpc85xx/cpu_init.c
+++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c
@@ -46,6 +46,14 @@
 #include <errno.h>
 #endif
 
+#if defined(CONFIG_SECURE_BOOT) && defined(CONFIG_FSL_CORENET)
+#include <asm/fsl_pamu.h>
+#endif
+#ifdef CONFIG_SECURE_BOOT
+#include <jr.h>
+#include <asm/fsl_secboot_err.h>
+#endif
+
 #include "../../../../drivers/block/fsl_sata.h"
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -650,6 +658,15 @@ skip_l2:
 	}
 #endif
 
+#if defined(CONFIG_SECURE_BOOT) && defined(CONFIG_FSL_CORENET)
+	if (pamu_init() < 0)
+		fsl_secboot_handle_error(ERROR_ESBC_PAMU_INIT);
+#endif
+
+#ifdef CONFIG_SECURE_BOOT
+	if (sec_init() < 0)
+		fsl_secboot_handle_error(ERROR_ESBC_SEC_INIT);
+#endif
 
 	return 0;
 }
diff --git a/arch/powerpc/cpu/mpc85xx/fsl_sfp_snvs.c b/arch/powerpc/cpu/mpc85xx/fsl_sfp_snvs.c
new file mode 100644
index 0000000..7382eea
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/fsl_sfp_snvs.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <asm/fsl_sfp_snvs.h>
+#include <configs/corenet_ds.h>
+#include <common.h>
+
+int change_sec_mon_state(u32 initial_state, u32 final_state)
+{
+	ccsr_snvs_regs_t *snvs_regs = (void *)(CONFIG_SYS_SNVS_ADDR);
+	u32 sts = in_be32(&snvs_regs->hp_stat);
+	int timeout = 10;
+
+	if ((sts & HPSR_SSM_ST_MASK) != initial_state)
+		return -1;
+
+	if (initial_state == HPSR_SSM_ST_TRUST) {
+		switch (final_state) {
+		case HPSR_SSM_ST_NON_SECURE:
+			printf("SNVS state transitioning to Soft Fail.\n");
+			setbits_be32(&snvs_regs->hp_com, HPCOMR_SW_SV);
+
+			/*
+			 * poll till SNVS is in
+			 * Soft Fail state
+			 */
+			while (((sts & HPSR_SSM_ST_MASK) !=
+				HPSR_SSM_ST_SOFT_FAIL)) {
+				while (timeout) {
+					sts = in_be32(&snvs_regs->hp_stat);
+
+					if ((sts & HPSR_SSM_ST_MASK) ==
+						HPSR_SSM_ST_SOFT_FAIL)
+						break;
+
+					udelay(10);
+					timeout--;
+				}
+			}
+
+			if (timeout == 0) {
+				printf("SNVS state transition timeout.\n");
+				branch_to_self();
+			}
+
+			timeout = 10;
+
+			printf("SNVS state transitioning to Non Secure.\n");
+			setbits_be32(&snvs_regs->hp_com, HPCOMR_SSM_ST);
+
+			/*
+			 * poll till SNVS is in
+			 * Non Secure state
+			 */
+			while (((sts & HPSR_SSM_ST_MASK) !=
+				HPSR_SSM_ST_NON_SECURE)) {
+				while (timeout) {
+					sts = in_be32(&snvs_regs->hp_stat);
+
+					if ((sts & HPSR_SSM_ST_MASK) ==
+						HPSR_SSM_ST_NON_SECURE)
+						break;
+
+					udelay(10);
+					timeout--;
+				}
+			}
+
+			if (timeout == 0) {
+				printf("SNVS state transition timeout.\n");
+				branch_to_self();
+			}
+			break;
+		case HPSR_SSM_ST_SOFT_FAIL:
+			printf("SNVS state transitioning to Soft Fail.\n");
+			setbits_be32(&snvs_regs->hp_com, HPCOMR_SW_FSV);
+
+			/*
+			 * polling loop till SNVS is in
+			 * Soft Fail state
+			 */
+			while (((sts & HPSR_SSM_ST_MASK) !=
+				HPSR_SSM_ST_SOFT_FAIL)) {
+				while (timeout) {
+					sts = in_be32(&snvs_regs->hp_stat);
+
+					if ((sts & HPSR_SSM_ST_MASK) ==
+						HPSR_SSM_ST_SOFT_FAIL)
+						break;
+
+					udelay(10);
+					timeout--;
+				}
+			}
+
+			if (timeout == 0) {
+				printf("SNVS state transition timeout.\n");
+				branch_to_self();
+			}
+			break;
+		default:
+			return -1;
+		}
+	} else if (initial_state == HPSR_SSM_ST_NON_SECURE) {
+		switch (final_state) {
+		case HPSR_SSM_ST_SOFT_FAIL:
+			printf("SNVS state transitioning to Soft Fail.\n");
+			setbits_be32(&snvs_regs->hp_com, HPCOMR_SW_FSV);
+
+			/*
+			 * polling loop till SNVS is in
+			 * Soft Fail state
+			 */
+			while (((sts & HPSR_SSM_ST_MASK) !=
+				HPSR_SSM_ST_SOFT_FAIL)) {
+				while (timeout) {
+					sts = in_be32(&snvs_regs->hp_stat);
+
+					if ((sts & HPSR_SSM_ST_MASK) ==
+						HPSR_SSM_ST_SOFT_FAIL)
+						break;
+
+					udelay(10);
+					timeout--;
+				}
+			}
+
+			if (timeout == 0) {
+				printf("SNVS state transition timeout.\n");
+				branch_to_self();
+			}
+			break;
+		default:
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+void generate_reset_req(void)
+{
+	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+	printf("Generating reset request");
+	out_be32(&gur->rstcr, 0x2);	/* HRESET_REQ */
+	branch_to_self();
+}
diff --git a/arch/powerpc/cpu/mpc85xx/fsl_validate.c b/arch/powerpc/cpu/mpc85xx/fsl_validate.c
new file mode 100644
index 0000000..a184933
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/fsl_validate.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <asm/fsl_validate.h>
+#include <asm/fsl_secboot_err.h>
+#include <asm/fsl_sfp_snvs.h>
+#include <command.h>
+#include <common.h>
+#include <malloc.h>
+#include <rsa_sec.h>
+#include <sha.h>
+#include <jr.h>
+#include <asm/fsl_pamu.h>
+
+#define SHA256_BITS	256
+#define SHA256_BYTES	(256/8)
+#define SHA256_NIBBLES	(256/4)
+#define NUM_HEX_CHARS	(sizeof(ulong) * 2)
+
+
+/* This array contains DER value for SHA-256 */
+static const u8 hash_identifier[] = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
+		0x86, 0x48, 0x01, 0x65,	0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
+		0x04, 0x20
+		};
+
+static u8 hash_val[SHA256_BYTES];
+static const u8 barker_code[ESBC_BARKER_LEN] = { 0x68, 0x39, 0x27, 0x81 };
+
+void branch_to_self(void) __attribute__ ((noreturn));
+
+/*
+ * This function will put core in infinite loop.
+ * This will be called when the ESBC can not proceed further due
+ * to some errors.
+ */
+void branch_to_self(void)
+{
+	printf("Core is in infinite loop due to errors.\n");
+	while (1);
+}
+
+/*
+ * Handles the ESBC uboot client header verification failure.
+ * This  function  handles all the errors which might occur in the
+ * parsing and checking of ESBC uboot client header. It will also
+ * set the error bits in the SNVS.
+ */
+static void fsl_secboot_header_verification_failure(void)
+{
+	ccsr_snvs_regs_t *snvs_regs = (void *)(CONFIG_SYS_SNVS_ADDR);
+	ccsr_sfp_regs_t *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
+	u32 sts = in_be32(&snvs_regs->hp_stat);
+
+	/* 29th bit of OSPR is ITS */
+	u32 its = in_be32(&sfp_regs->ospr) >> 2;
+
+	/*
+	 * Read the SNVS status register
+	 * Read SSM_ST field
+	 */
+	sts = in_be32(&snvs_regs->hp_stat);
+	if ((sts & HPSR_SSM_ST_MASK) == HPSR_SSM_ST_TRUST) {
+		if (its == 1)
+			change_sec_mon_state(HPSR_SSM_ST_TRUST,
+				HPSR_SSM_ST_SOFT_FAIL);
+		else
+			change_sec_mon_state(HPSR_SSM_ST_TRUST,
+				HPSR_SSM_ST_NON_SECURE);
+	}
+
+	generate_reset_req();
+}
+
+/*
+ * Handles the ESBC uboot client image verification failure.
+ * This  function  handles all the errors which might occur in the
+ * public key hash comparison and signature verification of
+ * ESBC uboot client image. It will also
+ * set the error bits in the SNVS.
+ */
+static void fsl_secboot_image_verification_failure(void)
+{
+	ccsr_snvs_regs_t *snvs_regs = (void *)(CONFIG_SYS_SNVS_ADDR);
+	ccsr_sfp_regs_t *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
+	u32 sts = in_be32(&snvs_regs->hp_stat);
+
+	/* 31st bit of OVPR is ITF */
+	u32 itf = in_be32(&sfp_regs->ovpr) & ITS_MASK >> ITS_BIT;
+
+	/*
+	 * Read the SNVS status register
+	 * Read SSM_ST field
+	 */
+	sts = in_be32(&snvs_regs->hp_stat);
+	if ((sts & HPSR_SSM_ST_MASK) == HPSR_SSM_ST_TRUST) {
+		if (itf == 1) {
+			change_sec_mon_state(HPSR_SSM_ST_TRUST,
+				HPSR_SSM_ST_SOFT_FAIL);
+
+			generate_reset_req();
+		} else {
+			change_sec_mon_state(HPSR_SSM_ST_TRUST,
+				HPSR_SSM_ST_NON_SECURE);
+		}
+	}
+}
+
+static void fsl_secboot_bootscript_parse_failure(void)
+{
+	fsl_secboot_header_verification_failure();
+}
+
+/*
+ * Handles the errors in esbc boot.
+ * This  function  handles all the errors which might occur in the
+ * esbc boot phase. It will call the appropriate api to log the
+ * errors and set the error bits in the SNVS.
+ */
+void fsl_secboot_handle_error(int error)
+{
+	const struct fsl_secboot_errcode *e;
+
+	for (e = fsl_secboot_errcodes; e->errcode != ERROR_ESBC_CLIENT_MAX;
+		e++) {
+		if (e->errcode == error)
+			printf("ERROR :: %x :: %s\n", error, e->name);
+	}
+
+	switch (error) {
+	case ERROR_ESBC_CLIENT_HEADER_BARKER:
+	case ERROR_ESBC_CLIENT_HEADER_IMG_SIZE:
+	case ERROR_ESBC_CLIENT_HEADER_KEY_LEN:
+	case ERROR_ESBC_CLIENT_HEADER_SIG_LEN:
+	case ERROR_ESBC_CLIENT_HEADER_KEY_LEN_NOT_TWICE_SIG_LEN:
+	case ERROR_ESBC_CLIENT_HEADER_KEY_MOD_1:
+	case ERROR_ESBC_CLIENT_HEADER_KEY_MOD_2:
+	case ERROR_ESBC_CLIENT_HEADER_SIG_KEY_MOD:
+	case ERROR_ESBC_CLIENT_HEADER_SG_ESBC_EP:
+	case ERROR_ESBC_CLIENT_HEADER_SG_ENTIRES_BAD:
+		fsl_secboot_header_verification_failure();
+		break;
+	case ERROR_ESBC_SEC_RESET:
+	case ERROR_ESBC_SEC_DEQ:
+	case ERROR_ESBC_SEC_ENQ:
+	case ERROR_ESBC_SEC_DEQ_TO:
+	case ERROR_ESBC_SEC_JOBQ_STATUS:
+	case ERROR_ESBC_CLIENT_HASH_COMPARE_KEY:
+	case ERROR_ESBC_CLIENT_HASH_COMPARE_EM:
+		fsl_secboot_image_verification_failure();
+		break;
+	case ERROR_ESBC_MISSING_BOOTM:
+		fsl_secboot_bootscript_parse_failure();
+		break;
+	case ERROR_ESBC_WRONG_CMD:
+	default:
+		branch_to_self();
+		break;
+	}
+}
+
+static void fsl_secblk_handle_error(int error)
+{
+	switch (error) {
+	case JQ_ENQ_ERR:
+		fsl_secboot_handle_error(ERROR_ESBC_SEC_ENQ);
+		break;
+	case JQ_DEQ_ERR:
+		fsl_secboot_handle_error(ERROR_ESBC_SEC_DEQ);
+		break;
+	case JQ_DEQ_TO_ERR:
+		 fsl_secboot_handle_error(ERROR_ESBC_SEC_DEQ_TO);
+		break;
+	default:
+		printf("Job Queue Output status %x\n", error);
+		fsl_secboot_handle_error(ERROR_ESBC_SEC_JOBQ_STATUS);
+		break;
+	}
+}
+
+/*
+ * Calculate hash of key obtained via offset present in ESBC uboot
+ * client hdr. This function calculates the hash of key which is obtained
+ * through offset present in ESBC uboot client header.
+ */
+static int calc_img_key_hash(struct sha_ctx *ctx,
+				struct fsl_secboot_img_priv *img)
+{
+	int i;
+	int ret = 0;
+
+	/* calc hash of the esbc key */
+	sha_init(ctx);
+	sha_update(ctx, img->img_key, img->hdr.key_len);
+	ret = sha_final(ctx);
+	if (ret)
+		return ret;
+
+	ret = sha_digest(ctx, hash_val);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < SHA256_BYTES; i++)
+		img->img_key_hash[i] = hash_val[i];
+
+	return 0;
+}
+
+/*
+ * Calculate hash of ESBC hdr and ESBC. This function calculates the
+ * single hash of ESBC header and ESBC image. If SG flag is on, all
+ * SG entries are also hashed alongwith the complete SG table.
+ */
+static int calc_esbchdr_esbc_hash(struct sha_ctx *ctx,
+	struct fsl_secboot_img_priv *img)
+{
+	int i = 0;
+	int ret = 0;
+
+	/* calculate the hash of the CSF header */
+	sha_init(ctx);
+	sha_update(ctx, (u8 *) &img->hdr,
+		sizeof(struct fsl_secboot_img_hdr));
+	sha_update(ctx, img->img_key, img->hdr.key_len);
+
+	if (img->hdr.sg_flag) {
+		/* calculate hash of the SG table */
+		sha_update(ctx, (u8 *) &img->sgtbl,
+			img->hdr.sg_entries *
+			sizeof(struct fsl_secboot_sg_table));
+
+		/* calculate the hash of each entry in the table */
+		for (i = 0; i < img->hdr.sg_entries; i++)
+			sha_update(ctx, img->sgtbl[i].pdata,
+				img->sgtbl[i].len);
+	} else {
+		/* contiguous ESBC */
+		sha_update(ctx, (u8 *) img->hdr.pimg,
+			img->hdr.img_size);
+	}
+
+	ret = sha_final(ctx);
+	if (ret)
+		return ret;
+
+	ret = sha_digest(ctx, hash_val);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * Construct encoded hash EM' wrt PKCSv1.5. This function calculates the
+ * pointers for padding, DER value and hash. And finally, constructs EM'
+ * which includes hash of complete CSF header and ESBC image. If SG flag
+ * is on, hash of SG table and entries is also included.
+ */
+static void construct_img_encoded_hash_second(struct fsl_secboot_img_priv *img)
+{
+	/*
+	 * RSA PKCSv1.5 encoding format for encoded message is below
+	 * EM = 0x0 || 0x1 || PS || 0x0 || DER || Hash
+	 * PS is Padding String
+	 * DER is DER value for SHA-256
+	 * Hash is SHA-256 hash
+	 * *********************************************************
+	 * representative points to first byte of EM initially and is
+	 * filled with 0x0
+	 * representative is incremented by 1 and second byte is filled
+	 * with 0x1
+	 * padding points to third byte of EM
+	 * digest points to full length of EM - 32 bytes
+	 * hash_id (DER value) points to 19 bytes before pDigest
+	 * separator is one byte which separates padding and DER
+	 */
+
+	size_t len;
+	u8 *representative;
+	u8 *padding, *digest;
+	u8 *hash_id, *separator;
+	int i;
+
+	len = (img->hdr.key_len / 2) - 1;
+	representative = img->img_encoded_hash_second;
+	representative[0] = 0;
+	representative[1] = 1;  /* block type 1 */
+
+	padding = &representative[2];
+	digest = &representative[1] + len - 32;
+	hash_id = digest - sizeof(hash_identifier);
+	separator = hash_id - 1;
+
+	/* fill padding area pointed by padding with 0xff */
+	memset(padding, 0xff, separator - padding);
+
+	/* fill byte pointed by separator */
+	*separator = 0;
+
+	/* fill SHA-256 DER value  pointed by HashId */
+	memcpy(hash_id, hash_identifier, sizeof(hash_identifier));
+
+	/* fill hash pointed by Digest */
+	for (i = 0; i < SHA256_BYTES; i++)
+		digest[i] = hash_val[i];
+}
+
+/*
+ * Reads and validates the ESBC client header.
+ * This function reads key and signature from the ESBC client header.
+ * If Scatter/Gather flag is on, lengths and offsets of images
+ * present as SG entries are also read. This function also checks
+ * whether the header is valid or not.
+ */
+static int read_validate_esbc_client_header(struct fsl_secboot_img_priv *img)
+{
+	char buf[20];
+	struct fsl_secboot_img_hdr *hdr = &img->hdr;
+	void *esbc = (u8 *) img->ehdrloc;
+	u8 *k, *s;
+
+	/* check barker code */
+	if (memcmp(hdr->barker, barker_code, ESBC_BARKER_LEN))
+		return ERROR_ESBC_CLIENT_HEADER_BARKER;
+
+	sprintf(buf, "%p", hdr->pimg);
+	setenv("img_addr", buf);
+
+	if (!hdr->img_size)
+		return ERROR_ESBC_CLIENT_HEADER_IMG_SIZE;
+
+	/* key length should be twice of signature length */
+	if (hdr->key_len == 2 * hdr->sign_len) {
+		/* check key length */
+		if (!((hdr->key_len == 2 * KEY_SIZE_BYTES / 4) ||
+			(hdr->key_len == 2 * KEY_SIZE_BYTES / 2) ||
+			(hdr->key_len == 2 * KEY_SIZE_BYTES)))
+			return ERROR_ESBC_CLIENT_HEADER_KEY_LEN;
+
+		/* check signature length */
+		if (!((hdr->sign_len == KEY_SIZE_BYTES / 4) ||
+			(hdr->sign_len == KEY_SIZE_BYTES / 2) ||
+			(hdr->sign_len == KEY_SIZE_BYTES)))
+			return ERROR_ESBC_CLIENT_HEADER_SIG_LEN;
+	} else {
+		return ERROR_ESBC_CLIENT_HEADER_KEY_LEN_NOT_TWICE_SIG_LEN;
+	}
+
+	memcpy(&img->img_key, esbc + hdr->pkey, hdr->key_len);
+	memcpy(&img->img_sign, esbc + hdr->psign, hdr->sign_len);
+
+	/* No SG support */
+	if (hdr->sg_flag)
+		return ERROR_ESBC_CLIENT_HEADER_SG;
+
+	/* modulus most significant bit should be set */
+	k = (u8 *) &img->img_key;
+
+	if ((k[0] & 0x80) == 0)
+		return ERROR_ESBC_CLIENT_HEADER_KEY_MOD_1;
+
+	/* modulus value should be odd */
+	if ((k[hdr->key_len / 2 - 1] & 0x1) == 0)
+		return ERROR_ESBC_CLIENT_HEADER_KEY_MOD_2;
+
+	/* Check signature value < modulus value */
+	s = (u8 *) &img->img_sign;
+
+	if (!(memcmp(s, k, hdr->sign_len) < 0))
+		return ERROR_ESBC_CLIENT_HEADER_SIG_KEY_MOD;
+
+	return ESBC_VALID_HDR;
+}
+
+static inline int str2long(const char *p, ulong *num)
+{
+	char *endptr;
+
+	if (!p)
+		return 0;
+	else
+		*num = simple_strtoul(p, &endptr, 16);
+
+	return *p != '\0' && *endptr == '\0';
+}
+
+int fsl_secboot_validate(cmd_tbl_t *cmdtp, int flag, int argc,
+		char * const argv[])
+{
+	int hash_srk = 1;
+	ccsr_sfp_regs_t *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
+	ulong hash[SHA256_BYTES/sizeof(ulong)];
+	char hash_str[NUM_HEX_CHARS + 1];
+	struct sha_ctx ctx;
+	struct rsa_context rsa_ctx;
+	ulong addr = simple_strtoul(argv[1], NULL, 16);
+	struct fsl_secboot_img_priv *img;
+	struct fsl_secboot_img_hdr *hdr;
+	void *esbc;
+	int ret, i;
+	u32 srk_hash[8];
+
+	if (argc == 3) {
+		char *cp = argv[2];
+		int i = 0;
+
+		if (*cp == '0' && *(cp + 1) == 'x')
+			cp += 2;
+
+		/* The input string expected is in hex, where
+		 * each 4 bits would be represented by a hex
+		 * sha256 hash is 256 bits long, which would mean
+		 * num of characters = 256 / 4
+		 */
+		if (strlen(cp) != SHA256_NIBBLES) {
+			printf("%s is not a 256 bits hex string as expected\n",
+				argv[2]);
+			return -1;
+		}
+
+		for (i = 0; i < sizeof(hash)/sizeof(ulong); i++) {
+			strncpy(hash_str, cp + (i * NUM_HEX_CHARS),
+				NUM_HEX_CHARS);
+			hash_str[NUM_HEX_CHARS] = '\0';
+			if (!str2long(hash_str, &hash[i])) {
+				printf("%s is not a 256 bits hex string "
+					"as expected\n", argv[2]);
+				return -1;
+			}
+		}
+
+		hash_srk = 0;
+	}
+
+#ifdef CONFIG_FSL_CORENET
+	pamu_enable();
+#endif
+	img = malloc(sizeof(struct fsl_secboot_img_priv));
+
+	if (!img)
+		return -1;
+
+	memset(img, 0, sizeof(struct fsl_secboot_img_priv));
+
+	hdr = &img->hdr;
+	img->ehdrloc = addr;
+	esbc = (u8 *) img->ehdrloc;
+
+	memcpy(hdr, esbc, sizeof(struct fsl_secboot_img_hdr));
+
+	/* read and validate esbc header */
+	ret = read_validate_esbc_client_header(img);
+
+	if (ret != ESBC_VALID_HDR) {
+		fsl_secboot_handle_error(ret);
+		goto exit1;
+		return 0;
+	}
+
+	/* SRKH present in SFP */
+	for (i = 0; i < NUM_SRKH_REGS; i++)
+		srk_hash[i] = in_be32(&sfp_regs->srk_hash[i]);
+
+	/*
+	 * Calculate hash of key obtained via offset present in
+	 * ESBC uboot client hdr
+	 */
+	ret = calc_img_key_hash(&ctx, img);
+	if (ret) {
+		fsl_secblk_handle_error(ret);
+		goto exit;
+	}
+
+	/* Compare hash obtained above with SRK hash present in SFP */
+	if (hash_srk)
+		ret = memcmp(srk_hash, img->img_key_hash, SHA256_BYTES);
+	else
+		ret = memcmp(&hash, &img->img_key_hash, SHA256_BYTES);
+
+	if (ret != 0) {
+		fsl_secboot_handle_error(ERROR_ESBC_CLIENT_HASH_COMPARE_KEY);
+		goto exit;
+	}
+
+	ret = calc_esbchdr_esbc_hash(&ctx, img);
+	if (ret) {
+		fsl_secblk_handle_error(ret);
+		goto exit;
+	}
+
+	/* Construct encoded hash EM' wrt PKCSv1.5 */
+	construct_img_encoded_hash_second(img);
+
+	ret = rsa_public_verif_sec(img->img_sign, img->img_encoded_hash,
+		img->img_key, img->hdr.key_len / 2, &rsa_ctx);
+	if (ret) {
+		fsl_secblk_handle_error(ret);
+		goto exit;
+	}
+
+	/*
+	 * compare the encoded messages EM' and EM wrt RSA PKCSv1.5
+	 * memcmp returns zero on success
+	 * memcmp returns non-zero on failure
+	 */
+	ret = memcmp(&img->img_encoded_hash_second, &img->img_encoded_hash,
+		img->hdr.sign_len);
+
+	if (ret) {
+		fsl_secboot_handle_error(ERROR_ESBC_CLIENT_HASH_COMPARE_EM);
+		goto exit;
+	}
+
+	printf("esbc_validate command successful\n");
+
+exit:
+	if (jr_reset() < 0) {
+		fsl_secboot_handle_error(ERROR_ESBC_SEC_RESET);
+		return 0;
+	}
+exit1:
+#ifdef CONFIG_FSL_CORENET
+	pamu_disable();
+#endif
+
+	return 0;
+}
diff --git a/arch/powerpc/include/asm/fsl_secure_boot.h b/arch/powerpc/include/asm/fsl_secure_boot.h
index d1c1967..6847362 100644
--- a/arch/powerpc/include/asm/fsl_secure_boot.h
+++ b/arch/powerpc/include/asm/fsl_secure_boot.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright 2010-2012 Freescale Semiconductor, Inc.
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -40,4 +40,70 @@
 #endif
 #define CONFIG_SYS_PBI_FLASH_WINDOW		0xcff80000
 
+/*
+ * Define the key hash for boot script here if public/private key pair used to
+ * sign bootscript are different from the SRK hash put in the fuse
+ * Example of defining KEY_HASH is
+ * #define CONFIG_BOOTSCRIPT_KEY_HASH \
+ *	 "41066b564c6ffcef40ccbc1e0a5d0d519604000c785d97bbefd25e4d288d1c8b"
+ */
+
+#define CONFIG_CMD_ESBC_VALIDATE
+
+#if defined(CONFIG_FSL_CORENET)
+#define CONFIG_BOOTSCRIPT_HDR_ADDR	0xe8e00000
+#else
+#define CONFIG_BOOTSCRIPT_HDR_ADDR	0xee020000
+#endif
+
+/*
+ * Control should not reach back to uboot after validation of images
+ * for secure boot flow and therefore bootscript should have
+ * the bootm command. If control reaches back to uboot anyhow
+ * after validating images, core should just spin.
+ */
+#ifdef CONFIG_BOOTSCRIPT_KEY_HASH
+#define CONFIG_SECBOOT \
+	"setenv bs_hdraddr " __stringify(CONFIG_BOOTSCRIPT_HDR_ADDR)";"	   \
+	"esbc_validate $bs_hdraddr " __stringify(CONFIG_BOOTSCRIPT_KEY_HASH)";"\
+	"source $img_addr;"					\
+	"esbc_halt;"
+#else
+#define CONFIG_SECBOOT \
+	"setenv bs_hdraddr " __stringify(CONFIG_BOOTSCRIPT_HDR_ADDR)";"	 \
+	"esbc_validate $bs_hdraddr;"			\
+	"source $img_addr;"				\
+	"esbc_halt;"
+#endif
+
+/* For secure boot flow, default environment used will be used */
+#if defined(CONFIG_SYS_RAMBOOT)
+#if defined(CONFIG_RAMBOOT_SPIFLASH)
+#undef CONFIG_ENV_IS_IN_SPI_FLASH
+#elif defined(CONFIG_NAND)
+#undef CONFIG_ENV_IS_IN_NAND
+#endif
+#else /*CONFIG_SYS_RAMBOOT*/
+#undef CONFIG_ENV_IS_IN_FLASH
+#endif
+
+#define CONFIG_ENV_IS_NOWHERE
+
+/*
+ * We don't want boot delay for secure boot flow
+ * before autoboot starts
+ */
+#undef CONFIG_BOOTDELAY
+#define CONFIG_BOOTDELAY	0
+#undef CONFIG_BOOTCOMMAND
+#define CONFIG_BOOTCOMMAND		CONFIG_SECBOOT
+
+/*
+ * CONFIG_ZERO_BOOTDELAY_CHECK should not be defined for
+ * secure boot flow as defining this would enable a user to
+ * reach uboot prompt by pressing some key before start of
+ * autoboot
+ */
+#undef CONFIG_ZERO_BOOTDELAY_CHECK
+
 #endif
diff --git a/arch/powerpc/include/asm/fsl_sfp_snvs.h b/arch/powerpc/include/asm/fsl_sfp_snvs.h
new file mode 100644
index 0000000..c215359
--- /dev/null
+++ b/arch/powerpc/include/asm/fsl_sfp_snvs.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _FSL_SFP_SNVS_
+#define _FSL_SFP_SNVS_
+
+#include <common.h>
+
+/* Number of SRKH registers */
+#define NUM_SRKH_REGS	8
+
+/*
+ * SNVS read. This specifies the possible reads
+ * from the SNVS
+ */
+enum {
+	SNVS_SSM_ST,
+	SNVS_SW_FSV,
+	SNVS_SW_SV,
+};
+
+void branch_to_self(void);
+int change_sec_mon_state(uint32_t initial_state, uint32_t final_state);
+void generate_reset_req(void);
+
+#endif
diff --git a/arch/powerpc/include/asm/immap_85xx.h b/arch/powerpc/include/asm/immap_85xx.h
index ac8f608..38f8b59 100644
--- a/arch/powerpc/include/asm/immap_85xx.h
+++ b/arch/powerpc/include/asm/immap_85xx.h
@@ -2949,6 +2949,48 @@ struct ccsr_pman {
 	u8	res_f4[0xf0c];
 };
 #endif
+#ifdef CONFIG_SFP_v3_0
+typedef struct ccsr_sfp_regs {
+	u32 ospr;		/* 0x200 */
+	u32 reserved0[14];
+	u32 srk_hash[8];	/* 0x23c Super Root Key Hash */
+	u32 oem_uid;		/* 0x9c OEM Unique ID */
+	u8 reserved2[0x04];
+	u32 ovpr;			/* 0xA4  Intent To Secure */
+	u8 reserved4[0x08];
+	u32 fsl_uid;		/* 0xB0  FSL Unique ID */
+} ccsr_sfp_regs_t;
+#else
+typedef struct ccsr_sfp_regs {
+	u8 reserved0[0x40];
+	u32 ospr;	/* 0x40  OEM Security Policy Register */
+	u8 reserved2[0x38];
+	u32 srk_hash[8];	/* 0x7c  Super Root Key Hash */
+	u32 oem_uid;	/* 0x9c  OEM Unique ID */
+	u8 reserved4[0x4];
+	u32 ovpr;	/* 0xA4  OEM Validation Policy Register */
+	u8 reserved8[0x8];
+	u32 fsl_uid;	/* 0xB0  FSL Unique ID */
+} ccsr_sfp_regs_t;
+#endif
+#define ITS_MASK	0x00000004
+#define ITS_BIT		2
+
+typedef struct ccsr_snvs_regs {
+	u8 reserved0[0x04];
+	u32 hp_com;	/* 0x04 SNVS_HP Command Register */
+	u8 reserved2[0x0c];
+	u32 hp_stat;	/* 0x08 SNVS_HP Status Register */
+} ccsr_snvs_regs_t;
+
+#define HPCOMR_SW_SV 0x100		/* Security Violation bit */
+#define HPCOMR_SW_FSV 0x200		/* Fatal Security Violation bit */
+#define HPCOMR_SSM_ST 0x1		/* SSM_ST field in SNVS command reg */
+#define HPSR_SSM_ST_CHECK	0x900	/* SNVS is in check state */
+#define HPSR_SSM_ST_NON_SECURE	0xb00	/* SNVS is in non secure state */
+#define HPSR_SSM_ST_TRUST	0xd00	/* SNVS is in trusted state */
+#define HPSR_SSM_ST_SOFT_FAIL	0x300	/* SNVS is in soft fail state */
+#define HPSR_SSM_ST_MASK	0xf00	/* Mask for SSM_ST field */
 
 #ifdef CONFIG_FSL_CORENET
 #define CONFIG_SYS_FSL_CORENET_CCM_OFFSET	0x0000
@@ -2962,6 +3004,14 @@ struct ccsr_pman {
 #define CONFIG_SYS_MPC8xxx_DDR3_OFFSET		0xA000
 #define CONFIG_SYS_FSL_CORENET_CLK_OFFSET	0xE1000
 #define CONFIG_SYS_FSL_CORENET_RCPM_OFFSET	0xE2000
+#ifdef CONFIG_SFP_v3_0
+/* In SFPv3, OSPR register is now at offset 0x200.
+ * So directly mapping sfp register map to this address */
+#define CONFIG_SYS_OSPR_OFFSET			0x200
+#define CONFIG_SYS_SFP_OFFSET		 (0xE8000 + CONFIG_SYS_OSPR_OFFSET)
+#else
+#define CONFIG_SYS_SFP_OFFSET			0xE8000
+#endif
 #define CONFIG_SYS_FSL_CORENET_SERDES_OFFSET	0xEA000
 #define CONFIG_SYS_FSL_CORENET_SERDES2_OFFSET	0xEB000
 #define CONFIG_SYS_FSL_CPC_OFFSET		0x10000
@@ -3163,6 +3213,11 @@ struct ccsr_pman {
 #define CONFIG_SYS_PCIE4_ADDR \
 	(CONFIG_SYS_IMMR + CONFIG_SYS_MPC85xx_PCIE4_OFFSET)
 
+#define CONFIG_SYS_SFP_ADDR  \
+	(CONFIG_SYS_IMMR + CONFIG_SYS_SFP_OFFSET)
+#define CONFIG_SYS_SNVS_ADDR  \
+	(CONFIG_SYS_IMMR + CONFIG_SYS_SNVS_OFFSET)
+
 #define TSEC_BASE_ADDR		(CONFIG_SYS_IMMR + CONFIG_SYS_TSEC1_OFFSET)
 #define MDIO_BASE_ADDR		(CONFIG_SYS_IMMR + CONFIG_SYS_MDIO1_OFFSET)
 
-- 
1.7.7.6




More information about the U-Boot mailing list