Added support for fTPM in TrustZone + STM32H5 test app

pull/756/head
Daniele Lacamera 2026-04-21 20:53:48 +02:00
parent 71b395d292
commit b22c85ed27
15 changed files with 780 additions and 12 deletions

View File

@ -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 fTPM (stm32h5)
run: |
make clean distclean
cp config/examples/stm32h5-tz-ftpm.config .config
make
m33mu wolfboot.bin test-app/image_v1_signed.bin:0x60000 --uart-stdout --expect-bkpt 0x7f --timeout 600 \
| tee /tmp/m33mu-ftpm.log
grep -q "fTPM PCR0 extended:" /tmp/m33mu-ftpm.log
grep -q "fTPM unsealed secret: wolfBoot fTPM PCR secret" /tmp/m33mu-ftpm.log
grep -q "fTPM NSC tests passed" /tmp/m33mu-ftpm.log
grep -q "\\[BKPT\\] imm=0x7f" /tmp/m33mu-ftpm.log
grep -q "\\[EXPECT BKPT\\] Success" /tmp/m33mu-ftpm.log
- name: Clean and build test with DICE attestation + OTP (stm32h5)
run: |
make clean distclean

View File

@ -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)

View File

@ -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_FTPM=1
IMAGE_HEADER_SIZE?=1024
ARMORED=1

View File

@ -434,7 +434,7 @@ extern int tolower(int c);
# define NO_CODING
#endif
#ifdef WOLFBOOT_TPM
#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FTPM)
/* 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_FTPM)
#undef NO_CMAC
#undef NO_KDF
#define WOLFSSL_AES_CFB
#define WOLFSSL_SHA384
#endif
#ifdef __QNX__
# define WOLFSSL_HAVE_MIN
# define WOLFSSL_HAVE_MAX

View File

@ -0,0 +1,27 @@
/* wcs_ftpm.h
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfBoot.
*/
#ifndef WOLFBOOT_WCS_FTPM_H
#define WOLFBOOT_WCS_FTPM_H
#include <stdint.h>
#include "wolfboot/wc_secure.h"
#ifdef WOLFBOOT_TZ_FTPM
#ifndef WCS_FTPM_MAX_COMMAND_SIZE
#define WCS_FTPM_MAX_COMMAND_SIZE 4096U
#endif
int CSME_NSE_API wcs_ftpm_transmit(const uint8_t *cmd, uint32_t cmdSz,
uint8_t *rsp, uint32_t *rspSz);
void wcs_ftpm_init(void);
#endif /* WOLFBOOT_TZ_FTPM */
#endif /* WOLFBOOT_WCS_FTPM_H */

@ -1 +1 @@
Subproject commit efaab4afe67fbe8616a08d46b721cb0cbd375894
Subproject commit c8d51e969301859b16fd62fdaf2011a23546d8f2

View File

@ -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_FTPM),1)
$(error WOLFCRYPT_TZ_PKCS11 and WOLFCRYPT_TZ_FTPM are mutually exclusive)
endif
endif
ifeq ($(WOLFCRYPT_TZ_PSA),1)
ifeq ($(WOLFCRYPT_TZ_FTPM),1)
$(error WOLFCRYPT_TZ_PSA and WOLFCRYPT_TZ_FTPM are mutually exclusive)
endif
endif
ifeq ($(WOLFCRYPT_TZ_PKCS11),1)
@ -919,6 +928,50 @@ ifeq ($(WOLFCRYPT_TZ_PSA),1)
endif
endif
ifeq ($(WOLFCRYPT_TZ_FTPM),1)
CFLAGS+=-DWOLFBOOT_TZ_FTPM
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/ftpm_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)

146
src/ftpm_callable.c 100644
View File

@ -0,0 +1,146 @@
/* ftpm_callable.c
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfBoot.
*/
#ifdef WOLFBOOT_TZ_FTPM
#include <stdint.h>
#include <string.h>
#include "store_sbrk.h"
#include "wolfboot/wcs_ftpm.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 ftpm_ctx;
static int ftpm_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_FTPM_NV_SIZE (16U * 1024U)
static uint8_t ftpm_nv[WCS_FTPM_NV_SIZE];
static int ftpm_nv_read(void *ctx, word32 offset, byte *buf, word32 size)
{
uint8_t *nv = (uint8_t *)ctx;
if (nv == NULL || buf == NULL || offset > WCS_FTPM_NV_SIZE ||
size > (WCS_FTPM_NV_SIZE - offset)) {
return BAD_FUNC_ARG;
}
XMEMCPY(buf, nv + offset, size);
return TPM_RC_SUCCESS;
}
static int ftpm_nv_write(void *ctx, word32 offset, const byte *buf,
word32 size)
{
uint8_t *nv = (uint8_t *)ctx;
if (nv == NULL || buf == NULL || offset > WCS_FTPM_NV_SIZE ||
size > (WCS_FTPM_NV_SIZE - offset)) {
return BAD_FUNC_ARG;
}
XMEMCPY(nv + offset, buf, size);
return TPM_RC_SUCCESS;
}
static int ftpm_nv_erase(void *ctx, word32 offset, word32 size)
{
uint8_t *nv = (uint8_t *)ctx;
if (nv == NULL || offset > WCS_FTPM_NV_SIZE ||
size > (WCS_FTPM_NV_SIZE - offset)) {
return BAD_FUNC_ARG;
}
XMEMSET(nv + offset, 0xFF, size);
return TPM_RC_SUCCESS;
}
static FWTPM_NV_HAL ftpm_nv_hal = {
ftpm_nv_read,
ftpm_nv_write,
ftpm_nv_erase,
ftpm_nv,
WCS_FTPM_NV_SIZE
};
#endif /* !FWTPM_NO_NV */
static uint32_t ftpm_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_ftpm_init(void)
{
int rc;
#ifndef FWTPM_NO_NV
XMEMSET(ftpm_nv, 0xFF, sizeof(ftpm_nv));
#endif
XMEMSET(&ftpm_ctx, 0, sizeof(ftpm_ctx));
#ifndef FWTPM_NO_NV
(void)FWTPM_NV_SetHAL(&ftpm_ctx, &ftpm_nv_hal);
#endif
rc = FWTPM_Init(&ftpm_ctx);
if (rc == 0) {
ftpm_ctx.wasStarted = 1;
ftpm_ready = 1;
}
}
int CSME_NSE_API wcs_ftpm_transmit(const uint8_t *cmd, uint32_t cmdSz,
uint8_t *rsp, uint32_t *rspSz)
{
int rspLen;
if (!ftpm_ready) {
return TPM_RC_INITIALIZE;
}
if (cmd == NULL || rsp == NULL || rspSz == NULL || cmdSz == 0U ||
cmdSz > WCS_FTPM_MAX_COMMAND_SIZE || *rspSz == 0U ||
*rspSz > WCS_FTPM_MAX_COMMAND_SIZE) {
return BAD_FUNC_ARG;
}
rspLen = (int)*rspSz;
int rc = FWTPM_ProcessCommand(&ftpm_ctx, cmd, (int)cmdSz, rsp, &rspLen, 0);
if (rc >= 0) {
uint32_t wireSz = ftpm_rsp_size(rsp, rspLen);
if (wireSz > 0U && wireSz <= *rspSz) {
*rspSz = wireSz;
rc = TPM_RC_SUCCESS;
}
else if (rspLen >= 0) {
*rspSz = (uint32_t)rspLen;
}
}
return rc;
}
#endif /* WOLFBOOT_TZ_FTPM */

View File

@ -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_FTPM)
if (wolfBoot_tpm2_init() != 0) {
wolfBoot_panic();
}

View File

@ -30,6 +30,10 @@
#include "hal.h"
#include <stdint.h>
#ifdef WOLFBOOT_TZ_FTPM
#include "wolfboot/wcs_ftpm.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_FTPM
wcs_ftpm_init();
#endif
}
#endif /* WOLFCRYPT_SECURE_MODE */

View File

@ -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_FTPM),1)
WOLFCRYPT_TZ=1
WOLFCRYPT_TZ_FTPM=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_FTPM),1)
CFLAGS:=$(filter-out -DWOLFTPM_FWTPM,$(CFLAGS))
CFLAGS+=-DWOLFBOOT_TZ_FTPM -DWOLFBOOT_TPM -DWOLFTPM_ADV_IO
CFLAGS+=-DWOLFTPM_EXAMPLE_HAL
CFLAGS+=-I"$(WOLFBOOT_LIB_WOLFTPM)"
APP_OBJS+=./wcs/ftpm_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

View File

@ -36,10 +36,15 @@
#endif
#include "target.h"
#ifdef WOLFBOOT_TPM
#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FTPM)
#include "tpm.h"
#endif
#ifdef WOLFBOOT_TZ_FTPM
#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_FTPM)
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_FTPM
static int cmd_ftpm_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_FTPM)
{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_FTPM
{cmd_ftpm_test, "ftpm", "run fTPM 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_FTPM)
#include <wolftpm/tpm2.h>
#include <wolftpm/tpm2_wrap.h>
@ -1119,7 +1130,221 @@ static int cmd_tpm_quote(const char *args)
return rc;
}
#endif /* WOLFTPM_MFG_IDENTITY */
#endif /* WOLFBOOT_TPM */
#endif /* WOLFBOOT_TPM && !WOLFBOOT_TZ_FTPM */
#ifdef WOLFBOOT_TZ_FTPM
extern int TPM2_IoCb_FtpmNsc(TPM2_CTX *ctx, INT32 isRead, UINT32 addr,
BYTE *buf, UINT16 size, void *userCtx);
static int ftpm_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 ftpm_seal_unseal_pcr_secret(WOLFTPM2_DEV *dev)
{
static const uint8_t secret[] = "wolfBoot fTPM 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("fTPM 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("fTPM 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("fTPM unseal failed: 0x%x\r\n", rc);
return rc;
}
if (unsealOut.outData.size != sizeof(secret) ||
XMEMCMP(unsealOut.outData.buffer, secret, sizeof(secret)) != 0) {
printf("fTPM unsealed secret mismatch\r\n");
return TPM_RC_FAILURE;
}
printf("fTPM unsealed secret: %.*s\r\n",
unsealOut.outData.size, unsealOut.outData.buffer);
return TPM_RC_SUCCESS;
}
static int cmd_ftpm_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_FtpmNsc, NULL);
if (rc != TPM_RC_SUCCESS) {
printf("fTPM init failed: 0x%x\r\n", rc);
return rc;
}
rc = wolfTPM2_GetCapabilities(&dev, &caps);
if (rc == TPM_RC_SUCCESS) {
printf("fTPM 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("fTPM random:");
print_hex(rnd, sizeof(rnd), 0);
}
else {
printf("fTPM 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) {
rc = wc_Sha256Hash((const uint8_t *)"wolfBoot fTPM PCR event",
23, pcrEvent);
}
if (rc == TPM_RC_SUCCESS) {
rc = ftpm_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("fTPM 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("fTPM PCR0 extend mismatch\r\n");
rc = TPM_RC_FAILURE;
}
if (rc == TPM_RC_SUCCESS) {
rc = ftpm_seal_unseal_pcr_secret(&dev);
}
wolfTPM2_Cleanup(&dev);
if (rc == TPM_RC_SUCCESS) {
printf("fTPM NSC tests passed\r\n");
}
else {
printf("fTPM NSC tests failed: 0x%x\r\n", rc);
}
return rc;
}
#endif /* WOLFBOOT_TZ_FTPM */
static int parse_cmd(const char *cmd)
@ -1268,9 +1493,16 @@ void main(void)
#endif
cmd_info(NULL);
#ifdef WOLFBOOT_TPM
#if defined(WOLFBOOT_TPM) && !defined(WOLFBOOT_TZ_FTPM)
cmd_tpm_info(NULL);
#endif
#ifdef WOLFBOOT_TZ_FTPM
ret = cmd_ftpm_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();

View File

@ -0,0 +1,208 @@
/* ftpm_stub.c
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfBoot.
*/
#ifdef WOLFBOOT_TZ_FTPM
#include <stdint.h>
#include <string.h>
#include "wolfboot/wcs_ftpm.h"
#include "wolftpm/tpm2.h"
#include "wolftpm/tpm2_tis.h"
#define FTPM_TIS_BASE 0xD40000U
#define FTPM_TIS_ACCESS 0x0000U
#define FTPM_TIS_INTF_CAPS 0x0014U
#define FTPM_TIS_STS 0x0018U
#define FTPM_TIS_BURST_COUNT 0x0019U
#define FTPM_TIS_DATA_FIFO 0x0024U
#define FTPM_TIS_DID_VID 0x0F00U
#define FTPM_TIS_RID 0x0F04U
#define FTPM_ACCESS_VALID 0x80U
#define FTPM_ACCESS_ACTIVE_LOCALITY 0x20U
#define FTPM_ACCESS_REQUEST_USE 0x02U
#define FTPM_STS_VALID 0x80U
#define FTPM_STS_COMMAND_READY 0x40U
#define FTPM_STS_GO 0x20U
#define FTPM_STS_DATA_AVAIL 0x10U
#define FTPM_STS_DATA_EXPECT 0x08U
#define FTPM_BURST_COUNT 64U
struct ftpm_tis_state {
uint8_t cmd[WCS_FTPM_MAX_COMMAND_SIZE];
uint8_t rsp[WCS_FTPM_MAX_COMMAND_SIZE];
uint32_t cmdSz;
uint32_t rspSz;
uint32_t rspPos;
uint8_t locality;
uint8_t status;
};
static struct ftpm_tis_state ftpm_tis = {
{0}, {0}, 0, 0, 0, 0,
FTPM_STS_VALID | FTPM_STS_COMMAND_READY
};
static uint32_t ftpm_reg_offset(uint32_t addr)
{
return (addr - FTPM_TIS_BASE) & 0x0FFFU;
}
static void ftpm_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 ftpm_cmd_size(void)
{
if (ftpm_tis.cmdSz < TPM2_HEADER_SIZE) {
return TPM2_HEADER_SIZE;
}
return ((uint32_t)ftpm_tis.cmd[2] << 24) |
((uint32_t)ftpm_tis.cmd[3] << 16) |
((uint32_t)ftpm_tis.cmd[4] << 8) |
(uint32_t)ftpm_tis.cmd[5];
}
static int ftpm_execute(void)
{
int rc;
ftpm_tis.rspSz = sizeof(ftpm_tis.rsp);
ftpm_tis.rspPos = 0;
rc = wcs_ftpm_transmit(ftpm_tis.cmd, ftpm_tis.cmdSz, ftpm_tis.rsp,
&ftpm_tis.rspSz);
ftpm_tis.cmdSz = 0;
if (rc == TPM_RC_SUCCESS) {
ftpm_tis.status = FTPM_STS_VALID | FTPM_STS_DATA_AVAIL;
}
else {
ftpm_tis.rspSz = 0;
ftpm_tis.status = FTPM_STS_VALID | FTPM_STS_COMMAND_READY;
}
return rc;
}
int TPM2_IoCb_FtpmNsc(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 || addr < FTPM_TIS_BASE) {
return BAD_FUNC_ARG;
}
off = ftpm_reg_offset(addr);
burst = FTPM_BURST_COUNT;
if (isRead) {
switch (off) {
case FTPM_TIS_ACCESS:
buf[0] = FTPM_ACCESS_VALID | FTPM_ACCESS_ACTIVE_LOCALITY;
break;
case FTPM_TIS_STS:
XMEMSET(buf, 0, size);
buf[0] = ftpm_tis.status;
if (size > 1U) {
buf[1] = (uint8_t)burst;
}
if (size > 2U) {
buf[2] = (uint8_t)(burst >> 8);
}
break;
case FTPM_TIS_BURST_COUNT:
ftpm_store_le(buf, size, burst);
break;
case FTPM_TIS_BURST_COUNT + 1U:
ftpm_store_le(buf, size, burst >> 8);
break;
case FTPM_TIS_DATA_FIFO:
if (ftpm_tis.rspPos + size > ftpm_tis.rspSz) {
return TPM_RC_FAILURE;
}
XMEMCPY(buf, ftpm_tis.rsp + ftpm_tis.rspPos, size);
ftpm_tis.rspPos += size;
if (ftpm_tis.rspPos >= ftpm_tis.rspSz) {
ftpm_tis.status = FTPM_STS_VALID | FTPM_STS_COMMAND_READY;
}
break;
case FTPM_TIS_INTF_CAPS:
ftpm_store_le(buf, size, 0x00000183U);
break;
case FTPM_TIS_DID_VID:
ftpm_store_le(buf, size, 0x00011B4EU);
break;
case FTPM_TIS_RID:
buf[0] = 0x01U;
break;
default:
XMEMSET(buf, 0, size);
break;
}
}
else {
switch (off) {
case FTPM_TIS_ACCESS:
if ((buf[0] & FTPM_ACCESS_REQUEST_USE) != 0U) {
ftpm_tis.locality = 0;
}
break;
case FTPM_TIS_STS:
if ((buf[0] & FTPM_STS_COMMAND_READY) != 0U) {
ftpm_tis.cmdSz = 0;
ftpm_tis.rspSz = 0;
ftpm_tis.rspPos = 0;
ftpm_tis.status = FTPM_STS_VALID |
FTPM_STS_COMMAND_READY;
}
else if ((buf[0] & FTPM_STS_GO) != 0U) {
return ftpm_execute();
}
break;
case FTPM_TIS_DATA_FIFO:
if (ftpm_tis.cmdSz + size > sizeof(ftpm_tis.cmd)) {
return TPM_RC_FAILURE;
}
XMEMCPY(ftpm_tis.cmd + ftpm_tis.cmdSz, buf, size);
ftpm_tis.cmdSz += size;
if (ftpm_tis.cmdSz < ftpm_cmd_size()) {
ftpm_tis.status = FTPM_STS_VALID | FTPM_STS_DATA_EXPECT;
}
else {
ftpm_tis.status = FTPM_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_FtpmNsc(ctx, isRead, addr, buf, size, userCtx);
}
#endif /* WOLFBOOT_TZ_FTPM */

View File

@ -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_FTPM)
static inline int wcs_cmse_get_random(unsigned char* output, int sz)
{

View File

@ -66,6 +66,7 @@ ifeq ($(ARCH),)
WOLFCRYPT_TZ?=0
WOLFCRYPT_TZ_PKCS11?=0
WOLFCRYPT_TZ_PSA?=0
WOLFCRYPT_TZ_FTPM?=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_FTPM \
WOLFBOOT_PARTITION_SIZE WOLFBOOT_SECTOR_SIZE \
WOLFBOOT_PARTITION_BOOT_ADDRESS WOLFBOOT_PARTITION_UPDATE_ADDRESS \
WOLFBOOT_PARTITION_SWAP_ADDRESS WOLFBOOT_LOAD_ADDRESS \