Skip to content

Commit c60ffbd

Browse files
committed
Fix from review
1 parent d9beafb commit c60ffbd

2 files changed

Lines changed: 96 additions & 7 deletions

File tree

src/tls.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14770,8 +14770,18 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1477014770
* pushes the running total past 0xFFFF is detected rather than
1477114771
* silently wrapped (the TLS extensions block length prefix on the
1477214772
* 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. */
14773+
* are invoked via a per-iteration shim (`cbShim`) and their delta
14774+
* is added back into the word32 total.
14775+
*
14776+
* MAINTAINER NOTE: do NOT pass &length to any *_GET_SIZE function
14777+
* that expects a `word16*` out-parameter — that would be a type
14778+
* mismatch (UB) and would silently bypass the overflow detection
14779+
* below. When adding a new extension case, either:
14780+
* - use `length += FOO_GET_SIZE(...)` when the helper returns a
14781+
* word16 by value, or
14782+
* - use the cbShim pattern: `cbShim = 0; ret = FOO_GET_SIZE(...,
14783+
* &cbShim); length += cbShim;`
14784+
*/
1477514785
word32 length = 0;
1477614786
word16 cbShim;
1477714787
byte isRequest = (msgType == client_hello ||
@@ -14964,16 +14974,18 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1496414974
break;
1496514975
}
1496614976

14967-
/* marks the extension as processed so ctx level */
14968-
/* extensions don't overlap with ssl level ones. */
14969-
TURN_ON(semaphore, TLSX_ToSemaphore((word16)extension->type));
14970-
1497114977
/* Early exit: stop accumulating as soon as the running total
14972-
* cannot possibly fit the 2-byte wire length. */
14978+
* cannot possibly fit the 2-byte wire length. Check *before*
14979+
* marking the extension as processed so the semaphore is not
14980+
* left in an inconsistent state on the error path. */
1497314981
if (length > WOLFSSL_MAX_16BIT) {
1497414982
WOLFSSL_MSG("TLSX_GetSize extension length exceeds word16");
1497514983
return BUFFER_E;
1497614984
}
14985+
14986+
/* marks the extension as processed so ctx level */
14987+
/* extensions don't overlap with ssl level ones. */
14988+
TURN_ON(semaphore, TLSX_ToSemaphore((word16)extension->type));
1497714989
}
1497814990

1497914991
if ((word32)*pLength + length > WOLFSSL_MAX_16BIT) {

tests/api.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10528,6 +10528,83 @@ static int test_tls_ext_word16_overflow(void)
1052810528
wolfSSL_free(ssl);
1052910529
wolfSSL_CTX_free(ctx);
1053010530
XFREE(big, NULL, DYNAMIC_TYPE_TMP_BUFFER);
10531+
ssl = NULL;
10532+
ctx = NULL;
10533+
big = NULL;
10534+
10535+
/* Boundary case: construct a SessionTicket extension sized so that the
10536+
* total extensions length in TLSX_GetRequestSize is exactly
10537+
* WOLFSSL_MAX_16BIT - OPAQUE16_LEN (0xFFFD) *before* the OPAQUE16_LEN
10538+
* block-prefix adjustment, which must succeed. This pins the `>`
10539+
* comparison in the overflow check — mutating it to `>=` would
10540+
* incorrectly reject this valid case and fail this test. */
10541+
{
10542+
WOLFSSL_CTX* ctx2 = NULL;
10543+
WOLFSSL* ssl2 = NULL;
10544+
SessionTicket* ticket2 = NULL;
10545+
byte* buf = NULL;
10546+
word32 baseLen = 0;
10547+
word32 baseInternal = 0;
10548+
word32 tickSz = 0;
10549+
/* TLSX_GetRequestSize rejects when internal sum > 0xFFFD. */
10550+
const word32 target = (word32)WOLFSSL_MAX_16BIT - (word32)OPAQUE16_LEN;
10551+
/* Session ticket extension contributes: type (2) + len (2) + size. */
10552+
const word32 extHdr = (word32)HELLO_EXT_TYPE_SZ
10553+
+ (word32)OPAQUE16_LEN;
10554+
int ret;
10555+
10556+
ExpectNotNull(ctx2 = wolfSSL_CTX_new(wolfSSLv23_client_method()));
10557+
ExpectNotNull(ssl2 = wolfSSL_new(ctx2));
10558+
10559+
/* Measure baseline length with no session ticket extension. The
10560+
* returned value already includes the 2-byte block-length prefix
10561+
* when nonzero; strip it to get the raw internal sum. */
10562+
if (EXPECT_SUCCESS()) {
10563+
baseLen = 0;
10564+
ret = TLSX_GetRequestSize(ssl2, client_hello, &baseLen);
10565+
ExpectIntEQ(ret, 0);
10566+
baseInternal = (baseLen > 0)
10567+
? baseLen - (word32)OPAQUE16_LEN : 0;
10568+
}
10569+
10570+
/* Target: baseInternal + extHdr + tickSz == 0xFFFD. */
10571+
if (EXPECT_SUCCESS() && baseInternal + extHdr < target) {
10572+
tickSz = target - baseInternal - extHdr;
10573+
}
10574+
10575+
if (EXPECT_SUCCESS() && tickSz > 0 && tickSz <= WOLFSSL_MAX_16BIT) {
10576+
buf = (byte*)XMALLOC(tickSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
10577+
ExpectNotNull(buf);
10578+
if (buf != NULL)
10579+
XMEMSET(buf, 0x5A, tickSz);
10580+
}
10581+
10582+
if (EXPECT_SUCCESS() && buf != NULL) {
10583+
ticket2 = TLSX_SessionTicket_Create(0, buf, (word16)tickSz,
10584+
ssl2->heap);
10585+
ExpectNotNull(ticket2);
10586+
}
10587+
if (EXPECT_SUCCESS() && ticket2 != NULL) {
10588+
ExpectIntEQ(TLSX_UseSessionTicket(&ssl2->extensions, ticket2,
10589+
ssl2->heap), WOLFSSL_SUCCESS);
10590+
ticket2 = NULL;
10591+
}
10592+
10593+
/* Exact boundary: internal sum == 0xFFFD must succeed, and the
10594+
* final returned length is 0xFFFD + OPAQUE16_LEN == 0xFFFF. */
10595+
if (EXPECT_SUCCESS()) {
10596+
word32 lenBoundary = 0;
10597+
ret = TLSX_GetRequestSize(ssl2, client_hello, &lenBoundary);
10598+
ExpectIntEQ(ret, 0);
10599+
ExpectIntEQ(lenBoundary, (word32)WOLFSSL_MAX_16BIT);
10600+
}
10601+
10602+
if (ticket2 != NULL)
10603+
TLSX_SessionTicket_Free(ticket2, ssl2->heap);
10604+
wolfSSL_free(ssl2);
10605+
wolfSSL_CTX_free(ctx2);
10606+
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
10607+
}
1053110608
#endif
1053210609
return EXPECT_RESULT();
1053310610
}

0 commit comments

Comments
 (0)