Merge pull request #10709 from douzzer/20260616-aes-fixes

20260616-aes-fixes
This commit is contained in:
JacobBarthelmeh
2026-06-17 15:58:23 -06:00
committed by GitHub
8 changed files with 307 additions and 19 deletions
+71 -2
View File
@@ -12808,6 +12808,18 @@ int wc_AesGcmEncryptUpdate(Aes* aes, byte* out, const byte* in, word32 sz,
ret = MISSING_IV;
}
/* Prevent overflow of aes->cSz and ->aSz. Per NIST SP 800-38D section
* 5.2.1.1, the maximum allowed ciphertext limit is 2^32 - 2 blocks, but we
* currently pass around the cumulative sizes in bytes as word32s, so we
* can't currently support the maximum allowed.
*/
if ((ret == 0) &&
((aes->cSz > WOLFSSL_MAX_32BIT - sz) ||
(aes->aSz > WOLFSSL_MAX_32BIT - authInSz)))
{
ret = AES_GCM_OVERFLOW_E;
}
if ((ret == 0) && aes->ctrSet && (aes->aSz == 0) && (aes->cSz == 0)) {
aes->invokeCtr[0]++;
if (aes->invokeCtr[0] == 0) {
@@ -12950,6 +12962,18 @@ int wc_AesGcmDecryptUpdate(Aes* aes, byte* out, const byte* in, word32 sz,
ret = MISSING_IV;
}
/* Prevent overflow of aes->cSz and ->aSz. Per NIST SP 800-38D section
* 5.2.1.1, the maximum allowed ciphertext limit is 2^32 - 2 blocks, but we
* currently pass around the cumulative sizes in bytes as word32s, so we
* can't currently support the maximum allowed.
*/
if ((ret == 0) &&
((aes->cSz > WOLFSSL_MAX_32BIT - sz) ||
(aes->aSz > WOLFSSL_MAX_32BIT - authInSz)))
{
ret = AES_GCM_OVERFLOW_E;
}
if (ret == 0) {
/* Decrypt with AAD and/or cipher text. */
#ifdef WOLFSSL_AESNI
@@ -13360,6 +13384,18 @@ int wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
return status;
}
{
word32 lenSz = (word32)WC_AES_BLOCK_SIZE - 1U - nonceSz;
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(inSz)) &&
(inSz >= ((word32)1 << (lenSz * 8))))
{
return AES_CCM_OVERFLOW_E;
}
}
status = wolfSSL_CryptHwMutexLock();
if (status != 0)
return status;
@@ -13394,6 +13430,18 @@ int wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
return status;
}
{
word32 lenSz = (word32)WC_AES_BLOCK_SIZE - 1U - nonceSz;
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(inSz)) &&
(inSz >= ((word32)1 << (lenSz * 8))))
{
return AES_CCM_OVERFLOW_E;
}
}
status = wolfSSL_CryptHwMutexLock();
if (status != 0)
return status;
@@ -13586,6 +13634,17 @@ int wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
return BAD_FUNC_ARG;
}
lenSz = (byte)(WC_AES_BLOCK_SIZE - 1U - nonceSz);
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(inSz)) &&
(inSz >= ((word32)1 << (lenSz * 8))))
{
return AES_CCM_OVERFLOW_E;
}
#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (aes->devId != INVALID_DEVID)
@@ -13602,7 +13661,7 @@ int wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
XMEMSET(A, 0, sizeof(A));
XMEMCPY(B+1, nonce, nonceSz);
lenSz = (byte)(WC_AES_BLOCK_SIZE - 1U - nonceSz);
B[0] = (byte)((authInSz > 0 ? 64 : 0)
+ (8 * (((byte)authTagSz - 2) / 2))
+ (lenSz - 1));
@@ -13739,6 +13798,17 @@ int wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
return BAD_FUNC_ARG;
}
lenSz = (byte)(WC_AES_BLOCK_SIZE - 1U - nonceSz);
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(inSz)) &&
(inSz >= ((word32)1 << (lenSz * 8))))
{
return AES_CCM_OVERFLOW_E;
}
#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (aes->devId != INVALID_DEVID)
@@ -13757,7 +13827,6 @@ int wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
oSz = inSz;
XMEMSET(A, 0, sizeof A);
XMEMCPY(B+1, nonce, nonceSz);
lenSz = (byte)(WC_AES_BLOCK_SIZE - 1U - nonceSz);
B[0] = (byte)(lenSz - 1U);
for (i = 0; i < lenSz; i++)
+2 -2
View File
@@ -498,10 +498,10 @@ const char* wc_GetErrorString(int error)
return "wolfcrypt FIPS ECDHE Known Answer Test Failure";
case AES_GCM_OVERFLOW_E:
return "AES-GCM invocation counter overflow";
return "AES-GCM internal overflow averted";
case AES_CCM_OVERFLOW_E:
return "AES-CCM invocation counter overflow";
return "AES-CCM internal overflow averted";
case RSA_KEY_PAIR_E:
return "RSA Key Pair-Wise Consistency check fail";
+24 -4
View File
@@ -494,7 +494,7 @@ int wc_AesCcmEncrypt(Aes* aes, byte* out,
word32 keySz;
word32 i;
byte B0Ctr0[WC_AES_BLOCK_SIZE + WC_AES_BLOCK_SIZE];
int lenSz;
word32 lenSz;
byte mask = 0xFF;
const word32 wordSz = (word32)sizeof(word32);
int ret;
@@ -513,10 +513,20 @@ int wc_AesCcmEncrypt(Aes* aes, byte* out,
return ret;
}
lenSz = WC_AES_BLOCK_SIZE - 1 - (byte)nonceSz;
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(inSz)) &&
(inSz >= ((word32)1 << (lenSz * 8))))
{
return AES_CCM_OVERFLOW_E;
}
/* set up B0 and CTR0 similar to how wolfcrypt/src/aes.c does */
XMEMCPY(B0Ctr0+1, nonce, nonceSz);
XMEMCPY(B0Ctr0+WC_AES_BLOCK_SIZE+1, nonce, nonceSz);
lenSz = WC_AES_BLOCK_SIZE - 1 - (byte)nonceSz;
B0Ctr0[0] = (authInSz > 0 ? 64 : 0)
+ (8 * (((byte)authTagSz - 2) / 2))
+ (lenSz - 1);
@@ -577,7 +587,7 @@ int wc_AesCcmDecrypt(Aes* aes, byte* out,
word32 i;
byte B0Ctr0[WC_AES_BLOCK_SIZE + WC_AES_BLOCK_SIZE];
byte tag[WC_AES_BLOCK_SIZE];
int lenSz;
word32 lenSz;
byte mask = 0xFF;
const word32 wordSz = (word32)sizeof(word32);
int ret;
@@ -596,10 +606,20 @@ int wc_AesCcmDecrypt(Aes* aes, byte* out,
return ret;
}
lenSz = WC_AES_BLOCK_SIZE - 1 - (byte)nonceSz;
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(inSz)) &&
(inSz >= ((word32)1 << (lenSz * 8))))
{
return AES_CCM_OVERFLOW_E;
}
/* set up B0 and CTR0 similar to how wolfcrypt/src/aes.c does */
XMEMCPY(B0Ctr0+1, nonce, nonceSz);
XMEMCPY(B0Ctr0+WC_AES_BLOCK_SIZE+1, nonce, nonceSz);
lenSz = WC_AES_BLOCK_SIZE - 1 - (byte)nonceSz;
B0Ctr0[0] = (authInSz > 0 ? 64 : 0)
+ (8 * (((byte)authTagSz - 2) / 2))
+ (lenSz - 1);
+29 -4
View File
@@ -9102,6 +9102,7 @@ int wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
const byte* authIn, word32 authInSz)
{
int ret = 0;
byte lenSz = 0;
/* sanity check on arguments */
if ((aes == NULL) || ((inSz != 0) && ((in == NULL) || (out == NULL))) ||
@@ -9114,14 +9115,26 @@ int wc_AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
lenSz = WC_AES_BLOCK_SIZE - 1 - (byte)nonceSz;
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(inSz)) &&
(inSz >= ((word32)1 << (lenSz * 8))))
{
ret = AES_CCM_OVERFLOW_E;
}
}
if (ret == 0) {
byte A[WC_AES_BLOCK_SIZE];
byte B[WC_AES_BLOCK_SIZE];
byte lenSz;
byte i;
XMEMCPY(B+1, nonce, nonceSz);
lenSz = WC_AES_BLOCK_SIZE - 1 - (byte)nonceSz;
B[0] = (authInSz > 0 ? 64 : 0)
+ (8 * (((byte)authTagSz - 2) / 2))
+ (lenSz - 1);
@@ -9180,6 +9193,7 @@ int wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
const byte* authIn, word32 authInSz)
{
int ret = 0;
byte lenSz = 0;
/* sanity check on arguments */
if ((aes == NULL) || ((inSz != 0) && ((in == NULL) || (out == NULL))) ||
@@ -9192,16 +9206,27 @@ int wc_AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
lenSz = WC_AES_BLOCK_SIZE - 1 - (byte)nonceSz;
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(inSz)) &&
(inSz >= ((word32)1 << (lenSz * 8))))
{
ret = AES_CCM_OVERFLOW_E;
}
}
if (ret == 0) {
byte A[WC_AES_BLOCK_SIZE];
byte B[WC_AES_BLOCK_SIZE];
byte lenSz;
byte i;
byte* o = out;
word32 oSz = inSz;
XMEMCPY(B+1, nonce, nonceSz);
lenSz = WC_AES_BLOCK_SIZE - 1 - (byte)nonceSz;
B[0] = lenSz - 1;
for (i = 0; i < lenSz; i++) {
+26
View File
@@ -273,10 +273,23 @@ int wc_AesCcmEncrypt_silabs (Aes* aes, byte* out, const byte* in, word32 sz,
{
sl_status_t status;
if ((in == NULL) || (out == NULL) || (iv == NULL) || (authTag == NULL) ||
(ivSz < CCM_NONCE_MIN_SZ) || (ivSz > CCM_NONCE_MAX_SZ) ||
(authIn == NULL && authInSz != 0) || (aes == NULL)) {
return BAD_FUNC_ARG;
}
{
word32 lenSz = (word32)WC_AES_BLOCK_SIZE - 1U - ivSz;
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(sz)) &&
(sz >= ((word32)1 << (lenSz * 8))))
{
return AES_CCM_OVERFLOW_E;
}
}
status = sl_se_ccm_encrypt_and_tag(
&(aes->ctx.cmd_ctx),
&(aes->ctx.key),
@@ -301,10 +314,23 @@ int wc_AesCcmDecrypt_silabs (Aes* aes, byte* out, const byte* in, word32 sz,
{
sl_status_t status;
if ((in == NULL) || (out == NULL) || (iv == NULL) || (authTag == NULL) ||
(ivSz < CCM_NONCE_MIN_SZ) || (ivSz > CCM_NONCE_MAX_SZ) ||
(authIn == NULL && authInSz != 0) || (aes == NULL)) {
return BAD_FUNC_ARG;
}
{
word32 lenSz = (word32)WC_AES_BLOCK_SIZE - 1U - ivSz;
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(sz)) &&
(sz >= ((word32)1 << (lenSz * 8))))
{
return AES_CCM_OVERFLOW_E;
}
}
status = sl_se_ccm_auth_decrypt(
&(aes->ctx.cmd_ctx),
&(aes->ctx.key),
+18 -5
View File
@@ -330,7 +330,7 @@ static int AesAuthSetKey(Aes* aes, const byte* key, word32 keySz)
static int AesAuthArgCheck(Aes* aes, byte* out, const byte* in, word32 inSz,
const byte* nonce, word32 nonceSz,
const byte* authTag, word32 authTagSz,
word32 *M, word32 *L)
word32 *M, word32 *L, int mode)
{
if (aes == NULL || nonce == NULL || authTag == NULL)
return BAD_FUNC_ARG;
@@ -376,6 +376,19 @@ static int AesAuthArgCheck(Aes* aes, byte* out, const byte* in, word32 inSz,
default:
return BAD_FUNC_ARG;
}
if (mode == AES_CFG_MODE_CCM) {
word32 lenSz = (word32)WC_AES_BLOCK_SIZE - 1U - nonceSz;
/* With a large nonce, B[] runs out of room to represent inSz, and beyond
* that, the counter itself can wrap.
*/
if ((lenSz < sizeof(inSz)) &&
(inSz >= ((word32)1 << (lenSz * 8))))
{
return AES_CCM_OVERFLOW_E;
}
}
return 0;
}
@@ -468,8 +481,8 @@ static int AesAuthEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
word32 tmpTag[WC_AES_BLOCK_SIZE/sizeof(word32)];
ret = AesAuthArgCheck(aes, out, in, inSz, nonce, nonceSz, authTag,
authTagSz, &M, &L);
if (ret == WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
authTagSz, &M, &L, mode);
if (ret != 0) {
return ret;
}
if ((authIn == NULL) && (authInSz > 0)) {
@@ -571,8 +584,8 @@ static int AesAuthDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz,
word32 tmpTag[WC_AES_BLOCK_SIZE/sizeof(word32)];
ret = AesAuthArgCheck(aes, out, in, inSz, nonce, nonceSz, authTag,
authTagSz, &M, &L);
if (ret == WC_NO_ERR_TRACE(BAD_FUNC_ARG)) {
authTagSz, &M, &L, mode);
if (ret != 0) {
return ret;
}
if ((authIn == NULL) && (authInSz > 0)) {
+135
View File
@@ -19148,6 +19148,26 @@ static wc_test_ret_t aesgcm_stream_test(Aes* enc)
ret = wc_AesGcmEncryptUpdate(enc, resultC, p, sizeof(p), a, sizeof(a));
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7, 0, 0)
ret = wc_AesGcmEncryptUpdate(enc, resultC, p, WOLFSSL_MAX_32BIT,
NULL /* authIn */, 0 /* authInSz */);
if (ret != WC_NO_ERR_TRACE(AES_GCM_OVERFLOW_E)) {
if (ret == 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
else
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
ret = wc_AesGcmEncryptUpdate(enc, resultC, (const byte *)"", 0,
(const byte *)"", WOLFSSL_MAX_32BIT);
if (ret != WC_NO_ERR_TRACE(AES_GCM_OVERFLOW_E)) {
if (ret == 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
else
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
#endif /* !HAVE_FIPS || FIPS_VERSION3_GE(7, 0, 0) */
ret = wc_AesGcmEncryptFinal(enc, resultT, sizeof(t1));
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
@@ -19163,6 +19183,26 @@ static wc_test_ret_t aesgcm_stream_test(Aes* enc)
ret = wc_AesGcmDecryptUpdate(enc, resultP, c1, sizeof(c1), a, sizeof(a));
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7, 0, 0)
ret = wc_AesGcmDecryptUpdate(enc, resultP, c1, WOLFSSL_MAX_32BIT,
NULL /* authIn */, 0 /* authInSz */);
if (ret != WC_NO_ERR_TRACE(AES_GCM_OVERFLOW_E)) {
if (ret == 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
else
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
ret = wc_AesGcmDecryptUpdate(enc, resultP, (const byte *)"", 0,
(const byte *)"", WOLFSSL_MAX_32BIT);
if (ret != WC_NO_ERR_TRACE(AES_GCM_OVERFLOW_E)) {
if (ret == 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
else
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
#endif /* !HAVE_FIPS || FIPS_VERSION3_GE(7, 0, 0) */
ret = wc_AesGcmDecryptFinal(enc, t1, sizeof(t1));
if (ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
@@ -21095,6 +21135,101 @@ static wc_test_ret_t aesccm_128_badarg_test(Aes* enc)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
#endif
#if !defined(BENCH_EMBEDDED) && !defined(WOLFSSL_NO_MALLOC)
/* Test 64k - 1 with full nonce -- must work. */
{
wc_static_assert(sizeof(iv) >= 13);
word32 clear_size = ((word32)1 << 16);
word32 cipher_size = ((word32)1 << 16);
byte *large_alloc = (byte *)XMALLOC(clear_size + cipher_size,
HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
byte *clear = large_alloc;
byte *cipher = large_alloc + clear_size;
if (large_alloc == NULL)
ERROR_OUT(WC_TEST_RET_ENC_EC(MEMORY_E), out);
XMEMSET(clear, 0, clear_size);
ret = wc_AesCcmEncrypt(enc, cipher, clear, clear_size - 1, iv,
13, t_empty2, sizeof(t_empty2), a,
sizeof(a));
if (ret != 0)
ret = WC_TEST_RET_ENC_EC(ret);
#ifdef HAVE_AES_DECRYPT
if (ret == 0) {
word32 i;
XMEMSET(clear, 0xff, clear_size);
ret = wc_AesCcmDecrypt(enc, clear, cipher, cipher_size - 1,
iv, 13, t_empty2, sizeof(t_empty2), a,
sizeof(a));
if (ret != 0)
ret = WC_TEST_RET_ENC_EC(ret);
else {
for (i = 0; i < clear_size - 1; ++i) {
if (clear[i] != 0) {
ret = WC_TEST_RET_ENC_I(i);
break;
}
}
}
}
#endif
XFREE(large_alloc, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (ret != 0)
goto out;
}
#endif /* !BENCH_EMBEDDED && !WOLFSSL_NO_MALLOC */
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7, 0, 0))
ret = wc_AesCcmEncrypt(enc, buf, (const byte *)"", (word32)1 << 16,
iv, 13, t_empty2, sizeof(t_empty2),
a, sizeof(a));
if (ret != WC_NO_ERR_TRACE(AES_CCM_OVERFLOW_E)) {
if (ret == 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
else
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
#ifdef HAVE_AES_DECRYPT
ret = wc_AesCcmDecrypt(enc, buf, (const byte *)"",
(word32)1 << 16, iv, 13, t_empty2,
sizeof(t_empty2), a, sizeof(a));
if (ret != WC_NO_ERR_TRACE(AES_CCM_OVERFLOW_E)) {
if (ret == 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
else
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
#endif
ret = wc_AesCcmEncrypt(enc, buf, (const byte *)"", (word32)1 << 24,
iv, 12, t_empty2, sizeof(t_empty2),
a, sizeof(a));
if (ret != WC_NO_ERR_TRACE(AES_CCM_OVERFLOW_E)) {
if (ret == 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
else
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
#ifdef HAVE_AES_DECRYPT
ret = wc_AesCcmDecrypt(enc, buf, (const byte *)"",
(word32)1 << 24, iv, 12, t_empty2,
sizeof(t_empty2), a, sizeof(a));
if (ret != WC_NO_ERR_TRACE(AES_CCM_OVERFLOW_E)) {
if (ret == 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
else
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
}
#endif
#endif /* !HAVE_SELFTEST && (!HAVE_FIPS || FIPS_VERSION3_GE(7, 0, 0)) */
ret = 0;
out:
return ret;
+2 -2
View File
@@ -251,8 +251,8 @@ enum wolfCrypt_ErrorCodes {
AESCCM_KAT_FIPS_E = -257, /* AESCCM KAT failure */
SHA3_KAT_FIPS_E = -258, /* SHA-3 KAT failure */
ECDHE_KAT_FIPS_E = -259, /* ECDHE KAT failure */
AES_GCM_OVERFLOW_E = -260, /* AES-GCM invocation counter overflow. */
AES_CCM_OVERFLOW_E = -261, /* AES-CCM invocation counter overflow. */
AES_GCM_OVERFLOW_E = -260, /* AES-GCM internal overflow averted */
AES_CCM_OVERFLOW_E = -261, /* AES-CCM internal overflow averted */
RSA_KEY_PAIR_E = -262, /* RSA Key Pair-Wise Consistency check fail. */
DH_CHECK_PRIV_E = -263, /* DH Check Priv Key error */