@@ -748,6 +748,17 @@ void FreeWriteDup(WOLFSSL* ssl)
748748
749749 if (doFree) {
750750 WOLFSSL_MSG("Doing WriteDup full free, count to zero");
751+ #ifdef WOLFSSL_DTLS13
752+ /* Free any pending ACK list that was never consumed by the write side */
753+ {
754+ struct Dtls13RecordNumber* rn = ssl->dupWrite->sendAckList;
755+ while (rn != NULL) {
756+ struct Dtls13RecordNumber* next = rn->next;
757+ XFREE(rn, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
758+ rn = next;
759+ }
760+ }
761+ #endif
751762 wc_FreeMutex(&ssl->dupWrite->dupMutex);
752763 XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP);
753764 }
@@ -807,6 +818,31 @@ static int DupSSL(WOLFSSL* dup, WOLFSSL* ssl)
807818 /* dup side now owns encrypt/write ciphers */
808819 XMEMSET(&ssl->encrypt, 0, sizeof(Ciphers));
809820
821+ #ifdef WOLFSSL_DTLS13
822+ if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
823+ /* Copy epoch array (contains only value types — safe to memcpy). */
824+ XMEMCPY(dup->dtls13Epochs, ssl->dtls13Epochs, sizeof(ssl->dtls13Epochs));
825+
826+ /* Re-point dtls13EncryptEpoch into dup's own epoch array. */
827+ if (ssl->dtls13EncryptEpoch != NULL) {
828+ dup->dtls13EncryptEpoch =
829+ &dup->dtls13Epochs[ssl->dtls13EncryptEpoch - ssl->dtls13Epochs];
830+ }
831+ /* dtls13DecryptEpoch is not needed by the write-only side; leave NULL. */
832+
833+ /* Copy current write epoch number (checked in Dtls13SendMessage). */
834+ dup->dtls13Epoch = ssl->dtls13Epoch;
835+
836+ /* Transfer record-number encryption cipher ownership to dup.
837+ * FreeCiphers() frees the aes/chacha pointer, so sharing it would
838+ * cause a double-free; use the same ownership-transfer pattern as
839+ * for ssl->encrypt above. */
840+ XMEMCPY(&dup->dtlsRecordNumberEncrypt, &ssl->dtlsRecordNumberEncrypt,
841+ sizeof(RecordNumberCiphers));
842+ XMEMSET(&ssl->dtlsRecordNumberEncrypt, 0, sizeof(RecordNumberCiphers));
843+ }
844+ #endif /* WOLFSSL_DTLS13 */
845+
810846 dup->IOCB_WriteCtx = ssl->IOCB_WriteCtx;
811847 dup->CBIOSend = ssl->CBIOSend;
812848#ifdef OPENSSL_EXTRA
@@ -2455,6 +2491,54 @@ static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz)
24552491 ssl->error = dupErr;
24562492 return WOLFSSL_FATAL_ERROR;
24572493 }
2494+
2495+ #ifdef WOLFSSL_DTLS13
2496+ /* DTLS 1.3: the read side cannot encrypt, so it delegates ACK sending
2497+ * to the write side. Check if an ACK was requested and send it. */
2498+ if (ssl->dupWrite && ssl->dupSide == WRITE_DUP_SIDE &&
2499+ ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
2500+ byte ackNeeded = 0;
2501+
2502+ if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) {
2503+ ackNeeded = ssl->dupWrite->sendAcks;
2504+ if (ackNeeded) {
2505+ /* Insert each record number so the
2506+ * ACK message is properly ordered. */
2507+ struct Dtls13RecordNumber* rn;
2508+ for (rn = ssl->dupWrite->sendAckList; rn != NULL;
2509+ rn = rn->next) {
2510+ ret = Dtls13RtxAddAck(ssl, rn->epoch, rn->seq);
2511+ if (ret != 0)
2512+ break;
2513+ }
2514+ /* Clear only on success so no ACKs get dropped */
2515+ if (ret == 0) {
2516+ rn = ssl->dupWrite->sendAckList;
2517+ ssl->dupWrite->sendAckList = NULL;
2518+ ssl->dupWrite->sendAcks = 0;
2519+ while (rn != NULL) {
2520+ struct Dtls13RecordNumber* next = rn->next;
2521+ XFREE(rn, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
2522+ rn = next;
2523+ }
2524+ }
2525+ }
2526+ wc_UnLockMutex(&ssl->dupWrite->dupMutex);
2527+ if (ret != 0) {
2528+ ssl->error = ret;
2529+ return WOLFSSL_FATAL_ERROR;
2530+ }
2531+ }
2532+
2533+ if (ackNeeded) {
2534+ ret = SendDtls13Ack(ssl);
2535+ if (ret != 0) {
2536+ ssl->error = ret;
2537+ return WOLFSSL_FATAL_ERROR;
2538+ }
2539+ }
2540+ }
2541+ #endif /* WOLFSSL_DTLS13 */
24582542 }
24592543#endif
24602544
0 commit comments