myEccKeyGen() generated the key share straight into the library's key object,
and myEccSharedSecret() is handed only the peer's key, so a TLS 1.3 client had
no private key left to reach and every handshake ended with:
wolfSSL_connect error -170, ECC input argument wrong type, invalid input
TEST_PK_PRIVKEY already kept the key on the application's side, which is what
a real PK-callback application does anyway; it just was not the default. Keep
it whenever the connection is TLS or DTLS v1.3 as well, and have the shared
secret callback pick the key by the same question its key gen asked, not by a
flag key gen has not set yet. The union holding it stops being
TEST_PK_PRIVKEY-only, and its comment stops naming TLS v1.2 as the version
that needs it.
Neither example zeroed its PkCbInfo, so hasKeyGen started as stack garbage.
Only the TEST_PK_PRIVKEY paths read it before, which hid that; zero it in
both.
scripts/pkcallbacks.test only ever ran the build's default version, and that
is TLS v1.2 wherever it is compiled in, so none of the above was covered. Run
the default and then each version the build has.
scripts/external.test connects to www.wolfssl.com without a server_name
extension, so the CDN in front of that host answers with its own default
certificate rather than the wolfSSL one. That chain currently runs through
the RSA-4096 GlobalSign Root R46, while the intended chain is RSA-2048
throughout, so the test only passes on builds able to verify a 4096-bit
signature.
Two PRB configurations fail on master because of it. The fastmath leg with
FP_MAX_BITS=6144 reports BUFFER_E, and the 32-bit leg reports
ASN_SIG_CONFIRM_E because a build without WOLFSSL_X86_64_BUILD,
WOLFSSL_AARCH64_BUILD or OPENSSL_EXTRA defaults SP_INT_BITS to 3072. Both
are correct refusals to handle a key larger than the build supports, so the
test, not the library, is what needs fixing.
Name the host with -S in both client invocations. The option is a no-op
where the build lacks SNI, so those configurations keep their current
behavior, and the check uses the client's own "-S check" probe to decide.
Verified by building master with CFLAGS=-DSP_INT_BITS=3072, which
reproduces the BUFFER_E failure, and confirming the test passes with this
change in the same build and in an --enable-all build.
Fix guard around inclunde of chacha20_poly1305.h in internal.h for when
session ticket is not ChaCha20-Poly1305.
Fix port allocation and readiness testing in scripts.
Fix other issues in the scripts as well.
Update test.h code around ready file.
For LTO compiles, all functions must be used.
Make sure the assembly functions are marked as 'used' when not called
internally.
Fix a race in the example client that intermittently failed
scripts/unit.test on TLS 1.3 non-blocking session resumption.
RISC-V 64-bit: s0 needed but functions need to omit frame pointer.
Have source matching generated code again.
snifferWorker() looped while the shutdown flag was clear and only then
drained its queue. Reading a capture file, main() enqueues every packet
and then sets that flag and joins, normally all before the worker thread
is scheduled for the first time, so the worker woke up, saw the flag and
returned without decoding a single packet. Instrumenting the loop shows
it exiting with zero iterations and a non-empty queue, at -O0 as well as
-O1, so this is an ordering race rather than a hoisted load.
Keep going after shutdown for as long as packets are queued. The check
has to be its own helper that takes the worker's semaphore, because a
placeholder head means an empty queue: looping on worker->head alone
would spin forever on a placeholder nothing will ever fill. shutdown and
unused are polled across threads, so mark them volatile.
That alone left -keylogfile broken in this build. The sniffer's server
and secret tables are thread local, so every worker has to repeat the
setup main() did for itself, but the workers only ever called load_key()
and so reported every packet as coming from an unregistered server. Carry
the keylog path in SnifferWorker and load the secrets and create the
keylog sniffer server per worker.
Verified with --enable-sniffer CFLAGS=-DTHREADED_SNIFFTEST: the whole
sniffer test suite passes, and the multi-session captures decode the same
application data at 1, 2, 4 and 8 threads as they do without threading.
curve25519 blinding is enabled by default for the C implementation, in
settings.h, and draws from the private key's own RNG on every shared secret.
The sniffer built its key with wc_curve25519_init_ex() followed by
wc_Curve25519PrivateKeyDecode(), and neither sets one, so the shared secret
reached wc_RNG_GenerateBlock() with a NULL RNG and came back BAD_FUNC_ARG
while every argument it was given was valid. SetupKeys() then reported a
server and client key mismatch and no X25519 session could be read at all.
The library's own static ephemeral path already calls
wc_curve25519_set_rng() under the same guard, and the sniffer already calls
wc_ecc_set_rng() for the ECC key a few lines above. Only X25519 was missed.
Regenerate the two X25519 captures. Both were committed as a bare 24 byte
pcap header with no packets in them, so those legs had never tested anything;
they now hold real traffic and fail against the unfixed sniffer.
Drop the has_packets guard added earlier in this branch. It existed to skip
the empty captures, and with every capture holding packets it is dead code.
Removing it is also the better behaviour: snifftest already fails a capture
that yields no plaintext, so an empty file now fails the suite loudly instead
of being skipped, which is what a missing fixture deserves.
Hand the corrected plaintext length to the WOLFSSL_SNIFFER_STORE_DATA_CB
callback. The previous commit fixed the length only for the branch that
copies into the caller's buffer; the callback branch still passed the raw
record size, which spans the explicit IV, the tag or MAC and any padding.
The callback pointer already points at the start of the plaintext, so the
extra bytes run off the end of the decrypt output buffer, which leaves only
a record header of slack. AddressSanitizer reports a heap-buffer-overflow
read of 68 bytes on a TLS 1.2 CBC capture before this change and is clean
after it.
Reject a non-empty encrypt_then_mac extension in the ServerHello. RFC 7366
section 3.1 specifies empty extension_data and TLSX_EncryptThenMac_Parse
enforces it, as do the neighbouring length-constrained cases in the same
switch.
Clear the Encrypt-Then-MAC decision at the start of every ServerHello.
Nothing reset it, so a renegotiation that dropped the extension kept
stripping a MAC that was no longer there, and one that added it started
stripping while the previous cipher was still active.
Reset the decrypted flag at doMessage and gate the padSz subtraction on it.
The flag is set inside the decrypt block and was never cleared, so it
described whichever earlier record in the packet had last been decrypted.
The handshake case already guards the same value with it.
Set the decoded-data flag on the WOLFSSL_ASYNC_CRYPT drain path too. A
record that goes pending is completed inside SnifferAsyncPollQueue rather
than DecodePacket, so an async build could decrypt a capture correctly and
still report that nothing was decrypted. Send that diagnostic to stderr
rather than into the decoded output, and note the exit status in the usage
text so a wrapper is not surprised by it.
Add a TLS 1.2 CBC Encrypt-Then-MAC capture and the sniffer-gen.sh recipe
that produces it, so the fix has a regression test that can be regenerated.
The existing static RSA and IPv6 captures exercise the same path but no
script in the tree can rebuild them. The new capture covers both failure
modes: with an HMAC-SHA1 suite the old code fails the decrypt outright,
and with HMAC-SHA256, whose MAC is a multiple of the block size, it
silently decrypts the wrong byte range and emits 48 bytes where 14 are
correct.
Warn when the Encrypt-Then-MAC gate drops the TLS 1.2 CBC captures, so a
build configuration that loses coverage says so, and regenerate the keylog
reference output with a binary that carries the new feature token.
The sniffer ignored the encrypt_then_mac extension (RFC 7366) in the
ServerHello. For a CBC suite that meant the trailing MAC was handed to the
block decrypt along with the ciphertext, so the length was not a multiple of
the block size and every record failed with BAD_FUNC_ARG. wolfSSL peers
negotiate Encrypt-Then-MAC by default, so no TLS 1.2 CBC capture taken from
one could be decrypted. Record the extension and remove the MAC before
decrypting.
The plaintext length returned to the caller, printed by snifftest as
SSL App Data(packet:length), came from the record size without subtracting
what DecryptMessage() had already worked out in ssl->keys.padSz. A 14 byte
payload was reported as 30 under TLS 1.2 AES-GCM and as 31 under TLS 1.3.
Subtract padSz so the sniffer removes the same bytes the ordinary read path
removes from ssl->curSize.
Both failures were invisible because the tests could not fail. snifftest
overwrote hadBadPacket on every packet instead of accumulating it, so errors
early in a capture were erased by later good packets and the process still
exited 0. The keylog leg read $? after a pipe into tee, which reports tee's
status rather than snifftest's. Accumulate the flag, use PIPESTATUS, and
treat a saved capture that yields no plaintext at all as a failure.
The two static RSA captures decode correctly again and the keylog reference
output is regenerated from the checked-in pcaps, which had drifted by a
packet since the files were last produced on 5.6.3.
The X25519 legs are skipped: both captures are in the tree as a bare 24 byte
pcap header with no packets. sniffer-gen.sh could never produce them because
its configure line for those two builds without ed25519, so the example
client and server fail to load their certificates and tcpdump writes an empty
file. Add the missing option, and pin the group with --disable-mlkem so the
capture negotiates X25519 rather than the X25519MLKEM768 hybrid the static
key does not match. Regenerating them is left out of this change: the sniffer
cannot yet derive the shared secret for an X25519 static ephemeral key, which
is a separate defect.
The negative tests accepted any non-zero client status, and the openssl.test
capability and protocol probes read only a command's output. A run killed by
timeout(1) therefore looked like the certificate rejection, auth failure or
missing feature each site was testing for, and the script still reported
success with the coverage silently dropped.
Check for the timeout statuses (124, and 137 for the SIGKILL used here)
before interpreting a result:
- trusted_peer.test: the three wrong-CA / wrong-peer rejection cases
- tls13.test: cipher mismatch, mutual auth, and the version downgrade cases
- psk.test: the no-peer-cert rejection case
- openssl.test: the seven wolfSSL/OpenSSL certificate capability probes and
the SSLv3, TLS 1.0 and TLS 1.1 connection probes
openssl.test sets IFS=: around its cipher suite loops, so an unquoted
$TIMEOUT_KILL_2M inside them did not split back into separate words and
the shell looked for a command literally named "timeout -s KILL 2m".
Every wolfSSL client run in do_wolfssl_client() then died with "command
not found", which the script reported as a failing cipher suite.
Use an array, whose expansion does not depend on IFS, and keep a
flattened copy for the two eval call sites, where the shell re-parses the
string and IFS does not apply.
Three ways the bounds added here failed to do their job:
- get_first_free_port ended the scan cap with 'exit 1', but every caller
runs it in a command substitution, so only the subshell died. The port
variable came back empty, the next $((port + 1)) evaluated to 1, and the
run limped on to a confusing wait_for_readyFile failure. Forcing the cap
on ocsp-stapling.test: before, the script ran on and hung until an outer
timeout killed it; now it exits 1 at the error. Return instead, and check
the status at all 25 call sites across the six scripts.
- The macOS timeout shim was a shell function. Backgrounding a function
forks a subshell, so $! was the subshell and cleanup killed that while
the server it was meant to stop leaked. Use a prefix variable that
expands to nothing when timeout(1) is absent, keeping $! the real pid.
- timeout -s KILL exits 137, not 124. Sites that read $? and treat any
non-zero as 'feature not compiled in' turned a hang into exit 0, so the
bound made a hang less visible than before. Add timed_out() and check it
before those skip branches; use it for the version probes too, which
matched any status >= 124.
The 'Bad SSL version' probes branch on grep's status, so a client
killed by the 2m timeout read as 'TLS v1.2 supported' and ran the
wrong branch. Take both statuses from PIPESTATUS and fail loudly on
a probe timeout.
- tls13.test: take the client's exit status from PIPESTATUS[0]; $? after
the pipe was tee's status, hiding a client failure or 2m-timeout kill.
- ocsp-responder-openssl-interop.test: only escalate to SIGKILL if the
responder is still running, and make the reap counter local.
A test script that blocks forever burns the CI job's full
timeout-minutes with no logs. e82ecdff93 and 5c5cbd3094 bounded the
waited-on servers; this covers the remaining hang classes in
scripts/*.test:
- Wrap foreground example client/server, openssl s_client, and
openssl ocsp invocations in "timeout -s KILL 2m". A client wedged
before or without a live peer (e.g. blocked in first-seed entropy
gathering, or DTLS with no reset from a dead peer) is not bounded
by its peer's timeout.
- Add the macOS timeout() fallback shim to scripts that now use
timeout.
- Bound the get_first_free_port scan loops (nc -w 1, 100-port cap).
- Add -w 1 to the remaining nc probes and dtls.test UDP pcap markers.
- ocsp-responder-openssl-interop.test: bound the responder reap in
cleanup: give each responder 5 s to exit after SIGTERM, then
SIGKILL before waiting, so a wedged responder cannot hang the EXIT
trap.
- benchmark.test: bound the clients but leave the -i servers
unwrapped: the script ends them with kill -6, which timeout(1)
does not forward, so wrapping would orphan the server.
- trusted_peer/tls13: kill the server with SIGTERM instead of
SIGKILL in cleanup so the signal forwards through the timeout
wrapper to the wrapped server.
SendTls13Certificate keeps its chain walk cursor in the function locals len,
idx, offset and p, but the only state that survives the WANT_WRITE return of a
non-blocking send is ssl->fragOffset, and that is consulted for the leaf
certificate alone. A send that blocked part way through the chain therefore
re-primed the walk on the next call and copied the chain from its first byte
again. The byte count still matched the announced payload size, so the message
stayed well formed on the wire while the tail of the chain was replaced by a
repeat of its head, and the peer rejected it with BUFFER_ERROR.
Rebuild the cursor from ssl->fragOffset when a resume lands inside the chain.
NextCert reads each entry's three byte length prefix and skips it, so passing
over the entries already sent costs one hop per certificate and only happens on
a resume. Guard the extension index bump the same way the send loop does, so
builds without certificate status request keep the leaf extension size.
Track the size of the chain entry being written in its own variable rather than
folding the extension size into len once the entry completes. The send loop
detected completion with offset == len + OPAQUE16_LEN and kept that check
honest by adding extSz[extIdx] - OPAQUE16_LEN to len at the end of an entry, so
until then len held the raw certificate length and the check read as complete
whenever a fragment boundary landed exactly OPAQUE16_LEN bytes into a real
extension. The walk then jumped to the next certificate in the middle of the
current one. entrySz records len + extSz[extIdx] when the entry is picked up,
len keeps the raw certificate length AddCertExt expects, and both the resume
and the ordinary multi fragment path test the same condition.
The stapled chain in scripts/ocsp-stapling_tls13multi.test reproduces the entry
size case with the server records held to 1482 bytes: the boundary falls two
bytes into an 1837 byte OCSP extension and the handshake fails, while 1480,
1481, 1483 and 1484 all pass.
Reaching this needs a certificate message larger than one record, which is why
it stayed dormant with classic certificates. Add SLH-DSA scenarios with
simulated WANT_WRITE, for server and for mutual authentication, to
tests/test-tls13-slhdsa-entity-128s.conf.
The same resume path mishandles the stapled OCSP responses. WriteCSRToBuffer
fills extSz[] only for the entries whose buffer it allocates, so on a resumed
call every entry that still held a buffer, the one being written and all that
follow it, kept the OPAQUE16_LEN default of an empty extension. The message
length, the entry sizes and the extension bytes written for those entries were
all derived from that default. Recover the size from the extension length
already written into the buffer instead.
SetupOcspResp appends a fresh request per certificate on every call, so a
message that resumed often enough exhausted the extension array and the
handshake ended with MAX_CERT_EXTENSIONS_ERR. Look the responses up once, when
the message starts, and reuse them for the rest of it.
A resumed call also reallocates the extension buffers of the entries it has
already sent, and the walk passes over those entries without writing them
again, so free them there. Free the array in wolfSSL_ResourceFree as well:
nothing released it when a connection ended part way through a Certificate
message, which leaked one OCSP response per unsent entry.
Test case 8 of scripts/ocsp-stapling_tls13multi.test covers all three. A
maximum fragment length of 512 bytes splits the stapled message over about
twenty records and the server blocks on every one of them; without these fixes
the handshake fails with MAX_CERT_EXTENSIONS_ERR.
The scripts that wait for a server to publish its ready file declare
counter at file scope and never reset it, so the retry budget is shared
by every server start in the script instead of applying to each one.
Once the early cases have used it up, every later create_port() falls
straight through to "NO ready file ending test", kills a server that was
starting normally, and the client then fails with "port number cannot be
0". Retry loops do not help, since the budget is already spent when they
run.
The failure needs only a build whose server start-up is slow enough to
consume a few tenths of a second each time. It showed up in the FIPS
dev-no-POST kernel-settings-all-pqc-asm job, where the server pays for
the CASTs, the PQC algorithms and the vector-register fallback fuzzer:
psk.test gave up after exactly 20 waits and tls13.test after exactly 51,
both the full script budget rather than a per-case one.
Reset counter where the wait begins, which is what the ocsp-stapling
scripts already do. Reproduced with a wrapper that delays the server by
one second: psk.test then fails on its third case before the change and
passes after it.
wolfSSL removed liboqs: Falcon is now provided natively by wolfCrypt, and
--with-liboqs is a deprecated no-op (configure.ac). A build therefore no
longer links liboqs, so recording it as an SBOM dependency is dead code and
the SBOM integration CI (which asserted a liboqs dep package) failed.
Remove the liboqs dependency throughout:
- scripts/gen-sbom: drop DEP_META['liboqs'] and the --dep-liboqs flag.
- Makefile.am / configure.ac: drop --dep-liboqs "$(ENABLED_LIBOQS)" and the
now-unused AC_SUBST([ENABLED_LIBOQS]).
- .github/workflows/sbom.yml: drop the liboqs install / --with-liboqs steps
and the liboqs dep assertion; keep the native-Falcon build so the
HAVE_FALCON build-property capture is still exercised.
- scripts/test_gen_sbom.py: drop the liboqs-specific tests, guard against
the key reappearing, and use openssl as the example dep elsewhere.
- doc/SBOM.md: drop the --dep-liboqs / liboqs dependency references.
Make the canonical SBOM fragment a true superset of the vendored copies
so it can be re-vendored to every product without regressions.
Products whose feature macros live in config.h (via AC_DEFINE) keep the
existing behaviour: the recipe derives them from a CC -dM -E dump with
AM_CPPFLAGS/AM_CFLAGS/CFLAGS and a force-included SBOM_CONFIG_H.
Products whose feature flags are NOT in config.h (wolfMQTT, wolfTPM,
wolfscep, which record them in a generated options.h) can now set
SBOM_OPTIONS_H to point gen-sbom at that header directly. When unset the
compiler-dump path is used exactly as before.
This folds the options.h capture that had diverged into the wolfMQTT/
wolfTPM/wolfscep copies back into the single source of truth, while
retaining the SBOM_CONFIG_H override, AM_CFLAGS/CFLAGS capture and
$(docdir) install those copies were missing.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Use Automake's $(docdir) for sbomdir so a --docdir override is honoured,
match tab/space in the wolfSSL version parse ([[:space:]]), document the
GNU-make requirement and the intentional install/uninstall-sbom
asymmetry, and widen the SBOM workflow pull_request filter to '**' so PRs
onto release/** base branches also run.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Add the canonical scripts/sbom.am shared Automake SBOM recipe that
downstream wolfSSL-stack products vendor, and ship it via EXTRA_DIST.
Capture AM_CFLAGS/CFLAGS (not just AM_CPPFLAGS) and make the config
header path overridable (SBOM_CONFIG_H) so products that carry feature
-D flags in AM_CFLAGS or place config.h in a subdirectory record their
real build configuration.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
- gen-advisory: honour explicit per-version status when defaultStatus is
"affected", so unaffected/fixed releases are no longer marked vulnerable
- gen-advisory: fail loudly when a CVE record has no non-empty English
description (CSAF/CycloneDX note text is required, minLength 1)
- gen-advisory: note that --cve-id fetches from the CVE Services API
- bomsh_verify: scope the object-store shape check to sha1, matching the
sha1 gitoid hashing (drop the unreachable sha256-length branch)
- Makefile.am: fail `make bomsh` early when python3/pyspdxtools are absent;
quote $(ENABLED_LIBZ)/$(ENABLED_LIBOQS); consolidate clean-local so the
omnibor/ and advisories/out/ build dirs are removed on clean
- tests: cover the defaultStatus fix, the _bucket_for unknown-state
hard-fail, and a csaf_validate.mjs runner self-test wired into CI
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Add an openssl entry to DEP_META (Apache-2.0, OpenSSL 3.x git-tag purl)
and a --dep-openssl flag so OpenSSL-compat products (wolfProvider,
wolfEngine) can record OpenSSL as a dependency component alongside
wolfSSL. Update tests.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Recognize the "GPLv3"/"GPLv3+" short form so downstream LICENSING files
map to GPL-3.0-only instead of NOASSERTION. Add --dep-wolfssl, a wolfssl
DEP_META entry, and --name-derived project URLs. Update tests.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Add tooling to produce Software Bills of Materials and build provenance
for wolfSSL, supporting EU Cyber Resilience Act (CRA) obligations.
SBOM generation:
- New `make sbom` target producing SPDX 2.3 output with NTIA minimum
elements, urn:uuid document namespaces, and SPDX LicenseRef compliance.
- Reproducible library discovery across autotools and CMake builds, with
liboqs recorded as a linked artefact.
- Standalone `scripts/gen-sbom` for embedded / RTOS / custom-builder
flows that do not use the main build system, plus --srcs-file,
--no-artifact-hash, and hash-source options.
Build provenance (OmniBOR / bomsh):
- End-to-end bomsh tracing of the built binaries with ArtifactID
insertion, snapshotting the traced library before libtool relink and
hashing the bomsh-traced binary.
- `scripts/bomsh_verify.py` to validate provenance against the traced
gitoid.
Security advisories:
- `scripts/gen-advisory` generating CSAF 2.0 and CycloneDX VEX, with a
`make` target, VEX overlay schema/example, and CWE name data.
Docs, tests, and CI:
- doc/SBOM.md and doc/CRA.md, plus README/INSTALL updates.
- Unit and regression tests for gen-sbom and gen-advisory.
- New sbom.yml and advisory.yml workflows: SPDX validation via
pyspdxtools, CSAF validation, bomsh provenance verification, SBOM
artifact archiving, macOS coverage, and actions pinned to SHAs.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Scrub the temporary "FN-DSA" name and the "FIPS 206" designation from all
in-tree comments, build text, and message strings, leaving the algorithm
named only as "Falcon". The eventual standardized name is not announced.
The differential known-answer test message ("wolfSSL FN-DSA differential
KAT") is a signed input, so the Falcon-512/1024 public keys and signatures
in wolfcrypt/test/test.c (and the mirrored Falcon-512 vector in
IDE/m33mu-falcon-verify/kat.h) were regenerated with liboqs over the new
message "wolfSSL Falcon differential KAT", preserving the differential
property (liboqs-produced signatures verified by the native verifier).
Verified: testwolfcrypt Falcon test passes; the m33mu verify-only harness
passes (BKPT 0x7f) with the regenerated vector.
Add a complete native Falcon post-quantum lattice signature implementation to
wolfCrypt, replacing the liboqs wrapper. Full key generation, signing and
verification for Falcon-512 (level 1) and Falcon-1024 (level 5).
- Public API wc_falcon_* / falcon_key in falcon.c wraps the native core
(falcon_native_* in wc_falcon.c) plus wc_falcon_{fpr,fft,poly,sampler,
codec,keygen,sign,bigint}.c. No liboqs dependency.
- Portable, constant-time integer-emulated floating-point (fpr) backend is
the default; opt-in per-architecture acceleration:
--enable-falcon-double inline native double
--enable-falcon-asm x86-64 SSE2 out-of-line fpr asm
--enable-falcon-avx2 x86-64 AVX2 (4-wide) FFT
- Division-free (Barrett) integer NTT on the verify path, so no hardware
divide is required on Cortex-M / embedded targets.
- Verify uses a cached twiddle-factor NTT; signing uses the FFT / ffLDL tree
and discrete Gaussian sampler over the abstract fpr seam.
- test.c falcon_test (KAT verify + native keygen/sign/verify roundtrip);
scripts/falcon-interop.c and a CI workflow cross-check native<->liboqs in
both directions.
Added support for encoding and decoding keys in ASN.1.
Added support for X.509 certificates and CSRs.
Generated certificates and CSRs. Not fo FrodoKEM-640 as is not in the specs.
The keylog reader used fscanf with three whitespace delimited tokens,
which is not line aware. RFC 9850 Section 1 requires readers to ignore
empty lines and lines whose first character is '#', and Section 2
recommends ignoring lines that do not conform to the format so secrets
can still be recovered from corrupted files. A comment line such as
"# note" was parsed as three fields spanning the line boundary, which
desynchronized the rest of the file.
Read one line at a time with fgets, skip empty and comment lines, and
parse each line with sscanf, skipping any line that does not yield the
three expected fields instead of aborting. Clear the field buffers each
iteration so a short field cannot pick up stale bytes from a previous
line, validate that the fixed length client random field is the exact
expected length, and leave the secret length variable because it depends
on the negotiated hash. Zero the new line buffer on every return path,
matching the existing ForceZero handling of the secret buffers.
Add a comment line, a blank line, and a malformed line to the TLS 1.3
keylog test data so the sniffer keylog test exercises the skip paths.
PRB nodes intermittently fail google.test with 'tcp connect failed:
Connection timed out' while www.google.com still answers ping and
www.wolfssl.com:443 (external.test) connects fine: Google drops or
throttles TCP connections from busy CI egress IPs, so the existing
ping reachability guard does not catch it.
Failing to even open the TCP connection exercises no wolfSSL code, so
treat it like the unreachable-server case and skip (77) instead of
failing. TLS-level failures still fail the test.
timeout(1) is GNU coreutils and is not installed on macOS, so the
"make check macos" job failed with "timeout: command not found" for
every wrapped server. Add a small shim to each affected test: when
timeout is unavailable (e.g. macOS) run the server unbounded, restoring
the prior macOS behavior. The flaky hang the timeout guards against is on
the Linux-only trackmemory job, so macOS does not need the bound.
Several test scripts share the same pattern as ocsp-stapling_tls13multi:
a backgrounded example server is "wait"ed on with no timeout, so a
server that flakily fails to exit blocks the script until the CI job
timeout. Wrap those servers in "timeout -s KILL 2m" as well.
Scripts: ocsp-stapling, ocsp-stapling2,
ocsp-stapling-with-wolfssl-responder, crl-revoked, tls13, resume,
pkcallbacks, dtlscid.
Test cases 6 and 7 background the example server and then "wait" for it
to exit. When the server occasionally fails to exit (a timing race under
heavy parallel CI load), the script blocks until the job's
timeout-minutes, cancelling the whole trackmemory run - seen
consistently on the all-wolfentropy config.
Wrap those two servers in "timeout -s KILL 2m" (as scripts/dtls.test
already does) so a stuck server is killed and the test fails fast instead
of timing out the whole job.
Replace the one-runner-per-configuration matrices across the
make-check workflow family with a generic pooled runner,
.github/scripts/parallel-make-check.py. Each workflow keeps its
configuration list as JSON next to the invocation; one runner (or a
small fixed set of shards, balanced by measured per-config minutes)
builds every config in its own out-of-tree (VPATH) build directory off
a single checkout/autogen, on a pool of one-per-CPU worker threads,
longest first. Concurrent checks are isolated with bubblewrap network
namespaces, compilations are cached with ccache, the first failure
aborts the rest (fail-fast, with --no-fail-fast to run everything),
and per-config timings plus pool efficiency land in the step summary.
Failure logs upload as artifacts. smoke-test.yml is likewise reworked
into a single pooled job that runs its nine configs on one runner.
Converted workflows (runner jobs per full pass):
os-check.yml 101 -> 8 (92 Ubuntu configs -> 4 shards;
the macOS matrix, the user-settings jobs and
the standalone
macos-apple-native-cert-validation.yml fold
into one macOS runner; Windows unchanged)
pq-all.yml 21 -> 2 shards
disable-pk-algs.yml 15 -> 1
wolfCrypt-Wconversion.yml 11 -> 1
trackmemory.yml 7 -> 1
cryptocb-only.yml 8 -> 1 (incl. the two new SHA512 entries)
multi-compiler.yml 6 -> 1
smallStackSize.yml 6 -> 1
multi-arch.yml 6 -> 1
async.yml 5 -> 1
psk.yml 5 -> 1
no-malloc.yml 3 -> 1
wolfsm.yml 3 -> 1
opensslcoexist.yml 2 -> 1
Measured against current upstream passing runs (job execution time,
queue excluded): ~200 runner jobs / ~374 runner-minutes per full pass
become 23 jobs / ~168 runner-minutes, with more coverage than before.
multi-arch's old matrix combined an "include" list of four
architectures with an "opts" axis; GitHub's include-merge rules made
each arch entry overwrite the previous one, so only the armel
combinations actually ran. The pooled list restores the intended
aarch64/armhf/riscv64 coverage (23 combinations; riscv64 x sp-math is
omitted as invalid - configure rejects sp-math without SP, and
--enable-riscv-asm, unlike --enable-sp-asm, does not bring SP in).
Out-of-tree build fixes this depends on:
- Makefile.am: symlink the read-only test data (certs/, tests/ config
files, sniffer captures and helpers, examples/crypto_policies,
input, quit) into the build tree via a BUILT_SOURCES stamp, removed
again in distclean-local. ChangeToWolfRoot() and the script tests
resolve everything relative to the working directory, so out-of-tree
make check and make distcheck now pass.
- scripts/multi-msg-record.py: locate the client binary from the build
tree working directory rather than the script's source directory.
- configure.ac + wolfssl/include.am: run
support/gen-debug-trace-error-codes.sh from $srcdir; it reads the
error-code headers from the source tree and generates into the build
tree.
- tests/swdev: a WOLFBUILD variable points the sub-make at the build
tree for the configure-generated headers (wolfssl/options.h,
wolfssl/version.h); the in-tree-only guards are dropped.
Portions of PR #10649 are incorporated: the cross-platform
ccache-setup composite action, repository_owner gates on check-headers
and check-source-text, the docs-only paths-ignore on os-check, and the
libspdm timeout bumps.
authorized any responder issued by an ancestor of the target's issuer;
RFC 6960 4.2.2.2 requires direct issuance by the CA identified in the
request.
- Remove CheckOcspResponderChain() and WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK.
- Drop now-unused vp parameter from CheckOcspResponder() and the
OcspRespCheck() helper; cascade through template and non-template
paths.
OCSP test blobs:
- Re-sign resp_server1_cert with intermediate1-ca (CA-direct path).
- Add resp_server1_cert_ancestor_responder for the negative test.
- Embed server1_cert_pem[] in test_ocsp_test_blobs.h so the new test
runs under NO_FILESYSTEM; matching entry added to
create_ocsp_test_blobs.py.
- Regenerate response[] in test_certman.c with intermediate1-ca as
signer; recipe switched from Wireshark export to openssl -respout
+ xxd -i for reproducibility.
- Fix self-XOR in test_wolfSSL_CertManagerCheckOCSPResponse so the
serial byte actually flips (^= 0xFF).
Live OCSP coverage:
- Add ocsp-responder-int1 (delegated responder issued directly by
intermediate1-ca, with id-kp-OCSPSigning EKU) for the
responder->intermediate->root chain.
- scripts/ocsp-stapling.test: intermediate1 responder switched to
ocsp-responder-int1 (delegated path).
- scripts/ocsp-stapling2.test, scripts/ocsp-stapling_tls13multi.test:
intermediate2 and intermediate3 sign their OCSP responses with
their own CA keys (CA-direct path); root block unchanged
(ocsp-responder-cert is still RFC-compliant for root-issued certs).
- .github/workflows/ocsp.yml: server1 OCSP responder switched to
ocsp-responder-int1 to match the cert chain.
- New test_ocsp_ancestor_responder_rejected confirms the
ancestor-issued response is rejected with OCSP_LOOKUP_FAIL.
The test certs are RSA; if NO_RSA is defined the client can neither
load nor verify them. Detect "RSA not supported" in client -? help
and exit 77 (SKIP) before tlslite-ng tries to use the RSA chain.
multi-msg-record.py: auto-detect the CA cert format the wolfSSL client
build accepts (PEM or DER) from the default shown in client -? help.
OPENSSL_EXTRA-style builds need PEM; NO_CODING builds need DER.
ocsp-stapling.test: skip the external login.live.com connection unless
WOLFSSL_EXTERNAL_TEST is explicitly enabled (matches external.test /
google.test convention). Local OCSP tests still run.
ocsp-responder-openssl-interop.test: use ${TMPDIR:-/tmp} for mktemp
templates so the test works when /tmp is not writable.