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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -240,7 +237,7 @@ uint32_t tpm_measure_region(const struct region_device *rdev, uint8_t pcr,
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_TPM1))
|
||||
hash_alg = VB2_HASH_SHA1;
|
||||
else /* CONFIG_TPM2 */
|
||||
else /* CONFIG_TPM2 */
|
||||
hash_alg = VB2_HASH_SHA256;
|
||||
|
||||
digest_len = vb2_digest_size(hash_alg);
|
||||
@@ -258,7 +255,7 @@ uint32_t tpm_measure_region(const struct region_device *rdev, uint8_t pcr,
|
||||
len = MIN(sizeof(buf), region_device_sz(rdev) - offset);
|
||||
if (rdev_readat(rdev, buf, offset, len) < 0) {
|
||||
printk(BIOS_ERR, "TPM: Not able to read region %s.\n",
|
||||
rname);
|
||||
rname);
|
||||
return TPM_E_READ_FAILURE;
|
||||
}
|
||||
if (vb2_digest_extend(&ctx, buf, len)) {
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
144
src/security/vboot/vboot_crtm.c
Normal file
144
src/security/vboot/vboot_crtm.c
Normal 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);
|
||||
}
|
62
src/security/vboot/vboot_crtm.h
Normal file
62
src/security/vboot/vboot_crtm.h
Normal 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__ */
|
@@ -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,24 +87,21 @@ 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,
|
||||
uint32_t data_size)
|
||||
__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. */
|
||||
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. */
|
||||
BUG(); /* Should never get called if init() returned an error. */
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -249,7 +247,7 @@ static int hash_body(struct vb2_context *ctx, struct region_device *fw_main)
|
||||
}
|
||||
|
||||
static int locate_firmware(struct vb2_context *ctx,
|
||||
struct region_device *fw_main)
|
||||
struct region_device *fw_main)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
@@ -281,7 +279,7 @@ static void save_if_needed(struct vb2_context *ctx)
|
||||
static uint32_t extend_pcrs(struct vb2_context *ctx)
|
||||
{
|
||||
return vboot_extend_pcr(ctx, 0, BOOT_MODE_PCR) ||
|
||||
vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR);
|
||||
vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,7 +307,7 @@ void verstage_main(void)
|
||||
* does verification of memory init and thus must ensure it resumes with
|
||||
* the same slot that it booted from. */
|
||||
if (IS_ENABLED(CONFIG_RESUME_PATH_SAME_AS_BOOT) &&
|
||||
vboot_platform_is_resuming())
|
||||
vboot_platform_is_resuming())
|
||||
ctx.flags |= VB2_CONTEXT_S3_RESUME;
|
||||
|
||||
/* Read secdata from TPM. Initialize TPM if secdata not found. We don't
|
||||
@@ -319,8 +317,15 @@ 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())
|
||||
get_developer_mode_switch())
|
||||
ctx.flags |= VB2_CONTEXT_FORCE_DEVELOPER_MODE;
|
||||
|
||||
if (get_recovery_mode_switch()) {
|
||||
@@ -330,7 +335,7 @@ void verstage_main(void)
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_VBOOT_WIPEOUT_SUPPORTED) &&
|
||||
get_wipeout_mode_switch())
|
||||
get_wipeout_mode_switch())
|
||||
ctx.flags |= VB2_CONTEXT_FORCE_WIPEOUT_MODE;
|
||||
|
||||
if (IS_ENABLED(CONFIG_VBOOT_LID_SWITCH) && !get_lid_switch())
|
||||
@@ -350,7 +355,7 @@ void verstage_main(void)
|
||||
if (rv == VB2_ERROR_API_PHASE1_RECOVERY) {
|
||||
printk(BIOS_INFO, "Recovery requested (%x)\n", rv);
|
||||
save_if_needed(&ctx);
|
||||
extend_pcrs(&ctx); /* ignore failures */
|
||||
extend_pcrs(&ctx); /* ignore failures */
|
||||
timestamp_add_now(TS_END_VBOOT);
|
||||
return;
|
||||
}
|
||||
|
Reference in New Issue
Block a user