Two MC/DC cases the campaign disclosed and PR 10973 fixed are now safe to
drive:
* ascon: wc_AsconAEAD128_DecryptUpdate(ctx, out, NULL, 0) demonstrates the
inSz!=0 operand (the NULL-memcpy on inSz==0 is fixed) -> ascon.c 36/36.
* rsa: the wc_CompareDiffPQ / _CheckProbablePrime / wc_CheckProbablePrime_ex
XMALLOC-chain later operands (idx1/idx2) are now faulted via arm(2)/arm(3)
in test_rsa_fault_whitebox.c; they were blocked by the partial-OOM
double-free the fix removed -> rsa.c 168 -> 172.
api.c references test_wc_WolfEventDecisionCoverage via TEST_WOLFEVENT_DECLS,
but the new tests/api/test_wolfevent.c was only added to tests/api/include.am,
so the cmake unit-test build never compiled it -> undefined symbol at link
(GitHub Actions "WolfSSL CMake Build Tests" / Build wolfssl). Mirror the
include.am addition into the CMakeLists.txt unit_test source list.
Add test_wc_WolfEventDecisionCoverage (group "wolfevent") driving the
wolfEvent / wolfEventQueue_* doubly-linked FIFO from the public API:
the queue==NULL || event==NULL guards (Push/Pop/Add/Remove, each operand
plus the all-false half), the Add first-element branch, the Remove
head/tail/sole cascade including the (event==head && event==tail) AND and
the defensive (next==NULL || prev==NULL) corruption guard, and the Poll
context-filter OR.
Guarded by HAVE_WOLF_EVENT (compiled empty otherwise). The queue core is
async-independent; it builds standalone (no WOLFSSL_ASYNC_CRYPT) now that
BUILD_WOLFEVENT is true under --enable-usersettings and wolfEvent_Poll no
longer warns on unused params in non-async builds.
Remove whitelist entries the check-source-text macro check (check K) no
longer needs because the macros are recognised independently: the falcon
backend macros set by configure.ac (WOLFSSL_FALCON_FPR_DOUBLE /
SIGN_SMALL_MEM / FFT_AVX2 / FFT_NEON / FPR_ASM), WOLFSSL_FALCON_NTT_DSP
(#defined in falcon.c), WOLFSSL_FALCON_VERIFY_ONLY (#defined in
IDE/m33mu-falcon-verify/user_settings.h), and WOLFSSL_CHECK_MEM_ZERO.
WOLFSSL_FALCON_SIGN_STATS and WOLFSSL_FALCON_NO_NTT_DSP are kept: they are
pure user-opt macros (used in #if, defined nowhere) that still require
whitelisting.
test_sp_cortexm_whitebox.c gated on defined(WOLFSSL_SP_256), which is not a
real wolfSSL macro (256-bit SP is the default, disabled via WOLFSSL_SP_NO_256;
the sized macros are WOLFSSL_SP_384/521/1024). check-source-text flags it as
an unrecognized macro and the guard was always false (dead code). Use
!defined(WOLFSSL_SP_NO_256) so the P-256 Cortex-M SP path is actually built.
Two check-source-text / clang-tidy fixes on the MC/DC test files:
* Wrap error-code comparison operands in WC_NO_ERR_TRACE() (check-source-text
check I). Code comparisons (blake2b/blake2s/hpke white-boxes and the
logging global-queue pull check) are wrapped; the pseudo-code in doc
comments and the WB_CHECK message strings (mcdc_fault_alloc.h, dsa/mlkem
fault white-boxes, logging white-box) are reworded so an error code is no
longer adjacent to == / != .
* Uppercase the integer-literal suffixes in test_sakke.c (384u -> 384U, etc.)
for clang-tidy readability-uppercase-literal-suffix.
No behavioral change.
test_wc_Des_CbcEncryptDecrypt drove the per-operand NULL guards of
wc_Des_CbcEncrypt/CbcDecrypt/EcbEncrypt/SetIV. The frozen FIPS/selftest
single-DES module predates those open-build NULL checks and dereferences a
NULL des/out/in directly, so the probes segfault (exit 139) in a FIPS build.
Gate the whole test on !HAVE_FIPS && !HAVE_SELFTEST -- this single-DES MC/DC
coverage is gathered in the open build; the frozen module is out of its scope.
codespell reads "statics" as a misspelling of "statistics" and fails the
Codespell CI lane. Reword the whitebox doc comments/notes to "static
helpers" (falcon/frodokem/rsa fault white-boxes). Comment/string only.
stm32h563_OTP.bin is a generated one-time-programmable flashing artifact,
not source. Remove it from the tree and add it to the directory .gitignore
alongside the other generated outputs (app-falcon.*) so a local build can
no longer re-add it.
check-source-text (check E) rejects C++-style // comments in C files, and
its regex fires on the // used as inline annotations inside the /* */ doc
blocks of mcdc_fault_alloc.h (sweep-pattern pseudo-code) and
test_integer_fault_whitebox.c (the mp_div alloc-chain line:col:cond refs).
Nested /* */ can't be used inside a block comment, so switch those inline
markers to '--'. No code change.
Add test_wc_FalconDecisionCoverage to the falcon API group, covering the
public wc_falcon_* wrapper decisions (level checks, import/export and
sign/verify argument guards, init_id/init_label) with per-condition MC/DC
independence cases.
Add tests/unit-mcdc/test_falcon_whitebox.c, a standalone binary that
#includes falcon.c and drives its file-static encode/decode/zint/modp/
sampler/keygen-solver/sign guards -- including the small-mem
falcon_do_sign_dyn twin -- with both halves of each independence pair, plus
a real Falcon-512 make/sign/verify round-trip for the proceed halves.
Register the whitebox in EXTRA_DIST (test-only; it is not part of the
library build).
Add the tests/unit-mcdc white-box drivers produced by the coverage campaign's
fault-injection and SP-ARM emulator-lane passes, and extend the EXTRA_DIST
listing to cover them (test-only; standalone main() + #include the target .c;
never built into libwolfssl or unit.test -- see the comment in tests/include.am).
Fault-injection (mcdc_fault_alloc.h: a fail-after-N wolfSSL_SetAllocators mock,
swept across allocation sites to drive the FALSE half of (err==MP_OKAY)&&step
success-chain guards): dsa, eccsi, sakke, hpke, mlkem, mldsa, integer, rsa,
frodokem (+ a shared frodokem fault header).
SP-ARM emulator lanes (drive the C-level decisions in the cross-only asm SP
backends under qemu-user / m33mu): sp_arm64, sp_arm32, sp_armthumb, sp_cortexm.
The tests/unit-mcdc/*.c MC/DC white-box supplements this branch adds each
#include a wolfCrypt .c and carry their own main(); they are built standalone
by the per-module coverage campaign and are NOT compiled into libwolfssl or
unit.test (that would duplicate main()/symbols). They are test-only.
The source-completeness check (per-PR diff) requires every file a PR adds to
appear in an include.am. Since these cannot be tests_unit_test_SOURCES, list
them in EXTRA_DIST -- the same bucket tests/api/include.am uses for its
non-compiled files -- so they ship in the dist tarball without being built.
Scope: only the white-boxes this branch introduces.
wc_ValidateEccsiPair() reports an off-curve PVT via wc_ecc_is_point(), whose
error code is backend-dependent: the mp-based check (classic / SP_MATH_ALL /
fast-math) returns IS_POINT_E, but the minimal WOLFSSL_SP_MATH backend routes
through sp_ecc_is_point_*(), which returns MP_VAL for a point not on the curve
(and eccsi.c only remaps -1 -> IS_POINT_E, not MP_VAL). Select the expected
code per backend so the all-pq-sp-math CI config (--enable-sp-math) passes.
Verified: full unit.test --api under --enable-all --enable-sp-math --enable-sp-asm
reports 0 failures.
- test_wolfmath.c: limit the "digits > capacity" mp_rand rejection vector to
the fixed-size backends. USE_INTEGER_HEAP_MATH grows the mp_int via
mp_set_bit instead of rejecting, so the call would legally succeed (and
force a large allocation), failing ExpectIntNE.
- test_memory_whitebox.c: guard the WOLFSSL_STATIC_MEMORY / WOLFSSL_MEM_FAIL_COUNT
defines with #ifndef so a build that already provides them (user_settings.h /
CFLAGS) does not hit a redefinition warning treated as error.
- test_sakke_whitebox.c: skip the sakke_mulmod_base_add() calls when
wc_ecc_new_point() returns NULL. That function does not validate its result
pointer and would dereference a NULL addResult under allocation pressure.
- test_hpke.c: guard both test bodies on HAVE_HPKE. They were gated only on
HAVE_CURVE25519 && !NO_SHA256 && WOLFSSL_AES_128, so configs with those but
without HPKE (e.g. pk-mlkem) compiled the body against absent HPKE symbols
and failed to build under -Werror.
- test_sakke.c: make the wc_GenerateSakkeRskTable / wc_GenerateSakkePointITable
/ wc_SetSakkePointITable checks SP-backend agnostic. The required table size
is 0 on the small-stack SP path but non-zero on the full precomputation path
(sizeof(sp_table_entry_1024) * 1167 / * 256), so the previous fixed
"len == 0" and success-with-tiny-buffer assertions failed (and could write a
full-size table into the small stack buffer) under --enable-all. Capture the
queried length and branch: the Rsk table builds into a correctly-sized heap
buffer; the PointI table's full-path build/store is left to the sakke_test
KAT (it stores the pointer in the key).
- codespell: rename addRes -> addResult in test_sakke_whitebox.c and reword a
comment in test_hpke.c ("statics").
The assembly/SP generators had been modified but not all output files were
generated.
All files now are up to date with the latest generator scripts, that were fixed.
wolfevent.c (the wolfEvent completion queue) only compiled under
--enable-asynccrypt: AM_CONDITIONAL([BUILD_WOLFEVENT],...) tested only
ENABLED_ASYNCCRYPT. But HAVE_WOLF_EVENT is a user-settable macro that
internal.c/ssl.c gate their wolfEventQueue_* references on, so a
--enable-usersettings build that defines HAVE_WOLF_EVENT referenced the
queue API while the object was never built -> link error (undefined
wolfEventQueue_Init/Free). BUILD_WOLFEVENT was also the only BUILD_*
conditional missing the standard "|| ENABLED_USERSETTINGS = yes" escape
hatch that lets a header-driven build compile a source and defer the
decision to the file's own #ifdef.
Add that clause (matching BUILD_FALCON/BUILD_MLKEM/etc.) so usersettings
builds compile wolfevent.c; its internal #ifdef HAVE_WOLF_EVENT still
gates whether the code is active, so non-event builds get an empty object.
Also silence wolfEvent_Poll's unused-parameter -Werror in non-async builds
(event/flags are consumed only by the async hardware poll), which the
above change surfaces now that the file compiles without WOLFSSL_ASYNC_CRYPT.
Restore the original short-circuit XMALLOC chains and leave the zeroing to
mp_init_multi(). On a partial allocation failure mp_init_multi() is skipped,
so nothing is initialized: free whatever was allocated right there and NULL
the pointers, so the shared cleanup at the end of the function never calls
mp_clear()/mp_forcezero() on an allocated-but-uninitialized mp_int.
No extra mp_init() calls, no XMEMSET, and the returned error codes are
unchanged.
Initialize the mp_int temporaries as soon as they are allocated in
wc_CompareDiffPQ(), _CheckProbablePrime() and wc_CheckProbablePrime_ex(),
so the cleanup path handles them consistently in all cases.
wc_mlkem.h/test_mlkem.c: Respect WC_NO_CONSTRUCTORS guard.
settings.h, fe_operations.h: move WOLFSSL_CURVE25519_USE_ED25519 derivation into settings.h so the assembler sees it; fixes fe_cmov_table undefined on ARM32.
ge_448.c: shift the product instead of the byte in six sc448_* loops, dodging a GCC ARM32 NEON miscompile that produced wrong ed448 signatures; table shrunk [56]→[28].