Skip to content

Commit

Permalink
FAPI: Eventlog add H-CRTM and different locality support.
Browse files Browse the repository at this point in the history
* For H-CRTM events pcr0 has to be initialized with 4.
* A different locality can be set in an event with a
  startup locality signature.

To enable the implementation of a corresponding unit test
the function ifapi_check_profile_pcr_selection was splitted
into two functions. The new function ifapi_calculate_pcrs
is used in the unit test to check whether the expected
pcr0 is computed from the event list computed from the
binary H-CRTM firmware file.
Fixes tpm2-software#2672.

Signed-off-by: Juergen Repp <juergen_repp@web.de>
  • Loading branch information
JuergenReppSIT committed Aug 20, 2023
1 parent 86949f7 commit 544e2e7
Show file tree
Hide file tree
Showing 10 changed files with 1,376 additions and 53 deletions.
3 changes: 2 additions & 1 deletion Makefile-test.am
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ FAPI_TEST_BINS = \
test/data/fapi/eventlog/sml-ima-sig-sha256-invalidated.bin \
test/data/fapi/eventlog/event-uefivar.bin \
test/data/fapi/eventlog/specid-vendordata.bin \
test/data/fapi/eventlog/sml-ima-ng-sha1.bin
test/data/fapi/eventlog/sml-ima-ng-sha1.bin \
test/data/fapi/eventlog/binary_measurements_hcrtm.bin

CLEANFILES += $(FAPI_TEST_BINS)
endif #FAPI
Expand Down
3 changes: 2 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,8 @@ EXTRA_DIST += \
test/data/fapi/eventlog/sml-ima-ng-sha1-invalidated.b64 \
test/data/fapi/eventlog/sml-ima-ng-sha1-invalidated.b64 \
test/data/fapi/eventlog/sml-ima-sig-sha256-invalidated.b64 \
test/data/fapi/eventlog/sml-ima-sha1-invalidated.b64
test/data/fapi/eventlog/sml-ima-sha1-invalidated.b64 \
test/data/fapi/eventlog/binary_measurements_hcrtm.b64

src_tss2_fapi_libtss2_fapi_la_LIBADD = $(libtss2_sys) $(libtss2_mu) $(libtss2_esys) \
$(libutil) $(libtss2_tctildr)
Expand Down
15 changes: 15 additions & 0 deletions src/tss2-fapi/efi_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,19 @@ typedef struct {
BYTE DevicePath[];
} PACKED UEFI_IMAGE_LOAD_EVENT;

/*
* EV_NO_ACTION_STRUCT is the structure of an EV_NO_ACTION event.
* Described in TCG PCClient PFP section 9.4.5.
* The Signature identifies which arm of the union applies.
*/
typedef struct {
BYTE Signature[16];
union {
BYTE StartupLocality;
} Cases;
} PACKED EV_NO_ACTION_STRUCT;

static const BYTE STARTUP_LOCALITY_SIGNATURE[16] = {0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4C,
0x6F, 0x63, 0x61, 0x6C, 0x69, 0x74, 0x79, 0};

#endif
62 changes: 56 additions & 6 deletions src/tss2-fapi/ifapi_eventlog_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ bool foreach_digest2(
unsigned pcr_index,
TCG_DIGEST2 const *digest,
size_t count,
size_t size) {
size_t size,
uint8_t locality) {

if (digest == NULL) {
LOG_ERROR("digest cannot be NULL");
Expand Down Expand Up @@ -149,6 +150,13 @@ bool foreach_digest2(
LOG_WARNING("PCR%d algorithm %d unsupported", pcr_index, alg);
}

if (event_type == EV_EFI_HCRTM_EVENT && pcr && pcr_index == 0) {
/* Trusted Platform Module Library Part 1 section 34.3 */
pcr[alg_size - 1] = 0x04;
} else if (event_type == EV_NO_ACTION && pcr && pcr_index == 0 && locality > 0) {
pcr[alg_size -1] = locality;
}

if (event_type == EV_NO_ACTION) {
/* Digest for EV_NO_ACTION must consist of 0 bytes. */
for (j = 0; j < alg_size; j++) {
Expand Down Expand Up @@ -237,6 +245,21 @@ bool parse_event2body(TCG_EVENT2 const *event, UINT32 type) {
/* what about the device path? */
}
break;
/* TCG PC Client Platform Firmware Profile Specification Level 00 Version 1.05 Revision 23 section 10.4.1 */
case EV_EFI_HCRTM_EVENT:
{
const char hcrtm_data[] = "HCRTM";
size_t len = strlen(hcrtm_data);
BYTE *data = (BYTE *)event->Event;
if (event->EventSize != len ||
strncmp((const char *)data, hcrtm_data, len)) {
LOG_ERROR("HCRTM Event Data MUST be the string: \"%s\"", hcrtm_data);
return false;
}
}
break;


}

return true;
Expand All @@ -262,7 +285,7 @@ bool parse_event2(TCG_EVENT_HEADER2 const *eventhdr, size_t buf_size,
};
ret = foreach_digest2(&ctx, eventhdr->EventType, eventhdr->PCRIndex,
eventhdr->Digests, eventhdr->DigestCount,
buf_size - sizeof(*eventhdr));
buf_size - sizeof(*eventhdr), 0);
if (ret != true) {
return false;
}
Expand Down Expand Up @@ -385,13 +408,15 @@ bool foreach_event2(tpm2_eventlog_context *ctx, TCG_EVENT_HEADER2 const *eventhd
TCG_EVENT_HEADER2 const *eventhdr;
size_t event_size;
bool ret;
bool found_hcrtm = false;

for (eventhdr = eventhdr_start, event_size = 0;
size > 0;
eventhdr = (TCG_EVENT_HEADER2*)((uintptr_t)eventhdr + event_size),
size -= event_size) {

size_t digests_size = 0;
uint8_t locality = 0;

ret = parse_event2(eventhdr, size, &event_size, &digests_size);
if (!ret) {
Expand All @@ -400,6 +425,25 @@ bool foreach_event2(tpm2_eventlog_context *ctx, TCG_EVENT_HEADER2 const *eventhd

TCG_EVENT2 *event = (TCG_EVENT2*)((uintptr_t)eventhdr->Digests + digests_size);

if (eventhdr->EventType == EV_EFI_HCRTM_EVENT && eventhdr->PCRIndex == 0) {
found_hcrtm = true;
}

/* Handle StartupLocality in replay for PCR0 */
if (!found_hcrtm && eventhdr->EventType == EV_NO_ACTION && eventhdr->PCRIndex == 0) {
if (event_size < sizeof(EV_NO_ACTION_STRUCT)) {
LOG_ERROR("EventSize is too small.");
return false;
}

EV_NO_ACTION_STRUCT *locality_event = (EV_NO_ACTION_STRUCT*)event->Event;

if (memcmp(locality_event->Signature, STARTUP_LOCALITY_SIGNATURE,
sizeof(STARTUP_LOCALITY_SIGNATURE)) == 0) {
locality = locality_event->Cases.StartupLocality;
}
}

/* event header callback */
if (ctx->event2hdr_cb != NULL) {
ret = ctx->event2hdr_cb(eventhdr, event_size, ctx->data);
Expand All @@ -410,7 +454,8 @@ bool foreach_event2(tpm2_eventlog_context *ctx, TCG_EVENT_HEADER2 const *eventhd

/* digest callback foreach digest */
ret = foreach_digest2(ctx, eventhdr->EventType, eventhdr->PCRIndex,
eventhdr->Digests, eventhdr->DigestCount, digests_size);
eventhdr->Digests, eventhdr->DigestCount, digests_size,
locality);
if (ret != true) {
return false;
}
Expand Down Expand Up @@ -567,6 +612,7 @@ ifapi_json_TCG_EVENT_TYPE_deserialize_txt(json_object *jso,
const char *token = json_object_get_string(jso);

check_oom(token);
LOG_TRACE("TCG Event: %s", token);

if (get_number(token, &i64)) {
*out = (IFAPI_EVENT_TYPE) i64;
Expand Down Expand Up @@ -606,6 +652,7 @@ TSS2_RC
ifapi_json_TCG_EVENT_TYPE_deserialize(json_object *jso, IFAPI_EVENT_TYPE *out)
{
LOG_TRACE("call");

return ifapi_json_TCG_EVENT_TYPE_deserialize_txt(jso, out);
}

Expand Down Expand Up @@ -661,6 +708,8 @@ ifapi_json_IFAPI_FIRMWARE_EVENT_deserialize(
r = ifapi_json_TCG_EVENT_TYPE_deserialize (jso2, &event_type);
return_if_error(r,"BAD VALUE");

out->event_type = event_type;

if (!ifapi_get_sub_object(jso, "event_data", &jso2)) {
LOG_ERROR("Bad value");
return TSS2_FAPI_RC_BAD_VALUE;
Expand Down Expand Up @@ -715,7 +764,10 @@ ifapi_json_IFAPI_FIRMWARE_EVENT_deserialize(
event_type == EV_IPL_PARTITION_DATA ||
event_type == EV_NONHOST_CODE ||
event_type == EV_NONHOST_CONFIG ||
event_type == EV_EFI_RUNTIME_SERVICES_DRIVER) {
event_type == EV_EFI_RUNTIME_SERVICES_DRIVER ||
/* Verification not possible. (TODO check) */
event_type == EV_EFI_HCRTM_EVENT ||
event_type == EV_EFI_VARIABLE_BOOT) {
*verify = false;
} else if (
/* Verification is possible. (TODO check) */
Expand All @@ -726,12 +778,10 @@ ifapi_json_IFAPI_FIRMWARE_EVENT_deserialize(
event_type == EV_EFI_VARIABLE_AUTHORITY ||
/* Verification is possible. */
event_type == EV_S_CRTM_VERSION ||
event_type == EV_EFI_HCRTM_EVENT ||
event_type == EV_SEPARATOR ||
event_type == EV_EFI_VARIABLE_DRIVER_CONFIG ||
event_type == EV_EFI_GPT_EVENT ||
event_type == EV_PLATFORM_CONFIG_FLAGS ||
event_type == EV_EFI_VARIABLE_BOOT ||
event_type == EV_EFI_ACTION) {
*verify = true;
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/tss2-fapi/ifapi_eventlog_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ bool digest2_accumulator_callback(TCG_DIGEST2 const *digest, size_t size,

bool parse_event2body(TCG_EVENT2 const *event, UINT32 type);
bool foreach_digest2(tpm2_eventlog_context *ctx, UINT32 event_type, unsigned pcr_index,
TCG_DIGEST2 const *event_hdr, size_t count, size_t size);
TCG_DIGEST2 const *event_hdr, size_t count, size_t size, uint8_t locality);
bool parse_event2(TCG_EVENT_HEADER2 const *eventhdr, size_t buf_size,
size_t *event_size, size_t *digests_size);
bool foreach_event2(tpm2_eventlog_context *ctx, TCG_EVENT_HEADER2 const *eventhdr_start, size_t size);
Expand Down
152 changes: 109 additions & 43 deletions src/tss2-fapi/ifapi_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2101,6 +2101,111 @@ ifapi_extend_pcr(
return r;
}

/** Compute pcr values from event list
*
* The event list is used to compute the PCR values corresponding
* to this event list.
* @param[in] jso_event_list The event list in JSON representation.
* @param[in] pcr_selection The definition of the used pcrs.
* @param[out] pcrs The computed pcr list
* @param[out] n_pcrs The number of used pcrs
*
* @retval TSS2_RC_SUCCESS: If the PCR digest from the event list matches
* the PCR digest passed with the quote_info.
* @retval TSS2_FAPI_RC_BAD_VALUE: If inappropriate values are detected in the
* input data.
* @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
* @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
* @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
*/
TSS2_RC
ifapi_calculate_pcrs(
json_object *jso_event_list,
const TPML_PCR_SELECTION *pcr_selection,
IFAPI_PCR_REG pcrs[],
size_t *n_pcrs)
{
TSS2_RC r = TSS2_RC_SUCCESS;
IFAPI_CRYPTO_CONTEXT_BLOB *cryptoContext = NULL;
size_t i, pcr, i_evt, hash_size, n_events = 0;

json_object *jso;
IFAPI_EVENT event;
bool found_hcrtm = false;
UINT8 locality = 0;

*n_pcrs = 0;

/* Initialize used pcrs */
for (i = 0; i < pcr_selection->count; i++) {
for (pcr = 0; pcr < TPM2_MAX_PCRS; pcr++) {
uint8_t byte_idx = pcr / 8;
uint8_t flag = 1 << (pcr % 8);
if (flag & pcr_selection->pcrSelections[i].pcrSelect[byte_idx]) {
hash_size = ifapi_hash_get_digest_size(pcr_selection->pcrSelections[i].hash);
pcrs[*n_pcrs].pcr = pcr;
pcrs[*n_pcrs].bank = pcr_selection->pcrSelections[i].hash;
pcrs[*n_pcrs].value.size = hash_size;
memset(&pcrs[*n_pcrs].value.buffer[0], 0, hash_size);
*n_pcrs += 1;
}
}
}

/* Compute pcr values based on event list */
if (jso_event_list) {
n_events = json_object_array_length(jso_event_list);
for (i_evt = 0; i_evt < n_events; i_evt++) {
jso = json_object_array_get_idx(jso_event_list, i_evt);
r = ifapi_json_IFAPI_EVENT_deserialize(jso, &event, DIGEST_CHECK_WARNING);
goto_if_error(r, "Error serialize policy", error_cleanup);
LOG_TRACE("Deserialized Event for PCR %u", event.pcr);

if (event.content_type == IFAPI_PC_CLIENT &&
event.content.firmware_event.event_type == EV_EFI_HCRTM_EVENT && event.pcr == 0) {
found_hcrtm = true;
}

/* Handle StartupLocality in replay for PCR0 */
if (event.content_type == IFAPI_PC_CLIENT &&
!found_hcrtm &&
event.content.firmware_event.event_type == EV_NO_ACTION && event.pcr == 0) {
if (event.content.firmware_event.data.size < sizeof(EV_NO_ACTION_STRUCT)) {
goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "EventSize is too small.", error_cleanup);
}
EV_NO_ACTION_STRUCT *locality_event = (EV_NO_ACTION_STRUCT*)&event.content.firmware_event.data.buffer[0];
if (memcmp(locality_event->Signature, STARTUP_LOCALITY_SIGNATURE,
sizeof(STARTUP_LOCALITY_SIGNATURE)) == 0) {
locality = locality_event->Cases.StartupLocality;
}
}

for (i = 0; i < *n_pcrs; i++) {
if (pcrs[i].pcr == event.pcr) {
if (event.content_type == IFAPI_PC_CLIENT && event.pcr == 0) {
if (event.content.firmware_event.event_type == EV_EFI_HCRTM_EVENT) {
/* Trusted Platform Module Library Part 1 section 34.3 */
pcrs[i].value.buffer[pcrs[i].value.size - 1] = 0x04;
} else if (event.content.firmware_event.event_type == EV_NO_ACTION &&
locality > 0) {
pcrs[i].value.buffer[pcrs[i].value.size - 1] = locality;
}
}
LOG_DEBUG("Extend PCR %uz", pcrs[i].pcr);
r = ifapi_extend_vpcr(&pcrs[i].value, pcrs[i].bank, &event);
goto_if_error2(r, "Extending vpcr %"PRIu32, error_cleanup, pcrs[i].pcr);
}
}
ifapi_cleanup_event(&event);
}
}

error_cleanup:
if (cryptoContext)
ifapi_crypto_hash_abort(&cryptoContext);
ifapi_cleanup_event(&event);
return r;
}

/** Check whether a event list corresponds to a certain quote information.
*
Expand Down Expand Up @@ -2130,15 +2235,9 @@ ifapi_calculate_pcr_digest(
{
TSS2_RC r;
IFAPI_CRYPTO_CONTEXT_BLOB *cryptoContext = NULL;
IFAPI_PCR_REG pcrs[TPM2_MAX_PCRS];
size_t i, hash_size, n_pcrs = 0;

struct {
TPMI_ALG_HASH bank;
TPM2_HANDLE pcr;
TPM2B_DIGEST value;
} pcrs[TPM2_MAX_PCRS];
size_t i, pcr, i_evt, hash_size, n_pcrs = 0, n_events = 0;

json_object *jso;
IFAPI_EVENT event;

const TPML_PCR_SELECTION *pcr_selection;
Expand Down Expand Up @@ -2166,41 +2265,8 @@ ifapi_calculate_pcr_digest(
return TSS2_FAPI_RC_BAD_VALUE;
}

/* Initialize used pcrs */
for (i = 0; i < pcr_selection->count; i++) {
for (pcr = 0; pcr < TPM2_MAX_PCRS; pcr++) {
uint8_t byte_idx = pcr / 8;
uint8_t flag = 1 << (pcr % 8);
if (flag & pcr_selection->pcrSelections[i].pcrSelect[byte_idx]) {
hash_size = ifapi_hash_get_digest_size(pcr_selection->pcrSelections[i].hash);
pcrs[n_pcrs].pcr = pcr;
pcrs[n_pcrs].bank = pcr_selection->pcrSelections[i].hash;
pcrs[n_pcrs].value.size = hash_size;
memset(&pcrs[n_pcrs].value.buffer[0], 0, hash_size);
n_pcrs += 1;
}
}
}

/* Compute pcr values based on event list */
if (jso_event_list) {
n_events = json_object_array_length(jso_event_list);
for (i_evt = 0; i_evt < n_events; i_evt++) {
jso = json_object_array_get_idx(jso_event_list, i_evt);
r = ifapi_json_IFAPI_EVENT_deserialize(jso, &event, DIGEST_CHECK_WARNING);
goto_if_error(r, "Error serialize policy", error_cleanup);
LOG_TRACE("Deserialized Event for PCR %u", event.pcr);

for (i = 0; i < n_pcrs; i++) {
if (pcrs[i].pcr == event.pcr) {
LOG_DEBUG("Extend PCR %uz", pcrs[i].pcr);
r = ifapi_extend_vpcr(&pcrs[i].value, pcrs[i].bank, &event);
goto_if_error2(r, "Extending vpcr %"PRIu32, error_cleanup, pcrs[i].pcr);
}
}
ifapi_cleanup_event(&event);
}
}
r = ifapi_calculate_pcrs(jso_event_list, pcr_selection, &pcrs[0], &n_pcrs);
goto_if_error(r, "Compute PCRFs", error_cleanup);

/* Compute digest for the used pcrs */
r = ifapi_crypto_hash_start(&cryptoContext, pcr_digest_hash_alg);
Expand Down
Loading

0 comments on commit 544e2e7

Please sign in to comment.