This series of patches adds TPM 2 support to SeaBIOS in the way previously proposed.
v2->v3: - Converted TPM_VERSION_* from enum's to #define's and removed unnecessary cases with TPM_VERSION_NONE in switch statements. - Convert the log_entry internal representation to TPM 2 native format. - Added patch that looks at command tags in the TPM_Passthrough API call and return error code in case of TPM version mismatch.
v1->v2: - Addressed most of Kevin's comments. - Added patch for writing logs in TPM 2 format
Stefan
Stefan Berger (11): tpm: Extend TPM TIS with TPM 2 support. tpm: Factor out tpm_extend tpm: Prepare code for TPM 2 functions tpm: Implement tpm20_startup and tpm20_s3_resume tpm: Implement tpm20_set_timeouts tpm: Implement tpm20_prepboot tpm: Implement tpm20_extend tpm: Implement tpm20_menu tpm: Implement TPM 2's tpm_set_failure part tpm: Write logs in TPM 2 format Filter TPM commands in passthrough API
src/hw/tpm_drivers.c | 38 ++- src/hw/tpm_drivers.h | 26 +- src/std/tcg.h | 147 +++++++++ src/tcgbios.c | 900 ++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 961 insertions(+), 150 deletions(-)
From: Stefan Berger stefanb@linux.vnet.ibm.com
Extend the probing of the interface with TPM 2 specifics.
Use the new interface ID register of the TIS to check whether a TPM 1.2 or a TPM 2 is underneath.
We select the TIS if possible and lock it so we can issue commands during S3 for example and prevent the OS from changing to CRB type of interface.
The register is described in table 13 here:
http://www.trustedcomputinggroup.org/resources/pc_client_platform_tpm_profil...
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/hw/tpm_drivers.c | 38 ++++++++++++++++++++++++++++++++++---- src/hw/tpm_drivers.h | 9 ++++++++- src/tcgbios.c | 12 +++++++++--- 3 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c index 08fd101..a137e62 100644 --- a/src/hw/tpm_drivers.c +++ b/src/hw/tpm_drivers.c @@ -23,6 +23,7 @@ struct tpm_driver { u32 *durations; void (*set_timeouts)(u32 timeouts[4], u32 durations[3]); u32 (*probe)(void); + TPMVersion (*get_tpm_version)(void); u32 (*init)(void); u32 (*activate)(u8 locty); u32 (*ready)(void); @@ -56,7 +57,6 @@ static const u32 tpm_default_durations[3] = { static u32 tpm_default_dur[3]; static u32 tpm_default_to[4];
- /* if device is not there, return '0', '1' otherwise */ static u32 tis_probe(void) { @@ -69,9 +69,39 @@ static u32 tis_probe(void) if ((didvid != 0) && (didvid != 0xffffffff)) rc = 1;
+ /* TPM 2 has an interface register */ + u32 ifaceid = readl(TIS_REG(0, TIS_REG_IFACE_ID)); + + if ((ifaceid & 0xf) != 0xf) { + if ((ifaceid & 0xf) == 1) { + /* CRB is active; no TIS */ + return 0; + } + if ((ifaceid & (1 << 13)) == 0) { + /* TIS cannot be selected */ + return 0; + } + /* write of 0 to bits 17-18 selects TIS */ + writel(TIS_REG(0, TIS_REG_IFACE_ID), 0); + /* since we only support TIS, we lock it */ + writel(TIS_REG(0, TIS_REG_IFACE_ID), (1 << 19)); + } + return rc; }
+static TPMVersion tis_get_tpm_version(void) +{ + /* TPM 2 has an interface register */ + u32 ifaceid = readl(TIS_REG(0, TIS_REG_IFACE_ID)); + + if ((ifaceid & 0xf) == 0) { + /* TPM 2 */ + return TPM_VERSION_2; + } + return TPM_VERSION_1_2; +} + static u32 tis_init(void) { if (!CONFIG_TCGBIOS) @@ -323,7 +353,7 @@ struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
static u8 TPMHW_driver_to_use = TPM_INVALID_DRIVER;
-int +TPMVersion tpmhw_probe(void) { unsigned int i; @@ -332,10 +362,10 @@ tpmhw_probe(void) if (td->probe() != 0) { td->init(); TPMHW_driver_to_use = i; - return 0; + return tis_get_tpm_version(); } } - return -1; + return TPM_VERSION_NONE; }
int diff --git a/src/hw/tpm_drivers.h b/src/hw/tpm_drivers.h index 15a60af..52c7a15 100644 --- a/src/hw/tpm_drivers.h +++ b/src/hw/tpm_drivers.h @@ -10,7 +10,13 @@ enum tpmDurationType { TPM_DURATION_TYPE_LONG, };
-int tpmhw_probe(void); +typedef u8 TPMVersion; + +#define TPM_VERSION_NONE 0 +#define TPM_VERSION_1_2 1 +#define TPM_VERSION_2 2 + +TPMVersion tpmhw_probe(void); int tpmhw_is_present(void); struct tpm_req_header; int tpmhw_transmit(u8 locty, struct tpm_req_header *req, @@ -33,6 +39,7 @@ void tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]); #define TIS_REG_INTF_CAPABILITY 0x14 #define TIS_REG_STS 0x18 #define TIS_REG_DATA_FIFO 0x24 +#define TIS_REG_IFACE_ID 0x30 #define TIS_REG_DID_VID 0xf00 #define TIS_REG_RID 0xf04
diff --git a/src/tcgbios.c b/src/tcgbios.c index 7077426..0559083 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -62,6 +62,8 @@ struct {
static int TPM_has_physical_presence;
+static TPMVersion TPM_version; + static struct tcpa_descriptor_rev2 * find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp) { @@ -498,11 +500,15 @@ tpm_setup(void) if (!CONFIG_TCGBIOS) return;
- int ret = tpmhw_probe(); - if (ret) + TPM_version = tpmhw_probe(); + if (TPM_version == TPM_VERSION_NONE) return;
- ret = tpm_tcpa_probe(); + dprintf(DEBUG_tcg, + "TCGBIOS: Detected a TPM %s.\n", + (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2"); + + int ret = tpm_tcpa_probe(); if (ret) return;
From: Stefan Berger stefanb@linux.vnet.ibm.com
In preparation for TPM 2 code support, factor out the TPM 1.2 specific code from tpm_log_extend_event and put it into tpm_extend().
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/tcgbios.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/tcgbios.c b/src/tcgbios.c index 0559083..799a8bf 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -287,18 +287,18 @@ determine_timeouts(void) }
static int -tpm_log_extend_event(struct pcpes *pcpes, const void *event) +tpm_extend(u32 pcrindex, const u8 *digest) { - if (pcpes->pcrindex >= 24) + if (pcrindex >= 24) return -1;
struct tpm_req_extend tre = { .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD), .hdr.totlen = cpu_to_be32(sizeof(tre)), .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend), - .pcrindex = cpu_to_be32(pcpes->pcrindex), + .pcrindex = cpu_to_be32(pcrindex), }; - memcpy(tre.digest, pcpes->digest, sizeof(tre.digest)); + memcpy(tre.digest, digest, sizeof(tre.digest));
struct tpm_rsp_extend rsp; u32 resp_length = sizeof(rsp); @@ -307,6 +307,16 @@ tpm_log_extend_event(struct pcpes *pcpes, const void *event) if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode) return -1;
+ return 0; +} + +static int +tpm_log_extend_event(struct pcpes *pcpes, const void *event) +{ + int ret = tpm_extend(pcpes->pcrindex, pcpes->digest); + if (ret) + return -1; + return tpm_log_event(pcpes, event); }
From: Stefan Berger stefanb@linux.vnet.ibm.com
This patch prepares the tcgbios.c file for extension with TPM 2 specific code by:
o prefixing all TPM 1.2 specific functions with tpm12_ o where necessary, introduce switch statements in tpm_ - prefixed functions; here we branch into TPM versions specific code o introduce tpm_ - prefixed functions where necessary; mostly in those cases where tpm12_ functions are too large and where the tpm_ function then only holds the switch statement o leave FIXMEs where we need to write TPM 2 specific code; subsequent patches will replace those FIXMEs
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/tcgbios.c | 297 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 185 insertions(+), 112 deletions(-)
diff --git a/src/tcgbios.c b/src/tcgbios.c index 799a8bf..6be1966 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -171,7 +171,13 @@ tpm_is_working(void) int tpm_can_show_menu(void) { - return tpm_is_working() && TPM_has_physical_presence; + switch (TPM_version) { + case TPM_VERSION_1_2: + return tpm_is_working() && TPM_has_physical_presence; + case TPM_VERSION_2: + return tpm_is_working(); + } + return 0; }
/* @@ -180,8 +186,8 @@ tpm_can_show_menu(void) * the custom part per command) and expect a response of the given size. */ static int -build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size, - enum tpmDurationType to_t) +tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, + u32 append_size, enum tpmDurationType to_t) { struct { struct tpm_req_header trqh; @@ -213,19 +219,26 @@ build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size, static void tpm_set_failure(void) { - /* - * We will try to deactivate the TPM now - ignoring all errors - * Physical presence is asserted. - */ + switch (TPM_version) { + case TPM_VERSION_1_2: + /* + * We will try to deactivate the TPM now - ignoring all errors + * Physical presence is asserted. + */
- build_and_send_cmd(0, TPM_ORD_SetTempDeactivated, - NULL, 0, TPM_DURATION_TYPE_SHORT); + tpm_build_and_send_cmd(0, TPM_ORD_SetTempDeactivated, + NULL, 0, TPM_DURATION_TYPE_SHORT); + break; + case TPM_VERSION_2: + // FIXME: missing code + break; + }
TPM_working = 0; }
static int -tpm_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize) +tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize) { struct tpm_req_getcap trgc = { .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD), @@ -249,17 +262,17 @@ tpm_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize) }
static int -determine_timeouts(void) +tpm12_determine_timeouts(void) { struct tpm_res_getcap_timeouts timeouts; - int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT - , &timeouts.hdr, sizeof(timeouts)); + int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT + , &timeouts.hdr, sizeof(timeouts)); if (ret) return ret;
struct tpm_res_getcap_durations durations; - ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION - , &durations.hdr, sizeof(durations)); + ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION + , &durations.hdr, sizeof(durations)); if (ret) return ret;
@@ -287,11 +300,8 @@ determine_timeouts(void) }
static int -tpm_extend(u32 pcrindex, const u8 *digest) +tpm12_extend(u32 pcrindex, const u8 *digest) { - if (pcrindex >= 24) - return -1; - struct tpm_req_extend tre = { .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD), .hdr.totlen = cpu_to_be32(sizeof(tre)), @@ -311,6 +321,22 @@ tpm_extend(u32 pcrindex, const u8 *digest) }
static int +tpm_extend(u32 pcrindex, const u8 *digest) +{ + if (pcrindex >= 24) + return -1; + + switch (TPM_version) { + case TPM_VERSION_1_2: + return tpm12_extend(pcrindex, digest); + case TPM_VERSION_2: + // FIXME: missing code + return -1; + } + return -1; +} + +static int tpm_log_extend_event(struct pcpes *pcpes, const void *event) { int ret = tpm_extend(pcpes->pcrindex, pcpes->digest); @@ -410,13 +436,13 @@ tpm_smbios_measure(void) }
static int -read_permanent_flags(char *buf, int buf_len) +tpm12_read_permanent_flags(char *buf, int buf_len) { memset(buf, 0, buf_len);
struct tpm_res_getcap_perm_flags pf; - int ret = tpm_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT - , &pf.hdr, sizeof(pf)); + int ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT + , &pf.hdr, sizeof(pf)); if (ret) return -1;
@@ -426,17 +452,17 @@ read_permanent_flags(char *buf, int buf_len) }
static int -assert_physical_presence(void) +tpm12_assert_physical_presence(void) { - int ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence, - PhysicalPresence_PRESENT, - sizeof(PhysicalPresence_PRESENT), - TPM_DURATION_TYPE_SHORT); + int ret = tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_PRESENT, + sizeof(PhysicalPresence_PRESENT), + TPM_DURATION_TYPE_SHORT); if (!ret) return 0;
struct tpm_permanent_flags pf; - ret = read_permanent_flags((char *)&pf, sizeof(pf)); + ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf)); if (ret) return -1;
@@ -448,26 +474,27 @@ assert_physical_presence(void)
if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK] && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) { - build_and_send_cmd(0, TPM_ORD_PhysicalPresence, - PhysicalPresence_CMD_ENABLE, - sizeof(PhysicalPresence_CMD_ENABLE), - TPM_DURATION_TYPE_SHORT); - - return build_and_send_cmd(0, TPM_ORD_PhysicalPresence, - PhysicalPresence_PRESENT, - sizeof(PhysicalPresence_PRESENT), - TPM_DURATION_TYPE_SHORT); + tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_CMD_ENABLE, + sizeof(PhysicalPresence_CMD_ENABLE), + TPM_DURATION_TYPE_SHORT); + + return tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_PRESENT, + sizeof(PhysicalPresence_PRESENT), + TPM_DURATION_TYPE_SHORT); } return -1; }
static int -tpm_startup(void) +tpm12_startup(void) { dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n"); - int ret = build_and_send_cmd(0, TPM_ORD_Startup, - Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR), - TPM_DURATION_TYPE_SHORT); + int ret = tpm_build_and_send_cmd(0, TPM_ORD_Startup, + Startup_ST_CLEAR, + sizeof(Startup_ST_CLEAR), + TPM_DURATION_TYPE_SHORT); if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT) /* with other firmware on the system the TPM may already have been * initialized @@ -477,21 +504,21 @@ tpm_startup(void) goto err_exit;
/* assertion of physical presence is only possible after startup */ - ret = assert_physical_presence(); + ret = tpm12_assert_physical_presence(); if (!ret) TPM_has_physical_presence = 1;
- ret = determine_timeouts(); + ret = tpm12_determine_timeouts(); if (ret) return -1;
- ret = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0, - TPM_DURATION_TYPE_LONG); + ret = tpm_build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0, + TPM_DURATION_TYPE_LONG); if (ret) goto err_exit;
- ret = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0, - TPM_DURATION_TYPE_SHORT); + ret = tpm_build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0, + TPM_DURATION_TYPE_SHORT); if (ret && ret != TPM_BAD_LOCALITY) goto err_exit;
@@ -504,6 +531,19 @@ err_exit: return -1; }
+static int +tpm_startup(void) +{ + switch (TPM_version) { + case TPM_VERSION_1_2: + return tpm12_startup(); + case TPM_VERSION_2: + // FIXME: missing code + return -1; + } + return -1; +} + void tpm_setup(void) { @@ -541,11 +581,18 @@ tpm_prepboot(void) if (!CONFIG_TCGBIOS) return;
- if (TPM_has_physical_presence) - build_and_send_cmd(0, TPM_ORD_PhysicalPresence, - PhysicalPresence_NOT_PRESENT_LOCK, - sizeof(PhysicalPresence_NOT_PRESENT_LOCK), - TPM_DURATION_TYPE_SHORT); + switch (TPM_version) { + case TPM_VERSION_1_2: + if (TPM_has_physical_presence) + tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_NOT_PRESENT_LOCK, + sizeof(PhysicalPresence_NOT_PRESENT_LOCK), + TPM_DURATION_TYPE_SHORT); + break; + case TPM_VERSION_2: + // FIXME: missing code + break; + }
tpm_add_action(4, "Calling INT 19h"); tpm_add_event_separators(); @@ -637,9 +684,21 @@ tpm_s3_resume(void)
dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
- int ret = build_and_send_cmd(0, TPM_ORD_Startup, - Startup_ST_STATE, sizeof(Startup_ST_STATE), - TPM_DURATION_TYPE_SHORT); + int ret = -1; + + switch (TPM_version) { + case TPM_VERSION_1_2: + ret = tpm_build_and_send_cmd(0, TPM_ORD_Startup, + Startup_ST_STATE, + sizeof(Startup_ST_STATE), + TPM_DURATION_TYPE_SHORT); + break; + case TPM_VERSION_2: + // FIXME: missing code + ret = -1; + break; + } + if (ret) goto err_exit;
@@ -941,11 +1000,11 @@ tpm_interrupt_handler32(struct bregs *regs) ****************************************************************/
static int -read_has_owner(int *has_owner) +tpm12_read_has_owner(int *has_owner) { struct tpm_res_getcap_ownerauth oauth; - int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER - , &oauth.hdr, sizeof(oauth)); + int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER + , &oauth.hdr, sizeof(oauth)); if (ret) return -1;
@@ -955,19 +1014,19 @@ read_has_owner(int *has_owner) }
static int -enable_tpm(int enable, int verbose) +tpm12_enable_tpm(int enable, int verbose) { struct tpm_permanent_flags pf; - int ret = read_permanent_flags((char *)&pf, sizeof(pf)); + int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf)); if (ret) return -1;
if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable) return 0;
- ret = build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable - : TPM_ORD_PhysicalDisable, - NULL, 0, TPM_DURATION_TYPE_SHORT); + ret = tpm_build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable + : TPM_ORD_PhysicalDisable, + NULL, 0, TPM_DURATION_TYPE_SHORT); if (ret) { if (enable) dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n"); @@ -978,10 +1037,10 @@ enable_tpm(int enable, int verbose) }
static int -activate_tpm(int activate, int allow_reset, int verbose) +tpm12_activate_tpm(int activate, int allow_reset, int verbose) { struct tpm_permanent_flags pf; - int ret = read_permanent_flags((char *)&pf, sizeof(pf)); + int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf)); if (ret) return -1;
@@ -991,12 +1050,12 @@ activate_tpm(int activate, int allow_reset, int verbose) if (pf.flags[PERM_FLAG_IDX_DISABLE]) return 0;
- ret = build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated, - activate ? CommandFlag_FALSE - : CommandFlag_TRUE, - activate ? sizeof(CommandFlag_FALSE) - : sizeof(CommandFlag_TRUE), - TPM_DURATION_TYPE_SHORT); + ret = tpm_build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated, + activate ? CommandFlag_FALSE + : CommandFlag_TRUE, + activate ? sizeof(CommandFlag_FALSE) + : sizeof(CommandFlag_TRUE), + TPM_DURATION_TYPE_SHORT); if (ret) return ret;
@@ -1013,20 +1072,21 @@ activate_tpm(int activate, int allow_reset, int verbose) }
static int -enable_activate(int allow_reset, int verbose) +tpm12_enable_activate(int allow_reset, int verbose) { - int ret = enable_tpm(1, verbose); + int ret = tpm12_enable_tpm(1, verbose); if (ret) return ret;
- return activate_tpm(1, allow_reset, verbose); + return tpm12_activate_tpm(1, allow_reset, verbose); }
static int -force_clear(int enable_activate_before, int enable_activate_after, int verbose) +tpm12_force_clear(int enable_activate_before, int enable_activate_after, + int verbose) { int has_owner; - int ret = read_has_owner(&has_owner); + int ret = tpm12_read_has_owner(&has_owner); if (ret) return -1; if (!has_owner) { @@ -1036,7 +1096,7 @@ force_clear(int enable_activate_before, int enable_activate_after, int verbose) }
if (enable_activate_before) { - ret = enable_activate(0, verbose); + ret = tpm12_enable_activate(0, verbose); if (ret) { dprintf(DEBUG_tcg, "TCGBIOS: Enabling/activating the TPM failed.\n"); @@ -1044,8 +1104,8 @@ force_clear(int enable_activate_before, int enable_activate_after, int verbose) } }
- ret = build_and_send_cmd(0, TPM_ORD_ForceClear, - NULL, 0, TPM_DURATION_TYPE_SHORT); + ret = tpm_build_and_send_cmd(0, TPM_ORD_ForceClear, + NULL, 0, TPM_DURATION_TYPE_SHORT); if (ret) return ret;
@@ -1056,14 +1116,14 @@ force_clear(int enable_activate_before, int enable_activate_after, int verbose) return 0; }
- return enable_activate(1, verbose); + return tpm12_enable_activate(1, verbose); }
static int -set_owner_install(int allow, int verbose) +tpm12_set_owner_install(int allow, int verbose) { int has_owner; - int ret = read_has_owner(&has_owner); + int ret = tpm12_read_has_owner(&has_owner); if (ret) return -1; if (has_owner) { @@ -1073,7 +1133,7 @@ set_owner_install(int allow, int verbose) }
struct tpm_permanent_flags pf; - ret = read_permanent_flags((char *)&pf, sizeof(pf)); + ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf)); if (ret) return -1;
@@ -1083,11 +1143,11 @@ set_owner_install(int allow, int verbose) return 0; }
- ret = build_and_send_cmd(0, TPM_ORD_SetOwnerInstall, - (allow) ? CommandFlag_TRUE - : CommandFlag_FALSE, - sizeof(CommandFlag_TRUE), - TPM_DURATION_TYPE_SHORT); + ret = tpm_build_and_send_cmd(0, TPM_ORD_SetOwnerInstall, + (allow) ? CommandFlag_TRUE + : CommandFlag_FALSE, + sizeof(CommandFlag_TRUE), + TPM_DURATION_TYPE_SHORT); if (ret) return ret;
@@ -1098,7 +1158,7 @@ set_owner_install(int allow, int verbose) }
static int -tpm_process_cfg(tpm_ppi_code msgCode, int verbose) +tpm12_process_cfg(tpm_ppi_code msgCode, int verbose) { int ret = 0;
@@ -1107,31 +1167,31 @@ tpm_process_cfg(tpm_ppi_code msgCode, int verbose) break;
case TPM_PPI_OP_ENABLE: - ret = enable_tpm(1, verbose); + ret = tpm12_enable_tpm(1, verbose); break;
case TPM_PPI_OP_DISABLE: - ret = enable_tpm(0, verbose); + ret = tpm12_enable_tpm(0, verbose); break;
case TPM_PPI_OP_ACTIVATE: - ret = activate_tpm(1, 1, verbose); + ret = tpm12_activate_tpm(1, 1, verbose); break;
case TPM_PPI_OP_DEACTIVATE: - ret = activate_tpm(0, 1, verbose); + ret = tpm12_activate_tpm(0, 1, verbose); break;
case TPM_PPI_OP_CLEAR: - ret = force_clear(1, 0, verbose); + ret = tpm12_force_clear(1, 0, verbose); break;
case TPM_PPI_OP_SET_OWNERINSTALL_TRUE: - ret = set_owner_install(1, verbose); + ret = tpm12_set_owner_install(1, verbose); break;
case TPM_PPI_OP_SET_OWNERINSTALL_FALSE: - ret = set_owner_install(0, verbose); + ret = tpm12_set_owner_install(0, verbose); break;
default: @@ -1145,14 +1205,14 @@ tpm_process_cfg(tpm_ppi_code msgCode, int verbose) }
static int -get_tpm_state(void) +tpm12_get_tpm_state(void) { int state = 0; struct tpm_permanent_flags pf; int has_owner;
- if (read_permanent_flags((char *)&pf, sizeof(pf)) || - read_has_owner(&has_owner)) + if (tpm12_read_permanent_flags((char *)&pf, sizeof(pf)) || + tpm12_read_has_owner(&has_owner)) return ~0;
if (!pf.flags[PERM_FLAG_IDX_DISABLE]) @@ -1172,7 +1232,7 @@ get_tpm_state(void) }
static void -show_tpm_menu(int state, int next_scancodes[7]) +tpm12_show_tpm_menu(int state, int next_scancodes[7]) { int i = 0;
@@ -1238,28 +1298,21 @@ show_tpm_menu(int state, int next_scancodes[7]) next_scancodes[i++] = 0; }
-void -tpm_menu(void) +static void +tpm12_menu(void) { - if (!CONFIG_TCGBIOS) - return; - int scancode, next_scancodes[7]; tpm_ppi_code msgCode; int state = 0, i; int waitkey;
- while (get_keystroke(0) >= 0) - ; - wait_threads(); - printf("The Trusted Platform Module (TPM) is a hardware device in " "this machine.\n" "It can help verify the integrity of system software.\n\n");
for (;;) { - if ((state = get_tpm_state()) != ~0) { - show_tpm_menu(state, next_scancodes); + if ((state = tpm12_get_tpm_state()) != ~0) { + tpm12_show_tpm_menu(state, next_scancodes); } else { printf("TPM is not working correctly.\n"); return; @@ -1316,7 +1369,7 @@ tpm_menu(void) break;
if (next_scancodes[i] == scancode) { - tpm_process_cfg(msgCode, 1); + tpm12_process_cfg(msgCode, 1); waitkey = 0; break; } @@ -1324,3 +1377,23 @@ tpm_menu(void) } } } + +void +tpm_menu(void) +{ + if (!CONFIG_TCGBIOS) + return; + + while (get_keystroke(0) >= 0) + ; + wait_threads(); + + switch (TPM_version) { + case TPM_VERSION_1_2: + tpm12_menu(); + break; + case TPM_VERSION_2: + // FIXME: missing code + break; + } +}
From: Stefan Berger stefanb@linux.vnet.ibm.com
Implement tpm20_startup and tpm20_s3_resume and their dependencies.
We follow this specification:
TCG PC Client Specific Platform Firmware Profile for TPM 2.0 Systems Revision 1.0 Version 21
It can be found on this page:
http://www.trustedcomputinggroup.org/resources/specifications_in_public_revi...
Power on: Figure 7 & 7.3.2 item 4. S3: Figure 9 & 7.3.2 item 4.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 20 +++++++++++++ src/tcgbios.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 6 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index 91692e9..db1155d 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -362,4 +362,24 @@ struct tpm_res_sha1complete { #define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8 #define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9
+/* + * TPM 2 + */ + +#define TPM2_NO 0 +#define TPM2_YES 1 + +#define TPM2_SU_CLEAR 0x0000 +#define TPM2_SU_STATE 0x0001 + +/* TPM 2 command tags */ +#define TPM2_ST_NO_SESSIONS 0x8001 + +/* TPM 2 commands */ +#define TPM2_CC_SelfTest 0x143 +#define TPM2_CC_Startup 0x144 + +/* TPM 2 error codes */ +#define TPM2_RC_INITIALIZE 0x100 + #endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index 6be1966..0b40a8f 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -25,6 +25,10 @@ #include "util.h" // printf, get_keystroke #include "stacks.h" // wait_threads, reset
+/**************************************************************** + * TPM 1.2 commands + ****************************************************************/ + static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR }; static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
@@ -36,8 +40,17 @@ static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 }; static const u8 CommandFlag_FALSE[1] = { 0x00 }; static const u8 CommandFlag_TRUE[1] = { 0x01 };
-typedef u8 tpm_ppi_code; +/**************************************************************** + * TPM 2 commands + ****************************************************************/ + +static const u8 Startup_SU_CLEAR[] = { 0x00, TPM2_SU_CLEAR}; +static const u8 Startup_SU_STATE[] = { 0x00, TPM2_SU_STATE};
+static const u8 TPM2_SelfTest_YES[] = { TPM2_YES }; /* full test */ + + +typedef u8 tpm_ppi_code;
/**************************************************************** * ACPI TCPA table interface @@ -191,12 +204,22 @@ tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, { struct { struct tpm_req_header trqh; - u8 cmd[2]; + u8 cmd[6]; } PACKED req = { .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD), .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size), .trqh.ordinal = cpu_to_be32(ordinal), }; + + switch (TPM_version) { + case TPM_VERSION_1_2: + req.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD); + break; + case TPM_VERSION_2: + req.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); + break; + } + u8 obuffer[64]; struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer; u32 obuffer_len = sizeof(obuffer); @@ -532,14 +555,53 @@ err_exit: }
static int +tpm20_startup(void) +{ + int ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup, + Startup_SU_CLEAR, + sizeof(Startup_SU_CLEAR), + TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n", + ret); + + if (CONFIG_COREBOOT && ret == TPM2_RC_INITIALIZE) + /* with other firmware on the system the TPM may already have been + * initialized + */ + ret = 0; + + if (ret) + goto err_exit; + + ret = tpm_build_and_send_cmd(0, TPM2_CC_SelfTest, + TPM2_SelfTest_YES, + sizeof(TPM2_SelfTest_YES), + TPM_DURATION_TYPE_LONG); + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest = 0x%08x\n", + ret); + + if (ret) + goto err_exit; + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + return -1; +} + +static int tpm_startup(void) { switch (TPM_version) { case TPM_VERSION_1_2: return tpm12_startup(); case TPM_VERSION_2: - // FIXME: missing code - return -1; + return tpm20_startup(); } return -1; } @@ -694,8 +756,25 @@ tpm_s3_resume(void) TPM_DURATION_TYPE_SHORT); break; case TPM_VERSION_2: - // FIXME: missing code - ret = -1; + ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup, + Startup_SU_STATE, + sizeof(Startup_SU_STATE), + TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_STATE) = 0x%08x\n", + ret); + + if (ret) + goto err_exit; + + + ret = tpm_build_and_send_cmd(0, TPM2_CC_SelfTest, + TPM2_SelfTest_YES, sizeof(TPM2_SelfTest_YES), + TPM_DURATION_TYPE_LONG); + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest() = 0x%08x\n", + ret); + break; }
From: Stefan Berger stefanb@linux.vnet.ibm.com
The TIS timeouts for TPM 2 are different than for TPM 1.2. Also the timeouts indicating a failed TPM 2 command are different. Further, the command durations and timeouts cannot be read from the device.
We take the command timeout values for short, medium, and long running commands from table 15 of the following specification:
TCG PC Client Platform TPM Profile (PTP) Specification
http://www.trustedcomputinggroup.org/resources/pc_client_platform_tpm_profil...
The values should work for all physical TPMs.
The tricky thing with virtualized environments is that the values may need to be longer for a system where a vTPM cannot get sufficient cycles. So a future patch _may_ need to multiply those values here with some factor.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/hw/tpm_drivers.h | 17 +++++++++++++++++ src/tcgbios.c | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+)
diff --git a/src/hw/tpm_drivers.h b/src/hw/tpm_drivers.h index 52c7a15..56fd9e8 100644 --- a/src/hw/tpm_drivers.h +++ b/src/hw/tpm_drivers.h @@ -66,6 +66,14 @@ void tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]); #define TIS_DEFAULT_TIMEOUT_C 750000 /* us */ #define TIS_DEFAULT_TIMEOUT_D 750000 /* us */
+/* + * Default TIS 2 timeouts given in TPM Profile (TPT) Spec + */ +#define TIS2_DEFAULT_TIMEOUT_A 750000 /* us */ +#define TIS2_DEFAULT_TIMEOUT_B 2000000 /* us */ +#define TIS2_DEFAULT_TIMEOUT_C 200000 /* us */ +#define TIS2_DEFAULT_TIMEOUT_D 30000 /* us */ + enum tisTimeoutType { TIS_TIMEOUT_TYPE_A = 0, TIS_TIMEOUT_TYPE_B, @@ -81,4 +89,13 @@ enum tisTimeoutType { #define TPM_DEFAULT_DURATION_MEDIUM 20000000 /* us */ #define TPM_DEFAULT_DURATION_LONG 60000000 /* us */
+/* + * TPM 2 command durations; we set them to the timeout values + * given in TPM Profile (PTP) Specification; exceeding those + * timeout values indicates a faulty TPM. + */ +#define TPM2_DEFAULT_DURATION_SHORT 750000 /* us */ +#define TPM2_DEFAULT_DURATION_MEDIUM 2000000 /* us */ +#define TPM2_DEFAULT_DURATION_LONG 2000000 /* us */ + #endif /* TPM_DRIVERS_H */ diff --git a/src/tcgbios.c b/src/tcgbios.c index 0b40a8f..463b7bb 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -322,6 +322,24 @@ tpm12_determine_timeouts(void) return 0; }
+static void +tpm20_set_timeouts(void) +{ + u32 durations[3] = { + TPM2_DEFAULT_DURATION_SHORT, + TPM2_DEFAULT_DURATION_MEDIUM, + TPM2_DEFAULT_DURATION_LONG, + }; + u32 timeouts[4] = { + TIS2_DEFAULT_TIMEOUT_A, + TIS2_DEFAULT_TIMEOUT_B, + TIS2_DEFAULT_TIMEOUT_C, + TIS2_DEFAULT_TIMEOUT_D, + }; + + tpmhw_set_timeouts(timeouts, durations); +} + static int tpm12_extend(u32 pcrindex, const u8 *digest) { @@ -557,6 +575,8 @@ err_exit: static int tpm20_startup(void) { + tpm20_set_timeouts(); + int ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup, Startup_SU_CLEAR, sizeof(Startup_SU_CLEAR),
From: Stefan Berger stefanb@linux.vnet.ibm.com
Implement tpm20_preboot.
Here we set the platform password to a random password that prevents higher layers (OS) to get this password. This avoids bad things like users clearing the TPM, erasing EK (primary key) certificates, changing the primary key etc.
The clearing of the TPM will still be possible through the TPM 2 menu.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 44 +++++++++++++++++++++++ src/tcgbios.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 153 insertions(+), 2 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index db1155d..e0d6f30 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -372,14 +372,58 @@ struct tpm_res_sha1complete { #define TPM2_SU_CLEAR 0x0000 #define TPM2_SU_STATE 0x0001
+#define TPM2_RS_PW 0x40000009 +#define TPM2_RH_PLATFORM 0x4000000c + /* TPM 2 command tags */ #define TPM2_ST_NO_SESSIONS 0x8001 +#define TPM2_ST_SESSIONS 0x8002
/* TPM 2 commands */ +#define TPM2_CC_HierarchyChangeAuth 0x129 #define TPM2_CC_SelfTest 0x143 #define TPM2_CC_Startup 0x144 +#define TPM2_CC_StirRandom 0x146 +#define TPM2_CC_GetRandom 0x17b
/* TPM 2 error codes */ #define TPM2_RC_INITIALIZE 0x100
+/* TPM 2 data structures */ + +struct tpm2b_stir { + u16 size; + u64 stir; +} PACKED; + +struct tpm2_req_getrandom { + struct tpm_req_header hdr; + u16 bytesRequested; +} PACKED; + +struct tpm2b_20 { + u16 size; + u8 buffer[20]; +} PACKED; + +struct tpm2_res_getrandom { + struct tpm_rsp_header hdr; + struct tpm2b_20 rnd; +} PACKED; + +struct tpm2_authblock { + u32 handle; + u16 noncesize; /* always 0 */ + u8 contsession; /* always TPM2_YES */ + u16 pwdsize; /* always 0 */ +} PACKED; + +struct tpm2_req_hierarchychangeauth { + struct tpm_req_header hdr; + u32 authhandle; + u32 authblocksize; + struct tpm2_authblock authblock; + struct tpm2b_20 newAuth; +} PACKED; + #endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index 463b7bb..a99d58d 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -204,7 +204,7 @@ tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, { struct { struct tpm_req_header trqh; - u8 cmd[6]; + u8 cmd[10]; } PACKED req = { .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD), .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size), @@ -657,6 +657,113 @@ tpm_setup(void) tpm_add_action(2, "Start Option ROM Scan"); }
+static int +tpm20_stirrandom(void) +{ + struct tpm2b_stir stir = { + .size = cpu_to_be16(sizeof(stir.stir)), + .stir = rdtscll(), + }; + /* set more bits to stir with */ + stir.stir += swab64(rdtscll()); + + int ret = tpm_build_and_send_cmd(0, TPM2_CC_StirRandom, + (u8 *)&stir, sizeof(stir), + TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n", + ret); + + return ret; +} + +static int +tpm20_getrandom(u8 *buf, u16 buf_len) +{ + struct tpm2_res_getrandom rsp; + + if (buf_len > sizeof(rsp.rnd.buffer)) + return -1; + + struct tpm2_req_getrandom trgr = { + .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trgr)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom), + .bytesRequested = cpu_to_be16(buf_len), + }; + u32 resp_length = sizeof(rsp); + + int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_MEDIUM); + if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode) + ret = -1; + else + memcpy(buf, rsp.rnd.buffer, buf_len); + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n", + ret); + + return ret; +} + +static int +tpm20_hierarchychangeauth(u8 auth[20]) +{ + struct tpm2_req_hierarchychangeauth trhca = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trhca)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trhca.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + .newAuth = { + .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)), + }, + }; + memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer)); + + struct tpm_rsp_header rsp; + u32 resp_length = sizeof(rsp); + int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_MEDIUM); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n", + ret); + + return ret; +} + +static void +tpm20_prepboot(void) +{ + int ret = tpm20_stirrandom(); + if (ret) + goto err_exit; + + u8 auth[20]; + ret = tpm20_getrandom(&auth[0], sizeof(auth)); + if (ret) + goto err_exit; + + ret = tpm20_hierarchychangeauth(auth); + if (ret) + goto err_exit; + + return; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); +} + void tpm_prepboot(void) { @@ -672,7 +779,7 @@ tpm_prepboot(void) TPM_DURATION_TYPE_SHORT); break; case TPM_VERSION_2: - // FIXME: missing code + tpm20_prepboot(); break; }
From: Stefan Berger stefanb@linux.vnet.ibm.com
Implement the tpm20_extend function. We use it with only SHA1.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 17 +++++++++++++++++ src/tcgbios.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index e0d6f30..d45c7f6 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -375,6 +375,8 @@ struct tpm_res_sha1complete { #define TPM2_RS_PW 0x40000009 #define TPM2_RH_PLATFORM 0x4000000c
+#define TPM2_ALG_SHA1 0x0004 + /* TPM 2 command tags */ #define TPM2_ST_NO_SESSIONS 0x8001 #define TPM2_ST_SESSIONS 0x8002 @@ -385,6 +387,7 @@ struct tpm_res_sha1complete { #define TPM2_CC_Startup 0x144 #define TPM2_CC_StirRandom 0x146 #define TPM2_CC_GetRandom 0x17b +#define TPM2_CC_PCR_Extend 0x182
/* TPM 2 error codes */ #define TPM2_RC_INITIALIZE 0x100 @@ -426,4 +429,18 @@ struct tpm2_req_hierarchychangeauth { struct tpm2b_20 newAuth; } PACKED;
+struct tpm2_digest_value { + u32 count; /* 1 entry only */ + u16 hashalg; /* TPM2_ALG_SHA1 */ + u8 sha1[SHA1_BUFSIZE]; +} PACKED; + +struct tpm2_req_extend { + struct tpm_req_header hdr; + u32 pcrindex; + u32 authblocksize; + struct tpm2_authblock authblock; + struct tpm2_digest_value digest; +} PACKED; + #endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index a99d58d..435e2eb 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -361,6 +361,37 @@ tpm12_extend(u32 pcrindex, const u8 *digest) return 0; }
+static int tpm20_extend(u32 pcrindex, const u8 *digest) +{ + struct tpm2_req_extend tre = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(tre)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend), + .pcrindex = cpu_to_be32(pcrindex), + .authblocksize = cpu_to_be32(sizeof(tre.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + .digest = { + .count = cpu_to_be32(1), + .hashalg = cpu_to_be16(TPM2_ALG_SHA1), + }, + }; + memcpy(tre.digest.sha1, digest, sizeof(tre.digest.sha1)); + + struct tpm_rsp_header rsp; + u32 resp_length = sizeof(rsp); + int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + return -1; + + return 0; +} + static int tpm_extend(u32 pcrindex, const u8 *digest) { @@ -371,8 +402,7 @@ tpm_extend(u32 pcrindex, const u8 *digest) case TPM_VERSION_1_2: return tpm12_extend(pcrindex, digest); case TPM_VERSION_2: - // FIXME: missing code - return -1; + return tpm20_extend(pcrindex, digest); } return -1; }
From: Stefan Berger stefanb@linux.vnet.ibm.com
In the TPM 2 menu we currently only allow to run the TPM2_Clear operation. For this we follow the TCG Physical Presence Interface Specification to be found here:
http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interfa...
Table 3 shows the 'Clear' operation and the sequence of commands to send.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 17 +++++++++ src/tcgbios.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 133 insertions(+), 1 deletion(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index d45c7f6..dd860e6 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -382,6 +382,8 @@ struct tpm_res_sha1complete { #define TPM2_ST_SESSIONS 0x8002
/* TPM 2 commands */ +#define TPM2_CC_Clear 0x126 +#define TPM2_CC_ClearControl 0x127 #define TPM2_CC_HierarchyChangeAuth 0x129 #define TPM2_CC_SelfTest 0x143 #define TPM2_CC_Startup 0x144 @@ -443,4 +445,19 @@ struct tpm2_req_extend { struct tpm2_digest_value digest; } PACKED;
+struct tpm2_req_clearcontrol { + struct tpm_req_header hdr; + u32 authhandle; + u32 authblocksize; + struct tpm2_authblock authblock; + u8 disable; +} PACKED; + +struct tpm2_req_clear { + struct tpm_req_header hdr; + u32 authhandle; + u32 authblocksize; + struct tpm2_authblock authblock; +} PACKED; + #endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index 435e2eb..cd2b228 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -1441,6 +1441,87 @@ tpm12_process_cfg(tpm_ppi_code msgCode, int verbose) }
static int +tpm20_clearcontrol(u8 disable, int verbose) +{ + struct tpm2_req_clearcontrol trc = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trc)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trc.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + .disable = disable, + }; + struct tpm_rsp_header rsp; + u32 resp_length = sizeof(rsp); + int ret = tpmhw_transmit(0, &trc.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n", + ret); + + return ret; +} + +static int +tpm20_clear(void) +{ + struct tpm2_req_clear trq = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trq)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_Clear), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trq.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + }; + struct tpm_rsp_header rsp; + u32 resp_length = sizeof(rsp); + int ret = tpmhw_transmit(0, &trq.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_MEDIUM); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n", + ret); + + return ret; +} + +static int +tpm20_process_cfg(tpm_ppi_code msgCode, int verbose) +{ + int ret = 0; + + switch (msgCode) { + case TPM_PPI_OP_NOOP: /* no-op */ + break; + + case TPM_PPI_OP_CLEAR: + ret = tpm20_clearcontrol(0, verbose); + if (!ret) + ret = tpm20_clear(); + break; + } + + if (ret) + printf("Op %d: An error occurred: 0x%x\n", msgCode, ret); + + return ret; +} + +static int tpm12_get_tpm_state(void) { int state = 0; @@ -1614,6 +1695,40 @@ tpm12_menu(void) } }
+static void +tpm20_menu(void) +{ + int scan_code; + tpm_ppi_code msgCode; + + for (;;) { + printf("1. Clear TPM\n"); + + printf("\nIf no change is desired or if this menu was reached by " + "mistake, press ESC to\n" + "reboot the machine.\n"); + + msgCode = TPM_PPI_OP_NOOP; + + while ((scan_code = get_keystroke(1000)) == ~0) + ; + + switch (scan_code) { + case 1: + // ESC + reset(); + break; + case 2: + msgCode = TPM_PPI_OP_CLEAR; + break; + default: + continue; + } + + tpm20_process_cfg(msgCode, 0); + } +} + void tpm_menu(void) { @@ -1629,7 +1744,7 @@ tpm_menu(void) tpm12_menu(); break; case TPM_VERSION_2: - // FIXME: missing code + tpm20_menu(); break; } }
From: Stefan Berger stefanb@linux.vnet.ibm.com
Implement TPM 2's tpm_set_failure part.
We follow this specification:
TCG PC Client Specific Platform Firmware Profile for TPM 2.0 Systems Revision 1.0 Version 21
It can be found on this page:
http://www.trustedcomputinggroup.org/resources/specifications_in_public_revi...
Make the TPM unavailable for OS-present applications following 6.2 item 2.d.i .
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 12 ++++++++++++ src/tcgbios.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index dd860e6..8466b14 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -372,7 +372,9 @@ struct tpm_res_sha1complete { #define TPM2_SU_CLEAR 0x0000 #define TPM2_SU_STATE 0x0001
+#define TPM2_RH_OWNER 0x40000001 #define TPM2_RS_PW 0x40000009 +#define TPM2_RH_ENDORSEMENT 0x4000000b #define TPM2_RH_PLATFORM 0x4000000c
#define TPM2_ALG_SHA1 0x0004 @@ -382,6 +384,7 @@ struct tpm_res_sha1complete { #define TPM2_ST_SESSIONS 0x8002
/* TPM 2 commands */ +#define TPM2_CC_HierarchyControl 0x121 #define TPM2_CC_Clear 0x126 #define TPM2_CC_ClearControl 0x127 #define TPM2_CC_HierarchyChangeAuth 0x129 @@ -460,4 +463,13 @@ struct tpm2_req_clear { struct tpm2_authblock authblock; } PACKED;
+struct tpm2_req_hierarchycontrol { + struct tpm_req_header hdr; + u32 authhandle; + u32 authblocksize; + struct tpm2_authblock authblock; + u32 enable; + u8 state; +} PACKED; + #endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index cd2b228..da457a4 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -239,6 +239,38 @@ tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, return ret; }
+static int +tpm20_hierarchycontrol(u32 hierarchy, u8 state) +{ + /* we will try to deactivate the TPM now - ignoring all errors */ + struct tpm2_req_hierarchycontrol trh = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trh)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trh.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + .enable = cpu_to_be32(hierarchy), + .state = state, + }; + struct tpm_rsp_header rsp; + u32 resp_length = sizeof(rsp); + int ret = tpmhw_transmit(0, &trh.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_MEDIUM); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n", + ret); + + return ret; +} + static void tpm_set_failure(void) { @@ -253,7 +285,8 @@ tpm_set_failure(void) NULL, 0, TPM_DURATION_TYPE_SHORT); break; case TPM_VERSION_2: - // FIXME: missing code + tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO); + tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO); break; }
From: Stefan Berger stefanb@linux.vnet.ibm.com
Introduce a log_entry 'object' that we use to hold the data to be logged in one log entry. Pass this object around rather than the TPM 1.2 specific 'pcpes' structure.
Write this log_entry in the format that is appropriate for the version of the host's TPM. For TPM 1.2 write it in the 'pcpes' structure's format, for TPM 2 in the new TPM 2 format.
By using this method we can keep the API interface on systems with a TPM 2 even though applications pass in the 'pcpes' structures directly. The log will still be written in the appropriate format.
The TPM 2 log contains a TPM 1.2 type of entry of event type EV_NO_ACTION and entry of type TCG_EfiSpeIdEventStruct as the first entry. This is described in the EFI specification (section 5.3):
TCG EFI Protocol Specification for TPM Family 2.0
http://www.trustedcomputinggroup.org/resources/tcg_efi_protocol_specificatio...
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 35 ++++++++++++ src/tcgbios.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 182 insertions(+), 27 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index 8466b14..1e8b250 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -89,6 +89,7 @@ enum irq_ids {
/* event types: 10.4.1 / table 11 */ #define EV_POST_CODE 1 +#define EV_NO_ACTION 3 #define EV_SEPARATOR 4 #define EV_ACTION 5 #define EV_EVENT_TAG 6 @@ -472,4 +473,38 @@ struct tpm2_req_hierarchycontrol { u8 state; } PACKED;
+/* TPM 2 log entry */ + +struct tpml_digest_values_sha1 { + u16 hashtype; + u8 sha1[SHA1_BUFSIZE]; +}; + +struct tcg_pcr_event2_sha1 { + u32 pcrindex; + u32 eventtype; + u32 count; /* number of digests */ + struct tpml_digest_values_sha1 digests[1]; + u32 eventsize; + u8 event[0]; +} PACKED; + +struct TCG_EfiSpecIdEventStruct { + u8 signature[16]; + u32 platformClass; + u8 specVersionMinor; + u8 specVersionMajor; + u8 specErrata; + u8 uintnSize; + u32 numberOfAlgorithms; + struct TCG_EfiSpecIdEventAlgorithmSize { + u16 algorithmId; + u16 digestSize; + } digestSizes[1]; + u8 vendorInfoSize; + u8 vendorInfo[0]; +}; + +#define TPM_TCPA_ACPI_CLASS_CLIENT 0 + #endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index da457a4..9456a45 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -130,6 +130,58 @@ tpm_tcpa_probe(void) return 0; }
+/**************************************************************** + * Log entry 'object' + ****************************************************************/ + +struct log_entry { + /* embedded TPM 2 type of log entry header */ + struct tcg_pcr_event2_sha1 entry; + const void *event; /* TPM 1.2 & 2 */ +}; + +static u32 +log_entry_write_size(struct log_entry *le, TPMVersion tpm_version) +{ + switch (tpm_version) { + case TPM_VERSION_1_2: + return sizeof(struct pcpes) + le->entry.eventsize; + case TPM_VERSION_2: + return sizeof(le->entry) + le->entry.eventsize; + } + return 0; +} + +static void +log_entry_write(struct log_entry *le, void *dest, TPMVersion tpm_version) +{ + struct pcpes *pcpes; + + switch (tpm_version) { + case TPM_VERSION_1_2: + pcpes = dest; + pcpes->pcrindex = le->entry.pcrindex; + pcpes->eventtype = le->entry.eventtype; + memcpy(pcpes->digest, le->entry.digests[0].sha1, + sizeof(pcpes->digest)); + pcpes->eventdatasize = le->entry.eventsize; + + dest += sizeof(*pcpes); + + break; + case TPM_VERSION_2: + /* fill in missing parts in TPM 2 log entry */ + le->entry.count = 1; + le->entry.digests[0].hashtype = TPM2_ALG_SHA1; + memcpy(dest, &le->entry, sizeof(le->entry)); + + dest += sizeof(le->entry); + + break; + } + memcpy(dest, le->event, le->entry.eventsize); +} + /* * Extend the ACPI log with the given entry by copying the * entry data into the log. @@ -141,7 +193,7 @@ tpm_tcpa_probe(void) * Returns an error code in case of faiure, 0 in case of success */ static int -tpm_log_event(struct pcpes *pcpes, const void *event) +tpm_log_event(struct log_entry *le, TPMVersion tpm_version) { dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n", tpm_state.log_area_start_address, tpm_state.log_area_next_entry); @@ -149,7 +201,7 @@ tpm_log_event(struct pcpes *pcpes, const void *event) if (tpm_state.log_area_next_entry == NULL) return -1;
- u32 size = sizeof(*pcpes) + pcpes->eventdatasize; + u32 size = log_entry_write_size(le, tpm_version);
if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) > tpm_state.log_area_minimum_length) { @@ -157,9 +209,7 @@ tpm_log_event(struct pcpes *pcpes, const void *event) return -1; }
- memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes)); - memcpy(tpm_state.log_area_next_entry + sizeof(*pcpes), - event, pcpes->eventdatasize); + log_entry_write(le, tpm_state.log_area_next_entry, tpm_version);
tpm_state.log_area_last_entry = tpm_state.log_area_next_entry; tpm_state.log_area_next_entry += size; @@ -168,6 +218,42 @@ tpm_log_event(struct pcpes *pcpes, const void *event) return 0; }
+/* + * Initialize the log; a TPM2 log needs a special TPM 1.2 log entry + * as the first entry serving identification purposes + */ +void tpm_log_init(void) +{ + struct TCG_EfiSpecIdEventStruct event = { + .signature = "Spec ID Event03", + .platformClass = TPM_TCPA_ACPI_CLASS_CLIENT, + .specVersionMinor = 0, + .specVersionMajor = 2, + .specErrata = 0, + .uintnSize = 2, + .numberOfAlgorithms = 1, + .digestSizes[0] = { + .algorithmId = TPM2_ALG_SHA1, + .digestSize = SHA1_BUFSIZE, + }, + .vendorInfoSize = 0, + }; + struct log_entry le = { + .entry = { + .eventtype = EV_NO_ACTION, + }, + .event = &event, + }; + + switch (TPM_version) { + case TPM_VERSION_1_2: + break; + case TPM_VERSION_2: + /* write a 1.2 type of entry */ + tpm_log_event(&le, 1); + } +} +
/**************************************************************** * Helper functions @@ -441,20 +527,28 @@ tpm_extend(u32 pcrindex, const u8 *digest) }
static int -tpm_log_extend_event(struct pcpes *pcpes, const void *event) +tpm_log_extend_event(struct log_entry *le) { - int ret = tpm_extend(pcpes->pcrindex, pcpes->digest); + int ret = tpm_extend(le->entry.pcrindex, le->entry.digests[0].sha1); if (ret) return -1;
- return tpm_log_event(pcpes, event); + return tpm_log_event(le, TPM_version); }
+/* + * hash hashdata; if hashdata is not given, caller has calculated + * the hash, so it is in pcpes->digest + */ static void -tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length) +tpm_fill_hash(struct log_entry *le, const void *hashdata, u32 hashdata_length, + struct pcpes *pcpes) { if (hashdata) - sha1(hashdata, hashdata_length, pcpes->digest); + sha1(hashdata, hashdata_length, le->entry.digests[0].sha1); + else if (pcpes) + memcpy(le->entry.digests[0].sha1, pcpes->digest, + sizeof(le->entry.digests[0].sha1)); }
/* @@ -477,13 +571,16 @@ tpm_add_measurement_to_log(u32 pcrindex, u32 event_type, if (!tpm_is_working()) return;
- struct pcpes pcpes = { - .pcrindex = pcrindex, - .eventtype = event_type, - .eventdatasize = event_length, + struct log_entry le = { + .entry = { + .pcrindex = pcrindex, + .eventtype = event_type, + .eventsize = event_length, + }, + .event = event, }; - tpm_fill_hash(&pcpes, hashdata, hashdata_length); - int ret = tpm_log_extend_event(&pcpes, event); + tpm_fill_hash(&le, hashdata, hashdata_length, NULL); + int ret = tpm_log_extend_event(&le); if (ret) tpm_set_failure(); } @@ -707,6 +804,8 @@ tpm_setup(void) if (ret) return;
+ tpm_log_init(); + TPM_working = 1;
if (runningOnXen()) @@ -1038,8 +1137,17 @@ hash_log_extend_event_int(const struct hleei_short *hleei_s, goto err_exit; }
- tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen); - int ret = tpm_log_extend_event(pcpes, pcpes->event); + struct log_entry le = { + .entry = { + .pcrindex = pcpes->pcrindex, + .eventtype = pcpes->eventtype, + .eventsize = pcpes->eventdatasize, + }, + .event = pcpes->event, + }; + + tpm_fill_hash(&le, hleei_s->hashdataptr, hleei_s->hashdatalen, pcpes); + int ret = tpm_log_extend_event(&le); if (ret) { rc = TCG_TCG_COMMAND_ERROR; goto err_exit; @@ -1048,7 +1156,7 @@ hash_log_extend_event_int(const struct hleei_short *hleei_s, hleeo->opblength = sizeof(struct hleeo); hleeo->reserved = 0; hleeo->eventnumber = hleo.eventnumber; - memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest)); + memcpy(hleeo->digest, le.entry.digests[0].sha1, sizeof(hleeo->digest));
err_exit: if (rc != 0) { @@ -1121,8 +1229,17 @@ hash_log_event_int(const struct hlei *hlei, struct hleo *hleo) goto err_exit; }
- tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen); - int ret = tpm_log_event(pcpes, pcpes->event); + struct log_entry le = { + .entry = { + .pcrindex = pcpes->pcrindex, + .eventtype = pcpes->eventtype, + .eventsize = pcpes->eventdatasize, + }, + .event = pcpes->event, + }; + + tpm_fill_hash(&le, hlei->hashdataptr, hlei->hashdatalen, pcpes); + int ret = tpm_log_event(&le, TPM_version); if (ret) { rc = TCG_PC_LOGOVERFLOW; goto err_exit; @@ -1171,14 +1288,17 @@ compact_hash_log_extend_event_int(u8 *buffer, u32 pcrindex, u32 *edx_ptr) { - struct pcpes pcpes = { - .pcrindex = pcrindex, - .eventtype = EV_COMPACT_HASH, - .eventdatasize = sizeof(info), + struct log_entry le = { + .entry = { + .pcrindex = pcrindex, + .eventtype = EV_COMPACT_HASH, + .eventsize = sizeof(info), + }, + .event = &info, };
- tpm_fill_hash(&pcpes, buffer, length); - int ret = tpm_log_extend_event(&pcpes, &info); + tpm_fill_hash(&le, buffer, length, NULL); + int ret = tpm_log_extend_event(&le); if (ret) return TCG_TCG_COMMAND_ERROR; *edx_ptr = tpm_state.entry_count;
From: Stefan Berger stefanb@linux.vnet.ibm.com
Filter TPM commands in the passthrough API call by matching the type of tag in the header with the version of the underlying TPM. Return an error code if the tag indicates that the command is for the wrong TPM version.
Fix a size check on the way.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 2 ++ src/tcgbios.c | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index 1e8b250..f692142 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -74,6 +74,8 @@
/* TPM command tags */ #define TPM_TAG_RQU_CMD 0x00c1 +#define TPM_TAG_RQU_AUTH1_CMD 0x00c2 +#define TPM_TAG_RQU_AUTH2_CMD 0x00c3
/* interrupt identifiers (al register) */ enum irq_ids { diff --git a/src/tcgbios.c b/src/tcgbios.c index 9456a45..34f727b 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -1173,13 +1173,30 @@ pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto) u32 rc = 0; struct tpm_req_header *trh = (void*)pttti->tpmopin;
- if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh) + if (pttti->ipblength < sizeof(struct pttti) + sizeof(*trh) || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen) || pttti->opblength < sizeof(struct pttto)) { rc = TCG_INVALID_INPUT_PARA; goto err_exit; }
+ u16 tag = be16_to_cpu(trh->tag); + + switch (TPM_version) { + case TPM_VERSION_1_2: + if (tag != TPM_TAG_RQU_CMD && tag != TPM_TAG_RQU_AUTH1_CMD + && tag != TPM_TAG_RQU_AUTH2_CMD) { + rc = TCG_INVALID_INPUT_PARA; + goto err_exit; + } + break; + case TPM_VERSION_2: + if (tag != TPM2_ST_NO_SESSIONS && tag != TPM2_ST_SESSIONS) { + rc = TCG_INVALID_INPUT_PARA; + goto err_exit; + } + } + u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout); int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen, TPM_DURATION_TYPE_LONG /* worst case */);
On Tue, Feb 02, 2016 at 01:09:08PM -0500, Stefan Berger wrote:
This series of patches adds TPM 2 support to SeaBIOS in the way previously proposed.
Thanks Stefan. I committed patches 1-9 and 11. I wanted to look further at patch 10.
-Kevin