mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-10-24 04:09:07 +03:00
Add tests for PQC verify clearing *res on error
Falcon: device success, silent device, device error, decline and bad arg. Whitebox: drive the dispatchers' *res clear with NULL res and ret == 0.
This commit is contained in:
@@ -1865,3 +1865,106 @@ int test_falcon_cb_free(void)
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#if defined(HAVE_FALCON) && defined(WOLF_CRYPTO_CB)
|
||||
#define TEST_FALCON_VERIFY_CB_RES
|
||||
#define TEST_FALCON_VERIFY_CB_RES_DEVID 0x46414C56
|
||||
#endif
|
||||
|
||||
#ifdef TEST_FALCON_VERIFY_CB_RES
|
||||
typedef struct FalconVerifyResCtx {
|
||||
int ret; /* Value the device returns. */
|
||||
int writeRes; /* Whether the device writes *res = 1 first. */
|
||||
} FalconVerifyResCtx;
|
||||
|
||||
/* A device that may claim the signature is valid and then returns ctx->ret,
|
||||
* which may be 0, an error or CRYPTOCB_UNAVAILABLE. */
|
||||
static int falcon_verify_res_cb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
FalconVerifyResCtx* cbCtx = (FalconVerifyResCtx*)ctx;
|
||||
|
||||
(void)devIdArg;
|
||||
|
||||
if ((info != NULL) && (info->algo_type == WC_ALGO_TYPE_PK) &&
|
||||
(info->pk.type == WC_PK_TYPE_PQC_SIG_VERIFY) &&
|
||||
(info->pk.pqc_verify.type == WC_PQC_SIG_TYPE_FALCON)) {
|
||||
if (cbCtx->writeRes) {
|
||||
*info->pk.pqc_verify.res = 1;
|
||||
}
|
||||
return cbCtx->ret;
|
||||
}
|
||||
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
}
|
||||
#endif /* TEST_FALCON_VERIFY_CB_RES */
|
||||
|
||||
/* *res must only be 1 when verify returns 0 and the signature was found
|
||||
* valid. Cases expecting 0 start res at 1 to catch a stale value. */
|
||||
int test_falcon_verify_cb_res(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#ifdef TEST_FALCON_VERIFY_CB_RES
|
||||
falcon_key key;
|
||||
byte sig[16];
|
||||
byte msg[16];
|
||||
FalconVerifyResCtx cbCtx;
|
||||
int res;
|
||||
#ifdef WOLF_CRYPTO_CB_ONLY_FALCON
|
||||
const int declineRet = WC_NO_ERR_TRACE(NO_VALID_DEVID);
|
||||
#else
|
||||
/* The software fallback rejects a key with no public key set. */
|
||||
const int declineRet = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
|
||||
#endif
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
XMEMSET(&cbCtx, 0, sizeof(cbCtx));
|
||||
XMEMSET(sig, 0, sizeof(sig));
|
||||
XMEMSET(msg, 0x5a, sizeof(msg));
|
||||
|
||||
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_FALCON_VERIFY_CB_RES_DEVID,
|
||||
falcon_verify_res_cb, &cbCtx), 0);
|
||||
ExpectIntEQ(wc_falcon_init_ex(&key, NULL,
|
||||
TEST_FALCON_VERIFY_CB_RES_DEVID), 0);
|
||||
ExpectIntEQ(wc_falcon_set_level(&key, falcon_levels[0]), 0);
|
||||
|
||||
/* The device verifies the signature. */
|
||||
cbCtx.ret = 0;
|
||||
cbCtx.writeRes = 1;
|
||||
res = 0;
|
||||
ExpectIntEQ(wc_falcon_verify_msg(sig, (word32)sizeof(sig), msg,
|
||||
(word32)sizeof(msg), &res, &key), 0);
|
||||
ExpectIntEQ(res, 1);
|
||||
|
||||
/* The device completes without writing *res. */
|
||||
cbCtx.writeRes = 0;
|
||||
res = 1;
|
||||
ExpectIntEQ(wc_falcon_verify_msg(sig, (word32)sizeof(sig), msg,
|
||||
(word32)sizeof(msg), &res, &key), 0);
|
||||
ExpectIntEQ(res, 0);
|
||||
|
||||
/* The device fails. */
|
||||
cbCtx.ret = WC_NO_ERR_TRACE(WC_HW_E);
|
||||
cbCtx.writeRes = 1;
|
||||
res = 1;
|
||||
ExpectIntEQ(wc_falcon_verify_msg(sig, (word32)sizeof(sig), msg,
|
||||
(word32)sizeof(msg), &res, &key), WC_NO_ERR_TRACE(WC_HW_E));
|
||||
ExpectIntEQ(res, 0);
|
||||
|
||||
/* The device declines, then the fallback rejects the call. */
|
||||
cbCtx.ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
cbCtx.writeRes = 1;
|
||||
res = 1;
|
||||
ExpectIntEQ(wc_falcon_verify_msg(sig, (word32)sizeof(sig), msg,
|
||||
(word32)sizeof(msg), &res, &key), declineRet);
|
||||
ExpectIntEQ(res, 0);
|
||||
|
||||
/* A bad argument is rejected before the device is reached. */
|
||||
res = 1;
|
||||
ExpectIntEQ(wc_falcon_verify_msg(NULL, (word32)sizeof(sig), msg,
|
||||
(word32)sizeof(msg), &res, &key), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(res, 0);
|
||||
|
||||
wc_falcon_free(&key);
|
||||
wc_CryptoCb_UnRegisterDevice(TEST_FALCON_VERIFY_CB_RES_DEVID);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ int test_wc_falcon_set_level_oom_callers(void);
|
||||
int test_wc_falcon_verify_oom(void);
|
||||
int test_wc_FalconDecisionCoverage(void);
|
||||
int test_falcon_cb_free(void);
|
||||
int test_falcon_verify_cb_res(void);
|
||||
|
||||
#define TEST_FALCON_DECLS \
|
||||
TEST_DECL_GROUP("falcon", test_wc_falcon_sizes), \
|
||||
@@ -53,6 +54,7 @@ int test_falcon_cb_free(void);
|
||||
TEST_DECL_GROUP("falcon", test_wc_falcon_set_level_oom_callers), \
|
||||
TEST_DECL_GROUP("falcon", test_wc_falcon_verify_oom), \
|
||||
TEST_DECL_GROUP("falcon", test_wc_FalconDecisionCoverage), \
|
||||
TEST_DECL_GROUP("falcon", test_falcon_cb_free)
|
||||
TEST_DECL_GROUP("falcon", test_falcon_cb_free), \
|
||||
TEST_DECL_GROUP("falcon", test_falcon_verify_cb_res)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_FALCON_H */
|
||||
|
||||
@@ -76,10 +76,12 @@
|
||||
* HMAC, RNG (RandomBlock/RandomSeed), GetCert, CMAC,
|
||||
* HKDF (extract/expand/two-step-CMAC), the generic Copy/Free/SetKey/
|
||||
* ExportKey callbacks, and the ML-KEM / ML-DSA PQC dispatch functions.
|
||||
* wc_SHE (WOLFSSL_SHE) and the LMS/XMSS/FALCON/SLHDSA/FRODOKEM PQC families
|
||||
* are left as residuals - they need family-specific key setup (wc_SHE,
|
||||
* LmsKey, XmssKey, falcon_key, SlhDsaKey) that is out of scope for this
|
||||
* pass; see the WB_NOTE calls below for exactly which are skipped.
|
||||
* LMS PqcStatefulSigVerify is also driven, from a zeroed LmsKey.
|
||||
* wc_SHE (WOLFSSL_SHE), the rest of the LMS/XMSS stateful family and the
|
||||
* FALCON/SLHDSA/FRODOKEM PQC families are left as residuals - they need
|
||||
* family-specific key setup (wc_SHE, LmsKey, XmssKey, falcon_key, SlhDsaKey)
|
||||
* that is out of scope for this pass; see the WB_NOTE calls below for
|
||||
* exactly which are skipped.
|
||||
*
|
||||
* Crash-safety: wb_cb() always returns CRYPTOCB_UNAVAILABLE before touching
|
||||
* `info`, so every `if (dev && dev->cb)` body returns immediately after the
|
||||
@@ -217,6 +219,32 @@ static int wb_cb_hash_fallback_ok(int devId, wc_CryptoInfo* info, void* ctx)
|
||||
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_LMS)
|
||||
/* A device that reports a PQC verify as completed without touching info,
|
||||
* so the post-dev->cb `ret != 0` decision that clears *res in
|
||||
* wc_CryptoCb_PqcVerify{,Msg} and wc_CryptoCb_PqcStatefulSigVerify can be
|
||||
* shown FALSE. Registered only around those calls. */
|
||||
#define WB_DEVID_VERIFY_OK 4
|
||||
|
||||
static int wb_cb_pqc_verify_ok(int devId, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
(void)devId;
|
||||
(void)ctx;
|
||||
if (info == NULL || info->algo_type != WC_ALGO_TYPE_PK)
|
||||
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
#ifdef WOLFSSL_HAVE_MLDSA
|
||||
if (info->pk.type == WC_PK_TYPE_PQC_SIG_VERIFY ||
|
||||
info->pk.type == WC_PK_TYPE_PQC_SIG_VERIFY_MSG)
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef WOLFSSL_HAVE_LMS
|
||||
if (info->pk.type == WC_PK_TYPE_PQC_STATEFUL_SIG_VERIFY)
|
||||
return 0;
|
||||
#endif
|
||||
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
}
|
||||
#endif /* WOLFSSL_HAVE_MLDSA || WOLFSSL_HAVE_LMS */
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB_FIND
|
||||
/* Find callback used ONLY by the :1159/:1189 (F,F) vectors. It rewrites the
|
||||
* INVALID_DEVID lookup that wc_CryptoCb_Curve25519MakePub/Generic issue into
|
||||
@@ -1019,6 +1047,40 @@ int main(void)
|
||||
WB_DRIVE3(mldsa.devId, wc_CryptoCb_PqcVerifyMsg(out, sizeof(out), in,
|
||||
sizeof(in), &res, WC_PQC_SIG_TYPE_MLDSA, &mldsa));
|
||||
|
||||
/* `ret != 0 && res != NULL` after dev->cb: (T,T) a declining
|
||||
* device clears *res, (T,F) res is NULL, (F,-) a device that
|
||||
* completes leaves *res as it wrote it. */
|
||||
if (wc_CryptoCb_RegisterDevice(WB_DEVID_VERIFY_OK,
|
||||
wb_cb_pqc_verify_ok, NULL) != 0)
|
||||
wb_fail = 1;
|
||||
mldsa.devId = WB_DEVID;
|
||||
res = 1;
|
||||
(void)wc_CryptoCb_PqcVerify(out, sizeof(out), in, sizeof(in), NULL,
|
||||
0, 0, &res, WC_PQC_SIG_TYPE_MLDSA, &mldsa);
|
||||
if (res != 0)
|
||||
wb_bad = 1;
|
||||
(void)wc_CryptoCb_PqcVerify(out, sizeof(out), in, sizeof(in), NULL,
|
||||
0, 0, NULL, WC_PQC_SIG_TYPE_MLDSA, &mldsa);
|
||||
res = 1;
|
||||
(void)wc_CryptoCb_PqcVerifyMsg(out, sizeof(out), in, sizeof(in),
|
||||
&res, WC_PQC_SIG_TYPE_MLDSA, &mldsa);
|
||||
if (res != 0)
|
||||
wb_bad = 1;
|
||||
(void)wc_CryptoCb_PqcVerifyMsg(out, sizeof(out), in, sizeof(in),
|
||||
NULL, WC_PQC_SIG_TYPE_MLDSA, &mldsa);
|
||||
mldsa.devId = WB_DEVID_VERIFY_OK;
|
||||
res = 1;
|
||||
(void)wc_CryptoCb_PqcVerify(out, sizeof(out), in, sizeof(in), NULL,
|
||||
0, 0, &res, WC_PQC_SIG_TYPE_MLDSA, &mldsa);
|
||||
if (res != 1)
|
||||
wb_bad = 1;
|
||||
res = 1;
|
||||
(void)wc_CryptoCb_PqcVerifyMsg(out, sizeof(out), in, sizeof(in),
|
||||
&res, WC_PQC_SIG_TYPE_MLDSA, &mldsa);
|
||||
if (res != 1)
|
||||
wb_bad = 1;
|
||||
wc_CryptoCb_UnRegisterDevice(WB_DEVID_VERIFY_OK);
|
||||
|
||||
/* bonus: an unrecognized algorithm type leaves GetDevId at
|
||||
* INVALID_DEVID, which then finds no device */
|
||||
mldsa.devId = WB_DEVID;
|
||||
@@ -1068,11 +1130,52 @@ int main(void)
|
||||
"defined; PQC signature dispatch skipped");
|
||||
#endif
|
||||
|
||||
/* ---- PQC stateful: PqcStatefulSigVerify ----
|
||||
* Only key->devId is read before dev->cb, so a zeroed LmsKey is enough
|
||||
* for the dev&&dev->cb guard and the *res clear after it. */
|
||||
#ifdef WOLFSSL_HAVE_LMS
|
||||
{
|
||||
LmsKey lms;
|
||||
XMEMSET(&lms, 0, sizeof(lms));
|
||||
|
||||
WB_DRIVE3(lms.devId, wc_CryptoCb_PqcStatefulSigVerify(out,
|
||||
sizeof(out), in, sizeof(in), &res, WC_PQC_STATEFUL_SIG_TYPE_LMS,
|
||||
&lms));
|
||||
|
||||
/* *res clear: same three vectors as the ML-DSA block above. */
|
||||
if (wc_CryptoCb_RegisterDevice(WB_DEVID_VERIFY_OK,
|
||||
wb_cb_pqc_verify_ok, NULL) != 0)
|
||||
wb_fail = 1;
|
||||
lms.devId = WB_DEVID;
|
||||
res = 1;
|
||||
(void)wc_CryptoCb_PqcStatefulSigVerify(out, sizeof(out), in,
|
||||
sizeof(in), &res, WC_PQC_STATEFUL_SIG_TYPE_LMS, &lms);
|
||||
if (res != 0)
|
||||
wb_bad = 1;
|
||||
(void)wc_CryptoCb_PqcStatefulSigVerify(out, sizeof(out), in,
|
||||
sizeof(in), NULL, WC_PQC_STATEFUL_SIG_TYPE_LMS, &lms);
|
||||
lms.devId = WB_DEVID_VERIFY_OK;
|
||||
res = 1;
|
||||
(void)wc_CryptoCb_PqcStatefulSigVerify(out, sizeof(out), in,
|
||||
sizeof(in), &res, WC_PQC_STATEFUL_SIG_TYPE_LMS, &lms);
|
||||
if (res != 1)
|
||||
wb_bad = 1;
|
||||
wc_CryptoCb_UnRegisterDevice(WB_DEVID_VERIFY_OK);
|
||||
|
||||
WB_NOTE("PQC LMS: PqcStatefulSigVerify dev&&dev->cb and "
|
||||
"ret!=0&&res!=NULL driven");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---- residuals: not driven in this pass ---- */
|
||||
#if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS)
|
||||
WB_NOTE("RESIDUAL: PqcStatefulSig{KeyGen,Sign,Verify,SigsLeft} "
|
||||
#ifdef WOLFSSL_HAVE_LMS
|
||||
WB_NOTE("RESIDUAL: PqcStatefulSig{KeyGen,Sign,SigsLeft} "
|
||||
"(LMS/XMSS) not driven - needs LmsKey/XmssKey-specific setup, "
|
||||
"out of scope for this pass");
|
||||
#elif defined(WOLFSSL_HAVE_XMSS)
|
||||
WB_NOTE("RESIDUAL: PqcStatefulSig{KeyGen,Sign,Verify,SigsLeft} "
|
||||
"(XMSS) not driven - needs XmssKey-specific setup, "
|
||||
"out of scope for this pass");
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHE
|
||||
WB_NOTE("RESIDUAL: wc_CryptoCb_She* family not driven - needs wc_SHE "
|
||||
|
||||
Reference in New Issue
Block a user