diff --git a/configs/config.emulation_qemu_x86_q35_uefi b/configs/config.emulation_qemu_x86_q35_uefi index 0be46de9698..7c3693ea0f1 100644 --- a/configs/config.emulation_qemu_x86_q35_uefi +++ b/configs/config.emulation_qemu_x86_q35_uefi @@ -14,7 +14,6 @@ CONFIG_DRIVERS_EFI_MAIN_FW_LSV=0x00020101 CONFIG_DRIVERS_EFI_UPDATE_CAPSULES=y CONFIG_TPM1=y CONFIG_TPM2=y -CONFIG_TPM_HASH_SHA256=y CONFIG_DEFAULT_CONSOLE_LOGLEVEL_0=y # CONFIG_CONSOLE_USE_LOGLEVEL_PREFIX is not set # CONFIG_CONSOLE_USE_ANSI_ESCAPES is not set diff --git a/configs/config.emulation_qemu_x86_q35_uefi_all_menus b/configs/config.emulation_qemu_x86_q35_uefi_all_menus index a720d7970c4..76261c43ef5 100644 --- a/configs/config.emulation_qemu_x86_q35_uefi_all_menus +++ b/configs/config.emulation_qemu_x86_q35_uefi_all_menus @@ -9,7 +9,6 @@ CONFIG_UDK_202005_BINDING=y CONFIG_DRIVERS_EFI_VARIABLE_STORE=y CONFIG_TPM1=y CONFIG_TPM2=y -CONFIG_TPM_HASH_SHA256=y CONFIG_DEFAULT_CONSOLE_LOGLEVEL_0=y # CONFIG_CONSOLE_USE_LOGLEVEL_PREFIX is not set # CONFIG_CONSOLE_USE_ANSI_ESCAPES is not set diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index df34594a53c..f63770e78f5 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -186,21 +186,12 @@ static bool cbfs_file_hash_mismatch(const void *buffer, size_t size, } if (CONFIG(TPM_MEASURED_BOOT) && !ENV_SMM) { - struct vb2_hash calculated_hash; - - /* No need to re-hash file if we already have it from verification. */ - if (!hash || hash->algo != tpm_log_alg()) { - if (vb2_hash_calculate(vboot_hwcrypto_allowed(), buffer, size, - tpm_log_alg(), &calculated_hash)) - hash = NULL; - else - hash = &calculated_hash; - } - - if (!hash || - tspi_cbfs_measurement(mdata->h.filename, be32toh(mdata->h.type), hash)) - ERROR("failed to measure '%s' into TPM log\n", mdata->h.filename); - /* We intentionally continue to boot on measurement errors. */ + tpm_result_t rc = tspi_cbfs_measurement(mdata->h.filename, buffer, size, + be32toh(mdata->h.type), hash); + if (rc != TPM_SUCCESS) + ERROR("failed to measure '%s' into TPM log, error %#x\n", + mdata->h.filename, rc); + /* We intentionally continue to boot on measurement errors. */ } return false; diff --git a/src/security/intel/cbnt/measurement.c b/src/security/intel/cbnt/measurement.c index 2e9aa956dc8..8a34f5f8581 100644 --- a/src/security/intel/cbnt/measurement.c +++ b/src/security/intel/cbnt/measurement.c @@ -38,6 +38,12 @@ #define KM_HASH_USAGE_SDEV (1 << 3) #define KM_HASH_USAGE_PFR_CPLD (1 << 4) +/* + * Allow for 4 8192-bit digests in PCR-0 measurements which is an unlikely situation, so this + * buffer should be enough to not run out of space (data measured into PCR-7 is smaller). + */ +#define MAX_DATA_SIZE (sizeof(uint64_t) + sizeof(uint16_t) + 4 * KiB) + /* * SRTM version is an upper-case hex dump of ACM's "Date" (offset 20) and "TXT SVN" (offset 28) * fields as a NUL-terminated UTF16 string. @@ -471,7 +477,23 @@ static enum cb_err fill_pcr7_km_fields(struct obuf *ob) return CB_SUCCESS; } -static enum cb_err copy_ibb_hash(struct obuf *ob, uint16_t tpm2_alg) +static const struct hash_struct *find_ibb_digest(const struct bpm_ibbs *ibbs, + enum vb2_hash_algorithm alg) +{ + unsigned int i; + const struct hash_struct *ibb_hash = ibbs->digest_list.hashes; + uint16_t tpm2_alg = tpm2_alg_from_vb2_hash(alg); + for (i = 0; i < ibbs->digest_list.count; ++i) { + if (ibb_hash->alg == tpm2_alg) + return ibb_hash; + + ibb_hash = (const void *)&ibb_hash->data[ibb_hash->size]; + } + + return NULL; +} + +static enum cb_err copy_ibb_hash(struct obuf *ob, enum vb2_hash_algorithm alg) { size_t bpm_len; const struct bpm_header *bpm = find_in_fit(FIT_ENTRY_TYPE_BPM, &bpm_len); @@ -480,16 +502,9 @@ static enum cb_err copy_ibb_hash(struct obuf *ob, uint16_t tpm2_alg) return CB_ERR; } - unsigned int i; const struct bpm_ibbs *ibbs = (const void *)bpm->se_element; - const struct hash_struct *ibb_hash = ibbs->digest_list.hashes; - for (i = 0; i < ibbs->digest_list.count; ++i) { - if (ibb_hash->alg == tpm2_alg) - break; - ibb_hash = (const void *)&ibb_hash->data[ibb_hash->size]; - } - - if (i == ibbs->digest_list.count) { + const struct hash_struct *ibb_hash = find_ibb_digest(ibbs, alg); + if (ibb_hash == NULL) { printk(BIOS_ERR, "CBnT: failed to find matching IBB digest\n"); return CB_ERR; } @@ -503,7 +518,7 @@ static enum cb_err copy_ibb_hash(struct obuf *ob, uint16_t tpm2_alg) return CB_SUCCESS; } -static enum cb_err copy_bpm_signature(struct obuf *ob) +static enum cb_err copy_bpm_signature(struct obuf *ob, enum vb2_hash_algorithm alg) { size_t bpm_len; const struct bpm_header *bpm = find_in_fit(FIT_ENTRY_TYPE_BPM, &bpm_len); @@ -522,7 +537,7 @@ static enum cb_err copy_bpm_signature(struct obuf *ob) return CB_ERR; } - return copy_ibb_hash(ob, tpm2_alg_from_vb2_hash(tpm_log_alg())); + return copy_ibb_hash(ob, alg); } /* @@ -539,9 +554,9 @@ static enum cb_err copy_bpm_signature(struct obuf *ob) * * Applies only for TPM2.0. * - * Returns true and initializes *hash on success. + * Returns true on success. */ -static bool make_pcr7_hash(struct obuf *ob, struct vb2_hash *hash) +static bool make_pcr7_data(struct obuf *ob) { /* * ACM.KeyHash[32] @@ -560,13 +575,6 @@ static bool make_pcr7_hash(struct obuf *ob, struct vb2_hash *hash) return false; } - size_t size; - const void *data = obuf_contents(ob, &size); - if (vb2_hash_calculate(vboot_hwcrypto_allowed(), data, size, tpm_log_alg(), hash)) { - printk(BIOS_ERR, "CBnT: failed to hash PCR-7 measurement data\n"); - return false; - } - return true; } @@ -587,15 +595,8 @@ int intel_cbnt_get_locality(void) return biosacm_sts.status.tpm_startup_locality == 0 ? 3 : 0; } -static enum cb_err cap_pcrs(union cbnt_biosacm_policy biosacm_sts) +static enum cb_err cap_pcrs_for_alg(enum vb2_hash_algorithm alg) { - /* TODO: when adding support of all active PCR banks to Measured Boot, implement - capping those PCRs for which there is no corresponding IBB digest in BPM. */ - - /* Nothing to do if there was no TPM failure. */ - if (biosacm_sts.status.tpm_success) - return CB_SUCCESS; - size_t bpm_len; const struct bpm_header *bpm = find_in_fit(FIT_ENTRY_TYPE_BPM, &bpm_len); if (bpm == NULL) { @@ -611,20 +612,59 @@ static enum cb_err cap_pcrs(union cbnt_biosacm_policy biosacm_sts) const uint32_t separator = 0x00000001; struct vb2_hash hash; - if (vb2_hash_calculate(vboot_hwcrypto_allowed(), &separator, sizeof(separator), - tpm_log_alg(), &hash)) { + if (vb2_hash_calculate(vboot_hwcrypto_allowed(), &separator, sizeof(separator), alg, + &hash)) { printk(BIOS_ERR, "CBnT: failed to hash PCR separator\n"); return CB_ERR; } + const struct tpm_digest cap_digests[] = { + { .hash_type = hash.algo, .hash = hash.raw }, + { .hash_type = VB2_HASH_INVALID } + }; + for (int pcr = 0; pcr < 8; pcr++) { - tpm_log_add_table_entry("CBnT hit TPM failure during boot", pcr, hash.algo, - hash.raw, vb2_digest_size(hash.algo)); + tpm_log_add_table_entry("CBnT hit TPM failure during boot", pcr, cap_digests); printk(BIOS_INFO, "CBnT: capped PCR-%d\n", pcr); } return CB_SUCCESS; } +static enum cb_err cap_pcrs(union cbnt_biosacm_policy biosacm_sts) +{ + size_t bpm_len; + const struct bpm_header *bpm = find_in_fit(FIT_ENTRY_TYPE_BPM, &bpm_len); + if (bpm == NULL) { + printk(BIOS_ERR, "CBnT: failed to find BPM\n"); + return CB_ERR; + } + + const struct bpm_ibbs *ibbs = (const void *)bpm->se_element; + + int i; + for (i = 0; i < ENABLED_TPM_ALGS_NUM; ++i) { + enum vb2_hash_algorithm alg = enabled_tpm_algs[i]; + if (!tpm_log_alg_active(alg)) + continue; + + /* + * If there was a TPM failure, cap all active banks. Otherwise, cap those + * active banks for which there is no corresponding IBB digests in BPM. + */ + if (biosacm_sts.status.tpm_success && find_ibb_digest(ibbs, alg) != NULL) + continue; + + enum cb_err err = cap_pcrs_for_alg(alg); + if (err != CB_SUCCESS) { + printk(BIOS_WARNING, "CBnT: failed to cap %s bank\n", + vb2_get_hash_algorithm_name(alg)); + return err; + } + } + + return CB_SUCCESS; +} + static char hex_digit(int nibble) { if (nibble < 10) @@ -632,197 +672,251 @@ static char hex_digit(int nibble) return 'A' + nibble - 10; } -void intel_cbnt_inject_ibg_measurements(void) +static void measure_intel_tgl_style(uint64_t biosacm_policy, bool auth_measure) { - const union cbnt_biosacm_policy biosacm_sts = { - .raw = read64p(CBNT_BIOSACM_POLICY_STS), - }; + uint8_t data[MAX_DATA_SIZE]; + struct obuf data_ob; + obuf_init(&data_ob, data, sizeof(data)); - /* Do nothing if BootGuard wasn't involved in the boot process. */ - if (biosacm_sts.status.scrtm_status == 0) + /* + * Making and hashing PCR-0 data. + * + * Pseudo-code of the data to be measured into PCR-0 for TigerLake and newer + * (older hardware isn't supported yet): + * + * struct { + * uint64_t ACM_POLICY_STATUS; + * uint16_t ACM.Header.SVN; + * uint8_t ACM.Signature[ACM signature size]; + * uint8_t KM.Signature[KM signature size]; + * uint8_t BPM.Signature[BPM signature size]; + * uint8_t IBB.Digest[IBB digest size]; + * } PCR0_DATA; + */ + + /* ACM_POLICY_STATUS (won't run out of space on this one) */ + (void)obuf_write_le64(&data_ob, biosacm_policy); + + if (fill_pcr0_acm_fields(&data_ob) != CB_SUCCESS) { + printk(BIOS_ERR, "CBnT: failed to fill ACM fields of PCR-0 measurement data\n"); return; + } - /* Do nothing if BootGuard doesn't measure anything. */ - if (!(biosacm_sts.status.bp & CBNT_BP_TYPE_M)) + if (copy_km_signature(&data_ob) != CB_SUCCESS) { + printk(BIOS_ERR, "CBnT: failed to copy KM signature for PCR-0 measurement\n"); return; + } - if (cap_pcrs(biosacm_sts) != CB_SUCCESS) { - printk(BIOS_ERR, "CBnT: failed to cap PCRs\n"); + int i, j; + struct tpm_digests pcr0_digests; + for (i = 0, j = 0; i < ENABLED_TPM_ALGS_NUM; ++i) { + enum vb2_hash_algorithm alg = enabled_tpm_algs[i]; + if (!tpm_log_alg_active(alg)) + continue; + + struct obuf local_ob = data_ob; + if (copy_bpm_signature(&local_ob, alg) != CB_SUCCESS) { + printk(BIOS_ERR, + "CBnT: failed to copy BPM signature for PCR-0 measurement\n"); + return; + } + + if (vb2_hash_calculate(vboot_hwcrypto_allowed(), data, + obuf_nr_written(&data_ob), alg, + &pcr0_digests.hashes[i])) { + printk(BIOS_ERR, "CBnT: failed to hash PCR-0 measurement data\n"); + return; + } + + pcr0_digests.values[j].hash_type = alg; + pcr0_digests.values[j].hash = pcr0_digests.hashes[i].raw; + ++j; + } + + pcr0_digests.values[j].hash_type = VB2_HASH_INVALID; + + /* Per BWG this should be logged with EV_S_CRTM_CONTENTS type. */ + tpm_log_add_table_entry(CBNT_EVENT_LOG_MESSAGE, 0, pcr0_digests.values); + + /* Optionally making and hashing PCR-7 data (not supported since MTL). */ + if (!auth_measure) + return; + + struct tpm_digests pcr7_digests; + + /* Reuse the first 2 fields of PCR-0 data which are identical in both cases. */ + obuf_init(&data_ob, data, sizeof(data)); + (void)obuf_oob_fill(&data_ob, sizeof(uint64_t) + sizeof(uint16_t)); + + if (!make_pcr7_data(&data_ob)) { + printk(BIOS_ERR, "CBnT: failed to build PCR-7 measurement data\n"); return; } - /* cap_pcrs() must have logged that PCRs were capped, nothing else to do on TPM - error. */ - if (!biosacm_sts.status.tpm_success) { - printk(BIOS_ERR, "CBnT: TPM failure detected\n"); + if (!tpm_make_digests(data, obuf_nr_written(&data_ob), NULL, &pcr7_digests)) { + printk(BIOS_ERR, "CBnT: failed to hash PCR-7 measurement data\n"); return; } - bool conventional_measurements; - bool auth_measure; - uint64_t biosacm_sts_mask; - if (get_flags(&conventional_measurements, &auth_measure, &biosacm_sts_mask) != - CB_SUCCESS) { - printk(BIOS_ERR, "CBnT: failed to obtain IBBS flags from BPM\n"); + /* Per BWG this should be logged with EV_EFI_VARIABLE_DRIVER_CONFIG type + and event name should be a Unicode string. */ + tpm_log_add_table_entry(CBNT_EVENT_LOG_MESSAGE, 7, pcr7_digests.values); + printk(BIOS_INFO, "CBnT: reconstructed PCR-7 measurement\n"); +} + +static void measure_tcg_style(uint64_t biosacm_policy) +{ + size_t acm_len; + const struct acm_header_v3 *acm = find_in_fit(FIT_ENTRY_TYPE_SACM, &acm_len); + if (acm == NULL) { + printk(BIOS_ERR, "CBnT: failed to find SACM\n"); return; } - /* - * Allow for 4 8192-bit digests in PCR-0 measurements which is an unlikely situation, - * so this buffer should be enough to not run out of space (data measured into PCR-7 is - * smaller). - */ - uint8_t data[sizeof(uint64_t) + sizeof(uint16_t) + 4 * KiB]; - struct obuf data_ob; - obuf_init(&data_ob, data, sizeof(data)); + uint8_t crtm_version[6]; + memcpy(&crtm_version[0], &acm->date, 4); + memcpy(&crtm_version[4], &acm->txt_svn, 2); - if (conventional_measurements) { - /* - * Making and hashing PCR-0 data. - * - * Pseudo-code of the data to be measured into PCR-0 for TigerLake and newer - * (older hardware isn't supported yet): - * - * struct { - * uint64_t ACM_POLICY_STATUS; - * uint16_t ACM.Header.SVN; - * uint8_t ACM.Signature[ACM signature size]; - * uint8_t KM.Signature[KM signature size]; - * uint8_t BPM.Signature[BPM signature size]; - * uint8_t IBB.Digest[IBB digest size]; - * } PCR0_DATA; - */ + char crtm_version_str[SCRTM_VERSION_LENGTH] = {0}; + uint16_t crtm_version_utf16[SCRTM_VERSION_LENGTH] = {0}; + for (int i = 0; i < sizeof(crtm_version); ++i) { + crtm_version_str[i*2 + 0] = hex_digit(crtm_version[i] >> 4); + crtm_version_str[i*2 + 1] = hex_digit(crtm_version[i] & 0xf); - /* ACM_POLICY_STATUS (won't run out of space on this one) */ - (void)obuf_write_le64(&data_ob, biosacm_sts.raw & biosacm_sts_mask); + crtm_version_utf16[i*2 + 0] = crtm_version_str[i*2 + 0]; + crtm_version_utf16[i*2 + 1] = crtm_version_str[i*2 + 1]; + } - if (fill_pcr0_acm_fields(&data_ob) != CB_SUCCESS) { - printk(BIOS_ERR, - "CBnT: failed to fill ACM fields of PCR-0 measurement data\n"); - return; - } + struct tpm_digests crtm_digests; + if (!tpm_make_digests(crtm_version_utf16, sizeof(crtm_version_utf16), NULL, + &crtm_digests)) { + printk(BIOS_ERR, "CBnT: failed to hash CRTM version\n"); + return; + } + /* Per BWG this should be logged with EV_S_CRTM_VERSION type. */ + tpm_log_add_table_entry(crtm_version_str, 0, crtm_digests.values); - if (copy_km_signature(&data_ob) != CB_SUCCESS) { - printk(BIOS_ERR, - "CBnT: failed to copy KM signature for PCR-0 measurement\n"); + int i, j; + + struct tpm_digests post_code_digests; + for (i = 0, j = 0; i < ENABLED_TPM_ALGS_NUM; ++i) { + enum vb2_hash_algorithm alg = enabled_tpm_algs[i]; + if (!tpm_log_alg_active(alg)) + continue; + + struct obuf data_ob; + obuf_init(&data_ob, post_code_digests.hashes[j].sha512, + sizeof(post_code_digests.hashes[j].sha512)); + + if (copy_ibb_hash(&data_ob, alg) != CB_SUCCESS) { + printk(BIOS_ERR, "CBnT: failed to obtain IBB digest\n"); return; } - if (copy_bpm_signature(&data_ob) != CB_SUCCESS) { + ++j; + } + + post_code_digests.values[j].hash_type = VB2_HASH_INVALID; + + /* Per BWG this should be logged with EV_POST_CODE type. */ + tpm_log_add_table_entry("Boot Guard Measured IBB", 0, post_code_digests.values); + + /* + * struct { + * uint64_t ACM_POLICY_STATUS; + * uint8_t KM.Signature[KM signature size]; + * uint8_t BPM.Signature[BPM signature size]; + * } POLICY_DATA; + */ + uint8_t data[MAX_DATA_SIZE]; + struct obuf data_ob; + obuf_init(&data_ob, data, sizeof(data)); + + /* ACM_POLICY_STATUS (won't run out of space on this one) */ + (void)obuf_write_le64(&data_ob, biosacm_policy); + if (copy_acm_signature(&data_ob) != CB_SUCCESS) { + printk(BIOS_ERR, "CBnT: failed to copy ACM signature\n"); + return; + } + if (copy_km_signature(&data_ob) != CB_SUCCESS) { + printk(BIOS_ERR, "CBnT: failed to copy KM signature\n"); + return; + } + + struct tpm_digests policy_digests; + for (i = 0, j = 0; i < ENABLED_TPM_ALGS_NUM; ++i) { + enum vb2_hash_algorithm alg = enabled_tpm_algs[i]; + if (!tpm_log_alg_active(alg)) + continue; + + struct obuf local_ob = data_ob; + if (copy_bpm_signature(&local_ob, alg) != CB_SUCCESS) { printk(BIOS_ERR, "CBnT: failed to copy BPM signature for PCR-0 measurement\n"); return; } - struct vb2_hash hash; if (vb2_hash_calculate(vboot_hwcrypto_allowed(), data, - obuf_nr_written(&data_ob), tpm_log_alg(), &hash)) { + obuf_nr_written(&data_ob), alg, + &policy_digests.hashes[i])) { printk(BIOS_ERR, "CBnT: failed to hash PCR-0 measurement data\n"); return; } - /* Per BWG this should be logged with EV_S_CRTM_CONTENTS type. */ - tpm_log_add_table_entry(CBNT_EVENT_LOG_MESSAGE, 0, hash.algo, hash.raw, - vb2_digest_size(hash.algo)); - - /* Optionally making and hashing PCR-7 data (not supported since MTL). */ - if (auth_measure) { - /* Reuse the first 2 fields of PCR-0 data which are identical in both - cases. */ - obuf_init(&data_ob, data, sizeof(data)); - (void)obuf_oob_fill(&data_ob, sizeof(uint64_t) + sizeof(uint16_t)); - - if (!make_pcr7_hash(&data_ob, &hash)) { - printk(BIOS_ERR, - "CBnT: failed to build and hash PCR-7 measurement data\n"); - return; - } - - /* Per BWG this should be logged with EV_EFI_VARIABLE_DRIVER_CONFIG type - and event name should be a Unicode string. */ - tpm_log_add_table_entry(CBNT_EVENT_LOG_MESSAGE, 7, hash.algo, hash.raw, - vb2_digest_size(hash.algo)); - printk(BIOS_INFO, "CBnT: reconstructed PCR-7 measurement\n"); - } + policy_digests.values[j].hash_type = alg; + policy_digests.values[j].hash = policy_digests.hashes[i].raw; + ++j; + } - } else { - size_t acm_len; - const struct acm_header_v3 *acm = find_in_fit(FIT_ENTRY_TYPE_SACM, &acm_len); - if (acm == NULL) { - printk(BIOS_ERR, "CBnT: failed to find SACM\n"); - return; - } + policy_digests.values[j].hash_type = VB2_HASH_INVALID; - uint8_t crtm_version[6]; - memcpy(&crtm_version[0], &acm->date, 4); - memcpy(&crtm_version[4], &acm->txt_svn, 2); + /* Per BWG this should be logged with EV_POST_CODE type. */ + if (tpm_extend_pcr(0, policy_digests.values, + "BIOS Measured Boot Guard Policy") != TPM_SUCCESS) + printk(BIOS_ERR, "CBnT: failed to extend POLICY_DATA\n"); +} - char crtm_version_str[SCRTM_VERSION_LENGTH] = {0}; - uint16_t crtm_version_utf16[SCRTM_VERSION_LENGTH] = {0}; - for (int i = 0; i < sizeof(crtm_version); ++i) { - crtm_version_str[i*2 + 0] = hex_digit(crtm_version[i] >> 4); - crtm_version_str[i*2 + 1] = hex_digit(crtm_version[i] & 0xf); +void intel_cbnt_inject_ibg_measurements(void) +{ + const union cbnt_biosacm_policy biosacm_sts = { + .raw = read64p(CBNT_BIOSACM_POLICY_STS), + }; - crtm_version_utf16[i*2 + 0] = crtm_version_str[i*2 + 0]; - crtm_version_utf16[i*2 + 1] = crtm_version_str[i*2 + 1]; - } + /* Do nothing if BootGuard wasn't involved in the boot process. */ + if (biosacm_sts.status.scrtm_status == 0) + return; - struct vb2_hash hash; - if (vb2_hash_calculate(vboot_hwcrypto_allowed(), crtm_version_utf16, - sizeof(crtm_version_utf16), tpm_log_alg(), &hash)) { - printk(BIOS_ERR, "CBnT: failed to hash CRTM version\n"); - return; - } - /* Per BWG this should be logged with EV_S_CRTM_VERSION type. */ - tpm_log_add_table_entry(crtm_version_str, 0, hash.algo, hash.raw, - vb2_digest_size(hash.algo)); + /* Do nothing if BootGuard doesn't measure anything. */ + if (!(biosacm_sts.status.bp & CBNT_BP_TYPE_M)) + return; - if (copy_ibb_hash(&data_ob, tpm2_alg_from_vb2_hash(tpm_log_alg())) != - CB_SUCCESS) { - printk(BIOS_ERR, "CBnT: failed to obtain IBB digest\n"); - return; - } - /* Per BWG this should be logged with EV_POST_CODE type. */ - tpm_log_add_table_entry("Boot Guard Measured IBB", 0, tpm_log_alg(), data, - obuf_nr_written(&data_ob)); + if (cap_pcrs(biosacm_sts) != CB_SUCCESS) { + printk(BIOS_ERR, "CBnT: failed to cap PCRs\n"); + return; + } - /* - * struct { - * uint64_t ACM_POLICY_STATUS; - * uint8_t KM.Signature[KM signature size]; - * uint8_t BPM.Signature[BPM signature size]; - * } POLICY_DATA; - */ - obuf_init(&data_ob, data, sizeof(data)); + /* cap_pcrs() must have logged that PCRs were capped, nothing else to do on TPM + error. */ + if (!biosacm_sts.status.tpm_success) { + printk(BIOS_ERR, "CBnT: TPM failure detected\n"); + return; + } - /* ACM_POLICY_STATUS (won't run out of space on this one) */ - (void)obuf_write_le64(&data_ob, biosacm_sts.raw & biosacm_sts_mask); - if (copy_acm_signature(&data_ob) != CB_SUCCESS) { - printk(BIOS_ERR, "CBnT: failed to copy ACM signature\n"); - return; - } - if (copy_km_signature(&data_ob) != CB_SUCCESS) { - printk(BIOS_ERR, "CBnT: failed to copy KM signature\n"); - return; - } - if (copy_bpm_signature(&data_ob) != CB_SUCCESS) { - printk(BIOS_ERR, - "CBnT: failed to copy BPM signature for PCR-0 measurement\n"); - return; - } - if (vb2_hash_calculate(vboot_hwcrypto_allowed(), data, - obuf_nr_written(&data_ob), tpm_log_alg(), &hash)) { - printk(BIOS_ERR, "CBnT: failed to hash POLICY_DATA\n"); - return; - } - /* Per BWG this should be logged with EV_POST_CODE type. */ - if (tpm_extend_pcr(0, hash.algo, hash.raw, vb2_digest_size(hash.algo), - "BIOS Measured Boot Guard Policy") != TPM_SUCCESS) { - printk(BIOS_ERR, "CBnT: failed to extend POLICY_DATA\n"); - return; - } + bool conventional_measurements; + bool auth_measure; + uint64_t biosacm_sts_mask; + if (get_flags(&conventional_measurements, &auth_measure, &biosacm_sts_mask) != + CB_SUCCESS) { + printk(BIOS_ERR, "CBnT: failed to obtain IBBS flags from BPM\n"); + return; } + uint64_t biosacm_policy = biosacm_sts.raw & biosacm_sts_mask; + if (conventional_measurements) + measure_intel_tgl_style(biosacm_policy, auth_measure); + else + measure_tcg_style(biosacm_policy); + /* * BWG suggests to Perform reconstruction at this point, but we are likely to continue * the boot anyway as Measured Boot failures generally aren't fatal and incorrect hash diff --git a/src/security/tpm/Kconfig b/src/security/tpm/Kconfig index 3ffbb8a8337..3e2a736e287 100644 --- a/src/security/tpm/Kconfig +++ b/src/security/tpm/Kconfig @@ -108,22 +108,20 @@ config TPM_LOG_TPM2 endchoice -choice - prompt "TPM2 hashing algorithm" - depends on TPM_MEASURED_BOOT && (TPM_LOG_TCG || TPM_LOG_TPM2) - default TPM_HASH_SHA1 if TPM1 - default TPM_HASH_SHA256 if TPM2 +if TPM_MEASURED_BOOT && (TPM_LOG_TCG || TPM_LOG_TPM2) config TPM_HASH_SHA1 - bool "SHA1" + bool "SHA1 PCR hashing" + default y if TPM1 || TPM2 config TPM_HASH_SHA256 - bool "SHA256" + bool "SHA256 PCR hashing" + default y if TPM2 config TPM_HASH_SHA384 - bool "SHA384" + bool "SHA384 PCR hashing" config TPM_HASH_SHA512 - bool "SHA512" + bool "SHA512 PCR hashing" -endchoice +endif config TPM_MEASURED_BOOT_INIT_BOOTBLOCK bool diff --git a/src/security/tpm/tpm2_log_serialized.h b/src/security/tpm/tpm2_log_serialized.h index aaaf576eca3..cc655b4b9f8 100644 --- a/src/security/tpm/tpm2_log_serialized.h +++ b/src/security/tpm/tpm2_log_serialized.h @@ -9,62 +9,36 @@ #define TPM_20_LOG_DATA_MAX_LENGTH 50 #define TPM_20_LOG_VI_MAGIC 0x32544243 /* "CBT2" in LE */ -#define TPM_20_LOG_VI_MAJOR 1 +#define TPM_20_LOG_VI_MAJOR 2 #define TPM_20_LOG_VI_MINOR 0 -/* - * TPM2.0 log entries can't be generally represented as C structures due to - * varying number of digests and their sizes. However, it works as long as - * we're only using single kind of digests. - */ -#if CONFIG(TPM_LOG_TCG) || CONFIG(TPM_LOG_TPM2) -# if CONFIG(TPM_HASH_SHA1) -# define TPM_20_LOG_DIGEST_MAX_LENGTH SHA1_DIGEST_SIZE -# endif -# if CONFIG(TPM_HASH_SHA256) -# define TPM_20_LOG_DIGEST_MAX_LENGTH SHA256_DIGEST_SIZE -# endif -# if CONFIG(TPM_HASH_SHA384) -# define TPM_20_LOG_DIGEST_MAX_LENGTH SHA384_DIGEST_SIZE -# endif -# if CONFIG(TPM_HASH_SHA512) -# define TPM_20_LOG_DIGEST_MAX_LENGTH SHA512_DIGEST_SIZE -# endif +#define TPM_20_VENDOR_INFO_SIZE (sizeof(struct tpm_2_log_bottom) - sizeof(uint8_t)) -# ifndef TPM_20_LOG_DIGEST_MAX_LENGTH -# error "Misconfiguration: failed to determine TPM hashing algorithm" -# endif -#else -# define TPM_20_LOG_DIGEST_MAX_LENGTH 1 /* To avoid compilation error */ -#endif - -/* TCG_PCR_EVENT2 */ -struct tpm_2_log_entry { - uint32_t pcr; - uint32_t event_type; - uint32_t digest_count; /* Always 1 in current implementation */ - uint16_t digest_type; - uint8_t digest[TPM_20_LOG_DIGEST_MAX_LENGTH]; - uint32_t data_length; - uint8_t data[TPM_20_LOG_DATA_MAX_LENGTH]; +/* This log table has two variable-sized portions one of which is in the middle. For this + * reason the declaration is split in two each ending on a variable-sized portion. */ +struct tpm_2_log_table { + struct tcg_efi_spec_id_event header; /* TCG_PCR_EVENT actually */ + // struct tpm_digest_sizes digest_sizes[header.num_of_algorithms]; + // struct tpm_2_log_bottom bottom; } __packed; -struct tpm_2_vendor { +/* The bottom part of the log which follows its first variable-sized portion (list of digest + sizes). */ +struct tpm_2_log_bottom { + /* Size of the following set of fields (doesn't include the size field). */ + uint8_t vendor_info_size; + + /* This is vendor info/data. */ uint8_t reserved; uint8_t version_major; uint8_t version_minor; uint32_t magic; - uint16_t max_entries; uint16_t num_entries; - uint32_t entry_size; -} __packed; + uint16_t next_offset; /* Offset within `events` array */ + uint16_t max_offset; /* Maximum offset within `events` array */ -struct tpm_2_log_table { - struct tcg_efi_spec_id_event header; /* TCG_PCR_EVENT actually */ - struct tpm_digest_sizes digest_sizes[1]; - uint8_t vendor_info_size; - struct tpm_2_vendor vendor; - struct tpm_2_log_entry entries[]; /* Variable number of entries */ + /* Events follow. */ + uint8_t events[]; } __packed; #endif diff --git a/src/security/tpm/tspi.h b/src/security/tpm/tspi.h index f79b2cf043e..4ec2d2859a9 100644 --- a/src/security/tpm/tspi.h +++ b/src/security/tpm/tspi.h @@ -43,28 +43,20 @@ static inline bool tpm_log_use_tpm2_format(void) } /** - * Retrieves hash algorithm used by TPM event log or VB2_HASH_INVALID. + * Checks whether a PCR banks corresponding to a hash algorithm is active. */ -static inline enum vb2_hash_algorithm tpm_log_alg(void) +static inline bool tpm_log_alg_active(enum vb2_hash_algorithm alg) { if (CONFIG(TPM_LOG_CB)) - return (tlcl_get_family() == TPM_1 ? VB2_HASH_SHA1 : VB2_HASH_SHA256); + return alg == (tlcl_get_family() == TPM_1 ? VB2_HASH_SHA1 : VB2_HASH_SHA256); if (tpm_log_use_tpm1_format()) - return VB2_HASH_SHA1; - - if (tpm_log_use_tpm2_format()) { - if (CONFIG(TPM_HASH_SHA1)) - return VB2_HASH_SHA1; - if (CONFIG(TPM_HASH_SHA256)) - return VB2_HASH_SHA256; - if (CONFIG(TPM_HASH_SHA384)) - return VB2_HASH_SHA384; - if (CONFIG(TPM_HASH_SHA512)) - return VB2_HASH_SHA512; - } - - return VB2_HASH_INVALID; + return alg == VB2_HASH_SHA1; + + if (tpm_log_use_tpm2_format()) + return tpm2_log_alg_active(alg); + + return false; } /** @@ -132,15 +124,15 @@ static inline void tpm_log_copy_entries(const void *from, void *to) /** * Retrieves an entry from a log. Returns non-zero on invalid index or error. */ -static inline int tpm_log_get(int entry_idx, int *pcr, const uint8_t **digest_data, - enum vb2_hash_algorithm *digest_algo, const char **event_name) +static inline int tpm_log_get(int entry_idx, int *pcr, struct tpm_digest *digests, + const char **event_name) { if (CONFIG(TPM_LOG_CB)) - return tpm_cb_log_get(entry_idx, pcr, digest_data, digest_algo, event_name); + return tpm_cb_log_get(entry_idx, pcr, digests, event_name); if (tpm_log_use_tpm1_format()) - return tpm1_log_get(entry_idx, pcr, digest_data, digest_algo, event_name); + return tpm1_log_get(entry_idx, pcr, digests, event_name); if (tpm_log_use_tpm2_format()) - return tpm2_log_get(entry_idx, pcr, digest_data, digest_algo, event_name); + return tpm2_log_get(entry_idx, pcr, digests, event_name); return 1; } @@ -148,21 +140,17 @@ static inline int tpm_log_get(int entry_idx, int *pcr, const uint8_t **digest_da * Add table entry for cbmem TPM log. * @param name Name of the hashed data * @param pcr PCR used to extend hashed data - * @param diget_algo sets the digest algorithm - * @param digest sets the hash extended into the tpm - * @param digest_len the length of the digest + * @param digests An array of digests terminated by an entry with VB2_HASH_NONE */ static inline void tpm_log_add_table_entry(const char *name, const uint32_t pcr, - enum vb2_hash_algorithm digest_algo, - const uint8_t *digest, - const size_t digest_len) + const struct tpm_digest *digests) { if (CONFIG(TPM_LOG_CB)) - tpm_cb_log_add_table_entry(name, pcr, digest_algo, digest, digest_len); + tpm_cb_log_add_table_entry(name, pcr, digests); else if (tpm_log_use_tpm1_format()) - tpm1_log_add_table_entry(name, pcr, digest_algo, digest, digest_len); + tpm1_log_add_table_entry(name, pcr, digests); else if (tpm_log_use_tpm2_format()) - tpm2_log_add_table_entry(name, pcr, digest_algo, digest, digest_len); + tpm2_log_add_table_entry(name, pcr, digests); } /** @@ -175,6 +163,15 @@ static inline void tpm_log_startup_locality(int locality) tpm2_log_startup_locality(locality); } +/** + * Align TPM log with the TPM if necessary. + */ +static inline void tpm_log_align_with_tpm(void) +{ + if (tpm_log_use_tpm2_format()) + tpm2_log_align_with_tpm(); +} + /** * Dump TPM log entries on console */ @@ -191,15 +188,11 @@ static inline void tpm_log_dump(void *unused) /** * Ask vboot for a digest and extend a TPM PCR with it. * @param pcr sets the pcr index - * @param diget_algo sets the digest algorithm - * @param digest sets the hash to extend into the tpm - * @param digest_len the length of the digest + * @param digests An array of digests terminated by an entry with VB2_HASH_NONE * @param name sets additional info where the digest comes from * @return TPM_SUCCESS on success. If not a tpm error is returned */ -tpm_result_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo, - const uint8_t *digest, size_t digest_len, - const char *name); +tpm_result_t tpm_extend_pcr(int pcr, const struct tpm_digest *digests, const char *name); /** * Issue a TPM_Clear and re-enable/reactivate the TPM. @@ -224,4 +217,44 @@ tpm_result_t tpm_setup(int s3flag); tpm_result_t tpm_measure_region(const struct region_device *rdev, uint8_t pcr, const char *rname); +/* + * Arrays of tpm_digest structures should generally have `ENABLED_TPM_ALGS_NUM + 1` entries. + * The extra entry terminates the list. Functions that fill such arrays rely on this + * assumption. + */ +#define ENABLED_TPM_ALGS_NUM ARRAY_SIZE(enabled_tpm_algs) + +/* + * This is a list of supported digests to be used in loops. + */ +static const enum vb2_hash_algorithm enabled_tpm_algs[] __maybe_unused = { +#if CONFIG(TPM_HASH_SHA1) || CONFIG(TPM_LOG_CB) + VB2_HASH_SHA1, +#endif +#if CONFIG(TPM_HASH_SHA256) || CONFIG(TPM_LOG_CB) + VB2_HASH_SHA256, +#endif +#if CONFIG(TPM_HASH_SHA384) + VB2_HASH_SHA384, +#endif +#if CONFIG(TPM_HASH_SHA512) + VB2_HASH_SHA512, +#endif +}; + +_Static_assert(ENABLED_TPM_ALGS_NUM <= HASH_COUNT, + "Marshalling code of TSS 2.0 can't accommodate all enabled hashes."); + +struct tpm_digests { + struct vb2_hash hashes[ENABLED_TPM_ALGS_NUM]; + struct tpm_digest values[ENABLED_TPM_ALGS_NUM + 1]; +}; + +/** + * Compute all supported hashes of a buffer. hash_hint can be passed in to avoid recomputing + * the digest if it's already known. + */ +bool tpm_make_digests(const void *buffer, size_t size, const struct vb2_hash *hash_hint, + struct tpm_digests *digests); + #endif /* TSPI_H_ */ diff --git a/src/security/tpm/tspi/crtm.c b/src/security/tpm/tspi/crtm.c index c870a90198e..0d77369e318 100644 --- a/src/security/tpm/tspi/crtm.c +++ b/src/security/tpm/tspi/crtm.c @@ -105,7 +105,8 @@ static bool is_runtime_data(const char *name) return !strcmp(allowlist, name); } -tpm_result_t tspi_cbfs_measurement(const char *name, uint32_t type, const struct vb2_hash *hash) +tpm_result_t tspi_cbfs_measurement(const char *name, const void *buffer, size_t size, + uint32_t type, const struct vb2_hash *hash_hint) { uint32_t pcr_index; char tpm_log_metadata[TPM_CB_LOG_PCR_HASH_NAME]; @@ -132,10 +133,15 @@ tpm_result_t tspi_cbfs_measurement(const char *name, uint32_t type, const struct break; } + struct tpm_digests digests; + if (!tpm_make_digests(buffer, size, hash_hint, &digests)) { + printk(BIOS_ERR, "%s: failed to fill digests!\n", __func__); + return TPM_FAIL; + } + snprintf(tpm_log_metadata, TPM_CB_LOG_PCR_HASH_NAME, "CBFS: %s", name); - return tpm_extend_pcr(pcr_index, hash->algo, hash->raw, vb2_digest_size(hash->algo), - tpm_log_metadata); + return tpm_extend_pcr(pcr_index, digests.values, tpm_log_metadata); } void *tpm_log_init(void) @@ -163,8 +169,7 @@ tpm_result_t tspi_measure_cache_to_pcr(void) int i; int pcr; const char *event_name; - const uint8_t *digest_data; - enum vb2_hash_algorithm digest_algo; + struct tpm_digest digests[ENABLED_TPM_ALGS_NUM + 1]; /* This means the table is empty. */ if (!tspi_tpm_log_available()) @@ -175,9 +180,16 @@ tpm_result_t tspi_measure_cache_to_pcr(void) return TPM_CB_FAIL; } + /* + * At this point TPM has been initialized, but none of coreboot's measurements have been + * submitted to it yet. Before extending cached digests, invoke a log-specific function + * to do modifications based on the information queried from a TPM. + */ + tpm_log_align_with_tpm(); + printk(BIOS_DEBUG, "TPM: Write digests cached in TPM log to PCR\n"); i = 0; - while (!tpm_log_get(i++, &pcr, &digest_data, &digest_algo, &event_name)) { + while (!tpm_log_get(i++, &pcr, digests, &event_name)) { /* * Skip log entries that coreboot synthesized to account for PCR extends * performed by hardware S-CRTM. @@ -193,11 +205,12 @@ tpm_result_t tspi_measure_cache_to_pcr(void) continue; printk(BIOS_DEBUG, "TPM: Write digest for %s into PCR %d\n", event_name, pcr); - tpm_result_t rc = tlcl_extend(pcr, digest_data, digest_algo); + + tpm_result_t rc = tlcl_extend(pcr, digests); if (rc != TPM_SUCCESS) { printk(BIOS_ERR, "TPM: Writing digest of %s into PCR failed with error %d\n", - event_name, rc); + event_name, rc); return rc; } } diff --git a/src/security/tpm/tspi/crtm.h b/src/security/tpm/tspi/crtm.h index cd20e81b646..04ee46a75fd 100644 --- a/src/security/tpm/tspi/crtm.h +++ b/src/security/tpm/tspi/crtm.h @@ -34,9 +34,11 @@ tpm_result_t tspi_init_crtm(void); tpm_result_t tspi_measure_cache_to_pcr(void); /** - * Extend a measurement hash taken for a CBFS file into the appropriate PCR. + * Extend a measurement hash of a CBFS file into the appropriate PCR. hash_hint can be passed + * in to avoid recomputing the digest if it's already known. */ -tpm_result_t tspi_cbfs_measurement(const char *name, uint32_t type, const struct vb2_hash *hash); +tpm_result_t tspi_cbfs_measurement(const char *name, const void *buffer, size_t size, + uint32_t type, const struct vb2_hash *hash_hint); /* * Provide a function on SoC level to measure the bootblock for cases where bootblock is diff --git a/src/security/tpm/tspi/log-tpm1.c b/src/security/tpm/tspi/log-tpm1.c index 0fbfa5ab503..7052425a9e0 100644 --- a/src/security/tpm/tspi/log-tpm1.c +++ b/src/security/tpm/tspi/log-tpm1.c @@ -83,10 +83,7 @@ void tpm1_log_dump(void) printk(BIOS_INFO, "\n"); } -void tpm1_log_add_table_entry(const char *name, const uint32_t pcr, - enum vb2_hash_algorithm digest_algo, - const uint8_t *digest, - const size_t digest_len) +void tpm1_log_add_table_entry(const char *name, uint32_t pcr, const struct tpm_digest *digests) { struct tpm_1_log_table *tclt; struct tpm_1_log_entry *tce; @@ -102,8 +99,14 @@ void tpm1_log_add_table_entry(const char *name, const uint32_t pcr, return; } - if (digest_algo != VB2_HASH_SHA1) { - printk(BIOS_WARNING, "TPM LOG: unsupported hash algorithm\n"); + if (digests[0].hash_type != VB2_HASH_SHA1) { + printk(BIOS_WARNING, "TPM LOG: digest is of unsupported type: %s\n", + vb2_get_hash_algorithm_name(digests[0].hash_type)); + return; + } + + if (digests[1].hash_type != VB2_HASH_INVALID) { + printk(BIOS_WARNING, "TPM LOG: TPM 1 can't handle multiple banks\n"); return; } @@ -118,7 +121,7 @@ void tpm1_log_add_table_entry(const char *name, const uint32_t pcr, tce->pcr = htole32(pcr); tce->event_type = htole32(EV_ACTION); - memcpy(tce->digest, digest, digest_len); + memcpy(tce->digest, digests[0].hash, TPM_1_LOG_DIGEST_MAX_LENGTH); tce->data_length = htole32(TPM_1_LOG_DATA_MAX_LENGTH); strncpy((char *)tce->data, name, sizeof(tce->data) - 1); @@ -137,8 +140,7 @@ void tpm1_preram_log_clear(void) tclt->vendor.num_entries = htole16(0); } -int tpm1_log_get(int entry_idx, int *pcr, const uint8_t **digest_data, - enum vb2_hash_algorithm *digest_algo, const char **event_name) +int tpm1_log_get(int entry_idx, int *pcr, struct tpm_digest *digests, const char **event_name) { struct tpm_1_log_table *tclt; struct tpm_1_log_entry *tce; @@ -152,9 +154,11 @@ int tpm1_log_get(int entry_idx, int *pcr, const uint8_t **digest_data, tce = &tclt->entries[entry_idx]; + digests[0].hash_type = VB2_HASH_SHA1; + digests[0].hash = tce->digest; + digests[1].hash_type = VB2_HASH_INVALID; + *pcr = le32toh(tce->pcr); - *digest_data = tce->digest; - *digest_algo = VB2_HASH_SHA1; *event_name = (char *)tce->data; return 0; } diff --git a/src/security/tpm/tspi/log-tpm2.c b/src/security/tpm/tspi/log-tpm2.c index 3e26970a880..a9352175565 100644 --- a/src/security/tpm/tspi/log-tpm2.c +++ b/src/security/tpm/tspi/log-tpm2.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -22,15 +23,154 @@ #include #include -#define TPM_LOG_SIZE (64 * KiB) -#define MAX_TPM_LOG_ENTRIES ((TPM_LOG_SIZE - sizeof(struct tpm_2_log_table)) / \ - sizeof(struct tpm_2_log_entry)) +#define TPM_LOG_SIZE (64 * KiB) + +struct log_event { + uint32_t pcr; + uint32_t event_type; + uint32_t digest_count; + struct tpm_digest digests[ENABLED_TPM_ALGS_NUM]; + uint32_t name_len; + const char *name; +}; struct startup_locality_event { char signature[16]; /* "StartupLocality" (NUL-terminated) */ uint8_t startup_locality; /* 0 or 3 */ } __packed; +struct pcr_banks_info { + int active_count; /* Number is_active entries set to true. */ + bool is_active[ENABLED_TPM_ALGS_NUM]; /* Set of active banks. */ +}; + +static int find_alg_index(enum vb2_hash_algorithm alg) +{ + unsigned int i; + for (i = 0; i < ENABLED_TPM_ALGS_NUM; i++) { + if (enabled_tpm_algs[i] == alg) + return i; + } + + return -1; +} + +static bool is_all_zeroes(const void *buffer, size_t size) +{ + const uint8_t *p = buffer; + while (size-- != 0) { + if (*p++ != 0) + return false; + } + return true; +} + +static bool supports_digest(const struct tpm_2_log_table *tclt, uint16_t alg_id) +{ + const struct tcg_efi_spec_id_event *hdr = &tclt->header; + + int i; + for (i = 0; i < le32toh(hdr->num_of_algorithms); ++i) { + if (hdr->digest_sizes[i].alg_id == htole16(alg_id)) + return true; + } + + return false; +} + +/* Assumes tclt->header.num_of_algorithms is already set to its final value. */ +static struct tpm_2_log_bottom *get_log_bottom(const struct tpm_2_log_table *tclt) +{ + uint8_t *p; + + /* Start at the first variable-sized part of the header. */ + p = (uint8_t *)tclt->header.digest_sizes; + /* Skip over it. */ + p += le32toh(tclt->header.num_of_algorithms) * sizeof(tclt->header.digest_sizes[0]); + /* `p` points at `uint8_t vendor_info_size` here. */ + return (struct tpm_2_log_bottom *)p; +} + +/* See comment on tpm2_log_align_with_tpm(). */ +static const struct pcr_banks_info *get_pcr_banks_info(void) +{ + static bool initialized; + static struct pcr_banks_info info; + + if (initialized) + return &info; + + /* Start by pretending that all supported banks are active in case there will be an + error. */ + unsigned int i; + for (i = 0; i < ENABLED_TPM_ALGS_NUM; ++i) + info.is_active[i] = true; + info.active_count = ENABLED_TPM_ALGS_NUM; + + if (CONFIG(TPM_INIT_RAMSTAGE) && !ENV_RAMSTAGE && !ENV_POSTCAR && !ENV_PAYLOAD_LOADER) { + /* TPM initialization is postponed until ramstage, no use poking it. */ + initialized = true; + return &info; + } + + tpm_result_t rc = tlcl_lib_init(); + if (rc != TPM_SUCCESS) { + printk(BIOS_WARNING, "TPM LOG: failed to initialize TLCL: %d\n", rc); + return &info; + } + + TPML_PCR_SELECTION pcrs; + rc = tlcl2_get_capability_pcrs(&pcrs); + if (rc != TPM_SUCCESS) { + printk(BIOS_WARNING, "TPM LOG: failed to query PCR capabilities: %d\n", rc); + return &info; + } + + if (pcrs.count == 0) { + /* TPM likely just hasn't been set up yet. */ + return &info; + } + + info.active_count = 0; + memset(info.is_active, 0, sizeof(info.is_active)); + + for (i = 0; i < pcrs.count; i++) { + TPMS_PCR_SELECTION *selection = &pcrs.pcrSelections[i]; + + enum vb2_hash_algorithm alg = tpm2_alg_to_vb2_hash(selection->hash); + if (alg == VB2_HASH_INVALID) { + printk(BIOS_INFO, "TPM LOG: unsupported PCR bank: %#x\n", + selection->hash); + continue; + } + + int alg_index = find_alg_index(alg); + if (alg_index < 0) { + printk(BIOS_INFO, + "TPM LOG: skipping PCR bank disabled at build-time: %s\n", + vb2_get_hash_algorithm_name(alg)); + continue; + } + + bool is_active = !is_all_zeroes(selection->pcrSelect, selection->sizeofSelect); + if (is_active) { + info.is_active[alg_index] = true; + ++info.active_count; + } + } + + initialized = true; + return &info; +} + +static uint16_t get_log_footprint(const struct tpm_2_log_table *tclt) +{ + return sizeof(*tclt) + + le32toh(tclt->header.num_of_algorithms) * sizeof(tclt->header.digest_sizes[0]) + + sizeof(struct tpm_2_log_bottom) + + le16toh(get_log_bottom(tclt)->next_offset); +} + void *tpm2_log_cbmem_init(void) { static struct tpm_2_log_table *tclt; @@ -38,7 +178,10 @@ void *tpm2_log_cbmem_init(void) return tclt; if (ENV_HAS_CBMEM) { + int i, j; struct tcg_efi_spec_id_event *hdr; + const struct pcr_banks_info *pcr_banks_info; + struct tpm_2_log_bottom *bottom; tclt = cbmem_find(CBMEM_ID_TPM2_TCG_LOG); if (tclt) @@ -48,180 +191,279 @@ void *tpm2_log_cbmem_init(void) if (!tclt) return NULL; + pcr_banks_info = get_pcr_banks_info(); + memset(tclt, 0, TPM_LOG_SIZE); hdr = &tclt->header; hdr->event_type = htole32(EV_NO_ACTION); - hdr->event_size = htole32(33 + sizeof(tclt->vendor)); + hdr->event_size = htole32(28 + + pcr_banks_info->active_count * sizeof(hdr->digest_sizes[0]) + + 1 + + TPM_20_VENDOR_INFO_SIZE); strcpy((char *)hdr->signature, TPM_20_SPEC_ID_EVENT_SIGNATURE); hdr->platform_class = htole32(0x00); // client platform hdr->spec_version_minor = 0x00; hdr->spec_version_major = 0x02; hdr->spec_errata = 0x00; hdr->uintn_size = 0x02; // 64-bit UINT - hdr->num_of_algorithms = htole32(1); - hdr->digest_sizes[0].alg_id = htole16(tpm2_alg_from_vb2_hash(tpm_log_alg())); - hdr->digest_sizes[0].digest_size = htole16(vb2_digest_size(tpm_log_alg())); - - tclt->vendor_info_size = sizeof(tclt->vendor); - tclt->vendor.reserved = 0; - tclt->vendor.version_major = TPM_20_LOG_VI_MAJOR; - tclt->vendor.version_minor = TPM_20_LOG_VI_MINOR; - tclt->vendor.magic = htole32(TPM_20_LOG_VI_MAGIC); - tclt->vendor.max_entries = htole16(MAX_TPM_LOG_ENTRIES); - tclt->vendor.num_entries = htole16(0); - tclt->vendor.entry_size = htole32(sizeof(struct tpm_2_log_entry)); + + hdr->num_of_algorithms = htole32(pcr_banks_info->active_count); + for (i = 0, j = -1; i < le32toh(hdr->num_of_algorithms); ++i) { + /* Find the next active bank. */ + while (!pcr_banks_info->is_active[++j]) + continue; + + hdr->digest_sizes[i].alg_id = + htole16(tpm2_alg_from_vb2_hash(enabled_tpm_algs[j])); + hdr->digest_sizes[i].digest_size = + htole16(vb2_digest_size(enabled_tpm_algs[j])); + } + + bottom = get_log_bottom(tclt); + bottom->vendor_info_size = TPM_20_VENDOR_INFO_SIZE; + bottom->reserved = 0; + bottom->version_major = TPM_20_LOG_VI_MAJOR; + bottom->version_minor = TPM_20_LOG_VI_MINOR; + bottom->magic = htole32(TPM_20_LOG_VI_MAGIC); + bottom->num_entries = 0; + bottom->next_offset = 0; + bottom->max_offset = htole16(TPM_LOG_SIZE - get_log_footprint(tclt)); } return tclt; } +/* The function assumes input buffer includes a complete event. */ +static void read_log_event(struct ibuf *ib, struct log_event *ev) +{ + ibuf_read_le32(ib, &ev->pcr); + ibuf_read_le32(ib, &ev->event_type); + ibuf_read_le32(ib, &ev->digest_count); + + uint32_t i; + for (i = 0; i < ev->digest_count; ++i) { + uint16_t alg; + ibuf_read_le16(ib, &alg); + + ev->digests[i].hash_type = tpm2_alg_to_vb2_hash(alg); + ev->digests[i].hash = ibuf_oob_drain(ib, + vb2_digest_size(ev->digests[i].hash_type)); + } + + ibuf_read_le32(ib, &ev->name_len); + ev->name = ibuf_oob_drain(ib, ev->name_len); +} + +/* Returns true if an event was parsed successfully. */ +static bool parse_log_event(const struct tpm_2_log_bottom *bottom, + struct log_event *ev, + uint16_t *offset) +{ + if (*offset == le16toh(bottom->next_offset)) + return false; + + struct ibuf ib; + ibuf_init(&ib, &bottom->events[*offset], le16toh(bottom->next_offset) - *offset); + + read_log_event(&ib, ev); + + *offset += ibuf_nr_read(&ib); + return true; +} + void tpm2_log_dump(void) { - int i, j; + uint16_t offset; + struct log_event ev; struct tpm_2_log_table *tclt; - int hash_size; - const char *alg_name; + const struct tpm_2_log_bottom *bottom; tclt = tpm_log_init(); if (!tclt) return; - hash_size = vb2_digest_size(tpm_log_alg()); - alg_name = vb2_get_hash_algorithm_name(tpm_log_alg()); + bottom = get_log_bottom(tclt); + + offset = 0; + while (parse_log_event(bottom, &ev, &offset)) { + uint32_t i; - printk(BIOS_INFO, "coreboot TPM 2.0 measurements:\n\n"); - for (i = 0; i < le16toh(tclt->vendor.num_entries); i++) { - struct tpm_2_log_entry *tce = &tclt->entries[i]; + printk(BIOS_INFO, " PCR-%u [%s]:\n", ev.pcr, ev.name); - printk(BIOS_INFO, " PCR-%u ", le32toh(tce->pcr)); + for (i = 0; i < ev.digest_count; ++i) { + enum vb2_hash_algorithm hash_type; + int digest_size, j; - for (j = 0; j < hash_size; j++) - printk(BIOS_INFO, "%02x", tce->digest[j]); + hash_type = ev.digests[i].hash_type; + digest_size = vb2_digest_size(hash_type); - printk(BIOS_INFO, " %s [%s]\n", alg_name, tce->data); + printk(BIOS_INFO, " %6s: ", vb2_get_hash_algorithm_name(hash_type)); + for (j = 0; j < digest_size; ++j) + printk(BIOS_INFO, "%02x", ev.digests[i].hash[j]); + printk(BIOS_INFO, "\n"); + } } printk(BIOS_INFO, "\n"); } -void tpm2_log_add_table_entry(const char *name, const uint32_t pcr, - enum vb2_hash_algorithm digest_algo, - const uint8_t *digest, - const size_t digest_len) +bool tpm2_log_alg_active(enum vb2_hash_algorithm alg) { - struct tpm_2_log_table *tclt; - struct tpm_2_log_entry *tce; + int alg_index = find_alg_index(alg); + if (alg_index < 0) + return false; - tclt = tpm_log_init(); - if (!tclt) { - printk(BIOS_WARNING, "TPM LOG: non-existent!\n"); - return; - } + return get_pcr_banks_info()->is_active[alg_index]; +} - if (!name) { - printk(BIOS_WARNING, "TPM LOG: entry name not set\n"); - return; - } +/* The function assumes output buffer has enough space for the new event. */ +static void write_log_event(struct obuf *ob, + const void *data, + size_t data_len, + uint32_t pcr, + uint32_t type, + const struct tpm_digest *digests) +{ + uint32_t digest_count = 0; + while (digests[digest_count].hash_type != VB2_HASH_INVALID) + ++digest_count; - if (digest_algo != tpm_log_alg()) { - printk(BIOS_WARNING, "TPM LOG: digest is of unsupported type: %s\n", - vb2_get_hash_algorithm_name(digest_algo)); - return; - } + obuf_write_le32(ob, pcr); + obuf_write_le32(ob, type); + obuf_write_le32(ob, digest_count); - if (digest_len != vb2_digest_size(tpm_log_alg())) { - printk(BIOS_WARNING, "TPM LOG: digest has invalid length: %d\n", - (int)digest_len); - return; + int i; + for (i = 0; digests[i].hash_type != VB2_HASH_INVALID; ++i) { + int hash_size = vb2_digest_size(digests[i].hash_type); + + obuf_write_le16(ob, tpm2_alg_from_vb2_hash(digests[i].hash_type)); + obuf_write(ob, digests[i].hash, hash_size); } - if (le16toh(tclt->vendor.num_entries) >= le16toh(tclt->vendor.max_entries)) { - printk(BIOS_WARNING, "TPM LOG: log table is full\n"); + obuf_write_le32(ob, data_len); + obuf_write(ob, data, data_len); +} + +static void add_log_table_entry(struct tpm_2_log_table *tclt, + const void *data, + size_t data_len, + uint32_t pcr, + uint32_t type, + const struct tpm_digest *digests) +{ + int i; + + uint16_t needed_size = 4 * sizeof(uint32_t) + data_len; + for (i = 0; digests[i].hash_type != VB2_HASH_INVALID; ++i) + needed_size += sizeof(uint16_t) + vb2_digest_size(digests[i].hash_type); + + struct tpm_2_log_bottom *bottom = get_log_bottom(tclt); + if (le16toh(bottom->next_offset) + needed_size > le16toh(bottom->max_offset)) { + printk(BIOS_WARNING, "TPM LOG: log is full: %u/%u (need %u)\n", + le16toh(bottom->next_offset), le16toh(bottom->max_offset), needed_size); return; } - tce = &tclt->entries[le16toh(tclt->vendor.num_entries)]; - tclt->vendor.num_entries = htole16(le16toh(tclt->vendor.num_entries) + 1); + struct obuf ob; + obuf_init(&ob, &bottom->events[le16toh(bottom->next_offset)], + le16toh(bottom->max_offset) - le16toh(bottom->next_offset)); - tce->pcr = htole32(pcr); - tce->event_type = htole32(EV_ACTION); + write_log_event(&ob, data, data_len, pcr, type, digests); - tce->digest_count = htole32(1); - tce->digest_type = htole16(tpm2_alg_from_vb2_hash(tpm_log_alg())); - memcpy(tce->digest, digest, vb2_digest_size(tpm_log_alg())); - - tce->data_length = htole32(sizeof(tce->data)); - strncpy((char *)tce->data, name, sizeof(tce->data) - 1); - tce->data[sizeof(tce->data) - 1] = '\0'; + bottom->next_offset = htole16(le16toh(bottom->next_offset) + needed_size); + bottom->num_entries = htole16(le16toh(bottom->num_entries) + 1); } -void tpm2_log_startup_locality(int locality) +void tpm2_log_add_table_entry(const char *name, uint32_t pcr, const struct tpm_digest *digests) { - _Static_assert(sizeof(struct startup_locality_event) <= TPM_20_LOG_DATA_MAX_LENGTH, - "Data field of TCG log for TPM2 is too short for Startup Locality.\n"); - - struct tpm_2_log_table *tclt; - struct tpm_2_log_entry *tce; - struct startup_locality_event locality_event; - - tclt = tpm_log_init(); + struct tpm_2_log_table *tclt = tpm_log_init(); if (!tclt) { printk(BIOS_WARNING, "TPM LOG: non-existent!\n"); return; } - if (le16toh(tclt->vendor.num_entries) >= le16toh(tclt->vendor.max_entries)) { - printk(BIOS_WARNING, "TPM LOG: log table is full\n"); + if (!name) { + printk(BIOS_WARNING, "TPM LOG: entry name not set\n"); return; } - tce = &tclt->entries[le16toh(tclt->vendor.num_entries)]; - tclt->vendor.num_entries = htole16(le16toh(tclt->vendor.num_entries) + 1); + add_log_table_entry(tclt, name, strlen(name) + 1, pcr, EV_ACTION, digests); +} - /* EV_NO_ACTION events use PCR-0 by default. */ - tce->pcr = htole32(0); - tce->event_type = htole32(EV_NO_ACTION); +void tpm2_log_startup_locality(int locality) +{ + struct tpm_2_log_table *tclt = tpm_log_init(); + if (!tclt) { + printk(BIOS_WARNING, "TPM LOG: non-existent!\n"); + return; + } + + const struct pcr_banks_info *pcr_banks_info = get_pcr_banks_info(); /* EV_NO_ACTION events use zeroes for digest(s). */ - tce->digest_count = htole32(1); - tce->digest_type = htole16(tpm2_alg_from_vb2_hash(tpm_log_alg())); - memset(tce->digest, 0, vb2_digest_size(tpm_log_alg())); + struct vb2_hash zero_hash = {0}; + struct tpm_digest digests[ENABLED_TPM_ALGS_NUM + 1]; - tce->data_length = htole32(sizeof(tce->data)); + int i, j; + for (i = 0, j = 0; i < ARRAY_SIZE(pcr_banks_info->is_active); ++i) { + if (!pcr_banks_info->is_active[i]) + continue; + + digests[j].hash_type = enabled_tpm_algs[i]; + digests[j].hash = zero_hash.raw; + ++j; + } + digests[j].hash_type = VB2_HASH_INVALID; - strcpy(locality_event.signature, "StartupLocality"); - locality_event.startup_locality = locality; + struct startup_locality_event event_data; + strcpy(event_data.signature, "StartupLocality"); + event_data.startup_locality = locality; - memset(tce->data, 0, sizeof(tce->data)); - memcpy(tce->data, &locality_event, sizeof(locality_event)); + /* EV_NO_ACTION events use PCR-0 by default. */ + add_log_table_entry(tclt, &event_data, sizeof(event_data), 0, EV_NO_ACTION, digests); } -int tpm2_log_get(int entry_idx, int *pcr, const uint8_t **digest_data, - enum vb2_hash_algorithm *digest_algo, const char **event_name) +int tpm2_log_get(int entry_idx, int *pcr, struct tpm_digest *digests, const char **event_name) { + uint16_t offset; + struct log_event ev; + int idx; struct tpm_2_log_table *tclt; - struct tpm_2_log_entry *tce; + struct tpm_2_log_bottom *bottom; tclt = tpm_log_init(); if (!tclt) return 1; - if (entry_idx < 0 || entry_idx >= le16toh(tclt->vendor.num_entries)) + bottom = get_log_bottom(tclt); + if (entry_idx < 0 || entry_idx >= le16toh(bottom->num_entries)) return 1; - tce = &tclt->entries[entry_idx]; + offset = 0; + idx = 0; + while (parse_log_event(bottom, &ev, &offset)) { + if (idx != entry_idx) { + ++idx; + continue; + } + + int i; + for (i = 0; i < ev.digest_count; ++i) + digests[i] = ev.digests[i]; + digests[ev.digest_count].hash_type = VB2_HASH_INVALID; - *pcr = le32toh(tce->pcr); - *digest_data = tce->digest; - *digest_algo = tpm_log_alg(); /* We validate algorithm on addition */ - *event_name = (char *)tce->data; - return 0; + *pcr = ev.pcr; + *event_name = ev.name; + return 0; + } + + return 1; } uint16_t tpm2_log_get_size(const void *log_table) { const struct tpm_2_log_table *tclt = log_table; - return le16toh(tclt->vendor.num_entries); + return le16toh(get_log_bottom(tclt)->num_entries); } void tpm2_preram_log_clear(void) @@ -229,37 +471,141 @@ void tpm2_preram_log_clear(void) printk(BIOS_INFO, "TPM LOG: clearing the log\n"); /* * Pre-RAM log is only for internal use and isn't exported anywhere, hence it's header - * is not initialized. + * is not fully initialized. */ struct tpm_2_log_table *tclt = (struct tpm_2_log_table *)_tpm_log; - tclt->vendor.max_entries = htole16(MAX_TPM_LOG_ENTRIES); - tclt->vendor.num_entries = htole16(0); + tclt->header.num_of_algorithms = htole32(get_pcr_banks_info()->active_count); + + struct tpm_2_log_bottom *bottom = get_log_bottom(tclt); + bottom->num_entries = 0; + bottom->next_offset = 0; + bottom->max_offset = htole16((_etpm_log - _tpm_log) - get_log_footprint(tclt)); } void tpm2_log_copy_entries(const void *from, void *to) { - const struct tpm_2_log_table *from_log = from; - struct tpm_2_log_table *to_log = to; + const struct tpm_2_log_bottom *from_bottom = get_log_bottom(from); + struct tpm_2_log_bottom *to_bottom = get_log_bottom(to); + + if (le16toh(to_bottom->max_offset) < le16toh(from_bottom->next_offset)) { + printk(BIOS_WARNING, + "TPM LOG: not enough space at destination to copy event log entries!\n"); + return; + } + + memcpy(to_bottom->events, from_bottom->events, le16toh(from_bottom->next_offset)); + to_bottom->num_entries = from_bottom->num_entries; + to_bottom->next_offset = from_bottom->next_offset; +} + +/* + * Events can be logged before TPM is initialized but the set of active PCR banks can be queried + * only after its initialization. For this reason get_pcr_banks_info() reports all supported + * banks as active if TPM is unavailable, collecting all possible digests in the log itself. + * Once TPM is initialized, tspi_measure_cache_to_pcr() is called which invokes this function. + * The purpose of the function is to trim down the log by removing unnecessary digests. + * Normally, this function gets called in the ramstage, but if TPM gets initialized in the + * bootblock, no trimming (and no unnecessary hashing) will occur. + */ +void tpm2_log_align_with_tpm(void) +{ + /* There is no point doing anything if exactly one digest algorithm is enabled. */ + if (ENABLED_TPM_ALGS_NUM == 1) + return; + + struct tpm_2_log_table *tclt = tpm_log_init(); + if (tclt == NULL) { + printk(BIOS_WARNING, "TPM LOG: can't adjust a non-existent log!\n"); + return; + } + + struct tcg_efi_spec_id_event *hdr = &tclt->header; + const int old_alg_count = le32toh(hdr->num_of_algorithms); + + /* Filter-out unsupported digest algorithms in place. */ int i; + int new_alg_count = 0; + for (i = 0; i < old_alg_count; ++i) { + uint16_t alg_id = le16toh(hdr->digest_sizes[i].alg_id); + if (tpm2_log_alg_active(tpm2_alg_to_vb2_hash(alg_id))) + hdr->digest_sizes[new_alg_count++] = hdr->digest_sizes[i]; + } - for (i = 0; i < le16toh(from_log->vendor.num_entries); i++) { - if (le16toh(to_log->vendor.num_entries) >= le16toh(to_log->vendor.max_entries)) { - printk(BIOS_WARNING, "TPM LOG: log table is full\n"); - return; - } + if (new_alg_count == old_alg_count) { + printk(BIOS_INFO, "TPM LOG: none of %d digests were filtered\n", old_alg_count); + return; + } + + if (new_alg_count == 0) { + printk(BIOS_WARNING, "TPM LOG: can't filter-out all digests, leaving as is\n"); + return; + } + + printk(BIOS_INFO, "TPM LOG: filtering-out digests of inactive banks: %d -> %d\n", + old_alg_count, new_alg_count); + + /* + * The following code excludes inactive hashes in place. This allows using it in a + * bootblock which lacks dynamic memory allocation and avoid reserving memory for a + * temporary copy. Updating in place is safe to do and success is guaranteed because + * the data is merely shifted. The only possible concern is that obuf_write() uses + * memcpy() which per standard doesn't deal with overlapping ranges but that should be + * fine in this environment which has its own memcpy(). + * + * How the update is performed: + * 1. Remember current range of event data. + * 2. Unsupported digest algorithms inside log's header are already gone, merely need + * to update their count. + * 3. Increase size of log's header (it got shorter). + * 4. Rediscover bottom part of the log (where vendor data is) whose location depends + * on the number of digest algorithms. + * 5. Reinsert all log entries while skipping inactive banks. + * 6. Fill bottom part with correct values and update offsets there. + * 7. Clear the remainder of the log. + */ + + /* Save original bottom part on the stack. */ + struct tpm_2_log_bottom *bottom = get_log_bottom(tclt); + const struct tpm_2_log_bottom old_bottom = *bottom; + + /* Set up input buffer before bottom gets moved (updates to the header above don't + hurt anything). */ + struct ibuf ib; + ibuf_init(&ib, bottom->events, le16toh(bottom->next_offset)); + + size_t size_diff = + (old_alg_count - new_alg_count) * sizeof(tclt->header.digest_sizes[0]); + + hdr->num_of_algorithms = htole32(new_alg_count); + hdr->event_size = htole32(le32toh(hdr->event_size) - size_diff); - struct tpm_2_log_entry *tce = - &to_log->entries[le16toh(to_log->vendor.num_entries)]; - to_log->vendor.num_entries = htole16(le16toh(to_log->vendor.num_entries) + 1); + /* Updating `hdr->num_of_algorithms` above shifted location of the bottom part. */ + bottom = get_log_bottom(tclt); - tce->pcr = from_log->entries[i].pcr; - tce->event_type = from_log->entries[i].event_type; + /* Set up output buffer at the new location. */ + struct obuf ob; + obuf_init(&ob, bottom->events, le16toh(old_bottom.max_offset) + size_diff); - tce->digest_count = from_log->entries[i].digest_count; - tce->digest_type = from_log->entries[i].digest_type; - memcpy(tce->digest, from_log->entries[i].digest, sizeof(tce->digest)); + for (i = 0; i < le16toh(old_bottom.num_entries); ++i) { + struct log_event ev; + read_log_event(&ib, &ev); - tce->data_length = from_log->entries[i].data_length; - memcpy(tce->data, from_log->entries[i].data, sizeof(tce->data)); + int j, k = 0; + struct tpm_digest digests[ENABLED_TPM_ALGS_NUM + 1]; + for (j = 0; j < ev.digest_count; ++j) { + uint16_t alg = tpm2_alg_from_vb2_hash(ev.digests[j].hash_type); + if (supports_digest(tclt, alg)) + digests[k++] = ev.digests[j]; + } + digests[k].hash_type = VB2_HASH_INVALID; + + write_log_event(&ob, ev.name, ev.name_len, ev.pcr, ev.event_type, digests); } + + *bottom = old_bottom; + bottom->max_offset = htole16(le16toh(old_bottom.max_offset) + size_diff); + bottom->next_offset = htole16(obuf_nr_written(&ob)); + + memset(&bottom->events[obuf_nr_written(&ob)], 0, + le16toh(bottom->max_offset) - obuf_nr_written(&ob)); } diff --git a/src/security/tpm/tspi/log.c b/src/security/tpm/tspi/log.c index a04f4070bf9..70482cf29d0 100644 --- a/src/security/tpm/tspi/log.c +++ b/src/security/tpm/tspi/log.c @@ -58,9 +58,7 @@ void tpm_cb_log_dump(void) } void tpm_cb_log_add_table_entry(const char *name, const uint32_t pcr, - enum vb2_hash_algorithm digest_algo, - const uint8_t *digest, - const size_t digest_len) + const struct tpm_digest *digests) { struct tpm_cb_log_table *tclt = tpm_log_init(); if (!tclt) { @@ -78,22 +76,32 @@ void tpm_cb_log_add_table_entry(const char *name, const uint32_t pcr, return; } + if (digests[0].hash_type == VB2_HASH_INVALID) { + printk(BIOS_WARNING, "TPM LOG: no digests provided\n"); + return; + } + + if (digests[1].hash_type != VB2_HASH_INVALID) { + printk(BIOS_WARNING, "TPM LOG: coreboot log can't handle multiple banks\n"); + return; + } + struct tpm_cb_log_entry *tce = &tclt->entries[tclt->num_entries++]; strncpy(tce->name, name, TPM_CB_LOG_PCR_HASH_NAME - 1); tce->name[TPM_CB_LOG_PCR_HASH_NAME - 1] = '\0'; tce->pcr = pcr; - if (digest_len > TPM_CB_LOG_DIGEST_MAX_LENGTH) { + if (vb2_digest_size(digests[0].hash_type) > TPM_CB_LOG_DIGEST_MAX_LENGTH) { printk(BIOS_WARNING, "TPM LOG: PCR digest too long for log entry\n"); return; } strncpy(tce->digest_type, - vb2_get_hash_algorithm_name(digest_algo), + vb2_get_hash_algorithm_name(digests[0].hash_type), TPM_CB_LOG_PCR_HASH_LEN - 1); - tce->digest_length = digest_len; - memcpy(tce->digest, digest, tce->digest_length); + tce->digest_length = vb2_digest_size(digests[0].hash_type); + memcpy(tce->digest, digests[0].hash, tce->digest_length); } void tpm_cb_preram_log_clear(void) @@ -104,8 +112,7 @@ void tpm_cb_preram_log_clear(void) tclt->num_entries = 0; } -int tpm_cb_log_get(int entry_idx, int *pcr, const uint8_t **digest_data, - enum vb2_hash_algorithm *digest_algo, const char **event_name) +int tpm_cb_log_get(int entry_idx, int *pcr, struct tpm_digest *digests, const char **event_name) { struct tpm_cb_log_table *tclt; struct tpm_cb_log_entry *tce; @@ -121,16 +128,19 @@ int tpm_cb_log_get(int entry_idx, int *pcr, const uint8_t **digest_data, tce = &tclt->entries[entry_idx]; *pcr = tce->pcr; - *digest_data = tce->digest; *event_name = tce->name; - *digest_algo = VB2_HASH_INVALID; + digests[0].hash = tce->digest; + digests[0].hash_type = VB2_HASH_INVALID; for (algo = VB2_HASH_INVALID; algo != VB2_HASH_ALG_COUNT; ++algo) { if (strcmp(tce->digest_type, vb2_hash_names[algo]) == 0) { - *digest_algo = algo; + digests[0].hash_type = algo; break; } } + + digests[1].hash_type = VB2_HASH_INVALID; + return 0; } diff --git a/src/security/tpm/tspi/logs.h b/src/security/tpm/tspi/logs.h index 3bfd0909175..f8b537576f6 100644 --- a/src/security/tpm/tspi/logs.h +++ b/src/security/tpm/tspi/logs.h @@ -7,6 +7,8 @@ #include #include +struct tpm_digest; + /* coreboot-specific TPM log format */ void *tpm_cb_log_init(void); @@ -14,12 +16,9 @@ void *tpm_cb_log_cbmem_init(void); void tpm_cb_preram_log_clear(void); uint16_t tpm_cb_log_get_size(const void *log_table); void tpm_cb_log_copy_entries(const void *from, void *to); -int tpm_cb_log_get(int entry_idx, int *pcr, const uint8_t **digest_data, - enum vb2_hash_algorithm *digest_algo, const char **event_name); +int tpm_cb_log_get(int entry_idx, int *pcr, struct tpm_digest *digests, const char **event_name); void tpm_cb_log_add_table_entry(const char *name, const uint32_t pcr, - enum vb2_hash_algorithm digest_algo, - const uint8_t *digest, - const size_t digest_len); + const struct tpm_digest *digests); void tpm_cb_log_dump(void); /* TPM 1.2 log format */ @@ -29,12 +28,9 @@ void *tpm1_log_cbmem_init(void); void tpm1_preram_log_clear(void); uint16_t tpm1_log_get_size(const void *log_table); void tpm1_log_copy_entries(const void *from, void *to); -int tpm1_log_get(int entry_idx, int *pcr, const uint8_t **digest_data, - enum vb2_hash_algorithm *digest_algo, const char **event_name); +int tpm1_log_get(int entry_idx, int *pcr, struct tpm_digest *digests, const char **event_name); void tpm1_log_add_table_entry(const char *name, const uint32_t pcr, - enum vb2_hash_algorithm digest_algo, - const uint8_t *digest, - const size_t digest_len); + const struct tpm_digest *digests); void tpm1_log_dump(void); /* TPM 2.0 log format */ @@ -44,14 +40,13 @@ void *tpm2_log_cbmem_init(void); void tpm2_preram_log_clear(void); uint16_t tpm2_log_get_size(const void *log_table); void tpm2_log_copy_entries(const void *from, void *to); -int tpm2_log_get(int entry_idx, int *pcr, const uint8_t **digest_data, - enum vb2_hash_algorithm *digest_algo, const char **event_name); +int tpm2_log_get(int entry_idx, int *pcr, struct tpm_digest *digests, const char **event_name); void tpm2_log_add_table_entry(const char *name, const uint32_t pcr, - enum vb2_hash_algorithm digest_algo, - const uint8_t *digest, - const size_t digest_len); + const struct tpm_digest *digests); void tpm2_log_startup_locality(int locality); +void tpm2_log_align_with_tpm(void); void tpm2_log_dump(void); +bool tpm2_log_alg_active(enum vb2_hash_algorithm alg); static inline uint16_t tpm2_alg_from_vb2_hash(enum vb2_hash_algorithm hash_type) { diff --git a/src/security/tpm/tspi/tspi.c b/src/security/tpm/tspi/tspi.c index 8c951506f29..7fb513be208 100644 --- a/src/security/tpm/tspi/tspi.c +++ b/src/security/tpm/tspi/tspi.c @@ -219,13 +219,14 @@ tpm_result_t tpm_clear_and_reenable(void) return TPM_SUCCESS; } -tpm_result_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo, - const uint8_t *digest, size_t digest_len, const char *name) +tpm_result_t tpm_extend_pcr(int pcr, const struct tpm_digest *digests, const char *name) { tpm_result_t rc; - if (!digest) + if (digests[0].hash_type == VB2_HASH_INVALID) { + /* This may be a sign of an absent TPM. */ return TPM_IOERROR; + } if (!tspi_tpm_log_available()) { rc = tspi_init_crtm(); @@ -245,7 +246,7 @@ tpm_result_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo, } printk(BIOS_DEBUG, "TPM: Extending digest for `%s` into PCR %d\n", name, pcr); - rc = tlcl_extend(pcr, digest, digest_algo); + rc = tlcl_extend(pcr, digests); if (rc != TPM_SUCCESS) { printk(BIOS_ERR, "TPM Error (%#x): Extending hash for `%s` into PCR %d failed.\n", rc, name, pcr); @@ -254,7 +255,7 @@ tpm_result_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo, } if (CONFIG(TPM_MEASURED_BOOT)) - tpm_log_add_table_entry(name, pcr, digest_algo, digest, digest_len); + tpm_log_add_table_entry(name, pcr, digests); printk(BIOS_DEBUG, "TPM: Digest of `%s` to PCR %d %s\n", name, pcr, tspi_tpm_is_setup() ? "measured" : "logged"); @@ -266,43 +267,84 @@ tpm_result_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo, tpm_result_t tpm_measure_region(const struct region_device *rdev, uint8_t pcr, const char *rname) { - uint8_t digest[TPM_PCR_MAX_LEN], digest_len; uint8_t buf[HASH_DATA_CHUNK_SIZE]; uint32_t offset; + int i, j; size_t len; struct vb2_digest_context ctx; + struct tpm_digests digests; if (!rdev || !rname) return TPM_CB_INVALID_ARG; - digest_len = vb2_digest_size(tpm_log_alg()); - assert(digest_len <= sizeof(digest)); - if (vb2_digest_init(&ctx, vboot_hwcrypto_allowed(), tpm_log_alg(), - region_device_sz(rdev))) { - printk(BIOS_ERR, "TPM: Error initializing hash.\n"); - return TPM_CB_HASH_ERROR; - } - /* - * Though one can mmap the full needed region on x86 this is not the - * case for e.g. ARM. In order to make this code as universal as - * possible across different platforms read the data to hash in chunks. - */ - for (offset = 0; offset < region_device_sz(rdev); offset += len) { - len = MIN(sizeof(buf), region_device_sz(rdev) - offset); - if (rdev_readat(rdev, buf, offset, len) < 0) { - printk(BIOS_ERR, "TPM: Not able to read region %s.\n", - rname); - return TPM_CB_READ_FAILURE; + for (i = 0, j = 0; i < ENABLED_TPM_ALGS_NUM; ++i) { + enum vb2_hash_algorithm alg = enabled_tpm_algs[i]; + if (!tpm_log_alg_active(alg)) + continue; + + if (vb2_digest_init(&ctx, vboot_hwcrypto_allowed(), alg, + region_device_sz(rdev))) { + printk(BIOS_ERR, "TPM: Error initializing hash.\n"); + return TPM_CB_HASH_ERROR; } - if (vb2_digest_extend(&ctx, buf, len)) { - printk(BIOS_ERR, "TPM: Error extending hash.\n"); + /* + * Though one can mmap the full needed region on x86 this is not the + * case for e.g. ARM. In order to make this code as universal as + * possible across different platforms read the data to hash in chunks. + */ + for (offset = 0; offset < region_device_sz(rdev); offset += len) { + len = MIN(sizeof(buf), region_device_sz(rdev) - offset); + if (rdev_readat(rdev, buf, offset, len) < 0) { + printk(BIOS_ERR, "TPM: Not able to read region %s.\n", + rname); + return TPM_CB_READ_FAILURE; + } + if (vb2_digest_extend(&ctx, buf, len)) { + printk(BIOS_ERR, "TPM: Error extending hash.\n"); + return TPM_CB_HASH_ERROR; + } + } + if (vb2_digest_finalize(&ctx, digests.hashes[j].raw, vb2_digest_size(alg))) { + printk(BIOS_ERR, "TPM: Error finalizing hash.\n"); return TPM_CB_HASH_ERROR; } + + digests.values[j].hash = digests.hashes[j].raw; + digests.values[j].hash_type = alg; + ++j; } - if (vb2_digest_finalize(&ctx, digest, digest_len)) { - printk(BIOS_ERR, "TPM: Error finalizing hash.\n"); - return TPM_CB_HASH_ERROR; + + digests.values[j].hash_type = VB2_HASH_INVALID; + return tpm_extend_pcr(pcr, digests.values, rname); +} + +bool tpm_make_digests(const void *buffer, size_t size, const struct vb2_hash *hash_hint, + struct tpm_digests *digests) +{ + int i, j; + for (i = 0, j = 0; i < ENABLED_TPM_ALGS_NUM; ++i) { + enum vb2_hash_algorithm alg = enabled_tpm_algs[i]; + if (!tpm_log_alg_active(alg)) + continue; + + digests->values[j].hash_type = alg; + + if (hash_hint != NULL && hash_hint->algo == alg) { + digests->values[j++].hash = hash_hint->raw; + continue; + } + + if (vb2_hash_calculate(vboot_hwcrypto_allowed(), buffer, size, + alg, &digests->hashes[i])) { + printk(BIOS_ERR, "%s: failed to compute %s hash.\n", __func__, + vb2_get_hash_algorithm_name(alg)); + return false; + } + + digests->values[j++].hash = digests->hashes[i].raw; } - return tpm_extend_pcr(pcr, tpm_log_alg(), digest, digest_len, rname); + + digests->values[j].hash_type = VB2_HASH_INVALID; + return true; } #endif /* VBOOT_LIB */ diff --git a/src/security/tpm/tss.h b/src/security/tpm/tss.h index c9aec082620..ac77d3b50d3 100644 --- a/src/security/tpm/tss.h +++ b/src/security/tpm/tss.h @@ -10,6 +10,7 @@ #define TSS_H_ #include +#include #include #include @@ -20,6 +21,13 @@ #include #include +struct tpm_digest { + /* Pointer to an array of length vb2_digest_size(hash_type) or bigger */ + const uint8_t *hash; + /* VB2_HASH_NONE/VB2_HASH_INVALID here marks the end of a digests list */ + enum vb2_hash_algorithm hash_type; +}; + /* * Operations that are applicable to both TPM versions have wrappers which * pick the implementation based on version determined during initialization via @@ -153,10 +161,9 @@ static inline tpm_result_t tlcl_force_clear(void) /** * Perform a TPM_Extend. */ -static inline tpm_result_t tlcl_extend(int pcr_num, const uint8_t *digest_data, - enum vb2_hash_algorithm digest_algo) +static inline tpm_result_t tlcl_extend(int pcr_num, const struct tpm_digest *digests) { - TLCL_CALL(extend, pcr_num, digest_data, digest_algo); + TLCL_CALL(extend, pcr_num, digests); } extern tis_sendrecv_fn tlcl_tis_sendrecv; diff --git a/src/security/tpm/tss/tcg-1.2/tss.c b/src/security/tpm/tss/tcg-1.2/tss.c index 04a02682a98..d050aa6b83e 100644 --- a/src/security/tpm/tss/tcg-1.2/tss.c +++ b/src/security/tpm/tss/tcg-1.2/tss.c @@ -318,18 +318,17 @@ tpm_result_t tlcl1_set_global_lock(void) return tlcl1_write(TPM_NV_INDEX0, NULL, 0); } -tpm_result_t tlcl1_extend(int pcr_num, const uint8_t *digest_data, - enum vb2_hash_algorithm digest_algo) +tpm_result_t tlcl1_extend(int pcr_num, const struct tpm_digest *digests) { struct s_tpm_extend_cmd cmd; uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength]; - if (digest_algo != VB2_HASH_SHA1) - return TPM_CB_INVALID_ARG; + if (digests[0].hash_type != VB2_HASH_SHA1 || digests[1].hash_type != VB2_HASH_INVALID) + return TPM_CB_HASH_ERROR; memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd)); to_tpm_uint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num); - memcpy(cmd.buffer + cmd.inDigest, digest_data, kPcrDigestLength); + memcpy(cmd.buffer + cmd.inDigest, digests[0].hash, kPcrDigestLength); return tlcl1_send_receive(cmd.buffer, response, sizeof(response)); } diff --git a/src/security/tpm/tss/tcg-2.0/tss.c b/src/security/tpm/tss/tcg-2.0/tss.c index 68d50f4f194..5701541d120 100644 --- a/src/security/tpm/tss/tcg-2.0/tss.c +++ b/src/security/tpm/tss/tcg-2.0/tss.c @@ -140,27 +140,29 @@ static TPM_ALG_ID tpmalg_from_vb2_hash(enum vb2_hash_algorithm hash_type) } } -/* - * The caller will provide the digest in a 32 byte buffer, let's consider it a - * sha256 digest. - */ -tpm_result_t tlcl2_extend(int pcr_num, const uint8_t *digest_data, - enum vb2_hash_algorithm digest_type) +tpm_result_t tlcl2_extend(int pcr_num, const struct tpm_digest *digests) { struct tpm2_pcr_extend_cmd pcr_ext_cmd; struct tpm2_response *response; - TPM_ALG_ID alg; + int i; + + for (i = 0; digests[i].hash_type != VB2_HASH_INVALID; ++i) { + TPM_ALG_ID alg = tpmalg_from_vb2_hash(digests[i].hash_type); + if (alg == TPM_ALG_ERROR) + return TPM_CB_HASH_ERROR; + + pcr_ext_cmd.digests.digests[i].hashAlg = alg; + + /* Always copying to sha512 as it's the largest one. */ + memcpy(pcr_ext_cmd.digests.digests[i].digest.sha512, digests[i].hash, + vb2_digest_size(digests[i].hash_type)); + } - alg = tpmalg_from_vb2_hash(digest_type); - if (alg == TPM_ALG_ERROR) + if (i == 0) return TPM_CB_HASH_ERROR; pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num; - pcr_ext_cmd.digests.count = 1; - pcr_ext_cmd.digests.digests[0].hashAlg = alg; - /* Always copying to sha512 as it's the largest one */ - memcpy(pcr_ext_cmd.digests.digests[0].digest.sha512, digest_data, - vb2_digest_size(digest_type)); + pcr_ext_cmd.digests.count = i; response = tlcl2_process_command(TPM2_PCR_Extend, &pcr_ext_cmd); @@ -494,3 +496,31 @@ tpm_result_t tlcl2_get_capability(TPM_CAP capability, uint32_t property, memcpy(capability_data, &response->gc.cd, sizeof(TPMS_CAPABILITY_DATA)); return TPM_SUCCESS; } + +tpm_result_t tlcl2_get_capability_pcrs(TPML_PCR_SELECTION *pcrs) +{ + TPMS_CAPABILITY_DATA TpmCap; + tpm_result_t rc; + int index; + + rc = tlcl2_get_capability(TPM_CAP_PCRS, 0, 1, &TpmCap); + if (rc != TPM_SUCCESS) + return rc; + + pcrs->count = TpmCap.data.assignedPCR.count; + printk(BIOS_DEBUG, "%s(): pcrs->count = %d\n", __func__, pcrs->count); + + for (index = 0; index < pcrs->count; index++) { + pcrs->pcrSelections[index].hash = + swab16(TpmCap.data.assignedPCR.pcrSelections[index].hash); + printk(BIOS_DEBUG, "%s(): pcrs->pcrSelections[%d].hash = %#x\n", + __func__, index, pcrs->pcrSelections[index].hash); + pcrs->pcrSelections[index].sizeofSelect = + TpmCap.data.assignedPCR.pcrSelections[index].sizeofSelect; + memcpy(pcrs->pcrSelections[index].pcrSelect, + TpmCap.data.assignedPCR.pcrSelections[index].pcrSelect, + pcrs->pcrSelections[index].sizeofSelect); + } + + return TPM_SUCCESS; +} diff --git a/src/security/tpm/tss/tcg-2.0/tss_structures.h b/src/security/tpm/tss/tcg-2.0/tss_structures.h index 5893ffdb68d..50b23317a9e 100644 --- a/src/security/tpm/tss/tcg-2.0/tss_structures.h +++ b/src/security/tpm/tss/tcg-2.0/tss_structures.h @@ -17,7 +17,7 @@ #define TPM2_RC_SUCCESS 0 #define TPM2_RC_NV_DEFINED 0x14c -#define HASH_COUNT 2 /* SHA-1 and SHA-256 are supported */ +#define HASH_COUNT 4 /* SHA-1, SHA-256, SHA384, SHA512 */ /* Basic TPM2 types. */ typedef uint16_t TPM_SU; diff --git a/src/security/tpm/tss1.h b/src/security/tpm/tss1.h index 9894e80b200..1f6c48c7287 100644 --- a/src/security/tpm/tss1.h +++ b/src/security/tpm/tss1.h @@ -4,7 +4,6 @@ #define TSS1_H_ #include -#include #include #include @@ -78,6 +77,8 @@ tpm_result_t tlcl1_get_permissions(uint32_t index, uint32_t *permissions); * based on TPM family. */ +struct tpm_digest; + tpm_result_t tlcl1_save_state(void); tpm_result_t tlcl1_resume(void); tpm_result_t tlcl1_startup(void); @@ -88,7 +89,6 @@ tpm_result_t tlcl1_assert_physical_presence(void); tpm_result_t tlcl1_physical_presence_cmd_enable(void); tpm_result_t tlcl1_finalize_physical_presence(void); tpm_result_t tlcl1_force_clear(void); -tpm_result_t tlcl1_extend(int pcr_num, const uint8_t *digest_data, - enum vb2_hash_algorithm digest_algo); +tpm_result_t tlcl1_extend(int pcr_num, const struct tpm_digest *digests); #endif /* TSS1_H_ */ diff --git a/src/security/tpm/tss2.h b/src/security/tpm/tss2.h index 9bb562a2349..6e6a52faf4d 100644 --- a/src/security/tpm/tss2.h +++ b/src/security/tpm/tss2.h @@ -4,7 +4,6 @@ #define TSS2_H_ #include -#include #include #include @@ -42,6 +41,21 @@ tpm_result_t tlcl2_get_capability(TPM_CAP capability, uint32_t property, uint32_t property_count, TPMS_CAPABILITY_DATA *capability_data); +/* + * tlcl2_get_capability_pcrs + * + * Return the TPM PCR information. + * + * This function parses the data got from tlcl2_get_capability and returns the + * PcrSelection. + * + * @param[out] pcrs The Pcr Selection + * + * @retval TPM_SUCCESS Operation completed successfully. + * @retval TPM_IOERROR The command was unsuccessful. + */ +tpm_result_t tlcl2_get_capability_pcrs(TPML_PCR_SELECTION *pcrs); + /* Issue TPM2_NV_SetBits command */ tpm_result_t tlcl2_set_bits(uint32_t index, uint64_t bits); @@ -74,6 +88,8 @@ tpm_result_t tlcl2_disable_platform_hierarchy(void); * based on TPM family. */ +struct tpm_digest; + tpm_result_t tlcl2_save_state(void); tpm_result_t tlcl2_resume(void); tpm_result_t tlcl2_startup(void); @@ -84,7 +100,6 @@ tpm_result_t tlcl2_assert_physical_presence(void); tpm_result_t tlcl2_physical_presence_cmd_enable(void); tpm_result_t tlcl2_finalize_physical_presence(void); tpm_result_t tlcl2_force_clear(void); -tpm_result_t tlcl2_extend(int pcr_num, const uint8_t *digest_data, - enum vb2_hash_algorithm digest_algo); +tpm_result_t tlcl2_extend(int pcr_num, const struct tpm_digest *digests); #endif /* TSS2_H_ */ diff --git a/src/security/vboot/tpm_common.c b/src/security/vboot/tpm_common.c index dedf8dfebcc..04a7dc31805 100644 --- a/src/security/vboot/tpm_common.c +++ b/src/security/vboot/tpm_common.c @@ -25,7 +25,7 @@ tpm_result_t vboot_setup_tpm(struct vb2_context *ctx) tpm_result_t vboot_extend_pcr(struct vb2_context *ctx, int pcr, enum vb2_pcr_digest which_digest) { - uint8_t buffer[VB2_PCR_DIGEST_RECOMMENDED_SIZE]; + uint8_t buffer[VB2_MAX_DIGEST_SIZE]; uint32_t size = sizeof(buffer); if (vb2api_get_pcr_digest(ctx, which_digest, buffer, &size) != VB2_SUCCESS) @@ -44,22 +44,39 @@ tpm_result_t vboot_extend_pcr(struct vb2_context *ctx, int pcr, */ _Static_assert(sizeof(buffer) >= VB2_SHA256_DIGEST_SIZE, "Buffer needs to be able to fit at least a SHA256"); - enum vb2_hash_algorithm algo = tlcl_get_family() == TPM_1 ? - VB2_HASH_SHA1 : VB2_HASH_SHA256; + + int i, j; + struct tpm_digest digests[ENABLED_TPM_ALGS_NUM + 1]; + for (i = 0, j = 0; i < ENABLED_TPM_ALGS_NUM; ++i) { + enum vb2_hash_algorithm alg = enabled_tpm_algs[i]; + if (!tpm_log_alg_active(alg)) + continue; + + if (vb2_digest_size(alg) > sizeof(buffer)) { + printk(BIOS_WARNING, + "vboot: Not extending %s digest (buffer in %s is too small).\n", + vb2_get_hash_algorithm_name(alg), __func__); + continue; + } + + /* Extending the same data to all banks. It either gets truncated, fits + perfectly or is padded with zeroes. */ + digests[j].hash = buffer; + digests[j].hash_type = alg; + ++j; + } + digests[j].hash_type = VB2_HASH_INVALID; switch (which_digest) { /* SHA1 of (devmode|recmode|keyblock) bits */ case BOOT_MODE_PCR: - return tpm_extend_pcr(pcr, algo, buffer, vb2_digest_size(algo), - TPM_PCR_BOOT_MODE); + return tpm_extend_pcr(pcr, digests, TPM_PCR_BOOT_MODE); /* SHA256 of HWID */ case HWID_DIGEST_PCR: - return tpm_extend_pcr(pcr, algo, buffer, vb2_digest_size(algo), - TPM_PCR_GBB_HWID_NAME); + return tpm_extend_pcr(pcr, digests, TPM_PCR_GBB_HWID_NAME); /* firmware version */ case FIRMWARE_VERSION_PCR: - return tpm_extend_pcr(pcr, algo, buffer, vb2_digest_size(algo), - TPM_PCR_FIRMWARE_VERSION); + return tpm_extend_pcr(pcr, digests, TPM_PCR_FIRMWARE_VERSION); default: return TPM_CB_FAIL; } diff --git a/src/vendorcode/eltan/security/mboot/mboot.c b/src/vendorcode/eltan/security/mboot/mboot.c index 9cdd0de2fe8..67ec41e2c6c 100644 --- a/src/vendorcode/eltan/security/mboot/mboot.c +++ b/src/vendorcode/eltan/security/mboot/mboot.c @@ -19,7 +19,7 @@ EFI_TCG2_EVENT_ALGORITHM_BITMAP tpm2_get_active_pcrs(void) uint32_t activePcrBanks = 0; uint32_t index; - rc = tpm2_get_capability_pcrs(&Pcrs); + rc = tlcl2_get_capability_pcrs(&Pcrs); if (rc != TPM_SUCCESS) { tpmHashAlgorithmBitmap = EFI_TCG2_BOOT_HASH_ALG_SHA1; activePcrBanks = EFI_TCG2_BOOT_HASH_ALG_SHA1; @@ -62,44 +62,6 @@ EFI_TCG2_EVENT_ALGORITHM_BITMAP tpm2_get_active_pcrs(void) return activePcrBanks; } -/* - * tpm2_get_capability_pcrs - * - * Return the TPM PCR information. - * - * This function parses the data got from tlcl2_get_capability and returns the - * PcrSelection. - * - * @param[out] Pcrs The Pcr Selection - * - * @retval TPM_SUCCESS Operation completed successfully. - * @retval TPM_IOERROR The command was unsuccessful. - */ -tpm_result_t tpm2_get_capability_pcrs(TPML_PCR_SELECTION *Pcrs) -{ - TPMS_CAPABILITY_DATA TpmCap; - tpm_result_t rc; - int index; - - rc = tlcl2_get_capability(TPM_CAP_PCRS, 0, 1, &TpmCap); - if (rc == TPM_SUCCESS) { - Pcrs->count = TpmCap.data.assignedPCR.count; - printk(BIOS_DEBUG, "Pcrs->count = %d\n", Pcrs->count); - for (index = 0; index < Pcrs->count; index++) { - Pcrs->pcrSelections[index].hash = - swab16(TpmCap.data.assignedPCR.pcrSelections[index].hash); - printk(BIOS_DEBUG, "Pcrs->pcrSelections[%d].hash = %#x\n", index, - Pcrs->pcrSelections[index].hash); - Pcrs->pcrSelections[index].sizeofSelect = - TpmCap.data.assignedPCR.pcrSelections[index].sizeofSelect; - memcpy(Pcrs->pcrSelections[index].pcrSelect, - TpmCap.data.assignedPCR.pcrSelections[index].pcrSelect, - Pcrs->pcrSelections[index].sizeofSelect); - } - } - return rc; -} - /* * mboot_hash_extend_log *