Frans Hendriks has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30826
Change subject: security/tpm/tss/tcg-2.0: Add function to return TMP2 capabilities. ......................................................................
security/tpm/tss/tcg-2.0: Add function to return TMP2 capabilities.
Add function tlcl_getcapability() to return capability, used by measured boot. In function unmarshal_get_capability handling of TPM_CAP_PCRS has been added for TPM2 get capability commands.
BUG=N/A TEST=Build binary and verified logging on Facebook FBG-1701
Change-Id: I85e1bd2822aa6e7fd95ff2b9faa25cf183e6de37 Signed-off-by: Frans Hendriks fhendriks@eltan.com --- M src/security/tpm/tss.h M src/security/tpm/tss/tcg-2.0/tss.c M src/security/tpm/tss/tcg-2.0/tss_marshaling.c M src/security/tpm/tss/tcg-2.0/tss_structures.h 4 files changed, 302 insertions(+), 19 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/26/30826/1
diff --git a/src/security/tpm/tss.h b/src/security/tpm/tss.h index c4f2608..610a99c 100644 --- a/src/security/tpm/tss.h +++ b/src/security/tpm/tss.h @@ -1,4 +1,5 @@ /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Copyright (C) 2018 Eltan B.V. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -122,6 +123,35 @@ uint32_t tlcl_continue_self_test(void);
/** + * Issue tpm get capability command + */ +uint32_t tlcl_getcapability(TPM_CAP capability, uint32_t property, + uint32_t propertyCount, TPMI_YES_NO *moreData, + TPMS_CAPABILITY_DATA *capabilityData); + +/** + * Issue more flexible process command + */ +void *tpm_process_command_ex(TPM_CC command, void *command_body, + size_t command_size, size_t *response_size, + bool marshal); + +/* + * tlcl_extend command that allows more digests to be passed in at the same + * time + */ +uint32_t tlcl_extend_ex(int pcr_num, const TPML_DIGEST_VALUES *in_digests); + +/** + * Return size of digest. + * + * @param[in] HashAlgo Hash algorithm + * + * @return size of digest + */ +uint16_t tlcl_get_hash_size_from_algo(TPMI_ALG_HASH hashAlgo); + +/** * Write [length] bytes of [data] to space at [index]. The TPM error code is * returned. */ @@ -144,7 +174,7 @@ uint32_t tlcl_physical_presence_cmd_enable(void);
/** - * Finalize the physical presence settings: sofware PP is enabled, hardware PP + * Finalize the physical presence settings: software PP is enabled, hardware PP * is disabled, and the lifetime lock is set. The TPM error code is returned. */ uint32_t tlcl_finalize_physical_presence(void); diff --git a/src/security/tpm/tss/tcg-2.0/tss.c b/src/security/tpm/tss/tcg-2.0/tss.c index e579bff..87f38e1 100644 --- a/src/security/tpm/tss/tcg-2.0/tss.c +++ b/src/security/tpm/tss/tcg-2.0/tss.c @@ -1,5 +1,6 @@ /* * Copyright 2016 The Chromium OS Authors. All rights reserved. + * Copyright 2017-2018 Eltan B.V. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -15,6 +16,12 @@ #include "tss_structures.h" #include "tss_marshaling.h"
+static INTERNAL_HASH_INFO mHashInfo[] = { + {TPM_ALG_ERROR, 1}, + {TPM_ALG_SHA1, SHA1_DIGEST_SIZE}, + {TPM_ALG_SHA256, SHA256_DIGEST_SIZE}, +}; + /* * This file provides interface between firmware and TPM2 device. The TPM1.2 * API was copied as is and relevant functions modified to comply with the @@ -53,6 +60,48 @@ return tpm_unmarshal_response(command, &ib); }
+void *tpm_process_command_ex(TPM_CC command, void *command_body, + size_t command_size, size_t *response_size, bool marshal) +{ + struct obuf ob; + struct ibuf ib; + size_t out_size; + size_t in_size; + const uint8_t *sendb; + /* Command/response buffer. */ + static uint8_t cr_buffer[TPM_BUFFER_SIZE] CAR_GLOBAL; + + uint8_t *cr_buffer_ptr = car_get_var_ptr(cr_buffer); + + if (marshal) { + obuf_init(&ob, cr_buffer_ptr, sizeof(cr_buffer)); + if (tpm_marshal_command(command, command_body, &ob) < 0) { + printk(BIOS_ERR, "command %#x\n", command); + return NULL; + } + sendb = obuf_contents(&ob, &out_size); + } else { + sendb = command_body; + out_size = command_size; + } + + in_size = sizeof(cr_buffer); + if (tis_sendrecv(sendb, out_size, cr_buffer_ptr, &in_size)) { + printk(BIOS_ERR, "tpm transaction failed\n"); + return NULL; + } + + ibuf_init(&ib, cr_buffer_ptr, in_size); + + if (response_size) + *response_size = in_size; + + if (marshal) + return tpm_unmarshal_response(command, &ib); + else + return cr_buffer_ptr; +} + static uint32_t tlcl_send_startup(TPM_SU type) { struct tpm2_startup startup; @@ -139,7 +188,7 @@ pcr_ext_cmd.digests.count = 1; pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256; memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest, - sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256)); + sizeof(TPMU_HA));
response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
@@ -151,6 +200,65 @@ return TPM_SUCCESS; }
+/* + * Handle multiple digests (SHA1 and SHA256 at the moment) + */ +uint32_t tlcl_extend_ex(int pcr_num, const TPML_DIGEST_VALUES *in_digests) +{ + struct tpm2_pcr_extend_cmd pcr_ext_cmd; + struct tpm2_response *response; + int i; + + pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num; + pcr_ext_cmd.digests.count = in_digests->count; + + printk(BIOS_SPEW, "%s: pcr = %d\n", __func__, pcr_num); + printk(BIOS_SPEW, "%s: in_digests->count = %d\n", __func__, + in_digests->count); + + for (i = 0; i < in_digests->count ; i++) { + pcr_ext_cmd.digests.digests[i].hashAlg = + in_digests->digests[i].hashAlg; + memcpy((void *) pcr_ext_cmd.digests.digests[i].digest.sha256, + (void *) in_digests->digests[i].digest.sha256, + sizeof(TPMU_HA)); + + printk(BIOS_SPEW, "%s: in_digests[%d]->hash_alg = 0x%x\n", + __func__, i, in_digests->digests[i].hashAlg); + } + + response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd); + + /* + * Check if we are invalidating the pcrs, ignore the error if this is + * the case + */ + if (in_digests->count == 1) { + if (in_digests->digests[0].hashAlg == TPM_ALG_ERROR) { + if (in_digests->digests[0].digest.invalidate_pcrs == + 1) { + if (response) { + if ((response->hdr.tpm_code & + ~TPM_RC_N_MASK) == (TPM_RC_P | + TPM_RC_HASH)){ + printk(BIOS_SPEW, "%s:" + " TPM_RC_HASH returned this is" + " expected\n", __func__); + return TPM_SUCCESS; + } + } + } + } + } + + printk(BIOS_INFO, "%s: response is 0x%x\n", + __func__, response ? response->hdr.tpm_code : -1); + if (!response || response->hdr.tpm_code) + return TPM_E_IOERROR; + + return TPM_SUCCESS; +} + uint32_t tlcl_finalize_physical_presence(void) { /* Nothing needs to be done with tpm2. */ @@ -178,13 +286,22 @@ uint32_t tlcl_lib_init(void) { uint8_t done = car_get_var(tlcl_init_done); + + printk(BIOS_SPEW, "%s: tlcl_init_done is %d\n", __func__, done); if (done) return VB2_SUCCESS;
- if (tis_init()) + printk(BIOS_SPEW, "%s: calling tis_init\n", __func__); + if (tis_init()) { + printk(BIOS_ERR, "%s: tis_init returned error\n", __func__); return VB2_ERROR_UNKNOWN; - if (tis_open()) + } + + printk(BIOS_SPEW, "%s: calling tis_open\n", __func__); + if (tis_open()) { + printk(BIOS_ERR, "%s: tis_open returned error\n", __func__); return VB2_ERROR_UNKNOWN; + }
car_set_var(tlcl_init_done, 1);
@@ -361,3 +478,61 @@
return TPM_SUCCESS; } + +/* + * Issue the tpm2 get capability command + * + * Please note that the capabilityData is not unmarshalled. + */ +uint32_t tlcl_getcapability(TPM_CAP capability, uint32_t property, + uint32_t propertyCount, TPMI_YES_NO *moreData, + TPMS_CAPABILITY_DATA *capabilityData) +{ + struct tpm2_get_capability cmd; + struct tpm2_response *response; + size_t response_size; + + cmd.capability = capability; + cmd.property = property; + cmd.propertyCount = propertyCount; + + if (propertyCount > 1) { + printk(BIOS_ERR, "%s: PropertyCount more than one not supported" + " yet\n", __func__); + } + + response = tpm_process_command_ex(TPM2_GetCapability, &cmd, 0, + &response_size, 1); + + if (!response) { + printk(BIOS_ERR, "%s: Command Failed\n", __func__); + return TPM_E_IOERROR; + } + + if (moreData) + *moreData = response->gc.more_data; + memcpy(capabilityData, &response->gc.cd, response_size - + sizeof(TPMI_YES_NO) - sizeof(struct tpm_header)); + return TPM_SUCCESS; +} + +/** + Return size of digest. + + @param[in] HashAlgo Hash algorithm + + @return size of digest +**/ + +uint16_t tlcl_get_hash_size_from_algo(TPMI_ALG_HASH hashAlgo) +{ + uint16_t index; + + for (index = 0; index < ARRAY_SIZE(mHashInfo); index++) + if (mHashInfo[index].hashAlgo == hashAlgo) + return mHashInfo[index].hashSize; + + printk(BIOS_SPEW, "%s: unknown hash algorithm %d\n", __func__, + hashAlgo); + return 0; +} diff --git a/src/security/tpm/tss/tcg-2.0/tss_marshaling.c b/src/security/tpm/tss/tcg-2.0/tss_marshaling.c index 49ac5e8..b4518d20 100644 --- a/src/security/tpm/tss/tcg-2.0/tss_marshaling.c +++ b/src/security/tpm/tss/tcg-2.0/tss_marshaling.c @@ -1,5 +1,6 @@ /* * Copyright 2016 The Chromium OS Authors. All rights reserved. + * Copyright (C) 2018 Eltan B.V. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -12,6 +13,7 @@
#include "tss_marshaling.h" #include <security/tpm/tss/vendor/cr50/cr50.h> +#include <security/tpm/tss.h>
static uint16_t tpm_tag CAR_GLOBAL; /* Depends on the command type. */
@@ -82,7 +84,7 @@
rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg); rc |= obuf_write(ob, tpmtha->digest.sha256, - sizeof(tpmtha->digest.sha256)); + tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
return rc; } @@ -398,6 +400,22 @@ rc |= ibuf_read_be32(ib, &pp->value); } break; + case TPM_CAP_PCRS: + if (ibuf_read_be32(ib, &gcr->cd.data.assignedPCR.count)) + return -1; + if (gcr->cd.data.assignedPCR.count > ARRAY_SIZE + (gcr->cd.data.assignedPCR.pcrSelections)) { + printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n", + __FILE__, __func__, __LINE__, + gcr->cd.data.assignedPCR.count); + return -1; + } + for (i = 0; i < gcr->cd.data.assignedPCR.count; i++) { + TPMS_PCR_SELECTION *pp = + gcr->cd.data.assignedPCR.pcrSelections + i; + rc |= ibuf_read(ib, pp, sizeof(TPMS_PCR_SELECTION)); + } + break; default: printk(BIOS_ERR, "%s:%d - unable to unmarshal capability response", @@ -448,12 +466,12 @@ }
/* - * Let's ignore the authorisation section. It should be 5 bytes total, + * Let's ignore the authorization section. It should be 5 bytes total, * just confirm that this is the case and report any discrepancy. */ if (ibuf_remaining(ib) != 5) printk(BIOS_ERR, - "%s:%d - unexpected authorisation seciton size %zd\n", + "%s:%d - unexpected authorization section size %zd\n", __func__, __LINE__, ibuf_remaining(ib));
ibuf_oob_drain(ib, ibuf_remaining(ib)); diff --git a/src/security/tpm/tss/tcg-2.0/tss_structures.h b/src/security/tpm/tss/tcg-2.0/tss_structures.h index 2bac633..e70ae02 100644 --- a/src/security/tpm/tss/tcg-2.0/tss_structures.h +++ b/src/security/tpm/tss/tcg-2.0/tss_structures.h @@ -1,5 +1,6 @@ /* * Copyright 2016 The Chromium OS Authors. All rights reserved. + * Copyright 2017-2018 Eltan B.V. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -22,6 +23,12 @@ #define TPM2_RC_SUCCESS 0 #define TPM2_RC_NV_DEFINED 0x14c
+// +// We set this to two here as we only support SHA1 and SHA256 right now. +// Should be updated when additional algorithms are supported +// +#define HASH_COUNT 2 + /* Basic TPM2 types. */ typedef uint16_t TPM_SU; typedef uint16_t TPM_ALG_ID; @@ -36,12 +43,28 @@ typedef TPM_HANDLE TPM_RH;
/* Some hardcoded algorithm values. */ -#define TPM_ALG_HMAC ((TPM_ALG_ID)0x0005) -#define TPM_ALG_NULL ((TPM_ALG_ID)0x0010) -#define TPM_ALG_SHA1 ((TPM_ALG_ID)0x0004) -#define TPM_ALG_SHA256 ((TPM_ALG_ID)0x000b) +// Table 7 - TPM_ALG_ID Constants +#define TPM_ALG_ERROR ((TPM_ALG_ID)0x0000) +#define TPM_ALG_HMAC ((TPM_ALG_ID)0x0005) +#define TPM_ALG_NULL ((TPM_ALG_ID)0x0010) +#define TPM_ALG_SHA1 ((TPM_ALG_ID)0x0004) +#define TPM_ALG_SHA256 ((TPM_ALG_ID)0x000b) +#define TPM_ALG_SHA384 ((TPM_ALG_ID)0x000C) +#define TPM_ALG_SHA512 ((TPM_ALG_ID)0x000D) +#define TPM_ALG_SM3_256 ((TPM_ALG_ID)0x0012)
+// Annex A Algorithm Constants + +// Table 205 - Defines for SHA1 Hash Values +#define SHA1_DIGEST_SIZE 20 +// Table 206 - Defines for SHA256 Hash Values #define SHA256_DIGEST_SIZE 32 +// Table 207 - Defines for SHA384 Hash Values +//#define SHA384_DIGEST_SIZE 48 +// Table 208 - Defines for SHA512 Hash Values +#define SHA512_DIGEST_SIZE 64 +// Table 209 - Defines for SM3_256 Hash Values +//#define SM3_256_DIGEST_SIZE 32
/* Some hardcoded hierarchies. */ #define TPM_RH_NULL 0x40000007 @@ -79,6 +102,12 @@ space is defined by the lower 16 bits. */ #define TPM_CC_VENDOR_BIT_MASK 0x20000000
+// Table 15 - TPM_RC Constants (Actions) +#define RC_FMT1 (TPM_RC)(0x080) +#define TPM_RC_HASH (TPM_RC)(RC_FMT1 + 0x003) +#define TPM_RC_P (TPM_RC)(0x040) +#define TPM_RC_N_MASK (TPM_RC)(0xF00) + /* Startup values. */ #define TPM_SU_CLEAR 0 #define TPM_SU_STATE 1 @@ -144,7 +173,9 @@ };
/* Various TPM capability types to use when querying the device. */ +// Table 21 - TPM_CAP Constants typedef uint32_t TPM_CAP; +#define TPM_CAP_PCRS ((TPM_CAP)0x00000005) #define TPM_CAP_TPM_PROPERTIES ((TPM_CAP)0x00000006)
typedef TPM_HANDLE TPMI_RH_NV_AUTH; @@ -224,16 +255,37 @@ sizeof(TPMI_YES_NO) - sizeof(TPM_CAP) - sizeof(uint32_t)) #define MAX_TPM_PROPERTIES (MAX_CAP_DATA/sizeof(TPMS_TAGGED_PROPERTY))
+#define IMPLEMENTATION_PCR 24 +#define PLATFORM_PCR 24 + +#define PCR_SELECT_MIN ((PLATFORM_PCR + 7) / 8) +#define PCR_SELECT_MAX ((IMPLEMENTATION_PCR + 7) / 8) + /* Somewhat arbitrary, leave enough room for command wrappers. */ #define MAX_NV_BUFFER_SIZE (TPM_BUFFER_SIZE - sizeof(struct tpm_header) - 50)
+// Table 81 - TPMS_PCR_SELECTION Structure typedef struct { - uint32_t count; - TPMS_TAGGED_PROPERTY tpmProperty[MAX_TPM_PROPERTIES]; + TPMI_ALG_HASH hash; + uint8_t sizeofSelect; + uint8_t pcrSelect[PCR_SELECT_MAX]; +} __packed TPMS_PCR_SELECTION; + +// Table 98 - TPML_PCR_SELECTION Structure +typedef struct { + uint32_t count; + TPMS_PCR_SELECTION pcrSelections[HASH_COUNT]; +} __packed TPML_PCR_SELECTION; + +// Table 100 - TPML_TAGGED_TPM_PROPERTY Structure +typedef struct { + uint32_t count; + TPMS_TAGGED_PROPERTY tpmProperty[MAX_TPM_PROPERTIES]; } TPML_TAGGED_TPM_PROPERTY;
typedef union { - TPML_TAGGED_TPM_PROPERTY tpmProperties; + TPML_TAGGED_TPM_PROPERTY tpmProperties; + TPML_PCR_SELECTION assignedPCR; } TPMU_CAPABILITIES;
typedef struct { @@ -271,22 +323,30 @@ } TPM2B_MAX_NV_BUFFER;
/* - * This is a union, but as of now we support just one digest - sha256, so - * there is just one element. + * This is a union, but as of now we support just sha1 and sha256 */ +// Table 66 - TPMU_HA Union typedef union { - uint8_t sha256[SHA256_DIGEST_SIZE]; + uint8_t invalidate_pcrs; + uint8_t sha1[SHA1_DIGEST_SIZE]; + uint8_t sha256[SHA256_DIGEST_SIZE]; } TPMU_HA;
typedef struct { + TPMI_ALG_HASH hashAlgo; + uint16_t hashSize; +} INTERNAL_HASH_INFO; + +typedef struct { TPMI_ALG_HASH hashAlg; TPMU_HA digest; } TPMT_HA;
+// Table 96 -- TPML_DIGEST_VALUES Structure <I/O> typedef struct { uint32_t count; - TPMT_HA digests[1]; /* Limit max number of hashes to 1. */ -} TPML_DIGEST_VALUES; + TPMT_HA digests[HASH_COUNT]; +} __packed TPML_DIGEST_VALUES;
struct nv_read_response { uint32_t params_size;