slhdsa: add WOLF_CRYPTO_CB and WOLF_PRIVATE_KEY_ID support#18
Open
slhdsa: add WOLF_CRYPTO_CB and WOLF_PRIVATE_KEY_ID support#18
Conversation
Wire SLH-DSA into the existing PQC CryptoCb dispatch (the same path
already used by ML-DSA / Dilithium) so a registered device can intercept
key generation, signing, verification, and key release. Also add
algorithm-specific id/label storage on SlhDsaKey for use with
WOLF_PRIVATE_KEY_ID, mirroring the dilithium_key API.
- types.h: add WC_PQC_SIG_TYPE_SLHDSA and widen the WC_PK_TYPE_PQC_SIG_*
/ wc_PqcSignatureType guards to include WOLFSSL_HAVE_SLHDSA.
- cryptocb.h/.c: include wc_slhdsa.h, widen the PQC sig guards, and
teach wc_CryptoCb_PqcSigGetDevId to extract devId from SlhDsaKey.
- wc_slhdsa.h: add devCtx (alongside devId) under WOLF_CRYPTO_CB; add
id/label storage and SLHDSA_MAX_{ID,LABEL}_LEN under WOLF_PRIVATE_KEY_ID;
declare wc_SlhDsaKey_Init_id and _Init_label.
- wc_slhdsa.c: implement Init_id / Init_label; hook
wc_CryptoCb_MakePqcSignatureKey in MakeKey, wc_CryptoCb_PqcSign in
Sign / SignHash, wc_CryptoCb_PqcVerify in Verify / VerifyHash, and
wc_CryptoCb_Free in Free; scrub id/label/devCtx on free.
Six fixes from PR review: 1. wc_SlhDsaKey_Verify / VerifyHash: stop collapsing non-zero cryptocb error codes (MEMORY_E, transport errors) into SIG_VERIFY_E. Real errors are returned as-is; only res != 1 with ret == 0 maps to SIG_VERIFY_E. 2. wc_SlhDsaKey_SignHash / VerifyHash: pre-compute the digest via slhdsakey_prehash_msg before invoking the cryptocb, then pass (digest, digestLen, hashType) to the device. Matches the existing ML-DSA cryptocb contract for the pre-hash variant; device backends can be written once for both algorithms. 3. cryptocb test coverage: route slhdsa_test through cryptocb_test by passing the global devId to wc_SlhDsaKey_Init in slhdsa_test_param (mirrors dilithium_test); extend myCryptoDevCb's WC_PK_TYPE_PQC_SIG_KEYGEN free dispatch with a WC_PQC_SIG_TYPE_SLHDSA arm. Exercises PqcSigGetDevId's new SLHDSA branch and wc_CryptoCb_Free for SLH-DSA. 4. wc_SlhDsaKey_Init_id: reject (id == NULL, len > 0) and (id != NULL, len <= 0) as BAD_FUNC_ARG instead of silently continuing with idLen = 0. 5. wc_SlhDsaKey_Free: hoist wc_CryptoCb_Free above the params != NULL gate so a partially-initialized key still releases its device-side handle. 6. SignHash / VerifyHash: reject negative wc_HashType before casting to word32 to avoid silently mis-routing the device call.
1. wc_SlhDsaKey_Init_id: drop the over-strict (id != NULL, len <= 0) rejection. Restore dilithium_init_id parity — only the silent contradiction (id == NULL, len > 0) is a caller bug. 2. wc_SlhDsaKey_VerifyHash / SignHash: compute the digest once. VerifyHash hoists slhdsakey_prehash_msg above the cryptocb hook so the same ph/phLen/oid/oidLen feed both the cryptocb dispatch and the SW path. SignHash extracts a new static slhdsakey_signhash_with_digest helper from slhdsakey_signhash_external; the cryptocb fall-through reuses the already-computed digest instead of re-hashing through SignHashWithRandom. slhdsakey_signhash_external now just prehashes + delegates. 3. cryptocb_test: extend myCryptoDevCtx with slhdsaInjectVerifyError; when set, the SLH-DSA verify dispatch returns that exact code. Add an inline test that signs a message, sets the inject flag to WC_HW_E, calls wc_SlhDsaKey_Verify, and asserts WC_HW_E propagates (not SIG_VERIFY_E). Initialize myCtx via XMEMSET — the new field would otherwise read garbage from stack and inject a random value. 4. slhdsa_test: add slhdsa_id_label_test() (gated on WOLF_PRIVATE_KEY_ID + one 128-bit param). Covers Init_id NULL key / NULL+len>0 / oversized len / negative len / round-trip; Init_label NULL key / NULL label / empty label / round-trip; and dilithium-parity case (id != NULL, len == 0 succeeds with idLen == 0). 5. wc_SlhDsaKey_Free: revert round-1's hoist of wc_CryptoCb_Free above the params!=NULL gate. wc_SlhDsaKey_Init is atomic — devId and params are set together — so params != NULL reliably signals "fully initialized" and prevents wc_CryptoCb_Free firing on a never-init key with garbage devId. 6. wc_SlhDsaKey_SignHash / VerifyHash: hoist the negative-hashType check into the function-level validation block, before any large stack buffers (ph[WC_MAX_DIGEST_SIZE]) are reserved. 7. Cleaned up: the cryptocb hook no longer keeps unused oidBuf/oidBufLen locals — the function-scope ph/oid plumbing replaces them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wires SLH-DSA into the existing PQC CryptoCb dispatch (the same path already used by ML-DSA / Dilithium) so a registered device can intercept key generation, signing, verification, and key release. Also adds algorithm-specific id/label storage on
SlhDsaKeyfor use withWOLF_PRIVATE_KEY_ID, mirroring thedilithium_keyAPI.Changes
wolfssl/wolfcrypt/types.h— addWC_PQC_SIG_TYPE_SLHDSA = 3; widen theWC_PK_TYPE_PQC_SIG_*andwc_PqcSignatureTypeguards to includeWOLFSSL_HAVE_SLHDSA.wolfssl/wolfcrypt/cryptocb.h/wolfcrypt/src/cryptocb.c— includewc_slhdsa.h, widen the PQC sig guards, and teachwc_CryptoCb_PqcSigGetDevIdto readdevIdfromSlhDsaKey. Reuses the existing genericpqc_sig_kg/pqc_sign/pqc_verifyinfo-struct members — no new union fields.wolfssl/wolfcrypt/wc_slhdsa.hvoid* devCtxalongsideint devIdunderWOLF_CRYPTO_CB.id[SLHDSA_MAX_ID_LEN],label[SLHDSA_MAX_LABEL_LEN],idLen,labelLen(both maxes = 32) underWOLF_PRIVATE_KEY_ID.wc_SlhDsaKey_Init_idandwc_SlhDsaKey_Init_label.wolfcrypt/src/wc_slhdsa.cwc_SlhDsaKey_Init_id/wc_SlhDsaKey_Init_label(mirrors the dilithium idiom).wc_CryptoCb_MakePqcSignatureKeyinMakeKey,wc_CryptoCb_PqcSigninSign/SignHash,wc_CryptoCb_PqcVerifyinVerify/VerifyHash. Hooks live at the top-level public API only — Deterministic / WithRandom / internal-M'variants run software-only.wc_CryptoCb_Freedispatch inwc_SlhDsaKey_Free(gated byWOLF_CRYPTO_CB_FREE) and scrubid/label/devCtxon free.Test plan
./configure --enable-slhdsa --enable-cryptocb --enable-dilithium CFLAGS="-DWOLF_PRIVATE_KEY_ID -DWOLF_CRYPTO_CB_FREE"builds cleanly../wolfcrypt/test/testwolfcryptpasses (SLH-DSA + DILITHIUM + crypto callback tests all green) on the same config../configure --enable-cryptocb --enable-dilithium(no SLH-DSA) builds and passes — confirms guard widening doesn't regress existing builds.myCryptoDevCbinwolfcrypt/test/test.cto dispatchWC_PQC_SIG_TYPE_SLHDSAcases back to the software path. Out of scope for this PR; the existing tests still cover theINVALID_DEVID/ fall-through path.🤖 Generated with Claude Code
Generated by Claude Code