Skip to content

Commit dd4fc26

Browse files
authored
Merge pull request #803 from rizlik/tpm_mfg_auth_value
IDevID: allow using pre-computed auth values
2 parents 7a76369 + 0438c54 commit dd4fc26

8 files changed

Lines changed: 226 additions & 13 deletions

File tree

.github/workflows/test-configs.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,18 @@ jobs:
518518
arch: arm
519519
config-file: ./config/examples/stm32h5-tz-tpm.config
520520

521+
stm32h5_tz_tpm_mfgid_test:
522+
uses: ./.github/workflows/test-build.yml
523+
with:
524+
arch: arm
525+
config-file: ./config/examples/stm32h5-tz-tpm-mfgid.config
526+
527+
stm32h5_tz_tpm_mfgid_precomputed_test:
528+
uses: ./.github/workflows/test-build.yml
529+
with:
530+
arch: arm
531+
config-file: ./config/examples/stm32h5-tz-tpm-mfgid-precomputed.config
532+
521533
stm32h5_tz_dualbank_test:
522534
uses: ./.github/workflows/test-build.yml
523535
with:
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
ARCH?=ARM
2+
TZEN?=1
3+
TARGET?=stm32h5
4+
SIGN?=ECC256
5+
HASH?=SHA256
6+
DEBUG?=0
7+
VTOR?=1
8+
CORTEX_M0?=0
9+
CORTEX_M33?=1
10+
NO_ASM?=0
11+
NO_MPU=1
12+
EXT_FLASH?=0
13+
SPI_FLASH?=0
14+
ALLOW_DOWNGRADE?=0
15+
NVM_FLASH_WRITEONCE?=1
16+
WOLFBOOT_VERSION?=1
17+
V?=0
18+
SPMATH?=1
19+
RAM_CODE?=1
20+
DUALBANK_SWAP?=0
21+
WOLFBOOT_PARTITION_SIZE?=0xA0000
22+
WOLFBOOT_SECTOR_SIZE?=0x2000
23+
WOLFBOOT_KEYVAULT_ADDRESS?=0x0C040000
24+
WOLFBOOT_KEYVAULT_SIZE?=0x1C000
25+
WOLFBOOT_NSC_ADDRESS?=0x0C05C000
26+
WOLFBOOT_NSC_SIZE?=0x4000
27+
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000
28+
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C100000
29+
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0C1A0000
30+
FLAGS_HOME=0
31+
DISABLE_BACKUP=0
32+
WOLFCRYPT_TZ=1
33+
WOLFCRYPT_TZ_PKCS11=1
34+
IMAGE_HEADER_SIZE?=1024
35+
ARMORED=1
36+
WOLFTPM=1
37+
# Exercise the pre-provisioned ST33KTPM identity keys (IAK/IDevID).
38+
# ST33 vendor support is required (wolfTPM2_SetIdentityAuth -> TPM2_GetProductInfo).
39+
CFLAGS_EXTRA+=-DWOLFTPM_ST33
40+
CFLAGS_EXTRA+=-DWOLFTPM_MFG_IDENTITY
41+
# Default precomputed mode (WOLFBOOT_TPM_MFG_AUTH_DERIVE unset): the per-device
42+
# authValue is set directly from the WOLFBOOT_TPM_MFG_AIK_AUTH/EH_AUTH macros.
43+
# Ships a 0xFF placeholder that fails TPM auth until provisioned per-device; this
44+
# config exists to build-test the precomputed branch in CI.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
ARCH?=ARM
2+
TZEN?=1
3+
TARGET?=stm32h5
4+
SIGN?=ECC256
5+
HASH?=SHA256
6+
DEBUG?=0
7+
VTOR?=1
8+
CORTEX_M0?=0
9+
CORTEX_M33?=1
10+
NO_ASM?=0
11+
NO_MPU=1
12+
EXT_FLASH?=0
13+
SPI_FLASH?=0
14+
ALLOW_DOWNGRADE?=0
15+
NVM_FLASH_WRITEONCE?=1
16+
WOLFBOOT_VERSION?=1
17+
V?=0
18+
SPMATH?=1
19+
RAM_CODE?=1
20+
DUALBANK_SWAP?=0
21+
WOLFBOOT_PARTITION_SIZE?=0xA0000
22+
WOLFBOOT_SECTOR_SIZE?=0x2000
23+
WOLFBOOT_KEYVAULT_ADDRESS?=0x0C040000
24+
WOLFBOOT_KEYVAULT_SIZE?=0x1C000
25+
WOLFBOOT_NSC_ADDRESS?=0x0C05C000
26+
WOLFBOOT_NSC_SIZE?=0x4000
27+
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000
28+
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C100000
29+
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0C1A0000
30+
FLAGS_HOME=0
31+
DISABLE_BACKUP=0
32+
WOLFCRYPT_TZ=1
33+
WOLFCRYPT_TZ_PKCS11=1
34+
IMAGE_HEADER_SIZE?=1024
35+
ARMORED=1
36+
WOLFTPM=1
37+
# Exercise the pre-provisioned ST33KTPM identity keys (IAK/IDevID).
38+
# ST33 vendor support is required (wolfTPM2_SetIdentityAuth -> TPM2_GetProductInfo).
39+
CFLAGS_EXTRA+=-DWOLFTPM_ST33
40+
CFLAGS_EXTRA+=-DWOLFTPM_MFG_IDENTITY
41+
# Derive the authValue on-device so the test-app works on a sample TPM. The
42+
# default precomputed mode ships a 0xFF placeholder that must be provisioned
43+
# per-device first.
44+
WOLFBOOT_TPM_MFG_AUTH_DERIVE=1

docs/TPM.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,42 @@ In wolfBoot we support TPM based root of trust, sealing/unsealing, cryptographic
1717
| `WOLFBOOT_TPM_SEAL=1` | `WOLFBOOT_TPM_SEAL` | Enables support for sealing/unsealing based on PCR policy signed externally. |
1818
| `WOLFBOOT_TPM_SEAL_NV_BASE=0x01400300` | `WOLFBOOT_TPM_SEAL_NV_BASE` | To override the default sealed blob storage location in the platform hierarchy. |
1919
| `WOLFBOOT_TPM_SEAL_AUTH=secret` | `WOLFBOOT_TPM_SEAL_AUTH` | Password for sealing/unsealing secrets, if omitted the PCR policy will be used |
20+
| `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`. |
21+
| (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). |
22+
| (header macro) | `WOLFBOOT_TPM_MFG_EH_MASTER` | Derive mode: override the endorsement-hierarchy master value (16-byte initializer list, sample default). |
23+
24+
## TPM manufacturing identity (IAK / IDevID authValue)
25+
26+
When `WOLFTPM_MFG_IDENTITY` is enabled, `wolfBoot_tpm2_get_aik()` and
27+
`wolfBoot_tpm2_get_timestamp()` authorize the pre-provisioned ST33KTPM identity
28+
keys. There are two ways to supply the required `authValue`:
29+
30+
- **Precomputed mode (default, recommended).** The final **per-device**
31+
`authValue` is set directly into the key handle; no master secret is present on
32+
the device. Defaults to a `0xFF` placeholder (fails TPM auth until
33+
provisioned). Per-device values are computed off-device at provisioning
34+
(`SHA-256(CPSN || master)`, low 16 bytes) and baked in via
35+
`WOLFBOOT_TPM_MFG_AIK_AUTH` / `WOLFBOOT_TPM_MFG_EH_AUTH`. When `WOLFBOOT_TPM_MFG_AUTH_DERIVE`
36+
is not enabled, the `authOverride` argument to `wolfBoot_tpm2_get_aik()` is
37+
treated as an optional override for the final AIK `authValue` (not a master secret).
38+
39+
- **Derive mode (`WOLFBOOT_TPM_MFG_AUTH_DERIVE`).** The `authValue` is computed
40+
on-device as the low 16 bytes of `SHA-256(TPM serial || master)`.
41+
The endorsement master defaults to a sample and is overridable with
42+
`WOLFBOOT_TPM_MFG_EH_MASTER`; the AIK master is passed to
43+
`wolfBoot_tpm2_get_aik()` (NULL = sample). Convenient, but the master is
44+
**shared across the whole reel/batch** — extracting it
45+
from one device's firmware lets an attacker derive the `authValue` for every
46+
sibling device.
47+
48+
The byte-array macros are header defaults (overridable via `-D` / `CFLAGS_EXTRA`);
49+
they are not plain `options.mk` variables because brace initializers contain
50+
commas. `WOLFTPM_MFG_IDENTITY` itself is supplied via `CFLAGS_EXTRA`.
51+
52+
> Note: because precomputed mode is the default and ships a `0xFF` placeholder, a
53+
> build that enables `WOLFTPM_MFG_IDENTITY` without provisioning the authValue (or
54+
> selecting `WOLFBOOT_TPM_MFG_AUTH_DERIVE`) fails TPM auth by design. The test-app
55+
> builds with `WOLFBOOT_TPM_MFG_AUTH_DERIVE` so it works on a sample TPM.
2056
2157
## Root of Trust (ROT)
2258

include/tpm.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,42 @@ int CSME_NSE_API wolfBoot_tpm2_read_pcr(uint8_t pcrIndex, uint8_t* digest, int*
6060
int CSME_NSE_API wolfBoot_tpm2_read_cert(uint32_t handle, uint8_t* cert, uint32_t* certSz);
6161

6262
#ifdef WOLFTPM_MFG_IDENTITY
63+
64+
/* MFG identity auth provisioning.
65+
* Precomputed mode (default): the final per-device authValue is set directly,
66+
* no master secret on the device. In this mode, wolfBoot_tpm2_get_aik() treats
67+
* the authOverride argument as an optional *authValue* override.
68+
* Derive mode (WOLFBOOT_TPM_MFG_AUTH_DERIVE): authValue = low 16 bytes of
69+
* SHA-256(TPM serial || master); the master is shared across the reel.
70+
* For wolfBoot_tpm2_get_aik() the master secret is provided via the
71+
* authOverride argument (NULL = sample). */
72+
#ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE
73+
/* EH master for derive mode (sample - override in production) */
74+
#ifndef WOLFBOOT_TPM_MFG_EH_MASTER
75+
#define WOLFBOOT_TPM_MFG_EH_MASTER { \
76+
0xDE, 0xEF, 0x8C, 0xDF, 0x1B, 0x77, 0xBD, 0x00, \
77+
0x30, 0x58, 0x5E, 0x47, 0xB8, 0x21, 0x46, 0x0B }
78+
#endif
79+
#else
80+
/* 16-byte per-device authValues. Placeholder defaults (all 0xFF) fail TPM auth
81+
* until overwritten per-device by the provisioning tool. */
82+
#ifndef WOLFBOOT_TPM_MFG_AIK_AUTH
83+
#define WOLFBOOT_TPM_MFG_AIK_AUTH { \
84+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
85+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
86+
#endif
87+
#ifndef WOLFBOOT_TPM_MFG_EH_AUTH
88+
#define WOLFBOOT_TPM_MFG_EH_AUTH { \
89+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
90+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
91+
#endif
92+
#endif
93+
94+
/* authOverride meaning depends on WOLFBOOT_TPM_MFG_AUTH_DERIVE:
95+
* derive mode -> master secret hashed into the authValue (NULL = sample)
96+
* precomputed mode -> optional literal authValue override (NULL = built-in) */
6397
int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik,
64-
uint8_t* masterPassword, uint16_t masterPasswordSz);
98+
uint8_t* authOverride, uint16_t authOverrideSz);
6599
int CSME_NSE_API wolfBoot_tpm2_get_timestamp(WOLFTPM2_KEY* aik, GetTime_Out* getTime);
66100
int CSME_NSE_API wolfBoot_tpm2_quote(WOLFTPM2_KEY* aik,
67101
byte* pcrArray, word32 pcrArraySz, Quote_Out* quoteResult);

options.mk

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ ifeq ($(WOLFBOOT_TPM_KEYSTORE),1)
5858
endif
5959
endif
6060

61+
## TPM manufacturing identity: precomputed per-device authValue is the default
62+
## (no master secret on device). Opt into on-device derive-from-master mode:
63+
ifeq ($(WOLFBOOT_TPM_MFG_AUTH_DERIVE),1)
64+
CFLAGS+=-D"WOLFBOOT_TPM_MFG_AUTH_DERIVE"
65+
endif
66+
6167
ifeq ($(WOLFBOOT_ATTESTATION_IAK),1)
6268
CFLAGS+=-D"WOLFBOOT_ATTESTATION_IAK"
6369
endif

src/tpm.c

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,8 +1345,22 @@ int CSME_NSE_API wolfBoot_tpm2_read_cert(uint32_t handle, uint8_t* cert, uint32_
13451345
}
13461346

13471347
#ifdef WOLFTPM_MFG_IDENTITY
1348+
#ifndef WOLFBOOT_TPM_MFG_AUTH_DERIVE
1349+
/* Copy a precomputed authValue directly into a TPM handle. */
1350+
static int wolfBoot_tpm2_set_handle_auth(WOLFTPM2_HANDLE* handle,
1351+
const uint8_t* auth, uint16_t authSz)
1352+
{
1353+
if (authSz > (uint16_t)sizeof(handle->auth.buffer)) {
1354+
return BAD_FUNC_ARG;
1355+
}
1356+
handle->auth.size = authSz;
1357+
XMEMCPY(handle->auth.buffer, auth, authSz);
1358+
return 0;
1359+
}
1360+
#endif
1361+
13481362
int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik,
1349-
uint8_t* masterPassword, uint16_t masterPasswordSz)
1363+
uint8_t* authOverride, uint16_t authOverrideSz)
13501364
{
13511365
int rc;
13521366
if (aik == NULL) {
@@ -1355,19 +1369,30 @@ int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik,
13551369
if (WOLFBOOT_TPM_NS_RW(aik, sizeof(*aik)) == NULL) {
13561370
return BAD_FUNC_ARG;
13571371
}
1358-
if (masterPassword != NULL &&
1359-
WOLFBOOT_TPM_NS_R(masterPassword, masterPasswordSz) == NULL) {
1372+
if (authOverride != NULL &&
1373+
WOLFBOOT_TPM_NS_R(authOverride, authOverrideSz) == NULL) {
13601374
return BAD_FUNC_ARG;
13611375
}
13621376

13631377
/* Load existing AIK and set auth */
13641378
rc = wolfTPM2_ReadPublicKey(&wolftpm_dev, aik, TPM2_IAK_KEY_HANDLE);
13651379
if (rc == 0) {
1366-
/* Custom should supply their own custom master password used during
1367-
* device provisioning. If using a sample TPM supply NULL to use the
1368-
* default password. */
1380+
#ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE
1381+
/* Derives the authValue on-device from a master secret shared across the
1382+
* reel; the precomputed default is preferred. Supply NULL for
1383+
* authOverride to use the sample default. */
13691384
rc = wolfTPM2_SetIdentityAuth(&wolftpm_dev, &aik->handle,
1370-
masterPassword, masterPasswordSz);
1385+
authOverride, authOverrideSz);
1386+
#else
1387+
/* Precomputed (default): set the final per-device authValue directly (no
1388+
* master secret on device). Caller may override the default via
1389+
* authOverride. */
1390+
static const uint8_t aikAuth[] = WOLFBOOT_TPM_MFG_AIK_AUTH;
1391+
const uint8_t* auth = (authOverride != NULL) ? authOverride : aikAuth;
1392+
uint16_t authSz = (authOverride != NULL) ?
1393+
authOverrideSz : (uint16_t)sizeof(aikAuth);
1394+
rc = wolfBoot_tpm2_set_handle_auth(&aik->handle, auth, authSz);
1395+
#endif
13711396
}
13721397
return rc;
13731398
}
@@ -1376,11 +1401,13 @@ int CSME_NSE_API wolfBoot_tpm2_get_timestamp(WOLFTPM2_KEY* aik, GetTime_Out* get
13761401
{
13771402
int rc;
13781403
WOLFTPM2_HANDLE eh_handle;
1379-
/* sample master password for EH */
1380-
uint8_t Master_EH_AuthValue[] = {
1381-
0xDE, 0xEF, 0x8C, 0xDF, 0x1B, 0x77, 0xBD, 0x00,
1382-
0x30, 0x58, 0x5E, 0x47, 0xB8, 0x21, 0x46, 0x0B
1383-
};
1404+
#ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE
1405+
/* EH master secret (shared across the reel) */
1406+
uint8_t Master_EH_AuthValue[] = WOLFBOOT_TPM_MFG_EH_MASTER;
1407+
#else
1408+
/* final per-device EH authValue */
1409+
static const uint8_t eh_auth[] = WOLFBOOT_TPM_MFG_EH_AUTH;
1410+
#endif
13841411

13851412
if (aik == NULL || getTime == NULL) {
13861413
return BAD_FUNC_ARG;
@@ -1395,9 +1422,17 @@ int CSME_NSE_API wolfBoot_tpm2_get_timestamp(WOLFTPM2_KEY* aik, GetTime_Out* get
13951422

13961423
eh_handle.hndl = TPM_RH_ENDORSEMENT;
13971424

1425+
#ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE
13981426
/* Calculate EH auth value */
13991427
rc = wolfTPM2_SetIdentityAuth(&wolftpm_dev, &eh_handle,
14001428
Master_EH_AuthValue, (uint16_t)sizeof(Master_EH_AuthValue));
1429+
/* master secret consumed; clear it from the stack */
1430+
TPM2_ForceZero(Master_EH_AuthValue, sizeof(Master_EH_AuthValue));
1431+
#else
1432+
/* Set EH authValue directly */
1433+
rc = wolfBoot_tpm2_set_handle_auth(&eh_handle, eh_auth,
1434+
(uint16_t)sizeof(eh_auth));
1435+
#endif
14011436
if (rc == 0) {
14021437
/* Set EH auth */
14031438
wolfTPM2_SetAuthHandle(&wolftpm_dev, 0, &eh_handle);

tools/config.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ ifeq ($(ARCH),)
5858
MEASURED_BOOT?=0
5959
WOLFBOOT_TPM_SEAL?=0
6060
WOLFBOOT_TPM_KEYSTORE?=0
61+
WOLFBOOT_TPM_MFG_AUTH_DERIVE?=0
6162
WOLFBOOT_ATTESTATION_IAK?=0
6263
WOLFBOOT_ATTESTATION_TEST?=0
6364
WOLFBOOT_UNIVERSAL_KEYSTORE?=0
@@ -106,6 +107,7 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
106107
DISABLE_BACKUP WOLFBOOT_VERSION V NO_MPU ENCRYPT FLAGS_HOME FLAGS_INVERT \
107108
SPMATH SPMATHALL RAM_CODE DUALBANK_SWAP IMAGE_HEADER_SIZE PKA TZEN PSOC6_CRYPTO \
108109
WOLFTPM WOLFBOOT_TPM_VERIFY MEASURED_BOOT WOLFBOOT_TPM_SEAL WOLFBOOT_TPM_KEYSTORE \
110+
WOLFBOOT_TPM_MFG_AUTH_DERIVE \
109111
WOLFBOOT_ATTESTATION_IAK \
110112
WOLFBOOT_ATTESTATION_TEST \
111113
WOLFBOOT_UDS_UID_FALLBACK_FORTEST \

0 commit comments

Comments
 (0)