Commit Graph
3680 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
Tobias Frauenschläger 757f866fd8 Fix buffer overrun in SignCert when sizing the signature wrapper
SignCert() checked the output buffer with

    requestSz + MAX_SEQ_SZ * 2 + sigSz > buffSz

before handing the buffer to AddSignature(). That accounts for the outer
SEQUENCE header but not for the signatureAlgorithm AlgorithmIdentifier
(OID plus optional NULL parameters) or the signatureValue BIT STRING
header that AddSignature() also writes, an under-count of about 13 bytes.
AddSignature() takes no buffer size of its own, so any certificate whose
final encoding lands in that narrow band just under buffSz passed the
check and was written past the end of the buffer.

The same estimate was used in wc_SignCert_cb().

Both call sites now ask AddSignature() for the exact encoding size by
passing a NULL buffer first, then compare that against buffSz. This is
the two-pass idiom already used when signing CRLs in SignCrl(), in
wolfssl_x509_make_der() and in wolfSSL_X509_CRL_sign(). Both the template
and the original ASN.1 encoders support the NULL buffer sizing call.

The comparison is made unsigned, matching the pre-flight in SignCrl().
Casting buffSz to int made a buffer larger than INT_MAX compare negative
and rejected every signature for it.

Both functions also now bound requestSz against buffSz up front.
MakeSignature() and MakeSignatureCb() hash requestSz bytes out of buf
before any size check runs, so a caller passing the two mismatched got an
out of bounds read of up to requestSz - buffSz bytes before the function
returned. Only a negative requestSz was rejected before. Reaching this
needs the application to pass values that disagree, so it is API misuse
rather than attacker controlled input, but the read side now carries the
same guarantee as the write side.

Reachable from the OpenSSL compatibility layer through
wolfSSL_X509_sign() and wolfSSL_X509_REQ_sign(), where the caller
controls the certificate contents that steer the encoded size into the
band.

Adds test_wc_SignCert_buffer_bounds(), which signs into buffers sized
across the band below the exact encoding size and requires BUFFER_E and
an untouched guard region for each, while still accepting the exact size.
test_wc_SignCert_cb() gains the same check for the callback entry point,
using its RSA half where the PKCS#1 v1.5 signature is fixed length, in
both directions so that an over-conservative estimate is caught too.

The bounds test covers ECDSA as well as RSA. IsSigAlgoNoParams() drops
the NULL parameters from the AlgorithmIdentifier, so the width an
estimate under-counts by differs between the two: 24 bytes of wrapper
against the 12 byte estimate for RSA, but only 19 for ECDSA, putting the
capacities that used to be accepted and overrun within 8 bytes of the
exact size.

An ECDSA encoding size cannot be measured once and reused, because the
DER INTEGERs holding r and s change length with the leading zero bytes of
each new signature. The sweep measures a fresh reference size every
iteration and, rather than requiring BUFFER_E for a capacity that the
next signature might genuinely fit, asserts what has to hold either way:
the call returns BUFFER_E or a size within the capacity, and the guard
region past the capacity is untouched. That covers the whole band instead
of trading it away for a margin wide enough to absorb the jitter.

The prerequisites are split into one condition macro per algorithm rather
than one shared list. Gating the whole test on the RSA prerequisites
would have compiled the ECDSA sweep out of a build without RSA, which is
exactly where it is the only coverage that exists.

Both tests set an explicit serial number. wc_InitCert() leaves serialSz at
zero, so wc_MakeCert() generates a random serial, and GenerateInteger()
does not shrink the length after dropping leading zero bytes, which lets
the promoted byte carry the MSB and makes the encoder pad the INTEGER with
an extra 0x00. Measured over 200000 generated bodies, 813 of them, 0.406
percent, came out one byte longer, which would have made the swept
capacities disagree with the reference size for roughly one run in 128.
2026-08-06 08:50:30 +02: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
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 589b98ff47 Merge pull request #10957 from SparkiDev/arm32_cpuid_flags
ARM32 assembly: Get CPU Id flags to choose assembly.
2026-08-05 07:34:34 -07:00
Sean Parkinson 4444e0cf26 ARM32 assembly: Get CPU Id flags to choose assembly.
Added flag determination for Linux/Android/BSD/Windows/privilege-mode.
Made AES and SHA-256 runtime dispatch.
Updated the ARM32 assembly to support having multiple implementations compiled
in.
2026-08-05 14:45:19 +10:00
Yosuke Shimizu 9909d0226c Zero EncryptedInfo in ProcessChainBufferCRL and reset info->set on parse 2026-08-05 13:02:45 +09: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 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
Aidan Garske 82cf3d8947 Add x509 tiny certificate test coverage 2026-08-04 12:21:25 -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 8e61a110ca Only zeroize the SRP temporaries once they are initialized
In a small stack build wc_SrpComputeKey allocates six objects up front and
checks them together afterwards, so a failure of any one of them jumps to the
cleanup with the others allocated but not yet passed through mp_init_multi.
The cleanup decided whether to zeroize the four temporaries by testing the
return code against MP_INIT_E, which does not hold on the allocation failure
path, so it called mp_forcezero on uninitialized memory. That takes its length
from the size field of the object being zeroized, so an unset field turns into
a write of arbitrary length past the end of the allocation.

Track whether mp_init_multi succeeded and gate the zeroize on that instead.
The flag is only set once the objects really are initialized, so it covers the
init failure case the return code test was aiming at as well.

Add a regression test that fails the last of the six allocations through a
custom allocator and requires the call to report a memory error without
touching the objects it never initialized.

Fixes F-7084.
2026-08-01 12:04:56 +02:00
Tobias Frauenschläger f4fbf8d9e5 Keep the ECIES context heap hint across a reset
wc_ecc_ctx_new_ex records the caller's heap hint in the context and then
calls wc_ecc_ctx_reset, which goes through ecc_ctx_init. That function opens
by clearing the whole context and only restores the algorithm choices, the
protocol role and the RNG, so the heap hint was lost on every context the
_ex variant produced, and on every later call to the public reset. The
context was then freed with a null hint, so it went to the default allocator
rather than the heap it came from, and the temporary buffers that
wc_ecc_encrypt_ex and wc_ecc_decrypt take from the same hint went to the
default allocator too.

A default build hides this because XMALLOC discards the hint, but with static
memory the block belongs to the caller's pool and handing it to the system
allocator is a free of memory that was never allocated there.

Save the hint before ecc_ctx_init and restore it afterwards. Doing it in the
reset covers both the constructor and the public reset. The other callers of
ecc_ctx_init pass an uninitialized context on the stack, so the hint must not
be read there.

Add a regression test that creates a context from a static heap and requires
the heap to be whole again once the context is freed.

Fixes F-7082.
2026-08-01 11:54:40 +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 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 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
Daniele Lacamera 26ef275f82 tests: MC/DC coverage for the wolfEvent queue (wolfevent.c)
Add test_wc_WolfEventDecisionCoverage (group "wolfevent") driving the
wolfEvent / wolfEventQueue_* doubly-linked FIFO from the public API:
the queue==NULL || event==NULL guards (Push/Pop/Add/Remove, each operand
plus the all-false half), the Add first-element branch, the Remove
head/tail/sole cascade including the (event==head && event==tail) AND and
the defensive (next==NULL || prev==NULL) corruption guard, and the Poll
context-filter OR.

Guarded by HAVE_WOLF_EVENT (compiled empty otherwise). The queue core is
async-independent; it builds standalone (no WOLFSSL_ASYNC_CRYPT) now that
BUILD_WOLFEVENT is true under --enable-usersettings and wolfEvent_Poll no
longer warns on unused params in non-async builds.
2026-07-31 12:56:52 +02:00
Daniele Lacamera 45a98467e4 tests: MC/DC decision coverage for remaining wolfCrypt primitives
Add DecisionCoverage/FeatureCoverage tests and tests/unit-mcdc white-box
supplements for the remaining reachable wolfCrypt primitive sources in the
ISO 26262 per-module MC/DC campaign (excluding asn* and the EVP/OpenSSL
compat layer, which are out of the MC/DC boundary).

tests/api:
- legacy ciphers / digests: des3, camellia, ascon, blake2, siphash
- niche PK: srp, eccsi, sakke, hpke
- native PQC KEM: frodokem
- math: wolfmath

tests/unit-mcdc white-box drivers (#include the .c to reach file-static
helpers and impl-selected paths, standalone main()/WB_NOTE harness):
- blake2b, blake2s
- eccsi, sakke, hpke
- SP host backends: sp_x86_64, sp_c64, sp_c32
- infra: cryptocb (dev && dev->cb dispatch three-vector, 127/127),
  logging (per-thread + global error-queue impls, 19/19),
  memory (static-pool allocator, 46/48)

Registrations in tests/api.c, tests/api/include.am and CMakeLists.txt.
2026-07-31 12:56:51 +02: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 81a70fa275 Cosmetic - delete trailing whitespace in PR 2026-07-28 08:57:29 +00:00
Roy Carter ed9865fa80 Implement a simple test case to check the chain counter increases. 2026-07-28 08:57:28 +00:00
Sean Parkinson 9c5436b853 Merge pull request #10968 from Frauschi/fenrir_tls
Fenrir fixes
2026-07-28 11:31:19 +10:00
Sean Parkinson 19c1d07beb Merge pull request #10944 from Frauschi/tls-read-ahead
Add TLS receive read-ahead support
2026-07-28 11:16:21 +10:00
Sean Parkinson 495296a739 Merge pull request #10625 from julek-wolfssl/client-custom-ext
Add SSL_CTX_add_client_custom_ext (OpenSSL-compat client custom extensions)
2026-07-28 09:22:47 +10:00
Daniel Pouzzner 142109db24 test/:
* fixes for NO_DH;
* fixes in test_wc_ed448_import_public() and test_wc_Ed448DecisionCoverage() for FIPS v6;
* fixes in tests/api/test_sha3.c for KMAC keysize in FIPS builds.
2026-07-24 16:39:54 -05:00
Tobias Frauenschläger f60002d137 Add TLS receive read-ahead support
Add WOLFSSL_TLS_READ_AHEAD (--enable-readahead), toggled at runtime via
wolfSSL_set_read_ahead(). When enabled, the record-header read pulls a
full record in one recv() so the body arrives without a second syscall.

The receive window is configurable with
wolfSSL_CTX/SSL_set_default_read_buffer_len() (OpenSSL-compatible):
0 keeps the one-record default, a larger value coalesces several records
per recv(), a smaller value caps the per-connection buffer footprint.
Records exceeding the window are still received correctly, the buffer
grows on demand and is reallocated back down to the window afterwards so
the retained footprint stays bounded.

Includes docs, API tests, and a benchmark toggle.
2026-07-24 08:17:41 +02:00
Sean Parkinson 15afad7f8f Merge pull request #10902 from rlm2002/coverity
2020714 Coverity fixes
2026-07-24 10:38:13 +10:00
JacobBarthelmeh b3424c4df6 Merge pull request #10966 from ejohnstown/upd-ocsp
Reject CR/LF and obs-fold in OCSP requests
2026-07-23 15:07:44 -06:00
Eric Blankenhorn a9aa459053 Enforce RFC 5746 renegotiation_info in TLS 1.2 client by default 2026-07-23 12:37:02 -05:00
Sean Parkinson e6c3bb4403 Merge pull request #10827 from danielinux/falcon-native
Falcon: native implementation replacing liboqs, with crypto callbacks and ARM acceleration. Deprecate liboqs support.
2026-07-23 21:17:10 +10:00
John Safranek 6b78c5952b Reject CR/LF and obs-fold in OCSP requests
The OpenSSL compatibility APIs copied caller-supplied strings into the
outbound OCSP request verbatim, so an embedded newline split it into
attacker-chosen header lines, and a header name starting with SP or HTAB
folded into the preceding header's value. OpenSSL rejects these; the
library's own fetch path already rejects CR/LF via wolfIO_DecodeUrl().

* wolfSSL_OCSP_REQ_CTX_http(): reject CR/LF in op and path.
* wolfSSL_OCSP_REQ_CTX_add1_header(): reject CR/LF in name and value.
* wolfSSL_OCSP_REQ_CTX_add1_header(): reject a name starting with SP or
  HTAB, which RFC 7230 Section 3.2.4 treats as an obs-fold continuation
  of the previous header rather than a new header.
* wolfSSL_OCSP_parse_url(): reject CR/LF anywhere in the URL, the likely
  source of a tainted path via a certificate's AIA extension.
2026-07-22 20:47:06 -07:00
Brett Nicholas e6d86b4bbb Merge pull request #10832 from padelsbach/curve25519-cryptocb-only
Add crypto callback only mode for curve25519
2026-07-22 17:35:55 -06:00
David Garske 983e1090d7 Merge pull request #10922 from aidangarske/fenrir-asn-strict
Enforce RFC 5280 extension MUSTs under WOLFSSL_NO_ASN_STRICT and validate DTLS 1.3 legacy_session_id echo
2026-07-22 14:12:33 -07:00
Tobias Frauenschläger 03cb14a30e Stop offering SHA-1 signature schemes for TLS 1.2 by default
InitSuitesHashSigAlgo added the ecdsa_sha1 and rsa_pkcs1_sha1 signature
schemes to the signature_algorithms list based only on the build flags,
ignoring the negotiated protocol version. Because that list is also the
set a peer's signatures are validated against, any build with old TLS
compiled in advertised and accepted SHA-1 handshake and certificate
signatures for TLS 1.2, which RFC 9155 deprecates. Gate the SHA-1 schemes
on the negotiated version so they are offered only for TLS 1.0 and 1.1
handshakes, unless WOLFSSL_ALLOW_TLS_SHA1 is defined to opt back in. The
same gate excludes them for TLS 1.3, as required by RFC 8446.

Fixes F-6991.
2026-07-22 13:07:55 +02:00
Daniele Lacamera 75b7b1b366 Falcon: add tests/api/test_falcon.c API unit tests
Falcon had crypto-level coverage (KAT + native round-trip in
wolfcrypt/test/test.c) but, unlike ML-DSA and SLH-DSA, no dedicated
tests/api/ unit test exercising the public wc_falcon_* / wc_Falcon_* API
surface. This adds one, wired into the unit test runner as the "falcon"
group.

Coverage (both Falcon-512 / L1 and Falcon-1024 / L5, which are always
compiled together):
- sizes:        size/priv_size/pub_size/sig_size vs the spec constants,
                get_level round-trip, and NULL / unset-level rejection.
- make_key:     NULL and unset-level rejection; real keygen -> check_key.
- sign_vfy:     sign -> verify; wrong-message and one-byte tamper rejected;
                too-small buffer -> BUFFER_E with the required length set;
                verify with no public key -> BAD_FUNC_ARG.
- import_export: public / private-only (raw) / private (concat) / export_key
                round-trips, each re-signed or verified, plus too-small
                (BUFFER_E) and wrong-size (BAD_FUNC_ARG) paths.
- check_key:    valid pass; corrupted public copy, public-only and
                private-only keys all fail (PUBLIC_KEY_E); NULL rejected.
- der:          KeyToDer / PrivateKeyToDer / PublicKeyToDer round-trips via
                PrivateKeyDecode / PublicKeyDecode, size-query (NULL output),
                and the SetAsymKeyDer too-small contract (BAD_FUNC_ARG).
- error_paths:  exhaustive NULL / bad-level / wrong-size / no-key-set
                argument sanitising for every public entry point.

Tests requiring key generation or signing are gated on
WC_FALCON_HAVE_NATIVE_SIGN so the file also builds in
WOLFSSL_FALCON_VERIFY_ONLY and WOLF_CRYPTO_CB_ONLY_FALCON configurations;
size and argument-sanitising tests run in every HAVE_FALCON build.

Verified: 7/7 pass under both --enable-falcon-avx2 and the default
constant-time build; compiles clean with WOLFSSL_FALCON_VERIFY_ONLY.
2026-07-22 09:52:26 +02:00
Ruby Martin 568bfe4299 limit extLen to MAX_RECORD_SIZE 2026-07-21 09:50:17 -06:00
Sean Parkinson 425d8f8c2e Merge pull request #10943 from Frauschi/crl_pqc
Add post-quantum and EdDSA CRL signing
2026-07-21 15:57:06 +10:00
Daniel Pouzzner 69a994e62b Merge pull request #10945 from ejohnstown/ocsp-fail
OCSP: opt-in fail-closed on missing responder
2026-07-20 16:42:04 -05:00
JacobBarthelmeh e19a1a4dc4 Merge pull request #10912 from danielinux/mcdc-test-coverage
MC/DC coverage for wolfCrypt modules - Part 3
2026-07-20 10:10:39 -06:00
Tobias Frauenschläger c30e8d6116 Add post-quantum and EdDSA CRL signing via wc_SignCRL_ex2
CRL signature verification already supported post-quantum algorithms
through the shared ConfirmSignature() engine, but CRL generation did not:
wc_SignCRL_ex accepted only RSA and ECC keys and sized its signature
buffer for a classic signature.

Add wc_SignCRL_ex2, which takes an untyped key plus a keyType selector,
the same scheme wc_MakeCert_ex and wc_SignCert_ex use. It resolves the key
and reuses the existing CheckSigTypeForKey, GetSignatureBufferSz and
MakeSignature helpers, so the signature buffer is sized from the key and
post-quantum signatures get enough room. wc_SignCRL_ex keeps its original
RSA/ECC signature and becomes a thin wrapper, preserving the public API.

This enables CRL signing with ML-DSA, SLH-DSA, Ed25519, Ed448 and Falcon.
Stateful hash-based schemes (LMS/XMSS) are rejected with ALGO_ID_E, since a
CRL is reissued periodically and would exhaust the key's one-time signature
state. Under WOLFSSL_NO_MALLOC the signature must still fit the fixed
CertSignCtx.sig buffer, consistent with the certificate signing path.

Tests cover CRL sign and verify through the certificate manager for ML-DSA
(44/65/87), SLH-DSA (SHAKE and SHA2 128s), Ed25519 and Ed448, plus negative
cases for a tampered signature, a sigType and key-family mismatch, and
rejection of LMS/XMSS.
2026-07-20 14:05:45 +02:00
JacobBarthelmeh c1ee61c8d1 Merge pull request #10888 from SparkiDev/kmac_cshake
KMAC and cSHAKE: Add new algorithms
2026-07-17 16:49:25 -06:00
John Safranek ae0bac50c9 OCSP: opt-in fail-closed on missing responder
WOLFSSL_OCSP_CHECKALL is a scope flag ("always leaf, but all ?"), selecting
which certs are checked, not how hard to fail when one advertises no OCSP
responder in its AIA. Treating a missing responder as a hard failure breaks
any chain whose CA publishes no OCSP URI (e.g. Google GTS WR2), a
configuration that only grows as CAs drop responders. Strictness belongs in
its own opt-in flag.

- Keep CHECKALL scope-only; a cert with no responder soft-fails by default.
- Return distinct OCSP_NO_URL for "no responder", separate from a failed
  lookup; stapling response handling stays best-effort (mapped to CERT_GOOD).
- Add WOLFSSL_OCSP_FAIL_IF_NOT_SUPPORTED (via OcspNoUrlPolicy) to refuse such
  certs; independent of CHECKALL.
- Add test_ocsp_no_url_policy covering both halves.
2026-07-17 13:21:01 -07:00
John Safranek 6f087a502e OCSP: opt-in SSRF screening of AIA responder
- Add wolfIO_OcspDestAllowed(); block internal-range responder hosts
- Call it in EmbedOcspLookup before connect (CWE-918)
- Gate on WOLFSSL_OCSP_SCREEN_RESPONDER (off by default)
- Add unit tests and CI for both resolver paths
2026-07-17 13:11:16 -07:00
Paul Adelsbach 2bc5d47ec3 Add missing checks for WOLF_CRYPTO_CB_ONLY_CURVE25519, add test case for no swdev 2026-07-17 10:00:54 -07:00
philljj dc1c77e079 Merge pull request #10830 from padelsbach/ed25519-cryptocb-only
Add crypto callback only mode for ed25519
2026-07-17 11:42:31 -05:00
Sean Parkinson 607d7cfdb3 FrodoKEM: Initial implementation
Supports Fast C code, small C code, small stack and assembly for x86_64, Aarch64, Aarch32, Thumb2.
2026-07-17 22:38:55 +10:00
Daniele Lacamera 9509583f65 tests: drive read_write_ex shutdown to completion instead of fixed sequence
test_wolfSSL_read_write_ex hard-coded the close-notify exchange as
NOT_DONE/NOT_DONE/SUCCESS/SUCCESS, which is protocol-version/config dependent
and fails under the cmake old-TLS build. Loop wolfSSL_shutdown on each side
until WOLFSSL_SUCCESS (pre-existing flake, not from this PR's new tests).
2026-07-17 08:56:03 +02:00
Daniele Lacamera 6859a144cb tests: MC/DC coverage for remaining wolfCrypt modules (Part 3)
Adds/extends tests/api MC/DC DecisionCoverage + FeatureCoverage and
tests/unit-mcdc white-box supplements for the remaining wolfCrypt
primitives (first-pass per-module union; gap-closing to follow):

- classic bigint: tfm.c, integer.c (extend test_wolfmath.c; tfm/integer whiteboxes)
- coding.c, error.c, wc_encrypt.c, pwdbased.c
- ed448.c + curve448.c (shared fe_448/ge_448 backends; ed448 whitebox)
- random.c deepened + new wolfentropy.c (MemUse SP800-90B), whiteboxes
- hash.c, kdf.c, signature.c, chacha20_poly1305.c
- LMS/XMSS (wc_lms*.c, wc_xmss*.c) with impl whiteboxes
- ML-KEM (wc_mlkem*.c), ML-DSA (wc_mldsa.c), SLH-DSA (wc_slhdsa.c) with whiteboxes

New tests register in tests/api.c + tests/api/include.am. Frozen-module
guards (!HAVE_SELFTEST && !HAVE_FIPS) applied to new random.c/pwdbased.c
tests that call post-v4.1.0 symbols.
2026-07-17 08:56:03 +02:00