This series of patches adds TPM 2 support to SeaBIOS in the way previously proposed.
TPM 2 support also changes the log entry format, which I have not addressed at all so far, and would append to the end of the series.
Stefan
Stefan Berger (9): tpm: Extend TPM TIS with TPM 2 support. tpm: Factor out tpm_extend tpm: Prepare code for TPM 2 functions tpm: Implement tpm2_startup and tpm2_s3_resume tpm: Implement tpm2_set_timeouts tpm: Implement tpm2_prepboot tpm: Implement tpm2_extend tpm: Implement tpm2_menu tpm: Implement TPM 2's set_failure
src/hw/tpm_drivers.c | 39 +++ src/hw/tpm_drivers.h | 24 ++ src/std/tcg.h | 110 ++++++++ src/tcgbios.c | 692 ++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 749 insertions(+), 116 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 | 39 +++++++++++++++++++++++++++++++++++++++ src/hw/tpm_drivers.h | 7 +++++++ src/tcgbios.c | 8 ++++++++ 3 files changed, 54 insertions(+)
diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c index 08fd101..dd6b022 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); @@ -69,6 +70,23 @@ 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; }
@@ -303,6 +321,19 @@ static u32 tis_waitrespready(enum tpmDurationType to_t) return rc; }
+TPMVersion tis_get_tpm_version(void) +{ + u8 locty = tis_find_active_locality(); + /* TPM 2 has an interface register */ + u32 ifaceid = readl(TIS_REG(locty, TIS_REG_IFACE_ID)); + + if ((ifaceid & 0xf) == 0) { + /* TPM 2 */ + return TPM_VERSION_2; + } + return TPM_VERSION_1_2; +} +
struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = { [TIS_DRIVER_IDX] = @@ -312,6 +343,7 @@ struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = { .set_timeouts = set_timeouts, .probe = tis_probe, .init = tis_init, + .get_tpm_version = tis_get_tpm_version, .activate = tis_activate, .ready = tis_ready, .senddata = tis_senddata, @@ -387,3 +419,10 @@ tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]) struct tpm_driver *td = &tpm_drivers[TPMHW_driver_to_use]; td->set_timeouts(timeouts, durations); } + +TPMVersion +tpmhw_get_tpm_version(void) +{ + struct tpm_driver *td = &tpm_drivers[TPMHW_driver_to_use]; + return td->get_tpm_version(); +} diff --git a/src/hw/tpm_drivers.h b/src/hw/tpm_drivers.h index 15a60af..665c534 100644 --- a/src/hw/tpm_drivers.h +++ b/src/hw/tpm_drivers.h @@ -10,6 +10,11 @@ enum tpmDurationType { TPM_DURATION_TYPE_LONG, };
+typedef enum TPMVersion { + TPM_VERSION_1_2 = 1, + TPM_VERSION_2 = 2, +} TPMVersion; + int tpmhw_probe(void); int tpmhw_is_present(void); struct tpm_req_header; @@ -17,6 +22,7 @@ int tpmhw_transmit(u8 locty, struct tpm_req_header *req, void *respbuffer, u32 *respbufferlen, enum tpmDurationType to_t); void tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]); +TPMVersion tpmhw_get_tpm_version(void);
/* TIS driver */ /* address of locality 0 (TIS) */ @@ -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..aa83f7f 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) { @@ -508,6 +510,12 @@ tpm_setup(void)
TPM_working = 1;
+ TPM_version = tpmhw_get_tpm_version(); + + dprintf(DEBUG_tcg, + "TCGBIOS: Detected a TPM %s.\n", + (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2"); + if (runningOnXen()) return;
On Fri, Jan 15, 2016 at 02:44:31PM -0500, Stefan Berger wrote:
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 | 39 +++++++++++++++++++++++++++++++++++++++ src/hw/tpm_drivers.h | 7 +++++++ src/tcgbios.c | 8 ++++++++ 3 files changed, 54 insertions(+)
diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c index 08fd101..dd6b022 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);
BTW, what is this function table used for? I think each function pointer always points to a static function in the current code. Is there some hardware that is significantly different?
@@ -69,6 +70,23 @@ 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;
}
@@ -303,6 +321,19 @@ static u32 tis_waitrespready(enum tpmDurationType to_t) return rc; }
+TPMVersion tis_get_tpm_version(void) +{
- u8 locty = tis_find_active_locality();
- /* TPM 2 has an interface register */
- u32 ifaceid = readl(TIS_REG(locty, TIS_REG_IFACE_ID));
- if ((ifaceid & 0xf) == 0) {
/* TPM 2 */
return TPM_VERSION_2;
- }
- return TPM_VERSION_1_2;
+}
struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = { [TIS_DRIVER_IDX] = @@ -312,6 +343,7 @@ struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = { .set_timeouts = set_timeouts, .probe = tis_probe, .init = tis_init,
.get_tpm_version = tis_get_tpm_version, .activate = tis_activate, .ready = tis_ready, .senddata = tis_senddata,
@@ -387,3 +419,10 @@ tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]) struct tpm_driver *td = &tpm_drivers[TPMHW_driver_to_use]; td->set_timeouts(timeouts, durations); }
+TPMVersion +tpmhw_get_tpm_version(void) +{
- struct tpm_driver *td = &tpm_drivers[TPMHW_driver_to_use];
- return td->get_tpm_version();
+}
Instead of exporting an additional function from tpm_drivers.c, could the version just be probed and returned from tpmhw_probe()?
-Kevin
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 aa83f7f..bdc2c35 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 | 298 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 186 insertions(+), 112 deletions(-)
diff --git a/src/tcgbios.c b/src/tcgbios.c index bdc2c35..89af876 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,20 @@ 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) { @@ -543,11 +584,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(); @@ -639,9 +687,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;
@@ -943,11 +1003,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;
@@ -957,19 +1017,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"); @@ -980,10 +1040,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;
@@ -993,12 +1053,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;
@@ -1015,20 +1075,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) { @@ -1038,7 +1099,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"); @@ -1046,8 +1107,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;
@@ -1058,14 +1119,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) { @@ -1075,7 +1136,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;
@@ -1085,11 +1146,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;
@@ -1100,7 +1161,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;
@@ -1109,31 +1170,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: @@ -1147,14 +1208,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]) @@ -1174,7 +1235,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;
@@ -1240,28 +1301,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; @@ -1318,7 +1372,7 @@ tpm_menu(void) break;
if (next_scancodes[i] == scancode) { - tpm_process_cfg(msgCode, 1); + tpm12_process_cfg(msgCode, 1); waitkey = 0; break; } @@ -1326,3 +1380,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; + } +}
On Fri, Jan 15, 2016 at 02:44:33PM -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_
I find the "tpm12_" and "tpm2_" prefixes to be a little confusing because it seems like 12 > 2. How about tpm12/tpm20 or tpm1/tpm2?
-Kevin
From: Stefan Berger stefanb@linux.vnet.ibm.com
Implement tpm2_startup and tpm2_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 | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 91 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 89af876..0d6cfdb 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,47 @@ err_exit: }
static int +tpm2_startup(void) +{ + dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM2_Startup(SU_CLEAR)\n"); + int ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup, + Startup_SU_CLEAR, + sizeof(Startup_SU_CLEAR), + TPM_DURATION_TYPE_SHORT); + + 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); + 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 tpm2_startup(); }
return -1; @@ -697,8 +753,17 @@ 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); + 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); 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 665c534..36d6ab9 100644 --- a/src/hw/tpm_drivers.h +++ b/src/hw/tpm_drivers.h @@ -66,6 +66,14 @@ TPMVersion tpmhw_get_tpm_version(void); #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 0d6cfdb..7b6409c 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -322,6 +322,24 @@ tpm12_determine_timeouts(void) return 0; }
+static void +tpm2_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 tpm2_startup(void) { + tpm2_set_timeouts(); + dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM2_Startup(SU_CLEAR)\n"); int ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup, Startup_SU_CLEAR,
On Fri, Jan 15, 2016 at 02:44:35PM -0500, Stefan Berger wrote:
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 665c534..36d6ab9 100644 --- a/src/hw/tpm_drivers.h +++ b/src/hw/tpm_drivers.h @@ -66,6 +66,14 @@ TPMVersion tpmhw_get_tpm_version(void); #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 0d6cfdb..7b6409c 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -322,6 +322,24 @@ tpm12_determine_timeouts(void) return 0; }
+static void +tpm2_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 tpm2_startup(void) {
- tpm2_set_timeouts();
How about just do this in tpmhw_probe() and not bother with calling tpmhw_set_timeouts in tcgbios.c (for tpm2).
-Kevin
From: Stefan Berger stefanb@linux.vnet.ibm.com
Implement tpm2_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 | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 152 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 7b6409c..4f5c5bb 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), @@ -654,6 +654,112 @@ tpm_setup(void) tpm_add_action(2, "Start Option ROM Scan"); }
+static int +tpm2_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()); + + return tpm_build_and_send_cmd(0, TPM2_CC_StirRandom, + (u8 *)&stir, sizeof(stir), + TPM_DURATION_TYPE_SHORT); +} + +static int +tpm2_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) + return -1; + + memcpy(buf, rsp.rnd.buffer, buf_len); + + return 0; +} + +static int +tpm2_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) + return -1; + + return 0; +} + +static void +tpm2_prepboot(void) +{ + int ret = tpm2_stirrandom(); + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_StirRandom = 0x%08x\n", + ret); + if (ret) + goto err_exit; + + u8 auth[20]; + ret = tpm2_getrandom(&auth[0], sizeof(auth)); + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_GetRandom = 0x%08x\n", + ret); + + if (ret) + goto err_exit; + + ret = tpm2_hierarchychangeauth(auth); + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_HierarchyChangeAuth = 0x%08x\n", + ret); + + 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) { @@ -669,7 +775,7 @@ tpm_prepboot(void) TPM_DURATION_TYPE_SHORT); break; case TPM_VERSION_2: - // FIXME: missing code + tpm2_prepboot(); break; }
On Fri, Jan 15, 2016 at 02:44:36PM -0500, Stefan Berger wrote:
From: Stefan Berger stefanb@linux.vnet.ibm.com
Implement tpm2_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 | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 152 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 7b6409c..4f5c5bb 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];
} PACKED req = { .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD), .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),u8 cmd[10];
@@ -654,6 +654,112 @@ tpm_setup(void) tpm_add_action(2, "Start Option ROM Scan"); }
+static int +tpm2_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());
- return tpm_build_and_send_cmd(0, TPM2_CC_StirRandom,
(u8 *)&stir, sizeof(stir),
TPM_DURATION_TYPE_SHORT);
+}
+static int +tpm2_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)
return -1;
- memcpy(buf, rsp.rnd.buffer, buf_len);
- return 0;
+}
+static int +tpm2_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)
return -1;
- return 0;
+}
+static void +tpm2_prepboot(void) +{
- int ret = tpm2_stirrandom();
- dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_StirRandom = 0x%08x\n",
ret);
- if (ret)
goto err_exit;
- u8 auth[20];
- ret = tpm2_getrandom(&auth[0], sizeof(auth));
- dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_GetRandom = 0x%08x\n",
ret);
- if (ret)
goto err_exit;
- ret = tpm2_hierarchychangeauth(auth);
- dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_HierarchyChangeAuth = 0x%08x\n",
ret);
Minor nit - I think it would be better for an error dprintf to be done in the function that raised the error instead of the callers of that function.
-Kevin
From: Stefan Berger stefanb@linux.vnet.ibm.com
Implement the tpm2_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 4f5c5bb..627a374 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -361,6 +361,37 @@ tpm12_extend(u32 pcrindex, const u8 *digest) return 0; }
+static int tpm2_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 tpm2_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 | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 135 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 627a374..356cef9 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -1429,6 +1429,89 @@ tpm12_process_cfg(tpm_ppi_code msgCode, int verbose) }
static int +tpm2_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) + return -1; + + return 0; +} + +static int +tpm2_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) + return -1; + + return 0; +} + +static int +tpm2_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 = tpm2_clearcontrol(0, verbose); + if (ret) + dprintf(DEBUG_tcg, + "TCGBIOS: tpm2_clearcontrol failed\n"); + if (!ret) { + ret = tpm2_clear(); + if (ret) { + dprintf(DEBUG_tcg, + "TCGBIOS: tpm2_clear failed\n"); + } + } + 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; @@ -1602,6 +1685,40 @@ tpm12_menu(void) } }
+static void +tpm2_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; + } + + tpm2_process_cfg(msgCode, 0); + } +} + void tpm_menu(void) { @@ -1617,7 +1734,7 @@ tpm_menu(void) tpm12_menu(); break; case TPM_VERSION_2: - // FIXME: missing code + tpm2_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 | 32 +++++++++++++++++++++++++++++++- 2 files changed, 43 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 356cef9..f1ea023 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -239,6 +239,35 @@ tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, return ret; }
+static int +tpm2_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) + return -1; + + return 0; +} + static void tpm_set_failure(void) { @@ -253,7 +282,8 @@ tpm_set_failure(void) NULL, 0, TPM_DURATION_TYPE_SHORT); break; case TPM_VERSION_2: - // FIXME: missing code + tpm2_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO); + tpm2_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO); break; }
On Fri, Jan 15, 2016 at 02:44:30PM -0500, Stefan Berger wrote:
This series of patches adds TPM 2 support to SeaBIOS in the way previously proposed.
TPM 2 support also changes the log entry format, which I have not addressed at all so far, and would append to the end of the series.
Thanks Stefan. In general it looks good to me. I have a few comments, which I'll send separately. All of my comments could be addressed after committing this series if desired.
How does one test and/or use this support? Does QEMU have support, or is there hardware available on coreboot with the tpm2 hardware?
-Kevin
"Kevin O'Connor" kevin@koconnor.net wrote on 01/21/2016 05:37:29 PM:
On Fri, Jan 15, 2016 at 02:44:30PM -0500, Stefan Berger wrote:
This series of patches adds TPM 2 support to SeaBIOS in the way
previously
proposed.
TPM 2 support also changes the log entry format, which I have not
addressed
at all so far, and would append to the end of the series.
Thanks Stefan. In general it looks good to me. I have a few comments, which I'll send separately. All of my comments could be addressed after committing this series if desired.
I can address those comments and repost a V2 with the 10th patch adding the part for the logging.
How does one test and/or use this support? Does QEMU have support, or is there hardware available on coreboot with the tpm2 hardware?
I did all the testing of these patches with the vTPM with CUSE interface integrated into QEMU. Unfortunately the vTPM-QEMU integration train seems a wreck now following comments on QEMU mailing list. So, I don't know of any TPM 2 hardware out there, less so hardware where coreboot runs. So that's probably currently the number one problem.
You know the TPM 1.2 PC BIOS specification, right? I think we can say that many of the functions implemented in this series for TPM 2 are necessary because of how it's done for TPM 1.2 as well as properties of the TPM 2 device. This includes the TPM initialization, S3 support, setting of timeouts, menu items, etc. The problem with TPM 2 is that there's no official spec for TPM 2 for a BIOS. So it's not quite clear to me how much leeway we have to go about this in the areas of ACPI tables for logging and the API. Regarding these topics:
ACPI tables for logging: The (U)EFI specification for TPM 2 don't require a TCPA table with the logging area because there seems to be an API for the OS for retrieving the log. UEFI seems to log into just some buffer, not connected to any ACPI table. For the BIOS we would still need that TCPA table. QEMU currently provides that. The Linux kernel (and all other OSes -- uuuh) would then have to allow a TCPA table for logging for TPM 2 even though we cannot point to a spec for that. Not sure whether we can create a standard for this little gap here...
BIOS API: Some functions pass the entry to write into the log via the function directly. Patch 10 handles that and transforms that entry into the log entry format as required for TPM 1.2 or TPM 2 (log entries are differently formatted for TPM 1.2 and for TPM 2). So the only remaining problem I know of is the function that allows one to pass TPM commands through to the TPM. This may end up causing problems in the application if it was written for TPM 1.2 and now there's a TPM 2 running underneath, which doesn't understand the TPM 1.2 commands. I would say this is likely the smaller of the problems also considering that there are not many applications out there that use that API call. Possibility to just shut down that function call is certainly there.
Stefan
-Kevin