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@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; + } + } + } } }