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 |
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 --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;
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(+)