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.
pull/803/head
Marco Oliverio 2026-06-17 14:34:12 +02:00
parent 61fd552526
commit 801ae8f1ca
5 changed files with 110 additions and 8 deletions

View File

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

View File

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

View File

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

View File

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

View File

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