[SLOF] [PATCH 08/16] Add support for controlling the states of the TPM
Nikunj A Dadhania
nikunj at linux.vnet.ibm.com
Mon Nov 9 21:12:45 AEDT 2015
Stefan Berger <stefanb at linux.vnet.ibm.com> writes:
> This patch adds support for controlling the various states of
> the TPM, such as enabling and disabling the TPM, deactivating
> and activating it, and clearing ownership.
>
> The TPM menu implementation will call these functions by
> calling tpm_process_opcode with an opcode indicating as to
> how the state of the TPM is to be changed.
>
> Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
> ---
> lib/libtpm/tcgbios.c | 459 +++++++++++++++++++++++++++++++++++++++++++++++
> lib/libtpm/tcgbios.h | 2 +
> lib/libtpm/tcgbios_int.h | 34 ++++
> lib/libtpm/tpm.code | 12 ++
> lib/libtpm/tpm.in | 1 +
> 5 files changed, 508 insertions(+)
>
> diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c
> index 2f5b048..cabd980 100644
> --- a/lib/libtpm/tcgbios.c
> +++ b/lib/libtpm/tcgbios.c
> @@ -51,6 +51,11 @@ static const uint8_t GetCapability_Permanent_Flags[] = {
> 0x00, 0x00, 0x01, 0x08
> };
>
> +static const uint8_t GetCapability_STClear_Flags[] = {
> + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
> + 0x00, 0x00, 0x01, 0x09
> +};
> +
> static const uint8_t GetCapability_OwnerAuth[] = {
> 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
> 0x00, 0x00, 0x01, 0x11
> @@ -82,6 +87,10 @@ static struct tpm_state tpm_state = {
>
> extern struct tpm_driver tpm_drivers[];
>
> +typedef struct {
> + uint8_t op;
> +} tpm_bios_cfg;
> +
> static void *log_base;
> static uint32_t log_area_size;
> /* next log entry goes here */
> @@ -891,3 +900,453 @@ uint32_t tpm_add_bcv(uint32_t bootdrv, const uint8_t *addr, uint32_t length)
>
> return tpm_ipl(IPL_BCV, addr, length);
> }
> +
> +static uint32_t read_stclear_flags(char *buf, int buf_len)
> +{
> + uint32_t rc;
> + uint32_t returnCode;
> + struct tpm_res_getcap_stclear_flags stcf;
> +
> + memset(buf, 0, buf_len);
> +
> + rc = build_and_send_cmd(TPM_ORD_GetCapability,
> + GetCapability_STClear_Flags,
> + sizeof(GetCapability_STClear_Flags),
> + (uint8_t *)&stcf, sizeof(stcf),
> + &returnCode, TPM_DURATION_TYPE_SHORT);
> +
> + dprintf("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("TPM malfunctioning (line %d).\n", __LINE__);
> +
> + tpm_state.tpm_working = 0;
> + if (rc)
> + return rc;
> + return TCGBIOS_COMMAND_ERROR;
> +}
> +
> +static uint32_t assert_physical_presence(bool verbose)
> +{
> + uint32_t rc = 0;
> + uint32_t returnCode;
> + struct tpm_stclear_flags stcf;
> +
> + rc = read_stclear_flags((char *)&stcf, sizeof(stcf));
> + if (rc) {
> + dprintf("Error reading STClear flags: 0x%08x\n", rc);
> + return rc;
> + }
> +
> + if (stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE])
> + /* physical presence already asserted */
> + return 0;
return rc; ?
> +
> + rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
> + PhysicalPresence_CMD_ENABLE,
> + sizeof(PhysicalPresence_CMD_ENABLE),
> + NULL, 0, &returnCode,
> + TPM_DURATION_TYPE_SHORT);
> +
> + dprintf("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(TPM_ORD_PhysicalPresence,
> + PhysicalPresence_PRESENT,
> + sizeof(PhysicalPresence_PRESENT),
> + NULL, 0, &returnCode,
> + TPM_DURATION_TYPE_SHORT);
> +
> + dprintf("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("TPM malfunctioning (line %d).\n", __LINE__);
> +
> + tpm_state.tpm_working = 0;
> + if (rc)
> + return rc;
> + return TCGBIOS_COMMAND_ERROR;
> +}
> +
> +static uint32_t read_permanent_flags(char *buf, int buf_len)
> +{
> + uint32_t rc;
> + uint32_t returnCode;
> + struct tpm_res_getcap_perm_flags pf;
> +
> + memset(buf, 0, buf_len);
> +
> + rc = build_and_send_cmd(TPM_ORD_GetCapability,
> + GetCapability_Permanent_Flags,
> + sizeof(GetCapability_Permanent_Flags),
> + (uint8_t *)&pf, sizeof(pf),
> + &returnCode, TPM_DURATION_TYPE_SHORT);
> +
> + dprintf("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("TPM malfunctioning (line %d).\n", __LINE__);
> +
> + tpm_state.tpm_working = 0;
> + if (rc)
> + return rc;
> + return TCGBIOS_COMMAND_ERROR;
> +}
> +
> +static uint32_t read_has_owner(bool *has_owner)
> +{
> + uint32_t rc;
> + uint32_t returnCode;
> + struct tpm_res_getcap_ownerauth oauth;
> +
> + rc = build_and_send_cmd(TPM_ORD_GetCapability,
> + GetCapability_OwnerAuth,
> + sizeof(GetCapability_OwnerAuth),
> + (uint8_t *)&oauth, sizeof(oauth),
> + &returnCode, TPM_DURATION_TYPE_SHORT);
> +
> + dprintf("Return code from TPM_GetCapability() = 0x%08x\n",
> + returnCode);
> +
> + if (rc || returnCode)
> + goto err_exit;
> +
> + *has_owner = oauth.flag;
> +
> + return 0;
> +
> +err_exit:
> + dprintf("TPM malfunctioning (line %d).\n", __LINE__);
> +
> + tpm_state.tpm_working = 0;
> + if (rc)
> + return rc;
> + return TCGBIOS_COMMAND_ERROR;
> +}
> +
> +static uint32_t enable_tpm(bool enable, uint32_t *returnCode, bool verbose)
> +{
> + uint32_t 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] == !enable)
With enable being bool here, i dont see a reason why this would not
work:
if (!pf.flags[PERM_FLAG_IDX_DISABLE] == enable) ?
> + return 0;
> +
> + rc = assert_physical_presence(verbose);
> + if (rc) {
> + dprintf("Asserting physical presence failed.\n");
> + return rc;
> + }
> +
> + rc = build_and_send_cmd(enable ? TPM_ORD_PhysicalEnable
> + : TPM_ORD_PhysicalDisable,
> + NULL, 0, NULL, 0, returnCode,
> + TPM_DURATION_TYPE_SHORT);
> + if (enable) {
> + dprintf("Return code from TPM_PhysicalEnable = 0x%08x\n",
> + *returnCode);
> + } else {
> + dprintf("Return code from TPM_PhysicalDisable = 0x%08x\n",
> + *returnCode);
> + }
> +
> + if (rc || *returnCode)
> + goto err_exit;
> +
> + return 0;
> +
> +err_exit:
> + if (enable) {
> + dprintf("Enabling the TPM failed.\n");
> + } else {
> + dprintf("Disabling the TPM failed.\n");
> + }
> + dprintf("TPM malfunctioning (line %d).\n", __LINE__);
> +
> + tpm_state.tpm_working = 0;
> + if (rc)
> + return rc;
> + return TCGBIOS_COMMAND_ERROR;
> +}
> +
> +static uint32_t activate_tpm(bool activate, bool allow_reset,
> + uint32_t *returnCode, bool verbose)
> +{
> + uint32_t 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] == !activate)
ditto here.
> + return 0;
> +
> + if (pf.flags[PERM_FLAG_IDX_DISABLE])
> + return 0;
> +
> + rc = assert_physical_presence(verbose);
> + if (rc) {
> + dprintf("Asserting physical presence failed.\n");
> + return rc;
> + }
> +
> + rc = build_and_send_cmd(TPM_ORD_PhysicalSetDeactivated,
> + activate ? CommandFlag_FALSE
> + : CommandFlag_TRUE,
> + activate ? sizeof(CommandFlag_FALSE)
> + : sizeof(CommandFlag_TRUE),
> + NULL, 0, returnCode,
> + TPM_DURATION_TYPE_SHORT);
> +
> + dprintf("Return code from PhysicalSetDeactivated(%d) = 0x%08x\n",
> + activate ? 0 : 1, *returnCode);
> +
> + if (rc || *returnCode)
> + goto err_exit;
> +
> + if (activate && allow_reset) {
> + if (verbose) {
> + printf("Requiring a reboot to activate the TPM.\n");
> + }
> + }
if (activate && allow_reset && verbose) {
printf("Requiring a reboot to activate the TPM.\n");
}
> +
> + return 0;
> +
> +err_exit:
> + dprintf("TPM malfunctioning (line %d).\n", __LINE__);
> +
> + tpm_state.tpm_working = 0;
> + if (rc)
> + return rc;
> + return TCGBIOS_COMMAND_ERROR;
> +}
> +
> +static uint32_t enable_activate(int allow_reset, uint32_t *returnCode,
> + bool verbose)
> +{
> + uint32_t rc;
> +
> + rc = enable_tpm(true, returnCode, verbose);
> + if (rc)
> + return rc;
A failure print will help to debug.
> +
> + rc = activate_tpm(true, allow_reset, returnCode, verbose);
> +
> + return rc;
> +}
> +
> +static uint32_t force_clear(bool enable_activate_before,
> + bool enable_activate_after,
> + uint32_t *returnCode, bool verbose)
> +{
> + uint32_t rc;
> + bool 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);
rc = enable_activate(false, returnCode, verbose);
> + if (rc) {
> + dprintf("Enabling/activating the TPM failed.\n");
> + return rc;
> + }
> + }
> +
> + rc = assert_physical_presence(verbose);
> + if (rc) {
> + dprintf("Asserting physical presence failed.\n");
> + return rc;
> + }
> +
> + rc = build_and_send_cmd(TPM_ORD_ForceClear,
> + NULL, 0, NULL, 0, returnCode,
> + TPM_DURATION_TYPE_SHORT);
> +
> + dprintf("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(true, returnCode, verbose);
> +
> + return 0;
> +
> +err_exit:
> + dprintf("TPM malfunctioning (line %d).\n", __LINE__);
> +
> + tpm_state.tpm_working = 0;
> + if (rc)
> + return rc;
> + return TCGBIOS_COMMAND_ERROR;
> +}
> +
> +static uint32_t set_owner_install(bool allow, uint32_t *returnCode,
> + bool verbose)
> +{
> + uint32_t rc;
> + bool 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("Asserting physical presence failed.\n");
> + return rc;
> + }
> +
> + rc = build_and_send_cmd(TPM_ORD_SetOwnerInstall,
> + (allow) ? CommandFlag_TRUE :
> + CommandFlag_FALSE,
> + sizeof(CommandFlag_TRUE),
> + NULL, 0, returnCode,
> + TPM_DURATION_TYPE_SHORT);
> +
> + dprintf("Return code from TPM_SetOwnerInstall() = 0x%08x\n",
> + *returnCode);
> +
> + if (rc || *returnCode)
> + goto err_exit;
> +
> + if (verbose) {
> + if (allow)
> + printf("Installation of owner enabled.\n");
> + else
> + printf("Installation of owner disabled.\n");
> + }
> +
> + return 0;
> +
> +err_exit:
> + dprintf("TPM malfunctioning (line %d).\n", __LINE__);
> + tpm_state.tpm_working = 0;
> + if (rc)
> + return rc;
> + return TCGBIOS_COMMAND_ERROR;
> +}
> +
> +static uint32_t tpm_process_cfg(const tpm_bios_cfg *cfg, bool verbose,
> + uint32_t *returnCode)
> +{
> + uint32_t rc = 0;
> +
> + switch (cfg->op) {
> + case TPM_PPI_OP_NOOP: /* no-op */
> + break;
> +
> + case TPM_PPI_OP_ENABLE:
> + rc = enable_tpm(true, returnCode, verbose);
> + break;
> +
> + case TPM_PPI_OP_DISABLE:
> + rc = enable_tpm(false, returnCode, verbose);
> + break;
> +
> + case TPM_PPI_OP_ACTIVATE:
> + rc = activate_tpm(true, true, returnCode, verbose);
> + break;
> +
> + case TPM_PPI_OP_DEACTIVATE:
> + rc = activate_tpm(false, true, returnCode, verbose);
> + break;
> +
> + case TPM_PPI_OP_CLEAR:
> + rc = force_clear(true, false, returnCode, verbose);
> + break;
> +
> + case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
> + rc = set_owner_install(true, returnCode, verbose);
> + break;
> +
> + case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
> + rc = set_owner_install(false, returnCode, verbose);
> + break;
> +
> + default:
> + break;
> + }
> +
> + if (rc)
> + printf("Op %d: An error occurred: 0x%x TPM return code: 0x%x\n",
> + cfg->op, rc, *returnCode);
> +
> + return rc;
> +}
> +
> +uint32_t tpm_process_opcode(uint8_t op, bool verbose)
> +{
> + uint32_t returnCode;
> + tpm_bios_cfg cfg = {
> + .op = op
> + };
> +
> + return tpm_process_cfg(&cfg, verbose, &returnCode);
> +}
> diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h
> index 9b43ce3..e0a7045 100644
> --- a/lib/libtpm/tcgbios.h
> +++ b/lib/libtpm/tcgbios.h
> @@ -14,6 +14,7 @@
> #define TCGBIOS_H
>
> #include <stdint.h>
> +#include <stdbool.h>
>
> enum ipltype {
> IPL_BCV = 0,
> @@ -28,5 +29,6 @@ uint32_t tpm_get_logsize(void);
> uint32_t tpm_ipl(enum ipltype bootcd, const uint8_t *addr, uint32_t length);
> uint32_t tpm_add_bcv(uint32_t bootdrv, const uint8_t *addr, uint32_t length);
> uint32_t tpm_add_event_separators(void);
> +uint32_t tpm_process_opcode(uint8_t op, bool verbose);
>
> #endif /* TCGBIOS_H */
> diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h
> index 888186c..420049f 100644
> --- a/lib/libtpm/tcgbios_int.h
> +++ b/lib/libtpm/tcgbios_int.h
> @@ -14,6 +14,7 @@
> #define TCGBIOS_INT_H
>
> #include <stdint.h>
> +#include <stdbool.h>
>
> #include "tpm_drivers.h"
>
> @@ -138,6 +139,30 @@ struct tpm_res_getcap_perm_flags {
> struct tpm_permanent_flags perm_flags;
> } __attribute__((packed));
>
> +struct tpm_req_getcap_stclear_flags {
> + TPM_REQ_HEADER
> + uint32_t capArea;
> + uint32_t subCapSize;
> + uint32_t subCap;
> +} __attribute__((packed));
> +
> +struct tpm_stclear_flags {
> + uint16_t tag;
> + uint8_t flags[5];
> +} __attribute__((packed));
> +
> +#define STCLEAR_FLAG_IDX_DEACTIVATED 0
> +#define STCLEAR_FLAG_IDX_DISABLE_FORCE_CLEAR 1
> +#define STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE 2
> +#define STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE_LOCK 3
> +#define STCLEAR_FLAG_IDX_GLOBAL_LOCK 4
> +
> +struct tpm_res_getcap_stclear_flags {
> + TPM_RSP_HEADER
> + uint32_t size;
> + struct tpm_stclear_flags stclear_flags;
> +} __attribute__((packed));
> +
> struct tpm_res_getcap_ownerauth {
> TPM_RSP_HEADER
> uint32_t size;
> @@ -160,4 +185,13 @@ struct tpm_res_sha1complete {
> uint8_t hash[SHA1_BUFSIZE];
> } __attribute__((packed));
>
> +#define TPM_PPI_OP_NOOP 0
> +#define TPM_PPI_OP_ENABLE 1
> +#define TPM_PPI_OP_DISABLE 2
> +#define TPM_PPI_OP_ACTIVATE 3
> +#define TPM_PPI_OP_DEACTIVATE 4
> +#define TPM_PPI_OP_CLEAR 5
> +#define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8
> +#define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9
> +
> #endif /* TCGBIOS_INT_H */
> diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code
> index de90717..7728317 100644
> --- a/lib/libtpm/tpm.code
> +++ b/lib/libtpm/tpm.code
> @@ -14,6 +14,7 @@
> */
>
> #include <tcgbios.h>
> +#include <stdbool.h>
>
>
> /************************************************/
> @@ -90,3 +91,14 @@ PRIM(tpm_X2d_add_X2d_bcv)
> int bootdrv = TOS.u;
> TOS.n = tpm_add_bcv(bootdrv, addr, length);
> MIRP
> +
> +/******************************************************/
> +/* Process an opcode to change state of the TPM */
> +/* SLOF: tpm-process-opcode ( opcode verbose -- ) */
return ?
> +/* LIBTPM: tpm_process_opcode(opcode, verbose) */
> +/******************************************************/
> +PRIM(tpm_X2d_process_X2d_opcode)
> + int opcode = TOS.u; POP;
> + bool verbose = TOS.u;
> + TOS.n = tpm_process_opcode(opcode, verbose);
> +MIRP
> diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in
> index 06b0672..e5dbc25 100644
> --- a/lib/libtpm/tpm.in
> +++ b/lib/libtpm/tpm.in
> @@ -20,3 +20,4 @@ cod(tpm-get-logsize)
> cod(tpm-add-event-separators)
> cod(tpm-ipl)
> cod(tpm-add-bcv)
> +cod(tpm-process-opcode)
> --
> 1.9.3
Regards
Nikunj
More information about the SLOF
mailing list