Skip to content

Commit

Permalink
FAPI: Fix synchronization eventlog.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
JuergenReppSIT committed Mar 20, 2024
1 parent f59d451 commit e8b016c
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 67 deletions.
2 changes: 1 addition & 1 deletion src/tss2-fapi/api/Fapi_PcrRead.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 4 additions & 1 deletion src/tss2-fapi/api/Fapi_Quote.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions src/tss2-fapi/api/Fapi_VerifyQuote.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
7 changes: 0 additions & 7 deletions src/tss2-fapi/fapi_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
11 changes: 9 additions & 2 deletions src/tss2-fapi/ifapi_eventlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions src/tss2-fapi/ifapi_eventlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);

Expand Down
108 changes: 61 additions & 47 deletions src/tss2-fapi/ifapi_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -1745,24 +1747,24 @@ 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 *)
&tpm_quoted->attestationData[0],
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. */
Expand Down Expand Up @@ -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
Expand All @@ -2122,32 +2125,32 @@ 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++) {
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;
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;
}
}
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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], &quote_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;
}
}

Expand Down Expand Up @@ -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 = &quote_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:
Expand All @@ -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,
&quote_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], &quote_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;
}

Expand Down
12 changes: 7 additions & 5 deletions src/tss2-fapi/ifapi_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
3 changes: 1 addition & 2 deletions test/unit/fapi-eventlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit e8b016c

Please sign in to comment.