[SeaBIOS] [PATCH 2/2] tpm: Write logs in TPM 2 format

Stefan Berger stefanb at linux.vnet.ibm.com
Mon Feb 8 13:25:35 CET 2016


On 02/06/2016 01:35 PM, Kevin O'Connor wrote:
> Add support for the TPM 2 format of log messages.
>
> Write the logs in the format that is appropriate for the version of
> the host's TPM. For TPM 1.2 write it in the 'pcpes' structure's
> format, for TPM 2 in the new TPM 2 format.
>
> By using this method we can keep the API interface on systems with a
> TPM 2 even though applications pass in the 'pcpes' structures
> directly. The log will still be written in the appropriate format.
>
> The TPM 2 log contains a TPM 1.2 type of entry of event type
> EV_NO_ACTION and entry of type TCG_EfiSpeIdEventStruct as the first
> entry. This is described in the EFI specification (section 5.3):
>
> Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
> ---
>   src/std/tcg.h | 35 +++++++++++++++++++++++++++
>   src/tcgbios.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
>   2 files changed, 101 insertions(+), 10 deletions(-)
>
> diff --git a/src/std/tcg.h b/src/std/tcg.h
> index dbb3a60..c59f671 100644
> --- a/src/std/tcg.h
> +++ b/src/std/tcg.h
> @@ -91,6 +91,7 @@ enum irq_ids {
>
>   /* event types: 10.4.1 / table 11 */
>   #define EV_POST_CODE             1
> +#define EV_NO_ACTION             3
>   #define EV_SEPARATOR             4
>   #define EV_ACTION                5
>   #define EV_EVENT_TAG             6
> @@ -474,4 +475,38 @@ struct tpm2_req_hierarchycontrol {
>       u8 state;
>   } PACKED;
>
> +/* TPM 2 log entry */
> +
> +struct tpml_digest_values_sha1 {
> +    u16 hashtype;
> +    u8 sha1[SHA1_BUFSIZE];
> +};
> +
> +struct tcg_pcr_event2_sha1 {
> +    u32 pcrindex;
> +    u32 eventtype;
> +    u32 count; /* number of digests */
> +    struct tpml_digest_values_sha1 digests[1];
> +    u32 eventdatasize;
> +    u8 event[0];
> +} PACKED;
> +
> +struct TCG_EfiSpecIdEventStruct {
> +    u8 signature[16];
> +    u32 platformClass;
> +    u8 specVersionMinor;
> +    u8 specVersionMajor;
> +    u8 specErrata;
> +    u8 uintnSize;
> +    u32 numberOfAlgorithms;
> +    struct TCG_EfiSpecIdEventAlgorithmSize {
> +        u16 algorithmId;
> +        u16 digestSize;
> +    } digestSizes[1];
> +    u8 vendorInfoSize;
> +    u8 vendorInfo[0];
> +};
> +
> +#define TPM_TCPA_ACPI_CLASS_CLIENT 0
> +
>   #endif // tcg.h
> diff --git a/src/tcgbios.c b/src/tcgbios.c
> index cddc99b..f0ab188 100644
> --- a/src/tcgbios.c
> +++ b/src/tcgbios.c
> @@ -141,7 +141,7 @@ tpm_tcpa_probe(void)
>    *  Returns an error code in case of faiure, 0 in case of success
>    */
>   static int
> -tpm_log_event(struct pcpes *pcpes, const void *event)
> +tpm_log_event(struct tcg_pcr_event2_sha1 *entry, const void *event)
>   {
>       dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
>               tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
> @@ -149,7 +149,7 @@ tpm_log_event(struct pcpes *pcpes, const void *event)
>       if (tpm_state.log_area_next_entry == NULL)
>           return -1;
>
> -    u32 size = sizeof(*pcpes) + pcpes->eventdatasize;
> +    u32 size = sizeof(*entry) + entry->eventdatasize;

This is only the correct size for TPM 2. I think there should be a case 
statement here.

>
>       if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) >
>            tpm_state.log_area_minimum_length) {
> @@ -157,9 +157,19 @@ tpm_log_event(struct pcpes *pcpes, const void *event)
>           return -1;
>       }
>
> -    memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes));
> -    memcpy(tpm_state.log_area_next_entry + sizeof(*pcpes),
> -           event, pcpes->eventdatasize);
> +    if (TPM_version == TPM_VERSION_1_2 || entry->eventtype == EV_NO_ACTION) {

This only works if TPM 2 entries don't have a EV_NO_ACTION (= 3). I 
think the cleaner solution would be to differentiate by version only.

The main difference here between parts of my code and yours is that you 
are inlining it.


> +        struct pcpes *pcpes = (void*)tpm_state.log_area_next_entry;
> +        pcpes->pcrindex = entry->pcrindex;
> +        pcpes->eventtype = entry->eventtype;
> +        memcpy(pcpes->digest, entry->digests[0].sha1, sizeof(pcpes->digest));
> +        pcpes->eventdatasize = entry->eventdatasize;
> +        memcpy(pcpes->event, event, entry->eventdatasize);
> +        size = sizeof(*pcpes) + entry->eventdatasize;
> +    } else {
> +        struct tcg_pcr_event2_sha1 *e = (void*)tpm_state.log_area_next_entry;
> +        memcpy(e, entry, sizeof(*e));
> +        memcpy(e->event, event, entry->eventdatasize);
> +    }
>
>       tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
>       tpm_state.log_area_next_entry += size;
> @@ -168,6 +178,40 @@ tpm_log_event(struct pcpes *pcpes, const void *event)
>       return 0;
>   }
>
> +/*
> + * Initialize the log; a TPM2 log needs a special TPM 1.2 log entry
> + * as the first entry serving identification purposes
> + */
> +void tpm_log_init(void)
> +{
> +    struct TCG_EfiSpecIdEventStruct event = {
> +        .signature = "Spec ID Event03",
> +        .platformClass = TPM_TCPA_ACPI_CLASS_CLIENT,
> +        .specVersionMinor = 0,
> +        .specVersionMajor = 2,
> +        .specErrata = 0,
> +        .uintnSize = 2,
> +        .numberOfAlgorithms = 1,
> +        .digestSizes[0] = {
> +             .algorithmId = TPM2_ALG_SHA1,
> +             .digestSize = SHA1_BUFSIZE,
> +        },
> +        .vendorInfoSize = 0,
> +    };
> +    struct tcg_pcr_event2_sha1 entry = {
> +        .eventtype = EV_NO_ACTION,
> +        .eventdatasize = sizeof(event),
> +    };
> +
> +    switch (TPM_version) {
> +    case TPM_VERSION_1_2:
> +        break;
> +    case TPM_VERSION_2:
> +        /* write a 1.2 type of entry */
> +        tpm_log_event(&entry, &event);
> +    }
> +}
> +
>
>   /****************************************************************
>    * Helper functions
> @@ -457,18 +501,20 @@ tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
>       if (!tpm_is_working())
>           return;
>
> -    struct pcpes pcpes = {
> +    struct tcg_pcr_event2_sha1 entry = {
>           .pcrindex = pcrindex,
>           .eventtype = event_type,
>           .eventdatasize = event_length,
> +        .count = 1,
> +        .digests[0].hashtype  = TPM2_ALG_SHA1,
>       };
> -    sha1(hashdata, hashdata_length, pcpes.digest);
> -    int ret = tpm_extend(pcpes.pcrindex, pcpes.digest);
> +    sha1(hashdata, hashdata_length, entry.digests[0].sha1);
> +    int ret = tpm_extend(entry.pcrindex, entry.digests[0].sha1);
>       if (ret) {
>           tpm_set_failure();
>           return;
>       }
> -    tpm_log_event(&pcpes, event);
> +    tpm_log_event(&entry, event);
>   }
>
>
> @@ -690,6 +736,8 @@ tpm_setup(void)
>       if (ret)
>           return;
>
> +    tpm_log_init();
> +
>       TPM_working = 1;
>
>       if (runningOnXen())
> @@ -992,7 +1040,15 @@ hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length
>           if (ret)
>               return TCG_TCG_COMMAND_ERROR;
>       }
> -    int ret = tpm_log_event(pcpes, pcpes->event);
> +    struct tcg_pcr_event2_sha1 entry = {
> +        .pcrindex = pcpes->pcrindex,
> +        .eventtype = pcpes->eventtype,
> +        .eventdatasize = pcpes->eventdatasize,
> +        .count = 1,
> +        .digests[0].hashtype = TPM2_ALG_SHA1,
> +    };
> +    memcpy(entry.digests[0].sha1, pcpes->digest, sizeof(entry.digests[0].sha1));
> +    int ret = tpm_log_event(&entry, pcpes->event);
>       if (ret)
>           return TCG_PC_LOGOVERFLOW;
>       return 0;

The rest looks good.

    Stefan




More information about the SeaBIOS mailing list