The following set of patches add support for - the BIOS taking measurements of various parts of the code and data, adding them to the ACPI log, and extending the PCRs of the TPM with the measurements - a reworked TPM menu - a reworked Physical Presence Interface
Regards, Stefan
Stefan Berger (3): Add 'measurement' code to the BIOS Support for TPM Physical Presence Interface Add a menu for TPM control
src/boot.c | 20 +- src/cdrom.c | 4 + src/hw/tpm_drivers.h | 1 + src/optionroms.c | 2 + src/tcgbios.c | 1067 +++++++++++++++++++++++++++++++++++++++++++++++++- src/tcgbios.h | 50 +++ src/util.h | 1 + 7 files changed, 1140 insertions(+), 5 deletions(-)
This patch adds invocations of functions that measure various parts of the code and data through various parts of the BIOS code. It follows TCG specifications on what needs to be measured. It also adds the implementation of the called functions.
Reference for what needs to be measured can be found in specs found here:
http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific...
The first measurements are done once the ACPI tables have been initialized.
Once booted into Linux, the current measurements produce the following logs which can be found in /sys/kernel/security/tpm0/ascii_bios_measurements. The below log also shows measurements from trusted grub.
1 3fb240d2a04085a4e84f81e4398e070ed5a18163 06 [SMBIOS] 2 cc812353fc277c1fab99e0b721752a1392984566 06 [Option ROM] 2 9dbd87163112e5670378abe4510491259a61f411 05 [Start Option ROM Scan] 2 6f74e357331b8dee11bbad85f27bc66cb873106c 06 [Option ROM] 2 5626eb7ac05c7231e46d7461e7d3839b03ae9fad 06 [Option ROM] 4 c1e25c3f6b0dc78d57296aa2870ca6f782ccf80f 05 [Calling INT 19h] 0 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 1 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 2 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 3 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 4 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 5 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 6 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 7 d9be6524a5f5047db5866813acf3277892a7a30a 04 [] 4 8cf2fe6c87d4d0b2998a43da630292e6d85ee8b6 05 [Booting BCV device 80h (HDD)] 4 5dff94459a3e2d13a433ef94afdc306144565bf7 0d [IPL] 5 d1b33afde65ad47502332af957c60f20c84c1edc 0e [IPL Partition Data] 4 487ce764b527ccad17f1d04243d0136fa981e6c4 0d [IPL] 4 91d285e4dead566324c8938a3cc75803f462d9a1 0d [IPL] 4 8ba79ac98bb491524fef29defc724daaf6263d35 0d [IPL] 4 c591c15b82e4ff30e7383a4ff1ef3b41b38521ac 06 [] 4 8cdc27ec545eda33fbba1e8b8dae4da5c7206972 04 [Grub Event Separator] 5 8cdc27ec545eda33fbba1e8b8dae4da5c7206972 04 [Grub Event Separator] 5 e8673b9e14b02dc12d8ccfd0176bca7a3de7fc3c 0e [IPL Partition Data] 5 0163e375a0af7525c5dac1a8e74b277359e40d1d 1105 [] 8 4be30f67c3d48ab7f04d9c0fd07f06d4c68379be 1205 [] 8 54c83965978de9708d026016ecb0e70660e04388 1305 [] 5 2431ed60130faeaf3a045f21963f71cacd46a029 04 [OS Event Separator] 8 2431ed60130faeaf3a045f21963f71cacd46a029 04 [OS Event Separator] 8 f3973cae05d6e2055062119d6e6e1e077b7df876 1005 []
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
--- src/boot.c | 6 + src/cdrom.c | 4 + src/optionroms.c | 2 + src/tcgbios.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/tcgbios.h | 4 + 5 files changed, 390 insertions(+), 3 deletions(-)
diff --git a/src/boot.c b/src/boot.c index d6b1fb7..ec59c37 100644 --- a/src/boot.c +++ b/src/boot.c @@ -19,6 +19,7 @@ #include "std/disk.h" // struct mbr_s #include "string.h" // memset #include "util.h" // irqtimer_calc +#include "tcgbios.h" // tpm_*
/**************************************************************** @@ -628,6 +629,8 @@ boot_disk(u8 bootdrv, int checksig) } }
+ tpm_add_bcv(bootdrv, MAKE_FLATPTR(bootseg, 0), 512); + /* Canonicalize bootseg:bootip */ u16 bootip = (bootseg & 0x0fff) << 4; bootseg &= 0xf000; @@ -651,6 +654,9 @@ boot_cdrom(struct drive_s *drive_g)
u8 bootdrv = CDEmu.emulated_drive; u16 bootseg = CDEmu.load_segment; + + tpm_add_cdrom(bootdrv, MAKE_FLATPTR(bootseg, 0), 512); + /* Canonicalize bootseg:bootip */ u16 bootip = (bootseg & 0x0fff) << 4; bootseg &= 0xf000; diff --git a/src/cdrom.c b/src/cdrom.c index 92f34f4..7ee36d9 100644 --- a/src/cdrom.c +++ b/src/cdrom.c @@ -15,6 +15,7 @@ #include "std/disk.h" // DISK_RET_SUCCESS #include "string.h" // memset #include "util.h" // cdrom_prepboot +#include "tcgbios.h" // tpm_*
// Locks for removable devices u8 CDRom_locks[BUILD_MAX_EXTDRIVE] VARLOW; @@ -192,6 +193,9 @@ cdrom_boot(struct drive_s *drive) if (buffer[0x20] != 0x88) return 11; // Bootable
+ /* measure 2048 bytes (one sector) */ + tpm_add_cdrom_catalog(MAKE_FLATPTR(GET_SEG(SS), buffer), sizeof(buffer)); + // Fill in el-torito cdrom emulation fields. emulated_drive_gf = drive; u8 media = buffer[0x21]; diff --git a/src/optionroms.c b/src/optionroms.c index f6047e6..7906908 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -19,6 +19,7 @@ #include "std/pnpbios.h" // PNP_SIGNATURE #include "string.h" // memset #include "util.h" // get_pnp_offset +#include "tcgbios.h" // tpm_*
static int EnforceChecksum, S3ResumeVga, RunPCIroms;
@@ -80,6 +81,7 @@ is_valid_rom(struct rom_header *rom) if (EnforceChecksum) return 0; } + tpm_option_rom(rom, len); return 1; }
diff --git a/src/tcgbios.c b/src/tcgbios.c index 04904e3..dc133c5 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -1,8 +1,8 @@ // Implementation of the TCG BIOS extension according to the specification -// described in -// https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementat... +// described in specs found at +// http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific... // -// Copyright (C) 2006-2011, 2014 IBM Corporation +// Copyright (C) 2006-2011, 2014, 2015 IBM Corporation // // Authors: // Stefan Berger stefanb@linux.vnet.ibm.com @@ -24,6 +24,7 @@ #include "bregs.h" // struct bregs #include "sha1.h" // sha1 #include "fw/paravirt.h" // runningOnXen +#include "std/smbios.h"
static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR }; static const u8 Startup_ST_STATE[2] = { 0x00, TPM_ST_STATE }; @@ -56,9 +57,17 @@ static const u8 GetCapability_Durations[] = { 0x00, 0x00, 0x01, 0x20 };
+static u8 evt_separator[] = {0xff,0xff,0xff,0xff}; +
#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr)
+/* local function prototypes */ + +static u32 tpm_calling_int19h(void); +static u32 tpm_add_event_separators(void); +static u32 tpm_start_option_rom_scan(void); +static u32 tpm_smbios_measure(void);
/* helper functions */
@@ -475,6 +484,14 @@ tpm_startup(void) if (rc) goto err_exit;
+ rc = tpm_smbios_measure(); + if (rc) + goto err_exit; + + rc = tpm_start_option_rom_scan(); + if (rc) + goto err_exit; + return 0;
err_exit: @@ -528,6 +545,14 @@ tpm_leave_bios(void) if (rc || returnCode) goto err_exit;
+ rc = tpm_calling_int19h(); + if (rc) + goto err_exit; + + rc = tpm_add_event_separators(); + if (rc) + goto err_exit; + return 0;
err_exit: @@ -1083,6 +1108,352 @@ tpm_interrupt_handler32(struct bregs *regs) return; }
+/* + * Add a measurement to the log; the data at data_seg:data/length are + * appended to the TCG_PCClientPCREventStruct + * + * Input parameters: + * pcrIndex : which PCR to extend + * event_type : type of event; specs section on 'Event Types' + * info : pointer to info (e.g., string) to be added to log as-is + * info_length: length of the info + * data : pointer to the data (i.e., string) to be added to the log + * data_length: length of the data + */ +static u32 +tpm_add_measurement_to_log(u32 pcrIndex, u32 event_type, + const char *info, u32 info_length, + const u8 *data, u32 data_length) +{ + u32 rc = 0; + struct hleeo hleeo; + u8 _pcpes[offsetof(struct pcpes, event) + 400]; + struct pcpes *pcpes = (struct pcpes *)_pcpes; + + if (info_length < sizeof(_pcpes) - offsetof(struct pcpes, event)) { + + pcpes->pcrindex = pcrIndex; + pcpes->eventtype = event_type; + memset(&pcpes->digest, 0x0, sizeof(pcpes->digest)); + pcpes->eventdatasize = info_length; + memcpy(&pcpes->event, info, info_length); + + struct hleei_short hleei = { + .ipblength = sizeof(hleei), + .hashdataptr = data, + .hashdatalen = data_length, + .pcrindex = pcrIndex, + .logdataptr = _pcpes, + .logdatalen = info_length + offsetof(struct pcpes, event), + }; + + rc = hash_log_extend_event(&hleei, &hleeo); + } else { + rc = TCG_GENERAL_ERROR; + } + + return rc; +} + + +/* + * Add a measurement to the list of measurements + * pcrIndex : PCR to be extended + * event_type : type of event; specs section on 'Event Types' + * data : additional parameter; used as parameter for + * 'action index' + */ +static u32 +tpm_add_measurement(u32 pcrIndex, + u16 event_type, + const char *string) +{ + u32 rc; + u32 len; + + switch (event_type) { + case EV_SEPARATOR: + len = sizeof(evt_separator); + rc = tpm_add_measurement_to_log(pcrIndex, event_type, + (char *)NULL, 0, + (u8 *)evt_separator, len); + break; + + case EV_ACTION: + rc = tpm_add_measurement_to_log(pcrIndex, event_type, + string, strlen(string), + (u8 *)string, strlen(string)); + break; + + default: + rc = TCG_INVALID_INPUT_PARA; + } + + return rc; +} + + +static u32 +tpm_calling_int19h(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + return tpm_add_measurement(4, EV_ACTION, + "Calling INT 19h"); +} + +/* + * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events' + */ +u32 +tpm_add_event_separators(void) +{ + u32 rc; + u32 pcrIndex = 0; + + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + while (pcrIndex <= 7) { + rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL); + if (rc) + break; + pcrIndex ++; + } + + return rc; +} + + +/* + * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to + * the list of measurements. + */ +static u32 +tpm_add_bootdevice(u32 bootcd, u32 bootdrv) +{ + const char *string; + + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + switch (bootcd) { + case 0: + switch (bootdrv) { + case 0: + string = "Booting BCV device 00h (Floppy)"; + break; + + case 0x80: + string = "Booting BCV device 80h (HDD)"; + break; + + default: + string = "Booting unknown device"; + break; + } + + break; + + default: + string = "Booting from CD ROM device"; + } + + return tpm_add_measurement_to_log(4, EV_ACTION, + string, strlen(string), + (u8 *)string, strlen(string)); +} + + +/* + * Add measurement to the log about option rom scan + */ +u32 +tpm_start_option_rom_scan(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + return tpm_add_measurement(2, EV_ACTION, + "Start Option ROM Scan"); +} + + +/* + * Add measurement to the log about an option rom + */ +u32 +tpm_option_rom(const void *addr, u32 len) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc; + struct pcctes_romex pcctes = { + .eventid = 7, + .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE, + }; + + rc = sha1((const u8 *)addr, len, pcctes.digest); + if (rc) + return rc; + + return tpm_add_measurement_to_log(2, + EV_EVENT_TAG, + (const char *)&pcctes, sizeof(pcctes), + (u8 *)&pcctes, sizeof(pcctes)); +} + + +u32 +tpm_smbios_measure(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc; + struct pcctes pcctes = { + .eventid = 1, + .eventdatasize = SHA1_BUFSIZE, + }; + struct smbios_entry_point *sep = SMBiosAddr; + + dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep); + + if (!sep) + return 0; + + rc = sha1((const u8 *)sep->structure_table_address, + sep->structure_table_length, pcctes.digest); + if (rc) + return rc; + + return tpm_add_measurement_to_log(1, + EV_EVENT_TAG, + (const char *)&pcctes, sizeof(pcctes), + (u8 *)&pcctes, sizeof(pcctes)); +} + + +/* + * Add a measurement related to Initial Program Loader to the log. + * Creates two log entries. + * + * Input parameter: + * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito + * addr : address where the IP data are located + * length : IP data length in bytes + */ +static u32 +tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length) +{ + u32 rc; + const char *string; + + switch (bootcd) { + case IPL_EL_TORITO_1: + /* specs: see section 'El Torito' */ + string = "EL TORITO IPL"; + rc = tpm_add_measurement_to_log(4, EV_IPL, + string, strlen(string), + addr, length); + break; + + case IPL_EL_TORITO_2: + /* specs: see section 'El Torito' */ + string = "BOOT CATALOG"; + rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA, + string, strlen(string), + addr, length); + break; + + default: + /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */ + /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */ + string = "MBR"; + rc = tpm_add_measurement_to_log(4, EV_IPL, + string, strlen(string), + addr, 0x1b8); + + if (rc) + break; + + /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */ + string = "MBR PARTITION_TABLE"; + rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA, + string, strlen(string), + addr + 0x1b8, 0x48); + } + + return rc; +} + +u32 +tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc = tpm_add_bootdevice(0, bootdrv); + if (rc) + return rc; + + return tpm_ipl(IPL_BCV, addr, length); +} + +u32 +tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc = tpm_add_bootdevice(1, bootdrv); + if (rc) + return rc; + + return tpm_ipl(IPL_EL_TORITO_1, addr, length); +} + +u32 +tpm_add_cdrom_catalog(const u8 *addr, u32 length) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc = tpm_add_bootdevice(1, 0); + if (rc) + return rc; + + return tpm_ipl(IPL_EL_TORITO_2, addr, length); +}
u32 tpm_s3_resume(void) diff --git a/src/tcgbios.h b/src/tcgbios.h index 72fd771..a1d0b0f 100644 --- a/src/tcgbios.h +++ b/src/tcgbios.h @@ -386,5 +386,9 @@ void tpm_interrupt_handler32(struct bregs *regs); u32 tpm_start(void); u32 tpm_leave_bios(void); u32 tpm_s3_resume(void); +u32 tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length); +u32 tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length); +u32 tpm_add_cdrom_catalog(const u8 *addr, u32 length); +u32 tpm_option_rom(const void *addr, u32 len);
#endif /* TCGBIOS_H */
On Tue, May 26, 2015 at 03:48:33PM -0400, Stefan Berger wrote:
This patch adds invocations of functions that measure various parts of the code and data through various parts of the BIOS code. It follows TCG specifications on what needs to be measured. It also adds the implementation of the called functions.
Thanks. I applied this patch.
[...]
--- a/src/optionroms.c +++ b/src/optionroms.c @@ -19,6 +19,7 @@ #include "std/pnpbios.h" // PNP_SIGNATURE #include "string.h" // memset #include "util.h" // get_pnp_offset +#include "tcgbios.h" // tpm_*
static int EnforceChecksum, S3ResumeVga, RunPCIroms;
@@ -80,6 +81,7 @@ is_valid_rom(struct rom_header *rom) if (EnforceChecksum) return 0; }
- tpm_option_rom(rom, len); return 1;
}
I don't think calling tpm_option_rom() from is_valid_rom() is correct, but I (as above) I've applied this patch as is. I think a future change should move the call. (Is calling it from init_optionrom() sufficient?)
-Kevin
On 06/01/2015 12:36 PM, Kevin O'Connor wrote:
On Tue, May 26, 2015 at 03:48:33PM -0400, Stefan Berger wrote:
This patch adds invocations of functions that measure various parts of the code and data through various parts of the BIOS code. It follows TCG specifications on what needs to be measured. It also adds the implementation of the called functions.
Thanks. I applied this patch.
[...]
--- a/src/optionroms.c +++ b/src/optionroms.c @@ -19,6 +19,7 @@ #include "std/pnpbios.h" // PNP_SIGNATURE #include "string.h" // memset #include "util.h" // get_pnp_offset +#include "tcgbios.h" // tpm_*
static int EnforceChecksum, S3ResumeVga, RunPCIroms;
@@ -80,6 +81,7 @@ is_valid_rom(struct rom_header *rom) if (EnforceChecksum) return 0; }
- tpm_option_rom(rom, len); return 1; }
I don't think calling tpm_option_rom() from is_valid_rom() is correct, but I (as above) I've applied this patch as is. I think a future change should move the call. (Is calling it from init_optionrom() sufficient?)
Sure, it can also be moved there. After the memmove?
Stefan
This patch implements the specification found here:
http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interfa...
It adds the necessary BIOS code so that for example an administrator can send messages from the OS to the BIOS for the BIOS to change the state of the TPM upon reboot. With the help of this interface, an administrator does not have to manually interact with the BIOS.
As an example, on Linux the root use can send an opcode to the BIOS through the TPM's sysfs entries following the opcodes listed in table 2 of the above specs. To for example disable and deactivate the TPM, the root user would send opcode '7' to the BIOS:
#> cd /sys/devices/pnp0/00:0?/ppi
#> echo 7 > request
#> reboot
To exchange data between the OS and SeaBIOS, we use the TIS's vendor specific extensions in locations 0xf90-fff where RAM locations reside that are not reset during a machine reboot. This memory is initialized and two locations receive a 32 bit value 'TCG_MAGIC' that the ACPI code and SeaBIOS are looking for to accept the memory. If after a reboot the signature is found by SeaBIOS, the opcode (sent from the OS) is looked at and acted upon.
The implementation requires an ACPI _DSM method to be implemented for the TPM's SSDT. The code in the _DSM will write the administrator's opcode into the TIS's RAM locations. The _DSM method is invoked when the root user interacts with the entries shown in the above ppi sysfs directory. The patch implementing the _DSM will be posted independently.
This patch supports opcodes 1-11, 14, 21, and 22.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/hw/tpm_drivers.h | 1 + src/tcgbios.c | 577 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/tcgbios.h | 44 ++++ 3 files changed, 622 insertions(+)
diff --git a/src/hw/tpm_drivers.h b/src/hw/tpm_drivers.h index 34bb12d..83e4a62 100644 --- a/src/hw/tpm_drivers.h +++ b/src/hw/tpm_drivers.h @@ -53,6 +53,7 @@ extern struct tpm_driver tpm_drivers[]; #define TIS_REG_DATA_FIFO 0x24 #define TIS_REG_DID_VID 0xf00 #define TIS_REG_RID 0xf04 +#define TIS_REG_RAM 0xfa0
#define TIS_STS_VALID (1 << 7) /* 0x80 */ #define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */ diff --git a/src/tcgbios.c b/src/tcgbios.c index dc133c5..3263ec6 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -25,6 +25,7 @@ #include "sha1.h" // sha1 #include "fw/paravirt.h" // runningOnXen #include "std/smbios.h" +#include "malloc.h" // malloc_*
static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR }; static const u8 Startup_ST_STATE[2] = { 0x00, TPM_ST_STATE }; @@ -42,6 +43,11 @@ static const u8 GetCapability_Permanent_Flags[12] = { 0x00, 0x00, 0x01, 0x08 };
+static const u8 GetCapability_STClear_Flags[12] = { + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x09 +}; + static const u8 GetCapability_OwnerAuth[12] = { 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x11 @@ -68,6 +74,8 @@ static u32 tpm_calling_int19h(void); static u32 tpm_add_event_separators(void); static u32 tpm_start_option_rom_scan(void); static u32 tpm_smbios_measure(void); +static void tpm_ppi_init(void); +static void tpm_ppi_process(void);
/* helper functions */
@@ -95,6 +103,10 @@ static tpm_state_t tpm_state = { .tpm_driver_to_use = TPM_INVALID_DRIVER, };
+typedef struct { + u8 op; +} tpm_bios_cfg_t; +
/******************************************************** Extensions for TCG-enabled BIOS @@ -443,6 +455,8 @@ tpm_startup(void) if (!has_working_tpm()) return TCG_GENERAL_ERROR;
+ tpm_ppi_init(); + dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n"); rc = build_and_send_cmd(0, TPM_ORD_Startup, Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR), @@ -484,6 +498,8 @@ tpm_startup(void) if (rc) goto err_exit;
+ tpm_ppi_process(); + rc = tpm_smbios_measure(); if (rc) goto err_exit; @@ -1489,3 +1505,564 @@ err_exit: return rc; return TCG_TCG_COMMAND_ERROR; } + +static u32 +read_stclear_flags(char *buf, int buf_len) +{ + u32 rc; + u32 returnCode; + struct tpm_res_getcap_stclear_flags stcf; + + memset(buf, 0x0, buf_len); + + rc = build_and_send_cmd(0, TPM_ORD_GetCapability, + GetCapability_STClear_Flags, + sizeof(GetCapability_STClear_Flags), + (u8 *)&stcf, + sizeof(struct tpm_res_getcap_stclear_flags), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() " + "= 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + memcpy(buf, &stcf.stclear_flags, buf_len); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +assert_physical_presence(int verbose) +{ + u32 rc = 0; + u32 returnCode; + struct tpm_stclear_flags stcf; + + rc = read_stclear_flags((char *)&stcf, sizeof(stcf)); + if (rc) { + dprintf(DEBUG_tcg, + "Error reading STClear flags: 0x%08x\n", rc); + return rc; + } + + if (stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE]) + /* physical presence already asserted */ + return 0; + + rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_CMD_ENABLE, + sizeof(PhysicalPresence_CMD_ENABLE), + NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, + "Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n", + returnCode); + + if (rc || returnCode) { + if (verbose) + printf("Error: Could not enable physical presence.\n\n"); + goto err_exit; + } + + rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_PRESENT, + sizeof(PhysicalPresence_PRESENT), + NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, + "Return code from TSC_PhysicalPresence(PRESENT) = 0x%08x\n", + returnCode); + + if (rc || returnCode) { + if (verbose) + printf("Error: Could not set presence flag.\n\n"); + goto err_exit; + } + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_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(0, TPM_ORD_GetCapability, + GetCapability_Permanent_Flags, + sizeof(GetCapability_Permanent_Flags), + (u8 *)&pf, + sizeof(struct tpm_res_getcap_perm_flags), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() " + "= 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + memcpy(buf, &pf.perm_flags, buf_len); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_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(0, TPM_ORD_GetCapability, + GetCapability_OwnerAuth, + sizeof(GetCapability_OwnerAuth), + (u8 *)&oauth, + sizeof(struct tpm_res_getcap_ownerauth), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() " + "= 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + *has_owner = oauth.flag; + + return 0; + +err_exit: + dprintf(DEBUG_tcg,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +disable_tpm(int disable, u32 *returnCode, int verbose) +{ + u32 rc; + 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(verbose); + if (rc) { + dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n"); + return rc; + } + + rc = build_and_send_cmd(0, disable ? TPM_ORD_PhysicalDisable + : TPM_ORD_PhysicalEnable, + NULL, 0, NULL, 10, returnCode, + TPM_DURATION_TYPE_SHORT); + dprintf(DEBUG_tcg, "Return code from TPM_Physical%sable = 0x%08x\n", + disable ? "Dis" : "En", *returnCode); + + if (rc || *returnCode) + goto err_exit; + + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: %sabling the TPM failed.\n", + disable ? "Dis" : "En"); + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +deactivate_tpm(int deactivate, int allow_reset, u32 *returnCode, int verbose) +{ + u32 rc; + 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(verbose); + if (rc) { + dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n"); + return rc; + } + + rc = build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated, + deactivate ? CommandFlag_TRUE + : CommandFlag_FALSE, + deactivate ? sizeof(CommandFlag_TRUE) + : sizeof(CommandFlag_FALSE), + NULL, 10, returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, + "Return code from PhysicalSetDeactivated(%d) = 0x%08x\n", + deactivate ? 1 : 0, *returnCode); + + if (rc || *returnCode) + goto err_exit; + + if (!deactivate && allow_reset) { + if (verbose) { + printf("Requiring a reboot to activate the TPM.\n"); + + msleep(2000); + } + extern void reset_vector(void) __noreturn; + reset_vector(); + } + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +enable_activate(int allow_reset, u32 *returnCode, int verbose) +{ + u32 rc; + + rc = disable_tpm(0, returnCode, verbose); + if (rc) + return rc; + + rc = deactivate_tpm(0, allow_reset, returnCode, verbose); + + return rc; +} + + +static u32 +force_clear(int enable_activate_before, int enable_activate_after, + u32 *returnCode, int verbose) +{ + u32 rc; + 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, returnCode, verbose); + if (rc) { + dprintf(DEBUG_tcg, + "TCGBIOS: Enabling/activating the TPM failed.\n"); + return rc; + } + } + + rc = assert_physical_presence(verbose); + if (rc) { + dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n"); + return rc; + } + + rc = build_and_send_cmd(0, TPM_ORD_ForceClear, + NULL, 0, NULL, 10, returnCode, + TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "Return code from TPM_ForceClear() = 0x%08x\n", + *returnCode); + + 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, returnCode, verbose); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +set_owner_install(int allow, u32 *returnCode, int verbose) +{ + u32 rc; + 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(verbose); + if (rc) { + dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n"); + return rc; + } + + rc = build_and_send_cmd(0, TPM_ORD_SetOwnerInstall, + (allow) ? CommandFlag_TRUE : + CommandFlag_FALSE, + sizeof(CommandFlag_TRUE), + NULL, 10, returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "Return code from TPM_SetOwnerInstall() = 0x%08x\n", + *returnCode); + + if (rc || *returnCode) + goto err_exit; + + if (verbose) + printf("Installation of owner %s.\n", allow ? "enabled" : "disabled"); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +tpm_process_cfg(const tpm_bios_cfg_t *cfg, int verbose, + u32 *returnCode, u8 *next_step) +{ + u32 rc = 0; + + switch (cfg->op) { + case 0: /* no-op */ + break; + + case 1: + rc = disable_tpm(0, returnCode, verbose); + break; + + case 2: + rc = disable_tpm(1, returnCode, verbose); + break; + + case 3: + rc = deactivate_tpm(0, 1, returnCode, verbose); + break; + + case 4: + rc = deactivate_tpm(1, 1, returnCode, verbose); + break; + + case 5: + rc = force_clear(1, 0, returnCode, verbose); + break; + + case 6: + rc = enable_activate(1, returnCode, verbose); + break; + + case 7: + rc = deactivate_tpm(1, 1, returnCode, verbose); + if (!rc) + rc = disable_tpm(1, returnCode, verbose); + break; + + case 8: + rc = set_owner_install(1, returnCode, verbose); + break; + + case 9: + rc = set_owner_install(0, returnCode, verbose); + break; + + case 10: + *next_step = 8; + rc = enable_activate(1, returnCode, verbose); + /* no reboot happened */ + if (!rc) + rc = set_owner_install(1, returnCode, verbose); + break; + + case 11: + rc = set_owner_install(0, returnCode, verbose); + if (!rc) + rc = deactivate_tpm(1, 0, returnCode, verbose); + if (!rc) + rc = disable_tpm(1, returnCode, verbose); + break; + + case 14: + rc = force_clear(0, 0, returnCode, verbose); + if (!rc) + rc = enable_activate(1, returnCode, verbose); + break; + + case 21: + *next_step = 5; + rc = enable_activate(1, returnCode, verbose); + /* no reboot happened */ + if (!rc) + rc = force_clear(0, 0, returnCode, verbose); + break; + + case 22: + *next_step = 14; + rc = enable_activate(1, returnCode, verbose); + /* no reboot happened */ + if (!rc) + rc = force_clear(0, 0, returnCode, verbose); + *next_step = 0; + if (!rc) + rc = enable_activate(1, returnCode, verbose); + break; + + default: + break; + } + + if (rc) + printf("Op %d: An error occurred: 0x%x\n", cfg->op, rc); + + /* no reboot, no next step */ + *next_step = 0; + + return rc; +} + +static void +tpm_ppi_init(void) +{ + if (runningOnQEMU()) { + struct tpm_ppi *tp = (void *)(TPM_TIS_BASE_ADDRESS + TIS_REG_RAM); + + if (tp->sign != TCG_MAGIC) { + memset(tp, 0x0, sizeof(*tp)); + tp->sign = TCG_MAGIC; + /* set number of bytes that ACPI can read/write */ + tp->size = sizeof(tp->opcode) + sizeof(tp->failure) + + sizeof(tp->recent_opcode) + sizeof(tp->response); + } + } +} + +static void +tpm_ppi_process(void) +{ + tpm_bios_cfg_t cfg; + + if (runningOnQEMU()) { + struct tpm_ppi *tp = (void *)(TPM_TIS_BASE_ADDRESS + TIS_REG_RAM); + + if (tp->sign == TCG_MAGIC) { + cfg.op = tp->opcode; + dprintf(DEBUG_tcg, "TCGBIOS: PPI opcode found: 0x%08x\n", tp->opcode); + if (!cfg.op) { + /* intermediate step after a reboot? */ + cfg.op = tp->next_step; + } else { + /* last full opcode */ + tp->recent_opcode = cfg.op; + tp->opcode = 0; + } + if (cfg.op) { + printf("Processing TPM PPI opcode %d [%d]\n", + tp->recent_opcode, cfg.op); + tp->failure = (tpm_process_cfg(&cfg, 0, &tp->response, + &tp->next_step) != 0); + } + } + } +} diff --git a/src/tcgbios.h b/src/tcgbios.h index a1d0b0f..0fcca15 100644 --- a/src/tcgbios.h +++ b/src/tcgbios.h @@ -329,6 +329,36 @@ struct tpm_res_getcap_perm_flags { } PACKED;
+struct tpm_req_getcap_stclear_flags { + TPM_REQ_HEADER + u32 capArea; + u32 subCapSize; + u32 subCap; +} PACKED; + + +struct tpm_stclear_flags { + u16 tag; + u8 flags[5]; +} PACKED; + + +enum stclearFlagsIndex { + STCLEAR_FLAG_IDX_DEACTIVATED = 0, + STCLEAR_FLAG_IDX_DISABLE_FORCE_CLEAR, + STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE, + STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE_LOCK, + STCLEAR_FLAG_IDX_GLOBAL_LOCK, +}; + + +struct tpm_res_getcap_stclear_flags { + TPM_RSP_HEADER + u32 size; + struct tpm_stclear_flags stclear_flags; +} PACKED; + + struct tpm_res_getcap_ownerauth { TPM_RSP_HEADER u32 size; @@ -379,6 +409,20 @@ enum ipltype { IPL_EL_TORITO_2 };
+/* + * physical presence interface + */ + +struct tpm_ppi { + u32 sign; + u16 size; // number of subsequent bytes for ACPI to access + u8 opcode; // set by ACPI + u8 failure; // set by BIOS (0 = success) + u8 recent_opcode; // set by BIOS + u32 response; // set by BIOS + u8 next_step; // BIOS only +} PACKED; +
struct bregs; void tpm_interrupt_handler32(struct bregs *regs);
On Tue, May 26, 2015 at 03:48:34PM -0400, Stefan Berger wrote:
This patch implements the specification found here:
http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interfa...
It adds the necessary BIOS code so that for example an administrator can send messages from the OS to the BIOS for the BIOS to change the state of the TPM upon reboot. With the help of this interface, an administrator does not have to manually interact with the BIOS.
As an example, on Linux the root use can send an opcode to the BIOS through the TPM's sysfs entries following the opcodes listed in table 2 of the above specs. To for example disable and deactivate the TPM, the root user would send opcode '7' to the BIOS:
#> cd /sys/devices/pnp0/00:0?/ppi
#> echo 7 > request
#> reboot
Given that this patch is dependent on upstream QEMU changes, I think it needs to wait until the upstream support is committed.
-Kevin
This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM's state.
If a working TPM has been detected, the boot menu will look like this:
Select boot device:
1. ata0-1: QEMU HARDDISK ATA-7 Hard-Disk (6144 MiBytes) 2. Legacy option rom 3. iPXE (PCI 00:03.0)
t. TPM Menu
Upon pressing t 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.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
--- src/boot.c | 14 ++++++- src/tcgbios.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/tcgbios.h | 2 + src/util.h | 1 + 4 files changed, 129 insertions(+), 3 deletions(-)
diff --git a/src/boot.c b/src/boot.c index ec59c37..bb3bddf 100644 --- a/src/boot.c +++ b/src/boot.c @@ -427,7 +427,7 @@ get_raw_keystroke(void) }
// Read a keystroke - waiting up to 'msec' milliseconds. -static int +int get_keystroke(int msec) { u32 end = irqtimer_calc(msec); @@ -461,7 +461,7 @@ interactive_bootmenu(void)
char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL); int menukey = romfile_loadint("etc/boot-menu-key", 1); - printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n\n"); + printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n"); free(bootmsg);
u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT); @@ -474,6 +474,7 @@ interactive_bootmenu(void) while (get_keystroke(0) >= 0) ;
+show_boot_menu: printf("Select boot device:\n\n"); wait_threads();
@@ -486,6 +487,9 @@ interactive_bootmenu(void) printf("%d. %s\n", maxmenu , strtcpy(desc, pos->description, ARRAY_SIZE(desc))); } + if (tpm_is_detected()) { + printf("\nt. TPM menu\n"); + }
// Get key press. If the menu key is ESC, do not restart boot unless // 1.5 seconds have passed. Otherwise users (trained by years of @@ -496,6 +500,12 @@ interactive_bootmenu(void) scan_code = get_keystroke(1000); if (scan_code == 1 && !irqtimer_check(esc_accepted_time)) continue; + if (tpm_is_detected() && scan_code == 20 /* t */) { + printf("\n"); + tpm_menu(); + printf("\n"); + goto show_boot_menu; + } if (scan_code >= 1 && scan_code <= maxmenu+1) break; } diff --git a/src/tcgbios.c b/src/tcgbios.c index 3263ec6..24edb44 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -26,6 +26,7 @@ #include "fw/paravirt.h" // runningOnXen #include "std/smbios.h" #include "malloc.h" // malloc_* +#include "stacks.h" // wait_threads
static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR }; static const u8 Startup_ST_STATE[2] = { 0x00, TPM_ST_STATE }; @@ -142,6 +143,17 @@ probe_tpm(void) } }
+int +tpm_is_detected(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + probe_tpm(); + + return tpm_state.tpm_found; +} + static int has_working_tpm(void) { @@ -1569,7 +1581,8 @@ assert_physical_presence(int verbose) "Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n", returnCode);
- if (rc || returnCode) { + /* some TPMs do not support phys. presence enablement */ + if (rc || (returnCode && returnCode != TPM_BAD_PARAMETER)) { if (verbose) printf("Error: Could not enable physical presence.\n\n"); goto err_exit; @@ -2066,3 +2079,103 @@ tpm_ppi_process(void) } } } + + +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"); + } + +} + + +void +tpm_menu(void) +{ + if (!CONFIG_TCGBIOS) + return; + + int scan_code; + u32 rc, returnCode; + u8 next_step; + tpm_bios_cfg_t cfg = { + .op = 0, + }; + + while (get_keystroke(0) >= 0) + ; + wait_threads(); + + for (;;) { + if (has_working_tpm()) { + 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"); + } else { + printf("TPM is not working correctly.\n"); + } + + printf("Escape for previous menu.\n"); + + if (has_working_tpm()) { + show_tpm_state(); + } + + cfg.op = 0; + + while ((scan_code = get_keystroke(1000)) == ~0) + ; + + switch (scan_code) { + case 1: + // ESC + return; + case 2 ... 6: + cfg.op = scan_code - 1; + break; + case 7 ... 8: + cfg.op = scan_code + 1; + break; + default: + continue; + } + + if (has_working_tpm()) { + rc = tpm_process_cfg(&cfg, 1, &returnCode, &next_step); + + if (rc) + printf("An error occurred: 0x%x\n", rc); + } + } +} diff --git a/src/tcgbios.h b/src/tcgbios.h index 0fcca15..28c646a 100644 --- a/src/tcgbios.h +++ b/src/tcgbios.h @@ -434,5 +434,7 @@ u32 tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length); u32 tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length); u32 tpm_add_cdrom_catalog(const u8 *addr, u32 length); u32 tpm_option_rom(const void *addr, u32 len); +int tpm_is_detected(void); +void tpm_menu(void);
#endif /* TCGBIOS_H */ diff --git a/src/util.h b/src/util.h index 2244090..bb24744 100644 --- a/src/util.h +++ b/src/util.h @@ -36,6 +36,7 @@ int bootprio_find_pci_rom(struct pci_device *pci, int instance); int bootprio_find_named_rom(const char *name, int instance); struct usbdevice_s; int bootprio_find_usb(struct usbdevice_s *usbdev, int lun); +int get_keystroke(int msec);
// bootsplash.c void enable_vga_console(void);
On Tue, May 26, 2015 at 03:48:35PM -0400, Stefan Berger wrote:
This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM's state.
If a working TPM has been detected, the boot menu will look like this:
Select boot device:
- ata0-1: QEMU HARDDISK ATA-7 Hard-Disk (6144 MiBytes)
- Legacy option rom
- iPXE (PCI 00:03.0)
t. TPM Menu
Upon pressing t the TPM menu will be shown:
- Enable TPM
- Disable TPM
- Activate TPM
- Deactivate TPM
- Clear ownership
- Allow installation of owner
- Prevent installation of owner
Escape for previous menu. TPM is enabled, active, does not have an owner but one can be installed.
I'm okay with adding a "t" to the boot menu. However, I think this sub-menu is too complex and cryptic. (For example, I suspect most users wont even know what "TPM" means.)
I think I'd prefer something like:
t. TPM Configuration
Upon pressing t the TPM menu will be shown:
The Trusted Platform Module (TPM) is a hardware device in this machine. It can help verify the integrity of system software.
The current state of the TPM is: Enabled No ownership key has been installed System software can install an ownership key
Available options are: d) Disable TPM and clear any ownership key settings
If no change is desired or if this menu was reached by mistake, press ESC and this machine will be rebooted without change.
Specifically, I think the menu should be a little more verbose (for users that just explore the menu), it should only be reached if the given hardware is present, and menu options should only be shown if they are actually available and make sense to invoke.
-Kevin
On 06/01/2015 12:54 PM, Kevin O'Connor wrote:
On Tue, May 26, 2015 at 03:48:35PM -0400, Stefan Berger wrote:
This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM's state.
If a working TPM has been detected, the boot menu will look like this:
Select boot device:
- ata0-1: QEMU HARDDISK ATA-7 Hard-Disk (6144 MiBytes)
- Legacy option rom
- iPXE (PCI 00:03.0)
t. TPM Menu
Upon pressing t the TPM menu will be shown:
- Enable TPM
- Disable TPM
- Activate TPM
- Deactivate TPM
- Clear ownership
- Allow installation of owner
- Prevent installation of owner
Escape for previous menu. TPM is enabled, active, does not have an owner but one can be installed.
I'm okay with adding a "t" to the boot menu. However, I think this sub-menu is too complex and cryptic. (For example, I suspect most users wont even know what "TPM" means.)
I think I'd prefer something like:
t. TPM Configuration
Upon pressing t the TPM menu will be shown:
The Trusted Platform Module (TPM) is a hardware device in this machine. It can help verify the integrity of system software.
The current state of the TPM is: Enabled
Well, there are two independent state bits indicating enabled/disable and activated/deactivated.
No ownership key has been installed
No ownership password has been set.
System software can install an ownership key
The system owner can take ownership of the TPM.
Available options are: d) Disable TPM and clear any ownership key settings
I think the disablement and clearing of ownership should be separated. The thing with the TPM 1.2 is that all keys that one has created (after taking ownership of it) depend on the ownership of the TPM. Once one gives up ownership, one looses all keys. Also, the device becomes disabled and deactivated, so one has to enable and activate it again, which even requires a reboot.
If no change is desired or if this menu was reached by mistake, press ESC and this machine will be rebooted without change.
There's no need to reboot if we only leave the menu. If the user activates the device from it being deactivated, a reboot will automatically happen.
Specifically, I think the menu should be a little more verbose (for users that just explore the menu), it should only be reached if the given hardware is present, and menu options should only be shown if they are actually available and make sense to invoke.
Ok. I'll rework this and will probably put this in front of the physical presence patch.
-Kevin
On Tue, Jun 02, 2015 at 01:05:47PM -0400, Stefan Berger wrote:
On 06/01/2015 12:54 PM, Kevin O'Connor wrote:
On Tue, May 26, 2015 at 03:48:35PM -0400, Stefan Berger wrote:
This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM's state.
If a working TPM has been detected, the boot menu will look like this:
Select boot device:
- ata0-1: QEMU HARDDISK ATA-7 Hard-Disk (6144 MiBytes)
- Legacy option rom
- iPXE (PCI 00:03.0)
t. TPM Menu
Upon pressing t the TPM menu will be shown:
- Enable TPM
- Disable TPM
- Activate TPM
- Deactivate TPM
- Clear ownership
- Allow installation of owner
- Prevent installation of owner
Escape for previous menu. TPM is enabled, active, does not have an owner but one can be installed.
I'm okay with adding a "t" to the boot menu. However, I think this sub-menu is too complex and cryptic. (For example, I suspect most users wont even know what "TPM" means.)
I think I'd prefer something like:
t. TPM Configuration
Upon pressing t the TPM menu will be shown:
The Trusted Platform Module (TPM) is a hardware device in this machine. It can help verify the integrity of system software.
The current state of the TPM is: Enabled
Well, there are two independent state bits indicating enabled/disable and activated/deactivated.
Could you describe the difference? Why would anyone want an enabled and deactivated tpm? I would like to see less use of "TPM lingo" in the menu. I think a casual user would not know the distinction between "enabled" and "activated" and would therefore find it confusing.
No ownership key has been installed
No ownership password has been set.
Okay - if it's a password (in the sense of "p5ssw0rd") then it of course should say password. For some reason I thought it was a public/private key pair that enabled remote management.
System software can install an ownership key
The system owner can take ownership of the TPM.
If you take a step back and look at that sentence from a pure English / non-technical perspective, I think you'll see my concern with it. (The person who purchased the machine already owns both the system and the tpm hardware in the system, and no software can alter that.)
Available options are: d) Disable TPM and clear any ownership key settings
I think the disablement and clearing of ownership should be separated. The thing with the TPM 1.2 is that all keys that one has created (after taking ownership of it) depend on the ownership of the TPM. Once one gives up ownership, one looses all keys. Also, the device becomes disabled and deactivated, so one has to enable and activate it again, which even requires a reboot.
So, are you saying that one might want to "disable the tpm", but not clear out any keys? I'm not against adding that option, but I don't see why anyone would want to do that.
If no change is desired or if this menu was reached by mistake, press ESC and this machine will be rebooted without change.
There's no need to reboot if we only leave the menu. If the user activates the device from it being deactivated, a reboot will automatically happen.
I think it's a better fit (and simpler) to just always reboot. Thus, one is not entering the "tpm menu", but is booting into the "tpm configuration".
If I understand this correctly (and please correct me if I'm not), a real world user might realistically want to enter this menu once a decade at most. Thus, the extra time to reboot (or even two reboots - one to disable and then one to re-enable) is not a problem.
Specifically, I think the menu should be a little more verbose (for users that just explore the menu), it should only be reached if the given hardware is present, and menu options should only be shown if they are actually available and make sense to invoke.
Ok. I'll rework this and will probably put this in front of the physical presence patch.
Thanks, -Kevin
On 06/02/2015 01:44 PM, Kevin O'Connor wrote:
On Tue, Jun 02, 2015 at 01:05:47PM -0400, Stefan Berger wrote:
On 06/01/2015 12:54 PM, Kevin O'Connor wrote:
On Tue, May 26, 2015 at 03:48:35PM -0400, Stefan Berger wrote:
This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM's state.
If a working TPM has been detected, the boot menu will look like this:
Select boot device:
- ata0-1: QEMU HARDDISK ATA-7 Hard-Disk (6144 MiBytes)
- Legacy option rom
- iPXE (PCI 00:03.0)
t. TPM Menu
Upon pressing t the TPM menu will be shown:
- Enable TPM
- Disable TPM
- Activate TPM
- Deactivate TPM
- Clear ownership
- Allow installation of owner
- Prevent installation of owner
Escape for previous menu. TPM is enabled, active, does not have an owner but one can be installed.
I'm okay with adding a "t" to the boot menu. However, I think this sub-menu is too complex and cryptic. (For example, I suspect most users wont even know what "TPM" means.)
I think I'd prefer something like:
t. TPM Configuration
Upon pressing t the TPM menu will be shown:
The Trusted Platform Module (TPM) is a hardware device in this machine. It can help verify the integrity of system software.
The current state of the TPM is: Enabled
Well, there are two independent state bits indicating enabled/disable and activated/deactivated.
Could you describe the difference? Why would anyone want an enabled and deactivated tpm? I would like to see less use of "TPM lingo" in the menu. I think a casual user would not know the distinction between "enabled" and "activated" and would therefore find it confusing.
So then we could combine the active/enabled state into let's say an 'enabled' state and any other combination of the states would be regarded as 'disabled'.
These states basically indicate the amount of functionality that is available. An enabled + active + owned TPM provides all of its functionality and a disabled + deactivated + un-owned TPM is basically a device that is turned off. There are other combinations in between that enable more functionality.
More info in Part 1 Design Principles section 9.4.x here (search for 'S8' for example):
http://www.trustedcomputinggroup.org/resources/tpm_main_specification
No ownership key has been installed
No ownership password has been set.
Okay - if it's a password (in the sense of "p5ssw0rd") then it of course should say password. For some reason I thought it was a public/private key pair that enabled remote management.
Such a key gets generated as part of taking ownership of the TPM, which is done by using a password.
System software can install an ownership key
The system owner can take ownership of the TPM.
If you take a step back and look at that sentence from a pure English / non-technical perspective, I think you'll see my concern with it. (The person who purchased the machine already owns both the system and the tpm hardware in the system, and no software can alter that.)
Available options are: d) Disable TPM and clear any ownership key settings
I think the disablement and clearing of ownership should be separated. The thing with the TPM 1.2 is that all keys that one has created (after taking ownership of it) depend on the ownership of the TPM. Once one gives up ownership, one looses all keys. Also, the device becomes disabled and deactivated, so one has to enable and activate it again, which even requires a reboot.
So, are you saying that one might want to "disable the tpm", but not clear out any keys? I'm not against adding that option, but I don't see why anyone would want to do that.
The only point I can bring here is to leave the flexibility to the user of being able to control those TPM states independently.
If no change is desired or if this menu was reached by mistake, press ESC and this machine will be rebooted without change.
There's no need to reboot if we only leave the menu. If the user activates the device from it being deactivated, a reboot will automatically happen.
I think it's a better fit (and simpler) to just always reboot. Thus, one is not entering the "tpm menu", but is booting into the "tpm configuration".
If I understand this correctly (and please correct me if I'm not), a real world user might realistically want to enter this menu once a decade at most. Thus, the extra time to reboot (or even two reboots - one to disable and then one to re-enable) is not a problem.
rotfl %eax :-)
It's just no necessary to reboot upon certain state changes, that's all there is to it. The way I implemented the menu, it would program the TPM immediately and reboot immediately when going from deactivated to activated. Otherwise no reboot is necessary.
Stefan
Specifically, I think the menu should be a little more verbose (for users that just explore the menu), it should only be reached if the given hardware is present, and menu options should only be shown if they are actually available and make sense to invoke.
Ok. I'll rework this and will probably put this in front of the physical presence patch.
Thanks, -Kevin
On 06/01/2015 12:54 PM, Kevin O'Connor wrote:
On Tue, May 26, 2015 at 03:48:35PM -0400, Stefan Berger wrote:
This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM's state.
If a working TPM has been detected, the boot menu will look like this:
Select boot device:
- ata0-1: QEMU HARDDISK ATA-7 Hard-Disk (6144 MiBytes)
- Legacy option rom
- iPXE (PCI 00:03.0)
t. TPM Menu
Upon pressing t the TPM menu will be shown:
- Enable TPM
- Disable TPM
- Activate TPM
- Deactivate TPM
- Clear ownership
- Allow installation of owner
- Prevent installation of owner
Escape for previous menu. TPM is enabled, active, does not have an owner but one can be installed.
I'm okay with adding a "t" to the boot menu. However, I think this sub-menu is too complex and cryptic. (For example, I suspect most users wont even know what "TPM" means.)
I think I'd prefer something like:
t. TPM Configuration
Upon pressing t the TPM menu will be shown:
The Trusted Platform Module (TPM) is a hardware device in this machine. It can help verify the integrity of system software.
The current state of the TPM is: Enabled No ownership key has been installed System software can install an ownership key
Available options are: d) Disable TPM and clear any ownership key settings
If no change is desired or if this menu was reached by mistake, press ESC and this machine will be rebooted without change.
Specifically, I think the menu should be a little more verbose (for users that just explore the menu), it should only be reached if the given hardware is present, and menu options should only be shown if they are actually available and make sense to invoke.
-Kevin
Here's now the (code for the) menu I created. I hope it's an acceptable middle-ground. This sub-menu will only be available if a TPM has been detected on the machine. Also, only those menu items that can be selected at the moment, considering the state of the TPM, are shown. The allowed scancodes are collected in an array.
static void show_tpm_menu(int state, int *scancodes) { int i = 0;
printf("\nThe current state of the TPM is\n");
if (state & TPM_STATE_ENABLED) printf(" Enabled"); else printf(" Disabled");
if (state & TPM_STATE_ACTIVE) printf(" and active\n"); else printf(" and deactivated\n");
if (state & TPM_STATE_OWNED) printf(" Ownership has been taken\n"); else { printf(" Ownership has not been taken\n"); if (state & TPM_STATE_OWNERINSTALL) printf(" A user can take ownership of the TPM\n"); else printf(" Taking ownership of the TPM has been disabled\n"); }
if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) != (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) { printf("\nNote: To make use of all functionality, the TPM must be " "enabled and active.\n"); }
printf("\nAvailable options are:\n"); if (state & TPM_STATE_ENABLED) { printf(" d. Disable the TPM\n"); scancodes[i++] = 32;
if (state & TPM_STATE_ACTIVE) { printf(" v. Deactivate the TPM\n"); scancodes[i++] = 47;
if (state & TPM_STATE_OWNERINSTALL) { printf(" p. Prevent installation of an owner\n"); scancodes[i++] = 25; } else { printf(" s. Allow installation of an owner\n"); scancodes[i++] = 31; } } else { printf(" a. Activate the TPM\n"); scancodes[i++] = 30; }
} else { printf(" e. Enable the TPM\n"); scancodes[i++] = 18; }
if (state & TPM_STATE_OWNED) { printf(" c. Clear ownership\n"); scancodes[i++] = 46; }
scancodes[i++] = 0; }
void tpm_menu(void) { if (!CONFIG_TCGBIOS) return;
int scancode, scancodes[7]; u32 rc, returnCode; u8 next_step; tpm_bios_cfg cfg = { .op = TPM_PPI_OP_NOOP, }; int state = 0, i; bool waitkey;
while (get_keystroke(0) >= 0) ; wait_threads();
if (has_working_tpm()) printf("The Trusted Platform Module (TPM) is a hardware device in " "this machine.\n" "It can help verify the integrity of system software.\n\n");
for (;;) { if (has_working_tpm() && (state = get_tpm_state()) != ~0) { show_tpm_menu(state, scancodes); } else { printf("TPM is not working correctly.\n"); return; }
printf("\nIf no change is desired or if this menu was reached by " "mistake, press ESC to\n" "return to the previous menu.\n"); [...]
Regards, Stefan
On Wed, Jun 10, 2015 at 07:12:29AM -0400, Stefan Berger wrote:
On 06/01/2015 12:54 PM, Kevin O'Connor wrote:
On Tue, May 26, 2015 at 03:48:35PM -0400, Stefan Berger wrote:
This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM's state.
If a working TPM has been detected, the boot menu will look like this:
Select boot device:
- ata0-1: QEMU HARDDISK ATA-7 Hard-Disk (6144 MiBytes)
- Legacy option rom
- iPXE (PCI 00:03.0)
t. TPM Menu
Upon pressing t the TPM menu will be shown:
- Enable TPM
- Disable TPM
- Activate TPM
- Deactivate TPM
- Clear ownership
- Allow installation of owner
- Prevent installation of owner
Escape for previous menu. TPM is enabled, active, does not have an owner but one can be installed.
I'm okay with adding a "t" to the boot menu. However, I think this sub-menu is too complex and cryptic. (For example, I suspect most users wont even know what "TPM" means.)
I think I'd prefer something like:
t. TPM Configuration
Upon pressing t the TPM menu will be shown:
The Trusted Platform Module (TPM) is a hardware device in this machine. It can help verify the integrity of system software.
The current state of the TPM is: Enabled No ownership key has been installed System software can install an ownership key
Available options are: d) Disable TPM and clear any ownership key settings
If no change is desired or if this menu was reached by mistake, press ESC and this machine will be rebooted without change.
Specifically, I think the menu should be a little more verbose (for users that just explore the menu), it should only be reached if the given hardware is present, and menu options should only be shown if they are actually available and make sense to invoke.
-Kevin
Here's now the (code for the) menu I created. I hope it's an acceptable middle-ground. This sub-menu will only be available if a TPM has been detected on the machine. Also, only those menu items that can be selected at the moment, considering the state of the TPM, are shown. The allowed scancodes are collected in an array.
Thanks. It does look much better to me. What's the difference between enabled and activated? Can you describe it or point me to a link?
-Kevin
On 06/10/2015 10:38 AM, Kevin O'Connor wrote:
On Wed, Jun 10, 2015 at 07:12:29AM -0400, Stefan Berger wrote:
On 06/01/2015 12:54 PM, Kevin O'Connor wrote:
On Tue, May 26, 2015 at 03:48:35PM -0400, Stefan Berger wrote:
This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM's state.
If a working TPM has been detected, the boot menu will look like this:
Select boot device:
- ata0-1: QEMU HARDDISK ATA-7 Hard-Disk (6144 MiBytes)
- Legacy option rom
- iPXE (PCI 00:03.0)
t. TPM Menu
Upon pressing t the TPM menu will be shown:
- Enable TPM
- Disable TPM
- Activate TPM
- Deactivate TPM
- Clear ownership
- Allow installation of owner
- Prevent installation of owner
Escape for previous menu. TPM is enabled, active, does not have an owner but one can be installed.
I'm okay with adding a "t" to the boot menu. However, I think this sub-menu is too complex and cryptic. (For example, I suspect most users wont even know what "TPM" means.)
I think I'd prefer something like:
t. TPM Configuration
Upon pressing t the TPM menu will be shown:
The Trusted Platform Module (TPM) is a hardware device in this machine. It can help verify the integrity of system software.
The current state of the TPM is: Enabled No ownership key has been installed System software can install an ownership key
Available options are: d) Disable TPM and clear any ownership key settings
If no change is desired or if this menu was reached by mistake, press ESC and this machine will be rebooted without change.
Specifically, I think the menu should be a little more verbose (for users that just explore the menu), it should only be reached if the given hardware is present, and menu options should only be shown if they are actually available and make sense to invoke.
-Kevin
Here's now the (code for the) menu I created. I hope it's an acceptable middle-ground. This sub-menu will only be available if a TPM has been detected on the machine. Also, only those menu items that can be selected at the moment, considering the state of the TPM, are shown. The allowed scancodes are collected in an array.
Thanks. It does look much better to me. What's the difference between enabled and activated? Can you describe it or point me to a link?
So I'll ditch the physical presence part for now , ditch that bool patch and post the menu patch on top of the cleanups.
Here the link to the documentation about the TPM 1.2 states:
http://www.trustedcomputinggroup.org/resources/tpm_main_specification
Access document Part 1 - Design Principles. Section 9.4 and subsections explain the different states of the TPM 1.2.
From the spec 9.4.1:
"A disabled TPM is not able to execute commands that use the resources of a TPM. While some commands are available (SHA-1 for example) the TPM is not able to load keys and perform TPM_Seal and other such operations. These restrictions are the same as for an inactive TPM. The difference between inactive and disabled is that a disabled TPM is unable to execute the TPM_TakeOwnership command. A disabled TPM that has a TPM Owner is not able to execute normal TPM commands."
From the spec 9.4.2:
"A deactivated TPM is not able to execute commands that use TPM resources. A major difference between deactivated and disabled is that a deactivated TPM CAN execute the TPM_TakeOwnership command. [...]"
Regards, Stefan
-Kevin
On Wed, Jun 10, 2015 at 10:58:40AM -0400, Stefan Berger wrote:
On 06/10/2015 10:38 AM, Kevin O'Connor wrote:
Thanks. It does look much better to me. What's the difference between enabled and activated? Can you describe it or point me to a link?
So I'll ditch the physical presence part for now , ditch that bool patch and post the menu patch on top of the cleanups.
Here the link to the documentation about the TPM 1.2 states:
http://www.trustedcomputinggroup.org/resources/tpm_main_specification
Access document Part 1 - Design Principles. Section 9.4 and subsections explain the different states of the TPM 1.2.
From the spec 9.4.1:
"A disabled TPM is not able to execute commands that use the resources of a TPM. While some commands are available (SHA-1 for example) the TPM is not able to load keys and perform TPM_Seal and other such operations. These restrictions are the same as for an inactive TPM. The difference between inactive and disabled is that a disabled TPM is unable to execute the TPM_TakeOwnership command. A disabled TPM that has a TPM Owner is not able to execute normal TPM commands."
From the spec 9.4.2:
"A deactivated TPM is not able to execute commands that use TPM resources. A major difference between deactivated and disabled is that a deactivated TPM CAN execute the TPM_TakeOwnership command. [...]"
Thanks. Unfortunately I'm still confused.
The above seems to say that the only difference between disabled and deactivated is that one can't take ownership of a disabled TPM. But, if that's the case, when a tpm is active, why does the menu provide for both "Deactivate the TPM" and "Prevent installation of an owner"? (And, why would anyone want to take "ownership" of a TPM that is disabled/deactivated anyway?)
-Kevin
On 06/11/2015 06:34 PM, Kevin O'Connor wrote:
On Wed, Jun 10, 2015 at 10:58:40AM -0400, Stefan Berger wrote:
On 06/10/2015 10:38 AM, Kevin O'Connor wrote:
Thanks. It does look much better to me. What's the difference between enabled and activated? Can you describe it or point me to a link?
So I'll ditch the physical presence part for now , ditch that bool patch and post the menu patch on top of the cleanups.
Here the link to the documentation about the TPM 1.2 states:
http://www.trustedcomputinggroup.org/resources/tpm_main_specification
Access document Part 1 - Design Principles. Section 9.4 and subsections explain the different states of the TPM 1.2.
From the spec 9.4.1:
"A disabled TPM is not able to execute commands that use the resources of a TPM. While some commands are available (SHA-1 for example) the TPM is not able to load keys and perform TPM_Seal and other such operations. These restrictions are the same as for an inactive TPM. The difference between inactive and disabled is that a disabled TPM is unable to execute the TPM_TakeOwnership command. A disabled TPM that has a TPM Owner is not able to execute normal TPM commands."
From the spec 9.4.2:
"A deactivated TPM is not able to execute commands that use TPM resources. A major difference between deactivated and disabled is that a deactivated TPM CAN execute the TPM_TakeOwnership command. [...]"
Thanks. Unfortunately I'm still confused.
The above seems to say that the only difference between disabled and deactivated is that one can't take ownership of a disabled TPM. But, if that's the case, when a tpm is active, why does the menu provide for both "Deactivate the TPM" and "Prevent installation of an owner"? (And, why would anyone want to take "ownership" of a TPM that is disabled/deactivated anyway?)
From that link to the TPM 1.2 specs you see in section 9.4 that there are actually 3 independent state bits of the TPM: - active/deactivated - enabled/disabled - taking ownership is possible / is not possible
These 3 bits can only be modified while one interacts with the firmware ( physical presence must be asserted ). I am giving control in the menu over these 3 bits because the firmware is the right and only place to do this. I admit that these fine grained controls are confusing, though that's the controls TPM 1.2 allows per its spec.
Stefan
-Kevin