This series of patches extends the TPM2 code to extend the BIOS related PCRs 0-7 in all available banks. This prevents that these PCRs remain untouched and filled with bogus values by applications. For example, the SHA1 hash is extended into the SHA256 bank. The value that is extended into this bank is essentially a SHA1 with zero bytes used for filling it to the size of a sha256 hash. This is done for all PCR banks of the TPM2 where these PCRs are available.
Regards, Stefan
Stefan Berger (3): tpm: Retrieve the PCR Bank configuration tpm: Restructure tpm20_extend to use buffer and take hash as parameter tpm: Extend tpm20_extend to support extending to multiple PCR banks
src/std/tcg.h | 45 +++++++++++++-- src/tcgbios.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 201 insertions(+), 19 deletions(-)
Implement tpm20_get_capability and retrieve the PCR Bank configuration from the TPM using this function.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 29 +++++++++++++++++++++++++++++ src/tcgbios.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
diff --git a/src/std/tcg.h b/src/std/tcg.h index c59f671..d60ee09 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -394,12 +394,16 @@ struct tpm_res_sha1complete { #define TPM2_CC_SelfTest 0x143 #define TPM2_CC_Startup 0x144 #define TPM2_CC_StirRandom 0x146 +#define TPM2_CC_GetCapability 0x17a #define TPM2_CC_GetRandom 0x17b #define TPM2_CC_PCR_Extend 0x182
/* TPM 2 error codes */ #define TPM2_RC_INITIALIZE 0x100
+/* TPM 2 Capabilities */ +#define TPM2_CAP_PCRS 0x00000005 + /* TPM 2 data structures */
struct tpm2b_stir { @@ -475,6 +479,31 @@ struct tpm2_req_hierarchycontrol { u8 state; } PACKED;
+struct tpm2_req_getcapability { + struct tpm_req_header hdr; + u32 capability; + u32 property; + u32 propertycount; +} PACKED; + +struct tpm2_res_getcapability { + struct tpm_rsp_header hdr; + u8 moreData; + u32 capability; + u8 data[0]; /* capability dependent data */ +} PACKED; + +struct tpms_pcr_selection { + u16 hashAlg; + u8 sizeOfSelect; + u8 pcrSelect[0]; +} PACKED; + +struct tpml_pcr_selection { + u32 count; + struct tpms_pcr_selection selections[0]; +} PACKED; + /* TPM 2 log entry */
struct tpml_digest_values_sha1 { diff --git a/src/tcgbios.c b/src/tcgbios.c index 334d99b..a79b880 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -24,6 +24,7 @@ #include "tcgbios.h"// tpm_*, prototypes #include "util.h" // printf, get_keystroke #include "stacks.h" // wait_threads, reset +#include "malloc.h" // malloc_high
/**************************************************************** * TPM 1.2 commands @@ -76,6 +77,9 @@ static int TPM_has_physical_presence;
static TPMVersion TPM_version;
+static u32 tpm20_pcr_selection_size; +static struct tpml_pcr_selection *tpm20_pcr_selection; + static struct tcpa_descriptor_rev2 * find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp) { @@ -669,6 +673,51 @@ err_exit: }
static int +tpm20_getcapability(u32 capability, u32 property, u32 count, + struct tpm_rsp_header *rsp, u32 rsize) +{ + struct tpm2_req_getcapability trg = { + .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trg)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_GetCapability), + .capability = cpu_to_be32(capability), + .property = cpu_to_be32(property), + .propertycount = cpu_to_be32(count), + }; + + u32 resp_size = rsize; + int ret = tpmhw_transmit(0, &trg.hdr, rsp, &resp_size, + TPM_DURATION_TYPE_SHORT); + ret = (ret || + rsize < be32_to_cpu(rsp->totlen)) ? -1 : be32_to_cpu(rsp->errcode); + + dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetCapability = 0x%08x\n", + ret); + + return ret; +} + +static int +tpm20_get_pcrbanks(void) +{ + u8 buffer[128]; + struct tpm2_res_getcapability *trg = + (struct tpm2_res_getcapability *)&buffer; + + int ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr, + sizeof(buffer)); + if (ret) + return ret; + + tpm20_pcr_selection_size = be32_to_cpu(trg->hdr.totlen) - + offsetof(struct tpm2_res_getcapability, data); + tpm20_pcr_selection = malloc_high(tpm20_pcr_selection_size); + memcpy(tpm20_pcr_selection, &trg->data, tpm20_pcr_selection_size); + + return 0; +} + +static int tpm20_startup(void) { tpm20_set_timeouts(); @@ -701,6 +750,10 @@ tpm20_startup(void) if (ret) goto err_exit;
+ ret = tpm20_get_pcrbanks(); + if (ret) + goto err_exit; + return 0;
err_exit:
On Tue, Jul 19, 2016 at 01:41:54PM -0400, Stefan Berger wrote:
Implement tpm20_get_capability and retrieve the PCR Bank configuration from the TPM using this function.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
src/std/tcg.h | 29 +++++++++++++++++++++++++++++ src/tcgbios.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
diff --git a/src/std/tcg.h b/src/std/tcg.h index c59f671..d60ee09 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -394,12 +394,16 @@ struct tpm_res_sha1complete { #define TPM2_CC_SelfTest 0x143 #define TPM2_CC_Startup 0x144 #define TPM2_CC_StirRandom 0x146 +#define TPM2_CC_GetCapability 0x17a #define TPM2_CC_GetRandom 0x17b #define TPM2_CC_PCR_Extend 0x182
/* TPM 2 error codes */ #define TPM2_RC_INITIALIZE 0x100
+/* TPM 2 Capabilities */ +#define TPM2_CAP_PCRS 0x00000005
/* TPM 2 data structures */
struct tpm2b_stir { @@ -475,6 +479,31 @@ struct tpm2_req_hierarchycontrol { u8 state; } PACKED;
+struct tpm2_req_getcapability {
- struct tpm_req_header hdr;
- u32 capability;
- u32 property;
- u32 propertycount;
+} PACKED;
+struct tpm2_res_getcapability {
- struct tpm_rsp_header hdr;
- u8 moreData;
- u32 capability;
- u8 data[0]; /* capability dependent data */
+} PACKED;
+struct tpms_pcr_selection {
- u16 hashAlg;
- u8 sizeOfSelect;
- u8 pcrSelect[0];
+} PACKED;
+struct tpml_pcr_selection {
- u32 count;
- struct tpms_pcr_selection selections[0];
+} PACKED;
/* TPM 2 log entry */
struct tpml_digest_values_sha1 { diff --git a/src/tcgbios.c b/src/tcgbios.c index 334d99b..a79b880 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -24,6 +24,7 @@ #include "tcgbios.h"// tpm_*, prototypes #include "util.h" // printf, get_keystroke #include "stacks.h" // wait_threads, reset +#include "malloc.h" // malloc_high
/****************************************************************
- TPM 1.2 commands
@@ -76,6 +77,9 @@ static int TPM_has_physical_presence;
static TPMVersion TPM_version;
+static u32 tpm20_pcr_selection_size; +static struct tpml_pcr_selection *tpm20_pcr_selection;
static struct tcpa_descriptor_rev2 * find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp) { @@ -669,6 +673,51 @@ err_exit: }
static int +tpm20_getcapability(u32 capability, u32 property, u32 count,
struct tpm_rsp_header *rsp, u32 rsize)
+{
- struct tpm2_req_getcapability trg = {
.hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
.hdr.totlen = cpu_to_be32(sizeof(trg)),
.hdr.ordinal = cpu_to_be32(TPM2_CC_GetCapability),
.capability = cpu_to_be32(capability),
.property = cpu_to_be32(property),
.propertycount = cpu_to_be32(count),
- };
- u32 resp_size = rsize;
- int ret = tpmhw_transmit(0, &trg.hdr, rsp, &resp_size,
TPM_DURATION_TYPE_SHORT);
- ret = (ret ||
rsize < be32_to_cpu(rsp->totlen)) ? -1 : be32_to_cpu(rsp->errcode);
- dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetCapability = 0x%08x\n",
ret);
- return ret;
+}
+static int +tpm20_get_pcrbanks(void) +{
- u8 buffer[128];
- struct tpm2_res_getcapability *trg =
(struct tpm2_res_getcapability *)&buffer;
- int ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr,
sizeof(buffer));
- if (ret)
return ret;
- tpm20_pcr_selection_size = be32_to_cpu(trg->hdr.totlen) -
offsetof(struct tpm2_res_getcapability, data);
- tpm20_pcr_selection = malloc_high(tpm20_pcr_selection_size);
- memcpy(tpm20_pcr_selection, &trg->data, tpm20_pcr_selection_size);
It's necessary to check the result of malloc_high() for NULL. (Otherwise, the memcpy could overwrite the memory at address zero, which is the real-mode IDT.)
-Kevin
Restructure the tpm20_extend function to use a buffer for the command to send to the TPM. The size of the buffer is calculated from the size of tpm2_req_extend structure and the appended SHA1 hash.
Add the hash algorithm that's being used as a parameter to this function.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 2 +- src/tcgbios.c | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index d60ee09..1644684 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -442,7 +442,6 @@ struct tpm2_req_hierarchychangeauth { } PACKED;
struct tpm2_digest_value { - u32 count; /* 1 entry only */ u16 hashalg; /* TPM2_ALG_SHA1 */ u8 sha1[SHA1_BUFSIZE]; } PACKED; @@ -452,6 +451,7 @@ struct tpm2_req_extend { u32 pcrindex; u32 authblocksize; struct tpm2_authblock authblock; + u32 count; struct tpm2_digest_value digest; } PACKED;
diff --git a/src/tcgbios.c b/src/tcgbios.c index a79b880..72ae3c6 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -446,31 +446,34 @@ tpm12_extend(u32 pcrindex, const u8 *digest) return 0; }
-static int tpm20_extend(u32 pcrindex, const u8 *digest) +static int tpm20_extend(u32 pcrindex, const u8 *digest, u16 hashAlg) { - struct tpm2_req_extend tre = { + struct tpm2_req_extend tmp_tre = { .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), - .hdr.totlen = cpu_to_be32(sizeof(tre)), + .hdr.totlen = cpu_to_be32(sizeof(tmp_tre)), .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend), .pcrindex = cpu_to_be32(pcrindex), - .authblocksize = cpu_to_be32(sizeof(tre.authblock)), + .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)), .authblock = { .handle = cpu_to_be32(TPM2_RS_PW), .noncesize = cpu_to_be16(0), .contsession = TPM2_YES, .pwdsize = cpu_to_be16(0), }, - .digest = { - .count = cpu_to_be32(1), - .hashalg = cpu_to_be16(TPM2_ALG_SHA1), - }, }; - memcpy(tre.digest.sha1, digest, sizeof(tre.digest.sha1)); + u32 count = 1; + u8 buffer[sizeof(tmp_tre) + sizeof(struct tpm2_digest_value)]; + struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer; + + memcpy(tre, &tmp_tre, sizeof(tmp_tre)); + tre->count = cpu_to_be32(count); + tre->digest.hashalg = cpu_to_be16(hashAlg); + memcpy(tre->digest.sha1, digest, sizeof(tmp_tre.digest.sha1));
struct tpm_rsp_header rsp; u32 resp_length = sizeof(rsp); - int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length, - TPM_DURATION_TYPE_SHORT); + int ret = tpmhw_transmit(0, &tre->hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); if (ret || resp_length != sizeof(rsp) || rsp.errcode) return -1;
@@ -478,13 +481,13 @@ static int tpm20_extend(u32 pcrindex, const u8 *digest) }
static int -tpm_extend(u32 pcrindex, const u8 *digest) +tpm_extend(u32 pcrindex, const u8 *digest, u16 hashAlg) { switch (TPM_version) { case TPM_VERSION_1_2: return tpm12_extend(pcrindex, digest); case TPM_VERSION_2: - return tpm20_extend(pcrindex, digest); + return tpm20_extend(pcrindex, digest, hashAlg); } return -1; } @@ -517,7 +520,7 @@ tpm_add_measurement_to_log(u32 pcrindex, u32 event_type, .digests[0].hashtype = TPM2_ALG_SHA1, }; sha1(hashdata, hashdata_length, entry.digests[0].sha1); - int ret = tpm_extend(entry.pcrindex, entry.digests[0].sha1); + int ret = tpm_extend(entry.pcrindex, entry.digests[0].sha1, TPM2_ALG_SHA1); if (ret) { tpm_set_failure(); return; @@ -1093,7 +1096,7 @@ hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length if (hashdata) sha1(hashdata, hashdata_length, pcpes->digest); if (extend) { - int ret = tpm_extend(pcpes->pcrindex, pcpes->digest); + int ret = tpm_extend(pcpes->pcrindex, pcpes->digest, TPM2_ALG_SHA1); if (ret) return TCG_TCG_COMMAND_ERROR; }
Extend the tpm20_extend function to support extending a hash to multiple PCR banks. The sha1 hash that's being extended into the sha256 bank for example, will be filled with zero-bytes to the size of a sha256 hash.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 14 +++++++-- src/tcgbios.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 105 insertions(+), 8 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index 1644684..9e4ef57 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -100,6 +100,10 @@ enum irq_ids { #define EV_IPL_PARTITION_DATA 14
#define SHA1_BUFSIZE 20 +#define SHA256_BUFSIZE 32 +#define SHA384_BUFSIZE 48 +#define SHA512_BUFSIZE 64 +#define SM3_256_BUFSIZE 32
/* Input and Output blocks for the TCG BIOS commands */
@@ -381,6 +385,10 @@ struct tpm_res_sha1complete { #define TPM2_RH_PLATFORM 0x4000000c
#define TPM2_ALG_SHA1 0x0004 +#define TPM2_ALG_SHA256 0x000b +#define TPM2_ALG_SHA384 0x000c +#define TPM2_ALG_SHA512 0x000d +#define TPM2_ALG_SM3_256 0x0012
/* TPM 2 command tags */ #define TPM2_ST_NO_SESSIONS 0x8001 @@ -442,8 +450,8 @@ struct tpm2_req_hierarchychangeauth { } PACKED;
struct tpm2_digest_value { - u16 hashalg; /* TPM2_ALG_SHA1 */ - u8 sha1[SHA1_BUFSIZE]; + u16 hashAlg; /* TPM2_ALG_SHA1 */ + u8 hash[0]; /* size depends on hashAlg */ } PACKED;
struct tpm2_req_extend { @@ -452,7 +460,7 @@ struct tpm2_req_extend { u32 authblocksize; struct tpm2_authblock authblock; u32 count; - struct tpm2_digest_value digest; + struct tpm2_digest_value digest[0]; } PACKED;
struct tpm2_req_clearcontrol { diff --git a/src/tcgbios.c b/src/tcgbios.c index 72ae3c6..acd0b71 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -446,11 +446,94 @@ tpm12_extend(u32 pcrindex, const u8 *digest) return 0; }
+static int +tpm20_get_hash_buffersize(u16 hashAlg) +{ + switch (hashAlg) { + case TPM2_ALG_SHA1: + return SHA1_BUFSIZE; + case TPM2_ALG_SHA256: + return SHA256_BUFSIZE; + case TPM2_ALG_SHA384: + return SHA384_BUFSIZE; + case TPM2_ALG_SHA512: + return SHA512_BUFSIZE; + case TPM2_ALG_SM3_256: + return SM3_256_BUFSIZE; + default: + return -1; + } +} + +/* + * Write the TPM2 PCR Extend 'body' containing the hashes. Follow + * the PCR bank configuration of the TPM. + * + * dest: destinatiobn buffer to write into; if NULL, nothing is written + * pcrindex: the PCR index + * hash: the hash value to write + * hashAlg: the hash alogorithm determining the size of the hash + * count: pointer to a counter for how many entries were writte + * + * Returns the number of bytes written into the buffer; -1 on fatal error + */ +static int +tpm20_write_extend_body(char *dest, u32 pcrindex, const u8 *hash, + u16 hashAlg, u32 *count) +{ + int offset = 0, hsize; + struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections; + void *nsel, *end = (void *)tpm20_pcr_selection + tpm20_pcr_selection_size; + int hash_size = tpm20_get_hash_buffersize(hashAlg); + + for (*count = 0; + *count < be32_to_cpu(tpm20_pcr_selection->count); + (*count)++) { + u8 sizeOfSelect = sel->sizeOfSelect; + + nsel = (void *)sel + + offsetof(struct tpms_pcr_selection, pcrSelect) + + sizeOfSelect; + if (nsel > end) + break; + + u8 idx = pcrindex >> 3; + u8 mask = (1 << (pcrindex & 7)); + /* skip if PCR not used in this bank */ + if (idx > sizeOfSelect || !(sel->pcrSelect[idx] & mask)) + continue; + + hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg)); + if (hsize < 0) { + dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n", + be16_to_cpu(sel->hashAlg)); + return -1; + } + + if (dest) { + struct tpm2_digest_value *v = + (struct tpm2_digest_value *)&dest[offset]; + v->hashAlg = sel->hashAlg; + memset(v->hash, 0, hsize); + memcpy(v->hash, hash, hash_size); + } + offset += sizeof(sel->hashAlg) + hsize; + sel = nsel; + } + + if (sel != end) { + dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n"); + return -1; + } + + return offset; +} + static int tpm20_extend(u32 pcrindex, const u8 *digest, u16 hashAlg) { struct tpm2_req_extend tmp_tre = { .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), - .hdr.totlen = cpu_to_be32(sizeof(tmp_tre)), + .hdr.totlen = cpu_to_be32(0), .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend), .pcrindex = cpu_to_be32(pcrindex), .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)), @@ -461,14 +544,20 @@ static int tpm20_extend(u32 pcrindex, const u8 *digest, u16 hashAlg) .pwdsize = cpu_to_be16(0), }, }; - u32 count = 1; - u8 buffer[sizeof(tmp_tre) + sizeof(struct tpm2_digest_value)]; + u32 count = 0; + int bsize = tpm20_write_extend_body(NULL, pcrindex, digest, hashAlg, + &count); + if (bsize < 0) + return bsize; + + u8 buffer[sizeof(tmp_tre) + bsize]; struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer;
memcpy(tre, &tmp_tre, sizeof(tmp_tre)); + tre->hdr.totlen = cpu_to_be32(sizeof(buffer)); + tpm20_write_extend_body((char *)&tre->digest, pcrindex, digest, hashAlg, + &count); tre->count = cpu_to_be32(count); - tre->digest.hashalg = cpu_to_be16(hashAlg); - memcpy(tre->digest.sha1, digest, sizeof(tmp_tre.digest.sha1));
struct tpm_rsp_header rsp; u32 resp_length = sizeof(rsp);
On Tue, Jul 19, 2016 at 01:41:56PM -0400, Stefan Berger wrote:
Extend the tpm20_extend function to support extending a hash to multiple PCR banks. The sha1 hash that's being extended into the sha256 bank for example, will be filled with zero-bytes to the size of a sha256 hash.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
src/std/tcg.h | 14 +++++++-- src/tcgbios.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 105 insertions(+), 8 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index 1644684..9e4ef57 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -100,6 +100,10 @@ enum irq_ids { #define EV_IPL_PARTITION_DATA 14
#define SHA1_BUFSIZE 20 +#define SHA256_BUFSIZE 32 +#define SHA384_BUFSIZE 48 +#define SHA512_BUFSIZE 64 +#define SM3_256_BUFSIZE 32
/* Input and Output blocks for the TCG BIOS commands */
@@ -381,6 +385,10 @@ struct tpm_res_sha1complete { #define TPM2_RH_PLATFORM 0x4000000c
#define TPM2_ALG_SHA1 0x0004 +#define TPM2_ALG_SHA256 0x000b +#define TPM2_ALG_SHA384 0x000c +#define TPM2_ALG_SHA512 0x000d +#define TPM2_ALG_SM3_256 0x0012
/* TPM 2 command tags */ #define TPM2_ST_NO_SESSIONS 0x8001 @@ -442,8 +450,8 @@ struct tpm2_req_hierarchychangeauth { } PACKED;
struct tpm2_digest_value {
- u16 hashalg; /* TPM2_ALG_SHA1 */
- u8 sha1[SHA1_BUFSIZE];
- u16 hashAlg; /* TPM2_ALG_SHA1 */
- u8 hash[0]; /* size depends on hashAlg */
} PACKED;
struct tpm2_req_extend { @@ -452,7 +460,7 @@ struct tpm2_req_extend { u32 authblocksize; struct tpm2_authblock authblock; u32 count;
- struct tpm2_digest_value digest;
- struct tpm2_digest_value digest[0];
} PACKED;
struct tpm2_req_clearcontrol { diff --git a/src/tcgbios.c b/src/tcgbios.c index 72ae3c6..acd0b71 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -446,11 +446,94 @@ tpm12_extend(u32 pcrindex, const u8 *digest) return 0; }
+static int +tpm20_get_hash_buffersize(u16 hashAlg) +{
- switch (hashAlg) {
- case TPM2_ALG_SHA1:
return SHA1_BUFSIZE;
- case TPM2_ALG_SHA256:
return SHA256_BUFSIZE;
- case TPM2_ALG_SHA384:
return SHA384_BUFSIZE;
- case TPM2_ALG_SHA512:
return SHA512_BUFSIZE;
- case TPM2_ALG_SM3_256:
return SM3_256_BUFSIZE;
- default:
return -1;
- }
+}
+/*
- Write the TPM2 PCR Extend 'body' containing the hashes. Follow
- the PCR bank configuration of the TPM.
- dest: destinatiobn buffer to write into; if NULL, nothing is written
Spelling typo.
- pcrindex: the PCR index
- hash: the hash value to write
- hashAlg: the hash alogorithm determining the size of the hash
- count: pointer to a counter for how many entries were writte
- Returns the number of bytes written into the buffer; -1 on fatal error
- */
+static int +tpm20_write_extend_body(char *dest, u32 pcrindex, const u8 *hash,
u16 hashAlg, u32 *count)
+{
- int offset = 0, hsize;
- struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
- void *nsel, *end = (void *)tpm20_pcr_selection + tpm20_pcr_selection_size;
- int hash_size = tpm20_get_hash_buffersize(hashAlg);
- for (*count = 0;
*count < be32_to_cpu(tpm20_pcr_selection->count);
(*count)++) {
u8 sizeOfSelect = sel->sizeOfSelect;
nsel = (void *)sel +
offsetof(struct tpms_pcr_selection, pcrSelect) +
sizeOfSelect;
if (nsel > end)
break;
u8 idx = pcrindex >> 3;
u8 mask = (1 << (pcrindex & 7));
/* skip if PCR not used in this bank */
if (idx > sizeOfSelect || !(sel->pcrSelect[idx] & mask))
continue;
hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
if (hsize < 0) {
dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
be16_to_cpu(sel->hashAlg));
return -1;
}
if (dest) {
struct tpm2_digest_value *v =
(struct tpm2_digest_value *)&dest[offset];
v->hashAlg = sel->hashAlg;
memset(v->hash, 0, hsize);
memcpy(v->hash, hash, hash_size);
}
offset += sizeof(sel->hashAlg) + hsize;
sel = nsel;
- }
- if (sel != end) {
dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
return -1;
- }
- return offset;
+}
static int tpm20_extend(u32 pcrindex, const u8 *digest, u16 hashAlg) { struct tpm2_req_extend tmp_tre = { .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
.hdr.totlen = cpu_to_be32(sizeof(tmp_tre)),
.hdr.totlen = cpu_to_be32(0), .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend), .pcrindex = cpu_to_be32(pcrindex), .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)),
@@ -461,14 +544,20 @@ static int tpm20_extend(u32 pcrindex, const u8 *digest, u16 hashAlg) .pwdsize = cpu_to_be16(0), }, };
- u32 count = 1;
- u8 buffer[sizeof(tmp_tre) + sizeof(struct tpm2_digest_value)];
- u32 count = 0;
- int bsize = tpm20_write_extend_body(NULL, pcrindex, digest, hashAlg,
&count);
- if (bsize < 0)
return bsize;
- u8 buffer[sizeof(tmp_tre) + bsize];
Is it possible to allocate buffer to be some suitably large size (like 512 bytes) instead of trying to calculate an exact size? SeaBIOS uses static stack sizes (typically 2K) and it's harder to analyze stack usage when buffers are dynamically sized.
struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer; memcpy(tre, &tmp_tre, sizeof(tmp_tre));
- tre->hdr.totlen = cpu_to_be32(sizeof(buffer));
- tpm20_write_extend_body((char *)&tre->digest, pcrindex, digest, hashAlg,
tre->count = cpu_to_be32(count);&count);
Isn't count always equal to tpm20_pcr_selection->count? If so, why pass it to/from tpm20_write_extend_body()?
Series looks good to me.
Thanks, -Kevin
On 07/19/2016 03:12 PM, Kevin O'Connor wrote:
On Tue, Jul 19, 2016 at 01:41:56PM -0400, Stefan Berger wrote:
Extend the tpm20_extend function to support extending a hash to multiple PCR banks. The sha1 hash that's being extended into the sha256 bank for example, will be filled with zero-bytes to the size of a sha256 hash.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
src/std/tcg.h | 14 +++++++-- src/tcgbios.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 105 insertions(+), 8 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index 1644684..9e4ef57 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -100,6 +100,10 @@ enum irq_ids { #define EV_IPL_PARTITION_DATA 14
#define SHA1_BUFSIZE 20 +#define SHA256_BUFSIZE 32 +#define SHA384_BUFSIZE 48 +#define SHA512_BUFSIZE 64 +#define SM3_256_BUFSIZE 32
/* Input and Output blocks for the TCG BIOS commands */
@@ -381,6 +385,10 @@ struct tpm_res_sha1complete { #define TPM2_RH_PLATFORM 0x4000000c
#define TPM2_ALG_SHA1 0x0004 +#define TPM2_ALG_SHA256 0x000b +#define TPM2_ALG_SHA384 0x000c +#define TPM2_ALG_SHA512 0x000d +#define TPM2_ALG_SM3_256 0x0012
/* TPM 2 command tags */ #define TPM2_ST_NO_SESSIONS 0x8001 @@ -442,8 +450,8 @@ struct tpm2_req_hierarchychangeauth { } PACKED;
struct tpm2_digest_value {
- u16 hashalg; /* TPM2_ALG_SHA1 */
- u8 sha1[SHA1_BUFSIZE];
u16 hashAlg; /* TPM2_ALG_SHA1 */
u8 hash[0]; /* size depends on hashAlg */ } PACKED;
struct tpm2_req_extend {
@@ -452,7 +460,7 @@ struct tpm2_req_extend { u32 authblocksize; struct tpm2_authblock authblock; u32 count;
- struct tpm2_digest_value digest;
struct tpm2_digest_value digest[0]; } PACKED;
struct tpm2_req_clearcontrol {
diff --git a/src/tcgbios.c b/src/tcgbios.c index 72ae3c6..acd0b71 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -446,11 +446,94 @@ tpm12_extend(u32 pcrindex, const u8 *digest) return 0; }
+static int +tpm20_get_hash_buffersize(u16 hashAlg) +{
- switch (hashAlg) {
- case TPM2_ALG_SHA1:
return SHA1_BUFSIZE;
- case TPM2_ALG_SHA256:
return SHA256_BUFSIZE;
- case TPM2_ALG_SHA384:
return SHA384_BUFSIZE;
- case TPM2_ALG_SHA512:
return SHA512_BUFSIZE;
- case TPM2_ALG_SM3_256:
return SM3_256_BUFSIZE;
- default:
return -1;
- }
+}
+/*
- Write the TPM2 PCR Extend 'body' containing the hashes. Follow
- the PCR bank configuration of the TPM.
- dest: destinatiobn buffer to write into; if NULL, nothing is written
Spelling typo.
- pcrindex: the PCR index
- hash: the hash value to write
- hashAlg: the hash alogorithm determining the size of the hash
- count: pointer to a counter for how many entries were writte
- Returns the number of bytes written into the buffer; -1 on fatal error
- */
+static int +tpm20_write_extend_body(char *dest, u32 pcrindex, const u8 *hash,
u16 hashAlg, u32 *count)
+{
- int offset = 0, hsize;
- struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
- void *nsel, *end = (void *)tpm20_pcr_selection + tpm20_pcr_selection_size;
- int hash_size = tpm20_get_hash_buffersize(hashAlg);
- for (*count = 0;
*count < be32_to_cpu(tpm20_pcr_selection->count);
(*count)++) {
u8 sizeOfSelect = sel->sizeOfSelect;
nsel = (void *)sel +
offsetof(struct tpms_pcr_selection, pcrSelect) +
sizeOfSelect;
if (nsel > end)
break;
u8 idx = pcrindex >> 3;
u8 mask = (1 << (pcrindex & 7));
/* skip if PCR not used in this bank */
if (idx > sizeOfSelect || !(sel->pcrSelect[idx] & mask))
continue;
hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
if (hsize < 0) {
dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
be16_to_cpu(sel->hashAlg));
return -1;
}
if (dest) {
struct tpm2_digest_value *v =
(struct tpm2_digest_value *)&dest[offset];
v->hashAlg = sel->hashAlg;
memset(v->hash, 0, hsize);
memcpy(v->hash, hash, hash_size);
}
offset += sizeof(sel->hashAlg) + hsize;
sel = nsel;
- }
- if (sel != end) {
dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
return -1;
- }
- return offset;
+}
- static int tpm20_extend(u32 pcrindex, const u8 *digest, u16 hashAlg) { struct tpm2_req_extend tmp_tre = { .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
.hdr.totlen = cpu_to_be32(sizeof(tmp_tre)),
.hdr.totlen = cpu_to_be32(0), .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend), .pcrindex = cpu_to_be32(pcrindex), .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)),
@@ -461,14 +544,20 @@ static int tpm20_extend(u32 pcrindex, const u8 *digest, u16 hashAlg) .pwdsize = cpu_to_be16(0), }, };
- u32 count = 1;
- u8 buffer[sizeof(tmp_tre) + sizeof(struct tpm2_digest_value)];
- u32 count = 0;
- int bsize = tpm20_write_extend_body(NULL, pcrindex, digest, hashAlg,
&count);
- if (bsize < 0)
return bsize;
- u8 buffer[sizeof(tmp_tre) + bsize];
Is it possible to allocate buffer to be some suitably large size (like 512 bytes) instead of trying to calculate an exact size? SeaBIOS uses static stack sizes (typically 2K) and it's harder to analyze stack usage when buffers are dynamically sized.
256 bytes should be plenty for this purpose. With the hashes we currently support we would need a maximum of 206bytes:
[2+ 20 + 2 + 32 + 2 + 48 + 2 + 64 + 2 + 32 = 206 bytes]
struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer; memcpy(tre, &tmp_tre, sizeof(tmp_tre));
- tre->hdr.totlen = cpu_to_be32(sizeof(buffer));
- tpm20_write_extend_body((char *)&tre->digest, pcrindex, digest, hashAlg,
&count); tre->count = cpu_to_be32(count);
Isn't count always equal to tpm20_pcr_selection->count? If so, why pass it to/from tpm20_write_extend_body()?
So I don't need to know outside the tpm20_write_extend_body function how many entries it actually writes.
Series looks good to me.
Thanks.
I may rename the function and add a 4th patch that uses it to write the multiple hashes also into the log. To check that we don't write beyond the end of the log, I may want to call this function once to check how many bytes it writes.
Stefan
Thanks, -Kevin