[SeaBIOS] [PATCH 3/3] tpm: Extend tpm20_extend to support extending to multiple PCR banks
Stefan Berger
stefanb at linux.vnet.ibm.com
Thu Jul 21 04:01:11 CEST 2016
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 at 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
>
More information about the SeaBIOS
mailing list