@@ -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+
91759286static 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