IDevID: allow using pre-computed auth values#803
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a build-time option to support TPM manufacturing identity (IAK/IDevID) authorization using precomputed per-device authValues (default) instead of always deriving authValues on-device from a shared master secret.
Changes:
- Introduces
WOLFBOOT_TPM_MFG_AUTH_DERIVEmake/config option and plumbs it through build configuration. - Updates TPM MFG identity paths to either derive authValues on-device (existing behavior) or set precomputed authValues directly into TPM handles.
- Documents the two modes and adds an STM32H5 TZ example config enabling derive mode for sample TPM usage.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/config.mk | Adds WOLFBOOT_TPM_MFG_AUTH_DERIVE default and exports it via CONFIG_VARS. |
| options.mk | Adds -DWOLFBOOT_TPM_MFG_AUTH_DERIVE when the option is enabled. |
| src/tpm.c | Implements derive vs precomputed authValue handling for AIK and EH authorization. |
| include/tpm.h | Adds MFG identity auth provisioning macros and documentation for both modes. |
| docs/TPM.md | Documents the new option and explains precomputed vs derive provisioning modes. |
| config/examples/stm32h5-tz-tpm-mfgid.config | New example enabling TPM MFG identity on STM32H5, with derive mode for sample devices. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
9dd326b to
dd4387e
Compare
dgarske
left a comment
There was a problem hiding this comment.
Skoll Multi-Scan Review
Modes: review + review-securityOverall recommendation: COMMENT
Findings: 8 total — 7 posted, 1 skipped
5 finding(s) posted as inline comments (see file-level comments below)
Posted findings
- [Medium] [review] New default (precomputed) authValue path has no build/CI coverage —
src/tpm.c:1372-1385 - [Medium] [review] masterPassword parameter has overloaded semantics based on a compile-time macro —
src/tpm.c:1348-1388 - [Low] [review-security] Master secret on stack not zeroized after use in derive mode —
src/tpm.c:1394-1418 - [Low] [review+review-security] Typo 'wolfBott_tpm2_get_aik' in new header comment —
include/tpm.h:70 - [Low] [review] Trailing whitespace on added lines —
include/tpm.h:69, docs/TPM.md:35, docs/TPM.md:40 - [Low] [review] Duplicated authValue-into-handle copy; EH bounds check is a compile-time constant —
src/tpm.c:1380-1384, src/tpm.c:1421-1426 - [Info] [review-security] Default MFG identity mode change: builds relying on the sample master now fail TPM auth until provisioned —
src/tpm.c:1363-1387
Skipped findings
- [Low]
Derive mode embeds a reel-wide shared master secret in firmware (enabled by the new example config)
Review generated by Skoll
| * masterPassword to use the sample default. */ | ||
| rc = wolfTPM2_SetIdentityAuth(&wolftpm_dev, &aik->handle, | ||
| masterPassword, masterPasswordSz); | ||
| #else |
There was a problem hiding this comment.
🟠 [Medium] New default (precomputed) authValue path has no build/CI coverage · test
The PR introduces a brand-new default code path (the #else / precomputed branch in both wolfBoot_tpm2_get_aik() and wolfBoot_tpm2_get_timestamp()), but the only config that enables WOLFTPM_MFG_IDENTITY (config/examples/stm32h5-tz-tpm-mfgid.config) sets WOLFBOOT_TPM_MFG_AUTH_DERIVE=1, which compiles the derive branch. The new precomputed branch is therefore never compiled by any example config. I also confirmed via grep that stm32h5-tz-tpm-mfgid.config is not referenced by any .github/workflows/*.yml job (the trustzone emulator tests list specific stm32h5 TZ configs by name and this one is absent). The net effect: the central new code added by this PR is unbuilt in CI, so a future regression or compile error in the precomputed path would go unnoticed.
Fix: Add a second config/example (or wire the new one into a workflow) that builds WOLFTPM_MFG_IDENTITY without WOLFBOOT_TPM_MFG_AUTH_DERIVE so the new default branch is compiled. At minimum, reference the new mfgid config from a CI job so at least the derive path is exercised.
| #endif | ||
| } | ||
| return rc; | ||
| } |
There was a problem hiding this comment.
🟠 [Medium] masterPassword parameter has overloaded semantics based on a compile-time macro · api
The same NS-callable API parameter masterPassword/masterPasswordSz now means two different things depending on the build-time flag WOLFBOOT_TPM_MFG_AUTH_DERIVE: in derive mode it is a master secret fed into SHA-256(serial || master), while in precomputed mode it is the final literal authValue copied verbatim into aik->handle.auth.buffer. The function signature is identical in both modes, so a caller cannot tell from the prototype which semantics apply. A downstream integrator who passes a real master password (expecting derivation) on a precomputed-mode build would instead have those bytes installed directly as the authValue, silently producing the wrong auth. This is documented in include/tpm.h and docs/TPM.md, which mitigates it, but it remains a misuse hazard for a public boundary API.
Fix: Consider renaming the parameter to something mode-neutral (e.g. authOverride) or documenting the dual meaning directly at the prototype, so the compile-time-dependent behavior is visible at the call site.
| 0xDE, 0xEF, 0x8C, 0xDF, 0x1B, 0x77, 0xBD, 0x00, | ||
| 0x30, 0x58, 0x5E, 0x47, 0xB8, 0x21, 0x46, 0x0B | ||
| }; | ||
| #ifdef WOLFBOOT_TPM_MFG_AUTH_DERIVE |
There was a problem hiding this comment.
🔵 [Low] Master secret on stack not zeroized after use in derive mode · Zeroization
In derive mode the PR populates uint8_t Master_EH_AuthValue[] (the shared reel master secret) on the stack and passes it to wolfTPM2_SetIdentityAuth(), but never clears it before the function returns. The buffer remains in the stack frame after the function exits and can linger in memory. The same gap existed before this PR (the literal was unconditional), but the PR rewrites this exact declaration line, making it a natural point to add zeroization. The file already uses TPM2_ForceZero() (line 1157) for the same purpose, so the helper is available. The precomputed #else path stores into the caller-owned aik->handle.auth/local eh_handle and does not introduce a new gap.
Fix: Call TPM2_ForceZero(Master_EH_AuthValue, sizeof(Master_EH_AuthValue)); (consistent with line 1157) on all exit paths after the master is consumed in derive mode.
| * 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 |
There was a problem hiding this comment.
🔵 [Low] Typo 'wolfBott_tpm2_get_aik' in new header comment · style
Both the review and review-security scans independently flagged the same typo. The new provisioning comment block added by this PR misspells the function name as wolfBott_tpm2_get_aik() (extra 't', missing 'o'). Cosmetic only, no functional impact, but it appears in a public header that documents the API contract. Severity views differed across modes (review: Low/NIT; review-security: Info); the stricter Low is kept here.
Fix: Fix the spelling to wolfBoot_tpm2_get_aik().
| @@ -1363,11 +1363,26 @@ int CSME_NSE_API wolfBoot_tpm2_get_aik(WOLFTPM2_KEY* aik, | |||
| /* Load existing AIK and set auth */ | |||
There was a problem hiding this comment.
⚪ [Info] Default MFG identity mode change: builds relying on the sample master now fail TPM auth until provisioned · Logic
Before this PR, wolfBoot_tpm2_get_aik()/wolfBoot_tpm2_get_timestamp() always derived the authValue from the built-in sample master via wolfTPM2_SetIdentityAuth(), so a WOLFTPM_MFG_IDENTITY build worked out of the box on a sample TPM. After the PR, the default (no WOLFBOOT_TPM_MFG_AUTH_DERIVE) is precomputed mode, whose WOLFBOOT_TPM_MFG_AIK_AUTH/WOLFBOOT_TPM_MFG_EH_AUTH defaults are all-0xFF placeholders that fail TPM auth until provisioned. This is intentional and documented in docs/TPM.md, and the new example config sets WOLFBOOT_TPM_MFG_AUTH_DERIVE=1 so the test-app still works. Flagged only so downstream integrators who previously built WOLFTPM_MFG_IDENTITY are aware their builds now require per-device provisioning or the explicit derive flag.
Fix: No code change required; ensure release notes/migration docs call out that existing WOLFTPM_MFG_IDENTITY builds must now either provision the per-device authValue or set WOLFBOOT_TPM_MFG_AUTH_DERIVE to retain previous behavior.
ZD#21988