Frans Hendriks has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30835
Change subject: vendorcode/eltan/security/verified_boot: Add verified boot support. ......................................................................
vendorcode/eltan/security/verified_boot: Add verified boot support.
Create verified boot support, which includes verifiication of bootblock. This feature use the vendorcode/eltan/security/lib.
Function verified_boot_bootblock_check(), verified_boot_should_run_oprom() and prog_locate_hook() must be called from coreboot (or mainboard).
The next lists will be used for verification: bootblock_verify_list[], romstage_verify_list[] ram_stage_additional_list[], ramstage_verify_list[]
BUG=N/A TEST=Created binary and verify logging on Facebook FBG-1701
Change-Id: If6c1423b0b4a309cefb7fe7a29d5100ba289e0b4 Signed-off-by: Frans Hendriks fhendriks@eltan.com --- A src/vendorcode/eltan/security/verified_boot/Kconfig A src/vendorcode/eltan/security/verified_boot/Makefile.inc A src/vendorcode/eltan/security/verified_boot/vboot_check.c A src/vendorcode/eltan/security/verified_boot/vboot_check.h 4 files changed, 605 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/35/30835/1
diff --git a/src/vendorcode/eltan/security/verified_boot/Kconfig b/src/vendorcode/eltan/security/verified_boot/Kconfig new file mode 100644 index 0000000..0670732 --- /dev/null +++ b/src/vendorcode/eltan/security/verified_boot/Kconfig @@ -0,0 +1,61 @@ +## This file is part of the coreboot project. +## +## Copyright (C) 2018 Eltan B.V. +## +## 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; version 2 of the License. +## +## 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. +## + +menu "Verified Boot (verified_boot)" + +config VERIFIED_BOOT + bool "Enable Verified Boot" + default n + +config VERIFIED_BOOT_SIGNED_MANIFEST + bool "Enable Signed Manifest" + depends on VERIFIED_BOOT + default n + +config VERIFIED_BOOT_USE_SHA512 + bool "SHA512 hashes" + depends on VERIFIED_BOOT + default n + help + Use SHA512 for the vboot operations, this applies to the digest in + the manifest and the manifest digest. + +config OEM_MANIFEST_LOC + hex "Manifest Location" + default 0xFFFFF840 + +config VERIFIED_BOOT_MANIFEST + string "Verified boot manifest file" + default "mainboard/$(MAINBOARD_DIR)/manifest.h" + +config OEM_MANIFEST_ITEMS + int "Manifest Items" + default 10 + +config OEM_MANIFEST_ITEM_SIZE + int + default 64 if VERIFIED_BOOT_USE_SHA512 + default 32 + +config VERIFIED_BOOT_KEY_LOCATION + hex "Verified boot Key Location" + depends on VERIFIED_BOOT_SIGNED_MANIFEST + default 0xFFFFF500 + +config VERIFIED_BOOT_KEY_SIZE + int + default 554 if VERIFIED_BOOT_USE_SHA512 + default 520 + +endmenu # Verified Boot (verified_boot) diff --git a/src/vendorcode/eltan/security/verified_boot/Makefile.inc b/src/vendorcode/eltan/security/verified_boot/Makefile.inc new file mode 100644 index 0000000..23044b4 --- /dev/null +++ b/src/vendorcode/eltan/security/verified_boot/Makefile.inc @@ -0,0 +1,47 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2018 Eltan B.V. +## +## 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; version 2 of the License. +## +## 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. +## + +ifeq ($(CONFIG_VERIFIED_BOOT),y) + +CPPFLAGS_common += -I$(src)/security/verified_boot + +bootblock-$(CONFIG_C_ENVIRONMENT_BOOTBLOCK) += vboot_check.c +romstage-y += vboot_check.c +ramstage-y += vboot_check.c + +cbfs-files-y += oemmanifest.bin +oemmanifest.bin-file := $(obj)/oemmanifest.bin +oemmanifest.bin-position := $(CONFIG_OEM_MANIFEST_LOC) +oemmanifest.bin-type := 0x50 + +$(obj)/oemmanifest.bin: +ifeq ($(CONFIG_VERIFIED_BOOT_SIGNED_MANIFEST),y) + dd if=/dev/zero of=$@ seek=8 bs=$(CONFIG_OEM_MANIFEST_ITEM_SIZE) count=$(CONFIG_OEM_MANIFEST_ITEMS) +else # ($(CONFIG_VERIFIED_BOOT_SIGNED_MANIFEST),y) + dd if=/dev/zero of=$@ bs=$(CONFIG_OEM_MANIFEST_ITEM_SIZE) count=$(CONFIG_OEM_MANIFEST_ITEMS) +endif # ($(CONFIG_VERIFIED_BOOT_SIGNED_MANIFEST),y) + +ifeq ($(CONFIG_VERIFIED_BOOT_SIGNED_MANIFEST),y) +cbfs-files-y += vboot_public_key.bin +vboot_public_key.bin-file := $(obj)/vboot_public_key.bin +vboot_public_key.bin-position := $(CONFIG_VERIFIED_BOOT_KEY_LOCATION) +vboot_public_key.bin-type := 0x50 + +$(obj)/vboot_public_key.bin: + dd if=/dev/zero of=$@ bs=$(CONFIG_VERIFIED_BOOT_KEY_SIZE) count=1 + +endif # ($(CONFIG_VERIFIED_BOOT_SIGNED_MANIFEST),y) + +endif # CONFIG_VERIFIED_BOOT diff --git a/src/vendorcode/eltan/security/verified_boot/vboot_check.c b/src/vendorcode/eltan/security/verified_boot/vboot_check.c new file mode 100644 index 0000000..fb7d1d7 --- /dev/null +++ b/src/vendorcode/eltan/security/verified_boot/vboot_check.c @@ -0,0 +1,414 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * Copyright (C) 2017-2018 Eltan B.V. + * + * 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; version 2 of the License. + * + * 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. + */ +#include <vboot_check.h> + +#define RSA_PUBLICKEY_FILE_NAME "vboot_public_key.bin" + +#if IS_ENABLED(CONFIG_VERIFIED_BOOT_USE_SHA512) +#define DIGEST_SIZE SHA512_DIGEST_SIZE +#else +#define DIGEST_SIZE SHA256_DIGEST_SIZE +#endif + +int verified_boot_check_manifest(void) +{ + struct vb2_public_key key; + uint8_t digest[DIGEST_SIZE]; + size_t size = 0; + uint8_t *signature = NULL; + uint8_t *buffer; + const struct vb2_workbuf wb; + + cbfs_boot_map_with_leak("oemmanifest.bin", CBFS_TYPE_RAW, &size); + + if (size != (CONFIG_OEM_MANIFEST_ITEMS * DIGEST_SIZE) + 256) { + printk(BIOS_ERR, "ERROR: Incorrect manifest size!\n"); + goto fail; + } + + buffer = cbfs_boot_map_with_leak(RSA_PUBLICKEY_FILE_NAME, + CBFS_TYPE_RAW, &size); + + size = DIGEST_SIZE; + if (!vb2_unpack_key_data(&key, buffer, size)) { + printk(BIOS_ERR, "ERROR: Unable to create RSA Public Key !\n"); + goto fail; + } + + if (IS_ENABLED(CONFIG_VERIFIED_BOOT_USE_SHA512)) + key.hash_alg = VB2_HASH_SHA512; + else + key.sig_alg = VB2_HASH_SHA256; + + + // + // Create a big endian digest + // + if (IS_ENABLED(CONFIG_VERIFIED_BOOT_USE_SHA512)) + cb_sha512_ex((const uint8_t *)CONFIG_OEM_MANIFEST_LOC, + CONFIG_OEM_MANIFEST_ITEMS * DIGEST_SIZE, digest, 1); + else + cb_sha256_ex((const uint8_t *)CONFIG_OEM_MANIFEST_LOC, + CONFIG_OEM_MANIFEST_ITEMS * DIGEST_SIZE, digest, 1); + + signature = (uint8_t *)CONFIG_OEM_MANIFEST_LOC + + CONFIG_OEM_MANIFEST_ITEMS * DIGEST_SIZE; + + if (!vb2_rsa_verify_digest(&key, signature, digest, &wb)) { + printk(BIOS_ERR, "ERROR: Signature verification failed for" + "hash table !!\n"); + goto fail; + } + + printk(BIOS_DEBUG, "%s: Successfully verified hash_table signature.\n", + __func__); + return 0; + +fail: + die("HASH table verification failed!\n"); + return -1; +} + +#ifndef __BOOTBLOCK__ + +/* + * + * measure_item + * + * extends the defined pcr using the hash calculated by the verified boot + * routines. + * + * @param[in] pcr PCR to extend + * @param[in] *hashData Pointer to the hash data + * @param[in] hashDataLen Length of the hash data + * @param[in] *event_msg Message to log or display + * @param[in] eventType Event type to use when logging + + * @retval TPM_SUCCESS Operation completed successfully. + * @retval TPM_E_IOERROR Unexpected device behavior. + */ +static int measure_item(uint32_t pcr, uint8_t *hashData, uint32_t hashDataLen, + int8_t *event_msg, TCG_EVENTTYPE eventType) +{ + int status = TPM_SUCCESS; + EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrs; + TCG_PCR_EVENT2_HDR tcgEventHdr; + + ActivePcrs = tpm2_get_active_pcrs(); + + memset(&tcgEventHdr, 0, sizeof(tcgEventHdr)); + tcgEventHdr.pcrIndex = pcr; + tcgEventHdr.eventType = eventType; + if (event_msg) { + status = mboot_hash_extend_log(ActivePcrs, MBOOT_HASH_PROVIDED, + hashData, hashDataLen, &tcgEventHdr, + (uint8_t *)event_msg, 0); + if (status == TPM_SUCCESS) { + printk(BIOS_DEBUG, "%s: Success! %s measured to pcr" + "%d.\n", __func__, event_msg, pcr); + } else { + printk(BIOS_DEBUG, "%s: Fail! %s can't be measured. " + "ABORTING!!!\n", __func__, event_msg); + return status; + } + } + return status; +} +#endif + +static void verified_boot_check_buffer(const char *name, void *start, + size_t size, uint32_t hash_index, int32_t pcr) +{ + uint8_t digest[DIGEST_SIZE]; +#ifndef __BOOTBLOCK__ + int status; +#endif + printk(BIOS_INFO, "%s: %s HASH verification buffer %p size %d\n", + __func__, name, start, (int) size); + + if (start && size) { + if (IS_ENABLED(CONFIG_VERIFIED_BOOT_USE_SHA512)) + cb_sha512((const uint8_t *)start, size, digest); + else + cb_sha256((const uint8_t*)start, size, digest); + + if (memcmp((void *)((uint8_t *)CONFIG_OEM_MANIFEST_LOC + + sizeof(digest) * hash_index), digest, sizeof(digest))) { + printk(BIOS_INFO, "%s: buffer hash\n", __func__); + hexdump(digest, sizeof(digest)); + printk(BIOS_INFO, "%s: manifest hash\n", __func__); + hexdump((void *)((uint8_t *)CONFIG_OEM_MANIFEST_LOC + + sizeof(digest) * hash_index), sizeof(digest)); + printk(BIOS_EMERG, "%s ", name); + die("HASH verification failed!\n"); + } else { +#ifndef __BOOTBLOCK__ + if (IS_ENABLED(CONFIG_MBOOT)) { + if (pcr != -1) { + printk(BIOS_INFO, "%s: measuring %s\n", + __func__, name); + status = measure_item(pcr, digest, + sizeof(digest), + (int8_t *)name, 0); + } + } +#endif + printk(BIOS_INFO, "%s HASH verification success\n", + name); + } + } else { + printk(BIOS_EMERG, "Invalid buffer "); + die("HASH verification failed!\n"); + } +} + +void verified_boot_check_cbfsfile(const char *name, uint32_t type, + uint32_t hash_index, void **buffer, uint32_t *filesize, + int32_t pcr) +{ + void *start; + size_t size; + + start = cbfs_boot_map_with_leak(name, type & ~VERIFIED_BOOT_COPY_BLOCK, + &size); + if (start && size) { + /* + * Speed up processing by copying the file content to memory + * first + */ +#ifndef __PRE_RAM__ + if ((type & VERIFIED_BOOT_COPY_BLOCK) && (buffer) && + (*buffer) && + ((uint32_t) start > (uint32_t)(~(CONFIG_CBFS_SIZE-1)))) { + printk(BIOS_INFO, "%s: move buffer to " + "memory\n", __func__); + /* Move the file to a memory bufferof which we know it + * doesn't harm + */ + memcpy(*buffer, start, size); + start = *buffer; + printk(BIOS_INFO, "%s: done\n", __func__); + } +#endif // __PRE_RAM__ + verified_boot_check_buffer(name, start, size, hash_index, pcr); + } else { + printk(BIOS_EMERG, "CBFS Failed to get file content for %s\n", + name); + die("HASH verification failed!\n"); + } + if (buffer) + *buffer = start; + if (filesize) + *filesize = size; +} + +void process_verify_list(const verify_item_t list[]) +{ + int i = 0; + + while (list[i].type != VERIFY_TERMINATOR) { + switch (list[i].type) { + case VERIFY_FILE: + verified_boot_check_cbfsfile(list[i].name, + list[i].data.file.cbfs_type, + list[i].hash_index, NULL, NULL, + list[i].pcr); + if (list[i].data.file.related_items) { + printk(BIOS_SPEW, "process related items\n"); + process_verify_list((verify_item_t *) + list[i].data.file.related_items); + } + break; + case VERIFY_BLOCK: + verified_boot_check_buffer(list[i].name, + (void *) list[i].data.block.start, + list[i].data.block.size, + list[i].hash_index, list[i].pcr); + break; + default: + printk(BIOS_EMERG, "INVALID TYPE IN VERIFY" + "LIST 0x%x\n", list[i].type); + die("HASH verification failed!\n"); + } + i++; + } +} +#ifndef __BOOTBLOCK__ + +static void process_named_list(const verify_item_t list[], const char *name, + void **buffer, uint32_t *size) +{ + int i = 0; + + while (list[i].type != VERIFY_TERMINATOR) { + switch (list[i].type) { + case VERIFY_FILE: + if (!strcmp(name, list[i].name)) { + if (list[i].data.file.related_items) { + printk(BIOS_SPEW, "process related" + "items\n"); + process_verify_list((verify_item_t *)list[i].data.file.related_items); + printk(BIOS_SPEW, "process related items done\n"); + } + verified_boot_check_cbfsfile(list[i].name, + list[i].data.file.cbfs_type, + list[i].hash_index, buffer, size, + list[i].pcr); + return; + } + break; + default: + printk(BIOS_EMERG, "INVALID TYPE IN NAMED LIST" + "0x%x\n", list[i].type); + die("HASH verification failed!\n"); + } + i++; + } + printk(BIOS_EMERG, "%s NOT IN LIST\n", name); + die("HASH verification failed!\n"); +} +#endif + +#ifdef __BOOTBLOCK__ +/* + * BOOTBLOCK + */ + +extern verify_item_t bootblock_verify_list[]; + +void verified_boot_bootblock_check(void) +{ + printk(BIOS_SPEW, "%s: processing bootblock items\n", __func__); + + if (IS_ENABLED(CONFIG_VERIFIED_BOOT_SIGNED_MANIFEST)) { + printk(BIOS_SPEW, "%s: check the manifest\n", __func__); + if (verified_boot_check_manifest() != 0) + die("invalid manifest"); + } + printk(BIOS_SPEW, "%s: process bootblock verify list\n", __func__); + process_verify_list(bootblock_verify_list); +} + +#endif //__BOOTBLOCK__ + + +#ifdef __ROMSTAGE__ +/* + * ROMSTAGE + */ + +extern verify_item_t ramstage_verify_list[]; + +int prog_locate_hook(struct prog *prog) +{ + if (prog->type == PROG_RAMSTAGE) { + process_named_list(ramstage_verify_list, prog->name, NULL, + NULL); + } + return 0; +} + +extern verify_item_t romstage_verify_list[]; + +void verified_boot_early_check(void) +{ + printk(BIOS_SPEW, "%s: processing early items\n", __func__); + + if (!IS_ENABLED(CONFIG_C_ENVIRONMENT_BOOTBLOCK) && + IS_ENABLED(CONFIG_VERIFIED_BOOT_SIGNED_MANIFEST)) { + printk(BIOS_SPEW, "%s: check the manifest\n", __func__); + if (verified_boot_check_manifest() != 0) + die("invalid manifest"); + } + printk(BIOS_SPEW, "%s: process early verify list\n", __func__); + process_verify_list(romstage_verify_list); +} +#endif //__ROMSTAGE__ + +#ifdef __RAMSTAGE__ +/* + * RAM STAGE + */ + +static int process_oprom_list(const verify_item_t list[], + struct rom_header *rom_header) +{ + int i = 0; + struct pci_data *rom_data; + uint32_t viddevid = 0; + + if (le32_to_cpu(rom_header->signature) != PCI_ROM_HDR) { + printk(BIOS_ERR, "Incorrect expansion ROM header " + "signature %04x DONT START\n", + le32_to_cpu(rom_header->signature)); + return 0; + } + + rom_data = (((void *)rom_header) + le32_to_cpu(rom_header->data)); + + viddevid |= (rom_data->vendor << 16); + viddevid |= rom_data->device; + + while (list[i].type != VERIFY_TERMINATOR) { + switch (list[i].type) { + case VERIFY_OPROM: + if (viddevid == list[i].data.oprom.viddev) { + verified_boot_check_buffer(list[i].name, + (void *) rom_header, + rom_header->size * 512, + list[i].hash_index, list[i].pcr); + if (list[i].data.oprom.related_items) { + printk(BIOS_SPEW, "%s: process" + " related items\n", __func__); + process_verify_list((verify_item_t *)list[i].data.oprom.related_items); + } + printk(BIOS_SPEW, "%s: option rom can be" + " started\n", __func__); + return 1; + } + break; + default: + printk(BIOS_EMERG, "%s: INVALID TYPE IN OPTION ROM LIST" + "0x%x\n", __func__, list[i].type); + die("HASH verification failed!\n"); + } + i++; + } + printk(BIOS_ERR, "%s: option rom not in list DONT START\n", __func__); + return 0; +} + +extern verify_item_t payload_verify_list[]; + +int prog_locate_hook(struct prog *prog) +{ + if (prog->type == PROG_PAYLOAD) { + void *buffer = (void*) 0x01000000; + printk(BIOS_SPEW, "%s: requesting %s\n", __func__, prog->name); + process_named_list(payload_verify_list, prog->name, &buffer, + NULL); + printk(BIOS_SPEW, "%s: running allowed\n", __func__); + } + return 0; +} + +extern verify_item_t oprom_verify_list[]; + +int verified_boot_should_run_oprom(struct rom_header *rom_header) +{ + return process_oprom_list(oprom_verify_list, rom_header); +} +#endif //__PRE_RAM__ diff --git a/src/vendorcode/eltan/security/verified_boot/vboot_check.h b/src/vendorcode/eltan/security/verified_boot/vboot_check.h new file mode 100644 index 0000000..34186f3 --- /dev/null +++ b/src/vendorcode/eltan/security/verified_boot/vboot_check.h @@ -0,0 +1,83 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2016 Intel Corp. + * Copyright (C) 2017-2018 Eltan B.V. + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef VBOOT_CHECK_H +#define VBOOT_CHECK_H + +#include <cbfs.h> +#include <device/device.h> +#include <device/pci.h> +#include <lib.h> +#include CONFIG_VERIFIED_BOOT_MANIFEST +#include <console/console.h> +#include <cryptolib.h> +#include <string.h> +#include <program_loading.h> +#if IS_ENABLED(CONFIG_MBOOT) +#include <mboot.h> +#endif + +#define VERIFIED_BOOT_COPY_BLOCK 0x80000000 +/* These method verifies the SHA256 hash over the 'named' CBFS component. + * 'type' denotes the type of CBFS component i.e. stage, payload or fsp. + */ +#ifdef __BOOTBLOCK__ +void verified_boot_bootblock_check(void); +#endif +#ifdef __ROMSTAGE__ +void verified_boot_early_check(void); +#endif + +int verified_boot_check_manifest(void); + +void verified_boot_check_cbfsfile(const char *name, uint32_t type, + uint32_t hash_index, void **buffer, uint32_t *filesize, int32_t pcr); + +typedef enum { + + VERIFY_TERMINATOR = 0, + VERIFY_FILE, + VERIFY_BLOCK, + VERIFY_OPROM + +} verify_type; + +typedef struct { + verify_type type; + const char *name; + union { + struct { + const void *related_items; + uint32_t cbfs_type; + } file; + struct { + const void *start; + uint32_t size; + } block; + struct { + const void *related_items; + uint32_t viddev; + } oprom; + } data; + uint32_t hash_index; +#if IS_ENABLED(CONFIG_MBOOT) + int32_t pcr; +#endif //IS_ENABLED(CONFIG_MBOOT) +} verify_item_t; + +void process_verify_list(const verify_item_t list[]); + +#endif //VBOOT_CHECK_H