@@ -55912,10 +55912,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5591255912 word32 bufSz = 0;
5591355913#ifdef WOLFSSL_NO_MALLOC
5591455914 static byte sk[2048];
55915- static byte old_sk[2048];
5591655915#else
5591755916 byte * sk = NULL;
55918- byte * old_sk = NULL;
5591955917#endif
5592055918 const char * msg = "XMSS post quantum signature test";
5592155919 word32 msgSz = (word32) XSTRLEN(msg);
@@ -55930,8 +55928,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5593055928#endif
5593155929#ifdef WOLFSSL_NO_MALLOC
5593255930 static byte sig[4096];
55931+ static byte old_sig[4096];
5593355932#else
5593455933 byte * sig = NULL;
55934+ byte * old_sig = NULL;
5593555935#endif
5593655936 int ret2 = -1;
5593755937 int ret = WC_TEST_RET_ENC_NC;
@@ -55968,13 +55968,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5596855968 ret = wc_XmssKey_GetSigLen(&signingKey, &sigSz);
5596955969 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); }
5597055970
55971- /* Allocate signature array . */
55971+ /* Allocate signature buffers (current and previous iteration) . */
5597255972#ifdef WOLFSSL_NO_MALLOC
55973+
5597355974 if (sigSz > sizeof(sig))
5597455975 ERROR_OUT(WC_TEST_RET_ENC_NC, out);
5597555976#else
5597655977 sig = (byte *)XMALLOC(sigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5597755978 if (sig == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); }
55979+
55980+ old_sig = (byte *)XMALLOC(sigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
55981+ if (old_sig == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); }
5597855982#endif
5597955983
5598055984 bufSz = sigSz;
@@ -55986,20 +55990,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5598655990 fprintf(stderr, "sigSz: %d\n", sigSz);
5598755991#endif
5598855992
55989- /* Allocate current and old secret keys.*/
55993+ /* Allocate the secret key buffer used by the software write/read
55994+ * callbacks. */
5599055995#ifdef WOLFSSL_NO_MALLOC
5599155996 if (skSz > sizeof(sk))
5599255997 ERROR_OUT(WC_TEST_RET_ENC_NC, out);
5599355998#else
5599455999 sk = (unsigned char *)XMALLOC(skSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5599556000 if (sk == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); }
55996-
55997- old_sk = (unsigned char *)XMALLOC(skSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
55998- if (old_sk == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); }
5599956001#endif
5600056002
5600156003 XMEMSET(sk, 0, skSz);
56002- XMEMSET(old_sk, 0, skSz);
5600356004 XMEMSET(sig, 0, sigSz);
5600456005
5600556006 ret = wc_XmssKey_SetWriteCb(&signingKey, xmss_write_key_mem);
@@ -56019,20 +56020,25 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5601956020 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); }
5602056021
5602156022 /* Repeat a few times to check that:
56022- * 1. The secret key is mutated on each sign.
56023+ * 1. Each Sign advances state (so signing the same message yields a
56024+ * different signature than the previous iteration).
5602356025 * 2. We can verify each new signature.
5602456026 * Only do a few times, because the full signature space
5602556027 * for this parameter set is huge. */
5602656028 for (i = 0; i < 10; ++i) {
56027- XMEMCPY(old_sk, sk, skSz);
56028-
5602956029 ret = wc_XmssKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
5603056030 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
5603156031 if (sigSz != bufSz) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
5603256032
56033- /* Old secret key and current secret key should not match. */
56034- ret = XMEMCMP(old_sk, sk, skSz);
56035- if (ret == 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
56033+ /* XMSS is deterministic given (SK_state, msg); a stuck leaf would
56034+ * produce an identical signature. This check is agnostic to whether
56035+ * the private state lives in user memory (software path) or on a
56036+ * cryptocb device. */
56037+ if (i > 0) {
56038+ ret = XMEMCMP(old_sig, sig, sigSz);
56039+ if (ret == 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
56040+ }
56041+ XMEMCPY(old_sig, sig, sigSz);
5603656042
5603756043 ret = wc_XmssKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz);
5603856044 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
@@ -56061,11 +56067,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5606156067 XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5606256068 sig = NULL;
5606356069
56070+ XFREE(old_sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56071+ old_sig = NULL;
56072+
5606456073 XFREE(sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5606556074 sk = NULL;
56066-
56067- XFREE(old_sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56068- old_sk = NULL;
5606956075#endif /* !WOLFSSL_NO_MALLOC */
5607056076
5607156077 wc_XmssKey_Free(&signingKey);
@@ -56590,31 +56596,34 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5659056596 word32 msgSz = (word32) XSTRLEN(msg);
5659156597#ifndef WOLFSSL_WC_LMS_SERIALIZE_STATE
5659256598 unsigned char priv[HSS_MAX_PRIVATE_KEY_LEN];
56593- unsigned char old_priv[HSS_MAX_PRIVATE_KEY_LEN];
5659456599#else
5659556600 static unsigned char priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN];
56596- static unsigned char old_priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN];
5659756601#endif
5659856602#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
5659956603 byte * sig = (byte*)XMALLOC(WC_TEST_LMS_SIG_LEN, HEAP_HINT,
5660056604 DYNAMIC_TYPE_TMP_BUFFER);
56605+ byte * old_sig = (byte*)XMALLOC(WC_TEST_LMS_SIG_LEN, HEAP_HINT,
56606+ DYNAMIC_TYPE_TMP_BUFFER);
5660156607#else
5660256608 byte sig[WC_TEST_LMS_SIG_LEN];
56609+ byte old_sig[WC_TEST_LMS_SIG_LEN];
5660356610#endif
5660456611 const byte * kid;
5660556612 word32 kidSz;
5660656613
5660756614 WOLFSSL_ENTER("lms_test");
5660856615
5660956616#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
56610- if (sig == NULL) {
56617+ if ((sig == NULL) || (old_sig == NULL)) {
56618+ XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56619+ XFREE(old_sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5661156620 return WC_TEST_RET_ENC_ERRNO;
5661256621 }
5661356622#endif
5661456623
5661556624 XMEMSET(priv, 0, sizeof(priv));
56616- XMEMSET(old_priv, 0, sizeof(old_priv));
5661756625 XMEMSET(sig, 0, WC_TEST_LMS_SIG_LEN);
56626+ XMEMSET(old_sig, 0, WC_TEST_LMS_SIG_LEN);
5661856627 XMEMSET(&rng, 0, sizeof(rng));
5661956628 XMEMSET(&signingKey, 0, sizeof(signingKey));
5662056629 XMEMSET(&verifyKey, 0, sizeof(verifyKey));
@@ -56659,8 +56668,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5665956668 ret = wc_LmsKey_MakeKey(&signingKey, &rng);
5666056669 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); }
5666156670
56662- XMEMCPY(old_priv, priv, sizeof(priv));
56663-
5666456671 ret = wc_LmsKey_GetKid(NULL, NULL, NULL);
5666556672 if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
5666656673 ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
@@ -56702,21 +56709,32 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5670256709 /* Test wc_LmsKey_Sign input validation. */
5670356710 {
5670456711 word32 smallSz = 1;
56705- wc_lms_write_private_key_cb saved_write_cb;
5670656712
56707- /* Undersized sig buffer should return BUFFER_E. */
56713+ /* Undersized sig buffer should return BUFFER_E. This check runs in
56714+ * wc_LmsKey_Sign before the cryptocb dispatch, so it applies in both
56715+ * software and HSM modes. */
5670856716 ret = wc_LmsKey_Sign(&signingKey, sig, &smallSz, (byte *) msg, msgSz);
5670956717 if (ret != WC_NO_ERR_TRACE(BUFFER_E)) {
5671056718 ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
5671156719 }
5671256720
56713- /* NULL write callback should return BAD_FUNC_ARG. */
56714- saved_write_cb = signingKey.write_private_key;
56715- signingKey.write_private_key = NULL;
56716- ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
56717- signingKey.write_private_key = saved_write_cb;
56718- if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
56719- ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
56721+ #ifdef WOLF_CRYPTO_CB
56722+ /* The NULL-WriteCb -> BAD_FUNC_ARG check in wc_LmsKey_Sign sits after
56723+ * the cryptocb dispatch; an HSM-backed Sign succeeds without ever
56724+ * reaching it. Only exercise this on the pure software path. */
56725+ if (devId == INVALID_DEVID)
56726+ #endif
56727+ {
56728+ wc_lms_write_private_key_cb saved_write_cb;
56729+
56730+ /* NULL write callback should return BAD_FUNC_ARG. */
56731+ saved_write_cb = signingKey.write_private_key;
56732+ signingKey.write_private_key = NULL;
56733+ ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
56734+ signingKey.write_private_key = saved_write_cb;
56735+ if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
56736+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
56737+ }
5672056738 }
5672156739
5672256740 ret = 0;
@@ -56730,17 +56748,21 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5673056748 ERROR_OUT(WC_TEST_RET_ENC_NC, out);
5673156749 }
5673256750
56733- /* Sign with key. The private key will be updated on every signature. */
56751+ /* Sign with key. State advances on every signature. */
5673456752 ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
5673556753 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
5673656754
56737- /* The updated private key should not match the old one. */
56738- if (XMEMCMP(old_priv, priv, sizeof(priv)) == 0) {
56739- printf("error: current priv key should not match old: %d\n", i);
56740- ERROR_OUT(WC_TEST_RET_ENC_I(i), out);
56755+ /* LMS/HSS is deterministic given (state, msg); a stuck leaf would
56756+ * produce an identical signature. This check is agnostic to whether
56757+ * the private state lives in user memory (software path) or on a
56758+ * cryptocb device. */
56759+ if (i > 0) {
56760+ if (XMEMCMP(old_sig, sig, sigSz) == 0) {
56761+ printf("error: current signature should not match old: %d\n", i);
56762+ ERROR_OUT(WC_TEST_RET_ENC_I(i), out);
56763+ }
5674156764 }
56742-
56743- XMEMCPY(old_priv, priv, sizeof(priv));
56765+ XMEMCPY(old_sig, sig, sigSz);
5674456766
5674556767 ret = wc_LmsKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz);
5674656768 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
@@ -56780,6 +56802,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5678056802
5678156803#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
5678256804 XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56805+ XFREE(old_sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5678356806#endif
5678456807
5678556808 return ret;
0 commit comments