Hi Stefan,
What do you think about something like these two patches in place of your last patch 10? Basically using 'struct tcg_pcr_event2_sha1' instead of introducing a new 'struct log_entry'.
-Kevin
Kevin O'Connor (2): tpm: Unify tpm_fill_hash()/tpm_log_extend_event() and use in BIOS interface tpm: Write logs in TPM 2 format
src/std/tcg.h | 35 ++++++++++++++ src/tcgbios.c | 145 +++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 133 insertions(+), 47 deletions(-)
Don't call tpm_fill_hash() or tpm_log_extend_event() from any internal code (ie, tpm_add_measurement_to_log). The internal code does not require the additional checks that these functions provide.
Unify the tpm_fill_hash() and tpm_log_extend_event() into a new function hash_log_extend(), and use this function only in the 16bit BIOS interface code. With the code now specific to the BIOS interface it can more easily return a BIOS specific error return code.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/tcgbios.c | 77 ++++++++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 41 deletions(-)
diff --git a/src/tcgbios.c b/src/tcgbios.c index d6010c1..cddc99b 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -428,9 +428,6 @@ static int tpm20_extend(u32 pcrindex, const u8 *digest) static int tpm_extend(u32 pcrindex, const u8 *digest) { - if (pcrindex >= 24) - return -1; - switch (TPM_version) { case TPM_VERSION_1_2: return tpm12_extend(pcrindex, digest); @@ -440,23 +437,6 @@ tpm_extend(u32 pcrindex, const u8 *digest) return -1; }
-static int -tpm_log_extend_event(struct pcpes *pcpes, const void *event) -{ - int ret = tpm_extend(pcpes->pcrindex, pcpes->digest); - if (ret) - return -1; - - return tpm_log_event(pcpes, event); -} - -static void -tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length) -{ - if (hashdata) - sha1(hashdata, hashdata_length, pcpes->digest); -} - /* * Add a measurement to the log; the data at data_seg:data/length are * appended to the TCG_PCClientPCREventStruct @@ -482,10 +462,13 @@ tpm_add_measurement_to_log(u32 pcrindex, u32 event_type, .eventtype = event_type, .eventdatasize = event_length, }; - tpm_fill_hash(&pcpes, hashdata, hashdata_length); - int ret = tpm_log_extend_event(&pcpes, event); - if (ret) + sha1(hashdata, hashdata_length, pcpes.digest); + int ret = tpm_extend(pcpes.pcrindex, pcpes.digest); + if (ret) { tpm_set_failure(); + return; + } + tpm_log_event(&pcpes, event); }
@@ -997,6 +980,25 @@ static inline void *output_buf32(struct bregs *regs) }
static u32 +hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length + , void *event, int extend) +{ + if (pcpes->pcrindex >= 24) + return TCG_INVALID_INPUT_PARA; + if (hashdata) + sha1(hashdata, hashdata_length, pcpes->digest); + if (extend) { + int ret = tpm_extend(pcpes->pcrindex, pcpes->digest); + if (ret) + return TCG_TCG_COMMAND_ERROR; + } + int ret = tpm_log_event(pcpes, pcpes->event); + if (ret) + return TCG_PC_LOGOVERFLOW; + return 0; +} + +static u32 hash_log_extend_event_int(const struct hleei_short *hleei_s, struct hleeo *hleeo) { @@ -1032,18 +1034,15 @@ hash_log_extend_event_int(const struct hleei_short *hleei_s,
pcpes = (struct pcpes *)logdataptr;
- if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex + if (pcpes->pcrindex != pcrindex || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) { rc = TCG_INVALID_INPUT_PARA; goto err_exit; } - - tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen); - int ret = tpm_log_extend_event(pcpes, pcpes->event); - if (ret) { - rc = TCG_TCG_COMMAND_ERROR; + rc = hash_log_extend(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen + , pcpes->event, 1); + if (rc) goto err_exit; - }
hleeo->opblength = sizeof(struct hleeo); hleeo->reserved = 0; @@ -1131,19 +1130,16 @@ hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
pcpes = (struct pcpes *)hlei->logdataptr;
- if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex + if (pcpes->pcrindex != hlei->pcrindex || pcpes->eventtype != hlei->logeventtype || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) { rc = TCG_INVALID_INPUT_PARA; goto err_exit; } - - tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen); - int ret = tpm_log_event(pcpes, pcpes->event); - if (ret) { - rc = TCG_PC_LOGOVERFLOW; + rc = hash_log_extend(pcpes, hlei->hashdataptr, hlei->hashdatalen + , pcpes->event, 0); + if (rc) goto err_exit; - }
/* updating the log was fine */ hleo->opblength = sizeof(struct hleo); @@ -1193,11 +1189,10 @@ compact_hash_log_extend_event_int(u8 *buffer, .eventtype = EV_COMPACT_HASH, .eventdatasize = sizeof(info), }; + u32 rc = hash_log_extend(&pcpes, buffer, length, &info, 1); + if (rc) + return rc;
- tpm_fill_hash(&pcpes, buffer, length); - int ret = tpm_log_extend_event(&pcpes, &info); - if (ret) - return TCG_TCG_COMMAND_ERROR; *edx_ptr = tpm_state.entry_count; return 0; }
On 02/06/2016 01:35 PM, Kevin O'Connor wrote:
Don't call tpm_fill_hash() or tpm_log_extend_event() from any internal code (ie, tpm_add_measurement_to_log). The internal code does not require the additional checks that these functions provide.
Unify the tpm_fill_hash() and tpm_log_extend_event() into a new function hash_log_extend(), and use this function only in the 16bit BIOS interface code. With the code now specific to the BIOS interface it can more easily return a BIOS specific error return code.
Signed-off-by: Kevin O'Connor kevin@koconnor.net
src/tcgbios.c | 77 ++++++++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 41 deletions(-)
diff --git a/src/tcgbios.c b/src/tcgbios.c index d6010c1..cddc99b 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -428,9 +428,6 @@ static int tpm20_extend(u32 pcrindex, const u8 *digest) static int tpm_extend(u32 pcrindex, const u8 *digest) {
- if (pcrindex >= 24)
return -1;
switch (TPM_version) { case TPM_VERSION_1_2: return tpm12_extend(pcrindex, digest);
@@ -440,23 +437,6 @@ tpm_extend(u32 pcrindex, const u8 *digest) return -1; }
-static int -tpm_log_extend_event(struct pcpes *pcpes, const void *event) -{
- int ret = tpm_extend(pcpes->pcrindex, pcpes->digest);
- if (ret)
return -1;
- return tpm_log_event(pcpes, event);
-}
-static void -tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length) -{
- if (hashdata)
sha1(hashdata, hashdata_length, pcpes->digest);
-}
- /*
- Add a measurement to the log; the data at data_seg:data/length are
- appended to the TCG_PCClientPCREventStruct
@@ -482,10 +462,13 @@ tpm_add_measurement_to_log(u32 pcrindex, u32 event_type, .eventtype = event_type, .eventdatasize = event_length, };
- tpm_fill_hash(&pcpes, hashdata, hashdata_length);
- int ret = tpm_log_extend_event(&pcpes, event);
- if (ret)
- sha1(hashdata, hashdata_length, pcpes.digest);
- int ret = tpm_extend(pcpes.pcrindex, pcpes.digest);
- if (ret) { tpm_set_failure();
return;
- }
- tpm_log_event(&pcpes, event); }
@@ -997,6 +980,25 @@ static inline void *output_buf32(struct bregs *regs) }
static u32 +hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length
, void *event, int extend)
+{
- if (pcpes->pcrindex >= 24)
return TCG_INVALID_INPUT_PARA;
- if (hashdata)
sha1(hashdata, hashdata_length, pcpes->digest);
- if (extend) {
int ret = tpm_extend(pcpes->pcrindex, pcpes->digest);
if (ret)
return TCG_TCG_COMMAND_ERROR;
- }
- int ret = tpm_log_event(pcpes, pcpes->event);
- if (ret)
return TCG_PC_LOGOVERFLOW;
- return 0;
+}
+static u32 hash_log_extend_event_int(const struct hleei_short *hleei_s, struct hleeo *hleeo) { @@ -1032,18 +1034,15 @@ hash_log_extend_event_int(const struct hleei_short *hleei_s,
pcpes = (struct pcpes *)logdataptr;
- if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
- if (pcpes->pcrindex != pcrindex || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) { rc = TCG_INVALID_INPUT_PARA; goto err_exit; }
- tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen);
- int ret = tpm_log_extend_event(pcpes, pcpes->event);
- if (ret) {
rc = TCG_TCG_COMMAND_ERROR;
- rc = hash_log_extend(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen
, pcpes->event, 1);
- if (rc) goto err_exit;
}
hleeo->opblength = sizeof(struct hleeo); hleeo->reserved = 0;
@@ -1131,19 +1130,16 @@ hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
pcpes = (struct pcpes *)hlei->logdataptr;
- if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
- if (pcpes->pcrindex != hlei->pcrindex || pcpes->eventtype != hlei->logeventtype || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) { rc = TCG_INVALID_INPUT_PARA; goto err_exit; }
- tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
- int ret = tpm_log_event(pcpes, pcpes->event);
- if (ret) {
rc = TCG_PC_LOGOVERFLOW;
- rc = hash_log_extend(pcpes, hlei->hashdataptr, hlei->hashdatalen
, pcpes->event, 0);
- if (rc) goto err_exit;
}
/* updating the log was fine */ hleo->opblength = sizeof(struct hleo);
@@ -1193,11 +1189,10 @@ compact_hash_log_extend_event_int(u8 *buffer, .eventtype = EV_COMPACT_HASH, .eventdatasize = sizeof(info), };
- u32 rc = hash_log_extend(&pcpes, buffer, length, &info, 1);
- if (rc)
return rc;
- tpm_fill_hash(&pcpes, buffer, length);
- int ret = tpm_log_extend_event(&pcpes, &info);
- if (ret)
}return TCG_TCG_COMMAND_ERROR; *edx_ptr = tpm_state.entry_count; return 0;
ACK.
Stefan
On Mon, Feb 08, 2016 at 07:19:27AM -0500, Stefan Berger wrote:
On 02/06/2016 01:35 PM, Kevin O'Connor wrote:
Don't call tpm_fill_hash() or tpm_log_extend_event() from any internal code (ie, tpm_add_measurement_to_log). The internal code does not require the additional checks that these functions provide.
Unify the tpm_fill_hash() and tpm_log_extend_event() into a new function hash_log_extend(), and use this function only in the 16bit BIOS interface code. With the code now specific to the BIOS interface it can more easily return a BIOS specific error return code.
[...]
ACK.
Thanks - I pushed this change. (I did not push patch 2.)
-Kevin
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@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;
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) { + 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;
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@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
On Mon, Feb 08, 2016 at 07:25:35AM -0500, Stefan Berger wrote:
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@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.
I didn't think it would matter to overestimate a v1 record size by 6 bytes. That is, the acpi log shouldn't overflow, and if it gets that close to overflowing then one could just call it overflowed?
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.
Okay.
The main difference here between parts of my code and yours is that you are inlining it.
Yes. Avoiding 'struct log_entry' was the main thing though.
Thanks, -Kevin
On Mon, Feb 08, 2016 at 11:36:40AM -0500, Kevin O'Connor wrote:
On Mon, Feb 08, 2016 at 07:25:35AM -0500, Stefan Berger wrote:
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@koconnor.net
Hi Stefan,
I updated the patch with your feedback on an explicit version check instead of using EV_NO_ACTION.
Are you okay with the patch below, and if so can I add your signed-off-by line?
-Kevin
commit 102648838c0cf640c01b5f092e8f432d8f2abb8f Author: Kevin O'Connor kevin@koconnor.net Date: Fri Feb 5 22:28:17 2016 -0500
tpm: Write logs in TPM 2 format
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@koconnor.net
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..ddf4f79 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -141,7 +141,8 @@ 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 + , 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,17 +150,30 @@ 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; - - if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) > - tpm_state.log_area_minimum_length) { + u32 size = sizeof(*entry) + entry->eventdatasize; + u32 logsize = (tpm_state.log_area_next_entry + size + - tpm_state.log_area_start_address); + if (logsize > tpm_state.log_area_minimum_length) { dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size); return -1; }
- memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes)); - memcpy(tpm_state.log_area_next_entry + sizeof(*pcpes), - event, pcpes->eventdatasize); + switch (tpm_version) { + case TPM_VERSION_1_2: ; + 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; + break; + case TPM_VERSION_2: ; + struct tcg_pcr_event2_sha1 *e = (void*)tpm_state.log_area_next_entry; + memcpy(e, entry, sizeof(*e)); + memcpy(e->event, event, entry->eventdatasize); + break; + }
tpm_state.log_area_last_entry = tpm_state.log_area_next_entry; tpm_state.log_area_next_entry += size; @@ -168,6 +182,41 @@ 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 + */ +static 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, TPM_VERSION_1_2); + } +} +
/**************************************************************** * Helper functions @@ -457,18 +506,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, TPM_version); }
@@ -690,6 +741,8 @@ tpm_setup(void) if (ret) return;
+ tpm_log_init(); + TPM_working = 1;
if (runningOnXen()) @@ -992,7 +1045,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, TPM_version); if (ret) return TCG_PC_LOGOVERFLOW; return 0;
On 02/23/2016 11:53 AM, Kevin O'Connor wrote:
On Mon, Feb 08, 2016 at 11:36:40AM -0500, Kevin O'Connor wrote:
On Mon, Feb 08, 2016 at 07:25:35AM -0500, Stefan Berger wrote:
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@koconnor.net
Hi Stefan,
I updated the patch with your feedback on an explicit version check instead of using EV_NO_ACTION.
Are you okay with the patch below, and if so can I add your signed-off-by line?
-Kevin
commit 102648838c0cf640c01b5f092e8f432d8f2abb8f Author: Kevin O'Connor kevin@koconnor.net Date: Fri Feb 5 22:28:17 2016 -0500
tpm: Write logs in TPM 2 format 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@koconnor.net>
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
On Fri, Feb 26, 2016 at 01:28:14PM -0500, Stefan Berger wrote:
On 02/23/2016 11:53 AM, Kevin O'Connor wrote:
commit 102648838c0cf640c01b5f092e8f432d8f2abb8f Author: Kevin O'Connor kevin@koconnor.net Date: Fri Feb 5 22:28:17 2016 -0500
tpm: Write logs in TPM 2 format 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@koconnor.net>
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
Thanks. I committed this patch.
-Kevin