Add verify-only LMS/HSS and XMSS/XMSS^MT support (RFC 8554 / RFC 8391) — Step 1#3
Open
Frauschi wants to merge 5 commits into
Open
Add verify-only LMS/HSS and XMSS/XMSS^MT support (RFC 8554 / RFC 8391) — Step 1#3Frauschi wants to merge 5 commits into
Frauschi wants to merge 5 commits into
Conversation
Step 1 of a phased addition of stateful hash-based signatures to
wolfPKCS11: public-key import and signature verification only. No
key generation, signing, or private-key state persistence — those
follow in later steps.
Two independent build options gate the work, each pulling in PKCS#11
v3.2 and requiring the matching wolfSSL capability:
--enable-lms -> -DWOLFPKCS11_LMS (requires WOLFSSL_HAVE_LMS)
--enable-xmss -> -DWOLFPKCS11_XMSS (requires WOLFSSL_HAVE_XMSS)
CMake gains the equivalent WOLFPKCS11_LMS / WOLFPKCS11_XMSS options.
Public API (wolfpkcs11/pkcs11.h), exposed unconditionally so downstream
consumers compile regardless of build flags (the library rejects an
unbuilt mechanism at runtime with CKR_MECHANISM_INVALID):
- key types CKK_HSS, CKK_XMSS, CKK_XMSSMT
- mechanisms CKM_HSS, CKM_XMSS, CKM_XMSSMT (+ the *_KEY_PAIR_GEN
identifiers, defined for completeness but not implemented here)
- CKA_HSS_* attributes and the CK_HSS_PARAMS / CKL_* helpers
Design: public keys are self-describing, so no parameter attribute is
required on import. LMS derives (levels, height, winternitz) from the
first 12 bytes of the raw RFC 8554 key; XMSS uses
wc_XmssKey_ImportPubRaw_ex with the OID embedded in the key, and the
PKCS#11 key type (CKK_XMSS vs CKK_XMSSMT) supplies the is_xmssmt flag
that disambiguates the overlapping OID namespaces. CKA_PARAMETER_SET is
accepted but ignored.
Implementation mirrors the existing ML-DSA/ML-KEM structure with
parallel per-scheme code (WP11_Hss_Verify / WP11_Xmss_Verify, separate
SetKey and GetAttr), a thin dispatch in crypto.c (C_CreateObject import,
C_VerifyInit / C_Verify), and mechanism advertising in slot.c
(CKF_VERIFY, 0..0 key-size envelope). Public keys persist as their raw
byte form under new WOLFPKCS11_STORE_{HSS,XMSS}KEY_PUB storage types, so
both session and token objects work. Private-key import and keygen are
rejected (CKR_ATTRIBUTE_VALUE_INVALID / CKR_MECHANISM_INVALID); object
copy of HBS keys is rejected as unsupported.
Tests (tests/pkcs11v3test.c): known-answer import+verify for HSS
(L1/H5/W4), XMSS (SHA2_10_256) and XMSS^MT (SHA2_20/2_256) — import the
raw public key, verify a valid signature, then flip a byte and require
CKR_SIGNATURE_INVALID — plus private-import-rejected and
keygen-rejected negative tests per scheme.
Verified across four configurations (disabled / LMS / XMSS / both) with
-Werror: builds clean, make check passes, and pkcs11.h compiles
standalone without the feature macros.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GtRoh5TVMmmfX81LLRbroa
Fixes from code review of the initial verify-only HBS commit: - internal.c: drop the erroneous wc_LmsKey_Free/wc_XmssKey_Free on import failure. The object still owns the key with encoded == 0, so WP11_Object_Free performs the single free; freeing on the import error path double-freed. - internal.c: reject a public key created without CKA_VALUE (BAD_FUNC_ARG -> CKR_ATTRIBUTE_VALUE_INVALID) instead of silently creating an unusable object; there is no keygen path in a verify-only build that would populate the value later. - internal.c: narrow the verify error mapping to SIG_VERIFY_E only. Argument/format errors (BAD_FUNC_ARG, BUFFER_E) are not signature forgeries and must surface as a function failure rather than being reported as an invalid signature. - crypto.c: map BUFFER_E (wrong-length raw public key) on import to CKR_ATTRIBUTE_VALUE_INVALID, matching BAD_FUNC_ARG. - crypto.c: register the CKA_HSS_* attribute types in attrType[] so IsKnownAttrType accepts them; without this, C_GetAttributeValue rejected the HSS parameter queries with CKR_ATTRIBUTE_TYPE_INVALID before ever dispatching to HssObject_GetAttr. - configure.ac, CMakeLists.txt: self-disable LMS/XMSS when SHA-256 is not available (both schemes require SHA-256), mirroring the ML-DSA/ML-KEM self-disable pattern. - tests: add coverage for CKA_VALUE round-trip, HSS parameter attribute queries, C_GetMechanismInfo (CKF_VERIFY set, no CKF_SIGN), empty-template rejection, truncated-public-key rejection, and mechanism/key-type mismatch. Change the KAT tampered-signature buffer from static to a local. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GtRoh5TVMmmfX81LLRbroa
Verify-only LMS/HSS and XMSS/XMSS^MT public keys imported as token objects (CKA_TOKEN=CK_TRUE) are already persisted to and reloaded from the token store by the existing encode/decode/load/store paths. Add an explicit regression test that exercises a real disk round-trip: create the token public key, C_Finalize + C_Initialize to force a reload from disk, find the key by CKA_ID, and confirm it still verifies a known-good signature (and rejects a tampered one). Covers HSS, XMSS and XMSS^MT. To avoid duplicating the ~650 lines of KAT vectors, factor the shared public keys, signatures and message out of pkcs11v3test.c into a new tests/hbs_kat.h included by both test programs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GtRoh5TVMmmfX81LLRbroa
6df7544 to
e8402ca
Compare
Address review findings on the verify-only HBS support: - Remove the unused WP11_Hss_SigLen, WP11_Hss_PubLen, WP11_Hss_GetParameters, WP11_Xmss_SigLen and WP11_Xmss_PubLen helpers and their prototypes. They had no callers and implied a signature-length check that verify does not perform; wolfSSL's verify validates the length internally. - Set encoded to 0 on all paths in the HSS and XMSS decode helpers so WP11_Object_Free performs the single key free even when the import fails. The import helpers never free, so the previous encoded = (ret != 0) leaked the key on a decode failure. - Correct the C_CopyObject comments to say public-key copy is intentionally not implemented rather than citing statefulness. - Drop the redundant CKO_PRIVATE_KEY guard in WP11_Object_SetHssKey and WP11_Object_SetXmssKey; it is subsumed by the following CKO_PUBLIC_KEY check. - Move the declarations in the HSS type-array attribute case to the top of the block to match the file's C89 style. - Allocate the tamper-copy signature buffers in the HBS tests with XMALLOC instead of an 8 KB stack array. - Return NOT_AVAILABLE_E for CKA_HSS_KEYS_REMAINING and the non-public CKA_VALUE branch so the result matches the switch default arm.
Address a second round of review findings on the verify-only HBS support: - Report a wrong-length or malformed HBS signature as CKR_SIGNATURE_INVALID instead of CKR_FUNCTION_FAILED. WP11_Hss_Verify and WP11_Xmss_Verify now compare the supplied length against the key's parameter-set signature length before calling wolfSSL and map a mismatch to stat = 0. - Register WP11_INIT_HSS_VERIFY and WP11_INIT_XMSS_VERIFY in wp11_init_get_op_category so an in-progress HBS verify is recognized as a verify operation. A second C_VerifyInit with no intervening C_Verify now returns CKR_OPERATION_ACTIVE instead of silently resetting the operation. - Drop the cached serialization in WP11_Object_SetHssKey and WP11_Object_SetXmssKey after a successful import so a re-import via C_SetAttributeValue does not persist stale public-key bytes on the next store. - Remove the redundant ulValueLen write in the CKA_HSS_KEYS_REMAINING attribute case; C_GetAttributeValue already sets it on NOT_AVAILABLE_E. - Document that HBS verification only reads the key, so the shared RO lock is safe for concurrent verifies. - Extend the HBS known-answer tests to cover a wrong-length signature, C_CopyObject rejection, and the double-C_VerifyInit CKR_OPERATION_ACTIVE guard.
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.
Overview
This is Step 1 of adding stateful hash-based signature (HBS) support to wolfPKCS11, split into phases for easier review:
Keeping Step 1 to the verify path makes it small and self-contained: a token can verify RFC 8554 / RFC 8391 signatures against imported public keys, with no changes to the storage backend beyond serializing raw public keys.
What's included
PKCS#11 API (
wolfpkcs11/pkcs11.h)CKK_HSS,CKK_XMSS,CKK_XMSSMT; mechanismsCKM_HSS,CKM_XMSS,CKM_XMSSMT(keygen mechanisms defined for header completeness but not wired until Step 2/3).CK_HSS_LEVELS,CK_LMS_TYPE,CK_LMOTS_TYPE,CKL_LMS_*,CKL_LMOTS_*,CK_HSS_PARAMS). Constants are always defined; the library rejects at runtime when built without support.Build system
--enable-lms→-DWOLFPKCS11_LMSand--enable-xmss→-DWOLFPKCS11_XMSS(autotools + CMake), each pulling in PKCS#11 v3.2.Verify implementation (
src/internal.c,src/crypto.c,src/slot.c)wc_LmsKey_Init→SetParameters→ImportPubRaw→Verify. Parameters are self-derived from the raw public key's type fields (L / LMS_type / LMOTS_type);CKA_PARAMETER_SETis accepted as an optional override.wc_XmssKey_ImportPubRaw_exauto-derives the parameter set from the embedded OID;is_xmssmtis taken from the key type (CKK_XMSSvsCKK_XMSSMT). OneXmssKeytype serves both.wc_*_ImportPubRawbyte format (60 bytes for HSS, 68 for XMSS with SHA-256).SIG_VERIFY_E) toCKR_SIGNATURE_INVALID; argument/format errors surface as function failures. Wrong-length or malformed public keys on import are rejected withCKR_ATTRIBUTE_VALUE_INVALID. Private-key import and keygen are rejected.CKF_VERIFYonly.Token-object persistence
CKA_TOKEN=CK_TRUE) are serialized to and reloaded from the token store — just the raw public-key bytes, no state-file machinery.Testing
CKA_VALUE,CKA_HSS_LEVELS/LMS_TYPE/LMOTS_TYPE),C_GetMechanismInfo(CKF_VERIFYset, noCKF_SIGN), mechanism/key-type mismatch, empty-template and truncated-key rejection.tests/hbs_persistence_test.cperforming a real disk round-trip: create token public key →C_Finalize/C_Initialize→ find byCKA_ID→ re-verify.Verified across four build configurations — disabled,
--enable-lms,--enable-xmss, and both — each building clean with-Werrorand passingmake check(48 test programs) with no regressions. Header ABI (pkcs11.h) compiles standalone without the feature macros.🤖 Generated with Claude Code
Generated by Claude Code