mirror of https://github.com/wolfSSL/wolfTPM.git
F-7272 - Honor caller response buffer capacity in FWTPM_ProcessCommand
parent
6e688cb9f1
commit
247853b4b0
|
|
@ -93,6 +93,7 @@ static void FwRspInit(TPM2_Packet* pkt, byte* buf, int bufSize)
|
|||
pkt->buf = buf;
|
||||
pkt->pos = TPM2_HEADER_SIZE; /* skip header, filled by Finalize */
|
||||
pkt->size = bufSize;
|
||||
pkt->overflow = 0;
|
||||
/* Zero header area so stale data doesn't confuse session detection */
|
||||
XMEMSET(buf, 0, TPM2_HEADER_SIZE);
|
||||
}
|
||||
|
|
@ -110,10 +111,10 @@ static int FwRspFinalize(TPM2_Packet* pkt, UINT16 tag, TPM_RC rc)
|
|||
}
|
||||
|
||||
/* Build a minimal error-only response */
|
||||
static int FwBuildErrorResponse(byte* rsp, UINT16 tag, TPM_RC rc)
|
||||
static int FwBuildErrorResponse(byte* rsp, int rspBufSz, UINT16 tag, TPM_RC rc)
|
||||
{
|
||||
TPM2_Packet pkt;
|
||||
FwRspInit(&pkt, rsp, FWTPM_MAX_COMMAND_SIZE);
|
||||
FwRspInit(&pkt, rsp, rspBufSz);
|
||||
return FwRspFinalize(&pkt, tag, rc);
|
||||
}
|
||||
|
||||
|
|
@ -1016,10 +1017,17 @@ static TPM_RC FwCmd_GetRandom(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize,
|
|||
/* TPM2B_DIGEST: size + data */
|
||||
TPM2_Packet_AppendU16(rsp, bytesRequested);
|
||||
|
||||
rc = wc_RNG_GenerateBlock(&ctx->rng,
|
||||
rsp->buf + rsp->pos, bytesRequested);
|
||||
if (rc != 0) {
|
||||
rc = TPM_RC_FAILURE;
|
||||
/* This writes past the packet API, so bound it explicitly. */
|
||||
if (rsp->pos + (int)bytesRequested > rsp->size) {
|
||||
rsp->overflow = 1;
|
||||
bytesRequested = 0;
|
||||
}
|
||||
else {
|
||||
rc = wc_RNG_GenerateBlock(&ctx->rng,
|
||||
rsp->buf + rsp->pos, bytesRequested);
|
||||
if (rc != 0) {
|
||||
rc = TPM_RC_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1091,12 +1099,28 @@ static int FwPcrLocalityAllowed(int pcrIndex, int locality, int isReset);
|
|||
/* Overwrite a big-endian UINT32 already appended at buf[pos]. Used to
|
||||
* back-patch a TPML count with the number of entries actually emitted, so a
|
||||
* count/payload mismatch is impossible even if two entries collapse to one. */
|
||||
static void FwPatchU32BE(byte* buf, int pos, UINT32 v)
|
||||
/* Back-patch a reserved field, but only where it actually fits. The
|
||||
* reservation is dropped silently when the buffer is already full. */
|
||||
static void FwPatchU32BE(TPM2_Packet* rsp, int pos, UINT32 v)
|
||||
{
|
||||
buf[pos + 0] = (byte)(v >> 24);
|
||||
buf[pos + 1] = (byte)(v >> 16);
|
||||
buf[pos + 2] = (byte)(v >> 8);
|
||||
buf[pos + 3] = (byte)(v);
|
||||
if (pos < 0 || pos + 4 > rsp->size) {
|
||||
rsp->overflow = 1;
|
||||
return;
|
||||
}
|
||||
rsp->buf[pos + 0] = (byte)(v >> 24);
|
||||
rsp->buf[pos + 1] = (byte)(v >> 16);
|
||||
rsp->buf[pos + 2] = (byte)(v >> 8);
|
||||
rsp->buf[pos + 3] = (byte)(v);
|
||||
}
|
||||
|
||||
/* Back-patch the one-byte moreData flag with the same guard. */
|
||||
static void FwPatchMoreData(TPM2_Packet* rsp, int pos, byte v)
|
||||
{
|
||||
if (pos < 0 || pos + 1 > rsp->size) {
|
||||
rsp->overflow = 1;
|
||||
return;
|
||||
}
|
||||
rsp->buf[pos] = v;
|
||||
}
|
||||
|
||||
/* --- TPM2_GetCapability (CC 0x017A) --- */
|
||||
|
|
@ -1210,7 +1234,7 @@ static TPM_RC FwCmd_GetCapability(FWTPM_CTX* ctx, TPM2_Packet* cmd,
|
|||
if ((UINT32)numOut > propertyCount)
|
||||
numOut = (int)propertyCount;
|
||||
if (avail > numOut)
|
||||
rsp->buf[moreDataPos] = 1; /* YES - more entries remain */
|
||||
FwPatchMoreData(rsp, moreDataPos, 1); /* more entries remain */
|
||||
|
||||
/* Reserve the count and back-patch it to entries actually emitted. */
|
||||
countPos = rsp->pos;
|
||||
|
|
@ -1235,7 +1259,7 @@ static TPM_RC FwCmd_GetCapability(FWTPM_CTX* ctx, TPM2_Packet* cmd,
|
|||
haveLast = 1;
|
||||
emitted++;
|
||||
}
|
||||
FwPatchU32BE(rsp->buf, countPos, (UINT32)emitted);
|
||||
FwPatchU32BE(rsp, countPos, (UINT32)emitted);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1261,7 +1285,7 @@ static TPM_RC FwCmd_GetCapability(FWTPM_CTX* ctx, TPM2_Packet* cmd,
|
|||
if ((UINT32)numOut > propertyCount)
|
||||
numOut = (int)propertyCount;
|
||||
if (avail > numOut)
|
||||
rsp->buf[moreDataPos] = 1; /* YES - more entries remain */
|
||||
FwPatchMoreData(rsp, moreDataPos, 1); /* more entries remain */
|
||||
|
||||
/* Reserve the count and back-patch it to entries actually emitted. */
|
||||
countPos = rsp->pos;
|
||||
|
|
@ -1287,7 +1311,7 @@ static TPM_RC FwCmd_GetCapability(FWTPM_CTX* ctx, TPM2_Packet* cmd,
|
|||
haveLast = 1;
|
||||
emitted++;
|
||||
}
|
||||
FwPatchU32BE(rsp->buf, countPos, (UINT32)emitted);
|
||||
FwPatchU32BE(rsp, countPos, (UINT32)emitted);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1418,7 +1442,7 @@ static TPM_RC FwCmd_GetCapability(FWTPM_CTX* ctx, TPM2_Packet* cmd,
|
|||
|
||||
/* Truncated (start offset or propertyCount cap): flag moreData=YES. */
|
||||
if (startIdx + numOut < totalProps)
|
||||
rsp->buf[moreDataPos] = 1; /* YES */
|
||||
FwPatchMoreData(rsp, moreDataPos, 1); /* YES */
|
||||
|
||||
TPM2_Packet_AppendU32(rsp, (UINT32)numOut);
|
||||
for (i = 0; i < (UINT32)numOut; i++) {
|
||||
|
|
@ -1496,7 +1520,7 @@ static TPM_RC FwCmd_GetCapability(FWTPM_CTX* ctx, TPM2_Packet* cmd,
|
|||
|
||||
/* Truncated (start offset or propertyCount cap): flag moreData=YES. */
|
||||
if (startIdx + numOut < totalProps)
|
||||
rsp->buf[moreDataPos] = 1; /* YES */
|
||||
FwPatchMoreData(rsp, moreDataPos, 1); /* YES */
|
||||
|
||||
TPM2_Packet_AppendU32(rsp, (UINT32)numOut);
|
||||
for (ii = 0; ii < (UINT32)numOut; ii++) {
|
||||
|
|
@ -1589,7 +1613,7 @@ static TPM_RC FwCmd_GetCapability(FWTPM_CTX* ctx, TPM2_Packet* cmd,
|
|||
|
||||
if ((UINT32)count > propertyCount) {
|
||||
count = (int)propertyCount;
|
||||
rsp->buf[moreDataPos] = 1; /* YES - more handles available */
|
||||
FwPatchMoreData(rsp, moreDataPos, 1); /* more handles available */
|
||||
}
|
||||
TPM2_Packet_AppendU32(rsp, (UINT32)count);
|
||||
if (count > 0) {
|
||||
|
|
@ -16221,13 +16245,23 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
#endif
|
||||
int pj, hj; /* Loop indices for auth validation */
|
||||
int authFail; /* Password comparison result */
|
||||
int rspCap; /* Caller's response buffer capacity */
|
||||
int rspTruncated = 0; /* Response did not fit the buffer */
|
||||
|
||||
if (ctx == NULL || cmdBuf == NULL || rspBuf == NULL || rspSize == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* rspSize is in/out: capacity in, bytes written out. Callers that leave
|
||||
* it unset get the historic FWTPM_MAX_COMMAND_SIZE assumption. */
|
||||
/* Handlers commit state before marshalling and some write outside the
|
||||
* packet API, so they are only ever run with a full-size buffer. A
|
||||
* caller with a smaller transport buffer must stage through one.
|
||||
* rspSize is output-only, so its incoming value is never read. */
|
||||
rspCap = FWTPM_MAX_COMMAND_SIZE;
|
||||
|
||||
if (cmdSize < TPM2_HEADER_SIZE) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, TPM_ST_NO_SESSIONS,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS,
|
||||
TPM_RC_COMMAND_SIZE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16243,13 +16277,13 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
TPM2_Packet_ParseU32(&cmdPkt, &cmdCode);
|
||||
|
||||
if (cmdTag != TPM_ST_NO_SESSIONS && cmdTag != TPM_ST_SESSIONS) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, TPM_ST_NO_SESSIONS,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS,
|
||||
TPM_RC_BAD_TAG);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
||||
if ((int)cmdSizeHdr != cmdSize) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, TPM_ST_NO_SESSIONS,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS,
|
||||
TPM_RC_COMMAND_SIZE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16257,14 +16291,14 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
/* A valid command code has only the 16-bit index plus the vendor V bit
|
||||
* (CC_VEND); reject any other reserved bit so it cannot alias a command. */
|
||||
if ((cmdCode & ~((UINT32)CC_VEND | 0xFFFFu)) != 0) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, TPM_ST_NO_SESSIONS,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS,
|
||||
TPM_RC_COMMAND_CODE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
||||
if (!ctx->wasStarted && cmdCode != TPM_CC_Startup &&
|
||||
cmdCode != TPM_CC_GetCapability) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, TPM_ST_NO_SESSIONS,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS,
|
||||
TPM_RC_INITIALIZE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16278,14 +16312,14 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
|
||||
entry = FwFindCmdEntry(cmdCode);
|
||||
if (entry == NULL) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, TPM_ST_NO_SESSIONS,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS,
|
||||
TPM_RC_COMMAND_CODE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
||||
/* Validate minimum command size: header + 4 bytes per input handle */
|
||||
if (cmdSize < TPM2_HEADER_SIZE + (entry->inHandleCnt * 4)) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, TPM_ST_NO_SESSIONS,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS,
|
||||
TPM_RC_COMMAND_SIZE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16295,7 +16329,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
* and bypasses every downstream auth/HMAC/policy enforcement loop, so
|
||||
* reject up front for any handler that declares authHandleCnt > 0. */
|
||||
if (cmdTag != TPM_ST_SESSIONS && entry->authHandleCnt > 0) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, TPM_ST_NO_SESSIONS,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS,
|
||||
TPM_RC_AUTH_MISSING);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16339,7 +16373,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
int authEnd;
|
||||
/* Reject if authAreaSz exceeds remaining command bytes */
|
||||
if (authAreaSz > (UINT32)(cmdSize - cmdPkt.pos)) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_AUTHSIZE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16476,7 +16510,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
|
||||
/* Check if auth area parsing encountered an error */
|
||||
if (rc != TPM_RC_SUCCESS) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, rc);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16548,7 +16582,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
printf("fwTPM: Policy digest mismatch for handle "
|
||||
"0x%x (CC=0x%x)\n", entityH, cmdCode);
|
||||
#endif
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16556,7 +16590,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
if (pSess->hasRequiredLocality &&
|
||||
(ctx->activeLocality > WOLFTPM_LOCALITY_MAX ||
|
||||
!((1u << ctx->activeLocality) & pSess->requiredLocality))) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_LOCALITY);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16571,7 +16605,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
(int)pSess->cpHashA.size != ccpHashSz ||
|
||||
TPM2_ConstantCompare(pSess->cpHashA.buffer,
|
||||
ccpHash, (word32)ccpHashSz) != 0) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16589,7 +16623,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
"handle 0x%x without authPolicy (CC=0x%x)\n",
|
||||
entityH, cmdCode);
|
||||
#endif
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_POLICY_FAIL);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16610,7 +16644,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
* etc.) — but not Clear via platformAuth, which is the recovery path. */
|
||||
if (ctx->lockoutAuthFailed && entry->authHandleCnt > 0 &&
|
||||
cmdHandleCnt > 0 && cmdHandles[0] == TPM_RH_LOCKOUT) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_LOCKOUT);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16633,7 +16667,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
cmdCode != TPM_CC_StartAuthSession &&
|
||||
cmdCode != TPM_CC_FlushContext &&
|
||||
!(cmdHandleCnt > 0 && FwHandleIsNoDA(ctx, cmdHandles[0]))) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_LOCKOUT);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16665,7 +16699,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
ctx->orderly = 0;
|
||||
(void)FWTPM_NV_SaveFlags(ctx);
|
||||
#ifdef FWTPM_DA_USED_RETRY
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_RETRY);
|
||||
return TPM_RC_SUCCESS;
|
||||
#endif
|
||||
|
|
@ -16693,7 +16727,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
printf("fwTPM: Password/HMAC auth rejected for handle "
|
||||
"0x%x — policy required (userWithAuth clear)\n", entityH);
|
||||
#endif
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_AUTH_UNAVAILABLE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16722,12 +16756,12 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
#endif
|
||||
#ifndef FWTPM_NO_DA
|
||||
if (FwDaRegisterFailure(ctx, entityH)) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_LOCKOUT);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_AUTH_FAIL);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16754,7 +16788,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
if (FwComputeCpHash(hSess->authHash, cmdCode,
|
||||
cmdBuf, cmdSize, cmdHandles, cmdHandleCnt,
|
||||
ctx, cpStart, cpHash, &cpHashSz) != 0) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_FAILURE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16776,7 +16810,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
printf("fwTPM: PolicyPassword auth failed for handle "
|
||||
"0x%x (CC=0x%x)\n", entityH, cmdCode);
|
||||
#endif
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_AUTH_FAIL);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16811,12 +16845,12 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
#endif
|
||||
#ifndef FWTPM_NO_DA
|
||||
if (FwDaRegisterFailure(ctx, entityH)) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_LOCKOUT);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_AUTH_FAIL);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16840,7 +16874,7 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
#ifdef DEBUG_WOLFTPM
|
||||
printf("fwTPM: ParamDecrypt failed %d\n", (int)rc);
|
||||
#endif
|
||||
*rspSize = FwBuildErrorResponse(rspBuf,
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_FAILURE);
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
|
@ -16849,11 +16883,22 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
#endif /* !FWTPM_NO_PARAM_ENC */
|
||||
|
||||
/* Set up response packet */
|
||||
FwRspInit(&rspPkt, rspBuf, FWTPM_MAX_COMMAND_SIZE);
|
||||
FwRspInit(&rspPkt, rspBuf, rspCap);
|
||||
|
||||
rc = entry->handler(ctx, &cmdPkt, cmdSize, &rspPkt, cmdTag);
|
||||
if (rc != TPM_RC_SUCCESS) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, TPM_ST_NO_SESSIONS, rc);
|
||||
/* The packet layer drops appends that would overrun the buffer, so
|
||||
* report the truncation instead of returning a malformed packet. The
|
||||
* session flush and deferred clear below must still run. */
|
||||
if (rc == TPM_RC_SUCCESS && rspPkt.overflow) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS,
|
||||
TPM_RC_SIZE);
|
||||
rspTruncated = 1;
|
||||
}
|
||||
if (rspTruncated) {
|
||||
/* response already built above */
|
||||
}
|
||||
else if (rc != TPM_RC_SUCCESS) {
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap, TPM_ST_NO_SESSIONS, rc);
|
||||
}
|
||||
else if (cmdTag != TPM_ST_SESSIONS) {
|
||||
/* Non-session: handler already finalized the response */
|
||||
|
|
@ -16880,6 +16925,9 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
int rpHashSz = 0;
|
||||
const byte* rpBytes = NULL;
|
||||
int rpBytesSz = 0;
|
||||
/* previous nonceTPM per session, restored if the response overflows
|
||||
* (66 bytes each, 3 sessions max) */
|
||||
TPM2B_NONCE savedNonce[FWTPM_MAX_CMD_AUTHS];
|
||||
|
||||
/* Read parameterSize from response buffer */
|
||||
if (rspHandleEnd + 4 <= rspPkt.pos) {
|
||||
|
|
@ -16894,12 +16942,13 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
rspParamEnd = rspParamStart + (int)rspParamSzVal;
|
||||
#endif
|
||||
|
||||
/* Generate fresh nonceTPM BEFORE response encryption (encryption
|
||||
* uses the new nonceTPM, matching what client receives in auth) */
|
||||
/* New nonceTPM before response encryption, saving the old one */
|
||||
for (j = 0; j < cmdAuthCnt; j++) {
|
||||
if (cmdAuths[j].sess != NULL) {
|
||||
FWTPM_Session* sess = cmdAuths[j].sess;
|
||||
int digestSz = TPM2_GetHashDigestSize(sess->authHash);
|
||||
XMEMCPY(&savedNonce[j], &sess->nonceTPM,
|
||||
sizeof(savedNonce[j]));
|
||||
if (digestSz > 0) {
|
||||
rngRc = wc_RNG_GenerateBlock(&ctx->rng,
|
||||
sess->nonceTPM.buffer, digestSz);
|
||||
|
|
@ -17017,9 +17066,24 @@ int FWTPM_ProcessCommand(FWTPM_CTX* ctx,
|
|||
}
|
||||
}
|
||||
|
||||
/* Finalize response header */
|
||||
FwRspFinalize(&rspPkt, TPM_ST_SESSIONS, TPM_RC_SUCCESS);
|
||||
*rspSize = rspPkt.pos;
|
||||
/* Auth area is appended after the handler ran, so it can overrun a
|
||||
* buffer the parameters alone fit in. Restore the nonces: the client
|
||||
* never received the new ones. */
|
||||
if (rspPkt.overflow) {
|
||||
for (j = 0; j < cmdAuthCnt; j++) {
|
||||
if (cmdAuths[j].sess != NULL) {
|
||||
XMEMCPY(&cmdAuths[j].sess->nonceTPM, &savedNonce[j],
|
||||
sizeof(savedNonce[j]));
|
||||
}
|
||||
}
|
||||
*rspSize = FwBuildErrorResponse(rspBuf, rspCap,
|
||||
TPM_ST_NO_SESSIONS, TPM_RC_SIZE);
|
||||
}
|
||||
else {
|
||||
/* Finalize response header */
|
||||
FwRspFinalize(&rspPkt, TPM_ST_SESSIONS, TPM_RC_SUCCESS);
|
||||
*rspSize = rspPkt.pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* Per TPM 2.0 spec Part 1 Section 19.6.4: flush sessions where the caller
|
||||
|
|
|
|||
|
|
@ -353,6 +353,7 @@ static int DispatchAndRespond(FWTPM_CTX* ctx, UINT32 cmdSize, int locality,
|
|||
* SPDM. Allowlist that one command; reject the rest. */
|
||||
cc = (cmdSize >= 10) ? FwLoadU32BE(ctx->cmdBuf + 6) : 0;
|
||||
if (cc == TPM_CC_GetCapability) {
|
||||
rspSize = (int)sizeof(ctx->rspBuf);
|
||||
procRc = FWTPM_ProcessCommand(ctx, ctx->cmdBuf, (int)cmdSize,
|
||||
ctx->rspBuf, &rspSize, locality);
|
||||
if (procRc != TPM_RC_SUCCESS || rspSize == 0) {
|
||||
|
|
@ -369,6 +370,7 @@ static int DispatchAndRespond(FWTPM_CTX* ctx, UINT32 cmdSize, int locality,
|
|||
#endif
|
||||
|
||||
if (!dispatched) {
|
||||
rspSize = (int)sizeof(ctx->rspBuf);
|
||||
procRc = FWTPM_ProcessCommand(ctx, ctx->cmdBuf, (int)cmdSize,
|
||||
ctx->rspBuf, &rspSize, locality);
|
||||
if (procRc != TPM_RC_SUCCESS || rspSize == 0) {
|
||||
|
|
|
|||
|
|
@ -81,10 +81,28 @@ static void usage(const char* progname)
|
|||
}
|
||||
|
||||
#ifdef WOLFTPM_SPDM_RESPONDER
|
||||
/* Build a 10-byte TPM response header carrying an error code. */
|
||||
static int FwtpmBuildErrorFrame(byte* resp, TPM_RC rc)
|
||||
{
|
||||
resp[0] = 0x80; resp[1] = 0x01; /* tag: TPM_ST_NO_SESSIONS */
|
||||
resp[2] = 0x00; resp[3] = 0x00; /* responseSize, upper half */
|
||||
resp[4] = 0x00; resp[5] = 0x0A; /* responseSize = 10 */
|
||||
resp[6] = (byte)((rc >> 24) & 0xFF); /* responseCode, MSB */
|
||||
resp[7] = (byte)((rc >> 16) & 0xFF);
|
||||
resp[8] = (byte)((rc >> 8) & 0xFF);
|
||||
resp[9] = (byte)(rc & 0xFF); /* responseCode, LSB */
|
||||
return TPM2_HEADER_SIZE;
|
||||
}
|
||||
|
||||
static int fwtpmSpdmTpmDispatch(void* userCtx,
|
||||
const byte* cmd, word32 cmdSz,
|
||||
byte* resp, word32 respBufSz, word32* respSz)
|
||||
{
|
||||
/* The dispatcher needs a full-size buffer but the SPDM envelope is
|
||||
* smaller, and ctx->rspBuf is already holding the SPDM frame this call
|
||||
* is nested inside (fwtpm_io.c), so stage here. Static, not stack: the
|
||||
* server serves one command at a time and this is 8KB. */
|
||||
static byte stageBuf[FWTPM_MAX_COMMAND_SIZE];
|
||||
FWTPM_CTX* ctx = (FWTPM_CTX*)userCtx;
|
||||
int rc;
|
||||
int rspSize;
|
||||
|
|
@ -92,22 +110,31 @@ static int fwtpmSpdmTpmDispatch(void* userCtx,
|
|||
if (ctx == NULL || cmd == NULL || resp == NULL || respSz == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
rspSize = (int)respBufSz;
|
||||
rc = FWTPM_ProcessCommand(ctx, cmd, (int)cmdSz, resp, &rspSize, 0);
|
||||
rspSize = (int)sizeof(stageBuf);
|
||||
rc = FWTPM_ProcessCommand(ctx, cmd, (int)cmdSz, stageBuf, &rspSize, 0);
|
||||
if (rc == TPM_RC_SUCCESS && rspSize >= TPM2_HEADER_SIZE) {
|
||||
if ((word32)rspSize <= respBufSz) {
|
||||
XMEMCPY(resp, stageBuf, (size_t)rspSize);
|
||||
}
|
||||
else if (respBufSz >= TPM2_HEADER_SIZE) {
|
||||
/* Does not fit the envelope; report it as a TPM error rather
|
||||
* than truncating the response. */
|
||||
rspSize = FwtpmBuildErrorFrame(resp, TPM_RC_SIZE);
|
||||
}
|
||||
else {
|
||||
rspSize = 0;
|
||||
}
|
||||
}
|
||||
/* A non-zero TPM_RC is a valid TPM response - the requester must see
|
||||
* the actual error code. If the dispatcher didn't write one (rspSize
|
||||
* left at zero or partial), synthesize a 10-byte TPM_ST_NO_SESSIONS
|
||||
* error frame here so the SPDM layer encrypts and sends it back. */
|
||||
if ((rc != TPM_RC_SUCCESS || rspSize < TPM2_HEADER_SIZE) &&
|
||||
respBufSz >= TPM2_HEADER_SIZE) {
|
||||
resp[0] = 0x80; resp[1] = 0x01; /* TPM_ST_NO_SESSIONS */
|
||||
resp[2] = 0x00; resp[3] = 0x00; resp[4] = 0x00; resp[5] = 0x0A;
|
||||
resp[6] = (byte)((rc >> 24) & 0xFF);
|
||||
resp[7] = (byte)((rc >> 16) & 0xFF);
|
||||
resp[8] = (byte)((rc >> 8) & 0xFF);
|
||||
resp[9] = (byte)(rc & 0xFF);
|
||||
rspSize = TPM2_HEADER_SIZE;
|
||||
rspSize = FwtpmBuildErrorFrame(resp, (TPM_RC)rc);
|
||||
}
|
||||
/* The staging copy holds the same plaintext as the wire response */
|
||||
TPM2_ForceZero(stageBuf, sizeof(stageBuf));
|
||||
*respSz = (word32)rspSize;
|
||||
return 0; /* I/O layer succeeded; TPM error code is in the response. */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ static void TisHandleRegAccess(FWTPM_CTX* ctx, FWTPM_TIS_REGS* regs)
|
|||
|
||||
/* Gated to the owner above, so loc == ctx->tisLocality:
|
||||
* execute under the addressed (owning) locality. */
|
||||
rspSize = (int)sizeof(regs->rsp_buf);
|
||||
procRc = FWTPM_ProcessCommand(ctx,
|
||||
localCmd, (int)localCmdLen,
|
||||
regs->rsp_buf, &rspSize, loc);
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ void TPM2_Packet_InitBuf(TPM2_Packet* packet, byte* buf, int size)
|
|||
packet->buf = buf;
|
||||
packet->pos = TPM2_HEADER_SIZE; /* skip header (fill during finalize) */
|
||||
packet->size = size;
|
||||
packet->overflow = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,6 +151,9 @@ void TPM2_Packet_AppendU8(TPM2_Packet* packet, UINT8 data)
|
|||
packet->buf[packet->pos] = data;
|
||||
packet->pos += sizeof(UINT8);
|
||||
}
|
||||
else if (packet != NULL) {
|
||||
packet->overflow = 1;
|
||||
}
|
||||
}
|
||||
void TPM2_Packet_ParseU8(TPM2_Packet* packet, UINT8* data)
|
||||
{
|
||||
|
|
@ -170,6 +174,9 @@ void TPM2_Packet_AppendU16(TPM2_Packet* packet, UINT16 data)
|
|||
XMEMCPY(&packet->buf[packet->pos], &data, sizeof(UINT16));
|
||||
packet->pos += sizeof(UINT16);
|
||||
}
|
||||
else if (packet != NULL) {
|
||||
packet->overflow = 1;
|
||||
}
|
||||
}
|
||||
void TPM2_Packet_ParseU16(TPM2_Packet* packet, UINT16* data)
|
||||
{
|
||||
|
|
@ -190,6 +197,9 @@ void TPM2_Packet_AppendU32(TPM2_Packet* packet, UINT32 data)
|
|||
XMEMCPY(&packet->buf[packet->pos], &data, sizeof(UINT32));
|
||||
packet->pos += sizeof(UINT32);
|
||||
}
|
||||
else if (packet != NULL) {
|
||||
packet->overflow = 1;
|
||||
}
|
||||
}
|
||||
void TPM2_Packet_ParseU32(TPM2_Packet* packet, UINT32* data)
|
||||
{
|
||||
|
|
@ -212,6 +222,9 @@ void TPM2_Packet_AppendU64(TPM2_Packet* packet, UINT64 data)
|
|||
XMEMCPY(&packet->buf[packet->pos], &data, sizeof(UINT64));
|
||||
packet->pos += sizeof(UINT64);
|
||||
}
|
||||
else if (packet != NULL) {
|
||||
packet->overflow = 1;
|
||||
}
|
||||
}
|
||||
void TPM2_Packet_ParseU64(TPM2_Packet* packet, UINT64* data)
|
||||
{
|
||||
|
|
@ -234,6 +247,9 @@ void TPM2_Packet_AppendS32(TPM2_Packet* packet, INT32 data)
|
|||
XMEMCPY(&packet->buf[packet->pos], &data, sizeof(INT32));
|
||||
packet->pos += sizeof(INT32);
|
||||
}
|
||||
else if (packet != NULL) {
|
||||
packet->overflow = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void TPM2_Packet_AppendBytes(TPM2_Packet* packet, byte* buf, int size)
|
||||
|
|
@ -243,6 +259,9 @@ void TPM2_Packet_AppendBytes(TPM2_Packet* packet, byte* buf, int size)
|
|||
XMEMCPY(&packet->buf[packet->pos], buf, size);
|
||||
packet->pos += size;
|
||||
}
|
||||
else if (packet != NULL) {
|
||||
packet->overflow = 1;
|
||||
}
|
||||
}
|
||||
void TPM2_Packet_ParseBytes(TPM2_Packet* packet, byte* buf, int size)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6218,6 +6218,87 @@ static void test_fwtpm_mldsa87_maxbuf(void)
|
|||
fwtpm_pass("MLDSA-87 max-buffer roundtrip:", 1);
|
||||
}
|
||||
|
||||
#define FWTPM_TEST_CANARY_SZ 1024
|
||||
#define FWTPM_TEST_CANARY_BYTE 0x5A
|
||||
|
||||
static byte gCapRsp[FWTPM_MAX_COMMAND_SIZE + FWTPM_TEST_CANARY_SZ];
|
||||
|
||||
static void test_fwtpm_response_buffer_capacity(void)
|
||||
{
|
||||
FWTPM_CTX ctx;
|
||||
int rc, rspSize, cmdSz, pos, j;
|
||||
UINT32 handle;
|
||||
UINT32 seqHandle;
|
||||
byte msg[16];
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
AssertIntEQ(fwtpm_test_startup(&ctx), 0);
|
||||
|
||||
cmdSz = BuildCreatePrimaryCmdParam(gCmd, TPM_ALG_MLDSA, TPM_MLDSA_87);
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, cmdSz, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
handle = GetU32BE(gRsp + TPM2_HEADER_SIZE);
|
||||
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_NO_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_CC_SignSequenceStart); pos += 4;
|
||||
PutU32BE(gCmd + pos, handle); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
rspSize = 0;
|
||||
FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
seqHandle = GetU32BE(gRsp + TPM2_HEADER_SIZE);
|
||||
memset(msg, 0xAB, sizeof(msg));
|
||||
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_CC_SignSequenceComplete); pos += 4;
|
||||
PutU32BE(gCmd + pos, seqHandle); pos += 4;
|
||||
PutU32BE(gCmd + pos, handle); pos += 4;
|
||||
PutU32BE(gCmd + pos, 18); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_RS_PW); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
gCmd[pos++] = 0; PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
PutU32BE(gCmd + pos, TPM_RS_PW); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
gCmd[pos++] = 0; PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
PutU16BE(gCmd + pos, sizeof(msg)); pos += 2;
|
||||
memcpy(gCmd + pos, msg, sizeof(msg)); pos += sizeof(msg);
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
|
||||
/* A full-size buffer is the documented contract: the response fits and
|
||||
* nothing is written past it. */
|
||||
memset(gCapRsp, 0, sizeof(gCapRsp));
|
||||
memset(gCapRsp + FWTPM_MAX_COMMAND_SIZE, FWTPM_TEST_CANARY_BYTE,
|
||||
FWTPM_TEST_CANARY_SZ);
|
||||
rspSize = FWTPM_MAX_COMMAND_SIZE;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, pos, gCapRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gCapRsp), TPM_RC_SUCCESS);
|
||||
AssertTrue(rspSize <= FWTPM_MAX_COMMAND_SIZE);
|
||||
for (j = 0; j < FWTPM_TEST_CANARY_SZ; j++) {
|
||||
AssertIntEQ(gCapRsp[FWTPM_MAX_COMMAND_SIZE + j],
|
||||
FWTPM_TEST_CANARY_BYTE);
|
||||
}
|
||||
|
||||
/* An MLDSA-87 signature is the largest response and must still fit. */
|
||||
AssertTrue(rspSize > 4096);
|
||||
|
||||
BuildCmdHeader(gCmd, TPM_ST_NO_SESSIONS, 14, TPM_CC_FlushContext);
|
||||
PutU32BE(gCmd + 10, handle);
|
||||
rspSize = 0;
|
||||
FWTPM_ProcessCommand(&ctx, gCmd, 14, gRsp, &rspSize, 0);
|
||||
|
||||
FWTPM_Cleanup(&ctx);
|
||||
fwtpm_pass("Response buffer capacity respected:", 1);
|
||||
}
|
||||
|
||||
/* ---- Hash-ML-DSA sequence round-trip across 44/65/87 -----------------
|
||||
* SignSequenceStart -> SequenceUpdate(chunked) -> SignSequenceComplete
|
||||
* exercises the hash accumulator path (wc_HashUpdate) through all three
|
||||
|
|
@ -11046,6 +11127,7 @@ int fwtpm_unit_tests(int argc, char *argv[])
|
|||
test_fwtpm_signseq_slot_exhaustion();
|
||||
test_fwtpm_signseq_longmsg_boundary();
|
||||
test_fwtpm_mldsa87_maxbuf();
|
||||
test_fwtpm_response_buffer_capacity();
|
||||
test_fwtpm_mlkem1024_maxbuf();
|
||||
test_fwtpm_hash_mldsa_seq_all_params();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -46,7 +46,9 @@
|
|||
\param cmdBuf input command buffer (big-endian TPM packet)
|
||||
\param cmdSize size of cmdBuf in bytes
|
||||
\param rspBuf output response buffer (caller-allocated)
|
||||
\param rspSize in: capacity of rspBuf; out: bytes written
|
||||
\param rspSize out: bytes written. rspBuf must be at least
|
||||
FWTPM_MAX_COMMAND_SIZE bytes; a caller whose transport buffer is
|
||||
smaller must stage the response through one that is not.
|
||||
\param locality TPM locality (0-4) reported by the transport
|
||||
|
||||
\sa FWTPM_IO_ServerLoop
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ typedef struct TPM2_Packet {
|
|||
byte* buf;
|
||||
int pos;
|
||||
int size;
|
||||
unsigned int overflow:1;
|
||||
} TPM2_Packet;
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue