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

Copy link
Copy Markdown

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.

Test harness (test-refactor/misc/wh_test_client_malformed_resp.c)

New misc test whTest_ClientMalformedResp, using a scripted transport client
callback that echoes the request's comm header and reports a frame length
independent of the body it wrote. Per handler: a well-formed exchange that
poisons the buffer, a claim one byte past the frame (rejected, caller buffer
verified untouched), a frame shorter than the response struct on a success
reply, an exact-fit acceptance, and a header-only error reply that must still
return the server's rc.

Verification

  • make check SHE=1 — 44 passed, 0 failed of 63.
  • make check SHE=1 DMA=1 — 48 passed, 0 failed of 63.
  • make check SHE=1 DMA=1 ASAN=1 — 48 passed, 0 failed, no sanitizer reports.
  • Legacy test/ suite with SHE=1 — clean, exit 0.
  • Mutation-verified: for each of the six guards, flipping > to <, to
    >=, dropping the header clause, and neutering the guard body each make the
    new test fail. 24/24 mutants caught.

Note: this adds test-refactor/misc/wh_test_client_malformed_resp.c, which
#463/#464 also add. Expect an add/add conflict; the registry entry and transport
scaffolding are byte-identical to #464's so the resolution is a concatenation of
sub-tests.

@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 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