DTLS 1.3: allow fragmenting the second ClientHello message

- DTLS 1.3 pqc support
- Add --enable-dtls-frag-ch option to enable CH fragmenting
- Send an alert when we get an empty keyshare with a cookie present to not allow for multiple HRR in one connection
- Only update the DTLS window when we have successfully processed or stored a message
- Call ssl->chGoodCb as soon as we have processed a verified full or fragmented ClientHello cookie
This commit is contained in:
Juliusz Sosinowicz
2023-09-01 16:38:52 +02:00
parent 832e0f3726
commit 85a596e54a
12 changed files with 685 additions and 122 deletions

View File

@ -4516,6 +4516,21 @@ then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DTLS_CID"
fi
# DTLS 1.3 Fragment Second ClientHello
AC_ARG_ENABLE([dtls-frag-ch],
[AS_HELP_STRING([--enable-dtls-frag-ch],[Enable wolfSSL DTLS 1.3 ClientHello fragmenting (default: disabled)])],
[ ENABLED_DTLS_CH_FRAG=$enableval ],
[ ENABLED_DTLS_CH_FRAG=no ]
)
if test "x$ENABLED_DTLS_CH_FRAG" = "xyes"
then
if test "x$ENABLED_DTLS13" != "xyes"
then
AC_MSG_ERROR([You need to enable DTLSv1.3 to use DTLS ClientHello fragmenting])
fi
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DTLS_CH_FRAG"
fi
# CODING
AC_ARG_ENABLE([coding],
[AS_HELP_STRING([--enable-coding],[Enable Coding base 16/64 (default: enabled)])],

View File

@ -3322,6 +3322,11 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
}
#endif /* WOLFSSL_DTLS_CID */
#ifdef WOLFSSL_DTLS_CH_FRAG
if (doDTLS)
wolfSSL_dtls13_allow_ch_frag(ssl, 1);
#endif
#ifndef WOLFSSL_CALLBACKS
if (nonBlocking) {
#ifdef WOLFSSL_DTLS

View File

@ -26,6 +26,13 @@
* will consume less bandwidth (one ClientHello and one HelloVerifyRequest
* less). On the other hand, if a valid SessionID is collected, forged
* clientHello messages will consume resources on the server.
* WOLFSSL_DTLS_CH_FRAG
* Allow a server to process a fragmented second/verified (one containing a
* valid cookie response) ClientHello message. The first/unverifies (one
* without a cookie extension) ClientHello MUST be unfragmented so that the
* DTLS server can process it statelessly. This is only implemented for
* DTLS 1.3. The user MUST call wolfSSL_dtls13_allow_ch_frag() on the server
* to explicitly enable this during runtime.
*/
#ifdef HAVE_CONFIG_H
@ -263,10 +270,13 @@ static int CheckDtlsCookie(const WOLFSSL* ssl, WolfSSL_CH* ch,
return ret;
}
static int ParseClientHello(const byte* input, word32 helloSz, WolfSSL_CH* ch)
static int ParseClientHello(const byte* input, word32 helloSz, WolfSSL_CH* ch,
byte isFirstCHFrag)
{
word32 idx = 0;
(void)isFirstCHFrag;
/* protocol version, random and session id length check */
if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
return BUFFER_ERROR;
@ -288,9 +298,20 @@ static int ParseClientHello(const byte* input, word32 helloSz, WolfSSL_CH* ch)
idx += ReadVector8(input + idx, &ch->compression);
if (idx < helloSz - OPAQUE16_LEN) {
/* Extensions are optional */
#ifdef WOLFSSL_DTLS_CH_FRAG
word32 extStart = idx + OPAQUE16_LEN;
#endif
idx += ReadVector16(input + idx, &ch->extension);
if (idx > helloSz)
return BUFFER_ERROR;
if (idx > helloSz) {
#ifdef WOLFSSL_DTLS_CH_FRAG
/* Allow incomplete extensions if we are parsing a fragment */
if (isFirstCHFrag && extStart < helloSz)
ch->extension.size = helloSz - extStart;
else
#endif
return BUFFER_ERROR;
idx = helloSz;
}
}
if (idx != helloSz)
return BUFFER_ERROR;
@ -860,17 +881,27 @@ static int ClientHelloSanityCheck(WolfSSL_CH* ch, byte isTls13)
return 0;
}
int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
word32* inOutIdx, word32 helloSz)
int DoClientHelloStateless(WOLFSSL* ssl, const byte* input, word32 helloSz,
byte isFirstCHFrag)
{
int ret;
WolfSSL_CH ch;
byte isTls13 = 0;
WOLFSSL_ENTER("DoClientHelloStateless");
if (isFirstCHFrag) {
#ifdef WOLFSSL_DTLS_CH_FRAG
WOLFSSL_MSG("\tProcessing fragmented ClientHello");
#else
WOLFSSL_MSG("\tProcessing fragmented ClientHello but "
"WOLFSSL_DTLS_CH_FRAG is not defined. This should not happen.");
#endif
}
XMEMSET(&ch, 0, sizeof(ch));
ssl->options.dtlsStateful = 0;
ret = ParseClientHello(input + *inOutIdx, helloSz, &ch);
ret = ParseClientHello(input, helloSz, &ch, isFirstCHFrag);
if (ret != 0)
return ret;
@ -894,7 +925,7 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
return ret;
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
if (!isTls13) {
if (!isTls13 && !isFirstCHFrag) {
int resume = FALSE;
ret = TlsResumptionIsValid(ssl, &ch, &resume);
if (ret != 0)
@ -907,7 +938,13 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
#endif
if (ch.cookie.size == 0 && ch.cookieExt.size == 0) {
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13);
#ifdef WOLFSSL_DTLS_CH_FRAG
/* Don't send anything here when processing fragment */
if (isFirstCHFrag)
ret = BUFFER_ERROR;
else
#endif
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13);
}
else {
byte cookieGood;
@ -921,6 +958,12 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
if (isTls13)
ret = INVALID_PARAMETER;
else
#endif
#ifdef WOLFSSL_DTLS_CH_FRAG
/* Don't send anything here when processing fragment */
if (isFirstCHFrag)
ret = BUFFER_ERROR;
else
#endif
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13);
}

View File

@ -1573,6 +1573,19 @@ static int Dtls13RtxSendBuffered(WOLFSSL* ssl)
return 0;
}
static int Dtls13AcceptFragmented(WOLFSSL *ssl, enum HandShakeType type)
{
if (IsEncryptionOn(ssl, 0))
return 1;
if (ssl->options.side == WOLFSSL_CLIENT_END && type == server_hello)
return 1;
#ifdef WOLFSSL_DTLS_CH_FRAG
if (ssl->options.side == WOLFSSL_SERVER_END && type == client_hello &&
ssl->options.dtls13ChFrag && ssl->options.dtlsStateful)
return 1;
#endif
return 0;
}
/**
* Dtls13HandshakeRecv() - process an handshake message. Deal with
fragmentation if needed
@ -1646,13 +1659,33 @@ static int _Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32 size,
isFirst = fragOff == 0;
isComplete = isFirst && fragLength == messageLength;
if (!isComplete && !IsEncryptionOn(ssl, 0)) {
if (!isComplete && !Dtls13AcceptFragmented(ssl, handshakeType)) {
#ifdef WOLFSSL_DTLS_CH_FRAG
/* check if the first CH fragment contains a valid cookie */
if (ssl->options.dtls13ChFrag && !ssl->options.dtlsStateful &&
isFirst && handshakeType == client_hello &&
DoClientHelloStateless(ssl, input + idx, fragLength, 1) == 0) {
/* We can save this message and continue as stateful. */
if (ssl->chGoodCb != NULL && !IsSCR(ssl)) {
int cbret = ssl->chGoodCb(ssl, ssl->chGoodCtx);
if (cbret < 0) {
ssl->error = cbret;
WOLFSSL_MSG("ClientHello Good Cb don't continue error");
return WOLFSSL_FATAL_ERROR;
}
}
WOLFSSL_MSG("ClientHello fragment verified");
}
else
#endif
{
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("DTLS1.3 not accepting fragmented plaintext message");
WOLFSSL_MSG("DTLS1.3 not accepting fragmented plaintext message");
#endif /* WOLFSSL_DEBUG_TLS */
/* ignore the message */
*processedSize = idx + fragLength + ssl->keys.padSz;
return 0;
/* ignore the message */
*processedSize = idx + fragLength + ssl->keys.padSz;
return 0;
}
}
usingAsyncCrypto = ssl->devId != INVALID_DEVID;
@ -2797,4 +2830,16 @@ int Dtls13CheckAEADFailLimit(WOLFSSL* ssl)
}
#endif
#ifdef WOLFSSL_DTLS_CH_FRAG
int wolfSSL_dtls13_allow_ch_frag(WOLFSSL *ssl, int enabled)
{
if (ssl->options.side == WOLFSSL_CLIENT_END) {
return WOLFSSL_FAILURE;
}
ssl->options.dtls13ChFrag = !!enabled;
return WOLFSSL_SUCCESS;
}
#endif
#endif /* WOLFSSL_DTLS13 */

View File

@ -8017,6 +8017,12 @@ void SSL_ResourceFree(WOLFSSL* ssl)
ssl->dtls13ClientHello = NULL;
ssl->dtls13ClientHelloSz = 0;
}
#ifdef WOLFSSL_DTLS_CH_FRAG
if (ssl->dtls13KSE != NULL) {
TLSX_KeyShare_FreeAll(ssl->dtls13KSE, ssl->heap);
ssl->dtls13KSE = NULL;
}
#endif
#endif /* WOLFSSL_DTLS13 */
#endif /* WOLFSSL_DTLS */
@ -16806,6 +16812,8 @@ static WC_INLINE int Dtls13CheckWindow(WOLFSSL* ssl)
int wordIndex;
word32 diff;
WOLFSSL_ENTER("Dtls13CheckWindow");
if (ssl->dtls13DecryptEpoch == NULL) {
WOLFSSL_MSG("Can't find decrypting epoch");
return 0;
@ -17047,14 +17055,26 @@ static WC_INLINE int Dtls13UpdateWindow(WOLFSSL* ssl)
int wordOffset;
int wordIndex;
word32 diff;
Dtls13Epoch* e = ssl->dtls13DecryptEpoch;
WOLFSSL_ENTER("Dtls13UpdateWindow");
if (ssl->dtls13DecryptEpoch == NULL) {
WOLFSSL_MSG("Can't find decrypting Epoch");
return BAD_STATE_E;
}
nextSeq = ssl->dtls13DecryptEpoch->nextPeerSeqNumber;
window = ssl->dtls13DecryptEpoch->window;
if (!w64Equal(ssl->keys.curEpoch64, ssl->dtls13DecryptEpoch->epochNumber)) {
/* ssl->dtls13DecryptEpoch has been updated since we received the msg */
e = Dtls13GetEpoch(ssl, ssl->keys.curEpoch64);
if (e == NULL) {
WOLFSSL_MSG("Can't find decrypting Epoch");
return BAD_STATE_E;
}
}
nextSeq = e->nextPeerSeqNumber;
window = e->window;
seq = ssl->keys.curSeq;
/* seq < nextSeq */
@ -17075,7 +17095,7 @@ static WC_INLINE int Dtls13UpdateWindow(WOLFSSL* ssl)
}
window[wordIndex] |= (1 << wordOffset);
return 1;
return 0;
}
/* seq >= nextSeq, seq - nextSeq */
@ -17086,9 +17106,9 @@ static WC_INLINE int Dtls13UpdateWindow(WOLFSSL* ssl)
_DtlsUpdateWindowGTSeq(w64GetLow32(diff64), window);
w64Increment(&seq);
ssl->dtls13DecryptEpoch->nextPeerSeqNumber = seq;
e->nextPeerSeqNumber = seq;
return 1;
return 0;
}
#endif /* WOLFSSL_DTLS13 */
@ -20714,32 +20734,17 @@ default:
/* the record layer is here */
case runProcessingOneRecord:
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version) &&
!Dtls13CheckWindow(ssl)) {
/* drop packet */
WOLFSSL_MSG("Dropping DTLS record outside receiving window");
ssl->options.processReply = doProcessInit;
ssl->buffers.inputBuffer.idx += ssl->curSize;
if (ssl->buffers.inputBuffer.idx >
ssl->buffers.inputBuffer.length)
return BUFFER_E;
if(!Dtls13CheckWindow(ssl)) {
/* drop packet */
WOLFSSL_MSG(
"Dropping DTLS record outside receiving window");
ssl->options.processReply = doProcessInit;
ssl->buffers.inputBuffer.idx += ssl->curSize;
if (ssl->buffers.inputBuffer.idx >
ssl->buffers.inputBuffer.length)
return BUFFER_E;
continue;
}
ret = Dtls13UpdateWindow(ssl);
if (ret != 1) {
WOLFSSL_ERROR(ret);
return ret;
}
ret = Dtls13RecordRecvd(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
continue;
}
#endif /* WOLFSSL_DTLS13 */
ssl->options.processReply = runProcessingOneMessage;
@ -20773,16 +20778,16 @@ default:
}
else
#endif
/* TLS13 plaintext limit is checked earlier before decryption */
/* For TLS v1.1 the block size and explicit IV are added to idx,
* so it needs to be included in this limit check */
if (!IsAtLeastTLSv1_3(ssl->version)
&& ssl->curSize - ssl->keys.padSz -
(ssl->buffers.inputBuffer.idx - startIdx)
> MAX_PLAINTEXT_SZ
/* TLS13 plaintext limit is checked earlier before decryption */
/* For TLS v1.1 the block size and explicit IV are added to idx,
* so it needs to be included in this limit check */
if (!IsAtLeastTLSv1_3(ssl->version)
&& ssl->curSize - ssl->keys.padSz -
(ssl->buffers.inputBuffer.idx - startIdx)
> MAX_PLAINTEXT_SZ
#ifdef WOLFSSL_ASYNC_CRYPT
&& ssl->buffers.inputBuffer.length !=
ssl->buffers.inputBuffer.idx
&& ssl->buffers.inputBuffer.length !=
ssl->buffers.inputBuffer.idx
#endif
) {
WOLFSSL_MSG("Plaintext too long");
@ -20793,17 +20798,6 @@ default:
return BUFFER_ERROR;
}
#ifdef WOLFSSL_DTLS
if (IsDtlsNotSctpMode(ssl) && !IsAtLeastTLSv1_3(ssl->version)) {
_DtlsUpdateWindow(ssl);
}
if (ssl->options.dtls) {
/* Reset timeout as we have received a valid DTLS message */
ssl->dtls_timeout = ssl->dtls_timeout_init;
}
#endif /* WOLFSSL_DTLS */
WOLFSSL_MSG("received record layer msg");
switch (ssl->curRL.type) {
@ -20813,16 +20807,23 @@ default:
if (ssl->options.dtls) {
#ifdef WOLFSSL_DTLS
if (!IsAtLeastTLSv1_3(ssl->version)) {
ret = DoDtlsHandShakeMsg(ssl,
ssl->buffers.inputBuffer.buffer,
&ssl->buffers.inputBuffer.idx,
ssl->buffers.inputBuffer.length);
if (ret != 0) {
if (SendFatalAlertOnly(ssl, ret)
== SOCKET_ERROR_E) {
ret = SOCKET_ERROR_E;
}
ret = DoDtlsHandShakeMsg(ssl,
ssl->buffers.inputBuffer.buffer,
&ssl->buffers.inputBuffer.idx,
ssl->buffers.inputBuffer.length);
if (ret == 0 && ssl->options.dtlsStateful) {
if (IsDtlsNotSctpMode(ssl))
_DtlsUpdateWindow(ssl);
/* Reset timeout as we have received a valid
* DTLS handshake message */
ssl->dtls_timeout = ssl->dtls_timeout_init;
}
if (ret != 0) {
if (SendFatalAlertOnly(ssl, ret)
== SOCKET_ERROR_E) {
ret = SOCKET_ERROR_E;
}
}
}
#endif
#ifdef WOLFSSL_DTLS13
@ -20831,6 +20832,18 @@ default:
ssl->buffers.inputBuffer.buffer,
&ssl->buffers.inputBuffer.idx,
ssl->buffers.inputBuffer.length);
if (ret == 0 && ssl->options.dtlsStateful) {
ret = Dtls13UpdateWindow(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
ret = Dtls13RecordRecvd(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
}
#ifdef WOLFSSL_EARLY_DATA
if (ret == 0 &&
ssl->options.side == WOLFSSL_SERVER_END &&
@ -20951,6 +20964,20 @@ default:
WOLFSSL_ERROR_VERBOSE(UNKNOWN_RECORD_TYPE);
return UNKNOWN_RECORD_TYPE;
}
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
ret = Dtls13UpdateWindow(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
ret = Dtls13RecordRecvd(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
}
#endif
break;
}
#endif
@ -21038,6 +21065,8 @@ default:
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
WOLFSSL_DTLS_PEERSEQ* peerSeq = ssl->keys.peerSeq;
if (IsDtlsNotSctpMode(ssl))
_DtlsUpdateWindow(ssl);
#ifdef WOLFSSL_MULTICAST
if (ssl->options.haveMcast) {
peerSeq += ssl->keys.curPeerId;
@ -21099,10 +21128,32 @@ default:
return SANITY_MSG_E;
}
#endif
if ((ret = DoApplicationData(ssl,
ssl->buffers.inputBuffer.buffer,
&ssl->buffers.inputBuffer.idx,
NO_SNIFF)) != 0) {
ret = DoApplicationData(ssl,
ssl->buffers.inputBuffer.buffer,
&ssl->buffers.inputBuffer.idx, NO_SNIFF);
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls &&
(ret == 0 || ret == APP_DATA_READY)) {
#ifdef WOLFSSL_DTLS13
if (IsAtLeastTLSv1_3(ssl->version)) {
int updateRet = Dtls13UpdateWindow(ssl);
if (updateRet != 0) {
WOLFSSL_ERROR(updateRet);
return updateRet;
}
updateRet = Dtls13RecordRecvd(ssl);
if (updateRet != 0) {
WOLFSSL_ERROR(updateRet);
return updateRet;
}
}
else
#endif
if (IsDtlsNotSctpMode(ssl))
_DtlsUpdateWindow(ssl);
}
#endif
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
@ -21131,6 +21182,27 @@ default:
/* Reset error if we got an alert level in ret */
if (ret > 0)
ret = 0;
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
#ifdef WOLFSSL_DTLS13
if (IsAtLeastTLSv1_3(ssl->version)) {
ret = Dtls13UpdateWindow(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
ret = Dtls13RecordRecvd(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
}
else
#endif
if (IsDtlsNotSctpMode(ssl))
_DtlsUpdateWindow(ssl);
}
#endif
break;
#ifdef WOLFSSL_DTLS13
@ -21147,6 +21219,16 @@ default:
ssl->buffers.inputBuffer.idx += ssl->keys.padSz;
if (ret != 0)
return ret;
ret = Dtls13UpdateWindow(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
ret = Dtls13RecordRecvd(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
break;
}
FALL_THROUGH;
@ -34214,8 +34296,15 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
"VerifyServerSuite() with MEMORY_E");
return 0;
}
if (cs->clientKSE == NULL && searched)
if (cs->clientKSE == NULL && searched) {
#ifdef WOLFSSL_SEND_HRR_COOKIE
/* If the CH contains a cookie then we need to send an alert to
* start from scratch. */
if (TLSX_Find(extensions, TLSX_COOKIE) != NULL)
return INVALID_PARAMETER;
#endif
cs->doHelloRetry = 1;
}
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_PENDING_E)
return ret;
@ -34716,9 +34805,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#ifdef WOLFSSL_DTLS
/* Update the ssl->options.dtlsStateful setting `if` statement in
* wolfSSL_accept when changing this one. */
if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl)) {
if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl) &&
!ssl->options.dtlsStateful) {
DtlsSetSeqNumForReply(ssl);
ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz);
ret = DoClientHelloStateless(ssl, input + *inOutIdx, helloSz, 0);
if (ret != 0 || !ssl->options.dtlsStateful) {
int alertType = TranslateErrorToAlert(ret);
if (alertType != invalid_alert) {
@ -34735,6 +34825,14 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
ret = 0;
return ret;
}
if (ssl->chGoodCb != NULL) {
int cbret = ssl->chGoodCb(ssl, ssl->chGoodCtx);
if (cbret < 0) {
ssl->error = cbret;
WOLFSSL_MSG("ClientHello Good Cb don't continue error");
return WOLFSSL_FATAL_ERROR;
}
}
}
ssl->options.dtlsStateful = 1;
#endif /* WOLFSSL_DTLS */

View File

@ -12987,17 +12987,6 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
}
#endif
#ifdef WOLFSSL_DTLS
if (ssl->chGoodCb != NULL && !IsSCR(ssl)) {
int cbret = ssl->chGoodCb(ssl, ssl->chGoodCtx);
if (cbret < 0) {
ssl->error = cbret;
WOLFSSL_MSG("ClientHello Good Cb don't continue error");
return WOLFSSL_FATAL_ERROR;
}
}
#endif
ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
FALL_THROUGH;
@ -13275,7 +13264,6 @@ int wolfSSL_SetHsDoneCb(WOLFSSL* ssl, HandShakeDoneCb cb, void* user_ctx)
ssl->hsDoneCb = cb;
ssl->hsDoneCtx = user_ctx;
return WOLFSSL_SUCCESS;
}
@ -19240,6 +19228,12 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
ssl->options.haveSessionId = 0;
ssl->options.tls = 0;
ssl->options.tls1_1 = 0;
#ifdef WOLFSSL_DTLS
ssl->options.dtlsStateful = 0;
#endif
#ifdef WOLFSSL_DTLS_CH_FRAG
ssl->options.dtlsSentEmptyKS = 0;
#endif
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
ssl->options.noPskDheKe = 0;
#ifdef HAVE_SUPPORTED_CURVES

View File

@ -67,7 +67,6 @@
#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
static int TLSX_KeyShare_IsSupported(int namedGroup);
static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap);
#endif
#ifdef HAVE_SUPPORTED_CURVES
@ -7769,7 +7768,7 @@ int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse)
* list The linked list of key share entry objects.
* heap The heap used for allocation.
*/
static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
{
KeyShareEntry* current;
@ -8722,7 +8721,7 @@ int TLSX_KeyShare_Parse_ClientHello(const WOLFSSL* ssl,
int TLSX_KeyShare_Parse(WOLFSSL* ssl, const byte* input, word16 length,
byte msgType)
{
int ret;
int ret = 0;
KeyShareEntry *keyShareEntry = NULL;
word16 group;
@ -8784,24 +8783,50 @@ int TLSX_KeyShare_Parse(WOLFSSL* ssl, const byte* input, word16 length,
if (ssl->error != WC_PENDING_E)
#endif
{
/* Check the selected group was supported by ClientHello extensions. */
/* Check the selected group was supported by ClientHello
* extensions. */
if (!TLSX_SupportedGroups_Find(ssl, group, ssl->extensions)) {
WOLFSSL_ERROR_VERBOSE(BAD_KEY_SHARE_DATA);
return BAD_KEY_SHARE_DATA;
}
/* Check if the group was sent. */
if (TLSX_KeyShare_Find(ssl, group)) {
WOLFSSL_ERROR_VERBOSE(BAD_KEY_SHARE_DATA);
return BAD_KEY_SHARE_DATA;
#ifdef WOLFSSL_DTLS_CH_FRAG
/* If we sent an empty key share then we can just limit the keyshare
* to the one selected by the server. */
if (ssl->options.dtlsSentEmptyKS) {
if (!TLSX_KeyShare_SelectGroup(ssl, group)) {
/* Clear out all groups if not found */
ret = TLSX_KeyShare_Empty(ssl);
if (ret != 0)
return ret;
}
}
else
#endif
{
/* Check if the group was sent. */
if (TLSX_KeyShare_Find(ssl, group)) {
WOLFSSL_ERROR_VERBOSE(BAD_KEY_SHARE_DATA);
return BAD_KEY_SHARE_DATA;
}
/* Clear out unusable key shares. */
ret = TLSX_KeyShare_Empty(ssl);
if (ret != 0)
return ret;
}
/* Clear out unusable key shares. */
ret = TLSX_KeyShare_Empty(ssl);
if (ret != 0)
return ret;
}
#ifdef WOLFSSL_DTLS_CH_FRAG
/* Check if we were able to limit the keyshare entries to one group */
if (ssl->options.dtlsSentEmptyKS &&
TLSX_KeyShare_SelectGroup(ssl, group)) {
/* Nothing to do */
}
else
#endif
#ifdef HAVE_PQC
/* For post-quantum groups, do this in TLSX_PopulateExtensions(). */
if (!WOLFSSL_NAMED_GROUP_IS_PQC(group))
@ -9102,6 +9127,38 @@ int TLSX_KeyShare_Use(const WOLFSSL* ssl, word16 group, word16 len, byte* data,
return 0;
}
/* Clear out all entries except for group
*
* ssl The SSL/TLS object.
* returns 1 when the group was found and 0 when it wasn't found.
* */
int TLSX_KeyShare_SelectGroup(WOLFSSL* ssl, word16 group)
{
TLSX* extension;
KeyShareEntry* list;
KeyShareEntry** prev;
/* Find the KeyShare extension if it exists. */
extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
if (extension != NULL) {
for (prev = (KeyShareEntry**)&extension->data,
list = (KeyShareEntry*)extension->data; list != NULL;
prev = &list->next, list = list->next) {
if (list->group == group) {
/* Unlink it from the list */
*prev = list->next;
list->next = NULL;
/* Free the list */
TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data,
ssl->heap);
extension->data = list;
return 1;
}
}
}
return 0;
}
/* Set an empty Key Share extension.
*
* ssl The SSL/TLS object.

View File

@ -4410,10 +4410,48 @@ int SendTls13ClientHello(WOLFSSL* ssl)
}
#endif
/* Include length of TLS extensions. */
ret = TLSX_GetRequestSize(ssl, client_hello, &args->length);
if (ret != 0)
return ret;
{
#ifdef WOLFSSL_DTLS_CH_FRAG
int maxFrag = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
word16 lenWithoutExts = args->length;
#endif
/* Include length of TLS extensions. */
ret = TLSX_GetRequestSize(ssl, client_hello, &args->length);
if (ret != 0)
return ret;
#ifdef WOLFSSL_DTLS_CH_FRAG
if (ssl->options.dtls && args->length > maxFrag &&
TLSX_Find(ssl->extensions, TLSX_COOKIE) == NULL) {
/* Try again with an empty key share if we would be fragmenting
* without a cookie */
TLSX* ks = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
if (ks == NULL) {
WOLFSSL_MSG("No key share and CH can't fit in one fragment.");
return BUFFER_ERROR;
}
args->length = lenWithoutExts;
if (ssl->dtls13KSE != NULL)
TLSX_KeyShare_FreeAll(ssl->dtls13KSE, ssl->heap);
ssl->dtls13KSE = (KeyShareEntry*)ks->data;
ks->data = NULL;
ret = TLSX_GetRequestSize(ssl, client_hello, &args->length);
if (ret != 0) {
/* Restore key share data */
ks->data = ssl->dtls13KSE;
ssl->dtls13KSE = NULL;
return ret;
}
if (args->length > maxFrag) {
WOLFSSL_MSG("Can't fit first CH in one fragment.");
return BUFFER_ERROR;
}
WOLFSSL_MSG("Sending empty key share so we don't fragment CH1");
ssl->options.dtlsSentEmptyKS = 1;
}
#endif
}
/* Total message size. */
args->sendSz = args->length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
@ -4653,6 +4691,19 @@ int SendTls13ClientHello(WOLFSSL* ssl)
if (ret == 0)
FreeAsyncCtx(ssl, 0);
#endif
#ifdef WOLFSSL_DTLS_CH_FRAG
if ((ret == 0 || ret == WANT_WRITE) && ssl->dtls13KSE != NULL) {
/* Restore the keyshare */
TLSX* ks = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
if (ks == NULL || ks->data != NULL) {
WOLFSSL_MSG("Missing key share or key share data not NULL");
return BUFFER_ERROR;
}
WOLFSSL_MSG("Restored key share");
ks->data = ssl->dtls13KSE;
ssl->dtls13KSE = NULL;
}
#endif
WOLFSSL_LEAVE("SendTls13ClientHello", ret);
WOLFSSL_END(WC_FUNC_CLIENT_HELLO_SEND);
@ -6624,12 +6675,21 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
/* Update the ssl->options.dtlsStateful setting `if` statement in
* wolfSSL_accept_TLSv13 when changing this one. */
if (IsDtlsNotSctpMode(ssl) && ssl->options.sendCookie) {
ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz);
if (IsDtlsNotSctpMode(ssl) && ssl->options.sendCookie &&
!ssl->options.dtlsStateful) {
ret = DoClientHelloStateless(ssl, input + *inOutIdx, helloSz, 0);
if (ret != 0 || !ssl->options.dtlsStateful) {
*inOutIdx += helloSz;
goto exit_dch;
}
if (ssl->chGoodCb != NULL && !IsSCR(ssl)) {
int cbret = ssl->chGoodCb(ssl, ssl->chGoodCtx);
if (cbret < 0) {
ssl->error = cbret;
WOLFSSL_MSG("ClientHello Good Cb don't continue error");
return WOLFSSL_FATAL_ERROR;
}
}
}
ssl->options.dtlsStateful = 1;
#endif /* WOLFSSL_DTLS */
@ -13223,17 +13283,6 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
case TLS13_ACCEPT_SECOND_REPLY_DONE :
#ifdef WOLFSSL_DTLS
if (ssl->chGoodCb != NULL) {
int cbret = ssl->chGoodCb(ssl, ssl->chGoodCtx);
if (cbret < 0) {
ssl->error = cbret;
WOLFSSL_MSG("ClientHello Good Cb don't continue error");
return WOLFSSL_FATAL_ERROR;
}
}
#endif
if ((ssl->error = SendTls13ServerHello(ssl, server_hello)) != 0) {
WOLFSSL_ERROR(ssl->error);
return WOLFSSL_FATAL_ERROR;

View File

@ -65238,6 +65238,236 @@ static int test_revoked_loaded_int_cert(void)
return EXPECT_RESULT();
}
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \
&& defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG)
static int test_dtls_frag_ch_count_records(byte* b, int len)
{
DtlsRecordLayerHeader* dtlsRH;
int records = 0;
size_t recordLen;
while (len > 0) {
records++;
dtlsRH = (DtlsRecordLayerHeader*)b;
recordLen = (dtlsRH->length[0] << 8) | dtlsRH->length[1];
b += sizeof(DtlsRecordLayerHeader) + recordLen;
len -= sizeof(DtlsRecordLayerHeader) + recordLen;
}
return records;
}
#endif
static int test_dtls_frag_ch(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
&& defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
static unsigned int DUMMY_MTU = 256;
unsigned char four_frag_CH[] = {
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xce, 0xfe, 0xfd, 0xf3, 0x94, 0x01, 0x33, 0x2c, 0xcf, 0x2c, 0x47, 0xb1,
0xe5, 0xa1, 0x7b, 0x19, 0x3e, 0xac, 0x68, 0xdd, 0xe6, 0x17, 0x6b, 0x85,
0xad, 0x5f, 0xfc, 0x7f, 0x6e, 0xf0, 0xb9, 0xe0, 0x2e, 0xca, 0x47, 0x00,
0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0,
0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc,
0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0,
0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00,
0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x02,
0x7c, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20,
0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06,
0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01,
0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00, 0x0c,
0x00, 0x0a, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00,
0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x02, 0x39, 0x02, 0x37, 0x00, 0x17,
0x00, 0x41, 0x04, 0x94, 0xdf, 0x36, 0xd7, 0xb3, 0x90, 0x6d, 0x01, 0xa1,
0xe6, 0xed, 0x67, 0xf4, 0xd9, 0x9d, 0x2c, 0xac, 0x57, 0x74, 0xff, 0x19,
0xbe, 0x5a, 0xc9, 0x30, 0x11, 0xb7, 0x2b, 0x59, 0x47, 0x80, 0x7c, 0xa9,
0xb7, 0x31, 0x8c, 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, 0x00, 0x00, 0x00,
0xce, 0x00, 0x00, 0xce, 0x9e, 0x13, 0x74, 0x3b, 0x86, 0xba, 0x69, 0x1f,
0x12, 0xf7, 0xcd, 0x78, 0x53, 0xe8, 0x50, 0x4d, 0x71, 0x3f, 0x4b, 0x4e,
0xeb, 0x3e, 0xe5, 0x43, 0x54, 0x78, 0x17, 0x6d, 0x00, 0x18, 0x00, 0x61,
0x04, 0xd1, 0x99, 0x66, 0x4f, 0xda, 0xc7, 0x12, 0x3b, 0xff, 0xb2, 0xd6,
0x2f, 0x35, 0xb6, 0x17, 0x1f, 0xb3, 0xd0, 0xb6, 0x52, 0xff, 0x97, 0x8b,
0x01, 0xe8, 0xd9, 0x68, 0x71, 0x40, 0x02, 0xd5, 0x68, 0x3a, 0x58, 0xb2,
0x5d, 0xee, 0xa4, 0xe9, 0x5f, 0xf4, 0xaf, 0x3e, 0x30, 0x9c, 0x3e, 0x2b,
0xda, 0x61, 0x43, 0x99, 0x02, 0x35, 0x33, 0x9f, 0xcf, 0xb5, 0xd3, 0x28,
0x19, 0x9d, 0x1c, 0xbe, 0x69, 0x07, 0x9e, 0xfc, 0xe4, 0x8e, 0xcd, 0x86,
0x4a, 0x1b, 0xf0, 0xfc, 0x17, 0x94, 0x66, 0x53, 0xda, 0x24, 0x5e, 0xaf,
0xce, 0xec, 0x62, 0x4c, 0x06, 0xb4, 0x52, 0x94, 0xb1, 0x4a, 0x7a, 0x8c,
0x4f, 0x00, 0x19, 0x00, 0x85, 0x04, 0x00, 0x27, 0xeb, 0x99, 0x49, 0x7f,
0xcb, 0x2c, 0x46, 0x54, 0x2d, 0x93, 0x5d, 0x25, 0x92, 0x58, 0x5e, 0x06,
0xc3, 0x7c, 0xfb, 0x9a, 0xa7, 0xec, 0xcd, 0x9f, 0xe1, 0x6b, 0x2d, 0x78,
0xf5, 0x16, 0xa9, 0x20, 0x52, 0x48, 0x19, 0x0f, 0x1a, 0xd0, 0xce, 0xd8,
0x68, 0xb1, 0x4e, 0x7f, 0x33, 0x03, 0x7d, 0x0c, 0x39, 0xdb, 0x9c, 0x4b,
0xf4, 0xe7, 0xc2, 0xf5, 0xdd, 0x51, 0x9b, 0x03, 0xa8, 0x53, 0x2b, 0xe6,
0x00, 0x15, 0x4b, 0xff, 0xd2, 0xa0, 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00,
0x00, 0x00, 0x01, 0x9c, 0x00, 0x00, 0xce, 0x58, 0x30, 0x10, 0x3d, 0x46,
0xcc, 0xca, 0x1a, 0x44, 0xc8, 0x58, 0x9b, 0x27, 0x17, 0x67, 0x31, 0x96,
0x8a, 0x66, 0x39, 0xf4, 0xcc, 0xc1, 0x9f, 0x12, 0x1f, 0x01, 0x30, 0x50,
0x16, 0xd6, 0x89, 0x97, 0xa3, 0x66, 0xd7, 0x99, 0x50, 0x09, 0x6e, 0x80,
0x87, 0xe4, 0xa2, 0x88, 0xae, 0xb4, 0x23, 0x57, 0x2f, 0x12, 0x60, 0xe7,
0x7d, 0x44, 0x2d, 0xad, 0xbe, 0xe9, 0x0d, 0x01, 0x00, 0x01, 0x00, 0xd5,
0xdd, 0x62, 0xee, 0xf3, 0x0e, 0xd9, 0x30, 0x0e, 0x38, 0xf3, 0x48, 0xf4,
0xc9, 0x8f, 0x8c, 0x20, 0xf7, 0xd3, 0xa8, 0xb3, 0x87, 0x3c, 0x98, 0x5d,
0x70, 0xc5, 0x03, 0x76, 0xb7, 0xd5, 0x0b, 0x7b, 0x23, 0x97, 0x6b, 0xe3,
0xb5, 0x18, 0xeb, 0x64, 0x55, 0x18, 0xb2, 0x8a, 0x90, 0x1a, 0x8f, 0x0e,
0x15, 0xda, 0xb1, 0x8e, 0x7f, 0xee, 0x1f, 0xe0, 0x3b, 0xb9, 0xed, 0xfc,
0x4e, 0x3f, 0x78, 0x16, 0x39, 0x95, 0x5f, 0xb7, 0xcb, 0x65, 0x55, 0x72,
0x7b, 0x7d, 0x86, 0x2f, 0x8a, 0xe5, 0xee, 0xf7, 0x57, 0x40, 0xf3, 0xc4,
0x96, 0x4f, 0x11, 0x4d, 0x85, 0xf9, 0x56, 0xfa, 0x3d, 0xf0, 0xc9, 0xa4,
0xec, 0x1e, 0xaa, 0x47, 0x90, 0x53, 0xdf, 0xe1, 0xb7, 0x78, 0x18, 0xeb,
0xdd, 0x0d, 0x89, 0xb7, 0xf6, 0x15, 0x0e, 0x55, 0x12, 0xb3, 0x23, 0x17,
0x0b, 0x59, 0x6f, 0x83, 0x05, 0x6b, 0xa6, 0xf8, 0x6c, 0x3a, 0x9b, 0x1b,
0x50, 0x93, 0x51, 0xea, 0x95, 0x2d, 0x99, 0x96, 0x38, 0x16, 0xfe, 0xfd,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x7e, 0x01, 0x00,
0x02, 0xdc, 0x00, 0x00, 0x00, 0x02, 0x6a, 0x00, 0x00, 0x72, 0x2d, 0x66,
0x3e, 0xf2, 0x36, 0x5a, 0xf2, 0x23, 0x8f, 0x28, 0x09, 0xa9, 0x55, 0x8c,
0x8f, 0xc0, 0x0d, 0x61, 0x98, 0x33, 0x56, 0x87, 0x7a, 0xfd, 0xa7, 0x50,
0x71, 0x84, 0x2e, 0x41, 0x58, 0x00, 0x87, 0xd9, 0x27, 0xe5, 0x7b, 0xf4,
0x6d, 0x84, 0x4e, 0x2e, 0x0c, 0x80, 0x0c, 0xf3, 0x8a, 0x02, 0x4b, 0x99,
0x3a, 0x1f, 0x9f, 0x18, 0x7d, 0x1c, 0xec, 0xad, 0x60, 0x54, 0xa6, 0xa3,
0x2c, 0x82, 0x5e, 0xf8, 0x8f, 0xae, 0xe1, 0xc4, 0x82, 0x7e, 0x43, 0x43,
0xc5, 0x99, 0x49, 0x05, 0xd3, 0xf6, 0xdf, 0xa1, 0xb5, 0x2d, 0x0c, 0x13,
0x2f, 0x1e, 0xb6, 0x28, 0x7c, 0x5c, 0xa1, 0x02, 0x6b, 0x8d, 0xa3, 0xeb,
0xd4, 0x58, 0xe6, 0xa0, 0x7e, 0x6b, 0xaa, 0x09, 0x43, 0x67, 0x71, 0x87,
0xa5, 0xcb, 0x68, 0xf3
};
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
/* Fragment msgs */
ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, DUMMY_MTU), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_s, DUMMY_MTU), WOLFSSL_SUCCESS);
/* Add in some key shares to make the CH long */
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP256R1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP384R1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP521R1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_2048), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS);
/* Reject fragmented first CH */
ExpectIntEQ(test_dtls_frag_ch_count_records(four_frag_CH,
sizeof(four_frag_CH)), 4);
XMEMCPY(test_ctx.s_buff, four_frag_CH, sizeof(four_frag_CH));
test_ctx.s_len = sizeof(four_frag_CH);
while (test_ctx.s_len > 0 && EXPECT_SUCCESS()) {
int s_len = test_ctx.s_len;
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* Fail if we didn't advance the buffer to avoid infinite loops */
ExpectIntLT(test_ctx.s_len, s_len);
}
/* Expect all fragments read */
ExpectIntEQ(test_ctx.s_len, 0);
/* Expect quietly dropping fragmented first CH */
ExpectIntEQ(test_ctx.c_len, 0);
/* CH1 */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Count records. Expect 1 unfragmented CH */
ExpectIntEQ(test_dtls_frag_ch_count_records(test_ctx.s_buff,
test_ctx.s_len), 1);
/* HRR */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* CH2 */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Count records. Expect fragmented CH */
ExpectIntGT(test_dtls_frag_ch_count_records(test_ctx.s_buff,
test_ctx.s_len), 1);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
#endif
return EXPECT_RESULT();
}
static int test_dtls_empty_keyshare_with_cookie(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
unsigned char ch_empty_keyshare_with_cookie[] = {
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x12, 0x01, 0x00, 0x01, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
0x06, 0xfe, 0xfd, 0xfb, 0x8c, 0x9b, 0x28, 0xae, 0x50, 0x1c, 0x4d, 0xf3,
0xb8, 0xcf, 0x4d, 0xd8, 0x7e, 0x93, 0x13, 0x7b, 0x9e, 0xd9, 0xeb, 0xe9,
0x13, 0x4b, 0x0d, 0x7f, 0x2e, 0x43, 0x62, 0x8c, 0xe4, 0x57, 0x79, 0x00,
0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0,
0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc,
0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0,
0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00,
0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x00,
0xa6, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x2c, 0x00, 0x47,
0x00, 0x45, 0x20, 0xee, 0x4b, 0x17, 0x70, 0x63, 0xa0, 0x4c, 0x82, 0xbf,
0x43, 0x01, 0x7d, 0x8d, 0xc1, 0x1b, 0x4e, 0x9b, 0xa0, 0x3c, 0x53, 0x1f,
0xb7, 0xd1, 0x10, 0x81, 0xa8, 0xdf, 0xdf, 0x8c, 0x7f, 0xf3, 0x11, 0x13,
0x01, 0x02, 0x3d, 0x3b, 0x7d, 0x14, 0x2c, 0x31, 0xb3, 0x60, 0x72, 0x4d,
0xe5, 0x1a, 0xb2, 0xa3, 0x61, 0x77, 0x73, 0x03, 0x40, 0x0e, 0x5f, 0xc5,
0x61, 0x38, 0x43, 0x56, 0x21, 0x4a, 0x95, 0xd5, 0x35, 0xa8, 0x0d, 0x00,
0x0d, 0x00, 0x2a, 0x00, 0x28, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02,
0x03, 0xfe, 0x0b, 0xfe, 0x0e, 0xfe, 0xa0, 0xfe, 0xa3, 0xfe, 0xa5, 0x08,
0x06, 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06,
0x01, 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00,
0x18, 0x00, 0x16, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01,
0x00, 0x02, 0x3a, 0x02, 0x3c, 0x02, 0x3d, 0x2f, 0x3a, 0x2f, 0x3c, 0x2f,
0x3d, 0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x00
};
DtlsRecordLayerHeader* dtlsRH;
byte sequence_number[8];
XMEMSET(&sequence_number, 0, sizeof(sequence_number));
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMCPY(test_ctx.s_buff, ch_empty_keyshare_with_cookie,
sizeof(ch_empty_keyshare_with_cookie));
test_ctx.s_len = sizeof(ch_empty_keyshare_with_cookie);
ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s,
NULL, wolfDTLSv1_3_server_method), 0);
/* CH1 */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* Expect an alert. A plaintext alert should be exactly 15 bytes. */
ExpectIntEQ(test_ctx.c_len, 15);
dtlsRH = (DtlsRecordLayerHeader*)test_ctx.c_buff;
ExpectIntEQ(dtlsRH->type, alert);
ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR);
ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR);
sequence_number[7] = 1;
ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number,
sizeof(sequence_number)), 0);
ExpectIntEQ(dtlsRH->length[0], 0);
ExpectIntEQ(dtlsRH->length[1], 2);
ExpectIntEQ(test_ctx.c_buff[13], alert_fatal);
ExpectIntEQ(test_ctx.c_buff[14], illegal_parameter);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/*----------------------------------------------------------------------------*
| Main
*----------------------------------------------------------------------------*/
@ -66507,6 +66737,8 @@ TEST_CASE testCases[] = {
TEST_DECL(test_dtls_dropped_ccs),
TEST_DECL(test_certreq_sighash_algos),
TEST_DECL(test_revoked_loaded_int_cert),
TEST_DECL(test_dtls_frag_ch),
TEST_DECL(test_dtls_empty_keyshare_with_cookie),
/* This test needs to stay at the end to clean up any caches allocated. */
TEST_DECL(test_wolfSSL_Cleanup)
};

View File

@ -3353,8 +3353,10 @@ typedef struct KeyShareEntry {
struct KeyShareEntry* next; /* List pointer */
} KeyShareEntry;
WOLFSSL_LOCAL void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap);
WOLFSSL_LOCAL int TLSX_KeyShare_Use(const WOLFSSL* ssl, word16 group,
word16 len, byte* data, KeyShareEntry **kse, TLSX** extensions);
WOLFSSL_LOCAL int TLSX_KeyShare_SelectGroup(WOLFSSL* ssl, word16 group);
WOLFSSL_LOCAL int TLSX_KeyShare_Empty(WOLFSSL* ssl);
WOLFSSL_LOCAL int TLSX_KeyShare_SetSupported(const WOLFSSL* ssl,
TLSX** extensions);
@ -4616,7 +4618,12 @@ struct Options {
word16 tls1_3:1; /* using TLSv1.3+ ? */
word16 seenUnifiedHdr:1; /* received msg with unified header */
word16 dtls:1; /* using datagrams ? */
#ifdef WOLFSSL_DTLS
word16 dtlsStateful:1; /* allow stateful processing ? */
#endif
#ifdef WOLFSSL_DTLS_CH_FRAG
word16 dtlsSentEmptyKS:1; /* did we send an empty key share ? */
#endif
word16 connReset:1; /* has the peer reset */
word16 isClosed:1; /* if we consider conn closed */
word16 closeNotify:1; /* we've received a close notify */
@ -4727,6 +4734,9 @@ struct Options {
#ifdef WOLFSSL_DTLS13
word16 dtls13SendMoreAcks:1; /* Send more acks during the
* handshake process */
#ifdef WOLFSSL_DTLS_CH_FRAG
word16 dtls13ChFrag:1;
#endif
#endif
#ifdef WOLFSSL_TLS13
word16 tls13MiddleBoxCompat:1; /* TLSv1.3 middlebox compatibility */
@ -5417,7 +5427,7 @@ struct WOLFSSL {
#endif
#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER)
ClientHelloGoodCb chGoodCb; /* notify user we parsed a verified
* ClientHello */
* ClientHello that passed basic tests */
void* chGoodCtx; /* user ClientHello cb context */
#endif
#ifndef NO_HANDSHAKE_DONE_CB
@ -5611,6 +5621,9 @@ struct WOLFSSL {
Dtls13Rtx dtls13Rtx;
byte *dtls13ClientHello;
word16 dtls13ClientHelloSz;
#ifdef WOLFSSL_DTLS_CH_FRAG
KeyShareEntry* dtls13KSE;
#endif
#endif /* WOLFSSL_DTLS13 */
#ifdef WOLFSSL_DTLS_CID
@ -6268,7 +6281,7 @@ WOLFSSL_LOCAL int cipherExtraData(WOLFSSL* ssl);
#if !defined(NO_WOLFSSL_SERVER)
WOLFSSL_LOCAL int DoClientHelloStateless(WOLFSSL* ssl,
const byte* input, word32* inOutIdx, word32 helloSz);
const byte* input, word32 helloSz, byte isFirstCHFrag);
#endif /* !defined(NO_WOLFSSL_SERVER) */
#endif /* WOLFSSL_DTLS */

View File

@ -5218,6 +5218,10 @@ WOLFSSL_API int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer,
unsigned int bufferSz);
#endif /* defined(WOLFSSL_DTLS_CID) */
#ifdef WOLFSSL_DTLS_CH_FRAG
WOLFSSL_API int wolfSSL_dtls13_allow_ch_frag(WOLFSSL *ssl, int enabled);
#endif
/* */
#define SSL2_VERSION 0x0002
#define SSL3_VERSION 0x0300

View File

@ -3014,6 +3014,14 @@ extern void uITRON4_free(void *p) ;
#error Please do not define both HAVE_LIBOQS and HAVE_PQM4.
#endif
#if defined(HAVE_PQC) && defined(WOLFSSL_DTLS13) && \
!defined(WOLFSSL_DTLS_CH_FRAG)
#warning "Using DTLS 1.3 + pqc without WOLFSSL_DTLS_CH_FRAG will probably fail. Use --enable-dtls-frag-ch to enable it."
#endif
#if !defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CH_FRAG)
#error "WOLFSSL_DTLS_CH_FRAG only works with DTLS 1.3"
#endif
/* SRTP requires DTLS */
#if defined(WOLFSSL_SRTP) && !defined(WOLFSSL_DTLS)
#error The SRTP extension requires DTLS