Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/fwtpm-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions docs/FWTPM.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) |
Expand Down Expand Up @@ -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 |
Expand Down
3 changes: 2 additions & 1 deletion src/fwtpm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions src/fwtpm/fwtpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
41 changes: 34 additions & 7 deletions src/fwtpm/fwtpm_nv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 &&
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down
81 changes: 81 additions & 0 deletions tests/fwtpm_unit_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
7 changes: 5 additions & 2 deletions wolftpm/fwtpm/fwtpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
Loading