This series of patches adds TPM 2 support to SeaBIOS in the way previously proposed.
v1->v2: - Addressed most of Kevin's comments. - Added patch for writing logs in TPM 2 format
Stefan
Stefan Berger (10): 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 set_failure tpm: Write logs in TPM 2 format
src/hw/tpm_drivers.c | 38 ++- src/hw/tpm_drivers.h | 26 +- src/std/tcg.h | 145 +++++++++ src/tcgbios.c | 890 +++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 955 insertions(+), 144 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..7dfb4ae 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 enum TPMVersion { + TPM_VERSION_NONE = 0, + TPM_VERSION_1_2 = 1, + TPM_VERSION_2 = 2, +} TPMVersion; + +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 | 311 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 199 insertions(+), 112 deletions(-)
diff --git a/src/tcgbios.c b/src/tcgbios.c index 799a8bf..7f314b7 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -171,7 +171,15 @@ tpm_is_working(void) int tpm_can_show_menu(void) { - return tpm_is_working() && TPM_has_physical_presence; + switch (TPM_version) { + case TPM_VERSION_NONE: + return 0; + 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 +188,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 +221,28 @@ 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_NONE: + break; + 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 +266,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 +304,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 +325,24 @@ 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_NONE: + return -1; + 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 +442,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 +458,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 +480,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 +510,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 +537,21 @@ err_exit: return -1; }
+static int +tpm_startup(void) +{ + switch (TPM_version) { + case TPM_VERSION_NONE: + return -1; + 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 +589,20 @@ 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_NONE: + return; + 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 +694,23 @@ 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_NONE: + return; + 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 +1012,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 +1026,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 +1049,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 +1062,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 +1084,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 +1108,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 +1116,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 +1128,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 +1145,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 +1155,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 +1170,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 +1179,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 +1217,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 +1244,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 +1310,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 +1381,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 +1389,25 @@ tpm_menu(void) } } } + +void +tpm_menu(void) +{ + if (!CONFIG_TCGBIOS) + return; + + while (get_keystroke(0) >= 0) + ; + wait_threads(); + + switch (TPM_version) { + case TPM_VERSION_NONE: + break; + case TPM_VERSION_1_2: + tpm12_menu(); + break; + case TPM_VERSION_2: + // FIXME: missing code + break; + } +}
On Fri, Jan 22, 2016 at 05:47:13PM -0500, Stefan Berger wrote:
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 | 311 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 199 insertions(+), 112 deletions(-)
diff --git a/src/tcgbios.c b/src/tcgbios.c index 799a8bf..7f314b7 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -171,7 +171,15 @@ tpm_is_working(void) int tpm_can_show_menu(void) {
- return tpm_is_working() && TPM_has_physical_presence;
- switch (TPM_version) {
- case TPM_VERSION_NONE:
return 0;
I find these "case TPM_VERSION_NONE:" clauses to be a little confusing, both in this patches and the later patches, because I don't think any of these additional code paths are reachable. I think it would be better to just have the branches that are active (ie, v1.2 and v2).
-Kevin
"Kevin O'Connor" kevin@koconnor.net wrote on 02/01/2016 04:54:53 PM:
From: "Kevin O'Connor" kevin@koconnor.net To: Stefan Berger/Watson/IBM@IBMUS Cc: seabios@seabios.org, Stefan Berger stefanb@linux.vnet.ibm.com Date: 02/01/2016 04:55 PM Subject: Re: [PATCH v2 03/10] tpm: Prepare code for TPM 2 functions
On Fri, Jan 22, 2016 at 05:47:13PM -0500, Stefan Berger wrote:
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_ -
prefixedfunctions;
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 | 311 ++++++++++++++++++++++++++++++++++++
+---------------------
1 file changed, 199 insertions(+), 112 deletions(-)
diff --git a/src/tcgbios.c b/src/tcgbios.c index 799a8bf..7f314b7 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -171,7 +171,15 @@ tpm_is_working(void) int tpm_can_show_menu(void) {
- return tpm_is_working() && TPM_has_physical_presence;
- switch (TPM_version) {
- case TPM_VERSION_NONE:
return 0;
I find these "case TPM_VERSION_NONE:" clauses to be a little confusing, both in this patches and the later patches, because I don't think any of these additional code paths are reachable. I think it would be better to just have the branches that are active (ie, v1.2 and v2).
I know. The 'enum' forced this. So I'll remove these then and make TPM_VERSION_NONE etc. individual #define's.
Stefan
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 | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 107 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 7f314b7..d58911a 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,9 +40,18 @@ 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 ****************************************************************/ @@ -193,12 +206,24 @@ 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_NONE: + return -1; + 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); @@ -538,6 +563,46 @@ 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) { @@ -546,8 +611,7 @@ tpm_startup(void) case TPM_VERSION_1_2: return tpm12_startup(); case TPM_VERSION_2: - // FIXME: missing code - return -1; + return tpm20_startup(); } return -1; } @@ -706,8 +770,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 7dfb4ae..b7dc44f 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) Speicfication; 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 d58911a..ecc85c4 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -328,6 +328,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) { @@ -565,6 +583,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 ecc85c4..87269ee 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -206,7 +206,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), @@ -667,6 +667,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) { @@ -684,7 +791,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 87269ee..e1baaa7 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -367,6 +367,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) { @@ -379,8 +410,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 e1baaa7..1b2790a 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -1455,6 +1455,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; @@ -1628,6 +1709,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) { @@ -1645,7 +1760,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 set failure.
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 1b2790a..f5500b1 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -243,6 +243,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) { @@ -259,7 +291,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 | 173 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 183 insertions(+), 25 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 f5500b1..369736c 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -52,6 +52,71 @@ static const u8 TPM2_SelfTest_YES[] = { TPM2_YES }; /* full test */
typedef u8 tpm_ppi_code;
+ +static TPMVersion TPM_version; + +/**************************************************************** + * Log entry 'object' + ****************************************************************/ + +struct log_entry { + u32 pcrindex; + u32 eventtype; + /* we only support SHA1 for TPM 2 */ + u8 sha1[SHA1_BUFSIZE]; + u32 eventdatasize; + const void *event; /* TPM 1.2 & 2 */ +}; + +static u32 +log_entry_write_size(struct log_entry *le) +{ + switch (TPM_version) { + case TPM_VERSION_NONE: + return 0; + case TPM_VERSION_1_2: + return sizeof(struct pcpes) + le->eventdatasize; + case TPM_VERSION_2: + return sizeof(struct tcg_pcr_event2_sha1); + } + return 0; +} + +static void +log_entry_write(struct log_entry *le, void *dest) +{ + struct pcpes *pcpes; + struct tcg_pcr_event2_sha1 *tpes; + + switch (TPM_version) { + case TPM_VERSION_NONE: + return; + case TPM_VERSION_1_2: + pcpes = dest; + pcpes->pcrindex = le->pcrindex; + pcpes->eventtype = le->eventtype; + memcpy(pcpes->digest, le->sha1, sizeof(pcpes->digest)); + pcpes->eventdatasize = le->eventdatasize; + + dest += sizeof(*pcpes); + + break; + case TPM_VERSION_2: + tpes = dest; + tpes->pcrindex = le->pcrindex; + tpes->eventtype = le->eventtype; + tpes->count = 1; + tpes->digests[0].hashtype = TPM2_ALG_SHA1; + memcpy(tpes->digests[0].sha1, le->sha1, sizeof(tpes->digests[0].sha1)); + tpes->eventsize = le->eventdatasize; + + dest += sizeof(*tpes); + + break; + } + memcpy(dest, le->event, le->eventdatasize); +} + /**************************************************************** * ACPI TCPA table interface ****************************************************************/ @@ -75,8 +140,6 @@ struct {
static int TPM_has_physical_presence;
-static TPMVersion TPM_version; - static struct tcpa_descriptor_rev2 * find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp) { @@ -141,7 +204,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) { dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n", tpm_state.log_area_start_address, tpm_state.log_area_next_entry); @@ -149,7 +212,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);
if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) > tpm_state.log_area_minimum_length) { @@ -157,9 +220,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_state.log_area_last_entry = tpm_state.log_area_next_entry; tpm_state.log_area_next_entry += size; @@ -168,6 +229,43 @@ 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 = { + .eventtype = EV_NO_ACTION, + .event = &event, + }; + + switch (TPM_version) { + case TPM_VERSION_NONE: + case TPM_VERSION_1_2: + break; + case TPM_VERSION_2: + /* write a 1.2 type of entry */ + TPM_version = 1; + tpm_log_event(&le); + TPM_version = 2; + } +} +
/**************************************************************** * Helper functions @@ -449,20 +547,27 @@ 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->pcrindex, le->sha1); if (ret) return -1;
- return tpm_log_event(pcpes, event); + return tpm_log_event(le); }
+/* + * 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->sha1); + else if (pcpes) + memcpy(le->sha1, pcpes->digest, sizeof(le->sha1)); }
/* @@ -485,13 +590,14 @@ tpm_add_measurement_to_log(u32 pcrindex, u32 event_type, if (!tpm_is_working()) return;
- struct pcpes pcpes = { + struct log_entry le = { .pcrindex = pcrindex, .eventtype = event_type, .eventdatasize = 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(); } @@ -717,6 +823,8 @@ tpm_setup(void) if (ret) return;
+ tpm_log_init(); + TPM_working = 1;
if (runningOnXen()) @@ -1052,8 +1160,15 @@ 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 = { + .pcrindex = pcpes->pcrindex, + .eventtype = pcpes->eventtype, + .eventdatasize = 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; @@ -1062,7 +1177,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.sha1, sizeof(hleeo->digest));
err_exit: if (rc != 0) { @@ -1135,8 +1250,15 @@ 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 = { + .pcrindex = pcpes->pcrindex, + .eventtype = pcpes->eventtype, + .eventdatasize = pcpes->eventdatasize, + .event = pcpes->event, + }; + + tpm_fill_hash(&le, hlei->hashdataptr, hlei->hashdatalen, pcpes); + int ret = tpm_log_event(&le); if (ret) { rc = TCG_PC_LOGOVERFLOW; goto err_exit; @@ -1185,14 +1307,15 @@ compact_hash_log_extend_event_int(u8 *buffer, u32 pcrindex, u32 *edx_ptr) { - struct pcpes pcpes = { - .pcrindex = pcrindex, - .eventtype = EV_COMPACT_HASH, + struct log_entry le = { + .pcrindex = pcrindex, + .eventtype = EV_COMPACT_HASH, .eventdatasize = 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;
On Fri, Jan 22, 2016 at 05:47:20PM -0500, Stefan Berger wrote:
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 | 173 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 183 insertions(+), 25 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 f5500b1..369736c 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -52,6 +52,71 @@ static const u8 TPM2_SelfTest_YES[] = { TPM2_YES }; /* full test */
typedef u8 tpm_ppi_code;
+static TPMVersion TPM_version;
+/****************************************************************
- Log entry 'object'
- ****************************************************************/
This section looks like it could be merged into the "ACPI TCPA table interface" section as both sections are focused solely on logging.
+struct log_entry {
- u32 pcrindex;
- u32 eventtype;
- /* we only support SHA1 for TPM 2 */
- u8 sha1[SHA1_BUFSIZE];
- u32 eventdatasize;
- const void *event; /* TPM 1.2 & 2 */
+};
Instead of introducing 'struct log_entry' to be the superset of tcg_pcr_event2_sha1 and pcpes, why not use tcg_pcr_event2_sha1 everywhere? That is, replace all the 'struct pcpes *' with 'struct tcg_pcr_event2_sha1 *' and then enhance tpm_log_event() to translate to a pcpes for older logs.
Of course, the above is assuming the log should be in an "efi" format - see previous email on that.
[...]
+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 = {
.eventtype = EV_NO_ACTION,
.event = &event,
- };
- switch (TPM_version) {
- case TPM_VERSION_NONE:
- case TPM_VERSION_1_2:
break;
- case TPM_VERSION_2:
/* write a 1.2 type of entry */
TPM_version = 1;
tpm_log_event(&le);
TPM_version = 2;
Altering the TPM_version seems ugly - I think tpm_log_event() could take the version as a parameter to avoid that.
-Kevin
On 02/01/2016 05:05 PM, Kevin O'Connor wrote:
On Fri, Jan 22, 2016 at 05:47:20PM -0500, Stefan Berger wrote:
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 | 173 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 183 insertions(+), 25 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 f5500b1..369736c 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -52,6 +52,71 @@ static const u8 TPM2_SelfTest_YES[] = { TPM2_YES }; /* full test */
typedef u8 tpm_ppi_code;
+static TPMVersion TPM_version;
+/****************************************************************
- Log entry 'object'
- ****************************************************************/
This section looks like it could be merged into the "ACPI TCPA table interface" section as both sections are focused solely on logging.
+struct log_entry {
- u32 pcrindex;
- u32 eventtype;
- /* we only support SHA1 for TPM 2 */
- u8 sha1[SHA1_BUFSIZE];
- u32 eventdatasize;
- const void *event; /* TPM 1.2 & 2 */
+};
Instead of introducing 'struct log_entry' to be the superset of tcg_pcr_event2_sha1 and pcpes, why not use tcg_pcr_event2_sha1 everywhere? That is, replace all the 'struct pcpes *' with 'struct tcg_pcr_event2_sha1 *' and then enhance tpm_log_event() to translate to a pcpes for older logs.
Sure, can do that also.
Of course, the above is assuming the log should be in an "efi" format
- see previous email on that.
The format doesn't depend on the kind of firmware (efi vs. bios), it's more a TPM 2 type of log that supports different types of hashes per measurement.
[...]
+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 = {
.eventtype = EV_NO_ACTION,
.event = &event,
- };
- switch (TPM_version) {
- case TPM_VERSION_NONE:
- case TPM_VERSION_1_2:
break;
- case TPM_VERSION_2:
/* write a 1.2 type of entry */
TPM_version = 1;
tpm_log_event(&le);
TPM_version = 2;
Altering the TPM_version seems ugly - I think tpm_log_event() could take the version as a parameter to avoid that.
:-)
Stefan