diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 6ba10282f5..e0c0f7a80b 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -55912,10 +55912,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void) word32 bufSz = 0; #ifdef WOLFSSL_NO_MALLOC static byte sk[2048]; - static byte old_sk[2048]; #else byte * sk = NULL; - byte * old_sk = NULL; #endif const char * msg = "XMSS post quantum signature test"; word32 msgSz = (word32) XSTRLEN(msg); @@ -55930,8 +55928,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void) #endif #ifdef WOLFSSL_NO_MALLOC static byte sig[4096]; + static byte old_sig[4096]; #else byte * sig = NULL; + byte * old_sig = NULL; #endif int ret2 = -1; int ret = WC_TEST_RET_ENC_NC; @@ -55968,13 +55968,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void) ret = wc_XmssKey_GetSigLen(&signingKey, &sigSz); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } - /* Allocate signature array. */ + /* Allocate signature buffers (current and previous iteration). */ #ifdef WOLFSSL_NO_MALLOC + if (sigSz > sizeof(sig)) ERROR_OUT(WC_TEST_RET_ENC_NC, out); #else sig = (byte *)XMALLOC(sigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (sig == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); } + + old_sig = (byte *)XMALLOC(sigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (old_sig == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); } #endif bufSz = sigSz; @@ -55986,20 +55990,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void) fprintf(stderr, "sigSz: %d\n", sigSz); #endif - /* Allocate current and old secret keys.*/ + /* Allocate the secret key buffer used by the software write/read + * callbacks. */ #ifdef WOLFSSL_NO_MALLOC if (skSz > sizeof(sk)) ERROR_OUT(WC_TEST_RET_ENC_NC, out); #else sk = (unsigned char *)XMALLOC(skSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (sk == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); } - - old_sk = (unsigned char *)XMALLOC(skSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - if (old_sk == NULL) { ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); } #endif XMEMSET(sk, 0, skSz); - XMEMSET(old_sk, 0, skSz); XMEMSET(sig, 0, sigSz); ret = wc_XmssKey_SetWriteCb(&signingKey, xmss_write_key_mem); @@ -56019,20 +56020,25 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void) if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } /* Repeat a few times to check that: - * 1. The secret key is mutated on each sign. + * 1. Each Sign advances state (so signing the same message yields a + * different signature than the previous iteration). * 2. We can verify each new signature. * Only do a few times, because the full signature space * for this parameter set is huge. */ for (i = 0; i < 10; ++i) { - XMEMCPY(old_sk, sk, skSz); - ret = wc_XmssKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); } if (sigSz != bufSz) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); } - /* Old secret key and current secret key should not match. */ - ret = XMEMCMP(old_sk, sk, skSz); - if (ret == 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); } + /* XMSS is deterministic given (SK_state, msg); a stuck leaf would + * produce an identical signature. This check is agnostic to whether + * the private state lives in user memory (software path) or on a + * cryptocb device. */ + if (i > 0) { + ret = XMEMCMP(old_sig, sig, sigSz); + if (ret == 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); } + } + XMEMCPY(old_sig, sig, sigSz); ret = wc_XmssKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz); 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) XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); sig = NULL; + XFREE(old_sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + old_sig = NULL; + XFREE(sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); sk = NULL; - - XFREE(old_sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - old_sk = NULL; #endif /* !WOLFSSL_NO_MALLOC */ wc_XmssKey_Free(&signingKey); @@ -56590,16 +56596,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) word32 msgSz = (word32) XSTRLEN(msg); #ifndef WOLFSSL_WC_LMS_SERIALIZE_STATE unsigned char priv[HSS_MAX_PRIVATE_KEY_LEN]; - unsigned char old_priv[HSS_MAX_PRIVATE_KEY_LEN]; #else static unsigned char priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN]; - static unsigned char old_priv[64 * 1024 + HSS_MAX_PRIVATE_KEY_LEN]; #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) byte * sig = (byte*)XMALLOC(WC_TEST_LMS_SIG_LEN, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + byte * old_sig = (byte*)XMALLOC(WC_TEST_LMS_SIG_LEN, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); #else byte sig[WC_TEST_LMS_SIG_LEN]; + byte old_sig[WC_TEST_LMS_SIG_LEN]; #endif const byte * kid; word32 kidSz; @@ -56607,14 +56614,16 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) WOLFSSL_ENTER("lms_test"); #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - if (sig == NULL) { + if ((sig == NULL) || (old_sig == NULL)) { + XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(old_sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); return WC_TEST_RET_ENC_ERRNO; } #endif XMEMSET(priv, 0, sizeof(priv)); - XMEMSET(old_priv, 0, sizeof(old_priv)); XMEMSET(sig, 0, WC_TEST_LMS_SIG_LEN); + XMEMSET(old_sig, 0, WC_TEST_LMS_SIG_LEN); XMEMSET(&rng, 0, sizeof(rng)); XMEMSET(&signingKey, 0, sizeof(signingKey)); XMEMSET(&verifyKey, 0, sizeof(verifyKey)); @@ -56659,8 +56668,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) ret = wc_LmsKey_MakeKey(&signingKey, &rng); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } - XMEMCPY(old_priv, priv, sizeof(priv)); - ret = wc_LmsKey_GetKid(NULL, NULL, NULL); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -56702,21 +56709,32 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) /* Test wc_LmsKey_Sign input validation. */ { word32 smallSz = 1; - wc_lms_write_private_key_cb saved_write_cb; - /* Undersized sig buffer should return BUFFER_E. */ + /* Undersized sig buffer should return BUFFER_E. This check runs in + * wc_LmsKey_Sign before the cryptocb dispatch, so it applies in both + * software and HSM modes. */ ret = wc_LmsKey_Sign(&signingKey, sig, &smallSz, (byte *) msg, msgSz); if (ret != WC_NO_ERR_TRACE(BUFFER_E)) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } - /* NULL write callback should return BAD_FUNC_ARG. */ - saved_write_cb = signingKey.write_private_key; - signingKey.write_private_key = NULL; - ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz); - signingKey.write_private_key = saved_write_cb; - if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { - ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); +#ifdef WOLF_CRYPTO_CB + /* The NULL-WriteCb -> BAD_FUNC_ARG check in wc_LmsKey_Sign sits after + * the cryptocb dispatch; an HSM-backed Sign succeeds without ever + * reaching it. Only exercise this on the pure software path. */ + if (devId == INVALID_DEVID) +#endif + { + wc_lms_write_private_key_cb saved_write_cb; + + /* NULL write callback should return BAD_FUNC_ARG. */ + saved_write_cb = signingKey.write_private_key; + signingKey.write_private_key = NULL; + ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz); + signingKey.write_private_key = saved_write_cb; + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } } ret = 0; @@ -56730,17 +56748,21 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) ERROR_OUT(WC_TEST_RET_ENC_NC, out); } - /* Sign with key. The private key will be updated on every signature. */ + /* Sign with key. State advances on every signature. */ ret = wc_LmsKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); } - /* The updated private key should not match the old one. */ - if (XMEMCMP(old_priv, priv, sizeof(priv)) == 0) { - printf("error: current priv key should not match old: %d\n", i); - ERROR_OUT(WC_TEST_RET_ENC_I(i), out); + /* LMS/HSS is deterministic given (state, msg); a stuck leaf would + * produce an identical signature. This check is agnostic to whether + * the private state lives in user memory (software path) or on a + * cryptocb device. */ + if (i > 0) { + if (XMEMCMP(old_sig, sig, sigSz) == 0) { + printf("error: current signature should not match old: %d\n", i); + ERROR_OUT(WC_TEST_RET_ENC_I(i), out); + } } - - XMEMCPY(old_priv, priv, sizeof(priv)); + XMEMCPY(old_sig, sig, sigSz); ret = wc_LmsKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz); 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) #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(old_sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret;