
On 22.06.24 16:35, Ilias Apalodimas wrote:
Simon reports that after enabling all algorithms on the TPM some boards fail since they don't have enough storage to accommodate the ~5KB growth.
The choice of hash algorithms are determined by the platform and the TPM configuration. Failing to cap a PCR in a bank which the platform left active is a security vulnerability. It might allow unsealing of secrets if an attacker can replay a good set of measurements into an unused bank.
If MEASURED_BOOT or EFI_TCG2_PROTOCOL is enabled our Kconfig will enable all supported hashing algorithms. We still want to allow users to add a TPM and not enable measured boot via EFI or bootm though and at the same time, control the compiled algorithms for size reasons.
So let's add a function tpm2_allow_extend() which checks the TPM active PCRs banks against the one U-Boot was compiled with. If all the active PCRs banks are not enabled refuse to extend a PCR but otherwise leave the TPM functional.
The paragraph above is bit hard to read. I guess you mean:
We only allow extending PCRs using one of the algorithms selected in the configuration.
It's worth noting that this is only added on TPM2.0, since TPM1.2 is lacking a lot of code at the moment to read the available PCRs. We unconditionally enable SHA1 when a TPM is selected, which is the only hashing algorithm v1.2 supports.
Why do we need SHA1 if we cannot access PCRs on a TPM1.2?
Best regards
Heinrich
Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org
boot/Kconfig | 4 ++++ include/tpm-v2.h | 59 +++++++++++++++++++++++++++++++++++------------- lib/Kconfig | 6 ++--- lib/tpm-v2.c | 40 +++++++++++++++++++++++++++++--- 4 files changed, 87 insertions(+), 22 deletions(-)
diff --git a/boot/Kconfig b/boot/Kconfig index 6f3096c15a6f..b061891e109c 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -734,6 +734,10 @@ config LEGACY_IMAGE_FORMAT config MEASURED_BOOT bool "Measure boot images and configuration when booting without EFI" depends on HASH && TPM_V2
- select SHA1
- select SHA256
- select SHA384
- select SHA512 help This option enables measurement of the boot process when booting without UEFI . Measurement involves creating cryptographic hashes
diff --git a/include/tpm-v2.h b/include/tpm-v2.h index eac04d1c6831..fccb07fa4695 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -277,48 +277,40 @@ struct digest_info { #define TCG2_BOOT_HASH_ALG_SM3_256 0x00000010
static const struct digest_info hash_algo_list[] = { +#if IS_ENABLED(CONFIG_SHA1) { "sha1", TPM2_ALG_SHA1, TCG2_BOOT_HASH_ALG_SHA1, TPM2_SHA1_DIGEST_SIZE, }, +#endif +#if IS_ENABLED(CONFIG_SHA256) { "sha256", TPM2_ALG_SHA256, TCG2_BOOT_HASH_ALG_SHA256, TPM2_SHA256_DIGEST_SIZE, }, +#endif +#if IS_ENABLED(CONFIG_SHA384) { "sha384", TPM2_ALG_SHA384, TCG2_BOOT_HASH_ALG_SHA384, TPM2_SHA384_DIGEST_SIZE, }, +#endif +#if IS_ENABLED(CONFIG_SHA512) { "sha512", TPM2_ALG_SHA512, TCG2_BOOT_HASH_ALG_SHA512, TPM2_SHA512_DIGEST_SIZE, }, +#endif };
-static inline u16 tpm2_algorithm_to_len(enum tpm2_algorithms a) -{
- switch (a) {
- case TPM2_ALG_SHA1:
return TPM2_SHA1_DIGEST_SIZE;
- case TPM2_ALG_SHA256:
return TPM2_SHA256_DIGEST_SIZE;
- case TPM2_ALG_SHA384:
return TPM2_SHA384_DIGEST_SIZE;
- case TPM2_ALG_SHA512:
return TPM2_SHA512_DIGEST_SIZE;
- default:
return 0;
- }
-}
- /* NV index attributes */ enum tpm_index_attrs { TPMA_NV_PPWRITE = 1UL << 0,
@@ -711,6 +703,41 @@ enum tpm2_algorithms tpm2_name_to_algorithm(const char *name); */ const char *tpm2_algorithm_name(enum tpm2_algorithms);
+/**
- tpm2_algorithm_to_len() - Return an algorithm length for supported algorithm id
- @algorithm_id: algorithm defined in enum tpm2_algorithms
- Return: len or 0 if not supported
- */
+u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo);
+/*
- When measured boot is enabled via EFI or bootX commands all the algorithms
- above are selected by our Kconfigs. Due to U-Boots nature of being small there
- are cases where we need some functionality from the TPM -- e.g storage or RNG
- but we don't want to support measurements.
- The choice of hash algorithms are determined by the platform and the TPM
- configuration. Failing to cap a PCR in a bank which the platform left
- active is a security vulnerability. It permits the unsealing of secrets
- if an attacker can replay a good set of measurements into an unused bank.
- On top of that a previous stage bootloader (e.g TF-A), migh pass an eventlog
- since it doesn't have a TPM driver, which U-Boot needs to replace. The algorit h
- choice is a compile time option in that case and we need to make sure we conform.
- Add a variable here that sums the supported algorithms U-Boot was compiled
- with so we can refuse to do measurements if we don't support all of them
- */
+/**
- tpm2_allow_extend() - Check if extending PCRs is allowed and safe
- @dev: TPM device
- Return: true if allowed
- */
+bool tpm2_allow_extend(struct udevice *dev);
- /**
- tpm2_is_active_pcr() - check the pcr_select. If at least one of the PCRs
supports the algorithm add it on the active ones
diff --git a/lib/Kconfig b/lib/Kconfig index 189e6eb31aa1..b3baa4b85b07 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -439,9 +439,6 @@ config TPM depends on DM imply DM_RNG select SHA1
- select SHA256
- select SHA384
- select SHA512 help This enables support for TPMs which can be used to provide security features for your board. The TPM can be connected via LPC or I2C
@@ -449,6 +446,9 @@ config TPM command to interactive the TPM. Driver model support is provided for the low-level TPM interface, but only one TPM is supported at a time by the TPM library.
For size reasons only SHA1 is selected which is supported on TPM1.2.
If you want a fully functional TPM enable all hashing algorithms.
If you enabled measured boot all hashing algorithms are selected.
config SPL_TPM bool "Trusted Platform Module (TPM) Support in SPL"
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 36aace03cf4e..59e6cbafafaa 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -196,6 +196,11 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
if (!digest) return -EINVAL;
- if (!tpm2_allow_extend(dev)) {
log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n");
return -EINVAL;
- } /*
- Fill the command structure starting from the first buffer:
- the digest
@@ -409,11 +414,10 @@ int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs)
pcrs->count = get_unaligned_be32(response); /*
* We only support 5 algorithms for now so check against that
* We only support 4 algorithms for now so check against that
*/
- instead of TPM2_NUM_PCR_BANKS
- if (pcrs->count > ARRAY_SIZE(hash_algo_list) ||
pcrs->count < 1) {
- if (pcrs->count > 4 || pcrs->count < 1) { printf("%s: too many pcrs: %u\n", __func__, pcrs->count); return -EMSGSIZE; }
@@ -880,3 +884,33 @@ const char *tpm2_algorithm_name(enum tpm2_algorithms algo) return ""; }
+u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo) +{
- size_t i;
- for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
if (hash_algo_list[i].hash_alg == algo)
return hash_algo_list[i].hash_len;
- }
- return 0;
+}
+bool tpm2_allow_extend(struct udevice *dev) +{
- struct tpml_pcr_selection pcrs;
- size_t i;
- int rc;
- rc = tpm2_get_pcr_info(dev, &pcrs);
- if (rc)
return false;
- for (i = 0; i < pcrs.count; i++) {
if (tpm2_is_active_pcr(&pcrs.selection[i]) &&
!tpm2_algorithm_to_len(pcrs.selection[i].hash))
return false;
- }
- return true;
+}