Wire the stateful hash-based signature schemes HSS/LMS (RFC 8554) and
XMSS / XMSS^MT (RFC 8391) into the X.509 cert-verification path per
RFC 9802.
asn:
- Register id-alg-hss-lms-hashsig (1.2.840.113549.1.9.16.3.17),
id-alg-xmss-hashsig (1.3.6.1.5.5.7.6.34) and id-alg-xmssmt-hashsig
(1.3.6.1.5.5.7.6.35) in oid_sum.h, asn.c and asn1_oid_sum.pl.
- Plumb the new keyOIDs through GetCertKey, SigOidMatchesKeyOid,
HashForSignature, FreeSignatureCtx and ConfirmSignature so leaf
and CA certificates parse, load and verify end-to-end.
- Rename IsSigAlgoECC -> IsSigAlgoNoParams; the function has tested
"AlgorithmIdentifier omits NULL parameters" since PQC algos were
added, and HSS/LMS + XMSS only made the original name more
misleading.
wc_lms / wc_xmss:
- Add wc_XmssKey_ImportPubRaw_ex which derives parameters from the
4-byte OID prefix at the start of the raw public key, taking an
is_xmssmt hint to disambiguate the overlapping XMSS / XMSS^MT OID
spaces.
- Extend wc_LmsKey_ImportPubRaw with the same auto-derive from
u32str(L) || lmsType || lmOtsType when key->params is NULL; this
also fixes a latent NULL-deref when the legacy precondition was
violated.
- Reject WC_*_STATE_OK in both ImportPubRaw paths so re-importing
on a private-key-loaded handle can't desync priv/pub.
- Tighten wc_XmssKey_Verify's length check to strict equality,
matching wc_LmsKey_Verify and the documented contract of using
wc_XmssKey_GetSigLen for the buffer size.
tests / fixtures:
- Bouncy Castle 1.81 fixtures in certs/lms and certs/xmss covering
every supported parameter set, plus CA->leaf chains per family
and one BC-native LMS fixture as a cross-impl interop gate.
- New api tests verify each fixture end-to-end, tamper TBS and
signature bytes, exercise the wolfCrypt-level negative paths
(NOT_COMPILED_IN, BUFFER_E, BAD_FUNC_ARG, BAD_STATE_E, OID/family
mismatch, partial-write invariants, lenient VERIFYONLY re-import,
strict sigLen check) and confirm the outer signatureAlgorithm
OID is rejected when it disagrees with the SPKI in both
XMSS<->XMSS^MT directions.
Previously parsing a SubjectInfoAccess certificate containing a
SubjectInfoAccess extension that did not contain an id-ad-caRepository
resulted in an error.
Replace the liboqs-based pre-standardization SPHINCS+ implementation
with the native FIPS 205 SLH-DSA implementation across the
certificate / ASN.1 / X.509 layers, and add SLH-DSA-rooted test
certificates plus TLS 1.3 .conf scenarios that exercise the new
verification path. All liboqs SPHINCS+ code is removed.
This enables SLH-DSA for certificate chain authentication: CA
certificates signed with SLH-DSA, certificate signature verification
against an SLH-DSA root. TLS 1.3 entity authentication via
CertificateVerify with SLH-DSA will be added in a follow-up PR.
Follows RFC 9909 (X.509 Algorithm Identifiers for SLH-DSA) and
NIST FIPS 205. Supports both SHAKE and SHA-2 parameter families
across all twelve standardized variants.
DER codec:
- New PrivateKeyDecode, PublicKeyDecode, KeyToDer, PrivateKeyToDer,
PublicKeyToDer with RFC 9909 encoding (bare OCTET STRING containing
4*n raw bytes = SK.seed || SK.prf || PK.seed || PK.root, no nested
wrapper). OID auto-detection across all twelve SHAKE / SHA-2 variants.
- PublicKeyDecode raw-bytes fast path mirrors wc_Falcon_PublicKeyDecode
and wc_Dilithium_PublicKeyDecode so callers (notably
wolfssl_x509_make_der and ConfirmSignature, which pass the raw
BIT STRING contents stashed by StoreKey) decode correctly. Honours
the caller's *inOutIdx start offset.
- Error paths in Private/PublicKeyDecode preserve params/flags/
inOutIdx and only ForceZero the buffer half each helper actually
writes; skip the wipe entirely on BAD_LENGTH_E (no bytes touched).
- ImportPublic uses |= on flags so a Private-then-Public import
sequence retains FLAG_PRIVATE.
OID dispatch:
- 12 standardized NIST OIDs (6 SHAKE + 6 SHA-2) per RFC 9909. The
pre-standardization OID-collision mechanism is removed since NIST
OIDs do not collide.
- wc_SlhDsaOidToParam / wc_SlhDsaOidToCertType return NOT_COMPILED_IN
(rather than -1) for recognised SLH-DSA OIDs whose parameter set
isn't built; wc_IsSlhDsaOid recognises both. The x509 dispatch
surfaces this as a precise diagnostic instead of the generic
"No public key found".
- wc_GetKeyOID picks a placeholder parameter from whatever variant is
compiled in and #errors at compile time if none is.
- asn_orig.c EncodeCert / EncodeCertReq accept SHA-2 SLH-DSA keyTypes
alongside SHAKE.
Tests and fixtures:
- Test cert chain in certs/slhdsa/: SLH-DSA-SHAKE-128s and
SLH-DSA-SHA2-128s self-signed roots that sign reused ML-DSA-44
entity keys (server + client), plus the gen script
(gen-slhdsa-mldsa-certs.sh, OpenSSL >= 3.5).
- New TLS 1.3 .conf scenarios under tests/suites.c dispatch:
test-tls13-slhdsa-shake.conf, test-tls13-slhdsa-sha2.conf, and a
wrong-CA negative test test-tls13-slhdsa-fail.conf.
- DER round-trip and on-disk decode tests; bench_slhdsa_*_key.der
fixtures regenerated with wolfSSL's own encoder so the codec is
pinned to RFC 9909.
- New unit test test_wc_slhdsa_x509_i2d_roundtrip exercises the raw
PublicKeyDecode entry point that wolfssl_x509_make_der relies on.
- test_wc_slhdsa_check_key now tests both Public-then-Private and
Private-then-Public import orderings.
Build / ABI:
- DYNAMIC_TYPE_SPHINCS = 98 kept as RESERVED with a tombstone comment
for ABI stability; new code should use DYNAMIC_TYPE_SLHDSA (107).
- All build system / IDE project files updated; SPHINCS+ sources,
headers, and test data removed.
- Dead bench_slhdsa_*_key arrays removed from gencertbuf.pl and
certs_test.h; the .der files on disk drive the decode tests.
OCSP Responder Core API:
- Add new public API for creating and managing an OCSP responder
- Add public wrappers for internal OCSP request/response functions
- OcspRespCheck: fix check when authorized responder is loaded into CM
Header Cleanup:
- Remove circular dependency when including `#include <wolfssl/wolfcrypt/asn.h>` from wolfssl/wolfcrypt/ecc.h and wolfssl/wolfcrypt/rsa.h
OCSP Responder Example (examples/ocsp_responder/):
- Add a command-line OCSP responder for interoperability testing with OpenSSL's `openssl ocsp` client
Test Scripts (scripts/):
- ocsp-responder-openssl-interop.test: Tests wolfSSL OCSP responder with `openssl ocsp` client
- ocsp-stapling-with-wolfssl-responder.test: Tests wolfSSL OCSP responder when doing OCSP stapling
Certificate Infrastructure (certs/ocsp/):
- Add DER-format certificates and keys for OCSP testing
- Update renewcerts.sh to generate DER versions
Known Limitations (documented in src/ocsp.c header comment):
- Single request/response per OCSP exchange only
- Key-hash responder ID only (no name-based responder ID)
- No singleExtensions support
- Fix SM4 GCM/CCM TLS 1.3 decrypt to read auth tag from input buffer
instead of output buffer, consistent with all other AEAD ciphers
(src/tls13.c)
- Fix SM4_BLOCK_SIZE typo (was SM$_BLOCK_SIZE) in TicketEncDec SM4-GCM
decrypt path (src/internal.c)
- Fix SM2 certificate signature verification for certs using
id-ecPublicKey (ECDSAk) with SM2-with-SM3 signature algorithm.
OpenSSL creates SM2 cert signatures without the standard
distinguishing identifier in the ZA hash. The SM2k code path already
handled this correctly (idSz=0), but the ECDSAk + CTC_SM3wSM2 path
was incorrectly using CERT_SIG_ID_SZ (16), causing ASN_SIG_CONFIRM_E
(-155) when verifying non-self-signed SM2 certs (wolfcrypt/src/asn.c)
- Regenerate expired SM2 test certificates via certs/sm2/gen-sm2-certs.sh
They had expired.
WOLFSSL_DEBUG_PRINTF() macro adapted from wolfssl_log(), refactor
wolfssl_log() to use it, and move printf setup includes/prototypes from
logging.c to logging.h;
src/ssl_load.c: add source_name arg and WOLFSSL_DEBUG_CERTIFICATE_LOADS clauses
to ProcessBuffer() and ProcessChainBuffer(), and pass reasonable values from
callers;
remove expired "Baltimore CyberTrust Root" from certs/external/ca_collection.pem
and certs/external/baltimore-cybertrust-root.pem.