Add SLH-DSA entity certificate support for the TLS 1.3 handshake signature#29
Open
Frauschi wants to merge 3 commits into
Open
Add SLH-DSA entity certificate support for the TLS 1.3 handshake signature#29Frauschi wants to merge 3 commits into
Frauschi wants to merge 3 commits into
Conversation
…ature Implement use of SLH-DSA (FIPS 205) entity certificates for TLS 1.3 client/server authentication, i.e. producing and consuming the CertificateVerify handshake signature with SLH-DSA. Follows draft-reddy-tls-slhdsa: the twelve SignatureScheme code points 0x0911-0x091C (matching oqs-provider and the FIPS 205 OIDs already present in asn.c), pure SLH-DSA with an empty context. TLS 1.3 only, mirroring the existing ML-DSA integration. Because SLH-DSA signatures range from ~7.8KB to ~50KB, a single CertificateVerify can exceed the 16KB TLS record limit. SendTls13CertificateVerify now fragments the message across multiple encrypted records when needed (mirroring SendTls13Certificate); the single-record fast path is unchanged for all other algorithms. Incoming reassembly is already handled generically by DoTls13HandShakeMsg. WC_MAX_CERT_VERIFY_SZ and MAX_X509_SIZE gain SLH-DSA branches so the large signatures fit the send buffer and the handshake-message reassembly cap. Details: - internal.h: slhdsa_*_sa_algo enum values, wire code points, SIG_SLHDSA mask, peerSlhDsaKey field, haveSlhDsaSig option flags. - tls13.c: EncodeSigAlg/DecodeTls13SigAlg cases (ML-DSA and SLH-DSA share the 0x09 major byte with disjoint minors), sign via wc_SlhDsaKey_Sign, verify via wc_SlhDsaKey_Verify, decodeSlhDsaKey, fragmented CertificateVerify emit. - internal.c: shared sa_algo<->param<->minor mapping helpers, DecodeSigAlg, AddSuiteHashSigAlgo/InitSuitesHashSigAlgo (advertising only compiled-in parameter sets), ProcessPeerCerts peer-key decode, DecodePrivateKey_ex, Alloc/Free/Reuse key plumbing, haveSig masks. - ssl_load.c: ProcessBufferTryDecodeSlhDsa and cert/key-OID have-flag and keyType detection. - wc_slhdsa.h: WC_SLHDSA_DEFAULT_PARAM placeholder macro (the SHAKE family may be disabled when only SHA2 is built, so a fixed SHAKE placeholder cannot be assumed). Testing: adds tests/test-tls13-slhdsa-entity.conf (registered in suites.c) using a self-signed SLH-DSA-SHAKE-128f entity certificate whose ~17KB signature exercises fragmented CertificateVerify send and reassembly in both directions, plus certs/slhdsa/gen-slhdsa-entity-cert.c to regenerate the fixtures. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SeLwE2QcsVHDFR5iXW6Hcj
The SLHDSA_MAX_N/A/H_M/INDICES_SZ/MD buffer-sizing maxima in wc_slhdsa.c and the WC_SLHDSA_MAX_PRIV_LEN/PUB_LEN/SEED public maxima in wc_slhdsa.h were conditioned only on the SHAKE-family disable guards (WOLFSSL_SLHDSA_PARAM_NO_256/192/SMALL/FAST). In a SHA2-only build (--enable-slhdsa=sha2) the SHAKE family is disabled, so those guards are all defined and the maxima collapse to their 128-bit-level values, while the SHA2 parameter tables remain fully enabled with larger n/a/h_m. Signing then wrote the FORS/XMSS 'nodes' stack buffers (sized (SLHDSA_MAX_A+1)*SLHDSA_MAX_N and (SLHDSA_MAX_H_M+2)*SLHDSA_MAX_N) using the true parameters and overran them, causing a stack-smashing abort; wc_SlhDsaKey_ExportPrivate similarly failed with BAD_LENGTH_E on the 192/256 SHA2 sets. Derive combined SLHDSA_ALL_NO_* guards (in wc_slhdsa.h) that treat a size/speed class as absent only when it is absent in BOTH the SHAKE and SHA2 families, and size every maximum off those. SHAKE-only and all-parameter builds are unaffected: with the SHA2 family off, WOLFSSL_SLHDSA_NO_SHA2 makes each combined guard equal to its SHAKE guard; with all sets enabled none of the guards are defined, so the maxima resolve to the same largest values as before. Verified under --enable-slhdsa=sha2: benchmark signs all SHA2 parameter sets, testwolfcrypt SLH-DSA (incl. keygen KATs and sign/verify) passes, and a TLS 1.3 handshake using a SHA2 SLH-DSA certificate completes. SHAKE-only and combined builds still pass with no behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SeLwE2QcsVHDFR5iXW6Hcj
Adds scripts/slhdsa-oqs-interop.sh, a manual interoperability harness that exercises the SLH-DSA CertificateVerify handshake signature between wolfSSL and OpenSSL 3.4 + oqs-provider (which supplies the draft-reddy-tls-slhdsa TLS signature schemes at code points 0x0911-0x091C that wolfSSL matches). It runs three scenarios: A) wolfSSL server signs -> OpenSSL+oqs client verifies (SHAKE-128f, SHA2-128s) B) OpenSSL+oqs server signs -> wolfSSL client verifies (SHAKE-128f) SHAKE-128f's ~17KB signature makes the CertificateVerify span multiple TLS records, so the harness also cross-checks fragmented CertificateVerify send and reassembly between the two stacks. The script header documents the from-source build of liboqs (main, OQS_USE_OPENSSL=OFF), OpenSSL 3.4, and oqs-provider (main); OpenSSL 3.4 is used because provider TLS signature algorithms work there and it has no native SLH-DSA to shadow oqs-provider's (OpenSSL >= 3.5 does not expose SLH-DSA as a TLS sig alg and causes oqs-provider to drop it). Verified locally: all three scenarios pass in both signing directions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SeLwE2QcsVHDFR5iXW6Hcj
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.
Description
Adds support for using SLH-DSA (FIPS 205) entity certificates for the TLS 1.3 handshake signature in the
CertificateVerifymessage. SLH-DSA was already usable for certificate chains (verify + creation); this wires it into the handshake itself so a wolfSSL client or server can authenticate with an SLH-DSA leaf key. TLS 1.3 only, mirroring the existing ML-DSA integration.Follows draft-reddy-tls-slhdsa: the twelve
SignatureSchemecode points0x0911–0x091C(which match oqs-provider and the FIPS 205 OIDs already present inasn.c), pure SLH-DSA with an empty context.Fragmented CertificateVerify. SLH-DSA signatures range ~7.8KB–50KB, so a single
CertificateVerifycan exceed the 16KB TLS record limit.SendTls13CertificateVerifynow fragments the message across multiple encrypted records when needed (mirroringSendTls13Certificate); the single-record fast path is unchanged for all other algorithms. Incoming reassembly is already handled generically byDoTls13HandShakeMsg.WC_MAX_CERT_VERIFY_SZandMAX_X509_SIZEgain SLH-DSA branches.Summary of changes:
wolfssl/internal.h:slhdsa_*_sa_algoenum values, wire code points,SIG_SLHDSAmask,peerSlhDsaKeyfield,haveSlhDsaSigflags.src/tls13.c:EncodeSigAlg/DecodeTls13SigAlgcases (ML-DSA and SLH-DSA share the0x09major byte with disjoint minors), sign viawc_SlhDsaKey_Sign, verify viawc_SlhDsaKey_Verify,decodeSlhDsaKey, and the fragmentedCertificateVerifyemit.src/internal.c: shared sa_algo↔param↔minor mapping helpers,DecodeSigAlg,AddSuiteHashSigAlgo/InitSuitesHashSigAlgo(advertising only compiled-in parameter sets),ProcessPeerCertspeer-key decode,DecodePrivateKey_ex, alloc/free/reuse key plumbing,haveSigmasks.src/ssl_load.c:ProcessBufferTryDecodeSlhDsaplus cert/key-OID have-flag and keyType detection.wolfcrypt/src/wc_slhdsa.c/wolfssl/wolfcrypt/wc_slhdsa.h: fix a pre-existing SHA2-only crash. The buffer-sizing maxima (SLHDSA_MAX_*andWC_SLHDSA_MAX_PRIV/PUB/SEED) were conditioned only on the SHAKE-family disable guards, so a--enable-slhdsa=sha2build collapsed them to the 128-bit level while the SHA2 tables still used largern/a/h_m— overflowing the FORS/XMSSnodesstack buffers when signing (stack-smashing abort), and failingExportPrivatewithBAD_LENGTH_Eon the 192/256 sets. CombinedSLHDSA_ALL_NO_*guards now treat a class as absent only when it is gone from both hash families; SHAKE-only and all-parameter builds are unchanged.Testing
tests/test-tls13-slhdsa-entity.conf, registered intests/suites.c): a self-signed SLH-DSA-SHAKE-128f entity certificate whose ~17KB signature forces multi-recordCertificateVerifysend + reassembly. Passes server-auth and mutual-auth through./tests/unit.test.-Werrorbuilds across SHAKE-only, SHA2-only, combined, and SLH-DSA-only (no ML-DSA/Falcon) configs.--enable-slhdsa=sha2,benchmark -slhdsasigns all SHA2 sets,testwolfcryptSLH-DSA (keygen KATs + sign/verify) passes, and a TLS 1.3 handshake with a SHA2 SLH-DSA cert completes. SHAKE-only/combined builds still pass.scripts/slhdsa-oqs-interop.sh). All pass in both signing directions:Note: OpenSSL+oqs advertises a very large
signature_algorithmslist; the interop harness constrains the peer's-sigalgsto the target scheme so it isn't truncated out of wolfSSL's sig-algs list. A follow-up could raise wolfSSL's received sig-algs list cap.Checklist
🤖 Generated with Claude Code
Generated by Claude Code