From 5e690269d579d9461be3c5f5e3f59d4c666863a0 Mon Sep 17 00:00:00 2001 From: Ruchika Gupta Date: Fri, 8 Apr 2022 13:14:44 +0530 Subject: [PATCH] feat(qemu): add support for measured boot Add helper functions to generate event log for qemu when MEASURED_BOOT=1. Signed-off-by: Ruchika Gupta Change-Id: I17a098cb614a3a89fe0fe9577bed6edda8bfd070 --- plat/qemu/common/qemu_common.c | 10 +- plat/qemu/common/qemu_private.h | 16 +- plat/qemu/common/qemu_trusted_boot.c | 7 +- plat/qemu/qemu/include/platform_def.h | 7 +- plat/qemu/qemu/platform.mk | 37 +++- plat/qemu/qemu/qemu_bl1_measured_boot.c | 28 +++ plat/qemu/qemu/qemu_common_measured_boot.c | 34 ++++ plat/qemu/qemu/qemu_helpers.c | 214 +++++++++++++++++++++ plat/qemu/qemu/qemu_measured_boot.c | 103 ++++++++++ 9 files changed, 441 insertions(+), 15 deletions(-) create mode 100644 plat/qemu/qemu/qemu_bl1_measured_boot.c create mode 100644 plat/qemu/qemu/qemu_common_measured_boot.c create mode 100644 plat/qemu/qemu/qemu_helpers.c create mode 100644 plat/qemu/qemu/qemu_measured_boot.c diff --git a/plat/qemu/common/qemu_common.c b/plat/qemu/common/qemu_common.c index 47ec79114..0c184f49b 100644 --- a/plat/qemu/common/qemu_common.c +++ b/plat/qemu/common/qemu_common.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -11,6 +11,7 @@ #include #include +#include #include "qemu_private.h" #define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \ @@ -160,4 +161,9 @@ DEFINE_CONFIGURE_MMU_EL(el3) DEFINE_CONFIGURE_MMU_EL(svc_mon) #endif - +#if MEASURED_BOOT || TRUSTED_BOARD_BOOT +int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) +{ + return get_mbedtls_heap_helper(heap_addr, heap_size); +} +#endif diff --git a/plat/qemu/common/qemu_private.h b/plat/qemu/common/qemu_private.h index 4dc62f539..c313cb63f 100644 --- a/plat/qemu/common/qemu_private.h +++ b/plat/qemu/common/qemu_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -34,4 +34,18 @@ void plat_qemu_gic_init(void); void qemu_pwr_gic_on_finish(void); void qemu_pwr_gic_off(void); +int qemu_set_tos_fw_info(uintptr_t config_base, uintptr_t log_addr, + size_t log_size); + +int qemu_set_nt_fw_info( +/* + * Currently OP-TEE does not support reading DTBs from Secure memory + * and this option should be removed when feature is supported. + */ +#ifdef SPD_opteed + uintptr_t log_addr, +#endif + size_t log_size, + uintptr_t *ns_log_addr); + #endif /* QEMU_PRIVATE_H */ diff --git a/plat/qemu/common/qemu_trusted_boot.c b/plat/qemu/common/qemu_trusted_boot.c index 1ef7e431b..6a8edcaaa 100644 --- a/plat/qemu/common/qemu_trusted_boot.c +++ b/plat/qemu/common/qemu_trusted_boot.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -29,8 +29,3 @@ int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { return 1; } - -int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) -{ - return get_mbedtls_heap_helper(heap_addr, heap_size); -} diff --git a/plat/qemu/qemu/include/platform_def.h b/plat/qemu/qemu/include/platform_def.h index c02eff9a8..78467c4af 100644 --- a/plat/qemu/qemu/include/platform_def.h +++ b/plat/qemu/qemu/include/platform_def.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -270,4 +270,9 @@ */ #define SYS_COUNTER_FREQ_IN_TICKS ((1000 * 1000 * 1000) / 16) +/* + * Maximum size of Event Log buffer used in Measured Boot Event Log driver + */ +#define PLAT_EVENT_LOG_MAX_SIZE UL(0x400) + #endif /* PLATFORM_DEF_H */ diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk index a8f978ae8..6a877c3ff 100644 --- a/plat/qemu/qemu/platform.mk +++ b/plat/qemu/qemu/platform.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -57,11 +57,7 @@ PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} ifneq (${TRUSTED_BOARD_BOOT},0) - include drivers/auth/mbedtls/mbedtls_crypto.mk - include drivers/auth/mbedtls/mbedtls_x509.mk - AUTH_SOURCES := drivers/auth/auth_mod.c \ - drivers/auth/crypto_mod.c \ drivers/auth/img_parser_mod.c \ drivers/auth/tbbr/tbbr_cot_common.c @@ -78,6 +74,8 @@ ifneq (${TRUSTED_BOARD_BOOT},0) $(PLAT_QEMU_COMMON_PATH)/qemu_rotpk.S \ drivers/auth/tbbr/tbbr_cot_bl2.c + include drivers/auth/mbedtls/mbedtls_x509.mk + ROT_KEY = $(BUILD_PLAT)/rot_key.pem ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin @@ -98,6 +96,34 @@ ifneq (${TRUSTED_BOARD_BOOT},0) openssl dgst -sha256 -binary > $@ 2>/dev/null endif +# Include Measured Boot makefile before any Crypto library makefile. +# Crypto library makefile may need default definitions of Measured Boot build +# flags present in Measured Boot makefile. +ifeq (${MEASURED_BOOT},1) + MEASURED_BOOT_MK := drivers/measured_boot/event_log/event_log.mk + $(info Including ${MEASURED_BOOT_MK}) + include ${MEASURED_BOOT_MK} + + BL2_SOURCES += plat/qemu/qemu/qemu_measured_boot.c \ + plat/qemu/qemu/qemu_common_measured_boot.c \ + plat/qemu/qemu/qemu_helpers.c \ + ${EVENT_LOG_SOURCES} + + BL1_SOURCES += plat/qemu/qemu/qemu_bl1_measured_boot.c + +endif + +ifneq ($(filter 1,${MEASURED_BOOT} ${TRUSTED_BOARD_BOOT}),) + CRYPTO_SOURCES := drivers/auth/crypto_mod.c + + BL1_SOURCES += ${CRYPTO_SOURCES} + BL2_SOURCES += ${CRYPTO_SOURCES} + + # We expect to locate the *.mk files under the directories specified below + # + include drivers/auth/mbedtls/mbedtls_crypto.mk +endif + BL1_SOURCES += drivers/io/io_semihosting.c \ drivers/io/io_storage.c \ drivers/io/io_fip.c \ @@ -131,6 +157,7 @@ BL2_SOURCES += drivers/io/io_semihosting.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_bl2_mem_params_desc.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_image_load.c \ common/fdt_fixup.c \ + common/fdt_wrappers.c \ common/desc_image_load.c ifeq ($(add-lib-optee),yes) diff --git a/plat/qemu/qemu/qemu_bl1_measured_boot.c b/plat/qemu/qemu/qemu_bl1_measured_boot.c new file mode 100644 index 000000000..3d20f974e --- /dev/null +++ b/plat/qemu/qemu/qemu_bl1_measured_boot.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022, Arm Limited. All rights reserved. + * Copyright (c) 2022, Linaro. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +/* + * Add dummy functions for measured boot for BL1. + * In most of the SoC's, ROM/BL1 code is pre-built. So we are assumimg that + * it doesn't have the capability to do measurements and extend eventlog. + * hence these are dummy functions. + */ +void bl1_plat_mboot_init(void) +{ +} + +void bl1_plat_mboot_finish(void) +{ +} + +int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data) +{ + return 0; +} diff --git a/plat/qemu/qemu/qemu_common_measured_boot.c b/plat/qemu/qemu/qemu_common_measured_boot.c new file mode 100644 index 000000000..41f7f87c9 --- /dev/null +++ b/plat/qemu/qemu/qemu_common_measured_boot.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, Linaro. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include + +extern event_log_metadata_t qemu_event_log_metadata[]; + +const event_log_metadata_t *plat_event_log_get_metadata(void) +{ + return qemu_event_log_metadata; +} + +int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data) +{ + /* Calculate image hash and record data in Event Log */ + int err = event_log_measure_and_record(image_data->image_base, + image_data->image_size, + image_id); + if (err != 0) { + ERROR("%s%s image id %u (%i)\n", + "Failed to ", "record", image_id, err); + return err; + } + + return 0; +} diff --git a/plat/qemu/qemu/qemu_helpers.c b/plat/qemu/qemu/qemu_helpers.c new file mode 100644 index 000000000..01b824977 --- /dev/null +++ b/plat/qemu/qemu/qemu_helpers.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2022, Linaro. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#if MEASURED_BOOT +#include +#endif +#include + +#include + +#ifdef SPD_opteed +/* + * Currently OP-TEE does not support reading DTBs from Secure memory + * and this property should be removed when this feature is supported. + */ +#define DTB_PROP_HW_SM_LOG_ADDR "tpm_event_log_sm_addr" +#endif + +#define DTB_PROP_HW_LOG_ADDR "tpm_event_log_addr" +#define DTB_PROP_HW_LOG_SIZE "tpm_event_log_size" + +#if MEASURED_BOOT + +#ifdef SPD_opteed +int qemu_set_tee_fw_info(uintptr_t config_base, uintptr_t log_addr, + size_t log_size) +{ + int offs, err = 0; + void *dtb = (void *)config_base; + const char *compatible = "arm,tpm_event_log"; + uint64_t sec_base = cpu_to_fdt64(log_addr); + uint32_t sz = cpu_to_fdt32(log_size); + + offs = fdtw_find_or_add_subnode(dtb, 0, "tpm-event-log"); + if (offs < 0) { + ERROR("Failed to add node tpm-event-log %d\n", offs); + return offs; + } + + if (fdt_appendprop(dtb, offs, "compatible", compatible, + strlen(compatible) + 1) < 0) { + return -1; + } + + err = fdt_setprop(dtb, offs, DTB_PROP_HW_SM_LOG_ADDR, &sec_base, 8); + if (err < 0) { + ERROR("Failed to add log addr err %d\n", err); + return err; + } + + err = fdt_setprop(dtb, offs, DTB_PROP_HW_LOG_SIZE, &sz, 4); + if (err < 0) { + ERROR("Failed to add log addr err %d\n", err); + return err; + } + + return err; +} +#endif + +/* + * Write the Event Log address and its size in the DTB. + * + * This function is supposed to be called only by BL2. + * + * Returns: + * 0 = success + * < 0 = error + */ +static int qemu_set_event_log_info(uintptr_t config_base, +#ifdef SPD_opteed + uintptr_t sm_log_addr, +#endif + uintptr_t log_addr, size_t log_size) +{ + /* As libfdt uses void *, we can't avoid this cast */ + void *dtb = (void *)config_base; + const char *compatible_tpm = "tcg,tpm-tis-mmio"; + uint64_t base = cpu_to_fdt64(log_addr); + uint32_t sz = cpu_to_fdt32(log_size); + int err, node; + + err = fdt_open_into(dtb, dtb, PLAT_QEMU_DT_MAX_SIZE); + if (err < 0) { + ERROR("Invalid Device Tree at %p: error %d\n", dtb, err); + return err; + } + + /* + * Verify that the DTB is valid, before attempting to write to it, + * and get the DTB root node. + */ + + /* Check if the pointer to DT is correct */ + err = fdt_check_header(dtb); + if (err < 0) { + WARN("Invalid DTB file passed\n"); + return err; + } + + /* + * Find the TPM node in device tree. On qemu, we assume it will + * be sw-tpm. + */ + node = fdt_node_offset_by_compatible(dtb, -1, compatible_tpm); + if (node < 0) { + ERROR("The compatible property '%s' not%s", compatible_tpm, + " found in the config\n"); + return node; + } + + err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_ADDR, &base, 8); + if (err < 0) { + ERROR("Failed to add log addr err %d\n", err); + return err; + } + + err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_SIZE, &sz, 4); + if (err < 0) { + ERROR("Failed to add log addr err %d\n", err); + return err; + } + +#ifdef SPD_opteed + err = qemu_set_tee_fw_info(config_base, sm_log_addr, log_size); + if (err < 0) { + ERROR("Failed to add tpm-event-node at %p: err %d\n", dtb, err); + return err; + } +#endif + + err = fdt_pack(dtb); + if (err < 0) { + ERROR("Failed to pack Device Tree at %p: err %d\n", dtb, err); + return err; + } + + /* + * Ensure that the info written to the DTB is visible + * to other images. + */ + flush_dcache_range(config_base, fdt_totalsize(dtb)); + + return err; +} + +/* + * This function writes the Event Log address and its size + * in the TOS_FW_CONFIG DTB. + * + * This function is supposed to be called only by BL2. + * + * Returns: + * 0 = success + * < 0 = error + */ +int qemu_set_tos_fw_info(uintptr_t config_base, uintptr_t log_addr, + size_t log_size) +{ + int err = 0; + + assert(config_base != 0UL); + assert(log_addr != 0UL); + + /* + * FIXME - add code to add/update Log address and it's + * size in TOS FW CONFIG. + * For now we don't have support for TOS FW config in OP-TEE. + * So leave this function blank + */ + + return err; +} + +/* + * This function writes the Event Log address and its size + * in the QEMU DTB. + * + * This function is supposed to be called only by BL2. + * + * Returns: + * 0 = success + * < 0 = error + */ +int qemu_set_nt_fw_info( +#ifdef SPD_opteed + uintptr_t log_addr, +#endif + size_t log_size, uintptr_t *ns_log_addr) +{ + uintptr_t ns_addr; + int err; + + assert(ns_log_addr != NULL); + + ns_addr = PLAT_QEMU_DT_BASE + PLAT_QEMU_DT_MAX_SIZE; + + /* Write the Event Log address and its size in the DTB */ + err = qemu_set_event_log_info(PLAT_QEMU_DT_BASE, +#ifdef SPD_opteed + log_addr, +#endif + ns_addr, log_size); + + /* Return Event Log address in Non-secure memory */ + *ns_log_addr = (err < 0) ? 0UL : ns_addr; + return err; +} +#endif /* MEASURED_BOOT */ diff --git a/plat/qemu/qemu/qemu_measured_boot.c b/plat/qemu/qemu/qemu_measured_boot.c new file mode 100644 index 000000000..d9e475abe --- /dev/null +++ b/plat/qemu/qemu/qemu_measured_boot.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2022, Arm Limited. All rights reserved. + * Copyright (c) 2022, Linaro. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include + +#include "../common/qemu_private.h" + +/* Event Log data */ +static uint8_t event_log[PLAT_EVENT_LOG_MAX_SIZE]; +static uint64_t event_log_base; + +/* FVP table with platform specific image IDs, names and PCRs */ +const event_log_metadata_t qemu_event_log_metadata[] = { + { BL31_IMAGE_ID, EVLOG_BL31_STRING, PCR_0 }, + { BL32_IMAGE_ID, EVLOG_BL32_STRING, PCR_0 }, + { BL32_EXTRA1_IMAGE_ID, EVLOG_BL32_EXTRA1_STRING, PCR_0 }, + { BL32_EXTRA2_IMAGE_ID, EVLOG_BL32_EXTRA2_STRING, PCR_0 }, + { BL33_IMAGE_ID, EVLOG_BL33_STRING, PCR_0 }, + { HW_CONFIG_ID, EVLOG_HW_CONFIG_STRING, PCR_0 }, + { NT_FW_CONFIG_ID, EVLOG_NT_FW_CONFIG_STRING, PCR_0 }, + { SCP_BL2_IMAGE_ID, EVLOG_SCP_BL2_STRING, PCR_0 }, + { SOC_FW_CONFIG_ID, EVLOG_SOC_FW_CONFIG_STRING, PCR_0 }, + { TOS_FW_CONFIG_ID, EVLOG_TOS_FW_CONFIG_STRING, PCR_0 }, + + { EVLOG_INVALID_ID, NULL, (unsigned int)(-1) } /* Terminator */ +}; + +void bl2_plat_mboot_init(void) +{ + /* + * Here we assume that BL1/ROM code doesn't have the driver + * to measure the BL2 code which is a common case for + * already existing platforms + */ + event_log_init(event_log, event_log + sizeof(event_log)); + event_log_write_header(); + + /* + * TBD - Add code to do self measurement of BL2 code and add an + * event for BL2 measurement + */ + + event_log_base = (uintptr_t)event_log; +} + +void bl2_plat_mboot_finish(void) +{ + int rc; + + /* Event Log address in Non-Secure memory */ + uintptr_t ns_log_addr; + + /* Event Log filled size */ + size_t event_log_cur_size; + + event_log_cur_size = event_log_get_cur_size((uint8_t *)event_log_base); + + rc = qemu_set_nt_fw_info( +#ifdef SPD_opteed + (uintptr_t)event_log_base, +#endif + event_log_cur_size, &ns_log_addr); + if (rc != 0) { + ERROR("%s(): Unable to update %s_FW_CONFIG\n", + __func__, "NT"); + /* + * It is a fatal error because on QEMU secure world software + * assumes that a valid event log exists and will use it to + * record the measurements into the fTPM or sw-tpm. + * Note: In QEMU platform, OP-TEE uses nt_fw_config to get the + * secure Event Log buffer address. + */ + panic(); + } + + /* Copy Event Log to Non-secure memory */ + (void)memcpy((void *)ns_log_addr, (const void *)event_log_base, + event_log_cur_size); + + /* Ensure that the Event Log is visible in Non-secure memory */ + flush_dcache_range(ns_log_addr, event_log_cur_size); + +#if defined(SPD_tspd) || defined(SPD_spmd) + /* Set Event Log data in TOS_FW_CONFIG */ + rc = qemu_set_tos_fw_info((uintptr_t)event_log_base, + event_log_cur_size); + if (rc != 0) { + ERROR("%s(): Unable to update %s_FW_CONFIG\n", + __func__, "TOS"); + panic(); + } +#endif /* defined(SPD_tspd) || defined(SPD_spmd) */ + + dump_event_log((uint8_t *)event_log_base, event_log_cur_size); +}