Skip to content

Bound CMAC response payloads against the received frame - #474

Open
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:mainfrom
yosuke-wolfssl:fix/cmac
Open

Bound CMAC response payloads against the received frame#474
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:mainfrom
yosuke-wolfssl:fix/cmac

Conversation

@yosuke-wolfssl

@yosuke-wolfssl yosuke-wolfssl commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Problem

wh_Client_RecvResponse reports the received payload length but never validates
it against the message being parsed. The comm client reuses one buffer for
request and response, so a short reply leaves the tail holding the client's own
outbound request bytes.

None of the six CMAC response handlers bounded the frame. CmacGenerateResponse,
CmacFinalResponse, CmacGenerateDmaResponse and CmacDmaFinalResponse do
memcpy(outMac, res + 1, *outMacLen) over trailing bytes the frame may not
carry, landing stale data in the caller's MAC buffer; the two Update handlers
restore CMAC state from an unvalidated struct. A malicious or malfunctioning
server returns a MAC the client silently accepts.

This is one of the follow-up requested on #457.

Fix (src/wh_client_crypto.c)

Every CMAC response goes through _getCryptoResponse(), which has already
consumed rc, so the bound is the combined form guarded by the left operand:

const uint32_t hdr_sz =
    sizeof(whMessageCrypto_GenericResponseHeader) + sizeof(*res);
if (res_len < hdr_sz || res->outSz > (res_len - hdr_sz)) {
    ret = WH_ERROR_ABORTED;
}
Handler Form
CmacGenerateResponse hdr_sz + res->outSz
CmacFinalResponse hdr_sz + res->outSz
CmacGenerateDmaResponse hdr_sz + res->outSz
CmacDmaFinalResponse hdr_sz + res->outSz
CmacUpdateResponse fixed size, no trailing payload
CmacDmaUpdateResponse fixed size, no trailing payload
  • Inside the success branch. Both crypto dispatchers reply with the generic
    header alone when a handler fails, so an unconditional bound would convert
    every legitimate error reply into WH_ERROR_ABORTED and hide the server's
    rc.
  • Before the state restore. wh_Crypto_CmacAesRestoreStateFromMsg() read
    res->resumeState ahead of any bound; it now sits under the new guard.
  • The pre-existing clamp (res->outSz < *outMacLen) is untouched — it bounds
    the caller's buffer, a different bound from the frame.

_CmacKdfMakeKey is KDF-via-CMAC and is covered by #467, not here. This PR is
now source-only.

Tests

The test added by the earlier revision has been removed. It was
test-refactor/misc/wh_test_client_malformed_resp.c (564 lines), built on a
scripted transport client callback that echoed the request's comm header and
reported a frame length independent of the body it wrote. Per review, a test
reachable only through a fake transport or a hand-built packet is testing the
harness, not the fix, so it and its wh_test_list.c entry are dropped. This also
removes the add/add conflict with #463/#473/#475/#476, which each created the
same file.

No replacement test is added: a conforming server always sends a frame that
satisfies these bounds, so the normal wh_Client_* API has no path to them.

Verification

  • test-refactor: default 37 passed / 25 skipped / 0 failed of 62 · DMA=1 41/21/0 · SHE=1 43/19/0
  • Legacy test/ suite clean.
  • Clean under -std=c90 -Werror -Wall -Wextra.
  • All six guards were previously mutation-checked (><, >>=,
    dropping the header clause, neutering the body): 24/24 mutants caught while
    the test existed.

@yosuke-wolfssl yosuke-wolfssl self-assigned this Jul 22, 2026
Copilot AI review requested due to automatic review settings July 22, 2026 02:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the client-side CMAC response handlers to ensure that any server-declared CMAC output/state being consumed is actually present in the received frame, preventing reuse-buffer tail data from being treated as valid MAC/state.

Changes:

  • Add response-length bounds checks to all six CMAC response handlers before copying MAC bytes or restoring CMAC state.
  • Preserve server error codes by keeping the new bounds checks inside the success path (so header-only error replies still return rc).
  • Add a new refactor misc test that scripts malformed/truncated responses and asserts WH_ERROR_ABORTED plus “caller output untouched” behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/wh_client_crypto.c Adds frame-length validation for CMAC response payloads/state prior to restore/copy.
test-refactor/misc/wh_test_client_malformed_resp.c New negative test covering truncated/short CMAC replies (DMA and non-DMA).
test-refactor/wh_test_list.c Registers the new malformed-response misc test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #474

Scan targets checked: wolfhsm-crypto-bugs, wolfhsm-src

No new issues found in the changed files. ✅

Frauschi
Frauschi previously approved these changes Jul 23, 2026
@Frauschi Frauschi removed their assignment Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants