tests/api/test_mldsa.c: fix misplaced PRIVATE_KEY_UNLOCK() in dilithium_oneasymkey_version_check();
wolfcrypt/test/test.c: fix valgrind-detected "Conditional jump or move depends on uninitialised value(s)" in ecc_test_curve_size() negative test on all-zeros digest.
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.
- 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
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.
Previously parsing a SubjectInfoAccess certificate containing a
SubjectInfoAccess extension that did not contain an id-ad-caRepository
resulted in an error.
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.
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.
wolfSSL_TicketKeyCb is the built-in ticket callback registered by the
OpenSSL-compat wolfSSL_CTX_set_tlsext_ticket_key_cb API. Its
ConstantCompare of the ticket HMAC was never reached in any test, so a
deletion of the check would silently accept forged tickets. New test
sets up the compat callback, establishes a TLS 1.2 session, saves it,
flips a byte of the encrypted ticket, and asserts the resumption
attempt does not complete.
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.