From: Stefan Berger stefanb@linux.vnet.ibm.com
Introduce a log_entry 'object' that we use to hold the data to be logged in one log entry. Pass this object around rather than the TPM 1.2 specific 'pcpes' structure.
Write this log_entry 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):
TCG EFI Protocol Specification for TPM Family 2.0
http://www.trustedcomputinggroup.org/resources/tcg_efi_protocol_specificatio...
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 35 ++++++++++++ src/tcgbios.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 182 insertions(+), 27 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index 8466b14..1e8b250 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -89,6 +89,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 @@ -472,4 +473,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 eventsize; + 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 da457a4..9456a45 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -130,6 +130,58 @@ tpm_tcpa_probe(void) return 0; }
+/**************************************************************** + * Log entry 'object' + ****************************************************************/ + +struct log_entry { + /* embedded TPM 2 type of log entry header */ + struct tcg_pcr_event2_sha1 entry; + const void *event; /* TPM 1.2 & 2 */ +}; + +static u32 +log_entry_write_size(struct log_entry *le, TPMVersion tpm_version) +{ + switch (tpm_version) { + case TPM_VERSION_1_2: + return sizeof(struct pcpes) + le->entry.eventsize; + case TPM_VERSION_2: + return sizeof(le->entry) + le->entry.eventsize; + } + return 0; +} + +static void +log_entry_write(struct log_entry *le, void *dest, TPMVersion tpm_version) +{ + struct pcpes *pcpes; + + switch (tpm_version) { + case TPM_VERSION_1_2: + pcpes = dest; + pcpes->pcrindex = le->entry.pcrindex; + pcpes->eventtype = le->entry.eventtype; + memcpy(pcpes->digest, le->entry.digests[0].sha1, + sizeof(pcpes->digest)); + pcpes->eventdatasize = le->entry.eventsize; + + dest += sizeof(*pcpes); + + break; + case TPM_VERSION_2: + /* fill in missing parts in TPM 2 log entry */ + le->entry.count = 1; + le->entry.digests[0].hashtype = TPM2_ALG_SHA1; + memcpy(dest, &le->entry, sizeof(le->entry)); + + dest += sizeof(le->entry); + + break; + } + memcpy(dest, le->event, le->entry.eventsize); +} + /* * Extend the ACPI log with the given entry by copying the * entry data into the log. @@ -141,7 +193,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 log_entry *le, TPMVersion tpm_version) { dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n", tpm_state.log_area_start_address, tpm_state.log_area_next_entry); @@ -149,7 +201,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 = log_entry_write_size(le, tpm_version);
if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) > tpm_state.log_area_minimum_length) { @@ -157,9 +209,7 @@ 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); + log_entry_write(le, tpm_state.log_area_next_entry, tpm_version);
tpm_state.log_area_last_entry = tpm_state.log_area_next_entry; tpm_state.log_area_next_entry += size; @@ -168,6 +218,42 @@ 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 log_entry le = { + .entry = { + .eventtype = EV_NO_ACTION, + }, + .event = &event, + }; + + switch (TPM_version) { + case TPM_VERSION_1_2: + break; + case TPM_VERSION_2: + /* write a 1.2 type of entry */ + tpm_log_event(&le, 1); + } +} +
/**************************************************************** * Helper functions @@ -441,20 +527,28 @@ tpm_extend(u32 pcrindex, const u8 *digest) }
static int -tpm_log_extend_event(struct pcpes *pcpes, const void *event) +tpm_log_extend_event(struct log_entry *le) { - int ret = tpm_extend(pcpes->pcrindex, pcpes->digest); + int ret = tpm_extend(le->entry.pcrindex, le->entry.digests[0].sha1); if (ret) return -1;
- return tpm_log_event(pcpes, event); + return tpm_log_event(le, TPM_version); }
+/* + * hash hashdata; if hashdata is not given, caller has calculated + * the hash, so it is in pcpes->digest + */ static void -tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length) +tpm_fill_hash(struct log_entry *le, const void *hashdata, u32 hashdata_length, + struct pcpes *pcpes) { if (hashdata) - sha1(hashdata, hashdata_length, pcpes->digest); + sha1(hashdata, hashdata_length, le->entry.digests[0].sha1); + else if (pcpes) + memcpy(le->entry.digests[0].sha1, pcpes->digest, + sizeof(le->entry.digests[0].sha1)); }
/* @@ -477,13 +571,16 @@ tpm_add_measurement_to_log(u32 pcrindex, u32 event_type, if (!tpm_is_working()) return;
- struct pcpes pcpes = { - .pcrindex = pcrindex, - .eventtype = event_type, - .eventdatasize = event_length, + struct log_entry le = { + .entry = { + .pcrindex = pcrindex, + .eventtype = event_type, + .eventsize = event_length, + }, + .event = event, }; - tpm_fill_hash(&pcpes, hashdata, hashdata_length); - int ret = tpm_log_extend_event(&pcpes, event); + tpm_fill_hash(&le, hashdata, hashdata_length, NULL); + int ret = tpm_log_extend_event(&le); if (ret) tpm_set_failure(); } @@ -707,6 +804,8 @@ tpm_setup(void) if (ret) return;
+ tpm_log_init(); + TPM_working = 1;
if (runningOnXen()) @@ -1038,8 +1137,17 @@ hash_log_extend_event_int(const struct hleei_short *hleei_s, goto err_exit; }
- tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen); - int ret = tpm_log_extend_event(pcpes, pcpes->event); + struct log_entry le = { + .entry = { + .pcrindex = pcpes->pcrindex, + .eventtype = pcpes->eventtype, + .eventsize = pcpes->eventdatasize, + }, + .event = pcpes->event, + }; + + tpm_fill_hash(&le, hleei_s->hashdataptr, hleei_s->hashdatalen, pcpes); + int ret = tpm_log_extend_event(&le); if (ret) { rc = TCG_TCG_COMMAND_ERROR; goto err_exit; @@ -1048,7 +1156,7 @@ hash_log_extend_event_int(const struct hleei_short *hleei_s, hleeo->opblength = sizeof(struct hleeo); hleeo->reserved = 0; hleeo->eventnumber = hleo.eventnumber; - memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest)); + memcpy(hleeo->digest, le.entry.digests[0].sha1, sizeof(hleeo->digest));
err_exit: if (rc != 0) { @@ -1121,8 +1229,17 @@ hash_log_event_int(const struct hlei *hlei, struct hleo *hleo) goto err_exit; }
- tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen); - int ret = tpm_log_event(pcpes, pcpes->event); + struct log_entry le = { + .entry = { + .pcrindex = pcpes->pcrindex, + .eventtype = pcpes->eventtype, + .eventsize = pcpes->eventdatasize, + }, + .event = pcpes->event, + }; + + tpm_fill_hash(&le, hlei->hashdataptr, hlei->hashdatalen, pcpes); + int ret = tpm_log_event(&le, TPM_version); if (ret) { rc = TCG_PC_LOGOVERFLOW; goto err_exit; @@ -1171,14 +1288,17 @@ compact_hash_log_extend_event_int(u8 *buffer, u32 pcrindex, u32 *edx_ptr) { - struct pcpes pcpes = { - .pcrindex = pcrindex, - .eventtype = EV_COMPACT_HASH, - .eventdatasize = sizeof(info), + struct log_entry le = { + .entry = { + .pcrindex = pcrindex, + .eventtype = EV_COMPACT_HASH, + .eventsize = sizeof(info), + }, + .event = &info, };
- tpm_fill_hash(&pcpes, buffer, length); - int ret = tpm_log_extend_event(&pcpes, &info); + tpm_fill_hash(&le, buffer, length, NULL); + int ret = tpm_log_extend_event(&le); if (ret) return TCG_TCG_COMMAND_ERROR; *edx_ptr = tpm_state.entry_count;