* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE ***
@ 2026-03-16 18:14 David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm David Garske
` (11 more replies)
0 siblings, 12 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
To: u-boot; +Cc: David Garske
*** BLURB HERE ***
Aidan (12):
tpm: export tpm_show_device, tpm_set_device, and get_tpm
include: add byteorder macro guards and SHA384 hash wrapper
spi: add BCM2835/BCM2711 hardware SPI controller driver
dts: add TPM device tree nodes for RPi4, QEMU, and sandbox
tpm: add wolfTPM library as git submodule
tpm: add wolfTPM headers and SHA384 glue code
tpm: add wolfTPM driver helpers and Kconfig options
cmd: refactor tpm2 command into frontend/backend architecture
tpm: add sandbox TPM SPI emulator
test: add wolfTPM C unit tests and Python integration tests
doc: add wolfTPM documentation
configs: enable wolfTPM in rpi_4_defconfig
.gitmodules | 3 +
README | 3 +
README.wolftpm.md | 154 +++
arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi | 54 +
arch/arm/dts/bcm2711-rpi-4-b.dts | 20 +
arch/arm/dts/qemu-arm64.dts | 4 +
arch/sandbox/dts/sandbox.dtsi | 11 +
cmd/Kconfig | 11 +
cmd/Makefile | 10 +-
cmd/native_tpm2.c | 516 ++++++++++
cmd/tpm-common.c | 4 +-
cmd/tpm-v2.c | 559 ++---------
cmd/tpm2-backend.h | 66 ++
cmd/wolftpm.c | 1170 ++++++++++++++++++++++
configs/rpi_4_defconfig | 29 +-
doc/usage/cmd/wolftpm.rst | 635 ++++++++++++
drivers/mtd/spi/sandbox.c | 30 +-
drivers/spi/Kconfig | 9 +
drivers/spi/Makefile | 1 +
drivers/spi/bcm2835_spi.c | 431 ++++++++
drivers/tpm/Kconfig | 44 +
drivers/tpm/Makefile | 9 +
drivers/tpm/tpm_spi_sandbox.c | 410 ++++++++
drivers/tpm/wolftpm_common.c | 137 +++
include/configs/user_settings.h | 118 +++
include/hash.h | 18 +
include/linux/byteorder/generic.h | 31 +-
include/tpm-common.h | 22 +
include/wolftpm.h | 34 +
lib/Kconfig | 13 +
lib/Makefile | 18 +
lib/wolftpm | 1 +
lib/wolftpm.c | 56 ++
test/cmd/Makefile | 1 +
test/cmd/wolftpm.c | 364 +++++++
test/py/tests/test_wolftpm.py | 375 +++++++
36 files changed, 4861 insertions(+), 510 deletions(-)
create mode 100644 .gitmodules
create mode 100644 README.wolftpm.md
create mode 100644 arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi
create mode 100644 cmd/native_tpm2.c
create mode 100644 cmd/tpm2-backend.h
create mode 100644 cmd/wolftpm.c
create mode 100644 doc/usage/cmd/wolftpm.rst
create mode 100644 drivers/spi/bcm2835_spi.c
create mode 100644 drivers/tpm/tpm_spi_sandbox.c
create mode 100644 drivers/tpm/wolftpm_common.c
create mode 100644 include/configs/user_settings.h
create mode 100644 include/wolftpm.h
create mode 160000 lib/wolftpm
create mode 100644 lib/wolftpm.c
create mode 100644 test/cmd/wolftpm.c
create mode 100644 test/py/tests/test_wolftpm.py
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 02/12] include: add byteorder macro guards and SHA384 hash wrapper David Garske ` (10 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Remove static scope from tpm_show_device(), tpm_set_device(), and get_tpm() in cmd/tpm-common.c so they can be called from other translation units. Add corresponding declarations to include/tpm-common.h. wolfTPM's command backend needs these functions for device enumeration and selection when operating through U-Boot's driver model. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- cmd/tpm-common.c | 4 ++-- include/tpm-common.h | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/cmd/tpm-common.c b/cmd/tpm-common.c index 1cd57f901b6..30e99e10758 100644 --- a/cmd/tpm-common.c +++ b/cmd/tpm-common.c @@ -234,7 +234,7 @@ int type_string_write_vars(const char *type_str, u8 *data, return 0; } -static int tpm_show_device(void) +int tpm_show_device(void) { struct udevice *dev; char buf[80]; @@ -253,7 +253,7 @@ static int tpm_show_device(void) return 0; } -static int tpm_set_device(unsigned long num) +int tpm_set_device(unsigned long num) { struct udevice *dev; unsigned long n = 0; diff --git a/include/tpm-common.h b/include/tpm-common.h index bfb84a931d1..1ea4463fbbe 100644 --- a/include/tpm-common.h +++ b/include/tpm-common.h @@ -337,4 +337,26 @@ enum tpm_version tpm_get_version(struct udevice *dev); /* Iterate on all TPM devices */ #define for_each_tpm_device(dev) uclass_foreach_dev_probe(UCLASS_TPM, (dev)) +/** + * tpm_show_device() - Show all TPM devices + * + * Return: 0 on success, -ve on failure + */ +int tpm_show_device(void); + +/** + * tpm_set_device() - Set the TPM device to use + * + * @num: The number of the TPM device to use + * Return: 0 on success, -ve on failure + */ +int tpm_set_device(unsigned long num); + +/** + * get_tpm() - Get the TPM device + * + * Return: 0 on success, -ve on failure + */ +int get_tpm(struct udevice **devp); + #endif /* __TPM_COMMON_H */ -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 02/12] include: add byteorder macro guards and SHA384 hash wrapper 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver David Garske ` (9 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Add #ifndef guards around cpu_to_beXX / beXX_to_cpu macro definitions in include/linux/byteorder/generic.h. wolfTPM, wolfCrypt, and U-Boot all define these macros; the guards prevent redefinition warnings when wolfTPM headers are included alongside U-Boot headers. Add #include <linux/types.h> to include/hash.h so that basic types (u8, u32, etc.) are available to all includers. Add a wc_Sha384Hash() wrapper declaration in include/hash.h, gated by WOLFTPM2_NO_WOLFCRYPT. When wolfTPM is built without wolfCrypt, this wrapper provides SHA-384 hashing via U-Boot's hash subsystem, which is needed for Infineon TPM firmware update manifest validation. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- include/hash.h | 18 ++++++++++++++++++ include/linux/byteorder/generic.h | 31 +++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/hash.h b/include/hash.h index 8b3f79ec473..26043c43a9c 100644 --- a/include/hash.h +++ b/include/hash.h @@ -6,6 +6,8 @@ #ifndef _HASH_H #define _HASH_H +#include <linux/types.h> + #ifdef USE_HOSTCC #include <linux/kconfig.h> #endif @@ -163,4 +165,20 @@ int hash_progressive_lookup_algo(const char *algo_name, */ int hash_parse_string(const char *algo_name, const char *str, uint8_t *result); +#ifdef WOLFTPM2_NO_WOLFCRYPT +/** + * wc_Sha384Hash() - Calculate SHA384 hash + * @data: Data to hash + * @len: Length of data + * @hash: Output buffer for hash + * + * This is a wrapper function to provide wolfCrypt-compatible SHA384 hashing + * when wolfCrypt is not available. + * + * Return: 0 on success, -1 on error + */ +int wc_Sha384Hash(const unsigned char *data, unsigned int len, + unsigned char *hash); +#endif /* WOLFTPM2_NO_WOLFCRYPT */ + #endif diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h index bee0ff60336..def601eed2b 100644 --- a/include/linux/byteorder/generic.h +++ b/include/linux/byteorder/generic.h @@ -89,12 +89,6 @@ #define le32_to_cpu __le32_to_cpu #define cpu_to_le16 __cpu_to_le16 #define le16_to_cpu __le16_to_cpu -#define cpu_to_be64 __cpu_to_be64 -#define be64_to_cpu __be64_to_cpu -#define cpu_to_be32 __cpu_to_be32 -#define be32_to_cpu __be32_to_cpu -#define cpu_to_be16 __cpu_to_be16 -#define be16_to_cpu __be16_to_cpu #define cpu_to_le64p __cpu_to_le64p #define le64_to_cpup __le64_to_cpup #define cpu_to_le32p __cpu_to_le32p @@ -120,6 +114,31 @@ #define cpu_to_be16s __cpu_to_be16s #define be16_to_cpus __be16_to_cpus +/* + * Check if byte-order functions are already defined by the system: + * wolfTPM, wolfCrypt, and U-boot all define these functions, so + * we need to check if they are already defined before defining + * them again. + */ +#ifndef cpu_to_be16 +#define cpu_to_be16 __cpu_to_be16 +#endif +#ifndef cpu_to_be32 +#define cpu_to_be32 __cpu_to_be32 +#endif +#ifndef cpu_to_be64 +#define cpu_to_be64 __cpu_to_be64 +#endif +#ifndef be16_to_cpu +#define be16_to_cpu __be16_to_cpu +#endif +#ifndef be32_to_cpu +#define be32_to_cpu __be32_to_cpu +#endif +#ifndef be64_to_cpu +#define be64_to_cpu __be64_to_cpu +#endif + /* * They have to be macros in order to do the constant folding * correctly - if the argument passed into a inline function -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 02/12] include: add byteorder macro guards and SHA384 hash wrapper David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox David Garske ` (8 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Add a hardware SPI controller driver for the BCM2835/BCM2711 SoC found on Raspberry Pi 3 and Pi 4 boards. The driver implements: - Register-based SPI transfers using the BCM2835 SPI0 peripheral - Software GPIO chip-select control (matching the Linux driver approach) rather than hardware CS, which avoids issues with automatic CS deassertion during multi-byte TPM TIS transactions - Clock divider calculation for configurable SPI speed - SPI mode 0/1/2/3 support via CPOL/CPHA configuration - GPIO pin setup for SPI0 (MISO/MOSI/SCLK as ALT0, CE0/CE1 as output for software CS) - TPM reset via GPIO4/GPIO24 during probe This driver is needed for wolfTPM to communicate with SPI-attached TPM chips (e.g., Infineon SLB9670/9672) on Raspberry Pi hardware. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- drivers/spi/Kconfig | 9 + drivers/spi/Makefile | 1 + drivers/spi/bcm2835_spi.c | 431 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 441 insertions(+) create mode 100644 drivers/spi/bcm2835_spi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 8c6c095a8cf..9625b1e073e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -117,6 +117,15 @@ config ATMEL_SPI many AT91 (ARM) chips. This driver can be used to access the SPI Flash, such as AT25DF321. +config BCM2835_SPI + bool "BCM2835/BCM2711 SPI driver" + depends on ARCH_BCM283X + help + Enable the BCM2835/BCM2711 SPI controller driver. This driver + can be used to access SPI devices on Raspberry Pi boards + including Pi 3 and Pi 4. It uses the hardware SPI controller + rather than GPIO bit-banging. + config BCM63XX_HSSPI bool "BCM63XX HSSPI driver" depends on (ARCH_BMIPS || ARCH_BCMBCA) diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 0dc2d23e172..47a1c6194b1 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_APPLE_SPI) += apple_spi.o obj-$(CONFIG_ATH79_SPI) += ath79_spi.o obj-$(CONFIG_ATMEL_QSPI) += atmel-quadspi.o obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o +obj-$(CONFIG_BCM2835_SPI) += bcm2835_spi.o obj-$(CONFIG_BCM63XX_HSSPI) += bcm63xx_hsspi.o obj-$(CONFIG_BCMBCA_HSSPI) += bcmbca_hsspi.o obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c new file mode 100644 index 00000000000..8133a41a0f8 --- /dev/null +++ b/drivers/spi/bcm2835_spi.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * BCM2835/BCM2711 SPI controller driver for U-Boot + * + * Copyright (C) 2025 wolfSSL Inc. + * Author: Aidan Garske <aidan@wolfssl.com> + * + * Based on Linux driver by Chris Boot, Martin Sperl, et al. + */ + +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <malloc.h> +#include <spi.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <dm/device_compat.h> +#include <linux/delay.h> + +/* SPI register offsets */ +#define BCM2835_SPI_CS 0x00 /* Control and Status */ +#define BCM2835_SPI_FIFO 0x04 /* TX and RX FIFOs */ +#define BCM2835_SPI_CLK 0x08 /* Clock Divider */ +#define BCM2835_SPI_DLEN 0x0c /* Data Length */ +#define BCM2835_SPI_LTOH 0x10 /* LoSSI mode TOH */ +#define BCM2835_SPI_DC 0x14 /* DMA DREQ Controls */ + +/* CS register bits */ +#define BCM2835_SPI_CS_LEN_LONG BIT(25) +#define BCM2835_SPI_CS_DMA_LEN BIT(24) +#define BCM2835_SPI_CS_CSPOL2 BIT(23) +#define BCM2835_SPI_CS_CSPOL1 BIT(22) +#define BCM2835_SPI_CS_CSPOL0 BIT(21) +#define BCM2835_SPI_CS_RXF BIT(20) +#define BCM2835_SPI_CS_RXR BIT(19) +#define BCM2835_SPI_CS_TXD BIT(18) +#define BCM2835_SPI_CS_RXD BIT(17) +#define BCM2835_SPI_CS_DONE BIT(16) +#define BCM2835_SPI_CS_LEN BIT(13) +#define BCM2835_SPI_CS_REN BIT(12) +#define BCM2835_SPI_CS_ADCS BIT(11) +#define BCM2835_SPI_CS_INTR BIT(10) +#define BCM2835_SPI_CS_INTD BIT(9) +#define BCM2835_SPI_CS_DMAEN BIT(8) +#define BCM2835_SPI_CS_TA BIT(7) +#define BCM2835_SPI_CS_CSPOL BIT(6) +#define BCM2835_SPI_CS_CLEAR_RX BIT(5) +#define BCM2835_SPI_CS_CLEAR_TX BIT(4) +#define BCM2835_SPI_CS_CPOL BIT(3) +#define BCM2835_SPI_CS_CPHA BIT(2) +#define BCM2835_SPI_CS_CS_10 BIT(1) +#define BCM2835_SPI_CS_CS_01 BIT(0) + +/* Default clock rate - 250 MHz for Pi 4 */ +#define BCM2835_SPI_DEFAULT_CLK 250000000 + +struct bcm2835_spi_priv { + void __iomem *regs; + u32 clk_hz; + u32 cs_reg; /* Cached CS register value */ + u32 speed_hz; + u8 mode; + struct gpio_desc cs_gpio; + int cs_gpio_valid; + int cs_asserted; /* Track if CS should stay asserted between transfers */ +}; + +struct bcm2835_spi_plat { + fdt_addr_t base; + u32 clk_hz; +}; + +static inline u32 bcm2835_spi_readl(struct bcm2835_spi_priv *priv, u32 reg) +{ + return readl(priv->regs + reg); +} + +static inline void bcm2835_spi_writel(struct bcm2835_spi_priv *priv, + u32 reg, u32 val) +{ + writel(val, priv->regs + reg); +} + +static void bcm2835_spi_reset(struct bcm2835_spi_priv *priv) +{ + /* Clear FIFOs and disable SPI */ + bcm2835_spi_writel(priv, BCM2835_SPI_CS, + BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); +} + +/* GPIO base for software CS control */ +static void __iomem *g_gpio_base = (void __iomem *)0xFE200000; + +/* Software CS control - assert (LOW = active) */ +static void bcm2835_spi_cs_assert(int cs_pin) +{ + /* GPCLR0 - clear pin (drive LOW) */ + writel(1 << cs_pin, g_gpio_base + 0x28); +} + +/* Software CS control - deassert (HIGH = inactive) */ +static void bcm2835_spi_cs_deassert(int cs_pin) +{ + /* GPSET0 - set pin (drive HIGH) */ + writel(1 << cs_pin, g_gpio_base + 0x1C); +} + +static int bcm2835_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(dev); + struct bcm2835_spi_priv *priv = dev_get_priv(bus); + const u8 *tx = dout; + u8 *rx = din; + u32 len = bitlen / 8; + u32 cs_reg; + u32 tx_count = 0, rx_count = 0; + int timeout; + int cs = spi_chip_select(dev); /* Get chip select from slave device */ + int cs_pin = (cs == 0) ? 8 : 7; /* CS0=GPIO8, CS1=GPIO7 */ + u32 stat; + + if (bitlen == 0) { + /* Handle CS-only operations (deassert) */ + if (flags & SPI_XFER_END) { + bcm2835_spi_cs_deassert(cs_pin); + priv->cs_asserted = 0; + } + return 0; + } + + if (bitlen % 8) { + dev_err(dev, "Non-byte-aligned transfer not supported\n"); + return -EINVAL; + } + + /* + * SOFTWARE GPIO CHIP SELECT - like Linux driver + * Don't use hardware CS bits - set to 0 (unused) + */ + cs_reg = priv->cs_reg & ~(BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01); + + /* Assert CS at start of transaction (SPI_XFER_BEGIN) */ + if (flags & SPI_XFER_BEGIN) { + bcm2835_spi_cs_assert(cs_pin); + priv->cs_asserted = 1; + udelay(1); /* CS setup time */ + } + + /* Clear FIFOs for new transaction */ + if (flags & SPI_XFER_BEGIN) { + bcm2835_spi_writel(priv, BCM2835_SPI_CS, + cs_reg | BCM2835_SPI_CS_CLEAR_RX | + BCM2835_SPI_CS_CLEAR_TX); + udelay(1); + } + + /* Start transfer with TA=1 (but CS is controlled by GPIO, not hardware) */ + bcm2835_spi_writel(priv, BCM2835_SPI_CS, cs_reg | BCM2835_SPI_CS_TA); + + /* Poll for completion - transfer byte by byte */ + timeout = 100000; + while ((tx_count < len || rx_count < len) && timeout > 0) { + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS); + + /* TX FIFO not full - send next byte */ + while ((stat & BCM2835_SPI_CS_TXD) && tx_count < len) { + u8 byte = tx ? tx[tx_count] : 0; + + bcm2835_spi_writel(priv, BCM2835_SPI_FIFO, byte); + tx_count++; + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS); + } + + /* RX FIFO has data - read it */ + while ((stat & BCM2835_SPI_CS_RXD) && rx_count < len) { + u8 byte = bcm2835_spi_readl(priv, BCM2835_SPI_FIFO) & 0xff; + + if (rx) + rx[rx_count] = byte; + rx_count++; + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS); + } + + timeout--; + } + + /* Wait for DONE */ + timeout = 10000; + while (!(bcm2835_spi_readl(priv, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE) && + timeout > 0) { + udelay(1); + timeout--; + } + + /* Read any remaining RX data from FIFO */ + while (bcm2835_spi_readl(priv, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD) { + u8 byte = bcm2835_spi_readl(priv, BCM2835_SPI_FIFO) & 0xff; + + if (rx && rx_count < len) + rx[rx_count++] = byte; + } + + /* Clear TA to complete this transfer (doesn't affect GPIO CS) */ + bcm2835_spi_writel(priv, BCM2835_SPI_CS, cs_reg); + + /* + * SOFTWARE GPIO CHIP SELECT control: + * - SPI_XFER_END: deassert CS (GPIO HIGH) + * - No END flag: keep CS asserted for next transfer + */ + if (flags & SPI_XFER_END) { + bcm2835_spi_cs_deassert(cs_pin); + priv->cs_asserted = 0; + } else { + /* Keep CS asserted for next transfer (e.g., wait state polling) */ + priv->cs_asserted = 1; + } + + if (timeout == 0) { + bcm2835_spi_cs_deassert(cs_pin); /* Make sure CS is released */ + return -ETIMEDOUT; + } + + return 0; +} + +static int bcm2835_spi_set_speed(struct udevice *bus, uint speed) +{ + struct bcm2835_spi_priv *priv = dev_get_priv(bus); + u32 cdiv; + + if (speed == 0) + speed = 1000000; /* Default 1 MHz */ + + priv->speed_hz = speed; + + /* Calculate clock divider */ + if (speed >= priv->clk_hz / 2) { + cdiv = 2; /* Fastest possible */ + } else { + cdiv = (priv->clk_hz + speed - 1) / speed; + cdiv += (cdiv & 1); /* Must be even */ + if (cdiv >= 65536) + cdiv = 0; /* Slowest: clk/65536 */ + } + + bcm2835_spi_writel(priv, BCM2835_SPI_CLK, cdiv); + + return 0; +} + +static int bcm2835_spi_set_mode(struct udevice *bus, uint mode) +{ + struct bcm2835_spi_priv *priv = dev_get_priv(bus); + u32 cs_reg = 0; + + priv->mode = mode; + + /* Set clock polarity and phase */ + if (mode & SPI_CPOL) + cs_reg |= BCM2835_SPI_CS_CPOL; + if (mode & SPI_CPHA) + cs_reg |= BCM2835_SPI_CS_CPHA; + + /* CS bits will be set in xfer based on slave's chip select */ + priv->cs_reg = cs_reg; + + return 0; +} + +static int bcm2835_spi_claim_bus(struct udevice *dev) +{ + return 0; +} + +static int bcm2835_spi_release_bus(struct udevice *dev) +{ + return 0; +} + +/* Setup GPIO pins for SPI0 with SOFTWARE chip select */ +static void bcm2835_spi_setup_gpio(void) +{ + u32 val; + + /* + * SPI0 pin configuration: + * GPIO7 (CE1) - OUTPUT (software CS) - GPFSEL0 bits 23:21 = 001 + * GPIO8 (CE0) - OUTPUT (software CS) - GPFSEL0 bits 26:24 = 001 + * GPIO9 (MISO) - ALT0 (SPI) - GPFSEL0 bits 29:27 = 100 + * GPIO10 (MOSI) - ALT0 (SPI) - GPFSEL1 bits 2:0 = 100 + * GPIO11 (SCLK) - ALT0 (SPI) - GPFSEL1 bits 5:3 = 100 + */ + + /* Set GPIO7, GPIO8 to OUTPUT, GPIO9 to ALT0 in GPFSEL0 */ + val = readl(g_gpio_base + 0x00); + val &= ~((7 << 21) | (7 << 24) | (7 << 27)); /* Clear GPIO7,8,9 */ + val |= (1 << 21); /* GPIO7 = OUTPUT (001) */ + val |= (1 << 24); /* GPIO8 = OUTPUT (001) */ + val |= (4 << 27); /* GPIO9 = ALT0 (100) for MISO */ + writel(val, g_gpio_base + 0x00); + + /* Set GPIO10, GPIO11 to ALT0 in GPFSEL1 */ + val = readl(g_gpio_base + 0x04); + val &= ~((7 << 0) | (7 << 3)); /* Clear GPIO10,11 */ + val |= (4 << 0); /* GPIO10 = ALT0 (100) for MOSI */ + val |= (4 << 3); /* GPIO11 = ALT0 (100) for SCLK */ + writel(val, g_gpio_base + 0x04); + + /* Deassert both CS lines (HIGH = inactive) */ + bcm2835_spi_cs_deassert(7); /* CE1 */ + bcm2835_spi_cs_deassert(8); /* CE0 */ +} + +/* TPM Reset via GPIO4 and GPIO24 */ +static void bcm2835_spi_tpm_reset(void) +{ + void __iomem *gpio_base = (void __iomem *)0xFE200000; + u32 val; + + /* Set GPIO4 as output (GPFSEL0, bits 14:12) */ + val = readl(gpio_base + 0x00); /* GPFSEL0 */ + val &= ~(7 << 12); /* Clear bits 14:12 for GPIO4 */ + val |= (1 << 12); /* Set to output */ + writel(val, gpio_base + 0x00); + + /* Set GPIO24 as output (GPFSEL2, bits 14:12) */ + val = readl(gpio_base + 0x08); /* GPFSEL2 */ + val &= ~(7 << 12); /* Clear bits 14:12 for GPIO24 */ + val |= (1 << 12); /* Set to output */ + writel(val, gpio_base + 0x08); + + /* Assert reset on BOTH pins (LOW) */ + writel((1 << 4) | (1 << 24), gpio_base + 0x28); /* GPCLR0 */ + mdelay(100); + + /* Release reset on BOTH pins (HIGH) */ + writel((1 << 4) | (1 << 24), gpio_base + 0x1C); /* GPSET0 */ + mdelay(150); /* Wait for TPM to initialize */ +} + +static int bcm2835_spi_probe(struct udevice *bus) +{ + struct bcm2835_spi_plat *plat = dev_get_plat(bus); + struct bcm2835_spi_priv *priv = dev_get_priv(bus); + int ret; + + priv->regs = (void __iomem *)plat->base; + priv->clk_hz = plat->clk_hz ? plat->clk_hz : BCM2835_SPI_DEFAULT_CLK; + + /* Setup GPIO pins for SPI0 (ALT0 function) */ + bcm2835_spi_setup_gpio(); + + /* Reset TPM before using SPI */ + bcm2835_spi_tpm_reset(); + + /* Try to get CS GPIO from device tree */ + ret = gpio_request_by_name(bus, "cs-gpios", 0, &priv->cs_gpio, + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); + if (!ret) { + priv->cs_gpio_valid = 1; + /* Deassert CS initially */ + dm_gpio_set_value(&priv->cs_gpio, 1); + } else { + priv->cs_gpio_valid = 0; + } + + /* Reset the SPI controller */ + bcm2835_spi_reset(priv); + + /* Set default speed and mode */ + bcm2835_spi_set_speed(bus, 1000000); /* 1 MHz default */ + bcm2835_spi_set_mode(bus, SPI_MODE_0); + + return 0; +} + +static int bcm2835_spi_of_to_plat(struct udevice *bus) +{ + struct bcm2835_spi_plat *plat = dev_get_plat(bus); + fdt_addr_t addr; + + addr = dev_read_addr(bus); + if (addr == FDT_ADDR_T_NONE) { + dev_err(bus, "Failed to get SPI base address\n"); + return -EINVAL; + } + + /* + * On BCM2711 (Pi 4), the device tree often uses VideoCore bus addresses + * which start with 0x7E. The ARM needs to access these via the ARM + * peripheral base at 0xFE000000. + */ + if ((addr & 0xFF000000) == 0x7E000000) + addr = (addr & 0x00FFFFFF) | 0xFE000000; + + plat->base = addr; + + /* Try to get clock rate from device tree */ + plat->clk_hz = dev_read_u32_default(bus, "clock-frequency", + BCM2835_SPI_DEFAULT_CLK); + + return 0; +} + +static const struct dm_spi_ops bcm2835_spi_ops = { + .claim_bus = bcm2835_spi_claim_bus, + .release_bus = bcm2835_spi_release_bus, + .xfer = bcm2835_spi_xfer, + .set_speed = bcm2835_spi_set_speed, + .set_mode = bcm2835_spi_set_mode, +}; + +static const struct udevice_id bcm2835_spi_ids[] = { + { .compatible = "brcm,bcm2835-spi" }, + { .compatible = "brcm,bcm2711-spi" }, + { } +}; + +U_BOOT_DRIVER(bcm2835_spi) = { + .name = "bcm2835_spi", + .id = UCLASS_SPI, + .of_match = bcm2835_spi_ids, + .ops = &bcm2835_spi_ops, + .of_to_plat = bcm2835_spi_of_to_plat, + .plat_auto = sizeof(struct bcm2835_spi_plat), + .priv_auto = sizeof(struct bcm2835_spi_priv), + .probe = bcm2835_spi_probe, +}; -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske ` (2 preceding siblings ...) 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 05/12] tpm: add wolfTPM library as git submodule David Garske ` (7 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Add device tree entries for TPM devices across three platforms: bcm2711-rpi-4-b.dts: Add SPI0 node with Infineon SLB9670/9672 TPM on CE1 (GPIO7), matching the standard Linux tpm-slb9670 overlay. Add spi0 alias so wolfTPM finds the bus at index 0. bcm2711-rpi-4-b-u-boot.dtsi (new file): Add soft-SPI (GPIO bit-bang) fallback node for TPM communication. This uses spi-gpio with GPIO11/10/9/7 and provides an alternative to the hardware SPI driver when pinctrl naming differs between U-Boot and Linux device trees. qemu-arm64.dts: Add MMIO-based TPM TIS node at 0x0c000000 for QEMU virt machine with swtpm. This allows wolfTPM testing via QEMU without hardware. sandbox.dtsi: Add sandbox TPM SPI device (sandbox,tpm-spi) on SPI bus CS1 with a phandle reference to a sandbox TPM SPI emulator node. This enables wolfTPM SPI HAL testing in the sandbox environment. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi | 54 ++++++++++++++++++++++++ arch/arm/dts/bcm2711-rpi-4-b.dts | 20 +++++++++ arch/arm/dts/qemu-arm64.dts | 4 ++ arch/sandbox/dts/sandbox.dtsi | 11 +++++ 4 files changed, 89 insertions(+) create mode 100644 arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi diff --git a/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi new file mode 100644 index 00000000000..c38276abee9 --- /dev/null +++ b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * U-Boot specific additions for Raspberry Pi 4 Model B + * + * Adds soft SPI support for Infineon SLB9670/9672 TPM HAT + * connected to SPI0 CE1 (GPIO 7) + * + * Uses GPIO bit-banging instead of hardware SPI to avoid + * GPIO chip naming issues (pinctrl-bcm2835 vs pinctrl-bcm2711) + */ + +#include "bcm283x-u-boot.dtsi" +#include <dt-bindings/gpio/gpio.h> + +/ { + aliases { + spi0 = &soft_spi; + }; + + soft_spi: soft-spi { + compatible = "spi-gpio"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + bootph-all; + + /* + * GPIO pins for SPI0 on Raspberry Pi 4: + * GPIO 11 = SCLK + * GPIO 10 = MOSI + * GPIO 9 = MISO + * GPIO 7 = CE1 (chip select for TPM) + */ + gpio-sck = <&gpio 11 GPIO_ACTIVE_HIGH>; + gpio-mosi = <&gpio 10 GPIO_ACTIVE_HIGH>; + gpio-miso = <&gpio 9 GPIO_ACTIVE_HIGH>; + cs-gpios = <&gpio 7 GPIO_ACTIVE_LOW>; + num-chipselects = <1>; + spi-delay-us = <1>; + + /* Infineon SLB9672 TPM on CS1 */ + tpm@0 { + compatible = "infineon,slb9672", "tcg,tpm-tis-spi"; + reg = <0>; + spi-max-frequency = <10000000>; + status = "okay"; + bootph-all; + }; + }; +}; + +&gpio { + bootph-all; +}; diff --git a/arch/arm/dts/bcm2711-rpi-4-b.dts b/arch/arm/dts/bcm2711-rpi-4-b.dts index 72ce80fbf26..a09276dc279 100644 --- a/arch/arm/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/dts/bcm2711-rpi-4-b.dts @@ -8,6 +8,11 @@ compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; model = "Raspberry Pi 4 Model B"; + /* Alias hardware SPI as spi0 so wolfTPM finds it at bus 0 */ + aliases { + spi0 = &spi; + }; + chosen { /* 8250 auxiliary UART instead of pl011 */ stdout-path = "serial1:115200n8"; @@ -54,6 +59,21 @@ enable-active-high; gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; }; + +}; + +/* Hardware SPI with TPM - matches Linux tpm-slb9670 overlay */ +&spi { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_gpio7>; + + /* Infineon SLB9670/9672 TPM 2.0 on CE1 (GPIO7) */ + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; /* CE1 */ + spi-max-frequency = <32000000>; + }; }; &ddc0 { diff --git a/arch/arm/dts/qemu-arm64.dts b/arch/arm/dts/qemu-arm64.dts index 95fcf53ed74..e74d036a532 100644 --- a/arch/arm/dts/qemu-arm64.dts +++ b/arch/arm/dts/qemu-arm64.dts @@ -12,4 +12,8 @@ #endif / { + tpm@0c000000 { + compatible = "tcg,tpm-tis-mmio"; + reg = <0x0 0x0c000000 0x0 0x5000>; + }; }; diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index 02b03894eaf..2fdd7f0e942 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -286,6 +286,17 @@ spi-max-frequency = <40000000>; sandbox,filename = "spi.bin"; }; + + tpm_spi: tpm@1 { + reg = <1>; + compatible = "sandbox,tpm-spi"; + spi-max-frequency = <10000000>; + sandbox,emul = <&tpm_spi_emul>; + }; + }; + + tpm_spi_emul: tpm-spi-emul { + compatible = "sandbox,tpm-spi-emul"; }; spl-test { -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 05/12] tpm: add wolfTPM library as git submodule 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske ` (3 preceding siblings ...) 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 06/12] tpm: add wolfTPM headers and SHA384 glue code David Garske ` (6 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Add wolfTPM (https://github.com/wolfSSL/wolfTPM) as a git submodule at lib/wolftpm. wolfTPM is a portable, open-source TPM 2.0 stack licensed under GPLv2, providing native API access to all TPM 2.0 commands and a wrapper API for common operations. The build system additions: .gitmodules: Registers the wolfTPM submodule pointing to the upstream repo. lib/Kconfig: Adds CONFIG_TPM_WOLF option under library routines, which selects SHA1 and implies DM_RNG. lib/Makefile: When CONFIG_TPM_WOLF and CONFIG_TPM_V2 are both enabled, compiles wolfTPM core source files (tpm2.c, tpm2_packet.c, tpm2_tis.c, tpm2_wrap.c, tpm2_param_enc.c) and the HAL layer (tpm_io.c). Sets -I include paths and -DWOLFTPM_USER_SETTINGS. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- .gitmodules | 3 +++ lib/Kconfig | 13 +++++++++++++ lib/Makefile | 18 ++++++++++++++++++ lib/wolftpm | 1 + 4 files changed, 35 insertions(+) create mode 100644 .gitmodules create mode 160000 lib/wolftpm diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000000..3f95a7c3eb9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/wolftpm"] + path = lib/wolftpm + url = https://github.com/wolfssl/wolfTPM.git diff --git a/lib/Kconfig b/lib/Kconfig index 931d5206936..24477ea53c9 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -500,6 +500,19 @@ config TPM If you want a fully functional TPM enable all hashing algorithms. If you enabled measured boot all hashing algorithms are selected. +config TPM_WOLF + bool "Enable wolfTPM support" + depends on DM + imply DM_RNG + select SHA1 + help + This option enables support for wolfTPM in U-Boot. WolfTPM can be + used to update ARM specific platforms. Enabling this option allows + U-Boot to interact with the TPM using wolfTPM commands such as + firmware updates, PCR extend, and more. It is especially useful on + platforms that require support for secure boot and other TPM-related + functionality. + config SPL_TPM bool "Trusted Platform Module (TPM) Support in SPL" depends on SPL_DM diff --git a/lib/Makefile b/lib/Makefile index 70667f3728c..76025cc77d8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_BITREVERSE) += bitrev.o obj-y += list_sort.o endif +# U-boot TPM obj-$(CONFIG_$(PHASE_)TPM) += tpm-common.o ifeq ($(CONFIG_$(PHASE_)TPM),y) obj-$(CONFIG_TPM) += tpm_api.o @@ -64,6 +65,23 @@ obj-$(CONFIG_EFI_TCG2_PROTOCOL) += tpm_tcg2.o obj-$(CONFIG_MEASURED_BOOT) += tpm_tcg2.o endif +# wolfTPM with TPM 2.0 support (including TPM firmware update) +ifeq ($(CONFIG_TPM_WOLF),y) +ifeq ($(CONFIG_TPM_V2),y) +ccflags-y += -I$(srctree)/lib/wolftpm \ + -I$(srctree)/include/configs \ + -DWOLFTPM_USER_SETTINGS +obj-y += wolftpm/hal/tpm_io.o +obj-$(CONFIG_WOLFTPM_LINUX_DEV) += wolftpm/src/tpm2_linux.o +obj-y += wolftpm/src/tpm2.o +obj-y += wolftpm/src/tpm2_packet.o +obj-y += wolftpm/src/tpm2_tis.o +obj-y += wolftpm/src/tpm2_wrap.o +obj-y += wolftpm/src/tpm2_param_enc.o +obj-y += wolftpm.o +endif +endif + obj-$(CONFIG_$(PHASE_)CRC8) += crc8.o obj-$(CONFIG_$(PHASE_)CRC16) += crc16.o obj-$(CONFIG_$(PHASE_)CRC16) += crc16-ccitt.o diff --git a/lib/wolftpm b/lib/wolftpm new file mode 160000 index 00000000000..664db130d57 --- /dev/null +++ b/lib/wolftpm @@ -0,0 +1 @@ +Subproject commit 664db130d57bfa18a3254a0ddc126da1beeb9895 -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 06/12] tpm: add wolfTPM headers and SHA384 glue code 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske ` (4 preceding siblings ...) 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 05/12] tpm: add wolfTPM library as git submodule David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 07/12] tpm: add wolfTPM driver helpers and Kconfig options David Garske ` (5 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Add the wolfTPM integration headers and hash wrapper needed to bridge wolfTPM with U-Boot's subsystems. include/wolftpm.h: Public header exposing TPM2_PCRs_Print(), TPM2_Init_Device(), and Infineon firmware update helpers (TPM2_IFX_FwData_Cb, TPM2_IFX_GetOpModeStr, TPM2_IFX_PrintInfo). Includes the core wolfTPM headers (tpm2.h, tpm2_wrap.h, tpm2_packet.h). include/configs/user_settings.h: wolfTPM compile-time configuration. Selects TPM chip type (SLB9672/SLB9673 for real hardware, WOLFTPM_AUTODETECT for swtpm/QEMU), communication mode (native SPI TIS layer for real hardware, WOLFTPM_LINUX_DEV for U-Boot driver model), timeout tuning, and feature flags (WOLFTPM2_NO_WOLFCRYPT, WOLFTPM2_NO_HEAP, WOLFTPM_CHECK_WAIT_STATE). lib/wolftpm.c: Provides wc_Sha384Hash() implementation when wolfCrypt is disabled (WOLFTPM2_NO_WOLFCRYPT). Uses U-Boot's hash_lookup_algo("sha384") to compute SHA-384 digests, which is required for Infineon TPM firmware update manifest validation. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- include/configs/user_settings.h | 118 ++++++++++++++++++++++++++++++++ include/wolftpm.h | 34 +++++++++ lib/wolftpm.c | 56 +++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 include/configs/user_settings.h create mode 100644 include/wolftpm.h create mode 100644 lib/wolftpm.c diff --git a/include/configs/user_settings.h b/include/configs/user_settings.h new file mode 100644 index 00000000000..e62be7a8f30 --- /dev/null +++ b/include/configs/user_settings.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * wolfTPM build configuration for U-Boot + * + * Copyright (C) 2025 wolfSSL Inc. + * Author: Aidan Garske <aidan@wolfssl.com> + */ + +#ifndef USER_SETTINGS_H +#define USER_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************/ +/* --- BEGIN wolfTPM U-boot Settings -- */ +/******************************************************************************/ + +/* ========================================================================= + * TPM Chip Configuration + * ========================================================================= + * + * CONFIG_TPM_AUTODETECT: For swtpm/QEMU testing (no specific chip) + * !CONFIG_TPM_AUTODETECT: For real hardware (SLB9672/SLB9673) + */ +#ifdef CONFIG_TPM_AUTODETECT + #define WOLFTPM_AUTODETECT +#else + /* Real hardware - Infineon SLB9672/SLB9673 + * Firmware upgrade only supported by these chips */ + #define WOLFTPM_FIRMWARE_UPGRADE + #define WOLFTPM_SLB9672 + /* #define WOLFTPM_SLB9673 */ +#endif + +/* Include delay.h and types.h for + * U-boot time delay and types */ +#include <linux/delay.h> +#include <linux/types.h> +#include <stdint.h> + +/* wolfCrypt disabled - pcr_setauthpolicy/pcr_setauthvalue not available + * To enable wolfCrypt, you would need to: + * 1. Uncomment the line below to undefine WOLFTPM2_NO_WOLFCRYPT + * 2. Add wolfCrypt source files to the U-Boot build (lib/Makefile) + * 3. Add wolfCrypt settings for embedded/no-OS use + */ +#undef WOLFTPM2_NO_WOLFCRYPT +#define WOLFTPM2_NO_WOLFCRYPT + +/* ========================================================================= + * TPM Communication Mode Selection (Auto-detected based on chip type) + * ========================================================================= + * + * For real SPI hardware (SLB9672/SLB9673): + * - Uses wolfTPM's native TIS layer with raw SPI via tpm_io_uboot.c + * - Requires CONFIG_SPI and CONFIG_DM_SPI enabled in U-Boot + * + * For swtpm/QEMU testing (no specific chip defined): + * - Uses WOLFTPM_LINUX_DEV mode with U-Boot's TPM driver (tpm_xfer()) + * - Works with MMIO-based TPM via tpm2_tis_mmio.c + */ + +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + /* Real SPI hardware - use native wolfTPM TIS with raw SPI */ + /* WOLFTPM_LINUX_DEV is NOT defined */ + #define WOLFTPM_EXAMPLE_HAL + + /* SPI bus and chip select for TPM + * Official Raspberry Pi tpm-slb9670 overlay uses CE1 (GPIO7) + * This matches LetsTrust and most Infineon evaluation boards */ + #ifndef TPM_SPI_BUS + #define TPM_SPI_BUS 0 + #endif + #ifndef TPM_SPI_CS + #define TPM_SPI_CS 1 /* CE1/GPIO7 - official RPi TPM overlay setting */ + #endif +#else + /* swtpm/QEMU - use U-Boot's TPM driver with MMIO communication mode */ + #define WOLFTPM_LINUX_DEV +#endif + +#define XSLEEP_MS(ms) udelay(ms * 1000) + +/* Timeout configuration */ +#ifdef WOLFTPM_FIRMWARE_UPGRADE + /* Firmware update requires much longer timeout for TPM processing */ + #define TPM_TIMEOUT_TRIES 2000000 +#else + /* Normal operations - reduce from default 1,000,000 to prevent long hangs */ + #define TPM_TIMEOUT_TRIES 10000 +#endif + +/* Add small delay between poll attempts to avoid tight spin loop */ +#define XTPM_WAIT() udelay(100) + +/* Do not include API's that use heap(), they are not required */ +#define WOLFTPM2_NO_HEAP + +/* Debugging - disabled for clean output */ +/* #define DEBUG_WOLFTPM */ +/* #define WOLFTPM_DEBUG_VERBOSE */ +/* #define WOLFTPM_DEBUG_IO */ +/* #define WOLFTPM_DEBUG_TIMEOUT */ + +/* SPI Wait state checking - most TPMs use this */ +#define WOLFTPM_CHECK_WAIT_STATE + +/******************************************************************************/ +/* --- END wolfTPM U-boot Settings -- */ +/******************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* USER_SETTINGS_H */ diff --git a/include/wolftpm.h b/include/wolftpm.h new file mode 100644 index 00000000000..a3cd9d0d2dd --- /dev/null +++ b/include/wolftpm.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * wolfTPM integration header for U-Boot + * + * Copyright (C) 2025 wolfSSL Inc. + * Author: Aidan Garske <aidan@wolfssl.com> + */ + +#ifndef __WOLFTPM_H__ +#define __WOLFTPM_H__ + +#include <wolftpm/tpm2.h> +#include <wolftpm/tpm2_wrap.h> +#include <wolftpm/tpm2_packet.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WOLFTPM_FIRMWARE_UPGRADE +int TPM2_IFX_FwData_Cb(uint8_t *data, uint32_t data_req_sz, + uint32_t offset, void *cb_ctx); +const char *TPM2_IFX_GetOpModeStr(int opMode); +void TPM2_IFX_PrintInfo(WOLFTPM2_CAPS *caps); +#endif + +int TPM2_PCRs_Print(void); +int TPM2_Init_Device(WOLFTPM2_DEV *dev, void *userCtx); + +#ifdef __cplusplus +} +#endif + +#endif /* __WOLFTPM_H__ */ diff --git a/lib/wolftpm.c b/lib/wolftpm.c new file mode 100644 index 00000000000..49e35401236 --- /dev/null +++ b/lib/wolftpm.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * wolfTPM wrapper layer for U-Boot + * + * Copyright (C) 2025 wolfSSL Inc. + * Author: Aidan Garske <aidan@wolfssl.com> + */ + +/* wolfTPM wrapper layer to expose U-boot API + * when wolfCrypt is not available. This is used by + * the U-boot firmware update command. + */ + +#include <configs/user_settings.h> +#include <hash.h> +#include <linux/types.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include <mapmem.h> +#include <asm/cache.h> +#include <errno.h> + +/* Add wolfTPM type definitions */ +typedef uint8_t byte; +typedef uint32_t word32; + +#ifdef WOLFTPM2_NO_WOLFCRYPT +int wc_Sha384Hash(const byte *data, word32 len, byte *hash) +{ + struct hash_algo *algo; + u8 *output; + void *buf; + + if (hash_lookup_algo("sha384", &algo)) { + printf("Unknown hash algorithm 'sha384'\n"); + return -1; + } + + output = (u8 *)memalign(ARCH_DMA_MINALIGN, + algo->digest_size); + if (!output) { + return -ENOMEM; + } + + buf = (void *)map_sysmem((ulong)data, len); + algo->hash_func_ws(buf, len, output, algo->chunk_size); + unmap_sysmem(buf); + + memcpy(hash, output, algo->digest_size); + + free(output); + return 0; +} +#endif /* WOLFTPM2_NO_WOLFCRYPT */ -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 07/12] tpm: add wolfTPM driver helpers and Kconfig options 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske ` (5 preceding siblings ...) 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 06/12] tpm: add wolfTPM headers and SHA384 glue code David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 08/12] cmd: refactor tpm2 command into frontend/backend architecture David Garske ` (4 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Add wolfTPM helper functions and configuration options to the TPM driver subsystem. drivers/tpm/wolftpm_common.c: Shared helper functions used by the wolfTPM command backend: - TPM2_IFX_FwData_Cb(): firmware data callback for Infineon firmware update streaming - TPM2_IFX_GetOpModeStr(): converts Infineon operational mode codes to human-readable strings - TPM2_IFX_PrintInfo(): prints manufacturer, vendor, firmware version, and operational mode from WOLFTPM2_CAPS - TPM2_PCRs_Print(): enumerates and prints assigned PCR banks and their selected PCR indices - TPM2_Init_Device(): initializes wolfTPM with the TPM2_IoCb HAL callback drivers/tpm/Kconfig: Adds configuration options under TPM_V2: - TPM2_SPI_SANDBOX: sandbox TPM SPI emulator for testing - TPM_AUTODETECT: auto-detect TPM chip for swtpm/QEMU - WOLFTPM_LINUX_DEV: use U-Boot driver model instead of wolfTPM's native TIS layer - WOLFTPM_SLB9672/SLB9673: Infineon chip-specific features - WOLFTPM_FIRMWARE_UPGRADE: firmware update support drivers/tpm/Makefile: Compiles wolftpm_common.o and sets wolfTPM include paths and -DWOLFTPM_USER_SETTINGS when CONFIG_TPM_WOLF is enabled. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- drivers/tpm/Kconfig | 44 +++++++++++ drivers/tpm/Makefile | 9 +++ drivers/tpm/wolftpm_common.c | 137 +++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 drivers/tpm/wolftpm_common.c diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index 219ea606b50..a2897a0e040 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -158,6 +158,14 @@ config TPM2_TIS_SANDBOX such as basic configuration, PCR extension and PCR read. Extended functionalities are not implemented. +config TPM2_SPI_SANDBOX + bool "Enable sandbox TPM SPI emulator" + depends on TPM_V2 && SANDBOX && DM_SPI + help + This driver emulates a TPM connected via SPI for sandbox testing. + It implements the TPM TIS SPI protocol and can be used to test + wolfTPM SPI HAL code without physical hardware. + config TPM2_TIS_SPI bool "Enable support for TPMv2.x SPI chips" depends on TPM_V2 && DM_SPI @@ -200,6 +208,42 @@ config TPM2_EVENT_LOG_SIZE allocated twice. One for the eventlog it self and one for the configuration table that is required from the TCG2 spec +config TPM_AUTODETECT + bool "wolfTPM auto-detect TPM chip (for swtpm/QEMU)" + depends on TPM_V2 && TPM_WOLF + help + Enable wolfTPM chip auto-detection instead of using a specific + chip type (SLB9672/SLB9673). Use this for swtpm/QEMU testing + where no specific hardware chip is present. + +config WOLFTPM_LINUX_DEV + bool "Use device-level TPM interface (bypass wolfTPM TIS layer)" + depends on TPM_V2 && TPM_WOLF + default y + help + Enable wolfTPM to use the underlying TPM driver instead of its own + TIS (TPM Interface Specification) layer. On U-Boot, this uses the + U-Boot TPM driver model (tpm_xfer). On Linux, this uses /dev/tpm0. + This is the recommended setting for U-Boot. + +config WOLFTPM_SLB9672 + bool "Enable support for Infineon SLB9672 TPM" + depends on TPM_V2 && TPM_WOLF + help + Enable support for Infineon SLB9672 TPM features in wolfTPM. + +config WOLFTPM_SLB9673 + bool "Enable support for Infineon SLB9673 TPM" + depends on TPM_V2 && TPM_WOLF + help + Enable support for Infineon SLB9673 TPM features in wolfTPM. + +config WOLFTPM_FIRMWARE_UPGRADE + bool "Enable firmware upgrade support for wolfTPM" + depends on TPM_V2 && TPM_WOLF + help + Enable support for Infineon TPM firmware upgrade commands in wolfTPM. + endif # TPM_V2 endmenu diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index b83ce703ec0..bee4193e9fc 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -10,7 +10,16 @@ obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o sandbox_common.o obj-$(CONFIG_$(PHASE_)TPM2_CR50_I2C) += cr50_i2c.o obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o sandbox_common.o +obj-$(CONFIG_TPM2_SPI_SANDBOX) += tpm_spi_sandbox.o obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_core.o tpm2_tis_spi.o obj-$(CONFIG_TPM2_TIS_I2C) += tpm2_tis_core.o tpm2_tis_i2c.o obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o obj-$(CONFIG_TPM2_MMIO) += tpm2_tis_core.o tpm2_tis_mmio.o + +# wolfTPM helper functions +ifeq ($(CONFIG_TPM_WOLF),y) +ccflags-y += -I$(srctree)/lib/wolftpm \ + -I$(srctree)/include/configs \ + -DWOLFTPM_USER_SETTINGS +obj-y += wolftpm_common.o +endif diff --git a/drivers/tpm/wolftpm_common.c b/drivers/tpm/wolftpm_common.c new file mode 100644 index 00000000000..bea36cf0229 --- /dev/null +++ b/drivers/tpm/wolftpm_common.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * wolfTPM common helper functions for U-Boot + * + * Copyright (C) 2025 wolfSSL Inc. + * Author: Aidan Garske <aidan@wolfssl.com> + */ + +#define LOG_CATEGORY UCLASS_BOOTSTD + +#include <wolftpm.h> +#include <wolftpm/tpm2.h> +#include <wolftpm/tpm2_wrap.h> +#include <wolftpm/tpm2_packet.h> +#include <hal/tpm_io.h> +#include <stdio.h> +#include <string.h> +#include <log.h> +#include <hash.h> +#include <examples/wrap/wrap_test.h> + +#ifndef WOLFTPM2_NO_WRAPPER +#ifdef WOLFTPM_FIRMWARE_UPGRADE + +/******************************************************************************/ +/* --- BEGIN helper functions -- */ +/******************************************************************************/ + +struct fw_info { + byte *manifest_buf; + byte *firmware_buf; + size_t manifest_bufSz; + size_t firmware_bufSz; +}; + +int TPM2_IFX_FwData_Cb(uint8_t *data, uint32_t data_req_sz, + uint32_t offset, void *cb_ctx) +{ + struct fw_info *fwinfo = (struct fw_info *)cb_ctx; + + if (offset > fwinfo->firmware_bufSz) + return BUFFER_E; + if (offset + data_req_sz > (uint32_t)fwinfo->firmware_bufSz) + data_req_sz = (uint32_t)fwinfo->firmware_bufSz - offset; + if (data_req_sz > 0) + memcpy(data, &fwinfo->firmware_buf[offset], data_req_sz); + return data_req_sz; +} + +const char *TPM2_IFX_GetOpModeStr(int opMode) +{ + const char *opModeStr = "Unknown"; + + switch (opMode) { + case 0x00: + opModeStr = "Normal TPM operational mode"; + break; + case 0x01: + opModeStr = "TPM firmware update mode (abandon possible)"; + break; + case 0x02: + opModeStr = "TPM firmware update mode (abandon not possible)"; + break; + case 0x03: + opModeStr = "After successful update, but before finalize"; + break; + case 0x04: + opModeStr = "After finalize or abandon, reboot required"; + break; + default: + break; + } + return opModeStr; +} + +void TPM2_IFX_PrintInfo(WOLFTPM2_CAPS *caps) +{ + printf("Mfg %s (%d), Vendor %s, Fw %u.%u (0x%x)\n", + caps->mfgStr, caps->mfg, caps->vendorStr, caps->fwVerMajor, + caps->fwVerMinor, caps->fwVerVendor); + printf("Operational mode: %s (0x%x)\n", + TPM2_IFX_GetOpModeStr(caps->opMode), caps->opMode); + printf("KeyGroupId 0x%x, FwCounter %d (%d same)\n", + caps->keyGroupId, caps->fwCounter, caps->fwCounterSame); +} +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ + +int TPM2_PCRs_Print(void) +{ + int rc; + int pcrCount, pcrIndex; + GetCapability_In capIn; + GetCapability_Out capOut; + TPML_PCR_SELECTION *pcrSel; + + memset(&capIn, 0, sizeof(capIn)); + capIn.capability = TPM_CAP_PCRS; + capIn.property = 0; + capIn.propertyCount = 1; + rc = TPM2_GetCapability(&capIn, &capOut); + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2_GetCapability failed rc=%d (%s)\n", + rc, TPM2_GetRCString(rc)); + return rc; + } + pcrSel = &capOut.capabilityData.data.assignedPCR; + printf("Assigned PCR's:\n"); + for (pcrCount = 0; pcrCount < (int)pcrSel->count; pcrCount++) { + printf("\t%s: ", + TPM2_GetAlgName(pcrSel->pcrSelections[pcrCount].hash)); + for (pcrIndex = 0; + pcrIndex < pcrSel->pcrSelections[pcrCount].sizeofSelect * 8; + pcrIndex++) { + if ((pcrSel->pcrSelections[pcrCount].pcrSelect[pcrIndex / 8] & + ((1 << (pcrIndex % 8)))) != 0) + printf(" %d", pcrIndex); + } + printf("\n"); + } + return TPM_RC_SUCCESS; +} + +int TPM2_Init_Device(WOLFTPM2_DEV *dev, void *userCtx) +{ + int rc; + + /* Use TPM2_IoCb callback for packet-level access */ + rc = wolfTPM2_Init(dev, TPM2_IoCb, userCtx); + log_debug("tpm2 init: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + return rc; +} + +#endif /* WOLFTPM2_NO_WRAPPER */ + +/******************************************************************************/ +/* --- END helper functions -- */ +/******************************************************************************/ -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 08/12] cmd: refactor tpm2 command into frontend/backend architecture 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske ` (6 preceding siblings ...) 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 07/12] tpm: add wolfTPM driver helpers and Kconfig options David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 09/12] tpm: add sandbox TPM SPI emulator David Garske ` (3 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Split the tpm2 command implementation into a shared frontend and two selectable backends. This allows wolfTPM to provide its own TPM2 command implementations while keeping the command table, dispatcher, and help text shared. Architecture: cmd/tpm-v2.c (frontend - always compiled): Contains the tpm2_commands[] table, get_tpm2_commands(), the do_tpm2() dispatcher, and the U_BOOT_CMD help text. References backend functions via cmd/tpm2-backend.h. When CONFIG_TPM_WOLF is enabled, additional wolfTPM-only commands (caps, pcr_print, firmware_update, firmware_cancel) are added to the table. cmd/tpm2-backend.h (new): Declares all backend function prototypes that both backends must implement: do_tpm2_device, do_tpm2_info, do_tpm2_init, do_tpm2_startup, do_tpm2_selftest, do_tpm2_clear, do_tpm2_pcr_extend, do_tpm2_pcr_read, do_tpm2_get_capability, do_tpm2_dam_reset, do_tpm2_dam_parameters, do_tpm2_change_auth, do_tpm2_pcr_setauthpolicy, do_tpm2_pcr_setauthvalue, do_tpm2_pcr_allocate, plus wolfTPM-only functions. cmd/native_tpm2.c (new - native backend): Contains the original tpm2 command implementations that use U-Boot's TPM driver model (tpm_api.h, tpm-v2.h). Compiled when CONFIG_TPM_WOLF is not set. Common commands delegate to tpm-common.c helpers (do_tpm_device, do_tpm_info, etc.). cmd/wolftpm.c (new - wolfTPM backend): Implements all tpm2 commands using wolfTPM library APIs directly (wolfTPM2_Init, wolfTPM2_GetCapabilities, wolfTPM2_ExtendPCR, etc.). Includes Infineon-specific firmware update and cancel commands. Each command initializes its own WOLFTPM2_DEV instance rather than going through U-Boot's driver model. cmd/Kconfig: Adds CMD_WOLFTPM option that selects TPM_WOLF and CMD_TPM_V2, providing a single menuconfig toggle for wolfTPM support. cmd/Makefile: Conditionally compiles wolftpm.o (when CONFIG_TPM_WOLF=y) or native_tpm2.o (otherwise) alongside the shared tpm-v2.o frontend. Sets wolfTPM include paths and -DWOLFTPM_USER_SETTINGS. The reason for separate backend files rather than a callback-based approach is that wolfTPM uses fundamentally different types and initialization patterns (WOLFTPM2_DEV vs struct udevice, direct library calls vs driver model ops), making runtime dispatch impractical without heavy abstraction. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- cmd/Kconfig | 11 + cmd/Makefile | 10 +- cmd/native_tpm2.c | 516 +++++++++++++++++++ cmd/tpm-v2.c | 559 +++------------------ cmd/tpm2-backend.h | 66 +++ cmd/wolftpm.c | 1170 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1840 insertions(+), 492 deletions(-) create mode 100644 cmd/native_tpm2.c create mode 100644 cmd/tpm2-backend.h create mode 100644 cmd/wolftpm.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 322ebe600c5..d9360d5237a 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -3202,4 +3202,15 @@ config CMD_SPAWN_NUM_JOBS When a jobs exits, its identifier is available to be re-used by the next spawn command. +config CMD_WOLFTPM + bool "Use wolfTPM as TPM2 backend" + depends on TPM_V2 + select TPM_WOLF + select CMD_TPM_V2 + help + Use the wolfTPM library as the backend for TPM2 commands instead + of the standard U-Boot TPM2 implementation. wolfTPM offers additional + features including firmware update support for Infineon TPMs and + enhanced capabilities reporting. + endif diff --git a/cmd/Makefile b/cmd/Makefile index 4cd13d4fa6e..2b12b26e61f 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -191,9 +191,17 @@ obj-$(CONFIG_CMD_TIMER) += timer.o obj-$(CONFIG_CMD_TRACE) += trace.o obj-$(CONFIG_HUSH_PARSER) += test.o obj-$(CONFIG_CMD_TPM) += tpm-common.o -obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o obj-$(CONFIG_CMD_TPM_TEST) += tpm_test.o +obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o obj-$(CONFIG_CMD_TPM_V2) += tpm-v2.o +ifeq ($(CONFIG_TPM_WOLF),y) +ccflags-y += -I$(srctree)/lib/wolftpm \ + -I$(srctree)/include/configs \ + -DWOLFTPM_USER_SETTINGS +obj-$(CONFIG_CMD_TPM_V2) += wolftpm.o +else +obj-$(CONFIG_CMD_TPM_V2) += native_tpm2.o +endif obj-$(CONFIG_CMD_CROS_EC) += cros_ec.o obj-$(CONFIG_CMD_UBI) += ubi.o obj-$(CONFIG_CMD_UBIFS) += ubifs.o diff --git a/cmd/native_tpm2.c b/cmd/native_tpm2.c new file mode 100644 index 00000000000..d8dea956156 --- /dev/null +++ b/cmd/native_tpm2.c @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Native TPM2 backend implementation + * + * Copyright (c) 2018 Bootlin + * Author: Miquel Raynal <miquel.raynal@bootlin.com> + */ + +#include <command.h> +#include <dm.h> +#include <log.h> +#include <mapmem.h> +#include <tpm-common.h> +#include <tpm-v2.h> +#include "tpm-user-utils.h" + +/* Wrappers for common commands - delegate to tpm-common.c */ +int do_tpm2_device(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return do_tpm_device(cmdtp, flag, argc, argv); +} + +int do_tpm2_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return do_tpm_info(cmdtp, flag, argc, argv); +} + +int do_tpm2_state(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return do_tpm_report_state(cmdtp, flag, argc, argv); +} + +int do_tpm2_init(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return do_tpm_init(cmdtp, flag, argc, argv); +} + +int do_tpm2_autostart(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return do_tpm_autostart(cmdtp, flag, argc, argv); +} + +int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + enum tpm2_startup_types mode; + struct udevice *dev; + int ret; + bool bon = true; + + ret = get_tpm(&dev); + if (ret) + return ret; + + /* argv[2] is optional to perform a TPM2_CC_SHUTDOWN */ + if (argc > 3 || (argc == 3 && strcasecmp("off", argv[2]))) + return CMD_RET_USAGE; + + if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) { + mode = TPM2_SU_CLEAR; + } else if (!strcasecmp("TPM2_SU_STATE", argv[1])) { + mode = TPM2_SU_STATE; + } else { + printf("Couldn't recognize mode string: %s\n", argv[1]); + return CMD_RET_FAILURE; + } + + if (argv[2]) + bon = false; + + return report_return_code(tpm2_startup(dev, bon, mode)); +} + +int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + enum tpm2_yes_no full_test; + struct udevice *dev; + int ret; + + ret = get_tpm(&dev); + if (ret) + return ret; + if (argc != 2) + return CMD_RET_USAGE; + + if (!strcasecmp("full", argv[1])) { + full_test = TPMI_YES; + } else if (!strcasecmp("continue", argv[1])) { + full_test = TPMI_NO; + } else { + printf("Couldn't recognize test mode: %s\n", argv[1]); + return CMD_RET_FAILURE; + } + + return report_return_code(tpm2_self_test(dev, full_test)); +} + +int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + u32 handle = 0; + const char *pw = (argc < 3) ? NULL : argv[2]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + struct udevice *dev; + int ret; + + ret = get_tpm(&dev); + if (ret) + return ret; + + if (argc < 2 || argc > 3) + return CMD_RET_USAGE; + + if (pw_sz > TPM2_DIGEST_LEN) + return -EINVAL; + + if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) + handle = TPM2_RH_LOCKOUT; + else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) + handle = TPM2_RH_PLATFORM; + else + return CMD_RET_USAGE; + + return report_return_code(tpm2_clear(dev, handle, pw, pw_sz)); +} + +int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + 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 || argc > 4) + return CMD_RET_USAGE; + if (argc == 4) { + algo = tpm2_name_to_algorithm(argv[3]); + if (algo == TPM2_ALG_INVAL) + return CMD_RET_FAILURE; + } + algo_len = tpm2_algorithm_to_len(algo); + + ret = get_tpm(&dev); + if (ret) + return ret; + + priv = dev_get_uclass_priv(dev); + if (!priv) + return -EINVAL; + + if (index >= priv->pcr_count) + return -EINVAL; + + 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); + + return report_return_code(rc); +} + +int do_tpm2_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 || argc > 4) + return CMD_RET_USAGE; + if (argc == 4) { + algo = tpm2_name_to_algorithm(argv[3]); + if (algo == TPM2_ALG_INVAL) + return CMD_RET_FAILURE; + } + algo_len = tpm2_algorithm_to_len(algo); + + ret = get_tpm(&dev); + if (ret) + return ret; + + priv = dev_get_uclass_priv(dev); + if (!priv) + return -EINVAL; + + index = simple_strtoul(argv[1], NULL, 0); + if (index >= priv->pcr_count) + return -EINVAL; + + data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0); + + rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, algo, + data, algo_len, &updates); + if (!rc) { + 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); + + return report_return_code(rc); +} + +int do_tpm2_get_capability(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + u32 capability, property, rc; + u8 *data; + size_t count; + int i, j; + struct udevice *dev; + int ret; + + ret = get_tpm(&dev); + if (ret) + return ret; + + if (argc != 5) + return CMD_RET_USAGE; + + capability = simple_strtoul(argv[1], NULL, 0); + property = simple_strtoul(argv[2], NULL, 0); + data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0); + count = simple_strtoul(argv[4], NULL, 0); + + rc = tpm2_get_capability(dev, capability, property, data, count); + if (rc) + goto unmap_data; + + printf("Capabilities read from TPM:\n"); + for (i = 0; i < count; i++) { + printf("Property 0x"); + for (j = 0; j < 4; j++) + printf("%02x", data[(i * 8) + j + sizeof(u32)]); + printf(": 0x"); + for (j = 4; j < 8; j++) + printf("%02x", data[(i * 8) + j + sizeof(u32)]); + printf("\n"); + } + +unmap_data: + unmap_sysmem(data); + + return report_return_code(rc); +} + +static u32 select_mask(u32 mask, enum tpm2_algorithms algo, bool select) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { + if (hash_algo_list[i].hash_alg != algo) + continue; + + if (select) + mask |= hash_algo_list[i].hash_mask; + else + mask &= ~hash_algo_list[i].hash_mask; + + break; + } + + return mask; +} + +static bool +is_algo_in_pcrs(enum tpm2_algorithms algo, struct tpml_pcr_selection *pcrs) +{ + size_t i; + + for (i = 0; i < pcrs->count; i++) { + if (algo == pcrs->selection[i].hash) + return true; + } + + return false; +} + +int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + int ret; + enum tpm2_algorithms algo; + const char *pw = (argc < 4) ? NULL : argv[3]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + static struct tpml_pcr_selection pcr = { 0 }; + u32 pcr_len = 0; + bool bon = false; + static u32 mask; + int i; + + /* argv[1]: algorithm (bank), argv[2]: on/off */ + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + if (!strcasecmp("on", argv[2])) + bon = true; + else if (strcasecmp("off", argv[2])) + return CMD_RET_USAGE; + + algo = tpm2_name_to_algorithm(argv[1]); + if (algo == TPM2_ALG_INVAL) + return CMD_RET_USAGE; + + ret = get_tpm(&dev); + if (ret) + return ret; + + if (!pcr.count) { + /* + * Get current active algorithms (banks), PCRs and mask via the + * first call + */ + ret = tpm2_get_pcr_info(dev, &pcr); + if (ret) + return ret; + + for (i = 0; i < pcr.count; i++) { + struct tpms_pcr_selection *sel = &pcr.selection[i]; + const char *name; + + if (!tpm2_is_active_bank(sel)) + continue; + + mask = select_mask(mask, sel->hash, true); + name = tpm2_algorithm_name(sel->hash); + if (name) + printf("Active bank[%d]: %s\n", i, name); + } + } + + if (!is_algo_in_pcrs(algo, &pcr)) { + printf("%s is not supported by the tpm device\n", argv[1]); + return CMD_RET_USAGE; + } + + mask = select_mask(mask, algo, bon); + ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len); + if (ret) + return ret; + + return report_return_code(tpm2_send_pcr_allocate(dev, pw, pw_sz, &pcr, + pcr_len)); +} + +int do_tpm2_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *pw = (argc < 2) ? NULL : argv[1]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + struct udevice *dev; + int ret; + + ret = get_tpm(&dev); + if (ret) + return ret; + + if (argc > 2) + return CMD_RET_USAGE; + + if (pw_sz > TPM2_DIGEST_LEN) + return -EINVAL; + + return report_return_code(tpm2_dam_reset(dev, pw, pw_sz)); +} + +int do_tpm2_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *pw = (argc < 5) ? NULL : argv[4]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + /* + * No Dictionary Attack Mitigation (DAM) means: + * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0 + */ + unsigned long int max_tries; + unsigned long int recovery_time; + unsigned long int lockout_recovery; + struct udevice *dev; + int ret; + + ret = get_tpm(&dev); + if (ret) + return ret; + + if (argc < 4 || argc > 5) + return CMD_RET_USAGE; + + if (pw_sz > TPM2_DIGEST_LEN) + return -EINVAL; + + if (strict_strtoul(argv[1], 0, &max_tries)) + return CMD_RET_USAGE; + + if (strict_strtoul(argv[2], 0, &recovery_time)) + return CMD_RET_USAGE; + + if (strict_strtoul(argv[3], 0, &lockout_recovery)) + return CMD_RET_USAGE; + + log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n"); + log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries); + log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time); + log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery); + + return report_return_code(tpm2_dam_parameters(dev, pw, pw_sz, max_tries, + recovery_time, + lockout_recovery)); +} + +int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + u32 handle; + const char *newpw = argv[2]; + const char *oldpw = (argc == 3) ? NULL : argv[3]; + const ssize_t newpw_sz = strlen(newpw); + const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0; + struct udevice *dev; + int ret; + + ret = get_tpm(&dev); + if (ret) + return ret; + + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN) + return -EINVAL; + + if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) + handle = TPM2_RH_LOCKOUT; + else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1])) + handle = TPM2_RH_ENDORSEMENT; + else if (!strcasecmp("TPM2_RH_OWNER", argv[1])) + handle = TPM2_RH_OWNER; + else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) + handle = TPM2_RH_PLATFORM; + else + return CMD_RET_USAGE; + + return report_return_code(tpm2_change_auth(dev, handle, newpw, newpw_sz, + oldpw, oldpw_sz)); +} + +int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + u32 index = simple_strtoul(argv[1], NULL, 0); + char *key = argv[2]; + const char *pw = (argc < 4) ? NULL : argv[3]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + struct udevice *dev; + int ret; + + ret = get_tpm(&dev); + if (ret) + return ret; + + if (strlen(key) != TPM2_DIGEST_LEN) + return -EINVAL; + + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + return report_return_code(tpm2_pcr_setauthpolicy(dev, pw, pw_sz, index, + key)); +} + +int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + u32 index = simple_strtoul(argv[1], NULL, 0); + char *key = argv[2]; + const ssize_t key_sz = strlen(key); + const char *pw = (argc < 4) ? NULL : argv[3]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + struct udevice *dev; + int ret; + + ret = get_tpm(&dev); + if (ret) + return ret; + + if (strlen(key) != TPM2_DIGEST_LEN) + return -EINVAL; + + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + return report_return_code(tpm2_pcr_setauthvalue(dev, pw, pw_sz, index, + key, key_sz)); +} diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index 847b2691581..a131a81d1a4 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -1,507 +1,51 @@ // SPDX-License-Identifier: GPL-2.0+ /* + * TPM2 command frontend - command table, dispatcher, and help text + * + * The actual command implementations are provided by the backend: + * - native_tpm2.c: U-Boot native TPM2 APIs (driver model) + * - wolftpm.c: wolfTPM library APIs + * * Copyright (c) 2018 Bootlin * Author: Miquel Raynal <miquel.raynal@bootlin.com> */ #include <command.h> -#include <dm.h> -#include <log.h> -#include <mapmem.h> #include <tpm-common.h> -#include <tpm-v2.h> -#include "tpm-user-utils.h" - -static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - enum tpm2_startup_types mode; - struct udevice *dev; - int ret; - bool bon = true; - - ret = get_tpm(&dev); - if (ret) - return ret; - - /* argv[2] is optional to perform a TPM2_CC_SHUTDOWN */ - if (argc > 3 || (argc == 3 && strcasecmp("off", argv[2]))) - return CMD_RET_USAGE; - - if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) { - mode = TPM2_SU_CLEAR; - } else if (!strcasecmp("TPM2_SU_STATE", argv[1])) { - mode = TPM2_SU_STATE; - } else { - printf("Couldn't recognize mode string: %s\n", argv[1]); - return CMD_RET_FAILURE; - } - - if (argv[2]) - bon = false; - - return report_return_code(tpm2_startup(dev, bon, mode)); -} - -static int do_tpm2_self_test(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - enum tpm2_yes_no full_test; - struct udevice *dev; - int ret; - - ret = get_tpm(&dev); - if (ret) - return ret; - if (argc != 2) - return CMD_RET_USAGE; - - if (!strcasecmp("full", argv[1])) { - full_test = TPMI_YES; - } else if (!strcasecmp("continue", argv[1])) { - full_test = TPMI_NO; - } else { - printf("Couldn't recognize test mode: %s\n", argv[1]); - return CMD_RET_FAILURE; - } - - return report_return_code(tpm2_self_test(dev, full_test)); -} - -static int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - u32 handle = 0; - const char *pw = (argc < 3) ? NULL : argv[2]; - const ssize_t pw_sz = pw ? strlen(pw) : 0; - struct udevice *dev; - int ret; - - ret = get_tpm(&dev); - if (ret) - return ret; - - if (argc < 2 || argc > 3) - return CMD_RET_USAGE; - - if (pw_sz > TPM2_DIGEST_LEN) - return -EINVAL; - - if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) - handle = TPM2_RH_LOCKOUT; - else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) - handle = TPM2_RH_PLATFORM; - else - return CMD_RET_USAGE; - - return report_return_code(tpm2_clear(dev, handle, pw, pw_sz)); -} - -static int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - struct udevice *dev; - 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 || argc > 4) - return CMD_RET_USAGE; - if (argc == 4) { - algo = tpm2_name_to_algorithm(argv[3]); - if (algo == TPM2_ALG_INVAL) - return CMD_RET_FAILURE; - } - algo_len = tpm2_algorithm_to_len(algo); - - ret = get_tpm(&dev); - if (ret) - return ret; - - priv = dev_get_uclass_priv(dev); - if (!priv) - return -EINVAL; - - if (index >= priv->pcr_count) - return -EINVAL; - - 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); - - return report_return_code(rc); -} - -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 || argc > 4) - return CMD_RET_USAGE; - if (argc == 4) { - algo = tpm2_name_to_algorithm(argv[3]); - if (algo == TPM2_ALG_INVAL) - return CMD_RET_FAILURE; - } - algo_len = tpm2_algorithm_to_len(algo); - - ret = get_tpm(&dev); - if (ret) - return ret; - - priv = dev_get_uclass_priv(dev); - if (!priv) - return -EINVAL; - - index = simple_strtoul(argv[1], NULL, 0); - if (index >= priv->pcr_count) - return -EINVAL; - - data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0); - - rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, algo, - data, algo_len, &updates); - if (!rc) { - 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); - - return report_return_code(rc); -} - -static int do_tpm_get_capability(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - u32 capability, property, rc; - u8 *data; - size_t count; - int i, j; - struct udevice *dev; - int ret; - - ret = get_tpm(&dev); - if (ret) - return ret; - - if (argc != 5) - return CMD_RET_USAGE; - - capability = simple_strtoul(argv[1], NULL, 0); - property = simple_strtoul(argv[2], NULL, 0); - data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0); - count = simple_strtoul(argv[4], NULL, 0); - - rc = tpm2_get_capability(dev, capability, property, data, count); - if (rc) - goto unmap_data; - - printf("Capabilities read from TPM:\n"); - for (i = 0; i < count; i++) { - printf("Property 0x"); - for (j = 0; j < 4; j++) - printf("%02x", data[(i * 8) + j + sizeof(u32)]); - printf(": 0x"); - for (j = 4; j < 8; j++) - printf("%02x", data[(i * 8) + j + sizeof(u32)]); - printf("\n"); - } - -unmap_data: - unmap_sysmem(data); - - return report_return_code(rc); -} - -static u32 select_mask(u32 mask, enum tpm2_algorithms algo, bool select) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { - if (hash_algo_list[i].hash_alg != algo) - continue; - - if (select) - mask |= hash_algo_list[i].hash_mask; - else - mask &= ~hash_algo_list[i].hash_mask; - - break; - } - - return mask; -} - -static bool -is_algo_in_pcrs(enum tpm2_algorithms algo, struct tpml_pcr_selection *pcrs) -{ - size_t i; - - for (i = 0; i < pcrs->count; i++) { - if (algo == pcrs->selection[i].hash) - return true; - } - - return false; -} - -static int do_tpm2_pcrallocate(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - struct udevice *dev; - int ret; - enum tpm2_algorithms algo; - const char *pw = (argc < 4) ? NULL : argv[3]; - const ssize_t pw_sz = pw ? strlen(pw) : 0; - static struct tpml_pcr_selection pcr = { 0 }; - u32 pcr_len = 0; - bool bon = false; - static u32 mask; - int i; - - /* argv[1]: algorithm (bank), argv[2]: on/off */ - if (argc < 3 || argc > 4) - return CMD_RET_USAGE; - - if (!strcasecmp("on", argv[2])) - bon = true; - else if (strcasecmp("off", argv[2])) - return CMD_RET_USAGE; - - algo = tpm2_name_to_algorithm(argv[1]); - if (algo == TPM2_ALG_INVAL) - return CMD_RET_USAGE; - - ret = get_tpm(&dev); - if (ret) - return ret; - - if (!pcr.count) { - /* - * Get current active algorithms (banks), PCRs and mask via the - * first call - */ - ret = tpm2_get_pcr_info(dev, &pcr); - if (ret) - return ret; - - for (i = 0; i < pcr.count; i++) { - struct tpms_pcr_selection *sel = &pcr.selection[i]; - const char *name; - - if (!tpm2_is_active_bank(sel)) - continue; - - mask = select_mask(mask, sel->hash, true); - name = tpm2_algorithm_name(sel->hash); - if (name) - printf("Active bank[%d]: %s\n", i, name); - } - } - - if (!is_algo_in_pcrs(algo, &pcr)) { - printf("%s is not supported by the tpm device\n", argv[1]); - return CMD_RET_USAGE; - } - - mask = select_mask(mask, algo, bon); - ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len); - if (ret) - return ret; - - return report_return_code(tpm2_send_pcr_allocate(dev, pw, pw_sz, &pcr, - pcr_len)); -} - -static int do_tpm_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - const char *pw = (argc < 2) ? NULL : argv[1]; - const ssize_t pw_sz = pw ? strlen(pw) : 0; - struct udevice *dev; - int ret; - - ret = get_tpm(&dev); - if (ret) - return ret; - - if (argc > 2) - return CMD_RET_USAGE; - - if (pw_sz > TPM2_DIGEST_LEN) - return -EINVAL; - - return report_return_code(tpm2_dam_reset(dev, pw, pw_sz)); -} - -static int do_tpm_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - const char *pw = (argc < 5) ? NULL : argv[4]; - const ssize_t pw_sz = pw ? strlen(pw) : 0; - /* - * No Dictionary Attack Mitigation (DAM) means: - * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0 - */ - unsigned long int max_tries; - unsigned long int recovery_time; - unsigned long int lockout_recovery; - struct udevice *dev; - int ret; - - ret = get_tpm(&dev); - if (ret) - return ret; - - if (argc < 4 || argc > 5) - return CMD_RET_USAGE; - - if (pw_sz > TPM2_DIGEST_LEN) - return -EINVAL; - - if (strict_strtoul(argv[1], 0, &max_tries)) - return CMD_RET_USAGE; - - if (strict_strtoul(argv[2], 0, &recovery_time)) - return CMD_RET_USAGE; - - if (strict_strtoul(argv[3], 0, &lockout_recovery)) - return CMD_RET_USAGE; - - log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n"); - log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries); - log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time); - log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery); - - return report_return_code(tpm2_dam_parameters(dev, pw, pw_sz, max_tries, - recovery_time, - lockout_recovery)); -} - -static int do_tpm_change_auth(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - u32 handle; - const char *newpw = argv[2]; - const char *oldpw = (argc == 3) ? NULL : argv[3]; - const ssize_t newpw_sz = strlen(newpw); - const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0; - struct udevice *dev; - int ret; - - ret = get_tpm(&dev); - if (ret) - return ret; - - if (argc < 3 || argc > 4) - return CMD_RET_USAGE; - - if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN) - return -EINVAL; - - if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) - handle = TPM2_RH_LOCKOUT; - else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1])) - handle = TPM2_RH_ENDORSEMENT; - else if (!strcasecmp("TPM2_RH_OWNER", argv[1])) - handle = TPM2_RH_OWNER; - else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) - handle = TPM2_RH_PLATFORM; - else - return CMD_RET_USAGE; - - return report_return_code(tpm2_change_auth(dev, handle, newpw, newpw_sz, - oldpw, oldpw_sz)); -} - -static int do_tpm_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - u32 index = simple_strtoul(argv[1], NULL, 0); - char *key = argv[2]; - const char *pw = (argc < 4) ? NULL : argv[3]; - const ssize_t pw_sz = pw ? strlen(pw) : 0; - struct udevice *dev; - int ret; - - ret = get_tpm(&dev); - if (ret) - return ret; - - if (strlen(key) != TPM2_DIGEST_LEN) - return -EINVAL; - - if (argc < 3 || argc > 4) - return CMD_RET_USAGE; - - return report_return_code(tpm2_pcr_setauthpolicy(dev, pw, pw_sz, index, - key)); -} - -static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, - int argc, char *const argv[]) -{ - u32 index = simple_strtoul(argv[1], NULL, 0); - char *key = argv[2]; - const ssize_t key_sz = strlen(key); - const char *pw = (argc < 4) ? NULL : argv[3]; - const ssize_t pw_sz = pw ? strlen(pw) : 0; - struct udevice *dev; - int ret; - - ret = get_tpm(&dev); - if (ret) - return ret; - - if (strlen(key) != TPM2_DIGEST_LEN) - return -EINVAL; - - if (argc < 3 || argc > 4) - return CMD_RET_USAGE; - - return report_return_code(tpm2_pcr_setauthvalue(dev, pw, pw_sz, index, - key, key_sz)); -} +#include "tpm2-backend.h" static struct cmd_tbl tpm2_commands[] = { - U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""), - U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), - U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""), - U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), + U_BOOT_CMD_MKENT(device, 0, 1, do_tpm2_device, "", ""), + U_BOOT_CMD_MKENT(info, 0, 1, do_tpm2_info, "", ""), + U_BOOT_CMD_MKENT(state, 0, 1, do_tpm2_state, "", ""), + U_BOOT_CMD_MKENT(init, 0, 1, do_tpm2_init, "", ""), + U_BOOT_CMD_MKENT(autostart, 0, 1, do_tpm2_autostart, "", ""), U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""), - U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""), + U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_selftest, "", ""), U_BOOT_CMD_MKENT(clear, 0, 1, do_tpm2_clear, "", ""), U_BOOT_CMD_MKENT(pcr_extend, 0, 1, do_tpm2_pcr_extend, "", ""), - U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm_pcr_read, "", ""), - U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm_get_capability, "", ""), - U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm_dam_reset, "", ""), - U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm_dam_parameters, "", ""), - U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm_change_auth, "", ""), - U_BOOT_CMD_MKENT(autostart, 0, 1, do_tpm_autostart, "", ""), + U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm2_pcr_read, "", ""), + U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm2_get_capability, "", ""), + U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm2_dam_reset, "", ""), + U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm2_dam_parameters, "", ""), + U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm2_change_auth, "", ""), U_BOOT_CMD_MKENT(pcr_setauthpolicy, 0, 1, - do_tpm_pcr_setauthpolicy, "", ""), + do_tpm2_pcr_setauthpolicy, "", ""), U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1, - do_tpm_pcr_setauthvalue, "", ""), - U_BOOT_CMD_MKENT(pcr_allocate, 0, 1, do_tpm2_pcrallocate, "", ""), + do_tpm2_pcr_setauthvalue, "", ""), + U_BOOT_CMD_MKENT(pcr_allocate, 0, 1, do_tpm2_pcr_allocate, "", ""), +#ifdef CONFIG_TPM_WOLF + U_BOOT_CMD_MKENT(caps, 0, 1, do_tpm2_caps, "", ""), + U_BOOT_CMD_MKENT(pcr_print, 0, 1, do_tpm2_pcr_print, "", ""), +#ifdef WOLFTPM_FIRMWARE_UPGRADE +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + U_BOOT_CMD_MKENT(firmware_update, 0, 1, + do_tpm2_firmware_update, "", ""), + U_BOOT_CMD_MKENT(firmware_cancel, 0, 1, + do_tpm2_firmware_cancel, "", ""), +#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */ +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ +#endif /* CONFIG_TPM_WOLF */ }; struct cmd_tbl *get_tpm2_commands(unsigned int *size) @@ -511,7 +55,22 @@ struct cmd_tbl *get_tpm2_commands(unsigned int *size) return tpm2_commands; } -U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", +static int do_tpm2(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct cmd_tbl *cmd; + + if (argc < 2) + return CMD_RET_USAGE; + + cmd = find_cmd_tbl(argv[1], tpm2_commands, ARRAY_SIZE(tpm2_commands)); + if (!cmd) + return CMD_RET_USAGE; + + return cmd->cmd(cmdtp, flag, argc - 1, argv + 1); +} + +U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm2, "Issue a TPMv2.x command", "<command> [<arguments>]\n" "\n" "device [num device]\n" @@ -521,7 +80,7 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", "state\n" " Show internal state from the TPM (if available)\n" "autostart\n" -" Initalize the tpm, perform a Startup(clear) and run a full selftest\n" +" Initialize the tpm, perform a Startup(clear) and run a full selftest\n" " sequence\n" "init\n" " Initialize the software stack. Always the first command to issue.\n" @@ -573,6 +132,10 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", " <password>: optional password of the LOCKOUT hierarchy\n" "change_auth <hierarchy> <new_pw> [<old_pw>]\n" " <hierarchy>: the hierarchy\n" +" * TPM2_RH_LOCKOUT\n" +" * TPM2_RH_ENDORSEMENT\n" +" * TPM2_RH_OWNER\n" +" * TPM2_RH_PLATFORM\n" " <new_pw>: new password for <hierarchy>\n" " <old_pw>: optional previous password of <hierarchy>\n" "pcr_setauthpolicy|pcr_setauthvalue <pcr> <key> [<password>]\n" @@ -596,4 +159,18 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", " * off - Clear all available PCRs associated with the specified\n" " algorithm (bank)\n" " <password>: optional password\n" +#ifdef CONFIG_TPM_WOLF +"caps\n" +" Show TPM capabilities and info\n" +"pcr_print\n" +" Prints the current PCR state\n" +#ifdef WOLFTPM_FIRMWARE_UPGRADE +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) +"firmware_update <manifest_addr> <manifest_sz> <firmware_addr> <firmware_sz>\n" +" Update TPM firmware\n" +"firmware_cancel\n" +" Cancel TPM firmware update\n" +#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */ +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ +#endif /* CONFIG_TPM_WOLF */ ); diff --git a/cmd/tpm2-backend.h b/cmd/tpm2-backend.h new file mode 100644 index 00000000000..39e9a3a6b7b --- /dev/null +++ b/cmd/tpm2-backend.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * TPM2 backend function declarations + * + * Each backend (native_tpm2.c or wolftpm.c) implements these functions. + * The frontend (tpm-v2.c) references them in the command table. + */ + +#ifndef __TPM2_BACKEND_H +#define __TPM2_BACKEND_H + +#include <command.h> + +/* Common TPM2 command handlers - both backends must implement these */ +int do_tpm2_device(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_state(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_init(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_autostart(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_get_capability(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); + +/* wolfTPM-only command handlers */ +#ifdef CONFIG_TPM_WOLF +int do_tpm2_caps(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_pcr_print(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +#ifdef WOLFTPM_FIRMWARE_UPGRADE +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) +int do_tpm2_firmware_update(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +int do_tpm2_firmware_cancel(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); +#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */ +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ +#endif /* CONFIG_TPM_WOLF */ + +#endif /* __TPM2_BACKEND_H */ diff --git a/cmd/wolftpm.c b/cmd/wolftpm.c new file mode 100644 index 00000000000..06ea8d47c8a --- /dev/null +++ b/cmd/wolftpm.c @@ -0,0 +1,1170 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * TPM2 command implementation using wolfTPM library + * + * Copyright (C) 2025 wolfSSL Inc. + * Author: Aidan Garske <aidan@wolfssl.com> + */ + +#define LOG_CATEGORY UCLASS_BOOTSTD + +#include <wolftpm/tpm2.h> +#include <wolftpm/tpm2_wrap.h> +#include <wolftpm/tpm2_packet.h> +#include <wolftpm.h> + +#include <stdio.h> +#include <hash.h> +#ifndef WOLFTPM2_NO_WRAPPER + +#include <hal/tpm_io.h> +#include <examples/wrap/wrap_test.h> + +/* U-boot specific includes */ +#include <command.h> +#include <tpm-common.h> +#include <vsprintf.h> +#include <mapmem.h> +#include <errno.h> +#include <log.h> +#include <string.h> + +/* Firmware update info structure for Infineon TPM */ +#ifdef WOLFTPM_FIRMWARE_UPGRADE +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) +struct fw_info { + byte *manifest_buf; + byte *firmware_buf; + size_t manifest_bufSz; + size_t firmware_bufSz; +}; +#endif +#endif + +/******************************************************************************/ +/* --- BEGIN Common Commands -- */ +/******************************************************************************/ + +int do_tpm2_device(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + WOLFTPM2_DEV dev; + WOLFTPM2_CAPS caps; + int rc; + + /* Expected 1 arg only in native SPI mode (no device switching) */ + if (argc != 1) + return CMD_RET_USAGE; + + /* Try to initialize and get device info */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); + if (!rc) { + rc = wolfTPM2_GetCapabilities(&dev, &caps); + if (!rc) { + printf("TPM Device 0: %s (%s) FW=%d.%d\n", + caps.mfgStr, caps.vendorStr, + caps.fwVerMajor, caps.fwVerMinor); + } + wolfTPM2_Cleanup(&dev); + } + + if (rc != 0) { + printf("No TPM device found (rc=%d: %s)\n", rc, TPM2_GetRCString(rc)); + return CMD_RET_FAILURE; + } + + return 0; +} + +int do_tpm2_info(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + WOLFTPM2_DEV dev; + WOLFTPM2_CAPS caps; + int rc; + + if (argc != 1) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); + if (!rc) { + rc = wolfTPM2_GetCapabilities(&dev, &caps); + if (!rc) { + printf("TPM 2.0: %s (%s)\n", caps.mfgStr, caps.vendorStr); + printf(" Firmware: %d.%d (0x%08X)\n", + caps.fwVerMajor, caps.fwVerMinor, caps.fwVerVendor); + printf(" Type: 0x%08X\n", caps.tpmType); + } + wolfTPM2_Cleanup(&dev); + } + + if (rc != 0) { + printf("Couldn't get TPM info (rc=%d: %s)\n", rc, TPM2_GetRCString(rc)); + return CMD_RET_FAILURE; + } + + log_debug("tpm2 info: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + return 0; +} + +int do_tpm2_state(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + WOLFTPM2_DEV dev; + WOLFTPM2_CAPS caps; + int rc; + + if (argc != 1) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); + if (!rc) { + rc = wolfTPM2_GetCapabilities(&dev, &caps); + if (!rc) { + printf("TPM State:\n"); + printf(" Manufacturer: %s\n", caps.mfgStr); + printf(" Vendor: %s\n", caps.vendorStr); + printf(" Firmware: %d.%d\n", caps.fwVerMajor, caps.fwVerMinor); +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + printf(" Mode: Infineon SLB967x (Native SPI)\n"); + printf(" OpMode: %d\n", caps.opMode); +#else + printf(" Mode: Native wolfTPM SPI\n"); +#endif + } + wolfTPM2_Cleanup(&dev); + } + + if (rc != 0) { + printf("Couldn't get TPM state (rc=%d: %s)\n", rc, TPM2_GetRCString(rc)); + return CMD_RET_FAILURE; + } + + log_debug("tpm2 state: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + return 0; +} + +int do_tpm2_init(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + WOLFTPM2_DEV dev; + + if (argc != 1) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + return TPM2_Init_Device(&dev, NULL); +} + +int do_tpm2_autostart(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + + if (argc != 1) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc != TPM_RC_SUCCESS) + return rc; + + /* Perform a startup clear - doStartup=1: Just starts up the TPM */ + rc = wolfTPM2_Reset(&dev, 0, 1); + /* TPM_RC_INITIALIZE means already started - treat as success */ + if (rc == TPM_RC_INITIALIZE) + rc = TPM_RC_SUCCESS; + if (rc != TPM_RC_SUCCESS) { + log_debug("wolfTPM2_Reset failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + return rc; + } + + /* Perform a full self test */ + rc = wolfTPM2_SelfTest(&dev); + if (rc != TPM_RC_SUCCESS) + log_debug("wolfTPM2_SelfTest failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + + log_debug("tpm2 autostart: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} + +/******************************************************************************/ +/* --- END Common Commands -- */ +/******************************************************************************/ + +/******************************************************************************/ +/* --- START TPM 2.0 Commands -- */ +/******************************************************************************/ + +int do_tpm2_get_capability(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + GetCapability_In in; + GetCapability_Out out; + u32 capability, property, rc; + u8 *data; + size_t count; + int i, j; + + if (argc != 5) + return CMD_RET_USAGE; + + capability = simple_strtoul(argv[1], NULL, 0); + property = simple_strtoul(argv[2], NULL, 0); + data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0); + count = simple_strtoul(argv[4], NULL, 0); + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + in.capability = capability; + in.property = property; + in.propertyCount = count; + rc = TPM2_GetCapability(&in, &out); + if (!rc) { + memcpy(data, &out.capabilityData.data, sizeof(out.capabilityData.data)); + + printf("Capabilities read from TPM:\n"); + for (i = 0; i < count; i++) { + printf("Property 0x"); + for (j = 0; j < 4; j++) + printf("%02x", data[(i * 8) + j + sizeof(u32)]); + printf(": 0x"); + for (j = 4; j < 8; j++) + printf("%02x", data[(i * 8) + j + sizeof(u32)]); + printf("\n"); + } + } + + unmap_sysmem(data); + + log_debug("tpm2 get_capability: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_caps(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_CAPS caps; + + if (argc != 1) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc != TPM_RC_SUCCESS) + return rc; + + rc = wolfTPM2_GetCapabilities(&dev, &caps); + if (rc != TPM_RC_SUCCESS) + goto cleanup; + + log_debug("Mfg %s (%d), Vendor %s, Fw %u.%u (0x%x), " + "FIPS 140-2 %d, CC-EAL4 %d\n", + caps.mfgStr, caps.mfg, caps.vendorStr, caps.fwVerMajor, + caps.fwVerMinor, caps.fwVerVendor, caps.fips140_2, caps.cc_eal4); +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + log_debug("Operational mode: %s (0x%x)\n", + TPM2_IFX_GetOpModeStr(caps.opMode), caps.opMode); + log_debug("KeyGroupId 0x%x, FwCounter %d (%d same)\n", + caps.keyGroupId, caps.fwCounter, caps.fwCounterSame); +#endif + + /* List the active persistent handles */ + rc = wolfTPM2_GetHandles(PERSISTENT_FIRST, NULL); + if (rc >= TPM_RC_SUCCESS) + log_debug("Found %d persistent handles\n", rc); + + /* Print the available PCR's */ + rc = TPM2_PCRs_Print(); + +cleanup: + /* Only doShutdown=1: Just shut down the TPM */ + wolfTPM2_Reset(&dev, 1, 0); + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 caps: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} + +#ifdef WOLFTPM_FIRMWARE_UPGRADE +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) +int do_tpm2_firmware_update(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_CAPS caps; + struct fw_info fwinfo; + ulong manifest_addr, firmware_addr; + size_t manifest_sz, firmware_sz; + uint8_t manifest_hash[TPM_SHA384_DIGEST_SIZE]; + int recovery = 0; + + memset(&fwinfo, 0, sizeof(fwinfo)); + + /* Need 5 args: command + 4 arguments */ + if (argc != 5) { + log_debug("Error: Expected 5 arguments but got %d\n", argc); + return CMD_RET_USAGE; + } + printf("TPM2 Firmware Update\n"); + + /* Convert all arguments from strings to numbers */ + manifest_addr = simple_strtoul(argv[1], NULL, 0); + manifest_sz = simple_strtoul(argv[2], NULL, 0); + firmware_addr = simple_strtoul(argv[3], NULL, 0); + firmware_sz = simple_strtoul(argv[4], NULL, 0); + + /* Map the memory addresses */ + fwinfo.manifest_buf = map_sysmem(manifest_addr, manifest_sz); + fwinfo.firmware_buf = map_sysmem(firmware_addr, firmware_sz); + fwinfo.manifest_bufSz = manifest_sz; + fwinfo.firmware_bufSz = firmware_sz; + + if (fwinfo.manifest_buf == NULL || fwinfo.firmware_buf == NULL) { + log_debug("Error: Invalid memory addresses\n"); + return CMD_RET_FAILURE; + } + + printf("Infineon Firmware Update Tool\n"); + printf("\tManifest Address: 0x%lx (size: %zu)\n", + manifest_addr, manifest_sz); + printf("\tFirmware Address: 0x%lx (size: %zu)\n", + firmware_addr, firmware_sz); + + rc = TPM2_Init_Device(&dev, NULL); + if (rc != TPM_RC_SUCCESS) + goto fw_cleanup; + + rc = wolfTPM2_GetCapabilities(&dev, &caps); + if (rc != TPM_RC_SUCCESS) + goto fw_cleanup; + + TPM2_IFX_PrintInfo(&caps); + if (caps.keyGroupId == 0) + log_debug("Error getting key group id from TPM!\n"); + if (caps.opMode == 0x02 || (caps.opMode & 0x80)) + recovery = 1; + + if (recovery) { + printf("Firmware Update (recovery mode):\n"); + rc = wolfTPM2_FirmwareUpgradeRecover(&dev, + fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz, + TPM2_IFX_FwData_Cb, &fwinfo); + } else { + /* Normal mode - hash with wc_Sha384Hash */ + printf("Firmware Update (normal mode):\n"); + rc = wc_Sha384Hash(fwinfo.manifest_buf, + (uint32_t)fwinfo.manifest_bufSz, manifest_hash); + if (rc != TPM_RC_SUCCESS) + goto fw_cleanup; + rc = wolfTPM2_FirmwareUpgradeHash(&dev, TPM_ALG_SHA384, + manifest_hash, (uint32_t)sizeof(manifest_hash), + fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz, + TPM2_IFX_FwData_Cb, &fwinfo); + } + + if (!rc) + TPM2_IFX_PrintInfo(&caps); + +fw_cleanup: + if (fwinfo.manifest_buf) + unmap_sysmem(fwinfo.manifest_buf); + if (fwinfo.firmware_buf) + unmap_sysmem(fwinfo.firmware_buf); + + if (rc != TPM_RC_SUCCESS) + log_debug("Infineon firmware update failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 firmware_update: rc=%d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_firmware_cancel(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + uint8_t cmd[TPM2_HEADER_SIZE + 2]; + uint16_t val16; + + if (argc != 1) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc == TPM_RC_SUCCESS) { + /* Setup command size in header */ + val16 = TPM2_HEADER_SIZE + 2; + memcpy(cmd, &val16, sizeof(val16)); + val16 = 0; + memcpy(&cmd[TPM2_HEADER_SIZE], &val16, sizeof(val16)); + + rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeAbandonVendor, + cmd, sizeof(cmd)); + if (rc != TPM_RC_SUCCESS) { + log_debug("Firmware abandon failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } + } + + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 firmware_cancel: rc=%d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} +#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */ +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ + +int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + Startup_In startupIn; + Shutdown_In shutdownIn; + int doStartup = YES; + + /* startup TPM2_SU_CLEAR|TPM2_SU_STATE [off] */ + if (argc < 2 || argc > 3) + return CMD_RET_USAGE; + /* Check if shutdown requested */ + if (argc == 3) { + if (strcmp(argv[2], "off") != 0) + return CMD_RET_USAGE; + doStartup = NO; /* shutdown */ + } + printf("TPM2 Startup\n"); + + memset(&startupIn, 0, sizeof(startupIn)); + memset(&shutdownIn, 0, sizeof(shutdownIn)); + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc != TPM_RC_SUCCESS) + return rc; + + if (!strcmp(argv[1], "TPM2_SU_CLEAR")) { + if (doStartup == YES) + startupIn.startupType = TPM_SU_CLEAR; + else + shutdownIn.shutdownType = TPM_SU_CLEAR; + } else if (!strcmp(argv[1], "TPM2_SU_STATE")) { + if (doStartup == YES) + startupIn.startupType = TPM_SU_STATE; + else + shutdownIn.shutdownType = TPM_SU_STATE; + } else { + log_debug("Couldn't recognize mode string: %s\n", argv[1]); + wolfTPM2_Cleanup(&dev); + return CMD_RET_FAILURE; + } + + /* startup */ + if (doStartup == YES) { + rc = TPM2_Startup(&startupIn); + /* TPM_RC_INITIALIZE = Already started */ + if (rc != TPM_RC_SUCCESS && rc != TPM_RC_INITIALIZE) { + log_debug("TPM2 Startup: Result = 0x%x (%s)\n", rc, + TPM2_GetRCString(rc)); + } + /* shutdown */ + } else { + rc = TPM2_Shutdown(&shutdownIn); + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2 Shutdown: Result = 0x%x (%s)\n", rc, + TPM2_GetRCString(rc)); + } + } + + wolfTPM2_Cleanup(&dev); + + if (rc >= 0) + rc = 0; + + log_debug("tpm2 startup (%s): rc = %d (%s)\n", + doStartup ? "startup" : "shutdown", rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + TPMI_YES_NO fullTest = YES; + + /* Need 2 arg: command + type */ + if (argc != 2) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc == TPM_RC_SUCCESS) { + if (!strcmp(argv[1], "full")) { + fullTest = YES; + } else if (!strcmp(argv[1], "continue")) { + fullTest = NO; + } else { + log_debug("Couldn't recognize test mode: %s\n", argv[1]); + wolfTPM2_Cleanup(&dev); + return CMD_RET_FAILURE; + } + + /* full test */ + if (fullTest == YES) { + rc = wolfTPM2_SelfTest(&dev); + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2 Self Test: Result = 0x%x (%s)\n", rc, + TPM2_GetRCString(rc)); + } + /* continue test */ + } else { + rc = wolfTPM2_SelfTest(&dev); + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2 Self Test: Result = 0x%x (%s)\n", rc, + TPM2_GetRCString(rc)); + } + } + } + + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 selftest (%s): rc = %d (%s)\n", + fullTest ? "full" : "continue", rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + Clear_In clearIn; + TPMI_RH_CLEAR handle; + + /* Need 2 arg: command + type */ + if (argc != 2) + return CMD_RET_USAGE; + + if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) + handle = TPM_RH_LOCKOUT; + else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) + handle = TPM_RH_PLATFORM; + else + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc == TPM_RC_SUCCESS) { + /* Set up clear */ + memset(&clearIn, 0, sizeof(clearIn)); + clearIn.authHandle = handle; + + rc = TPM2_Clear(&clearIn); + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2 Clear: Result = 0x%x (%s)\n", rc, + TPM2_GetRCString(rc)); + } + } + + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 clear (%s): rc = %d (%s)\n", + handle == TPM_RH_LOCKOUT ? "TPM2_RH_LOCKOUT" : "TPM2_RH_PLATFORM", + rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + uint32_t pcrIndex; + int algo = TPM_ALG_SHA256; + int digestLen; + void *digest; + ulong digest_addr; + + /* Need 3-4 args: command + pcr + digest_addr + [algo] */ + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + printf("TPM2 PCR Extend\n"); + + pcrIndex = simple_strtoul(argv[1], NULL, 0); + digest_addr = simple_strtoul(argv[2], NULL, 0); + + /* Optional algorithm */ + if (argc == 4) { + algo = TPM2_GetAlgId(argv[3]); + if (algo < 0) { + log_debug("Couldn't recognize algorithm: %s\n", argv[3]); + return CMD_RET_FAILURE; + } + log_debug("Using algorithm: %s\n", TPM2_GetAlgName(algo)); + } + + /* Get digest length based on algorithm */ + digestLen = TPM2_GetHashDigestSize(algo); + if (digestLen <= 0) { + log_debug("Invalid algorithm digest length\n"); + return CMD_RET_FAILURE; + } + + /* Map digest from memory address */ + digest = map_sysmem(digest_addr, digestLen); + if (digest == NULL) { + log_debug("Error: Invalid digest memory address\n"); + return CMD_RET_FAILURE; + } + + log_debug("TPM2 PCR Extend: PCR %u with %s digest\n", + (unsigned int)pcrIndex, TPM2_GetAlgName(algo)); + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc != TPM_RC_SUCCESS) { + unmap_sysmem(digest); + return rc; + } + + /* Extend the PCR */ + rc = wolfTPM2_ExtendPCR(&dev, pcrIndex, algo, digest, digestLen); + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2_PCR_Extend failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + } + + unmap_sysmem(digest); + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 pcr_extend: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_pcr_read(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + uint32_t pcrIndex; + int algo = TPM_ALG_SHA256; + void *digest; + ulong digest_addr; + int digestLen; + + /* Need 3-4 args: command + pcr + digest_addr + [algo] */ + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + pcrIndex = simple_strtoul(argv[1], NULL, 0); + digest_addr = simple_strtoul(argv[2], NULL, 0); + + /* Optional algorithm */ + if (argc == 4) { + algo = TPM2_GetAlgId(argv[3]); + if (algo < 0) { + log_debug("Couldn't recognize algorithm: %s\n", argv[3]); + return CMD_RET_FAILURE; + } + log_debug("Using algorithm: %s\n", TPM2_GetAlgName(algo)); + } + + /* Get digest length based on algorithm */ + digestLen = TPM2_GetHashDigestSize(algo); + if (digestLen <= 0) { + log_debug("Invalid algorithm digest length\n"); + return CMD_RET_FAILURE; + } + + /* Map digest from memory address */ + digest = map_sysmem(digest_addr, digestLen); + if (digest == NULL) { + log_debug("Error: Invalid digest memory address\n"); + return CMD_RET_FAILURE; + } + + log_debug("TPM2 PCR Read: PCR %u to %s digest\n", + (unsigned int)pcrIndex, TPM2_GetAlgName(algo)); + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc != TPM_RC_SUCCESS) { + unmap_sysmem(digest); + return rc; + } + + /* Read the PCR */ + rc = wolfTPM2_ReadPCR(&dev, pcrIndex, algo, digest, &digestLen); + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2_PCR_Read failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + } + + unmap_sysmem(digest); + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 pcr_read: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + PCR_Allocate_In in; + PCR_Allocate_Out out; + TPM2B_AUTH auth; + + /* Need 3-4 args: command + algorithm + on/off + [password] */ + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc != TPM_RC_SUCCESS) + return rc; + + /* Setup PCR Allocation command */ + memset(&in, 0, sizeof(in)); + in.authHandle = TPM_RH_PLATFORM; + + /* Single PCR bank allocation */ + in.pcrAllocation.count = 1; /* Change only one bank */ + in.pcrAllocation.pcrSelections[0].hash = TPM2_GetAlgId(argv[1]); + in.pcrAllocation.pcrSelections[0].sizeofSelect = PCR_SELECT_MAX; + + /* Set all PCRs for this algorithm */ + if (!strcmp(argv[2], "on")) { + memset(in.pcrAllocation.pcrSelections[0].pcrSelect, 0xFF, + PCR_SELECT_MAX); + } else if (!strcmp(argv[2], "off")) { + /* Clear all PCRs for this algorithm */ + memset(in.pcrAllocation.pcrSelections[0].pcrSelect, 0x00, + PCR_SELECT_MAX); + } else { + log_debug("Couldn't recognize allocate mode: %s\n", argv[2]); + wolfTPM2_Cleanup(&dev); + return CMD_RET_USAGE; + } + log_debug("Attempting to set %s bank to %s\n", + TPM2_GetAlgName(in.pcrAllocation.pcrSelections[0].hash), + argv[2]); + + /* Set auth password if provided */ + if (argc == 4) { + memset(&auth, 0, sizeof(auth)); + auth.size = strlen(argv[3]); + memcpy(auth.buffer, argv[3], auth.size); + rc = wolfTPM2_SetAuth(&dev, 0, TPM_RH_PLATFORM, &auth, 0, NULL); + if (rc != TPM_RC_SUCCESS) { + log_debug("wolfTPM2_SetAuth failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + wolfTPM2_Cleanup(&dev); + return rc; + } + } + + /* Allocate the PCR */ + rc = TPM2_PCR_Allocate(&in, &out); + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2_PCR_Allocate failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + } + + /* Print current PCR state */ + printf("\n\tNOTE: A TPM restart is required for changes to take effect\n"); + printf("\nCurrent PCR state:\n"); + TPM2_PCRs_Print(); + + wolfTPM2_Cleanup(&dev); + + printf("Allocation Success: %s\n", + out.allocationSuccess ? "YES" : "NO"); + log_debug("tpm2 pcr_allocate %s (%s): rc = %d (%s)\n", + TPM2_GetAlgName(in.pcrAllocation.pcrSelections[0].hash), + argv[2], rc, TPM2_GetRCString(rc)); + + return rc; +} + +/* + * Without wolfCrypt, parameter encryption is not available. + * A session is required to protect the new platform auth. + */ +#ifndef WOLFTPM2_NO_WOLFCRYPT +static int TPM2_PCR_SetAuth(int argc, char *const argv[], + int isPolicy) +{ + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_SESSION session; + TPM2B_AUTH auth; + const char *pw = (argc < 4) ? NULL : argv[3]; + const char *key = argv[2]; + const ssize_t key_sz = strlen(key); + u32 pcrIndex = simple_strtoul(argv[1], NULL, 0); + + /* Need 3-4 args: command + pcr + auth + [platform_auth] */ + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + /* Init the TPM2 device for value/policy */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc != TPM_RC_SUCCESS) + return rc; + + /* Start the session */ + rc = wolfTPM2_StartSession(&dev, &session, NULL, NULL, + isPolicy ? TPM_SE_POLICY : TPM_SE_HMAC, TPM_ALG_NULL); + if (rc != TPM_RC_SUCCESS) { + log_debug("wolfTPM2_StartSession failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + wolfTPM2_Cleanup(&dev); + return rc; + } + + /* Set the platform auth if provided */ + if (pw) { + TPM2B_AUTH platformAuth; + + memset(&platformAuth, 0, sizeof(platformAuth)); + platformAuth.size = strlen(pw); + memcpy(platformAuth.buffer, pw, platformAuth.size); + rc = wolfTPM2_SetAuth(&dev, 0, TPM_RH_PLATFORM, + &platformAuth, 0, NULL); + if (rc != TPM_RC_SUCCESS) { + log_debug("wolfTPM2_SetAuth failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + wolfTPM2_UnloadHandle(&dev, &session.handle); + wolfTPM2_Cleanup(&dev); + return rc; + } + } + + printf("Setting %s auth for PCR %u\n", + isPolicy ? "policy" : "value", pcrIndex); + + /* Set up the auth value/policy */ + memset(&auth, 0, sizeof(auth)); + auth.size = key_sz; + memcpy(auth.buffer, key, key_sz); + + if (isPolicy) { + /* Use TPM2_PCR_SetAuthPolicy command */ + PCR_SetAuthPolicy_In in; + + memset(&in, 0, sizeof(in)); + in.authHandle = TPM_RH_PLATFORM; + in.authPolicy = auth; + in.hashAlg = TPM_ALG_SHA256; /* Default to SHA256 */ + in.pcrNum = pcrIndex; + rc = TPM2_PCR_SetAuthPolicy(&in); + } else { + /* Use TPM2_PCR_SetAuthValue command */ + PCR_SetAuthValue_In in; + + memset(&in, 0, sizeof(in)); + in.pcrHandle = pcrIndex; + in.auth = auth; + rc = TPM2_PCR_SetAuthValue(&in); + } + + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2_PCR_SetAuth%s failed 0x%x: %s\n", + isPolicy ? "Policy" : "Value", + rc, TPM2_GetRCString(rc)); + } + + wolfTPM2_UnloadHandle(&dev, &session.handle); + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 set_auth %s: rc = %d (%s)\n", + isPolicy ? "Policy" : "Value", rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + return TPM2_PCR_SetAuth(argc, argv, YES); +} + +int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + return TPM2_PCR_SetAuth(argc, argv, NO); +} + +int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_SESSION session; + const char *newpw = argv[2]; + const char *oldpw = (argc == 4) ? argv[3] : NULL; + const ssize_t newpw_sz = strlen(newpw); + const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0; + HierarchyChangeAuth_In in; + TPM2B_AUTH newAuth; + + /* Need 3-4 args: command + hierarchy + new_pw + [old_pw] */ + if (argc < 3 || argc > 4) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc != TPM_RC_SUCCESS) + return rc; + + memset(&in, 0, sizeof(in)); + + /* Set the handle */ + if (!strcmp(argv[1], "TPM2_RH_LOCKOUT")) + in.authHandle = TPM_RH_LOCKOUT; + else if (!strcmp(argv[1], "TPM2_RH_ENDORSEMENT")) + in.authHandle = TPM_RH_ENDORSEMENT; + else if (!strcmp(argv[1], "TPM2_RH_OWNER")) + in.authHandle = TPM_RH_OWNER; + else if (!strcmp(argv[1], "TPM2_RH_PLATFORM")) + in.authHandle = TPM_RH_PLATFORM; + else { + wolfTPM2_Cleanup(&dev); + return CMD_RET_USAGE; + } + + /* Validate password length if provided */ + if (newpw_sz > TPM_SHA256_DIGEST_SIZE || + oldpw_sz > TPM_SHA256_DIGEST_SIZE) { + wolfTPM2_Cleanup(&dev); + return -EINVAL; + } + + /* Start auth session */ + rc = wolfTPM2_StartSession(&dev, &session, NULL, NULL, + TPM_SE_HMAC, TPM_ALG_CFB); + if (rc != TPM_RC_SUCCESS) { + log_debug("wolfTPM2_StartSession failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + wolfTPM2_Cleanup(&dev); + return rc; + } + + /* If old password exists then set it as the current auth */ + if (oldpw) { + TPM2B_AUTH oldAuth; + + memset(&oldAuth, 0, sizeof(oldAuth)); + oldAuth.size = oldpw_sz; + memcpy(oldAuth.buffer, oldpw, oldpw_sz); + rc = wolfTPM2_SetAuthPassword(&dev, 0, &oldAuth); + if (rc != TPM_RC_SUCCESS) { + log_debug("wolfTPM2_SetAuthPassword failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + wolfTPM2_UnloadHandle(&dev, &session.handle); + wolfTPM2_Cleanup(&dev); + return rc; + } + } + + memset(&newAuth, 0, sizeof(newAuth)); + newAuth.size = newpw_sz; + memcpy(newAuth.buffer, newpw, newpw_sz); + in.newAuth = newAuth; + + /* Change the auth based on the hierarchy */ + rc = wolfTPM2_ChangeHierarchyAuth(&dev, &session, in.authHandle); + if (rc != TPM_RC_SUCCESS) { + log_debug("wolfTPM2_ChangeHierarchyAuth failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + } else { + log_debug("Successfully changed auth for %s\n", argv[1]); + } + + wolfTPM2_UnloadHandle(&dev, &session.handle); + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 change_auth: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} +#else /* WOLFTPM2_NO_WOLFCRYPT */ +int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + printf("wolfCrypt support required for change_auth\n"); + return CMD_RET_FAILURE; +} + +int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + printf("wolfCrypt support required for pcr_setauthpolicy\n"); + return CMD_RET_FAILURE; +} + +int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + printf("wolfCrypt support required for pcr_setauthvalue\n"); + return CMD_RET_FAILURE; +} +#endif /* !WOLFTPM2_NO_WOLFCRYPT */ + +int do_tpm2_pcr_print(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + + /* Need 1 arg: command */ + if (argc != 1) + return CMD_RET_USAGE; + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc == TPM_RC_SUCCESS) { + /* Print the current PCR state */ + TPM2_PCRs_Print(); + } + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 pcr_print: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_dam_reset(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + const char *pw = (argc < 2) ? NULL : argv[1]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + DictionaryAttackLockReset_In in; + TPM2_AUTH_SESSION session[MAX_SESSION_NUM]; + + /* Need 1-2 args: command + [password] */ + if (argc > 2) + return CMD_RET_USAGE; + + /* Validate password length if provided */ + if (pw && pw_sz > TPM_SHA256_DIGEST_SIZE) { + log_debug("Error: Password too long\n"); + return -EINVAL; + } + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc == TPM_RC_SUCCESS) { + /* set lock handle */ + memset(&in, 0, sizeof(in)); + in.lockHandle = TPM_RH_LOCKOUT; + + /* Setup auth session only if password provided */ + memset(session, 0, sizeof(session)); + session[0].sessionHandle = TPM_RS_PW; + if (pw) { + session[0].auth.size = pw_sz; + memcpy(session[0].auth.buffer, pw, pw_sz); + } + TPM2_SetSessionAuth(session); + + rc = TPM2_DictionaryAttackLockReset(&in); + log_debug("TPM2_Dam_Reset: Result = 0x%x (%s)\n", rc, + TPM2_GetRCString(rc)); + } + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 dam_reset: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} + +int do_tpm2_dam_parameters(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + const char *pw = (argc < 5) ? NULL : argv[4]; + const ssize_t pw_sz = pw ? strlen(pw) : 0; + DictionaryAttackParameters_In in; + TPM2_AUTH_SESSION session[MAX_SESSION_NUM]; + + /* + * Need 4-5 args: command + max_tries + recovery_time + + * lockout_recovery + [password] + */ + if (argc < 4 || argc > 5) + return CMD_RET_USAGE; + + /* Validate password length if provided */ + if (pw && pw_sz > TPM_SHA256_DIGEST_SIZE) { + log_debug("Error: Password too long\n"); + return -EINVAL; + } + + /* Init the TPM2 device */ + rc = TPM2_Init_Device(&dev, NULL); + if (rc == TPM_RC_SUCCESS) { + /* Set parameters */ + memset(&in, 0, sizeof(in)); + in.newMaxTries = simple_strtoul(argv[1], NULL, 0); + in.newRecoveryTime = simple_strtoul(argv[2], NULL, 0); + in.lockoutRecovery = simple_strtoul(argv[3], NULL, 0); + + /* set lock handle */ + in.lockHandle = TPM_RH_LOCKOUT; + + /* Setup auth session only if password provided */ + memset(session, 0, sizeof(session)); + session[0].sessionHandle = TPM_RS_PW; + if (pw) { + session[0].auth.size = pw_sz; + memcpy(session[0].auth.buffer, pw, pw_sz); + } + TPM2_SetSessionAuth(session); + + /* Set DAM parameters */ + rc = TPM2_DictionaryAttackParameters(&in); + if (rc != TPM_RC_SUCCESS) { + log_debug("TPM2_DictionaryAttackParameters failed 0x%x: %s\n", rc, + TPM2_GetRCString(rc)); + } + + printf("Changing dictionary attack parameters:\n"); + printf(" maxTries: %u\n", in.newMaxTries); + printf(" recoveryTime: %u\n", in.newRecoveryTime); + printf(" lockoutRecovery: %u\n", in.lockoutRecovery); + } + wolfTPM2_Cleanup(&dev); + + log_debug("tpm2 dam_parameters: rc = %d (%s)\n", rc, TPM2_GetRCString(rc)); + + return rc; +} + +#endif /* !WOLFTPM2_NO_WRAPPER */ -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 09/12] tpm: add sandbox TPM SPI emulator 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske ` (7 preceding siblings ...) 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 08/12] cmd: refactor tpm2 command into frontend/backend architecture David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 10/12] test: add wolfTPM C unit tests and Python integration tests David Garske ` (2 subsequent siblings) 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Add a TPM SPI emulator for sandbox testing that implements the TIS (TPM Interface Specification) SPI protocol, allowing wolfTPM's SPI HAL code to be tested without physical hardware. drivers/tpm/tpm_spi_sandbox.c (new): Emulates a TPM connected via SPI by implementing the TIS register set and SPI protocol: - SPI protocol state machine: parses 4-byte TIS SPI headers (R/W bit, transfer length, register address) and handles data phase with immediate ready signaling (no wait states) - TIS register emulation: TPM_ACCESS (locality request/grant), TPM_STS (command ready, data expect, data available, burst count), TPM_INTF_CAPS, TPM_DID_VID (Infineon SLB9670 IDs), TPM_RID, and TPM_DATA_FIFO (command/response buffering) - TIS state machine: IDLE -> READY -> RECEPTION -> EXECUTION -> COMPLETION, with command-ready abort support - Generates simple TPM_RC_SUCCESS responses (a full implementation would integrate the sandbox TPM2 state machine) - Registers as UCLASS_SPI_EMUL with compatible "sandbox,tpm-spi-emul" - Also registers a SPI slave driver (UCLASS_SPI_GENERIC) with compatible "sandbox,tpm-spi" for the DTS device node drivers/mtd/spi/sandbox.c: Modify sandbox_spi_get_emul() to check for a "sandbox,emul" phandle property on SPI slave devices before falling back to the default SPI flash emulation binding. This allows non-flash SPI devices (like the TPM emulator) to specify their own emulator via device tree phandle. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- drivers/mtd/spi/sandbox.c | 30 ++- drivers/tpm/tpm_spi_sandbox.c | 410 ++++++++++++++++++++++++++++++++++ 2 files changed, 431 insertions(+), 9 deletions(-) create mode 100644 drivers/tpm/tpm_spi_sandbox.c diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index e5ebc3479fb..41bd07817aa 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -571,16 +571,28 @@ int sandbox_spi_get_emul(struct sandbox_state *state, info = &state->spi[busnum][cs]; if (!info->emul) { - /* Use the same device tree node as the SPI flash device */ - debug("%s: busnum=%u, cs=%u: binding SPI flash emulation: ", - __func__, busnum, cs); - ret = sandbox_sf_bind_emul(state, busnum, cs, bus, - dev_ofnode(slave), slave->name); - if (ret) { - debug("failed (err=%d)\n", ret); - return ret; + struct udevice *emul; + ofnode node = dev_ofnode(slave); + + /* First check for sandbox,emul phandle property */ + ret = uclass_get_device_by_phandle(UCLASS_SPI_EMUL, slave, + "sandbox,emul", &emul); + if (!ret) { + debug("%s: busnum=%u, cs=%u: using phandle emulator\n", + __func__, busnum, cs); + info->emul = emul; + } else { + /* Fall back to SPI flash emulation binding */ + debug("%s: busnum=%u, cs=%u: binding SPI flash emulation: ", + __func__, busnum, cs); + ret = sandbox_sf_bind_emul(state, busnum, cs, bus, + node, slave->name); + if (ret) { + debug("failed (err=%d)\n", ret); + return ret; + } + debug("OK\n"); } - debug("OK\n"); } *emulp = info->emul; diff --git a/drivers/tpm/tpm_spi_sandbox.c b/drivers/tpm/tpm_spi_sandbox.c new file mode 100644 index 00000000000..694c5d721f0 --- /dev/null +++ b/drivers/tpm/tpm_spi_sandbox.c @@ -0,0 +1,410 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Sandbox TPM SPI Emulator + * + * Copyright (c) 2025 wolfSSL Inc. + * Author: Aidan Garske <aidan@wolfssl.com> + * + * Emulates TPM TIS SPI protocol for testing wolfTPM SPI HAL + * without hardware. Wraps the existing sandbox TPM2 state machine. + */ + +#include <dm.h> +#include <log.h> +#include <spi.h> +#include <spi_flash.h> +#include <asm/spi.h> +#include <asm/state.h> +#include <linux/bitops.h> + +/* TIS register addresses (locality 0) */ +#define TPM_ACCESS_REG 0x0000 +#define TPM_INT_ENABLE_REG 0x0008 +#define TPM_INTF_CAPS_REG 0x0014 +#define TPM_STS_REG 0x0018 +#define TPM_DATA_FIFO_REG 0x0024 +#define TPM_DID_VID_REG 0x0F00 +#define TPM_RID_REG 0x0F04 + +/* TIS access register bits */ +#define TPM_ACCESS_VALID 0x80 +#define TPM_ACCESS_ACTIVE_LOCALITY 0x20 +#define TPM_ACCESS_REQUEST_PENDING 0x04 +#define TPM_ACCESS_REQUEST_USE 0x02 + +/* TIS status register bits */ +#define TPM_STS_VALID 0x80 +#define TPM_STS_COMMAND_READY 0x40 +#define TPM_STS_GO 0x20 +#define TPM_STS_DATA_AVAIL 0x10 +#define TPM_STS_DATA_EXPECT 0x08 + +/* Interface capabilities */ +#define TPM_INTF_CAPS_VALUE 0x30000697 /* Typical Infineon value */ + +/* Device/Vendor ID - Infineon SLB9670 */ +#define TPM_DID_VID_VALUE 0x001D15D1 + +/* Revision ID */ +#define TPM_RID_VALUE 0x36 + +/* Maximum buffer sizes */ +#define TPM_CMD_BUF_SIZE 4096 +#define TPM_RSP_BUF_SIZE 4096 +#define MAX_SPI_FRAMESIZE 64 + +/* TPM TIS SPI protocol states */ +enum tpm_spi_state { + TPM_SPI_IDLE, + TPM_SPI_HEADER, /* Receiving 4-byte header */ + TPM_SPI_WAIT_STATE, /* Sending wait state bytes */ + TPM_SPI_DATA, /* Transfer data */ +}; + +/* TIS state machine */ +enum tpm_tis_state { + TIS_IDLE, + TIS_READY, /* Ready to receive command */ + TIS_RECEPTION, /* Receiving command data */ + TIS_EXECUTION, /* Executing command */ + TIS_COMPLETION, /* Response available */ +}; + +struct sandbox_tpm_spi { + /* SPI protocol state */ + enum tpm_spi_state spi_state; + u8 header[4]; + int header_pos; + bool is_read; + u32 addr; + int xfer_len; + int data_pos; + + /* TIS state */ + enum tpm_tis_state tis_state; + u8 access_reg; + u32 sts_reg; + u32 intf_caps; + + /* Command/response buffers */ + u8 cmd_buf[TPM_CMD_BUF_SIZE]; + int cmd_len; + int cmd_pos; + u8 rsp_buf[TPM_RSP_BUF_SIZE]; + int rsp_len; + int rsp_pos; + + /* Burst count for status register */ + u16 burst_count; +}; + +/* + * Parse TIS SPI header + * Format: [R/W|len-1][0xD4][addr_hi][addr_lo] + * Bit 7 of byte 0: 1=read, 0=write + * Bits 5:0 of byte 0: transfer length - 1 + */ +static void parse_spi_header(struct sandbox_tpm_spi *priv) +{ + priv->is_read = (priv->header[0] & 0x80) != 0; + priv->xfer_len = (priv->header[0] & 0x3F) + 1; + priv->addr = (priv->header[2] << 8) | priv->header[3]; + priv->data_pos = 0; +} + +/* + * Read from TIS register + */ +static u8 tis_reg_read(struct sandbox_tpm_spi *priv, u32 addr) +{ + u32 reg = addr & 0x0FFF; /* Mask off locality bits */ + + switch (reg) { + case TPM_ACCESS_REG: + return priv->access_reg; + + case TPM_STS_REG: + case TPM_STS_REG + 1: + case TPM_STS_REG + 2: + case TPM_STS_REG + 3: { + int byte_off = reg - TPM_STS_REG; + u32 sts = priv->sts_reg; + + /* Update burst count in status */ + sts |= ((u32)priv->burst_count << 8); + return (sts >> (byte_off * 8)) & 0xFF; + } + + case TPM_INTF_CAPS_REG: + case TPM_INTF_CAPS_REG + 1: + case TPM_INTF_CAPS_REG + 2: + case TPM_INTF_CAPS_REG + 3: { + int byte_off = reg - TPM_INTF_CAPS_REG; + + return (priv->intf_caps >> (byte_off * 8)) & 0xFF; + } + + case TPM_DID_VID_REG: + case TPM_DID_VID_REG + 1: + case TPM_DID_VID_REG + 2: + case TPM_DID_VID_REG + 3: { + int byte_off = reg - TPM_DID_VID_REG; + + return (TPM_DID_VID_VALUE >> (byte_off * 8)) & 0xFF; + } + + case TPM_RID_REG: + return TPM_RID_VALUE; + + default: + /* + * Handle FIFO reads - the FIFO can be accessed at any address + * from 0x0024 up to 0x0F00 for multi-byte transfers. + */ + if (reg >= TPM_DATA_FIFO_REG && reg < TPM_DID_VID_REG) { + if (priv->tis_state == TIS_COMPLETION && + priv->rsp_pos < priv->rsp_len) { + u8 data = priv->rsp_buf[priv->rsp_pos++]; + + /* Update status when all data read */ + if (priv->rsp_pos >= priv->rsp_len) { + priv->sts_reg &= ~TPM_STS_DATA_AVAIL; + priv->sts_reg |= TPM_STS_COMMAND_READY; + priv->tis_state = TIS_READY; + } + return data; + } + return 0xFF; + } + return 0xFF; + } +} + +/* + * Write to TIS register + */ +static void tis_reg_write(struct sandbox_tpm_spi *priv, u32 addr, u8 value) +{ + u32 reg = addr & 0x0FFF; + + switch (reg) { + case TPM_ACCESS_REG: + if (value & TPM_ACCESS_REQUEST_USE) { + /* Request locality */ + priv->access_reg |= TPM_ACCESS_ACTIVE_LOCALITY; + priv->access_reg |= TPM_ACCESS_VALID; + } + break; + + case TPM_STS_REG: + if (value & TPM_STS_COMMAND_READY) { + /* Abort current command and go to ready state */ + priv->tis_state = TIS_READY; + priv->cmd_len = 0; + priv->cmd_pos = 0; + priv->rsp_len = 0; + priv->rsp_pos = 0; + priv->sts_reg = TPM_STS_VALID | TPM_STS_COMMAND_READY; + priv->burst_count = MAX_SPI_FRAMESIZE; + } + if (value & TPM_STS_GO) { + /* Execute command */ + if (priv->tis_state == TIS_RECEPTION && + priv->cmd_len > 0) { + /* + * Generate a simple success response. + * A full implementation would call the + * sandbox TPM2 state machine here. + */ + priv->rsp_buf[0] = 0x80; /* TPM_ST_NO_SESSIONS */ + priv->rsp_buf[1] = 0x01; + priv->rsp_buf[2] = 0x00; /* Response size: 10 */ + priv->rsp_buf[3] = 0x00; + priv->rsp_buf[4] = 0x00; + priv->rsp_buf[5] = 0x0A; + priv->rsp_buf[6] = 0x00; /* TPM_RC_SUCCESS */ + priv->rsp_buf[7] = 0x00; + priv->rsp_buf[8] = 0x00; + priv->rsp_buf[9] = 0x00; + priv->rsp_len = 10; + priv->rsp_pos = 0; + + priv->tis_state = TIS_COMPLETION; + priv->sts_reg = TPM_STS_VALID | + TPM_STS_DATA_AVAIL; + } + } + break; + + default: + /* + * Handle FIFO writes - the FIFO is at 0x0024 but any address + * from 0x0024 up to 0x0F00 can be used for FIFO access when + * doing multi-byte transfers (address auto-increments). + */ + if (reg >= TPM_DATA_FIFO_REG && reg < TPM_DID_VID_REG) { + if (priv->tis_state == TIS_READY) { + /* Start receiving command */ + priv->tis_state = TIS_RECEPTION; + priv->cmd_len = 0; + priv->cmd_pos = 0; + priv->sts_reg = TPM_STS_VALID | TPM_STS_DATA_EXPECT; + } + if (priv->tis_state == TIS_RECEPTION) { + if (priv->cmd_len < TPM_CMD_BUF_SIZE) { + priv->cmd_buf[priv->cmd_len++] = value; + + /* Check if we have complete command */ + if (priv->cmd_len >= 6) { + u32 expected_len; + + expected_len = (priv->cmd_buf[2] << 24) | + (priv->cmd_buf[3] << 16) | + (priv->cmd_buf[4] << 8) | + priv->cmd_buf[5]; + if (priv->cmd_len >= expected_len) { + /* Command complete */ + priv->sts_reg &= + ~TPM_STS_DATA_EXPECT; + } + } + } + } + } + break; + } +} + +/* + * SPI emulation transfer callback + */ +static int sandbox_tpm_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct sandbox_tpm_spi *priv = dev_get_priv(dev); + int bytes = bitlen / 8; + const u8 *tx = dout; + u8 *rx = din; + int i; + + /* Handle CS assert - reset state machine */ + if (flags & SPI_XFER_BEGIN) { + priv->spi_state = TPM_SPI_HEADER; + priv->header_pos = 0; + } + + for (i = 0; i < bytes; i++) { + u8 tx_byte = tx ? tx[i] : 0; + u8 rx_byte = 0; + + switch (priv->spi_state) { + case TPM_SPI_IDLE: + /* Should not happen during active transfer */ + rx_byte = 0xFF; + break; + + case TPM_SPI_HEADER: + /* Receive 4-byte header */ + priv->header[priv->header_pos++] = tx_byte; + rx_byte = 0x00; + + if (priv->header_pos >= 4) { + parse_spi_header(priv); + log_debug("TPM SPI: %s len=%d addr=0x%04x\n", + priv->is_read ? "read" : "write", + priv->xfer_len, priv->addr); + /* Return wait state in last header byte */ + rx_byte = 0x01; /* Ready immediately */ + priv->spi_state = TPM_SPI_DATA; + } + break; + + case TPM_SPI_DATA: + if (priv->is_read) { + /* Read from TPM register */ + rx_byte = tis_reg_read(priv, + priv->addr + priv->data_pos); + } else { + /* Write to TPM register */ + tis_reg_write(priv, priv->addr + priv->data_pos, + tx_byte); + rx_byte = 0x00; + } + priv->data_pos++; + break; + + default: + rx_byte = 0xFF; + break; + } + + if (rx) + rx[i] = rx_byte; + } + + /* Handle CS deassert - return to idle */ + if (flags & SPI_XFER_END) + priv->spi_state = TPM_SPI_IDLE; + + return 0; +} + +static int sandbox_tpm_spi_probe(struct udevice *dev) +{ + struct sandbox_tpm_spi *priv = dev_get_priv(dev); + + /* Initialize TIS state */ + priv->spi_state = TPM_SPI_IDLE; + priv->tis_state = TIS_IDLE; + priv->access_reg = TPM_ACCESS_VALID; + priv->sts_reg = TPM_STS_VALID; + priv->intf_caps = TPM_INTF_CAPS_VALUE; + priv->burst_count = MAX_SPI_FRAMESIZE; + priv->cmd_len = 0; + priv->rsp_len = 0; + + log_debug("TPM SPI sandbox emulator probed\n"); + + return 0; +} + +static const struct dm_spi_emul_ops sandbox_tpm_spi_ops = { + .xfer = sandbox_tpm_spi_xfer, +}; + +static const struct udevice_id sandbox_tpm_spi_ids[] = { + { .compatible = "sandbox,tpm-spi-emul" }, + { } +}; + +U_BOOT_DRIVER(sandbox_tpm_spi_emul) = { + .name = "sandbox_tpm_spi_emul", + .id = UCLASS_SPI_EMUL, + .of_match = sandbox_tpm_spi_ids, + .ops = &sandbox_tpm_spi_ops, + .probe = sandbox_tpm_spi_probe, + .priv_auto = sizeof(struct sandbox_tpm_spi), +}; + +/* + * SPI slave driver for TPM device + * This gets probed when a device with "sandbox,tpm-spi" is found in DTS. + * The actual SPI transfers are handled by the emulator above. + */ +static int sandbox_tpm_spi_slave_probe(struct udevice *dev) +{ + log_debug("TPM SPI slave device probed\n"); + return 0; +} + +static const struct udevice_id sandbox_tpm_spi_slave_ids[] = { + { .compatible = "sandbox,tpm-spi" }, + { } +}; + +U_BOOT_DRIVER(sandbox_tpm_spi) = { + .name = "sandbox_tpm_spi", + .id = UCLASS_SPI_GENERIC, + .of_match = sandbox_tpm_spi_slave_ids, + .probe = sandbox_tpm_spi_slave_probe, +}; -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 10/12] test: add wolfTPM C unit tests and Python integration tests 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske ` (8 preceding siblings ...) 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 09/12] tpm: add sandbox TPM SPI emulator David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 11/12] doc: add wolfTPM documentation David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 12/12] configs: enable wolfTPM in rpi_4_defconfig David Garske 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Add comprehensive test suites for wolfTPM commands, modeled after the existing TPM2 test infrastructure. test/cmd/wolftpm.c (C unit tests): 18 tests using U-Boot's unit test framework (CMD_TEST macro): - autostart, init, info, state, device: basic lifecycle - self_test (full and continue): TPM self-test verification - startup_clear, startup_state: TPM2_Startup modes - get_capability: read TPM properties - caps: wolfTPM-enhanced capabilities display - clear: TPM state reset via LOCKOUT hierarchy - pcr_read, pcr_extend, pcr_print: PCR operations - pcr_allocate: PCR bank reconfiguration - dam_reset, dam_parameters: dictionary attack mitigation - change_auth: hierarchy password change (requires wolfCrypt) - cleanup: reset TPM state after tests Run with: ut cmd cmd_test_wolftpm_* test/cmd/Makefile: Adds wolftpm.o when CONFIG_TPM_WOLF is enabled. test/py/tests/test_wolftpm.py (Python integration tests): 21 tests using pytest with the U-Boot test framework: - Requires QEMU + swtpm (not sandbox) because wolfTPM bypasses U-Boot's driver model and communicates directly with TPM hardware via its own SPI/MMIO HAL - Tests mirror the C tests but run end-to-end through the U-Boot console, checking return codes via 'echo $?' - Includes force_init() helper for TPM reinitialization after test failures - Skippable via env__wolftpm_device_test_skip config - Verified: 19 passed, 2 skipped (change_auth requires wolfCrypt, get_capability may skip on some platforms) Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- test/cmd/Makefile | 1 + test/cmd/wolftpm.c | 364 +++++++++++++++++++++++++++++++++ test/py/tests/test_wolftpm.py | 375 ++++++++++++++++++++++++++++++++++ 3 files changed, 740 insertions(+) create mode 100644 test/cmd/wolftpm.c create mode 100644 test/py/tests/test_wolftpm.py diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 8c9f112782d..6e346dfa4bf 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_CMD_SPAWN) += spawn.o ifdef CONFIG_CMD_ZIP obj-$(CONFIG_CMD_UNZIP) += unzip.o endif +obj-$(CONFIG_TPM_WOLF) += wolftpm.o diff --git a/test/cmd/wolftpm.c b/test/cmd/wolftpm.c new file mode 100644 index 00000000000..b2e6f82a098 --- /dev/null +++ b/test/cmd/wolftpm.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for wolfTPM commands + * + * Copyright (C) 2025 wolfSSL Inc. + * Author: Aidan Garske <aidan@wolfssl.com> + * + * Based on test/py/tests/test_tpm2.py and test/dm/tpm.c + * + * Note: These tests verify command success via return code only. + * Console output is not checked since it varies with debug levels. + * Run with: ut cmd + */ + +#include <command.h> +#include <dm.h> +#include <dm/test.h> +#include <test/cmd.h> +#include <test/test.h> +#include <test/ut.h> + +/** + * Test wolfTPM autostart command + * + * This initializes the TPM, performs startup and self-test + */ +static int cmd_test_wolftpm_autostart(struct unit_test_state *uts) +{ + /* Initialize and autostart the TPM */ + ut_assertok(run_command("tpm2 autostart", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_autostart, 0); + +/** + * Test wolfTPM init command + */ +static int cmd_test_wolftpm_init(struct unit_test_state *uts) +{ + ut_assertok(run_command("tpm2 init", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_init, 0); + +/** + * Test wolfTPM info command + * + * Display TPM device information + */ +static int cmd_test_wolftpm_info(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Get TPM info */ + ut_assertok(run_command("tpm2 info", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_info, 0); + +/** + * Test wolfTPM state command + * + * Display TPM internal state + */ +static int cmd_test_wolftpm_state(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Get TPM state */ + ut_assertok(run_command("tpm2 state", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_state, 0); + +/** + * Test wolfTPM device command + * + * Show all TPM devices + */ +static int cmd_test_wolftpm_device(struct unit_test_state *uts) +{ + /* Show TPM devices - no autostart needed */ + ut_assertok(run_command("tpm2 device", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_device, 0); + +/** + * Test wolfTPM self_test command + */ +static int cmd_test_wolftpm_self_test(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Run full self test */ + ut_assertok(run_command("tpm2 self_test full", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_self_test, 0); + +/** + * Test wolfTPM self_test continue command + */ +static int cmd_test_wolftpm_self_test_continue(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Run continue self test */ + ut_assertok(run_command("tpm2 self_test continue", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_self_test_continue, 0); + +/** + * Test wolfTPM startup command with TPM2_SU_CLEAR + * + * Issue TPM2_Startup with CLEAR mode (reset state) + */ +static int cmd_test_wolftpm_startup_clear(struct unit_test_state *uts) +{ + /* First init to prepare TPM */ + ut_assertok(run_command("tpm2 init", 0)); + + /* Issue startup with CLEAR mode */ + ut_assertok(run_command("tpm2 startup TPM2_SU_CLEAR", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_startup_clear, 0); + +/** + * Test wolfTPM startup command with TPM2_SU_STATE + * + * Issue TPM2_Startup with STATE mode (preserved state) + */ +static int cmd_test_wolftpm_startup_state(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM has state */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Shutdown first to prepare for STATE startup */ + run_command("tpm2 startup TPM2_SU_STATE off", 0); + + /* Re-init */ + ut_assertok(run_command("tpm2 init", 0)); + + /* Issue startup with STATE mode - may return already started */ + run_command("tpm2 startup TPM2_SU_STATE", 0); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_startup_state, 0); + +/** + * Test wolfTPM get_capability command + * + * Read TPM capabilities by property + */ +static int cmd_test_wolftpm_get_capability(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Get capability - property 0x6 (TPM_CAP_TPM_PROPERTIES), 0x20e (PT_MANUFACTURER) */ + ut_assertok(run_command("tpm2 get_capability 0x6 0x20e 0x1000000 1", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_get_capability, 0); + +/** + * Test wolfTPM caps command (get capabilities) + * + * Display TPM capabilities and vendor info + */ +static int cmd_test_wolftpm_caps(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Get TPM capabilities */ + ut_assertok(run_command("tpm2 caps", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_caps, 0); + +/** + * Test wolfTPM clear command + * + * Reset TPM internal state using LOCKOUT hierarchy + */ +static int cmd_test_wolftpm_clear(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Clear using LOCKOUT hierarchy */ + ut_assertok(run_command("tpm2 clear TPM2_RH_LOCKOUT", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_clear, 0); + +/** + * Test wolfTPM pcr_read command + * + * Read PCR value from a specific index to a memory address + */ +static int cmd_test_wolftpm_pcr_read(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Read PCR 0 with SHA256 to memory address 0x1000000 */ + ut_assertok(run_command("tpm2 pcr_read 0 0x1000000 SHA256", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_pcr_read, 0); + +/** + * Test wolfTPM pcr_extend command + * + * Extend a PCR with a digest value + */ +static int cmd_test_wolftpm_pcr_extend(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Clear to start fresh */ + run_command("tpm2 clear TPM2_RH_LOCKOUT", 0); + + /* Extend PCR 16 (resettable PCR) with digest from memory + * PCR 16-23 are typically available for debug/testing + */ + ut_assertok(run_command("tpm2 pcr_extend 16 0x1000000 SHA256", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_pcr_extend, 0); + +/** + * Test wolfTPM pcr_print command + * + * Print all PCR values + */ +static int cmd_test_wolftpm_pcr_print(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Print all PCRs */ + ut_assertok(run_command("tpm2 pcr_print", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_pcr_print, 0); + +/** + * Test wolfTPM pcr_allocate command + * + * Reconfigure PCR bank algorithm. Note: A TPM restart is required + * for changes to take effect, so we just verify the command succeeds. + */ +static int cmd_test_wolftpm_pcr_allocate(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Allocate SHA256 bank on - this should succeed */ + ut_assertok(run_command("tpm2 pcr_allocate SHA256 on", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_pcr_allocate, 0); + +/** + * Test wolfTPM dam_reset command + * + * Reset Dictionary Attack Mitigation counter + */ +static int cmd_test_wolftpm_dam_reset(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Reset DAM counter */ + ut_assertok(run_command("tpm2 dam_reset", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_dam_reset, 0); + +/** + * Test wolfTPM dam_parameters command + * + * Set Dictionary Attack Mitigation parameters + */ +static int cmd_test_wolftpm_dam_parameters(struct unit_test_state *uts) +{ + /* First autostart to ensure TPM is ready */ + ut_assertok(run_command("tpm2 autostart", 0)); + + /* Set DAM parameters: + * - max_tries: 3 + * - recovery_time: 10 seconds + * - lockout_recovery: 0 seconds + */ + ut_assertok(run_command("tpm2 dam_parameters 3 10 0", 0)); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_dam_parameters, 0); + +/** + * Test wolfTPM change_auth command + * + * Change hierarchy authorization password + * Note: Requires WOLFTPM2_NO_WOLFCRYPT to NOT be defined + */ +static int cmd_test_wolftpm_change_auth(struct unit_test_state *uts) +{ + /* First autostart and clear to ensure clean state */ + ut_assertok(run_command("tpm2 autostart", 0)); + run_command("tpm2 clear TPM2_RH_LOCKOUT", 0); + + /* Change LOCKOUT password to "testpw" + * This may fail if WOLFTPM2_NO_WOLFCRYPT is defined + */ + if (run_command("tpm2 change_auth TPM2_RH_LOCKOUT testpw", 0) == 0) { + /* Clear with new password to verify it worked */ + ut_assertok(run_command("tpm2 clear TPM2_RH_LOCKOUT testpw", 0)); + } + + return 0; +} +CMD_TEST(cmd_test_wolftpm_change_auth, 0); + +/** + * Cleanup test - ensure TPM is cleared after tests + */ +static int cmd_test_wolftpm_cleanup(struct unit_test_state *uts) +{ + /* Clear TPM to reset any passwords or test state */ + run_command("tpm2 autostart", 0); + run_command("tpm2 clear TPM2_RH_LOCKOUT", 0); + run_command("tpm2 clear TPM2_RH_PLATFORM", 0); + + return 0; +} +CMD_TEST(cmd_test_wolftpm_cleanup, 0); diff --git a/test/py/tests/test_wolftpm.py b/test/py/tests/test_wolftpm.py new file mode 100644 index 00000000000..b862fa06c5b --- /dev/null +++ b/test/py/tests/test_wolftpm.py @@ -0,0 +1,375 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2025 wolfSSL Inc. +# Author: Aidan Garske <aidan@wolfssl.com> +# +# Based on test_tpm2.py by Miquel Raynal <miquel.raynal@bootlin.com> + +""" +Test the wolfTPM related commands. These tests require a TPM device +(real hardware or software TPM emulator like swtpm). + +Notes: +* These tests will prove the password mechanism. The TPM chip must be cleared of + any password. +* Tests are designed to be similar to test_tpm2.py but use wolfTPM wrapper APIs. + +Configuration: +* Set env__wolftpm_device_test_skip to True to skip these tests. +""" + +import os.path +import pytest +import utils +import re +import time + + +def force_init(ubman, force=False): + """Initialize wolfTPM before running tests. + + When a test fails, U-Boot may be reset. Because TPM stack must be initialized + after each reboot, we must ensure these lines are always executed before + trying any command or they will fail with no reason. + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + output = ubman.run_command('tpm2 autostart') + if force or 'Error' not in output: + ubman.run_command('echo --- start of init ---') + ubman.run_command('tpm2 clear TPM2_RH_LOCKOUT') + output = ubman.run_command('echo $?') + if not output.endswith('0'): + ubman.run_command('tpm2 clear TPM2_RH_PLATFORM') + ubman.run_command('echo --- end of init ---') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_autostart(ubman): + """Test wolfTPM autostart command. + + Initialize the software stack, perform startup and self-test. + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + ubman.run_command('tpm2 autostart') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_init(ubman): + """Test wolfTPM init command. + + Initialize the TPM device for communication. + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + ubman.run_command('tpm2 init') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_self_test_full(ubman): + """Test wolfTPM full self_test command. + + Perform a full TPM self-test to verify all components are operational. + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + ubman.run_command('tpm2 autostart') + ubman.run_command('tpm2 self_test full') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_self_test_continue(ubman): + """Test wolfTPM continue self_test command. + + Ask the TPM to finish any remaining self tests. + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + ubman.run_command('tpm2 autostart') + ubman.run_command('tpm2 self_test continue') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_caps(ubman): + """Test wolfTPM caps command. + + Display TPM capabilities and vendor information. + """ + force_init(ubman) + ubman.run_command('tpm2 caps') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_clear(ubman): + """Test wolfTPM clear command. + + Clear the TPM internal state using LOCKOUT hierarchy. + LOCKOUT/PLATFORM hierarchies must not have a password set. + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + ubman.run_command('tpm2 autostart') + ubman.run_command('tpm2 clear TPM2_RH_LOCKOUT') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + ubman.run_command('tpm2 clear TPM2_RH_PLATFORM') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_change_auth(ubman): + """Test wolfTPM change_auth command. + + Change the owner/hierarchy password. + """ + force_init(ubman) + + # Change LOCKOUT password to 'unicorn' + # Note: change_auth requires wolfCrypt (WOLFTPM2_NO_WOLFCRYPT must not be set) + ubman.run_command('tpm2 change_auth TPM2_RH_LOCKOUT unicorn') + output = ubman.run_command('echo $?') + if not output.endswith('0'): + # wolfCrypt not available, skip password test + pytest.skip('change_auth requires wolfCrypt support') + + # Clear with new password to verify + ubman.run_command('tpm2 clear TPM2_RH_LOCKOUT unicorn') + output = ubman.run_command('echo $?') + ubman.run_command('tpm2 clear TPM2_RH_PLATFORM') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_dam_parameters(ubman): + """Test wolfTPM dam_parameters command. + + Change Dictionary Attack Mitigation parameters: + - Max number of failed authentication before lockout: 3 + - Time before failure counter is decremented: 10 sec + - Time after lockout failure before retry: 0 sec + """ + force_init(ubman) + + # Set DAM parameters + ubman.run_command('tpm2 dam_parameters 3 10 0') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_dam_reset(ubman): + """Test wolfTPM dam_reset command. + + Reset the Dictionary Attack Mitigation counter. + """ + force_init(ubman) + + ubman.run_command('tpm2 dam_reset') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_pcr_read(ubman): + """Test wolfTPM pcr_read command. + + Read PCR value from a specific index. + """ + force_init(ubman) + + ram = utils.find_ram_base(ubman) + + # Read PCR 0 with SHA256 + read_pcr = ubman.run_command('tpm2 pcr_read 0 0x%x SHA256' % ram) + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_pcr_extend(ubman): + """Test wolfTPM pcr_extend command. + + Extend a PCR with a digest value. + PCR 16-23 are typically available for debug/testing. + """ + force_init(ubman) + ram = utils.find_ram_base(ubman) + + # Read PCR 16 first + read_pcr = ubman.run_command('tpm2 pcr_read 16 0x%x SHA256' % ram) + output = ubman.run_command('echo $?') + assert output.endswith('0') + + # Extend PCR 16 with zeroed memory + ubman.run_command('tpm2 pcr_extend 16 0x%x SHA256' % ram) + output = ubman.run_command('echo $?') + assert output.endswith('0') + + # Read again to verify it changed + read_pcr_after = ubman.run_command('tpm2 pcr_read 16 0x%x SHA256' % ram) + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_pcr_print(ubman): + """Test wolfTPM pcr_print command. + + Print all assigned PCRs. + """ + force_init(ubman) + + pcr_output = ubman.run_command('tpm2 pcr_print') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + # Should contain PCR info + assert 'PCR' in pcr_output or 'Assigned' in pcr_output + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_info(ubman): + """Test wolfTPM info command. + + Display TPM device information. + """ + force_init(ubman) + + ubman.run_command('tpm2 info') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_state(ubman): + """Test wolfTPM state command. + + Display TPM internal state. + """ + force_init(ubman) + + ubman.run_command('tpm2 state') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_device(ubman): + """Test wolfTPM device command. + + Show all TPM devices. + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + ubman.run_command('tpm2 device') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_startup_clear(ubman): + """Test wolfTPM startup command with TPM2_SU_CLEAR. + + Issue TPM2_Startup with CLEAR mode (reset state). + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + ubman.run_command('tpm2 init') + ubman.run_command('tpm2 startup TPM2_SU_CLEAR') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_startup_state(ubman): + """Test wolfTPM startup command with TPM2_SU_STATE. + + Issue TPM2_Startup with STATE mode (preserved state). + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + # First autostart to have valid state + ubman.run_command('tpm2 autostart') + # Shutdown with STATE + ubman.run_command('tpm2 startup TPM2_SU_STATE off') + # Re-init + ubman.run_command('tpm2 init') + # Startup with STATE - may return already started + ubman.run_command('tpm2 startup TPM2_SU_STATE') + output = ubman.run_command('echo $?') + # May return non-zero if already started, just verify command ran + assert output is not None + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_startup_shutdown(ubman): + """Test wolfTPM startup shutdown command. + + Issue TPM2_Shutdown. + """ + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False) + if skip_test: + pytest.skip('skip wolfTPM device test') + ubman.run_command('tpm2 autostart') + ubman.run_command('tpm2 startup TPM2_SU_CLEAR off') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_get_capability(ubman): + """Test wolfTPM get_capability command. + + Read TPM capabilities by property. + """ + force_init(ubman) + ram = utils.find_ram_base(ubman) + + # Get capability - TPM_CAP_TPM_PROPERTIES (0x6), PT_MANUFACTURER (0x20e) + ubman.run_command('tpm2 get_capability 0x6 0x20e 0x%x 1' % ram) + output = ubman.run_command('echo $?') + # May fail on some platforms if RAM address is not accessible + if not output.endswith('0'): + pytest.skip('get_capability failed (RAM address may not be accessible)') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_pcr_allocate(ubman): + """Test wolfTPM pcr_allocate command. + + Reconfigure PCR bank algorithm. + Note: A TPM restart is required for changes to take effect. + """ + force_init(ubman) + + # Allocate SHA256 bank on + ubman.run_command('tpm2 pcr_allocate SHA256 on') + output = ubman.run_command('echo $?') + assert output.endswith('0') + + +@pytest.mark.buildconfigspec('tpm_wolf') +def test_wolftpm_cleanup(ubman): + """Cleanup test - ensure TPM is cleared after tests.""" + force_init(ubman, True) -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 11/12] doc: add wolfTPM documentation 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske ` (9 preceding siblings ...) 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 10/12] test: add wolfTPM C unit tests and Python integration tests David Garske @ 2026-03-16 18:14 ` David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 12/12] configs: enable wolfTPM in rpi_4_defconfig David Garske 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Add documentation for wolfTPM integration, commands, and testing. doc/usage/cmd/wolftpm.rst: Comprehensive RST documentation covering: - All wolfTPM tpm2 subcommands with usage and examples - Infineon TPM firmware update step-by-step guide (extract manifest/firmware, load to RAM, perform update, recovery mode) - Build instructions for RPi4 and QEMU targets - Enabling debug output (U-Boot log system + wolfTPM library) - Complete test suite documentation with test coverage table - Python test framework setup (QEMU + swtpm instructions, helper scripts, verified test results) README.wolftpm.md: Quick-start guide with overview, feature comparison vs standard U-Boot TPM, command reference, build instructions, hardware support details, and file listing. README: Add CONFIG_TPM_WOLF reference in the configuration options section alongside existing CONFIG_TPM entries. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- README | 3 + README.wolftpm.md | 154 +++++++++ doc/usage/cmd/wolftpm.rst | 635 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 792 insertions(+) create mode 100644 README.wolftpm.md create mode 100644 doc/usage/cmd/wolftpm.rst diff --git a/README b/README index 20a73bab802..b9bfe14a1c7 100644 --- a/README +++ b/README @@ -361,6 +361,9 @@ The following options need to be configured: CONFIG_TPM Support TPM devices. + CONFIG_TPM_WOLF + Enables support for wolfTPM library. + CONFIG_TPM_TIS_INFINEON Support for Infineon i2c bus TPM devices. Only one device per system is supported at this time. diff --git a/README.wolftpm.md b/README.wolftpm.md new file mode 100644 index 00000000000..cdebe96ecb1 --- /dev/null +++ b/README.wolftpm.md @@ -0,0 +1,154 @@ +# wolfTPM Support for U-Boot + +This fork adds [wolfTPM](https://github.com/wolfSSL/wolfTPM) support to U-Boot, providing full TPM 2.0 command support using wolfTPM APIs and the wolfTPM library. + +## Overview + +wolfTPM is a portable, open-source TPM 2.0 library that provides: + +- **Native TPM 2.0 API** - Direct access to all TPM 2.0 commands +- **Wrapper API** - Simplified interface for common TPM operations +- **Hardware SPI Support** - Direct communication with TPM hardware via SPI +- **Firmware Update** - Support for Infineon SLB9672/SLB9673 firmware updates +- **No External Dependencies** - Standalone implementation without kernel TPM stack + +## Why wolfTPM vs Standard U-Boot TPM? + +| Feature | Standard U-Boot TPM | wolfTPM | +|---------|---------------------|---------| +| API | Basic TPM commands | Full TPM 2.0 + Wrapper API | +| PCR Operations | Basic read/extend | Full PCR management | +| Firmware Update | Not supported | Infineon SLB9672/9673 | +| Capabilities Query | Limited | Comprehensive `caps` command | +| SPI Communication | Via kernel driver | Native wolfTPM TIS layer | +| Library Integration | N/A | wolfSSL ecosystem compatible | + +## Command: `tpm2` + +When wolfTPM is enabled, the `tpm2` command uses wolfTPM APIs instead of the standard implementation. The command interface is compatible with the standard `tpm2` command, with additional wolfTPM-specific features. + +### Basic Commands + +```bash +tpm2 autostart # Initialize TPM, startup, and self-test +tpm2 init # Initialize TPM software stack +tpm2 info # Show TPM device information +tpm2 caps # Show TPM capabilities (wolfTPM enhanced) +tpm2 self_test full # Run full self-test +``` + +### PCR Operations + +```bash +tpm2 pcr_read <pcr> <addr> [algo] # Read PCR value +tpm2 pcr_extend <pcr> <addr> [algo] # Extend PCR with digest +tpm2 pcr_print # Print all PCR values +tpm2 pcr_allocate <algo> <on|off> # Configure PCR banks +``` + +### Security Management + +```bash +tpm2 clear <hierarchy> # Clear TPM +tpm2 change_auth <hierarchy> <new_pw> [old_pw] # Change password +tpm2 dam_reset [password] # Reset DAM counter +tpm2 dam_parameters <tries> <recovery> <lockout> # Set DAM params +``` + +### Firmware Update (Infineon Only) + +```bash +tpm2 firmware_update <manifest_addr> <size> <firmware_addr> <size> +tpm2 firmware_cancel +``` + +## Building + +### For Raspberry Pi 4 + +```bash +git clone https://github.com/aidangarske/u-boot.git +cd u-boot +git checkout rpi4-wolftpm-uboot +git submodule update --init lib/wolftpm + +export CROSS_COMPILE=aarch64-elf- +make rpi_4_defconfig +make -j$(nproc) +``` + +### Configuration Options + +Enable in `menuconfig` or defconfig: + +``` +# Core TPM support +CONFIG_TPM=y +CONFIG_TPM_V2=y + +# wolfTPM (replaces standard tpm2 command) +CONFIG_TPM_WOLF=y +CONFIG_CMD_TPM=y + +# For Infineon hardware +CONFIG_WOLFTPM_SLB9672=y + +# For QEMU/swtpm testing +# CONFIG_WOLFTPM_LINUX_DEV=y +``` + +**Note:** The `tpm2` command frontend (`cmd/tpm-v2.c`) is always compiled. The backend is selected at build time: when `CONFIG_TPM_WOLF` is enabled, `cmd/wolftpm.c` provides the wolfTPM backend; otherwise, `cmd/native_tpm2.c` provides the native U-Boot backend. + +## Hardware Support + +### Tested Hardware + +- Raspberry Pi 4 Model B +- Infineon SLB9670 TPM (LetsTrust HAT) +- Infineon SLB9672 TPM (with firmware update support) + +### SPI Configuration + +The TPM is configured on SPI0 CE1 (GPIO7), matching the standard Raspberry Pi `tpm-slb9670` overlay: + +``` +SPI0 Pins: +- SCLK: GPIO11 (pin 23) +- MOSI: GPIO10 (pin 19) +- MISO: GPIO9 (pin 21) +- CE1: GPIO7 (pin 26) +``` + +## Documentation + +- **Full Guide**: [rpi4-wolftpm-uboot](https://github.com/aidangarske/rpi4-wolftpm-uboot) +- **Firmware Update**: See `doc/usage/cmd/wolftpm.rst` +- **wolfTPM Library**: [github.com/wolfSSL/wolfTPM](https://github.com/wolfSSL/wolfTPM) + +## Files Modified/Added + +``` +cmd/tpm-v2.c # Shared tpm2 command frontend (dispatch table, help) +cmd/native_tpm2.c # Native U-Boot backend (when wolfTPM is OFF) +cmd/wolftpm.c # wolfTPM backend (when wolfTPM is ON) +cmd/tpm2-backend.h # Backend function declarations +lib/wolftpm/ # wolfTPM library (submodule) +lib/wolftpm.c # wolfTPM library glue code +include/configs/user_settings.h # wolfTPM configuration +include/wolftpm.h # wolfTPM header +arch/arm/dts/bcm2711-rpi-4-b.dts # Device tree with SPI/TPM config +configs/rpi_4_defconfig # RPi4 build configuration +drivers/spi/bcm2835_spi.c # BCM2835 SPI driver +doc/usage/cmd/wolftpm.rst # Command documentation +``` + +## License + +- U-Boot: GPL-2.0 +- wolfTPM: GPL-2.0 +- This integration: GPL-2.0 + +## Author + +Aidan Garske <aidan@wolfssl.com> +wolfSSL Inc. diff --git a/doc/usage/cmd/wolftpm.rst b/doc/usage/cmd/wolftpm.rst new file mode 100644 index 00000000000..85e6be544bb --- /dev/null +++ b/doc/usage/cmd/wolftpm.rst @@ -0,0 +1,635 @@ +wolfTPM Support For Das U-Boot +============================== + +wolfTPM provides experimental support for U-Boot with the following key features: + +- Utilizes SOFT SPI driver in U-Boot for TPM communication +- Implements TPM 2.0 driver functionality through its internal TIS layer +- Provides native API access to all TPM 2.0 commands +- Includes wrapper API for common TPM 2.0 operations +- Supports two integration paths: + - ``__linux__``: Uses existing tpm interface via tpm2_linux.c + - ``__UBOOT__``: Direct SPI communication through tpm_io_uboot.c + +wolfTPM U-Boot Commands +---------------------- + +The following commands are available through the ``tpm2`` command (powered by wolfTPM): + +Basic Commands +~~~~~~~~~~~~~~ + +- ``help`` - Show help text +- ``device [num device]`` - Show all devices or set the specified device +- ``info`` - Show information about the TPM +- ``state`` - Show internal state from the TPM (if available) +- ``autostart`` - Initialize the TPM, perform a Startup(clear) and run a full selftest sequence +- ``init`` - Initialize the software stack (must be first command) +- ``startup <mode> [<op>]`` - Issue a TPM2_Startup command + - ``<mode>``: TPM2_SU_CLEAR (reset state) or TPM2_SU_STATE (preserved state) + - ``[<op>]``: optional shutdown with "off" +- ``self_test <type>`` - Test TPM capabilities + - ``<type>``: "full" (all tests) or "continue" (untested tests only) + +PCR Operations +~~~~~~~~~~~~~~ + +- ``pcr_extend <pcr> <digest_addr> [<digest_algo>]`` - Extend PCR with digest +- ``pcr_read <pcr> <digest_addr> [<digest_algo>]`` - Read PCR to memory +- ``pcr_allocate <algorithm> <on/off> [<password>]`` - Reconfig PCR bank algorithm +- ``pcr_setauthpolicy | pcr_setauthvalue <pcr> <key> [<password>]`` - Change PCR access key +- ``pcr_print`` - Print current PCR state + +Security Management +~~~~~~~~~~~~~~~~~~~ + +- ``clear <hierarchy>`` - Issue TPM2_Clear command + - ``<hierarchy>``: TPM2_RH_LOCKOUT or TPM2_RH_PLATFORM +- ``change_auth <hierarchy> <new_pw> [<old_pw>]`` - Change hierarchy password + - ``<hierarchy>``: TPM2_RH_LOCKOUT, TPM2_RH_ENDORSEMENT, TPM2_RH_OWNER, or TPM2_RH_PLATFORM +- ``dam_reset [<password>]`` - Reset internal error counter +- ``dam_parameters <max_tries> <recovery_time> <lockout_recovery> [<password>]`` - Set DAM parameters +- ``caps`` - Show TPM capabilities and info + +Firmware Management +~~~~~~~~~~~~~~~~~~~ + +- ``firmware_update <manifest_addr> <manifest_sz> <firmware_addr> <firmware_sz>`` - Update TPM firmware +- ``firmware_cancel`` - Cancel TPM firmware update + +Infineon TPM Firmware Update Guide +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**WARNING: Firmware updates are risky. A failed update can brick your TPM. +Only proceed if you have a valid reason to update (security patches, new features) +and understand the risks.** + +The firmware update commands are for Infineon SLB9672/SLB9673 TPMs only. The process +requires extracting manifest and firmware data from Infineon's combined ``.BIN`` file. + +**Prerequisites:** + +- Infineon firmware file (e.g., ``TPM20_16.13.17733.0_R1.BIN``) +- wolfTPM's ``ifx_fw_extract`` tool (in ``lib/wolftpm/examples/firmware/``) +- Your TPM's KeyGroupId (shown by ``tpm2 caps`` command) + +**Step 1: Get your TPM's KeyGroupId** + +Run ``tpm2 caps`` to find your TPM's KeyGroupId:: + + U-Boot> tpm2 caps + Mfg IFX (1), Vendor SLB9672, Fw 16.13 (0x4545), FIPS 140-2 1, CC-EAL4 1 + Operational mode: Normal TPM operational mode (0x0) + KeyGroupId 0x5, FwCounter 1255 (255 same) + ... + +In this example, KeyGroupId is ``0x5``. + +**Step 2: Build the extraction tool (on host machine)** + +:: + + cd lib/wolftpm/examples/firmware + gcc -o ifx_fw_extract ifx_fw_extract.c + +**Step 3: List available key groups in firmware file** + +:: + + ./ifx_fw_extract TPM20_16.13.17733.0_R1.BIN + Found group 00000005 + +Verify your TPM's KeyGroupId matches one in the firmware file. + +**Step 4: Extract manifest and firmware data** + +Use your KeyGroupId (0x5 in this example):: + + ./ifx_fw_extract TPM20_16.13.17733.0_R1.BIN 0x5 manifest.bin firmware.bin + Found group 00000005 + Chosen group found: 00000005 + Manifest size is 3229 + Data size is 925539 + Wrote 3229 bytes to manifest.bin + Wrote 925539 bytes to firmware.bin + +**Step 5: Copy files to SD card** + +Copy ``manifest.bin`` and ``firmware.bin`` to your boot partition (FAT):: + + cp manifest.bin firmware.bin /Volumes/bootfs/ # macOS + cp manifest.bin firmware.bin /boot/firmware/ # Linux + +**Step 6: Load files into memory** + +In U-Boot, load the files from SD card into RAM:: + + U-Boot> fatload mmc 0:1 0x10000000 manifest.bin + 3229 bytes read in 32 ms (97.7 KiB/s) + + U-Boot> fatload mmc 0:1 0x10100000 firmware.bin + 925539 bytes read in 86 ms (10.3 MiB/s) + +**Step 7: Perform firmware update (CAUTION!)** + +Convert file sizes to hex: + +- manifest.bin: 3229 bytes = 0xC9D +- firmware.bin: 925539 bytes = 0xE1F63 + +Run the firmware update:: + + U-Boot> tpm2 firmware_update 0x10000000 0xC9D 0x10100000 0xE1F63 + TPM2 Firmware Update + Infineon Firmware Update Tool + Manifest Address: 0x10000000 (size: 3229) + Firmware Address: 0x10100000 (size: 925539) + tpm2 init: rc = 0 (Success) + Mfg IFX (1), Vendor SLB9672, Fw 16.13 (0x4545) + Operational mode: Normal TPM operational mode (0x0) + KeyGroupId 0x5, FwCounter 1255 (255 same) + Firmware Update (normal mode): + Mfg IFX (1), Vendor SLB9672, Fw 16.13 (0x4545) + Operational mode: Normal TPM operational mode (0x0) + KeyGroupId 0x5, FwCounter 1255 (255 same) + tpm2 firmware_update: rc=0 (Success) + +**DO NOT power off or reset during the update!** + +**Step 8: Verify update** + +After the update completes, verify with:: + + U-Boot> tpm2 caps + +The firmware version should show the new version. + +**Recovery Mode:** + +If the TPM enters recovery mode (opMode shows 0x02 or 0x8x), the firmware update +command will automatically use recovery mode. You may need to run the update again +to complete the process. + +Canceling a Firmware Update +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If an update is in progress and needs to be abandoned (opMode 0x01), use:: + + U-Boot> tpm2 firmware_cancel + tpm2 init: rc = 0 (Success) + tpm2 firmware_cancel: rc=0 (Success) + +**IMPORTANT: After running firmware_cancel, you MUST reboot/power cycle the system +before running any other TPM commands.** If you attempt to run commands without +rebooting, you will get ``TPM_RC_REBOOT`` (error 304):: + + U-Boot> tpm2 firmware_update ... + tpm2 init: rc = 304 (TPM_RC_REBOOT) + Infineon firmware update failed 0x130: TPM_RC_REBOOT + +After rebooting, the TPM will return to normal operation and you can retry the +firmware update or continue with normal TPM operations. + +**Note:** If no firmware update is in progress, ``firmware_cancel`` returns +``TPM_RC_COMMAND_CODE`` (0x143), which is expected and harmless:: + + U-Boot> tpm2 firmware_cancel + tpm2 firmware_cancel: rc=323 (TPM_RC_COMMAND_CODE) + +Enabling wolfTPM in U-Boot +-------------------------- + +Enable wolfTPM support in U-Boot by adding these options to your board's defconfig:: + + CONFIG_TPM=y + CONFIG_TPM_V2=y + CONFIG_TPM_WOLF=y + CONFIG_CMD_WOLFTPM=y + + if with __LINUX__: + CONFIG_TPM_LINUX_DEV=y + +Or use ``make menuconfig`` and enable: + +Enabling Debug Output +~~~~~~~~~~~~~~~~~~~~~ + +wolfTPM commands use U-Boot's logging system (``log_debug()``). To enable debug +output, you must first enable the logging subsystem in your board's defconfig:: + + CONFIG_LOG=y + CONFIG_LOG_MAX_LEVEL=7 + CONFIG_LOG_DEFAULT_LEVEL=7 + +Or via ``make menuconfig``: + +- Console → Enable logging support +- Console → Maximum log level to record = 7 +- Console → Default logging level to display = 7 + +Log levels: +- 7 = DEBUG (to show wolfTPM command debug output) + +**Note:** Without ``CONFIG_LOG=y``, the ``log level`` command will not exist +and ``log_debug()`` calls will produce no output. + +wolfTPM Library Debug +^^^^^^^^^^^^^^^^^^^^^ + +For lower-level wolfTPM library debug output (TPM protocol messages), edit +``include/configs/user_settings.h`` and uncomment:: + + #define DEBUG_WOLFTPM /* Basic wolfTPM debug messages */ + #define WOLFTPM_DEBUG_VERBOSE /* Verbose debug messages */ + #define WOLFTPM_DEBUG_IO /* IO-level debug (SPI transfers) */ + +After enabling, rebuild U-Boot:: + + make clean + make -j4 + +Menuconfig Paths +^^^^^^^^^^^^^^^^ + +The following menuconfig paths are useful for wolfTPM: + +- Device Drivers → TPM → TPM 2.0 Support +- Device Drivers → TPM → wolfTPM Support +- Command line interface → Security commands → Enable wolfTPM commands +- Console → Enable logging support (for ``log_debug()`` output) + +Building and Running wolfTPM with U-Boot using QEMU +--------------------------------------------------- + +To build and run wolfTPM with U-Boot using QEMU and a TPM simulator, follow these steps: + +1. Install swtpm:: + + git clone https://github.com/stefanberger/swtpm.git + cd swtpm + ./autogen.sh + make + +2. Build U-Boot:: + + make distclean + export CROSS_COMPILE=aarch64-linux-gnu- + export ARCH=aarch64 + make qemu_arm64_defconfig + make -j4 + +3. Create TPM directory:: + + mkdir -p /tmp/mytpm1 + +4. Start swtpm (in first terminal):: + + swtpm socket --tpm2 --tpmstate dir=/tmp/mytpm1 --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock --log level=20 + +5. Start QEMU (in second terminal):: + + qemu-system-aarch64 -machine virt -nographic -cpu cortex-a57 -bios u-boot.bin -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis-device,tpmdev=tpm0 + +6. Example output:: + + U-Boot 2025.07-rc1-ge15cbf232ddf-dirty (May 06 2025 - 16:25:56 -0700) + ... + => tpm2 help + tpm2 - Issue a TPMv2.x command + Usage: + tpm2 <command> [<arguments>] + ... + => tpm2 info + tpm_tis@0 v2.0: VendorID 0x1014, DeviceID 0x0001, RevisionID 0x01 [open] + => tpm2 startup TPM2_SU_CLEAR + => tpm2 get_capability 0x6 0x20e 0x200 1 + Capabilities read from TPM: + Property 0x6a2e45a9: 0x6c3646a9 + => tpm2 pcr_read 10 0x100000 + PCR #10 sha256 32 byte content (20 known updates): + 20 25 73 0a 00 56 61 6c 75 65 3a 0a 00 23 23 20 + 4f 75 74 20 6f 66 20 6d 65 6d 6f 72 79 0a 00 23 + +7. Example commands:: + + => tpm2 info + tpm_tis@0 v2.0: VendorID 0x1014, DeviceID 0x0001, RevisionID 0x01 [open] + ... + => tpm2 pcr_read 10 0x100000 + PCR #10 sha256 32 byte content (20 known updates): + 20 25 73 0a 00 56 61 6c 75 65 3a 0a 00 23 23 20 + 4f 75 74 20 6f 66 20 6d 65 6d 6f 72 79 0a 00 23 + +8. Exiting the QEMU: + Press Ctrl-A followed by X + +Testing wolfTPM +--------------- + +wolfTPM includes a comprehensive test suite based on the existing TPM2 tests. +The tests are located in: + +- ``test/cmd/wolftpm.c`` - C unit tests (based on ``test/dm/tpm.c`` and ``test/cmd/hash.c``) +- ``test/py/tests/test_wolftpm.py`` - Python integration tests (based on ``test/py/tests/test_tpm2.py``) + +Running C Unit Tests +~~~~~~~~~~~~~~~~~~~~ + +The C unit tests use the U-Boot test framework and can be run in sandbox mode +or on real hardware. To run all wolfTPM tests:: + + # Build sandbox with tests enabled + make sandbox_defconfig + # Enable wolfTPM in menuconfig + make menuconfig + make -j4 + + # Run U-Boot sandbox + ./u-boot -T + + # In U-Boot sandbox, run the unit tests + => ut cmd + +Individual tests can be run by name:: + + => ut cmd cmd_test_wolftpm_autostart + => ut cmd cmd_test_wolftpm_init + => ut cmd cmd_test_wolftpm_self_test + => ut cmd cmd_test_wolftpm_caps + => ut cmd cmd_test_wolftpm_clear + => ut cmd cmd_test_wolftpm_pcr_read + => ut cmd cmd_test_wolftpm_pcr_extend + +Running Tests Manually in QEMU +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also test wolfTPM commands manually in QEMU: + +1. Start swtpm:: + + mkdir -p /tmp/mytpm + swtpm socket --tpm2 --tpmstate dir=/tmp/mytpm \ + --ctrl type=unixio,path=/tmp/mytpm/swtpm-sock --log level=20 + +2. Start QEMU with TPM:: + + qemu-system-aarch64 -machine virt -cpu cortex-a57 -m 1024 \ + -bios u-boot.bin \ + -chardev socket,id=chrtpm,path=/tmp/mytpm/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis-device,tpmdev=tpm0 \ + -nographic + +3. Run wolfTPM commands at the U-Boot prompt:: + + => tpm2 autostart + => tpm2 caps + => tpm2 pcr_read 0 sha256 + => tpm2 pcr_print + => tpm2 self_test full + => tpm2 clear TPM2_RH_LOCKOUT + => tpm2 dam_parameters 3 10 0 + +Test Coverage +~~~~~~~~~~~~~ + +The test suite covers the following wolfTPM functionality: + ++---------------------------+------------------------------------------+ +| Test Name | Description | ++===========================+==========================================+ +| wolftpm_autostart | TPM initialization and startup | ++---------------------------+------------------------------------------+ +| wolftpm_init | TPM device initialization | ++---------------------------+------------------------------------------+ +| wolftpm_self_test | Full TPM self-test | ++---------------------------+------------------------------------------+ +| wolftpm_self_test_continue| Continue incomplete self-tests | ++---------------------------+------------------------------------------+ +| wolftpm_caps | Read TPM capabilities | ++---------------------------+------------------------------------------+ +| wolftpm_clear | Clear TPM state | ++---------------------------+------------------------------------------+ +| wolftpm_pcr_read | Read PCR values | ++---------------------------+------------------------------------------+ +| wolftpm_pcr_extend | Extend PCR with digest | ++---------------------------+------------------------------------------+ +| wolftpm_pcr_print | Print all PCR values | ++---------------------------+------------------------------------------+ +| wolftpm_pcr_allocate | Reconfigure PCR bank algorithm | ++---------------------------+------------------------------------------+ +| wolftpm_dam_reset | Reset DAM counter | ++---------------------------+------------------------------------------+ +| wolftpm_dam_parameters | Set DAM parameters | ++---------------------------+------------------------------------------+ +| wolftpm_change_auth | Change hierarchy password | ++---------------------------+------------------------------------------+ +| wolftpm_info | Display TPM info | ++---------------------------+------------------------------------------+ +| wolftpm_state | Display TPM state | ++---------------------------+------------------------------------------+ +| wolftpm_device | Show/set TPM device | ++---------------------------+------------------------------------------+ +| wolftpm_startup_clear | TPM2_Startup with CLEAR mode | ++---------------------------+------------------------------------------+ +| wolftpm_startup_state | TPM2_Startup with STATE mode | ++---------------------------+------------------------------------------+ +| wolftpm_startup_shutdown | TPM2_Shutdown command | ++---------------------------+------------------------------------------+ +| wolftpm_get_capability | Read TPM capabilities by property | ++---------------------------+------------------------------------------+ + +The following commands are implemented in ``cmd/wolftpm.c`` but do not yet have +test coverage due to special requirements. These have been tested locally on +hardware but dont have test suites due to different build configurations. + ++---------------------------+------------------------------------------+------------------+ +| Command | Description | Notes | ++===========================+==========================================+==================+ +| pcr_setauthpolicy | Set PCR authorization policy | Requires | +| | | wolfCrypt | ++---------------------------+------------------------------------------+------------------+ +| pcr_setauthvalue | Set PCR authorization value | Requires | +| | | wolfCrypt | ++---------------------------+------------------------------------------+------------------+ +| firmware_update | Update TPM firmware (Infineon only) | Requires | +| | | Infineon HW | ++---------------------------+------------------------------------------+------------------+ +| firmware_cancel | Cancel firmware update (Infineon only) | Requires | +| | | Infineon HW | ++---------------------------+------------------------------------------+------------------+ + +**Note:** The ``pcr_setauthpolicy`` and ``pcr_setauthvalue`` commands require +``WOLFTPM2_NO_WOLFCRYPT`` to be undefined (i.e., wolfCrypt must be enabled). +The ``firmware_update`` and ``firmware_cancel`` commands require Infineon +SLB9672/SLB9673 hardware. + +Testing on SLB 9672 on Raspberry Pi 4 Hardware +---------------------------------------------- + +For testing with real TPM hardware (e.g., Infineon SLB9672 TPM HAT on Raspberry Pi): + +1. Build U-Boot for Raspberry Pi:: + + make distclean + export CROSS_COMPILE=aarch64-linux-gnu- + export ARCH=aarch64 + make rpi_arm64_defconfig + make -j$(nproc) + +2. Backup current boot configuration:: + + sudo cp /boot/firmware/config.txt /boot/firmware/config.txt.backup + +3. Copy U-Boot to boot partition:: + + sudo cp u-boot.bin /boot/firmware/ + +4. Edit ``/boot/firmware/config.txt`` and add:: + + # U-Boot for wolfTPM testing + enable_uart=1 + kernel=u-boot.bin + arm_64bit=1 + +5. Connect serial console (recommended) - USB-to-serial adapter on GPIO 14/15 + (pins 8/10) at 115200 baud. + +6. Reboot and test at U-Boot prompt:: + + U-Boot> tpm2 device + U-Boot> tpm2 info + U-Boot> tpm2 autostart + U-Boot> tpm2 caps + U-Boot> tpm2 pcr_read 0 0x1000000 SHA256 + +7. To restore normal Linux boot:: + + sudo cp /boot/firmware/config.txt.backup /boot/firmware/config.txt + sudo reboot + +**Note:** The Raspberry Pi build uses GPIO-based soft SPI for TPM communication. +Standard SPI0 pins are used: GPIO 11 (SCLK), GPIO 10 (MOSI), GPIO 9 (MISO), +GPIO 7 (CE1 for TPM). Adjust ``arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi`` if +your TPM HAT uses different GPIO pins. + +Python Test Framework +~~~~~~~~~~~~~~~~~~~~~ + +**Why QEMU+swtpm is required (not sandbox):** + +The native ``test_tpm2.py`` tests run directly in sandbox because the native +TPM backend uses U-Boot's driver model, which has a built-in sandbox TPM +emulator. wolfTPM bypasses driver model entirely and communicates with TPM +hardware directly via its own SPI/MMIO HAL layer. This means there is no +sandbox emulator for wolfTPM to talk to. Instead, wolfTPM Python tests require +QEMU with swtpm (software TPM emulator) which provides a real TPM device +interface that wolfTPM can communicate with via MMIO. + +**Prerequisites:** + +Install swtpm and QEMU:: + + sudo apt-get install -y swtpm qemu-system-aarch64 pytest + +**Running wolfTPM Python Tests with QEMU+swtpm:** + +1. Build U-Boot for QEMU arm64 with wolfTPM and autodetect enabled:: + + make qemu_arm64_defconfig + scripts/config --enable CONFIG_CMD_WOLFTPM --enable CONFIG_TPM_AUTODETECT + make olddefconfig + make -j$(nproc) + +2. Create the test helper scripts in the U-Boot root directory: + + ``u-boot-test-flash`` (no-op for QEMU):: + + #!/bin/bash + exit 0 + + ``u-boot-test-console`` (starts swtpm + QEMU):: + + #!/bin/bash + SWTPM_DIR=/tmp/mytpm + SWTPM_SOCK=${SWTPM_DIR}/swtpm-sock + mkdir -p ${SWTPM_DIR} + if [ ! -S "${SWTPM_SOCK}" ]; then + swtpm socket --tpm2 --tpmstate dir=${SWTPM_DIR} \ + --ctrl type=unixio,path=${SWTPM_SOCK} --log level=0 & + sleep 1 + fi + exec qemu-system-aarch64 -machine virt -nographic -cpu cortex-a57 \ + -bios u-boot.bin \ + -chardev socket,id=chrtpm,path=${SWTPM_SOCK} \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis-device,tpmdev=tpm0 + + ``u-boot-test-reset`` (no-op):: + + #!/bin/bash + exit 0 + + ``u-boot-test-release`` (cleanup):: + + #!/bin/bash + pkill -f "swtpm.*mytpm" 2>/dev/null + exit 0 + + Make them executable:: + + chmod +x u-boot-test-flash u-boot-test-console u-boot-test-reset u-boot-test-release + +3. Run the wolfTPM Python tests:: + + export PATH=".:$PATH" + ./test/py/test.py --bd qemu_arm64 --build-dir . -k "test_wolftpm and not ut_cmd" -v + +**Verified output (QEMU arm64 + swtpm, 19 passed, 2 skipped):** + +:: + + test_wolftpm_autostart PASSED + test_wolftpm_init PASSED + test_wolftpm_self_test_full PASSED + test_wolftpm_self_test_continue PASSED + test_wolftpm_caps PASSED + test_wolftpm_clear PASSED + test_wolftpm_change_auth SKIPPED (requires wolfCrypt) + test_wolftpm_dam_parameters PASSED + test_wolftpm_dam_reset PASSED + test_wolftpm_pcr_read PASSED + test_wolftpm_pcr_extend PASSED + test_wolftpm_pcr_print PASSED + test_wolftpm_info PASSED + test_wolftpm_state PASSED + test_wolftpm_device PASSED + test_wolftpm_startup_clear PASSED + test_wolftpm_startup_state PASSED + test_wolftpm_startup_shutdown PASSED + test_wolftpm_get_capability SKIPPED + test_wolftpm_pcr_allocate PASSED + test_wolftpm_cleanup PASSED + +The native ``test_tpm2.py`` tests can be run directly in sandbox:: + + ./test/py/test.py --bd sandbox --build -k test_tpm2 -v + +Enabling Debug Output +~~~~~~~~~~~~~~~~~~~~~ + +To see debug messages, enable logging before running:: + + # At U-Boot prompt + => log level 7 + +Or enable in defconfig:: + + CONFIG_LOG=y + CONFIG_LOG_MAX_LEVEL=7 + CONFIG_LOG_DEFAULT_LEVEL=7 + +For wolfTPM library-level debug, edit ``include/configs/user_settings.h``:: + + #define DEBUG_WOLFTPM + #define WOLFTPM_DEBUG_IO /* Shows SPI transfer details */ -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 12/12] configs: enable wolfTPM in rpi_4_defconfig 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske ` (10 preceding siblings ...) 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 11/12] doc: add wolfTPM documentation David Garske @ 2026-03-16 18:14 ` David Garske 11 siblings, 0 replies; 13+ messages in thread From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw) To: u-boot; +Cc: Aidan From: Aidan <aidan@wolfssl.com> Enable SPI, TPM, and wolfTPM support in the Raspberry Pi 4 default configuration for out-of-the-box TPM 2.0 support with Infineon SLB9670/9672 TPM HATs. SPI support: CONFIG_SPI, CONFIG_DM_SPI, CONFIG_BCM2835_SPI, CONFIG_CMD_SPI Enables the BCM2835 hardware SPI driver. Soft SPI is disabled since the hardware driver is used. TPM and wolfTPM: CONFIG_TPM, CONFIG_TPM_V2, CONFIG_CMD_TPM: core TPM support CONFIG_TPM_WOLF: wolfTPM library integration CONFIG_CMD_WOLFTPM: wolfTPM command backend for tpm2 CONFIG_WOLFTPM_SLB9672: Infineon SLB9672 chip support WOLFTPM_LINUX_DEV disabled: uses native wolfTPM TIS layer with direct SPI communication rather than U-Boot's TPM driver model Logging: CONFIG_LOG with level 7 (DEBUG) to enable log_debug() output from wolfTPM commands. Testing: CONFIG_UNIT_TEST, CONFIG_CONSOLE_RECORD, CONFIG_HEXDUMP for running the wolfTPM C unit test suite. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- configs/rpi_4_defconfig | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/configs/rpi_4_defconfig b/configs/rpi_4_defconfig index 8362242b97f..22280d9b70e 100644 --- a/configs/rpi_4_defconfig +++ b/configs/rpi_4_defconfig @@ -69,4 +69,31 @@ CONFIG_SYS_WHITE_ON_BLACK=y CONFIG_VIDEO_BCM2835=y CONFIG_CONSOLE_SCROLL_LINES=10 CONFIG_PHYS_TO_BUS=y -# CONFIG_HEXDUMP is not set +# HEXDUMP enabled for unit tests + +# SPI support (hardware SPI - matches Linux tpm-slb9670 overlay) +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_BCM2835_SPI=y +# CONFIG_SOFT_SPI is not set +CONFIG_CMD_SPI=y + +# TPM and wolfTPM support +CONFIG_TPM=y +CONFIG_TPM_V2=y +CONFIG_CMD_TPM=y +CONFIG_TPM_WOLF=y +# CONFIG_WOLFTPM_LINUX_DEV is not set +CONFIG_WOLFTPM_SLB9672=y +CONFIG_CMD_WOLFTPM=y + +# Logging (debug level to see log_debug output) +CONFIG_LOG=y +CONFIG_LOGLEVEL=7 +CONFIG_LOG_MAX_LEVEL=7 +CONFIG_LOG_DEFAULT_LEVEL=7 + +# Unit testing support +CONFIG_UNIT_TEST=y +CONFIG_CONSOLE_RECORD=y +CONFIG_HEXDUMP=y -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-03-16 18:26 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 02/12] include: add byteorder macro guards and SHA384 hash wrapper David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 05/12] tpm: add wolfTPM library as git submodule David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 06/12] tpm: add wolfTPM headers and SHA384 glue code David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 07/12] tpm: add wolfTPM driver helpers and Kconfig options David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 08/12] cmd: refactor tpm2 command into frontend/backend architecture David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 09/12] tpm: add sandbox TPM SPI emulator David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 10/12] test: add wolfTPM C unit tests and Python integration tests David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 11/12] doc: add wolfTPM documentation David Garske 2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 12/12] configs: enable wolfTPM in rpi_4_defconfig David Garske
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox