Skip to content

Commit 599eec6

Browse files
committed
Fix ImportKeyState wordAdj always-zero bug in DTLS session import
In ImportKeyState(), wordAdj was always zero because it was computed after clamping wordCount, and the subtraction direction was reversed. This caused misaligned parsing of all subsequent fields when importing state from a peer compiled with a larger WOLFSSL_DTLS_WINDOW_WORDS. Fix both window and prevWindow blocks to compute the adjustment before clamping, with the correct subtraction direction. Add test that imports a state buffer with wordCount > WOLFSSL_DTLS_WINDOW_WORDS to verify the fix.
1 parent 10325b4 commit 599eec6

2 files changed

Lines changed: 114 additions & 2 deletions

File tree

src/internal.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,8 +1123,8 @@ static int ImportKeyState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver,
11231123
idx += OPAQUE16_LEN;
11241124

11251125
if (wordCount > WOLFSSL_DTLS_WINDOW_WORDS) {
1126+
wordAdj = (wordCount - WOLFSSL_DTLS_WINDOW_WORDS) * sizeof(word32);
11261127
wordCount = WOLFSSL_DTLS_WINDOW_WORDS;
1127-
wordAdj = (WOLFSSL_DTLS_WINDOW_WORDS - wordCount) * sizeof(word32);
11281128
}
11291129

11301130
XMEMSET(keys->peerSeq[0].window, 0xFF, DTLS_SEQ_SZ);
@@ -1139,8 +1139,8 @@ static int ImportKeyState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver,
11391139
idx += OPAQUE16_LEN;
11401140

11411141
if (wordCount > WOLFSSL_DTLS_WINDOW_WORDS) {
1142+
wordAdj = (wordCount - WOLFSSL_DTLS_WINDOW_WORDS) * sizeof(word32);
11421143
wordCount = WOLFSSL_DTLS_WINDOW_WORDS;
1143-
wordAdj = (WOLFSSL_DTLS_WINDOW_WORDS - wordCount) * sizeof(word32);
11441144
}
11451145

11461146
XMEMSET(keys->peerSeq[0].prevWindow, 0xFF, DTLS_SEQ_SZ);

tests/api.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9172,6 +9172,117 @@ static int test_wolfSSL_dtls_export_peers(void)
91729172
return EXPECT_RESULT();
91739173
}
91749174

9175+
/* Test that ImportKeyState correctly skips extra window words when importing
9176+
* state from a peer compiled with a larger WOLFSSL_DTLS_WINDOW_WORDS. */
9177+
static int test_wolfSSL_dtls_import_state_extra_window_words(void)
9178+
{
9179+
EXPECT_DECLS;
9180+
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT)
9181+
WOLFSSL_CTX* ctx = NULL;
9182+
WOLFSSL* ssl = NULL;
9183+
unsigned int stateSz = 0;
9184+
byte* state = NULL;
9185+
byte* modified = NULL;
9186+
unsigned int modifiedSz;
9187+
word16 origKeyLen;
9188+
word16 origTotalLen;
9189+
/* Offset from start of key state data to the first wordCount field.
9190+
* Layout: 4 sequence numbers (16 bytes) + DTLS-specific fields (42 bytes) +
9191+
* encryptSz(4) + padSz(4) + encryptionOn(1) + decryptedCur(1) = 68 */
9192+
const int keyStateWindowOffset = 68;
9193+
/* Buffer header: 2 proto + 2 total_len + 2 key_len = 6 */
9194+
const int headerSz = 6;
9195+
int idx, modIdx;
9196+
int extraPerWindow = 2 * (int)sizeof(word32); /* 8 bytes extra per window */
9197+
int totalExtra = extraPerWindow * 2; /* 16 bytes extra total */
9198+
9199+
/* Create DTLS context and SSL object */
9200+
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method()));
9201+
ExpectNotNull(ssl = wolfSSL_new(ctx));
9202+
9203+
/* Get required buffer size and export state-only */
9204+
ExpectIntEQ(wolfSSL_dtls_export_state_only(ssl, NULL, &stateSz), 0);
9205+
ExpectIntGT((int)stateSz, 0);
9206+
state = (byte*)XMALLOC(stateSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
9207+
ExpectNotNull(state);
9208+
ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, state, &stateSz), 0);
9209+
9210+
/* Build a modified buffer that simulates a peer with
9211+
* WOLFSSL_DTLS_WINDOW_WORDS = WOLFSSL_DTLS_WINDOW_WORDS + 2.
9212+
* Each window section gets 2 extra word32 values (8 bytes).
9213+
* Two windows => 16 extra bytes total. */
9214+
modifiedSz = stateSz + totalExtra;
9215+
modified = (byte*)XMALLOC(modifiedSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
9216+
ExpectNotNull(modified);
9217+
9218+
if (EXPECT_SUCCESS()) {
9219+
int windowWords = WOLFSSL_DTLS_WINDOW_WORDS;
9220+
int windowDataSz = windowWords * (int)sizeof(word32);
9221+
9222+
XMEMSET(modified, 0, modifiedSz);
9223+
9224+
/* Copy protocol/version bytes (first 2 bytes) */
9225+
XMEMCPY(modified, state, 2);
9226+
9227+
/* Read original total length and key state length */
9228+
ato16(state + 2, &origTotalLen);
9229+
ato16(state + 4, &origKeyLen);
9230+
9231+
/* Write updated total length and key state length */
9232+
c16toa((word16)(origTotalLen + totalExtra), modified + 2);
9233+
c16toa((word16)(origKeyLen + totalExtra), modified + 4);
9234+
9235+
/* Copy key state data up to first window section */
9236+
idx = headerSz;
9237+
modIdx = headerSz;
9238+
XMEMCPY(modified + modIdx, state + idx, keyStateWindowOffset);
9239+
idx += keyStateWindowOffset;
9240+
modIdx += keyStateWindowOffset;
9241+
9242+
/* First window: write increased wordCount */
9243+
c16toa((word16)(windowWords + 2), modified + modIdx);
9244+
idx += OPAQUE16_LEN;
9245+
modIdx += OPAQUE16_LEN;
9246+
9247+
/* Copy original window data */
9248+
XMEMCPY(modified + modIdx, state + idx, windowDataSz);
9249+
idx += windowDataSz;
9250+
modIdx += windowDataSz;
9251+
9252+
/* Insert 2 extra word32 padding values */
9253+
XMEMSET(modified + modIdx, 0, extraPerWindow);
9254+
modIdx += extraPerWindow;
9255+
9256+
/* Second window (prevWindow): same transformation */
9257+
c16toa((word16)(windowWords + 2), modified + modIdx);
9258+
idx += OPAQUE16_LEN;
9259+
modIdx += OPAQUE16_LEN;
9260+
9261+
XMEMCPY(modified + modIdx, state + idx, windowDataSz);
9262+
idx += windowDataSz;
9263+
modIdx += windowDataSz;
9264+
9265+
XMEMSET(modified + modIdx, 0, extraPerWindow);
9266+
modIdx += extraPerWindow;
9267+
9268+
/* Copy remainder of key state (after both windows) */
9269+
XMEMCPY(modified + modIdx, state + idx, stateSz - idx);
9270+
}
9271+
9272+
/* Import the modified state - should succeed with the fix */
9273+
wolfSSL_free(ssl);
9274+
ssl = NULL;
9275+
ExpectNotNull(ssl = wolfSSL_new(ctx));
9276+
ExpectIntGT(wolfSSL_dtls_import(ssl, modified, modifiedSz), 0);
9277+
9278+
XFREE(state, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
9279+
XFREE(modified, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
9280+
wolfSSL_free(ssl);
9281+
wolfSSL_CTX_free(ctx);
9282+
#endif
9283+
return EXPECT_RESULT();
9284+
}
9285+
91759286
static int test_wolfSSL_UseTrustedCA(void)
91769287
{
91779288
EXPECT_DECLS;
@@ -32913,6 +33024,7 @@ TEST_CASE testCases[] = {
3291333024
TEST_DECL(test_wolfSSL_tls_export),
3291433025
#endif
3291533026
TEST_DECL(test_wolfSSL_dtls_export_peers),
33027+
TEST_DECL(test_wolfSSL_dtls_import_state_extra_window_words),
3291633028
TEST_DECL(test_wolfSSL_SetMinVersion),
3291733029
TEST_DECL(test_wolfSSL_CTX_SetMinVersion),
3291833030

0 commit comments

Comments
 (0)