Skip to content

Bound AES DMA response frames in the crypto client - #475

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

Bound AES DMA response frames in the crypto client#475
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:mainfrom
yosuke-wolfssl:fix/aes

Conversation

@yosuke-wolfssl

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

Copy link
Copy Markdown
Contributor

Problem

The four AES DMA response handlers in wh_client_crypto.c overlaid their
response struct on the comm buffer without validating the length
wh_Client_RecvResponse reported. 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:

  • AesCtrDmaResponse restores aes->reg and aes->tmp from
    AES_IV_SIZE + AES_BLOCK_SIZE bytes read past the struct.
  • AesCbcDmaResponse restores the chaining IV the same way.
  • AesGcmDmaResponse copies res->authTagSz tag bytes from past the
    struct into the caller's buffer, bounded only by the caller's tag_len.
  • AesEcbDmaResponse parses the header only, but overlays unchecked.

A malicious or malfunctioning server returns stale data instead of an error;
for CTR/CBC that silently corrupts cipher state, for GCM it hands the caller
a tag built from its own request bytes.

Follow-up to #457, continuing the wh_Client_RecvResponse audit. This is the
AES DMA family; CMAC, LMS/XMSS DMA, ML-KEM DMA and EccCheckPubKey follow in
separate PRs.

Fix (src/wh_client_crypto.c)

Each handler now bounds res_len before parsing:

Handler Required size beyond the generic response header
AesCtrDmaResponse sizeof(*res) + AES_IV_SIZE + AES_BLOCK_SIZE
AesEcbDmaResponse sizeof(*res)
AesCbcDmaResponse sizeof(*res) + AES_IV_SIZE
AesGcmDmaResponse sizeof(*res), plus res->authTagSz against the remainder

Each size matches exactly what the server emits (*outSize in
_HandleAes*Dma). Two placement rules the DMA paths impose:

  • The check sits inside the rc == WH_ERROR_OK branch. The DMA
    dispatcher sends a header-only frame when a handler fails, so an
    unconditional bound would convert every real server error into
    WH_ERROR_ABORTED.
  • It assigns ret rather than returning early, so the DMA *_POST
    unmapping at the bottom of each function still runs.

GCM keeps its pre-existing authTagSz > tag_len branch — that bounds the
caller's buffer, which is a different limit from the received frame. 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 (480 lines), built on a
scripted transport client callback that echoed the request's comm header and
replied with a crafted frame whose reported length varied independently of the
body. 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/#474/#476,
which each created the same file.

No replacement test is added: a conforming server always emits the exact sizes
in the table above, so the normal wh_Client_* API has no path to these guards.

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.
  • The four guards plus GCM's tag clause were previously mutation-checked
    (neuter, <>, ±1, >>=, and a hoist above the rc check):
    10/10 killed 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 03:59

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 wolfHSM crypto client’s AES DMA response parsing to prevent truncated/malformed server replies from causing the client to read stale bytes from the reused comm buffer (which can silently corrupt AES state for CTR/CBC or copy unintended bytes into a GCM tag buffer).

Changes:

  • Add response-length bounds checks in the AES DMA response handlers (CTR/ECB/CBC/GCM) in src/wh_client_crypto.c, keeping the checks inside the rc == WH_ERROR_OK path and preserving DMA POST cleanup behavior.
  • Add a new scripted-transport test (whTest_ClientMalformedResp) that exercises accept-at-bound, reject-at-bound−1, and header-only server-error replies for the AES DMA family.
  • Register the new test in the refactor test list.

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 per-handler res_len bounds checks before parsing/copying trailing AES DMA response payload.
test-refactor/misc/wh_test_client_malformed_resp.c New misc test using a scripted transport to validate the client rejects truncated AES DMA responses without corrupting caller state.
test-refactor/wh_test_list.c Registers whTest_ClientMalformedResp in the misc test suite.

💡 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 #475

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

No new issues found in the changed files. ✅

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