[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