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.
This commit is contained in:
Daniele Lacamera
2026-08-07 09:27:42 +02:00
parent 1344162ce4
commit 68972905f4
5 changed files with 67 additions and 19 deletions
+4 -3
View File
@@ -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
+10
View File
@@ -143,6 +143,16 @@
#include <wolfcrypt/src/memory.c>
/* 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 <stdio.h>
#include <string.h>
@@ -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);
@@ -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];
+28 -16
View File
@@ -356,8 +356,8 @@ static void wb_hash_family_pairs(void)
}
state.params = &paramsFull;
/* 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 = &paramsFull;
/* 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 = &paramsFull;
#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 */