From 57c601cd7b6268176c5e501452568aa0d607053f Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Wed, 15 May 2024 16:21:38 -0700 Subject: tpm: display warning if using gpio reset with TPM Instead of displaying what looks like an error message if a gpio-reset dt prop is missing for a TPM display a warning that having a gpio reset on a TPM should not be used for a secure production device. TCG TIS spec [1] says: "The TPM_Init (LRESET#/SPI_RST#) signal MUST be connected to the platform CPU Reset signal such that it complies with the requirements specified in section 1.2.7 HOST Platform Reset in the PC Client Implementation Specification for Conventional BIOS." The reasoning is that you should not be able to toggle a GPIO and reset the TPM without resetting the CPU as well because if an attacker can break into your OS via an OS level security flaw they can then reset the TPM via GPIO and replay the measurements required to unseal keys that you have otherwise protected. Additionally restructure the code for improved readability allowing for removal of the init label. Before: - board with no reset gpio u-boot=> tpm init && tpm info tpm_tis_spi_probe: missing reset GPIO tpm@1 v2.0: VendorID 0x1114, DeviceID 0x3205, RevisionID 0x01 [open] - board with a reset gpio u-boot=> tpm init && tpm info tpm@1 v2.0: VendorID 0x1114, DeviceID 0x3205, RevisionID 0x01 [open] After: - board with no reset gpio u-boot=> tpm init && tpm info tpm@1 v2.0: VendorID 0x1114, DeviceID 0x3205, RevisionID 0x01 [open] - board with a reset gpio u-boot=> tpm init && tpm info tpm@1: TPM gpio reset should not be used on secure production devices tpm@1 v2.0: VendorID 0x1114, DeviceID 0x3205, RevisionID 0x01 [open] [1] https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientTPMInterfaceSpecification_TIS__1-3_27_03212013.pdf Signed-off-by: Tim Harvey Reviewed-by: Miquel Raynal Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- drivers/tpm/tpm2_tis_spi.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/tpm/tpm2_tis_spi.c b/drivers/tpm/tpm2_tis_spi.c index de9cf8f..7f8df31 100644 --- a/drivers/tpm/tpm2_tis_spi.c +++ b/drivers/tpm/tpm2_tis_spi.c @@ -237,19 +237,22 @@ static int tpm_tis_spi_probe(struct udevice *dev) /* legacy reset */ ret = gpio_request_by_name(dev, "gpio-reset", 0, &reset_gpio, GPIOD_IS_OUT); - if (ret) { + if (!ret) { log(LOGC_NONE, LOGL_NOTICE, - "%s: missing reset GPIO\n", __func__); - goto init; + "%s: gpio-reset is deprecated\n", __func__); } - log(LOGC_NONE, LOGL_NOTICE, - "%s: gpio-reset is deprecated\n", __func__); } - dm_gpio_set_value(&reset_gpio, 1); - mdelay(1); - dm_gpio_set_value(&reset_gpio, 0); + + if (!ret) { + log(LOGC_NONE, LOGL_WARNING, + "%s: TPM gpio reset should not be used on secure production devices\n", + dev->name); + dm_gpio_set_value(&reset_gpio, 1); + mdelay(1); + dm_gpio_set_value(&reset_gpio, 0); + } } -init: + /* Ensure a minimum amount of time elapsed since reset of the TPM */ mdelay(drv_data->time_before_first_cmd_ms); -- cgit v1.1 From 954b95e77ef0a857a0b5272e3e6c0e5318dc1208 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Sat, 25 May 2024 13:00:48 -0700 Subject: tpm-v2: add support for mapping algorithm names to algos replace tpm2_supported_algorithms with an array of structures relating algorithm names, to TCG id's, digest length and mask values. While at it fix the tpm2_algorithm_to_mask to return the proper value. Cc: Eddie James Cc: Ilias Apalodimas Fixes: 97707f12fdab ("tpm: Support boot measurements") Signed-off-by: Tim Harvey Tested-by: Ilias Apalodimas Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- include/tpm-v2.h | 77 ++++++++++++++++++++++++++++++++++++++++++-- lib/efi_loader/efi_tcg2.c | 6 ++-- lib/tpm-v2.c | 82 ++++++++++++++++++++++++++++++----------------- 3 files changed, 129 insertions(+), 36 deletions(-) diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 33dd103..c9d5cb6 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -386,7 +386,54 @@ enum tpm2_algorithms { TPM2_ALG_SM3_256 = 0x12, }; -extern const enum tpm2_algorithms tpm2_supported_algorithms[4]; +/** + * struct digest_info - details of supported digests + * + * @hash_name: hash name + * @hash_alg: hash algorithm id + * @hash_mask: hash registry mask + * @hash_len: hash digest length + */ +struct digest_info { + const char *hash_name; + u16 hash_alg; + u32 hash_mask; + u16 hash_len; +}; + +/* Algorithm Registry */ +#define TCG2_BOOT_HASH_ALG_SHA1 0x00000001 +#define TCG2_BOOT_HASH_ALG_SHA256 0x00000002 +#define TCG2_BOOT_HASH_ALG_SHA384 0x00000004 +#define TCG2_BOOT_HASH_ALG_SHA512 0x00000008 +#define TCG2_BOOT_HASH_ALG_SM3_256 0x00000010 + +static const struct digest_info hash_algo_list[] = { + { + "sha1", + TPM2_ALG_SHA1, + TCG2_BOOT_HASH_ALG_SHA1, + TPM2_SHA1_DIGEST_SIZE, + }, + { + "sha256", + TPM2_ALG_SHA256, + TCG2_BOOT_HASH_ALG_SHA256, + TPM2_SHA256_DIGEST_SIZE, + }, + { + "sha384", + TPM2_ALG_SHA384, + TCG2_BOOT_HASH_ALG_SHA384, + TPM2_SHA384_DIGEST_SIZE, + }, + { + "sha512", + TPM2_ALG_SHA512, + TCG2_BOOT_HASH_ALG_SHA512, + TPM2_SHA512_DIGEST_SIZE, + }, +}; static inline u16 tpm2_algorithm_to_len(enum tpm2_algorithms a) { @@ -404,8 +451,6 @@ static inline u16 tpm2_algorithm_to_len(enum tpm2_algorithms a) } } -#define tpm2_algorithm_to_mask(a) (1 << (a)) - /* NV index attributes */ enum tpm_index_attrs { TPMA_NV_PPWRITE = 1UL << 0, @@ -965,4 +1010,30 @@ u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, */ u32 tpm2_auto_start(struct udevice *dev); +/** + * tpm2_name_to_algorithm() - Return an algorithm id given a supported + * algorithm name + * + * @name: algorithm name + * Return: enum tpm2_algorithms or -EINVAL + */ +enum tpm2_algorithms tpm2_name_to_algorithm(const char *name); + +/** + * tpm2_algorithm_name() - Return an algorithm name string for a + * supported algorithm id + * + * @algorithm_id: algorithm defined in enum tpm2_algorithms + * Return: algorithm name string or "" + */ +const char *tpm2_algorithm_name(enum tpm2_algorithms); + +/** + * tpm2_algorithm_to_mask() - Get a TCG hash mask for algorithm + * + * @hash_alg: TCG defined algorithm + * Return: TCG hashing algorithm bitmaps (or 0 if algo not supported) + */ +u32 tpm2_algorithm_to_mask(enum tpm2_algorithms); + #endif /* __TPM_V2_H */ diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c index b07e009..945aafb 100644 --- a/lib/efi_loader/efi_tcg2.c +++ b/lib/efi_loader/efi_tcg2.c @@ -414,10 +414,10 @@ static efi_status_t tcg2_hash_pe_image(void *efi, u64 efi_size, } digest_list->count = 0; - for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); i++) { - u16 hash_alg = tpm2_supported_algorithms[i]; + for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { + u16 hash_alg = hash_algo_list[i].hash_alg; - if (!(active & tpm2_algorithm_to_mask(hash_alg))) + if (!(active & hash_algo_list[i].hash_mask)) continue; switch (hash_alg) { case TPM2_ALG_SHA1: diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 68eaaa6..a67daed 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -22,13 +22,6 @@ #include "tpm-utils.h" -const enum tpm2_algorithms tpm2_supported_algorithms[4] = { - TPM2_ALG_SHA1, - TPM2_ALG_SHA256, - TPM2_ALG_SHA384, - TPM2_ALG_SHA512, -}; - int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks) { u32 supported = 0; @@ -82,14 +75,11 @@ int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length, return rc; digest_list->count = 0; - for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) { - u32 mask = - tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]); - - if (!(active & mask)) + for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { + if (!(active & hash_algo_list[i].hash_mask)) continue; - switch (tpm2_supported_algorithms[i]) { + switch (hash_algo_list[i].hash_alg) { case TPM2_ALG_SHA1: sha1_starts(&ctx); sha1_update(&ctx, input, length); @@ -116,12 +106,12 @@ int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length, break; default: printf("%s: unsupported algorithm %x\n", __func__, - tpm2_supported_algorithms[i]); + hash_algo_list[i].hash_alg); continue; } digest_list->digests[digest_list->count].hash_alg = - tpm2_supported_algorithms[i]; + hash_algo_list[i].hash_alg; memcpy(&digest_list->digests[digest_list->count].digest, final, len); digest_list->count++; @@ -198,7 +188,6 @@ static int tcg2_log_init(struct udevice *dev, struct tcg2_event_log *elog) u32 count = 0; u32 log_size; u32 active; - u32 mask; size_t i; u16 len; int rc; @@ -208,13 +197,11 @@ static int tcg2_log_init(struct udevice *dev, struct tcg2_event_log *elog) return rc; event_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes); - for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) { - mask = tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]); - - if (!(active & mask)) + for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { + if (!(active & hash_algo_list[i].hash_mask)) continue; - switch (tpm2_supported_algorithms[i]) { + switch (hash_algo_list[i].hash_alg) { case TPM2_ALG_SHA1: case TPM2_ALG_SHA256: case TPM2_ALG_SHA384: @@ -253,17 +240,15 @@ static int tcg2_log_init(struct udevice *dev, struct tcg2_event_log *elog) put_unaligned_le32(count, &ev->number_of_algorithms); count = 0; - for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) { - mask = tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]); - - if (!(active & mask)) + for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { + if (!(active & hash_algo_list[i].hash_mask)) continue; - len = tpm2_algorithm_to_len(tpm2_supported_algorithms[i]); + len = hash_algo_list[i].hash_len; if (!len) continue; - put_unaligned_le16(tpm2_supported_algorithms[i], + put_unaligned_le16(hash_algo_list[i].hash_alg, &ev->digest_sizes[count].algorithm_id); put_unaligned_le16(len, &ev->digest_sizes[count].digest_size); count++; @@ -304,7 +289,7 @@ static int tcg2_replay_eventlog(struct tcg2_event_log *elog, pos = offsetof(struct tcg_pcr_event2, digests) + offsetof(struct tpml_digest_values, count); count = get_unaligned_le32(log + pos); - if (count > ARRAY_SIZE(tpm2_supported_algorithms) || + if (count > ARRAY_SIZE(hash_algo_list) || (digest_list->count && digest_list->count != count)) return 0; @@ -407,7 +392,7 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) return 0; count = get_unaligned_le32(&event->number_of_algorithms); - if (count > ARRAY_SIZE(tpm2_supported_algorithms)) + if (count > ARRAY_SIZE(hash_algo_list)) return 0; calc_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes) + @@ -1110,7 +1095,7 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, * We only support 5 algorithms for now so check against that * instead of TPM2_NUM_PCR_BANKS */ - if (pcrs.count > ARRAY_SIZE(tpm2_supported_algorithms) || + if (pcrs.count > ARRAY_SIZE(hash_algo_list) || pcrs.count < 1) { printf("%s: too many pcrs: %u\n", __func__, pcrs.count); return -EMSGSIZE; @@ -1555,3 +1540,40 @@ u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, return 0; } + +enum tpm2_algorithms tpm2_name_to_algorithm(const char *name) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { + if (!strcasecmp(name, hash_algo_list[i].hash_name)) + return hash_algo_list[i].hash_alg; + } + printf("%s: unsupported algorithm %s\n", __func__, name); + + return -EINVAL; +} + +const char *tpm2_algorithm_name(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_name; + } + + return ""; +} + +u32 tpm2_algorithm_to_mask(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_mask; + } + + return 0; +} -- cgit v1.1 From 89aa8463cdf3919ca4f04fc24ec8b154ff56d97e Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Sat, 25 May 2024 13:00:49 -0700 Subject: tpm-v2: allow algorithm name to be configured for pcr_read and pcr_extend For pcr_read and pcr_extend commands allow the digest algorithm to be specified by an additional argument. If not specified it will default to SHA256 for backwards compatibility. Additionally update test_tpm2.py for the changes in output in pcr_read which now shows the algo and algo length in the output. A follow-on to this could be to extend all PCR banks with the detected algo when the argument is 'auto'. Signed-off-by: Tim Harvey Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- cmd/tpm-v2.c | 49 +++++++++++++++++++++++++++++++++------------- test/py/tests/test_tpm2.py | 2 +- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index 7e479b9..2343b4d 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -99,11 +99,19 @@ static int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc, struct tpm_chip_priv *priv; u32 index = simple_strtoul(argv[1], NULL, 0); void *digest = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0); + int algo = TPM2_ALG_SHA256; + int algo_len; int ret; u32 rc; - if (argc != 3) + if (argc < 3 || argc > 4) return CMD_RET_USAGE; + if (argc == 4) { + algo = tpm2_name_to_algorithm(argv[3]); + if (algo < 0) + return CMD_RET_FAILURE; + } + algo_len = tpm2_algorithm_to_len(algo); ret = get_tpm(&dev); if (ret) @@ -116,8 +124,12 @@ static int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc, if (index >= priv->pcr_count) return -EINVAL; - rc = tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, digest, - TPM2_DIGEST_LEN); + rc = tpm2_pcr_extend(dev, index, algo, digest, algo_len); + if (!rc) { + printf("PCR #%u extended with %d byte %s digest\n", index, + algo_len, tpm2_algorithm_name(algo)); + print_byte_string(digest, algo_len); + } unmap_sysmem(digest); @@ -127,15 +139,23 @@ static int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc, static int do_tpm_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { + enum tpm2_algorithms algo = TPM2_ALG_SHA256; struct udevice *dev; struct tpm_chip_priv *priv; u32 index, rc; + int algo_len; unsigned int updates; void *data; int ret; - if (argc != 3) + if (argc < 3 || argc > 4) return CMD_RET_USAGE; + if (argc == 4) { + algo = tpm2_name_to_algorithm(argv[3]); + if (algo < 0) + return CMD_RET_FAILURE; + } + algo_len = tpm2_algorithm_to_len(algo); ret = get_tpm(&dev); if (ret) @@ -151,11 +171,12 @@ static int do_tpm_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc, data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0); - rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, TPM2_ALG_SHA256, - data, TPM2_DIGEST_LEN, &updates); + rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, algo, + data, algo_len, &updates); if (!rc) { - printf("PCR #%u content (%u known updates):\n", index, updates); - print_byte_string(data, TPM2_DIGEST_LEN); + printf("PCR #%u %s %d byte content (%u known updates):\n", index, + tpm2_algorithm_name(algo), algo_len, updates); + print_byte_string(data, algo_len); } unmap_sysmem(data); @@ -415,14 +436,14 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", " is one of:\n" " * TPM2_RH_LOCKOUT\n" " * TPM2_RH_PLATFORM\n" -"pcr_extend \n" -" Extend PCR # with digest at .\n" +"pcr_extend []\n" +" Extend PCR # with digest at with digest_algo.\n" " : index of the PCR\n" -" : address of a 32-byte SHA256 digest\n" -"pcr_read \n" -" Read PCR # to memory address .\n" +" : address of digest of digest_algo type (defaults to SHA256)\n" +"pcr_read []\n" +" Read PCR # to memory address with .\n" " : index of the PCR\n" -" : address to store the a 32-byte SHA256 digest\n" +" : address of digest of digest_algo type (defaults to SHA256)\n" "get_capability \n" " Read and display entries indexed by /.\n" " Values are 4 bytes long and are written at .\n" diff --git a/test/py/tests/test_tpm2.py b/test/py/tests/test_tpm2.py index 1d654cd..75f5d31 100644 --- a/test/py/tests/test_tpm2.py +++ b/test/py/tests/test_tpm2.py @@ -257,7 +257,7 @@ def test_tpm2_pcr_read(u_boot_console): updates = int(re.findall(r'\d+', str)[0]) # Check the output value - assert 'PCR #10 content' in read_pcr + assert 'PCR #10 sha256 32 byte content' in read_pcr assert '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' in read_pcr @pytest.mark.buildconfigspec('cmd_tpm_v2') -- cgit v1.1