On the ubuntu-24.04 runner image with kernel 7.0.0-1017-azure, every
--enable-linuxkm-pie build fails with:
libwolfssl.o: error: objtool: wc_HmacSizeByType+0x55: unannotated
intra-function call
PIE builds use -mindirect-branch=thunk-inline, whose inline retpolines
are calls to a label inside the same function. On 7.0 objtool checks
the linked libwolfssl.o, which ignores OBJECT_FILES_NON_STANDARD, and
rejects them. The same builds pass on the older 6.17 runner kernel, so
the failure depends on which image a job lands on.
Pass KBUILD_EXTRA_FLAGS=FORCE_GLOBAL_OBJTOOL_OFF=1 for the PIE builds
in the Membrowse linuxkm-pie target and the Kernel Module Build
workflow. linuxkm/Kbuild then undefines CONFIG_OBJTOOL, which disables
all objtool passes since the kernel's objtool rules are gated on it.
Non-PIE builds keep objtool.
membrowse-action v1.2.16 moved the floating v1 tag to a release whose
action.yml has "${{ github.workspace }}" in an input description. The
runner rejects the github context there, so every Membrowse analyze job
fails in "Set up job" with "Unrecognized named-value: 'github'". The
onboard action has the same problem, and the comment workflow then
fails because no report was uploaded.
Pin the report, onboard and comment workflows to the v1.2.15 commit SHA,
the last release that worked, as the Zephyr workflow already does.
-- i.e., by default, disable the TLS/DTLS layer when KERNEL_MODE_DEFAULTS;
CMakeLists.txt: add WOLFSSL_KERNEL_SETTINGS and make existing
WOLFSSL_LINUXKM_DEFAULTS an alias for it, and make WOLFSSL_CRYPT_ONLY default
follow WOLFSSL_KERNEL_SETTINGS via new internal variable
WOLFSSL_CRYPT_ONLY_DEFAULT;
.github/workflows/linuxkm.yml: explicitly --disable-cryptonly in the
--enable-all scenario;
.github/workflows/fips-dev-no-post.yml: explicitly --disable-cryptonly in the
kernel-settings* scenarios.
wolfIP releases up to v1.1.0 have three Makefile rules that each run
tools/certs/mkcerts.sh, one per generated cert source. Under make -j
they run concurrently and clobber each other's files, leaving
server_cert.c without server_der, so build/test-wolfssl intermittently
fails to link. On the latest-release leg the job then asks for a
breaks-wolfip= token although wolfSSL broke nothing.
Run mkcerts.sh once before make so the cert sources already exist.
This stays harmless once wolfIP serializes the rule itself, and keeps
the released tags, which will never get that fix, building reliably.
The script is only run when present so a later wolfIP layout change
cannot fail the job here.
- WOLFSSL_IP_ALT_NAME no longer requires NETWORKING with USER_IO or
CRYPTO_ONLY: the only socket use is the TLS layer's MatchIPv6(), which
is compiled out under WOLFSSL_USER_IO. prj-x25519-ed448.conf now
enables it with user I/O and no network stack.
- WOLFSSL_CERT_EXT no longer depends on WOLFSSL_CERT_GEN, matching
--enable-certext, since the macro also enables extension decoding.
- Add a wolfssl_tls_sock build with tls_cert.conf, so the TLS-only
options (post-handshake auth, IP SAN matching, kept peer cert) are
linked into a real handshake rather than dropped by the wolfCrypt test
app.
- Document the app-directory overlay fallback in zephyr-test.sh usage.
The wolfssl_test_cert, _x25519_ed448 and _ed25519_x448 twister scenarios
were not run by any workflow: zephyr.yml names its scenarios explicitly
and zephyr-4.x.yml builds from builds.txt instead of running twister.
Add all three to builds.txt, so each builds and runs on native_sim for
every Zephyr version in the 4.x matrix. The curve-split scenarios move
from extra_configs into prj-x25519-ed448.conf and prj-ed25519-x448.conf
so twister and the CI list read the same files, and zephyr-test.sh now
takes an overlay that is not in its own directory from the app
directory instead.
The SSL_SESSION_set1_id and set1_id_context regression test needs
OPENSSL_ALL as well as the client cache reference path. With
NO_SESSION_CACHE_REF now the configure default, the plain
--enable-opensslall legs no longer take the reference path. The
session-cache-ref leg is the only one left on it, and it built with
opensslextra only, so the test skipped everywhere. Adding
--enable-opensslall keeps it running.
tests/swdev/Makefile localized every swdev symbol except the two entry
points with objcopy --keep-global-symbol, which macOS does not ship. On
Darwin, do the same with a second ld64 relocatable link and
-exported_symbol. The export check strips the Mach-O leading underscore
before comparing. The exported names now live in one SWDEV_EXPORTS list
that feeds both localization commands and the check.
The localization step is picked from configure's host_os rather than
uname, so cross-builds use the target's toolchain.
Add a macOS CI config that builds swdev with WOLF_CRYPTO_CB_ONLY_ED25519,
so make check depends on the ld64-localized swdev object.
The verify-only SLH-DSA benchmark only had a SHAKE-128s vector, because
that is the only verify-only signature in wolfcrypt/test/test.c. Builds
with only the SHA2 parameter sets showed no SLH-DSA row at all.
Add a SHA2-128s vector: a deterministic, empty-context signature of
"Hello World!" by the existing bench_slhdsa_sha2_128s_key.der. It was
generated with OpenSSL 4.0.3; wolfSSL verifies it, rejects it once a
message bit is flipped, and its own deterministic signature from the
same key is byte-identical. gen-slhdsa-mldsa-certs.sh gains the step
that produces it, and a rerun reproduces the committed files. The pq-all
verify-only benchmark config enables sha2 and requires this row too.
bench_slhdsa_verify() now takes the parameter set and vector. The row
uses the full benchmark's name, SLH-DSA-SHA2-S, and takes its strength
from the public key size, as the full benchmark does. Verify-only
builds accept -slhdsa-sha2-128s when SHA2-128s is built.
Tested on the host with --enable-slhdsa=yes,sha2,verify-only on its
own, with --enable-smallstack and with --disable-rng, with sha2 only,
with SHAKE only and 192f only (no SHA2 row, no warnings), and with the
full sha2 build.
The benchmark measured LMS, XMSS and SLH-DSA verify only after
generating a key and signing with it, so a build with
WOLFSSL_LMS_VERIFY_ONLY, WOLFSSL_XMSS_VERIFY_ONLY or
WOLFSSL_SLHDSA_VERIFY_ONLY compiled the algorithm out of the benchmark
entirely. Targets that only check signatures, such as a boot loader
verifying an image, got no numbers at all.
Verify-only builds now time verify against a fixed vector: LMS
L1_H10_W8, XMSS-SHA2_10_256 and SLH-DSA-SHAKE-128s. The vectors are the
verify-only KATs already in wolfcrypt/test/test.c, stored as binary
files under certs/lms, certs/xmss and certs/slhdsa and emitted into
certs_test.h by gencertbuf.pl. The rows use the same names as the full
benchmark, and a parameter set without a vector, or one that is not
compiled in, is skipped. If loading the key fails, the failing call is
printed and no row is shown.
In a verify-only build, -lms_hss, -xmss_xmssmt(_sha256),
-slhdsa-shake128s and -slhdsa are accepted only when their vector
applies, and the other XMSS and SLH-DSA parameter options are rejected,
so no option silently runs nothing.
Verify needs no RNG, so the asymmetric result printing is built
whenever one of these vectors applies, also with WC_NO_RNG. A
verify-only build with no vector no longer counts as an asymmetric
algorithm. This also fixes an LMS verify-only build with no other
asymmetric algorithm, which failed -Werror on master with an unused
bench_stats_asym_finish(). The SRTP-KDF, scrypt and Argon2 benchmarks
also call it, so it is now built for them too: on master each of them
failed to compile with no asymmetric algorithm, which an LMS
verify-only build used to hide.
The benchmark exits 0 even when verify fails, so a new pq-all CI config
builds all three verify-only with no other asymmetric algorithm and
-Werror=unused-function, runs the benchmark, and fails on any reported
benchmark error, such as a key that does not import, or on a missing
verify row.
Tested on the host with --enable-{lms,xmss,slhdsa}=yes,verify-only on
its own, with --enable-smallstack, with --disable-rng, and with
--enable-all-crypto; with edge configurations where no vector applies
(SLH-DSA 192f only, LMS max height 5, XMSS min hash size 512), both
with --disable-rng and with RNG but no other asymmetric algorithm; with
SRTP-KDF, scrypt or Argon2 as the only such user, with and without an
RNG and with LMS verify-only; and
with --enable-all and the full LMS/XMSS/SLH-DSA build, whose benchmark
output is unchanged. The new CI config passes under
parallel-make-check.py and fails with a corrupted signature byte, a
truncated public key, a missing row and an unused static function.
The fpr shift helpers have a separate implementation for targets
without WC_64BIT_CPU, which no CI job built. Add a smallest-mem leg with
-DWC_32BIT_CPU so the white-box exercises it.
falcon_native_verify_msg placed its 2*n word16 working buffer on the stack
unless WOLFSSL_SMALL_STACK was set. That buffer is sized for the highest
enabled level, so a Falcon-512 verify used 4 KB of stack for it whenever
Falcon-1024 was built in, and verify reached about 5.7 KB of stack on a
Cortex-M33/M7 while keygen and sign stay near 1.2-1.4 KB.
Verify now allocates the buffer per call, sized for the key's own level
(2 KB for Falcon-512, 4 KB for Falcon-1024), so it can return MEMORY_E;
the wc_falcon_verify_msg documentation says so. WOLFSSL_NO_MALLOC builds
keep the buffer on the stack. To keep it off the stack without an
allocator, WOLFSSL_FALCON_VERIFY_NO_MALLOC
(--enable-falcon=verify-no-malloc) holds the buffer in falcon_key
instead, sized for the highest enabled level, the same approach as
WOLFSSL_MLDSA_VERIFY_NO_MALLOC. With it, a key verifies one signature at
a time and falcon_key grows by 4*FALCON_MAX_N bytes.
On an STM32H743 a Falcon-512 verify goes from 5648 B of stack and no heap
to 1568 B of stack and 2048 B of heap, at the same speed. The peak stack
of a TLS 1.3 handshake that verifies a Falcon-512 chain drops from 6.3 KB
to 3.7 KB.
The falcon-interop backend matrix gains verify-no-malloc and
level1+dynamic-keys+verify-no-malloc legs running the full unit suite.
fips-dev-no-post.yml runs seven configs through parallel-make-check.py,
four at a time, but never installed bubblewrap. The test scripts only
re-exec under bwrap --unshare-net when it is present, so every unit.test
shared the runner's network namespace.
test.h binds its listeners with SO_REUSEADDR and SO_REUSEPORT. With
those set, a Linux UDP bind to port 0 can return a port another process
already holds, and the DTLS server rebinds its port for each resumption.
A client's ClientHello can then reach another config's DTLS server,
which answers with a fatal alert, e.g. a DTLS 1.2 -r pair failing with
"wolfSSL_connect resume error -313" while every API test passed.
Install bubblewrap and lift the AppArmor userns restriction, as the
other parallel make check workflows already do. The job installs from
the ubuntu-24.04-linuxkm bundle, so add bubblewrap to its package set
too; until that bundle is rebuilt the job falls back to the apt mirror.
Documentation:
- wolfSSL_get_verify_result() reports WOLFSSL_X509_V_OK once the callback
accepts. wolfSSL verified nothing, so say that this records the
callback's verdict rather than a check wolfSSL made.
- The OCSP stapling restriction is client-side. Both guards test
side != WOLFSSL_SERVER_END: a server staples its own status, which is not
part of verifying the peer. A server that asks the client to staple is
not refused, and no stapled response is checked for it either, because
ProcessPeerCertLeafRevocation is skipped with the callback.
- The list of what still applies was neither "two" nor complete. Add
PEER_KEY_ERROR and SCR_DIFFERENT_CERT_E, note MAX_CERTIFICATE_SZ next to
MAX_CHAIN_DEPTH, and state that 0 is the only accepting value, so
returning WOLFSSL_SUCCESS rejects.
- DoChainVerifyCb no longer allocates; drop MEMORY_E from its comment.
Code:
- NULL-check the certificate manager in ChainVerifyCbCheckSsl, as
ChainVerifyCbCheckCtx already does for ctx->cm.
- Re-run ChainVerifyCbCheckSsl in TLS_ASYNC_BUILD. A deferred verdict
resumes there, so TLS_ASYNC_BEGIN ran on the first pass only.
Tests:
- Pin both halves of the headline contract on the accept path: the verify
callback set with wolfSSL_set_verify() is not called, and
wolfSSL_get_verify_result() reports WOLFSSL_X509_V_OK.
- Cover a callback returning WOLFSSL_SUCCESS, which rejects.
- Rename test_tls13_chain_verify_cb_async to _defer. It exercises deferral
over TLS 1.3, not async crypto.
CI:
- Add chain-verify-cb-async, the first build combining the callback with
WOLFSSL_ASYNC_CRYPT, and the only one with async crypt and CRL but
without WOLFSSL_NONBLOCK_OCSP.
Three behaviour changes to existing configurations, introduced earlier in
this series and not called out until now:
- IsHsSuspendErr() recognizes OCSP_WANT_READ only under
WOLFSSL_NONBLOCK_OCSP, where the sites it replaced tested
WOLFSSL_ASYNC_CRYPT || WOLFSSL_NONBLOCK_OCSP. The keep-state re-entry
branch it replaced was itself under WOLFSSL_NONBLOCK_OCSP, so an
async-only build rewound into reset args and a freed pendingMsg. It now
fails cleanly instead.
- DoCertificate no longer advances serverState to SERVER_CERT_COMPLETE
when ProcessPeerCerts suspended.
- ReceiveData admits a suspended handshake error rather than refusing the
read, which under WOLFSSL_NONBLOCK_OCSP now includes OCSP_WANT_READ.
Adds an opt-in callback that takes over the peer certificate trust
decision. wolfSSL builds no chain, verifies no signature and checks no
date, revocation status, key usage or host name; the verify callback is
not called either. The callback gets only the DER certificates from the
Certificate message as WOLFSSL_BUFFER_INFO entries, certs[0] first. It
is consulted even under WOLFSSL_VERIFY_NONE, and its rejection fails the
handshake either way.
wolfSSL still decodes every certificate with ParseCert(NO_VERIFY) before
the callback runs, so malformed DER fails the handshake and the callback
is never handed it. Content wolfSSL does not understand - an unknown
critical extension, an unsupported key or signature algorithm, a
signature algorithm mismatch - is not a decoding failure and is left for
the callback to judge. The check runs once, not again on re-entry after
a deferred verdict.
The callback may return CHAIN_VERIFY_WANT_E to suspend the handshake and
be asked again with the same certificates when the application re-enters
wolfSSL_connect(), wolfSSL_accept(), wolfSSL_read() or wolfSSL_write().
A certificate received after the handshake (TLS 1.3 post-handshake
authentication) arrives inside wolfSSL_read() and is resumed by reading
again: ReceiveData() re-enters on any handshake-suspend error, and the
ticket-sent accept state leaves a suspended message alone. Rejection
fails with CHAIN_VERIFY_CB_E and one bad_certificate alert, and sets
peerVerifyRet so wolfSSL_get_verify_result() does not report X509_V_OK.
Still applied: an empty Certificate message keeps the existing
mutual-auth policy (the callback is not called for it), and the minimum
peer key sizes still gate the peer's own key, which the handshake uses
directly.
DTLS, raw public keys and OCSP stapling are not supported with the
callback. wolfSSL_CTX_SetChainVerifyCb() and wolfSSL_SetChainVerifyCb()
refuse with CHAIN_VERIFY_UNSUPPORTED_E when the context or object is
already configured for one of them, and a connection that uses one of
them anyway fails with the same error and an internal_error alert before
the callback is called. The DTLS paths are otherwise untouched.
The callback and its user context can be set on the context or on the
SSL object, the object's taking precedence. The feature is part of
--enable-all, has a CMake option and Doxygen entries.
The suspend machinery is shared with WOLFSSL_NONBLOCK_OCSP and
WOLFSSL_ASYNC_CRYPT. The open-coded pairs of comparisons against
WC_PENDING_E and OCSP_WANT_READ are replaced by IsHsSuspendErr(), and the
matching build guards by WOLFSSL_HAVE_HS_SUSPEND. That also closes three
holes which affected WOLFSSL_NONBLOCK_OCSP builds:
- DoHandShakeMsg() freed ssl->pendingMsg on a non-WC_PENDING_E suspend
while ProcPeerCertArgs still pointed into it.
- wolfSSL_connect()/wolfSSL_accept() and their TLS 1.3 counterparts
called FreeAsyncCtx() when buffered output flushed, discarding the
saved certificate state.
- ProcessPeerCerts() XFREE'd args in WOLFSSL_SMALL_STACK builds without
WOLFSSL_ASYNC_CRYPT, where args points inside ssl->async.
FreeHandshakeResources() unloads SSL-owned certificates and keys once
the handshake is done. The side check that limits this to the server
was compiled out when WOLFSSL_POST_HANDSHAKE_AUTH is defined, so a PHA
build unloaded the client's identity too, which is the side that needs
it to answer a post-handshake CertificateRequest. The client then sent
an empty Certificate and the server failed with NO_PEER_CERT, or
carried on unauthenticated when it did not require a certificate.
This hits TLS 1.3 clients that load their certificate and key on the
WOLFSSL object in builds with post-handshake auth but without
OPENSSL_EXTRA or WOLFSSL_WPAS_SMALL, both of which compile the unload
out. Identities loaded on the CTX are not owned by the SSL and were
never unloaded. A client that authenticated during the handshake was
hit as well on the first post-handshake request.
Unload on the server only, in every configuration.
test_tls13_pha stopped at wolfSSL_request_certificate() and never ran
the exchange. It now drives two post-handshake rounds to completion,
after an initial handshake with and without client auth, with the
client identity on the SSL. Both cases fail with NO_PEER_CERT without
the fix in a build with --enable-postauth and without OPENSSL_EXTRA.
Add a postauth-no-compat entry to the Linux os-check matrix, so a
GitHub Actions build runs the test with the unload compiled in;
--enable-all brings OPENSSL_EXTRA along and compiles it out.
SE050 and CryptoCell are supported with this.
WOLFSSL_NO_RSA_SW to disable the RSA software implementation.
WOLFSSL_NO_ECC_SW to disable the ECC software implementation.