diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml index 757e779ebf..432421dc0a 100644 --- a/.github/workflows/trustzone-emulator-tests.yml +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -106,6 +106,19 @@ jobs: make m33mu wolfboot.bin test-app/image_v1_signed.bin:0x60000 --uart-stdout --expect-bkpt 0x7f --timeout 600 + - name: Clean and build test with fwTPM (stm32h5) + run: | + make clean distclean + cp config/examples/stm32h5-tz-fwtpm.config .config + make + m33mu wolfboot.bin test-app/image_v1_signed.bin:0x60000 --uart-stdout --expect-bkpt 0x7f --timeout 600 \ + | tee /tmp/m33mu-fwtpm.log + grep -q "fwTPM PCR0 extended:" /tmp/m33mu-fwtpm.log + grep -q "fwTPM unsealed secret: wolfBoot fwTPM PCR secret" /tmp/m33mu-fwtpm.log + grep -q "fwTPM NSC tests passed" /tmp/m33mu-fwtpm.log + grep -q "\\[BKPT\\] imm=0x7f" /tmp/m33mu-fwtpm.log + grep -q "\\[EXPECT BKPT\\] Success" /tmp/m33mu-fwtpm.log + - name: Clean and build test with DICE attestation + OTP (stm32h5) run: | make clean distclean diff --git a/.gitignore b/.gitignore index 71dcbc5cba..77ef20818e 100644 --- a/.gitignore +++ b/.gitignore @@ -186,6 +186,7 @@ tools/unit-tests/unit-loader-tpm-init tools/unit-tests/unit-update-ram-nofixed tools/unit-tests/unit-max-space tools/unit-tests/unit-sdhci-disk-unaligned +tools/unit-tests/unit-fwtpm-stub diff --git a/Makefile b/Makefile index 775822c7e4..f85d53f75c 100644 --- a/Makefile +++ b/Makefile @@ -575,7 +575,7 @@ keys: $(PRIVATE_KEY) clean: $(Q)rm -f src/*.o hal/*.o hal/spi/*.o test-app/*.o src/x86/*.o $(Q)rm -f src/wolfboot_tz_nsc.o - $(Q)rm -f $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/*.o $(WOLFBOOT_LIB_WOLFTPM)/src/*.o $(WOLFBOOT_LIB_WOLFTPM)/hal/*.o $(WOLFBOOT_LIB_WOLFTPM)/examples/pcr/*.o + $(Q)rm -f $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/*.o $(WOLFBOOT_LIB_WOLFTPM)/src/*.o $(WOLFBOOT_LIB_WOLFTPM)/src/fwtpm/*.o $(WOLFBOOT_LIB_WOLFTPM)/hal/*.o $(WOLFBOOT_LIB_WOLFTPM)/examples/pcr/*.o $(Q)rm -f $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/Renesas/*.o $(Q)rm -f wolfboot.bin wolfboot.elf wolfboot.map test-update.rom wolfboot.hex wolfboot.srec factory.srec $(Q)rm -f $(MACHINE_OBJ) $(MAIN_TARGET) $(LSCRIPT) diff --git a/config/examples/stm32h5-tz-fwtpm.config b/config/examples/stm32h5-tz-fwtpm.config new file mode 100644 index 0000000000..7cb45acf38 --- /dev/null +++ b/config/examples/stm32h5-tz-fwtpm.config @@ -0,0 +1,35 @@ +ARCH?=ARM +TZEN?=1 +TARGET?=stm32h5 +SIGN?=ECC256 +HASH?=SHA256 +DEBUG?=0 +VTOR?=1 +CORTEX_M0?=0 +CORTEX_M33?=1 +NO_ASM?=0 +NO_MPU=1 +EXT_FLASH?=0 +SPI_FLASH?=0 +ALLOW_DOWNGRADE?=0 +NVM_FLASH_WRITEONCE?=1 +WOLFBOOT_VERSION?=1 +V?=0 +SPMATH?=1 +RAM_CODE?=1 +DUALBANK_SWAP?=0 +WOLFBOOT_PARTITION_SIZE?=0xA0000 +WOLFBOOT_SECTOR_SIZE?=0x2000 +WOLFBOOT_KEYVAULT_ADDRESS?=0x0C040000 +WOLFBOOT_KEYVAULT_SIZE?=0x1C000 +WOLFBOOT_NSC_ADDRESS?=0x0C05C000 +WOLFBOOT_NSC_SIZE?=0x4000 +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C100000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0C1A0000 +FLAGS_HOME=0 +DISABLE_BACKUP=0 +WOLFCRYPT_TZ=1 +WOLFCRYPT_TZ_FWTPM=1 +IMAGE_HEADER_SIZE?=1024 +ARMORED=1 diff --git a/docs/fwTPM.md b/docs/fwTPM.md new file mode 100644 index 0000000000..69758e65a8 --- /dev/null +++ b/docs/fwTPM.md @@ -0,0 +1,100 @@ +# wolfBoot fwTPM on STM32H5 + +wolfBoot can host wolfTPM's firmware TPM 2.0 implementation in the secure +TrustZone image and expose it to the non-secure application through the wolfBoot +callable service interface. This lets the non-secure application use the normal +wolfTPM client API while TPM commands are processed inside the secure world. + +The feature is intended for STM32H5 TrustZone builds. The secure image contains +the fwTPM command processor and the non-secure test application uses a small TIS +shim that forwards commands through the NSC entry point. + +## Configuration + +Use these wolfBoot configuration options: + +| Option | Effect | +| ------ | ------ | +| `TZEN=1` | Builds wolfBoot for TrustZone-enabled STM32H5 parts. | +| `WOLFCRYPT_TZ=1` | Enables the wolfCrypt secure callable service layer. | +| `WOLFCRYPT_TZ_FWTPM=1` | Enables the secure fwTPM service and non-secure fwTPM test support. | + +`WOLFCRYPT_TZ_FWTPM=1` defines `WOLFBOOT_TZ_FWTPM` for the secure and +non-secure builds. It also enables wolfTPM fwTPM sources, `WOLFTPM_FWTPM`, +`FWTPM_NO_NV`, and the callable fwTPM object. + +The ready-to-use STM32H5 configuration is: + +```sh +cp config/examples/stm32h5-tz-fwtpm.config .config +``` + +## Build + +Build wolfBoot and the signed STM32H5 test application from the repository root: + +```sh +cp config/examples/stm32h5-tz-fwtpm.config .config +make clean +make +make test-app/image_v1_signed.bin +``` + +The main outputs are: + +| Output | Description | +| ------ | ----------- | +| `wolfboot.bin` | Secure wolfBoot image with the fwTPM service. | +| `test-app/image_v1_signed.bin` | Signed non-secure STM32H5 test application. | +| `test-app/image.elf` | Non-secure test application ELF for debugging. | + +## Flash on STM32H5 + +Enable TrustZone and program the secure and non-secure images with +STM32CubeProgrammer: + +```sh +STM32_Programmer_CLI -c port=swd mode=hotplug -ob TZEN=0xB4 +STM32_Programmer_CLI -c port=swd -d wolfboot.bin 0x0C000000 +STM32_Programmer_CLI -c port=swd -d test-app/image_v1_signed.bin 0x08060000 +``` + +The addresses above match `config/examples/stm32h5-tz-fwtpm.config`: + +| Region | Address | +| ------ | ------- | +| Secure wolfBoot image | `0x0C000000` | +| Non-secure boot partition | `0x08060000` | +| Non-secure update partition | `0x0C100000` | +| Swap partition | `0x0C1A0000` | +| NSC veneer region | `0x0C05C000` | + +## Test + +Open the board serial console and run the fwTPM test command: + +```text +fwtpm +``` + +The test application initializes wolfTPM using the non-secure TIS callback, +queries capabilities, requests random bytes, extends PCR 0, verifies the PCR +value, and seals/unseals a PCR-bound secret. A successful run ends with: + +```text +fwTPM NSC tests passed +``` + +The STM32H5 test app also runs the same fwTPM test automatically during startup +when built with `WOLFBOOT_TZ_FWTPM`. + +## Notes + +The current wolfBoot integration builds the secure fwTPM service with +`FWTPM_NO_NV`, so TPM NV state is not persistent across resets. To add persistent +NV storage, provide a flash-backed `FWTPM_NV_HAL` implementation and remove +`FWTPM_NO_NV` from the fwTPM build flags. + +`WOLFCRYPT_TZ_FWTPM` is mutually exclusive with `WOLFCRYPT_TZ_PKCS11` and +`WOLFCRYPT_TZ_PSA` because each option selects a different TrustZone secure +service surface for the test application. diff --git a/include/user_settings.h b/include/user_settings.h index ca93d72af9..4c701be45d 100644 --- a/include/user_settings.h +++ b/include/user_settings.h @@ -434,7 +434,7 @@ extern int tolower(int c); # define NO_CODING #endif -#ifdef WOLFBOOT_TPM +#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FWTPM) /* Do not use heap */ #define WOLFTPM2_NO_HEAP /* small stack options */ @@ -632,6 +632,13 @@ extern int tolower(int c); #undef NO_KDF #endif +#if defined(WOLFBOOT_TZ_FWTPM) +#undef NO_CMAC +#undef NO_KDF +#define WOLFSSL_AES_CFB +#define WOLFSSL_SHA384 +#endif + #ifdef __QNX__ # define WOLFSSL_HAVE_MIN # define WOLFSSL_HAVE_MAX diff --git a/include/wolfboot/wcs_fwtpm.h b/include/wolfboot/wcs_fwtpm.h new file mode 100644 index 0000000000..9f75f047eb --- /dev/null +++ b/include/wolfboot/wcs_fwtpm.h @@ -0,0 +1,27 @@ +/* wcs_fwtpm.h + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + */ + +#ifndef WOLFBOOT_WCS_FWTPM_H +#define WOLFBOOT_WCS_FWTPM_H + +#include +#include "wolfboot/wc_secure.h" + +#ifdef WOLFBOOT_TZ_FWTPM + +#ifndef WCS_FWTPM_MAX_COMMAND_SIZE +#define WCS_FWTPM_MAX_COMMAND_SIZE 4096U +#endif + +int CSME_NSE_API wcs_fwtpm_transmit(const uint8_t *cmd, uint32_t cmdSz, + uint8_t *rsp, uint32_t *rspSz); + +void wcs_fwtpm_init(void); + +#endif /* WOLFBOOT_TZ_FWTPM */ + +#endif /* WOLFBOOT_WCS_FWTPM_H */ diff --git a/lib/wolfTPM b/lib/wolfTPM index efaab4afe6..c8d51e9693 160000 --- a/lib/wolfTPM +++ b/lib/wolfTPM @@ -1 +1 @@ -Subproject commit efaab4afe67fbe8616a08d46b721cb0cbd375894 +Subproject commit c8d51e969301859b16fd62fdaf2011a23546d8f2 diff --git a/options.mk b/options.mk index e75f43c6a2..24f6e32904 100644 --- a/options.mk +++ b/options.mk @@ -810,6 +810,15 @@ ifeq ($(WOLFCRYPT_TZ_PKCS11),1) ifeq ($(WOLFCRYPT_TZ_PSA),1) $(error WOLFCRYPT_TZ_PKCS11 and WOLFCRYPT_TZ_PSA are mutually exclusive) endif + ifeq ($(WOLFCRYPT_TZ_FWTPM),1) + $(error WOLFCRYPT_TZ_PKCS11 and WOLFCRYPT_TZ_FWTPM are mutually exclusive) + endif +endif + +ifeq ($(WOLFCRYPT_TZ_PSA),1) + ifeq ($(WOLFCRYPT_TZ_FWTPM),1) + $(error WOLFCRYPT_TZ_PSA and WOLFCRYPT_TZ_FWTPM are mutually exclusive) + endif endif ifeq ($(WOLFCRYPT_TZ_PKCS11),1) @@ -919,6 +928,50 @@ ifeq ($(WOLFCRYPT_TZ_PSA),1) endif endif +ifeq ($(WOLFCRYPT_TZ_FWTPM),1) + CFLAGS+=-DWOLFBOOT_TZ_FWTPM + CFLAGS+=-DWOLFCRYPT_SECURE_MODE + CFLAGS+=-DWOLFTPM_FWTPM + CFLAGS+=-DFWTPM_NO_NV + CFLAGS+=-DWC_RSA_PSS + CFLAGS+=-DWOLFSSL_PSS_SALT_LEN_DISCOVER + CFLAGS+=-DFWTPM_MAX_COMMAND_SIZE=4096 + CFLAGS+=-I$(WOLFBOOT_LIB_WOLFTPM) + ifeq ($(USE_CLANG),1) + CLANG_MULTILIB_FLAGS:=$(filter -mthumb -mlittle-endian,$(LDFLAGS)) $(filter -mcpu=%,$(CFLAGS)) + LIBS+=$(shell $(CLANG_GCC_NAME) $(CLANG_MULTILIB_FLAGS) -print-file-name=libc.a) + LIBS+=$(shell $(CLANG_GCC_NAME) $(CLANG_MULTILIB_FLAGS) -print-libgcc-file-name) + else + LDFLAGS+=--specs=nano.specs + endif + WOLFCRYPT_OBJS+=src/store_sbrk.o + WOLFCRYPT_OBJS+=src/fwtpm_callable.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFTPM)/src/fwtpm/fwtpm.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFTPM)/src/fwtpm/fwtpm_command.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFTPM)/src/fwtpm/fwtpm_crypto.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFTPM)/src/fwtpm/fwtpm_nv.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_util.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_packet.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_crypto.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_param_enc.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/hmac.o + ifneq ($(SIGN),ED25519) + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha512.o + endif + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/wc_encrypt.o + ifeq ($(ENCRYPT_WITH_AES128)$(ENCRYPT_WITH_AES256),) + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/aes.o + endif + WOLFCRYPT_OBJS+=$(RSA_OBJS) + ifeq ($(findstring ECC,$(SIGN)),) + ifeq ($(findstring ECC,$(SIGN_SECONDARY)),) + WOLFCRYPT_OBJS+=$(ECC_OBJS) + WOLFCRYPT_OBJS+=$(MATH_OBJS) + endif + endif + STACK_USAGE=20000 +endif + OBJS+=$(PUBLIC_KEY_OBJS) ifneq ($(STAGE1),1) OBJS+=$(UPDATE_OBJS) @@ -931,6 +984,8 @@ ifeq ($(WOLFTPM),1) $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_packet.o \ $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_tis.o \ $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_wrap.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_crypto.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_util.o \ $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_param_enc.o CFLAGS+=-I$(WOLFBOOT_LIB_WOLFTPM) CFLAGS+=-D"WOLFBOOT_TPM" diff --git a/src/fwtpm_callable.c b/src/fwtpm_callable.c new file mode 100644 index 0000000000..0aa514bbcf --- /dev/null +++ b/src/fwtpm_callable.c @@ -0,0 +1,155 @@ +/* fwtpm_callable.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + */ + +#ifdef WOLFBOOT_TZ_FWTPM + +#include +#include + +#include "store_sbrk.h" +#include "wolfboot/wcs_fwtpm.h" +#include "wolftpm/fwtpm/fwtpm.h" +#include "wolftpm/fwtpm/fwtpm_command.h" +#include "wolftpm/fwtpm/fwtpm_nv.h" +#include "wolftpm/tpm2_types.h" + +static FWTPM_CTX fwtpm_ctx; +static int fwtpm_ready; + +extern unsigned int _start_heap; +extern unsigned int _heap_size; + +void *_sbrk(unsigned int incr) +{ + static uint8_t *heap; + return wolfboot_store_sbrk(incr, &heap, (uint8_t *)&_start_heap, + (uint32_t)(&_heap_size)); +} + +#ifndef FWTPM_NO_NV +#define WCS_FWTPM_NV_SIZE (16U * 1024U) +static uint8_t fwtpm_nv[WCS_FWTPM_NV_SIZE]; + +static int fwtpm_nv_read(void *ctx, word32 offset, byte *buf, word32 size) +{ + uint8_t *nv = (uint8_t *)ctx; + + if (nv == NULL || buf == NULL || offset > WCS_FWTPM_NV_SIZE || + size > (WCS_FWTPM_NV_SIZE - offset)) { + return BAD_FUNC_ARG; + } + + XMEMCPY(buf, nv + offset, size); + return TPM_RC_SUCCESS; +} + +static int fwtpm_nv_write(void *ctx, word32 offset, const byte *buf, + word32 size) +{ + uint8_t *nv = (uint8_t *)ctx; + + if (nv == NULL || buf == NULL || offset > WCS_FWTPM_NV_SIZE || + size > (WCS_FWTPM_NV_SIZE - offset)) { + return BAD_FUNC_ARG; + } + + XMEMCPY(nv + offset, buf, size); + return TPM_RC_SUCCESS; +} + +static int fwtpm_nv_erase(void *ctx, word32 offset, word32 size) +{ + uint8_t *nv = (uint8_t *)ctx; + + if (nv == NULL || offset > WCS_FWTPM_NV_SIZE || + size > (WCS_FWTPM_NV_SIZE - offset)) { + return BAD_FUNC_ARG; + } + + XMEMSET(nv + offset, 0xFF, size); + return TPM_RC_SUCCESS; +} + +static FWTPM_NV_HAL fwtpm_nv_hal = { + fwtpm_nv_read, + fwtpm_nv_write, + fwtpm_nv_erase, + fwtpm_nv, + WCS_FWTPM_NV_SIZE +}; +#endif /* !FWTPM_NO_NV */ + +static uint32_t fwtpm_rsp_size(const uint8_t *rsp, int rspLen) +{ + if (rsp == NULL || rspLen < TPM2_HEADER_SIZE) { + return 0; + } + + return ((uint32_t)rsp[2] << 24) | + ((uint32_t)rsp[3] << 16) | + ((uint32_t)rsp[4] << 8) | + (uint32_t)rsp[5]; +} + +void wcs_fwtpm_init(void) +{ + int rc; + +#ifndef FWTPM_NO_NV + XMEMSET(fwtpm_nv, 0xFF, sizeof(fwtpm_nv)); +#endif + XMEMSET(&fwtpm_ctx, 0, sizeof(fwtpm_ctx)); +#ifndef FWTPM_NO_NV + (void)FWTPM_NV_SetHAL(&fwtpm_ctx, &fwtpm_nv_hal); +#endif + + rc = FWTPM_Init(&fwtpm_ctx); + if (rc == 0) { + fwtpm_ctx.wasStarted = 1; + fwtpm_ready = 1; + } +} + +int CSME_NSE_API wcs_fwtpm_transmit(const uint8_t *cmd, uint32_t cmdSz, + uint8_t *rsp, uint32_t *rspSz) +{ + int rc; + int rspLen; + uint32_t rspCapacity; + uint32_t wireSz; + + if (!fwtpm_ready) { + return TPM_RC_INITIALIZE; + } + if (cmd == NULL || rsp == NULL || rspSz == NULL || cmdSz == 0U || + cmdSz > WCS_FWTPM_MAX_COMMAND_SIZE) { + return BAD_FUNC_ARG; + } + + rspCapacity = *rspSz; + if (rspCapacity == 0U || rspCapacity > WCS_FWTPM_MAX_COMMAND_SIZE) { + return BAD_FUNC_ARG; + } + + rspLen = (int)rspCapacity; + rc = FWTPM_ProcessCommand(&fwtpm_ctx, cmd, (int)cmdSz, rsp, &rspLen, 0); + if (rc == TPM_RC_SUCCESS) { + wireSz = fwtpm_rsp_size(rsp, rspLen); + if (wireSz > 0U && wireSz <= rspCapacity) { + *rspSz = wireSz; + } + else if (rspLen >= 0 && (uint32_t)rspLen <= rspCapacity) { + *rspSz = (uint32_t)rspLen; + } + else { + rc = TPM_RC_FAILURE; + } + } + return rc; +} + +#endif /* WOLFBOOT_TZ_FWTPM */ diff --git a/src/loader.c b/src/loader.c index 929b818872..3c26f4db42 100644 --- a/src/loader.c +++ b/src/loader.c @@ -123,7 +123,7 @@ int main(void) uart_init(UART_FLASH_BITRATE, 8, 'N', 1); uart_send_current_version(); #endif -#ifdef WOLFBOOT_TPM +#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FWTPM) if (wolfBoot_tpm2_init() != 0) { wolfBoot_panic(); } diff --git a/src/wc_callable.c b/src/wc_callable.c index 656f9746b2..1dd9761232 100644 --- a/src/wc_callable.c +++ b/src/wc_callable.c @@ -30,6 +30,10 @@ #include "hal.h" #include +#ifdef WOLFBOOT_TZ_FWTPM +#include "wolfboot/wcs_fwtpm.h" +#endif + static WC_RNG wcs_rng; int CSME_NSE_API wcs_get_random(uint8_t *rand, uint32_t size) @@ -41,6 +45,9 @@ void wcs_Init(void) { hal_trng_init(); wc_InitRng(&wcs_rng); +#ifdef WOLFBOOT_TZ_FWTPM + wcs_fwtpm_init(); +#endif } #endif /* WOLFCRYPT_SECURE_MODE */ diff --git a/stage1/Makefile b/stage1/Makefile index a5af1526df..2f0b027b26 100644 --- a/stage1/Makefile +++ b/stage1/Makefile @@ -59,6 +59,8 @@ ifeq ($(WOLFTPM),1) tpm2_packet.o \ tpm2_tis.o \ tpm2_wrap.o \ + tpm2_crypto.o \ + tpm2_util.o \ tpm2_param_enc.o \ image.o endif diff --git a/test-app/Makefile b/test-app/Makefile index bb50facbab..f404e1c063 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -4,9 +4,13 @@ -include ./wcs/pkcs11.mk WOLFBOOT_LIB_WOLFSSL?=../lib/wolfssl +WOLFBOOT_LIB_WOLFTPM?=../lib/wolfTPM WOLFSSL_LOCAL_OBJDIR?=wolfssl_obj +WOLFTPM_LOCAL_OBJDIR?=wolftpm_obj vpath %.c $(WOLFBOOT_LIB_WOLFSSL) vpath %.S $(WOLFBOOT_LIB_WOLFSSL) +vpath %.c $(WOLFBOOT_LIB_WOLFTPM) +vpath %.S $(WOLFBOOT_LIB_WOLFTPM) TARGET?=none ARCH?=ARM @@ -100,6 +104,11 @@ ifeq ($(WOLFCRYPT_TZ_PSA),1) WOLFCRYPT_TZ_PSA=1 endif +ifeq ($(WOLFCRYPT_TZ_FWTPM),1) + WOLFCRYPT_TZ=1 + WOLFCRYPT_TZ_FWTPM=1 +endif + # Setup default linker flags LDFLAGS+=-T $(LSCRIPT) -Wl,-gc-sections -Wl,-Map=image.map -nostartfiles @@ -325,6 +334,24 @@ ifeq ($(TZEN),1) $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/psa/psa_hash.o \ $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/psa/psa_pkcbs.o endif + ifeq ($(WOLFCRYPT_TZ_FWTPM),1) + CFLAGS:=$(filter-out -DWOLFTPM_FWTPM,$(CFLAGS)) + CFLAGS+=-DWOLFBOOT_TZ_FWTPM -DWOLFBOOT_TPM -DWOLFTPM_ADV_IO + CFLAGS+=-DWOLFTPM_EXAMPLE_HAL + CFLAGS+=-I"$(WOLFBOOT_LIB_WOLFTPM)" + APP_OBJS+=./wcs/fwtpm_stub.o + WOLFTPM_APP_OBJS+=\ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_packet.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_tis.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_wrap.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_param_enc.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_util.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_crypto.o + WOLFTPM_APP_OBJS := $(patsubst $(WOLFBOOT_LIB_WOLFTPM)/%, \ + $(WOLFTPM_LOCAL_OBJDIR)/%, $(WOLFTPM_APP_OBJS)) + APP_OBJS+=$(sort $(WOLFTPM_APP_OBJS)) + endif WOLFCRYPT_APP_OBJS := $(patsubst $(WOLFBOOT_LIB_WOLFSSL)/%, \ $(WOLFSSL_LOCAL_OBJDIR)/%, $(WOLFCRYPT_APP_OBJS)) ifneq ($(WOLFCRYPT_TZ_PKCS11),1) @@ -908,6 +935,7 @@ endif # Capture final flags for locally built wolfSSL objects. WOLFSSL_CFLAGS:=$(CFLAGS) +WOLFTPM_CFLAGS:=$(CFLAGS) ifeq ($(WOLFHSM_CLIENT),1) CFLAGS += -DSTRING_USER -I"$(WOLFBOOT_LIB_WOLFSSL)" @@ -995,9 +1023,19 @@ $(WOLFSSL_LOCAL_OBJDIR)/%.o: %.S $(Q)mkdir -p $(dir $@) $(Q)$(CC) $(WOLFSSL_CFLAGS) -c $(OUTPUT_FLAG) $@ $< +$(WOLFTPM_LOCAL_OBJDIR)/%.o: %.c + @echo "\t[CC-$(ARCH)] $@" + $(Q)mkdir -p $(dir $@) + $(Q)$(CC) $(WOLFTPM_CFLAGS) -c $(OUTPUT_FLAG) $@ $< + +$(WOLFTPM_LOCAL_OBJDIR)/%.o: %.S + @echo "\t[AS-$(ARCH)] $@" + $(Q)mkdir -p $(dir $@) + $(Q)$(CC) $(WOLFTPM_CFLAGS) -c $(OUTPUT_FLAG) $@ $< + clean: $(Q)rm -f *.bin *.elf tags *.o $(LSCRIPT) $(APP_OBJS) wcs/*.o - $(Q)rm -rf $(WOLFSSL_LOCAL_OBJDIR) + $(Q)rm -rf $(WOLFSSL_LOCAL_OBJDIR) $(WOLFTPM_LOCAL_OBJDIR) $(LSCRIPT): $(LSCRIPT_TEMPLATE) FORCE $(Q)printf "%d" $(WOLFBOOT_PARTITION_BOOT_ADDRESS) > .wolfboot-offset diff --git a/test-app/app_stm32h5.c b/test-app/app_stm32h5.c index 2c68e25839..660718aa4a 100644 --- a/test-app/app_stm32h5.c +++ b/test-app/app_stm32h5.c @@ -36,10 +36,15 @@ #endif #include "target.h" -#ifdef WOLFBOOT_TPM +#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FWTPM) #include "tpm.h" #endif +#ifdef WOLFBOOT_TZ_FWTPM +#include "wolftpm/tpm2_wrap.h" +#include "wolfssl/wolfcrypt/sha256.h" +#endif + #ifdef WOLFBOOT_TZ_PKCS11 #include "test_pkcs11.h" #endif @@ -201,7 +206,7 @@ static int cmd_timestamp(const char *args); static int cmd_update(const char *args); static int cmd_update_xmodem(const char *args); static int cmd_reboot(const char *args); -#ifdef WOLFBOOT_TPM +#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FWTPM) static int cmd_tpm_info(const char *args); #ifdef WOLFTPM_MFG_IDENTITY static int cmd_tpm_idevid(const char *args); @@ -210,6 +215,9 @@ static int cmd_tpm_signed_timestamp(const char *args); static int cmd_tpm_quote(const char *args); #endif #endif +#ifdef WOLFBOOT_TZ_FWTPM +static int cmd_fwtpm_test(const char *args); +#endif #define CMD_BUFFER_SIZE 256 @@ -238,7 +246,7 @@ struct console_command COMMANDS[] = {cmd_test, "test", "run the wolfCrypt test"}, {cmd_update_xmodem, "update", "update the firmware via XMODEM"}, {cmd_reboot, "reboot", "reboot the system"}, -#ifdef WOLFBOOT_TPM +#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FWTPM) {cmd_tpm_info, "tpm", "get TPM capabilities"}, #ifdef WOLFTPM_MFG_IDENTITY {cmd_tpm_idevid, "idevid", "show Initial Device Identification (IDevID) certificate"}, @@ -246,6 +254,9 @@ struct console_command COMMANDS[] = {cmd_tpm_signed_timestamp, "signed_time", "TPM IAK signed timestamp attestation report"}, {cmd_tpm_quote, "quote", "TPM IAK signed PCR(s) attestation report"}, #endif +#endif +#ifdef WOLFBOOT_TZ_FWTPM + {cmd_fwtpm_test, "fwtpm", "run fwTPM tests through the secure NSC interface"}, #endif {NULL, "", ""} }; @@ -852,7 +863,7 @@ static int cmd_test(const char *args) return 0; } -#ifdef WOLFBOOT_TPM +#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FWTPM) #include #include @@ -1119,7 +1130,222 @@ static int cmd_tpm_quote(const char *args) return rc; } #endif /* WOLFTPM_MFG_IDENTITY */ -#endif /* WOLFBOOT_TPM */ +#endif /* WOLFBOOT_TPM && !WOLFBOOT_TZ_FWTPM */ + +#ifdef WOLFBOOT_TZ_FWTPM +extern int TPM2_IoCb_FwtpmNsc(TPM2_CTX *ctx, INT32 isRead, UINT32 addr, + BYTE *buf, UINT16 size, void *userCtx); + +static int fwtpm_expected_pcr_after_extend(const uint8_t *before, + const uint8_t *event, uint8_t *expected) +{ + wc_Sha256 sha; + int rc; + + rc = wc_InitSha256(&sha); + if (rc == 0) { + rc = wc_Sha256Update(&sha, before, WC_SHA256_DIGEST_SIZE); + } + if (rc == 0) { + rc = wc_Sha256Update(&sha, event, WC_SHA256_DIGEST_SIZE); + } + if (rc == 0) { + rc = wc_Sha256Final(&sha, expected); + } + + wc_Sha256Free(&sha); + return rc; +} + +static int fwtpm_seal_unseal_pcr_secret(WOLFTPM2_DEV *dev) +{ + static const uint8_t secret[] = "wolfBoot fwTPM PCR secret"; + uint8_t pcrArray[1] = { 0 }; + uint8_t policyDigest[TPM_MAX_DIGEST_SIZE]; + word32 policyDigestSz = sizeof(policyDigest); + WOLFTPM2_KEY storage; + WOLFTPM2_KEYBLOB sealBlob; + WOLFTPM2_SESSION trialSession; + WOLFTPM2_SESSION policySession; + TPMT_PUBLIC sealTemplate; + Unseal_In unsealIn; + Unseal_Out unsealOut; + int rc; + + XMEMSET(&storage, 0, sizeof(storage)); + XMEMSET(&sealBlob, 0, sizeof(sealBlob)); + XMEMSET(&trialSession, 0, sizeof(trialSession)); + XMEMSET(&policySession, 0, sizeof(policySession)); + XMEMSET(&sealTemplate, 0, sizeof(sealTemplate)); + XMEMSET(&unsealIn, 0, sizeof(unsealIn)); + XMEMSET(&unsealOut, 0, sizeof(unsealOut)); + + rc = wolfTPM2_CreateSRK(dev, &storage, TPM_ALG_ECC, NULL, 0); + if (rc != TPM_RC_SUCCESS) { + printf("fwTPM seal SRK failed: 0x%x\r\n", rc); + return rc; + } + + rc = wolfTPM2_StartSession(dev, &trialSession, NULL, NULL, + TPM_SE_TRIAL, TPM_ALG_NULL); + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_PolicyPCR(dev, trialSession.handle.hndl, + TPM_ALG_SHA256, pcrArray, 1); + } + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_GetPolicyDigest(dev, trialSession.handle.hndl, + policyDigest, &policyDigestSz); + } + wolfTPM2_UnloadHandle(dev, &trialSession.handle); + if (rc != TPM_RC_SUCCESS) { + printf("fwTPM seal policy failed: 0x%x\r\n", rc); + wolfTPM2_UnloadHandle(dev, &storage.handle); + return rc; + } + + wolfTPM2_GetKeyTemplate_KeySeal(&sealTemplate, TPM_ALG_SHA256); + sealTemplate.objectAttributes &= ~TPMA_OBJECT_userWithAuth; + sealTemplate.authPolicy.size = (UINT16)policyDigestSz; + XMEMCPY(sealTemplate.authPolicy.buffer, policyDigest, policyDigestSz); + + rc = wolfTPM2_CreateKeySeal_ex(dev, &sealBlob, &storage.handle, + &sealTemplate, NULL, 0, TPM_ALG_SHA256, pcrArray, 1, + secret, (int)sizeof(secret)); + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_LoadKey(dev, &sealBlob, &storage.handle); + } + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_StartSession(dev, &policySession, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL); + } + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_PolicyPCR(dev, policySession.handle.hndl, + TPM_ALG_SHA256, pcrArray, 1); + } + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_SetAuthSession(dev, 0, &policySession, + TPMA_SESSION_continueSession); + } + if (rc == TPM_RC_SUCCESS) { + wolfTPM2_SetAuthHandleName(dev, 0, &sealBlob.handle); + unsealIn.itemHandle = sealBlob.handle.hndl; + rc = TPM2_Unseal(&unsealIn, &unsealOut); + } + + wolfTPM2_UnloadHandle(dev, &policySession.handle); + wolfTPM2_UnloadHandle(dev, &sealBlob.handle); + wolfTPM2_UnloadHandle(dev, &storage.handle); + + if (rc != TPM_RC_SUCCESS) { + printf("fwTPM unseal failed: 0x%x\r\n", rc); + return rc; + } + + if (unsealOut.outData.size != sizeof(secret) || + XMEMCMP(unsealOut.outData.buffer, secret, sizeof(secret)) != 0) { + printf("fwTPM unsealed secret mismatch\r\n"); + return TPM_RC_FAILURE; + } + + printf("fwTPM unsealed secret: %.*s\r\n", + unsealOut.outData.size, unsealOut.outData.buffer); + return TPM_RC_SUCCESS; +} + +static int cmd_fwtpm_test(const char *args) +{ + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_CAPS caps; + uint8_t rnd[16]; + uint8_t pcr[TPM_MAX_DIGEST_SIZE]; + uint8_t pcrBefore[TPM_SHA256_DIGEST_SIZE]; + uint8_t pcrEvent[TPM_SHA256_DIGEST_SIZE]; + uint8_t pcrExpected[TPM_SHA256_DIGEST_SIZE]; + int pcrSz = 0; + + (void)args; + + XMEMSET(&dev, 0, sizeof(dev)); + XMEMSET(&caps, 0, sizeof(caps)); + XMEMSET(rnd, 0, sizeof(rnd)); + XMEMSET(pcr, 0, sizeof(pcr)); + XMEMSET(pcrBefore, 0, sizeof(pcrBefore)); + XMEMSET(pcrEvent, 0, sizeof(pcrEvent)); + XMEMSET(pcrExpected, 0, sizeof(pcrExpected)); + + rc = wolfTPM2_Init(&dev, TPM2_IoCb_FwtpmNsc, NULL); + if (rc != TPM_RC_SUCCESS) { + printf("fwTPM init failed: 0x%x\r\n", rc); + return rc; + } + + rc = wolfTPM2_GetCapabilities(&dev, &caps); + if (rc == TPM_RC_SUCCESS) { + printf("fwTPM caps: mfg %s vendor %s fw %u.%u\r\n", + caps.mfgStr, caps.vendorStr, caps.fwVerMajor, caps.fwVerMinor); + } + + if (rc == TPM_RC_SUCCESS) { + int randRc = wolfTPM2_GetRandom(&dev, rnd, sizeof(rnd)); + if (randRc == TPM_RC_SUCCESS) { + printf("fwTPM random:"); + print_hex(rnd, sizeof(rnd), 0); + } + else { + printf("fwTPM random unavailable: 0x%x\r\n", randRc); + } + } + + if (rc == TPM_RC_SUCCESS) { + pcrSz = sizeof(pcr); + rc = wolfTPM2_ReadPCR(&dev, 0, TPM_ALG_SHA256, pcr, &pcrSz); + if (rc == TPM_RC_SUCCESS) { + XMEMCPY(pcrBefore, pcr, sizeof(pcrBefore)); + } + } + + if (rc == TPM_RC_SUCCESS) { + static const uint8_t pcrEventName[] = "wolfBoot fwTPM PCR event"; + rc = wc_Sha256Hash(pcrEventName, sizeof(pcrEventName) - 1U, + pcrEvent); + } + if (rc == TPM_RC_SUCCESS) { + rc = fwtpm_expected_pcr_after_extend(pcrBefore, pcrEvent, pcrExpected); + } + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_ExtendPCR(&dev, 0, TPM_ALG_SHA256, pcrEvent, + sizeof(pcrEvent)); + } + if (rc == TPM_RC_SUCCESS) { + pcrSz = sizeof(pcr); + rc = wolfTPM2_ReadPCR(&dev, 0, TPM_ALG_SHA256, pcr, &pcrSz); + if (rc == TPM_RC_SUCCESS) { + printf("fwTPM PCR0 extended:"); + print_hex(pcr, (uint32_t)pcrSz, 0); + } + } + if (rc == TPM_RC_SUCCESS && (pcrSz != (int)sizeof(pcrExpected) || + XMEMCMP(pcr, pcrExpected, sizeof(pcrExpected)) != 0)) { + printf("fwTPM PCR0 extend mismatch\r\n"); + rc = TPM_RC_FAILURE; + } + if (rc == TPM_RC_SUCCESS) { + rc = fwtpm_seal_unseal_pcr_secret(&dev); + } + + wolfTPM2_Cleanup(&dev); + + if (rc == TPM_RC_SUCCESS) { + printf("fwTPM NSC tests passed\r\n"); + } + else { + printf("fwTPM NSC tests failed: 0x%x\r\n", rc); + } + + return rc; +} +#endif /* WOLFBOOT_TZ_FWTPM */ static int parse_cmd(const char *cmd) @@ -1268,9 +1494,16 @@ void main(void) #endif cmd_info(NULL); -#ifdef WOLFBOOT_TPM +#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FWTPM) cmd_tpm_info(NULL); #endif +#ifdef WOLFBOOT_TZ_FWTPM + ret = cmd_fwtpm_test(NULL); + if (ret == 0) + asm volatile ("bkpt #0x7f"); + else + asm volatile ("bkpt #0x7e"); +#endif #if defined(WOLFBOOT_ATTESTATION_TEST) && defined(WOLFCRYPT_TZ_PSA) (void)run_attestation_test(); diff --git a/test-app/wcs/fwtpm_stub.c b/test-app/wcs/fwtpm_stub.c new file mode 100644 index 0000000000..aa8b6d62eb --- /dev/null +++ b/test-app/wcs/fwtpm_stub.c @@ -0,0 +1,217 @@ +/* fwtpm_stub.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + */ + +#ifdef WOLFBOOT_TZ_FWTPM + +#include +#include + +#include "wolfboot/wcs_fwtpm.h" +#include "wolftpm/tpm2.h" +#include "wolftpm/tpm2_tis.h" + +#define FWTPM_TIS_BASE 0xD40000U +#define FWTPM_TIS_ACCESS 0x0000U +#define FWTPM_TIS_INTF_CAPS 0x0014U +#define FWTPM_TIS_STS 0x0018U +#define FWTPM_TIS_BURST_COUNT 0x0019U +#define FWTPM_TIS_DATA_FIFO 0x0024U +#define FWTPM_TIS_DID_VID 0x0F00U +#define FWTPM_TIS_RID 0x0F04U + +#define FWTPM_ACCESS_VALID 0x80U +#define FWTPM_ACCESS_ACTIVE_LOCALITY 0x20U +#define FWTPM_ACCESS_REQUEST_USE 0x02U + +#define FWTPM_STS_VALID 0x80U +#define FWTPM_STS_COMMAND_READY 0x40U +#define FWTPM_STS_GO 0x20U +#define FWTPM_STS_DATA_AVAIL 0x10U +#define FWTPM_STS_DATA_EXPECT 0x08U + +#define FWTPM_BURST_COUNT 64U + +struct fwtpm_tis_state { + uint8_t cmd[WCS_FWTPM_MAX_COMMAND_SIZE]; + uint8_t rsp[WCS_FWTPM_MAX_COMMAND_SIZE]; + uint32_t cmdSz; + uint32_t rspSz; + uint32_t rspPos; + uint8_t locality; + uint8_t status; +}; + +static struct fwtpm_tis_state fwtpm_tis = { + {0}, {0}, 0, 0, 0, 0, + FWTPM_STS_VALID | FWTPM_STS_COMMAND_READY +}; + +static int fwtpm_reg_offset(uint32_t addr, uint32_t *off) +{ + if (off == NULL || addr < FWTPM_TIS_BASE || + addr >= (FWTPM_TIS_BASE + 0x1000U)) { + return BAD_FUNC_ARG; + } + + *off = addr - FWTPM_TIS_BASE; + return TPM_RC_SUCCESS; +} + +static void fwtpm_store_le(uint8_t *buf, uint16_t size, uint32_t val) +{ + uint16_t i; + + for (i = 0; i < size; i++) { + buf[i] = (uint8_t)(val >> (8U * i)); + } +} + +static uint32_t fwtpm_cmd_size(void) +{ + if (fwtpm_tis.cmdSz < TPM2_HEADER_SIZE) { + return TPM2_HEADER_SIZE; + } + + return ((uint32_t)fwtpm_tis.cmd[2] << 24) | + ((uint32_t)fwtpm_tis.cmd[3] << 16) | + ((uint32_t)fwtpm_tis.cmd[4] << 8) | + (uint32_t)fwtpm_tis.cmd[5]; +} + +static int fwtpm_execute(void) +{ + int rc; + + fwtpm_tis.rspSz = sizeof(fwtpm_tis.rsp); + fwtpm_tis.rspPos = 0; + + rc = wcs_fwtpm_transmit(fwtpm_tis.cmd, fwtpm_tis.cmdSz, fwtpm_tis.rsp, + &fwtpm_tis.rspSz); + fwtpm_tis.cmdSz = 0; + + if (rc == TPM_RC_SUCCESS) { + fwtpm_tis.status = FWTPM_STS_VALID | FWTPM_STS_DATA_AVAIL; + } + else { + fwtpm_tis.rspSz = 0; + fwtpm_tis.status = FWTPM_STS_VALID | FWTPM_STS_COMMAND_READY; + } + + return rc; +} + +int TPM2_IoCb_FwtpmNsc(TPM2_CTX *ctx, INT32 isRead, UINT32 addr, + BYTE *buf, UINT16 size, void *userCtx) +{ + uint32_t off; + uint16_t burst; + + (void)ctx; + (void)userCtx; + + if (buf == NULL || size == 0U) { + return BAD_FUNC_ARG; + } + + if (fwtpm_reg_offset(addr, &off) != TPM_RC_SUCCESS) { + return BAD_FUNC_ARG; + } + + burst = FWTPM_BURST_COUNT; + + if (isRead) { + switch (off) { + case FWTPM_TIS_ACCESS: + buf[0] = FWTPM_ACCESS_VALID | FWTPM_ACCESS_ACTIVE_LOCALITY; + break; + case FWTPM_TIS_STS: + XMEMSET(buf, 0, size); + buf[0] = fwtpm_tis.status; + if (size > 1U) { + buf[1] = (uint8_t)burst; + } + if (size > 2U) { + buf[2] = (uint8_t)(burst >> 8); + } + break; + case FWTPM_TIS_BURST_COUNT: + fwtpm_store_le(buf, size, burst); + break; + case FWTPM_TIS_BURST_COUNT + 1U: + fwtpm_store_le(buf, size, burst >> 8); + break; + case FWTPM_TIS_DATA_FIFO: + if (fwtpm_tis.rspPos + size > fwtpm_tis.rspSz) { + return TPM_RC_FAILURE; + } + XMEMCPY(buf, fwtpm_tis.rsp + fwtpm_tis.rspPos, size); + fwtpm_tis.rspPos += size; + if (fwtpm_tis.rspPos >= fwtpm_tis.rspSz) { + fwtpm_tis.status = FWTPM_STS_VALID | FWTPM_STS_COMMAND_READY; + } + break; + case FWTPM_TIS_INTF_CAPS: + fwtpm_store_le(buf, size, 0x00000183U); + break; + case FWTPM_TIS_DID_VID: + fwtpm_store_le(buf, size, 0x00011B4EU); + break; + case FWTPM_TIS_RID: + buf[0] = 0x01U; + break; + default: + XMEMSET(buf, 0, size); + break; + } + } + else { + switch (off) { + case FWTPM_TIS_ACCESS: + if ((buf[0] & FWTPM_ACCESS_REQUEST_USE) != 0U) { + fwtpm_tis.locality = 0; + } + break; + case FWTPM_TIS_STS: + if ((buf[0] & FWTPM_STS_COMMAND_READY) != 0U) { + fwtpm_tis.cmdSz = 0; + fwtpm_tis.rspSz = 0; + fwtpm_tis.rspPos = 0; + fwtpm_tis.status = FWTPM_STS_VALID | + FWTPM_STS_COMMAND_READY; + } + else if ((buf[0] & FWTPM_STS_GO) != 0U) { + return fwtpm_execute(); + } + break; + case FWTPM_TIS_DATA_FIFO: + if (fwtpm_tis.cmdSz + size > sizeof(fwtpm_tis.cmd)) { + return TPM_RC_FAILURE; + } + XMEMCPY(fwtpm_tis.cmd + fwtpm_tis.cmdSz, buf, size); + fwtpm_tis.cmdSz += size; + if (fwtpm_tis.cmdSz < fwtpm_cmd_size()) { + fwtpm_tis.status = FWTPM_STS_VALID | FWTPM_STS_DATA_EXPECT; + } + else { + fwtpm_tis.status = FWTPM_STS_VALID; + } + break; + default: + break; + } + } + + return TPM_RC_SUCCESS; +} + +int TPM2_IoCb(TPM2_CTX *ctx, INT32 isRead, UINT32 addr, BYTE *buf, + UINT16 size, void *userCtx) +{ + return TPM2_IoCb_FwtpmNsc(ctx, isRead, addr, buf, size, userCtx); +} + +#endif /* WOLFBOOT_TZ_FWTPM */ diff --git a/test-app/wcs/user_settings.h b/test-app/wcs/user_settings.h index 2f497f77a1..1f71ff86a8 100644 --- a/test-app/wcs/user_settings.h +++ b/test-app/wcs/user_settings.h @@ -156,7 +156,7 @@ extern int tolower(int c); #define HAVE_PKCS8 #define HAVE_PKCS12 -#ifdef SECURE_PKCS11 +#if defined(SECURE_PKCS11) || defined(WOLFBOOT_TZ_FWTPM) static inline int wcs_cmse_get_random(unsigned char* output, int sz) { diff --git a/tools/config.mk b/tools/config.mk index 2d158ee3ff..4ef65ca06b 100644 --- a/tools/config.mk +++ b/tools/config.mk @@ -66,6 +66,7 @@ ifeq ($(ARCH),) WOLFCRYPT_TZ?=0 WOLFCRYPT_TZ_PKCS11?=0 WOLFCRYPT_TZ_PSA?=0 + WOLFCRYPT_TZ_FWTPM?=0 WOLFBOOT_PARTITION_SIZE?=0x20000 WOLFBOOT_SECTOR_SIZE?=0x20000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08020000 @@ -104,6 +105,7 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO WOLFBOOT_UDS_OBKEYS \ WOLFCRYPT_TZ WOLFCRYPT_TZ_PKCS11 \ WOLFCRYPT_TZ_PSA \ + WOLFCRYPT_TZ_FWTPM \ WOLFBOOT_PARTITION_SIZE WOLFBOOT_SECTOR_SIZE \ WOLFBOOT_PARTITION_BOOT_ADDRESS WOLFBOOT_PARTITION_UPDATE_ADDRESS \ WOLFBOOT_PARTITION_SWAP_ADDRESS WOLFBOOT_LOAD_ADDRESS \ diff --git a/tools/tpm/Makefile b/tools/tpm/Makefile index e9bf9f37cc..050554b460 100644 --- a/tools/tpm/Makefile +++ b/tools/tpm/Makefile @@ -67,6 +67,8 @@ OBJS_REAL=\ $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2.o \ $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_linux.o \ $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_packet.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_crypto.o \ + $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_util.o \ $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_param_enc.o \ $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_swtpm.o \ $(WOLFBOOT_LIB_WOLFTPM)/src/tpm2_tis.o \ diff --git a/tools/unit-tests/Makefile b/tools/unit-tests/Makefile index 63b4334a14..24b7ccab03 100644 --- a/tools/unit-tests/Makefile +++ b/tools/unit-tests/Makefile @@ -50,7 +50,7 @@ TESTS:=unit-parser unit-fdt unit-extflash unit-string unit-spi-flash unit-aes128 unit-enc-nvm-flagshome unit-delta unit-update-flash unit-update-flash-delta \ unit-update-flash-self-update \ unit-update-flash-enc unit-update-ram unit-update-ram-nofixed unit-pkcs11_store unit-psa_store unit-disk \ - unit-update-disk unit-multiboot unit-boot-x86-fsp unit-loader-tpm-init unit-qspi-flash unit-tpm-rsa-exp \ + unit-update-disk unit-multiboot unit-boot-x86-fsp unit-loader-tpm-init unit-qspi-flash unit-fwtpm-stub unit-tpm-rsa-exp \ unit-image-nopart unit-image-sha384 unit-image-sha3-384 unit-store-sbrk \ unit-tpm-blob unit-policy-create unit-policy-sign unit-rot-auth unit-sdhci-response-bits \ unit-sdhci-disk-unaligned unit-sign-encrypted-output @@ -168,6 +168,11 @@ unit-tpm-check-rot-auth: ../../include/target.h unit-tpm-check-rot-auth.c ../../ -DWOLFBOOT_HASH_SHA256 \ -ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections +unit-fwtpm-stub: ../../include/target.h unit-fwtpm-stub.c + gcc -o $@ $^ $(CFLAGS) -I$(WOLFBOOT_LIB_WOLFTPM) \ + -DWOLFTPM_USER_SETTINGS -ffunction-sections -fdata-sections \ + $(LDFLAGS) -Wl,--gc-sections + unit-tpm-blob: ../../include/target.h unit-tpm-blob.c gcc -o $@ $^ $(CFLAGS) -I$(WOLFBOOT_LIB_WOLFTPM) -DWOLFBOOT_TPM \ -DWOLFTPM_USER_SETTINGS -DWOLFBOOT_TPM_SEAL -DWOLFBOOT_SIGN_RSA2048 \ diff --git a/tools/unit-tests/unit-fwtpm-stub.c b/tools/unit-tests/unit-fwtpm-stub.c new file mode 100644 index 0000000000..6c23b0ad47 --- /dev/null +++ b/tools/unit-tests/unit-fwtpm-stub.c @@ -0,0 +1,83 @@ +/* unit-fwtpm-stub.c + * + * Unit tests for the fwTPM non-secure TIS callback shim. + */ + +#include +#include + +#define WOLFBOOT_TZ_FWTPM + +int wcs_fwtpm_transmit(const uint8_t *cmd, uint32_t cmdSz, uint8_t *rsp, + uint32_t *rspSz) +{ + (void)cmd; + (void)cmdSz; + (void)rsp; + (void)rspSz; + return -1; +} + +#include "../../test-app/wcs/fwtpm_stub.c" + +START_TEST(fwtpm_tis_rejects_address_below_window) +{ + BYTE buf[4] = {0}; + + ck_assert_int_eq(TPM2_IoCb_FwtpmNsc(NULL, 1, FWTPM_TIS_BASE - 1U, + buf, sizeof(buf), NULL), BAD_FUNC_ARG); +} +END_TEST + +START_TEST(fwtpm_tis_rejects_address_above_window) +{ + BYTE buf[4] = {0}; + + ck_assert_int_eq(TPM2_IoCb_FwtpmNsc(NULL, 1, FWTPM_TIS_BASE + 0x1000U, + buf, sizeof(buf), NULL), BAD_FUNC_ARG); +} +END_TEST + +START_TEST(fwtpm_tis_accepts_valid_window_register) +{ + BYTE buf[4] = {0}; + + ck_assert_int_eq(TPM2_IoCb_FwtpmNsc(NULL, 1, + FWTPM_TIS_BASE + FWTPM_TIS_DID_VID, buf, sizeof(buf), NULL), + TPM_RC_SUCCESS); + ck_assert_uint_eq(buf[0], 0x4EU); + ck_assert_uint_eq(buf[1], 0x1BU); + ck_assert_uint_eq(buf[2], 0x01U); + ck_assert_uint_eq(buf[3], 0x00U); +} +END_TEST + +static Suite *fwtpm_stub_suite(void) +{ + Suite *s; + TCase *tc; + + s = suite_create("fwtpm_stub"); + tc = tcase_create("tis_window"); + tcase_add_test(tc, fwtpm_tis_rejects_address_below_window); + tcase_add_test(tc, fwtpm_tis_rejects_address_above_window); + tcase_add_test(tc, fwtpm_tis_accepts_valid_window_register); + suite_add_tcase(s, tc); + + return s; +} + +int main(void) +{ + int fails; + Suite *s; + SRunner *sr; + + s = fwtpm_stub_suite(); + sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + fails = srunner_ntests_failed(sr); + srunner_free(sr); + + return fails == 0 ? 0 : 1; +}