Hi Ilias, On Sun, 23 Jun 2024 at 05:49, Ilias Apalodimas <ilias.apalodi...@linaro.org> 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 is 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. We only allow > extending PCRs if the algorithms selected during build match the TPM > configuration. > > It's worth noting that this is only added for TPM2.0, since TPM1.2 is > lacking a lot of code at the moment to read the available PCR banks. > We unconditionally enable SHA1 when a TPM is selected, which is the only > hashing algorithm v1.2 supports. > > Signed-off-by: Ilias Apalodimas <ilias.apalodi...@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(-)
Reviewed-by: Simon Glass <s...@chromium.org> Tested-by: Simon Glass <s...@chromium.org> # chromebook-link nits / thoughts for the future below > > 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 aedf2c0f4f5c..4fd19c52fd70 100644 > --- a/include/tpm-v2.h > +++ b/include/tpm-v2.h > @@ -278,48 +278,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", This is a duplicate of common/hash.c (we can worry about all this later) > TPM2_ALG_SHA512, > TCG2_BOOT_HASH_ALG_SHA512, > TPM2_SHA512_DIGEST_SIZE, so is this > }, > +#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, > @@ -712,6 +704,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 U-Boot's > + * 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 might > + * since it doesn't have a TPM driver, which U-Boot needs to replace. The > algorit h algorithm > + * 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) nit: return uint? There is no need to mask the register here > +{ > + 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; > +} At some point we could have a HASH_ALGOT variable in hash.h which encodes the hash algorithm, then some of this will be common > + > +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; > +} > -- > 2.45.2 > REgards, Simon