Implement a TPM 2.0 menu item that allows a user to toggle the activation of PCR banks of the TPM 2.0. After successful activation we shut down the TPM 2.0 and reset the machine.
Signed-off-by: Stefan Berger stefanb@linux.ibm.com --- src/std/tcg.h | 18 ++++ src/tcgbios.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++- src/util.h | 2 + 3 files changed, 253 insertions(+), 2 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index 09a92d8..eb9e67d 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -336,6 +336,12 @@ struct tpm_res_sha1complete { #define TPM2_ALG_SHA512 0x000d #define TPM2_ALG_SM3_256 0x0012
+#define TPM2_ALG_SHA1_FLAG (1 << 0) +#define TPM2_ALG_SHA256_FLAG (1 << 1) +#define TPM2_ALG_SHA384_FLAG (1 << 2) +#define TPM2_ALG_SHA512_FLAG (1 << 3) +#define TPM2_ALG_SM3_256_FLAG (1 << 4) + /* TPM 2 command tags */ #define TPM2_ST_NO_SESSIONS 0x8001 #define TPM2_ST_SESSIONS 0x8002 @@ -345,8 +351,10 @@ struct tpm_res_sha1complete { #define TPM2_CC_Clear 0x126 #define TPM2_CC_ClearControl 0x127 #define TPM2_CC_HierarchyChangeAuth 0x129 +#define TPM2_CC_PCR_Allocate 0x12b #define TPM2_CC_SelfTest 0x143 #define TPM2_CC_Startup 0x144 +#define TPM2_CC_Shutdown 0x145 #define TPM2_CC_StirRandom 0x146 #define TPM2_CC_GetCapability 0x17a #define TPM2_CC_GetRandom 0x17b @@ -442,6 +450,15 @@ struct tpm2_res_getcapability { u8 data[0]; /* capability dependent data */ } PACKED;
+struct tpm2_req_pcr_allocate { + struct tpm_req_header hdr; + u32 authhandle; + u32 authblocksize; + struct tpm2_authblock authblock; + u32 count; + u8 tpms_pcr_selections[4]; +} PACKED; + struct tpms_pcr_selection { u16 hashAlg; u8 sizeOfSelect; @@ -550,5 +567,6 @@ struct pcctes_romex #define TPM_PPI_OP_CLEAR 5 #define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8 #define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9 +#define TPM_PPI_OP_SET_PCR_BANKS 23
#endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index 24846d3..ae0020e 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -180,6 +180,60 @@ tpm20_get_hash_buffersize(u16 hashAlg) } }
+static u8 +tpm20_hashalg_to_flag(u16 hashAlg) +{ + switch (hashAlg) { + case TPM2_ALG_SHA1: + return TPM2_ALG_SHA1_FLAG; + case TPM2_ALG_SHA256: + return TPM2_ALG_SHA256_FLAG; + case TPM2_ALG_SHA384: + return TPM2_ALG_SHA384_FLAG; + case TPM2_ALG_SHA512: + return TPM2_ALG_SHA512_FLAG; + case TPM2_ALG_SM3_256: + return TPM2_ALG_SM3_256_FLAG; + default: + return 0; + } +} + +static u16 +tpm20_hashalg_flag_to_hashalg(u8 hashalg_flag) +{ + switch (hashalg_flag) { + case TPM2_ALG_SHA1_FLAG: + return TPM2_ALG_SHA1; + case TPM2_ALG_SHA256_FLAG: + return TPM2_ALG_SHA256; + case TPM2_ALG_SHA384_FLAG: + return TPM2_ALG_SHA384; + case TPM2_ALG_SHA512_FLAG: + return TPM2_ALG_SHA512; + case TPM2_ALG_SM3_256_FLAG: + return TPM2_ALG_SM3_256; + default: + return 0; + } +} + +static const char * +tpm20_hashalg_flag_to_name(u8 hashalg_flag) +{ + switch (hashalg_flag) { + case TPM2_ALG_SHA1_FLAG: + return "SHA1"; + case TPM2_ALG_SHA256_FLAG: + return "SHA256"; + case TPM2_ALG_SHA384_FLAG: + return "SHA384"; + case TPM2_ALG_SHA512_FLAG: + return "SHA512"; + } + return NULL; +} + // Add an entry at the start of the log describing digest formats static int tpm20_write_EfiSpecIdEventStruct(void) @@ -432,6 +486,104 @@ tpm20_get_pcrbanks(void) return ret; }
+static int +tpm20_get_suppt_pcrbanks(u8 *suppt_pcrbanks, u8 *active_pcrbanks) +{ + *suppt_pcrbanks = 0; + *active_pcrbanks = 0; + + if (!tpm20_pcr_selection) + return -1; + + struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections; + void *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size; + + while (1) { + u8 sizeOfSelect = sel->sizeOfSelect; + void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect; + if (nsel > end) + return 0; + + u16 hashalg = be16_to_cpu(sel->hashAlg); + u8 hashalg_flag = tpm20_hashalg_to_flag(hashalg); + + *suppt_pcrbanks |= hashalg_flag; + + unsigned i; + for (i = 0; i < sizeOfSelect; i++) { + if (sel->pcrSelect[i]) { + *active_pcrbanks |= hashalg_flag; + break; + } + } + + sel = nsel; + } +} + +static int +tpm20_set_pcrbanks(u32 active_banks) +{ + struct tpm2_req_pcr_allocate trpa = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Allocate), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trpa.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + }; + struct tpms_pcr_selection3 { + u16 hashAlg; + u8 sizeOfSelect; + u8 pcrSelect[3]; + } tps[ARRAY_SIZE(trpa.tpms_pcr_selections)]; + int i = 0; + u8 hashalg_flag = TPM2_ALG_SHA1_FLAG; + u8 dontcare, suppt_banks; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare); + + while (hashalg_flag) { + if ((hashalg_flag & suppt_banks)) { + u16 hashalg = tpm20_hashalg_flag_to_hashalg(hashalg_flag); + + if (hashalg) { + u8 mask = 0; + tps[i].hashAlg = cpu_to_be16(hashalg); + tps[i].sizeOfSelect = 3; + + if (active_banks & hashalg_flag) + mask = 0xff; + + tps[i].pcrSelect[0] = mask; + tps[i].pcrSelect[1] = mask; + tps[i].pcrSelect[2] = mask; + i++; + } + } + hashalg_flag <<= 1; + } + + trpa.count = cpu_to_be32(i); + memcpy(trpa.tpms_pcr_selections, tps, i * sizeof(tps[0])); + trpa.hdr.totlen = cpu_to_be32(offsetof(struct tpm2_req_pcr_allocate, + tpms_pcr_selections) + + i * sizeof(tps[0])); + + struct tpm_rsp_header rsp; + u32 resp_length = sizeof(rsp); + + int ret = tpmhw_transmit(0, &trpa.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); + ret = ret ? -1 : be32_to_cpu(rsp.errcode); + + return ret; +} + static int tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize) { @@ -1752,7 +1904,7 @@ tpm20_clear(void) }
static int -tpm20_process_cfg(tpm_ppi_code msgCode, int verbose) +tpm20_process_cfg(tpm_ppi_code msgCode, u32 pprm, int verbose) { int ret = 0;
@@ -1765,6 +1917,13 @@ tpm20_process_cfg(tpm_ppi_code msgCode, int verbose) if (!ret) ret = tpm20_clear(); break; + + case TPM_PPI_OP_SET_PCR_BANKS: + ret = tpm20_set_pcrbanks(pprm); + if (!ret) + ret = tpm_simple_cmd(0, TPM2_CC_Shutdown, + 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT); + break; }
if (ret) @@ -1947,14 +2106,77 @@ tpm12_menu(void) } }
+static int +tpm20_menu_change_active_pcrbanks(u8 *activate_banks) +{ + u8 active_banks, suppt_banks; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &active_banks); + + *activate_banks = active_banks; + + while (1) { + u8 hashalg_flag = TPM2_ALG_SHA1_FLAG; + u8 i = 0; + + printf("\nToggle active PCR banks by pressing number key\n\n"); + + while (hashalg_flag) { + u8 flag = hashalg_flag & suppt_banks; + const char *hashname = tpm20_hashalg_flag_to_name(flag); + + i++; + if (hashname) { + printf(" %d: %s", i, hashname); + if (*activate_banks & hashalg_flag) + printf(" (enabled)"); + printf("\n"); + } + + hashalg_flag <<= 1; + } + printf("\n" + "ESC: return to previous menu without changing active PCR banks\n" + "A : activate selection\n"); + u8 flagnum; + int show = 0; + while (!show) { + int scancode = get_keystroke(1000); + + switch (scancode) { + case ~0: + continue; + case 1: /* ESC */ + printf("\n"); + return -1; + case 2 ... 6: /* keys 1 .. 5 */ + flagnum = scancode - 1; + if (flagnum > i) + continue; + if (suppt_banks & (1 << (flagnum - 1))) { + *activate_banks ^= 1 << (flagnum - 1); + show = 1; + } + break; + case SCANCODE_A: + return 0; + } + } + } +} + static void tpm20_menu(void) { int scan_code; tpm_ppi_code msgCode; + u32 pprm; + u8 active_banks; + int do_reset = 0;
for (;;) { printf("1. Clear TPM\n"); + printf("2. Change active PCR banks\n");
printf("\nIf no change is desired or if this menu was reached by " "mistake, press ESC to\n" @@ -1973,11 +2195,20 @@ tpm20_menu(void) case 2: msgCode = TPM_PPI_OP_CLEAR; break; + case 3: + if (tpm20_menu_change_active_pcrbanks(&active_banks) < 0) + continue; + msgCode = TPM_PPI_OP_SET_PCR_BANKS; + pprm = active_banks; + do_reset = 1; + break; default: continue; }
- tpm20_process_cfg(msgCode, 0); + tpm20_process_cfg(msgCode, pprm, 0); + if (do_reset) + reset(); } }
diff --git a/src/util.h b/src/util.h index 6dd080f..b7169dd 100644 --- a/src/util.h +++ b/src/util.h @@ -38,6 +38,8 @@ struct usbdevice_s; int bootprio_find_usb(struct usbdevice_s *usbdev, int lun); int get_keystroke(int msec);
+#define SCANCODE_A 0x1e + // bootsplash.c void enable_vga_console(void); void enable_bootsplash(void);