Commit Graph
837 Commits
Author SHA1 Message Date
David Garske 1e0fa211d0 Merge pull request #10886 from night1rider/cryptocb-hooks-rsapss-ed448-cmac
Cryptocb hooks rsapss ed448 cmac
2026-08-10 15:49:05 -07:00
David Garske 14a72c96e4 wolfCrypt SRAM PUF: configurable error correction and footprint 2026-08-09 09:04:51 +02:00
night1rider 375febc944 Extend the RSA-PSS verify callback and harden the Ed448/CMAC hooks
The PSS hook can hand back the recovered block through out/outSz/outLen.
A device that reports only a verdict leaves outLen at 0; wolfSSL then
zeroes the buffer and returns saltLen + hLen, and rejects a buffer
smaller than that with RSA_BUFFER_E. A reported length is clamped to the
buffer size, and any positive handler return maps to SIG_VERIFY_E.

Move the Ed448 sign WOLFSSL_CHECK_MEM_ZERO registration below the crypto
callback hook so the device path no longer returns past it, and guard the
RSA-PSS test callback against WOLF_CRYPTO_CB_ONLY_RSA.

Adds tests for the recovered-data, over-claimed-length and undersized
buffer paths, and an os-check config that builds the hooks under
WOLFSSL_CHECK_MEM_ZERO.
2026-08-08 15:14:28 -06:00
philljj e71b086fc8 Merge pull request #10724 from dgarske/ti_c25
wolfCrypt on TI C2000 C28x (LAUNCHXL-F28P55X)
2026-08-08 14:26:28 -05:00
David Garske ea57a537c7 Merge pull request #11107 from Frauschi/gate_fix
Fix link failure with NO_SESSION_CACHE and session tickets
2026-08-07 12:16:29 -07:00
David Garske 8abc253c16 ci: name and document the three CHAR_BIT != 8 guards in ti-c2000-compile.yml 2026-08-07 12:07:42 -07:00
David Garske e2ddff61b7 Merge pull request #11105 from Frauschi/psk_fix
Send decrypt_error alert for TLS 1.3 PSK binder failures
2026-08-07 11:31:32 -07:00
David Garske 586f1ed490 Merge pull request #11096 from Frauschi/pqc_only
Support post-quantum-only (ML-KEM + ML-DSA/SLH-DSA) TLS 1.3 builds
2026-08-07 10:08:34 -07:00
Tobias Frauenschläger 41da354dc8 Add CI coverage for NO_SESSION_CACHE with session tickets
The os-check matrix had one NO_SESSION_CACHE entry, dtls13-client-minimal,
and it is client only with no session tickets. Both paths that failed to
link are server side ticket code, so nothing in the matrix covered them.

Add two entries. no-session-cache-session-ticket sets the macro directly
and enables DTLS 1.3 with WOLFSSL_DTLS_NO_HVR_ON_RESUME, covering both
call sites. It also sets HAVE_EXT_CACHE, since an external cache with no
internal one is the only configuration in which the external cache branch
of FreeSessionFromCacheOrExt() survives the preprocessor, and a build can
reach it through --enable-wpas with --enable-lowresource.

lowresource-tls13-session-ticket reaches the src/internal.c paths purely
through configure options, since --enable-lowresource defines
NO_SESSION_CACHE, which is how a user runs into this without setting any
flags by hand. It does not cover src/dtls.c, whose TlsSessionIdIsValid()
needs WOLFSSL_DTLS_NO_HVR_ON_RESUME, so the two entries are not
interchangeable.

Both disable the examples, because tests/unit.test calls
wolfSSL_get1_session() and wolfSSL_set_session(), which NO_SESSION_CACHE
compiles out. The entries are therefore compile coverage for the library.
Making the tests build in this configuration is a larger change.
2026-08-07 18:59:55 +02:00
David Garske a82f5b79c0 Merge pull request #11067 from SparkiDev/docs_user_settings_embedded_h
Documentation and embedded user_settings.h.
2026-08-07 09:14:36 -07:00
Tobias Frauenschläger ec7d2de6a2 Send decrypt_error alert for TLS 1.3 PSK binder failures
RFC 8446 Section 6.2 lists failure to validate a PSK binder under
decrypt_error, but TranslateErrorToAlert() mapped BAD_BINDER to
illegal_parameter. That told the peer its ClientHello was malformed, when
in fact the message was well formed and only the binder MAC did not match.

BAD_BINDER is also returned when no offered PSK matched and the server has
no certificate to fall back to. That reuse is deliberate, because it keeps
an unknown PSK identity indistinguishable from a failed binder, so both
conditions still map to a single alert after this change. A comment at the
return site in CheckPreSharedKeys() now records the invariant at both ends.

Splitting BAD_BINDER off illegal_parameter exposed a second path that had to
move with it. FindPsk() raised PSK_KEY_ERROR, which stays mapped to
illegal_parameter, when the server callback recognised an identity carrying
a non-zero obfuscated_ticket_age. That check ran before any binder was
derived, so on a certificate-less server the two alerts would have let an
unauthenticated peer enumerate valid PSK identities without holding a key.
The check is removed rather than made to fail differently: RFC 8446 Section
4.2.11 says that for an externally established identity an
obfuscated_ticket_age of 0 SHOULD be used and servers MUST ignore the value.
Ignoring it satisfies that requirement, closes the oracle, and lets a
conformant client that sends a non-zero age complete a handshake that was
previously rejected. test_tls13_psk_age_no_identity_oracle() asserts a known
and an unknown identity produce the same alert, with a positive control that
the known run really took the matched path.

Also removes an unreachable branch in CheckPreSharedKeys(). Since commit
089f1f7c9 added the earlier !*usingPSK certificate check, the later
certificate check and its BAD_BINDER return can no longer be reached. A
build with certificates returns BAD_BINDER earlier when none is loaded, and
a NO_CERTS build returns it unconditionally. The remaining branch now falls
through to the shared exit so WOLFSSL_LEAVE() is emitted on the certificate
fallback path as well.

Adds an os-check-linux configuration, tls13-psk-no-certs. psk.yml already
covers NO_CERTS with TLS 1.3 PSK through static-psk-lowresource-tls13, but
that config disables DH, so it only reaches the psk_ke branch. This one
leaves DH enabled and covers psk_dhe_ke under NO_CERTS.

Applications that inspect wolfSSL_get_alert_history() will observe alert 51
instead of 47 for these conditions. The affected tests are updated.
2026-08-07 15:07:51 +02:00
Tobias Frauenschläger f5f3dd4c6e Support post-quantum-only (ML-KEM + ML-DSA/SLH-DSA) TLS 1.3 builds
Allow a quantum-safe-only TLS 1.3 stack - ML-KEM key exchange with ML-DSA or
SLH-DSA authentication - with RSA, ECC and DH all disabled (the CNSA 2.0 /
EO 14412 posture).

- Treat a usable standalone ML-KEM group as a valid key exchange and
  Falcon/ML-DSA/SLH-DSA as valid authentication, so the "no cipher suites"
  #errors no longer fire (ssl.c, internal.h), and extend the CopyDecodedToX509
  pkCurveOID guard to match the struct member guards (internal.c).
- asn.c: guard the RSA/ECC-only certificate signing helpers so cert generation
  compiles with RSA and ECC disabled, while keeping MakeSignatureCb available
  for the WOLFSSL_CERT_SIGN_CB (TPM/HSM) offload path.
- tls.c: advertise the psk_dhe_ke exchange mode when a standalone ML-KEM group
  is usable on the client side, that is when the build has both key generation
  and decapsulation. Without it an ML-KEM-only build fell back to psk_ke, the
  resumption key schedules diverged, and the first AEAD record failed to
  authenticate (AES_GCM_AUTH_E), breaking session-ticket resumption.
- tls13.c: hoist the hashAlgo void cast in EncodeSigAlg out of the Ed25519 and
  Ed448 cases so a build with no classic signature algorithm still marks the
  parameter used.
- Examples and tests: add ML-DSA and SLH-DSA certificate selection (gated on
  NO_RSA so it only applies in true PQC-only builds) and default to TLS 1.3
  when no classic auth is built in and a post-quantum signature is available
  (test.h, client/server/echo*, test_tls13.c). SLH-DSA uses the SHAKE-128s leaf
  certificates and their shared 128s root.
- CI: add PQC-only entries to the pq-all.json config list (ML-DSA and SLH-DSA),
  each exercising the build, a full TLS 1.3 handshake, and ML-KEM-only
  session-ticket resumption.

Whether a build can authenticate with a post-quantum certificate is three
separate questions - is the algorithm compiled in, are test credentials wired
up for the enabled parameter set, and can this build sign - so test.h answers
them with three tiers of macro rather than testing WOLFSSL_HAVE_MLDSA and
WOLFSSL_HAVE_SLHDSA directly:

- TEST_HAVE_MLDSA_CERT_FILES / TEST_HAVE_SLHDSA_CERT_FILES: the credential
  paths name real files. ML-DSA needs an enabled parameter level; SLH-DSA needs
  a 128s parameter set, since both families share a 128s root and only those
  certificates are wired up, and PEM decoding, since the entity certificates
  ship as PEM only. Loading a certificate needs verification support alone, so
  test_tls13.c uses this tier - it only needs a certificate on the context.
- TEST_HAVE_MLDSA_CERTS / TEST_HAVE_SLHDSA_CERTS: the above, plus the ability
  to sign. A verify-only build derives WOLFSSL_MLDSA_NO_SIGN and drops private
  key support entirely, so it can neither load the key nor produce a
  CertificateVerify. The example credential ladders use this tier.
- TEST_HAVE_PQC_CERT_AUTH: either of those, plus WOLFSSL_TLS13. Both algorithms
  are TLS 1.3 only, so folding the version into the macro keeps the version
  defaults and the PSK fallbacks in the client, server and echo examples from
  disagreeing. Falcon is deliberately absent, having no credentials in the
  ladders, so a Falcon-only build keeps the historic TLS 1.2 PSK behavior.

A build that fails a gate now falls back to PSK instead of naming credentials
it cannot use, which removes two hard #errors that were reachable from
configure: --enable-slhdsa with only non-128s parameter sets broke every build
that includes test.h, even ones with RSA and ECC enabled that would never touch
an SLH-DSA credential.

Also in the credential material and the configurations this opens up:

- test.h: pair the DER ML-DSA certificate with mldsa<N>-key.der. The
  mldsa<N>_priv-only.der files are standalone PKCS#8 encoding vectors from an
  unrelated key pair, so a build without PEM decoding presented a certificate
  and signed with a key that did not match it, and the peer rejected the
  CertificateVerify.
- echoserver.c: load the SLH-DSA key with CERT_FILETYPE like every neighboring
  branch, rather than hardcoding WOLFSSL_FILETYPE_PEM against a certificate
  loaded in the build-dependent format.
- internal.c, tls13.c, ssl_load.c: mark ssl, sigOut, keyType and keySz used.
  Every reader of these sits in a per-algorithm block, so a build with no
  signing algorithm at all left them unused and -Werror rejected the library.
- tests/api.c: skip test_wolfSSL_PKCS8 unless RSA, ECC or PEM decoding is
  available. With none of them every key-loading body compiles out, leaving the
  file locals unused and nothing for the test to do.
2026-08-07 08:14:26 +02:00
Tobias Frauenschläger b1e01d6d64 Fix PKCS12 PBKDF mp variant buffer size to include password block
The mp API variant of wc_PKCS12_PBKDF_ex builds a working buffer holding
D || S || P, but totalLen was computed as dLen + sLen and so left out the
password block entirely. The fill loop writes pLen bytes starting at
S + sLen, which is past the end of the buffer, and DoPKCS12Hash was called
with the short length so the password was never absorbed into the digest.
A build with this variant enabled therefore derived the same key for every
password over a given salt, and overflowed the heap allocation or the
static buffer by pLen bytes depending on the salt length.

Sum dLen with iLen instead, matching the non-mp variant. That corrects the
allocation size, the hash input length, the I update bound and the
ForceZero coverage in one place.

Fixes F-7306.
2026-08-07 08:11:23 +02:00
Tobias Frauenschläger 9533a8182a Fix RSA_W_ENC verify guard in signature wrapper
The DigestInfo length extraction in wc_SignatureVerifyHash was compiled
only when WOLFSSL_RSA_PUBLIC_ONLY was not defined, but the block depends
on ASN.1 support, not on private key support. In a public only build the
RSA verify path stays reachable and wc_SignatureVerify still DER encodes
the digest, so the length check fell through to the plain digest size
comparison and rejected every valid signature with BAD_LENGTH_E. The
same guard also broke compilation with NO_ASN and RSA enabled, since
asn.h is not included in that case and GetSequence and GetOctetString
are undeclared.

Guard the block on NO_ASN instead, matching the DER encode call site in
wc_SignatureVerify.

Fixes F-7412.
2026-08-07 08:11:23 +02:00
Sean Parkinson f9038b7809 Documentation and embedded user_settings.h.
Added documentation of the defines for algorithms and assembly code and math.
user_settings_embedded.h has configuration defines at the top that are set to
0 for off and 1 for on. Setting these turns on the appropriate defines.
2026-08-07 15:07:27 +10:00
David Garske 80d2969348 Merge pull request #11098 from Frauschi/script_fix
Fix CI flakes from ccache saturation and stale schedule estimates
2026-08-06 18:31:03 -07:00
David Garske b7dd5bb06e Peer review fixes 2026-08-06 16:56:10 -07:00
David Garske f067cd88a2 types/ci: scope 16-bit word64 to WIDE_BYTE and add portable split-64 Keccak host test 2026-08-06 16:56:10 -07:00
David Garske 4f2fd9c23c test/benchmark/ci: CHAR_BIT != 8 test vectors, NO_MALLOC benchmark, TI C2000 compile CI and docs 2026-08-06 16:56:10 -07:00
Tobias Frauenschläger 5d2188f958 CI: build the cert sign callback path
WOLFSSL_CERT_SIGN_CB is set only by --enable-certsigncb, and that flag
appears nowhere under .github/. wc_SignCert_cb() is therefore compiled by
no CI job, and neither is test_wc_SignCert_cb(), the only test covering
it. The buffer bounds check the preceding commits add to that function,
and the test assertions that go with it, would have merged without
anything building them.

Added as its own entry in the os-check Linux config list, in sorted
position. "minutes" is seeded at 8.3 from the sibling --enable-all entries
rather than omitted: the omission defaults it to 1.0, which sorts an
eight minute build last in a list scheduled longest-first and deals it
into whichever shard is already fullest. It also suppresses the stale
estimate annotation that would otherwise prompt the refresh. Replace it
with the real number from the Minutes column of the first run.

Verified by running the entry through the workflow's own driver,
.github/scripts/parallel-make-check.py, with the CFLAGS the workflow
applies at make time (-pedantic -Wdeclaration-after-statement
-Wnull-dereference -Wno-overlength-strings
-DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE) and --private-dir=certs.
The out-of-tree build produces no compiler warnings and make check
reports 17 passed, 6 skipped, 0 failed. Both test_wc_SignCert_buffer_bounds
and test_wc_SignCert_cb run rather than skip.
2026-08-06 22:19:42 +02:00
Tobias Frauenschläger 9a788724d7 Fix CI flakes from ccache saturation and stale schedule estimates
pq-all and trackmemory restore a seed ccache that already sits at its
cap, so every object a run compiles evicts a seeded one that is still
needed. Both reported a cache 100% full with over 200 cleanups and a
43-44% hit rate, and their configs took 3-5x their warm time. That left
pq-all shards finishing at 23-26 min against a 30 min limit: a healthy
shard passed with 5.6 min to spare, so any hiccup ahead of the build
took the job down. One did, twice, when the prebuilt deb image came up
short and the dependency step fell back to apt for 9.7 min - the only
two jobs out of 47 whose install ran past 2 min are the only two that
timed out. Size both caches to hold the seeded objects and a run's own
alongside them, and widen the limits so a slow install is survivable.

Raise the trackmemory limit as well, for a different reason: its
wolfEntropy configs have overrun it outright, once with six configs
done inside 8 min while all-wolfentropy ran on for another 32. That is
a stall rather than a slow run - 91 jobs have a 17.2 min median and a
17.9 min p90, with nothing between 18 min and the cap - so the higher
limit is headroom, not a fix. It costs nothing on a healthy run.

Recalibrate "minutes", which drives longest-first scheduling and shard
balancing. pq-all and fips-dev-no-post had drifted several-fold in both
directions: two frodokem cross-builds were declared at 4 min but take
0.3, so the pool kept scheduling them first as its longest work. pq-all
is calibrated from runs whose ccache actually hit, which the resized
cache makes the normal case; a value read off a cold run makes every
warm run warn instead. os-check-linux was already calibrated cold and
correct, so only its three genuine outliers change.

Both config lists are re-sorted to restore the documented descending
order, so most of their diff is a mechanical move rather than a value
change. Shard totals come out at 29.4/29.6 for pq-all and 76.9-77.7
across the four os-check shards.
2026-08-06 18:56:15 +02: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
Daniel Pouzzner 67df4928c5 fixes from peer review, post-rebase test results, and test coverage expansion:
wolfcrypt/src/wc_mldsa.c: WC_C_DYNAMIC_FALLBACK fixes for AVX512.

tests/api/test_frodokem.c, wolfcrypt/test/test.c: fixes for WC_DEBUG_CIPHER_LIFECYCLE.

wolfcrypt/src/fe_x25519_asm.S, wolfcrypt/src/port/arm/armv8-32-aes-asm.S,
wolfcrypt/src/port/arm/armv8-aes-asm.S, wolfcrypt/src/port/arm/armv8-aes-asm_c.c,
wolfcrypt/src/port/arm/thumb2-aes-asm.S, wolfcrypt/src/sha3_asm.S,
wolfcrypt/src/wc_mldsa_asm.S: regenerate from scripts#647

.github/workflows/fips-dev-no-post.yml:
* update "minutes" for tests using empirical data;
* add --enable-experimental --enable-all-quantum-crypto to kernel-settings-all-asm scenario and rename it kernel-settings-all-pqc-asm; add all-pqc-asm-fallback-fuzzer scenario.

wolfcrypt/src/wolfentropy.c: remove WC_FIPS_LL_CRYPTO (it is not a FIPS file except in FIPS v5.2.4).

wolfcrypt/src/sha256.c: fix for rebase error (stray #endif).
2026-08-05 13:55:14 -05: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 2f15926139 .github/workflows/fips-dev-no-post.yml: add new workflow to cover --enable-fips=dev-no-post.
Notes:

* EXTRA_CPPFLAGS carries -Werror in the base configure line, because the
  autotools -Werror is gated on a VCS checkout being detected in the configure
  CWD and these are VPATH builds, which would otherwise silently get no -Werror
  at all.

* The fuzzing cell's WC_DEBUG_VECTOR_REGISTERS_FUZZING_SEED is $$, which changes
  from run to run.

* The two out-of-tree kernel-module cells (linuxkm, linuxkm-all-asm) are
  commented out, with a note that out-of-tree module builds don't work yet.
2026-08-05 13:53:47 -05:00
Daniel Pouzzner 4f2953252d .github/workflows/codespell.yml: add *.bin to skip list. 2026-08-05 13:53:46 -05: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
Tobias Frauenschläger ac7bff1147 CI: run the async software simulator against --enable-all
Nothing in CI exercised an asynchronous build that actually returns
WC_PENDING_E from a full feature set, which is why the five preceding
fixes all describe failures no workflow could see.

The async workflow has two groups and neither reaches these paths. The
asynccrypt-all entries pass --enable-asynccrypt --enable-all, but
--enable-all turns on cryptocb, and configure.ac only auto-enables the
software simulator when cryptocb, pkcallbacks, Cavium and Intel QA are all
off. Those builds therefore define WOLFSSL_ASYNC_CRYPT without ever
suspending an operation. The asynccrypt-sw entries do suspend, but they
build only OCSP stapling, so they compile neither TLS 1.3 post-handshake
authentication nor DTLS.

Add one entry that pairs --enable-asynccrypt-sw with --enable-all and
--enable-dtls13, which covers both reproducers: the post-handshake auth
case in tests/test-tls13.conf and the DTLS MTU case in
tests/test-dtls-mtu.conf.

Measured at 1.6 minutes locally. Declared as 3 to match the neighbouring
asynccrypt-all entries, which measure 1.4 locally against their declared 3,
so this machine runs roughly twice as fast as whatever those values were
taken from and 1.6 here projects to about 3.4 there. The value is only a
scheduling weight, and the existing entries are left alone rather than
rewritten from local timings.
2026-08-05 08:34:09 +02:00
David Garske e51c06e0a6 Merge pull request #10983 from Frauschi/zephyr_fixes
Zephyr: wolfSSL module support for the wolfPSA provider and native RTOS use
2026-08-04 20:04:25 -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 0ffedd2b69 Merge pull request #10971 from LinuxJedi/se050_applet72_ecdh
SE050: create ECDH derive target object for applet 7.2 middleware
2026-08-04 17:35:23 -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
David Garske 684e06df00 Merge pull request #10991 from padelsbach/ccache-init-seed-settings
CI: set ccache path so settings are saved on initial seed
2026-08-04 15:54:14 -07:00
Tobias Frauenschläger 039d689809 Merge pull request #10975 from aidangarske/x509-tiny-ci
Move WOLFSSL_X509_TINY test to the unit test suite and run
2026-08-04 23:28:52 +02: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
Paul Adelsbach 1c9ebe1af6 PR feedback: use instead of duplicating path 2026-08-04 12:06:11 -07:00
Tobias Frauenschläger 044f08c0ea Zephyr: wolfSSL module support for the wolfPSA provider and native RTOS use
Extend the wolfSSL Zephyr module for the wolfPSA-provider and secure-sockets
efforts:

  - Native RTOS threading: wolfCrypt's Zephyr port uses k_mutex/k_thread/
    k_condvar directly (no CONFIG_POSIX_THREADS), with k_condvar gated on the
    kernel version, covered by a native-threading ztest wired into CI.
  - Config interface: a user-supplied CONFIG_WOLFSSL_SETTINGS_FILE is
    authoritative and the module never layers Kconfig #defines over it. The
    module-default block is shaped by build-profile knobs (WOLFSSL_CRYPTO_ONLY,
    WOLFSSL_SINGLE_THREADED, which now defaults from !MULTITHREADING) plus new
    classic-crypto/TLS/PQC feature knobs (RSA/ECC/ChaCha-Poly/Curve25519/SNI/
    session-cache/session-ticket and ML-KEM/ML-DSA/LMS/XMSS/Falcon, each with
    its memory-reduction "small" options). A consumer such as wolfPSA validates
    its own requirements rather than the module injecting them.
  - DRBG seeding: wc_GenerateSeed() on Zephyr draws seed material from the
    hardware entropy driver when present (chunked to the entropy API's uint16_t
    length, DT_HAS_CHOSEN-guarded) and falls back to sys_rand_get() otherwise;
    HAVE_HASHDRBG stays guarded by WC_NO_HASHDRBG.
  - z_time(): read the native_sim simulator RTC for a real wall clock on the
    native targets regardless of libc.

Verified on native_sim/native/64 and nucleo_h743zi.
2026-08-04 20:53:36 +02:00
Andrew Hutchings 6176a5a77d SE050: skip peer key upload on applet 7.2 ECDH path (peer review)
The direct ECDH APDU carries the peer public point in the command, so
uploading the peer key to the SE050 on the applet >= 7.2 path wasted
APDU round trips, consumed a persistent object slot per distinct peer
in the default build, and added a failure path the derive does not
need. Confine the upload, the keyId bookkeeping and the keyCreated
cleanup to the pre-7.2 arm; on 7.2 builds a reference object is only
taken when the peer public key is already SE050-resident.

Also from review: validate the ECC direct-APDU response length against
the curve size, mirroring the Curve25519 arm; scope the derive-key
state (deriveKey, ctx_derive_key, deriveKeyCreated and their init and
cleanup) into the pre-7.2 arm instead of voiding it; and reword the CI
workflow comment to describe SE050_SIM_STRICT_ECDH as a regression
guard, noting the pre-7.2 arm is hardware-verified (SE050C applet
3.1.1) until an 03_XX matrix leg exists.

Verified: wolfCrypt suite passes against the strict simulator on the
07_02 build; the pre-7.2 arm compiles clean against an 03_XX SDK.
2026-08-04 11:42:20 +01:00
Sean Parkinson 03e9107df4 AES asm: Add GCM 8-bit table, fixes
Added assembly to do 8-bit-table GCM_gmult_len.
Wired it into aes.c and wired small to use C code.
Fixed guards around assembly.
2026-08-04 17:48:14 +10:00
Andrew Hutchings 160c616a97 SE050 CI: update pinned simulator to PR 12 head
The pinned simulator gained review cleanups; move SIMULATORS_REF to the
final wolfSSL/simulators PR #12 head. Becomes fetchable from the
upstream clone once that PR is merged.
2026-08-03 16:34:07 +01:00
Andrew Hutchings dc364d0eaa SE050 CI: pin simulator with direct ECDH variant support
Bump SIMULATORS_REF to the simulator commit that accepts the Tag7-less
direct ECDH form the port now uses on applet >= 7.2 and that refuses
HMACKey ReadObject unconditionally, both matching SE051 applet 7.2.0
hardware. The pinned commit is wolfSSL/simulators PR #12 and becomes
fetchable from the upstream clone once that PR is merged.
2026-08-03 16:34:07 +01:00
Andrew Hutchings a2bde67b70 SE050 CI: update pinned simulator to PR 11 head
The pinned simulator gained an sdk-test fix and review changes; move
SIMULATORS_REF to the final wolfSSL/simulators PR #11 head. Becomes
fetchable from the upstream clone once that PR is merged.
2026-08-03 16:34:07 +01:00
Andrew Hutchings 2ae4ec7300 SE050 CI: pin simulator that always enforces symmetric read policy
Bump SIMULATORS_REF to the simulator commit that refuses ReadObject on
an HMACKey object without POLICY_OBJ_ALLOW_READ in all modes, matching
real hardware on every applet generation as verified on SE050C applet
3.1.1 silicon. With this pin a plain (non-strict) CI run reproduces the
SW 0x6986 readback failure that previously only appeared on hardware,
covering the pre-7.2 Binary derive target fix in the previous commit.

The pinned commit is wolfSSL/simulators PR #11 and becomes fetchable
from the upstream clone once that PR is merged.
2026-08-03 16:34:07 +01:00
Andrew Hutchings 4c055f5272 SE050 CI: pin simulator with applet 7.2 read-policy enforcement
Bump SIMULATORS_REF to the simulator commit that, in strict mode,
refuses ReadObject on an HMACKey object unless the policy attached at
creation grants POLICY_OBJ_ALLOW_READ. This reproduces the SW 0x6986
derive-target readback failure seen on SE05x applet >= 7.2 hardware
(ZD 22212) and verifies the attached-policy fix in the previous commit.

The pinned commit is wolfSSL/simulators PR #10 and becomes fetchable
from the upstream clone once that PR is merged.
2026-08-03 16:34:07 +01:00
Andrew Hutchings 356aa6338b SE050 CI: correct pinned simulator commit id
The previous pin abbreviated to the right commit but the full hash was
invalid, so the simulator checkout step could never resolve it. Pin the
full commit id of the merged simulator change.
2026-08-03 16:34:06 +01:00
Andrew Hutchings 6213bbaf58 SE050 CI: pin strict simulator for applet 7.2 ECDH contract
Bump SIMULATORS_REF to the simulator commit that supports HMACKey
WriteSymmKey and the applet 7.2 ECDH InObject contract, and run the
test container with SE050_SIM_STRICT_ECDH=1 so the simulator refuses
an ECDH derive whose Tag7 target object was not pre-created. This is
the failure mode seen on SE05x applet >= 7.2 hardware and reproduces
it in CI against the unfixed port.

The pinned simulator commit also consumes the WOLFSSL_EXTRA_CFLAGS
build ARG, so the only-key-id matrix leg now really builds with
-DWOLFSSL_SE050_ONLY_KEY_ID (previously the ARG was not consumed and
the leg silently built the default configuration), and it fixes the
simulator to derive the EC public key on private-only key pair import
so wc_ecc_use_key_id can read the public part back.

Raise the job timeout for cold image rebuilds until the weekend cron
refreshes the registry cache for the new ref.
2026-08-03 16:34:06 +01:00
Tobias Frauenschläger 91769d99f6 CI: raise the os-check linux timeout and allow seeding on demand
The ccache that keeps this workflow fast is written only by the weekday
seed job, which runs on a schedule against the default branch. Nothing
had seeded it since 2026-07-24, because the workflow itself was failing
to load for that whole stretch, and the Actions cache evicts entries
untouched for seven days. The first run after the fix therefore reported
"Cache not found for input keys" on all four shards.

That cold run measured ~102 thread-minutes per shard, or 24-27 minutes
of wall including checkout, deps and autogen, against a 30 minute
timeout. Three minutes of headroom on the slowest shard is not enough,
and a shard killed by the timeout presents as a test failure rather than
as a cold cache. Raise it to 40. The comment above it claimed ~68
thread-minutes and ~20 minutes of wall, which the measurement above
contradicts, so replace it with the measured figures. macOS and Windows
are left alone: they came in at 11.6 minutes against 45 and 2.0 against
6.

Add workflow_dispatch so the seed can be run on demand rather than
waiting up to a day for the next cron, which matters exactly in the
situation above, where every PR run stays cold until something refills
the cache.

Adding the trigger alone would not have been enough. The seed behaviour
hangs off `github.event_name == 'schedule'` in five places (CCACHE_RECACHE,
--build-only on linux and macOS, the cache save, and skipping the Windows
job), so a manual run would have gone through the full test path and
saved nothing. All five now treat a dispatch as a seed as well.

The condition is written against `github.event.inputs.seed` rather than
`inputs.seed`, because the `inputs` context is only documented as
available on workflow_dispatch and workflow_call, whereas `github.event`
always exists. That yields strings, so it is compared explicitly rather
than for truthiness, where the string 'false' would read as true. It
tests `!= 'false'` and not `== 'true'` so that a dispatch which sends no
input at all still seeds: a declared default is not reliably reflected
into `github.event.inputs`, and keying on the positive would have made
`gh workflow run` quietly skip the seeding it was invoked to do.

Comments are brought in line with all of this, including one that was
already wrong before the trigger existed: the macOS ccache step is
read-only purely on pull_request, so every non-PR run writes that cache,
where the note claimed only the seed did. The two platforms seed
differently in a second way as well - linux sets CCACHE_RECACHE and so
rebuilds from scratch, macOS never does and only accumulates deltas.
Neither behaviour is changed here, but both are now written down at the
top of the file rather than left to be rediscovered from a surprising
cache.
2026-08-03 17:05:29 +02:00
Tobias Frauenschläger 641c39dbf3 CI: catch workflows that GitHub silently fails to load
A workflow file GitHub cannot load does not fail loudly. Its runs end
within 0s with zero jobs, no logs, no annotations and no check runs, and
the workflow re-registers under its bare path instead of its `name:`
field. Among the few hundred checks on a PR that reads as unrelated
flake, so the coverage just disappears: os-check.yml was in this state on
master for ten days in July 2026 before anyone noticed, and no open PR
reported a problem the whole time.

Add two guards.

Pre-merge, check-workflows.py measures every `run:` step against
GitHub's 21000 character cap and fails the build past it, with a warning
from 18000 so a growing step is noticed while there is still runway.
Sizes come from the parsed YAML, which is what the Actions service
evaluates, so block-scalar indentation needs no guessing. It runs from
check-source-text.yml over every workflow and composite action rather
than only PR-changed files: the cap applies per file, the whole sweep
takes well under a second, and a file can be pushed over the line by a
change elsewhere in the PR. Note that this cap is enforced by the
service and not by the workflow schema, so neither a YAML validator nor
actionlint reports it.

Post-merge, workflow-health.yml runs check-workflow-health.py daily and
looks for the symptom rather than any particular cause, so a workflow
that stops loading for a reason nobody anticipated is still caught. Two
signals: an active workflow whose registered name equals its path, and a
completed run that failed with zero jobs (prefiltered on
created_at == updated_at, so only a handful need a jobs lookup). Against
the live repository the first signal flags os-check.yml and nothing else
across 107 workflows, and reports clean on wolfTPM and wolfMQTT. It
exits 1 on a finding and 2 when the check could not be carried out at
all, because a missing token and a broken workflow call for different
responses.

Findings go into a single reused issue rather than another red check
that would blend into the noise: the body is rewritten on each run, a
comment is posted only when the set of affected workflows changes, and
the issue closes itself once everything loads again.

Finding that issue reliably turned out to be the fiddly part, and the
approach here is the one that survived testing against a live
repository. The issue is identified by both a dedicated label and its
title, and looked up through the REST issues endpoint. Both halves of
that identity matter: the label alone is a normal repository label that
anyone can apply, and an adopted issue has its body overwritten and is
then closed, so matching on the label alone would destroy a mislabelled
issue. Searching by title instead is unusable, because search ignores
--state and returns closed issues, which had the monitor re-closing an
already closed issue on every clean run. `gh issue list` reads a GraphQL
replica that can lag. The REST endpoint lags too, by about 2.4s for a
newly created issue, so the lookup re-checks a few times before
concluding nothing is open - without that, consecutive runs each open a
duplicate, and a clean run right after an outage fails to close the
issue it just opened.

Verified against the commit that caused the outage: check-workflows.py
fails on acff4d62a (21813 characters) and passes on its parent
f5ace71dd, which it flags at 20662 - already inside the warning band,
338 characters short of breaking. The full issue lifecycle (open,
repeat with no comment, comment on change, close, stay closed, reopen a
fresh issue for a new outage) was exercised end to end against a live
repository.
2026-08-03 17:05:29 +02:00