[SeaBIOS] [PATCH] tcgbios: Implement TPM 2.0 menu item to activate and deactivate PCR banks

Stefan Berger posted 1 patch 5 years, 3 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/seabios tags/patchew/20190114192848.1993980-1-stefanb@linux.vnet.ibm.com
src/std/tcg.h |  18 ++++
src/tcgbios.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++-
src/util.h    |   2 +
3 files changed, 253 insertions(+), 2 deletions(-)
[SeaBIOS] [PATCH] tcgbios: Implement TPM 2.0 menu item to activate and deactivate PCR banks
Posted by Stefan Berger 5 years, 3 months ago
Implement a TPM 2.0 menu item that allows a user to toggle the activation
of PCR banks of the TPM 2.0. After successful activation we shut down the
TPM 2.0 and reset the machine.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
 src/std/tcg.h |  18 ++++
 src/tcgbios.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++-
 src/util.h    |   2 +
 3 files changed, 253 insertions(+), 2 deletions(-)

diff --git a/src/std/tcg.h b/src/std/tcg.h
index 09a92d8..eb9e67d 100644
--- a/src/std/tcg.h
+++ b/src/std/tcg.h
@@ -336,6 +336,12 @@ struct tpm_res_sha1complete {
 #define TPM2_ALG_SHA512             0x000d
 #define TPM2_ALG_SM3_256            0x0012
 
+#define TPM2_ALG_SHA1_FLAG          (1 << 0)
+#define TPM2_ALG_SHA256_FLAG        (1 << 1)
+#define TPM2_ALG_SHA384_FLAG        (1 << 2)
+#define TPM2_ALG_SHA512_FLAG        (1 << 3)
+#define TPM2_ALG_SM3_256_FLAG       (1 << 4)
+
 /* TPM 2 command tags */
 #define TPM2_ST_NO_SESSIONS         0x8001
 #define TPM2_ST_SESSIONS            0x8002
@@ -345,8 +351,10 @@ struct tpm_res_sha1complete {
 #define TPM2_CC_Clear               0x126
 #define TPM2_CC_ClearControl        0x127
 #define TPM2_CC_HierarchyChangeAuth 0x129
+#define TPM2_CC_PCR_Allocate        0x12b
 #define TPM2_CC_SelfTest            0x143
 #define TPM2_CC_Startup             0x144
+#define TPM2_CC_Shutdown            0x145
 #define TPM2_CC_StirRandom          0x146
 #define TPM2_CC_GetCapability       0x17a
 #define TPM2_CC_GetRandom           0x17b
@@ -442,6 +450,15 @@ struct tpm2_res_getcapability {
     u8 data[0]; /* capability dependent data */
 } PACKED;
 
+struct tpm2_req_pcr_allocate {
+    struct tpm_req_header hdr;
+    u32 authhandle;
+    u32 authblocksize;
+    struct tpm2_authblock authblock;
+    u32 count;
+    u8 tpms_pcr_selections[4];
+} PACKED;
+
 struct tpms_pcr_selection {
     u16 hashAlg;
     u8 sizeOfSelect;
@@ -550,5 +567,6 @@ struct pcctes_romex
 #define TPM_PPI_OP_CLEAR 5
 #define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8
 #define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9
+#define TPM_PPI_OP_SET_PCR_BANKS 23
 
 #endif // tcg.h
diff --git a/src/tcgbios.c b/src/tcgbios.c
index 24846d3..ae0020e 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -180,6 +180,60 @@ tpm20_get_hash_buffersize(u16 hashAlg)
     }
 }
 
+static u8
+tpm20_hashalg_to_flag(u16 hashAlg)
+{
+    switch (hashAlg) {
+    case TPM2_ALG_SHA1:
+        return TPM2_ALG_SHA1_FLAG;
+    case TPM2_ALG_SHA256:
+        return TPM2_ALG_SHA256_FLAG;
+    case TPM2_ALG_SHA384:
+        return TPM2_ALG_SHA384_FLAG;
+    case TPM2_ALG_SHA512:
+        return TPM2_ALG_SHA512_FLAG;
+    case TPM2_ALG_SM3_256:
+        return TPM2_ALG_SM3_256_FLAG;
+    default:
+        return 0;
+    }
+}
+
+static u16
+tpm20_hashalg_flag_to_hashalg(u8 hashalg_flag)
+{
+    switch (hashalg_flag) {
+    case TPM2_ALG_SHA1_FLAG:
+        return TPM2_ALG_SHA1;
+    case TPM2_ALG_SHA256_FLAG:
+        return TPM2_ALG_SHA256;
+    case TPM2_ALG_SHA384_FLAG:
+        return TPM2_ALG_SHA384;
+    case TPM2_ALG_SHA512_FLAG:
+        return TPM2_ALG_SHA512;
+    case TPM2_ALG_SM3_256_FLAG:
+        return TPM2_ALG_SM3_256;
+    default:
+        return 0;
+    }
+}
+
+static const char *
+tpm20_hashalg_flag_to_name(u8 hashalg_flag)
+{
+    switch (hashalg_flag) {
+    case TPM2_ALG_SHA1_FLAG:
+        return "SHA1";
+    case TPM2_ALG_SHA256_FLAG:
+        return "SHA256";
+    case TPM2_ALG_SHA384_FLAG:
+        return "SHA384";
+    case TPM2_ALG_SHA512_FLAG:
+        return "SHA512";
+    }
+    return NULL;
+}
+
 // Add an entry at the start of the log describing digest formats
 static int
 tpm20_write_EfiSpecIdEventStruct(void)
@@ -432,6 +486,104 @@ tpm20_get_pcrbanks(void)
     return ret;
 }
 
+static int
+tpm20_get_suppt_pcrbanks(u8 *suppt_pcrbanks, u8 *active_pcrbanks)
+{
+    *suppt_pcrbanks = 0;
+    *active_pcrbanks = 0;
+
+    if (!tpm20_pcr_selection)
+        return -1;
+
+    struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
+    void *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
+
+    while (1) {
+        u8 sizeOfSelect = sel->sizeOfSelect;
+        void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
+        if (nsel > end)
+            return 0;
+
+        u16 hashalg = be16_to_cpu(sel->hashAlg);
+        u8 hashalg_flag = tpm20_hashalg_to_flag(hashalg);
+
+        *suppt_pcrbanks |= hashalg_flag;
+
+        unsigned i;
+        for (i = 0; i < sizeOfSelect; i++) {
+            if (sel->pcrSelect[i]) {
+                *active_pcrbanks |= hashalg_flag;
+                break;
+            }
+        }
+
+        sel = nsel;
+    }
+}
+
+static int
+tpm20_set_pcrbanks(u32 active_banks)
+{
+    struct tpm2_req_pcr_allocate trpa = {
+        .hdr.tag     = cpu_to_be16(TPM2_ST_SESSIONS),
+        .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Allocate),
+        .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+        .authblocksize = cpu_to_be32(sizeof(trpa.authblock)),
+        .authblock = {
+            .handle = cpu_to_be32(TPM2_RS_PW),
+            .noncesize = cpu_to_be16(0),
+            .contsession = TPM2_YES,
+            .pwdsize = cpu_to_be16(0),
+        },
+    };
+    struct tpms_pcr_selection3 {
+        u16 hashAlg;
+        u8 sizeOfSelect;
+        u8 pcrSelect[3];
+    } tps[ARRAY_SIZE(trpa.tpms_pcr_selections)];
+    int i = 0;
+    u8 hashalg_flag = TPM2_ALG_SHA1_FLAG;
+    u8 dontcare, suppt_banks;
+
+    tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare);
+
+    while (hashalg_flag) {
+        if ((hashalg_flag & suppt_banks)) {
+            u16 hashalg = tpm20_hashalg_flag_to_hashalg(hashalg_flag);
+
+            if (hashalg) {
+                u8 mask = 0;
+                tps[i].hashAlg = cpu_to_be16(hashalg);
+                tps[i].sizeOfSelect = 3;
+
+                if (active_banks & hashalg_flag)
+                    mask = 0xff;
+
+                tps[i].pcrSelect[0] = mask;
+                tps[i].pcrSelect[1] = mask;
+                tps[i].pcrSelect[2] = mask;
+                i++;
+            }
+        }
+        hashalg_flag <<= 1;
+    }
+
+    trpa.count = cpu_to_be32(i);
+    memcpy(trpa.tpms_pcr_selections, tps, i * sizeof(tps[0]));
+    trpa.hdr.totlen = cpu_to_be32(offsetof(struct tpm2_req_pcr_allocate,
+                                           tpms_pcr_selections) +
+                                  i * sizeof(tps[0]));
+
+    struct tpm_rsp_header rsp;
+    u32 resp_length = sizeof(rsp);
+
+    int ret = tpmhw_transmit(0, &trpa.hdr, &rsp, &resp_length,
+                             TPM_DURATION_TYPE_SHORT);
+    ret = ret ? -1 : be32_to_cpu(rsp.errcode);
+
+    return ret;
+}
+
 static int
 tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
 {
@@ -1752,7 +1904,7 @@ tpm20_clear(void)
 }
 
 static int
-tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
+tpm20_process_cfg(tpm_ppi_code msgCode, u32 pprm, int verbose)
 {
     int ret = 0;
 
@@ -1765,6 +1917,13 @@ tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
             if (!ret)
                  ret = tpm20_clear();
             break;
+
+        case TPM_PPI_OP_SET_PCR_BANKS:
+            ret = tpm20_set_pcrbanks(pprm);
+            if (!ret)
+                ret = tpm_simple_cmd(0, TPM2_CC_Shutdown,
+                                     2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
+            break;
     }
 
     if (ret)
@@ -1947,14 +2106,77 @@ tpm12_menu(void)
     }
 }
 
+static int
+tpm20_menu_change_active_pcrbanks(u8 *activate_banks)
+{
+    u8 active_banks, suppt_banks;
+
+    tpm20_get_suppt_pcrbanks(&suppt_banks, &active_banks);
+
+    *activate_banks = active_banks;
+
+    while (1) {
+        u8 hashalg_flag = TPM2_ALG_SHA1_FLAG;
+        u8 i = 0;
+
+        printf("\nToggle active PCR banks by pressing number key\n\n");
+
+        while (hashalg_flag) {
+            u8 flag = hashalg_flag & suppt_banks;
+            const char *hashname = tpm20_hashalg_flag_to_name(flag);
+
+            i++;
+            if (hashname) {
+                printf("  %d: %s", i, hashname);
+                if (*activate_banks & hashalg_flag)
+                    printf(" (enabled)");
+                printf("\n");
+            }
+
+            hashalg_flag <<= 1;
+        }
+        printf("\n"
+               "ESC: return to previous menu without changing active PCR banks\n"
+               "A  : activate selection\n");
+        u8 flagnum;
+        int show = 0;
+        while (!show) {
+            int scancode = get_keystroke(1000);
+
+            switch (scancode) {
+            case ~0:
+                continue;
+            case 1: /* ESC */
+                printf("\n");
+                return -1;
+            case 2 ... 6: /* keys 1 .. 5 */
+                flagnum = scancode - 1;
+                if (flagnum > i)
+                    continue;
+                if (suppt_banks & (1 << (flagnum - 1))) {
+                    *activate_banks ^= 1 << (flagnum - 1);
+                    show = 1;
+                }
+                break;
+            case SCANCODE_A:
+                return 0;
+            }
+        }
+    }
+}
+
 static void
 tpm20_menu(void)
 {
     int scan_code;
     tpm_ppi_code msgCode;
+    u32 pprm;
+    u8 active_banks;
+    int do_reset = 0;
 
     for (;;) {
         printf("1. Clear TPM\n");
+        printf("2. Change active PCR banks\n");
 
         printf("\nIf no change is desired or if this menu was reached by "
                "mistake, press ESC to\n"
@@ -1973,11 +2195,20 @@ tpm20_menu(void)
         case 2:
             msgCode = TPM_PPI_OP_CLEAR;
             break;
+        case 3:
+            if (tpm20_menu_change_active_pcrbanks(&active_banks) < 0)
+                continue;
+            msgCode = TPM_PPI_OP_SET_PCR_BANKS;
+            pprm = active_banks;
+            do_reset = 1;
+            break;
         default:
             continue;
         }
 
-        tpm20_process_cfg(msgCode, 0);
+        tpm20_process_cfg(msgCode, pprm,  0);
+        if (do_reset)
+            reset();
     }
 }
 
diff --git a/src/util.h b/src/util.h
index 6dd080f..b7169dd 100644
--- a/src/util.h
+++ b/src/util.h
@@ -38,6 +38,8 @@ struct usbdevice_s;
 int bootprio_find_usb(struct usbdevice_s *usbdev, int lun);
 int get_keystroke(int msec);
 
+#define SCANCODE_A 0x1e
+
 // bootsplash.c
 void enable_vga_console(void);
 void enable_bootsplash(void);
-- 
2.17.2
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-leave@seabios.org