From 720ce9f2a4e48293fc584ea9d5abbb705ee29970 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Mon, 7 Sep 2026 16:29:56 +0100 Subject: [PATCH] PIC32MZ: give hash copies their own cached message buffer wc_Md5Copy/wc_ShaCopy/wc_Sha256Copy shallow copy the whole hash struct and then call wc_Pic32HashCopy, which only set dst->isCopy so the shared buffer would not be freed twice. The copy therefore kept pointing at the source's storage: - With more than one block buffered the message lives in a heap buffer. An update to either context that still fits the allocation writes through the shared pointer, so the other context's message is corrupted and its digest depends on the order of operations. - Finalizing the original frees that heap buffer while the copy still references it. - With a short message the cache points at the source struct's embedded block buffer. Finalizing the original re-initializes the struct and zeroes that buffer, so the copy then hashes zeros. Deep copy the cache in wc_Pic32HashCopy instead: re-point the copy at its own embedded block buffer when the source used its own, or allocate a new heap buffer and copy the buffered bytes. Every context now owns its buffer, so the isCopy flag and the checks on it are removed. Add md5/sha/sha256 copy_update tests to wolfcrypt/test/test.c covering copy-then-update-both, copy-then-finalize-original-first and the short-message case, checked against one-shot reference digests. Reproduced and verified on the PIC32MZ simulator (EF and EC). F-10042 --- wolfcrypt/src/md5.c | 3 +- wolfcrypt/src/port/pic32/pic32mz-crypt.c | 40 ++- wolfcrypt/src/sha.c | 3 +- wolfcrypt/src/sha256.c | 3 +- wolfcrypt/test/test.c | 351 +++++++++++++++++++ wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h | 4 +- 6 files changed, 390 insertions(+), 14 deletions(-) diff --git a/wolfcrypt/src/md5.c b/wolfcrypt/src/md5.c index 56b43dc1abc..c8e9c5c2fda 100644 --- a/wolfcrypt/src/md5.c +++ b/wolfcrypt/src/md5.c @@ -560,7 +560,8 @@ int wc_Md5Copy(wc_Md5* src, wc_Md5* dst) ret = wolfAsync_DevCopy(&src->asyncDev, &dst->asyncDev); #endif #ifdef WOLFSSL_PIC32MZ_HASH - ret = wc_Pic32HashCopy(&src->cache, &dst->cache); + ret = wc_Pic32HashCopy(&src->cache, &dst->cache, (byte*)src->buffer, + (byte*)dst->buffer, dst->heap); #endif #ifdef WOLFSSL_HASH_FLAGS dst->flags |= WC_HASH_FLAG_ISCOPY; diff --git a/wolfcrypt/src/port/pic32/pic32mz-crypt.c b/wolfcrypt/src/port/pic32/pic32mz-crypt.c index 2a86445957d..018c3362530 100644 --- a/wolfcrypt/src/port/pic32/pic32mz-crypt.c +++ b/wolfcrypt/src/port/pic32/pic32mz-crypt.c @@ -491,12 +491,35 @@ int wc_Pic32Hash(const byte* in, int inLen, word32* out, int outLen, int algo) NULL, 0, NULL, 0); } -int wc_Pic32HashCopy(hashUpdCache* src, hashUpdCache* dst) +/* Give a hash context that was shallow copied from src its own copy of the + * cached message. The caller has already copied the whole hash struct, so + * dst->buf still points at src's storage: either src's embedded block buffer + * (srcStdBuf), whose contents the struct copy already placed in dstStdBuf, + * or a heap buffer that has to be duplicated here. Sharing the buffer would + * let an update or final on one context corrupt the other's message. */ +int wc_Pic32HashCopy(hashUpdCache* src, hashUpdCache* dst, + const byte* srcStdBuf, byte* dstStdBuf, void* heap) { - /* mark destination as copy, so cache->buf is not free'd */ - if (dst) { - dst->isCopy = 1; + if (src == NULL || dst == NULL) + return BAD_FUNC_ARG; + + if (src->buf == NULL) { + dst->buf = NULL; + } + else if (src->buf == srcStdBuf) { + dst->buf = dstStdBuf; + } + else { + dst->buf = (byte*)XMALLOC(src->bufLen, heap, DYNAMIC_TYPE_HASH_TMP); + if (dst->buf == NULL) { + dst->updLen = dst->bufLen = 0; + return MEMORY_E; + } + XMEMCPY(dst->buf, src->buf, src->updLen); } + dst->updLen = src->updLen; + dst->bufLen = src->bufLen; + return 0; } @@ -548,7 +571,7 @@ static int wc_Pic32HashUpdate(hashUpdCache* cache, byte* stdBuf, int stdBufLen, /* alloc buffer */ newBuf = (byte*)XMALLOC(newLenPad, heap, DYNAMIC_TYPE_HASH_TMP); if (newBuf == NULL) { - if (cache->buf != stdBuf && !cache->isCopy) { + if (cache->buf != stdBuf) { XFREE(cache->buf, heap, DYNAMIC_TYPE_HASH_TMP); cache->buf = NULL; cache->updLen = cache->bufLen = 0; @@ -556,7 +579,6 @@ static int wc_Pic32HashUpdate(hashUpdCache* cache, byte* stdBuf, int stdBufLen, return MEMORY_E; } isNewBuf = 1; - cache->isCopy = 0; /* no longer using copy buffer */ } else { /* use existing buffer */ @@ -594,7 +616,7 @@ static int wc_Pic32HashFinal(hashUpdCache* cache, byte* stdBuf, if (cache->bufLen == cache->finalLen) { start_engine(); if (wait_engine(digest, (word32)digestSz) != 0) { - if (cache->buf && cache->buf != stdBuf && !cache->isCopy) { + if (cache->buf && cache->buf != stdBuf) { XFREE(cache->buf, heap, DYNAMIC_TYPE_HASH_TMP); cache->buf = NULL; } @@ -645,7 +667,7 @@ static int wc_Pic32HashFinal(hashUpdCache* cache, byte* stdBuf, } } - if (cache->buf && cache->buf != stdBuf && !cache->isCopy) { + if (cache->buf && cache->buf != stdBuf) { XFREE(cache->buf, heap, DYNAMIC_TYPE_HASH_TMP); cache->buf = NULL; } @@ -659,7 +681,7 @@ static int wc_Pic32HashFinal(hashUpdCache* cache, byte* stdBuf, static void wc_Pic32HashFree(hashUpdCache* cache, void* stdBuf, void* heap) { - if (cache && cache->buf && cache->buf != stdBuf && !cache->isCopy) { + if (cache && cache->buf && cache->buf != stdBuf) { XFREE(cache->buf, heap, DYNAMIC_TYPE_HASH_TMP); cache->buf = NULL; } diff --git a/wolfcrypt/src/sha.c b/wolfcrypt/src/sha.c index d65766313e5..da9b97ff690 100644 --- a/wolfcrypt/src/sha.c +++ b/wolfcrypt/src/sha.c @@ -1261,7 +1261,8 @@ int wc_ShaCopy(wc_Sha* src, wc_Sha* dst) #endif #ifdef WOLFSSL_PIC32MZ_HASH - ret = wc_Pic32HashCopy(&src->cache, &dst->cache); + ret = wc_Pic32HashCopy(&src->cache, &dst->cache, (byte*)src->buffer, + (byte*)dst->buffer, dst->heap); #endif #if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_HASH) diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c index 14c1f99caa0..915cf8e52bf 100644 --- a/wolfcrypt/src/sha256.c +++ b/wolfcrypt/src/sha256.c @@ -3438,7 +3438,8 @@ int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) #endif #ifdef WOLFSSL_PIC32MZ_HASH - ret = wc_Pic32HashCopy(&src->cache, &dst->cache); + ret = wc_Pic32HashCopy(&src->cache, &dst->cache, (byte*)src->buffer, + (byte*)dst->buffer, dst->heap); #endif #if defined(WOLFSSL_USE_ESP32_CRYPT_HASH_HW) && \ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 68e63525e5c..ba690afe2ee 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5097,6 +5097,121 @@ static wc_test_ret_t md5_copy_test(wc_Md5* md5, wc_Md5* md5Copy) return ret; } +/* Copy a context and then drive the original and the copy independently. + * The message is longer than one block so that ports which buffer the whole + * message before hashing (e.g. PIC32MZ) have to spill it to the heap. The + * copy must get its own storage rather than share the original's, otherwise + * updating or finalizing one context corrupts the other's digest. */ +static wc_test_ret_t md5_copy_update_test(wc_Md5* md5, + wc_Md5* md5Copy) +{ + wc_test_ret_t ret = 0; + byte hash[WC_MD5_DIGEST_SIZE]; + byte expectA[WC_MD5_DIGEST_SIZE]; + byte expectB[WC_MD5_DIGEST_SIZE]; + byte expectS[WC_MD5_DIGEST_SIZE]; + byte msg[WC_MD5_BLOCK_SIZE + WC_MD5_BLOCK_SIZE / 2]; + const byte tailA[] = "original"; + const byte tailB[] = "copy"; + word32 tailASz = (word32)sizeof(tailA) - 1; + word32 tailBSz = (word32)sizeof(tailB) - 1; + int i; + + for (i = 0; i < (int)sizeof(msg); i++) + msg[i] = (byte)i; + + ret = wc_InitMd5_ex(md5, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_InitMd5_ex(md5Copy, HEAP_HINT, devId); + if (ret != 0) { + wc_Md5Free(md5); + return WC_TEST_RET_ENC_EC(ret); + } + + /* Reference digests of msg || tailA, msg || tailB and tailA alone. */ + ret = wc_Md5Update(md5, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_Md5Update(md5, tailA, tailASz); + if (ret == 0) + ret = wc_Md5Final(md5, expectA); + if (ret == 0) + ret = wc_Md5Update(md5, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_Md5Update(md5, tailB, tailBSz); + if (ret == 0) + ret = wc_Md5Final(md5, expectB); + if (ret == 0) + ret = wc_Md5Update(md5, tailA, tailASz); + if (ret == 0) + ret = wc_Md5Final(md5, expectS); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + + /* Copy, update both, then finalize both. */ + ret = wc_Md5Update(md5, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_Md5Copy(md5, md5Copy); + if (ret == 0) + ret = wc_Md5Update(md5, tailA, tailASz); + if (ret == 0) + ret = wc_Md5Update(md5Copy, tailB, tailBSz); + if (ret == 0) + ret = wc_Md5Final(md5, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectA, WC_MD5_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + ret = wc_Md5Final(md5Copy, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectB, WC_MD5_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + + /* Copy, then finish the original before touching the copy. */ + ret = wc_Md5Update(md5, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_Md5Copy(md5, md5Copy); + if (ret == 0) + ret = wc_Md5Update(md5, tailA, tailASz); + if (ret == 0) + ret = wc_Md5Final(md5, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectA, WC_MD5_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + ret = wc_Md5Update(md5Copy, tailB, tailBSz); + if (ret == 0) + ret = wc_Md5Final(md5Copy, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectB, WC_MD5_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + + /* Message that fits in the block buffer: finalizing the original resets + * its buffer, which must not change the copy's digest. */ + ret = wc_Md5Update(md5, tailA, tailASz); + if (ret == 0) + ret = wc_Md5Copy(md5, md5Copy); + if (ret == 0) + ret = wc_Md5Final(md5, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectS, WC_MD5_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + ret = wc_Md5Final(md5Copy, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectS, WC_MD5_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + +exit: + wc_Md5Free(md5); + wc_Md5Free(md5Copy); + + return ret; +} + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t md5_test(void) { wc_Md5 md5, md5Copy; @@ -5110,6 +5225,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t md5_test(void) #endif if ((ret = md5_copy_test(&md5, &md5Copy)) != 0) return ret; + if ((ret = md5_copy_update_test(&md5, &md5Copy)) != 0) + return ret; return 0; } #endif /* NO_MD5 */ @@ -5392,6 +5509,121 @@ static wc_test_ret_t sha_copy_test(wc_Sha* sha, wc_Sha* shaCopy) return ret; } + +/* Copy a context and then drive the original and the copy independently. + * The message is longer than one block so that ports which buffer the whole + * message before hashing (e.g. PIC32MZ) have to spill it to the heap. The + * copy must get its own storage rather than share the original's, otherwise + * updating or finalizing one context corrupts the other's digest. */ +static wc_test_ret_t sha_copy_update_test(wc_Sha* sha, + wc_Sha* shaCopy) +{ + wc_test_ret_t ret = 0; + byte hash[WC_SHA_DIGEST_SIZE]; + byte expectA[WC_SHA_DIGEST_SIZE]; + byte expectB[WC_SHA_DIGEST_SIZE]; + byte expectS[WC_SHA_DIGEST_SIZE]; + byte msg[WC_SHA_BLOCK_SIZE + WC_SHA_BLOCK_SIZE / 2]; + const byte tailA[] = "original"; + const byte tailB[] = "copy"; + word32 tailASz = (word32)sizeof(tailA) - 1; + word32 tailBSz = (word32)sizeof(tailB) - 1; + int i; + + for (i = 0; i < (int)sizeof(msg); i++) + msg[i] = (byte)i; + + ret = wc_InitSha_ex(sha, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_InitSha_ex(shaCopy, HEAP_HINT, devId); + if (ret != 0) { + wc_ShaFree(sha); + return WC_TEST_RET_ENC_EC(ret); + } + + /* Reference digests of msg || tailA, msg || tailB and tailA alone. */ + ret = wc_ShaUpdate(sha, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_ShaUpdate(sha, tailA, tailASz); + if (ret == 0) + ret = wc_ShaFinal(sha, expectA); + if (ret == 0) + ret = wc_ShaUpdate(sha, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_ShaUpdate(sha, tailB, tailBSz); + if (ret == 0) + ret = wc_ShaFinal(sha, expectB); + if (ret == 0) + ret = wc_ShaUpdate(sha, tailA, tailASz); + if (ret == 0) + ret = wc_ShaFinal(sha, expectS); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + + /* Copy, update both, then finalize both. */ + ret = wc_ShaUpdate(sha, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_ShaCopy(sha, shaCopy); + if (ret == 0) + ret = wc_ShaUpdate(sha, tailA, tailASz); + if (ret == 0) + ret = wc_ShaUpdate(shaCopy, tailB, tailBSz); + if (ret == 0) + ret = wc_ShaFinal(sha, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectA, WC_SHA_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + ret = wc_ShaFinal(shaCopy, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectB, WC_SHA_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + + /* Copy, then finish the original before touching the copy. */ + ret = wc_ShaUpdate(sha, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_ShaCopy(sha, shaCopy); + if (ret == 0) + ret = wc_ShaUpdate(sha, tailA, tailASz); + if (ret == 0) + ret = wc_ShaFinal(sha, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectA, WC_SHA_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + ret = wc_ShaUpdate(shaCopy, tailB, tailBSz); + if (ret == 0) + ret = wc_ShaFinal(shaCopy, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectB, WC_SHA_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + + /* Message that fits in the block buffer: finalizing the original resets + * its buffer, which must not change the copy's digest. */ + ret = wc_ShaUpdate(sha, tailA, tailASz); + if (ret == 0) + ret = wc_ShaCopy(sha, shaCopy); + if (ret == 0) + ret = wc_ShaFinal(sha, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectS, WC_SHA_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + ret = wc_ShaFinal(shaCopy, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectS, WC_SHA_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + +exit: + wc_ShaFree(sha); + wc_ShaFree(shaCopy); + + return ret; +} #endif /* !HAVE_SELFTEST && (!HAVE_FIPS || FIPS_VERSION_GE(7, 0)) */ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha_test(void) @@ -5408,6 +5640,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha_test(void) #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7, 0)) if ((ret = sha_copy_test(&sha, &shaCopy)) != 0) return ret; + if ((ret = sha_copy_update_test(&sha, &shaCopy)) != 0) + return ret; #endif return 0; } @@ -6305,6 +6539,121 @@ static wc_test_ret_t sha256_copy_test(wc_Sha256* sha, wc_Sha256* shaCopy) return ret; } + +/* Copy a context and then drive the original and the copy independently. + * The message is longer than one block so that ports which buffer the whole + * message before hashing (e.g. PIC32MZ) have to spill it to the heap. The + * copy must get its own storage rather than share the original's, otherwise + * updating or finalizing one context corrupts the other's digest. */ +static wc_test_ret_t sha256_copy_update_test(wc_Sha256* sha, + wc_Sha256* shaCopy) +{ + wc_test_ret_t ret = 0; + byte hash[WC_SHA256_DIGEST_SIZE]; + byte expectA[WC_SHA256_DIGEST_SIZE]; + byte expectB[WC_SHA256_DIGEST_SIZE]; + byte expectS[WC_SHA256_DIGEST_SIZE]; + byte msg[WC_SHA256_BLOCK_SIZE + WC_SHA256_BLOCK_SIZE / 2]; + const byte tailA[] = "original"; + const byte tailB[] = "copy"; + word32 tailASz = (word32)sizeof(tailA) - 1; + word32 tailBSz = (word32)sizeof(tailB) - 1; + int i; + + for (i = 0; i < (int)sizeof(msg); i++) + msg[i] = (byte)i; + + ret = wc_InitSha256_ex(sha, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_InitSha256_ex(shaCopy, HEAP_HINT, devId); + if (ret != 0) { + wc_Sha256Free(sha); + return WC_TEST_RET_ENC_EC(ret); + } + + /* Reference digests of msg || tailA, msg || tailB and tailA alone. */ + ret = wc_Sha256Update(sha, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_Sha256Update(sha, tailA, tailASz); + if (ret == 0) + ret = wc_Sha256Final(sha, expectA); + if (ret == 0) + ret = wc_Sha256Update(sha, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_Sha256Update(sha, tailB, tailBSz); + if (ret == 0) + ret = wc_Sha256Final(sha, expectB); + if (ret == 0) + ret = wc_Sha256Update(sha, tailA, tailASz); + if (ret == 0) + ret = wc_Sha256Final(sha, expectS); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + + /* Copy, update both, then finalize both. */ + ret = wc_Sha256Update(sha, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_Sha256Copy(sha, shaCopy); + if (ret == 0) + ret = wc_Sha256Update(sha, tailA, tailASz); + if (ret == 0) + ret = wc_Sha256Update(shaCopy, tailB, tailBSz); + if (ret == 0) + ret = wc_Sha256Final(sha, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectA, WC_SHA256_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + ret = wc_Sha256Final(shaCopy, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectB, WC_SHA256_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + + /* Copy, then finish the original before touching the copy. */ + ret = wc_Sha256Update(sha, msg, (word32)sizeof(msg)); + if (ret == 0) + ret = wc_Sha256Copy(sha, shaCopy); + if (ret == 0) + ret = wc_Sha256Update(sha, tailA, tailASz); + if (ret == 0) + ret = wc_Sha256Final(sha, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectA, WC_SHA256_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + ret = wc_Sha256Update(shaCopy, tailB, tailBSz); + if (ret == 0) + ret = wc_Sha256Final(shaCopy, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectB, WC_SHA256_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + + /* Message that fits in the block buffer: finalizing the original resets + * its buffer, which must not change the copy's digest. */ + ret = wc_Sha256Update(sha, tailA, tailASz); + if (ret == 0) + ret = wc_Sha256Copy(sha, shaCopy); + if (ret == 0) + ret = wc_Sha256Final(sha, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectS, WC_SHA256_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + ret = wc_Sha256Final(shaCopy, hash); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); + if (XMEMCMP(hash, expectS, WC_SHA256_DIGEST_SIZE) != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + +exit: + wc_Sha256Free(sha); + wc_Sha256Free(shaCopy); + + return ret; +} #endif /* !HAVE_SELFTEST && (!HAVE_FIPS || FIPS_VERSION_GE(7, 0)) */ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha256_test(void) @@ -6326,6 +6675,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sha256_test(void) #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7, 0)) if ((ret = sha256_copy_test(&sha, &shaCopy)) != 0) return ret; + if ((ret = sha256_copy_update_test(&sha, &shaCopy)) != 0) + return ret; #endif return 0; } diff --git a/wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h b/wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h index b9864521b77..f38506ffbc3 100644 --- a/wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h +++ b/wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h @@ -116,7 +116,6 @@ typedef struct hashUpdCache { unsigned char* buf; unsigned int bufLen; unsigned int updLen; - int isCopy; #ifdef WOLFSSL_PIC32MZ_LARGE_HASH unsigned int finalLen; #endif @@ -198,7 +197,8 @@ int wc_Pic32DesCrypt(word32 *key, int keyLen, word32 *iv, int ivLen, #define WOLFSSL_NO_HASH_RAW int wc_Pic32Hash(const byte* in, int inLen, word32* out, int outLen, int algo); -int wc_Pic32HashCopy(hashUpdCache* src, hashUpdCache* dst); +int wc_Pic32HashCopy(hashUpdCache* src, hashUpdCache* dst, + const byte* srcStdBuf, byte* dstStdBuf, void* heap); #ifndef NO_MD5 struct wc_Md5;