From c07f8fbe6fd13e4245da71574b52b47e9733db84 Mon Sep 17 00:00:00 2001 From: Philipp Deppenwiese Date: Tue, 27 Feb 2018 19:40:52 +0100 Subject: security/tpm: Unify the coreboot TPM software stack * Remove 2nd software stack in pc80 drivers directory. * Create TSPI interface for common usage. * Refactor TSS / TIS code base. * Add vendor tss (Cr50) directory. * Change kconfig options for TPM to TPM1. * Add user / board configuration with: * MAINBOARD_HAS_*_TPM # * BUS driver * MAINBOARD_HAS_TPM1 or MAINBOARD_HAS_TPM2 * Add kconfig TPM user selection (e.g. pluggable TPMs) * Fix existing headers and function calls. * Fix vboot for interface usage and antirollback mode. Change-Id: I7ec277e82a3c20c62a0548a1a2b013e6ce8f5b3f Signed-off-by: Philipp Deppenwiese Reviewed-on: https://review.coreboot.org/24903 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- src/security/tpm/tspi/tspi.c | 190 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 src/security/tpm/tspi/tspi.c (limited to 'src/security/tpm/tspi') diff --git a/src/security/tpm/tspi/tspi.c b/src/security/tpm/tspi/tspi.c new file mode 100644 index 0000000000..407e1fa1e0 --- /dev/null +++ b/src/security/tpm/tspi/tspi.c @@ -0,0 +1,190 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Copyright 2017 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 +#include +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_TPM1) +static uint32_t tpm1_invoke_state_machine(void) +{ + uint8_t disable; + uint8_t deactivated; + uint32_t result = TPM_SUCCESS; + + /* Check that the TPM is enabled and activated. */ + result = tlcl_get_flags(&disable, &deactivated, NULL); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Can't read capabilities.\n"); + return result; + } + + if (!!deactivated != IS_ENABLED(CONFIG_TPM_DEACTIVATE)) { + printk(BIOS_INFO, + "TPM: Unexpected TPM deactivated state. Toggling...\n"); + result = tlcl_set_deactivated(!deactivated); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, + "TPM: Can't toggle deactivated state.\n"); + return result; + } + + deactivated = !deactivated; + result = TPM_E_MUST_REBOOT; + } + + if (disable && !deactivated) { + printk(BIOS_INFO, "TPM: disabled (%d). Enabling...\n", disable); + + result = tlcl_set_enable(); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Can't set enabled state.\n"); + return result; + } + + printk(BIOS_INFO, "TPM: Must reboot to re-enable\n"); + result = TPM_E_MUST_REBOOT; + } + + return result; +} +#endif + +/* + * tpm_setup starts the TPM and establishes the root of trust for the + * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a + * TPM hardware failure. 3 An unexpected TPM state due to some attack. In + * general we cannot easily distinguish the kind of failure, so our strategy is + * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM + * again, which executes (almost) the same sequence of operations. There is a + * good chance that, if recovery mode was entered because of a TPM failure, the + * failure will repeat itself. (In general this is impossible to guarantee + * because we have no way of creating the exact TPM initial state at the + * previous boot.) In recovery mode, we ignore the failure and continue, thus + * giving the recovery kernel a chance to fix things (that's why we don't set + * bGlobalLock). The choice is between a knowingly insecure device and a + * bricked device. + * + * As a side note, observe that we go through considerable hoops to avoid using + * the STCLEAR permissions for the index spaces. We do this to avoid writing + * to the TPM flashram at every reboot or wake-up, because of concerns about + * the durability of the NVRAM. + */ +uint32_t tpm_setup(int s3flag) +{ + uint32_t result; + + result = tlcl_lib_init(); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Can't initialize.\n"); + goto out; + } + + /* Handle special init for S3 resume path */ + if (s3flag) { + result = tlcl_resume(); + if (result == TPM_E_INVALID_POSTINIT) + printk(BIOS_INFO, "TPM: Already initialized.\n"); + + return TPM_SUCCESS; + } + + result = tlcl_startup(); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Can't run startup command.\n"); + goto out; + } + + result = tlcl_assert_physical_presence(); + if (result != TPM_SUCCESS) { + /* + * It is possible that the TPM was delivered with the physical + * presence command disabled. This tries enabling it, then + * tries asserting PP again. + */ + result = tlcl_physical_presence_cmd_enable(); + if (result != TPM_SUCCESS) { + printk( + BIOS_ERR, + "TPM: Can't enable physical presence command.\n"); + goto out; + } + + result = tlcl_assert_physical_presence(); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, + "TPM: Can't assert physical presence.\n"); + goto out; + } + } + +#if IS_ENABLED(CONFIG_TPM1) + result = tpm1_invoke_state_machine(); + if (result != TPM_SUCCESS) + return result; +#endif + +out: + if (result != TPM_SUCCESS) + post_code(POST_TPM_FAILURE); + else + printk(BIOS_INFO, "TPM: setup succeeded\n"); + + return result; +} + +uint32_t tpm_clear_and_reenable(void) +{ + uint32_t result; + + printk(BIOS_INFO, "TPM: Clear and re-enable\n"); + result = tlcl_force_clear(); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Can't initiate a force clear.\n"); + return result; + } + +#if IS_ENABLED(CONFIG_TPM1) + result = tlcl_set_enable(); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Can't set enabled state.\n"); + return result; + } + + result = tlcl_set_deactivated(0); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Can't set deactivated state.\n"); + return result; + } +#endif + + return TPM_SUCCESS; +} + +uint32_t tpm_extend_pcr(int pcr, uint8_t *digest, uint8_t *out_digest) +{ + if (!digest) + return TPM_E_IOERROR; + + if (out_digest) + return tlcl_extend(pcr, digest, out_digest); + + return tlcl_extend(pcr, digest, NULL); +} -- cgit v1.2.3