From e8b016c12e3b7fb70db74000b4daffa17075bb30 Mon Sep 17 00:00:00 2001 From: Juergen Repp Date: Fri, 29 Dec 2023 19:37:17 +0100 Subject: [PATCH] FAPI: Fix synchronization eventlog. After the execution of a quote the ima eventlog can be extended before the read of the log. Therefore every entry in the eventlog is checked whether the digest in the attest matches the current digest computed from the reconstructed pcrs. If yes success is returned and the following events are ignored in Fapi_VerfiyQuote and deleted in Fapi_Quote. Thus old attestations can be verified with newer event lists. The event list produced by Fapi_Quote represents the valid event list for this quote. Signed-off-by: Juergen Repp --- src/tss2-fapi/api/Fapi_PcrRead.c | 2 +- src/tss2-fapi/api/Fapi_Quote.c | 5 +- src/tss2-fapi/api/Fapi_VerifyQuote.c | 3 +- src/tss2-fapi/fapi_int.h | 7 -- src/tss2-fapi/ifapi_eventlog.c | 11 ++- src/tss2-fapi/ifapi_eventlog.h | 8 ++ src/tss2-fapi/ifapi_helpers.c | 108 +++++++++++++++------------ src/tss2-fapi/ifapi_helpers.h | 12 +-- test/unit/fapi-eventlog.c | 3 +- 9 files changed, 92 insertions(+), 67 deletions(-) diff --git a/src/tss2-fapi/api/Fapi_PcrRead.c b/src/tss2-fapi/api/Fapi_PcrRead.c index b88616e4e..d1ac36afd 100644 --- a/src/tss2-fapi/api/Fapi_PcrRead.c +++ b/src/tss2-fapi/api/Fapi_PcrRead.c @@ -258,7 +258,7 @@ Fapi_PcrRead_Finish( fallthrough; statecase(context->state, PCR_READ_READ_EVENT_LIST); - r = ifapi_eventlog_get_finish(&context->eventlog, &context->io, pcrLog); + r = ifapi_eventlog_get_finish(&context->eventlog, NULL, &context->io, pcrLog); return_try_again(r); goto_if_error(r, "Error getting event log", cleanup); diff --git a/src/tss2-fapi/api/Fapi_Quote.c b/src/tss2-fapi/api/Fapi_Quote.c index 52d2e7726..2f0d851b7 100644 --- a/src/tss2-fapi/api/Fapi_Quote.c +++ b/src/tss2-fapi/api/Fapi_Quote.c @@ -421,6 +421,7 @@ Fapi_Quote_Finish( signed by the TPM. */ r = ifapi_compute_quote_info(sig_key_object, command->tpm_quoted, + &command->fapi_quote_info, quoteInfo); goto_if_error(r, "Create compute quote info.", error_cleanup); @@ -444,7 +445,9 @@ Fapi_Quote_Finish( fallthrough; statecase(context->state, PCR_QUOTE_READ_EVENT_LIST); - r = ifapi_eventlog_get_finish(&context->eventlog, &context->io, + r = ifapi_eventlog_get_finish(&context->eventlog, + &command->fapi_quote_info, + &context->io, &command->pcrLog); return_try_again(r); goto_if_error(r, "Error getting event log", error_cleanup); diff --git a/src/tss2-fapi/api/Fapi_VerifyQuote.c b/src/tss2-fapi/api/Fapi_VerifyQuote.c index 4c7271b09..fda532397 100644 --- a/src/tss2-fapi/api/Fapi_VerifyQuote.c +++ b/src/tss2-fapi/api/Fapi_VerifyQuote.c @@ -266,7 +266,6 @@ Fapi_VerifyQuote_Finish( TSS2_RC r; IFAPI_OBJECT key_object; TPM2B_ATTEST attest2b; - TPM2B_DIGEST pcr_digest; /* Check for NULL parameters */ check_not_null(context); @@ -323,7 +322,7 @@ Fapi_VerifyQuote_Finish( /* Recalculate and verify the PCR digests. */ r = ifapi_calculate_pcr_digest(command->event_list, - &command->fapi_quote_info, &pcr_digest); + &command->fapi_quote_info); goto_if_error(r, "Verify event list.", error_cleanup); diff --git a/src/tss2-fapi/fapi_int.h b/src/tss2-fapi/fapi_int.h index 55a6cff02..69e4af074 100644 --- a/src/tss2-fapi/fapi_int.h +++ b/src/tss2-fapi/fapi_int.h @@ -191,13 +191,6 @@ typedef struct { TPMS_NV_PUBLIC public; /**< Template for public data */ } IFAPI_NV_TEMPLATE; -/** Type for representing a external public key - */ -typedef struct { - TPMT_SIG_SCHEME sig_scheme; /**< Signature scheme used for quote. */ - TPMS_ATTEST attest; /**< Attestation data from Quote */ -} FAPI_QUOTE_INFO; - /** The states for the FAPI's NV read state */ enum _FAPI_STATE_NV_READ { diff --git a/src/tss2-fapi/ifapi_eventlog.c b/src/tss2-fapi/ifapi_eventlog.c index 8e542eef9..c641ba4bf 100644 --- a/src/tss2-fapi/ifapi_eventlog.c +++ b/src/tss2-fapi/ifapi_eventlog.c @@ -200,10 +200,11 @@ ifapi_eventlog_get_async( TSS2_RC ifapi_eventlog_get_finish( IFAPI_EVENTLOG *eventlog, + FAPI_QUOTE_INFO *fapi_quote_info, IFAPI_IO *io, char **log) { - /* eventlog parameter currently not used */ + /* eventlog parameteifapi_eventlog_get_finishr currently not used */ check_not_null(eventlog); check_not_null(io); check_not_null(log); @@ -230,7 +231,13 @@ ifapi_eventlog_get_finish( goto_if_error(r, "Error serialize policy", error); ifapi_cleanup_event(&event); - } + } + if (fapi_quote_info) { + r = ifapi_calculate_pcr_digest(eventlog->log, + fapi_quote_info); + + goto_if_error(r, "Verify event list.", error); + } *log = strdup(json_object_to_json_string_ext(eventlog->log, JSON_C_TO_STRING_PRETTY)); check_oom(*log); diff --git a/src/tss2-fapi/ifapi_eventlog.h b/src/tss2-fapi/ifapi_eventlog.h index 0ef50abdc..e70893ae8 100644 --- a/src/tss2-fapi/ifapi_eventlog.h +++ b/src/tss2-fapi/ifapi_eventlog.h @@ -84,6 +84,13 @@ typedef struct IFAPI_EVENT { verified. */ } IFAPI_EVENT; +/** Type for representing the quote info and signature scheme for quote. + */ +typedef struct { + TPMT_SIG_SCHEME sig_scheme; /**< Signature scheme used for quote. */ + TPMS_ATTEST attest; /**< Attestation data from Quote */ +} FAPI_QUOTE_INFO; + enum IFAPI_EVENTLOG_STATE { IFAPI_EVENTLOG_STATE_INIT = 0, IFAPI_EVENTLOG_STATE_READING, @@ -120,6 +127,7 @@ ifapi_eventlog_get_async( TSS2_RC ifapi_eventlog_get_finish( IFAPI_EVENTLOG *eventlog, + FAPI_QUOTE_INFO *fapi_quote_info, IFAPI_IO *io, char **log); diff --git a/src/tss2-fapi/ifapi_helpers.c b/src/tss2-fapi/ifapi_helpers.c index 84c499259..7c7188c1f 100644 --- a/src/tss2-fapi/ifapi_helpers.c +++ b/src/tss2-fapi/ifapi_helpers.c @@ -1730,6 +1730,8 @@ ifapi_tpm_to_fapi_signature( * * @param[in] sig_key_object The key object which was used for the quote. * @param[in] tpm_quoted: The attest produced by the quote. + * @param[out] fapi_quote_info Info The representation of the + * attest together with the signing schemed. * @param[out] quoteInfo The character string with the JSON representation of the * attest together with the signing schemed. * @@ -1745,13 +1747,13 @@ TSS2_RC ifapi_compute_quote_info( IFAPI_OBJECT *sig_key_object, TPM2B_ATTEST *tpm_quoted, + FAPI_QUOTE_INFO *fapi_quote_info, char **quoteInfo) { json_object *jso = NULL; TSS2_RC r; size_t offset = 0; TPMS_ATTEST attest_struct; - FAPI_QUOTE_INFO fapi_quote_info; /* The TPM2B_ATTEST contains the marshaled TPMS_ATTEST structure. */ r = Tss2_MU_TPMS_ATTEST_Unmarshal((const uint8_t *) @@ -1759,10 +1761,10 @@ ifapi_compute_quote_info( tpm_quoted->size, &offset, &attest_struct); return_if_error(r, "Unmarshal TPMS_ATTEST."); - fapi_quote_info.attest = attest_struct; + fapi_quote_info->attest = attest_struct; /* The signate scheme will be taken from the key used for qoting. */ - fapi_quote_info.sig_scheme = sig_key_object->misc.key.signing_scheme; - r = ifapi_json_FAPI_QUOTE_INFO_serialize(&fapi_quote_info, &jso); + fapi_quote_info->sig_scheme = sig_key_object->misc.key.signing_scheme; + r = ifapi_json_FAPI_QUOTE_INFO_serialize(fapi_quote_info, &jso); return_if_error(r, "Conversion to TPM2B_ATTEST to JSON."); /* The intermediate structure of type FAPI_QOTE_INFO will be serialized. */ @@ -2101,10 +2103,11 @@ ifapi_extend_pcr( return r; } -/** Compute pcr values from event list +/** Compute pcr values from event list and verify quote digest. * * The event list is used to compute the PCR values corresponding - * to this event list. + * to this event list. If a quote digest is passed success will + * be returned if the computed pcr digest matches the quote digest. * @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 @@ -2122,20 +2125,20 @@ TSS2_RC ifapi_calculate_pcrs( json_object *jso_event_list, const TPML_PCR_SELECTION *pcr_selection, - IFAPI_PCR_REG pcrs[], - size_t *n_pcrs) + TPMI_ALG_HASH pcr_digest_hash_alg, + const TPM2B_DIGEST *quote_digest, + IFAPI_PCR_REG *pcrs) { TSS2_RC r = TSS2_RC_SUCCESS; IFAPI_CRYPTO_CONTEXT_BLOB *cryptoContext = NULL; size_t i, pcr, i_evt, hash_size, n_events = 0; - + size_t n_pcrs = 0; + TPM2B_DIGEST pcr_digest; 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++) { @@ -2143,11 +2146,11 @@ ifapi_calculate_pcrs( 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; + 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; } } } @@ -2180,7 +2183,7 @@ ifapi_calculate_pcrs( } } - for (i = 0; i < *n_pcrs; i++) { + 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) { @@ -2197,6 +2200,42 @@ ifapi_calculate_pcrs( } } ifapi_cleanup_event(&event); + + /* Compute digest for the used pcrs */ + if (quote_digest) { + r = ifapi_crypto_hash_start(&cryptoContext, pcr_digest_hash_alg); + return_if_error(r, "crypto hash start"); + + for (i = 0; i < n_pcrs; i++) { + HASH_UPDATE_BUFFER(cryptoContext, &pcrs[i].value.buffer, pcrs[i].value.size, + r, error_cleanup); + } + r = ifapi_crypto_hash_finish(&cryptoContext, + (uint8_t *) &pcr_digest.buffer[0], + &hash_size); + return_if_error(r, "crypto hash finish"); + pcr_digest.size = hash_size; + + /* Compare the digest from the event list with the digest from the attest */ + if (memcmp(&pcr_digest.buffer[0], "e_digest->buffer[0], + pcr_digest.size) == 0) { + if (i_evt < (n_events - 1)) { + /* delete the events added after the quote */ + if (json_object_array_del_idx(jso_event_list, i_evt + 1, + n_events - i_evt - 1)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Can't delete remaining eventsize", error_cleanup); + } + } + break; + } else { + ifapi_crypto_hash_abort(&cryptoContext); + } + } + } + if (i_evt == n_events && quote_digest) { + /* Quote digest was not found. */ + r = TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED; } } @@ -2230,22 +2269,17 @@ ifapi_calculate_pcrs( TSS2_RC ifapi_calculate_pcr_digest( json_object *jso_event_list, - const FAPI_QUOTE_INFO *quote_info, - TPM2B_DIGEST *pcr_digest) + const FAPI_QUOTE_INFO *quote_info) { TSS2_RC r; IFAPI_CRYPTO_CONTEXT_BLOB *cryptoContext = NULL; IFAPI_PCR_REG pcrs[TPM2_MAX_PCRS]; - size_t i, hash_size, n_pcrs = 0; - - IFAPI_EVENT event; const TPML_PCR_SELECTION *pcr_selection; TPMI_ALG_HASH pcr_digest_hash_alg; /* Get some data from the quote info for easier access */ pcr_selection = "e_info->attest.attested.quote.pcrSelect; - pcr_digest->size = quote_info->attest.attested.quote.pcrDigest.size; switch (quote_info->sig_scheme.scheme) { case TPM2_ALG_RSAPSS: @@ -2265,35 +2299,15 @@ ifapi_calculate_pcr_digest( return TSS2_FAPI_RC_BAD_VALUE; } - 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); - return_if_error(r, "crypto hash start"); - - for (i = 0; i < n_pcrs; i++) { - HASH_UPDATE_BUFFER(cryptoContext, &pcrs[i].value.buffer, pcrs[i].value.size, - r, error_cleanup); - } - r = ifapi_crypto_hash_finish(&cryptoContext, - (uint8_t *) &pcr_digest->buffer[0], - &hash_size); - return_if_error(r, "crypto hash finish"); - pcr_digest->size = hash_size; + r = ifapi_calculate_pcrs(jso_event_list, pcr_selection, pcr_digest_hash_alg, + "e_info->attest.attested.quote.pcrDigest, + &pcrs[0]); + goto_if_error(r, "Compute PCRs", error_cleanup); - /* Compare the digest from the event list with the digest from the attest */ - if (memcmp(&pcr_digest->buffer[0], "e_info->attest.attested.quote.pcrDigest.buffer[0], - pcr_digest->size) != 0) { - goto_error(r, TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED, - "The digest computed from event list does not match the attest.", - error_cleanup); - } error_cleanup: if (cryptoContext) ifapi_crypto_hash_abort(&cryptoContext); - ifapi_cleanup_event(&event); return r; } diff --git a/src/tss2-fapi/ifapi_helpers.h b/src/tss2-fapi/ifapi_helpers.h index 3a9244183..ef4482985 100644 --- a/src/tss2-fapi/ifapi_helpers.h +++ b/src/tss2-fapi/ifapi_helpers.h @@ -139,6 +139,7 @@ TSS2_RC ifapi_compute_quote_info( IFAPI_OBJECT *sig_key_object, TPM2B_ATTEST *tpm_quoted, + FAPI_QUOTE_INFO *fapi_quote_info, char **quoteInfo); TSS2_RC @@ -173,16 +174,17 @@ ifapi_filter_pcr_selection_by_index( const TPM2_HANDLE *pcr_index, size_t pcr_count); -TSS2_RC ifapi_calculate_pcrs( +TSS2_RC +ifapi_calculate_pcrs( json_object *jso_event_list, const TPML_PCR_SELECTION *pcr_selection, - IFAPI_PCR_REG pcrs[], - size_t *n_pcrs); + TPMI_ALG_HASH pcr_digest_hash_alg, + const TPM2B_DIGEST *quote_digest, + IFAPI_PCR_REG *pcrs); TSS2_RC ifapi_calculate_pcr_digest( json_object *jso_event_list, - const FAPI_QUOTE_INFO *quote_info, - TPM2B_DIGEST *pcr_digest); + const FAPI_QUOTE_INFO *quote_info); TSS2_RC ifapi_compute_policy_digest( diff --git a/test/unit/fapi-eventlog.c b/test/unit/fapi-eventlog.c index 1063eecd6..dba463ade 100644 --- a/test/unit/fapi-eventlog.c +++ b/test/unit/fapi-eventlog.c @@ -138,7 +138,6 @@ check_eventlog_pcr0(const char *file, uint32_t *pcr_list, size_t pcr_list_size, uint8_t *eventlog; size_t size; json_object *json_event_list = NULL; - size_t n_pcrs; IFAPI_PCR_REG pcrs[TPM2_MAX_PCRS]; TPML_PCR_SELECTION pcr_selection = @@ -166,7 +165,7 @@ check_eventlog_pcr0(const char *file, uint32_t *pcr_list, size_t pcr_list_size, r = ifapi_get_tcg_firmware_event_list(file, pcr_list, pcr_list_size, &json_event_list); assert_int_equal (r, TSS2_RC_SUCCESS); - r = ifapi_calculate_pcrs(json_event_list, &pcr_selection, &pcrs[0], &n_pcrs); + r = ifapi_calculate_pcrs(json_event_list, &pcr_selection, TPM2_ALG_SHA1, NULL, &pcrs[0]); assert_int_equal (r, TSS2_RC_SUCCESS); /* Compare with the pcr0 value got from system with HCRTM events */