[SeaBIOS] [PATCH 1/2] tcbios: Add menu item to create an EK for TPM 2

Stefan Berger stefanb at linux.vnet.ibm.com
Wed Dec 13 19:00:31 CET 2017


Add a menu item to create an EK with the handle 0x81010001
per the Infrastructure Work Group specification

TCG TPM v2.0 Provisioning Guidance; Version 1.0, Rev 1.0, March 15, 2017

https://trustedcomputinggroup.org/tcg-tpm-v2-0-provisioning-guidance/

For the creation flags to set on the EK we follow the spec

TCG EK Credential Profile For TPM Family 2.0; Level 0; Rev 14, Nov. 4 2014

https://trustedcomputinggroup.org/tcg-ek-credential-profile-tpm-family-2-0/

Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
---
 src/std/tcg.h |  62 ++++++++++++++
 src/tcgbios.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 316 insertions(+), 16 deletions(-)

diff --git a/src/std/tcg.h b/src/std/tcg.h
index 09a92d8..beecd1f 100644
--- a/src/std/tcg.h
+++ b/src/std/tcg.h
@@ -330,21 +330,27 @@ struct tpm_res_sha1complete {
 #define TPM2_RH_ENDORSEMENT         0x4000000b
 #define TPM2_RH_PLATFORM            0x4000000c
 
+#define TPM2_ALG_RSA                0x0001
 #define TPM2_ALG_SHA1               0x0004
+#define TPM2_ALG_AES                0x0006
 #define TPM2_ALG_SHA256             0x000b
 #define TPM2_ALG_SHA384             0x000c
 #define TPM2_ALG_SHA512             0x000d
+#define TPM2_ALG_NULL               0x0010
 #define TPM2_ALG_SM3_256            0x0012
+#define TPM2_ALG_CFB                0x0043
 
 /* TPM 2 command tags */
 #define TPM2_ST_NO_SESSIONS         0x8001
 #define TPM2_ST_SESSIONS            0x8002
 
 /* TPM 2 commands */
+#define TPM2_CC_EvictControl        0x120
 #define TPM2_CC_HierarchyControl    0x121
 #define TPM2_CC_Clear               0x126
 #define TPM2_CC_ClearControl        0x127
 #define TPM2_CC_HierarchyChangeAuth 0x129
+#define TPM2_CC_CreatePrimary       0x131
 #define TPM2_CC_SelfTest            0x143
 #define TPM2_CC_Startup             0x144
 #define TPM2_CC_StirRandom          0x146
@@ -356,8 +362,25 @@ struct tpm_res_sha1complete {
 #define TPM2_RC_INITIALIZE          0x100
 
 /* TPM 2 Capabilities */
+#define TPM2_CAP_HANDLES            0x00000001
 #define TPM2_CAP_PCRS               0x00000005
 
+/* TPM 2 Handle types */
+#define TPM2_HT_PERSISTENT          0x81000000
+
+/* TPM 2 Object flags */
+#define TPM2_OBJECT_FIXEDTPM        (1 << 1)
+#define TPM2_OBJECT_STCLEAR         (1 << 2)
+#define TPM2_OBJECT_FIXEDPARENT     (1 << 4)
+#define TPM2_OBJECT_SENSITIVEDATAORIGIN (1 << 5)
+#define TPM2_OBJECT_USERWITHAUTH    (1 << 6)
+#define TPM2_OBJECT_ADMINWITHPOLICY (1 << 7)
+#define TPM2_OBJECT_NODA            (1 << 10)
+#define TPM2_OBJECT_ENCRYPTEDDUPLICATION (1 << 11)
+#define TPM2_OBJECT_RESTRICTED      (1 << 16)
+#define TPM2_OBJECT_DECRYPT         (1 << 17)
+#define TPM2_OBJECT_SIGN            (1 << 18)
+
 /* TPM 2 data structures */
 
 struct tpm2_req_stirrandom {
@@ -453,6 +476,39 @@ struct tpml_pcr_selection {
     struct tpms_pcr_selection selections[0];
 } PACKED;
 
+struct tpml_handle {
+    u32 count;
+    u32 handle[0];
+} PACKED;
+
+struct tpm2_req_createprimary_p1 {
+    struct tpm_req_header hdr;
+    u32 authhandle;
+    u32 authblocksize;
+    struct tpm2_authblock authblock;
+    u16 sensitive_len;
+    u8 sensitive[4]; /* set to 0 */
+    /*
+    TPM2B_PUBLIC inPublic;
+    TPM2B_DATA outsideInfo
+    TPML_PCR_SELECTION creationPCR;
+    */
+} PACKED;
+
+struct tpm2_res_createprimary {
+    struct tpm_rsp_header hdr;
+    u32 keyhandle;
+    /* lots more data */
+} PACKED;
+
+struct tpm20_evictcontrol {
+    struct tpm_req_header hdr;
+    u32 authhandle;
+    u32 keyhandle;
+    u32 authblocksize;
+    struct tpm2_authblock authblock;
+    u32 persistentHandle;
+} PACKED;
 
 /****************************************************************
  * ACPI TCPA table interface
@@ -542,6 +598,9 @@ struct pcctes_romex
 #define TPM_STATE_OWNED 4
 #define TPM_STATE_OWNERINSTALL 8
 
+#define TPM2_STATE_CREATE_EK 1
+#define TPM2_STATE_CREATE_PSK 2
+
 #define TPM_PPI_OP_NOOP 0
 #define TPM_PPI_OP_ENABLE 1
 #define TPM_PPI_OP_DISABLE 2
@@ -551,4 +610,7 @@ struct pcctes_romex
 #define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8
 #define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9
 
+/* additional operations */
+#define TPM_PPI_EXT_OP_CREATE_EK  (0xe0 + 0)
+
 #endif // tcg.h
diff --git a/src/tcgbios.c b/src/tcgbios.c
index 40b3028..e5b5678 100644
--- a/src/tcgbios.c
+++ b/src/tcgbios.c
@@ -1752,9 +1752,157 @@ tpm20_clear(void)
 }
 
 static int
+tpm20_createprimary(u32 authhandle,
+                    void *pubdata, size_t pubdata_len,
+                    u32 *keyhandle)
+{
+    u8 buffer[128];
+    struct tpm2_req_createprimary_p1 trcp = {
+        .hdr.tag     = cpu_to_be16(TPM2_ST_SESSIONS),
+        .hdr.totlen  = 0,
+        .hdr.ordinal = cpu_to_be32(TPM2_CC_CreatePrimary),
+        .authhandle = cpu_to_be32(authhandle),
+        .authblocksize = cpu_to_be32(sizeof(trcp.authblock)),
+        .authblock = {
+            .handle = cpu_to_be32(TPM2_RS_PW),
+            .noncesize = cpu_to_be16(0),
+            .contsession = TPM2_YES,
+            .pwdsize = cpu_to_be16(0),
+        },
+        .sensitive_len = cpu_to_be16(sizeof(trcp.sensitive)),
+        .sensitive = {0, },
+    };
+    u16 outsideInfoLen = cpu_to_be16(0);
+    struct tpml_pcr_selection {
+        u32 count;
+        u16 hash;
+    } PACKED tps = {
+        .count = cpu_to_be32(0),
+        .hash = cpu_to_be16(0),
+    };
+
+    u32 off = sizeof(trcp);
+    memcpy(&buffer[off], pubdata, pubdata_len);
+
+    off += pubdata_len;
+    memcpy(&buffer[off], &outsideInfoLen, sizeof(outsideInfoLen));
+
+    off += sizeof(outsideInfoLen);
+    memcpy(&buffer[off], &tps, sizeof(tps));
+
+    off += sizeof(tps);
+    if (off > sizeof(buffer))
+        warn_internalerror();
+    /* complete header and copy */
+    trcp.hdr.totlen = cpu_to_be32(off);
+    memcpy(buffer, &trcp, sizeof(trcp));
+
+    struct tpm2_res_createprimary rsp;
+    u32 resp_length = sizeof(rsp);
+
+    int ret = tpmhw_transmit(0, (struct tpm_req_header *)buffer,
+                             &rsp, &resp_length,
+                             TPM_DURATION_TYPE_LONG);
+    dprintf(DEBUG_tcg, "TCGBIOS: ret= 0x%08x, resp_length = %d (%d), errcode=0x%08x\n",
+            ret, resp_length, sizeof(rsp), rsp.hdr.errcode);
+    if (ret || rsp.hdr.errcode)
+        ret = -1;
+
+    *keyhandle = be32_to_cpu(rsp.keyhandle);
+
+    dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_CreatePirmary = 0x%08x, keyhandle=0x%08x\n",
+            ret, *keyhandle);
+
+    return ret;
+}
+
+static int
+tpm20_create_ek(int verbose, u32 *keyhandle)
+{
+    struct tpm2_tpmt_public {
+        u16 publen;
+        u16 alg_key;
+        u16 alg_hash;
+        u32 keyflags;
+        u16 authpolicylen;
+        u8 authpolicy[32];
+        struct symkeydata {
+            u16 algorithm;
+            u16 keyBits;
+            u16 mode;
+        } symkeydata;
+        u16 scheme;
+        u16 keyBits;
+        u32 exponent;
+    } PACKED ttp = {
+        .publen = cpu_to_be16(sizeof(ttp)),
+        .alg_key = cpu_to_be16(TPM2_ALG_RSA),
+        .alg_hash = cpu_to_be16(TPM2_ALG_SHA256),
+        .keyflags = cpu_to_be32(TPM2_OBJECT_FIXEDTPM |
+                                TPM2_OBJECT_FIXEDPARENT |
+                                TPM2_OBJECT_SENSITIVEDATAORIGIN |
+                                TPM2_OBJECT_ADMINWITHPOLICY |
+                                TPM2_OBJECT_RESTRICTED |
+                                TPM2_OBJECT_DECRYPT),
+        .authpolicylen = cpu_to_be16(sizeof(ttp.authpolicy)),
+        .authpolicy = {
+            0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xb3, 0xf8,
+            0x1a, 0x90, 0xcc, 0x8d, 0x46, 0xa5, 0xd7, 0x24,
+            0xfd, 0x52, 0xd7, 0x6e, 0x06, 0x52, 0x0b, 0x64,
+            0xf2, 0xa1, 0xda, 0x1b, 0x33, 0x14, 0x69, 0xaa
+        },
+        .symkeydata = {
+            .algorithm = cpu_to_be16(TPM2_ALG_AES),
+            .keyBits = cpu_to_be16(128),
+            .mode = cpu_to_be16(TPM2_ALG_CFB),
+        },
+        .scheme = cpu_to_be16(TPM2_ALG_NULL),
+        .keyBits = cpu_to_be16(2048),
+        .exponent = cpu_to_be32(0),
+    };
+
+    return tpm20_createprimary(TPM2_RH_ENDORSEMENT, &ttp, sizeof(ttp),
+                               keyhandle);
+}
+
+static int
+tpm20_evictcontrol(u32 authhandle, u32 keyhandle,
+                   u32 persistentHandle)
+{
+    struct tpm20_evictcontrol te = {
+        .hdr.tag     = cpu_to_be16(TPM2_ST_SESSIONS),
+        .hdr.totlen  = cpu_to_be32(sizeof(te)),
+        .hdr.ordinal = cpu_to_be32(TPM2_CC_EvictControl),
+        .authhandle = cpu_to_be32(authhandle),
+        .keyhandle = cpu_to_be32(keyhandle),
+        .authblocksize = cpu_to_be32(sizeof(te.authblock)),
+        .authblock = {
+            .handle = cpu_to_be32(TPM2_RS_PW),
+            .noncesize = cpu_to_be16(0),
+            .contsession = TPM2_YES,
+            .pwdsize = cpu_to_be16(0),
+        },
+        .persistentHandle = cpu_to_be32(persistentHandle),
+    };
+
+    struct tpm_rsp_header rsp;
+    u32 resp_length = sizeof(rsp);
+    int ret = tpmhw_transmit(0, &te.hdr, &rsp, &resp_length,
+                             TPM_DURATION_TYPE_SHORT);
+    if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+        ret = -1;
+
+    dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_EvictControl = 0x%08x\n",
+            ret);
+
+    return ret;
+}
+
+static int
 tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
 {
     int ret = 0;
+    u32 keyhandle;
 
     switch (msgCode) {
         case TPM_PPI_OP_NOOP: /* no-op */
@@ -1765,6 +1913,15 @@ tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
             if (!ret)
                  ret = tpm20_clear();
             break;
+
+        case TPM_PPI_EXT_OP_CREATE_EK:
+            ret = tpm20_create_ek(verbose, &keyhandle);
+            if (ret)
+                break;
+            ret = tpm20_evictcontrol(TPM2_RH_OWNER,
+                                     keyhandle,
+                                     0x81010001);
+            break;
     }
 
     if (ret)
@@ -1947,14 +2104,75 @@ tpm12_menu(void)
     }
 }
 
+static int
+tpm20_get_tpm_state(void)
+{
+    int state = 0;
+    u8 buffer[256];
+    struct tpm2_res_getcapability *trg =
+      (struct tpm2_res_getcapability *)&buffer;
+    u32 i, num_handles;
+
+    int ret = tpm20_getcapability(TPM2_CAP_HANDLES, TPM2_HT_PERSISTENT,
+          (sizeof(buffer) - offsetof(struct tpm2_res_getcapability, data)) / 4,
+          &trg->hdr, sizeof(buffer));
+    if (ret)
+        return ~0;
+
+    struct tpml_handle *handles = (struct tpml_handle *)&trg->data;
+    int has_ek = 0;
+
+    num_handles = be32_to_cpu(handles->count);
+
+    for (i = 0; i < num_handles; i++) {
+        u32 h = be32_to_cpu(handles->handle[i]);
+        if (h >= 0x81010000 && h <= 0x8101ffff)
+             has_ek = 1;
+    }
+
+    if (!has_ek)
+        state |= TPM2_STATE_CREATE_EK;
+
+    return state;
+}
+
+static void
+tpm20_show_tpm_menu(int state, int next_scancodes[4])
+{
+    int i = 0;
+
+    printf("\nThe current state of the TPM is:\n");
+    if (state & TPM2_STATE_CREATE_EK)
+        printf(" - does not have");
+    else
+        printf(" - has");
+    printf(" a persistent endorsement key.\n");
+
+    printf("\n1. Clear TPM\n");
+    next_scancodes[i++] = 2;
+
+    if (state & TPM2_STATE_CREATE_EK) {
+        printf("2. Create a persistent endorsement primary key\n");
+        next_scancodes[i++] = 3;
+    }
+    next_scancodes[i++] = 0;
+}
+
 static void
 tpm20_menu(void)
 {
-    int scan_code;
+    int scan_code, next_scancodes[4];
     tpm_ppi_code msgCode;
+    int state, i;
+    int waitkey;
 
     for (;;) {
-        printf("1. Clear TPM\n");
+        if ((state = tpm20_get_tpm_state()) != ~0) {
+            tpm20_show_tpm_menu(state, next_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"
@@ -1962,22 +2180,42 @@ tpm20_menu(void)
 
         msgCode = TPM_PPI_OP_NOOP;
 
-        while ((scan_code = get_keystroke(1000)) == ~0)
-            ;
+        waitkey = 1;
 
-        switch (scan_code) {
-        case 1:
-            // ESC
-            reset();
-            break;
-        case 2:
-            msgCode = TPM_PPI_OP_CLEAR;
-            break;
-        default:
-            continue;
-        }
+        while (waitkey) {
+            while ((scan_code = get_keystroke(1000)) == ~0)
+                ;
+
+            switch (scan_code) {
+            case 1:
+                // ESC
+                reset();
+                break;
+            case 2:
+                msgCode = TPM_PPI_OP_CLEAR;
+                break;
+            case 3:
+                msgCode = TPM_PPI_EXT_OP_CREATE_EK;
+                break;
+            default:
+                continue;
+            }
 
-        tpm20_process_cfg(msgCode, 0);
+            /*
+             * Using the next_scancodes array, check whether the
+             * pressed key is currently a valid option.
+             */
+            for (i = 0; i < sizeof(next_scancodes); i++) {
+                if (next_scancodes[i] == 0)
+                    break;
+
+                if (next_scancodes[i] == scan_code) {
+                    tpm20_process_cfg(msgCode, 0);
+                    waitkey = 0;
+                    break;
+                }
+            }
+        }
     }
 }
 
-- 
2.5.5




More information about the SeaBIOS mailing list