From 8aeeb8bb9c280de69a4d7ae46894304aaad73870 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 21 Feb 2023 16:31:59 -0500 Subject: [PATCH] tpm2: add tpm2_pcr_read() (cherry picked from commit c57d8bc8717110ff343358be9fdfea1472fc360f) Related: RHEL-16182 --- src/shared/tpm2-util.c | 129 ++++++++++++++++++++++++++++------------- 1 file changed, 89 insertions(+), 40 deletions(-) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index cf62524e34..722ae3ca9c 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -744,6 +744,14 @@ size_t tpm2_tpml_pcr_selection_weight(const TPML_PCR_SELECTION *l) { return weight; } +static void tpm2_log_debug_tpml_pcr_selection(const TPML_PCR_SELECTION *l, const char *msg) { + if (!DEBUG_LOGGING || !l) + return; + + _cleanup_free_ char *s = tpm2_tpml_pcr_selection_to_string(l); + log_debug("%s: %s", msg ?: "PCR selection", strna(s)); +} + static void tpm2_log_debug_buffer(const void *buffer, size_t size, const char *msg) { if (!DEBUG_LOGGING || !buffer || size == 0) return; @@ -792,26 +800,82 @@ static int tpm2_get_policy_digest( return 0; } -static unsigned find_nth_bit(uint32_t mask, unsigned n) { - uint32_t bit = 1; +static int tpm2_pcr_read( + Tpm2Context *c, + const TPML_PCR_SELECTION *pcr_selection, + TPML_PCR_SELECTION *ret_pcr_selection, + TPM2B_DIGEST **ret_pcr_values, + size_t *ret_pcr_values_size) { + + _cleanup_free_ TPM2B_DIGEST *pcr_values = NULL; + TPML_PCR_SELECTION remaining, total_read = {}; + size_t pcr_values_size = 0; + TSS2_RC rc; - assert(n < 32); + assert(c); + assert(pcr_selection); - /* Returns the bit index of the nth set bit, e.g. mask=0b101001, n=3 → 5 */ + remaining = *pcr_selection; + while (!tpm2_tpml_pcr_selection_is_empty(&remaining)) { + _cleanup_(Esys_Freep) TPML_PCR_SELECTION *current_read = NULL; + _cleanup_(Esys_Freep) TPML_DIGEST *current_values = NULL; - for (unsigned i = 0; i < sizeof(mask)*8; i++) { + tpm2_log_debug_tpml_pcr_selection(&remaining, "Reading PCR selection"); - if (bit & mask) { - if (n == 0) - return i; + /* Unfortunately, PCR_Read will not return more than 8 values. */ + rc = sym_Esys_PCR_Read( + c->esys_context, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + &remaining, + NULL, + ¤t_read, + ¤t_values); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to read TPM2 PCRs: %s", sym_Tss2_RC_Decode(rc)); - n--; + if (tpm2_tpml_pcr_selection_is_empty(current_read)) { + log_warning("TPM2 refused to read possibly unimplemented PCRs, ignoring."); + break; } - bit <<= 1; + tpm2_tpml_pcr_selection_sub(&remaining, current_read); + tpm2_tpml_pcr_selection_add(&total_read, current_read); + + if (!GREEDY_REALLOC(pcr_values, pcr_values_size + current_values->count)) + return log_oom(); + + memcpy_safe(&pcr_values[pcr_values_size], current_values->digests, + current_values->count * sizeof(TPM2B_DIGEST)); + pcr_values_size += current_values->count; + + if (DEBUG_LOGGING) { + unsigned i = 0; + FOREACH_PCR_IN_TPML_PCR_SELECTION(pcr, s, current_read) { + assert(i < current_values->count); + + TPM2B_DIGEST *d = ¤t_values->digests[i]; + i++; + + TPML_PCR_SELECTION l; + tpm2_tpml_pcr_selection_from_mask(INDEX_TO_MASK(uint32_t, pcr), s->hash, &l); + + _cleanup_free_ char *desc = tpm2_tpml_pcr_selection_to_string(&l); + tpm2_log_debug_digest(d, strna(desc)); + } + } } - return UINT_MAX; + if (ret_pcr_selection) + *ret_pcr_selection = total_read; + if (ret_pcr_values) + *ret_pcr_values = TAKE_PTR(pcr_values); + if (ret_pcr_values_size) + *ret_pcr_values_size = pcr_values_size; + + return 0; } static int tpm2_pcr_mask_good( @@ -819,10 +883,10 @@ static int tpm2_pcr_mask_good( TPMI_ALG_HASH bank, uint32_t mask) { - _cleanup_(Esys_Freep) TPML_DIGEST *pcr_values = NULL; + _cleanup_free_ TPM2B_DIGEST *pcr_values = NULL; TPML_PCR_SELECTION selection; - bool good = false; - TSS2_RC rc; + size_t pcr_values_size = 0; + int r; assert(c); @@ -832,38 +896,23 @@ static int tpm2_pcr_mask_good( tpm2_tpml_pcr_selection_from_mask(mask, bank, &selection); - rc = sym_Esys_PCR_Read( - c->esys_context, - ESYS_TR_NONE, - ESYS_TR_NONE, - ESYS_TR_NONE, - &selection, - NULL, - NULL, - &pcr_values); - if (rc != TSS2_RC_SUCCESS) - return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to read TPM2 PCRs: %s", sym_Tss2_RC_Decode(rc)); + r = tpm2_pcr_read(c, &selection, &selection, &pcr_values, &pcr_values_size); + if (r < 0) + return r; /* If at least one of the selected PCR values is something other than all 0x00 or all 0xFF we are happy. */ - for (unsigned i = 0; i < pcr_values->count; i++) { - if (DEBUG_LOGGING) { - _cleanup_free_ char *h = NULL; - unsigned j; + unsigned i = 0; + FOREACH_PCR_IN_TPML_PCR_SELECTION(pcr, s, &selection) { + assert(i < pcr_values_size); - h = hexmem(pcr_values->digests[i].buffer, pcr_values->digests[i].size); - j = find_nth_bit(mask, i); - assert(j != UINT_MAX); - - log_debug("PCR %u value: %s", j, strna(h)); - } + if (!memeqbyte(0x00, pcr_values[i].buffer, pcr_values[i].size) && + !memeqbyte(0xFF, pcr_values[i].buffer, pcr_values[i].size)) + return true; - if (!memeqbyte(0x00, pcr_values->digests[i].buffer, pcr_values->digests[i].size) && - !memeqbyte(0xFF, pcr_values->digests[i].buffer, pcr_values->digests[i].size)) - good = true; + i++; } - return good; + return false; } static int tpm2_bank_has24(const TPMS_PCR_SELECTION *selection) {