diff options
author | Stefan Berger <stefanb@linux.ibm.com> | 2020-01-21 15:01:46 -0500 |
---|---|---|
committer | Alexey Kardashevskiy <aik@ozlabs.ru> | 2020-02-21 14:03:07 +1100 |
commit | 8a6b0d7061c5e504be2e378bd691a762307a1805 (patch) | |
tree | f54824d7e940d210d312230c590d959a231fd4a7 /lib | |
parent | ae2e38c3ad59bfebfd35f1f5c1f4636147d67999 (diff) | |
download | SLOF-8a6b0d7061c5e504be2e378bd691a762307a1805.zip SLOF-8a6b0d7061c5e504be2e378bd691a762307a1805.tar.gz SLOF-8a6b0d7061c5e504be2e378bd691a762307a1805.tar.bz2 |
tcgbios: Implement menu to clear TPM 2 and activate its PCR banks
Implement a TPM 2 menu and enable the user to clear the TPM
and its activate PCR banks.
The main TPM menu is activated by pressing the 't' key during
firmware startup.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libtpm/tcgbios.c | 348 | ||||
-rw-r--r-- | lib/libtpm/tcgbios.h | 1 | ||||
-rw-r--r-- | lib/libtpm/tpm.code | 9 | ||||
-rw-r--r-- | lib/libtpm/tpm.in | 1 |
4 files changed, 359 insertions, 0 deletions
diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c index d81d392..c5f8ccf 100644 --- a/lib/libtpm/tcgbios.c +++ b/lib/libtpm/tcgbios.c @@ -63,6 +63,12 @@ static struct { struct tpml_pcr_selection *tpm20_pcr_selection; } tpm_state; +#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 logs are written in little endian format. */ @@ -110,23 +116,36 @@ struct tpm_log_entry { static const struct hash_parameters { uint16_t hashalg; + uint8_t hashalg_flag; uint8_t hash_buffersize; + const char *name; } hash_parameters[] = { { .hashalg = TPM2_ALG_SHA1, + .hashalg_flag = TPM2_ALG_SHA1_FLAG, .hash_buffersize = SHA1_BUFSIZE, + .name = "SHA1", }, { .hashalg = TPM2_ALG_SHA256, + .hashalg_flag = TPM2_ALG_SHA256_FLAG, .hash_buffersize = SHA256_BUFSIZE, + .name = "SHA256", }, { .hashalg = TPM2_ALG_SHA384, + .hashalg_flag = TPM2_ALG_SHA384_FLAG, .hash_buffersize = SHA384_BUFSIZE, + .name = "SHA384", + }, { .hashalg = TPM2_ALG_SHA512, + .hashalg_flag = TPM2_ALG_SHA512_FLAG, .hash_buffersize = SHA512_BUFSIZE, + .name = "SHA512", }, { .hashalg = TPM2_ALG_SM3_256, + .hashalg_flag = TPM2_ALG_SM3_256_FLAG, .hash_buffersize = SM3_256_BUFSIZE, + .name = "SM3-256", } }; @@ -141,6 +160,18 @@ static const struct hash_parameters *tpm20_find_by_hashalg(uint16_t hashAlg) return NULL; } +static const struct hash_parameters * +tpm20_find_by_hashalg_flag(uint16_t hashalg_flag) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) { + if (hash_parameters[i].hashalg_flag == hashalg_flag) + return &hash_parameters[i]; + } + return NULL; +} + static inline int tpm20_get_hash_buffersize(uint16_t hashAlg) { const struct hash_parameters *hp = tpm20_find_by_hashalg(hashAlg); @@ -150,6 +181,35 @@ static inline int tpm20_get_hash_buffersize(uint16_t hashAlg) return -1; } +static inline uint8_t tpm20_hashalg_to_flag(uint16_t hashAlg) +{ + const struct hash_parameters *hp = tpm20_find_by_hashalg(hashAlg); + + if (hp) + return hp->hashalg_flag; + return 0; +} + +static uint16_t tpm20_hashalg_flag_to_hashalg(uint8_t hashalg_flag) +{ + const struct hash_parameters *hp; + + hp = tpm20_find_by_hashalg_flag(hashalg_flag); + if (hp) + return hp->hashalg; + return 0; +} + +static const char * tpm20_hashalg_flag_to_name(uint8_t hashalg_flag) +{ + const struct hash_parameters *hp; + + hp = tpm20_find_by_hashalg_flag(hashalg_flag); + if (hp) + return hp->name; + return NULL; +} + /* * Build the TPM2 TPML_DIGEST_VALUES data structure from the given hash. * Follow the PCR bank configuration of the TPM and write the same hash @@ -923,3 +983,291 @@ void tpm_driver_set_failure_reason(uint32_t errcode) spapr_vtpm_set_error(errcode); } + +/**************************************************************** + * TPM Configuration Menu + ****************************************************************/ + +static int +tpm20_get_suppt_pcrbanks(uint8_t *suppt_pcrbanks, uint8_t *active_pcrbanks) +{ + struct tpms_pcr_selection *sel; + void *end; + + *suppt_pcrbanks = 0; + *active_pcrbanks = 0; + + sel = tpm_state.tpm20_pcr_selection->selections; + end = (void*)tpm_state.tpm20_pcr_selection + + tpm_state.tpm20_pcr_selection_size; + + while (1) { + uint16_t hashalg; + uint8_t hashalg_flag; + unsigned i; + uint8_t sizeOfSelect = sel->sizeOfSelect; + void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect; + + if (nsel > end) + return 0; + + hashalg = be16_to_cpu(sel->hashAlg); + hashalg_flag = tpm20_hashalg_to_flag(hashalg); + + *suppt_pcrbanks |= hashalg_flag; + + for (i = 0; i < sizeOfSelect; i++) { + if (sel->pcrSelect[i]) { + *active_pcrbanks |= hashalg_flag; + break; + } + } + + sel = nsel; + } +} + +static int +tpm20_set_pcrbanks(uint32_t 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 { + uint16_t hashAlg; + uint8_t sizeOfSelect; + uint8_t pcrSelect[3]; + } tps[ARRAY_SIZE(trpa.tpms_pcr_selections)]; + int i = 0; + uint8_t hashalg_flag = TPM2_ALG_SHA1_FLAG; + uint8_t dontcare, suppt_banks; + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + uint16_t hashalg; + int ret; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare); + + while (hashalg_flag) { + if ((hashalg_flag & suppt_banks)) { + hashalg = tpm20_hashalg_flag_to_hashalg(hashalg_flag); + + if (hashalg) { + uint8_t 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(offset_of(struct tpm2_req_pcr_allocate, + tpms_pcr_selections) + + i * sizeof(tps[0])); + + ret = spapr_transmit(0, &trpa.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); + ret = ret ? -1 : be32_to_cpu(rsp.errcode); + + return ret; +} + +static int tpm20_activate_pcrbanks(uint32_t active_banks) +{ + int ret; + + ret = tpm20_set_pcrbanks(active_banks); + if (!ret) + ret = tpm_simple_cmd(0, TPM2_CC_Shutdown, + 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT); + if (!ret) + SLOF_reset(); + return ret; +} + +static int +tpm20_clearcontrol(uint8_t disable) +{ + 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; + uint32_t resp_length = sizeof(rsp); + int ret; + + ret = spapr_transmit(0, &trc.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf("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; + uint32_t resp_length = sizeof(rsp); + int ret; + + ret = spapr_transmit(0, &trq.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_MEDIUM); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf("TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n", + ret); + + return ret; +} + +static int tpm20_menu_change_active_pcrbanks(void) +{ + uint8_t active_banks, suppt_banks, activate_banks; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &active_banks); + + activate_banks = active_banks; + + while (1) { + uint8_t hashalg_flag = TPM2_ALG_SHA1_FLAG; + uint8_t i = 0; + uint8_t flagnum; + int show = 0; + + printf("\nToggle active PCR banks by pressing number key\n\n"); + + while (hashalg_flag) { + uint8_t 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 changes\n"); + if (activate_banks) + printf("a : activate selection\n"); + + while (!show) { + int key_code = SLOF_get_keystroke(); + + switch (key_code) { + case ~0: + continue; + case 27: /* ESC */ + printf("\n"); + return -1; + case '1' ... '5': /* keys 1 .. 5 */ + flagnum = key_code - '0'; + if (flagnum > i) + continue; + if (suppt_banks & (1 << (flagnum - 1))) { + activate_banks ^= 1 << (flagnum - 1); + show = 1; + } + break; + case 'a': /* a */ + if (activate_banks) + tpm20_activate_pcrbanks(activate_banks); + } + } + } +} + +void tpm20_menu(void) +{ + int key_code; + int waitkey; + int ret; + + for (;;) { + printf("1. Clear TPM\n"); + printf("2. Change active PCR banks\n"); + + printf("\nIf not change is desired or if this menu was reached by " + "mistake, press ESC to\ncontinue the boot.\n"); + + waitkey = 1; + + while (waitkey) { + key_code = SLOF_get_keystroke(); + switch (key_code) { + case 27: + // ESC + return; + case '1': + ret = tpm20_clearcontrol(false); + if (!ret) + ret = tpm20_clear(); + if (ret) + printf("An error occurred clearing " + "the TPM: 0x%x\n", + ret); + break; + case '2': + tpm20_menu_change_active_pcrbanks(); + waitkey = 0; + continue; + default: + continue; + } + + waitkey = 0; + } + } +} diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h index e9f9c36..c4a2e71 100644 --- a/lib/libtpm/tcgbios.h +++ b/lib/libtpm/tcgbios.h @@ -28,5 +28,6 @@ uint32_t tpm_add_event_separators(uint32_t start_pcr, uint32_t end_pcr); uint32_t tpm_driver_get_failure_reason(void); void tpm_driver_set_failure_reason(uint32_t errcode); bool tpm_is_working(void); +void tpm20_menu(void); #endif /* TCGBIOS_H */ diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code index 05f4547..b8f5669 100644 --- a/lib/libtpm/tpm.code +++ b/lib/libtpm/tpm.code @@ -128,3 +128,12 @@ PRIM(tpm_X2d_measure_X2d_scrtm) PUSH; TOS.n = tpm_measure_scrtm(); MIRP + +/*******************************************************************/ +/* Firmware API */ +/* SLOF: tpm20-menu ( -- tpm-version ) */ +/* LIBTPM: tpm20_menu() */ +/*******************************************************************/ +PRIM(tpm20_X2d_menu) + tpm20_menu(); +MIRP diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in index 22713e4..590fee1 100644 --- a/lib/libtpm/tpm.in +++ b/lib/libtpm/tpm.in @@ -24,3 +24,4 @@ cod(tpm-is-working) cod(tpm-measure-scrtm) cod(tpm-driver-get-failure-reason) cod(tpm-driver-set-failure-reason) +cod(tpm20-menu) |