From bc03d1e9728ab1faa9eebbee3ed90e57bd27c051 Mon Sep 17 00:00:00 2001 From: Robert Rosengren Date: Wed, 15 Dec 2010 09:48:59 +0100 Subject: 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 Reviewed-by: Michael BRANDT Reviewed-by: QATOOLS Reviewed-by: Jens WIKLANDER --- Makefile | 3 + common/cmd_bootm.c | 12 +++ cpu/arm_cortexa9/db8500/itp.c | 45 ++++++++++ cpu/arm_cortexa9/db8500/sec_bridge.c | 143 ++++++++++++++++++++++++++++++- include/asm-arm/arch-db8500/sec_bridge.h | 5 ++ u-boot-u8500.spec | 2 +- 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 #include @@ -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" -- cgit v1.2.3