Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions tests/unit-mcdc/test_slhdsa_hash_fault_whitebox.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,17 @@
* ImportPublic() (whose SHA-2 midstate precompute is the only caller of
* slhdsakey_precompute_sha2_midstates()).
*
* NOT COMPILED HERE: the SHA-512 code is only built with a category 3/5 SHA2
* parameter set (WC_SLHDSA_NEED_SHA512), and this module's base config
* compiles ONLY the 128-bit sets (WOLFSSL_SLHDSA_PARAM_NO_192/256 and
* *_NO_SHA2_192/256), so these decisions are not in the build to cover:
* - `(ret == 0) && (n > 16)` / `(ret == 0) && (key->params->n > 16)` in
* slhdsakey_precompute_sha2_midstates() and wc_SlhDsaKey_Init().
* - slhdsakey_h_msg_sha2()'s `(ret == 0) && (hdr != NULL)` and
* `(ret == 0) && (ctxSz > 0) && (ctx != NULL)` in its SHA-512 arm.
*
* NOT REACHABLE HERE (documented residuals, mirrored in
* the exclusion record):
* - `(ret == 0) && (n > 16)` / `(ret == 0) && (key->params->n > 16)`: the
* second operand needs a category 3/5 parameter set, and this module's base
* config compiles ONLY the 128-bit sets (WOLFSSL_SLHDSA_PARAM_NO_192/256
* and *_NO_SHA2_192/256), so n is always 16. NEITHER operand pairs: with
* `n > 16` pinned false the decision is false in every vector, so flipping
* `ret == 0` cannot change the outcome either.
* - slhdsakey_h_msg_sha2()'s `(ret == 0) && (hdr != NULL)` and
* `(ret == 0) && (ctxSz > 0) && (ctx != NULL)`: those two live in the
* `else` arm of `if (n == WC_SLHDSA_N_128)`, i.e. the SHA-512 category 3/5
* arm, which the 128-bit-only parameter table can never select.
* - `(ret != 0) && WC_VAR_OK(sk)`: without WOLFSSL_SMALL_STACK, types.h
* defines WC_VAR_OK(x) as the literal 1, so the operand is not merely
* undriven -- it has no false side to drive. No slhdsa variant sets
Expand All @@ -94,8 +93,9 @@
* skip stub. main() always returns 0.
*/

/* wc_SlhDsaKey_Init()'s `(ret == 0) && (key->params->n > 16)` takes its ret
* from wc_InitSha256() and from nothing else, so the SHA context-init family
/* wc_SlhDsaKey_Init()'s hash-object init checks take their ret from
* wc_InitSha256() (and, with a category 3/5 SHA2 set compiled in, feed
* `(ret == 0) && (key->params->n > 16)`), so the SHA context-init family
* has to be interposed too. It is opt-in, and armed only inside
* wb_init_rows(); every other sweep here builds its keys while disarmed. */
#define MCDC_FH_WITH_SHA_INIT
Expand Down Expand Up @@ -423,8 +423,9 @@ static void wb_sweep_checkkey(int param)

/* Raw import: slhdsakey_precompute_sha2_midstates() is reached only from
* ImportPrivate / ImportPublic / MakeKeyWithRandom, and an armed import is the
* cheapest way to make its `(ret == 0) && (n > 16)` guard see ret != 0 -- the
* import does almost nothing before the precompute, so a low fault index lands
* cheapest way to make its ret checks (and, with a category 3/5 SHA2 set
* compiled in, its `(ret == 0) && (n > 16)` guard) see ret != 0 -- the import
* does almost nothing before the precompute, so a low fault index lands
* squarely inside it. */
static void wb_sweep_import(int param)
{
Expand Down Expand Up @@ -458,9 +459,11 @@ static void wb_sweep_import(int param)
printf(" [wb] param %d: import sweep: %ld points\n", param, points);
}

/* wc_SlhDsaKey_Init()'s `(ret == 0) && (key->params->n > 16)` -- the only
* assignment to ret before it is wc_InitSha256()'s, so the SHA context-init
* interposer is what drives the first operand false. */
/* wc_SlhDsaKey_Init()'s hash-object init checks -- for the SHA2 sets the
* first assignment to ret is wc_InitSha256()'s, so the SHA context-init
* interposer is what drives `ret == 0` false, including in
* `(ret == 0) && (key->params->n > 16)` when a category 3/5 SHA2 set is
* compiled in. */
static void wb_init_rows(int param)
{
SlhDsaKey k2;
Expand All @@ -477,6 +480,7 @@ static void wb_init_rows(int param)
printf(" [wb] param %d: init hash-object rows exercised\n", param);
}

#ifndef NO_ASN
/* Import/export + DER encode/decode: the ASN-side residuals
* (`(key->params != NULL) && ...`, `while (ret == 0 && *inOutIdx < seqEnd)`)
* live here and cost nothing to drive. */
Expand Down Expand Up @@ -568,6 +572,7 @@ static void wb_der_rows(int param)

(void)wc_SlhDsaKey_ExportPublic(&wb_key, pub, &idx);
}
#endif /* !NO_ASN */

static void wb_run_param(int param)
{
Expand All @@ -594,8 +599,10 @@ static void wb_run_param(int param)
wb_sweep_verify(param);
if (!wb_expired())
wb_sweep_prehash(param);
#ifndef NO_ASN
if (!wb_expired())
wb_der_rows(param);
#endif
if (!wb_expired())
wb_sweep_import(param);
if (!wb_expired())
Expand Down
46 changes: 34 additions & 12 deletions tests/unit-mcdc/test_slhdsa_whitebox.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ static int wb_fail = 0;

#ifdef WOLFSSL_HAVE_SLHDSA

#ifndef NO_ASN
/* ------------------------------------------------------------------------- *
* slhdsa_find_params(): found vs not-found (both halves of the table compare).
* Only compiled with the DER decoders that use it.
* ------------------------------------------------------------------------- */
static void wb_find_params(void)
{
Expand Down Expand Up @@ -79,6 +81,7 @@ static void wb_find_params(void)

WB_NOTE("slhdsa_find_params found/not-found pair exercised");
}
#endif /* !NO_ASN */

/* ------------------------------------------------------------------------- *
* slhdsakey_base_2b(): nested for/while loop decisions.
Expand Down Expand Up @@ -125,15 +128,18 @@ static void wb_ha_encode(void)
adrs[i] = (word32)(0x01020300u + (word32)i);
}

#ifndef WOLFSSL_SLHDSA_NO_SHAKE
/* HA_Encode: the WOLFSSL_WC_SLHDSA_SMALL variant takes the for-loop body
* (its "i < 8" decision), the default variant the unrolled writes. Either
* way this is the direct, sign-free drive of that arm. */
* way this is the direct, sign-free drive of that arm. HA_Encode is only
* compiled when a SHAKE parameter set is. */
XMEMSET(address, 0, sizeof(address));
HA_Encode(adrs, address);
if ((address[0] == 0) && (address[SLHDSA_HA_SZ - 1] != 0)) {
/* purely to consume the output so it is not optimized away */
WB_NOTE("HA_Encode produced an unexpected all-zero prefix");
}
#endif

#ifdef WOLFSSL_SLHDSA_SHA2
/* HA_Encode_Compressed is only compiled under WOLFSSL_SLHDSA_SHA2. */
Expand All @@ -148,17 +154,20 @@ static void wb_ha_encode(void)
* SHA-2 message-hash static functions: gap-closing supplement (see the uncovered-condition report).
*
* The tests/api DecisionCoverage additions close every arg-check reachable
* from the public API. What's left needs either a real n>16 SHA-2 param
* (every suite variant restricts to 128-bit only, see config_base's
* notes) or a ctx/ctxSz combination the public API itself rejects before
* ever reaching these static functions (ctx==NULL with ctxSz>0 is BAD_FUNC_ARG at
* the wc_SlhDsaKey_Sign/Verify layer). Both are driven directly here.
* from the public API. What's left is either the n>16 SHA-512 code or a
* ctx/ctxSz combination the public API itself rejects before ever reaching
* these static functions (ctx==NULL with ctxSz>0 is BAD_FUNC_ARG at the
* wc_SlhDsaKey_Sign/Verify layer). Both are driven directly here. The SHA-512
* code is only compiled in with a category 3/5 SHA2 parameter set
* (WC_SLHDSA_NEED_SHA512), so in the 128-bit-only suite variants (see
* config_base's notes) it is not in the build at all.
* ------------------------------------------------------------------------- */
#ifdef WOLFSSL_SLHDSA_SHA2

/* slhdsakey_precompute_sha2_midstates(): "(ret==0) && (n>16)" -- n>16
* (SHA-512 midstate) half. A locally-built SlhDsaParameters with n=24
* exercises it without any variant ever compiling a real n>16 param. */
* (SHA-512 midstate) half, compiled in only with WC_SLHDSA_NEED_SHA512. A
* locally-built SlhDsaParameters with n=24 exercises it without needing a
* real category 3/5 key. */
static void wb_precompute_sha2_midstates(void)
{
SlhDsaKey key;
Expand All @@ -176,16 +185,19 @@ static void wb_precompute_sha2_midstates(void)
wb_fail = 1;
}

#ifdef WC_SLHDSA_NEED_SHA512
Comment thread
LinuxJedi marked this conversation as resolved.
Resolved
/* n > 16 (categories 3, 5): true side. The function only reads
* key->params->n and key->sk, so this crafted entry is a faithful
* exercise of the SHA-512 midstate branch. */
* exercise of the SHA-512 midstate branch. The branch is only compiled
* when a category 3 or 5 SHA2 parameter set is. */
fakeParams.n = 24;
key.hash.sha2.sha256_mid_inited = 0;
key.hash.sha2.sha512_mid_inited = 0;
if (slhdsakey_precompute_sha2_midstates(&key) != 0) {
WB_NOTE("precompute_sha2_midstates(n=24) failed");
wb_fail = 1;
}
#endif

/* Free the hash objects directly (not via wc_SlhDsaKey_Free): fakeParams
* isn't a real table entry, so SLHDSA_IS_SHA2(key->params->param) can't
Expand All @@ -199,6 +211,7 @@ static void wb_precompute_sha2_midstates(void)
if (key.hash.sha2.sha256_mid_inited) {
wc_Sha256Free(&key.hash.sha2.sha256_mid);
}
#ifdef WC_SLHDSA_NEED_SHA512
if (key.hash.sha2.sha512_inited) {
wc_Sha512Free(&key.hash.sha2.sha512);
}
Expand All @@ -208,6 +221,7 @@ static void wb_precompute_sha2_midstates(void)
if (key.hash.sha2.sha512_mid_inited) {
wc_Sha512Free(&key.hash.sha2.sha512_mid);
}
#endif

WB_NOTE("slhdsakey_precompute_sha2_midstates n<=16/n>16 pair exercised");
}
Expand Down Expand Up @@ -250,8 +264,9 @@ static void wb_prf_msg_sha2_ctx(void)

/* slhdsakey_h_msg_sha2(): SHA-256 branch's "ctx!=NULL" pair (same rationale
* as wb_prf_msg_sha2_ctx above) plus the SHA-512 branch (n>16, category 3/5)
* hdr/ctx/ctxSz decisions -- unreachable from the API for the same reason as
* wb_precompute_sha2_midstates (no variant ever builds an n>16 param). */
* hdr/ctx/ctxSz decisions, when WC_SLHDSA_NEED_SHA512 compiles that branch
* in -- driven with a crafted n=24 entry for the same reason as
* wb_precompute_sha2_midstates. */
static void wb_h_msg_sha2_ctx_pairs(void)
{
SlhDsaKey key;
Expand Down Expand Up @@ -280,7 +295,9 @@ static void wb_h_msg_sha2_ctx_pairs(void)
wb_fail = 1;
}

/* SHA-512 branch (n > WC_SLHDSA_N_128). Four combinations:
#ifdef WC_SLHDSA_NEED_SHA512
/* SHA-512 branch (n > WC_SLHDSA_N_128), only compiled when a category 3
* or 5 SHA2 parameter set is. Four combinations:
* A: hdr==NULL, ctxSz==0 -> both false
* B: hdr!=NULL, ctxSz==0 -> hdr pair's true side
* C: hdr!=NULL, ctxSz>0, ctx==NULL -> ctxSz>0 T, ctx!=NULL F
Expand Down Expand Up @@ -312,19 +329,22 @@ static void wb_h_msg_sha2_ctx_pairs(void)
WB_NOTE("h_msg_sha2(n=24,D) failed");
wb_fail = 1;
}
#endif

if (key.hash.sha2.sha256_inited) {
wc_Sha256Free(&key.hash.sha2.sha256);
}
if (key.hash.sha2.sha256_2_inited) {
wc_Sha256Free(&key.hash.sha2.sha256_2);
}
#ifdef WC_SLHDSA_NEED_SHA512
if (key.hash.sha2.sha512_inited) {
wc_Sha512Free(&key.hash.sha2.sha512);
}
if (key.hash.sha2.sha512_2_inited) {
wc_Sha512Free(&key.hash.sha2.sha512_2);
}
#endif

WB_NOTE("slhdsakey_h_msg_sha2 hdr/ctx independence pairs exercised");
}
Expand Down Expand Up @@ -419,7 +439,9 @@ int main(void)
printf(" WOLFSSL_HAVE_SLHDSA not defined; nothing to exercise\n");
return 0;
#else
#ifndef NO_ASN
wb_find_params();
#endif
wb_base_2b();
wb_ha_encode();
#ifdef WOLFSSL_SLHDSA_SHA2
Expand Down
Loading
Loading