@@ -55982,10 +55982,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5598255982 word32 bufSz = 0;
5598355983#ifdef WOLFSSL_NO_MALLOC
5598455984 static byte sk[2048];
55985- static byte old_sk[2048];
5598655985#else
5598755986 byte * sk = NULL;
55988- byte * old_sk = NULL;
5598955987#endif
5599055988 const char * msg = "XMSS post quantum signature test";
5599155989 word32 msgSz = (word32) XSTRLEN(msg);
@@ -56000,8 +55998,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5600055998#endif
5600155999#ifdef WOLFSSL_NO_MALLOC
5600256000 static byte sig[4096];
56001+ static byte old_sig[4096];
5600356002#else
5600456003 byte * sig = NULL;
56004+ byte * old_sig = NULL;
5600556005#endif
5600656006 int ret2 = -1;
5600756007 int ret = WC_TEST_RET_ENC_NC;
@@ -56038,13 +56038,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5603856038 ret = wc_XmssKey_GetSigLen(&signingKey, &sigSz);
5603956039 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); }
5604056040
56041- /* Allocate signature array . */
56041+ /* Allocate signature buffers (current and previous iteration) . */
5604256042#ifdef WOLFSSL_NO_MALLOC
56043+
5604356044 if (sigSz > sizeof(sig))
5604456045 ERROR_OUT(WC_TEST_RET_ENC_NC, out);
5604556046#else
5604656047 sig = (byte *)XMALLOC(sigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5604756048 if (sig == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); }
56049+
56050+ old_sig = (byte *)XMALLOC(sigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56051+ if (old_sig == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); }
5604856052#endif
5604956053
5605056054 bufSz = sigSz;
@@ -56056,20 +56060,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5605656060 fprintf(stderr, "sigSz: %d\n", sigSz);
5605756061#endif
5605856062
56059- /* Allocate current and old secret keys.*/
56063+ /* Allocate the secret key buffer used by the software write/read
56064+ * callbacks. */
5606056065#ifdef WOLFSSL_NO_MALLOC
5606156066 if (skSz > sizeof(sk))
5606256067 ERROR_OUT(WC_TEST_RET_ENC_NC, out);
5606356068#else
5606456069 sk = (unsigned char *)XMALLOC(skSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5606556070 if (sk == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); }
56066-
56067- old_sk = (unsigned char *)XMALLOC(skSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56068- if (old_sk == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); }
5606956071#endif
5607056072
5607156073 XMEMSET(sk, 0, skSz);
56072- XMEMSET(old_sk, 0, skSz);
5607356074 XMEMSET(sig, 0, sigSz);
5607456075
5607556076 ret = wc_XmssKey_SetWriteCb(&signingKey, xmss_write_key_mem);
@@ -56089,20 +56090,25 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5608956090 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); }
5609056091
5609156092 /* Repeat a few times to check that:
56092- * 1. The secret key is mutated on each sign.
56093+ * 1. Each Sign advances state (so signing the same message yields a
56094+ * different signature than the previous iteration).
5609356095 * 2. We can verify each new signature.
5609456096 * Only do a few times, because the full signature space
5609556097 * for this parameter set is huge. */
5609656098 for (i = 0; i < 10; ++i) {
56097- XMEMCPY(old_sk, sk, skSz);
56098-
5609956099 ret = wc_XmssKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
5610056100 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
5610156101 if (sigSz != bufSz) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
5610256102
56103- /* Old secret key and current secret key should not match. */
56104- ret = XMEMCMP(old_sk, sk, skSz);
56105- if (ret == 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
56103+ /* XMSS is deterministic given (SK_state, msg); a stuck leaf would
56104+ * produce an identical signature. This check is agnostic to whether
56105+ * the private state lives in user memory (software path) or on a
56106+ * cryptocb device. */
56107+ if (i > 0) {
56108+ ret = XMEMCMP(old_sig, sig, sigSz);
56109+ if (ret == 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
56110+ }
56111+ XMEMCPY(old_sig, sig, sigSz);
5610656112
5610756113 ret = wc_XmssKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz);
5610856114 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
@@ -56131,11 +56137,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
5613156137 XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5613256138 sig = NULL;
5613356139
56140+ XFREE(old_sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56141+ old_sig = NULL;
56142+
5613456143 XFREE(sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5613556144 sk = NULL;
56136-
56137- XFREE(old_sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56138- old_sk = NULL;
5613956145#endif /* !WOLFSSL_NO_MALLOC */
5614056146
5614156147 wc_XmssKey_Free(&signingKey);
@@ -56660,31 +56666,34 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5666056666 word32 msgSz = (word32) XSTRLEN(msg);
5666156667#ifndef WOLFSSL_WC_LMS_SERIALIZE_STATE
5666256668 unsigned char priv[HSS_MAX_PRIVATE_KEY_LEN];
56663- unsigned char old_priv[HSS_MAX_PRIVATE_KEY_LEN];
5666456669#else
5666556670 static unsigned char priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN];
56666- static unsigned char old_priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN];
5666756671#endif
5666856672#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
5666956673 byte * sig = (byte*)XMALLOC(WC_TEST_LMS_SIG_LEN, HEAP_HINT,
5667056674 DYNAMIC_TYPE_TMP_BUFFER);
56675+ byte * old_sig = (byte*)XMALLOC(WC_TEST_LMS_SIG_LEN, HEAP_HINT,
56676+ DYNAMIC_TYPE_TMP_BUFFER);
5667156677#else
5667256678 byte sig[WC_TEST_LMS_SIG_LEN];
56679+ byte old_sig[WC_TEST_LMS_SIG_LEN];
5667356680#endif
5667456681 const byte * kid;
5667556682 word32 kidSz;
5667656683
5667756684 WOLFSSL_ENTER("lms_test");
5667856685
5667956686#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
56680- if (sig == NULL) {
56687+ if ((sig == NULL) || (old_sig == NULL)) {
56688+ XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56689+ XFREE(old_sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5668156690 return WC_TEST_RET_ENC_ERRNO;
5668256691 }
5668356692#endif
5668456693
5668556694 XMEMSET(priv, 0, sizeof(priv));
56686- XMEMSET(old_priv, 0, sizeof(old_priv));
5668756695 XMEMSET(sig, 0, WC_TEST_LMS_SIG_LEN);
56696+ XMEMSET(old_sig, 0, WC_TEST_LMS_SIG_LEN);
5668856697 XMEMSET(&rng, 0, sizeof(rng));
5668956698 XMEMSET(&signingKey, 0, sizeof(signingKey));
5669056699 XMEMSET(&verifyKey, 0, sizeof(verifyKey));
@@ -56729,8 +56738,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5672956738 ret = wc_LmsKey_MakeKey(&signingKey, &rng);
5673056739 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); }
5673156740
56732- XMEMCPY(old_priv, priv, sizeof(priv));
56733-
5673456741 ret = wc_LmsKey_GetKid(NULL, NULL, NULL);
5673556742 if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
5673656743 ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
@@ -56772,21 +56779,32 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5677256779 /* Test wc_LmsKey_Sign input validation. */
5677356780 {
5677456781 word32 smallSz = 1;
56775- wc_lms_write_private_key_cb saved_write_cb;
5677656782
56777- /* Undersized sig buffer should return BUFFER_E. */
56783+ /* Undersized sig buffer should return BUFFER_E. This check runs in
56784+ * wc_LmsKey_Sign before the cryptocb dispatch, so it applies in both
56785+ * software and HSM modes. */
5677856786 ret = wc_LmsKey_Sign(&signingKey, sig, &smallSz, (byte *) msg, msgSz);
5677956787 if (ret != WC_NO_ERR_TRACE(BUFFER_E)) {
5678056788 ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
5678156789 }
5678256790
56783- /* NULL write callback should return BAD_FUNC_ARG. */
56784- saved_write_cb = signingKey.write_private_key;
56785- signingKey.write_private_key = NULL;
56786- ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
56787- signingKey.write_private_key = saved_write_cb;
56788- if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
56789- ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
56791+ #ifdef WOLF_CRYPTO_CB
56792+ /* The NULL-WriteCb -> BAD_FUNC_ARG check in wc_LmsKey_Sign sits after
56793+ * the cryptocb dispatch; an HSM-backed Sign succeeds without ever
56794+ * reaching it. Only exercise this on the pure software path. */
56795+ if (devId == INVALID_DEVID)
56796+ #endif
56797+ {
56798+ wc_lms_write_private_key_cb saved_write_cb;
56799+
56800+ /* NULL write callback should return BAD_FUNC_ARG. */
56801+ saved_write_cb = signingKey.write_private_key;
56802+ signingKey.write_private_key = NULL;
56803+ ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
56804+ signingKey.write_private_key = saved_write_cb;
56805+ if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
56806+ ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
56807+ }
5679056808 }
5679156809
5679256810 ret = 0;
@@ -56800,17 +56818,21 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5680056818 ERROR_OUT(WC_TEST_RET_ENC_NC, out);
5680156819 }
5680256820
56803- /* Sign with key. The private key will be updated on every signature. */
56821+ /* Sign with key. State advances on every signature. */
5680456822 ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
5680556823 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
5680656824
56807- /* The updated private key should not match the old one. */
56808- if (XMEMCMP(old_priv, priv, sizeof(priv)) == 0) {
56809- printf("error: current priv key should not match old: %d\n", i);
56810- ERROR_OUT(WC_TEST_RET_ENC_I(i), out);
56825+ /* LMS/HSS is deterministic given (state, msg); a stuck leaf would
56826+ * produce an identical signature. This check is agnostic to whether
56827+ * the private state lives in user memory (software path) or on a
56828+ * cryptocb device. */
56829+ if (i > 0) {
56830+ if (XMEMCMP(old_sig, sig, sigSz) == 0) {
56831+ printf("error: current signature should not match old: %d\n", i);
56832+ ERROR_OUT(WC_TEST_RET_ENC_I(i), out);
56833+ }
5681156834 }
56812-
56813- XMEMCPY(old_priv, priv, sizeof(priv));
56835+ XMEMCPY(old_sig, sig, sigSz);
5681456836
5681556837 ret = wc_LmsKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz);
5681656838 if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); }
@@ -56850,6 +56872,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
5685056872
5685156873#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
5685256874 XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
56875+ XFREE(old_sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
5685356876#endif
5685456877
5685556878 return ret;
0 commit comments