Skip to content

Commit aeeb98c

Browse files
authored
Merge pull request #10400 from embhorn/gh10383
Fix Dilithium signing when WC_DILITHIUM_CACHE_MATRIX_A is enabled
2 parents e78418d + 935c390 commit aeeb98c

2 files changed

Lines changed: 128 additions & 2 deletions

File tree

wolfcrypt/src/dilithium.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8333,10 +8333,14 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
83338333
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
83348334
#ifndef WC_DILITHIUM_FIXED_ARRAY
83358335
if ((ret == 0) && (key->a == NULL)) {
8336-
a = (sword32*)XMALLOC(params->aSz, key->heap, DYNAMIC_TYPE_DILITHIUM);
8337-
if (a == NULL) {
8336+
key->a = (sword32*)XMALLOC((size_t)params->aSz, key->heap,
8337+
DYNAMIC_TYPE_DILITHIUM);
8338+
if (key->a == NULL) {
83388339
ret = MEMORY_E;
83398340
}
8341+
else {
8342+
XMEMSET(key->a, 0, (size_t)params->aSz);
8343+
}
83408344
}
83418345
#endif
83428346
if (ret == 0) {

wolfcrypt/test/test.c

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52545,6 +52545,106 @@ static wc_test_ret_t dilithium_param_test(int param, WC_RNG* rng)
5254552545
}
5254652546
#endif
5254752547

52548+
#if defined(WC_DILITHIUM_CACHE_MATRIX_A) && \
52549+
!defined(WC_DILITHIUM_FIXED_ARRAY) && \
52550+
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
52551+
!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
52552+
!defined(WOLFSSL_DILITHIUM_NO_VERIFY)
52553+
/* Regression test for sign path matrix A cache allocation.
52554+
*
52555+
* dilithium_sign_with_seed_mu() previously stored the result of XMALLOC for
52556+
* the matrix A cache into a local variable instead of key->a. The local was
52557+
* then immediately overwritten by `a = key->a` (still NULL), so the just-
52558+
* allocated buffer was leaked and a NULL pointer was passed to
52559+
* dilithium_expand_a().
52560+
*
52561+
* This test exercises that exact code path by clearing the cache state on a
52562+
* key after make_key, then signing. The post-condition asserts that key->a
52563+
* was populated (proving the allocation made it into the key, not the local)
52564+
* and that signing produces a verifiable signature.
52565+
*/
52566+
static wc_test_ret_t dilithium_sign_cache_alloc_test(int param, WC_RNG* rng)
52567+
{
52568+
wc_test_ret_t ret;
52569+
dilithium_key* key = NULL;
52570+
byte* sig = NULL;
52571+
word32 sigLen;
52572+
byte msg[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
52573+
int res = 0;
52574+
52575+
key = (dilithium_key*)XMALLOC(sizeof(*key), HEAP_HINT,
52576+
DYNAMIC_TYPE_TMP_BUFFER);
52577+
if (key == NULL) {
52578+
ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out);
52579+
}
52580+
/* Init before further allocations so wc_dilithium_free() in the cleanup
52581+
* path operates on a zeroed struct, not garbage cached-pointer fields. */
52582+
ret = wc_dilithium_init_ex(key, NULL, devId);
52583+
if (ret != 0)
52584+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
52585+
52586+
sig = (byte*)XMALLOC(DILITHIUM_MAX_SIG_SIZE, HEAP_HINT,
52587+
DYNAMIC_TYPE_TMP_BUFFER);
52588+
if (sig == NULL) {
52589+
ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out);
52590+
}
52591+
52592+
ret = wc_dilithium_set_level(key, param);
52593+
if (ret != 0)
52594+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
52595+
52596+
ret = wc_dilithium_make_key(key, rng);
52597+
if (ret != 0)
52598+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
52599+
52600+
/* Drop the cached matrix A so the next sign exercises the allocation
52601+
* branch in dilithium_sign_with_seed_mu(). */
52602+
XFREE(key->a, key->heap, DYNAMIC_TYPE_DILITHIUM);
52603+
key->a = NULL;
52604+
key->aSet = 0;
52605+
#ifdef WC_DILITHIUM_CACHE_PRIV_VECTORS
52606+
XFREE(key->s1, key->heap, DYNAMIC_TYPE_DILITHIUM);
52607+
key->s1 = NULL;
52608+
key->s2 = NULL;
52609+
key->t0 = NULL;
52610+
key->privVecsSet = 0;
52611+
#endif
52612+
52613+
sigLen = wc_dilithium_sig_size(key);
52614+
if (sigLen <= 0)
52615+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
52616+
52617+
ret = wc_dilithium_sign_ctx_msg(NULL, 0, msg, (word32)sizeof(msg), sig,
52618+
&sigLen, key, rng);
52619+
if (ret != 0)
52620+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
52621+
52622+
/* With the fix, signing must populate key->a (allocated buffer is owned
52623+
* by the key, not leaked to a local). Without the fix, key->a remains
52624+
* NULL because the XMALLOC result was assigned to a local variable. */
52625+
if (key->a == NULL)
52626+
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
52627+
if (key->aSet != 1)
52628+
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
52629+
52630+
ret = wc_dilithium_verify_ctx_msg(sig, sigLen, NULL, 0, msg,
52631+
(word32)sizeof(msg), &res, key);
52632+
if (ret != 0)
52633+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
52634+
if (res != 1)
52635+
ERROR_OUT(WC_TEST_RET_ENC_EC(res), out);
52636+
52637+
out:
52638+
if (key != NULL)
52639+
wc_dilithium_free(key);
52640+
XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
52641+
XFREE(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
52642+
return ret;
52643+
}
52644+
#endif /* WC_DILITHIUM_CACHE_MATRIX_A && !WC_DILITHIUM_FIXED_ARRAY &&
52645+
* !WOLFSSL_DILITHIUM_NO_MAKE_KEY && !WOLFSSL_DILITHIUM_NO_SIGN &&
52646+
* !WOLFSSL_DILITHIUM_NO_VERIFY */
52647+
5254852648

5254952649
#if (defined(WOLFSSL_DILITHIUM_PRIVATE_KEY) && \
5255052650
!defined(WOLFSSL_DILITHIUM_NO_SIGN)) || \
@@ -52835,6 +52935,28 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dilithium_test(void)
5283552935
#endif
5283652936
#endif
5283752937

52938+
#if defined(WC_DILITHIUM_CACHE_MATRIX_A) && \
52939+
!defined(WC_DILITHIUM_FIXED_ARRAY) && \
52940+
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
52941+
!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
52942+
!defined(WOLFSSL_DILITHIUM_NO_VERIFY)
52943+
#ifndef WOLFSSL_NO_ML_DSA_44
52944+
ret = dilithium_sign_cache_alloc_test(WC_ML_DSA_44, &rng);
52945+
if (ret != 0)
52946+
ERROR_OUT(ret, out);
52947+
#endif
52948+
#ifndef WOLFSSL_NO_ML_DSA_65
52949+
ret = dilithium_sign_cache_alloc_test(WC_ML_DSA_65, &rng);
52950+
if (ret != 0)
52951+
ERROR_OUT(ret, out);
52952+
#endif
52953+
#ifndef WOLFSSL_NO_ML_DSA_87
52954+
ret = dilithium_sign_cache_alloc_test(WC_ML_DSA_87, &rng);
52955+
if (ret != 0)
52956+
ERROR_OUT(ret, out);
52957+
#endif
52958+
#endif
52959+
5283852960
#if (defined(WOLFSSL_DILITHIUM_PRIVATE_KEY) && \
5283952961
!defined(WOLFSSL_DILITHIUM_NO_SIGN)) || \
5284052962
(defined(WOLFSSL_DILITHIUM_PUBLIC_KEY) && \

0 commit comments

Comments
 (0)