Reduce FWTPM_NO_NV context memory

pull/610/head
Aidan Garske 2026-09-16 10:41:13 -07:00
parent c3c0621333
commit 64a6437e0e
7 changed files with 139 additions and 12 deletions

View File

@ -439,6 +439,13 @@ jobs:
wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen
extra_cflags: -DIMPLEMENTATION_PCR=8 -DPLATFORM_PCR=8
# FWTPM_NO_NV has distinct volatile-only initialization and context
# layout, so run the handler suite in addition to the build-only leg.
- name: no-nv
wolftpm_config: --enable-fwtpm --enable-swtpm
wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen
extra_cflags: -DFWTPM_NO_NV
steps:
- name: Checkout wolfTPM
uses: actions/checkout@v4

View File

@ -559,7 +559,7 @@ All macros are compile-time overridable (e.g., `-DFWTPM_MAX_OBJECTS=8`).
| `FWTPM_MAX_HASH_SEQ` | 4 | Maximum concurrent hash/HMAC sequences |
| `FWTPM_MAX_PRIMARY_CACHE` | 16 | Cached primary keys per hierarchy+template |
| `FWTPM_MAX_SESSIONS` | 8 | Maximum concurrent auth sessions |
| `FWTPM_MAX_NV_INDICES` | 16 | Maximum NV RAM index slots |
| `FWTPM_MAX_NV_INDICES` | 16 | Maximum NV RAM index slots; omitted from `FWTPM_CTX` with `FWTPM_NO_NV` |
| `FWTPM_MAX_NV_DATA` | 2048 | Maximum data per NV index (bytes) |
| `FWTPM_DA_DEFAULT_MAX_TRIES` | 32 | DA failed-auth count before lockout |
| `FWTPM_DA_DEFAULT_RECOVERY` | 600 | DA self-heal interval (seconds per try) |
@ -665,7 +665,7 @@ to reduce code size on constrained targets.
| Macro | Default | Commands Excluded |
|-------|---------|-------------------|
| `FWTPM_NO_ATTESTATION` | not defined | `Quote`, `Certify`, `CertifyCreation`, `GetTime`, `NV_Certify` |
| `FWTPM_NO_NV` | not defined | `NV_DefineSpace`, `NV_UndefineSpace`, `NV_ReadPublic`, `NV_Write`, `NV_Read`, `NV_Extend`, `NV_Increment`, `NV_WriteLock`, `NV_ReadLock`, `NV_Certify` |
| `FWTPM_NO_NV` | not defined | `NV_DefineSpace`, `NV_UndefineSpace`, `NV_ReadPublic`, `NV_Write`, `NV_Read`, `NV_Extend`, `NV_Increment`, `NV_WriteLock`, `NV_ReadLock`, `NV_Certify`; also removes the in-memory NV index slots from `FWTPM_CTX` |
| `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 |

View File

@ -250,7 +250,8 @@ EncryptDecrypt, EncryptDecrypt2
- `FWTPM_NO_NV`: NV\_DefineSpace, NV\_UndefineSpace, NV\_UndefineSpaceSpecial,
NV\_ReadPublic, NV\_Write, NV\_Read, NV\_Extend, NV\_Increment, NV\_WriteLock,
NV\_ReadLock, NV\_SetBits, NV\_ChangeAuth, NV\_GlobalWriteLock (13 commands).
Also gates PolicyNV and PolicyAuthorizeNV when policy is enabled.
Also gates PolicyNV and PolicyAuthorizeNV when policy is enabled and removes
the `FWTPM_CTX` in-memory NV index slots.
- `FWTPM_NO_ATTESTATION`: Quote, Certify, CertifyCreation, GetTime, NV\_Certify
- `FWTPM_NO_CREDENTIAL`: MakeCredential, ActivateCredential
- `FWTPM_NO_DA`: DictionaryAttackLockReset, DictionaryAttackParameters (2 commands)

View File

@ -137,6 +137,14 @@ int FWTPM_Init(FWTPM_CTX* ctx)
if (rc == 0) {
ctx->pcrAllocatedBanks = FWTPM_PCR_ALLOC_DEFAULT;
}
#ifndef FWTPM_NO_DA
if (rc == 0) {
ctx->daMaxTries = FWTPM_DA_DEFAULT_MAX_TRIES;
ctx->daRecoveryTime = FWTPM_DA_DEFAULT_RECOVERY;
ctx->daLockoutRecovery = FWTPM_DA_DEFAULT_LOCKOUT_RECOVERY;
ctx->orderly = 1;
}
#endif
#endif
if (rc != 0) {

View File

@ -469,6 +469,7 @@ static int FwNvUnmarshalName(const byte* buf, word32* pos, word32 maxSz,
return rc;
}
#ifndef FWTPM_NO_NV
/* Marshal TPMS_NV_PUBLIC manually (no packet function exists) */
static int FwNvMarshalNvPublic(byte* buf, word32* pos, word32 maxSz,
const TPMS_NV_PUBLIC* nvPub)
@ -603,6 +604,7 @@ static int FwNvUnmarshalNvIndex(const byte* buf, word32* pos, word32 maxSz,
}
return rc;
}
#endif /* !FWTPM_NO_NV */
/* Marshal FWTPM_Object → value bytes */
static int FwNvMarshalObject(byte* buf, word32* pos, word32 maxSz,
@ -1115,21 +1117,24 @@ static int FwNvTagIsDelete(UINT16 tag)
static int FwNvAppendEntry(FWTPM_CTX* ctx, UINT16 tag,
const byte* value, UINT16 valueLen)
{
FWTPM_NV_HAL* hal = &ctx->nvHal;
FWTPM_NV_HAL* hal;
word32 entrySize = TLV_HDR_SIZE + valueLen;
word32 reserve = FWTPM_NV_MAC_SIZE;
byte tlvHdr[TLV_HDR_SIZE];
word32 savedWritePos;
int rc;
if (hal->write == NULL) {
#ifdef FWTPM_NO_NV
/* Volatile-only build: there is no backing store, so a state change
* succeeds without being persisted rather than reporting a failure. */
return TPM_RC_SUCCESS;
#else
return TPM_RC_FAILURE;
(void)ctx;
(void)tag;
(void)value;
(void)valueLen;
return TPM_RC_SUCCESS;
#endif
hal = &ctx->nvHal;
if (hal->write == NULL) {
return TPM_RC_FAILURE;
}
#ifdef WOLFTPM_FWTPM_NV_APPEND_ONLY
@ -1218,6 +1223,7 @@ static int FwNvAppendEntry(FWTPM_CTX* ctx, UINT16 tag,
/* Journal Load (Init) */
/* ========================================================================= */
#ifndef FWTPM_NO_NV
/* Find NV index slot by handle, or allocate empty slot */
static int FwNvFindOrAllocNvSlot(FWTPM_CTX* ctx, UINT32 nvHandle)
{
@ -1235,6 +1241,7 @@ static int FwNvFindOrAllocNvSlot(FWTPM_CTX* ctx, UINT32 nvHandle)
}
return freeSlot;
}
#endif /* !FWTPM_NO_NV */
/* Find persistent object slot by handle, or allocate empty slot */
static int FwNvFindOrAllocPersSlot(FWTPM_CTX* ctx, UINT32 handle)
@ -1440,6 +1447,7 @@ static int FwNvProcessEntry(FWTPM_CTX* ctx, UINT16 tag,
break;
}
#ifndef FWTPM_NO_NV
case FWTPM_NV_TAG_NV_INDEX: {
FWTPM_NvIndex nv;
int slot;
@ -1469,6 +1477,7 @@ static int FwNvProcessEntry(FWTPM_CTX* ctx, UINT16 tag,
}
break;
}
#endif /* !FWTPM_NO_NV */
case FWTPM_NV_TAG_PERSISTENT: {
FWTPM_Object obj;
@ -1996,6 +2005,10 @@ int FWTPM_NV_Save(FWTPM_CTX* ctx)
return BAD_FUNC_ARG;
}
#ifdef FWTPM_NO_NV
return TPM_RC_SUCCESS;
#endif
hal = &ctx->nvHal;
if (hal->write == NULL) {
return TPM_RC_FAILURE;
@ -2200,6 +2213,7 @@ int FWTPM_NV_Save(FWTPM_CTX* ctx)
}
}
#ifndef FWTPM_NO_NV
/* --- NV indices (only used slots, minus a pending deletion) --- */
for (i = 0; i < FWTPM_MAX_NV_INDICES && rc == 0; i++) {
if (ctx->nvIndices[i].inUse &&
@ -2230,6 +2244,7 @@ int FWTPM_NV_Save(FWTPM_CTX* ctx)
}
}
}
#endif /* !FWTPM_NO_NV */
/* --- Persistent objects (only used slots, minus a pending deletion) --- */
for (i = 0; i < FWTPM_MAX_PERSISTENT && rc == 0; i++) {
@ -2546,6 +2561,11 @@ int FWTPM_NV_SaveHierarchyPolicy(FWTPM_CTX* ctx, UINT32 hierarchy)
int FWTPM_NV_SaveNvIndex(FWTPM_CTX* ctx, int slot)
{
#ifdef FWTPM_NO_NV
(void)ctx;
(void)slot;
return NOT_COMPILED_IN;
#else
int rc;
byte* buf;
word32 pos = 0;
@ -2580,10 +2600,16 @@ int FWTPM_NV_SaveNvIndex(FWTPM_CTX* ctx, int slot)
TPM2_ForceZero(buf, bufSz);
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return rc;
#endif /* FWTPM_NO_NV */
}
int FWTPM_NV_DeleteNvIndex(FWTPM_CTX* ctx, UINT32 nvHandle)
{
#ifdef FWTPM_NO_NV
(void)ctx;
(void)nvHandle;
return NOT_COMPILED_IN;
#else
int rc;
byte buf[4];
word32 pos = 0;
@ -2597,6 +2623,7 @@ int FWTPM_NV_DeleteNvIndex(FWTPM_CTX* ctx, UINT32 nvHandle)
rc = FwNvAppendEntry(ctx, FWTPM_NV_TAG_NV_INDEX_DEL, buf, (UINT16)pos);
ctx->nvDeleteHandle = 0;
return rc;
#endif /* FWTPM_NO_NV */
}
int FWTPM_NV_SavePersistent(FWTPM_CTX* ctx, int slot)

View File

@ -227,6 +227,84 @@ static int fwtpm_test_startup(FWTPM_CTX* ctx)
/* 1. Core Lifecycle Tests */
/* ================================================================== */
#ifdef FWTPM_NO_NV
static int gNoNvHalCalls;
static int test_no_nv_hal_read(void* userCtx, word32 offset, byte* data,
word32 dataSz)
{
(void)userCtx;
(void)offset;
(void)data;
(void)dataSz;
gNoNvHalCalls++;
return TPM_RC_FAILURE;
}
static int test_no_nv_hal_write(void* userCtx, word32 offset,
const byte* data, word32 dataSz)
{
(void)userCtx;
(void)offset;
(void)data;
(void)dataSz;
gNoNvHalCalls++;
return TPM_RC_FAILURE;
}
static int test_no_nv_hal_erase(void* userCtx, word32 offset, word32 dataSz)
{
(void)userCtx;
(void)offset;
(void)dataSz;
gNoNvHalCalls++;
return TPM_RC_FAILURE;
}
static void test_fwtpm_no_nv_volatile(void)
{
FWTPM_CTX ctx;
FWTPM_NV_HAL hal;
memset(&ctx, 0, sizeof(ctx));
memset(&hal, 0, sizeof(hal));
hal.read = test_no_nv_hal_read;
hal.write = test_no_nv_hal_write;
hal.erase = test_no_nv_hal_erase;
hal.maxSize = 4096;
AssertIntEQ(FWTPM_NV_SetHAL(&ctx, &hal), TPM_RC_SUCCESS);
gNoNvHalCalls = 0;
AssertIntEQ(FWTPM_Init(&ctx), TPM_RC_SUCCESS);
#ifndef FWTPM_NO_DA
AssertIntEQ((int)ctx.daMaxTries, FWTPM_DA_DEFAULT_MAX_TRIES);
AssertIntEQ((int)ctx.daRecoveryTime, FWTPM_DA_DEFAULT_RECOVERY);
AssertIntEQ((int)ctx.daLockoutRecovery,
FWTPM_DA_DEFAULT_LOCKOUT_RECOVERY);
AssertIntEQ(ctx.orderly, 1);
#endif
AssertIntEQ(FWTPM_NV_Save(&ctx), TPM_RC_SUCCESS);
AssertIntEQ(FWTPM_NV_SaveSeeds(&ctx), TPM_RC_SUCCESS);
AssertIntEQ(FWTPM_NV_SaveAuth(&ctx, TPM_RH_OWNER), TPM_RC_SUCCESS);
AssertIntEQ(FWTPM_NV_SavePcrState(&ctx), TPM_RC_SUCCESS);
AssertIntEQ(FWTPM_NV_SavePcrAuth(&ctx), TPM_RC_SUCCESS);
AssertIntEQ(FWTPM_NV_SaveFlags(&ctx), TPM_RC_SUCCESS);
AssertIntEQ(FWTPM_NV_SaveClock(&ctx), TPM_RC_SUCCESS);
AssertIntEQ(FWTPM_NV_SaveHierarchyPolicy(&ctx, TPM_RH_OWNER),
TPM_RC_SUCCESS);
AssertIntEQ(FWTPM_NV_SaveNvIndex(&ctx, 0), NOT_COMPILED_IN);
AssertIntEQ(FWTPM_NV_SaveNvIndex(NULL, -1), NOT_COMPILED_IN);
AssertIntEQ(FWTPM_NV_DeleteNvIndex(&ctx, NV_INDEX_FIRST),
NOT_COMPILED_IN);
AssertIntEQ(FWTPM_NV_DeleteNvIndex(NULL, 0), NOT_COMPILED_IN);
AssertIntEQ(gNoNvHalCalls, 0);
AssertIntEQ(FWTPM_Cleanup(&ctx), TPM_RC_SUCCESS);
AssertIntEQ(gNoNvHalCalls, 0);
fwtpm_pass("No-NV volatile state:", 0);
}
#endif /* FWTPM_NO_NV */
static void test_fwtpm_init_cleanup(void)
{
FWTPM_CTX ctx;
@ -15496,6 +15574,9 @@ int fwtpm_unit_tests(int argc, char *argv[])
(void)remove(FWTPM_NV_FILE);
/* Lifecycle */
#ifdef FWTPM_NO_NV
test_fwtpm_no_nv_volatile();
#endif
test_fwtpm_init_cleanup();
test_fwtpm_startup_clear();
test_fwtpm_double_startup();

View File

@ -128,7 +128,7 @@
* 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_NV - all NV_* commands and in-memory NV index slots
* 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)
@ -795,8 +795,11 @@ typedef struct FWTPM_CTX {
/* Persistent object slots (0x81xxxxxx handles via EvictControl) */
FWTPM_Object persistent[FWTPM_MAX_PERSISTENT];
/* NV index slots (0x01xxxxxx handles) */
/* NV index slots (0x01xxxxxx handles). They are the dominant fixed RAM
* cost of the NV command group, so omit them when that group is disabled. */
#ifndef FWTPM_NO_NV
FWTPM_NvIndex nvIndices[FWTPM_MAX_NV_INDICES];
#endif
/* Hash sequence slots */
#ifndef FWTPM_NO_HASH_CMDS