From 1d8ea0cfd2df6188701f6fd8c0aba9ad3bc1b743 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 10 Sep 2026 14:05:48 -0700 Subject: [PATCH] Advance SPDM receive sequence after auth and harden size checks --- hal/tpm_io.c | 3 ++- src/spdm/spdm_msg.c | 24 +++++++++++++++--------- src/spdm/spdm_secured.c | 10 +++++++--- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/hal/tpm_io.c b/hal/tpm_io.c index 9c4e4452..4ab945d6 100644 --- a/hal/tpm_io.c +++ b/hal/tpm_io.c @@ -183,7 +183,8 @@ int TPM2_IoCb(TPM2_CTX* ctx, INT32 isRead, UINT32 addr, (void)userCtx; #endif #else - if (buf == NULL || size == 0 || size > MAX_SPI_FRAMESIZE) { + if (buf == NULL || size == 0 || + size > (UINT16)(sizeof(txBuf) - TPM_TIS_HEADER_SZ)) { ret = BAD_FUNC_ARG; } else { diff --git a/src/spdm/spdm_msg.c b/src/spdm/spdm_msg.c index 9cd50007..388ec403 100644 --- a/src/spdm/spdm_msg.c +++ b/src/spdm/spdm_msg.c @@ -55,6 +55,18 @@ static int wolfSPDM_BuildSimpleMsg(WOLFSPDM_CTX* ctx, byte msgCode, return WOLFSPDM_SUCCESS; } +/* KEY_EXCHANGE request size: 8-byte header, 32-byte RandomData, and two ECC + * coordinates, plus a config-specific OpaqueData block. Keep + * WOLFSPDM_KEYEX_OPAQUE_SZ in sync with the OpaqueData written below. */ +#define WOLFSPDM_KEYEX_FIXED_SZ (40 + 2 * WOLFSPDM_ECC_KEY_SIZE) +#ifdef WOLFSPDM_NUVOTON + #define WOLFSPDM_KEYEX_OPAQUE_SZ 14 +#elif defined(WOLFSPDM_NATIONS) + #define WOLFSPDM_KEYEX_OPAQUE_SZ 2 +#else + #define WOLFSPDM_KEYEX_OPAQUE_SZ 22 +#endif + int wolfSPDM_BuildKeyExchange(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) { word32 offset = 0; @@ -64,15 +76,9 @@ int wolfSPDM_BuildKeyExchange(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) word32 pubKeyYSz = sizeof(pubKeyY); int rc; - /* Require exactly the encoded request size: 40-byte fixed header, two ECC - * coordinates, and the config-specific OpaqueData block */ -#ifdef WOLFSPDM_NUVOTON - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 40 + 2 * WOLFSPDM_ECC_KEY_SIZE + 14); -#elif defined(WOLFSPDM_NATIONS) - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 40 + 2 * WOLFSPDM_ECC_KEY_SIZE + 2); -#else - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 40 + 2 * WOLFSPDM_ECC_KEY_SIZE + 22); -#endif + /* Require exactly the encoded request size */ + SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, + WOLFSPDM_KEYEX_FIXED_SZ + WOLFSPDM_KEYEX_OPAQUE_SZ); rc = wolfSPDM_GenerateEphemeralKey(ctx); if (rc == WOLFSPDM_SUCCESS) diff --git a/src/spdm/spdm_secured.c b/src/spdm/spdm_secured.c index acc5a6e3..705a757d 100644 --- a/src/spdm/spdm_secured.c +++ b/src/spdm/spdm_secured.c @@ -294,6 +294,13 @@ int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, wolfSPDM_DebugPrint(ctx, "AES-GCM decrypt failed: %d\n", rc); ret = WOLFSPDM_E_DECRYPT_FAIL; } + else { + /* Record is authenticated (tag verified) so the peer has advanced; + * advance now. A forged record fails the tag and never reaches + * here, and a later payload parse error stays fatal without + * desyncing the sequence. */ + ctx->rspSeqNum++; + } } if (aesInit) { wc_AesFree(&aes); @@ -336,9 +343,6 @@ int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, } if (ret == WOLFSPDM_SUCCESS) { - /* Advance the receive counter only after authentication and payload - * validation succeed, so a forged record cannot desync the sequence */ - ctx->rspSeqNum++; wolfSPDM_DebugPrint(ctx, "Decrypted %u bytes -> %u bytes\n", encSz, *plainSz); }