[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