diff options
-rw-r--r-- | arch/arm/mach-socfpga/Kconfig | 15 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/board.c | 45 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/include/mach/mailbox_s10.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/include/mach/secure_vab.h | 63 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/secure_vab.c | 186 | ||||
-rw-r--r-- | common/Kconfig.boot | 2 |
7 files changed, 309 insertions, 5 deletions
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index 9b1abdaabd..0c35406232 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -6,6 +6,21 @@ config ERR_PTR_OFFSET config NR_DRAM_BANKS default 1 +config SOCFPGA_SECURE_VAB_AUTH + bool "Enable boot image authentication with Secure Device Manager" + depends on TARGET_SOCFPGA_AGILEX + select FIT_IMAGE_POST_PROCESS + select SHA384 + select SHA512_ALGO + select SPL_FIT_IMAGE_POST_PROCESS + help + All images loaded from FIT will be authenticated by Secure Device + Manager. + +config SOCFPGA_SECURE_VAB_AUTH_ALLOW_NON_FIT_IMAGE + bool "Allow non-FIT VAB signed images" + depends on SOCFPGA_SECURE_VAB_AUTH + config SPL_SIZE_LIMIT default 0x10000 if TARGET_SOCFPGA_GEN5 diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 82b681d870..1f1e21766d 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -4,6 +4,7 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. # # Copyright (C) 2012-2017 Altera Corporation <www.altera.com> +# Copyright (C) 2017-2020 Intel Corporation <www.intel.com> obj-y += board.o obj-y += clock_manager.o @@ -47,6 +48,7 @@ obj-y += mailbox_s10.o obj-y += misc_s10.o obj-y += mmu-arm64_s10.o obj-y += reset_manager_s10.o +obj-$(CONFIG_SOCFPGA_SECURE_VAB_AUTH) += secure_vab.o obj-y += system_manager_s10.o obj-y += timer_s10.o obj-y += wrap_pinmux_config_s10.o diff --git a/arch/arm/mach-socfpga/board.c b/arch/arm/mach-socfpga/board.c index 2a6af9d1f8..81aa07c902 100644 --- a/arch/arm/mach-socfpga/board.c +++ b/arch/arm/mach-socfpga/board.c @@ -6,14 +6,17 @@ */ #include <common.h> -#include <errno.h> -#include <fdtdec.h> -#include <init.h> -#include <asm/arch/reset_manager.h> #include <asm/arch/clock_manager.h> #include <asm/arch/misc.h> +#include <asm/arch/reset_manager.h> +#include <asm/arch/secure_vab.h> #include <asm/global_data.h> #include <asm/io.h> +#include <errno.h> +#include <fdtdec.h> +#include <hang.h> +#include <image.h> +#include <init.h> #include <log.h> #include <usb.h> #include <usb/dwc2_udc.h> @@ -98,3 +101,37 @@ __weak int board_fit_config_name_match(const char *name) return 0; } #endif + +#if IS_ENABLED(CONFIG_FIT_IMAGE_POST_PROCESS) +void board_fit_image_post_process(void **p_image, size_t *p_size) +{ + if (IS_ENABLED(CONFIG_SOCFPGA_SECURE_VAB_AUTH)) { + if (socfpga_vendor_authentication(p_image, p_size)) + hang(); + } +} +#endif + +#if !IS_ENABLED(CONFIG_SPL_BUILD) && IS_ENABLED(CONFIG_FIT) +void board_prep_linux(bootm_headers_t *images) +{ + if (!IS_ENABLED(CONFIG_SECURE_VAB_AUTH_ALLOW_NON_FIT_IMAGE)) { + /* + * Ensure the OS is always booted from FIT and with + * VAB signed certificate + */ + if (!images->fit_uname_cfg) { + printf("Please use FIT with VAB signed images!\n"); + hang(); + } + + env_set_hex("fdt_addr", (ulong)images->ft_addr); + debug("images->ft_addr = 0x%08lx\n", (ulong)images->ft_addr); + } + + if (IS_ENABLED(CONFIG_CADENCE_QSPI)) { + if (env_get("linux_qspi_enable")) + run_command(env_get("linux_qspi_enable"), 0); + } +} +#endif diff --git a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h index 4d783119ea..fbaf11597e 100644 --- a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h +++ b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h @@ -118,6 +118,7 @@ enum ALT_SDM_MBOX_RESP_CODE { #define MBOX_RECONFIG_MSEL 7 #define MBOX_RECONFIG_DATA 8 #define MBOX_RECONFIG_STATUS 9 +#define MBOX_VAB_SRC_CERT 11 #define MBOX_QSPI_OPEN 50 #define MBOX_QSPI_CLOSE 51 #define MBOX_QSPI_DIRECT 59 diff --git a/arch/arm/mach-socfpga/include/mach/secure_vab.h b/arch/arm/mach-socfpga/include/mach/secure_vab.h new file mode 100644 index 0000000000..42588588e8 --- /dev/null +++ b/arch/arm/mach-socfpga/include/mach/secure_vab.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2020 Intel Corporation <www.intel.com> + * + */ + +#ifndef _SECURE_VAB_H_ +#define _SECURE_VAB_H_ + +#include <linux/sizes.h> +#include <linux/stddef.h> +#include <u-boot/sha512.h> + +#define VAB_DATA_SZ 64 + +#define SDM_CERT_MAGIC_NUM 0x25D04E7F +#define FCS_HPS_VAB_MAGIC_NUM 0xD0564142 + +#define MAX_CERT_SIZE (SZ_4K) + +/* + * struct fcs_hps_vab_certificate_data + * @vab_cert_magic_num: VAB Certificate Magic Word (0xD0564142) + * @flags: TBD + * @fcs_data: Data words being certificate signed. + * @cert_sign_keychain: Certificate Signing Keychain + */ +struct fcs_hps_vab_certificate_data { + u32 vab_cert_magic_num; /* offset 0x10 */ + u32 flags; + u8 rsvd0_1[8]; + u8 fcs_sha384[SHA384_SUM_LEN]; /* offset 0x20 */ +}; + +/* + * struct fcs_hps_vab_certificate_header + * @cert_magic_num: Certificate Magic Word (0x25D04E7F) + * @cert_data_sz: size of this certificate header (0x80) + * Includes magic number all the way to the certificate + * signing keychain (excludes cert. signing keychain) + * @cert_ver: Certificate Version + * @cert_type: Certificate Type + * @data: VAB HPS Image Certificate data + */ +struct fcs_hps_vab_certificate_header { + u32 cert_magic_num; /* offset 0 */ + u32 cert_data_sz; + u32 cert_ver; + u32 cert_type; + struct fcs_hps_vab_certificate_data d; /* offset 0x10 */ + /* keychain starts at offset 0x50 */ +}; + +#define VAB_CERT_HEADER_SIZE sizeof(struct fcs_hps_vab_certificate_header) +#define VAB_CERT_MAGIC_OFFSET offsetof \ + (struct fcs_hps_vab_certificate_header, d) +#define VAB_CERT_FIT_SHA384_OFFSET offsetof \ + (struct fcs_hps_vab_certificate_data, \ + fcs_sha384[0]) + +int socfpga_vendor_authentication(void **p_image, size_t *p_size); + +#endif /* _SECURE_VAB_H_ */ diff --git a/arch/arm/mach-socfpga/secure_vab.c b/arch/arm/mach-socfpga/secure_vab.c new file mode 100644 index 0000000000..e2db588506 --- /dev/null +++ b/arch/arm/mach-socfpga/secure_vab.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Intel Corporation <www.intel.com> + * + */ + +#include <asm/arch/mailbox_s10.h> +#include <asm/arch/secure_vab.h> +#include <asm/arch/smc_api.h> +#include <asm/unaligned.h> +#include <common.h> +#include <exports.h> +#include <linux/errno.h> +#include <linux/intel-smc.h> +#include <log.h> + +#define CHUNKSZ_PER_WD_RESET (256 * SZ_1K) + +/* + * Read the length of the VAB certificate from the end of image + * and calculate the actual image size (excluding the VAB certificate). + */ +static size_t get_img_size(u8 *img_buf, size_t img_buf_sz) +{ + u8 *img_buf_end = img_buf + img_buf_sz; + u32 cert_sz = get_unaligned_le32(img_buf_end - sizeof(u32)); + u8 *p = img_buf_end - cert_sz - sizeof(u32); + + /* Ensure p is pointing within the img_buf */ + if (p < img_buf || p > (img_buf_end - VAB_CERT_HEADER_SIZE)) + return 0; + + if (get_unaligned_le32(p) == SDM_CERT_MAGIC_NUM) + return (size_t)(p - img_buf); + + return 0; +} + +/* + * Vendor Authorized Boot (VAB) is a security feature for authenticating + * the images such as U-Boot, ARM trusted Firmware, Linux kernel, + * device tree blob and etc loaded from FIT. User can also trigger + * the VAB authentication from U-Boot command. + * + * This function extracts the VAB certificate and signature block + * appended at the end of the image, then send to Secure Device Manager + * (SDM) for authentication. This function will validate the SHA384 + * of the image against the SHA384 hash stored in the VAB certificate + * before sending the VAB certificate to SDM for authentication. + * + * RETURN + * 0 if authentication success or + * if authentication is not required and bypassed on a non-secure device + * negative error code if authentication fail + */ +int socfpga_vendor_authentication(void **p_image, size_t *p_size) +{ + int retry_count = 20; + u8 hash384[SHA384_SUM_LEN]; + u64 img_addr, mbox_data_addr; + size_t img_sz, mbox_data_sz; + u8 *cert_hash_ptr, *mbox_relocate_data_addr; + u32 resp = 0, resp_len = 1; + int ret; + + img_addr = (uintptr_t)*p_image; + + debug("Authenticating image at address 0x%016llx (%ld bytes)\n", + img_addr, *p_size); + + img_sz = get_img_size((u8 *)img_addr, *p_size); + debug("img_sz = %ld\n", img_sz); + + if (!img_sz) { + puts("VAB certificate not found in image!\n"); + return -ENOKEY; + } + + if (!IS_ALIGNED(img_sz, sizeof(u32))) { + printf("Image size (%ld bytes) not aliged to 4 bytes!\n", + img_sz); + return -EBFONT; + } + + /* Generate HASH384 from the image */ + sha384_csum_wd((u8 *)img_addr, img_sz, hash384, CHUNKSZ_PER_WD_RESET); + + cert_hash_ptr = (u8 *)(img_addr + img_sz + VAB_CERT_MAGIC_OFFSET + + VAB_CERT_FIT_SHA384_OFFSET); + + /* + * Compare the SHA384 found in certificate against the SHA384 + * calculated from image + */ + if (memcmp(hash384, cert_hash_ptr, SHA384_SUM_LEN)) { + puts("SHA384 not match!\n"); + return -EKEYREJECTED; + } + + mbox_data_addr = img_addr + img_sz - sizeof(u32); + /* Size in word (32bits) */ + mbox_data_sz = (ALIGN(*p_size - img_sz, sizeof(u32))) >> 2; + + debug("mbox_data_addr = 0x%016llx\n", mbox_data_addr); + debug("mbox_data_sz = %ld words\n", mbox_data_sz); + + /* + * Relocate certificate to first memory block before trigger SMC call + * to send mailbox command because ATF only able to access first + * memory block. + */ + mbox_relocate_data_addr = (u8 *)malloc(mbox_data_sz * sizeof(u32)); + if (!mbox_relocate_data_addr) { + puts("Out of memory for VAB certificate relocation!\n"); + return -ENOMEM; + } + + memcpy(mbox_relocate_data_addr, (u8 *)mbox_data_addr, mbox_data_sz * sizeof(u32)); + *(u32 *)mbox_relocate_data_addr = 0; + + debug("mbox_relocate_data_addr = 0x%p\n", mbox_relocate_data_addr); + + do { + if (!IS_ENABLED(CONFIG_SPL_BUILD) && IS_ENABLED(CONFIG_SPL_ATF)) { + /* Invoke SMC call to ATF to send the VAB certificate to SDM */ + ret = smc_send_mailbox(MBOX_VAB_SRC_CERT, mbox_data_sz, + (u32 *)mbox_relocate_data_addr, 0, &resp_len, + &resp); + } else { + /* Send the VAB certficate to SDM for authentication */ + ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_VAB_SRC_CERT, + MBOX_CMD_DIRECT, mbox_data_sz, + (u32 *)mbox_relocate_data_addr, 0, &resp_len, + &resp); + } + /* If SDM is not available, just delay 50ms and retry again */ + if (ret == MBOX_RESP_DEVICE_BUSY) + mdelay(50); + else + break; + } while (--retry_count); + + /* Free the relocate certificate memory space */ + free(mbox_relocate_data_addr); + + /* Exclude the size of the VAB certificate from image size */ + *p_size = img_sz; + + debug("ret = 0x%08x, resp = 0x%08x, resp_len = %d\n", ret, resp, + resp_len); + + if (ret) { + /* + * Unsupported mailbox command or device not in the + * owned/secure state + */ + if (ret == MBOX_RESP_NOT_ALLOWED_UNDER_SECURITY_SETTINGS) { + /* SDM bypass authentication */ + printf("%s 0x%016llx (%ld bytes)\n", + "Image Authentication bypassed at address", + img_addr, img_sz); + return 0; + } + puts("VAB certificate authentication failed in SDM"); + if (ret == MBOX_RESP_DEVICE_BUSY) { + puts(" (SDM busy timeout)\n"); + return -ETIMEDOUT; + } else if (ret == MBOX_RESP_UNKNOWN) { + puts(" (Not supported)\n"); + return -ESRCH; + } + puts("\n"); + return -EKEYREJECTED; + } else { + /* If Certificate Process Status has error */ + if (resp) { + puts("VAB certificate process failed\n"); + return -ENOEXEC; + } + } + + printf("%s 0x%016llx (%ld bytes)\n", + "Image Authentication passed at address", img_addr, img_sz); + + return 0; +} diff --git a/common/Kconfig.boot b/common/Kconfig.boot index e650c605d1..9c335f4f8c 100644 --- a/common/Kconfig.boot +++ b/common/Kconfig.boot @@ -138,7 +138,7 @@ config FIT_BEST_MATCH config FIT_IMAGE_POST_PROCESS bool "Enable post-processing of FIT artifacts after loading by U-Boot" - depends on TI_SECURE_DEVICE + depends on TI_SECURE_DEVICE || SOCFPGA_SECURE_VAB_AUTH help Allows doing any sort of manipulation to blobs after they got extracted from FIT images like stripping off headers or modifying the size of the |