@@ -189,6 +189,18 @@ static int wb_intr_ret = 0;
189189#include <stdio.h>
190190
191191static int wb_fail = 0 ;
192+ /* Set while the save is refused. Every driven operation must fail then, so
193+ * these two counters turn that pass from a coverage sweep into a check. */
194+ static int wb_expect_refusal = 0 ;
195+ static int wb_contract_fail = 0 ; /* a refused save failed to stop a call */
196+ static long wb_refused_ok = 0 ; /* failed as required */
197+ static long wb_refused_bad = 0 ; /* succeeded despite a refused save */
198+ #define WB_OUTCOME (ret ) do { \
199+ if (wb_expect_refusal) { \
200+ if ((ret) == 0) wb_refused_bad++; else wb_refused_ok++; \
201+ } } while (0)
202+ /* Evaluates the call once, records its outcome, yields it to the caller. */
203+ #define WB_CHECK (call ) __extension__ ({ int wb_r_ = (call); WB_OUTCOME(wb_r_); wb_r_; })
192204#define WB_NOTE (msg ) do { printf(" [wb] %s\n", (msg)); } while (0)
193205
194206/* Crafted-input driver shared with the sp_c64.c/sp_c32.c white-boxes: the
@@ -260,33 +272,33 @@ static void wb_run_ecc_curve(int curve_id, int fieldSz, const char* label)
260272 return ;
261273 }
262274
263- if (wc_ecc_make_key_ex (& rng , fieldSz , & keyA , curve_id ) != 0 ) {
275+ if (WB_CHECK ( wc_ecc_make_key_ex (& rng , fieldSz , & keyA , curve_id ) ) != 0 ) {
264276 WB_NOTE ("wc_ecc_make_key_ex(keyA) failed" );
265277 wb_fail = 1 ;
266278 ok = 0 ;
267279 }
268- if (ok && wc_ecc_make_key_ex (& rng , fieldSz , & keyB , curve_id ) != 0 ) {
280+ if (ok && WB_CHECK ( wc_ecc_make_key_ex (& rng , fieldSz , & keyB , curve_id ) ) != 0 ) {
269281 WB_NOTE ("wc_ecc_make_key_ex(keyB) failed" );
270282 wb_fail = 1 ;
271283 ok = 0 ;
272284 }
273285
274286 if (ok ) {
275287 sigLen = (word32 )sizeof (sig );
276- if (wc_ecc_sign_hash (wb_digest , (word32 )sizeof (wb_digest ), sig ,
277- & sigLen , & rng , & keyA ) != 0 ) {
288+ if (WB_CHECK ( wc_ecc_sign_hash (wb_digest , (word32 )sizeof (wb_digest ), sig ,
289+ & sigLen , & rng , & keyA )) != 0 ) {
278290 WB_NOTE ("wc_ecc_sign_hash failed" );
279291 wb_fail = 1 ;
280292 }
281- else if (wc_ecc_verify_hash (sig , sigLen , wb_digest ,
282- (word32 )sizeof (wb_digest ), & verifyRes , & keyA ) != 0 ) {
293+ else if (WB_CHECK ( wc_ecc_verify_hash (sig , sigLen , wb_digest ,
294+ (word32 )sizeof (wb_digest ), & verifyRes , & keyA )) != 0 ) {
283295 WB_NOTE ("wc_ecc_verify_hash failed" );
284296 wb_fail = 1 ;
285297 }
286298
287299 PRIVATE_KEY_UNLOCK ();
288300 secretALen = (word32 )sizeof (secretA );
289- if (wc_ecc_shared_secret (& keyA , & keyB , secretA , & secretALen ) != 0 ) {
301+ if (WB_CHECK ( wc_ecc_shared_secret (& keyA , & keyB , secretA , & secretALen ) ) != 0 ) {
290302 WB_NOTE ("wc_ecc_shared_secret(A,B) failed" );
291303 wb_fail = 1 ;
292304 }
@@ -1579,12 +1591,12 @@ static void wb_run_crafted_curve(int curve_id, int fieldSz,
15791591 return ;
15801592 }
15811593
1582- if (wc_ecc_make_key_ex (& rng , fieldSz , & keyA , curve_id ) != 0 ) {
1594+ if (WB_CHECK ( wc_ecc_make_key_ex (& rng , fieldSz , & keyA , curve_id ) ) != 0 ) {
15831595 WB_NOTE ("wc_ecc_make_key_ex(keyA) failed (crafted)" );
15841596 wb_fail = 1 ;
15851597 ok = 0 ;
15861598 }
1587- if (ok && wc_ecc_make_key_ex (& rng , fieldSz , & keyB , curve_id ) != 0 ) {
1599+ if (ok && WB_CHECK ( wc_ecc_make_key_ex (& rng , fieldSz , & keyB , curve_id ) ) != 0 ) {
15881600 WB_NOTE ("wc_ecc_make_key_ex(keyB) failed (crafted)" );
15891601 wb_fail = 1 ;
15901602 ok = 0 ;
@@ -1985,18 +1997,34 @@ int main(void)
19851997 wb_run_crafted ();
19861998 wb_spc_all ();
19871999
1988- /* Refused save: every lane returns its error instead of running,
1989- * so the drivers report failures here by design. */
2000+ /* Refused save: every lane returns its error instead of running, so
2001+ * the drivers report failures here by design. The counters turn that
2002+ * into a check: a call that SUCCEEDS with the save refused means the
2003+ * dispatch found another way to run, which is what this file exists
2004+ * to keep out. */
19902005 cpuid_select_flags (real );
19912006 wb_intr_ret = 1 ;
2007+ wb_expect_refusal = 1 ;
19922008 wb_run_ecc ();
19932009 wb_run_rsa_signverify ();
19942010 wb_run_dh ();
19952011 wb_run_dispatch ();
19962012 wb_run_crafted ();
19972013 wb_spc_all ();
2014+ wb_expect_refusal = 0 ;
19982015 wb_intr_ret = 0 ;
19992016
2017+ printf (" [wb] refused save: %ld calls failed as required, %ld ran anyway\n" ,
2018+ wb_refused_ok , wb_refused_bad );
2019+ if (wb_refused_bad != 0 ) {
2020+ printf (" [wb] FAIL: a refused vector-register save did not stop the call\n" );
2021+ wb_contract_fail = 1 ;
2022+ }
2023+ if (wb_refused_ok == 0 ) {
2024+ printf (" [wb] FAIL: nothing was seen failing, so this check proves nothing\n" );
2025+ wb_contract_fail = 1 ;
2026+ }
2027+
20002028 wb_run_rsa_free ();
20012029
20022030 /* Allocation-failure pass.
@@ -2042,5 +2070,6 @@ int main(void)
20422070 printf (" no SP feature; nothing to exercise\n" );
20432071#endif
20442072 (void )wb_fail ;
2045- return 0 ;
2073+ /* Coverage sweeps stay advisory; the fail-closed contract does not. */
2074+ return wb_contract_fail ;
20462075}
0 commit comments