The compat macro cast the caller's callback to WOLFSSL_TLSEXT_DEBUG_CB.
Calling a function through an incompatible pointer type is undefined
(C17 6.3.2.3 p8), and the cast silenced the diagnostic that would have
caught a mismatch.
WOLFSSL_TLSEXT_DEBUG_CB already matches OpenSSL's callback, which takes
const unsigned char *data, so the macro can be a plain alias. A callback
spelled the OpenSSL way now compiles unchanged and a mismatched one is a
compile error instead of undefined behaviour at run time.
Test a callback declared with OpenSSL's spelling through the macro.
Three more configurations failed to link, all the same shape as the last
round: a guard that names what the test needs rather than what the build
provides.
NO_TLS builds (certgen-no-tls, no-tls-cryptocb-aesgcm-setkey-free)
wolfSSLv23_client_method and wolfSSLv23_server_method are implemented
under !NO_TLS && !NO_WOLFSSL_{CLIENT,SERVER}, and wolfSSL_UseSNI,
wolfSSL_CTX_UseSNI, wolfSSL_SNI_Get*, wolfSSL_UseSupportedCurve and
wolfSSL_CTX_UseSupportedCurve all sit under !NO_TLS in ssl_api_ext.c on
top of their own feature macro. Eleven blocks were missing !NO_TLS.
dtls13-client-minimal (WOLFSSL_NO_TLS12)
wolfDTLSv1_2_{client,server}_method are implemented under
!WOLFSSL_NO_TLS12: DTLS 1.2 is built on the TLS 1.2 code. Three blocks
wanted that, including the CID argument-guard test.
Found the first pass by line number and missed a second block carrying the
identical guard text, so this was checked mechanically instead: for every call
site of each of these symbols, walk the enclosing #if chain and assert it
carries the macros the implementation requires. That found the leftovers and
now reports zero for this branch. Verified by building all seven affected
configurations locally -- the three new ones and the four fixed last round, so
neither set regressed the other.
Campaign unaffected: ssl_api, dtls, revocation and tls_core re-measured, gates
green, white-box smoke 82 passed 0 failed.
The rebase cost ssl_sess.c two conditions: 32/120 before, 30/120 after, same
denominator, deterministic across two runs with byte-identical GAPS.md. The
only upstream change to that file is a one-line fopen swap inside
wolfSSL_save_session_cache, whose conditions are all still covered, so the
cause is elsewhere -- most likely the +52 lines upstream added to src/ssl.c,
which drives these paths.
Rather than accept a lower baseline, the two are recovered by covering more:
the session object lifecycle guards, which are almost all
"session == NULL || something about the session" and which a test that
establishes a session reaches with a well-formed object every time.
wolfSSL_SESSION_new / _dup / _up_ref / _free are unguarded in both ssl.h and
src/ssl_sess.c -- checked before writing, since a declaration without a
compiled implementation is a link error, not a compile error. Vectors cover
the NULL half of each entry point, a session that exists but was never
established, the up_ref / double-free refcount path, set_session with a
not-set-up session, and SetServerID's three operands plus its new-session arm.
ssl_sess.c 30/120 -> 32/120. Gate passes with no baseline drop.
A census of the remaining NULL-shaped conditions splits them by how the NULL
actually arises: 282 from an argument the caller passes, 145 from a struct
member legitimately NULL in some state, and only 15 from a failed allocation.
This batch takes the first kind in public functions -- no fixture needed at
all, which makes it the cheapest coverage left.
One call per uncovered operand with every other argument valid, then the
all-valid partner: a NULL in the first slot pairs only the first operand
because the rest short-circuit away. Covered here: the two cipher-list getters
(buf/len), check_domain_name and check_ip_address, CTX_GetDevId,
get_cipher_suite_from_name, get_curve_name including its per-curve OID arms,
load_verify_locations_ex's compound (file == NULL && path == NULL),
use_certificate_ASN1, and export_keying_material.
Every symbol was checked against BOTH its ssl.h declaration guard and its
implementation guard in src/ before being called. A declaration without a
compiled implementation is a link error rather than a compile error, and that
distinction has cost this branch several CI rounds.
ssl.c 12/89 -> 24/89, ssl_load.c 35/155 -> 41/155, ssl_certman.c 47 -> 48.
The rebase push took CI from 108 failures to 10. Of those, three are ours.
LeakSanitizer flagged two allocations the tests own and discard:
wolfSSL_SESSION_dup() returns a new session object, not a borrowed one, so
calling it for its side effect leaks it -- 2664 bytes from
wolfSSL_NewSession. The duplicate is freed now.
wolfSSL_CertManagerNew_ex(NULL) returns an owned CertManager -- 280 bytes.
It was called bare to exercise the NULL-heap argument; the result is freed
now.
wolfSSL_SNI_GetRequest and wolfSSL_SNI_GetFromBuffer are compiled under
HAVE_SNI && !NO_WOLFSSL_SERVER (src/ssl_api_ext.c): both read what a client
sent, so a client-only build has neither. Guarding on HAVE_SNI alone left them
undefined at link time there.
Verified with -Werror in a client-only build (NO_WOLFSSL_SERVER, SNI and ALPN
on): both touched files compile clean.
The other seven failures are not ours: scripts/ocsp.test needs external DNS
and the runner had none ("Couldn't find www.google.com, skipping", then
"Both OCSP connection to globalsign and google failed"); that script is
upstream and untouched by this branch. The make-check-linux matrix entries
report "aborted (fail-fast)", i.e. cascade from a sibling, not independent
failures.
Second CI round narrowed from every job to two clusters, both failing to link
tests/unit.test on the same two symbols.
test_wolfIO_DecodeUrl_host_bounds was defined only inside
#if defined(HAVE_HTTP_CLIENT) but registered in the api.c test table
unconditionally, so wherever HTTP client support is off the table referenced a
symbol with no definition. Its sibling test_wolfIO_DecodeUrl_crlf_reject in
the same block already carries an #else stub returning TEST_SKIPPED; this now
has the same. Verified by preprocessing test_ocsp.c with HTTP client off:
exactly one declaration and one definition survive, no duplicate.
wolfSSL_SetSession() (capital S) is WOLFSSL_LOCAL -- declared in internal.h,
not public API -- so referencing it from tests/api left an undefined reference
in configurations that do not export internal symbols. The two calls are
removed rather than guarded: the public wolfSSL_set_session() is already
exercised a few lines above in the same function and covers the same guard, so
nothing is lost.
Smoke suite: 77 passed, 0 failed.
CI failed every job on 09409464a with four distinct errors, all in tests
added earlier this part, all from guards that did not match what
wolfssl/ssl.h actually declares:
unused-variable: proto/protoSz were used only under HAVE_ALPN and sz only
under WOLFSSL_DTLS, but all three were declared unconditionally. Wherever
those features are off they are unused, and the tree builds with
-Werror=unused-variable. Declarations now sit under the same guard as their
uses.
implicit-function-declaration / nested-externs / int-conversion:
test_wolfSSL_x509_accessor_guards was guarded on WOLFSSL_CERT_GEN, which is
not what gates that API. ssl.h declares wolfSSL_X509_load_certificate_file,
_get_signature, _get_pubkey_buffer and _free under OPENSSL_EXTRA ||
OPENSSL_EXTRA_X509_SMALL || KEEP_PEER_CERT || KEEP_OUR_CERT ||
SESSION_CERTS. With the wrong macro they were implicit declarations, and the
implied int return then tripped int-conversion on the WOLFSSL_X509*
assignment. Guard now mirrors the header.
implicit-function-declaration: wolfSSL_dtls_set_mtu is declared under
(WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) && WOLFSSL_DTLS. Guarding the call on
WOLFSSL_DTLS_MTU alone left SCTP-only configs calling an undeclared
function.
discarded-qualifiers: wolfSSL_UseALPN takes char*, not const char*, so the
string literals passed to it were a const violation. Uses a mutable buffer
now.
Verified locally before pushing, with -Werror, in the two configs that
reproduce these: one with alpn/sni/dtls/opensslextra all off, and one with
dtls+sctp but no dtls-mtu. Both compile clean.
tests/api.c is one shared translation unit compiled into every module's
unit.test, filtered by --group only at runtime. Two calls added earlier this
part referenced symbols that do not exist in every module's config, and broke
the shared build for anything without that specific feature on -- not just
the module the test was written for.
test_ssl_cert.c: WOLFSSL_CERT_TYPE_X509 and the *_cert_type / *_expected_rpk
family are declared only under #ifdef HAVE_RPK in wolfssl/ssl.h. The guard on
test_wolfSSL_cert_api_arg_guards was only !NO_CERTS && !NO_WOLFSSL_CLIENT, so
any config without --enable-rpk (asn, pkcs7, and the rest of wolfCrypt-only
modules) failed to compile. Confirmed by inspecting the header's own #ifdef
nesting, then by a real build.
test_ssl_ext.c and test_ssl_cert.c: wolfSSL_dtls_set_pending_peer() is
declared unconditionally in ssl.h but implemented only under
WOLFSSL_DTLS_CID && !WOLFSSL_NO_SOCK (src/ssl_api_dtls.c). The surrounding
#ifdef WOLFSSL_DTLS guard is not sufficient -- a config with WOLFSSL_DTLS on
and WOLFSSL_DTLS_CID off compiles the call and fails at LINK time, not
compile time, which is why tracing the header's #ifdefs alone did not catch
it and a real build was needed. Reproduced against asn's own
ignore_name_constraints and runtime_date_check variants: 'ld.lld: error:
undefined symbol: wolfSSL_dtls_set_pending_peer'.
Verified with real (non-cached) rebuilds of asn, pkcs7 and tls_core after the
fix: all three link and gate clean. asn.c 1490/1580, pkcs7.c 943/1058,
internal.c 752/1722 -- all unchanged from before this fix, confirming it
repairs the build without touching what those modules measure.
The previous pass sprayed NULL at the first argument of everything and
returned 11 conditions for about a hundred calls. A guard like
if ((ssl == NULL) || (p == NULL) || (g == NULL))
has three operands, and a NULL in the first slot pairs only the first -- the
other two are never evaluated because the chain short-circuits. Each operand
needs its own call with every other argument valid, and the ledger already
says which operand of which decision is missing.
Taking the vectors from GAPS.md instead of from the function name: 26
conditions from one test, against 11 from the spray.
ssl_api_ext.c 30->38, ssl_load.c 22->34, ssl_sess.c 27->32, ssl.c 8->11.
Null-guards are the largest remaining type: 749 of 2855 uncovered conditions,
26%. Splitting them by enclosing function is the part that matters for
planning, because it bounds what an API suite can do at all:
246 in public wolfSSL_* / wc_* functions reachable by calling them
503 in file-static helpers white-box only
These vectors take the public third across the extension, DTLS, session and
record APIs: an object never created, an output pointer that is NULL, a zero
length with a real buffer, each followed by the same call made correctly so
the guard has its partner.
ssl_api_ext.c 24->30, ssl_api_rw.c 35->37, ssl_api_dtls.c 3->5, ssl.c 7->8.
The yield per call is low because most of the 246 sit behind guards that a
correctly-typed call already satisfies; what is left needs the specific wrong
argument each function checks for, read from the source rather than guessed.
The SESSION_* accessors are absent entirely -- they live behind the OpenSSL
compatibility layer this option list excludes as a build fact.
src/ssl_ech.c measured 0 of 52 conditions -- zero, not "poorly covered" --
even though ECH is compiled in and five ECH tests run in the tls13 group of
the same binary. Those tests drive ECH through a handshake using configs the
harness makes for them; none calls the public configuration API, and that is
where every condition in the file lives: generating a config for a named
KEM/KDF/AEAD, importing one from raw bytes or base64, reading one back into a
caller's buffer, and the size and argument checks on all of it.
The file was invisible to the campaign until this part because ssl_ech.c is
#included into ssl.c rather than compiled standalone, so it produced no object
file and never appeared in a filtered llvm-cov export.
Vectors a handshake cannot produce: a NULL ctx, a buffer one byte too small, a
length of zero, base64 that is not base64, base64 that decodes to something
that is not a config, a KEM triple no build implements, and a retry-config
query on a connection that never negotiated ECH.
ssl_ech.c 0/52 -> 19/52.
Add !NO_TLS to test_wolfSSL_set_tlsext_debug_arg_ext. The body calls
wolfSSLv23_client_method(), declared only under !NO_TLS, so
--disable-tls --enable-opensslextra did not build.
Require WOLFSSL_TLS13 or HAVE_EXTENDED_MASTER for
test_tlsext_debug_find_len. Its only call sites are under those macros,
so --disable-tls13 --disable-extended-master tripped
-Werror=unused-function.
Guard the cData.client_server assertion with the same condition as the
neighbouring cData.count check. It is only written when the callback
fires on the client, which the count guard already concedes may not
happen.
test_tlsext_debug_find_len() was compiled whenever a client build was
enabled, but only the memio handshake test uses it. Builds without the
memio dependencies (e.g. --enable-leantls, which turns RSA off) failed
with -Werror=unused-function.
The debug callback and its argument are OpenSSL-compat features
(SSL_set_tlsext_debug_callback/_arg) unrelated to the crypto
callbacks, but the implementation kept its state in the
HAVE_PK_CALLBACKS section of the WOLFSSL struct and passed the
pkcallbacks logging argument to the callback, so the feature only
built with --enable-pkcallbacks.
The callback and a dedicated argument field now live under
OPENSSL_EXTRA; wolfSSL_set_tlsext_debug_arg sets that argument and
the TLSX_Parse call site reports it, matching OpenSSL semantics.
Add wolfSSL_set_tlsext_debug_callback() with the WOLFSSL_TLSEXT_DEBUG_CB
callback type, mirroring OpenSSL's SSL_set_tlsext_debug_callback(). The
callback is invoked once for every TLS extension received during the
handshake, in wire order, before the extension is processed, with the
connection side, extension type, raw extension content and the argument
set via wolfSSL_set_tlsext_debug_arg(). This covers client hello,
server hello, hello retry request, encrypted extensions, certificate,
certificate request and session ticket messages for TLS 1.2/1.3 and
DTLS, mirroring OpenSSL's tls1_handle_extensions() receive path.
Unlike OpenSSL 3.x, unknown (unregistered) extension types are also
reported.
The callback is stored in the WOLFSSL object and guarded by
OPENSSL_EXTRA && HAVE_PK_CALLBACKS, matching the existing
wolfSSL_set_tlsext_debug_arg(). The argument reuses ssl->loggingCtx.
Document the new API in doc/dox_comments/header_files/ssl.h and add
API tests, including a loopback handshake test asserting that both
sides observe the expected extensions (TLSX_SUPPORTED_VERSIONS for
TLS 1.3, TLSX_EXTENDED_MASTER_SECRET for TLS 1.2 with EMS).
Clean up includes single return point from every function, consistent formatting function block comment and tests added.
ssl_api_rw.c: Cleanup; 6 helpers extracted from write_dup/shutdown; fixed a SendBuffered corner case that returned 0 instead of an error.
ssl_api_ext.c: Cleanup; extracted wolfssl_ticket_key_cb_process, wolfssl_rehandshake_prepare.
ssl_api_hs.c: Cleanup + de-indent; 9 helpers extracted, incl. shared wolfssl_handshake_flush/_done between connect and accept (~100 duplicated lines removed). wolfSSL_connect/accept left multi-exit.
ssl_api_cert.c: Cleanup of newer functions at end of file; extracted PushPeerCertToChain; fixed a double free in CreatePeerCertChain; fixed 5 wrong @param names.
ssl_api_crl_ocsp.c: Full cleanup of all 49 functions; wolfSSL_OCSP_parse_url rewritten; fixed a URL with no host returning success with the rest of the URL as the host; added IPv6 literal support; fixed 4 wrong WOLFSSL_ENTER names.
ssl.c: Moved the x509GetIssuerFromCM forward declaration here for clarity.
The default ticket encryption callback rotates two keys and can only
honor a hint below WOLFSSL_TICKET_KEY_LIFETIME/2; a larger hint
previously left no key available for encryption, failing every handshake
after the first on a reused server CTX. Now these values are rejected.
Align the argument parsing and handling of input group names to align it
with OpenSSL behavior:
* Do a case-insensitive comparison of the input names with our names
* Add aliases for "MLKEMxxx" groups without underscores in addition to
our names with underscores (keep our for backward compatibility)
* Extend unit tests for both