aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorStefan Berger <stefanb@linux.ibm.com>2020-01-21 15:01:46 -0500
committerAlexey Kardashevskiy <aik@ozlabs.ru>2020-02-21 14:03:07 +1100
commit8a6b0d7061c5e504be2e378bd691a762307a1805 (patch)
treef54824d7e940d210d312230c590d959a231fd4a7 /lib
parentae2e38c3ad59bfebfd35f1f5c1f4636147d67999 (diff)
downloadSLOF-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.c348
-rw-r--r--lib/libtpm/tcgbios.h1
-rw-r--r--lib/libtpm/tpm.code9
-rw-r--r--lib/libtpm/tpm.in1
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)