Address PR 629 review

pull/629/head
Aidan Garske 2026-10-16 11:51:10 -07:00
parent 2272ac6653
commit 334c6d0850
8 changed files with 91 additions and 82 deletions

View File

@ -49,6 +49,12 @@ jobs:
- name: "LeakSan"
cflags: "-fsanitize=leak -fno-omit-frame-pointer -g"
ldflags: "-fsanitize=leak"
- name: "ASan (small stack)"
cflags: "-fsanitize=address -fno-omit-frame-pointer -g -O1"
ldflags: "-fsanitize=address"
asan_options: "detect_leaks=0"
wolftpm_extra_config: "--enable-smallstack"
wolfssl_extra_config: "--enable-smallstack"
# Same base sanitizers, but linked against the latest wolfSSL -stable
# release instead of master.

View File

@ -499,7 +499,7 @@ typedef struct FWTPM_EventHashCopies {
* tpm2_param_enc.c (TPM2_KDFa, TPM2_KDFe, TPM2_ParamEnc_XOR,
* TPM2_ParamEnc_AESCFB). See wolftpm/tpm2_param_enc.h */
static int FwSessionIsBoundToEntity(FWTPM_CTX* ctx,
WOLFTPM_TEST_VIS int FwSessionIsBoundToEntity(FWTPM_CTX* ctx,
const FWTPM_Session* sess, TPM_HANDLE handle);
static void FwLookupEntityAuth(FWTPM_CTX* ctx, TPM_HANDLE handle,
const byte** authVal, int* authValSz);
@ -741,7 +741,7 @@ static int FwGetEntityName(FWTPM_CTX* ctx, TPM_HANDLE handle,
return 0;
}
static int FwSessionIsBoundToEntity(FWTPM_CTX* ctx,
WOLFTPM_TEST_VIS int FwSessionIsBoundToEntity(FWTPM_CTX* ctx,
const FWTPM_Session* sess, TPM_HANDLE handle)
{
byte entityName[sizeof(sess->bindName.name)];
@ -764,17 +764,6 @@ static int FwSessionIsBoundToEntity(FWTPM_CTX* ctx,
entityAuth, entityAuthSz) == 0;
}
#ifdef WOLFTPM_FWTPM_UNIT_TEST
int FWTPM_TestSessionIsBoundToEntity(FWTPM_CTX* ctx,
const FWTPM_Session* sess, TPM_HANDLE handle);
int FWTPM_TestSessionIsBoundToEntity(FWTPM_CTX* ctx,
const FWTPM_Session* sess, TPM_HANDLE handle)
{
return FwSessionIsBoundToEntity(ctx, sess, handle);
}
#endif
/** \brief Look up the authValue for an entity by its TPM handle.
* Searches hierarchies, NV indices, loaded objects, and hash sequences. */
static void FwLookupEntityAuth(FWTPM_CTX* ctx, TPM_HANDLE handle,
@ -6031,26 +6020,6 @@ static TPM_RC FwCmd_ReadPublic(FWTPM_CTX* ctx, TPM2_Packet* cmd,
return rc;
}
#ifdef WOLFTPM_FWTPM_UNIT_TEST
static int gFwTestClearRngFailure;
void FWTPM_TestSetClearRngFailure(int enabled);
void FWTPM_TestSetClearRngFailure(int enabled)
{
gFwTestClearRngFailure = enabled;
}
#endif
static int FwGenerateClearSeed(WC_RNG* rng, byte* seed, word32 seedSz)
{
#ifdef WOLFTPM_FWTPM_UNIT_TEST
if (gFwTestClearRngFailure)
return TPM_RC_FAILURE;
#endif
return wc_RNG_GenerateBlock(rng, seed, seedSz);
}
/* --- TPM2_Clear (CC 0x0126) --- */
static TPM_RC FwCmd_Clear(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize,
TPM2_Packet* rsp, UINT16 cmdTag)
@ -6094,10 +6063,10 @@ static TPM_RC FwCmd_Clear(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize,
#endif
/* Generate new storage primary seed */
rc = FwGenerateClearSeed(&ctx->rng, newOwnerSeed,
rc = wc_RNG_GenerateBlock(&ctx->rng, newOwnerSeed,
sizeof(newOwnerSeed));
if (rc == 0) {
rc = FwGenerateClearSeed(&ctx->rng, newTimeEpoch,
rc = wc_RNG_GenerateBlock(&ctx->rng, newTimeEpoch,
sizeof(newTimeEpoch));
}
if (rc != 0) rc = TPM_RC_FAILURE;
@ -17556,7 +17525,7 @@ static int FwHexNibble(char c)
/* Convert a big-endian hex value to binary. An odd leading digit is the low
* nibble of the first output byte. Returns byte count, or -1 on error. */
static int FwHexToBin(const char* hex, byte* out, int outSz)
WOLFTPM_TEST_VIS int FwHexToBin(const char* hex, byte* out, int outSz)
{
int i, len, decodedLen, outPos = 0;
int hi, lo;
@ -17586,15 +17555,6 @@ static int FwHexToBin(const char* hex, byte* out, int outSz)
return outPos;
}
#ifdef WOLFTPM_FWTPM_UNIT_TEST
int FWTPM_TestHexToBin(const char* hex, byte* out, int outSz);
int FWTPM_TestHexToBin(const char* hex, byte* out, int outSz)
{
return FwHexToBin(hex, out, outSz);
}
#endif
/* --- TPM2_ECC_Parameters (CC 0x0178) ---
* Returns curve parameters from wolfCrypt's ecc_set_type via
* wc_ecc_get_curve_params(). Automatically supports P-256, P-384,

View File

@ -375,17 +375,6 @@ static int HandleMssimSignal(FWTPM_CTX* ctx, SOCKET_T clientFd, UINT32 tssCmd)
return TransportSend(ctx, FWTPM_IO_TYPE_COMMAND, clientFd, &netVal, 4);
}
#ifdef WOLFTPM_FWTPM_UNIT_TEST
int FWTPM_IO_TestHandleMssimSignal(FWTPM_CTX* ctx, SOCKET_T clientFd,
UINT32 tssCmd);
int FWTPM_IO_TestHandleMssimSignal(FWTPM_CTX* ctx, SOCKET_T clientFd,
UINT32 tssCmd)
{
return HandleMssimSignal(ctx, clientFd, tssCmd);
}
#endif
/* --- Process and send TPM command response --- */
static int DispatchAndRespond(FWTPM_CTX* ctx, UINT32 cmdSize, int locality,
SOCKET_T clientFd, int isSwtpm)

View File

@ -25,6 +25,7 @@ FAIL=0
SKIP=0
STARTED_SERVER=0
SKIP_EXAMPLES=0
SKIP_EXAMPLES_REASON=""
# --- Helpers ---
@ -250,6 +251,15 @@ if [ -f "$WOLFTPM_OPTIONS" ]; then
if grep -q "^#define NO_GETENV" "$WOLFTPM_OPTIONS"; then
HAS_GETENV=0
fi
if [ $IS_FWTPM_MODE -eq 1 ] && \
grep -q "^#define WOLFTPM_SMALL_STACK" "$WOLFTPM_OPTIONS"; then
# fwTPM serializes private RSA state into Create responses that exceed
# the supported 1,350-byte small-stack client response buffer. The
# unit tests use ECC for those cases; skip the general example suite,
# which intentionally exercises RSA child-key creation.
SKIP_EXAMPLES=1
SKIP_EXAMPLES_REASON="fwTPM RSA responses exceed small-stack buffer"
fi
fi
# Determine mode
@ -293,6 +303,7 @@ if [ $HAS_RSA_NO_PAD -eq 0 ]; then
echo " Rebuild wolfSSL with: CFLAGS=\"-DWC_RSA_NO_PADDING\""
echo " fwTPM requires WC_RSA_NO_PADDING for RSA encrypt/decrypt"
SKIP_EXAMPLES=1
SKIP_EXAMPLES_REASON="missing WC_RSA_NO_PADDING"
fi
# --- Auto-detect feature flags for run_examples.sh ---
@ -502,7 +513,7 @@ fi
# --- Run examples ---
if [ $SKIP_EXAMPLES -eq 1 ]; then
echo "SKIP: run_examples.sh (missing WC_RSA_NO_PADDING)"
echo "SKIP: run_examples.sh ($SKIP_EXAMPLES_REASON)"
SKIP=$((SKIP + 1))
elif [ -x "$RUN_EXAMPLES" ]; then
echo ""

View File

@ -14,3 +14,12 @@
#endif
#include "../src/fwtpm/fwtpm_io.c"
int FWTPM_IO_TestHandleMssimSignal(FWTPM_CTX* ctx, SOCKET_T clientFd,
UINT32 tssCmd);
int FWTPM_IO_TestHandleMssimSignal(FWTPM_CTX* ctx, SOCKET_T clientFd,
UINT32 tssCmd)
{
return HandleMssimSignal(ctx, clientFd, tssCmd);
}

View File

@ -67,6 +67,15 @@ int FWTPM_IO_TestHandleMssimSignal(FWTPM_CTX* ctx, SOCKET_T clientFd,
UINT32 tssCmd);
#endif
#if defined(WOLFTPM_FWTPM_UNIT_TEST) && defined(HAVE_HASHDRBG)
/* wolfSSL 5.8 and older keep this Hash-DRBG state value private. */
#ifdef WC_DRBG_FAILED
#define FWTPM_TEST_DRBG_FAILED WC_DRBG_FAILED
#else
#define FWTPM_TEST_DRBG_FAILED 2
#endif
#endif
/* Test Fail Helpers (same as unit_tests.c) */
#ifndef NO_ABORT
#ifndef XABORT
@ -1518,21 +1527,19 @@ static void test_fwtpm_getcap_ecc_curves(void)
#if defined(HAVE_ECC) && !defined(FWTPM_NO_ECDH) && \
defined(WOLFTPM_FWTPM_UNIT_TEST)
int FWTPM_TestHexToBin(const char* hex, byte* out, int outSz);
static void test_fwtpm_hex_to_bin(void)
{
byte out[2];
XMEMSET(out, 0, sizeof(out));
AssertIntEQ(FWTPM_TestHexToBin("abc", out, sizeof(out)), 2);
AssertIntEQ(FwHexToBin("abc", out, sizeof(out)), 2);
AssertIntEQ(out[0], 0x0a);
AssertIntEQ(out[1], 0xbc);
AssertIntEQ(FWTPM_TestHexToBin("f", out, sizeof(out)), 1);
AssertIntEQ(FwHexToBin("f", out, sizeof(out)), 1);
AssertIntEQ(out[0], 0x0f);
AssertIntEQ(FWTPM_TestHexToBin("0g", out, sizeof(out)), -1);
AssertIntEQ(FWTPM_TestHexToBin("1234", out, 1), -1);
AssertIntEQ(FWTPM_TestHexToBin(NULL, out, sizeof(out)), -1);
AssertIntEQ(FwHexToBin("0g", out, sizeof(out)), -1);
AssertIntEQ(FwHexToBin("1234", out, 1), -1);
AssertIntEQ(FwHexToBin(NULL, out, sizeof(out)), -1);
fwtpm_pass("ECC parameter hex decoding:", 0);
}
@ -10343,7 +10350,7 @@ static UINT32 StartSessionHelper(FWTPM_CTX* ctx, UINT8 sessType)
}
#ifdef WOLFTPM_FWTPM_UNIT_TEST
int FWTPM_TestSessionIsBoundToEntity(FWTPM_CTX* ctx,
int FwSessionIsBoundToEntity(FWTPM_CTX* ctx,
const FWTPM_Session* sess, TPM_HANDLE handle);
static void test_fwtpm_bound_session_auth_change(void)
@ -10363,10 +10370,10 @@ static void test_fwtpm_bound_session_auth_change(void)
sess.bindAuth.size = (UINT16)sizeof(oldAuth);
XMEMCPY(sess.bindAuth.buffer, oldAuth, sizeof(oldAuth));
AssertIntEQ(FWTPM_TestSessionIsBoundToEntity(&ctx, &sess,
AssertIntEQ(FwSessionIsBoundToEntity(&ctx, &sess,
TPM_RH_OWNER), 1);
XMEMCPY(ctx.ownerAuth.buffer, newAuth, sizeof(newAuth));
AssertIntEQ(FWTPM_TestSessionIsBoundToEntity(&ctx, &sess,
AssertIntEQ(FwSessionIsBoundToEntity(&ctx, &sess,
TPM_RH_OWNER), 0);
TPM2_ForceZero(&ctx, sizeof(ctx));
@ -14012,9 +14019,7 @@ static void test_fwtpm_clear(void)
fwtpm_pass("Clear preserves endorsement seed:", 0);
}
#ifdef WOLFTPM_FWTPM_UNIT_TEST
void FWTPM_TestSetClearRngFailure(int enabled);
#if defined(WOLFTPM_FWTPM_UNIT_TEST) && defined(HAVE_HASHDRBG)
/* A failed seed replacement must leave the live hierarchy state unchanged. */
static void test_fwtpm_clear_rng_failure_atomic(void)
{
@ -14022,6 +14027,7 @@ static void test_fwtpm_clear_rng_failure_atomic(void)
TPM2B_AUTH ownerAuth;
TPM2B_AUTH endorsementAuth;
byte ownerSeed[FWTPM_SEED_SIZE];
byte rngStatus;
XMEMSET(&ctx, 0, sizeof(ctx));
AssertIntEQ(fwtpm_test_startup(&ctx), TPM_RC_SUCCESS);
@ -14034,10 +14040,12 @@ static void test_fwtpm_clear_rng_failure_atomic(void)
sizeof(endorsementAuth));
XMEMCPY(ownerSeed, ctx.ownerSeed, sizeof(ownerSeed));
FWTPM_TestSetClearRngFailure(1);
/* Use wolfCrypt's real failed-DRBG path instead of a library test hook. */
rngStatus = ctx.rng.status;
ctx.rng.status = FWTPM_TEST_DRBG_FAILED;
AssertIntEQ(SendSimpleSessionCmd(&ctx, TPM_CC_Clear, TPM_RH_LOCKOUT),
TPM_RC_FAILURE);
FWTPM_TestSetClearRngFailure(0);
ctx.rng.status = rngStatus;
AssertIntEQ(ctx.pendingClear, 0);
AssertIntEQ(XMEMCMP(&ctx.ownerAuth, &ownerAuth, sizeof(ownerAuth)), 0);
AssertIntEQ(XMEMCMP(&ctx.endorsementAuth, &endorsementAuth,
@ -14050,7 +14058,7 @@ static void test_fwtpm_clear_rng_failure_atomic(void)
FWTPM_Cleanup(&ctx);
fwtpm_pass("Clear RNG failure is atomic:", 0);
}
#endif /* WOLFTPM_FWTPM_UNIT_TEST */
#endif /* WOLFTPM_FWTPM_UNIT_TEST && HAVE_HASHDRBG */
#ifndef FWTPM_NO_NV
static int fail_nv_write(void* ctx, word32 offset, const byte* buf,
@ -18197,12 +18205,12 @@ int fwtpm_unit_tests(int argc, char *argv[])
test_fwtpm_clear();
return 0;
}
#ifdef WOLFTPM_FWTPM_UNIT_TEST
#if defined(WOLFTPM_FWTPM_UNIT_TEST) && defined(HAVE_HASHDRBG)
if (argc == 2 && XSTRCMP(argv[1], "clear-rng-failure") == 0) {
test_fwtpm_clear_rng_failure_atomic();
return 0;
}
#endif /* WOLFTPM_FWTPM_UNIT_TEST */
#endif /* WOLFTPM_FWTPM_UNIT_TEST && HAVE_HASHDRBG */
#if !defined(FWTPM_NO_POLICY) && !defined(NO_RSA) && \
defined(WOLFSSL_KEY_GEN)
if (argc == 2 && XSTRCMP(argv[1], "clear-child") == 0) {
@ -18690,9 +18698,9 @@ int fwtpm_unit_tests(int argc, char *argv[])
test_fwtpm_nv_delete_at_capacity();
test_fwtpm_nv_stclear_startup();
#endif /* !FWTPM_NO_NV */
#ifdef WOLFTPM_FWTPM_UNIT_TEST
#if defined(WOLFTPM_FWTPM_UNIT_TEST) && defined(HAVE_HASHDRBG)
test_fwtpm_clear_rng_failure_atomic();
#endif /* WOLFTPM_FWTPM_UNIT_TEST */
#endif /* WOLFTPM_FWTPM_UNIT_TEST && HAVE_HASHDRBG */
test_fwtpm_clear();
#if defined(WOLFTPM_FWTPM_UNIT_TEST) && !defined(_WIN32)

View File

@ -2288,7 +2288,11 @@ static void test_wolfTPM2_BoundSession_EmptyAuth_ParamEnc(void)
WOLFTPM2_KEY child;
WOLFTPM2_SESSION session;
TPMT_PUBLIC publicTemplate;
#if !defined(NO_RSA)
#if defined(WOLFTPM_SMALL_STACK) && defined(WOLFTPM_FWTPM_BUILD) && \
defined(HAVE_ECC)
/* RSA Create responses exceed the reduced small-stack response buffer. */
TPM_ALG_ID srkAlg = TPM_ALG_ECC;
#elif !defined(NO_RSA)
TPM_ALG_ID srkAlg = TPM_ALG_RSA;
#else
TPM_ALG_ID srkAlg = TPM_ALG_ECC;
@ -2329,7 +2333,13 @@ static void test_wolfTPM2_BoundSession_EmptyAuth_ParamEnc(void)
AssertIntEQ(rc, TPM_RC_SUCCESS);
/* Create+load a child under the EmptyAuth SRK; fails pre-fix. */
#if !defined(NO_RSA)
#if defined(WOLFTPM_SMALL_STACK) && defined(WOLFTPM_FWTPM_BUILD) && \
defined(HAVE_ECC)
rc = wolfTPM2_GetKeyTemplate_ECC(&publicTemplate,
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_sign | TPMA_OBJECT_noDA,
TPM_ECC_NIST_P256, TPM_ALG_ECDSA);
#elif !defined(NO_RSA)
rc = wolfTPM2_GetKeyTemplate_RSA(&publicTemplate,
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_sign | TPMA_OBJECT_noDA);
@ -2368,7 +2378,11 @@ static void test_wolfTPM2_CreateLoaded_ParamEnc(void)
WOLFTPM2_KEYBLOB child;
WOLFTPM2_SESSION session;
TPMT_PUBLIC publicTemplate;
#if !defined(NO_RSA)
#if defined(WOLFTPM_SMALL_STACK) && defined(WOLFTPM_FWTPM_BUILD) && \
defined(HAVE_ECC)
/* RSA CreateLoaded responses exceed the small-stack response buffer. */
TPM_ALG_ID srkAlg = TPM_ALG_ECC;
#elif !defined(NO_RSA)
TPM_ALG_ID srkAlg = TPM_ALG_RSA;
#else
TPM_ALG_ID srkAlg = TPM_ALG_ECC;
@ -2405,7 +2419,13 @@ static void test_wolfTPM2_CreateLoaded_ParamEnc(void)
TPMA_SESSION_continueSession));
AssertIntEQ(rc, TPM_RC_SUCCESS);
#if !defined(NO_RSA)
#if defined(WOLFTPM_SMALL_STACK) && defined(WOLFTPM_FWTPM_BUILD) && \
defined(HAVE_ECC)
rc = wolfTPM2_GetKeyTemplate_ECC(&publicTemplate,
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_sign | TPMA_OBJECT_noDA,
TPM_ECC_NIST_P256, TPM_ALG_ECDSA);
#elif !defined(NO_RSA)
rc = wolfTPM2_GetKeyTemplate_RSA(&publicTemplate,
TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_sign | TPMA_OBJECT_noDA);
@ -10306,7 +10326,10 @@ int unit_tests(int argc, char *argv[])
!defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC)
test_readKeyBlob_PrivOverflow();
#endif
/* An RSA Create response does not fit the reduced small-stack buffer. */
#if !defined(WOLFTPM_SMALL_STACK) || !defined(WOLFTPM_FWTPM_BUILD)
test_wolfTPM2_KeyBlob(TPM_ALG_RSA);
#endif
test_wolfTPM2_KeyBlob(TPM_ALG_ECC);
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \
!defined(WOLFTPM2_NO_ASN)

View File

@ -66,7 +66,7 @@ WOLFTPM_API int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
*/
WOLFTPM_API void FWTPM_ResetCommandClient(FWTPM_CTX* ctx);
/* Internal crypto helpers exposed only to the fwTPM unit-test build. */
/* Internal helpers exposed only to the fwTPM unit-test build. */
#ifdef WOLFTPM_FWTPM_UNIT_TEST
#define WOLFTPM_TEST_VIS
int FwHashOneShot(TPMI_ALG_HASH hashAlg,
@ -83,6 +83,9 @@ WOLFTPM_API void FWTPM_ResetCommandClient(FWTPM_CTX* ctx);
const byte* authValue, int authValueSz,
const TPM2B_NONCE* nonceDecrypt, const TPM2B_NONCE* nonceEncrypt,
int isResponse, byte* hmacOut, int* hmacOutSz);
#ifndef FWTPM_NO_ECDH
int FwHexToBin(const char* hex, byte* out, int outSz);
#endif
#else
#define WOLFTPM_TEST_VIS static
#endif