Skip to content

Fix bug in data unwrap. Remove unnecessary stack buffers in key wrap code - #510

Open
AlexLanzano wants to merge 1 commit into
wolfSSL:mainfrom
AlexLanzano:keywrap-fixes
Open

Fix bug in data unwrap. Remove unnecessary stack buffers in key wrap code#510
AlexLanzano wants to merge 1 commit into
wolfSSL:mainfrom
AlexLanzano:keywrap-fixes

Conversation

@AlexLanzano

Copy link
Copy Markdown
Member

Bug fix

  • _AesGcmDataUnwrapWithKek decrypts into a staging plainData[] instead of dataOut, which overlapped the ciphertext in the shared comm buffer. Fixes silent corruption of any wh_Client_DataUnwrap payload >= 32 bytes.
  • Added encBlobSz > dataSz bound check.

Data wrap restructure

  • _AesGcmDataWrapWithKek now stages into plainData[] and rejects dataSz > MAX_DATA_SIZE, so the helper owns the no-alias requirement rather than trusting callers.
  • _HandleDataWrapRequest drops its 2 KB data[] and uses reqData directly.
  • Both data helpers ForceZero the staging buffer and return the wolfSSL error instead of discarding it.

Stack buffers removed (~6 KB)

  • _HandleKeyWrapRequest: key[] becomes a pointer into reqData.
  • _HandleKeyUnwrapAndCacheRequest: key[] becomes a pointer into reqData. Scrub now uses keySz, since sizeof on a pointer would have wiped only 8 bytes.
  • _HandleKeyWrapExportRequest: key[] reads into respData. keySz bounded by min(respDataSz, MAX_KEY_SIZE), and the scrub is failure-only so it cannot clobber the wrapped output.

Tests

  • Added a data wrap/unwrap round-trip sweep over sizes 1 to 128, spanning the AES block boundary.
  • Enlarged the two legacy data-wrap payloads from 14 to 63 bytes. The old sub-block payload is why the corruption went unnoticed.

@AlexLanzano
AlexLanzano requested a lite review from Copilot August 12, 2026 17:52
@AlexLanzano AlexLanzano self-assigned this Aug 12, 2026

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Fixes silent corruption in AES-GCM data unwrap/wrap paths caused by in-place buffer overlap, removes several large stack buffers in key handling code, and strengthens tests to catch regressions around AES block boundaries.

Changes:

  • Stage AES-GCM wrap/unwrap input/output to prevent plaintext/ciphertext aliasing and add output-size bounds checking.
  • Refactor key wrap/unwrap handlers to use request/response buffers directly (removing multi-KB stack arrays) and correct scrubbing sizes.
  • Expand/augment tests with larger payloads and a round-trip size sweep around AES block boundaries.

Reviewed changes

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

File Description
test/wh_test_keywrap.c Increases legacy data-wrap test payload size to span multiple AES blocks (better overlap detection).
test-refactor/client-server/wh_test_keywrap.c Adds data wrap/unwrap round-trip coverage for multiple sizes near AES block boundaries.
src/wh_server_keystore.c Adds staging buffers for AES-GCM wrap/unwrap to avoid overlap corruption, adds size checks, removes stack key/data buffers in request handlers, and improves/limits scrubbing.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test-refactor/client-server/wh_test_keywrap.c
Comment thread src/wh_server_keystore.c
Comment thread src/wh_server_keystore.c
@AlexLanzano

Copy link
Copy Markdown
Member Author

CI will fail until #511 is merged

@bigbrett
bigbrett requested review from wolfSSL-Fenrir-bot and removed request for wolfSSL-Fenrir-bot August 13, 2026 15:23

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

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

Findings: 3
3 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread src/wh_server_keystore.c
uint8_t iv[WH_KEYWRAP_AES_GCM_IV_SIZE];
uint8_t* encBlob;
uint16_t encBlobSz;
uint8_t plainData[WOLFHSM_CFG_KEYWRAP_MAX_DATA_SIZE];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 [Low] Data-unwrap path gains a full MAX_DATA_SIZE stack buffer · Resource leaks on error paths

_AesGcmDataUnwrapWithKek adds plainData[WOLFHSM_CFG_KEYWRAP_MAX_DATA_SIZE] (up to 2 KB) on the WH_KEY_DATAUNWRAP call chain, which carried no such buffer before: _HandleDataUnwrapRequest uses respData directly. Unlike the wrap path, no buffer was removed to offset it, so peak server stack for data unwrap grows by MAX_DATA_SIZE.

Fix: Bound the staging buffer to the AES block size and decrypt in chunks, or copy the ciphertext out of the overlapping region instead of staging the whole plaintext.

Comment thread src/wh_server_keystore.c
encBlob = (uint8_t*)wrappedDataIn + sizeof(iv) + sizeof(authTag);
encBlobSz = wrappedDataSz - sizeof(iv) - sizeof(authTag);

if (encBlobSz > dataSz) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚪ [Info] New encBlobSz dataSz check is unreachable from the only caller · Dead error handling

WH_KEYWRAP_AES_GCM_HEADER_SIZE is defined as IV_SIZE + TAG_SIZE, and the sole caller _HandleDataUnwrapRequest passes dataSz = req->wrappedDataSz - WH_KEYWRAP_AES_GCM_HEADER_SIZE, which is identically encBlobSz. The guard can never return WH_ERROR_BUFFER_SIZE, so it is untestable and adds no runtime protection today.

Fix: Keep the guard but document it as an internal invariant assertion, or drop it in favour of asserting encBlobSz == dataSz.

big[i] = (uint8_t)(i & 0xFF);
}

for (i = 0; i < (sizeof(sizes) / sizeof(sizes[0])); i++) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 [Low] New MAX_DATA_SIZE staging buffers are never exercised at their boundary · Missing edge-case coverage on a function the PR also changed

The PR adds plainData[WOLFHSM_CFG_KEYWRAP_MAX_DATA_SIZE] staging buffers to both data-wrap helpers, guarded by dataSz > WOLFHSM_CFG_KEYWRAP_MAX_DATA_SIZE. The new sweep stops at 128 bytes and _whTest_KeywrapOversizeRequest only tests MAX+1, so the exact-max case — the only input that fills the new stack buffers completely — is untested in both suites.

Fix: Add WOLFHSM_CFG_KEYWRAP_MAX_DATA_SIZE and MAX_DATA_SIZE - 1 to the round-trip sweep sizes.

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.

3 participants