Commit Graph
10169 Commits
Author SHA1 Message Date
Sean Parkinson 5a1cd9fc3e ssl.c split: cleanup
Clean up includes single return point from every function, consistent formatting function block comment and tests added.

ssl_api_rw.c: Cleanup; 6 helpers extracted from write_dup/shutdown; fixed a SendBuffered corner case that returned 0 instead of an error.

ssl_api_ext.c: Cleanup; extracted wolfssl_ticket_key_cb_process, wolfssl_rehandshake_prepare.

ssl_api_hs.c: Cleanup + de-indent; 9 helpers extracted, incl. shared wolfssl_handshake_flush/_done between connect and accept (~100 duplicated lines removed). wolfSSL_connect/accept left multi-exit.

ssl_api_cert.c: Cleanup of newer functions at end of file; extracted PushPeerCertToChain; fixed a double free in CreatePeerCertChain; fixed 5 wrong @param names.

ssl_api_crl_ocsp.c: Full cleanup of all 49 functions; wolfSSL_OCSP_parse_url rewritten; fixed a URL with no host returning success with the rest of the URL as the host; added IPv6 literal support; fixed 4 wrong WOLFSSL_ENTER names.

ssl.c: Moved the x509GetIssuerFromCM forward declaration here for clarity.
2026-08-07 09:30:56 +10:00
David Garske 950fe9a3f7 Merge pull request #11048 from yosuke-wolfssl/fix/f_7543
Lock globalRNGMutex in BN_rand, ECDH, EC25519 and AddSession
2026-08-06 14:16:24 -07:00
David Garske 38c51ca509 Merge pull request #11058 from yosuke-wolfssl/fix/f_7544
Release sniffer static ephemeral lock on all SetupKeys exits
2026-08-06 11:42:21 -07:00
Tobias Frauenschläger eab70a1e88 Merge pull request #11031 from douzzer/20260727-fips-dev-no-post
20260727-fips-dev-no-post
2026-08-06 08:47:10 +02:00
David Garske e941761ace Merge pull request #11060 from Frauschi/async_pha
Make `--enable-all --enable-asynccrypt-sw` work end to end
2026-08-05 21:32:17 -07:00
David Garske 55e25428d8 Merge pull request #10517 from Roy-Carter/bugfix/wolfSSL_add0_chain_cert_not_incrementing
Bugfix- wolf ssl add0 chain cert not incrementing certchain and causing TLS1.3 to fail
2026-08-05 21:29:30 -07:00
Yosuke Shimizu 0154eca6c0 Release sniffer static ephemeral lock on all SetupKeys exits 2026-08-06 09:18:34 +09:00
Yosuke Shimizu 266a9eab5f Lock globalRNGMutex in BN_rand, ECDH, EC25519 and AddSession 2026-08-06 09:16:54 +09:00
Daniel Pouzzner 64a91957af fixes from AI review:
linuxkm/x86_vector_register_glue.c: in wc_save_vector_registers_x86(), properly squelch the hard-IRQ call warning if flags & WC_SVR_FLAG_MAYBE_INHIBIT;

src/internal.c: in AllocKey(), properly set key_inited = 1 if wc_SlhDsaKey_Init() succeeds;

.github/workflows/fips-dev-no-post.yml: test -DWC_FIPS_AESGCM_NO_SHORT_NONCES.
2026-08-05 13:53:47 -05:00
Daniel Pouzzner 83b175ce95 fixes and improvements from AI review:
.github/workflows/fips-dev-no-post.yml: add reporting of fuzzing seed.

wolfcrypt/src/aes.c, tests/api/test_aes.c, .wolfssl_known_macro_extras:

* change FIPS AES-GCM nonce size restrictions from from opt-out (WC_FIPS_AESGCM_ALLOW_SHORT_NONCES) to opt-in (WC_FIPS_AESGCM_NO_SHORT_NONCES).
* apply restrictions only on encryption operations, never on decryption.

configure.ac: fix HAVE_FIPS_VERSION of fips-ready; fix enable_dh setup in KERNEL_MODE_DEFAULTS setup; fix help message for --enable-dh.

linuxkm/x86_vector_register_glue.c: add dump_stack() on each BUG/WARNING message that didn't already have it.

src/tls.c: fix a couple leaks in TLSX_KeyShare_GenDhKey().

tests/swdev/swdev.c: gate src->sha_method access in swdev_sha256_copy_state() and swdev_sha512_copy_state() appropriately.

tests/unit.c: conditionally include dh.h, to assure wc_dh_enable() is available.

wolfcrypt/src/dh.c:
* in wc_InitDhKey_ex(), zero the key at entry unless null, remove duplicate key->trustedGroup = 0, and call wc_FreeDhKey() on error at end.
* add missing wc_dh_enabled checks in  wc_DhGeneratePublic() and wc_DhGenerateParams().

wolfcrypt/src/error.c: fix missing space in FIPS_UNAPPROVED_E string.

b/wolfssl/wolfcrypt/settings.h: sense __SIZEOF_INT128__ and if defined, but HAVE___INT128_T and/or HAVE___UINT128_T are undefined, define them.

wolfcrypt/src/falcon.c: tweak the gate on __uint128_t availability to lean solely on HAVE___UINT128_T.

wolfcrypt/src/random.c: fix a couple missed WC_NO_ERR_TRACE() wrappers.

wolfcrypt/src/rng_bank.c: properly tolerate WC_ACCEL_INHIBIT_E as a retval from bank->affinity_lock_cb().

wolfcrypt/src/sha256.c, wolfcrypt/src/sha512.c: move #undef WC_C_DYNAMIC_FALLBACK for WOLFSSL_AESNI without USE_INTEL_SPEEDUP to follow all includes, assuring no struct layout conflict.

wolfcrypt/src/sha512.c: fix wrong call in intelasm Transform_Sha512() !WC_C_DYNAMIC_FALLBACK SHA512_C path.

wolfcrypt/test/test.c: fix double-WC_TEST_RET_ENC_EC() in mldsa_param_*_vfy_test().
2026-08-05 13:53:47 -05:00
Daniel Pouzzner 625f39f665 src/internal.c:
* in AllocKey capture and propagate the return of the per-type wc_*_init_ex
  calls (ed25519, ed448, falcon, ML-DSA, ML-KEM, ...) instead of discarding it,
  so an init failure surfaces rather than leaving a partially-constructed key
  for later use.

* The `default:` arm of the type switch now sets `ret = BAD_FUNC_ARG` and
  breaks, instead of returning directly, so it reaches the common cleanup.

* The failure cleanup distinguishes the two states: if the key was initialized,
  FreeKey(); otherwise XFREE(*pKey) and NULL the caller's pointer -- previously
  an allocation that failed before init leaked.

* Two mis-copied #endif comments corrected: HAVE_CURVE25519 -> HAVE_ED25519 and
  HAVE_CURVE448 -> HAVE_ED448.
2026-08-05 13:53:45 -05:00
Daniel Pouzzner c7a2c6c46d configure.ac: add --enable-fips=dev-no-post (WOLFSSL_FIPS_DEV_NO_POST, MAJOR=8)
and AM_CONDITIONAL BUILD_FIPS_NO_POST. Refactor FIPS dev/ready version setup:
hoist ENABLED_FIPS_DEV / ENABLED_FIPS_READY to set -DWOLFSSL_FIPS_DEV /
-DWOLFSSL_FIPS_READY centrally, and switch the FIPS AS_CASE arms from
`test "$FIPS_VERSION" != "dev"` to `test "$ENABLED_FIPS_DEV" != "yes"` so the
dev semantics extend to v5-dev/v6-dev/lean-aesgcm-dev.

src/include.am: under !BUILD_FIPS_NO_POST, drop fips.c / fips_test.c /
wolfcrypt_first.c / wolfcrypt_last.c from the build (dev-no-post uses no fips
repo content).

wolfssl/wolfcrypt/settings.h, wolfssl/wolfcrypt/wc_compat.h: under
WOLFSSL_FIPS_DEV_NO_POST, squat WOLF_CRYPT_FIPS_H to inhibit fips.h, and change
the FIPS_READY/DEV version block guard to `!defined(HAVE_FIPS_VERSION)`
(required so an externally supplied version is not clobbered).

wolfssl/wolfcrypt/fips_test.h: add WOLFSSL_FIPS_DEV_NO_POST stub block
(fipsCastStatus_get, the PRIVATE_KEY macros) so master builds without the fips
repo.

linuxkm/linuxkm_wc_port.h, linuxkm/module_hooks.c: accommodate
WOLFSSL_FIPS_DEV_NO_POST (guard verifyCore / CAST / fencepost paths that the
fips repo would otherwise provide; force WC_USE_PIE_FENCEPOSTS_FOR_FIPS).

wolfcrypt/test/test.c: in hmac_sha256_test(), don't expect HMAC_KAT_FIPS_E in
WOLFSSL_FIPS_DEV_NO_POST builds.

wolfssl/wolfcrypt/types.h: add stub macro for
wolfCrypt_SetPrivateKeyReadEnable_fips() when WOLFSSL_FIPS_DEV_NO_POST.
2026-08-05 13:53:45 -05:00
Tobias Frauenschläger 28c92aa81a Guard the async event handling in EccVerify against a NULL key
EccVerify() dereferenced key unconditionally in both of its async spots:

    ret = wolfSSL_AsyncInit(ssl, &key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
    ...
    ret = wolfSSL_AsyncPush(ssl, &key->asyncDev);

Its siblings EccSign() and VerifyRsaSign() wrap both calls in if (key),
because with HAVE_PK_CALLBACKS the private key can live only in the
callback and is never decoded into ssl->hsKey. The self verify step that
WOLFSSL_CHECK_SIG_FAULTS performs after signing passes that same
ssl->hsKey to EccVerify(), so an --enable-asynccrypt build dereferences
NULL there: at the init on entry, and again at the push if EccVerifyCb
returns WC_PENDING_E. Note wc_ecc_verify_hash() cannot produce that
second case, since it rejects a NULL key before starting any async work.

The check on the push goes inside the pending branch rather than into its
condition, because unlike EccSign() this block has an else that maps a
non zero ret onto a verification failure. Extending the condition would
send a pending result down that else and log a bogus
WOLFSSL_ERROR_VERBOSE() for it.

Reproduced with --enable-asynccrypt --enable-pkcallbacks
--enable-faultharden --enable-ecc --enable-supportedcurves and
-DTEST_PK_PRIVKEY, which is what makes examples/server.c leave the
private key to the callback. Running examples/server against
examples/client with ECC certificates, the server takes SIGSEGV without
this change and exits cleanly with it, reaching the verify callback with
keySz 0 instead. The push needed one more step to reach: the in tree
myEccVerify() is synchronous, so it was patched to return WC_PENDING_E
once, after which the server dies in wolfAsync_EventQueuePush() at the
offset of ecc_key.asyncDev, reached from EccVerify() by way of
SendTls13CertificateVerify().

Note the crash is only reachable once the two callers stop dereferencing
ssl->buffers.key->length on the line just above the EccVerify() call,
which is what PR 11000 fixes. Both sites were patched locally to
reproduce. This guard is needed in addition to that fix, not instead of
it, and only matters for asynchronous builds.
2026-08-05 20:39:57 +02:00
Tobias Frauenschläger ff730fec9e Keep the record size probe clear of a suspended build
Second review follow-up on the async record layer series.

Stop the probe reselecting the cipher side. BuildMessage()'s BUILD_MSG_BEGIN
case can call SetKeysSide() for DTLS with secure renegotiation, which swaps
the active encryption state and clears recordSzOverhead. That is not part of a
size calculation, and after the previous commit the suspended build survives
to resume against whatever side the probe last chose, so a DTLS 1.2 record
suspended for PREV_ORDER could resume against the renegotiation keys. Skip it
when sizeOnly is set; the sizes are the same either way.

The probe itself has to keep running. Not re-entering BuildMessage at all
while a build is suspended looks tidier, but wolfssl_local_GetMaxPlaintextSize()
derives the DTLS fragment size from this result, so falling back to the upper
bound there shrinks fragments inconsistently between calls and the MTU
reproducer fails its buffer comparison. Saving and restoring the two fields is
what keeps the answer exact.

Resume inside the record when handshake content is left. The previous commit
declined to skip the padding for a fragmented or coalesced
certificate_request, which was right, but left processReply at doProcessInit
with the index inside the record, so the resume still started a fresh record
parse in the middle of one. Mirror both halves of the end of record block
instead: set runProcessingOneMessage when content remains, advance past the
padding only at the boundary.

Note the shared state at the source. BuildMessage() and BuildTls13Message()
write ssl->options.buildMsgState even for a sizeOnly probe with asyncOkay
clear, where everything else goes to the caller's own arguments. Nothing said
so at those sites, so the next sizeOnly caller would reintroduce this.

Record why only one of the three wc_ecc_make_key_ex() calls in eccsi.c needs
a wait: the other two are preceded by wc_ecc_free(), which clears the marker
their pending path is gated on. Moving either free would make them pend.

Test changes. Force the overhead cache cold before probing, otherwise an AEAD
suite answers from the cache without ever calling BuildMessage and the
assertions hold no matter what the probe did. Compare against BuildMessage's
own figure rather than only checking the size is positive, and run the whole
thing for TLS 1.3 as well as TLS 1.2, since BuildTls13Message() clobbers the
state by a different route: its sizeOnly return bypasses exit_buildmsg
entirely. Checked by stubbing the restore out again, which fails the test.

Also spell the new guard in cryptocb_test() as #if defined(WOLFSSL_ASYNC_CRYPT)
to match the rest of that file, which uses that form 170 times against 4.
2026-08-05 20:39:57 +02:00
David Garske e5b3fb118e Merge pull request #11046 from yosuke-wolfssl/fix/f_7352
Zero EncryptedInfo in ProcessChainBufferCRL and reset info->set on parse
2026-08-05 08:49:18 -07:00
David Garske 556b969195 Merge pull request #11045 from yosuke-wolfssl/fix/f_7522
Declare QUIC record length from bytes remaining
2026-08-05 08:47:18 -07:00
Tobias Frauenschläger 1c5382f169 Harden the async record layer fixes and cover the size probe
Review follow-up on the two preceding commits.

Only skip the padding when the record content is actually consumed. The
post-handshake auth advance ran on any pending return that left processReply
at doProcessInit, which assumes the certificate_request was the last message
in its record. Two states break that: a fragmented certificate_request makes
DoTls13HandShakeMsg() rewind inOutIdx so the fragment can be reprocessed, and
RFC 8446 section 5.1 lets a peer coalesce several handshake messages into one
record, leaving the index inside the record. Adding padSz in either case
points the index at record content. Both states are already mishandled
without this series, since post-handshake auth forces processReply to
doProcessInit regardless, so this is a narrower guard rather than a
regression, and there is no memory safety consequence either way: the largest
possible index is the end of the record. The new test mirrors the end of
record check that follows the message handlers.

Also restore buildArgsSet across the record size probe. The probe borrows
buildMsgState and buildArgsSet from the suspended build; the previous commit
put back only the first. FreeBuildMsgArgs() clears buildArgsSet
unconditionally on the way out, and the resumed call skips the block that
would set it again, so the flag stays clear for the rest of the record. That
is currently harmless, because the only thing it guards is freeing a
dynamically allocated IV and no cipher in the tree needs one, but it leaves
the fix one field short of its own premise.

Add test_record_size_preserves_build_msg_state, which parks a connection at
BUILD_MSG_ENCRYPT with the arguments flag set, runs the probe, and requires
both fields to survive. It fails without the restore and passes with it.

Guard the post-handshake auth block on WOLFSSL_POST_HANDSHAKE_AUTH as well.
The only code that leaves processReply at doProcessInit from inside
DoTls13HandShakeMsg() is the post-handshake auth branch, which is itself
behind that macro, so the check cannot fire without it.

Say that the oversized record is rejected rather than that it overflows the
buffer. BuildMessage() catches it and returns BUFFER_E; the old wording read
like memory corruption.

Verified with --enable-all --enable-asynccrypt-sw and with plain --enable-all,
both warning free under the os-check CFLAGS. The two reproducers from the
preceding commits still complete.
2026-08-05 08:34:09 +02:00
Tobias Frauenschläger f3065f9ed0 Preserve the build message state across the record size probe
Writing application data over DTLS fails with -132 BUFFER_E in an
asynchronous build once a record goes pending. It is reproducible with
the shipped examples:

  ./examples/server/server -e -u -f -v 3 -l ECDHE-RSA-AES128-SHA -2 -p 11151 &
  ./examples/client/client -B 4000,1310 -u -f -v 3 -l ECDHE-RSA-AES128-SHA -2 -p 11151

The client reports "Oops, want to write past output buffer size" and the
write fails. This is the DTLS MTU configuration from tests/test-dtls-mtu.conf.

SendData() sizes the output buffer by calling wolfssl_local_GetRecordSize(),
which runs BuildMessage() with sizeOnly set and asyncOkay clear. That probe
keeps its own arguments on the stack, but the state machine it drives lives
in ssl->options.buildMsgState, which is shared with the asynchronous
BuildMessage() that may still be in flight for the same record.

Because SendData() re-probes the size on every retry, the sequence is:
the real BuildMessage() suspends at BUILD_MSG_ENCRYPT, the retry's probe
resets the shared state to BUILD_MSG_BEGIN and leaves it there, and the
resumed call then re-runs the begin and size stages against arguments that
already carry the header and cipher overhead. For a 1310 byte payload with
ECDHE-RSA-AES128-SHA that takes the header from 13 to 21 bytes and the
record from 1361 to 1417, which no longer fits the 1361 byte buffer the
first probe correctly sized.

Save the state around the probe and put it back afterwards. The probe still
needs to start from BUILD_MSG_BEGIN to compute a size, so restoring is the
narrowest fix; the arguments themselves are already private to the probe.

Verified with --enable-all --enable-asynccrypt-sw: the reproducer above goes
from a failed write to completing its benchmark. Full make check in that
configuration passes, 17 passed and 6 skipped with no failures, though that
run also needs the wolfcrypt test fixes for ECIES, ECCSI and the crypto
callback test, which that configuration trips over first and which are not
part of this change.

Non-async builds are unaffected, since the saved value is only read and
written under WOLFSSL_ASYNC_CRYPT.
2026-08-05 08:34:08 +02:00
Tobias Frauenschläger 8767340251 Finish the record when post-handshake auth returns pending
A TLS 1.3 client doing post-handshake authentication fails the next read
with -326 VERSION_ERROR in an asynchronous build, and the connection dies.
It is reproducible with the shipped examples:

  ./examples/server/server -v 4 -l TLS13-AES128-GCM-SHA256 -Q -2 -p 11119 &
  ./examples/client/client -v 4 -l TLS13-AES128-GCM-SHA256 -Q -2 -p 11119

DoTls13CertificateRequest() handles a post-handshake CertificateRequest by
resetting the handshake states, setting processReply back to doProcessInit
and calling wolfSSL_connect_TLSv13() to send the certificate, certificate
verify and finished flight. It runs that from inside DoTls13HandShakeMsg(),
which is itself inside DoProcessReplyEx().

When the flight goes pending, WC_PENDING_E travels back out of
DoTls13HandShakeMsg() and DoProcessReplyEx() returns immediately, so the
end of record accounting that follows never runs and the record is left
short by ssl->keys.padSz bytes. The client resumes through
wolfSSL_negotiate() from ReceiveData() rather than by reprocessing the
record, so nothing ever advances past those bytes. The next ProcessReply()
starts a fresh record at that offset and parses the record's own MAC as a
record header, which fails the version check in GetRecordHeader().

Measured on the failing read: idx 50, length 67, padSz 17, with the header
bytes decoding as type 0x16 and version 0x70 0xEA.

Advance past the padding when the handler returns pending having already
marked the record complete. processReply is what distinguishes the two
cases: post-handshake auth leaves it at doProcessInit, while an ordinary
pending message leaves it at runProcessingOneMessage and must not be
advanced, since that one really is reprocessed on resume. Confirmed by
tracing every pending return in the failing run: three ordinary ones at
runProcessingOneMessage, and only the post-handshake one at doProcessInit,
where idx plus padSz lands exactly on the buffer length.

This mirrors what the early data path a few lines below already does when
it returns early after marking the record done.

Synchronous builds are unaffected. wolfSSL_connect_TLSv13() completes in
place there, DoTls13HandShakeMsg() returns 0, and the normal accounting
runs.
2026-08-05 08:34:08 +02:00
Yosuke Shimizu f6bd188eee Declare QUIC record length from bytes remaining 2026-08-05 14:12:26 +09:00
Yosuke Shimizu 9909d0226c Zero EncryptedInfo in ProcessChainBufferCRL and reset info->set on parse 2026-08-05 13:02:45 +09:00
David Garske aa0d44dac5 Merge pull request #11030 from cconlon/csrExtCritical
Encode basicConstraints critical flag and pathlen into generated CSRs
2026-08-04 20:52:21 -07:00
David Garske 5f272267c0 Merge pull request #10901 from Frauschi/slhdsa_tls_handshake
Add SLH-DSA support for the TLS 1.3 and DTLS 1.3 handshake
2026-08-04 18:46:01 -07:00
David Garske 36c35c9a49 Merge pull request #11007 from kareem-wolfssl/zd22219
Fix a couple of issues in DTLS ClientHello parsing.
2026-08-04 17:21:39 -07:00
David Garske d6708600a2 Merge pull request #11027 from Frauschi/fenrir_2
Fixes for OCSP stapling, cert manager, and certificate_status_request_v2 handling
2026-08-04 15:54:59 -07:00
Tobias Frauenschläger ac75f181cd Add SLH-DSA support for the TLS 1.3 and DTLS 1.3 handshake
Implement SLH-DSA (SPHINCS+, FIPS 205) as an entity authentication
algorithm for the TLS 1.3 and DTLS 1.3 handshake, following
draft-reddy-tls-slhdsa. All twelve parameter sets (SHAKE and SHA2 families,
128/192/256 in the f and s variants) are wired into the handshake for
signing and verifying the CertificateVerify message; test certificates and
configs cover the 128f and 128s sets.

Handshake integration:
- Map the SLH-DSA signature schemes to and from the wire in the
  signature_algorithms extension and CertificateVerify. The mapping,
  advertisement, and OID handling are gated per parameter set so a build
  only offers, accepts, and maps the variants actually compiled in
  (including partial SHA2 builds).
- Sign and verify the CertificateVerify with an SLH-DSA entity key, and
  load SLH-DSA private keys and certificates (ssl_load.c, ssl.c,
  ssl_api_pk.c, asn.c).
- Preserve the verify return code on a failed SLH-DSA CertificateVerify
  rather than flattening every non-zero result to SIG_VERIFY_E.
  wc_SlhDsaKey_Verify already returns SIG_VERIFY_E on a real mismatch, so
  the failure semantics are unchanged while WC_PENDING_E (async crypto
  callbacks) and hard errors now propagate, matching ML-DSA and Falcon.

Protocol version gating:
- SLH-DSA is defined for TLS 1.3 only, so the schemes are no longer offered
  to a TLS 1.2 peer, and MatchSigAlgo and PickHashSigAlgo pin an SLH-DSA
  certificate both to the scheme for its exact parameter set and to
  TLS 1.3.
- Reject a Falcon, ML-DSA or SLH-DSA key in the TLS 1.2 CertificateVerify
  with SIG_TYPE_E. No signature scheme below TLS 1.3 covers a post-quantum
  key, the record is reserved for a classic signature, and the signing
  switches have no post-quantum case, so continuing would have sent the
  reserved buffer's uninitialized tail.

Streamed CertificateVerify send:
- SLH-DSA signatures are large (up to ~50 KB). When the CertificateVerify
  body exceeds a single record, generate the signature into a
  connection-level buffer and emit it one record at a time so the output
  buffer never has to hold the whole signature. This keeps peak memory near
  one signature plus a single fragment and resumes correctly across a
  non-blocking WANT_WRITE without recomputing the randomized signature.
  Gated by WOLFSSL_TLS13_STREAM_CERT_VERIFY (TLS 1.3, non-async, PQC
  signatures); DTLS and WOLFSSL_ASYNC_CRYPT keep the existing in-place
  fragmented path.
- Drop a half-sent streamed CertificateVerify in wolfSSL_clear. Left in
  place, the resume guard would fire on the next handshake and re-send the
  previous one's signature into a different transcript.
- Dual-algorithm (WOLFSSL_DUAL_ALG_CERTS, BOTH) CertificateVerify bodies are
  streamed as well. The combined two-signature body may include a
  variable-length signature, so the body buffer is sized from the
  per-signature upper bounds and the exact length is recorded after signing;
  the small trailing slack is never sent.

Buffer sizing:
- Keep MAX_X509_SIZE a fixed 9 KB for post-quantum builds. It sizes a
  static per-certificate slot embedded by value in every cached session, so
  it must not scale with a post-quantum signature; nor may it derive from
  the enabled ML-DSA level, or a level-restricted build would silently drop
  certificates that a full build keeps.
- Add MAX_CERT_WIRE_SZ for the largest certificate that may appear in a
  handshake message, sized from the enabled post-quantum signatures, and
  derive MAX_CERTIFICATE_SZ from it instead of from MAX_X509_SIZE.
- Add MAX_CERT_MSG_DEPTH for the chain depth assumed when sizing the
  certificate message. MAX_CHAIN_DEPTH bounds how deep a chain may be
  verified, while this sizes a buffer an unauthenticated peer can make us
  allocate, so it is trimmed to 5 when a post-quantum certificate has
  inflated the per-certificate size. Classic builds are unchanged.
- Size the CertificateVerify buffers from the actual signature length
  instead of the worst-case WC_MAX_CERT_VERIFY_SZ, which balloons with
  SLH-DSA. WC_MAX_CERT_VERIFY_SZ is retained for API compatibility and its
  growth is documented in README.md.
- Order Scv13Args widest member first so it carries no interior padding and
  still fits ssl->async->args under WOLFSSL_ASYNC_CRYPT together with
  WOLFSSL_DUAL_ALG_CERTS.

Dual-algorithm certificates:
- Reserve the two signature length prefixes in the in-place
  CertificateVerify sizing that the streamed path already accounted for.
- Build the PreTBS for an alternative signature check from the certificate
  size minus both signatures, and retry once at a size the canonical
  re-encode cannot exceed when that estimate turns out short. The estimate
  keeps the allocation small on constrained targets, and wc_GeneratePreTBS
  reports an encoder failure as WOLFSSL_FAILURE, which is zero, so a
  non-positive result is now an error instead of silently skipping
  ConfirmSignature and reading as a verified signature.

Device held private keys:
- Support an SLH-DSA private key that lives in a device and is referenced
  by id or label. The parameter set cannot be recovered from a device side
  identifier, so it is carried from the key type down to
  wc_SlhDsaKey_Init_id and wc_SlhDsaKey_Init_label, and the key is released
  with wc_SlhDsaKey_Free once the certificate and key pair is checked.

Robustness:
- Check the SlhDsaParamToType, wc_SlhDsaKey_PublicSizeFromParam and
  wc_SlhDsaParamToOid results in the certificate and key load paths.
- Zeroize an SLH-DSA key before wc_SlhDsaKey_Init, which can return
  NOT_COMPILED_IN before it clears the object, in both the certificate load
  path and AllocKey.
- Take the alternative key's parameter set from the certificate's sapkiOID
  rather than keyOID, which describes the native key.
- Re-initialise across hash families in wc_SlhDsaKey_PublicKeyDecode as
  wc_SlhDsaKey_PrivateKeyDecode already does. The hash objects share a union
  selected by family, so importing across families writes the new family's
  state over the old one's and orphans it.
- Copy pkCurveOID in SetSSL_CTX when only SLH-DSA is enabled, matching the
  struct member guard. Without it the field stayed zero and the signature
  scheme matching above was dead in exactly that build.
- Derive the per parameter set WOLFSSL_SLHDSA_PARAM_NO_* macros from the
  group level exclusions, and select WC_SLHDSA_DEFAULT_PARAM with those
  same macros, so the parameter table and the TLS mappings cannot disagree.
- Add SLH-DSA to the lean build WOLFSSL_MAX_SIGALGO carve-out, since twelve
  more entries no longer fit the small list.
- Prefix the new SLHDSA_ALL_NO_* macros in the installed header with WC_.

Tests and certificates:
- Add SLH-DSA entity (client and server) certificates for the SHAKE and
  SHA2 128f and 128s parameter sets, and update the generation script.
- Add TLS 1.3 and DTLS 1.3 entity-cert CertificateVerify test configs
  covering the fragmented (128f) and single-record (128s) send paths for
  both hash families, wired into suites.c. These sign with the entity key,
  so they are excluded from verify-only builds.
- Interrupt the streamed CertificateVerify with one WANT_WRITE and with
  several on the same record, and assert the handshake still completes and
  re-emits identical bytes, which the blocking .conf handshakes never
  exercise. The record to interrupt is counted first, because the server's
  record batching differs between builds. Where the flight is flushed as a
  single write the send is retried below SendTls13CertificateVerify, so
  these do not by themselves cover the fragOffset resume path.
- Drive the streamed path with an ML-DSA leaf under a negotiated
  max_fragment_length, covering it for a non SLH-DSA algorithm.
- Reject a TLS 1.2 handshake that presents an SLH-DSA client certificate.
- Map every compiled-in scheme from its wire code point to the key OID, and
  extend the exhaustive SaToNid coverage with the twelve new algorithms.
- Accept an SLH-DSA private key referenced by id and by label.

Build configuration:
- configure.ac: --enable-slhdsa now keeps the certificate/ASN code enabled
  (as --enable-mldsa does), so an SLH-DSA-only build with RSA, ECC and DH
  disabled configures instead of erroring that ASN is off.
- Guard the WOLFSSL, WOLFSSL_CTX and WOLFSSL_X509 pkCurveOID members for
  WOLFSSL_HAVE_SLHDSA, so an SLH-DSA-only build declares the field the
  handshake and CopyDecodedToX509 already reference under an SLH-DSA guard.
- Mark checkKeySz used in the SLH-DSA branch of ProcessBufferCertPublicKey;
  SLH-DSA is the only certificate signature algorithm with no minimum-size
  check, so an SLH-DSA-only build otherwise tripped -Wunused-parameter.
- Propagate haveSlhDsaSig in wolfSSL_set_SSL_CTX, which copied the Falcon
  and ML-DSA flags but not the SLH-DSA one.
- CI: add a SHA2-only SLH-DSA build (--enable-slhdsa=sha2) so the
  SHAKE-disabled combined-maxima guards are exercised, and an async crypto
  build with dual-algorithm certificates, which is the only configuration
  that compiles the in-place fragmented CertificateVerify send.
2026-08-04 22:23:03 +02:00
David Garske 3656306dd4 Merge pull request #10930 from julek-wolfssl/fenrir-wolfcrypt-tls-fixes
wolfCrypt and TLS 1.3 correctness fixes (F-1376, F-2653, F-1972, F-4593)
2026-08-04 10:31:44 -07:00
John Safranek 396a160954 Merge pull request #10984 from embhorn/zd22162
Enforce RFC 5746 renegotiation_info in TLS 1.2 client by default
2026-08-03 10:11:25 -07:00
Tobias Frauenschläger 18414d7b4b Let a DTLS 1.3 reader send the work it schedules
With WOLFSSL_RW_THREADED the read path performs no scheduled work, because
transmitting from the reader would race the write thread over the output
buffer and the sending key schedule, neither of which is covered by a lock.
Post-handshake the only remaining consumers are on the write path, and
wolfSSL_dtls_retransmit() only helps while the handshake is unfinished. An
application that reads without writing therefore never acknowledges a
NewSessionTicket, KeyUpdate or connection ID message, and the peer keeps
retransmitting what it is waiting to have acknowledged. RFC 9147 relies on
those ACKs, so this is a protocol level break rather than a missed
optimisation.

Add wolfSSL_dtls13_do_scheduled_work() so such an application can send that
work from its write thread, and wolfSSL_dtls13_pending_work() so it can tell
when there is any.

Both entry points ask the same helpers rather than each testing conditions of
their own, so they cannot drift into the predicate promising work the pump
then declines or silently discards, which would leave a drain loop spinning or
mislead the caller about what happened. That covers key updates in particular:
none is sent while one of ours is unacknowledged, since DTLS must not have two
in flight and Tls13UpdateKeys() drops a locally scheduled one in that state,
and a peer request is kept rather than dropped until it can be answered. The
predicate also errs towards reporting work when it cannot tell, so a loop
surfaces the error rather than stopping silently.

Refusing an object is treated as a usage error and leaves ssl->error alone.
That field is sticky, since SendData() only clears it for WANT_WRITE, pending
async work and the DTLS MAC and decrypt cases, and wolfSSL_write() skips its
write-dup drain while it is set, so recording one would disable the very drain
a write-dup application depends on.

Write-dup pairs are out of scope on both sides. They park the read side's work
in the shared WriteDup struct, which only wolfSSL_write() reconciles, so they
already have a drain. Completing a key update we started ourselves is out of
scope too: that needs the peer's acknowledgement processed, which rotates the
sending keys and creates an epoch, and the epoch table has no locking while
the read thread mutates it as well.

The declaration is gated to match where the definitions live, so a lean build
is not promised a symbol it does not get.
2026-08-01 12:04:56 +02:00
Tobias Frauenschläger 428bfe9f58 Restore the caller's key RNG after an HPKE operation
The encap and decap paths create a temporary RNG, install it into a key that
belongs to the caller so the shared secret computation can blind, and then
free it without taking it back out. Both wc_ecc_set_rng and
wc_curve25519_set_rng only record the pointer, and nothing else ever writes
that field, so the caller's key was left pointing at freed memory. Encap does
this to the ephemeral key and decap to the receiver key, including the
curve25519 branch. Repeated HPKE calls hide it because each one installs a
fresh RNG first, but any other use of the key that consults it, such as an
ECDH or a signature under timing resistance, reads the freed object. ECH
holds exactly such a long lived key.

Save whatever RNG the key already had and put it back before freeing the
temporary one, so the key is handed back to the caller unchanged. Clearing
the field instead would silently drop an RNG the caller had installed for
blinding of their own.

Extend the HPKE round trip test to give both keys an RNG of its own and to
require them to still have it once the seal and open have finished.

Fixes F-7083.
2026-08-01 12:04:56 +02:00
Tobias Frauenschläger e2cce035eb Zeroize key material when clearing a WOLFSSL for reuse
SSL_clear recycles a WOLFSSL object for a new connection, which is the usual
pattern in connection pooling servers, and wolfSSL_shutdown calls it on
success as well. It reset the option and state fields but left every piece of
key material from the previous connection in place. The teardown path in
SSL_ResourceFree is careful here and force zeroes the keys struct and the TLS
1.3 traffic secrets, so a reused object ended up holding material that a
freed one would not.

The keys struct keeps the write keys, MAC secrets and IVs, clientSecret and
serverSecret keep the TLS 1.3 traffic secrets, the DTLS 1.3 epoch table keeps
traffic keys, IVs and sequence number keys for every epoch, and the handshake
arrays keep the master secret, the pre master secret, the PSK key and the TLS
1.3 key schedule secret. The tls-unique fields keep the Finished values of the
connection that just ended, so the next caller could bind to the wrong
session. The buffers are sized for the largest supported algorithm, so a later
handshake that negotiates something smaller only overwrites a prefix and the
tail survives.

Force zero all of it. A freshly created object has these zeroed already, with
two exceptions that are put back after the wipe: the multicast peer identifier
sentinel, and the unprotected DTLS 1.3 epoch 0 together with the epoch
pointers aimed at it, which only InitSSL sets up and without which the next
handshake has no valid epoch.

Wipe the handshake arrays in place rather than releasing them. They have to
stay allocated because wolfSSL_set_secret, the exporter and the accessors that
run after a connection all read from them on an object that is being recycled
rather than freed, and because the key agreement routines take preMasterSz as
the size of the buffer they may write, so that is restored to what a freshly
allocated Arrays carries. An application that asked to keep the arrays still
gets back everything the API can hand it, so the master secret and the
exporter secret only go when it did not ask, while the pre master secret, the
PSK key and the key schedule secret always do because nothing reads those
back.

wolfSSL_set_secret and wolfSSL_make_eap_keys both reached into the arrays
without checking that they are there, which the ordinary handshake teardown
can already leave them not to be, so both now report a bad argument instead.

Add a regression test that runs a handshake, clears the object with the arrays
kept, and requires the write keys, both traffic secrets and the pre master
secret to be gone while the master secret, the exporter secret and the client
random survive. It then takes that request back, clears again, and requires
the master and exporter secrets to be gone with the arrays themselves still
present.

Fixes F-7258.
2026-08-01 11:54:40 +02:00
Tobias Frauenschläger cb73424c31 Zeroize the saved HMAC pads on cleanup
WOLFSSL_HMAC_CTX keeps a copy of the inner and outer pads outside the
embedded wolfCrypt HMAC object so that a later init with a NULL key can
restore the key. Those pads are the key combined with the fixed padding, so
for any key no longer than the hash block size the key falls out of a single
exclusive or. Cleanup only called wc_HmacFree on the embedded object, which
zeroes what it is given but cannot reach the enclosing context, so the saved
pads survived. HMAC_CTX_free then returned that heap block to the allocator
with the key material still in it, where it stayed until some later
allocation happened to overwrite it.

Wipe both saved pads in wolfSSL_HMAC_cleanup, which HMAC_CTX_cleanup,
HMAC_CTX_reset and HMAC_CTX_free all reach. Do the same on the set key
failure path in the init function, since the context is reported as unkeyed
there while the previous key's pads would otherwise remain.

The session ticket key callback had the same leak for the same reason. It
holds a WOLFSSL_HMAC_CTX on the stack, hands it to the application to be
keyed with the long lived ticket HMAC key, and then only freed the embedded
object, leaving the pads on the stack after every ticket encrypt and every
ticket decrypt including the error paths. Have it clean up through
wolfSSL_HMAC_CTX_cleanup so it picks up the wipe.

Add a regression test that keys a context, checks the pads were populated,
runs cleanup and requires both arrays to be zero.

Fixes F-7256 and F-7257.
2026-08-01 11:54:40 +02:00
Tobias Frauenschläger 96fb284398 Honour chklen when matching an IP in X509_check_host
wolfSSL_X509_check_host takes an explicit length and its own validation
accepts a buffer with no NUL terminator, since only an embedded NUL is
rejected and a trailing one is merely stripped when present. The iPAddress
check then called CheckIPAddr, which drops the length and measures the
buffer with XSTRLEN, reading past the end of a caller supplied buffer that
is length delimited rather than terminated. This ran on every call, not
only when checking an IP address, and is compiled in whenever
WOLFSSL_IP_ALT_NAME is defined, which OPENSSL_ALL and WOLFSSL_QT enable.

Call CheckHostName directly with the caller's length and the IP flag set.
That is what CheckIPAddr does internally, minus the length being recomputed.
Behaviour is unchanged for NUL terminated input, because the normalization
above already leaves chklen equal to the string length in that case. It
also fixes a matching bug, since a length delimited IP address sitting in a
longer buffer no longer fails to match an iPAddress entry.

Add a regression test covering an interior slice of a longer buffer and a
buffer sized exactly to the name with no terminator.

Fixes F-7248.
2026-08-01 11:54:40 +02:00
Tobias Frauenschläger 2788d9dac1 Use the stored entry length when printing a directoryName
X509PrintDirType derived the length of the alt name payload with XSTRLEN.
A directoryName entry holds raw DER, which routinely contains zero bytes,
and under WC_ASN_NO_HEAP the buffer is not NUL terminated at all, so the
computed length was wrong in general and reading it was already out of
bounds in the no-heap case. The length then fed an unsigned loop bound of
src_len - 5, so any entry that XSTRLEN measured as shorter than five bytes
wrapped the bound to nearly UINT32_MAX and the tag scan read far past the
end of the entry. A certificate with a short or empty directoryName alt
name reaches this from the ordinary certificate printing path.

Take the length from entry->len, which the parser already fills in, and
return early when the entry is too short to hold an OID, a tag and a
length. The scan is unchanged for entries of five bytes or more, and the
ASN parsing helpers now receive the true buffer length as their bound.

Add a regression test that prints a certificate carrying a directoryName
with an embedded zero byte before the common name, and one carrying a
directoryName too short for the tag scan.

Fixes F-7223.
2026-08-01 11:54:40 +02:00
Tobias Frauenschläger 6e4a2429e6 Take the write lock when setting the pending DTLS peer
wolfSSL_dtls_set_pending_peer acquired the DTLS peer lock for reading and
then mutated the shared state under it. It frees and clears pendingPeer,
calls SockAddrSet which frees and reallocates the address buffer, and
writes processingPendingRecord. A read lock allows several holders at once,
so two threads in this function can both free pendingPeer.sa, and a reader
in wolfSSL_dtls_get_peer or the wolfio send path can observe a dangling
pointer.

Acquire the lock for writing instead, matching wolfSSL_dtls_set_peer, which
already does so for the same class of mutation. Only affects builds that
define WOLFSSL_RW_THREADED, since the locking is compiled out otherwise.

Fixes F-7222.
2026-08-01 11:54:40 +02:00
Tobias Frauenschläger 22985984d1 Clamp CBC pad length before deriving the MAC input length
TimingPadVerify passes (pLen - macSz - padLen - 1) to ssl->hmac and relies
on the callee recovering the record length by modular addition. TLS_hmac now
does that addition with overflow checking and returns BUFFER_E before hashing
anything, so a record whose padding length byte exceeds pLen - macSz - 1 is
rejected without a MAC being computed at all, while a smaller padding byte
gets the full constant time HMAC. The padding length byte is taken straight
from the decrypted record, so this hands an attacker a Lucky13 style timing
oracle worth an entire HMAC.

Clamp the padding length in constant time before it is used, so the length
handed to ssl->hmac never wraps and every value of the padding length byte
results in the same amount of hashing. The rejection decision is unchanged,
since MaskPadding already flags an out of range padding length. The overflow
check in TLS_hmac stays as a backstop for genuinely bogus sizes.

Add a regression test that drives TimingPadVerify over every padding length
byte with a recording MAC callback and asserts the callback is always invoked
with a length that does not wrap.

Fixes F-7240.
2026-08-01 11:54:40 +02:00
Chris Conlon 9e5c365cd1 Encode basicConstraints critical flag and pathlen into generated CSRs 2026-07-31 17:46:16 -06:00
Kareem 706f38c918 Code review feedback 2026-07-31 16:14:45 -07:00
Kareem 834db02277 Fix a couple of issues in DTLS ClientHello parsing.
Thanks to the Fuzz0x team for the report.
2026-07-31 15:39:04 -07:00
David Garske 51f694193e Merge pull request #10972 from philljj/misc_fixes
ssl: fix miscellaneous issues found in review.
2026-07-31 14:02:17 -07:00
Tobias Frauenschläger 3e7f1c8172 Do not free CRL and OCSP objects whose initialization failed
wolfSSL_CertManagerEnableCRL, wolfSSL_CertManagerEnableOCSP,
wolfSSL_CertManagerEnableOCSPStapling and wolfSSL_d2i_X509_CRL called
FreeCRL() or FreeOCSP() on an object that InitCRL() or InitOCSP() had
just failed to initialize. The other callers of those two functions,
wolfSSL_X509_crl_new(), wolfSSL_X509_CRL_new(), SwapLists() and
wc_NewOCSP(), only dispose of the memory, which is the contract the
init functions are written to.

Freeing the object is not harmless. InitCRL() releases the read/write
lock and the condition variable itself before returning an error from
the reference count path, so FreeCRL() destroys both a second time, and
on the two earlier failure paths it destroys primitives that were never
created at all. InitOCSP() only fails when it cannot create its mutex,
which FreeOCSP() then destroys. Destroying a synchronization object
twice, or one that was never created, is undefined behaviour on every
platform and a real double free on the ports where the object holds a
handle to allocated storage, such as vSemaphoreDelete() on FreeRTOS and
CloseHandle() for Windows condition variables.

Dispose of only the memory in all four places. In the certificate
manager that also removes the reason to defer the disposal until after
caLock is released, so the extra local and the second free block go
with it.

Complete InitCRL()'s own cleanup while here: when wc_InitRwLock() fails
it returned without releasing the condition variable it had created
just above, leaking it for every caller.
2026-07-31 22:22:26 +02:00
Tobias Frauenschläger d5893aa9fd Initialize cert manager CRL and OCSP objects before publishing
The lazy creation paths in wolfSSL_CertManagerEnableCRL,
wolfSSL_CertManagerEnableOCSP and wolfSSL_CertManagerEnableOCSPStapling
stored the freshly allocated object in the shared certificate manager
before zeroing and initializing it. A certificate manager is shared by
every WOLFSSL created from a CTX, so another thread could observe the
non-NULL pointer and operate on uninitialized memory, for example by
taking crl->crlLock before InitCRL had created it.

Build each object in a local, initialize it, and store it in the
certificate manager only on success. The CRL lookup callback is set on
the local as well, so a thread that picks the object up cannot find it
without one and fall back to CRL_MISSING.

Serialize the creation with caLock and re-check the pointer after
locking, so that two concurrent Enable calls cannot both allocate and
leak one of the objects. This does not make every writer of the pointer
safe: wolfSSL_X509_STORE_add_crl() still publishes cm->crl with no lock,
and readers observe it without one.

Dispose of a half-built object after releasing caLock rather than under
it. Neither free can actually block here: InitCRL() sets tid to
INVALID_THREAD_VAL before any of its failure returns so FreeCRL() skips
the monitor join, and FreeOCSP() takes no lock at all. The point is to
keep the critical section down to the decision of what to publish, and
to keep caLock out of the CRL free path as a rule: FreeCRL() on a
published object joins the CRL monitor thread, which takes crlLock,
while the verification path already takes crlLock (CheckCertCRLList())
before caLock (GetCA()).

Fixes F-7235.
2026-07-31 22:11:09 +02:00
Tobias Frauenschläger 1d15e1f27f Make OCSP stapling request ownership explicit
The OcspRequest carried a "void* ssl" back-pointer that the stapling
paths wrote just before handing the request to the OCSP layer. For the
request cached on the WOLFSSL_CTX that field is shared by every
connection using it, so concurrent handshakes raced on it. Drop the
field and pass the connection to CheckOcspRequest() and
CheckOcspResponse() as an argument instead, which is the only thing it
was ever read for.

Ownership of the cached request was equally implicit. Publication moves
out of CreateOcspRequest() into CreateOcspResponse(), and callers now
learn whether the CTX took ownership from a "ctxOwnsRequest" flag rather
than by comparing pointers against ssl->ctx->certOcspRequest, which was
read without the lock that guards it. The flag and the request are
handed back together on success and both left untouched on failure, so a
caller never decides ownership against a request it is not holding.

The cache is a field of the WOLFSSL_CTX, so serialize it with a lock
scoped to the CTX. SSL_CM(ssl) can resolve to a per-SSL cert manager
when WOLFSSL_LOCAL_X509_STORE is defined, which left two connections on
one CTX taking different locks for a check-then-set on the same pointer.
GetCtxOcspLock() keys off ssl->ctx->cm for both the reader and the
publisher, and a failure to take it is logged instead of silently
disabling the cache.

CheckOcspRequest() also loses its heap argument. It was only ever the
hint for the response buffer it hands back, which the caller frees
against the connection, so take it from the connection rather than from
a parameter every caller had to keep in step with its own free.

Smaller fixes in the same paths: zero the caller's response buffer
before the argument check can return, since SendCertificateStatus()
frees it without checking the return code; fold the ocsp_stapling NULL
check into the single early skip so the later uses need no guard;
gate the SetupOcspResp() free on success like the other two callers;
split the three differently owned requests in the
WOLFSSL_CSR2_OCSP_MULTI case into separate variables; and let that
case's allocation failures fall through to its shared cleanup instead of
returning, which leaked an already built leaf response.

Add test_ocsp_ctx_request_cache, which runs three handshakes over one
CTX pair and checks that the later ones reuse the cached request rather
than building another. The responder callback answers with a canned good
response, so stapling runs all the way through and the ownership
decision each connection makes is actually acted on: a connection that
freed the shared request shows up as a use after free on the next pass
and a double free at CTX teardown. The cached request is marked before
the last pass and the encoded request the callback sees is compared,
since a request rebuilt from the same certificate would otherwise be
identical byte for byte. The test is gated on !WOLFSSL_COPY_CERT:
OPENSSL_ALL implies it, and it gives every WOLFSSL its own certificate
copy, which takes the cache out of play. A new ocsp.yml job covers the
plain stapling build, an --enable-all build with the copy turned back
off, and an ASan build.

Also gate test_tls13_pha_status_request on KEEP_PEER_CERT. It checks the
received client certificate with wolfSSL_get_peer_certificate(), which is
only built when that macro is defined, so a post-handshake auth build with
stapling but without the OpenSSL compatibility layer failed to link
tests/unit.test.

Fixes F-7230 and F-7231.
2026-07-31 22:02:42 +02:00
Tobias Frauenschläger 525f52bd57 Improve certificate_status_request_v2 handling
RFC 8446 Section 4.4.2.1 deprecates the status_request_v2 extension for
TLS 1.3. The server side already avoided it; on the client side, reject
it in every message type but ClientHello once TLS 1.3 is negotiated, so
TLSX_CSR2_Parse() can no longer record it. ClientHello stays allowed
because the peer may still negotiate a lower version, where the
extension does apply.

Also align the pending signer registration in the chain verification
loop with the CA checks AddCA() performs on the normal path, so the same
conditions apply on both. Register the signer as WOLFSSL_CHAIN_CA rather
than CA_TYPE while doing so. TLSX_CSR2_MergePendingCA() promotes it into
the certificate manager, and wolfSSL_CertManagerUnloadIntermediateCerts()
selects entries by that type, so a chain CA learned over a
status_request_v2 multi handshake could never be unloaded again.

Add test_TLSX_CSR2_tls13_msg_type_validation, which feeds the extension
to TLSX_Parse() in the TLS 1.3 message types that must not carry it.

Fixes F-7227.
2026-07-31 22:01:27 +02:00
Tobias Frauenschläger b844cdcce0 Merge pull request #10421 from kojo1/pha
TLS 1.3 PHA with OCSP Stapling
2026-07-31 09:07:29 +02:00
David Garske 4f92fe3e85 Merge pull request #10988 from SparkiDev/mem_zero_fixes_1
MemZero: Add more checks of buffers.
2026-07-30 15:42:10 -07:00
David Garske 643d209dba Merge pull request #10961 from anhu/crl_unknown_ext
New API for CRL unknown extension callback
2026-07-30 09:00:23 -07:00
Sean Parkinson 1106d593fb MemZero: Add more checks of buffers.
Added wc_MemZero_Add calls and wc_MemZero_Check calls wheter ForceZero is used.
Fixed a couple of places that had the wrong size.
2026-07-30 10:50:52 +10:00
Juliusz Sosinowicz 07f9b11728 Address review: cover add1_chain_cert and fix X509 leak
Cover wolfSSL_add1_chain_cert, which funnels through add0. Assert both the
chain count and the X509 reference bump so the caller's own free is proven
safe. Free the X509 when add0 fails instead of leaking it.

Place certChainCnt++ exactly as the missing_openssl_functionality branch
does. That branch carries the same fix, and with the two spellings apart
git merges both insertions without a conflict, incrementing twice.
2026-07-28 13:45:02 +00:00
Roy Carter 2b506e2526 bugfix - in TLS 1.3 handshake we're dependent on the cert chain cnt in SendTls13Certificate not updating the chain count made TLS 1.3 handshake fail and leave with leaft-only certficiate and then peer rejected the chain 2026-07-28 08:57:28 +00:00