From patchwork Wed Mar 30 17:55:41 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 88945 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) by ozlabs.org (Postfix) with ESMTP id 15147B6F10 for ; Thu, 31 Mar 2011 05:09:37 +1100 (EST) Received: from localhost ([127.0.0.1]:52028 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q4zkD-0007R0-NP for incoming@patchwork.ozlabs.org; Wed, 30 Mar 2011 14:03:49 -0400 Received: from [140.186.70.92] (port=60239 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q4zcn-00042b-KO for qemu-devel@nongnu.org; Wed, 30 Mar 2011 13:56:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q4zcj-0008Hq-8m for qemu-devel@nongnu.org; Wed, 30 Mar 2011 13:56:09 -0400 Received: from e35.co.us.ibm.com ([32.97.110.153]:52125) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q4zci-0008HS-SW for qemu-devel@nongnu.org; Wed, 30 Mar 2011 13:56:05 -0400 Received: from d03relay01.boulder.ibm.com (d03relay01.boulder.ibm.com [9.17.195.226]) by e35.co.us.ibm.com (8.14.4/8.13.1) with ESMTP id p2UHeRNh019301 for ; Wed, 30 Mar 2011 11:40:27 -0600 Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d03relay01.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p2UHu4pV096906 for ; Wed, 30 Mar 2011 11:56:04 -0600 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p2UHu2U6031864 for ; Wed, 30 Mar 2011 11:56:03 -0600 Received: from localhost6.localdomain6 (d941e-10.watson.ibm.com [9.59.241.154]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p2UHu0C1031725 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 30 Mar 2011 11:56:01 -0600 Received: from localhost6.localdomain6 (localhost.localdomain [127.0.0.1]) by localhost6.localdomain6 (8.14.4/8.14.3) with ESMTP id p2UHu0kO024925; Wed, 30 Mar 2011 13:56:00 -0400 Received: (from root@localhost) by localhost6.localdomain6 (8.14.4/8.14.4/Submit) id p2UHu0kG024924; Wed, 30 Mar 2011 13:56:00 -0400 Message-Id: <20110330175600.354016618@linux.vnet.ibm.com> User-Agent: quilt/0.48-1 Date: Wed, 30 Mar 2011 13:55:41 -0400 From: Stefan Berger To: stefanb@linux.vnet.ibm.com, seabios@seabios.org References: <20110330175534.302129463@linux.vnet.ibm.com> Content-Disposition: inline; filename=tcgbios_menu.diff X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 32.97.110.153 Cc: qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH V1 7/8] Add a menu for TPM control X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM. If a working TPM has been detected, the top level BIOS menu will look like this: Press F12 for boot menu. Press F11 to TPM menu. Upon pressing F11 the TPM menu will be shown: 1. Enable TPM 2. Disable TPM 3. Activate TPM 4. Deactivate TPM 5. Clear ownership 6. Allow installation of owner 7. Prevent installation of owner Escape for previous menu. TPM is enabled, active, does not have an owner but one can be installed. The code for the above 7 menu items is part of this patch. Signed-off-by: Stefan Berger --- src/boot.c | 10 - src/tcgbios.c | 576 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 584 insertions(+), 2 deletions(-) Index: seabios/src/tcgbios.c =================================================================== --- seabios.orig/src/tcgbios.c +++ seabios/src/tcgbios.c @@ -1,4 +1,4 @@ -/* +;/* * Implementation of the TCG BIOS extension according to the specification * described in * https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf @@ -95,6 +95,11 @@ static tcpa_state_t tcpa_state = { extern struct tpm_driver tpm_drivers[]; +typedef struct { + u16 revision; + u8 op; +} tpm_bios_cfg_t; + /******************************************************** Extensions for TCG-enabled BIOS @@ -1633,4 +1638,573 @@ tcpa_measure_post(void *from, void *to) } + +static u32 +assert_physical_presence(void) +{ + u32 rc = 0; + u32 returnCode; + + rc = build_and_send_cmd(TPM_ORD_PhysicalPresence, + PhysicalPresence_CMD_ENABLE, + sizeof(PhysicalPresence_CMD_ENABLE), + NULL, 10, &returnCode); + +#ifdef DEBUG_TCGBIOS + printf("Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n", + returnCode); +#endif + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(TPM_ORD_PhysicalPresence, + PhysicalPresence_PRESENT, + sizeof(PhysicalPresence_PRESENT), + NULL, 10, &returnCode); + +#ifdef DEBUG_TCGBIOS + printf("Return code from TSC_PhysicalPresence(PRESENT) = 0x%08x\n", + returnCode); +#endif + if (rc || returnCode) + goto err_exit; + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +read_permanent_flags(char *buf, int buf_len) +{ + u32 rc; + u32 returnCode; + struct tpm_res_getcap_perm_flags pf; + + memset(buf, 0x0, buf_len); + + rc = build_and_send_cmd(TPM_ORD_GetCapability, + GetCapability_Permanent_Flags, + sizeof(GetCapability_Permanent_Flags), + (u8 *)&pf, + sizeof(struct tpm_res_getcap_perm_flags), + &returnCode); + +#ifdef DEBUG_TCGBIOS + dprintf(1, "TCGBIOS: Return code from TPM_GetCapability() = 0x%08x\n", + returnCode); +#endif + + if (rc || returnCode) + goto err_exit; + + memcpy(buf, &pf.perm_flags, buf_len); + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +read_has_owner(u8 *has_owner) +{ + u32 rc; + u32 returnCode; + struct tpm_res_getcap_ownerauth oauth; + + rc = build_and_send_cmd(TPM_ORD_GetCapability, + GetCapability_OwnerAuth, + sizeof(GetCapability_OwnerAuth), + (u8 *)&oauth, + sizeof(struct tpm_res_getcap_ownerauth), + &returnCode); + +#ifdef DEBUG_TCGBIOS + dprintf(1, "TCGBIOS: Return code from TPM_GetCapability() = 0x%08x\n", + returnCode); +#endif + + if (rc || returnCode) + goto err_exit; + + *has_owner = oauth.flag; + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +disable_tpm(int disable, int verbose) +{ + u32 rc; + u32 returnCode; + struct tpm_permanent_flags pf; + + rc = read_permanent_flags((char *)&pf, sizeof(pf)); + if (rc) + return rc; + + if (!!pf.flags[PERM_FLAG_IDX_DISABLE] == !!disable) { + if (verbose) + printf("TPM is already %s.\n,", + disable ? "disabled" : "enabled"); + return 0; + } + + rc = assert_physical_presence(); + if (rc) { +#ifdef DEBUG_TCGBIOS + dprintf(1, "TCGBIOS: Asserting physical presence " + "failed.\n"); +#endif + return rc; + } + + rc = build_and_send_cmd(disable ? TPM_ORD_PhysicalDisable + : TPM_ORD_PhysicalEnable, + NULL, 0, NULL, 10, &returnCode); +#ifdef DEBUG_TCGBIOS + printf("Return code from TPM_Physical%sable = 0x%08x\n", + disable ? "Dis" : "En", returnCode); +#endif + if (rc || returnCode) + goto err_exit; + + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1, "TCGBIOS: %sabling the TPM failed.\n", + disable ? "Dis" : "En"); + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +deactivate_tpm(int deactivate, int allow_reset, int verbose) +{ + u32 rc; + u32 returnCode; + struct tpm_permanent_flags pf; + + rc = read_permanent_flags((char *)&pf, sizeof(pf)); + if (rc) + return rc; + + if (!!pf.flags[PERM_FLAG_IDX_DEACTIVATED] == !!deactivate) { + if (verbose) + printf("TPM is already %s.\n", + deactivate ? "deactivated" : "activated"); + return 0; + } + + if (pf.flags[PERM_FLAG_IDX_DISABLE]) { + if (verbose) + printf("TPM must first be enabled.\n"); + return 0; + } + + rc = assert_physical_presence(); + if (rc) { +#ifdef DEBUG_TCGBIOS + dprintf(1, "TCGBIOS: Asserting physical presence " + "failed.\n"); +#endif + return rc; + } + + rc = build_and_send_cmd(TPM_ORD_PhysicalSetDeactivated, + deactivate ? CommandFlag_TRUE + : CommandFlag_FALSE, + deactivate ? sizeof(CommandFlag_TRUE) + : sizeof(CommandFlag_FALSE), + NULL, 10, &returnCode); +#ifdef DEBUG_TCGBIOS + printf("Return code from PhysicalSetDeactivated(%d) = 0x%08x\n", + deactivate ? 1 : 0, returnCode); +#endif + if (rc || returnCode) + goto err_exit; + + if (!deactivate && allow_reset) { + if (verbose) { + printf("Requiring a reboot to activate the TPM.\n"); + + msleep(2000); + } + reset_vector(); + } + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +enable_activate(int allow_reset, int verbose) +{ + u32 rc; + + rc = disable_tpm(0, verbose); + if (rc) + return rc; + + rc = deactivate_tpm(0, allow_reset, verbose); + + return rc; +} + + +static u32 +force_clear(int enable_activate_before, int enable_activate_after, int verbose) +{ + u32 rc; + u32 returnCode; + u8 has_owner; + + rc = read_has_owner(&has_owner); + if (rc) + return rc; + if (!has_owner) { + if (verbose) + printf("TPM does not have an owner.\n"); + return 0; + } + + if (enable_activate_before) { + rc = enable_activate(0, verbose); + if (rc) { +#ifdef DEBUG_TCGBIOS + dprintf(1, "TCGBIOS: Enabling/activating the TPM " + "failed.\n"); +#endif + return rc; + } + } + + rc = assert_physical_presence(); + if (rc) { +#ifdef DEBUG_TCGBIOS + dprintf(1, "TCGBIOS: Asserting physical presence " + "failed.\n"); +#endif + return rc; + } + + rc = build_and_send_cmd(TPM_ORD_ForceClear, + NULL, 0, NULL, 10, &returnCode); +#ifdef DEBUG_TCGBIOS + printf("Return code from TPM_ForceClear() = 0x%08x\n", returnCode); +#endif + if (rc || returnCode) + goto err_exit; + + if (!enable_activate_after) { + if (verbose) + printf("Owner successfully cleared.\n" + "You will need to enable/activate the TPM again.\n\n"); + return 0; + } + + enable_activate(1, verbose); + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +set_owner_install(int allow, int verbose) +{ + u32 rc, returnCode; + u8 has_owner; + struct tpm_permanent_flags pf; + + rc = read_has_owner(&has_owner); + if (rc) + return rc; + if (has_owner) { + if (verbose) + printf("Must first remove owner.\n"); + return 0; + } + + rc = read_permanent_flags((char *)&pf, sizeof(pf)); + if (rc) + return rc; + + if (pf.flags[PERM_FLAG_IDX_DISABLE]) { + if (verbose) + printf("TPM must first be enable.\n"); + return 0; + } + + rc = assert_physical_presence(); + if (rc) { +#ifdef DEBUG_TCGBIOS + dprintf(1, "TCGBIOS: Asserting physical presence failed.\n"); +#endif + return rc; + } + + rc = build_and_send_cmd(TPM_ORD_SetOwnerInstall, + (allow) ? CommandFlag_TRUE : + CommandFlag_FALSE, + sizeof(CommandFlag_TRUE), + NULL, 10, &returnCode); +#ifdef DEBUG_TCGBIOS + printf("Return code from TPM_SetOwnerInstall() = 0x%08x\n", + returnCode); +#endif + if (rc || returnCode) + goto err_exit; + + if (verbose) + printf("Installation of owner %s.\n", allow ? "enabled" : "disabled"); + + return 0; + +err_exit: +#ifdef DEBUG_TCGBIOS + dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); +#endif + tcpa_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static void +show_tpm_state(void) +{ + struct tpm_permanent_flags pf; + u8 has_owner; + + if (read_permanent_flags((char *)&pf, sizeof(pf)) || + read_has_owner(&has_owner)) + return; + + printf("TPM is "); + + if (pf.flags[PERM_FLAG_IDX_DISABLE]) + printf("disabled"); + else + printf("enabled"); + + if (pf.flags[PERM_FLAG_IDX_DEACTIVATED]) + printf(", deactivated"); + else + printf(", active"); + + if (has_owner) + printf(" and has an owner.\n"); + else { + printf(", does not have an owner "); + if (pf.flags[PERM_FLAG_IDX_OWNERSHIP]) + printf("but one can be installed.\n"); + else + printf("and an owner cannot be installed.\n"); + } + +} + + +static u32 +tcpa_process_cfg(const tpm_bios_cfg_t *cfg, int verbose) +{ + u32 rc = 0; + +#ifdef DEBUG_TCGBIOS + printf("TCGBIOS: cfg rev = %d, op = %d\n", cfg->revision, cfg->op); +#endif + if (cfg->revision < 1) + return 0; + + switch (cfg->op) { + case 0: /* no-op */ + break; + + case 1: + rc = disable_tpm(0, verbose); + break; + + case 2: + rc = disable_tpm(1, verbose); + break; + + case 3: + rc = deactivate_tpm(0, 1, verbose); + break; + + case 4: + rc = deactivate_tpm(1, 1, verbose); + break; + + case 5: + rc = force_clear(0, 0, verbose); + break; + + case 6: + rc = enable_activate(1, verbose); + break; + + case 7: + rc = deactivate_tpm(1, 1, verbose); + if (!rc) + rc = disable_tpm(1, verbose); + break; + + case 8: + rc = set_owner_install(1, verbose); + break; + + case 9: + rc = set_owner_install(0, verbose); + break; + + case 10: + rc = enable_activate(1, verbose); + if (!rc) + rc = set_owner_install(1, verbose); + break; + + case 11: + rc = set_owner_install(0, verbose); + if (!rc) { + rc = deactivate_tpm(1, 1, verbose); + if (!rc) + rc = disable_tpm(1, verbose); + } + break; + + case 14: + rc = force_clear(0, 1, verbose); + break; + + case 21: + rc = force_clear(1, 0, verbose); + break; + + case 22: + rc = force_clear(1, 1, verbose); + break; + + default: + break; + } + + if (rc) + printf("Op %d: An error occurred: 0x%x\n", cfg->op, rc); + + return rc; +} + + +void +tcpa_menu(void) +{ + int show_menu = 1; + int scan_code; + u32 rc; + tpm_bios_cfg_t cfg = { + .revision = 1, + .op = 0, + }; + + while (get_keystroke(0) >= 0) + ; + wait_threads(); + + for (;;) { + if (show_menu) { + printf("1. Enable TPM\n" + "2. Disable TPM\n" + "3. Activate TPM\n" + "4. Deactivate TPM\n" + "5. Clear ownership\n" + "6. Allow installation of owner\n" + "7. Prevent installation of owner\n" + "Escape for previous menu.\n"); + show_menu = 0; + show_tpm_state(); + } + + cfg.op = 0; + + scan_code = get_keystroke(1000); + + switch (scan_code) { + case 1: + // ESC + return; + case 2 ... 5: + cfg.op = scan_code - 1; + break; + case 6: /* force clear */ + cfg.op = 21; + break; + case 7 ... 8: + cfg.op = scan_code + 1; + break; + default: + continue; + } + + rc = tcpa_process_cfg(&cfg, 1); + + if (rc) + printf("An error occurred: 0x%x\n", rc); + + show_menu = 1; + } +} + #endif /* CONFIG_TCGBIOS */ Index: seabios/src/boot.c =================================================================== --- seabios.orig/src/boot.c +++ seabios/src/boot.c @@ -364,11 +364,19 @@ interactive_bootmenu(void) while (get_keystroke(0) >= 0) ; - printf("Press F12 for boot menu.\n\n"); +again: + printf("Press F12 for boot menu.\n"); + if (has_working_tpm()) + printf("Press F11 to TPM menu.\n"); + printf("\n"); enable_bootsplash(); int scan_code = get_keystroke(CONFIG_BOOTMENU_WAIT); disable_bootsplash(); + if (has_working_tpm() && scan_code == 0x85) { + tcpa_menu(); + goto again; + } if (scan_code != 0x86) /* not F12 */ return;