summaryrefslogtreecommitdiff
path: root/src/security/tpm/tspi
diff options
context:
space:
mode:
Diffstat (limited to 'src/security/tpm/tspi')
-rw-r--r--src/security/tpm/tspi/crtm.c197
-rw-r--r--src/security/tpm/tspi/crtm.h65
-rw-r--r--src/security/tpm/tspi/log.c12
-rw-r--r--src/security/tpm/tspi/tspi.c52
4 files changed, 305 insertions, 21 deletions
diff --git a/src/security/tpm/tspi/crtm.c b/src/security/tpm/tspi/crtm.c
new file mode 100644
index 0000000000..dc7d7d21f0
--- /dev/null
+++ b/src/security/tpm/tspi/crtm.c
@@ -0,0 +1,197 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ *
+ * 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 <cbfs.h>
+#include "crtm.h"
+#include <string.h>
+
+/*
+ * This function sets the TCPA log namespace
+ * for the cbfs file (region) lookup.
+ */
+static int create_tcpa_metadata(const struct region_device *rdev,
+ const char *cbfs_name, char log_string[TCPA_PCR_HASH_NAME])
+{
+ int i;
+ struct region_device fmap;
+ static const char *const fmap_cbfs_names[] = {
+ "COREBOOT",
+ "FW_MAIN_A",
+ "FW_MAIN_B",
+ "RW_LEGACY"
+ };
+
+ for (i = 0; i < ARRAY_SIZE(fmap_cbfs_names); i++) {
+ if (fmap_locate_area_as_rdev(fmap_cbfs_names[i], &fmap) == 0) {
+ if (region_is_subregion(region_device_region(&fmap),
+ region_device_region(rdev))) {
+ snprintf(log_string, TCPA_PCR_HASH_NAME,
+ "FMAP: %s CBFS: %s",
+ fmap_cbfs_names[i], cbfs_name);
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static int tcpa_log_initialized;
+static inline int tcpa_log_available(void)
+{
+ if (ENV_BOOTBLOCK)
+ return tcpa_log_initialized;
+
+ return 1;
+}
+
+uint32_t tspi_init_crtm(void)
+{
+ struct prog bootblock = PROG_INIT(PROG_BOOTBLOCK, "bootblock");
+
+ /* Initialize TCPA PRERAM log. */
+ if (!tcpa_log_available()) {
+ tcpa_preram_log_clear();
+ tcpa_log_initialized = 1;
+ } else {
+ printk(BIOS_WARNING, "TSPI: CRTM already initialized!\n");
+ return VB2_SUCCESS;
+ }
+
+ /* 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,
+ "FMAP: BOOTBLOCK"))
+ return VB2_ERROR_UNKNOWN;
+ } else {
+ if (cbfs_boot_locate(&bootblock_data,
+ prog_name(&bootblock), NULL)) {
+ /*
+ * measurement is done in
+ * tspi_measure_cbfs_hook()
+ */
+ printk(BIOS_INFO,
+ "TSPI: Couldn't measure bootblock into CRTM!\n");
+ return VB2_ERROR_UNKNOWN;
+ }
+ }
+
+ return VB2_SUCCESS;
+}
+
+static bool is_runtime_data(const char *name)
+{
+ const char *whitelist = CONFIG_TPM_MEASURED_BOOT_RUNTIME_DATA;
+ size_t whitelist_len = sizeof(CONFIG_TPM_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 tspi_measure_cbfs_hook(struct cbfsf *fh, const char *name)
+{
+ uint32_t pcr_index;
+ uint32_t cbfs_type;
+ struct region_device rdev;
+ char tcpa_metadata[TCPA_PCR_HASH_NAME];
+
+ if (!tcpa_log_available()) {
+ if (tspi_init_crtm() != VB2_SUCCESS) {
+ printk(BIOS_WARNING,
+ "Initializing CRTM failed!");
+ return 0;
+ }
+ printk(BIOS_DEBUG, "CRTM initialized.");
+ }
+
+ 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;
+ }
+
+ if (create_tcpa_metadata(&rdev, name, tcpa_metadata) < 0)
+ return VB2_ERROR_UNKNOWN;
+
+ return tpm_measure_region(&rdev, pcr_index, tcpa_metadata);
+}
+
+int tspi_measure_cache_to_pcr(void)
+{
+ int i;
+ enum vb2_hash_algorithm hash_alg;
+ struct tcpa_table *tclt = tcpa_log_init();
+
+ if (!tclt) {
+ printk(BIOS_WARNING, "TCPA: Log non-existent!\n");
+ return VB2_ERROR_UNKNOWN;
+ }
+ if (CONFIG(TPM1)) {
+ hash_alg = VB2_HASH_SHA1;
+ } else { /* CONFIG_TPM2 */
+ hash_alg = VB2_HASH_SHA256;
+ }
+
+
+ printk(BIOS_DEBUG, "TPM: Write digests cached in TCPA log to PCR\n");
+ for (i = 0; i < tclt->num_entries; i++) {
+ struct tcpa_entry *tce = &tclt->entries[i];
+ if (tce) {
+ printk(BIOS_DEBUG, "TPM: Write digest for"
+ " %s into PCR %d\n",
+ tce->name, tce->pcr);
+ int result = tlcl_extend(tce->pcr,
+ tce->digest,
+ NULL);
+ if (result != TPM_SUCCESS) {
+ printk(BIOS_ERR, "TPM: Writing digest"
+ " of %s into PCR failed with error"
+ " %d\n",
+ tce->name, result);
+ return VB2_ERROR_UNKNOWN;
+ }
+ }
+ }
+
+ return VB2_SUCCESS;
+}
diff --git a/src/security/tpm/tspi/crtm.h b/src/security/tpm/tspi/crtm.h
new file mode 100644
index 0000000000..dfd91e1c0e
--- /dev/null
+++ b/src/security/tpm/tspi/crtm.h
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ *
+ * 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_TSPI_CRTM_H__
+#define __SECURITY_TSPI_CRTM_H__
+
+#include <commonlib/cbfs.h>
+#include <program_loading.h>
+#include <security/tpm/tspi.h>
+#include <types.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 tspi_init_crtm(void);
+
+/**
+ * Measure digests cached in TCPA log entries into PCRs
+ */
+int tspi_measure_cache_to_pcr(void);
+
+#if CONFIG(TPM_MEASURED_BOOT)
+/*
+ * Measures cbfs data via hook (cbfs)
+ * fh is the cbfs file handle to measure
+ * return 0 if successful, else an error
+ */
+uint32_t tspi_measure_cbfs_hook(struct cbfsf *fh, const char *name);
+
+#else
+#define tspi_measure_cbfs_hook(fh, name) 0
+#endif
+
+#endif /* __SECURITY_TSPI_CRTM_H__ */
diff --git a/src/security/tpm/tspi/log.c b/src/security/tpm/tspi/log.c
index 068d78da19..e43f74d069 100644
--- a/src/security/tpm/tspi/log.c
+++ b/src/security/tpm/tspi/log.c
@@ -16,7 +16,7 @@
#include <security/tpm/tspi.h>
#include <region_file.h>
#include <string.h>
-#include <security/vboot/symbols.h>
+#include <symbols.h>
#include <cbmem.h>
#include <bootstate.h>
#include <vb2_sha.h>
@@ -42,7 +42,7 @@ static struct tcpa_table *tcpa_cbmem_init(void)
return tclt;
}
-static struct tcpa_table *tcpa_log_init(void)
+struct tcpa_table *tcpa_log_init(void)
{
MAYBE_STATIC_BSS struct tcpa_table *tclt = NULL;
@@ -50,12 +50,12 @@ static struct tcpa_table *tcpa_log_init(void)
* If cbmem isn't available use CAR or SRAM */
if (!cbmem_possibly_online() &&
!CONFIG(VBOOT_RETURN_FROM_VERSTAGE))
- return (struct tcpa_table *)_vboot2_tpm_log;
+ return (struct tcpa_table *)_tpm_tcpa_log;
else if (ENV_ROMSTAGE &&
!CONFIG(VBOOT_RETURN_FROM_VERSTAGE)) {
tclt = tcpa_cbmem_init();
if (!tclt)
- return (struct tcpa_table *)_vboot2_tpm_log;
+ return (struct tcpa_table *)_tpm_tcpa_log;
} else {
tclt = tcpa_cbmem_init();
}
@@ -128,7 +128,7 @@ void tcpa_log_add_table_entry(const char *name, const uint32_t pcr,
void tcpa_preram_log_clear(void)
{
printk(BIOS_INFO, "TCPA: Clearing coreboot TCPA log\n");
- struct tcpa_table *tclt = (struct tcpa_table *)_vboot2_tpm_log;
+ struct tcpa_table *tclt = (struct tcpa_table *)_tpm_tcpa_log;
tclt->max_entries = MAX_TCPA_LOG_ENTRIES;
tclt->num_entries = 0;
}
@@ -136,7 +136,7 @@ void tcpa_preram_log_clear(void)
#if !CONFIG(VBOOT_RETURN_FROM_VERSTAGE)
static void recover_tcpa_log(int is_recovery)
{
- struct tcpa_table *preram_log = (struct tcpa_table *)_vboot2_tpm_log;
+ struct tcpa_table *preram_log = (struct tcpa_table *)_tpm_tcpa_log;
struct tcpa_table *ram_log = NULL;
int i;
diff --git a/src/security/tpm/tspi/tspi.c b/src/security/tpm/tspi/tspi.c
index 0095183ca2..4f0cc972a7 100644
--- a/src/security/tpm/tspi/tspi.c
+++ b/src/security/tpm/tspi/tspi.c
@@ -14,13 +14,14 @@
#include <console/cbmem_console.h>
#include <console/console.h>
+#include <security/tpm/tspi/crtm.h>
#include <security/tpm/tspi.h>
#include <security/tpm/tss.h>
-#if CONFIG(VBOOT)
+#include <assert.h>
+#include <security/vboot/misc.h>
+#include <string.h>
#include <vb2_api.h>
#include <vb2_sha.h>
-#include <assert.h>
-#endif
#if CONFIG(TPM1)
static uint32_t tpm1_invoke_state_machine(void)
@@ -100,6 +101,18 @@ static uint32_t tpm_setup_epilogue(uint32_t result)
return result;
}
+static int tpm_is_setup;
+static inline int tspi_tpm_is_setup(void)
+{
+ if (CONFIG(VBOOT))
+ return vboot_logic_executed() || tpm_is_setup;
+
+ if (ENV_RAMSTAGE)
+ return tpm_is_setup;
+
+ return 0;
+}
+
/*
* tpm_setup starts the TPM and establishes the root of trust for the
* anti-rollback mechanism. tpm_setup can fail for three reasons. 1 A bug.
@@ -170,7 +183,10 @@ uint32_t tpm_setup(int s3flag)
#if CONFIG(TPM1)
result = tpm1_invoke_state_machine();
#endif
+ if (CONFIG(TPM_MEASURED_BOOT))
+ result = tspi_measure_cache_to_pcr();
+ tpm_is_setup = 1;
return tpm_setup_epilogue(result);
}
@@ -210,18 +226,27 @@ uint32_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo,
if (!digest)
return TPM_E_IOERROR;
- result = tlcl_extend(pcr, digest, NULL);
- if (result != TPM_SUCCESS)
- return result;
+ if (tspi_tpm_is_setup()) {
+ result = tlcl_lib_init();
+ if (result != TPM_SUCCESS) {
+ printk(BIOS_ERR, "TPM: Can't initialize library.\n");
+ return result;
+ }
+
+ printk(BIOS_DEBUG, "TPM: Extending digest for %s into PCR %d\n", name, pcr);
+ result = tlcl_extend(pcr, digest, NULL);
+ if (result != TPM_SUCCESS)
+ return result;
+ }
- if (CONFIG(VBOOT_MEASURED_BOOT))
+ if (CONFIG(TPM_MEASURED_BOOT))
tcpa_log_add_table_entry(name, pcr, digest_algo,
digest, digest_len);
return TPM_SUCCESS;
}
-#if CONFIG(VBOOT)
+#if CONFIG(VBOOT_LIB)
uint32_t tpm_measure_region(const struct region_device *rdev, uint8_t pcr,
const char *rname)
{
@@ -234,11 +259,7 @@ uint32_t tpm_measure_region(const struct region_device *rdev, uint8_t pcr,
if (!rdev || !rname)
return TPM_E_INVALID_ARG;
- result = tlcl_lib_init();
- if (result != TPM_SUCCESS) {
- printk(BIOS_ERR, "TPM: Can't initialize library.\n");
- return result;
- }
+
if (CONFIG(TPM1)) {
hash_alg = VB2_HASH_SHA1;
} else { /* CONFIG_TPM2 */
@@ -277,7 +298,8 @@ uint32_t tpm_measure_region(const struct region_device *rdev, uint8_t pcr,
printk(BIOS_ERR, "TPM: Extending hash into PCR failed.\n");
return result;
}
- printk(BIOS_DEBUG, "TPM: Measured %s into PCR %d\n", rname, pcr);
+ printk(BIOS_DEBUG, "TPM: Digest of %s to PCR %d %s\n",
+ rname, pcr, tspi_tpm_is_setup() ? "measured" : "logged");
return TPM_SUCCESS;
}
-#endif /* VBOOT */
+#endif /* VBOOT_LIB */