DTLS 1.3 write dup support

- Copy TLS 1.3 traffic secrets and DTLS 1.3 epoch/cipher state to the
  write-dup side in DupSSL so key updates can be performed.
- Delegate KeyUpdate responses from the read side to the write side via
  the shared WriteDup struct, for both peer-initiated and local key
  updates.
- Delegate DTLS 1.3 ACK sending from the read side to the write side.
- Track DTLS 1.3 KeyUpdate ACKs: write side records the in-flight
  KeyUpdate epoch/seq, read side sets keyUpdateAcked when the matching
  ACK arrives.
- Delegate post-handshake certificate authentication (CertificateRequest
  processing) from the read side to the write side, transferring
  transcript hashes, cert context, and signature parameters.
- Reset prevSent/plainSz to prevent stale values from SendData to think
  that data was already sent.
- Refactor FreeHandshakeHashes into Free_HS_Hashes for reuse.
- Move DTLS 1.3 epoch initialization earlier in InitSSL so the
  write-dup early-return path has valid epoch state.
- Add tests for write dup with all protocol versions, key update,
  post-handshake auth, and WANT_WRITE recovery.
- Add --enable-all --enable-writedup to CI os-check matrix.
This commit is contained in:
Juliusz Sosinowicz
2026-03-13 19:04:42 +01:00
parent 86db2d4a77
commit 9dbd35dc7c
7 changed files with 723 additions and 94 deletions
+1
View File
@@ -99,6 +99,7 @@ jobs:
'--enable-certreq --enable-certext --enable-certgen --disable-secure-renegotiation-info CPPFLAGS="-DNO_TLS"',
'--enable-ocsp --enable-ocsp-responder --enable-ocspstapling CPPFLAGS="-DWOLFSSL_NONBLOCK_OCSP" --enable-maxfragment',
'--enable-all CPPFLAGS=-DWOLFSSL_HASH_KEEP',
'--enable-all --enable-writedup',
]
name: make check
if: github.repository_owner == 'wolfssl'
+53 -5
View File
@@ -2034,8 +2034,21 @@ int Dtls13HandshakeSend(WOLFSSL* ssl, byte* message, word16 outputSize,
maxFrag = wolfssl_local_GetMaxPlaintextSize(ssl);
maxLen = length;
if (handshakeType == key_update)
if (handshakeType == key_update) {
ssl->dtls13WaitKeyUpdateAck = 1;
#ifdef HAVE_WRITE_DUP
/* Notify the read side so it can watch for the ACK on our behalf. */
if (ssl->dupWrite != NULL && ssl->dupSide == WRITE_DUP_SIDE) {
if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) {
ssl->dupWrite->keyUpdateEpoch = ssl->dtls13Epoch;
ssl->dupWrite->keyUpdateSeq =
ssl->dtls13EncryptEpoch->nextSeqNumber;
ssl->dupWrite->keyUpdateWaiting = 1;
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
}
}
#endif /* HAVE_WRITE_DUP */
}
if (maxLen < maxFrag) {
ret = Dtls13SendOneFragmentRtx(ssl, handshakeType, outputSize, message,
@@ -2656,7 +2669,7 @@ static void Dtls13PrintRtxRecord(Dtls13RtxRecord* r)
}
#endif /* WOLFSSL_DEBUG_TLS */
static void Dtls13RtxRemoveRecord(WOLFSSL* ssl, w64wrapper epoch,
void Dtls13RtxRemoveRecord(WOLFSSL* ssl, w64wrapper epoch,
w64wrapper seq)
{
Dtls13RtxRecord *r, **prevNext;
@@ -2706,9 +2719,28 @@ int Dtls13DoScheduledWork(WOLFSSL* ssl)
ret = wc_UnLockMutex(&ssl->dtls13Rtx.mutex);
#endif
if (sendAcks) {
ret = SendDtls13Ack(ssl);
if (ret != 0)
return ret;
#ifdef HAVE_WRITE_DUP
/* The read side cannot encrypt. Transfer the seenRecords list to the
* shared WriteDup struct so the write side sends the ACK instead. */
if (ssl->dupWrite != NULL && ssl->dupSide == READ_DUP_SIDE) {
if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) {
struct Dtls13RecordNumber** tail =
(struct Dtls13RecordNumber**)&ssl->dupWrite->sendAckList;
while (*tail != NULL)
tail = &(*tail)->next;
*tail = ssl->dtls13Rtx.seenRecords;
ssl->dtls13Rtx.seenRecords = NULL;
ssl->dupWrite->sendAcks = 1;
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
}
}
else
#endif /* HAVE_WRITE_DUP */
{
ret = SendDtls13Ack(ssl);
if (ret != 0)
return ret;
}
}
if (ssl->dtls13Rtx.retransmit) {
@@ -2824,6 +2856,22 @@ int DoDtls13Ack(WOLFSSL* ssl, const byte* input, word32 inputSize,
ato64(ackMessage + i + OPAQUE64_LEN, &seq);
WOLFSSL_MSG_EX("epoch %d seq %d", epoch, seq);
Dtls13RtxRemoveRecord(ssl, epoch, seq);
#ifdef HAVE_WRITE_DUP
/* Read side: check if this ACK covers the write side's pending KeyUpdate.
* Match on both epoch AND seq to avoid false positives from data records
* in the same epoch (sent while dtls13WaitKeyUpdateAck == 1). */
if (ssl->dupWrite != NULL && ssl->dupSide == READ_DUP_SIDE) {
if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) {
if (ssl->dupWrite->keyUpdateWaiting &&
w64Equal(epoch, ssl->dupWrite->keyUpdateEpoch) &&
w64Equal(seq, ssl->dupWrite->keyUpdateSeq)) {
ssl->dupWrite->keyUpdateAcked = 1;
ssl->dupWrite->keyUpdateWaiting = 0;
}
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
}
}
#endif /* HAVE_WRITE_DUP */
}
/* last client flight was completely acknowledged by the server. Handshake
+46 -41
View File
@@ -7462,43 +7462,49 @@ int InitHandshakeHashes(WOLFSSL* ssl)
return ret;
}
void FreeHandshakeHashes(WOLFSSL* ssl)
void Free_HS_Hashes(HS_Hashes* hsHashes, void* heap)
{
if (ssl->hsHashes) {
if (hsHashes) {
#if !defined(NO_MD5) && !defined(NO_OLD_TLS)
wc_Md5Free(&ssl->hsHashes->hashMd5);
wc_Md5Free(&hsHashes->hashMd5);
#endif
#if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \
defined(WOLFSSL_ALLOW_TLS_SHA1))
wc_ShaFree(&ssl->hsHashes->hashSha);
wc_ShaFree(&hsHashes->hashSha);
#endif
#ifndef NO_SHA256
wc_Sha256Free(&ssl->hsHashes->hashSha256);
wc_Sha256Free(&hsHashes->hashSha256);
#endif
#ifdef WOLFSSL_SHA384
wc_Sha384Free(&ssl->hsHashes->hashSha384);
wc_Sha384Free(&hsHashes->hashSha384);
#endif
#ifdef WOLFSSL_SHA512
wc_Sha512Free(&ssl->hsHashes->hashSha512);
wc_Sha512Free(&hsHashes->hashSha512);
#endif
#ifdef WOLFSSL_SM3
wc_Sm3Free(&ssl->hsHashes->hashSm3);
wc_Sm3Free(&hsHashes->hashSm3);
#endif
#if (defined(HAVE_ED25519) || defined(HAVE_ED448) || \
(defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3))) && \
!defined(WOLFSSL_NO_CLIENT_AUTH)
if (ssl->hsHashes->messages != NULL) {
ForceZero(ssl->hsHashes->messages, (word32)ssl->hsHashes->length);
XFREE(ssl->hsHashes->messages, ssl->heap, DYNAMIC_TYPE_HASHES);
ssl->hsHashes->messages = NULL;
if (hsHashes->messages != NULL) {
ForceZero(hsHashes->messages, (word32)hsHashes->length);
XFREE(hsHashes->messages, heap, DYNAMIC_TYPE_HASHES);
hsHashes->messages = NULL;
}
#endif
XFREE(ssl->hsHashes, ssl->heap, DYNAMIC_TYPE_HASHES);
ssl->hsHashes = NULL;
XFREE(hsHashes, heap, DYNAMIC_TYPE_HASHES);
hsHashes = NULL;
}
}
void FreeHandshakeHashes(WOLFSSL* ssl)
{
Free_HS_Hashes(ssl->hsHashes, ssl->heap);
ssl->hsHashes = NULL;
}
/* copy the hashes from source to a newly made destination return status */
int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source,
HS_Hashes** destination)
@@ -7509,15 +7515,8 @@ int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source,
return BAD_FUNC_ARG;
/* If *destination is already allocated, its constituent hashes need to be
* freed, else they would leak. To keep things simple, we reuse
* FreeHandshakeHashes(), which deallocates *destination.
*/
if (*destination != NULL) {
HS_Hashes* tmp = ssl->hsHashes;
ssl->hsHashes = *destination;
FreeHandshakeHashes(ssl);
ssl->hsHashes = tmp;
}
* freed, else they would leak. */
Free_HS_Hashes(*destination, ssl->heap);
/* allocate handshake hashes */
*destination = (HS_Hashes*)XMALLOC(sizeof(HS_Hashes), ssl->heap,
@@ -8065,6 +8064,24 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
}
ssl->options.dtls = ssl->version.major == DTLS_MAJOR;
#ifdef WOLFSSL_DTLS13
/* setup 0 (un-protected) epoch */
ssl->dtls13Epochs[0].isValid = 1;
ssl->dtls13Epochs[0].side = ENCRYPT_AND_DECRYPT_SIDE;
ssl->dtls13EncryptEpoch = &ssl->dtls13Epochs[0];
ssl->dtls13DecryptEpoch = &ssl->dtls13Epochs[0];
ssl->options.dtls13SendMoreAcks = WOLFSSL_DTLS13_SEND_MOREACK_DEFAULT;
ssl->dtls13Rtx.rtxRecordTailPtr = &ssl->dtls13Rtx.rtxRecords;
#ifdef WOLFSSL_RW_THREADED
ret = wc_InitMutex(&ssl->dtls13Rtx.mutex);
if (ret < 0) {
return ret;
}
#endif
#endif /* WOLFSSL_DTLS13 */
#ifdef HAVE_WRITE_DUP
if (writeDup) {
/* all done */
@@ -8176,24 +8193,6 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
}
#endif /* HAVE_SECURE_RENEGOTIATION */
#ifdef WOLFSSL_DTLS13
/* setup 0 (un-protected) epoch */
ssl->dtls13Epochs[0].isValid = 1;
ssl->dtls13Epochs[0].side = ENCRYPT_AND_DECRYPT_SIDE;
ssl->dtls13EncryptEpoch = &ssl->dtls13Epochs[0];
ssl->dtls13DecryptEpoch = &ssl->dtls13Epochs[0];
ssl->options.dtls13SendMoreAcks = WOLFSSL_DTLS13_SEND_MOREACK_DEFAULT;
ssl->dtls13Rtx.rtxRecordTailPtr = &ssl->dtls13Rtx.rtxRecords;
#ifdef WOLFSSL_RW_THREADED
ret = wc_InitMutex(&ssl->dtls13Rtx.mutex);
if (ret < 0) {
return ret;
}
#endif
#endif /* WOLFSSL_DTLS13 */
#ifdef WOLFSSL_QUIC
if (ctx->quic.method) {
ret = wolfSSL_set_quic_method(ssl, ctx->quic.method);
@@ -26094,6 +26093,10 @@ static int CheckTLS13AEADSendLimit(WOLFSSL* ssl)
}
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
if (ssl->dtls13EncryptEpoch == NULL) {
WOLFSSL_MSG("DTLS 1.3 encrypt epoch not set");
return BAD_STATE_E;
}
seq = ssl->dtls13EncryptEpoch->nextSeqNumber;
}
else
@@ -26324,6 +26327,8 @@ int SendData(WOLFSSL* ssl, const void* data, size_t sz)
else {
/* advance sent to previous sent + plain size just sent */
sent = ssl->buffers.prevSent + ssl->buffers.plainSz;
ssl->buffers.prevSent = 0;
ssl->buffers.plainSz = 0;
WOLFSSL_MSG("sent write buffered data");
if (sent > (word32)sz) {
+183 -19
View File
@@ -842,9 +842,28 @@ void FreeWriteDup(WOLFSSL* ssl)
}
if (doFree) {
WOLFSSL_MSG("Doing WriteDup full free, count to zero");
#ifdef WOLFSSL_DTLS13
struct Dtls13RecordNumber* rn = ssl->dupWrite->sendAckList;
while (rn != NULL) {
struct Dtls13RecordNumber* next = rn->next;
XFREE(rn, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
rn = next;
}
#endif
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
Free_HS_Hashes(ssl->dupWrite->postHandshakeHashState, ssl->heap);
{
CertReqCtx* ctx = ssl->dupWrite->postHandshakeCertReqCtx;
while (ctx != NULL) {
CertReqCtx* nxt = ctx->next;
XFREE(ctx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
ctx = nxt;
}
}
#endif /* WOLFSSL_TLS13 && WOLFSSL_POST_HANDSHAKE_AUTH */
wc_FreeMutex(&ssl->dupWrite->dupMutex);
XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP);
WOLFSSL_MSG("Did WriteDup full free, count to zero");
}
}
@@ -902,6 +921,40 @@ static int DupSSL(WOLFSSL* dup, WOLFSSL* ssl)
/* dup side now owns encrypt/write ciphers */
XMEMSET(&ssl->encrypt, 0, sizeof(Ciphers));
#ifdef WOLFSSL_TLS13
if (IsAtLeastTLSv1_3(ssl->version)) {
/* Copy TLS 1.3 application traffic secrets so the write side can
* derive updated keys when wolfSSL_update_keys() is called. */
XMEMCPY(dup->clientSecret, ssl->clientSecret, SECRET_LEN);
XMEMCPY(dup->serverSecret, ssl->serverSecret, SECRET_LEN);
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
/* Copy epoch array (contains only value types -- safe to memcpy). */
XMEMCPY(dup->dtls13Epochs, ssl->dtls13Epochs,
sizeof(ssl->dtls13Epochs));
/* Re-point dtls13EncryptEpoch into dup's own epoch array. */
if (ssl->dtls13EncryptEpoch != NULL) {
dup->dtls13EncryptEpoch =
&dup->dtls13Epochs[ssl->dtls13EncryptEpoch -
ssl->dtls13Epochs];
}
/* Copy current write epoch number. */
dup->dtls13Epoch = ssl->dtls13Epoch;
/* Transfer record-number encryption cipher ownership to dup. */
XMEMCPY(&dup->dtlsRecordNumberEncrypt,
&ssl->dtlsRecordNumberEncrypt, sizeof(RecordNumberCiphers));
XMEMSET(&ssl->dtlsRecordNumberEncrypt,
0, sizeof(RecordNumberCiphers));
}
#endif /* WOLFSSL_DTLS13 */
}
#endif /* WOLFSSL_TLS13 */
dup->IOCB_WriteCtx = ssl->IOCB_WriteCtx;
dup->CBIOSend = ssl->CBIOSend;
#ifdef OPENSSL_EXTRA
@@ -2509,7 +2562,7 @@ int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl)
static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz)
{
int ret;
int ret = 0;
WOLFSSL_ENTER("wolfSSL_write");
@@ -2524,32 +2577,143 @@ static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz)
#endif
#ifdef HAVE_WRITE_DUP
{ /* local variable scope */
if (ssl->dupSide == READ_DUP_SIDE) {
WOLFSSL_MSG("Read dup side cannot write");
return WRITE_DUP_WRITE_E;
}
/* Only enter special dupWrite logic when error is cleared. This will help
* with handling async data and other edge case errors. */
if (ssl->dupWrite != NULL && ssl->error == 0) {
int dupErr = 0; /* local copy */
ret = 0;
if (ssl->dupWrite && ssl->dupSide == READ_DUP_SIDE) {
WOLFSSL_MSG("Read dup side cannot write");
return WRITE_DUP_WRITE_E;
}
if (ssl->dupWrite) {
if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) {
return BAD_MUTEX_E;
/* Lock ssl->dupWrite to gather what needs to be done. */
if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0)
return BAD_MUTEX_E;
dupErr = ssl->dupWrite->dupErr;
#ifdef WOLFSSL_TLS13
if (IsAtLeastTLSv1_3(ssl->version)) {
/* TLS 1.3: if the read side received a KeyUpdate(update_requested)
* it cannot respond; send the response from here. */
ssl->keys.keyUpdateRespond |= ssl->dupWrite->keyUpdateRespond;
ssl->dupWrite->keyUpdateRespond = 0;
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
ssl->postHandshakeAuthPending |=
ssl->dupWrite->postHandshakeAuthPending;
ssl->dupWrite->postHandshakeAuthPending = 0;
if (ssl->postHandshakeAuthPending) {
/* Take ownership of the delegated auth state. */
CertReqCtx** tail = &ssl->dupWrite->postHandshakeCertReqCtx;
while (*tail != NULL)
tail = &(*tail)->next;
*tail = ssl->certReqCtx;
ssl->certReqCtx = ssl->dupWrite->postHandshakeCertReqCtx;
ssl->dupWrite->postHandshakeCertReqCtx = NULL;
FreeHandshakeHashes(ssl);
ssl->hsHashes = ssl->dupWrite->postHandshakeHashState;
ssl->dupWrite->postHandshakeHashState = NULL;
ssl->options.sendVerify = ssl->dupWrite->postHandshakeSendVerify;
ssl->options.sigAlgo = ssl->dupWrite->postHandshakeSigAlgo;
ssl->options.hashAlgo = ssl->dupWrite->postHandshakeHashAlgo;
}
dupErr = ssl->dupWrite->dupErr;
ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex);
}
#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
/* Schedule key update to be sent. */
if (ssl->keys.keyUpdateRespond)
ssl->dtls13DoKeyUpdate = 1;
if (ret != 0) {
ssl->error = ret; /* high priority fatal error */
return WOLFSSL_FATAL_ERROR;
/* Copy over ACKs */
ssl->dtls13Rtx.sendAcks |= ssl->dupWrite->sendAcks;
if (ssl->dupWrite->sendAcks) {
/* Insert each record number so the
* ACK message is properly ordered. */
struct Dtls13RecordNumber* rn;
for (rn = ssl->dupWrite->sendAckList; rn != NULL;
rn = rn->next) {
ret = Dtls13RtxAddAck(ssl, rn->epoch, rn->seq);
if (ret != 0)
break;
}
/* Clear only on success so no ACKs get dropped */
if (ret == 0) {
rn = ssl->dupWrite->sendAckList;
ssl->dupWrite->sendAckList = NULL;
ssl->dupWrite->sendAcks = 0;
while (rn != NULL) {
struct Dtls13RecordNumber* next = rn->next;
XFREE(rn, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
rn = next;
}
}
}
/* Remove KeyUpdate record from RTX list. */
if (ssl->dupWrite->keyUpdateAcked) {
Dtls13RtxRemoveRecord(ssl, ssl->dupWrite->keyUpdateEpoch,
ssl->dupWrite->keyUpdateSeq);
}
/* Store if KeyUpdate was ACKed. */
ssl->dtls13KeyUpdateAcked |= ssl->dupWrite->keyUpdateAcked;
ssl->dupWrite->keyUpdateAcked = 0;
}
#endif /* WOLFSSL_DTLS13 */
}
#endif /* WOLFSSL_TLS13 */
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
if (dupErr != 0) {
WOLFSSL_MSG("Write dup error from other side");
ssl->error = dupErr;
return WOLFSSL_FATAL_ERROR;
}
if (ret != 0) {
ssl->error = ret;
return WOLFSSL_FATAL_ERROR;
}
#ifdef WOLFSSL_TLS13
if (IsAtLeastTLSv1_3(ssl->version)) {
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
/* Read side received a CertificateRequest but couldn't write;
* send Certificate+CertificateVerify+Finished from the write side. */
if (ssl->postHandshakeAuthPending) {
/* reset handshake states */
ssl->postHandshakeAuthPending = 0;
ssl->options.clientState = CLIENT_HELLO_COMPLETE;
ssl->options.connectState = FIRST_REPLY_DONE;
ssl->options.handShakeState = CLIENT_HELLO_COMPLETE;
ssl->options.processReply = 0; /* doProcessInit */
if (wolfSSL_connect_TLSv13(ssl) != WOLFSSL_SUCCESS) {
if (ssl->error != WC_NO_ERR_TRACE(WANT_WRITE) &&
ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E)) {
WOLFSSL_MSG("Post-handshake auth send failed");
ssl->error = POST_HAND_AUTH_ERROR;
}
return WOLFSSL_FATAL_ERROR;
}
}
#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
if (ssl->dtls13KeyUpdateAcked)
ret = DoDtls13KeyUpdateAck(ssl);
ssl->dtls13KeyUpdateAcked = 0;
if (ret == 0)
ret = Dtls13DoScheduledWork(ssl);
}
else
#endif /* WOLFSSL_DTLS13 */
if (ssl->keys.keyUpdateRespond) /* cleared in SendTls13KeyUpdate */
ret = Tls13UpdateKeys(ssl);
if (ret != 0) {
ssl->error = ret;
return WOLFSSL_FATAL_ERROR;
}
/* WANT_WRITE is safe to clear. Data is buffered in output buffer
* or in DTLS RTX queue */
ret = 0;
}
#endif /* WOLFSSL_TLS13 */
}
#endif
+65 -17
View File
@@ -11819,6 +11819,18 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
}
#endif /* WOLFSSL_DTLS13 */
#if defined(HAVE_WRITE_DUP) && defined(WOLFSSL_TLS13)
/* Read side cannot write; delegate the response to the write side. */
if (ssl->dupWrite != NULL && ssl->dupSide == READ_DUP_SIDE) {
if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) {
ssl->dupWrite->keyUpdateRespond = 1;
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
}
ssl->keys.keyUpdateRespond = 0;
return 0;
}
#endif /* HAVE_WRITE_DUP && WOLFSSL_TLS13 */
#ifndef WOLFSSL_RW_THREADED
return SendTls13KeyUpdate(ssl);
#else
@@ -13286,25 +13298,61 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
if (type == certificate_request &&
ssl->options.handShakeState == HANDSHAKE_DONE) {
/* reset handshake states */
ssl->options.clientState = CLIENT_HELLO_COMPLETE;
ssl->options.connectState = FIRST_REPLY_DONE;
ssl->options.handShakeState = CLIENT_HELLO_COMPLETE;
ssl->options.processReply = 0; /* doProcessInit */
#if defined(HAVE_WRITE_DUP)
/* Read side cannot write; delegate the cert response to the
* write side by saving auth state in the shared WriteDup. */
if (ssl->dupSide == READ_DUP_SIDE) {
if (ssl->dupWrite == NULL)
return BAD_STATE_E;
if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0)
return BAD_MUTEX_E;
/* Copy the current transcript so the write side can
* compute the correct Finished MAC. */
ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes,
&ssl->dupWrite->postHandshakeHashState);
if (ret == 0) {
/* Copy the cert request context. */
CertReqCtx** tail = &ssl->certReqCtx;
while (*tail != NULL)
tail = &(*tail)->next;
*tail = ssl->dupWrite->postHandshakeCertReqCtx;
ssl->dupWrite->postHandshakeCertReqCtx = ssl->certReqCtx;
ssl->certReqCtx = NULL;
ssl->dupWrite->postHandshakeSendVerify =
ssl->options.sendVerify;
ssl->dupWrite->postHandshakeSigAlgo =
ssl->options.sigAlgo;
ssl->dupWrite->postHandshakeHashAlgo =
ssl->options.hashAlgo;
ssl->dupWrite->postHandshakeAuthPending = 1;
}
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
/* Leave ssl->options unchanged: read side must not reset
* its states or call wolfSSL_connect_TLSv13. */
}
else
#endif /* HAVE_WRITE_DUP */
{
/* reset handshake states */
ssl->options.clientState = CLIENT_HELLO_COMPLETE;
ssl->options.connectState = FIRST_REPLY_DONE;
ssl->options.handShakeState = CLIENT_HELLO_COMPLETE;
ssl->options.processReply = 0; /* doProcessInit */
/*
DTLSv1.3 note: We can't reset serverState to
SERVER_FINISHED_COMPLETE with the goal that this connect
blocks until the cert/cert_verify/finished flight gets ACKed
by the server. The problem is that we will invoke
ProcessReplyEx() in that case, but we came here from
ProcessReplyEx() and it is not re-entrant safe (the input
buffer would still have the certificate_request message). */
/*
DTLSv1.3 note: We can't reset serverState to
SERVER_FINISHED_COMPLETE with the goal that this connect
blocks until the cert/cert_verify/finished flight gets ACKed
by the server. The problem is that we will invoke
ProcessReplyEx() in that case, but we came here from
ProcessReplyEx() and it is not re-entrant safe (the input
buffer would still have the certificate_request message). */
if (wolfSSL_connect_TLSv13(ssl) != WOLFSSL_SUCCESS) {
ret = ssl->error;
if (ret != WC_NO_ERR_TRACE(WC_PENDING_E))
ret = POST_HAND_AUTH_ERROR;
if (wolfSSL_connect_TLSv13(ssl) != WOLFSSL_SUCCESS) {
ret = ssl->error;
if (ret != WC_NO_ERR_TRACE(WC_PENDING_E))
ret = POST_HAND_AUTH_ERROR;
}
}
}
#endif
+323 -11
View File
@@ -32902,9 +32902,12 @@ static int test_write_dup(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP)
size_t i, j;
size_t i, j, k;
char hiWorld[] = "dup message";
char readData[sizeof(hiWorld) + 5];
#ifdef WOLFSSL_TLS13
int required;
#endif
struct {
method_provider client_meth;
method_provider server_meth;
@@ -32913,9 +32916,11 @@ static int test_write_dup(void)
} methods[] = {
#ifndef WOLFSSL_NO_TLS12
{wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLS 1.2", WOLFSSL_TLSV1_2},
{wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLS 1.2", WOLFSSL_TLSV1_2},
#endif
#ifdef WOLFSSL_TLS13
{wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLS 1.3", WOLFSSL_TLSV1_3},
{wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLS 1.3", WOLFSSL_TLSV1_3},
#endif
};
struct {
@@ -32981,6 +32986,18 @@ static int test_write_dup(void)
#endif
};
/* Macro capturing local variables for concise bidirectional data exchange. */
#define EXCHANGE_DATA do { \
ExpectIntEQ(wolfSSL_write(ssl_s, hiWorld, sizeof(hiWorld)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_read(ssl_c, readData, sizeof(readData)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_read(ssl_s, readData, sizeof(readData)), \
sizeof(hiWorld)); \
} while (0)
for (i = 0; i < XELEM_CNT(methods); i++) {
for (j = 0; j < XELEM_CNT(ciphers) && !EXPECT_FAIL(); j++) {
struct test_memio_ctx test_ctx;
@@ -33003,23 +33020,77 @@ static int test_write_dup(void)
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
methods[i].client_meth, methods[i].server_meth), 0);
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
if (methods[i].version == WOLFSSL_TLSV1_3) {
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_c, cliCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_c, cliKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl_c), 0);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile,
NULL), WOLFSSL_SUCCESS);
}
#endif
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c));
ExpectIntEQ(wolfSSL_write(ssl_c, hiWorld, sizeof(hiWorld)),
WC_NO_ERR_TRACE(WRITE_DUP_WRITE_E));
ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)),
sizeof(hiWorld));
ExpectIntEQ(wolfSSL_read(ssl_s, readData, sizeof(readData)),
sizeof(hiWorld));
ExpectIntEQ(wolfSSL_write(ssl_s, hiWorld, sizeof(hiWorld)),
sizeof(hiWorld));
EXCHANGE_DATA;
ExpectIntEQ(wolfSSL_read(ssl_c2, readData, sizeof(readData)),
WC_NO_ERR_TRACE(WRITE_DUP_READ_E));
ExpectIntEQ(wolfSSL_read(ssl_c, readData, sizeof(readData)),
sizeof(hiWorld));
#ifdef WOLFSSL_DTLS13
/* The initial EXCHANGE_DATA above processes the post-handshake
* NewSessionTicket (S2C part delegates ACK) and triggers the
* ACK (C2S part sends it). Verify it completed. */
if (methods[i].client_meth == wolfDTLSv1_3_client_method) {
ExpectNotNull(ssl_c->dupWrite);
ExpectIntEQ(ssl_c->dupWrite->sendAcks, 0);
ExpectNull(ssl_s->dtls13Rtx.rtxRecords);
}
#endif
for (k = 0; k < 10; k++)
EXCHANGE_DATA;
#ifdef WOLFSSL_TLS13
if (methods[i].version == WOLFSSL_TLSV1_3) {
/* Client-initiated key update. */
ExpectIntEQ(wolfSSL_update_keys(ssl_c2), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_key_update_response(ssl_c2, &required), 0);
ExpectIntEQ(required, 1);
for (k = 0; k < 10; k++)
EXCHANGE_DATA;
}
if (methods[i].version == WOLFSSL_TLSV1_3) {
/* Server-initiated key update. */
ExpectIntEQ(wolfSSL_update_keys(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
ExpectIntEQ(required, 1);
for (k = 0; k < 10; k++)
EXCHANGE_DATA;
ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
ExpectIntEQ(required, 0);
}
#endif /* WOLFSSL_TLS13 */
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
if (methods[i].version == WOLFSSL_TLSV1_3) {
WOLFSSL_X509_CHAIN* chain = NULL;
ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
ExpectIntEQ(wolfSSL_get_chain_count(chain), 0);
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
EXCHANGE_DATA;
ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
ExpectIntEQ(wolfSSL_get_chain_count(chain), 1);
for (k = 0; k < 10; k++)
EXCHANGE_DATA;
}
#endif
if (EXPECT_SUCCESS())
printf("ok\n");
@@ -33033,6 +33104,245 @@ static int test_write_dup(void)
wolfSSL_CTX_free(ctx_s);
}
}
#undef EXCHANGE_DATA
#endif
return EXPECT_RESULT();
}
static int test_write_dup_want_write(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP)
size_t i, k;
char hiWorld[] = "dup message";
char readData[sizeof(hiWorld) + 5];
#ifdef WOLFSSL_TLS13
int required;
#endif
struct {
method_provider client_meth;
method_provider server_meth;
const char* version_name;
int version;
} methods[] = {
#ifndef WOLFSSL_NO_TLS12
{wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLS 1.2", WOLFSSL_TLSV1_2},
{wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLS 1.2", WOLFSSL_TLSV1_2},
#endif
#ifdef WOLFSSL_TLS13
{wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLS 1.3", WOLFSSL_TLSV1_3},
{wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLS 1.3", WOLFSSL_TLSV1_3},
#endif
};
/* Same as test_write_dup's EXCHANGE_DATA but every client (write-dup side)
* write is preceded by a simulated WANT_WRITE that must be retried. */
#define EXCHANGE_DATA do { \
ExpectIntEQ(wolfSSL_write(ssl_s, hiWorld, sizeof(hiWorld)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_read(ssl_c, readData, sizeof(readData)), \
sizeof(hiWorld)); \
test_memio_simulate_want_write(&test_ctx, 1, 1); \
ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
WOLFSSL_FATAL_ERROR); \
ExpectIntEQ(wolfSSL_get_error(ssl_c2, WOLFSSL_FATAL_ERROR), \
WOLFSSL_ERROR_WANT_WRITE); \
test_memio_simulate_want_write(&test_ctx, 1, 0); \
ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_read(ssl_s, readData, sizeof(readData)), \
sizeof(hiWorld)); \
} while (0)
for (i = 0; i < XELEM_CNT(methods) && !EXPECT_FAIL(); i++) {
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL *ssl_c2 = NULL;
if (i == 0)
printf("\n");
printf("Testing write_dup WANT_WRITE %s... ",
methods[i].version_name);
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
methods[i].client_meth, methods[i].server_meth), 0);
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
if (methods[i].version == WOLFSSL_TLSV1_3) {
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_c, cliCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_c, cliKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl_c), 0);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile,
NULL), WOLFSSL_SUCCESS);
}
#endif
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c));
for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
#ifdef WOLFSSL_TLS13
if (methods[i].version == WOLFSSL_TLSV1_3) {
/* Client-initiated key update with WANT_WRITE. */
ExpectIntEQ(wolfSSL_update_keys(ssl_c2), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_key_update_response(ssl_c2, &required), 0);
ExpectIntEQ(required, 1);
for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
/* Server-initiated key update: response goes through write side
* with WANT_WRITE. */
ExpectIntEQ(wolfSSL_update_keys(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
ExpectIntEQ(required, 1);
for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
ExpectIntEQ(required, 0);
}
#endif /* WOLFSSL_TLS13 */
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
if (methods[i].version == WOLFSSL_TLSV1_3) {
WOLFSSL_X509_CHAIN* chain = NULL;
ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
ExpectIntEQ(wolfSSL_get_chain_count(chain), 0);
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
EXCHANGE_DATA;
ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
ExpectIntEQ(wolfSSL_get_chain_count(chain), 1);
for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
}
#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */
if (EXPECT_SUCCESS())
printf("ok\n");
else
printf("failed\n");
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_c2);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
}
#undef EXCHANGE_DATA
#endif
return EXPECT_RESULT();
}
/* Simultaneous key update and cert req */
static int test_write_dup_want_write_simul(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP) && \
defined(WOLFSSL_POST_HANDSHAKE_AUTH) && defined(WOLFSSL_TLS13)
size_t i, k;
char hiWorld[] = "dup message";
char readData[sizeof(hiWorld) + 5];
int required;
struct {
method_provider client_meth;
method_provider server_meth;
const char* version_name;
} methods[] = {
#ifdef WOLFSSL_TLS13
{wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLS 1.3"},
{wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLS 1.3"},
#endif
};
/* Same as test_write_dup's EXCHANGE_DATA but every client (write-dup side)
* write is preceded by a simulated WANT_WRITE that must be retried. */
#define EXCHANGE_DATA do { \
ExpectIntEQ(wolfSSL_write(ssl_s, hiWorld, sizeof(hiWorld)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_read(ssl_c, readData, sizeof(readData)), \
sizeof(hiWorld)); \
test_memio_simulate_want_write(&test_ctx, 1, 1); \
ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
WOLFSSL_FATAL_ERROR); \
ExpectIntEQ(wolfSSL_get_error(ssl_c2, WOLFSSL_FATAL_ERROR), \
WOLFSSL_ERROR_WANT_WRITE); \
test_memio_simulate_want_write(&test_ctx, 1, 0); \
ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_read(ssl_s, readData, sizeof(readData)), \
sizeof(hiWorld)); \
} while (0)
for (i = 0; i < XELEM_CNT(methods) && !EXPECT_FAIL(); i++) {
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL *ssl_c2 = NULL;
WOLFSSL_X509_CHAIN* chain = NULL;
if (i == 0)
printf("\n");
printf("Testing write_dup WANT_WRITE %s... ",
methods[i].version_name);
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
methods[i].client_meth, methods[i].server_meth), 0);
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_c, cliCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_c, cliKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl_c), 0);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile,
NULL), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c));
for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
/* Server-initiated key update and cert req: response goes through
* write side with WANT_WRITE. */
ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
ExpectIntEQ(wolfSSL_get_chain_count(chain), 0);
ExpectIntEQ(wolfSSL_update_keys(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
ExpectIntEQ(required, 1);
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
ExpectIntEQ(wolfSSL_get_chain_count(chain), 1);
ExpectIntEQ(wolfSSL_key_update_response(ssl_s, &required), 0);
ExpectIntEQ(required, 0);
if (EXPECT_SUCCESS())
printf("ok\n");
else
printf("failed\n");
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_c2);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
}
#undef EXCHANGE_DATA
#endif
return EXPECT_RESULT();
}
@@ -34749,6 +35059,8 @@ TEST_CASE testCases[] = {
TEST_DTLS_DECLS,
TEST_DECL(test_tls_multi_handshakes_one_record),
TEST_DECL(test_write_dup),
TEST_DECL(test_write_dup_want_write),
TEST_DECL(test_write_dup_want_write_simul),
TEST_DECL(test_read_write_hs),
TEST_DECL(test_get_signature_nid),
#ifndef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
+52 -1
View File
@@ -5771,9 +5771,47 @@ typedef struct BuildMsgArgs {
#define READ_DUP_SIDE 2
typedef struct WriteDup {
wolfSSL_Mutex dupMutex; /* reference count mutex */
wolfSSL_Mutex dupMutex; /* field access mutex */
int dupCount; /* reference count */
int dupErr; /* under dupMutex, pass to other side */
#ifdef WOLFSSL_DTLS13
struct Dtls13RecordNumber* sendAckList; /* ownership transferred */
/* Key update ACK tracking: write side stores the (epoch, seq) of its
* in-flight KeyUpdate; read side sets keyUpdateAcked when the ACK for
* that exact record arrives. Both epoch and seq are checked to avoid
* false positives from data records in the same epoch. */
w64wrapper keyUpdateEpoch; /* epoch of the KeyUpdate */
w64wrapper keyUpdateSeq; /* seq num of the KeyUpdate */
#endif /* WOLFSSL_DTLS13 */
#ifdef WOLFSSL_TLS13
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
/* Post-handshake certificate request delegation: the read side received
* a CertificateRequest but cannot write; it saves state here and the
* write side sends Certificate+CertificateVerify+Finished. */
struct HS_Hashes* postHandshakeHashState; /* transcript at CR time */
struct CertReqCtx* postHandshakeCertReqCtx; /* context from CR */
byte postHandshakeSendVerify; /* ssl->options.sendVerify */
byte postHandshakeSigAlgo; /* ssl->options.sigAlgo */
byte postHandshakeHashAlgo; /* ssl->options.hashAlgo */
#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */
#endif /* WOLFSSL_TLS13 */
/* Flags */
#ifdef WOLFSSL_DTLS13
WC_BITFIELD keyUpdateWaiting:1; /* write side has an unACKed KeyUpdate */
WC_BITFIELD keyUpdateAcked:1; /* read side confirmed the ACK arrived */
/* DTLS 1.3: read side cannot write, so it passes ACK work to the
* write side. */
WC_BITFIELD sendAcks:1;
#endif /* WOLFSSL_DTLS13 */
#ifdef WOLFSSL_TLS13
/* TLS 1.3 (and DTLS 1.3): read side received a KeyUpdate(update_requested)
* but cannot send the response; write side handles it. */
WC_BITFIELD keyUpdateRespond:1; /* write side must send a KeyUpdate response */
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
WC_BITFIELD postHandshakeAuthPending:1; /* write side must respond */
#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */
#endif /* WOLFSSL_TLS13 */
} WriteDup;
WOLFSSL_LOCAL void FreeWriteDup(WOLFSSL* ssl);
@@ -6178,6 +6216,9 @@ struct WOLFSSL {
byte dtls13SendingFragments:1;
byte dtls13SendingAckOrRtx;
byte dtls13FastTimeout:1;
#ifdef HAVE_WRITE_DUP
byte dtls13KeyUpdateAcked:1;
#endif
byte dtls13WaitKeyUpdateAck;
byte dtls13DoKeyUpdate;
word32 dtls13MessageLength;
@@ -6454,6 +6495,13 @@ struct WOLFSSL {
defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK)
WC_BITFIELD scr_check_enabled:1; /* enable/disable SCR check */
#endif
#ifdef HAVE_WRITE_DUP
#ifdef WOLFSSL_TLS13
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
WC_BITFIELD postHandshakeAuthPending:1;
#endif
#endif
#endif
};
#if defined(WOLFSSL_SYS_CRYPTO_POLICY)
@@ -7088,6 +7136,7 @@ WOLFSSL_LOCAL int SetDhExternal(WOLFSSL_DH *dh);
#endif
WOLFSSL_LOCAL int InitHandshakeHashes(WOLFSSL* ssl);
WOLFSSL_LOCAL void Free_HS_Hashes(HS_Hashes* hsHashes, void* heap);
WOLFSSL_LOCAL void FreeHandshakeHashes(WOLFSSL* ssl);
WOLFSSL_LOCAL int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source,
HS_Hashes** destination);
@@ -7187,6 +7236,8 @@ WOLFSSL_LOCAL int Dtls13SetEpochKeys(WOLFSSL* ssl, w64wrapper epochNumber,
enum encrypt_side side);
WOLFSSL_LOCAL int Dtls13GetSeq(WOLFSSL* ssl, int order, word32* seq,
byte increment);
WOLFSSL_LOCAL void Dtls13RtxRemoveRecord(WOLFSSL* ssl, w64wrapper epoch,
w64wrapper seq);
WOLFSSL_LOCAL int Dtls13DoScheduledWork(WOLFSSL* ssl);
WOLFSSL_LOCAL int Dtls13DeriveSnKeys(WOLFSSL* ssl, int provision);
WOLFSSL_LOCAL int Dtls13SetRecordNumberKeys(WOLFSSL* ssl,