mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 14:30:49 +02:00
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:
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user