Translate the key wrap metadata trailer - #472
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes cross-endian interoperability for the key-wrap protocol by translating the whNvmMetadata “raw struct trailer” that follows the fixed key-wrap request/response headers. It introduces a dedicated metadata translation helper and applies it in the server handlers so policy checks and storage always operate on native-order metadata, while the wire-facing trailer is translated appropriately.
Changes:
- Add
wh_MessageNvm_TranslateMetadata()to translatewhNvmMetadatatrailers (including in-place translation support). - Update key wrap / unwrap-and-export server handlers to translate the metadata trailer on ingress/egress based on the request
magic. - Add a dedicated endianness regression test for key-wrap metadata trailers and register it in the server test list.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| wolfhsm/wh_message_nvm.h | Declares the new wh_MessageNvm_TranslateMetadata() helper for raw-struct metadata trailers. |
| src/wh_message_nvm.c | Implements wh_MessageNvm_TranslateMetadata() using existing translation macros and label passthrough. |
| src/wh_server_keystore.c | Translates key-wrap metadata trailer on request ingest and on unwrap-and-export response egress using magic. |
| test-refactor/server/wh_test_keywrap_endian.c | Adds endianness coverage: helper property checks plus wrap→unwrap/export round-trips under native/swapped magic. |
| test-refactor/wh_test_list.c | Registers the new whTest_KeyWrapEndian server test. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #472
Scan targets checked: wolfhsm-core-bugs, wolfhsm-crypto-bugs, wolfhsm-src
No new issues found in the changed files. ✅
d8f30fb to
9be189c
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #472
Scan targets checked: wolfhsm-core-bugs, wolfhsm-crypto-bugs, wolfhsm-src
No new issues found in the changed files. ✅
|
Hello @AlexLanzano , |
9be189c to
7cae950
Compare
|
@yosuke-wolfssl Looks like you have some failing test cases with your new changes? Could you take a look? |
7cae950 to
ae8198b
Compare
|
Looks good. Passing off to you @bigbrett |
Problem
The key wrap protocol carries a
whNvmMetadataas a raw struct trailerafter the fixed request/response headers, but the server translated only the
headers.
whNvmMetadatais fouruint16_tfields (id,access,flags,len), so every one is byte-swapped for a cross-endian client/server pair:WH_KEY_KEYWRAPrequestwhNvmMetadata+ keyid0x4025(TYPE=WRAPPED) read as0x2540(TYPE=SHE) → valid wrap rejectedWH_ERROR_BADARGSWH_KEY_KEYUNWRAPEXPORTresponsewhNvmMetadata+ keyid,access,flags,lenreturned byte-swappedEvery other NVM message flattens the struct into message fields and translates
each one; key wrap is the only place the raw struct crosses the boundary.
Addressed by f_5469.
Fix (
src/wh_server_keystore.c)Server-side only: clients always send native byte order, and the server
translates both directions from the comm-header
magic.wh_MessageNvm_TranslateMetadata()— new helper inwh_message_nvm.[ch],in-place safe, label copied verbatim.
_HandleKeyWrapRequesttranslates on ingress before any field isinspected, establishing the invariant that blobs always store metadata in
server-native order.
_HandleKeyUnwrapAndExportRequesttranslates on egress last, after everypolicy check has run on native values.
Both handlers are
staticwith one call site each, so they gain amagicparameter. No client, wire-format, or struct change.
Also fixed, found while auditing the failure paths:
*out_resp_sizeforKEYUNWRAPEXPORTunconditionally counts awhNvmMetadatatrailer, so a failedunwrap shipped up to 32 bytes of stale comm-buffer content to the client. The
handler now zeroes the trailer and any decrypted key with
wh_Utils_ForceZero()on every failure exit, and the dispatcher scrubs as a backstop. In-switch
returns becameret = X; break;so one epilogue covers them all._HandleKeyWrapRequestalso setsresp->cipherTypebefore its first failureexit — the client checks
cipherTypeahead ofrc, so an early returnpreviously surfaced as
WH_ERROR_ABORTEDinstead of the real error.Tests
Reworked on review: 1,179 test lines removed, 128 added. Both original
files were shapes a real peer cannot produce —
wh_test_keywrap_endian.c(720)drove
whServerContext*internals with synthetic magics, andwh_test_keywrap_endian_e2e.c(459) hand-built packets and pushed them at thetransport, because
wh_CommClientonly ever sends native magic. Their twowh_test_list.centries and theREADME.mdcoverage-gap bullet go with them.Replaced by
test-refactor/misc/wh_test_message_nvm.c, following #468: aloopback pair structurally cannot observe a byte-order bug, so the test calls
wh_MessageNvm_TranslateMetadata()directly withWH_COMM_MAGIC_SWAP. Nopacket crafting, no new entry point registered beyond the one parent function.
It asserts native magic is a no-op, all four scalars swap, the
labelbytearray does not move, translation is its own inverse, in-place (
src == dest)matches out-of-place, and NULL args give
WH_ERROR_BADARGS. Expected values arewritten out as literals rather than derived from
wh_Translate16(), so theoracle does not share the code under test. The helper is ungated, so the test
runs in every configuration.
The
whNvmMetadataentry added towh_test_check_struct_padding.cstays — itis what keeps the raw wire struct padding-free.
Coverage dropped with the harness, none of it reachable from a real client:
foreign-magic acceptance at the comm layer, the
req_packet/resp_packetaliasing that makes egress translation an in-place swap, wrap/unwrap policy
negatives already covered by
client-server/wh_test_keywrap.c, and themalformed-request residue check for the scrub described above. The new
"keep in step with
wh_MessageNvm_TranslateAddObjectRequest" comment likewisehas no test behind it; the twin is pre-existing code this PR does not touch.
Verification
On merge base
237bfbc, clean under-std=c90 -Werror -Wall -Wextra, zerowarnings in all four configurations:
test-refactordefaulttest-refactor DMA=1test-refactor SHE=1test-refactor NOCRYPTO=1whTest_MessageNvmTranslatepasses in all four. Two negative controls, eachrebuilt and re-run: dropping the
accessWH_T16fails the test, and droppingthe label
memcpyfails it; restoring both returns 46/26/0.