From 801ae8f1ca06fa46bcf5631bf2d3879f2047633d Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 17 Jun 2026 14:34:12 +0200 Subject: [PATCH 1/8] tpm: DevId identity allow to use precomputed auth values Allow to either use a master different that the sample one or to directly use the pre-computed per-device auth values for EH and AIK. Using the per-device value is preferred as it doesn't expose the auth value of the sibling devices in the same fleet. --- docs/TPM.md | 36 ++++++++++++++++++++++++++++++++++++ include/tpm.h | 31 +++++++++++++++++++++++++++++++ options.mk | 6 ++++++ src/tpm.c | 43 +++++++++++++++++++++++++++++++++++-------- tools/config.mk | 2 ++ 5 files changed, 110 insertions(+), 8 deletions(-) diff --git a/docs/TPM.md b/docs/TPM.md index 94fd77f2af..228b03f29c 100644 --- a/docs/TPM.md +++ b/docs/TPM.md @@ -17,6 +17,42 @@ In wolfBoot we support TPM based root of trust, sealing/unsealing, cryptographic | `WOLFBOOT_TPM_SEAL=1` | `WOLFBOOT_TPM_SEAL` | Enables support for sealing/unsealing based on PCR policy signed externally. | | `WOLFBOOT_TPM_SEAL_NV_BASE=0x01400300` | `WOLFBOOT_TPM_SEAL_NV_BASE` | To override the default sealed blob storage location in the platform hierarchy. | | `WOLFBOOT_TPM_SEAL_AUTH=secret` | `WOLFBOOT_TPM_SEAL_AUTH` | Password for sealing/unsealing secrets, if omitted the PCR policy will be used | +| `WOLFBOOT_TPM_MFG_AUTH_DERIVE=1` | `WOLFBOOT_TPM_MFG_AUTH_DERIVE` | MFG identity: opt into on-device derive-from-master. The default is a precomputed per-device authValue (no master secret on device). Requires `WOLFTPM_MFG_IDENTITY`. | +| (header macro) | `WOLFBOOT_TPM_MFG_AIK_AUTH` / `WOLFBOOT_TPM_MFG_EH_AUTH` | Default (precomputed) mode: the 16-byte per-device AIK / EH authValues (placeholder `0xFF` default). | +| (header macro) | `WOLFBOOT_TPM_MFG_EH_MASTER` | Derive mode: override the endorsement-hierarchy master value (16-byte initializer list, sample default). | + +## TPM manufacturing identity (IAK / IDevID authValue) + +When `WOLFTPM_MFG_IDENTITY` is enabled, `wolfBoot_tpm2_get_aik()` and +`wolfBoot_tpm2_get_timestamp()` authorize the pre-provisioned ST33KTPM identity +keys. There are two ways to supply the required `authValue`: + +- **Precomputed mode (default, recommended).** The final **per-device** + `authValue` is set directly into the key handle; no master secret is present on + the device. Defaults to a `0xFF` placeholder (fails TPM auth until + provisioned). Per-device values are computed off-device at provisioning + (`SHA-256(CPSN || master)`, low 16 bytes) and baked in via + `WOLFBOOT_TPM_MFG_AIK_AUTH` / `WOLFBOOT_TPM_MFG_EH_AUTH`. When `WOLFBOOT_TPM_MFG_AUTH_DERIVE` + is not enabled, the `masterPassword` argument to `wolfBoot_tpm2_get_aik()` is + treated as an optional override for the final AIK `authValue` (not a master secret). + +- **Derive mode (`WOLFBOOT_TPM_MFG_AUTH_DERIVE`).** The `authValue` is computed + on-device as the low 16 bytes of `SHA-256(TPM serial || master)`. + The endorsement master defaults to a sample and is overridable with + `WOLFBOOT_TPM_MFG_EH_MASTER`; the AIK master is passed to + `wolfBoot_tpm2_get_aik()` (NULL = sample). Convenient, but the master is + **shared across the whole reel/batch** — extracting it + from one device's firmware lets an attacker derive the `authValue` for every + sibling device. + +The byte-array macros are header defaults (overridable via `-D` / `CFLAGS_EXTRA`); +they are not plain `options.mk` variables because brace initializers contain +commas. `WOLFTPM_MFG_IDENTITY` itself is supplied via `CFLAGS_EXTRA`. + +> Note: because precomputed mode is the default and ships a `0xFF` placeholder, a +> build that enables `WOLFTPM_MFG_IDENTITY` without provisioning the authValue (or +> selecting `WOLFBOOT_TPM_MFG_AUTH_DERIVE`) fails TPM auth by design. The test-app +> builds with `WOLFBOOT_TPM_MFG_AUTH_DERIVE` so it works on a sample TPM. ## Root of Trust (ROT) diff --git a/include/tpm.h b/include/tpm.h index 08cd104468..c119828813 100644 --- a/include/tpm.h +++ b/include/tpm.h @@ -60,6 +60,37 @@ int CSME_NSE_API wolfBoot_tpm2_read_pcr(uint8_t pcrIndex, uint8_t* digest, int* int CSME_NSE_API wolfBoot_tpm2_read_cert(uint32_t handle, uint8_t* cert, uint32_t* certSz); #ifdef WOLFTPM_MFG_IDENTITY + +/* MFG identity auth provisioning. + * Precomputed mode (default): the final per-device authValue is set directly, + * no master secret on the device. In this mode, wolfBoot_tpm2_get_aik() treats + * the masterPassword argument as an optional *authValue* override. + * Derive mode (WOLFBOOT_TPM_MFG_AUTH_DERIVE): authValue = low 16 bytes of + * SHA-256(TPM serial || master); the master is shared across the reel. + * For wolfBott_tpm2_get_aik() the master password is provided via the + * masterPassword argument (NULL = sample). */ +#ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE +/* EH master for derive mode (sample - override in production) */ +#ifndef WOLFBOOT_TPM_MFG_EH_MASTER +#define WOLFBOOT_TPM_MFG_EH_MASTER { \ + 0xDE, 0xEF, 0x8C, 0xDF, 0x1B, 0x77, 0xBD, 0x00, \ + 0x30, 0x58, 0x5E, 0x47, 0xB8, 0x21, 0x46, 0x0B } +#endif +#else +/* 16-byte per-device authValues. Placeholder defaults (all 0xFF) fail TPM auth + * until overwritten per-device by the provisioning tool. */ +#ifndef WOLFBOOT_TPM_MFG_AIK_AUTH +#define WOLFBOOT_TPM_MFG_AIK_AUTH { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } +#endif +#ifndef WOLFBOOT_TPM_MFG_EH_AUTH +#define WOLFBOOT_TPM_MFG_EH_AUTH { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } +#endif +#endif + int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik, uint8_t* masterPassword, uint16_t masterPasswordSz); int CSME_NSE_API wolfBoot_tpm2_get_timestamp(WOLFTPM2_KEY* aik, GetTime_Out* getTime); diff --git a/options.mk b/options.mk index 37f676d797..b6b18a5af0 100644 --- a/options.mk +++ b/options.mk @@ -58,6 +58,12 @@ ifeq ($(WOLFBOOT_TPM_KEYSTORE),1) endif endif +## TPM manufacturing identity: precomputed per-device authValue is the default +## (no master secret on device). Opt into on-device derive-from-master mode: +ifeq ($(WOLFBOOT_TPM_MFG_AUTH_DERIVE),1) + CFLAGS+=-D"WOLFBOOT_TPM_MFG_AUTH_DERIVE" +endif + ifeq ($(WOLFBOOT_ATTESTATION_IAK),1) CFLAGS+=-D"WOLFBOOT_ATTESTATION_IAK" endif diff --git a/src/tpm.c b/src/tpm.c index 6a11aad253..c4fcea4b36 100644 --- a/src/tpm.c +++ b/src/tpm.c @@ -1363,11 +1363,26 @@ int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik, /* Load existing AIK and set auth */ rc = wolfTPM2_ReadPublicKey(&wolftpm_dev, aik, TPM2_IAK_KEY_HANDLE); if (rc == 0) { - /* Custom should supply their own custom master password used during - * device provisioning. If using a sample TPM supply NULL to use the - * default password. */ +#ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE + /* Derives the authValue on-device from a master secret shared across the + * reel; the precomputed default is preferred. Supply NULL for + * masterPassword to use the sample default. */ rc = wolfTPM2_SetIdentityAuth(&wolftpm_dev, &aik->handle, masterPassword, masterPasswordSz); +#else + /* Precomputed (default): set the final per-device authValue directly (no + * master secret on device). Caller may override the default via + * masterPassword. */ + static const uint8_t aikAuth[] = WOLFBOOT_TPM_MFG_AIK_AUTH; + const uint8_t* auth = (masterPassword != NULL) ? masterPassword : aikAuth; + uint16_t authSz = (masterPassword != NULL) ? + masterPasswordSz : (uint16_t)sizeof(aikAuth); + if (authSz > (uint16_t)sizeof(aik->handle.auth.buffer)) { + return BAD_FUNC_ARG; + } + aik->handle.auth.size = authSz; + XMEMCPY(aik->handle.auth.buffer, auth, authSz); +#endif } return rc; } @@ -1376,11 +1391,13 @@ int CSME_NSE_API wolfBoot_tpm2_get_timestamp(WOLFTPM2_KEY* aik, GetTime_Out* get { int rc; WOLFTPM2_HANDLE eh_handle; - /* sample master password for EH */ - uint8_t Master_EH_AuthValue[] = { - 0xDE, 0xEF, 0x8C, 0xDF, 0x1B, 0x77, 0xBD, 0x00, - 0x30, 0x58, 0x5E, 0x47, 0xB8, 0x21, 0x46, 0x0B - }; +#ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE + /* EH master secret (shared across the reel) */ + uint8_t Master_EH_AuthValue[] = WOLFBOOT_TPM_MFG_EH_MASTER; +#else + /* final per-device EH authValue */ + static const uint8_t eh_auth[] = WOLFBOOT_TPM_MFG_EH_AUTH; +#endif if (aik == NULL || getTime == NULL) { return BAD_FUNC_ARG; @@ -1395,9 +1412,19 @@ int CSME_NSE_API wolfBoot_tpm2_get_timestamp(WOLFTPM2_KEY* aik, GetTime_Out* get eh_handle.hndl = TPM_RH_ENDORSEMENT; +#ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE /* Calculate EH auth value */ rc = wolfTPM2_SetIdentityAuth(&wolftpm_dev, &eh_handle, Master_EH_AuthValue, (uint16_t)sizeof(Master_EH_AuthValue)); +#else + /* Set EH authValue directly */ + if (sizeof(eh_auth) > sizeof(eh_handle.auth.buffer)) { + return BAD_FUNC_ARG; + } + eh_handle.auth.size = (uint16_t)sizeof(eh_auth); + XMEMCPY(eh_handle.auth.buffer, eh_auth, sizeof(eh_auth)); + rc = 0; +#endif if (rc == 0) { /* Set EH auth */ wolfTPM2_SetAuthHandle(&wolftpm_dev, 0, &eh_handle); diff --git a/tools/config.mk b/tools/config.mk index 98aa0dcae2..59d830f641 100644 --- a/tools/config.mk +++ b/tools/config.mk @@ -58,6 +58,7 @@ ifeq ($(ARCH),) MEASURED_BOOT?=0 WOLFBOOT_TPM_SEAL?=0 WOLFBOOT_TPM_KEYSTORE?=0 + WOLFBOOT_TPM_MFG_AUTH_DERIVE?=0 WOLFBOOT_ATTESTATION_IAK?=0 WOLFBOOT_ATTESTATION_TEST?=0 WOLFBOOT_UNIVERSAL_KEYSTORE?=0 @@ -106,6 +107,7 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO DISABLE_BACKUP WOLFBOOT_VERSION V NO_MPU ENCRYPT FLAGS_HOME FLAGS_INVERT \ SPMATH SPMATHALL RAM_CODE DUALBANK_SWAP IMAGE_HEADER_SIZE PKA TZEN PSOC6_CRYPTO \ WOLFTPM WOLFBOOT_TPM_VERIFY MEASURED_BOOT WOLFBOOT_TPM_SEAL WOLFBOOT_TPM_KEYSTORE \ + WOLFBOOT_TPM_MFG_AUTH_DERIVE \ WOLFBOOT_ATTESTATION_IAK \ WOLFBOOT_ATTESTATION_TEST \ WOLFBOOT_UDS_UID_FALLBACK_FORTEST \ From dd4387e62d7200f32fe5e2315004a4d63b1efa20 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 17 Jun 2026 15:11:16 +0200 Subject: [PATCH 2/8] config: example: stm32h5 tpm IDevId example --- config/examples/stm32h5-tz-tpm-mfgid.config | 44 +++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 config/examples/stm32h5-tz-tpm-mfgid.config diff --git a/config/examples/stm32h5-tz-tpm-mfgid.config b/config/examples/stm32h5-tz-tpm-mfgid.config new file mode 100644 index 0000000000..aec830f0ad --- /dev/null +++ b/config/examples/stm32h5-tz-tpm-mfgid.config @@ -0,0 +1,44 @@ +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_PKCS11=1 +IMAGE_HEADER_SIZE?=1024 +ARMORED=1 +WOLFTPM=1 +# Exercise the pre-provisioned ST33KTPM identity keys (IAK/IDevID). +# ST33 vendor support is required (wolfTPM2_SetIdentityAuth -> TPM2_GetProductInfo). +CFLAGS_EXTRA+=-DWOLFTPM_ST33 +CFLAGS_EXTRA+=-DWOLFTPM_MFG_IDENTITY +# Derive the authValue on-device so the test-app works on a sample TPM. The +# default precomputed mode ships a 0xFF placeholder that must be provisioned +# per-device first. +WOLFBOOT_TPM_MFG_AUTH_DERIVE=1 From 8518eabc23f944d54c81c446e0e7166459bb62b4 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 18 Jun 2026 10:45:02 +0200 Subject: [PATCH 3/8] tpm: fix wolfBoot_tpm2_get_aik typo in header comment --- include/tpm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/tpm.h b/include/tpm.h index c119828813..d3b05092b8 100644 --- a/include/tpm.h +++ b/include/tpm.h @@ -67,7 +67,7 @@ int CSME_NSE_API wolfBoot_tpm2_read_cert(uint32_t handle, uint8_t* cert, uint32_ * the masterPassword argument as an optional *authValue* override. * Derive mode (WOLFBOOT_TPM_MFG_AUTH_DERIVE): authValue = low 16 bytes of * SHA-256(TPM serial || master); the master is shared across the reel. - * For wolfBott_tpm2_get_aik() the master password is provided via the + * For wolfBoot_tpm2_get_aik() the master password is provided via the * masterPassword argument (NULL = sample). */ #ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE /* EH master for derive mode (sample - override in production) */ From cb56e866b687a357ad32c3a6e5709c916fb63b46 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 18 Jun 2026 10:45:13 +0200 Subject: [PATCH 4/8] tpm: remove trailing whitespace in MFG identity docs --- docs/TPM.md | 4 ++-- include/tpm.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/TPM.md b/docs/TPM.md index 228b03f29c..739562dde6 100644 --- a/docs/TPM.md +++ b/docs/TPM.md @@ -32,12 +32,12 @@ keys. There are two ways to supply the required `authValue`: the device. Defaults to a `0xFF` placeholder (fails TPM auth until provisioned). Per-device values are computed off-device at provisioning (`SHA-256(CPSN || master)`, low 16 bytes) and baked in via - `WOLFBOOT_TPM_MFG_AIK_AUTH` / `WOLFBOOT_TPM_MFG_EH_AUTH`. When `WOLFBOOT_TPM_MFG_AUTH_DERIVE` + `WOLFBOOT_TPM_MFG_AIK_AUTH` / `WOLFBOOT_TPM_MFG_EH_AUTH`. When `WOLFBOOT_TPM_MFG_AUTH_DERIVE` is not enabled, the `masterPassword` argument to `wolfBoot_tpm2_get_aik()` is treated as an optional override for the final AIK `authValue` (not a master secret). - **Derive mode (`WOLFBOOT_TPM_MFG_AUTH_DERIVE`).** The `authValue` is computed - on-device as the low 16 bytes of `SHA-256(TPM serial || master)`. + on-device as the low 16 bytes of `SHA-256(TPM serial || master)`. The endorsement master defaults to a sample and is overridable with `WOLFBOOT_TPM_MFG_EH_MASTER`; the AIK master is passed to `wolfBoot_tpm2_get_aik()` (NULL = sample). Convenient, but the master is diff --git a/include/tpm.h b/include/tpm.h index d3b05092b8..3a609dd8ec 100644 --- a/include/tpm.h +++ b/include/tpm.h @@ -66,7 +66,7 @@ int CSME_NSE_API wolfBoot_tpm2_read_cert(uint32_t handle, uint8_t* cert, uint32_ * no master secret on the device. In this mode, wolfBoot_tpm2_get_aik() treats * the masterPassword argument as an optional *authValue* override. * Derive mode (WOLFBOOT_TPM_MFG_AUTH_DERIVE): authValue = low 16 bytes of - * SHA-256(TPM serial || master); the master is shared across the reel. + * SHA-256(TPM serial || master); the master is shared across the reel. * For wolfBoot_tpm2_get_aik() the master password is provided via the * masterPassword argument (NULL = sample). */ #ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE From f9cad20f5bf036a59231406c99a44b907bf71d39 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 18 Jun 2026 10:45:40 +0200 Subject: [PATCH 5/8] tpm: zeroize EH master secret after derive --- src/tpm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tpm.c b/src/tpm.c index c4fcea4b36..af73c21233 100644 --- a/src/tpm.c +++ b/src/tpm.c @@ -1416,6 +1416,8 @@ int CSME_NSE_API wolfBoot_tpm2_get_timestamp(WOLFTPM2_KEY* aik, GetTime_Out* get /* Calculate EH auth value */ rc = wolfTPM2_SetIdentityAuth(&wolftpm_dev, &eh_handle, Master_EH_AuthValue, (uint16_t)sizeof(Master_EH_AuthValue)); + /* master secret consumed; clear it from the stack */ + TPM2_ForceZero(Master_EH_AuthValue, sizeof(Master_EH_AuthValue)); #else /* Set EH authValue directly */ if (sizeof(eh_auth) > sizeof(eh_handle.auth.buffer)) { From 68c797db72079806034166f04200c22ad7635814 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 18 Jun 2026 10:46:40 +0200 Subject: [PATCH 6/8] tpm: dedupe precomputed authValue handle copy --- src/tpm.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/tpm.c b/src/tpm.c index af73c21233..6186337134 100644 --- a/src/tpm.c +++ b/src/tpm.c @@ -1345,6 +1345,20 @@ int CSME_NSE_API wolfBoot_tpm2_read_cert(uint32_t handle, uint8_t* cert, uint32_ } #ifdef WOLFTPM_MFG_IDENTITY +#ifndef WOLFBOOT_TPM_MFG_AUTH_DERIVE +/* Copy a precomputed authValue directly into a TPM handle. */ +static int wolfBoot_tpm2_set_handle_auth(WOLFTPM2_HANDLE* handle, + const uint8_t* auth, uint16_t authSz) +{ + if (authSz > (uint16_t)sizeof(handle->auth.buffer)) { + return BAD_FUNC_ARG; + } + handle->auth.size = authSz; + XMEMCPY(handle->auth.buffer, auth, authSz); + return 0; +} +#endif + int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik, uint8_t* masterPassword, uint16_t masterPasswordSz) { @@ -1377,11 +1391,7 @@ int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik, const uint8_t* auth = (masterPassword != NULL) ? masterPassword : aikAuth; uint16_t authSz = (masterPassword != NULL) ? masterPasswordSz : (uint16_t)sizeof(aikAuth); - if (authSz > (uint16_t)sizeof(aik->handle.auth.buffer)) { - return BAD_FUNC_ARG; - } - aik->handle.auth.size = authSz; - XMEMCPY(aik->handle.auth.buffer, auth, authSz); + rc = wolfBoot_tpm2_set_handle_auth(&aik->handle, auth, authSz); #endif } return rc; @@ -1420,12 +1430,8 @@ int CSME_NSE_API wolfBoot_tpm2_get_timestamp(WOLFTPM2_KEY* aik, GetTime_Out* get TPM2_ForceZero(Master_EH_AuthValue, sizeof(Master_EH_AuthValue)); #else /* Set EH authValue directly */ - if (sizeof(eh_auth) > sizeof(eh_handle.auth.buffer)) { - return BAD_FUNC_ARG; - } - eh_handle.auth.size = (uint16_t)sizeof(eh_auth); - XMEMCPY(eh_handle.auth.buffer, eh_auth, sizeof(eh_auth)); - rc = 0; + rc = wolfBoot_tpm2_set_handle_auth(&eh_handle, eh_auth, + (uint16_t)sizeof(eh_auth)); #endif if (rc == 0) { /* Set EH auth */ From 723fffebc8592188387638f2766cfe929b4f7707 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 18 Jun 2026 10:47:12 +0200 Subject: [PATCH 7/8] tpm: build MFG identity configs in CI --- .github/workflows/test-configs.yml | 12 +++++ .../stm32h5-tz-tpm-mfgid-precomputed.config | 44 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 config/examples/stm32h5-tz-tpm-mfgid-precomputed.config diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index 91d517fa29..13503fd2e4 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -518,6 +518,18 @@ jobs: arch: arm config-file: ./config/examples/stm32h5-tz-tpm.config + stm32h5_tz_tpm_mfgid_test: + uses: ./.github/workflows/test-build.yml + with: + arch: arm + config-file: ./config/examples/stm32h5-tz-tpm-mfgid.config + + stm32h5_tz_tpm_mfgid_precomputed_test: + uses: ./.github/workflows/test-build.yml + with: + arch: arm + config-file: ./config/examples/stm32h5-tz-tpm-mfgid-precomputed.config + stm32h5_tz_dualbank_test: uses: ./.github/workflows/test-build.yml with: diff --git a/config/examples/stm32h5-tz-tpm-mfgid-precomputed.config b/config/examples/stm32h5-tz-tpm-mfgid-precomputed.config new file mode 100644 index 0000000000..2a661e4c2e --- /dev/null +++ b/config/examples/stm32h5-tz-tpm-mfgid-precomputed.config @@ -0,0 +1,44 @@ +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_PKCS11=1 +IMAGE_HEADER_SIZE?=1024 +ARMORED=1 +WOLFTPM=1 +# Exercise the pre-provisioned ST33KTPM identity keys (IAK/IDevID). +# ST33 vendor support is required (wolfTPM2_SetIdentityAuth -> TPM2_GetProductInfo). +CFLAGS_EXTRA+=-DWOLFTPM_ST33 +CFLAGS_EXTRA+=-DWOLFTPM_MFG_IDENTITY +# Default precomputed mode (WOLFBOOT_TPM_MFG_AUTH_DERIVE unset): the per-device +# authValue is set directly from the WOLFBOOT_TPM_MFG_AIK_AUTH/EH_AUTH macros. +# Ships a 0xFF placeholder that fails TPM auth until provisioned per-device; this +# config exists to build-test the precomputed branch in CI. From 0438c54c9b28d8310dd7812310cb890ae7a9adba Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 18 Jun 2026 10:45:57 +0200 Subject: [PATCH 8/8] tpm: rename masterPassword param to authOverride --- docs/TPM.md | 2 +- include/tpm.h | 11 +++++++---- src/tpm.c | 18 +++++++++--------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/TPM.md b/docs/TPM.md index 739562dde6..c25b279536 100644 --- a/docs/TPM.md +++ b/docs/TPM.md @@ -33,7 +33,7 @@ keys. There are two ways to supply the required `authValue`: provisioned). Per-device values are computed off-device at provisioning (`SHA-256(CPSN || master)`, low 16 bytes) and baked in via `WOLFBOOT_TPM_MFG_AIK_AUTH` / `WOLFBOOT_TPM_MFG_EH_AUTH`. When `WOLFBOOT_TPM_MFG_AUTH_DERIVE` - is not enabled, the `masterPassword` argument to `wolfBoot_tpm2_get_aik()` is + is not enabled, the `authOverride` argument to `wolfBoot_tpm2_get_aik()` is treated as an optional override for the final AIK `authValue` (not a master secret). - **Derive mode (`WOLFBOOT_TPM_MFG_AUTH_DERIVE`).** The `authValue` is computed diff --git a/include/tpm.h b/include/tpm.h index 3a609dd8ec..7802f734dd 100644 --- a/include/tpm.h +++ b/include/tpm.h @@ -64,11 +64,11 @@ int CSME_NSE_API wolfBoot_tpm2_read_cert(uint32_t handle, uint8_t* cert, uint32_ /* MFG identity auth provisioning. * Precomputed mode (default): the final per-device authValue is set directly, * no master secret on the device. In this mode, wolfBoot_tpm2_get_aik() treats - * the masterPassword argument as an optional *authValue* override. + * the authOverride argument as an optional *authValue* override. * Derive mode (WOLFBOOT_TPM_MFG_AUTH_DERIVE): authValue = low 16 bytes of * SHA-256(TPM serial || master); the master is shared across the reel. - * For wolfBoot_tpm2_get_aik() the master password is provided via the - * masterPassword argument (NULL = sample). */ + * For wolfBoot_tpm2_get_aik() the master secret is provided via the + * authOverride argument (NULL = sample). */ #ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE /* EH master for derive mode (sample - override in production) */ #ifndef WOLFBOOT_TPM_MFG_EH_MASTER @@ -91,8 +91,11 @@ int CSME_NSE_API wolfBoot_tpm2_read_cert(uint32_t handle, uint8_t* cert, uint32_ #endif #endif +/* authOverride meaning depends on WOLFBOOT_TPM_MFG_AUTH_DERIVE: + * derive mode -> master secret hashed into the authValue (NULL = sample) + * precomputed mode -> optional literal authValue override (NULL = built-in) */ int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik, - uint8_t* masterPassword, uint16_t masterPasswordSz); + uint8_t* authOverride, uint16_t authOverrideSz); int CSME_NSE_API wolfBoot_tpm2_get_timestamp(WOLFTPM2_KEY* aik, GetTime_Out* getTime); int CSME_NSE_API wolfBoot_tpm2_quote(WOLFTPM2_KEY* aik, byte* pcrArray, word32 pcrArraySz, Quote_Out* quoteResult); diff --git a/src/tpm.c b/src/tpm.c index 6186337134..efb783f85b 100644 --- a/src/tpm.c +++ b/src/tpm.c @@ -1360,7 +1360,7 @@ static int wolfBoot_tpm2_set_handle_auth(WOLFTPM2_HANDLE* handle, #endif int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik, - uint8_t* masterPassword, uint16_t masterPasswordSz) + uint8_t* authOverride, uint16_t authOverrideSz) { int rc; if (aik == NULL) { @@ -1369,8 +1369,8 @@ int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik, if (WOLFBOOT_TPM_NS_RW(aik, sizeof(*aik)) == NULL) { return BAD_FUNC_ARG; } - if (masterPassword != NULL && - WOLFBOOT_TPM_NS_R(masterPassword, masterPasswordSz) == NULL) { + if (authOverride != NULL && + WOLFBOOT_TPM_NS_R(authOverride, authOverrideSz) == NULL) { return BAD_FUNC_ARG; } @@ -1380,17 +1380,17 @@ int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik, #ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE /* Derives the authValue on-device from a master secret shared across the * reel; the precomputed default is preferred. Supply NULL for - * masterPassword to use the sample default. */ + * authOverride to use the sample default. */ rc = wolfTPM2_SetIdentityAuth(&wolftpm_dev, &aik->handle, - masterPassword, masterPasswordSz); + authOverride, authOverrideSz); #else /* Precomputed (default): set the final per-device authValue directly (no * master secret on device). Caller may override the default via - * masterPassword. */ + * authOverride. */ static const uint8_t aikAuth[] = WOLFBOOT_TPM_MFG_AIK_AUTH; - const uint8_t* auth = (masterPassword != NULL) ? masterPassword : aikAuth; - uint16_t authSz = (masterPassword != NULL) ? - masterPasswordSz : (uint16_t)sizeof(aikAuth); + const uint8_t* auth = (authOverride != NULL) ? authOverride : aikAuth; + uint16_t authSz = (authOverride != NULL) ? + authOverrideSz : (uint16_t)sizeof(aikAuth); rc = wolfBoot_tpm2_set_handle_auth(&aik->handle, auth, authSz); #endif }