Skip to content

Commit 85228f0

Browse files
Merge pull request #9824 from embhorn/zd21239
Fix issues in TLS Extension size calculations
2 parents ba859d2 + f53ce49 commit 85228f0

5 files changed

Lines changed: 103 additions & 12 deletions

File tree

src/tls.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,10 +2135,10 @@ static void TLSX_SNI_FreeAll(SNI* list, void* heap)
21352135
}
21362136

21372137
/** Tells the buffered size of the SNI objects in a list. */
2138-
static word16 TLSX_SNI_GetSize(SNI* list)
2138+
WOLFSSL_TEST_VIS word16 TLSX_SNI_GetSize(SNI* list)
21392139
{
21402140
SNI* sni;
2141-
word16 length = OPAQUE16_LEN; /* list length */
2141+
word32 length = OPAQUE16_LEN; /* list length */
21422142

21432143
while ((sni = list)) {
21442144
list = sni->next;
@@ -2147,12 +2147,16 @@ static word16 TLSX_SNI_GetSize(SNI* list)
21472147

21482148
switch (sni->type) {
21492149
case WOLFSSL_SNI_HOST_NAME:
2150-
length += (word16)XSTRLEN((char*)sni->data.host_name);
2150+
length += (word32)XSTRLEN((char*)sni->data.host_name);
21512151
break;
21522152
}
2153+
2154+
if (length > WOLFSSL_MAX_16BIT) {
2155+
return 0;
2156+
}
21532157
}
21542158

2155-
return length;
2159+
return (word16)length;
21562160
}
21572161

21582162
/** Writes the SNI objects of a list in a buffer. */
@@ -3216,7 +3220,7 @@ static void TLSX_CSR_Free(CertificateStatusRequest* csr, void* heap)
32163220
word16 TLSX_CSR_GetSize_ex(CertificateStatusRequest* csr, byte isRequest,
32173221
int idx)
32183222
{
3219-
word16 size = 0;
3223+
word32 size = 0;
32203224

32213225
/* shut up compiler warnings */
32223226
(void) csr; (void) isRequest;
@@ -3237,15 +3241,25 @@ word16 TLSX_CSR_GetSize_ex(CertificateStatusRequest* csr, byte isRequest,
32373241
if (csr->ssl != NULL && SSL_CM(csr->ssl) != NULL &&
32383242
SSL_CM(csr->ssl)->ocsp_stapling != NULL &&
32393243
SSL_CM(csr->ssl)->ocsp_stapling->statusCb != NULL) {
3240-
return OPAQUE8_LEN + OPAQUE24_LEN + csr->ssl->ocspCsrResp[idx].length;
3244+
if (WOLFSSL_MAX_16BIT - OPAQUE8_LEN - OPAQUE24_LEN <
3245+
csr->ssl->ocspCsrResp[idx].length) {
3246+
return 0;
3247+
}
3248+
size = OPAQUE8_LEN + OPAQUE24_LEN +
3249+
csr->ssl->ocspCsrResp[idx].length;
3250+
return (word16)size;
32413251
}
3242-
return (word16)(OPAQUE8_LEN + OPAQUE24_LEN +
3243-
csr->responses[idx].length);
3252+
if (WOLFSSL_MAX_16BIT - OPAQUE8_LEN - OPAQUE24_LEN <
3253+
csr->responses[idx].length) {
3254+
return 0;
3255+
}
3256+
size = OPAQUE8_LEN + OPAQUE24_LEN + csr->responses[idx].length;
3257+
return (word16)size;
32443258
}
32453259
#else
32463260
(void)idx;
32473261
#endif
3248-
return size;
3262+
return (word16)size;
32493263
}
32503264

32513265
#if (defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER))
@@ -3855,7 +3869,7 @@ static void TLSX_CSR2_FreeAll(CertificateStatusRequestItemV2* csr2, void* heap)
38553869
static word16 TLSX_CSR2_GetSize(CertificateStatusRequestItemV2* csr2,
38563870
byte isRequest)
38573871
{
3858-
word16 size = 0;
3872+
word32 size = 0;
38593873

38603874
/* shut up compiler warnings */
38613875
(void) csr2; (void) isRequest;
@@ -3876,11 +3890,15 @@ static word16 TLSX_CSR2_GetSize(CertificateStatusRequestItemV2* csr2,
38763890
size += OCSP_NONCE_EXT_SZ;
38773891
break;
38783892
}
3893+
3894+
if (size > WOLFSSL_MAX_16BIT) {
3895+
return 0;
3896+
}
38793897
}
38803898
}
38813899
#endif
38823900

3883-
return size;
3901+
return (word16)size;
38843902
}
38853903

38863904
static int TLSX_CSR2_Write(CertificateStatusRequestItemV2* csr2,

tests/api.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33145,6 +33145,7 @@ TEST_CASE testCases[] = {
3314533145
TEST_DECL(test_certificate_authorities_certificate_request),
3314633146
TEST_DECL(test_certificate_authorities_client_hello),
3314733147
TEST_DECL(test_TLSX_TCA_Find),
33148+
TEST_DECL(test_TLSX_SNI_GetSize_overflow),
3314833149
TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation),
3314933150
TEST_DECL(test_wolfSSL_SCR_Reconnect),
3315033151
TEST_DECL(test_wolfSSL_SCR_check_enabled),

tests/api/test_tls_ext.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,3 +545,67 @@ int test_certificate_authorities_client_hello(void) {
545545
#endif
546546
return EXPECT_RESULT();
547547
}
548+
549+
/* Test that the SNI size calculation returns 0 on overflow instead of
550+
* wrapping around to a small value (integer overflow vulnerability). */
551+
int test_TLSX_SNI_GetSize_overflow(void)
552+
{
553+
EXPECT_DECLS;
554+
#if defined(HAVE_SNI) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
555+
WOLFSSL_CTX* ctx = NULL;
556+
WOLFSSL* ssl = NULL;
557+
TLSX* sni_ext = NULL;
558+
SNI* head = NULL;
559+
SNI* sni = NULL;
560+
int i;
561+
/* Each SNI adds ENUM_LEN(1) + OPAQUE16_LEN(2) + hostname_len to the size.
562+
* With a 1-byte hostname, each entry adds 4 bytes. Starting from
563+
* OPAQUE16_LEN(2) base, we need enough entries to exceed UINT16_MAX. */
564+
const int num_sni = (0xFFFF / 4) + 2;
565+
566+
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
567+
ExpectNotNull(ssl = wolfSSL_new(ctx));
568+
569+
/* Add initial SNI via public API */
570+
ExpectIntEQ(WOLFSSL_SUCCESS,
571+
wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, "a", 1));
572+
573+
/* Find the SNI extension and manually build a long chain */
574+
if (EXPECT_SUCCESS()) {
575+
sni_ext = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
576+
ExpectNotNull(sni_ext);
577+
}
578+
579+
if (EXPECT_SUCCESS()) {
580+
head = (SNI*)sni_ext->data;
581+
ExpectNotNull(head);
582+
}
583+
584+
/* Append many SNI nodes to force overflow in the size calculation */
585+
for (i = 1; EXPECT_SUCCESS() && i < num_sni; i++) {
586+
sni = (SNI*)XMALLOC(sizeof(SNI), NULL, DYNAMIC_TYPE_TLSX);
587+
ExpectNotNull(sni);
588+
if (sni != NULL) {
589+
XMEMSET(sni, 0, sizeof(SNI));
590+
sni->type = WOLFSSL_SNI_HOST_NAME;
591+
sni->data.host_name = (char*)XMALLOC(2, NULL, DYNAMIC_TYPE_TLSX);
592+
ExpectNotNull(sni->data.host_name);
593+
if (sni->data.host_name != NULL) {
594+
sni->data.host_name[0] = 'a';
595+
sni->data.host_name[1] = '\0';
596+
}
597+
sni->next = head->next;
598+
head->next = sni;
599+
}
600+
}
601+
602+
if (EXPECT_SUCCESS()) {
603+
/* The fixed calculation should return 0 (overflow detected) */
604+
ExpectIntEQ(TLSX_SNI_GetSize((SNI*)sni_ext->data), 0);
605+
}
606+
607+
wolfSSL_free(ssl);
608+
wolfSSL_CTX_free(ctx);
609+
#endif
610+
return EXPECT_RESULT();
611+
}

tests/api/test_tls_ext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ int test_wolfSSL_DisableExtendedMasterSecret(void);
2727
int test_certificate_authorities_certificate_request(void);
2828
int test_certificate_authorities_client_hello(void);
2929
int test_TLSX_TCA_Find(void);
30+
int test_TLSX_SNI_GetSize_overflow(void);
3031

3132
#endif /* TESTS_API_TEST_TLS_EMS_H */

wolfssl/internal.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3169,7 +3169,10 @@ struct TLSX {
31693169
struct TLSX* next; /* List Behavior */
31703170
};
31713171

3172-
WOLFSSL_LOCAL TLSX* TLSX_Find(TLSX* list, TLSX_Type type);
3172+
#ifdef WOLFSSL_API_PREFIX_MAP
3173+
#define TLSX_Find wolfSSL_TLSX_Find
3174+
#endif
3175+
WOLFSSL_TEST_VIS TLSX* TLSX_Find(TLSX* list, TLSX_Type type);
31733176
WOLFSSL_LOCAL void TLSX_Remove(TLSX** list, TLSX_Type type, void* heap);
31743177
WOLFSSL_LOCAL void TLSX_FreeAll(TLSX* list, void* heap);
31753178
WOLFSSL_LOCAL int TLSX_SupportExtensions(WOLFSSL* ssl);
@@ -3237,6 +3240,10 @@ WOLFSSL_LOCAL int TLSX_UseSNI(TLSX** extensions, byte type, const void* data,
32373240
WOLFSSL_LOCAL byte TLSX_SNI_Status(TLSX* extensions, byte type);
32383241
WOLFSSL_LOCAL word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type,
32393242
void** data, byte ignoreStatus);
3243+
#ifdef WOLFSSL_API_PREFIX_MAP
3244+
#define TLSX_SNI_GetSize wolfSSL_TLSX_SNI_GetSize
3245+
#endif
3246+
WOLFSSL_TEST_VIS word16 TLSX_SNI_GetSize(SNI* list);
32403247

32413248
#ifndef NO_WOLFSSL_SERVER
32423249
WOLFSSL_LOCAL void TLSX_SNI_SetOptions(TLSX* extensions, byte type,

0 commit comments

Comments
 (0)