Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c6b2104
F-6318 - Validate priv size marker before read in readKeyBlob
aidangarske Jun 22, 2026
52ae1f9
F-6310 - Enable Nuvoton GPIO pull-up by setting the bit
aidangarske Jun 22, 2026
7e060e1
F-6315 - Add testable swtpm response-size validation helper
aidangarske Jun 22, 2026
3696b0a
F-6319 - Clamp NV dataSize to digest buffer in secure_rot
aidangarske Jun 22, 2026
4d3b2d6
F-6320 - Zeroize GetRandom response buffer in TPM2_GetNonceNoLock
aidangarske Jun 22, 2026
211d439
F-4165 - Zeroize partial SPDM key material on derive failure
aidangarske Jun 22, 2026
2246a42
F-5656 - Scrub wrapped private blob from CreateKey stack output
aidangarske Jun 22, 2026
95eb1f7
F-5657 - Scrub wrapped private blob from CreateLoadedKey stack output
aidangarske Jun 22, 2026
615b7e4
F-5661 - Scrub sealed key blob from CreateKeySeal stack output
aidangarske Jun 22, 2026
577f3ab
F-6321 - Zeroize decrypted TPM response buffer in TPM2_SPDM_SendCommand
aidangarske Jun 22, 2026
6b3b50f
F-5662 - Zeroize TIS transport tx/rx buffers after TPM traffic
aidangarske Jun 22, 2026
98a5f95
F-6312 - Clamp classic-arm inner size in TPM2_Packet_AppendSensitive
aidangarske Jun 22, 2026
af8fe5b
F-6313 - Clear publicArea when ParsePublic reads zero size
aidangarske Jun 22, 2026
02bc641
F-6316 - Add testable TIS response-size validation helper
aidangarske Jun 22, 2026
05f6cb7
F-6317 - Add testable SPDM I/O response-size validation helper
aidangarske Jun 22, 2026
a9ea3dc
F-6322 - Correct ML-DSA sign sequence comments to streamable
aidangarske Jun 22, 2026
b5be21d
F-6314 - Add maximum-size TPM2B sensitive roundtrip test
aidangarske Jun 22, 2026
8c1f246
F-6311 - Prefer tpmrm0 with tpm0 fallback on Linux default
aidangarske Jun 22, 2026
f9ebeb3
F-6315 - Preserve SwTpmReceive error before response-size validation
aidangarske Jun 22, 2026
9e7769a
F-6318 - Return BUFFER_E on short private read in readKeyBlob
aidangarske Jun 22, 2026
68f4084
F-6312 - Cover ECC, KEYEDHASH, SYMCIPHER arms in AppendSensitive clam…
aidangarske Jun 22, 2026
ac87e6b
F-6318 - Create readKeyBlob test files with owner-only permissions
aidangarske Jun 22, 2026
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
3 changes: 3 additions & 0 deletions examples/boot/secure_rot.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,9 @@ int TPM2_Boot_SecureROT_Example(void* userCtx, int argc, char *argv[])
rc = wolfTPM2_NVReadPublic(&dev, nvIndex, &nvPublic);
if (rc == 0) {
digestSz = nvPublic.dataSize;
if (digestSz > (int)sizeof(digest)) {
digestSz = (int)sizeof(digest);
}
}

/* Read access */
Expand Down
2 changes: 1 addition & 1 deletion examples/gpio/gpio_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ int TPM2_GPIO_Config_Example(void* userCtx, int argc, char *argv[])

/* Extra step for open-drain with pull-up mode */
if (gpioMode == TPM_GPIO_MODE_PULLUP) {
newConfig.GpioPullUp &= ~(1 << gpioNum);
newConfig.GpioPullUp |= (1 << gpioNum);
}

#ifdef WOLFTPM_DEBUG_VERBOSE
Expand Down
13 changes: 6 additions & 7 deletions examples/pqc/mldsa_sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
* (SignSequenceComplete), Sec.17.6 (VerifySequenceStart), Sec.20.3
* (VerifySequenceComplete).
*
* Pure ML-DSA is one-shot on the sign path: SequenceUpdate is rejected
* with TPM_RC_ONE_SHOT_SIGNATURE, the full message must arrive via the
* SignSequenceComplete buffer. Verify sequences do accept Update per
* Sec.20.3 and this example uses that path to exercise both idioms. */
* Pure ML-DSA is streamable on both sign and verify: SequenceUpdate is
* accepted (only multi-pass schemes such as EdDSA are one-shot). This
* example passes the whole message via SignSequenceComplete on sign and
* streams it through SequenceUpdate on verify to exercise both idioms. */

#ifdef HAVE_CONFIG_H
#include <config.h>
Expand Down Expand Up @@ -144,9 +144,8 @@ static int mldsa_sign_run(int argc, char *argv[])
(unsigned)mldsaKey.handle.hndl,
(unsigned)mldsaKey.pub.publicArea.unique.mldsa.size);

/* Sign: Pure ML-DSA is one-shot per Sec.17.5. Message goes via
* SignSequenceComplete's buffer parameter, not via SequenceUpdate
* (which returns TPM_RC_ONE_SHOT_SIGNATURE for Pure MLDSA keys). */
/* Sign: pass the whole message via SignSequenceComplete's buffer.
* Pure ML-DSA also accepts SequenceUpdate since it is streamable. */
rc = wolfTPM2_SignSequenceStart(&dev, &mldsaKey, NULL, 0, &seqHandle);
if (rc != TPM_RC_SUCCESS) {
printf("SignSequenceStart failed 0x%x: %s\n",
Expand Down
2 changes: 1 addition & 1 deletion examples/pqc/mldsa_verify_neg.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ static int mldsa_verify_neg_run(int argc, char *argv[])
goto exit;
}

/* Sign the message (Pure ML-DSA is one-shot via Complete's buffer). */
/* Sign the message via Complete's buffer (Pure ML-DSA is streamable). */
rc = wolfTPM2_SignSequenceStart(&dev, &mldsaKey, NULL, 0, &seqHandle);
if (rc == TPM_RC_SUCCESS) {
rc = wolfTPM2_SignSequenceComplete(&dev, seqHandle, &mldsaKey,
Expand Down
22 changes: 17 additions & 5 deletions examples/tpm_test_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key)
goto exit;
}
fileSz -= bytes_read;
if (key->pub.size > sizeof(UINT16) + sizeof(pubAreaBuffer)) {
if (sizeof(UINT16) + key->pub.size > sizeof(pubAreaBuffer)) {
printf("Public key size is too large\n");
rc = BUFFER_E; goto exit;
}
Expand All @@ -249,11 +249,23 @@ int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key)

if (fileSz > 0) {
printf("Reading the private part of the key\n");
bytes_read = XFREAD(&key->priv, 1, fileSz, fp);
if (bytes_read != fileSz) {
/* Read and validate the size marker before the buffer so a
* crafted file cannot overflow priv */
bytes_read = XFREAD(&key->priv.size, 1, sizeof(key->priv.size), fp);
if (bytes_read != sizeof(key->priv.size)) {
printf("Read %zu, expected private size marker of %zu bytes\n",
bytes_read, sizeof(key->priv.size));
rc = BUFFER_E; goto exit;
}
if (key->priv.size > sizeof(key->priv.buffer)) {
printf("Private key size is too large\n");
rc = BUFFER_E; goto exit;
}
bytes_read = XFREAD(key->priv.buffer, 1, key->priv.size, fp);
if (bytes_read != key->priv.size) {
printf("Read %zu, expected private blob %zu bytes\n",
bytes_read, fileSz);
goto exit;
bytes_read, (size_t)key->priv.size);
rc = BUFFER_E; goto exit;
}
rc = 0; /* success */
}
Expand Down
13 changes: 13 additions & 0 deletions src/spdm/spdm_kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,19 @@ int wolfSPDM_DeriveFromHandshakeSecret(WOLFSPDM_CTX* ctx,
ctx->rspDataKey, ctx->rspDataIv);
}

if (rc != WOLFSPDM_SUCCESS) {
/* wipe any partially derived material so it cannot carry into a
* reused ctx */
wc_ForceZero(ctx->reqHsSecret, sizeof(ctx->reqHsSecret));
wc_ForceZero(ctx->rspHsSecret, sizeof(ctx->rspHsSecret));
wc_ForceZero(ctx->reqFinishedKey, sizeof(ctx->reqFinishedKey));
wc_ForceZero(ctx->rspFinishedKey, sizeof(ctx->rspFinishedKey));
wc_ForceZero(ctx->reqDataKey, sizeof(ctx->reqDataKey));
wc_ForceZero(ctx->rspDataKey, sizeof(ctx->rspDataKey));
wc_ForceZero(ctx->reqDataIv, sizeof(ctx->reqDataIv));
wc_ForceZero(ctx->rspDataIv, sizeof(ctx->rspDataIv));
}

return rc;
}

Expand Down
11 changes: 9 additions & 2 deletions src/tpm2.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,14 +450,19 @@ static TPM_RC TPM2_SPDM_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet)

rc = wolfTPM2_SPDM_SecuredExchange(spdmCtx,
packet->buf, packet->pos, tpmResp, &tpmRespSz);
if (rc != 0)
if (rc != 0) {
TPM2_ForceZero(tpmResp, sizeof(tpmResp));
return rc;
}

if (tpmRespSz > MAX_RESPONSE_SIZE)
if (tpmRespSz > MAX_RESPONSE_SIZE) {
TPM2_ForceZero(tpmResp, sizeof(tpmResp));
return TPM_RC_SIZE;
}
XMEMCPY(packet->buf, tpmResp, tpmRespSz);
packet->pos = 0;
packet->size = tpmRespSz;
TPM2_ForceZero(tpmResp, sizeof(tpmResp));
return TPM_RC_SUCCESS;
}
#endif /* WOLFTPM_SPDM */
Expand Down Expand Up @@ -6529,6 +6534,8 @@ int TPM2_GetNonceNoLock(byte* nonceBuf, int nonceSz)
TPM2_Packet_ParseBytes(&packet, &nonceBuf[randSz], outSz);
randSz += outSz;
}
/* response buffer held freshly generated random; wipe before return */
TPM2_ForceZero(buffer, sizeof(buffer));
#endif

return rc;
Expand Down
35 changes: 24 additions & 11 deletions src/tpm2_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,19 @@ int TPM2_LINUX_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet)
#include <string.h>

/* TPM Device Path Configuration:
* - /dev/tpm0: TPM raw device (default)
* - /dev/tpmrm0: TPM resource manager (requires kernel 5.12+)
* Enabled with WOLFTPM_USE_TPMRM
* - /dev/tpmrm0: TPM resource manager (requires kernel 5.12+), preferred as it
* isolates and flushes per-connection transient objects/sessions
* - /dev/tpm0: TPM raw device, no in-kernel resource management
* The default prefers the resource manager and falls back to the raw device
* when it is unavailable. Define WOLFTPM_USE_TPMRM for resource manager only,
* or set TPM2_LINUX_DEV to pin a specific device.
*/
#ifndef TPM2_LINUX_DEV
#ifdef WOLFTPM_USE_TPMRM
#define TPM2_LINUX_DEV "/dev/tpmrm0"
#else
#define TPM2_LINUX_DEV "/dev/tpm0"
#define TPM2_LINUX_DEV "/dev/tpmrm0"
#define TPM2_LINUX_DEV_FALLBACK "/dev/tpm0"
#endif
#endif

Expand All @@ -121,14 +125,23 @@ int TPM2_LINUX_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet)
int rc_poll, nfds = 1; /* Polling single TPM dev file */
struct pollfd fds;
int rspSz = 0;
const char* devName = TPM2_LINUX_DEV;

#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Command size: %d\n", packet->pos);
TPM2_PrintBin(packet->buf, packet->pos);
#endif

if (ctx->fd < 0)
if (ctx->fd < 0) {
ctx->fd = open(TPM2_LINUX_DEV, O_RDWR | O_NONBLOCK);
#ifdef TPM2_LINUX_DEV_FALLBACK
if (ctx->fd < 0) {
ctx->fd = open(TPM2_LINUX_DEV_FALLBACK, O_RDWR | O_NONBLOCK);
if (ctx->fd >= 0)
devName = TPM2_LINUX_DEV_FALLBACK;
}
#endif
}
if (ctx->fd >= 0) {
/* Send the TPM command */
if (write(ctx->fd, packet->buf, packet->pos) == packet->pos) {
Expand All @@ -147,11 +160,11 @@ int TPM2_LINUX_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet)
else {
#ifdef DEBUG_WOLFTPM
if (ret == 0) {
printf("Received EOF from %s\n", TPM2_LINUX_DEV);
printf("Received EOF from %s\n", devName);
}
else {
printf("Failed to read from %s (ret %zd):"
" errno %d = %s\n", TPM2_LINUX_DEV, ret,
" errno %d = %s\n", devName, ret,
errno, strerror(errno));
}
#endif
Expand All @@ -161,27 +174,27 @@ int TPM2_LINUX_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet)
else {
#ifdef DEBUG_WOLFTPM
printf("Failed poll on %s: errno %d = %s\n",
TPM2_LINUX_DEV, errno, strerror(errno));
devName, errno, strerror(errno));
#endif
rc = TPM_RC_FAILURE;
}
}
else {
#ifdef DEBUG_WOLFTPM
printf("Failed write to %s: errno %d = %s\n",
TPM2_LINUX_DEV, errno, strerror(errno));
devName, errno, strerror(errno));
#endif
rc = TPM_RC_FAILURE;
}
}
else if (ctx->fd == -1 && errno == EACCES) {
printf("Permission denied on %s\n"
"Use sudo or add tss group to user.\n", TPM2_LINUX_DEV);
"Use sudo or add tss group to user.\n", devName);
}
else {
#ifdef DEBUG_WOLFTPM
printf("Failed to open %s: errno %d = %s\n",
TPM2_LINUX_DEV, errno, strerror(errno));
devName, errno, strerror(errno));
#endif
}

Expand Down
11 changes: 11 additions & 0 deletions src/tpm2_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -830,18 +830,26 @@ void TPM2_Packet_AppendSensitive(TPM2_Packet* packet, TPM2B_SENSITIVE* sensitive

switch (sensitive->sensitiveArea.sensitiveType) {
case TPM_ALG_RSA:
if (sens->rsa.size > sizeof(sens->rsa.buffer))
sens->rsa.size = sizeof(sens->rsa.buffer);
TPM2_Packet_AppendU16(packet, sens->rsa.size);
TPM2_Packet_AppendBytes(packet, sens->rsa.buffer, sens->rsa.size);
break;
case TPM_ALG_ECC:
if (sens->ecc.size > sizeof(sens->ecc.buffer))
sens->ecc.size = sizeof(sens->ecc.buffer);
TPM2_Packet_AppendU16(packet, sens->ecc.size);
TPM2_Packet_AppendBytes(packet, sens->ecc.buffer, sens->ecc.size);
break;
case TPM_ALG_KEYEDHASH:
if (sens->bits.size > sizeof(sens->bits.buffer))
sens->bits.size = sizeof(sens->bits.buffer);
TPM2_Packet_AppendU16(packet, sens->bits.size);
TPM2_Packet_AppendBytes(packet, sens->bits.buffer, sens->bits.size);
break;
case TPM_ALG_SYMCIPHER:
if (sens->sym.size > sizeof(sens->sym.buffer))
sens->sym.size = sizeof(sens->sym.buffer);
TPM2_Packet_AppendU16(packet, sens->sym.size);
TPM2_Packet_AppendBytes(packet, sens->sym.buffer, sens->sym.size);
break;
Expand Down Expand Up @@ -1206,6 +1214,9 @@ void TPM2_Packet_ParsePublic(TPM2_Packet* packet, TPM2B_PUBLIC* pub)

TPM2_Packet_ParseU16(packet, &pub->size);
pubStartPos = (packet != NULL) ? packet->pos : 0;
if (pub->size == 0) {
XMEMSET(&pub->publicArea, 0, sizeof(pub->publicArea));
}
if (pub->size > 0) {
TPM2_Packet_ParseU16(packet, &pub->publicArea.type);
TPM2_Packet_ParseU16(packet, &pub->publicArea.nameAlg);
Expand Down
17 changes: 15 additions & 2 deletions src/tpm2_spdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@
/* TIS I/O Callback (SPI/I2C TPM transport for SPDM) */
/* -------------------------------------------------------------------------- */

/* Bound a framed response size against both the caller buffer and the local
* I/O buffer before copying into the caller's rxBuf. */
int wolfTPM2_SPDM_ValidateRspSz(word32 rspSz, word32 rxSz, word32 ioBufSz)
{
if (rspSz > rxSz || rspSz > ioBufSz) {
return -1;
}
return 0;
}

#ifdef WOLFTPM_SPDM_TIS_IO
/* TIS I/O callback for routing wolfSPDM through TPM SPI/I2C FIFO.
* This matches the WOLFSPDM_IO_CB signature. TCG framing (headers) is
Expand Down Expand Up @@ -117,7 +127,7 @@ static int wolfTPM2_SPDM_TisIoCb(
XMEMCPY(&rspSz, &ioBuf[2], sizeof(UINT32));
rspSz = TPM2_Packet_SwapU32(rspSz);

if (rspSz > *rxSz || rspSz > sizeof(ioBuf)) {
if (wolfTPM2_SPDM_ValidateRspSz(rspSz, *rxSz, sizeof(ioBuf)) != 0) {
return -1;
}

Expand Down Expand Up @@ -171,7 +181,10 @@ static int wolfTPM2_SPDM_SwtpmIoCb(
XMEMCPY(&rspSz, &ioBuf[2], sizeof(word32));
rspSz = TPM2_Packet_SwapU32(rspSz);

if (rspSz < TPM2_HEADER_SIZE || rspSz > *rxSz || rspSz > sizeof(ioBuf)) {
if (rspSz < TPM2_HEADER_SIZE) {
return -1;
}
if (wolfTPM2_SPDM_ValidateRspSz(rspSz, *rxSz, sizeof(ioBuf)) != 0) {
return -1;
}

Expand Down
27 changes: 20 additions & 7 deletions src/tpm2_swtpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,18 @@ static TPM_RC SwTpmDisconnect(TPM2_CTX* ctx)
return rc;
}

/* Validate a swtpm-reported response size against the receive buffer before
* it is used to read into packet->buf. Rejects undersized headers and any
* length that would overflow the buffer. */
int TPM2_SwtpmValidateRspSz(int packetSize, uint32_t rspSz)
{
int rc = TPM_RC_SUCCESS;
if (rspSz < TPM2_HEADER_SIZE || rspSz > (uint32_t)packetSize) {
rc = TPM_RC_FAILURE;
}
return rc;
}

/* Talk to a TPM through socket
* return TPM_RC_SUCCESS on success,
* TPM_RC_FAILURE on other errors
Expand Down Expand Up @@ -543,13 +555,14 @@ int TPM2_SWTPM_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet)
if (rc == TPM_RC_SUCCESS) {
rc = SwTpmReceive(ctx, &tss_word, sizeof(uint32_t));
rspSz = TPM2_Packet_SwapU32(tss_word);
if (rspSz < TPM2_HEADER_SIZE ||
rspSz > (uint32_t)packet->size) {
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Response size(%u) out of range (header=%d, buf=%d)\n",
rspSz, TPM2_HEADER_SIZE, packet->size);
#endif
rc = TPM_RC_FAILURE;
if (rc == TPM_RC_SUCCESS) {
rc = TPM2_SwtpmValidateRspSz(packet->size, rspSz);
if (rc != TPM_RC_SUCCESS) {
#ifdef WOLFTPM_DEBUG_VERBOSE
printf("Response size(%u) out of range (header=%d, buf=%d)\n",
rspSz, TPM2_HEADER_SIZE, packet->size);
#endif
}
}
}

Expand Down
Loading
Loading