wolfcrypt/test/test.c: in aes_cbc_test(), use unconditional static on msg4 and verify4 to work around gcc optimizer bug (probably same bug as noted in ac11279c60).
- x509_str: require CA:TRUE unconditionally in wolfSSL_X509_verify_cert;
verify leaf signature even when verify_cb overrides INVALID_CA
- x509_str: align WOLFSSL_X509_V_ERR_INVALID_CA with OpenSSL value (79)
so OPENSSL_COEXIST builds compile; bump WC_OSSL_V509_V_ERR_MAX to 80
and extend error_test() missing-value table for the new gaps
- asn: reject embedded NUL in dNSName / rfc822Name / URI SAN entries
- internal: re-verify restored ticket peer cert against trust store with
CRL/OCSP checks; clear stale state from session cache on verification
failure
- ticket: bind SNI and ALPN into session ticket via compile-time selected
hash (TICKET_BINDING_HASH_TYPE); reject resumption on mismatch in both
TLS 1.3 and TLS 1.2 paths
- ticket: defer SNI/ALPN binding check until after extensions are parsed
by consolidating into VerifyTicketBinding(), called once after
ALPN_Select in DoTls13ClientHello and DoClientHello; the early
per-call sites ran before extensions were parsed and rejected valid
resumptions in nginx, haproxy, grpc, and CPython integration tests
- ssl_sess: free previous session in wolfSSL_d2i_SSL_SESSION before
overwrite
- examples/client: increase SESSION_TICKET_LEN fallback from 256 to 2048
to support larger tickets
- tests: update SAN NUL fixtures and add parse-time rejection coverage;
add test_tls13_ticket_peer_cert_reverify for CA-removal scenario; skip
it under WOLFSSL_NO_DEF_TICKET_ENC_CB
linuxkm/Makefile, linuxkm/linuxkm-fips-hash-wrapper.sh, linuxkm/linuxkm_memory.c: refactor coreKey extraction to use ELF tools rather than WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE and user_settings.h.
linuxkm/module_hooks.c: add stack measurement for wc_RunAllCast_fips().
tests/api/test_slhdsa.c: frivolous initialization to work around a false positive -Wmaybe-uninitialized in slhdsa_der_roundtrip_one().
wolfcrypt/src/wc_slhdsa.c, wolfssl/wolfcrypt/wc_slhdsa.h:
* refactor lifecycle management for SHA-2 objects to fix a leak via wc_SlhDsaKey_CheckKey().
* add support for WC_SLHDSA_NO_ASM.
* add WOLFSSL_SLHDSA_VERIFY_ONLY gates around prototypes, to get compile-time failures for misuse.
wolfcrypt/test/test.c:
* clean up myFipsCb() and restore usability of TEST_ALWAYS_RUN_TO_END with bad FIPS hash (useful test coverage).
* add wc_RunAllCast_fips() to wolfcrypt_test().
* when WOLFSSL_KERNEL_MODE or BENCH_EMBEDDED, force on WOLFSSL_SLHDSA_VERIFY_ONLY unless WOLFSSL_SLHDSA_FORCE_FULL_TESTS is defined.
wolfssl/wolfcrypt/settings.h:
* add WC_MLKEM_NO_ASM to WOLFSSL_LINUXKM section to work around asm bug.
* remove clause in WOLFSSL_KERNEL_MODE section that forced on WOLFSSL_SLHDSA_VERIFY_ONLY.
Windows test code pre-picked a random port via GetRandomPort() (returning
a value in [49152, 65535]) before calling bind(), with no check that the
port was free and no retry on collision. Under load this occasionally
collided with an already-bound port and aborted the test with
"tcp bind failed", producing intermittent Jenkins failures (e.g. PRB
windows-test-v2 #17140 in the OCSP responder test).
The Unix path already does the right thing: bind to port 0 (OS-assigned
ephemeral) and read the port back via getsockname(). The same primitives
exist in Winsock 1.1, so drop the USE_WINDOWS_API guard around the
getsockname block in tcp_listen()/udp_accept() and remove the per-caller
GetRandomPort() workarounds in the OCSP responder, server example, and
the api.c / test_ossl_bio.c test sites. socklen_t is already typedef'd
as int on Windows in test.h.
GetRandomPort() itself is left in place since it is a static inline in a
shipped public test header.
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.
wolfssl/wolfcrypt/wc_slhdsa.h: implement WOLFSSL_SLHDSA_NO_SHAKE and WOLFSSL_SLHDSA_NO_SHA2, and fix WC_SLHDSA_MAX_SIG_LEN setup to reflect SHA2 variants;
wolfssl/wolfcrypt/settings.h: if WOLFSSL_KERNEL_MODE, set WOLFSSL_SLHDSA_VERIFY_ONLY unless WOLFSSL_SLHDSA_NO_VERIFY_ONLY;
wolfcrypt/src/wc_slhdsa.c: fix WOLFSSL_SLHDSA_VERIFY_ONLY to work with --enable-slhdsa=sha2,verifyonly;
fix -Wunused-variables in slhdsakey_wots_pk_from_sig_x4();
wolfcrypt/test/test.c: in slhdsa_test(), fix gating for compatibility with --enable-slhdsa=sha2,verifyonly;
tests/api/test_slhdsa.c: fix gating in test_wc_slhdsa() and test_wc_slhdsa_sizes().
RFC 8446 section 8 requires any server instance to accept 0-RTT for a
given ClientHello at most once. Prior to this change wolfSSL's behaviour
diverged from that requirement in several ways:
* ctx->maxEarlyDataSz defaulted to MAX_EARLY_DATA_SZ whenever the
library was built with WOLFSSL_EARLY_DATA, so servers auto-
advertised 0-RTT in NewSessionTicket without the application
asking. RFC 8446 E.5 says 0-RTT MUST NOT be enabled unless
specifically requested.
* The post-accept eviction is compiled out under NO_SESSION_CACHE,
so builds without the cache accepted 0-RTT with no replay defence.
* Stateless self-encrypted tickets do not carry a session ID on the
stateless DoClientTicket decrypt path, so wolfSSL_SSL_CTX_remove_
session could not locate them to evict.
* wolfSSL_SSL_CTX_remove_session always returned 0 on success
regardless of whether the session was actually in the cache,
diverging from OpenSSL's SSL_CTX_remove_session (1 on success,
0 on not-found).
Changes:
* src/internal.c: ctx->maxEarlyDataSz defaults to 0; applications
must opt in with wolfSSL_CTX_set_max_early_data.
* src/tls13.c: #error when WOLFSSL_EARLY_DATA is built with
HAVE_SESSION_TICKET and NO_SESSION_CACHE. Escape hatch
WOLFSSL_EARLY_DATA_NO_ANTI_REPLAY for deployments that take
application-layer responsibility.
* wolfssl/internal.h: imply WOLFSSL_TICKET_HAVE_ID from
WOLFSSL_EARLY_DATA so stateless-ticket issuance populates the
cache under an ID that eviction can find.
* src/ssl_sess.c: wolfSSL_SSL_CTX_remove_session returns 1 when the
session was found (internal-cache hit, or ctx->rem_sess_cb fired
for an external cache), 0 otherwise. Matches OpenSSL semantics.
* src/tls13.c: the 0-RTT acceptance condition in CheckPreSharedKeys
now calls wolfSSL_SSL_CTX_remove_session and checks its return:
the eviction is the check. If the session was in the cache, 0-RTT
is accepted and the single-use requirement is satisfied. If not,
the early_data extension is rejected through the normal path so
the record layer correctly skips in-flight 0-RTT records.
WOLFSSL_MSG at each rejection site.
* doc/dox_comments/header_files/ssl.h: document runtime opt-in.
* tests: four new tests —
test_tls13_0rtt_default_off (fails without default-to-0 fix),
test_tls13_0rtt_stateless_replay (fails without TICKET_HAVE_ID
implication and remove_session gate),
test_tls13_remove_session_return (fails without return-value fix),
test_tls13_0rtt_ext_cache_eviction (fails without ext-cache
counts-as-found fix).
test_tls13_early_data explicitly opts in via
wolfSSL_CTX_set_max_early_data.
tests/api.c: two SSL_CTX_remove_session == 0 assertions updated
to == 1.
ReadPemFromBioToBuffer slurps the entire BIO in one shot, so iterative
callers like wolfSSL_PEM_read_bio_X509_CRL (and by extension
wolfSSL_X509_load_crl_file's BIO branch) saw EOF after the first block
and silently dropped every CRL after the first in a multi-CRL bundle.
Refactor wolfSSL_PEM_read_bio_X509_CRL to delegate to
wolfSSL_PEM_X509_X509_CRL_X509_PKEY_read_bio, which already reads one
PEM BEGIN/END pair per call and leaves the BIO positioned just past the
END line. Loop over it so we skip past intervening cert/key blocks and
return the next CRL in the stream — matching OpenSSL's
PEM_read_bio_X509_CRL, verified against OpenSSL 3.0.13 with cases
{cert,CRL}, {CRL,cert}, {CRL,cert,CRL}, {key,CRL}, {CRL,key,CRL}: in
each case OpenSSL skips non-CRL blocks until EOF.
When the caller passes a non-NULL `x` whose `*x` is already populated,
free the previous CRL before overwriting the slot — matching the
d2i_X509_CRL reuse contract the old body relied on.
To keep both helpers visible at the new call site, drop their `static`
qualifier (wolfSSL_PEM_X509_X509_CRL_X509_PKEY_read_bio for the per-block
read, wolfSSL_X509_PKEY_free to free defensively-allocated keys parsed
from intervening non-CRL blocks). Their definitions in src/x509.c and
declarations in wolfssl/internal.h are widened from OPENSSL_ALL to
OPENSSL_EXTRA || OPENSSL_ALL so the OPENSSL_EXTRA-only build (which
compiles wolfSSL_PEM_read_bio_X509_CRL) links cleanly. The unrelated
INFO_read_bio / INFO_read_bio_X509_INFO group below them keeps its
OPENSSL_ALL gate because it depends on wolfSSL_X509_INFO_new/free that
are still OPENSSL_ALL-only.
Also register the previously-orphaned test_wolfSSL_X509_load_crl_file
(its slot in TEST_OSSL_X509_LOOKUP_DECLS was a duplicated
test_wolfSSL_X509_LOOKUP_ctrl_hash_dir entry), update its assertion for
crl2.pem (which already contains two CRLs) to expect 2 instead of 1, and
add a multi-CRL bundle case that builds a memory BIO from
crl.pem + server-cert.pem + crl2.pem and asserts that the reader walks
past the cert and returns all 3 CRLs before NULL.
- tls.c: TLSX_CertWithExternPsk_GetSize takes word16*, but length was
widened to word32 in TLSX_GetSize. Use the hsz staging variable like
the other cases so WOLFSSL_CERT_WITH_EXTERN_PSK builds compile.
- tls.c: silence -Wunused-variable for hsz in builds where every case
that consumes it (TLS 1.3, PSK, ETM, early data, PHA, cookie, cert
with extern PSK) is compiled out, e.g. user_settings_tls12.h.
- test_tls_ext.c: assert session->ticketLen > 0 before mutating
ticketAdd in the ticket-age out-of-window test so it fails loudly if
no NewSessionTicket was received.
DoClientTicketCheck's ticket-age bounds (-1000 ms low bound and
MAX_TICKET_AGE_DIFF*1000+1000 ms high bound) were never exercised by
any integration test, so mutations of the constants went undetected.
Establish a TLS 1.3 session, read the NewSessionTicket, then shift the
client's cached ageAdd by well over 1 second so the server's
unobfuscated diff falls outside the valid window on resumption. The
server must reject the PSK — session_reused stays 0.
DoTls13ClientHello enforces RFC 8446 Section 4.1.4 by comparing the
cipher suite in the second ClientHello to the hrrCipherSuite cached on
the server from the HelloRetryRequest. No existing test covers the
mismatch branch, so a deletion of the check would silently allow a
client to switch cipher suite between CH1 and CH2. Drive a partial
handshake until the server has emitted the HRR, then flip the cached
hrrCipherSuite on the server; processing CH2 must surface
INVALID_PARAMETER.
Cover both branches of TLSX_SecureRenegotiation_Parse's ConstantCompare
against the cached Finished verify_data: a single memio test loops
over client-side and server-side corruption, renegotiates, and
asserts the offending peer surfaces SECURE_RENEGOTIATION_E.
Tls13IntegrityOnly_Decrypt was completely untouched by existing tests,
so any mutation of its ConstantCompare would pass CI. Add a memio
TLS 1.3 handshake over TLS13-SHA256-SHA256 (integrity-only NULL cipher),
then corrupt the final byte of the next record body via an IORecv
wrapper and assert the server surfaces DECRYPT_ERROR.
Cover the Poly1305 ConstantCompare tag check in ChachaAEADDecrypt that
no existing test was hitting (VERIFY_MAC_ERROR never expected in the
suite). A memio-based TLS 1.2 handshake over
ECDHE-RSA-CHACHA20-POLY1305 completes, the server's IORecv is then
replaced with a wrapper that flips the final byte of the next record
body so the forged Poly1305 tag no longer matches. The server's
wolfSSL_read must surface VERIFY_MAC_ERROR.
Covers the HandleResumeHistory check that RFC 7627 Section 5.3 requires:
if the original session used Extended Master Secret, the server MUST
abort when a resumption ClientHello is received without EMS. The new
memio test performs a TLS 1.2 handshake with EMS, saves the session,
disables EMS on a fresh client, resumes with the saved session, and
asserts the server returns EXT_MASTER_SECRET_NEEDED_E.