@@ -6493,7 +6493,7 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, const byte* input,
64936493 return ret;
64946494}
64956495
6496- WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
6496+ WOLFSSL_TEST_VIS SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
64976497 byte* data, word16 size, void* heap)
64986498{
64996499 SessionTicket* ticket = (SessionTicket*)XMALLOC(sizeof(SessionTicket),
@@ -6514,7 +6514,7 @@ WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
65146514
65156515 return ticket;
65166516}
6517- WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap)
6517+ WOLFSSL_TEST_VIS void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap)
65186518{
65196519 if (ticket) {
65206520 XFREE(ticket->data, heap, DYNAMIC_TYPE_TLSX);
@@ -14868,7 +14868,14 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1486814868{
1486914869 int ret = 0;
1487014870 TLSX* extension;
14871- word16 length = 0;
14871+ /* Use a word32 accumulator so that an extension whose contribution
14872+ * pushes the running total past 0xFFFF is detected rather than
14873+ * silently wrapped (the TLS extensions block length prefix on the
14874+ * wire is a 2-byte field). Callees that take a word16* accumulator
14875+ * are invoked via a per-iteration shim and their delta is added
14876+ * back into the word32 total. */
14877+ word32 length = 0;
14878+ word16 cbShim;
1487214879 byte isRequest = (msgType == client_hello ||
1487314880 msgType == certificate_request);
1487414881
@@ -14954,19 +14961,25 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1495414961#endif
1495514962#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
1495614963 case TLSX_ENCRYPT_THEN_MAC:
14957- ret = ETM_GET_SIZE(msgType, &length);
14964+ cbShim = 0;
14965+ ret = ETM_GET_SIZE(msgType, &cbShim);
14966+ length += cbShim;
1495814967 break;
1495914968#endif /* HAVE_ENCRYPT_THEN_MAC */
1496014969
1496114970#if defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)
1496214971 #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
1496314972 case TLSX_PRE_SHARED_KEY:
14973+ cbShim = 0;
1496414974 ret = PSK_GET_SIZE((PreSharedKey*)extension->data, msgType,
14965- &length);
14975+ &cbShim);
14976+ length += cbShim;
1496614977 break;
1496714978 #ifdef WOLFSSL_TLS13
1496814979 case TLSX_PSK_KEY_EXCHANGE_MODES:
14969- ret = PKM_GET_SIZE((byte)extension->val, msgType, &length);
14980+ cbShim = 0;
14981+ ret = PKM_GET_SIZE((byte)extension->val, msgType, &cbShim);
14982+ length += cbShim;
1497014983 break;
1497114984 #ifdef WOLFSSL_CERT_WITH_EXTERN_PSK
1497214985 case TLSX_CERT_WITH_EXTERN_PSK:
@@ -14982,22 +14995,30 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1498214995
1498314996#ifdef WOLFSSL_TLS13
1498414997 case TLSX_SUPPORTED_VERSIONS:
14985- ret = SV_GET_SIZE(extension->data, msgType, &length);
14998+ cbShim = 0;
14999+ ret = SV_GET_SIZE(extension->data, msgType, &cbShim);
15000+ length += cbShim;
1498615001 break;
1498715002
1498815003 case TLSX_COOKIE:
14989- ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length);
15004+ cbShim = 0;
15005+ ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &cbShim);
15006+ length += cbShim;
1499015007 break;
1499115008
1499215009 #ifdef WOLFSSL_EARLY_DATA
1499315010 case TLSX_EARLY_DATA:
14994- ret = EDI_GET_SIZE(msgType, &length);
15011+ cbShim = 0;
15012+ ret = EDI_GET_SIZE(msgType, &cbShim);
15013+ length += cbShim;
1499515014 break;
1499615015 #endif
1499715016
1499815017 #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
1499915018 case TLSX_POST_HANDSHAKE_AUTH:
15000- ret = PHA_GET_SIZE(msgType, &length);
15019+ cbShim = 0;
15020+ ret = PHA_GET_SIZE(msgType, &cbShim);
15021+ length += cbShim;
1500115022 break;
1500215023 #endif
1500315024
@@ -15053,9 +15074,21 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1505315074 /* marks the extension as processed so ctx level */
1505415075 /* extensions don't overlap with ssl level ones. */
1505515076 TURN_ON(semaphore, TLSX_ToSemaphore((word16)extension->type));
15077+
15078+ /* Early exit: stop accumulating as soon as the running total
15079+ * cannot possibly fit the 2-byte wire length. */
15080+ if (length > WOLFSSL_MAX_16BIT) {
15081+ WOLFSSL_MSG("TLSX_GetSize extension length exceeds word16");
15082+ return BUFFER_E;
15083+ }
1505615084 }
1505715085
15058- *pLength += length;
15086+ if ((word32)*pLength + length > WOLFSSL_MAX_16BIT) {
15087+ WOLFSSL_MSG("TLSX_GetSize total extensions length exceeds word16");
15088+ return BUFFER_E;
15089+ }
15090+
15091+ *pLength += (word16)length;
1505915092
1506015093 return ret;
1506115094}
@@ -15068,6 +15101,7 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
1506815101 TLSX* extension;
1506915102 word16 offset = 0;
1507015103 word16 length_offset = 0;
15104+ word32 prevOffset;
1507115105 byte isRequest = (msgType == client_hello ||
1507215106 msgType == certificate_request);
1507315107
@@ -15082,6 +15116,10 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
1508215116 if (!IS_OFF(semaphore, TLSX_ToSemaphore((word16)extension->type)))
1508315117 continue; /* skip! */
1508415118
15119+ /* Snapshot offset to detect word16 wrap within this iteration;
15120+ * see matching comment in TLSX_GetSize. */
15121+ prevOffset = offset;
15122+
1508515123 /* writes extension type. */
1508615124 c16toa((word16)extension->type, output + offset);
1508715125 offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
@@ -15315,6 +15353,16 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
1531515353 /* if we encountered an error propagate it */
1531615354 if (ret != 0)
1531715355 break;
15356+
15357+ if (offset < prevOffset) {
15358+ WOLFSSL_MSG("TLSX_Write extension length exceeds word16");
15359+ return BUFFER_E;
15360+ }
15361+ }
15362+
15363+ if ((word32)*pOffset + (word32)offset > WOLFSSL_MAX_16BIT) {
15364+ WOLFSSL_MSG("TLSX_Write total extensions length exceeds word16");
15365+ return BUFFER_E;
1531815366 }
1531915367
1532015368 *pOffset += offset;
@@ -16421,6 +16469,13 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength)
1642116469 }
1642216470#endif
1642316471
16472+ /* The TLS extensions block length prefix is a 2-byte field, so any
16473+ * accumulated total above 0xFFFF must be rejected rather than silently
16474+ * truncating and producing a short, malformed handshake message. */
16475+ if (length > (word16)(WOLFSSL_MAX_16BIT - OPAQUE16_LEN)) {
16476+ WOLFSSL_MSG("TLSX_GetRequestSize extensions exceed word16");
16477+ return BUFFER_E;
16478+ }
1642416479 if (length)
1642516480 length += OPAQUE16_LEN; /* for total length storage. */
1642616481
@@ -16624,6 +16679,12 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word32* pOffset)
1662416679 #endif
1662516680#endif
1662616681
16682+ /* Wrap detection for the TLSX_Write calls above is handled inside
16683+ * TLSX_Write itself: any iteration that would push the local word16
16684+ * offset past 0xFFFF returns BUFFER_E so we never reach here with a
16685+ * truncated value. The TLS extensions block length prefix on the
16686+ * wire is a 2-byte field, matching this invariant. */
16687+
1662716688 if (offset > OPAQUE16_LEN || msgType != client_hello)
1662816689 c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
1662916690
0 commit comments