[SLOF] [PATCH v7 7/8] tcgbios: Implement menu to clear TPM 2 and activate its PCR banks
Kevin O'Connor
kevin at koconnor.net
Sat Feb 15 02:37:08 AEDT 2020
On Tue, Jan 21, 2020 at 03:01:46PM -0500, Stefan Berger wrote:
> 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 at linux.ibm.com>
Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
-Kevin
> ---
> board-qemu/slof/OF.fs | 3 +
> board-qemu/slof/vtpm-sml.fs | 6 +
> lib/libtpm/tcgbios.c | 348 ++++++++++++++++++++++++++++++++++++
> lib/libtpm/tcgbios.h | 1 +
> lib/libtpm/tpm.code | 9 +
> lib/libtpm/tpm.in | 1 +
> slof/fs/start-up.fs | 7 +
> 7 files changed, 375 insertions(+)
>
> diff --git a/board-qemu/slof/OF.fs b/board-qemu/slof/OF.fs
> index 3e117ad..f0fc9c6 100644
> --- a/board-qemu/slof/OF.fs
> +++ b/board-qemu/slof/OF.fs
> @@ -175,6 +175,9 @@ CREATE version-str 10 ALLOT
> version-str 8 + @ \ end
> over - dump-display-write
> " Press 's' to enter Open Firmware." dump-display-write
> + s" /ibm,vtpm" find-node IF
> + " Press 't' to enter TPM menu." dump-display-write
> + THEN
> cr cr
> temp-ptr disp-size > IF
> temp-ptr disp-size MOD
> diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs
> index 8e2ab6d..a51c907 100644
> --- a/board-qemu/slof/vtpm-sml.fs
> +++ b/board-qemu/slof/vtpm-sml.fs
> @@ -56,6 +56,12 @@ s" ibm,vtpm" 2dup device-name device-type
> THEN
> ;
>
> +: vtpm-menu
> + tpm-is-working IF
> + tpm20-menu
> + THEN
> +;
> +
> : open true ;
> : close ;
>
> 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)
> diff --git a/slof/fs/start-up.fs b/slof/fs/start-up.fs
> index c1f931a..45e8926 100644
> --- a/slof/fs/start-up.fs
> +++ b/slof/fs/start-up.fs
> @@ -55,6 +55,12 @@
> nvramlog-write-string-cr
> ;
>
> +: (t-pressed) ( -- )
> + s" /ibm,vtpm" find-node ?dup IF
> + s" vtpm-menu" rot $call-static
> + THEN
> +;
> +
> : (boot?) ( -- )
> \ last step before we boot we give up physical presence on the TPM
> s" /ibm,vtpm" find-node ?dup IF
> @@ -105,6 +111,7 @@ TRUE VALUE use-load-watchdog?
> key? IF
> key CASE
> [char] s OF (s-pressed) ENDOF
> + [char] t OF (t-pressed) (boot?) ENDOF
> 1b OF
> (esc-sequence) CASE
> 1 OF
> --
> 2.24.1
>
More information about the SLOF
mailing list