Merge pull request #491 from aidangarske/fenrir-fixes-9

fwTPM/SPDM/src corrections and unit test additions
pull/492/head
David Garske 2026-04-21 16:01:57 -07:00 committed by GitHub
commit 423ce0dc71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 452 additions and 89 deletions

View File

@ -63,7 +63,7 @@
#define LOG(t) { printf(__FILE__":%i: %s\n", __LINE__, t); }
#define READ_BE16(dest, buf, size, off) { \
if (off + sizeof(dest) >= size) { \
if (off + sizeof(dest) > size) { \
LOG("FW file too short"); \
return -1; \
} \
@ -73,7 +73,7 @@
}
#define READ_BE32(dest, buf, size, off) { \
if (off + sizeof(dest) >= size) { \
if (off + sizeof(dest) > size) { \
LOG("FW file too short"); \
return -1; \
} \
@ -172,7 +172,7 @@ static int extractFW(
}
READ_BE32(size32, fw, fw_size, offset);
if (offset + size32 >= fw_size) {
if (offset + size32 > fw_size) {
LOG("FW file too short");
return -1;
}

View File

@ -170,7 +170,7 @@ int TPM2_IFX_Firmware_Update(void* userCtx, int argc, char *argv[])
else {
printf("Success: Please reset or power cycle TPM\n");
}
return rc;
goto exit;
}
if (manifest_file == NULL || firmware_file == NULL) {

View File

@ -264,7 +264,7 @@ int TPM2_ST33_Firmware_Update(void* userCtx, int argc, char *argv[])
else {
printf("Success: Please reset or power cycle TPM\n");
}
return rc;
goto exit;
}
if (fi_file == NULL) {

View File

@ -98,12 +98,17 @@ int TPM2_PCR_Quote_Test(void* userCtx, int argc, char *argv[])
/* Advanced usage */
if (argv[1][0] != '-') {
if (pcrIndex < 0 || pcrIndex > 23 || *argv[1] < '0' || *argv[1] > '9') {
if (*argv[1] < '0' || *argv[1] > '9') {
printf("PCR index is out of range (0-23)\n");
usage();
return 0;
}
pcrIndex = XATOI(argv[1]);
if (pcrIndex < 0 || pcrIndex > 23) {
printf("PCR index is out of range (0-23)\n");
usage();
return 0;
}
}
if (argc >= 3 && argv[2][0] != '-')
outputFile = argv[2];

View File

@ -115,10 +115,14 @@ static int PKCS7_SignVerifyEx(WOLFTPM2_DEV* dev, int tpmDevId,
XMEMSET(&pkcs7, 0, sizeof(pkcs7));
hashSz = wc_HashGetDigestSize(hashType);
if (hashSz <= 0) {
return hashSz;
rc = wc_HashGetDigestSize(hashType);
if (rc <= 0) {
/* Preserve the wolfCrypt error on negatives; for a 0 return
* (not currently produced by wolfCrypt), report BAD_FUNC_ARG
* rather than masquerading as success. */
return (rc < 0) ? rc : BAD_FUNC_ARG;
}
hashSz = (word32)rc;
/* calculate hash for content */
rc = wc_HashInit(&hash, hashType);

View File

@ -186,7 +186,7 @@
#include <Qspi/SpiMaster/IfxQspi_SpiMaster.h>
/* externally declared SPI master channel */
extern IfxQspi_SpiMaster_Channel spiMasterChannel
extern IfxQspi_SpiMaster_Channel spiMasterChannel;
static int TPM2_IoCb_Infineon_TriCore_SPI(TPM2_CTX* ctx, const byte* txBuf,
byte* rxBuf, word16 xferSz, void* userCtx)

View File

@ -223,6 +223,8 @@
return -1;
}
busy_retry = TPM_I2C_TRIES;
while (I2C_BB_IsBusy() && --busy_retry > 0) {
microchip_wait(250);
}

View File

@ -429,6 +429,46 @@ static void FwLookupEntityAuth(FWTPM_CTX* ctx, TPM_HANDLE handle,
}
}
/* Constant-time password vs authValue comparison.
* Iterates a fixed upper bound (TPM_MAX_DIGEST_SIZE) with bitwise masks so
* neither the trip count nor per-iteration work depends on the secret
* authValSz. Trailing zeros on either side are treated as insignificant
* (matches TCG reference for authValues padded to nameAlg digest size).
* Returns 1 on mismatch, 0 on match. Precondition: pwSz and avSz must
* each be <= TPM_MAX_DIGEST_SIZE; out-of-range inputs fail closed. */
static int FwCtAuthCompare(const byte* password, int pwSz,
const byte* authVal, int avSz)
{
byte zeroAuth[TPM_MAX_DIGEST_SIZE];
const byte* avPtr;
volatile byte diff = 0;
int ci;
if (pwSz < 0 || avSz < 0 ||
pwSz > TPM_MAX_DIGEST_SIZE || avSz > TPM_MAX_DIGEST_SIZE) {
return 1;
}
XMEMSET(zeroAuth, 0, sizeof(zeroAuth));
avPtr = (authVal != NULL) ? authVal : zeroAuth;
for (ci = 0; ci < TPM_MAX_DIGEST_SIZE; ci++) {
/* 0xFF if ci < bound, else 0x00. Use UINT32 (guaranteed 32-bit
* wolfTPM typedef) so the >> 31 shift is always well-defined. */
byte pwMask = (byte)-((UINT32)(ci - pwSz) >> 31);
byte avMask = (byte)-((UINT32)(ci - avSz) >> 31);
byte overlap = (byte)(pwMask & avMask);
/* Overlap region: bytes must match */
diff |= (byte)((password[ci] ^ avPtr[ci]) & overlap);
/* Trailing bytes of pw past avSz must be zero */
diff |= (byte)(password[ci] & (pwMask & (byte)~avMask));
/* Trailing bytes of av past pwSz must be zero */
diff |= (byte)(avPtr[ci] & (avMask & (byte)~pwMask));
}
return ((int)diff != 0) ? 1 : 0;
}
/* Compute cpHash = H(commandCode || name1 || ... || cpBuffer)
* Per TPM 2.0 Part 1 Section 18.7 */
static int FwComputeCpHash(TPMI_ALG_HASH hashAlg, TPM_CC cmdCode,
@ -9975,6 +10015,7 @@ static TPM_RC FwCmd_NV_DefineSpace(FWTPM_CTX* ctx, TPM2_Packet* cmd,
FwRspNoParams(rsp, cmdTag);
}
TPM2_ForceZero(&auth, sizeof(auth));
return rc;
}
@ -12719,9 +12760,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
int doEncRsp = 0; /* Encrypt outgoing response param */
#endif
int pj, hj; /* Loop indices for auth validation */
int pwSz, avSz, maxSz, minSz, authFail; /* Password comparison */
volatile byte diff;
int ci;
int authFail; /* Password comparison result */
if (ctx == NULL || cmdBuf == NULL || rspBuf == NULL || rspSize == NULL) {
return BAD_FUNC_ARG;
@ -13085,29 +13124,8 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
FwLookupEntityAuth(ctx, entityH, &authVal, &authValSz);
/* Compare password with authValue in constant time.
* Per TCG reference implementation, trailing zeros are
* insignificant (handles authValues padded to nameAlg
* digest size). We compare up to the max of both sizes
* and verify trailing bytes are zero, all in constant
* time to avoid leaking the effective auth length. */
diff = 0;
pwSz = (int)cmdAuths[pj].passwordSize;
avSz = authValSz;
maxSz = (pwSz > avSz) ? pwSz : avSz;
minSz = (pwSz < avSz) ? pwSz : avSz;
/* Compare overlapping portion */
for (ci = 0; ci < minSz; ci++) {
diff |= cmdAuths[pj].password[ci] ^ authVal[ci];
}
/* Verify trailing bytes of the longer buffer are zero */
for (ci = minSz; ci < maxSz; ci++) {
if (ci < pwSz)
diff |= cmdAuths[pj].password[ci];
if (ci < avSz)
diff |= authVal[ci];
}
authFail = ((int)diff != 0);
authFail = FwCtAuthCompare(cmdAuths[pj].password,
(int)cmdAuths[pj].passwordSize, authVal, authValSz);
if (authFail) {
#ifdef DEBUG_WOLFTPM
printf("fwTPM: Password auth failed for handle "

View File

@ -540,6 +540,178 @@ static int test_mitm_signature_rejected(void)
TEST_PASS();
}
/* Drive wolfSPDM_ParseKeyExchangeRsp past the signature check and exercise
* the ResponderVerifyData HMAC compare. The fixture reuses a single P-384
* key pair as both requester and responder identity so the test can
* produce a signature that the parse path will accept; everything after
* (ECDH, KDF, HMAC) then runs on real inputs. */
static int test_key_exchange_rsp_hmac_check(void)
{
byte keRsp[300];
const word32 keRspLen = 282;
const word32 keRspPartialLen = 138;
ecc_key ltKey;
ecc_key respEphem;
ecc_key ourPubKey;
byte ltPriv[48], ltPubX[48], ltPubY[48], ltPub[96];
word32 ltPrivSz = 48, ltPubXSz = 48, ltPubYSz = 48;
byte respPubX[48], respPubY[48];
word32 respPubXSz = 48, respPubYSz = 48;
byte ourPubX[48], ourPubY[48];
word32 ourXSz = 48, ourYSz = 48;
byte sharedSecret[64];
word32 sharedSz = sizeof(sharedSecret);
byte signMsg[160];
word32 signMsgLen = 0;
byte th1SigHash[WOLFSPDM_HASH_SIZE];
byte signMsgHash[WOLFSPDM_HASH_SIZE];
byte th1[WOLFSPDM_HASH_SIZE];
byte sigRaw[WOLFSPDM_ECC_SIG_SIZE];
word32 sigRawSz = WOLFSPDM_ECC_SIG_SIZE;
byte expectedHmac[WOLFSPDM_HASH_SIZE];
const char* ctxStr = "responder-key_exchange_rsp signing";
const word32 ctxStrLen = 34;
word32 zeroPadLen;
int i, rc;
WOLFSPDM_CTX helperBuf;
WOLFSPDM_CTX* helper = &helperBuf;
TEST_CTX_SETUP_V12();
printf("test_key_exchange_rsp_hmac_check...\n");
/* Long-term P-384 key, shared between requester (for test signing)
* and responder (for parse verification) */
ASSERT_SUCCESS(wc_ecc_init(&ltKey));
ASSERT_SUCCESS(wc_ecc_make_key(&ctx->rng, 48, &ltKey));
ASSERT_SUCCESS(wc_ecc_export_private_only(&ltKey, ltPriv, &ltPrivSz));
ASSERT_SUCCESS(wc_ecc_export_public_raw(&ltKey,
ltPubX, &ltPubXSz, ltPubY, &ltPubYSz));
if (ltPrivSz < 48) {
XMEMMOVE(ltPriv + (48 - ltPrivSz), ltPriv, ltPrivSz);
XMEMSET(ltPriv, 0, 48 - ltPrivSz);
}
if (ltPubXSz < 48) {
XMEMMOVE(ltPubX + (48 - ltPubXSz), ltPubX, ltPubXSz);
XMEMSET(ltPubX, 0, 48 - ltPubXSz);
}
if (ltPubYSz < 48) {
XMEMMOVE(ltPubY + (48 - ltPubYSz), ltPubY, ltPubYSz);
XMEMSET(ltPubY, 0, 48 - ltPubYSz);
}
XMEMCPY(ltPub, ltPubX, 48);
XMEMCPY(ltPub + 48, ltPubY, 48);
ASSERT_SUCCESS(wolfSPDM_SetRequesterKeyPair(ctx, ltPriv, 48, ltPub, 96));
ASSERT_SUCCESS(wolfSPDM_SetResponderPubKey(ctx, ltPub, 96));
/* Our ephemeral ECDH key (requester side). Some wolfSSL builds
* (e.g. ECC_TIMING_RESISTANT) require an RNG on the ECDH private
* key for blinding; ensure one is attached for wc_ecc_shared_secret. */
ASSERT_SUCCESS(wolfSPDM_GenerateEphemeralKey(ctx));
ASSERT_SUCCESS(wc_ecc_set_rng(&ctx->ephemeralKey, &ctx->rng));
ASSERT_SUCCESS(wolfSPDM_ExportEphemeralPubKey(ctx,
ourPubX, &ourXSz, ourPubY, &ourYSz));
/* Responder ephemeral ECDH key (simulated responder side) */
ASSERT_SUCCESS(wc_ecc_init(&respEphem));
ASSERT_SUCCESS(wc_ecc_make_key(&ctx->rng, 48, &respEphem));
ASSERT_SUCCESS(wc_ecc_set_rng(&respEphem, &ctx->rng));
ASSERT_SUCCESS(wc_ecc_export_public_raw(&respEphem,
respPubX, &respPubXSz, respPubY, &respPubYSz));
if (respPubXSz < 48) {
XMEMMOVE(respPubX + (48 - respPubXSz), respPubX, respPubXSz);
XMEMSET(respPubX, 0, 48 - respPubXSz);
}
if (respPubYSz < 48) {
XMEMMOVE(respPubY + (48 - respPubYSz), respPubY, respPubYSz);
XMEMSET(respPubY, 0, 48 - respPubYSz);
}
/* Build partial KE_RSP (bytes 0..137) */
XMEMSET(keRsp, 0, sizeof(keRsp));
keRsp[0] = SPDM_VERSION_12;
keRsp[1] = SPDM_KEY_EXCHANGE_RSP;
SPDM_Set16LE(&keRsp[4], 0x1234);
XMEMSET(&keRsp[8], 0x5A, 32);
XMEMCPY(&keRsp[40], respPubX, 48);
XMEMCPY(&keRsp[88], respPubY, 48);
SPDM_Set16LE(&keRsp[136], 0);
/* th1SigHash = Hash(transcript + partial KE_RSP); transcript starts empty */
ASSERT_SUCCESS(wolfSPDM_Sha384Hash(th1SigHash,
keRsp, keRspPartialLen, NULL, 0, NULL, 0));
/* Replicate wolfSPDM_BuildSignedHash for SPDM 1.2 over th1SigHash */
signMsgLen = 0;
for (i = 0; i < 4; i++) {
XMEMCPY(&signMsg[signMsgLen], "dmtf-spdm-v1.2.*", 16);
signMsgLen += 16;
}
zeroPadLen = 36 - ctxStrLen;
XMEMSET(&signMsg[signMsgLen], 0, zeroPadLen);
signMsgLen += zeroPadLen;
XMEMCPY(&signMsg[signMsgLen], ctxStr, ctxStrLen);
signMsgLen += ctxStrLen;
XMEMCPY(&signMsg[signMsgLen], th1SigHash, WOLFSPDM_HASH_SIZE);
signMsgLen += WOLFSPDM_HASH_SIZE;
ASSERT_SUCCESS(wolfSPDM_Sha384Hash(signMsgHash,
signMsg, signMsgLen, NULL, 0, NULL, 0));
/* Sign with long-term key; wolfSPDM_SignHash pads R||S to 96 bytes */
sigRawSz = WOLFSPDM_ECC_SIG_SIZE;
ASSERT_SUCCESS(wolfSPDM_SignHash(ctx, signMsgHash, WOLFSPDM_HASH_SIZE,
sigRaw, &sigRawSz));
XMEMCPY(&keRsp[138], sigRaw, WOLFSPDM_ECC_SIG_SIZE);
/* TH1 = Hash(partial || signature) */
ASSERT_SUCCESS(wolfSPDM_Sha384Hash(th1,
keRsp, keRspPartialLen + WOLFSPDM_ECC_SIG_SIZE, NULL, 0, NULL, 0));
/* Shared secret from responder ephemeral and our public key (mirrors
* ECDH(our_priv, resp_pub) that parse will compute on ctx) */
ASSERT_SUCCESS(wc_ecc_init(&ourPubKey));
ASSERT_SUCCESS(wc_ecc_import_unsigned(&ourPubKey,
ourPubX, ourPubY, NULL, ECC_SECP384R1));
ASSERT_SUCCESS(wc_ecc_shared_secret(&respEphem, &ourPubKey,
sharedSecret, &sharedSz));
wc_ecc_free(&ourPubKey);
if (sharedSz < 48) {
XMEMMOVE(sharedSecret + (48 - sharedSz), sharedSecret, sharedSz);
XMEMSET(sharedSecret, 0, 48 - sharedSz);
}
sharedSz = 48;
/* Derive rspFinishedKey via a throwaway helper ctx */
ASSERT_SUCCESS(wolfSPDM_Init(helper));
helper->spdmVersion = SPDM_VERSION_12;
XMEMCPY(helper->sharedSecret, sharedSecret, 48);
helper->sharedSecretSz = 48;
ASSERT_SUCCESS(wolfSPDM_DeriveHandshakeKeys(helper, th1));
ASSERT_SUCCESS(wolfSPDM_ComputeVerifyData(
helper->rspFinishedKey, th1, expectedHmac));
wolfSPDM_Free(helper);
/* Positive: valid HMAC must succeed and advance state to KEY_EX */
XMEMCPY(&keRsp[234], expectedHmac, WOLFSPDM_HASH_SIZE);
rc = wolfSPDM_ParseKeyExchangeRsp(ctx, keRsp, keRspLen);
ASSERT_EQ(rc, WOLFSPDM_SUCCESS, "valid HMAC should succeed");
ASSERT_EQ(ctx->state, WOLFSPDM_STATE_KEY_EX,
"state should advance to KEY_EX on valid parse");
/* Negative: a single bit flip in rspVerifyData must be rejected.
* Reset transcript/state only; keep ephemeral key so ECDH reproduces. */
wolfSPDM_TranscriptReset(ctx);
ctx->state = WOLFSPDM_STATE_INIT;
keRsp[234] ^= 0x01;
rc = wolfSPDM_ParseKeyExchangeRsp(ctx, keRsp, keRspLen);
ASSERT_EQ(rc, WOLFSPDM_E_BAD_HMAC,
"flipped rspVerifyData byte must return BAD_HMAC");
wc_ecc_free(&ltKey);
wc_ecc_free(&respEphem);
TEST_CTX_FREE();
TEST_PASS();
}
/* Test Fix 4: Invalid curve point must be rejected by ComputeSharedSecret */
static int test_invalid_curve_point(void)
{
@ -1400,6 +1572,71 @@ static int test_parse_psk_exchange_rsp_null_args(void)
TEST_PASS();
}
/* Drive wolfSPDM_ParsePskExchangeRsp through key derivation to exercise
* the PSK ResponderVerifyData HMAC compare. Previously only NULL/short-
* buffer paths were covered, so mutations of the `if (diff != 0)` block
* or of `diff |= ...` `diff &= ...` survived every test. */
static int test_parse_psk_exchange_rsp_hmac_check(void)
{
byte pskRsp[64];
const word32 pskRspLen = 60; /* 12-byte partial + 48 HMAC */
const word32 pskRspPartialLen = 12;
byte psk[48];
byte th1[WOLFSPDM_HASH_SIZE];
byte expectedHmac[WOLFSPDM_HASH_SIZE];
int rc;
WOLFSPDM_CTX helperBuf;
WOLFSPDM_CTX* helper = &helperBuf;
TEST_CTX_SETUP_V12();
printf("test_parse_psk_exchange_rsp_hmac_check...\n");
XMEMSET(psk, 0xA5, sizeof(psk));
/* Build PSK_EXCHANGE_RSP partial (12 bytes): rspContextLen=0, opaqueLen=0 */
XMEMSET(pskRsp, 0, sizeof(pskRsp));
pskRsp[0] = SPDM_VERSION_12;
pskRsp[1] = SPDM_PSK_EXCHANGE_RSP;
SPDM_Set16LE(&pskRsp[4], 0x1234); /* RspSessionID */
SPDM_Set16LE(&pskRsp[8], 0); /* RspContextLength */
SPDM_Set16LE(&pskRsp[10], 0); /* OpaqueDataLength */
/* TH1 = Hash(transcript + partial); transcript starts empty */
ASSERT_SUCCESS(wolfSPDM_Sha384Hash(th1,
pskRsp, pskRspPartialLen, NULL, 0, NULL, 0));
/* Derive rspFinishedKey on a throwaway helper ctx */
ASSERT_SUCCESS(wolfSPDM_Init(helper));
helper->spdmVersion = SPDM_VERSION_12;
ASSERT_SUCCESS(wolfSPDM_SetPSK(helper, psk, sizeof(psk), NULL, 0));
ASSERT_SUCCESS(wolfSPDM_DeriveHandshakeKeysPsk(helper, th1));
ASSERT_SUCCESS(wolfSPDM_ComputeVerifyData(
helper->rspFinishedKey, th1, expectedHmac));
wolfSPDM_Free(helper);
/* Positive: correct HMAC must succeed and advance state to KEY_EX */
XMEMCPY(&pskRsp[12], expectedHmac, WOLFSPDM_HASH_SIZE);
ASSERT_SUCCESS(wolfSPDM_SetPSK(ctx, psk, sizeof(psk), NULL, 0));
rc = wolfSPDM_ParsePskExchangeRsp(ctx, pskRsp, pskRspLen);
ASSERT_EQ(rc, WOLFSPDM_SUCCESS, "valid PSK HMAC should succeed");
ASSERT_EQ(ctx->state, WOLFSPDM_STATE_KEY_EX,
"state should advance to KEY_EX on valid PSK parse");
/* Negative: flip one byte — must return BAD_HMAC.
* Parse scrubs ctx->psk after derivation, so re-set it; also reset
* transcript because the successful parse appended 60 bytes. */
wolfSPDM_TranscriptReset(ctx);
ctx->state = WOLFSPDM_STATE_INIT;
ASSERT_SUCCESS(wolfSPDM_SetPSK(ctx, psk, sizeof(psk), NULL, 0));
pskRsp[12] ^= 0x01;
rc = wolfSPDM_ParsePskExchangeRsp(ctx, pskRsp, pskRspLen);
ASSERT_EQ(rc, WOLFSPDM_E_BAD_HMAC,
"flipped PSK rspVerifyData byte must return BAD_HMAC");
TEST_CTX_FREE();
TEST_PASS();
}
static int test_build_psk_finish_null_args(void)
{
byte buf[128];
@ -1937,6 +2174,7 @@ int main(void)
/* Security tests */
test_mitm_signature_rejected();
test_key_exchange_rsp_hmac_check();
test_invalid_curve_point();
#ifdef WOLFTPM_SPDM_TCG
test_tcg_underflow();
@ -1989,6 +2227,7 @@ int main(void)
#endif
#ifdef WOLFTPM_SPDM_PSK
test_parse_psk_exchange_rsp_null_args();
test_parse_psk_exchange_rsp_hmac_check();
test_build_psk_finish_null_args();
test_build_psk_finish_format();
test_parse_psk_finish_rsp();

View File

@ -1304,14 +1304,19 @@ TPM_RC TPM2_PCR_Extend(PCR_Extend_In* in)
int i;
TPM2_Packet packet;
CmdInfo_t info = {0,0,0,0};
UINT32 count;
info.inHandleCnt = 1;
info.flags = (CMD_FLAG_AUTH_USER1);
count = in->digests.count;
if (count > HASH_COUNT)
count = HASH_COUNT;
TPM2_Packet_Init(ctx, &packet);
TPM2_Packet_AppendU32(&packet, in->pcrHandle);
TPM2_Packet_AppendAuth(&packet, ctx, &info);
TPM2_Packet_AppendU32(&packet, in->digests.count);
for (i=0; i<(int)in->digests.count; i++) {
TPM2_Packet_AppendU32(&packet, count);
for (i=0; i<(int)count; i++) {
UINT16 hashAlg = in->digests.digests[i].hashAlg;
int digestSz = TPM2_GetHashDigestSize(hashAlg);
TPM2_Packet_AppendU16(&packet, hashAlg);
@ -1719,34 +1724,14 @@ TPM_RC TPM2_LoadExternal(LoadExternal_In* in, LoadExternal_Out* out)
TPM2_Packet_Init(ctx, &packet);
st = TPM2_Packet_AppendAuth(&packet, ctx, &info);
/* Reading sensitive.any.size is valid regardless of sensitiveType:
* every TPM2B variant in TPMU_SENSITIVE_COMPOSITE has UINT16 size
* at offset 0, so the .any view reliably reflects the populated
* typed member (common-initial-sequence aliasing). */
if (in->inPrivate.sensitiveArea.authValue.size > 0 ||
in->inPrivate.sensitiveArea.seedValue.size > 0 ||
in->inPrivate.sensitiveArea.sensitive.any.size > 0) {
in->inPrivate.size = 2 + /* sensitiveType */
2 + in->inPrivate.sensitiveArea.authValue.size +
2 + in->inPrivate.sensitiveArea.seedValue.size +
2 + in->inPrivate.sensitiveArea.sensitive.any.size;
TPM2_Packet_AppendU16(&packet, in->inPrivate.size);
TPM2_Packet_AppendU16(&packet,
in->inPrivate.sensitiveArea.sensitiveType);
TPM2_Packet_AppendU16(&packet,
in->inPrivate.sensitiveArea.authValue.size);
TPM2_Packet_AppendBytes(&packet,
in->inPrivate.sensitiveArea.authValue.buffer,
in->inPrivate.sensitiveArea.authValue.size);
TPM2_Packet_AppendU16(&packet,
in->inPrivate.sensitiveArea.seedValue.size);
TPM2_Packet_AppendBytes(&packet,
in->inPrivate.sensitiveArea.seedValue.buffer,
in->inPrivate.sensitiveArea.seedValue.size);
TPM2_Packet_AppendU16(&packet,
in->inPrivate.sensitiveArea.sensitive.any.size);
TPM2_Packet_AppendBytes(&packet,
in->inPrivate.sensitiveArea.sensitive.any.buffer,
in->inPrivate.sensitiveArea.sensitive.any.size);
TPM2_Packet_AppendSensitive(&packet, &in->inPrivate);
}
else {
TPM2_Packet_AppendU16(&packet, 0);
@ -2310,10 +2295,7 @@ TPM_RC TPM2_ECC_Parameters(ECC_Parameters_In* in,
TPM2_Packet_ParseU16(&packet,
&out->parameters.kdf.details.any.hashAlg);
TPM2_Packet_ParseU16(&packet, &out->parameters.sign.scheme);
if (out->parameters.sign.scheme != TPM_ALG_NULL)
TPM2_Packet_ParseU16(&packet,
&out->parameters.sign.details.any.hashAlg);
TPM2_Packet_ParseEccScheme(&packet, &out->parameters.sign);
TPM2_Packet_ParseU16Buf(&packet, &out->parameters.p.size,
out->parameters.p.buffer,
@ -3325,9 +3307,18 @@ TPM_RC TPM2_SetCommandCodeAuditStatus(SetCommandCodeAuditStatus_In* in)
int i;
TPM2_Packet packet;
CmdInfo_t info = {0,0,0,0};
UINT32 setCount;
UINT32 clearCount;
info.inHandleCnt = 1;
info.flags = (CMD_FLAG_AUTH_USER1);
setCount = in->setList.count;
clearCount = in->clearList.count;
if (setCount > MAX_CAP_CC)
setCount = MAX_CAP_CC;
if (clearCount > MAX_CAP_CC)
clearCount = MAX_CAP_CC;
TPM2_Packet_Init(ctx, &packet);
TPM2_Packet_AppendU32(&packet, in->auth);
@ -3336,13 +3327,13 @@ TPM_RC TPM2_SetCommandCodeAuditStatus(SetCommandCodeAuditStatus_In* in)
TPM2_Packet_AppendU16(&packet, in->auditAlg);
TPM2_Packet_AppendU32(&packet, in->setList.count);
for (i=0; i<(int)in->setList.count; i++) {
TPM2_Packet_AppendU32(&packet, setCount);
for (i=0; i<(int)setCount; i++) {
TPM2_Packet_AppendU32(&packet, in->setList.commandCodes[i]);
}
TPM2_Packet_AppendU32(&packet, in->clearList.count);
for (i=0; i<(int)in->clearList.count; i++) {
TPM2_Packet_AppendU32(&packet, clearCount);
for (i=0; i<(int)clearCount; i++) {
TPM2_Packet_AppendU32(&packet, in->clearList.commandCodes[i]);
}
@ -3742,12 +3733,19 @@ TPM_RC TPM2_PolicyOR(PolicyOR_In* in)
if (rc == TPM_RC_SUCCESS) {
int i;
TPM2_Packet packet;
const UINT32 digestsMax =
(UINT32)(sizeof(in->pHashList.digests) /
sizeof(in->pHashList.digests[0]));
UINT32 count = in->pHashList.count;
if (count > digestsMax)
count = digestsMax;
TPM2_Packet_Init(ctx, &packet);
TPM2_Packet_AppendU32(&packet, in->policySession);
TPM2_Packet_AppendU32(&packet, in->pHashList.count);
for (i=0; i<(int)in->pHashList.count; i++) {
TPM2_Packet_AppendU32(&packet, count);
for (i=0; i<(int)count; i++) {
TPM2_Packet_AppendU16(&packet, in->pHashList.digests[i].size);
TPM2_Packet_AppendBytes(&packet,
in->pHashList.digests[i].buffer,

View File

@ -5695,6 +5695,15 @@ int wolfTPM2_NVCreateAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
if (dev == NULL || nv == NULL || parent == NULL) {
return BAD_FUNC_ARG;
}
if (auth != NULL && authSz > 0 &&
authSz > (int)sizeof(in.auth.buffer)) {
return BUFFER_E;
}
if (authPolicy != NULL && authPolicySz > 0 &&
authPolicySz >
(int)sizeof(in.publicInfo.nvPublic.authPolicy.buffer)) {
return BUFFER_E;
}
/* set session auth for key */
if (dev->ctx.session && !parent->policyAuth) {
@ -5705,8 +5714,6 @@ int wolfTPM2_NVCreateAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
XMEMSET(&in, 0, sizeof(in));
in.authHandle = parent->hndl;
if (auth != NULL && authSz > 0) {
if (authSz > (int)sizeof(in.auth.buffer))
authSz = (int)sizeof(in.auth.buffer);
in.auth.size = authSz;
XMEMCPY(in.auth.buffer, auth, in.auth.size);
}
@ -5715,11 +5722,6 @@ int wolfTPM2_NVCreateAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent,
in.publicInfo.nvPublic.attributes = nvAttributes;
in.publicInfo.nvPublic.dataSize = (UINT16)maxSize;
if (authPolicy != NULL && authPolicySz > 0) {
if (authPolicySz >
(int)sizeof(in.publicInfo.nvPublic.authPolicy.buffer)) {
authPolicySz =
(int)sizeof(in.publicInfo.nvPublic.authPolicy.buffer);
}
in.publicInfo.nvPublic.authPolicy.size = authPolicySz;
XMEMCPY(in.publicInfo.nvPublic.authPolicy.buffer, authPolicy,
in.publicInfo.nvPublic.authPolicy.size);
@ -6375,10 +6377,10 @@ int wolfTPM2_HashStart(WOLFTPM2_DEV* dev, WOLFTPM2_HASH* hash,
(usageAuthSz > 0 && usageAuth == NULL)) {
return BAD_FUNC_ARG;
}
if (usageAuthSz > sizeof(hash->handle.auth.buffer))
return BUFFER_E;
/* Capture usage auth */
if (usageAuthSz > sizeof(hash->handle.auth.buffer))
usageAuthSz = sizeof(hash->handle.auth.buffer);
XMEMSET(hash, 0, sizeof(WOLFTPM2_HASH));
hash->handle.auth.size = usageAuthSz;
if (usageAuth != NULL)
@ -6833,6 +6835,10 @@ int wolfTPM2_LoadKeyedHashKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
if (keySz == 0 || keySz > MAX_SYM_DATA) {
return BUFFER_E;
}
if (usageAuth != NULL && usageAuthSz >
sizeof(createIn.inSensitive.sensitive.userAuth.buffer)) {
return BUFFER_E;
}
hashAlgDigSz = TPM2_GetHashDigestSize(hashAlg);
if (hashAlgDigSz <= 0) {
@ -6848,11 +6854,6 @@ int wolfTPM2_LoadKeyedHashKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
XMEMSET(&createIn, 0, sizeof(createIn));
createIn.parentHandle = parent->hndl;
if (usageAuth) {
if (usageAuthSz >
sizeof(createIn.inSensitive.sensitive.userAuth.buffer)) {
usageAuthSz =
sizeof(createIn.inSensitive.sensitive.userAuth.buffer); /* truncate */
}
createIn.inSensitive.sensitive.userAuth.size = usageAuthSz;
XMEMCPY(createIn.inSensitive.sensitive.userAuth.buffer, usageAuth,
usageAuthSz);
@ -6925,11 +6926,13 @@ int wolfTPM2_HmacStart(WOLFTPM2_DEV* dev, WOLFTPM2_HMAC* hmac,
if (dev == NULL || hmac == NULL || hashAlg == TPM_ALG_NULL) {
return BAD_FUNC_ARG;
}
if (usageAuth != NULL &&
usageAuthSz > sizeof(hmac->hash.handle.auth.buffer)) {
return BUFFER_E;
}
if (usageAuth != NULL) {
/* Capture usage auth */
if (usageAuthSz > sizeof(hmac->hash.handle.auth.buffer))
usageAuthSz = sizeof(hmac->hash.handle.auth.buffer); /* truncate */
hmac->hash.handle.auth.size = usageAuthSz;
XMEMCPY(hmac->hash.handle.auth.buffer, usageAuth, usageAuthSz);
}

View File

@ -1824,6 +1824,53 @@ static void test_TPM2_SchemeSerialize(void)
printf("Test TPM Wrapper:\tSchemeSerialize:\t\tPassed\n");
}
/* Exercise the parse sequence used by TPM2_ECC_Parameters response: sign
* scheme = ECDAA (scheme + hashAlg + count) followed by a trailing U16
* size field. Ensures the ECDAA count field is consumed so the next read
* lands at the correct offset. The wire bytes are built by hand to avoid
* relying on non-exported packet helpers. */
static void test_TPM2_ECC_Parameters_EcdaaResponseParse(void)
{
TPM2_Packet packet;
byte buf[32];
TPMT_SIG_SCHEME signOut;
UINT16 pSizeOut = 0;
/* Hand-built wire: TPM2B wire is big-endian.
* [0-1] sign.scheme = TPM_ALG_ECDAA (0x001A)
* [2-3] sign.hashAlg = TPM_ALG_SHA256 (0x000B)
* [4-5] sign.count = 0x0007
* [6-7] p.size sentinel= 0x0030
*/
XMEMSET(buf, 0, sizeof(buf));
buf[0] = 0x00; buf[1] = (byte)TPM_ALG_ECDAA;
buf[2] = 0x00; buf[3] = (byte)TPM_ALG_SHA256;
buf[4] = 0x00; buf[5] = 0x07;
buf[6] = 0x00; buf[7] = 0x30;
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = buf;
packet.size = sizeof(buf);
packet.pos = 0;
XMEMSET(&signOut, 0, sizeof(signOut));
TPM2_Packet_ParseEccScheme(&packet, &signOut);
AssertIntEQ(signOut.scheme, TPM_ALG_ECDAA);
AssertIntEQ(signOut.details.ecdaa.hashAlg, TPM_ALG_SHA256);
AssertIntEQ(signOut.details.ecdaa.count, 7);
/* After parsing the ECDAA scheme, packet.pos must be at byte 6 so the
* next U16 read returns the sentinel 0x0030 (the simulated p.size).
* The buggy inline parser in TPM2_ECC_Parameters consumed only
* scheme+hashAlg (4 bytes) and left the count on the wire, which
* would make p.size read 0x0007 instead. */
AssertIntEQ(packet.pos, 6);
pSizeOut = (UINT16)((buf[packet.pos] << 8) | buf[packet.pos + 1]);
AssertIntEQ(pSizeOut, 0x0030);
printf("Test TPM Wrapper:\tEcdaaResponseParse:\t\tPassed\n");
}
static void test_TPM2_KeyedHashScheme_XorSerialize(void)
{
TPM2_Packet packet;
@ -2012,6 +2059,52 @@ static void test_TPM2_Sensitive_Roundtrip(void)
AssertIntEQ(XMEMCMP(sensOut.sensitiveArea.sensitive.ecc.buffer,
rsaPriv, sizeof(rsaPriv)), 0);
/* KEYEDHASH sensitive roundtrip */
XMEMSET(&sensIn, 0, sizeof(sensIn));
sensIn.sensitiveArea.sensitiveType = TPM_ALG_KEYEDHASH;
sensIn.sensitiveArea.sensitive.bits.size = sizeof(rsaPriv);
XMEMCPY(sensIn.sensitiveArea.sensitive.bits.buffer, rsaPriv,
sizeof(rsaPriv));
XMEMSET(buf, 0, sizeof(buf));
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = buf;
packet.size = sizeof(buf);
TPM2_Packet_AppendSensitive(&packet, &sensIn);
packet.pos = 0;
XMEMSET(&sensOut, 0, sizeof(sensOut));
TPM2_Packet_ParseSensitive(&packet, &sensOut);
AssertIntEQ(sensOut.sensitiveArea.sensitiveType, TPM_ALG_KEYEDHASH);
AssertIntEQ(sensOut.sensitiveArea.sensitive.bits.size, sizeof(rsaPriv));
AssertIntEQ(XMEMCMP(sensOut.sensitiveArea.sensitive.bits.buffer,
rsaPriv, sizeof(rsaPriv)), 0);
/* SYMCIPHER sensitive roundtrip */
XMEMSET(&sensIn, 0, sizeof(sensIn));
sensIn.sensitiveArea.sensitiveType = TPM_ALG_SYMCIPHER;
sensIn.sensitiveArea.sensitive.sym.size = sizeof(rsaPriv);
XMEMCPY(sensIn.sensitiveArea.sensitive.sym.buffer, rsaPriv,
sizeof(rsaPriv));
XMEMSET(buf, 0, sizeof(buf));
XMEMSET(&packet, 0, sizeof(packet));
packet.buf = buf;
packet.size = sizeof(buf);
TPM2_Packet_AppendSensitive(&packet, &sensIn);
packet.pos = 0;
XMEMSET(&sensOut, 0, sizeof(sensOut));
TPM2_Packet_ParseSensitive(&packet, &sensOut);
AssertIntEQ(sensOut.sensitiveArea.sensitiveType, TPM_ALG_SYMCIPHER);
AssertIntEQ(sensOut.sensitiveArea.sensitive.sym.size, sizeof(rsaPriv));
AssertIntEQ(XMEMCMP(sensOut.sensitiveArea.sensitive.sym.buffer,
rsaPriv, sizeof(rsaPriv)), 0);
printf("Test TPM Wrapper:\tSensitive roundtrip:\t\tPassed\n");
}
@ -3163,6 +3256,7 @@ int unit_tests(int argc, char *argv[])
test_wolfTPM2_ComputeName();
#endif
test_TPM2_SchemeSerialize();
test_TPM2_ECC_Parameters_EcdaaResponseParse();
test_TPM2_KeyedHashScheme_XorSerialize();
test_TPM2_Signature_EcSchnorrSm2Serialize();
test_TPM2_Sensitive_Roundtrip();