From patchwork Sat Jan 11 01:21:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1221518 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47vhsw5pt8z9sP6 for ; Sat, 11 Jan 2020 12:22:28 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 47vhsw4qVyzDqk7 for ; Sat, 11 Jan 2020 12:22:28 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 47vhsV23kczDqfB for ; Sat, 11 Jan 2020 12:22:06 +1100 (AEDT) Received: from pps.filterd (m0098409.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00B1HxuI007332; Fri, 10 Jan 2020 20:22:04 -0500 Received: from ppma04dal.us.ibm.com (7a.29.35a9.ip4.static.sl-reverse.com [169.53.41.122]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xedsu68rs-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Jan 2020 20:22:03 -0500 Received: from pps.filterd (ppma04dal.us.ibm.com [127.0.0.1]) by ppma04dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00B1LTgP006856; Sat, 11 Jan 2020 01:22:03 GMT Received: from b03cxnp08028.gho.boulder.ibm.com (b03cxnp08028.gho.boulder.ibm.com [9.17.130.20]) by ppma04dal.us.ibm.com with ESMTP id 2xajb7t4h0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 11 Jan 2020 01:22:03 +0000 Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp08028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00B1M2BT61276586 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 11 Jan 2020 01:22:02 GMT Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 3313A6E054; Sat, 11 Jan 2020 01:22:02 +0000 (GMT) Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id ADA1D6E04C; Sat, 11 Jan 2020 01:22:01 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP; Sat, 11 Jan 2020 01:22:01 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Fri, 10 Jan 2020 20:21:55 -0500 Message-Id: <20200111012155.3350198-8-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200111012155.3350198-1-stefanb@linux.ibm.com> References: <20200111012155.3350198-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.572 definitions=2020-01-10_04:2020-01-10, 2020-01-10 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=9 priorityscore=1501 lowpriorityscore=0 malwarescore=0 impostorscore=0 phishscore=0 bulkscore=0 adultscore=0 mlxscore=0 mlxlogscore=999 spamscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001110008 Subject: [SLOF] [PATCH v5 7/7] tcgbios: Implement menu to clear TPM 2 and activate its PCR banks X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kevin@koconnor.net, Stefan Berger Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" 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 --- board-qemu/slof/OF.fs | 3 + board-qemu/slof/vtpm-sml.fs | 6 + lib/libtpm/tcgbios.c | 324 ++++++++++++++++++++++++++++++++++++ lib/libtpm/tcgbios.h | 1 + lib/libtpm/tpm.code | 9 + lib/libtpm/tpm.in | 1 + slof/fs/start-up.fs | 9 + 7 files changed, 353 insertions(+) diff --git a/board-qemu/slof/OF.fs b/board-qemu/slof/OF.fs index 3e117ad..7bdd6ea 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." terminal-write drop + 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 a140276..53d9eae 100644 --- a/board-qemu/slof/vtpm-sml.fs +++ b/board-qemu/slof/vtpm-sml.fs @@ -116,6 +116,12 @@ log-base LOG-SIZE tpm-set-log-parameters 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 ba5cc46..c493bb7 100644 --- a/lib/libtpm/tcgbios.c +++ b/lib/libtpm/tcgbios.c @@ -117,19 +117,30 @@ static const struct hash_parameters { } 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", } }; @@ -145,6 +156,42 @@ tpm20_get_hash_buffersize(uint16_t hashAlg) return -1; } +static uint8_t +tpm20_hashalg_to_flag(uint16_t hashAlg) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) { + if (hash_parameters[i].hashalg == hashAlg) + return hash_parameters[i].hashalg_flag; + } + return 0; +} + +static uint16_t +tpm20_hashalg_flag_to_hashalg(uint8_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].hashalg; + } + return 0; +} + +static const char * +tpm20_hashalg_flag_to_name(uint8_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].name; + } + return NULL; +} + /* * Build the TPM2 tpm2_digest_values data structure from the given hash. * Follow the PCR bank configuration of the TPM and write the same hash @@ -914,3 +961,280 @@ 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) +{ + *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) { + uint8_t sizeOfSelect = sel->sizeOfSelect; + void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect; + if (nsel > end) + return 0; + + uint16_t hashalg = be16_to_cpu(sel->hashAlg); + uint8_t 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(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; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare); + + while (hashalg_flag) { + if ((hashalg_flag & suppt_banks)) { + uint16_t 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])); + + struct tpm_rsp_header rsp; + uint32_t 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 tpm20_activate_pcrbanks(uint32_t active_banks) +{ + int 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 = tpmhw_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 = tpmhw_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; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &active_banks); + + uint8_t activate_banks = active_banks; + + while (1) { + uint8_t hashalg_flag = TPM2_ALG_SHA1_FLAG; + uint8_t i = 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"); + + uint8_t flagnum; + int show = 0; + 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 a9fbbb8..ef792c5 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 8254eba..1ec91ca 100644 --- a/slof/fs/start-up.fs +++ b/slof/fs/start-up.fs @@ -55,6 +55,14 @@ nvramlog-write-string-cr ; +: (t-pressed) ( -- ) + s" /ibm,vtpm" find-node dup IF + s" vtpm-menu" rot $call-static + ELSE + drop + THEN +; + : (boot?) ( -- ) \ last step before we boot we give up physical presence on the TPM s" /ibm,vtpm" find-node dup IF @@ -107,6 +115,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