The following two patches add functionality to create EK and SRK keys to the TPM 2 menu. We follow TCG specifications for how to create those as RSA keys.
Regards, Stefan
Stefan Berger (2): tcbios: Add menu item to create an EK for TPM 2 tcbios: Add menu item to create a primary storage key for TPM 2
src/std/tcg.h | 63 +++++++++++ src/tcgbios.c | 341 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 388 insertions(+), 16 deletions(-)
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; + } + } + } } }
Add a menu item to create an SRK with the handle 0x81000001 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 above spec Section 7.5.1 "Storage Primary Key (SRK) Templates" and the following 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 | 3 ++- src/tcgbios.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index beecd1f..19dab64 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -599,7 +599,7 @@ struct pcctes_romex #define TPM_STATE_OWNERINSTALL 8
#define TPM2_STATE_CREATE_EK 1 -#define TPM2_STATE_CREATE_PSK 2 +#define TPM2_STATE_CREATE_SPK 2
#define TPM_PPI_OP_NOOP 0 #define TPM_PPI_OP_ENABLE 1 @@ -612,5 +612,6 @@ struct pcctes_romex
/* additional operations */ #define TPM_PPI_EXT_OP_CREATE_EK (0xe0 + 0) +#define TPM_PPI_EXT_OP_CREATE_SPK (0xe0 + 1)
#endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index e5b5678..9348a23 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -1866,6 +1866,50 @@ tpm20_create_ek(int verbose, u32 *keyhandle) }
static int +tpm20_create_spk(int verbose, u32 *keyhandle) +{ + struct tpm2_tpmt_public { + u16 publen; + u16 alg_key; + u16 alg_hash; + u32 keyflags; + u16 authpolicylen; + u8 authpolicy[0]; + 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_USERWITHAUTH | + TPM2_OBJECT_NODA | + TPM2_OBJECT_RESTRICTED | + TPM2_OBJECT_DECRYPT), + .authpolicylen = cpu_to_be16(sizeof(ttp.authpolicy)), + .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_OWNER, &ttp, sizeof(ttp), + keyhandle); +} + +static int tpm20_evictcontrol(u32 authhandle, u32 keyhandle, u32 persistentHandle) { @@ -1922,6 +1966,15 @@ tpm20_process_cfg(tpm_ppi_code msgCode, int verbose) keyhandle, 0x81010001); break; + + case TPM_PPI_EXT_OP_CREATE_SPK: + ret = tpm20_create_spk(verbose, &keyhandle); + if (ret) + break; + ret = tpm20_evictcontrol(TPM2_RH_OWNER, + keyhandle, + 0x81000001); + break; }
if (ret) @@ -2121,6 +2174,7 @@ tpm20_get_tpm_state(void)
struct tpml_handle *handles = (struct tpml_handle *)&trg->data; int has_ek = 0; + int has_spk = 0;
num_handles = be32_to_cpu(handles->count);
@@ -2128,10 +2182,14 @@ tpm20_get_tpm_state(void) u32 h = be32_to_cpu(handles->handle[i]); if (h >= 0x81010000 && h <= 0x8101ffff) has_ek = 1; + if (h >= 0x81000000 && h <= 0x8100ffff) + has_spk = 1; }
if (!has_ek) state |= TPM2_STATE_CREATE_EK; + if (!has_spk) + state |= TPM2_STATE_CREATE_SPK;
return state; } @@ -2148,6 +2206,12 @@ tpm20_show_tpm_menu(int state, int next_scancodes[4]) printf(" - has"); printf(" a persistent endorsement key.\n");
+ if (state & TPM2_STATE_CREATE_SPK) + printf(" - does not have"); + else + printf(" - has"); + printf(" a persistent storage primary key.\n"); + printf("\n1. Clear TPM\n"); next_scancodes[i++] = 2;
@@ -2155,6 +2219,10 @@ tpm20_show_tpm_menu(int state, int next_scancodes[4]) printf("2. Create a persistent endorsement primary key\n"); next_scancodes[i++] = 3; } + if (state & TPM2_STATE_CREATE_SPK) { + printf("3. Create a primary storage key\n"); + next_scancodes[i++] = 4; + } next_scancodes[i++] = 0; }
@@ -2197,6 +2265,9 @@ tpm20_menu(void) case 3: msgCode = TPM_PPI_EXT_OP_CREATE_EK; break; + case 4: + msgCode = TPM_PPI_EXT_OP_CREATE_SPK; + break; default: continue; }
On Wed, Dec 13, 2017 at 01:00:30PM -0500, Stefan Berger wrote:
The following two patches add functionality to create EK and SRK keys to the TPM 2 menu. We follow TCG specifications for how to create those as RSA keys.
Thanks Stefan. The patches look fine to me. However, so I can better understand the impact, can you provide a descrption of what real-world features this enables users to accomplish?
-Kevin
On 12/20/2017 11:32 AM, Kevin O'Connor wrote:
On Wed, Dec 13, 2017 at 01:00:30PM -0500, Stefan Berger wrote:
The following two patches add functionality to create EK and SRK keys to the TPM 2 menu. We follow TCG specifications for how to create those as RSA keys.
Thanks Stefan. The patches look fine to me. However, so I can better understand the impact, can you provide a descrption of what real-world features this enables users to accomplish?
Please don't apply these patches for now. These two patches seemed to help Win 10 accept the TPM 2 but now it looks like it generates the missing keys itself.
Stefan
-Kevin