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);