Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,7 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
int ret = 0;
const byte* macSecret = NULL;
word32 hashSz = 0;
word32 totalSz = 0;

if (ssl == NULL)
return BAD_FUNC_ARG;
Expand All @@ -1294,11 +1295,23 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
hashSz = ssl->specs.hash_size;
#endif

/* Pre-compute sz + hashSz + padSz + 1 with overflow checking.
* Used by fuzzer callback and Hmac_UpdateFinal* in the verify path. */
if (verify && padSz >= 0) {
word32 hmacSz;
if (!WC_SAFE_SUM_WORD32(sz, hashSz, hmacSz) ||
!WC_SAFE_SUM_WORD32(hmacSz, (word32)padSz, hmacSz) ||
!WC_SAFE_SUM_WORD32(hmacSz, 1, hmacSz)) {
return BUFFER_E;
}
totalSz = hmacSz;
}

#ifdef HAVE_FUZZER
/* Fuzz "in" buffer with sz to be used in HMAC algorithm */
if (ssl->fuzzerCb) {
if (verify && padSz >= 0) {
ssl->fuzzerCb(ssl, in, sz + hashSz + padSz + 1, FUZZ_HMAC,
ssl->fuzzerCb(ssl, in, totalSz, FUZZ_HMAC,
ssl->fuzzerCtx);
}
else {
Expand Down Expand Up @@ -1335,19 +1348,18 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
#ifdef HAVE_BLAKE2
if (wolfSSL_GetHmacType(ssl) == WC_HASH_TYPE_BLAKE2B) {
ret = Hmac_UpdateFinal(&hmac, digest, in,
sz + hashSz + (word32)padSz + 1, myInner, innerSz);
totalSz, myInner, innerSz);
}
else
#endif
{
ret = Hmac_UpdateFinal_CT(&hmac, digest, in,
(sz + hashSz + (word32)padSz + 1),
totalSz,
(int)hashSz, myInner, innerSz);

}
#else
ret = Hmac_UpdateFinal(&hmac, digest, in, sz + hashSz +
(word32)(padSz) + 1,
ret = Hmac_UpdateFinal(&hmac, digest, in, totalSz,
myInner, innerSz);
#endif
}
Expand Down
73 changes: 73 additions & 0 deletions tests/api/test_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <wolfssl/wolfcrypt/hmac.h>
#include <wolfssl/wolfcrypt/types.h>
#include <wolfssl/internal.h>
#include <tests/api/api.h>
#include <tests/api/test_hmac.h>

Expand Down Expand Up @@ -681,3 +682,75 @@ int test_wc_Sha384HmacFinal(void)
return EXPECT_RESULT();
} /* END test_wc_Sha384HmacFinal */

/* Test for integer overflow in TLS_hmac size calculation (ZD #21240).
*
* TLS_hmac() computes sz + hashSz + padSz + 1 and passes the result to
* Hmac_UpdateFinal / Hmac_UpdateFinal_CT. When sz (word32) is near
* UINT32_MAX, the addition overflows and wraps to a small value, causing
* the HMAC routines to operate on an undersized length. The fix adds
* WC_SAFE_SUM_WORD32 overflow checks and returns BUFFER_E on overflow.
*
* This test calls through ssl->hmac (which points to TLS_hmac) with
* values that trigger the overflow condition and verifies the function
* correctly rejects them.
*/
int test_tls_hmac_size_overflow(void)
{
EXPECT_DECLS;
#if !defined(NO_HMAC) && !defined(WOLFSSL_AEAD_ONLY) && !defined(NO_TLS) && \
defined(NO_OLD_TLS) && !defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
byte digest[WC_MAX_DIGEST_SIZE];
byte dummy_in[64];

XMEMSET(dummy_in, 0xAA, sizeof(dummy_in));
XMEMSET(digest, 0, sizeof(digest));

ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
ExpectNotNull(ctx);
ssl = wolfSSL_new(ctx);
ExpectNotNull(ssl);

if (EXPECT_SUCCESS()) {
ExpectNotNull(ssl->hmac);

/* Set a hash size so the verify path in TLS_hmac is exercised. */
ssl->specs.hash_size = WC_SHA256_DIGEST_SIZE;

/* Overflow case 1: sz near UINT32_MAX, padSz pushes sum past limit.
* (UINT32_MAX - 300) + 32 + 500 + 1 = UINT32_MAX + 233 -> wraps to 232
*/
ExpectIntEQ(ssl->hmac(ssl, digest, dummy_in,
(word32)(WOLFSSL_MAX_32BIT - 300),
500, /* padSz */
application_data, 1, PEER_ORDER),
WC_NO_ERR_TRACE(BUFFER_E));

/* Overflow case 2: padSz = 0, hashSz alone causes overflow.
* (UINT32_MAX - 10) + 32 + 0 + 1 = UINT32_MAX + 23 -> wraps to 22
*/
ExpectIntEQ(ssl->hmac(ssl, digest, dummy_in,
(word32)(WOLFSSL_MAX_32BIT - 10),
0, /* padSz */
application_data, 1, PEER_ORDER),
WC_NO_ERR_TRACE(BUFFER_E));

/* Normal case: should NOT return BUFFER_E.
* May fail for other reasons (no keys configured) but the overflow
* check must not fire for small legitimate values.
*/
ExpectIntNE(ssl->hmac(ssl, digest, dummy_in,
100,
10, /* padSz */
application_data, 1, PEER_ORDER),
WC_NO_ERR_TRACE(BUFFER_E));
}

wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif /* !NO_HMAC && !WOLFSSL_AEAD_ONLY && !NO_TLS && NO_OLD_TLS &&
* !NO_WOLFSSL_CLIENT */
return EXPECT_RESULT();
} /* END test_tls_hmac_size_overflow */

4 changes: 3 additions & 1 deletion tests/api/test_hmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ int test_wc_Sha256HmacFinal(void);
int test_wc_Sha384HmacSetKey(void);
int test_wc_Sha384HmacUpdate(void);
int test_wc_Sha384HmacFinal(void);
int test_tls_hmac_size_overflow(void);

#define TEST_HMAC_DECLS \
TEST_DECL_GROUP("hmac", test_wc_Md5HmacSetKey), \
Expand All @@ -55,6 +56,7 @@ int test_wc_Sha384HmacFinal(void);
TEST_DECL_GROUP("hmac", test_wc_Sha256HmacFinal), \
TEST_DECL_GROUP("hmac", test_wc_Sha384HmacSetKey), \
TEST_DECL_GROUP("hmac", test_wc_Sha384HmacUpdate), \
TEST_DECL_GROUP("hmac", test_wc_Sha384HmacFinal)
TEST_DECL_GROUP("hmac", test_wc_Sha384HmacFinal), \
TEST_DECL_GROUP("hmac", test_tls_hmac_size_overflow)

#endif /* WOLFCRYPT_TEST_HMAC_H */