You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
7.4 KiB
190 lines
7.4 KiB
8 months ago
|
From 8aeeb8bb9c280de69a4d7ae46894304aaad73870 Mon Sep 17 00:00:00 2001
|
||
|
From: Dan Streetman <ddstreet@ieee.org>
|
||
|
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) {
|