Skip to content

Fix hybrid LMS/XMSS keystore import and PQ secondary builds - #963

Merged
danielinux merged 1 commit into
wolfSSL:masterfrom
dgarske:hybrid_sign
Oct 29, 2026
Merged

danielinux merged 1 commit into
wolfSSL:masterfrom
dgarske:hybrid_sign

Conversation

@dgarske

@dgarske dgarske commented Oct 29, 2026

Copy link
Copy Markdown
Member

Description

Hybrid signing has never worked with LMS or XMSS as one of the two algorithms. On current master:

Verifying signature...info: LMS wolfBoot_verify_signature
error: wc_LmsKey_ImportPubRaw returned -132
Boot failed: Hdr 1, Hash 1, Sig 0

wolfBoot_verify_signature_lms() and ..._xmss() imported the public key at KEYSTORE_PUBKEY_SIZE, the keystore slot width. With WOLFBOOT_UNIVERSAL_KEYSTORE=1 that macro falls through to the RSA-4096 value, so the key arrives padded and the import rejects it. In a single-algorithm build the macro is the LMS or XMSS size, which is why sim-lms and sim-xmss pass and this went unseen. The key tools always store exactly KEYSTORE_PUBKEY_SIZE_LMS or _XMSS bytes in the slot, so the verify side now imports that length. ML-DSA was unaffected, as it already asked the key for its own length.

The same assumption - that the primary algorithm describes the whole keystore - caused three more. The SIGN_SECONDARY branches defined the primary macros to get the verify bodies compiled, so a classic primary with a post-quantum secondary defined wolfBoot_verify_signature_primary twice and did not build; the slot width and the -Wstack-usage ceiling followed the primary alone; and keygen -i mistook slot padding for a DER header when reading the first public key back out of the keystore.

Separately, the LMS callback setters and wc_LmsKey_Reload() reject a key already in WC_LMS_STATE_OK, which is what a successful signature leaves behind, so a delta image - which signs its own header - failed. The key is now loaded once. And header_required_size() now sizes the manifest for every image rather than only when a certificate chain, custom TLV or DTS is present, with the delta path resolving the same growth before it computes the inverse-patch offset.

Testing

Adds simulator jobs pairing LMS and XMSS with ECDSA P-256 under a universal keystore, in both orderings, which is the combination that had no coverage. Reverting only the changed source files makes all three new jobs fail, so they are regression tests rather than decoration.

sim-lms, sim-xmss, sim-ml-dsa-ecc-hybrid and sim.config are unchanged, the unit tests pass, and the LMS and XMSS footprint limits are untouched because the verify paths come out byte-identical in size.

@dgarske dgarske self-assigned this Oct 29, 2026
@dgarske
dgarske requested a review from danielinux October 29, 2026 05:34
@dgarske dgarske assigned wolfSSL-Bot and unassigned dgarske Oct 29, 2026
@danielinux
danielinux merged commit a8542bd into wolfSSL:master Oct 29, 2026
524 checks passed
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