diff --git a/.github/workflows/fwtpm-test.yml b/.github/workflows/fwtpm-test.yml index c05ce5ef..a36890ba 100644 --- a/.github/workflows/fwtpm-test.yml +++ b/.github/workflows/fwtpm-test.yml @@ -149,6 +149,88 @@ jobs: build_only: true extra_cflags: -DFWTPM_NO_PARAM_ENC + # Build-only: finer per-command-group FWTPM_NO_* macros + - name: fwtpm-no-key-migration + os: ubuntu-latest + wolftpm_config: --enable-fwtpm --enable-swtpm + wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen + build_only: true + extra_cflags: -DFWTPM_NO_KEY_MIGRATION + + - name: fwtpm-no-ecdh + os: ubuntu-latest + wolftpm_config: --enable-fwtpm --enable-swtpm + wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen + build_only: true + extra_cflags: -DFWTPM_NO_ECDH + + - name: fwtpm-no-hash-cmds + os: ubuntu-latest + wolftpm_config: --enable-fwtpm --enable-swtpm + wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen + build_only: true + extra_cflags: -DFWTPM_NO_HASH_CMDS + + - name: fwtpm-no-context + os: ubuntu-latest + wolftpm_config: --enable-fwtpm --enable-swtpm + wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen + build_only: true + extra_cflags: -DFWTPM_NO_CONTEXT + + - name: fwtpm-no-sym-encrypt + os: ubuntu-latest + wolftpm_config: --enable-fwtpm --enable-swtpm + wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen + build_only: true + extra_cflags: -DFWTPM_NO_SYM_ENCRYPT + + - name: fwtpm-no-clock + os: ubuntu-latest + wolftpm_config: --enable-fwtpm --enable-swtpm + wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen + build_only: true + extra_cflags: -DFWTPM_NO_CLOCK + + # Build-only: all command-group gates enabled together (there is no + # umbrella macro; each flag is set explicitly), standalone and combined + # with MLDSA (which shares the sequence commands) + - name: fwtpm-all-gates + os: ubuntu-latest + wolftpm_config: --enable-fwtpm --enable-swtpm + wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen + build_only: true + extra_cflags: >- + -DFWTPM_NO_POLICY + -DFWTPM_NO_ATTESTATION + -DFWTPM_NO_CREDENTIAL + -DFWTPM_NO_DA + -DFWTPM_NO_PARAM_ENC + -DFWTPM_NO_KEY_MIGRATION + -DFWTPM_NO_ECDH + -DFWTPM_NO_HASH_CMDS + -DFWTPM_NO_CONTEXT + -DFWTPM_NO_SYM_ENCRYPT + -DFWTPM_NO_CLOCK + + - name: fwtpm-all-gates-mldsa + os: ubuntu-latest + wolftpm_config: --enable-fwtpm --enable-swtpm --enable-v185 --enable-mldsa + wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen --enable-experimental --enable-mldsa + build_only: true + extra_cflags: >- + -DFWTPM_NO_POLICY + -DFWTPM_NO_ATTESTATION + -DFWTPM_NO_CREDENTIAL + -DFWTPM_NO_DA + -DFWTPM_NO_PARAM_ENC + -DFWTPM_NO_KEY_MIGRATION + -DFWTPM_NO_ECDH + -DFWTPM_NO_HASH_CMDS + -DFWTPM_NO_CONTEXT + -DFWTPM_NO_SYM_ENCRYPT + -DFWTPM_NO_CLOCK + # Build-only: cross-algorithm + feature macro combinations - name: fwtpm-no-rsa-no-policy os: ubuntu-latest diff --git a/README.md b/README.md index 5ec2dca9..3dc9af9f 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Features: * TIS register-level transport over shared memory or SPI/I2C for bare-metal integration * HAL abstractions for IO transport and NV storage portability * File-based or custom NV storage via HAL callbacks -* Compile-time algorithm and feature selection (e.g., `NO_RSA`, `FWTPM_NO_NV`) +* Compile-time algorithm and per-command-group feature selection (e.g., `NO_RSA`, `FWTPM_NO_NV`, and independent per-command-group gates you pick and choose to shrink the fTPM footprint) * `WOLFTPM_SMALL_STACK` support for constrained environments See [docs/FWTPM.md](docs/FWTPM.md) for build instructions, configuration, and API reference. diff --git a/docs/FWTPM.md b/docs/FWTPM.md index 46696371..dd62e114 100644 --- a/docs/FWTPM.md +++ b/docs/FWTPM.md @@ -664,22 +664,43 @@ to reduce code size on constrained targets. | `FWTPM_NO_POLICY` | not defined | `PolicyGetDigest`, `PolicyRestart`, `PolicyPCR`, `PolicyPassword`, `PolicyAuthValue`, `PolicyCommandCode`, `PolicyOR`, `PolicySecret`, `PolicyAuthorize`, `PolicyNV` | | `FWTPM_NO_CREDENTIAL` | not defined | `MakeCredential`, `ActivateCredential` | | `FWTPM_NO_DA` | not defined | `DictionaryAttackParameters`, `DictionaryAttackLockReset`, and all lockout accounting | +| `FWTPM_NO_PARAM_ENC` | not defined | command/response parameter (XOR/AES-CFB) encryption support in sessions | +| `FWTPM_NO_KEY_MIGRATION` | not defined | `Import`, `Duplicate`, `Rewrap` | +| `FWTPM_NO_ECDH` | not defined | `ECDH_KeyGen`, `ECDH_ZGen`, `EC_Ephemeral`, `ZGen_2Phase`, `ECC_Parameters` (ECDSA sign/verify retained) | +| `FWTPM_NO_HASH_CMDS` | not defined | `Hash`, `HMAC`, `HMAC_Start`, `HashSequenceStart`, `SequenceUpdate`, `SequenceComplete`, `EventSequenceComplete` | +| `FWTPM_NO_CONTEXT` | not defined | `ContextSave`, `ContextLoad` (`FlushContext` retained) | +| `FWTPM_NO_SYM_ENCRYPT` | not defined | `EncryptDecrypt`, `EncryptDecrypt2` | +| `FWTPM_NO_CLOCK` | not defined | `ReadClock`, `ClockSet`, `ClockRateAdjust` | + +Removing a command group also removes it from the `TPM2_GetCapability(TPM_CAP_COMMANDS)` advertisement and the `TPM_PT_TOTAL_COMMANDS` count, since both are derived from the dispatch table. Note: when `WOLFTPM_MLDSA` is built, `SequenceUpdate`/`SequenceComplete` are retained even under `FWTPM_NO_HASH_CMDS` because the MLDSA sign-sequence commands share them. The `FWTPM_DA_USED_RETRY` macro (off by default) does not remove commands; it makes the server return `TPM_RC_RETRY` on the first DA-protected auth use after startup, emulating a real TPM persisting `daUsed`. See [Dictionary Attack (DA) Protection](#dictionary-attack-da-protection). -**Minimal build example** (measured boot only): +**Minimal build example.** There is no umbrella macro - select the command +groups to drop explicitly, so each is a deliberate choice. For example, to build +a small ECC-only signing + NV fTPM (this set drops attestation; keep +`Sign`/`VerifySignature`, PCR, and NV): ```sh ./configure --enable-fwtpm --enable-swtpm \ - CFLAGS="-DNO_RSA -DFWTPM_NO_NV -DFWTPM_NO_ATTESTATION \ - -DFWTPM_NO_POLICY -DFWTPM_NO_CREDENTIAL" + CFLAGS="-DNO_RSA \ + -DFWTPM_NO_POLICY -DFWTPM_NO_ATTESTATION -DFWTPM_NO_CREDENTIAL \ + -DFWTPM_NO_DA -DFWTPM_NO_PARAM_ENC -DFWTPM_NO_KEY_MIGRATION \ + -DFWTPM_NO_ECDH -DFWTPM_NO_HASH_CMDS -DFWTPM_NO_CONTEXT \ + -DFWTPM_NO_SYM_ENCRYPT -DFWTPM_NO_CLOCK" ``` -This retains only: `Startup`, `Shutdown`, `SelfTest`, `GetRandom`, `GetCapability`, -`PCR_Read`, `PCR_Extend`, `PCR_Reset`, `Hash`, ECC keygen/sign, and session support. +That set retains a core fTPM: `Startup`, `Shutdown`, `SelfTest`, `GetRandom`, +`GetCapability`, the `PCR_*` commands, `Create`/`CreatePrimary`/`Load`/ +`ReadPublic`/`FlushContext`, `Sign`/`VerifySignature`, the `NV_*` commands, and +session support (`StartAuthSession`/`Unseal`). Add `-DFWTPM_NO_NV` to also drop +NV, or drop any `-DFWTPM_NO_*` above to keep that group. This ECC-only build is +small enough to run as a soft-core fTPM on a constrained FPGA (see the MicroBlaze +V example in the `wolftpm-examples` repo, which fits an ECC-only fTPM into +~192 KB of on-chip memory). **Dependencies:** - `FWTPM_NO_NV` also removes `NV_Certify` (even if `FWTPM_NO_ATTESTATION` is not set) diff --git a/src/fwtpm/README.md b/src/fwtpm/README.md index 75840250..e677a479 100644 --- a/src/fwtpm/README.md +++ b/src/fwtpm/README.md @@ -113,6 +113,14 @@ All tests below run in GitHub Actions CI. Run manually before PR submission. | fwtpm-no-credential | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_CREDENTIAL` | | fwtpm-no-da | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_DA` | | fwtpm-no-param-enc | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_PARAM_ENC` | +| fwtpm-no-key-migration | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_KEY_MIGRATION` | +| fwtpm-no-ecdh | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_ECDH` | +| fwtpm-no-hash-cmds | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_HASH_CMDS` | +| fwtpm-no-context | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_CONTEXT` | +| fwtpm-no-sym-encrypt | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_SYM_ENCRYPT` | +| fwtpm-no-clock | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_CLOCK` | +| fwtpm-all-gates | `--enable-fwtpm --enable-swtpm` | | the eleven command-group `-DFWTPM_NO_*` gates together (NV retained) | +| fwtpm-all-gates-mldsa | `--enable-fwtpm --enable-swtpm --enable-v185 --enable-mldsa` | | the eleven command-group `-DFWTPM_NO_*` gates together (NV retained) | | fwtpm-no-rsa-no-policy | `--enable-fwtpm --enable-swtpm` | `--disable-rsa` | `-DFWTPM_NO_POLICY` | | fwtpm-no-ecc-no-nv | `--enable-fwtpm --enable-swtpm` | `--disable-ecc` | `-DFWTPM_NO_NV` | | fwtpm-small-stack | `--enable-fwtpm --enable-swtpm` | | `-DWOLFTPM_SMALL_STACK` | @@ -221,6 +229,26 @@ EncryptDecrypt, EncryptDecrypt2 - `FWTPM_NO_PARAM_ENC`: Disables parameter encryption/decryption for command and response parameters. Sessions still work for HMAC auth, but encrypted transport is disabled. Reduces code size by removing AES-CFB and XOR param encryption. +- `FWTPM_NO_KEY_MIGRATION`: Import, Duplicate, Rewrap (3 commands). Shared key + helpers (used by Create/Load) are retained. +- `FWTPM_NO_ECDH`: ECDH\_KeyGen, ECDH\_ZGen, EC\_Ephemeral, ZGen\_2Phase, + ECC\_Parameters (5 commands). ECDSA sign/verify are retained. +- `FWTPM_NO_HASH_CMDS`: Hash, HMAC, HMAC\_Start, HashSequenceStart, + SequenceUpdate, SequenceComplete, EventSequenceComplete (7 commands). When + `WOLFTPM_MLDSA` is built, SequenceUpdate/SequenceComplete are retained because + the MLDSA sign-sequence commands share them. +- `FWTPM_NO_CONTEXT`: ContextSave, ContextLoad (2 commands). FlushContext is + retained. +- `FWTPM_NO_SYM_ENCRYPT`: EncryptDecrypt, EncryptDecrypt2 (2 commands). Nests + inside `NO_AES`; AES itself is retained for context protection and AES-GCM. +- `FWTPM_NO_CLOCK`: ReadClock, ClockSet, ClockRateAdjust (3 commands). GetTime is + under `FWTPM_NO_ATTESTATION`, not this flag. +These gates are independent and there is intentionally no umbrella macro: pick +exactly the groups your fTPM does not need. Applying all of them plus the earlier +`FWTPM_NO_POLICY/ATTESTATION/CREDENTIAL/DA/PARAM_ENC` (keeping NV, or adding +`FWTPM_NO_NV` to drop it) leaves a core fTPM (Startup/GetCapability/GetRandom/ +PCR/Create/Load/Sign/VerifySignature/NV/sessions) - see the MicroBlaze V example +in wolftpm-examples for a worked selection. ### Missing Commands -- TODO diff --git a/src/fwtpm/fwtpm_command.c b/src/fwtpm/fwtpm_command.c index ca480b31..6dc52d68 100644 --- a/src/fwtpm/fwtpm_command.c +++ b/src/fwtpm/fwtpm_command.c @@ -2145,7 +2145,13 @@ static TPM_RC FwCmd_PCR_Read(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize, * dump (loc2 reset of PCR 20-22 hardware-confirmed over SPI). * reset: 0-15 never; 16,23 loc0-3; 17-19 loc4; 20-22 loc2-4. * extend: 0-16,23 any; 17,18 loc2-4; 19 loc2-3; 20 loc1-3; 21,22 loc2. */ -static const byte fwPcrResetLocality[IMPLEMENTATION_PCR] = { +/* The TCG PCR locality attributes are defined for the 24 standard PCRs. Size the + * tables to that fixed count (not IMPLEMENTATION_PCR) so a build implementing + * fewer PCRs (IMPLEMENTATION_PCR < 24, e.g. a minimal soft-core fTPM) neither + * drops initializers nor warns; FwPcrLocalityAllowed() only indexes valid PCRs. */ +#define FW_PCR_LOCALITY_TABLE 24 + +static const byte fwPcrResetLocality[FW_PCR_LOCALITY_TABLE] = { /* 0- 7 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 8-15 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 16 */ 0x0F, /* loc0-3 */ @@ -2158,7 +2164,7 @@ static const byte fwPcrResetLocality[IMPLEMENTATION_PCR] = { /* 23 */ 0x0F /* loc0-3 */ }; -static const byte fwPcrExtendLocality[IMPLEMENTATION_PCR] = { +static const byte fwPcrExtendLocality[FW_PCR_LOCALITY_TABLE] = { /* 0- 7 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, /* any */ /* 8-15 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, /* any */ /* 16 */ 0x1F, /* any */ @@ -2177,7 +2183,8 @@ static int FwPcrLocalityAllowed(int pcrIndex, int locality, int isReset) { byte mask; - if (pcrIndex < 0 || pcrIndex >= IMPLEMENTATION_PCR) { + if (pcrIndex < 0 || pcrIndex >= IMPLEMENTATION_PCR || + pcrIndex >= FW_PCR_LOCALITY_TABLE) { return 0; } if (locality < 0 || locality > WOLFTPM_LOCALITY_MAX) { @@ -2705,6 +2712,7 @@ static TPM_RC FwCmd_PCR_SetAuthValue(FWTPM_CTX* ctx, TPM2_Packet* cmd, return rc; } +#ifndef FWTPM_NO_CLOCK /* --- TPM2_ReadClock (CC 0x0181) --- */ static TPM_RC FwCmd_ReadClock(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize, TPM2_Packet* rsp, UINT16 cmdTag) @@ -2824,6 +2832,7 @@ static TPM_RC FwCmd_ClockRateAdjust(FWTPM_CTX* ctx, TPM2_Packet* cmd, return rc; } +#endif /* !FWTPM_NO_CLOCK */ /* --- Object management helpers --- */ @@ -3523,6 +3532,7 @@ static TPM_RC FwCmd_FlushContext(FWTPM_CTX* ctx, TPM2_Packet* cmd, * stored externally (e.g. a .ctx file) and later reloaded with ContextLoad. * We use an opaque blob that stores the handle number; the object remains * in its slot so ContextLoad can find it for the lifetime of the server. */ +#ifndef FWTPM_NO_CONTEXT #define FWTPM_CTX_MAGIC 0x4657544Du /* 'FWTM' */ #define FWTPM_CTX_VER 1u static TPM_RC FwCmd_ContextSave(FWTPM_CTX* ctx, TPM2_Packet* cmd, @@ -3861,6 +3871,7 @@ static TPM_RC FwCmd_ContextLoad(FWTPM_CTX* ctx, TPM2_Packet* cmd, return rc; } +#endif /* !FWTPM_NO_CONTEXT */ /* --- TPM2_ReadPublic (CC 0x0173) --- */ static TPM_RC FwCmd_ReadPublic(FWTPM_CTX* ctx, TPM2_Packet* cmd, @@ -5482,6 +5493,7 @@ static TPM_RC FwCmd_LoadExternal(FWTPM_CTX* ctx, TPM2_Packet* cmd, } +#ifndef FWTPM_NO_KEY_MIGRATION /* --- TPM2_Import (CC 0x156) --- * Import an externally created key (outer-wrapped) under a parent key. * Response: [paramSz] | outPrivate */ @@ -6598,6 +6610,7 @@ static TPM_RC FwCmd_Rewrap(FWTPM_CTX* ctx, TPM2_Packet* cmd, FWTPM_FREE_BUF(encSeedBuf); return rc; } +#endif /* !FWTPM_NO_KEY_MIGRATION */ /* --- TPM2_CreateLoaded (CC 0x0191) --- * Like Create but also loads the key into a transient slot. @@ -7536,6 +7549,7 @@ static TPM_RC FwCmd_RSA_Decrypt(FWTPM_CTX* ctx, TPM2_Packet* cmd, /* Hash, HMAC, HashSequence, ECDH */ /* ================================================================== */ +#ifndef FWTPM_NO_HASH_CMDS /* --- TPM2_Hash (CC 0x017D) --- */ static TPM_RC FwCmd_Hash(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize, TPM2_Packet* rsp, UINT16 cmdTag) @@ -7768,6 +7782,7 @@ static FWTPM_HashSeq* FwAllocHashSeq(FWTPM_CTX* ctx, TPM_HANDLE* handle) } return NULL; } +#endif /* !FWTPM_NO_HASH_CMDS */ static FWTPM_HashSeq* FwFindHashSeq(FWTPM_CTX* ctx, TPM_HANDLE handle) { @@ -7791,6 +7806,7 @@ static void FwFreeHashSeq(FWTPM_HashSeq* seq) XMEMSET(seq, 0, sizeof(*seq)); } +#ifndef FWTPM_NO_HASH_CMDS /* --- TPM2_HMAC_Start (CC 0x015B) --- */ /* Starts an HMAC sequence using a loaded KEYEDHASH key. */ static TPM_RC FwCmd_HMAC_Start(FWTPM_CTX* ctx, TPM2_Packet* cmd, @@ -7964,7 +7980,11 @@ static TPM_RC FwCmd_HashSequenceStart(FWTPM_CTX* ctx, TPM2_Packet* cmd, return rc; } +#endif /* !FWTPM_NO_HASH_CMDS */ +/* SequenceUpdate/SequenceComplete are shared with MLDSA sign sequences - keep + * them whenever MLDSA is built, even if the hash commands are gated. */ +#if !defined(FWTPM_NO_HASH_CMDS) || defined(WOLFTPM_MLDSA) /* --- TPM2_SequenceUpdate (CC 0x015C) --- */ static TPM_RC FwCmd_SequenceUpdate(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize, TPM2_Packet* rsp, UINT16 cmdTag) @@ -8234,7 +8254,9 @@ static TPM_RC FwCmd_SequenceComplete(FWTPM_CTX* ctx, TPM2_Packet* cmd, FWTPM_FREE_BUF(dataBuf); return rc; } +#endif /* !FWTPM_NO_HASH_CMDS || WOLFTPM_MLDSA */ +#ifndef FWTPM_NO_HASH_CMDS /* --- TPM2_EventSequenceComplete (CC 0x0185) --- */ /* Like SequenceComplete but also extends the result into a PCR. * Wire: pcrHandle (U32) → sequenceHandle (U32) → auth area → buffer @@ -8384,8 +8406,10 @@ static TPM_RC FwCmd_EventSequenceComplete(FWTPM_CTX* ctx, TPM2_Packet* cmd, FWTPM_FREE_BUF(dataBuf); return rc; } +#endif /* !FWTPM_NO_HASH_CMDS */ #ifdef HAVE_ECC +#ifndef FWTPM_NO_ECDH /* --- TPM2_ECDH_KeyGen (CC 0x0163) --- */ static TPM_RC FwCmd_ECDH_KeyGen(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize, TPM2_Packet* rsp, UINT16 cmdTag) @@ -8680,6 +8704,7 @@ static TPM_RC FwCmd_ECDH_ZGen(FWTPM_CTX* ctx, TPM2_Packet* cmd, FWTPM_FREE_VAR(inPoint); return rc; } +#endif /* !FWTPM_NO_ECDH */ #endif /* HAVE_ECC */ /* --- TPM2_StartAuthSession (CC 0x0176) --- */ @@ -12392,6 +12417,7 @@ static TPM_RC FwCmd_DictionaryAttackParameters(FWTPM_CTX* ctx, #endif /* !FWTPM_NO_DA */ #ifndef NO_AES +#ifndef FWTPM_NO_SYM_ENCRYPT /* --- TPM2_EncryptDecrypt (CC 0x0164) and EncryptDecrypt2 (CC 0x0187) --- * Symmetric encrypt/decrypt using a loaded SYMCIPHER key. * EncryptDecrypt: keyHandle, decrypt, mode, ivIn, inData @@ -12684,6 +12710,7 @@ static TPM_RC FwCmd_EncryptDecrypt2(FWTPM_CTX* ctx, TPM2_Packet* cmd, { return FwEncryptDecryptCore(ctx, cmd, cmdSize, rsp, cmdTag, 1); } +#endif /* !FWTPM_NO_SYM_ENCRYPT */ #endif /* !NO_AES */ /* ================================================================== */ @@ -13818,6 +13845,7 @@ static TPM_RC FwCmd_ActivateCredential(FWTPM_CTX* ctx, TPM2_Packet* cmd, /* ECC Parameters */ /* ================================================================== */ +#ifndef FWTPM_NO_ECDH /* Convert hex string to binary. Returns byte count, or -1 on error. */ static int FwHexToBin(const char* hex, byte* out, int outSz) { @@ -14251,6 +14279,7 @@ static TPM_RC FwCmd_ZGen_2Phase(FWTPM_CTX* ctx, TPM2_Packet* cmd, FWTPM_FREE_VAR(peerPub); return rc; } +#endif /* !FWTPM_NO_ECDH */ #endif /* HAVE_ECC */ #ifdef WOLFTPM_FWTPM_TCG_TEST @@ -16140,14 +16169,18 @@ static const FWTPM_CMD_ENTRY fwCmdTable[] = { { TPM_CC_PCR_Allocate, FwCmd_PCR_Allocate, 1, 1, 0, 0 }, { TPM_CC_PCR_SetAuthPolicy, FwCmd_PCR_SetAuthPolicy, 1, 1, 0, FW_CMD_FLAG_ENC }, { TPM_CC_PCR_SetAuthValue, FwCmd_PCR_SetAuthValue, 1, 1, 0, FW_CMD_FLAG_ENC }, +#ifndef FWTPM_NO_CLOCK { TPM_CC_ReadClock, FwCmd_ReadClock, 0, 0, 0, 0 }, { TPM_CC_ClockSet, FwCmd_ClockSet, 1, 1, 0, 0 }, { TPM_CC_ClockRateAdjust, FwCmd_ClockRateAdjust, 1, 1, 0, 0 }, +#endif /* !FWTPM_NO_CLOCK */ /* --- Key management (always enabled, algorithm checks inside) --- */ { TPM_CC_CreatePrimary, FwCmd_CreatePrimary, 1, 1, 1, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, { TPM_CC_FlushContext, FwCmd_FlushContext, 1, 0, 0, 0 }, +#ifndef FWTPM_NO_CONTEXT { TPM_CC_ContextSave, FwCmd_ContextSave, 1, 0, 0, 0 }, { TPM_CC_ContextLoad, FwCmd_ContextLoad, 0, 0, 1, 0 }, +#endif /* !FWTPM_NO_CONTEXT */ { TPM_CC_ReadPublic, FwCmd_ReadPublic, 1, 0, 0, FW_CMD_FLAG_DEC }, { TPM_CC_Clear, FwCmd_Clear, 1, 1, 0, 0 }, { TPM_CC_ClearControl, FwCmd_ClearControl, 1, 1, 0, 0 }, @@ -16167,19 +16200,29 @@ static const FWTPM_CMD_ENTRY fwCmdTable[] = { { TPM_CC_RSA_Decrypt, FwCmd_RSA_Decrypt, 1, 1, 0, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, #endif /* --- Hash/HMAC --- */ +#ifndef FWTPM_NO_HASH_CMDS { TPM_CC_Hash, FwCmd_Hash, 0, 0, 0, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, { TPM_CC_HMAC, FwCmd_HMAC, 1, 1, 0, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, { TPM_CC_HMAC_Start, FwCmd_HMAC_Start, 1, 1, 1, FW_CMD_FLAG_ENC }, { TPM_CC_HashSequenceStart, FwCmd_HashSequenceStart, 0, 0, 1, FW_CMD_FLAG_ENC }, +#endif /* !FWTPM_NO_HASH_CMDS */ + /* SequenceUpdate/SequenceComplete are shared with MLDSA sign sequences - + * keep them whenever MLDSA is built, even if the hash commands are gated. */ +#if !defined(FWTPM_NO_HASH_CMDS) || defined(WOLFTPM_MLDSA) { TPM_CC_SequenceUpdate, FwCmd_SequenceUpdate, 1, 1, 0, FW_CMD_FLAG_ENC }, { TPM_CC_SequenceComplete, FwCmd_SequenceComplete, 1, 1, 0, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, +#endif +#ifndef FWTPM_NO_HASH_CMDS { TPM_CC_EventSequenceComplete, FwCmd_EventSequenceComplete, 2, 2, 0, FW_CMD_FLAG_ENC }, +#endif /* !FWTPM_NO_HASH_CMDS */ /* --- ECC --- */ #ifdef HAVE_ECC +#ifndef FWTPM_NO_ECDH { TPM_CC_ECDH_KeyGen, FwCmd_ECDH_KeyGen, 1, 0, 0, FW_CMD_FLAG_DEC }, { TPM_CC_ECDH_ZGen, FwCmd_ECDH_ZGen, 1, 1, 0, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, { TPM_CC_EC_Ephemeral, FwCmd_EC_Ephemeral, 0, 0, 0, FW_CMD_FLAG_DEC }, { TPM_CC_ZGen_2Phase, FwCmd_ZGen_2Phase, 1, 1, 0, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, +#endif /* !FWTPM_NO_ECDH */ #endif /* --- Sessions --- */ { TPM_CC_StartAuthSession, FwCmd_StartAuthSession, 2, 0, 1, 0 }, @@ -16214,14 +16257,18 @@ static const FWTPM_CMD_ENTRY fwCmdTable[] = { #endif /* !FWTPM_NO_POLICY */ /* --- Key import/export --- */ { TPM_CC_LoadExternal, FwCmd_LoadExternal, 0, 0, 1, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, +#ifndef FWTPM_NO_KEY_MIGRATION { TPM_CC_Import, FwCmd_Import, 1, 1, 0, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, { TPM_CC_Duplicate, FwCmd_Duplicate, 2, 1, 0, FW_CMD_FLAG_DEC }, { TPM_CC_Rewrap, FwCmd_Rewrap, 2, 1, 0, 0 }, +#endif /* !FWTPM_NO_KEY_MIGRATION */ { TPM_CC_CreateLoaded, FwCmd_CreateLoaded, 1, 1, 1, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, /* --- Symmetric --- */ #ifndef NO_AES +#ifndef FWTPM_NO_SYM_ENCRYPT { TPM_CC_EncryptDecrypt, FwCmd_EncryptDecrypt, 1, 1, 0, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, { TPM_CC_EncryptDecrypt2, FwCmd_EncryptDecrypt2, 1, 1, 0, FW_CMD_FLAG_ENC | FW_CMD_FLAG_DEC }, +#endif /* !FWTPM_NO_SYM_ENCRYPT */ #endif /* --- NV RAM --- */ #ifndef FWTPM_NO_NV @@ -16241,7 +16288,9 @@ static const FWTPM_CMD_ENTRY fwCmdTable[] = { #endif /* !FWTPM_NO_NV */ /* --- ECC Parameters --- */ #ifdef HAVE_ECC +#ifndef FWTPM_NO_ECDH { TPM_CC_ECC_Parameters, FwCmd_ECC_Parameters, 0, 0, 0, 0 }, +#endif /* !FWTPM_NO_ECDH */ #endif /* --- Attestation --- */ #ifndef FWTPM_NO_ATTESTATION diff --git a/wolftpm/fwtpm/fwtpm.h b/wolftpm/fwtpm/fwtpm.h index f2d99c35..db92de20 100644 --- a/wolftpm/fwtpm/fwtpm.h +++ b/wolftpm/fwtpm/fwtpm.h @@ -110,6 +110,30 @@ #define FWTPM_MAX_RANDOM_BYTES 48 #endif +/* Command feature-group toggles - opt-in macros that compile out fwTPM command + * groups a minimal build does not need. All default OFF (the full command set is + * built). Removing a group drops its handlers AND its TPM2_GetCapability + * advertisement (the command list is derived from the dispatch table). + * FWTPM_NO_POLICY - policy session commands (TPM2_Policy*) + * FWTPM_NO_ATTESTATION - Quote/Certify/CertifyCreation/GetTime/NV_Certify + * FWTPM_NO_CREDENTIAL - MakeCredential/ActivateCredential + * FWTPM_NO_DA - dictionary-attack lockout protection (see below) + * FWTPM_NO_PARAM_ENC - command/response parameter encryption + * FWTPM_NO_NV - all NV_* commands + * FWTPM_NO_KEY_MIGRATION - Import/Duplicate/Rewrap + * FWTPM_NO_ECDH - ECDH_KeyGen/ECDH_ZGen/EC_Ephemeral/ZGen_2Phase/ + * ECC_Parameters (ECDSA sign/verify are retained) + * FWTPM_NO_HASH_CMDS - Hash, HMAC, and the hash/HMAC sequence commands + * FWTPM_NO_CONTEXT - ContextSave/ContextLoad (FlushContext retained) + * FWTPM_NO_SYM_ENCRYPT - EncryptDecrypt/EncryptDecrypt2 + * FWTPM_NO_CLOCK - ReadClock/ClockSet/ClockRateAdjust + * + * These flags are independent; select exactly the command groups your fTPM does + * not need. There is intentionally no single "minimal" umbrella macro - dropping + * a command group removes real TPM functionality, so each choice must be made + * deliberately. For a worked example that picks a set for a constrained target, + * see the MicroBlaze V build in the wolftpm-examples repository. */ + /* Dictionary Attack (DA) feature toggles: * FWTPM_NO_DA - compile out all DA lockout protection. * FWTPM_DA_USED_RETRY - emulate real-TPM behavior where the first use of a