diff --git a/wolfcrypt/src/ascon.c b/wolfcrypt/src/ascon.c index 8bd1e88d4d..4544635c08 100644 --- a/wolfcrypt/src/ascon.c +++ b/wolfcrypt/src/ascon.c @@ -459,6 +459,13 @@ int wc_AsconAEAD128_DecryptUpdate(wc_AsconAEAD128* a, byte* out, else if (a->op != ASCON_AEAD128_DECRYPT) return BAD_STATE_E; + /* Nothing to process. The argument check above deliberately permits + * in == NULL when inSz == 0, so return here before the XMEMCPY() calls + * below would pass a NULL source pointer (undefined behavior, flagged by + * -fsanitize=undefined). Mirrors wc_AsconHash256_Update()/SetAD(). */ + if (inSz == 0) + return 0; + /* Process leftover block */ if (a->lastBlkSz != 0) { word32 toProcess = min(ASCON_AEAD128_RATE - a->lastBlkSz, inSz); diff --git a/wolfcrypt/src/integer.c b/wolfcrypt/src/integer.c index bcd050c117..894a679a6f 100644 --- a/wolfcrypt/src/integer.c +++ b/wolfcrypt/src/integer.c @@ -4590,6 +4590,13 @@ int mp_cnt_lsb(mp_int *a) /* scan lower digits until non-zero */ for (x = 0; x < a->used && a->dp[x] == 0; x++) {} + /* All used digits are zero -- a non-normalized zero that mp_iszero() above + * did not catch. There is no set bit; return before reading dp[x] past the + * used digits (which, if also zero, would spin the scan-for-1 loop below + * forever). */ + if (x == a->used) { + return 0; + } if (a->dp) q = a->dp[x]; x *= DIGIT_BIT; diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 096c0e50e2..a19b121acd 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -5062,8 +5062,18 @@ static int wc_CompareDiffPQ(mp_int* p, mp_int* q, int size, int* valid) return BAD_FUNC_ARG; #ifdef WOLFSSL_SMALL_STACK - if (((c = (mp_int *)XMALLOC(sizeof(*c), NULL, DYNAMIC_TYPE_WOLF_BIGINT)) == NULL) || - ((d = (mp_int *)XMALLOC(sizeof(*d), NULL, DYNAMIC_TYPE_WOLF_BIGINT)) == NULL)) + c = (mp_int *)XMALLOC(sizeof(*c), NULL, DYNAMIC_TYPE_WOLF_BIGINT); + d = (mp_int *)XMALLOC(sizeof(*d), NULL, DYNAMIC_TYPE_WOLF_BIGINT); + /* Zero any struct that was allocated so the cleanup path's mp_clear()/ + * mp_forcezero() are safe even when the sibling allocation fails and the + * mp_init_multi() below is skipped on MEMORY_E. Without this, clearing an + * allocated-but-uninitialized mp_int reads a garbage ->used and corrupts + * the heap. */ + if (c != NULL) + XMEMSET(c, 0, sizeof(*c)); + if (d != NULL) + XMEMSET(d, 0, sizeof(*d)); + if (c == NULL || d == NULL) ret = MEMORY_E; else ret = 0; @@ -5205,8 +5215,17 @@ static int _CheckProbablePrime(mp_int* p, mp_int* q, mp_int* e, int nlen, *isPrime = MP_NO; #ifdef WOLFSSL_SMALL_STACK - if (((tmp1 = (mp_int *)XMALLOC(sizeof(*tmp1), NULL, DYNAMIC_TYPE_WOLF_BIGINT)) == NULL) || - ((tmp2 = (mp_int *)XMALLOC(sizeof(*tmp2), NULL, DYNAMIC_TYPE_WOLF_BIGINT)) == NULL)) { + tmp1 = (mp_int *)XMALLOC(sizeof(*tmp1), NULL, DYNAMIC_TYPE_WOLF_BIGINT); + tmp2 = (mp_int *)XMALLOC(sizeof(*tmp2), NULL, DYNAMIC_TYPE_WOLF_BIGINT); + /* Zero any allocated struct so the notOkay cleanup's mp_forcezero()/ + * mp_clear() are safe when the sibling allocation fails and the + * mp_init_multi() below is skipped: clearing an allocated-but- + * uninitialized mp_int reads a garbage ->used and corrupts the heap. */ + if (tmp1 != NULL) + XMEMSET(tmp1, 0, sizeof(*tmp1)); + if (tmp2 != NULL) + XMEMSET(tmp2, 0, sizeof(*tmp2)); + if (tmp1 == NULL || tmp2 == NULL) { ret = MEMORY_E; goto notOkay; } @@ -5309,9 +5328,20 @@ int wc_CheckProbablePrime_ex(const byte* pRaw, word32 pRawSz, #ifdef WOLFSSL_SMALL_STACK - if (((p = (mp_int *)XMALLOC(sizeof(*p), NULL, DYNAMIC_TYPE_RSA_BUFFER)) == NULL) || - ((q = (mp_int *)XMALLOC(sizeof(*q), NULL, DYNAMIC_TYPE_RSA_BUFFER)) == NULL) || - ((e = (mp_int *)XMALLOC(sizeof(*e), NULL, DYNAMIC_TYPE_RSA_BUFFER)) == NULL)) + p = (mp_int *)XMALLOC(sizeof(*p), NULL, DYNAMIC_TYPE_RSA_BUFFER); + q = (mp_int *)XMALLOC(sizeof(*q), NULL, DYNAMIC_TYPE_RSA_BUFFER); + e = (mp_int *)XMALLOC(sizeof(*e), NULL, DYNAMIC_TYPE_RSA_BUFFER); + /* Zero any allocated struct so the cleanup path's mp_forcezero()/ + * mp_clear() are safe when a later allocation in the chain fails and the + * mp_init_multi() below is skipped on MEMORY_E: clearing an allocated-but- + * uninitialized mp_int reads a garbage ->used and corrupts the heap. */ + if (p != NULL) + XMEMSET(p, 0, sizeof(*p)); + if (q != NULL) + XMEMSET(q, 0, sizeof(*q)); + if (e != NULL) + XMEMSET(e, 0, sizeof(*e)); + if (p == NULL || q == NULL || e == NULL) ret = MEMORY_E; else ret = 0; diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c index e521200ce5..bb5440c99d 100644 --- a/wolfcrypt/src/tfm.c +++ b/wolfcrypt/src/tfm.c @@ -4835,6 +4835,13 @@ int fp_cnt_lsb(fp_int *a) /* scan lower digits until non-zero */ for (x = 0; x < a->used && a->dp[x] == 0; x++) {} + /* All used digits are zero -- a non-normalized zero that fp_iszero() above + * did not catch. There is no set bit; return before reading dp[x] past the + * used digits (which, if also zero, would spin the scan-for-1 loop below + * forever). */ + if (x == a->used) { + return 0; + } q = a->dp[x]; x *= DIGIT_BIT;