Skip to content

Commit 2f53add

Browse files
authored
Merge pull request #9758 from LinuxJedi/lxj-fixes
Minor fixes to EVP and PKCS12 code
2 parents 1847c6e + 33abaca commit 2f53add

File tree

6 files changed

+153
-6
lines changed

6 files changed

+153
-6
lines changed

tests/api/test_evp_cipher.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2702,3 +2702,82 @@ int test_wolfSSL_EVP_mdc2(void)
27022702
return EXPECT_RESULT();
27032703
}
27042704

2705+
/* Test for integer overflow in EVP AEAD AAD accumulation.
2706+
*
2707+
* wolfSSL_EVP_CipherUpdate_GCM_AAD (and the CCM/ARIA variants) compute
2708+
* allocation sizes as (ctx->authInSz + inl) where both operands are int.
2709+
* Repeated AAD calls can accumulate authInSz to a value where adding inl
2710+
* overflows the signed int sum. The overflowed value is then cast to size_t
2711+
* for XMALLOC/XREALLOC, producing either:
2712+
* - A huge allocation on 64-bit (masking the bug as MEMORY_E), or
2713+
* - A potential heap buffer overflow on 32-bit if the wrapped size is small
2714+
* enough to succeed but the subsequent XMEMCPY uses the original large
2715+
* authInSz offset.
2716+
*
2717+
* This test simulates the overflow condition by directly setting authInSz near
2718+
* INT_MAX after legitimate initialization, then calling EVP_EncryptUpdate with
2719+
* AAD that triggers the overflow. A properly-fixed implementation should detect
2720+
* the overflow and return WOLFSSL_FAILURE before attempting the allocation.
2721+
*/
2722+
int test_evp_cipher_aead_aad_overflow(void)
2723+
{
2724+
EXPECT_DECLS;
2725+
#if defined(OPENSSL_EXTRA) && !defined(NO_AES) && defined(HAVE_AESGCM) && \
2726+
defined(WOLFSSL_AES_256) && !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) && \
2727+
!defined(WOLFSSL_AESGCM_STREAM)
2728+
2729+
WOLFSSL_EVP_CIPHER_CTX *ctx = NULL;
2730+
byte key[32] = {0};
2731+
byte iv[12] = {0};
2732+
byte aad[32] = {0};
2733+
int outl = 0;
2734+
int savedAuthInSz;
2735+
2736+
/* Initialize AES-256-GCM encryption context */
2737+
ctx = EVP_CIPHER_CTX_new();
2738+
ExpectNotNull(ctx);
2739+
ExpectIntEQ(WOLFSSL_SUCCESS, EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(),
2740+
NULL, key, iv));
2741+
2742+
/* Feed a small legitimate AAD to allocate authIn */
2743+
ExpectIntEQ(WOLFSSL_SUCCESS, EVP_EncryptUpdate(ctx, NULL, &outl, aad, 16));
2744+
2745+
if (EXPECT_SUCCESS()) {
2746+
ExpectIntEQ(ctx->authInSz, 16);
2747+
2748+
/* Simulate accumulated AAD near INT_MAX.
2749+
* In a real attack scenario, an attacker controlling AAD input to a
2750+
* server could accumulate authInSz toward INT_MAX through many calls.
2751+
* We set it directly to avoid needing ~2GB of actual allocations.
2752+
*/
2753+
savedAuthInSz = ctx->authInSz;
2754+
ctx->authInSz = INT_MAX - 16;
2755+
2756+
/* Attempt AAD update that causes overflow:
2757+
* (INT_MAX - 16) + 32 = INT_MAX + 16
2758+
* This overflows signed int (undefined behavior in C). The result:
2759+
* - As signed int: wraps to INT_MIN + 15 (on 2's complement)
2760+
* - Cast to size_t on 64-bit: ~0xFFFFFFFF8000000F (huge)
2761+
* - Cast to size_t on 32-bit: ~0x8000000F (~2GB)
2762+
*
2763+
* With no overflow check, the code proceeds to XREALLOC with the
2764+
* wrapped size. On 64-bit this fails (MEMORY_E), accidentally
2765+
* preventing corruption. On 32-bit, if the allocation succeeds,
2766+
* XMEMCPY writes at offset (INT_MAX - 16) into the buffer, causing
2767+
* heap corruption.
2768+
*/
2769+
ExpectIntNE(WOLFSSL_SUCCESS,
2770+
EVP_EncryptUpdate(ctx, NULL, &outl, aad, 32));
2771+
2772+
/* Restore authInSz so cleanup doesn't operate on corrupted state */
2773+
if (ctx != NULL)
2774+
ctx->authInSz = savedAuthInSz;
2775+
}
2776+
2777+
EVP_CIPHER_CTX_free(ctx);
2778+
2779+
#endif /* OPENSSL_EXTRA && HAVE_AESGCM && WOLFSSL_AES_256 */
2780+
return EXPECT_RESULT();
2781+
}
2782+
2783+

tests/api/test_evp_cipher.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ int test_wolfSSL_EVP_rc4(void);
6363
int test_wolfSSL_EVP_enc_null(void);
6464
int test_wolfSSL_EVP_rc2_cbc(void);
6565
int test_wolfSSL_EVP_mdc2(void);
66+
int test_evp_cipher_aead_aad_overflow(void);
6667

6768
#define TEST_EVP_CIPHER_DECLS \
6869
TEST_DECL_GROUP("evp_cipher", test_wolfSSL_EVP_CIPHER_CTX), \
@@ -103,6 +104,7 @@ int test_wolfSSL_EVP_mdc2(void);
103104
TEST_DECL_GROUP("evp_cipher", test_wolfSSL_EVP_rc4), \
104105
TEST_DECL_GROUP("evp_cipher", test_wolfSSL_EVP_enc_null), \
105106
TEST_DECL_GROUP("evp_cipher", test_wolfSSL_EVP_rc2_cbc), \
106-
TEST_DECL_GROUP("evp_cipher", test_wolfSSL_EVP_mdc2)
107+
TEST_DECL_GROUP("evp_cipher", test_wolfSSL_EVP_mdc2), \
108+
TEST_DECL_GROUP("evp_cipher", test_evp_cipher_aead_aad_overflow)
107109

108110
#endif /* WOLFCRYPT_TEST_EVP_CIPHER_H */

tests/api/test_pkcs12.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,42 @@ int test_wc_PKCS12_create(void)
196196
return EXPECT_RESULT();
197197
}
198198

199+
int test_wc_d2i_PKCS12_bad_mac_salt(void)
200+
{
201+
EXPECT_DECLS;
202+
#if !defined(NO_ASN) && !defined(NO_PWDBASED) && defined(HAVE_PKCS12) \
203+
&& !defined(NO_FILESYSTEM) && !defined(NO_RSA) \
204+
&& !defined(NO_AES) && !defined(NO_SHA) && !defined(NO_SHA256)
205+
WC_PKCS12* pkcs12 = NULL;
206+
unsigned char der[FOURK_BUF * 2];
207+
int derSz = 0;
208+
const char p12_f[] = "./certs/test-servercert.p12";
209+
XFILE f = XBADFILE;
210+
int i;
211+
int found = 0;
212+
213+
ExpectTrue((f = XFOPEN(p12_f, "rb")) != XBADFILE);
214+
ExpectIntGT(derSz = (int)XFREAD(der, 1, sizeof(der), f), 0);
215+
if (f != XBADFILE)
216+
XFCLOSE(f);
217+
218+
/* Scan backward within the last 100 bytes to find the MAC salt
219+
* OCTET STRING (tag 0x04, length 0x08 for a typical 8-byte salt).
220+
* Corrupt its length so that saltSz + curIdx > totalSz, triggering
221+
* the error path in GetSignData() after salt allocation. */
222+
for (i = derSz - 2; i >= 0 && i >= derSz - 100; i--) {
223+
if (der[i] == 0x04 && der[i + 1] == 0x08) {
224+
der[i + 1] = 0xFF;
225+
found = 1;
226+
break;
227+
}
228+
}
229+
ExpectIntEQ(found, 1);
230+
231+
ExpectNotNull(pkcs12 = wc_PKCS12_new());
232+
ExpectIntNE(wc_d2i_PKCS12(der, (word32)derSz, pkcs12), 0);
233+
wc_PKCS12_free(pkcs12);
234+
#endif
235+
return EXPECT_RESULT();
236+
}
237+

tests/api/test_pkcs12.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626

2727
int test_wc_i2d_PKCS12(void);
2828
int test_wc_PKCS12_create(void);
29+
int test_wc_d2i_PKCS12_bad_mac_salt(void);
2930

3031
#define TEST_PKCS12_DECLS \
3132
TEST_DECL_GROUP("pkcs12", test_wc_i2d_PKCS12), \
32-
TEST_DECL_GROUP("pkcs12", test_wc_PKCS12_create)
33+
TEST_DECL_GROUP("pkcs12", test_wc_PKCS12_create), \
34+
TEST_DECL_GROUP("pkcs12", test_wc_d2i_PKCS12_bad_mac_salt)
3335

3436
#endif /* WOLFCRYPT_TEST_PKCS12_H */

wolfcrypt/src/evp.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,10 @@ static int wolfSSL_EVP_CipherUpdate_GCM_AAD(WOLFSSL_EVP_CIPHER_CTX *ctx,
745745
const unsigned char *in, int inl) {
746746
if (in && inl > 0) {
747747
byte* tmp;
748+
if (inl > INT_MAX - ctx->authInSz) {
749+
WOLFSSL_MSG("AuthIn overflow");
750+
return BAD_FUNC_ARG;
751+
}
748752
#ifdef WOLFSSL_NO_REALLOC
749753
tmp = (byte*)XMALLOC((size_t)(ctx->authInSz + inl), NULL,
750754
DYNAMIC_TYPE_OPENSSL);
@@ -789,6 +793,9 @@ static int wolfSSL_EVP_CipherUpdate_GCM(WOLFSSL_EVP_CIPHER_CTX *ctx,
789793
/* Buffer input for one-shot API */
790794
if (inl > 0) {
791795
byte* tmp;
796+
if ((int)inl > INT_MAX - ctx->authBufferLen) {
797+
return MEMORY_E;
798+
}
792799
#ifdef WOLFSSL_NO_REALLOC
793800
tmp = (byte*)XMALLOC((size_t)(ctx->authBufferLen + inl), NULL,
794801
DYNAMIC_TYPE_OPENSSL);
@@ -872,6 +879,10 @@ static int wolfSSL_EVP_CipherUpdate_CCM_AAD(WOLFSSL_EVP_CIPHER_CTX *ctx,
872879
const unsigned char *in, int inl) {
873880
if (in && inl > 0) {
874881
byte* tmp;
882+
if (inl > INT_MAX - ctx->authInSz) {
883+
WOLFSSL_MSG("AuthIn overflow");
884+
return BAD_FUNC_ARG;
885+
}
875886
#ifdef WOLFSSL_NO_REALLOC
876887
tmp = (byte*)XMALLOC((size_t)(ctx->authInSz + inl), NULL,
877888
DYNAMIC_TYPE_OPENSSL);
@@ -908,6 +919,9 @@ static int wolfSSL_EVP_CipherUpdate_CCM(WOLFSSL_EVP_CIPHER_CTX *ctx,
908919
/* Buffer input for one-shot API */
909920
if (inl > 0) {
910921
byte* tmp;
922+
if (inl > INT_MAX - ctx->authBufferLen) {
923+
return MEMORY_E;
924+
}
911925
#ifdef WOLFSSL_NO_REALLOC
912926
tmp = (byte*)XMALLOC((size_t)(ctx->authBufferLen + inl), NULL,
913927
DYNAMIC_TYPE_OPENSSL);
@@ -951,8 +965,12 @@ static int wolfSSL_EVP_CipherUpdate_AriaGCM_AAD(WOLFSSL_EVP_CIPHER_CTX *ctx,
951965
{
952966
if (in && inl > 0) {
953967
byte* tmp;
968+
if (inl > INT_MAX - ctx->authInSz) {
969+
WOLFSSL_MSG("AuthIn overflow");
970+
return BAD_FUNC_ARG;
971+
}
954972
#ifdef WOLFSSL_NO_REALLOC
955-
tmp = (byte*)XMALLOC((size_t)ctx->authInSz + inl, NULL,
973+
tmp = (byte*)XMALLOC((size_t)(ctx->authInSz + inl), NULL,
956974
DYNAMIC_TYPE_OPENSSL);
957975
if (tmp != NULL) {
958976
XMEMCPY(tmp, ctx->authIn, (size_t)ctx->authInSz);
@@ -961,7 +979,7 @@ static int wolfSSL_EVP_CipherUpdate_AriaGCM_AAD(WOLFSSL_EVP_CIPHER_CTX *ctx,
961979
}
962980
#else
963981
tmp = (byte*)XREALLOC(ctx->authIn,
964-
(size_t)ctx->authInSz + inl, NULL, DYNAMIC_TYPE_OPENSSL);
982+
(size_t)(ctx->authInSz + inl), NULL, DYNAMIC_TYPE_OPENSSL);
965983
#endif
966984
if (tmp) {
967985
ctx->authIn = tmp;

wolfcrypt/src/pkcs12.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ static int GetSignData(WC_PKCS12* pkcs12, const byte* mem, word32* idx,
509509
if (ret != 0) {
510510
if (mac) {
511511
XFREE(mac->digest, pkcs12->heap, DYNAMIC_TYPE_DIGEST);
512+
XFREE(mac->salt, pkcs12->heap, DYNAMIC_TYPE_SALT);
512513
XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
513514
}
514515
}
@@ -1134,6 +1135,7 @@ static byte* PKCS12_ConcatenateContent(WC_PKCS12* pkcs12,byte* mergedData,
11341135
{
11351136
byte* oldContent;
11361137
word32 oldContentSz;
1138+
word32 newSz;
11371139

11381140
(void)pkcs12;
11391141

@@ -1145,14 +1147,19 @@ static byte* PKCS12_ConcatenateContent(WC_PKCS12* pkcs12,byte* mergedData,
11451147
oldContentSz = *mergedSz;
11461148

11471149
/* re-allocate new buffer to fit appended data */
1148-
mergedData = (byte*)XMALLOC(oldContentSz + inSz, pkcs12->heap,
1150+
if (WC_SAFE_SUM_WORD32(oldContentSz, inSz, newSz) == 0) {
1151+
XFREE(oldContent, pkcs12->heap, DYNAMIC_TYPE_PKCS);
1152+
return NULL;
1153+
}
1154+
1155+
mergedData = (byte*)XMALLOC(newSz, pkcs12->heap,
11491156
DYNAMIC_TYPE_PKCS);
11501157
if (mergedData != NULL) {
11511158
if (oldContent != NULL) {
11521159
XMEMCPY(mergedData, oldContent, oldContentSz);
11531160
}
11541161
XMEMCPY(mergedData + oldContentSz, in, inSz);
1155-
*mergedSz += inSz;
1162+
*mergedSz = newSz;
11561163
}
11571164
XFREE(oldContent, pkcs12->heap, DYNAMIC_TYPE_PKCS);
11581165

0 commit comments

Comments
 (0)