diff mbox series

[v2,3/6] tpm: add wrapper and helper APIs for PCR allocate

Message ID 20250117164032.88942-4-raymond.mao@linaro.org
State Superseded
Delegated to: Ilias Apalodimas
Headers show
Series Reconfigure TPM when active hash algorithms dismatch | expand

Commit Message

Raymond Mao Jan. 17, 2025, 4:40 p.m. UTC
Add PCR allocate wrapper APIs for using in tcg2 protocol.
The wrapper proceeds a PCR allocate command, followed by a
shutdown command.
A system boot is required after two commands since TPM device needs
a HW reset to activate the new algorithms config.
Also, a helper function is included to determine the new bank mask
for PCR allocation by combining the status of current active,
supported and eventlog bank masks.
A new kconfig is created. PCR allocate and system reboot only
happens when the kconfig is selected, otherwise just exit with
errors.

Signed-off-by: Raymond Mao <raymond.mao@linaro.org>
---
changes in v2
- Rename the newly added APIs.

 include/tpm-v2.h |  22 +++++++++
 lib/Kconfig      |  12 +++++
 lib/tpm-v2.c     | 121 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)

Comments

Ilias Apalodimas Jan. 23, 2025, 6:31 a.m. UTC | #1
Hi Raymond,


On Fri, 17 Jan 2025 at 18:40, Raymond Mao <raymond.mao@linaro.org> wrote:
>
> Add PCR allocate wrapper APIs for using in tcg2 protocol.
> The wrapper proceeds a PCR allocate command, followed by a
> shutdown command.
> A system boot is required after two commands since TPM device needs
> a HW reset to activate the new algorithms config.
> Also, a helper function is included to determine the new bank mask
> for PCR allocation by combining the status of current active,
> supported and eventlog bank masks.
> A new kconfig is created. PCR allocate and system reboot only
> happens when the kconfig is selected, otherwise just exit with
> errors.
>
> Signed-off-by: Raymond Mao <raymond.mao@linaro.org>
> ---
> changes in v2
> - Rename the newly added APIs.
>
>  include/tpm-v2.h |  22 +++++++++
>  lib/Kconfig      |  12 +++++
>  lib/tpm-v2.c     | 121 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 155 insertions(+)
>
> diff --git a/include/tpm-v2.h b/include/tpm-v2.h
> index af3158f6e4..58085c9c59 100644
> --- a/include/tpm-v2.h
> +++ b/include/tpm-v2.h
> @@ -703,6 +703,19 @@ u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
>  u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
>                           uint vendor_subcmd);
>
> +/**
> + * tpm2_set_algorithm_mask - Set the bitmask of algorithms based on the
> + *                          active/supported banks and the one from
> + *                          eventlog.
> + *
> + * @dev                TPM device
> + * @log_active Active algorithm bitmask
> + * @mask       Bitmask to set
> + *
> + * Return: zero on success, negative errno otherwise
> + */
> +int tpm2_set_algorithm_mask(struct udevice *dev, u32 log_active, u32 *mask);

This isn't a set right? This is getting the pcr banks we need to
configure later on.
The previous version had this as 'tpm2_pcr_allocate_get_mask' which
was a bit less confusing. But on that version, I asked to rename it to
tpm2_scan_masks(). Since the function is trying to cross-check the
available banks and the ones sent in the EventLog.
Can you rename it to that? Or perhaps tpm2_is_mask_allowed()?

Thanks
/Ilias

> +
>  /**
>   * tpm2_pcr_config_algo() - Allocate the active PCRs. Requires reboot
>   *
> @@ -730,6 +743,15 @@ u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask,
>  u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw,
>                            const ssize_t pw_sz, struct tpml_pcr_selection *pcr,
>                            u32 pcr_len);
> +/**
> + * tpm2_activate_banks() - Activate PCR banks
> + *
> + * @param dev   TPM device
> + * @log_active Bitmask of eventlog algorithms
> + *
> + * Return: code of the operation
> + */
> +int tpm2_activate_banks(struct udevice *dev, u32 log_active);
>
>  /**
>   * tpm2_auto_start() - start up the TPM and perform selftests.
> diff --git a/lib/Kconfig b/lib/Kconfig
> index baeb615626..0732333849 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -514,6 +514,18 @@ config VPL_TPM
>           for the low-level TPM interface, but only one TPM is supported at
>           a time by the TPM library.
>
> +config TPM_PCR_ALLOCATE
> +       bool "Re-configurate TPM algorithms in run-time (PCR allocate)"
> +       depends on TPM_V2 && (MEASURED_BOOT || EFI_TCG2_PROTOCOL)
> +       help
> +         This enables a detection for the dismatches of algorithms among TPM
> +         device, eventlog from previous boot stage and U-Boot support.
> +         A PCR allocate command will be sent to reconfigurate the TPM device
> +         in run-time to make sure algorithms in TPM device, eventlog and
> +         U-Boot are aligned with each other.
> +         A system reboot will be proceeded after then to activate the new
> +         algorithms.
> +
>  endmenu
>
>  menu "Android Verified Boot"
> diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
> index 045b5dd9eb..0e497b2c2a 100644
> --- a/lib/tpm-v2.c
> +++ b/lib/tpm-v2.c
> @@ -44,6 +44,127 @@ static int tpm2_update_active_banks(struct udevice *dev)
>         return 0;
>  }
>
> +static void tpm2_print_selected_algorithm_name(u32 selected)
> +{
> +       size_t i;
> +       const char *str;
> +
> +       for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
> +               const struct digest_info *algo = &hash_algo_list[i];
> +
> +               if (!(selected & algo->hash_mask))
> +                       continue;
> +
> +               str = tpm2_algorithm_name(algo->hash_alg);
> +               if (str)
> +                       log_info("%s\n", str);
> +       }
> +}
> +
> +int tpm2_set_algorithm_mask(struct udevice *dev, u32 log_active, u32 *mask)
> +{
> +       struct tpml_pcr_selection pcrs;
> +       u32 active = 0;
> +       u32 supported = 0;
> +       int rc, i;
> +
> +       *mask = 0;
> +
> +       rc = tpm2_get_pcr_info(dev, &pcrs);
> +       if (rc)
> +               return rc;
> +
> +       for (i = 0; i < pcrs.count; i++) {
> +               struct tpms_pcr_selection *sel = &pcrs.selection[i];
> +               size_t j;
> +               u32 hash_mask = 0;
> +
> +               for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) {
> +                       if (hash_algo_list[j].hash_alg == sel->hash)
> +                               hash_mask = hash_algo_list[j].hash_mask;
> +               }
> +
> +               if (tpm2_algorithm_supported(sel->hash))
> +                       supported |= hash_mask;
> +
> +               if (tpm2_is_active_bank(sel))
> +                       active |= hash_mask;
> +       }
> +
> +       /* All eventlog algorithm(s) must be supported */
> +       if (log_active & ~supported) {
> +               log_err("EventLog contains U-Boot unsupported algorithm(s)\n");
> +               tpm2_print_selected_algorithm_name(log_active & ~supported);
> +               rc = -1;
> +       }
> +       if (log_active && active & ~log_active) {
> +               log_warning("TPM active algorithm(s) not exist in eventlog\n");
> +               tpm2_print_selected_algorithm_name(active & ~log_active);
> +               *mask = log_active;
> +       }
> +
> +       /* Any active algorithm(s) which are not supported must be removed */
> +       if (active & ~supported) {
> +               log_warning("TPM active algorithm(s) unsupported by u-boot\n");
> +               tpm2_print_selected_algorithm_name(active & ~supported);
> +               if (*mask)
> +                       *mask = active & supported & *mask;
> +               else
> +                       *mask = active & supported;
> +       }
> +
> +       return rc;
> +}
> +
> +static int tpm2_pcr_allocate(struct udevice *dev, u32 algo_mask)
> +{
> +       struct tpml_pcr_selection pcr = { 0 };
> +       u32 pcr_len = 0;
> +       int rc;
> +
> +       rc = tpm2_get_pcr_info(dev, &pcr);
> +       if (rc)
> +               return rc;
> +
> +       rc = tpm2_pcr_config_algo(dev, algo_mask, &pcr, &pcr_len);
> +       if (rc)
> +               return rc;
> +
> +       /* Assume no password */
> +       rc = tpm2_send_pcr_allocate(dev, NULL, 0, &pcr, pcr_len);
> +       if (rc)
> +               return rc;
> +
> +       /* Send TPM2_Shutdown, assume mode = TPM2_SU_CLEAR */
> +       return tpm2_startup(dev, false, TPM2_SU_CLEAR);
> +}
> +
> +int tpm2_activate_banks(struct udevice *dev, u32 log_active)
> +{
> +       u32 algo_mask = 0;
> +       int rc;
> +
> +       rc = tpm2_set_algorithm_mask(dev, log_active, &algo_mask);
> +       if (rc)
> +               return rc;
> +
> +       if (algo_mask) {
> +               if (!IS_ENABLED(CONFIG_TPM_PCR_ALLOCATE))
> +                       return -1;
> +
> +               rc = tpm2_pcr_allocate(dev, algo_mask);
> +               if (rc)
> +                       return rc;
> +
> +               log_info("PCR allocate done, shutdown TPM and reboot\n");
> +               do_reset(NULL, 0, 0, NULL);
> +               log_err("reset does not work!\n");
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> +
>  u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode)
>  {
>         int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN;
> --
> 2.25.1
>
diff mbox series

Patch

diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index af3158f6e4..58085c9c59 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -703,6 +703,19 @@  u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
 u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
 			  uint vendor_subcmd);
 
+/**
+ * tpm2_set_algorithm_mask - Set the bitmask of algorithms based on the
+ *			     active/supported banks and the one from
+ *			     eventlog.
+ *
+ * @dev		TPM device
+ * @log_active	Active algorithm bitmask
+ * @mask	Bitmask to set
+ *
+ * Return: zero on success, negative errno otherwise
+ */
+int tpm2_set_algorithm_mask(struct udevice *dev, u32 log_active, u32 *mask);
+
 /**
  * tpm2_pcr_config_algo() - Allocate the active PCRs. Requires reboot
  *
@@ -730,6 +743,15 @@  u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask,
 u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw,
 			   const ssize_t pw_sz, struct tpml_pcr_selection *pcr,
 			   u32 pcr_len);
+/**
+ * tpm2_activate_banks() - Activate PCR banks
+ *
+ * @param dev   TPM device
+ * @log_active	Bitmask of eventlog algorithms
+ *
+ * Return: code of the operation
+ */
+int tpm2_activate_banks(struct udevice *dev, u32 log_active);
 
 /**
  * tpm2_auto_start() - start up the TPM and perform selftests.
diff --git a/lib/Kconfig b/lib/Kconfig
index baeb615626..0732333849 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -514,6 +514,18 @@  config VPL_TPM
 	  for the low-level TPM interface, but only one TPM is supported at
 	  a time by the TPM library.
 
+config TPM_PCR_ALLOCATE
+	bool "Re-configurate TPM algorithms in run-time (PCR allocate)"
+	depends on TPM_V2 && (MEASURED_BOOT || EFI_TCG2_PROTOCOL)
+	help
+	  This enables a detection for the dismatches of algorithms among TPM
+	  device, eventlog from previous boot stage and U-Boot support.
+	  A PCR allocate command will be sent to reconfigurate the TPM device
+	  in run-time to make sure algorithms in TPM device, eventlog and
+	  U-Boot are aligned with each other.
+	  A system reboot will be proceeded after then to activate the new
+	  algorithms.
+
 endmenu
 
 menu "Android Verified Boot"
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 045b5dd9eb..0e497b2c2a 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -44,6 +44,127 @@  static int tpm2_update_active_banks(struct udevice *dev)
 	return 0;
 }
 
+static void tpm2_print_selected_algorithm_name(u32 selected)
+{
+	size_t i;
+	const char *str;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
+		const struct digest_info *algo = &hash_algo_list[i];
+
+		if (!(selected & algo->hash_mask))
+			continue;
+
+		str = tpm2_algorithm_name(algo->hash_alg);
+		if (str)
+			log_info("%s\n", str);
+	}
+}
+
+int tpm2_set_algorithm_mask(struct udevice *dev, u32 log_active, u32 *mask)
+{
+	struct tpml_pcr_selection pcrs;
+	u32 active = 0;
+	u32 supported = 0;
+	int rc, i;
+
+	*mask = 0;
+
+	rc = tpm2_get_pcr_info(dev, &pcrs);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < pcrs.count; i++) {
+		struct tpms_pcr_selection *sel = &pcrs.selection[i];
+		size_t j;
+		u32 hash_mask = 0;
+
+		for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) {
+			if (hash_algo_list[j].hash_alg == sel->hash)
+				hash_mask = hash_algo_list[j].hash_mask;
+		}
+
+		if (tpm2_algorithm_supported(sel->hash))
+			supported |= hash_mask;
+
+		if (tpm2_is_active_bank(sel))
+			active |= hash_mask;
+	}
+
+	/* All eventlog algorithm(s) must be supported */
+	if (log_active & ~supported) {
+		log_err("EventLog contains U-Boot unsupported algorithm(s)\n");
+		tpm2_print_selected_algorithm_name(log_active & ~supported);
+		rc = -1;
+	}
+	if (log_active && active & ~log_active) {
+		log_warning("TPM active algorithm(s) not exist in eventlog\n");
+		tpm2_print_selected_algorithm_name(active & ~log_active);
+		*mask = log_active;
+	}
+
+	/* Any active algorithm(s) which are not supported must be removed */
+	if (active & ~supported) {
+		log_warning("TPM active algorithm(s) unsupported by u-boot\n");
+		tpm2_print_selected_algorithm_name(active & ~supported);
+		if (*mask)
+			*mask = active & supported & *mask;
+		else
+			*mask = active & supported;
+	}
+
+	return rc;
+}
+
+static int tpm2_pcr_allocate(struct udevice *dev, u32 algo_mask)
+{
+	struct tpml_pcr_selection pcr = { 0 };
+	u32 pcr_len = 0;
+	int rc;
+
+	rc = tpm2_get_pcr_info(dev, &pcr);
+	if (rc)
+		return rc;
+
+	rc = tpm2_pcr_config_algo(dev, algo_mask, &pcr, &pcr_len);
+	if (rc)
+		return rc;
+
+	/* Assume no password */
+	rc = tpm2_send_pcr_allocate(dev, NULL, 0, &pcr, pcr_len);
+	if (rc)
+		return rc;
+
+	/* Send TPM2_Shutdown, assume mode = TPM2_SU_CLEAR */
+	return tpm2_startup(dev, false, TPM2_SU_CLEAR);
+}
+
+int tpm2_activate_banks(struct udevice *dev, u32 log_active)
+{
+	u32 algo_mask = 0;
+	int rc;
+
+	rc = tpm2_set_algorithm_mask(dev, log_active, &algo_mask);
+	if (rc)
+		return rc;
+
+	if (algo_mask) {
+		if (!IS_ENABLED(CONFIG_TPM_PCR_ALLOCATE))
+			return -1;
+
+		rc = tpm2_pcr_allocate(dev, algo_mask);
+		if (rc)
+			return rc;
+
+		log_info("PCR allocate done, shutdown TPM and reboot\n");
+		do_reset(NULL, 0, 0, NULL);
+		log_err("reset does not work!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode)
 {
 	int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN;