diff mbox series

[v2,8/8] tpm: allow the user to select the compiled algorithms

Message ID 20240623114838.14639-9-ilias.apalodimas@linaro.org
State Accepted
Commit e7505b3b8bcd1bca2d30291367713f442b453c41
Headers show
Series The great TCG deduplication saga | expand

Commit Message

Ilias Apalodimas June 23, 2024, 11:48 a.m. UTC
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.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(-)

Comments

Simon Glass June 23, 2024, 9:52 p.m. UTC | #1
Hi Ilias,

On Sun, 23 Jun 2024 at 05:49, Ilias Apalodimas
<ilias.apalodimas@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.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(-)

Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Simon Glass <sjg@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
Ilias Apalodimas June 24, 2024, 4:43 a.m. UTC | #2
On Mon, 24 Jun 2024 at 00:52, Simon Glass <sjg@chromium.org> wrote:
>
> Hi Ilias,
>
> On Sun, 23 Jun 2024 at 05:49, Ilias Apalodimas
> <ilias.apalodimas@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.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(-)
>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> Tested-by: Simon Glass <sjg@chromium.org>  # chromebook-link
>
> nits / thoughts for the future below

I'll fix the spelling errors before merging

> >
> > 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)

The name and length are. TPM2_ALG_SHAXXX is what the device returns
though when probed for available algorithms and since those values are
not maskable, TCG defined its masks .... TCG2_BOOT_HASH_ALG_SHA512
etc.
This is unfortunate but I can't immediately think of an elegant way to
combine those.

>
> >                 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

Yes, I was toying around with the idea of creating a mask with the
supported algorithms. We could even reuse the masking the TCG defines.
There's nothing special to this function tbh, so we can move it in
common/hash.c instead as well. But I'll pick this as-is for now and
plan for a wider refactoring of all the hashing support we have. There
are a lot of places we redefine those and we shouldn't.

Thanks
/Ilias

>
> > +
> > +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
diff mbox series

Patch

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",
 		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,
@@ -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
+ * 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;
+}