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(a)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);
--
2.17.2