@@ -6477,7 +6477,7 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, const byte* input,
64776477 return ret;
64786478}
64796479
6480- WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
6480+ WOLFSSL_TEST_VIS SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
64816481 byte* data, word16 size, void* heap)
64826482{
64836483 SessionTicket* ticket = (SessionTicket*)XMALLOC(sizeof(SessionTicket),
@@ -6498,7 +6498,7 @@ WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
64986498
64996499 return ticket;
65006500}
6501- WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap)
6501+ WOLFSSL_TEST_VIS void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap)
65026502{
65036503 if (ticket) {
65046504 XFREE(ticket->data, heap, DYNAMIC_TYPE_TLSX);
@@ -14159,10 +14159,16 @@ static int TLSX_ECH_ExpandOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech,
1415914159 }
1416014160
1416114161 if (ret == 0) {
14162- XFREE(ech->innerClientHello, heap, DYNAMIC_TYPE_TMP_BUFFER);
14163- ech->innerClientHello = newInnerCh;
14164- ech->innerClientHelloLen = (word16)newInnerChLen;
14165- newInnerCh = NULL;
14162+ if (newInnerChLen > WOLFSSL_MAX_16BIT) {
14163+ WOLFSSL_MSG("ECH expanded inner ClientHello exceeds word16");
14164+ ret = BUFFER_E;
14165+ }
14166+ else {
14167+ XFREE(ech->innerClientHello, heap, DYNAMIC_TYPE_TMP_BUFFER);
14168+ ech->innerClientHello = newInnerCh;
14169+ ech->innerClientHelloLen = (word16)newInnerChLen;
14170+ newInnerCh = NULL;
14171+ }
1416614172 }
1416714173
1416814174 if (newInnerCh != NULL)
@@ -14760,7 +14766,14 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1476014766{
1476114767 int ret = 0;
1476214768 TLSX* extension;
14763- word16 length = 0;
14769+ /* Use a word32 accumulator so that an extension whose contribution
14770+ * pushes the running total past 0xFFFF is detected rather than
14771+ * silently wrapped (the TLS extensions block length prefix on the
14772+ * wire is a 2-byte field). Callees that take a word16* accumulator
14773+ * are invoked via a per-iteration shim and their delta is added
14774+ * back into the word32 total. */
14775+ word32 length = 0;
14776+ word16 cbShim;
1476414777 byte isRequest = (msgType == client_hello ||
1476514778 msgType == certificate_request);
1476614779
@@ -14846,19 +14859,25 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1484614859#endif
1484714860#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
1484814861 case TLSX_ENCRYPT_THEN_MAC:
14849- ret = ETM_GET_SIZE(msgType, &length);
14862+ cbShim = 0;
14863+ ret = ETM_GET_SIZE(msgType, &cbShim);
14864+ length += cbShim;
1485014865 break;
1485114866#endif /* HAVE_ENCRYPT_THEN_MAC */
1485214867
1485314868#if defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)
1485414869 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
1485514870 case TLSX_PRE_SHARED_KEY:
14871+ cbShim = 0;
1485614872 ret = PSK_GET_SIZE((PreSharedKey*)extension->data, msgType,
14857- &length);
14873+ &cbShim);
14874+ length += cbShim;
1485814875 break;
1485914876 #ifdef WOLFSSL_TLS13
1486014877 case TLSX_PSK_KEY_EXCHANGE_MODES:
14861- ret = PKM_GET_SIZE((byte)extension->val, msgType, &length);
14878+ cbShim = 0;
14879+ ret = PKM_GET_SIZE((byte)extension->val, msgType, &cbShim);
14880+ length += cbShim;
1486214881 break;
1486314882 #endif
1486414883 #endif
@@ -14869,22 +14888,30 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1486914888
1487014889#ifdef WOLFSSL_TLS13
1487114890 case TLSX_SUPPORTED_VERSIONS:
14872- ret = SV_GET_SIZE(extension->data, msgType, &length);
14891+ cbShim = 0;
14892+ ret = SV_GET_SIZE(extension->data, msgType, &cbShim);
14893+ length += cbShim;
1487314894 break;
1487414895
1487514896 case TLSX_COOKIE:
14876- ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length);
14897+ cbShim = 0;
14898+ ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &cbShim);
14899+ length += cbShim;
1487714900 break;
1487814901
1487914902 #ifdef WOLFSSL_EARLY_DATA
1488014903 case TLSX_EARLY_DATA:
14881- ret = EDI_GET_SIZE(msgType, &length);
14904+ cbShim = 0;
14905+ ret = EDI_GET_SIZE(msgType, &cbShim);
14906+ length += cbShim;
1488214907 break;
1488314908 #endif
1488414909
1488514910 #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
1488614911 case TLSX_POST_HANDSHAKE_AUTH:
14887- ret = PHA_GET_SIZE(msgType, &length);
14912+ cbShim = 0;
14913+ ret = PHA_GET_SIZE(msgType, &cbShim);
14914+ length += cbShim;
1488814915 break;
1488914916 #endif
1489014917
@@ -14940,9 +14967,21 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1494014967 /* marks the extension as processed so ctx level */
1494114968 /* extensions don't overlap with ssl level ones. */
1494214969 TURN_ON(semaphore, TLSX_ToSemaphore((word16)extension->type));
14970+
14971+ /* Early exit: stop accumulating as soon as the running total
14972+ * cannot possibly fit the 2-byte wire length. */
14973+ if (length > WOLFSSL_MAX_16BIT) {
14974+ WOLFSSL_MSG("TLSX_GetSize extension length exceeds word16");
14975+ return BUFFER_E;
14976+ }
1494314977 }
1494414978
14945- *pLength += length;
14979+ if ((word32)*pLength + length > WOLFSSL_MAX_16BIT) {
14980+ WOLFSSL_MSG("TLSX_GetSize total extensions length exceeds word16");
14981+ return BUFFER_E;
14982+ }
14983+
14984+ *pLength += (word16)length;
1494614985
1494714986 return ret;
1494814987}
@@ -14955,6 +14994,7 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
1495514994 TLSX* extension;
1495614995 word16 offset = 0;
1495714996 word16 length_offset = 0;
14997+ word32 prevOffset;
1495814998 byte isRequest = (msgType == client_hello ||
1495914999 msgType == certificate_request);
1496015000
@@ -14969,6 +15009,10 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
1496915009 if (!IS_OFF(semaphore, TLSX_ToSemaphore((word16)extension->type)))
1497015010 continue; /* skip! */
1497115011
15012+ /* Snapshot offset to detect word16 wrap within this iteration;
15013+ * see matching comment in TLSX_GetSize. */
15014+ prevOffset = offset;
15015+
1497215016 /* writes extension type. */
1497315017 c16toa((word16)extension->type, output + offset);
1497415018 offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
@@ -15196,6 +15240,16 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
1519615240 /* if we encountered an error propagate it */
1519715241 if (ret != 0)
1519815242 break;
15243+
15244+ if (offset < prevOffset) {
15245+ WOLFSSL_MSG("TLSX_Write extension length exceeds word16");
15246+ return BUFFER_E;
15247+ }
15248+ }
15249+
15250+ if ((word32)*pOffset + (word32)offset > WOLFSSL_MAX_16BIT) {
15251+ WOLFSSL_MSG("TLSX_Write total extensions length exceeds word16");
15252+ return BUFFER_E;
1519915253 }
1520015254
1520115255 *pOffset += offset;
@@ -16283,6 +16337,13 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength)
1628316337 }
1628416338#endif
1628516339
16340+ /* The TLS extensions block length prefix is a 2-byte field, so any
16341+ * accumulated total above 0xFFFF must be rejected rather than silently
16342+ * truncating and producing a short, malformed handshake message. */
16343+ if (length > (word16)(WOLFSSL_MAX_16BIT - OPAQUE16_LEN)) {
16344+ WOLFSSL_MSG("TLSX_GetRequestSize extensions exceed word16");
16345+ return BUFFER_E;
16346+ }
1628616347 if (length)
1628716348 length += OPAQUE16_LEN; /* for total length storage. */
1628816349
@@ -16486,6 +16547,12 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word32* pOffset)
1648616547 #endif
1648716548#endif
1648816549
16550+ /* Wrap detection for the TLSX_Write calls above is handled inside
16551+ * TLSX_Write itself: any iteration that would push the local word16
16552+ * offset past 0xFFFF returns BUFFER_E so we never reach here with a
16553+ * truncated value. The TLS extensions block length prefix on the
16554+ * wire is a 2-byte field, matching this invariant. */
16555+
1648916556 if (offset > OPAQUE16_LEN || msgType != client_hello)
1649016557 c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
1649116558
0 commit comments