summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Rosengren <robert.rosengren@stericsson.com>2010-12-15 09:48:59 +0100
committerMichael BRANDT <michael.brandt@stericsson.com>2011-01-27 16:06:37 +0100
commitbc03d1e9728ab1faa9eebbee3ed90e57bd27c051 (patch)
tree32733565d203074d952928421c8edb481342e230
parent3f27019fbb4a5c411e80c5c876bfae0a67228da5 (diff)
db8500: Verify signature of kernel before booting
Verification of the kernel and ITP signature before allowing to boot is added. This feature is configurable and by default not activated. MeeGo- built RPM will have this enabled. ST-Ericsson ID: WP275634, ER275440 Change-Id: Ib888f39dd5dca1bc8b7d6e1b002da83a77908b07 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/11415 Tested-by: Robert ROSENGREN <robert.rosengren@stericsson.com> Reviewed-by: Michael BRANDT <michael.brandt@stericsson.com> Reviewed-by: QATOOLS Reviewed-by: Jens WIKLANDER <jens.wiklander@stericsson.com>
-rw-r--r--Makefile3
-rw-r--r--common/cmd_bootm.c12
-rw-r--r--cpu/arm_cortexa9/db8500/itp.c45
-rw-r--r--cpu/arm_cortexa9/db8500/sec_bridge.c143
-rw-r--r--include/asm-arm/arch-db8500/sec_bridge.h5
-rw-r--r--u-boot-u8500.spec2
6 files changed, 206 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index bad1598f8..0f6c8861c 100644
--- a/Makefile
+++ b/Makefile
@@ -3183,6 +3183,9 @@ u8500_auto_config:
$(MKCONFIG) -a u8500 arm arm_cortexa9 u8500 st db8500 ; \
fi
+u8500_secboot_config: u8500_def_config
+ echo "#define CONFIG_SECURE_KERNEL_BOOT" >> $(obj)include/config.h
+
#########################################################################
## XScale Systems
#########################################################################
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 94ddac37c..0cac9cf1b 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -867,6 +867,18 @@ static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]
/* copy from dataflash if needed */
img_addr = genimg_get_image (img_addr);
+#if defined(CONFIG_SECURE_KERNEL_BOOT)
+ {
+ /*
+ * Extern declaration could more nicely done, but keeping
+ * it here to have as low impact as possible...
+ */
+ extern int sec_bridge_verify_kernel_image(u32 *img_addr);
+ if (sec_bridge_verify_kernel_image ((u32*)&img_addr))
+ img_addr = 0;
+ }
+#endif
+
/* check image type, for FIT images get FIT kernel node */
*os_data = *os_len = 0;
switch (genimg_get_format ((void *)img_addr)) {
diff --git a/cpu/arm_cortexa9/db8500/itp.c b/cpu/arm_cortexa9/db8500/itp.c
index 03716a571..6e1102444 100644
--- a/cpu/arm_cortexa9/db8500/itp.c
+++ b/cpu/arm_cortexa9/db8500/itp.c
@@ -55,11 +55,16 @@ static int itp_load_ipl(block_dev_desc_t *block_dev)
static int itp_load_toc_entry(block_dev_desc_t *block_dev,
const char *partname,
+ int verify_signature,
u32 *loadaddress)
{
u32 n;
u32 offset;
u32 size;
+#if defined(CONFIG_SECURE_KERNEL_BOOT)
+ u32 real_loadaddr = 0;
+ u32 size_in_bytes = 0;
+#endif
debug("itp_load_toc_entry: Loading %s\n", partname);
@@ -69,6 +74,23 @@ static int itp_load_toc_entry(block_dev_desc_t *block_dev,
return 1;
}
+#if defined(CONFIG_SECURE_KERNEL_BOOT)
+ if (verify_signature) {
+ size_in_bytes = size;
+ real_loadaddr = *loadaddress;
+ /*
+ * We might need an offset, since ISSW doesn't support
+ * address 0.
+ */
+ if (*loadaddress == 0)
+ *loadaddress = *loadaddress + block_dev->blksz;
+ }
+#else
+ if (verify_signature) {
+ debug("itp_load_toc_entry: secure boot disabled so verify signature has no effect\n");
+ }
+#endif
+
size = (size / block_dev->blksz) +
((size % block_dev->blksz) ? 1 : 0);
@@ -82,6 +104,27 @@ static int itp_load_toc_entry(block_dev_desc_t *block_dev,
return 1;
}
+#if defined(CONFIG_SECURE_KERNEL_BOOT)
+ if (verify_signature) {
+ debug("itp_load_toc_entry: Verifying image...\n");
+
+ if (sec_bridge_verify_itp_image(loadaddress)) {
+ printf("itp_load_toc_entry: Failed to verify image %s!\n", partname);
+ return 1;
+ }
+
+ if (real_loadaddr != *loadaddress) {
+ /*
+ * Loadaddr is moved, need to move it back to ensure
+ * binary is not put out of order...
+ */
+ memmove((void *)(real_loadaddr), (void*)*loadaddress, size_in_bytes);
+ *loadaddress = real_loadaddr;
+ }
+ }
+
+#endif
+
return 0;
}
@@ -121,6 +164,7 @@ int itp_load_itp_and_modem(block_dev_desc_t *block_dev)
if (cspsa_key & ITP_LOAD_MODEM) {
if (itp_load_toc_entry(block_dev,
ITP_TOC_MODEM_NAME,
+ 0, /* verify_signature false */
&loadaddress)) {
retval = 1;
goto exit;
@@ -135,6 +179,7 @@ int itp_load_itp_and_modem(block_dev_desc_t *block_dev)
if (cspsa_key & ITP_LOAD_ITP) {
if (itp_load_toc_entry(block_dev,
ITP_TOC_ITP_NAME,
+ 1, /* verify_signature true */
&loadaddress)) {
retval = 1;
goto exit;
diff --git a/cpu/arm_cortexa9/db8500/sec_bridge.c b/cpu/arm_cortexa9/db8500/sec_bridge.c
index fb94804eb..542c42b1e 100644
--- a/cpu/arm_cortexa9/db8500/sec_bridge.c
+++ b/cpu/arm_cortexa9/db8500/sec_bridge.c
@@ -5,7 +5,6 @@
*
* License terms: GNU General Public License (GPL), version 2.
*/
-
#include <common.h>
#include <asm/arch/sec_bridge.h>
@@ -42,7 +41,7 @@ int sec_bridge_init_bridge(void)
return 0;
}
- printf("sec_bridge_init_bridge: cutid not found\n");
+ printf("sec_bridge: cutid not found\n");
return 1;
}
@@ -75,10 +74,148 @@ int sec_bridge_flush_issw(void)
0);
if (ret != SEC_ROM_RET_OK) {
- printf("sec_bridge_flush_issw: ISSWAPI_FLUSH_BOOT_CODE: %d\n",
+ printf("sec_bridge: ISSWAPI_FLUSH_BOOT_CODE: %d\n",
ret);
return 1;
}
}
return 0;
}
+
+/*
+ * All this signed header verification code is put here to reuse the static
+ * functions defined in this file to call secure world.
+ *
+ * We are planning to export generic code verifcation to u-boot via another
+ * module so the generic code below can be removed at that stage.
+ */
+
+#if defined(CONFIG_SECURE_KERNEL_BOOT)
+
+/* Stuff copied from isswapi_types.h */
+enum issw_payload_type {
+ ISSW_PL_TYPE_TAPP = 0,
+ ISSW_PL_TYPE_PRCMU,
+ ISSW_PL_TYPE_MEMINIT,
+ ISSW_PL_TYPE_X_LOADER,
+ ISSW_PL_TYPE_OS_LOADER,
+ ISSW_PL_TYPE_APE_NW_CODE,
+ ISSW_PL_TYPE_FC_LOADER,
+ ISSW_PL_TYPE_MODEM_CODE,
+ ISSW_PL_TYPE_FOTA,
+ ISSW_PL_TYPE_DNTCERT,
+ ISSW_PL_TYPE_AUTHCERT,
+ ISSW_PL_TYPE_IPL,
+ ISSW_PL_TYPE_FLASH_ARCHIVE,
+ ISSW_PL_TYPE_ITP,
+ ISSW_PL_TYPE_AUTH_CHALLENGE = -1 /* 0xffffffff */
+};
+
+
+typedef struct issw_signed_header {
+ u32 magic;
+ u16 size_of_signed_header;
+ u16 size_of_signature;
+ u32 sign_hash_type; /* see t_hash_type */
+ u32 signature_type; /* see t_signature_type */
+ u32 hash_type; /* see t_hash_type */
+ u32 payload_type; /* see enum issw_payload_type */
+ u32 flags; /* reserved */
+ u32 size_of_payload;
+ u32 sw_vers_nbr;
+ u32 load_address;
+ u32 startup_address;
+ u32 spare; /* reserved */
+#if 0
+ /* Pseudo code visualize layout of signed header */
+ u8 hash[get_hash_length(this.hash_type)];
+ u8 signature[size_of_signature];
+#endif
+} issw_signed_header_t;
+
+#define ISSW_SIGNED_HEADER_MAGIC 0x53484452
+
+#define ISSW_SIGNED_HEADER_HASH(hdr) \
+ ((u8 *)((issw_signed_header_t *)(hdr) + 1))
+
+#define ISSW_SIGNED_HEADER_HASH_SIZE(hdr) \
+ (((issw_signed_header_t *)(hdr))->size_of_signed_header - \
+ ((issw_signed_header_t *)(hdr))->size_of_signature - \
+ sizeof(issw_signed_header_t))
+
+#define ISSW_SIGNED_HEADER_SIGNATURE(hdr) \
+ (ISSW_SIGNED_HEADER_HASH(hdr) + ISSW_SIGNED_HEADER_HASH_SIZE(hdr))
+
+#define ISSW_SIGNED_HEADER_PAYLOAD(hdr) \
+ ((u8 *)(hdr) + \
+ ((issw_signed_header_t *)(hdr))->size_of_signed_header)
+
+static int sec_bridge_verify_signed_header(issw_signed_header_t *hdr,
+ enum issw_payload_type pt)
+{
+ u32 ret;
+
+ ret = sec_bridge_call_secure_service(ISSWAPI_VERIFY_SIGNED_HEADER,
+ SEC_ROM_FORCE_CLEAN_MASK, hdr, (u32)pt);
+ if (ret != SEC_ROM_RET_OK) {
+ printf("sec_bridge: "
+ "ISSWAPI_VERIFY_SIGNED_HEADER: %d\n", ret);
+ return 1;
+ }
+ return 0;
+}
+
+static int sec_bridge_verify_hash(u8 *hash, u32 hash_size, u8 *payload,
+ u32 payload_size, u32 hash_type)
+{
+ u32 ret;
+
+ ret = sec_bridge_call_secure_service(ISSWAPI_VERIFY_HASH,
+ SEC_ROM_FORCE_CLEAN_MASK,
+ hash, hash_size, payload, payload_size,
+ hash_type);
+ if (ret != SEC_ROM_RET_OK) {
+ printf("sec_bridge: "
+ "ISSWAPI_VERIFY_HASH: %d\n", ret);
+ return 1;
+ }
+ return 0;
+}
+
+static int sec_bridge_verify_image(u32 *img_addr,
+ enum issw_payload_type payload_type)
+{
+ issw_signed_header_t *hdr = (issw_signed_header_t *) *img_addr;
+
+ debug("sec_bridge_verify_image(img_addr->0x%08x, payload_type:%d)\n", *img_addr, payload_type);
+
+ if (*img_addr == 0)
+ return 1;
+
+ if (sec_bridge_verify_signed_header(hdr, payload_type))
+ return 1;
+
+ /*
+ * Using a secure service for this since sha256 in u-boot
+ * was incedible slow.
+ */
+ if (sec_bridge_verify_hash(ISSW_SIGNED_HEADER_HASH(hdr),
+ ISSW_SIGNED_HEADER_HASH_SIZE(hdr),
+ ISSW_SIGNED_HEADER_PAYLOAD(hdr),
+ hdr->size_of_payload, hdr->hash_type))
+ return 1;
+
+ *img_addr = (ulong)ISSW_SIGNED_HEADER_PAYLOAD(hdr);
+ debug("sec_bridge: Changed img_addr->0x%08x\n", *img_addr);
+ return 0;
+}
+
+int sec_bridge_verify_kernel_image(u32 *img_addr) {
+ return sec_bridge_verify_image(img_addr, ISSW_PL_TYPE_APE_NW_CODE);
+}
+
+int sec_bridge_verify_itp_image(u32 *img_addr) {
+ return sec_bridge_verify_image(img_addr, ISSW_PL_TYPE_ITP);
+}
+
+#endif /* CONFIG_SECURE_KERNEL_BOOT */
diff --git a/include/asm-arm/arch-db8500/sec_bridge.h b/include/asm-arm/arch-db8500/sec_bridge.h
index c02bc38a3..447911c72 100644
--- a/include/asm-arm/arch-db8500/sec_bridge.h
+++ b/include/asm-arm/arch-db8500/sec_bridge.h
@@ -15,9 +15,14 @@
#define ISSWAPI_SECURE_LOAD 0x10000002
#define ISSWAPI_FLUSH_BOOT_CODE 0x11000003
+#define ISSWAPI_VERIFY_SIGNED_HEADER 0x11000005
+#define ISSWAPI_VERIFY_HASH 0x11000006
int sec_bridge_init_bridge(void);
u32 sec_bridge_call_secure_service(const u32 serviceid,
const u32 secureconfig, ...);
int sec_bridge_flush_issw(void);
+int sec_bridge_verify_kernel_image(u32 *img_addr);
+int sec_bridge_verify_itp_image(u32 *img_addr);
+
#endif
diff --git a/u-boot-u8500.spec b/u-boot-u8500.spec
index 8d0f1bdd6..a76820418 100644
--- a/u-boot-u8500.spec
+++ b/u-boot-u8500.spec
@@ -37,7 +37,7 @@ cp %{SOURCE1} .
%build
#Make default config for variant
-make %{variant_name}_def_config
+make %{variant_name}_secboot_config
#Build-id needed/wanted by rpmbuild
export LDFLAGS="$LDFLAGS --build-id"