From 68972905f4f08b2bebbd4279039df6d440e2cdb4 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Thu, 6 Aug 2026 16:33:22 +0200 Subject: [PATCH] tests: repair the white-boxes that stopped building Six white-box builds were being skipped, each contributing nothing to the union while the runs still reported success. test_frodokem_fault_common.h: a comment contained "wc_Shake*" followed by "/wc_AesEcbEncrypt", and the "*/" closed the block comment, so the rest of the sentence parsed as code. One character in a shared header took out two white-boxes across two variants. test_wc_xmss_impl_whitebox.c: wc_xmss_rand_hash_lr(), wc_xmss_chain_sha256_32() and the BdsState helpers exist only in the non-small signing path, so the file never compiled under WOLFSSL_WC_XMSS_SMALL. Each section now carries the guard its target carries in wc_xmss_impl.c, and the existing stub block covers the excluded builds. test_mldsa_fault_whitebox.c: the DER encode/decode entry points need ASN.1 support plus the export and private-key options. All ten call sites now sit behind one WB_MLDSA_ASN1 gate; without it the sweeps cover the raw import/export paths instead. test_memory_whitebox.c: this file compiles memory.c with WOLFSSL_STATIC_MEMORY, where the wc_MemStats_Ptr definition is guarded out, while the rest of the library still references it through mem_track.h. With memory.o trimmed from the archive that reference dangled. Supply the definition; void* because the type is not visible here and only the storage matters. test_rsa_fault_whitebox.c: setvbuf(stdout) so output survives a run that dies mid-buffer. Measured after each fix: frodokem, xmss, mldsa and infra now build every white-box in every variant. wc_xmss_impl.c returns to 57/74 -- an earlier attempt at the xmss fix removed a section that was still live and cost a condition. --- tests/unit-mcdc/test_frodokem_fault_common.h | 7 ++-- tests/unit-mcdc/test_memory_whitebox.c | 10 +++++ tests/unit-mcdc/test_mldsa_fault_whitebox.c | 21 ++++++++++ tests/unit-mcdc/test_rsa_fault_whitebox.c | 4 ++ tests/unit-mcdc/test_wc_xmss_impl_whitebox.c | 44 +++++++++++++------- 5 files changed, 67 insertions(+), 19 deletions(-) diff --git a/tests/unit-mcdc/test_frodokem_fault_common.h b/tests/unit-mcdc/test_frodokem_fault_common.h index b5cb778f5d..eacca96112 100644 --- a/tests/unit-mcdc/test_frodokem_fault_common.h +++ b/tests/unit-mcdc/test_frodokem_fault_common.h @@ -63,9 +63,10 @@ * FrodoKEM scratch takes the AESNI/C non-allocating path), so NO heap-fault * index can make them fail. The mat file's 13 residuals are therefore NOT * closable by this heap-alloc mock under any x86 variant -- they would need - * a primitive-return fault mock (stub wc_Shake*/wc_AesEcbEncrypt), a - * separate deferred technique. This driver still exercises the mat file - * end to end (its baseline true-chain rows) but closes none of the 13. + * a primitive-return fault mock (stubbing the wc_Shake family and + * wc_AesEcbEncrypt), a separate deferred technique. This driver still + * exercises the mat file end to end (its baseline true-chain rows) but + * closes none of the 13. * * Crash-safety: every armed call either fails an allocation whose MEMORY_E the * FrodoKEM cleanup absorbs (that cleanup is what is under test) or returns diff --git a/tests/unit-mcdc/test_memory_whitebox.c b/tests/unit-mcdc/test_memory_whitebox.c index 1312f21299..6b2e7b4374 100644 --- a/tests/unit-mcdc/test_memory_whitebox.c +++ b/tests/unit-mcdc/test_memory_whitebox.c @@ -143,6 +143,16 @@ #include +/* memory.c defines wc_MemStats_Ptr only in the non-static-memory build, but + * this file compiles it with WOLFSSL_STATIC_MEMORY, while the rest of the + * library still references the symbol via mem_track.h. Since memory.o is + * trimmed from the archive, supply the definition it would have provided. + * Declared void* because memoryStats is not visible here: only the storage + * matters, and nothing in this binary dereferences it. */ +#if defined(WOLFSSL_TRACK_MEMORY) && defined(USE_WOLFSSL_MEMORY) +void *wc_MemStats_Ptr; +#endif + #include #include diff --git a/tests/unit-mcdc/test_mldsa_fault_whitebox.c b/tests/unit-mcdc/test_mldsa_fault_whitebox.c index ce8f5a97ab..69ffdc5e90 100644 --- a/tests/unit-mcdc/test_mldsa_fault_whitebox.c +++ b/tests/unit-mcdc/test_mldsa_fault_whitebox.c @@ -133,6 +133,14 @@ static int wb_fail = 0; #define WB_NOTE(msg) do { printf(" [wb] %s\n", (msg)); } while (0) +/* The DER encode/decode entry points exist only with ASN.1 support and the + * export/private-key options they each need (dilithium.h). Where they are not + * built, the sweeps below cover the raw import/export paths instead. */ +#if !defined(WOLFSSL_MLDSA_NO_ASN1) && defined(WC_ENABLE_ASYM_KEY_EXPORT) && \ + defined(WOLFSSL_MLDSA_PRIVATE_KEY) && defined(WOLFSSL_MLDSA_PUBLIC_KEY) + #define WB_MLDSA_ASN1 +#endif + #if !defined(WOLFSSL_HAVE_MLDSA) int main(void) @@ -248,6 +256,7 @@ static void sweep_export(wc_MlDsaKey* key) mcdc_fa_arm(n); (void)wc_MlDsaKey_ExportPrivRaw(key, s_privRaw, &l2); mcdc_fa_disarm(); +#ifdef WB_MLDSA_ASN1 mcdc_fa_arm(n); (void)wc_MlDsaKey_PublicKeyToDer(key, s_pubDer, (word32)sizeof(s_pubDer), 1); @@ -256,6 +265,7 @@ static void sweep_export(wc_MlDsaKey* key) (void)wc_MlDsaKey_PrivateKeyToDer(key, s_privDer, (word32)sizeof(s_privDer)); mcdc_fa_disarm(); +#endif } } @@ -265,6 +275,10 @@ static void sweep_export(wc_MlDsaKey* key) static void sweep_decode(const byte* pubDer, word32 pubDerLen, const byte* privDer, word32 privDerLen) { +#ifndef WB_MLDSA_ASN1 + (void)pubDer; (void)pubDerLen; (void)privDer; (void)privDerLen; + WB_NOTE("ASN.1 key coding not built; decode sweep skipped"); +#else int n; for (n = 1; n <= K_DECODE; n++) { wc_MlDsaKey k; @@ -285,6 +299,7 @@ static void sweep_decode(const byte* pubDer, word32 pubDerLen, wc_MlDsaKey_Free(&k); } } +#endif /* WB_MLDSA_ASN1 */ } #endif /* !MCDC_FA_UNAVAILABLE */ @@ -337,6 +352,7 @@ int main(int argc, char** argv) (void)wc_MlDsaKey_ExportPrivRaw(&key, s_privRaw, &l); } +#ifdef WB_MLDSA_ASN1 pubDerLen = wc_MlDsaKey_PublicKeyToDer(&key, s_pubDer, (word32)sizeof(s_pubDer), 1); if (pubDerLen < 0) { @@ -347,6 +363,8 @@ int main(int argc, char** argv) if (privDerLen < 0) { privDerLen = 0; } +#endif +#ifdef WB_MLDSA_ASN1 /* one unarmed round trip through the decode paths for baseline coverage */ if (pubDerLen > 0) { wc_MlDsaKey dk; @@ -368,6 +386,7 @@ int main(int argc, char** argv) wc_MlDsaKey_Free(&dk); } } +#endif #ifndef MCDC_FA_UNAVAILABLE if (do_probe) { @@ -395,6 +414,7 @@ int main(int argc, char** argv) (void)wc_MlDsaKey_VerifyCtx(&key, s_sig, sigLen, NULL, 0, s_msg, (word32)sizeof(s_msg), &r); printf(" PROBE verify allocs = %lu\n", mcdc_fa_count); +#ifdef WB_MLDSA_ASN1 if (pubDerLen > 0 && wc_MlDsaKey_Init(&pk, NULL, INVALID_DEVID) == 0) { word32 idx = 0; @@ -417,6 +437,7 @@ int main(int argc, char** argv) mcdc_fa_disarm(); wc_MlDsaKey_Free(&pk); } +#endif /* WB_MLDSA_ASN1 */ mcdc_fa_disarm(); mcdc_fa_restore(); wc_MlDsaKey_Free(&key); diff --git a/tests/unit-mcdc/test_rsa_fault_whitebox.c b/tests/unit-mcdc/test_rsa_fault_whitebox.c index b18308e266..556b4ffa99 100644 --- a/tests/unit-mcdc/test_rsa_fault_whitebox.c +++ b/tests/unit-mcdc/test_rsa_fault_whitebox.c @@ -252,6 +252,10 @@ int main(int argc, char** argv) const char* only = (do_sweep && argc > 1) ? argv[1] : NULL; #define WANT(s) (only == NULL || strcmp(only, (s)) == 0) WC_RNG rng; + + /* Unbuffered: if a fault-injected path dies, whatever ran so far must + * still be in the log. */ + setvbuf(stdout, NULL, _IONBF, 0); RsaKey key; byte msg[32]; byte ct[WB_RSA_BYTES]; diff --git a/tests/unit-mcdc/test_wc_xmss_impl_whitebox.c b/tests/unit-mcdc/test_wc_xmss_impl_whitebox.c index 5fa0b73e23..80883d8f3d 100644 --- a/tests/unit-mcdc/test_wc_xmss_impl_whitebox.c +++ b/tests/unit-mcdc/test_wc_xmss_impl_whitebox.c @@ -356,8 +356,8 @@ static void wb_hash_family_pairs(void) } state.params = ¶msFull; - /* Lines 1033-1035 / 1218-1220: wc_xmss_rand_hash() / - * wc_xmss_rand_hash_lr()'s "params->n == XMSS_SHA256_32_N" operand. */ + /* wc_xmss_rand_hash() and wc_xmss_rand_hash_lr()'s + * "params->n == XMSS_SHA256_32_N" operand, both arms of each. */ state.ret = 0; XMEMSET(&addr, 0, sizeof(addr)); wc_xmss_rand_hash(&state, data, pk_seed, addr, hashOut); @@ -375,6 +375,9 @@ static void wb_hash_family_pairs(void) } state.params = ¶msFull; +/* wc_xmss_rand_hash_lr() is compiled under this condition only + * (wc_xmss_impl.c). */ +#if !defined(WOLFSSL_WC_XMSS_SMALL) || defined(WOLFSSL_XMSS_VERIFY_ONLY) state.ret = 0; XMEMSET(&addr, 0, sizeof(addr)); wc_xmss_rand_hash_lr(&state, data, data + 32, pk_seed, addr, hashOut); @@ -391,6 +394,7 @@ static void wb_hash_family_pairs(void) wb_fail = 1; } state.params = ¶msFull; +#endif #ifndef WOLFSSL_XMSS_VERIFY_ONLY /* Lines 1813-1815: wc_xmss_wots_gen_pk(). */ @@ -494,9 +498,12 @@ static void wb_hash_family_pairs(void) * is "i < XMSS_WOTS_W" alone that is true for i=1..15 and false at i=16 - * both sides of that one operand, shown within this single call. ********************************************/ +/* wc_xmss_chain_sha256_32() is built only in the non-small SHA-256 path + * (wc_xmss_impl.c). */ +#if !defined(WOLFSSL_WC_XMSS_SMALL) && defined(WC_XMSS_SHA256) static void wb_wots_chain_loop(void) { - /* Line 1623: wc_xmss_chain_sha256_32() - fixed SHA-256/32-byte path. */ + /* wc_xmss_chain_sha256_32() - fixed SHA-256/32-byte path. */ { XmssParams params; XmssState state; @@ -560,12 +567,21 @@ static void wb_wots_chain_loop(void) } } #else - WB_NOTE("WC_XMSS_SHA512 not compiled in; generic wc_xmss_chain (line " - "1697) arm skipped"); + WB_NOTE("WC_XMSS_SHA512 not compiled in; generic wc_xmss_chain arm " + "skipped"); #endif } +#else +static void wb_wots_chain_loop(void) +{ + WB_NOTE("WOLFSSL_WC_XMSS_SMALL: wc_xmss_chain_sha256_32 not built; " + "chain-loop section skipped"); +} +#endif /* !WOLFSSL_WC_XMSS_SMALL && WC_XMSS_SHA256 */ -#ifndef WOLFSSL_XMSS_VERIFY_ONLY +/* BdsState and the BDS helpers exist only in the non-small signing path + * (wc_xmss_impl.c). */ +#if !defined(WOLFSSL_XMSS_VERIFY_ONLY) && !defined(WOLFSSL_WC_XMSS_SMALL) /******************************************** * 2846: wc_xmss_bds_next_idx()'s "if ((hsk > 0) && (i == 3))". * hsk = sub_h - bds_k. Direct calls with offset=0 (so the function's @@ -999,28 +1015,24 @@ static void wb_full_cycle_d1(void) } } } -#else /* WOLFSSL_XMSS_VERIFY_ONLY */ +#else /* verify-only, or the small signing path */ static void wb_bds_next_idx(void) { - WB_NOTE("WOLFSSL_XMSS_VERIFY_ONLY: signing-side BDS helpers not " - "compiled in; wb_bds_next_idx skipped"); + WB_NOTE("BDS helpers not compiled in; wb_bds_next_idx skipped"); } static void wb_bds_auth_path(void) { - WB_NOTE("WOLFSSL_XMSS_VERIFY_ONLY: signing-side BDS helpers not " - "compiled in; wb_bds_auth_path skipped"); + WB_NOTE("BDS helpers not compiled in; wb_bds_auth_path skipped"); } static void wb_full_cycle_d2(void) { - WB_NOTE("WOLFSSL_XMSS_VERIFY_ONLY: keygen/sign not compiled in; " - "wb_full_cycle_d2 skipped"); + WB_NOTE("keygen/sign not compiled in; wb_full_cycle_d2 skipped"); } static void wb_full_cycle_d1(void) { - WB_NOTE("WOLFSSL_XMSS_VERIFY_ONLY: keygen/sign not compiled in; " - "wb_full_cycle_d1 skipped"); + WB_NOTE("keygen/sign not compiled in; wb_full_cycle_d1 skipped"); } -#endif /* !WOLFSSL_XMSS_VERIFY_ONLY */ +#endif /* !WOLFSSL_XMSS_VERIFY_ONLY && !WOLFSSL_WC_XMSS_SMALL */ #else /* WOLFSSL_HAVE_XMSS */