security/vboot: Add measured boot mode

* Introduce a measured boot mode into vboot.
* Add hook for stage measurements in prog_loader and cbfs.
* Implement and hook-up CRTM in vboot and check for suspend.

Change-Id: I339a2f1051e44f36aba9f99828f130592a09355e
Signed-off-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
Signed-off-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-on: https://review.coreboot.org/c/29547
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Philipp Deppenwiese 2018-11-08 10:59:40 +01:00
parent bacd57dfaf
commit 66f9a09916
22 changed files with 349 additions and 37 deletions

View File

@ -167,6 +167,7 @@ Contents:
* [Code of Conduct](community/code_of_conduct.md)
* [Community forums](community/forums.md)
* [coreboot at conferences](community/conferences.md)
* [Security](security.md)
* [Payloads](payloads.md)
* [Distributions](distributions.md)
* [Timestamps](timestamp.md)

View File

@ -0,0 +1,5 @@
# Security
## Google VBoot2 Measured boot extension
- [Measured Boot](vboot/measured_boot.md)

View File

@ -0,0 +1,58 @@
# Measured Boot
coreboot measured boot is implemented as Google Verified Boot extension. This
means in order to use it, vboot needs to be available for your platform.
## IBB/CRTM
The "Initial Boot Block" or "Core Root of Trust for Measurement" is the first
code block loaded at reset vector and measured by a DRTM solution.
In case SRTM mode is active, the IBB measures itself before measuring the next
code block. In coreboot, cbfs files which are part of the IBB are identified
by a metatdata tag. This makes it possible to have platform specific IBB
measurements without hardcoding them.
## Known Limitations
At the moment measuring IBB dynamically and FMAP partitions are not possible but
will be added later to the implementation.
Also SoCs making use of VBOOT_RETURN_FROM_VERSTAGE are not able to use the
measured boot extension because of platform constraints.
## SRTM Mode
The "Static Root of Trust for Measurement" is the easiest way doing measurements
by measuring code before it is loaded.
![][srtm]
[srtm]: srtm.png
## DRTM Mode
The "Dynamic Root of Trust for Measurement" is realised by platform features
like Intel TXT or Boot Guard. The features provide a way of loading a signed
"Authenticated Code Module" aka signed blob. Most of these features are also
a "Trusted Execution Environment", e.g. Intel TXT.
DRTM gives you the ability of measuring the IBB from a higher Root of Trust
instead of doing it yourself without any hardware support.
## Platform Configuration Register
Normally PCR 0-7 are reserved for firmware usage. In coreboot we use just 4 PCR
banks in order to store the measurements. coreboot uses the SHA-1 or SHA-256
hash algorithm depending on the TPM specification for measurements. PCR-4 to
PCR-7 are left empty.
### PCR-0
_Hash:_ SHA1
_Description:_ Google VBoot GBB flags.
### PCR-1
_Hash:_ SHA1/SHA256
_Description:_ Google VBoot GBB HWID.
### PCR-2
_Hash:_ SHA1/SHA256
_Description:_ Core Root of Trust for Measurement which includes all stages,
data and blobs.
### PCR-3
_Hash:_ SHA1/SHA256
_Description:_ Runtime data like hwinfo.hex or MRC cache.

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -4,6 +4,8 @@ romstage-y += romstage.c
romstage-y += tsc_freq.c
romstage-y += ../car/romstage.c
postcar-y += tsc_freq.c
ramstage-y += acpi.c
ramstage-$(CONFIG_CACHE_RELOCATED_RAMSTAGE_OUTSIDE_CBMEM) += stage_cache.c
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smmrelocate.c

View File

@ -12,6 +12,7 @@ subdirs-y += ../common
ramstage-y += tsc_freq.c
romstage-y += tsc_freq.c
postcar-y += tsc_freq.c
smm-$(CONFIG_HAVE_SMI_HANDLER) += tsc_freq.c
ramstage-y += acpi.c

View File

@ -19,6 +19,7 @@ smm-$(CONFIG_HAVE_SMI_HANDLER) += common.c
ramstage-y += tsc_freq.c
romstage-y += tsc_freq.c
postcar-y += tsc_freq.c
smm-$(CONFIG_HAVE_SMI_HANDLER) += tsc_freq.c
smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c

View File

@ -26,6 +26,7 @@
#include <timestamp.h>
#include <fmap.h>
#include "fmap_config.h"
#include <security/vboot/vboot_crtm.h>
#define ERROR(x...) printk(BIOS_ERR, "CBFS: " x)
#define LOG(x...) printk(BIOS_INFO, "CBFS: " x)
@ -59,7 +60,12 @@ int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type)
return -1;
}
return cbfs_locate(fh, &rdev, name, type);
int ret = cbfs_locate(fh, &rdev, name, type);
if (!ret)
if (vboot_measure_cbfs_hook(fh, name))
return -1;
return ret;
}
void *cbfs_boot_map_with_leak(const char *name, uint32_t type, size_t *size)
@ -157,9 +163,9 @@ static inline int tohex4(unsigned int c)
static void tohex16(unsigned int val, char *dest)
{
dest[0] = tohex4(val>>12);
dest[1] = tohex4((val>>8) & 0xf);
dest[2] = tohex4((val>>4) & 0xf);
dest[0] = tohex4(val >> 12);
dest[1] = tohex4((val >> 8) & 0xf);
dest[2] = tohex4((val >> 4) & 0xf);
dest[3] = tohex4(val & 0xf);
}
@ -167,8 +173,8 @@ void *cbfs_boot_map_optionrom(uint16_t vendor, uint16_t device)
{
char name[17] = "pciXXXX,XXXX.rom";
tohex16(vendor, name+3);
tohex16(device, name+8);
tohex16(vendor, name + 3);
tohex16(device, name + 8);
return cbfs_boot_map_with_leak(name, CBFS_TYPE_OPTIONROM, NULL);
}
@ -202,7 +208,8 @@ size_t cbfs_boot_load_file(const char *name, void *buf, size_t buf_size,
return 0;
if (cbfsf_decompression_info(&fh, &compression_algo,
&decompressed_size) < 0
&decompressed_size)
< 0
|| decompressed_size > buf_size)
return 0;

View File

@ -90,7 +90,6 @@ static uint32_t tpm_setup_s3_helper(void)
default:
printk(BIOS_ERR, "TPM: Resume failed (%#x).\n", result);
break;
}
return result;
@ -215,8 +214,6 @@ uint32_t tpm_extend_pcr(int pcr, uint8_t *digest,
if (result != TPM_SUCCESS)
return result;
tcpa_log_add_table_entry(name, pcr, digest, digest_len);
return TPM_SUCCESS;
}

View File

@ -26,6 +26,22 @@ config VBOOT
if VBOOT
config VBOOT_MEASURED_BOOT
bool "Enable Measured Boot"
default n
depends on !VBOOT_MOCK_SECDATA
depends on !VBOOT_RETURN_FROM_VERSTAGE
help
Enables measured boot mode in vboot (experimental)
config VBOOT_MEASURED_BOOT_RUNTIME_DATA
string "Runtime data whitelist"
default ""
depends on VBOOT_MEASURED_BOOT
help
Runtime data whitelist of cbfs filenames. Needs to be a comma separated
list
config VBOOT_SLOTS_RW_A
bool "Firmware RO + RW_A"
help
@ -37,7 +53,6 @@ config VBOOT_SLOTS_RW_AB
help
Have two update partitions beside the RO partition.
config VBOOT_VBNV_CMOS
bool
default n

View File

@ -69,6 +69,13 @@ romstage-y += vboot_common.c
ramstage-y += vboot_common.c
postcar-y += vboot_common.c
ifeq ($(CONFIG_VBOOT_MEASURED_BOOT),y)
verstage-y += vboot_crtm.c
romstage-y += vboot_crtm.c
ramstage-y += vboot_crtm.c
postcar-y += vboot_crtm.c
endif
bootblock-y += common.c
verstage-y += vboot_logic.c
verstage-y += common.c

View File

@ -0,0 +1,144 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2018 Facebook Inc.
*
* 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 <console/console.h>
#include <fmap.h>
#include <security/vboot/vboot_crtm.h>
#include <security/vboot/misc.h>
uint32_t vboot_init_crtm(void)
{
struct prog bootblock = PROG_INIT(PROG_BOOTBLOCK, "bootblock");
struct prog verstage =
PROG_INIT(PROG_VERSTAGE, CONFIG_CBFS_PREFIX "/verstage");
struct prog romstage =
PROG_INIT(PROG_ROMSTAGE, CONFIG_CBFS_PREFIX "/romstage");
/* measure bootblock from RO */
struct cbfsf bootblock_data;
struct region_device bootblock_fmap;
if (fmap_locate_area_as_rdev("BOOTBLOCK", &bootblock_fmap) == 0) {
if (tpm_measure_region(&bootblock_fmap,
TPM_CRTM_PCR,
prog_name(&bootblock)))
return VB2_ERROR_UNKNOWN;
} else {
if (cbfs_boot_locate(&bootblock_data,
prog_name(&bootblock), NULL) == 0) {
cbfs_file_data(prog_rdev(&bootblock), &bootblock_data);
if (tpm_measure_region(prog_rdev(&bootblock),
TPM_CRTM_PCR,
prog_name(&bootblock)))
return VB2_ERROR_UNKNOWN;
} else {
printk(BIOS_INFO,
"VBOOT: Couldn't measure bootblock into CRTM!\n");
return VB2_ERROR_UNKNOWN;
}
}
if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) {
struct cbfsf romstage_data;
/* measure romstage from RO */
if (cbfs_boot_locate(&romstage_data,
prog_name(&romstage), NULL) == 0) {
cbfs_file_data(prog_rdev(&romstage), &romstage_data);
if (tpm_measure_region(prog_rdev(&romstage),
TPM_CRTM_PCR,
CONFIG_CBFS_PREFIX "/romstage"))
return VB2_ERROR_UNKNOWN;
} else {
printk(BIOS_INFO,
"VBOOT: Couldn't measure %s into CRTM!\n",
CONFIG_CBFS_PREFIX "/romstage");
return VB2_ERROR_UNKNOWN;
}
}
if (IS_ENABLED(CONFIG_VBOOT_SEPARATE_VERSTAGE)) {
struct cbfsf verstage_data;
/* measure verstage from RO */
if (cbfs_boot_locate(&verstage_data,
prog_name(&verstage), NULL) == 0) {
cbfs_file_data(prog_rdev(&verstage), &verstage_data);
if (tpm_measure_region(prog_rdev(&verstage),
TPM_CRTM_PCR,
CONFIG_CBFS_PREFIX "/verstage"))
return VB2_ERROR_UNKNOWN;
} else {
printk(BIOS_INFO,
"VBOOT: Couldn't measure %s into CRTM!\n",
CONFIG_CBFS_PREFIX "/verstage");
return VB2_ERROR_UNKNOWN;
}
}
return VB2_SUCCESS;
}
static bool is_runtime_data(const char *name)
{
const char *whitelist = CONFIG_VBOOT_MEASURED_BOOT_RUNTIME_DATA;
size_t whitelist_len = sizeof(CONFIG_VBOOT_MEASURED_BOOT_RUNTIME_DATA) - 1;
size_t name_len = strlen(name);
int i;
if (!whitelist_len || !name_len)
return false;
for (i = 0; (i + name_len) <= whitelist_len; i++) {
if (!strcmp(whitelist + i, name))
return true;
}
return false;
}
uint32_t vboot_measure_cbfs_hook(struct cbfsf *fh, const char *name)
{
uint32_t pcr_index;
uint32_t cbfs_type;
struct region_device rdev;
if (!vb2_logic_executed())
return 0;
cbfsf_file_type(fh, &cbfs_type);
cbfs_file_data(&rdev, fh);
switch (cbfs_type) {
case CBFS_TYPE_MRC:
case CBFS_TYPE_MRC_CACHE:
pcr_index = TPM_RUNTIME_DATA_PCR;
break;
case CBFS_TYPE_STAGE:
case CBFS_TYPE_SELF:
case CBFS_TYPE_FIT:
pcr_index = TPM_CRTM_PCR;
break;
default:
if (is_runtime_data(name))
pcr_index = TPM_RUNTIME_DATA_PCR;
else
pcr_index = TPM_CRTM_PCR;
break;
}
return tpm_measure_region(&rdev, pcr_index,
name);
}

View File

@ -0,0 +1,62 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2018 Facebook Inc.
*
* 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 __SECURITY_VBOOT_CRTM_H__
#define __SECURITY_VBOOT_CRTM_H__
#include <program_loading.h>
#include <security/tpm/tspi.h>
#include <types.h>
#include <cbfs.h>
/* CRTM */
#define TPM_CRTM_PCR 2
/* PCR for measuring data which changes during runtime
* e.g. CMOS, NVRAM...
*/
#define TPM_RUNTIME_DATA_PCR 3
/*
* Initializes the Core Root of Trust for Measurements
* in coreboot. The initial code in a chain of trust must measure
* itself.
*
* Summary:
* + Measures bootblock in CBFS or BOOTBLOCK FMAP partition.
* + If vboot starts in romstage, it measures the romstage
* in CBFS.
* + Measure the verstage if it is compiled as separate
* stage.
*
* Takes the current vboot context as parameter for s3 checks.
* returns on success VB2_SUCCESS, else a vboot error.
*/
uint32_t vboot_init_crtm(void);
#if (IS_ENABLED(CONFIG_VBOOT_MEASURED_BOOT) && \
!ENV_BOOTBLOCK && !ENV_DECOMPRESSOR && !ENV_SMM)
/*
* Measures cbfs data via hook (cbfs)
* fh is the cbfs file handle to measure
* return 0 if successful, else an error
*/
uint32_t vboot_measure_cbfs_hook(struct cbfsf *fh, const char *name);
#else
#define vboot_measure_cbfs_hook(fh, name) 0
#endif
#endif /* __VBOOT_VBOOT_CRTM_H__ */

View File

@ -24,6 +24,7 @@
#include <vb2_api.h>
#include <security/vboot/misc.h>
#include <security/vboot/vbnv.h>
#include <security/vboot/vboot_crtm.h>
#include "antirollback.h"
@ -86,22 +87,19 @@ int vb2ex_read_resource(struct vb2_context *ctx,
}
/* No-op stubs that can be overridden by SoCs with hardware crypto support. */
__weak
int vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
__weak int vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
uint32_t data_size)
{
return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
}
__weak
int vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
__weak int vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
{
BUG(); /* Should never get called if init() returned an error. */
return VB2_ERROR_UNKNOWN;
}
__weak
int vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
__weak int vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
{
BUG(); /* Should never get called if init() returned an error. */
return VB2_ERROR_UNKNOWN;
@ -319,6 +317,13 @@ void verstage_main(void)
antirollback_read_space_firmware(&ctx);
timestamp_add_now(TS_END_TPMINIT);
/* Enable measured boot mode */
if (IS_ENABLED(CONFIG_VBOOT_MEASURED_BOOT) &&
!(ctx.flags & VB2_CONTEXT_S3_RESUME)) {
if (vboot_init_crtm() != VB2_SUCCESS)
die("Initializing measured boot mode failed!");
}
if (IS_ENABLED(CONFIG_VBOOT_PHYSICAL_DEV_SWITCH) &&
get_developer_mode_switch())
ctx.flags |= VB2_CONTEXT_FORCE_DEVELOPER_MODE;

View File

@ -89,6 +89,7 @@ postcar-y += ramtop.c
postcar-y += sb_util.c
postcar-y += nb_util.c
postcar-$(CONFIG_VBOOT_MEASURED_BOOT) += i2c.c
postcar-y += tsc_freq.c
ramstage-y += BiosCallOuts.c
ramstage-y += i2c.c

View File

@ -14,6 +14,7 @@ romstage-y += memmap.c
postcar-y += memmap.c
ramstage-y += tsc_freq.c
romstage-y += tsc_freq.c
postcar-y += tsc_freq.c
smm-y += tsc_freq.c
ramstage-y += spi.c
smm-y += spi.c

View File

@ -16,6 +16,8 @@ romstage-y += memmap.c
romstage-y += pmutil.c
romstage-y += tsc_freq.c
postcar-y += tsc_freq.c
ramstage-y += acpi.c
ramstage-y += chip.c
ramstage-y += cpu.c

View File

@ -61,6 +61,7 @@ ramstage-y += systemagent.c
ramstage-y += tsc_freq.c
romstage-y += tsc_freq.c
smm-y += tsc_freq.c
postcar-y += tsc_freq.c
bootblock-$(CONFIG_USBDEBUG) += usb_debug.c
romstage-$(CONFIG_USBDEBUG) += usb_debug.c
ramstage-$(CONFIG_USBDEBUG) += usb_debug.c

View File

@ -32,6 +32,7 @@ ramstage-y += memmap.c
romstage-y += memmap.c
ramstage-y += tsc_freq.c
romstage-y += tsc_freq.c
postcar-y += tsc_freq.c
smm-$(CONFIG_HAVE_SMI_HANDLER) += tsc_freq.c
ramstage-y += spi.c
smm-$(CONFIG_HAVE_SMI_HANDLER) += spi.c

View File

@ -24,6 +24,7 @@ ramstage-y += acpi.c
ramstage-y += smbus_common.c
ramstage-y += smbus.c
romstage-y += tsc_freq.c
postcar-y += tsc_freq.c
ramstage-y += smi.c
ramstage-y += gpio.c
ramstage-y += iou_complto.c

View File

@ -39,7 +39,7 @@ SECTIONS
SRAM_END(0x00120000)
SRAM_L2C_START(0x00200000)
OVERLAP_DECOMPRESSOR_ROMSTAGE(0x000201000, 110K)
OVERLAP_DECOMPRESSOR_ROMSTAGE(0x000201000, 152K)
BOOTBLOCK(0x00227000, 89K)
VERSTAGE(0x0023E000, 114K)
SRAM_L2C_END(0x00280000)

View File

@ -717,7 +717,7 @@ while true ; do
chromeos=true
testclass=chromeos
customizing="${customizing}, chrome os"
configoptions="${configoptions}CONFIG_CHROMEOS=y\n"
configoptions="${configoptions}CONFIG_CHROMEOS=y\nCONFIG_VBOOT_MEASURED_BOOT=y\n"
;;
-X|--xmlfile) shift; XMLFILE=$1; REAL_XMLFILE=$1; shift;;
-I|--recursive) shift; recursive=true;;