Merge pull request #6748 from julek-wolfssl/dtls13-frag-ch2

DTLS 1.3: allow fragmenting the second ClientHello message
This commit is contained in:
JacobBarthelmeh
2023-10-11 11:13:57 -06:00
committed by GitHub
16 changed files with 671 additions and 158 deletions

View File

@ -4,15 +4,16 @@ on:
workflow_call:
jobs:
build:
build-and-test:
runs-on: ubuntu-latest
# This should be a safe limit for the tests to run.
timeout-minutes: 14
timeout-minutes: 25
steps:
- name: Install test dependencies
run: |
sudo apt-get update
sudo apt-get install nghttp2
sudo pip install impacket
- name: Build wolfSSL
uses: wolfSSL/actions-build-autotools-project@v1
@ -21,10 +22,14 @@ jobs:
configure: --enable-curl
install: true
- name: Build and test curl
- name: Build curl
uses: wolfSSL/actions-build-autotools-project@v1
with:
repository: curl/curl
path: curl
configure: --with-wolfssl=$GITHUB_WORKSPACE/build-dir
check: true
check: false
- name: Test curl
working-directory: curl
run: make -j test-ci

View File

@ -1,11 +1,12 @@
#!/bin/sh
runCMD() { # usage: runCMD "<command>" "<retVal>"
eval $1 >/dev/null 2>&1
TMP_FILE=$(mktemp)
eval $1 > $TMP_FILE 2>&1
RETVAL=$?
if [ "$RETVAL" != "$2" ]; then
echo "Command ($1) returned ${RETVAL}, but expected $2. Rerunning with output to terminal:"
eval $1
echo "Command ($1) returned ${RETVAL}, but expected $2. Error output:"
cat $TMP_FILE
exit 1
fi
}
@ -16,11 +17,11 @@ runCMD "ldd /lib/libustream-ssl.so" 0
# Remove after fixed upstream.
runCMD "sed '\/src\/gz openwrt_kmods https:\/\/downloads.openwrt.org\/releases\/21.02-SNAPSHOT\/targets\/x86\/64\/kmods\/5.4.238-1-5a722da41bc36de95a7195be6fce1b45/s//#&/' -i /etc/opkg/distfeeds.conf" 0
runCMD "opkg update" 0
runCMD "uclient-fetch -O /dev/null 'https://letsencrypt.org'" 0
runCMD "uclient-fetch 'https://letsencrypt.org'" 0
# Negative tests
runCMD "uclient-fetch --ca-certificate=/dev/null -O /dev/null 'https://letsencrypt.org'" 5
runCMD "uclient-fetch -O /dev/null 'https://self-signed.badssl.com/'" 5
runCMD "uclient-fetch -O /dev/null 'https://untrusted-root.badssl.com/'" 5
runCMD "uclient-fetch -O /dev/null 'https://expired.badssl.com/'" 5
runCMD "uclient-fetch --ca-certificate=/dev/null 'https://letsencrypt.org'" 5
runCMD "uclient-fetch 'https://self-signed.badssl.com/'" 5
runCMD "uclient-fetch 'https://untrusted-root.badssl.com/'" 5
runCMD "uclient-fetch 'https://expired.badssl.com/'" 5
echo "All tests passed."

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/unverified (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
idx = helloSz;
/* Allow incomplete extensions if we are parsing a fragment */
if (isFirstCHFrag && extStart < helloSz)
ch->extension.size = helloSz - extStart;
else
#endif
return BUFFER_ERROR;
}
}
if (idx != helloSz)
return BUFFER_ERROR;
@ -860,17 +881,30 @@ 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, byte* tls13)
{
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.");
return BAD_STATE_E;
#endif
}
if (tls13 != NULL)
*tls13 = 0;
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;
@ -879,6 +913,8 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
ret = TlsCheckSupportedVersion(ssl, &ch, &isTls13);
if (ret != 0)
return ret;
if (tls13 != NULL)
*tls13 = isTls13;
if (isTls13) {
int tlsxFound;
ret = FindExtByType(&ch.cookieExt, TLSX_COOKIE, ch.extension,
@ -894,7 +930,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 +943,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 = COOKIE_ERROR;
else
#endif
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13);
}
else {
byte cookieGood;
@ -921,11 +963,25 @@ 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 = COOKIE_ERROR;
else
#endif
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13);
}
else
else {
ssl->options.dtlsStateful = 1;
/* Update the window now that we enter the stateful parsing */
#ifdef WOLFSSL_DTLS13
if (isTls13)
ret = Dtls13UpdateWindowRecordRecvd(ssl);
else
#endif
DtlsUpdateWindow(ssl);
}
}
return ret;

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,35 @@ 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
byte tls13 = 0;
/* 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, &tls13)
== 0 && tls13) {
/* We can save this message and continue as stateful. */
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;
}
}
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;
@ -2369,7 +2404,11 @@ static int Dtls13WriteAckMessage(WOLFSSL* ssl,
c16toa(msgSz, ackMessage);
ackMessage += OPAQUE16_LEN;
WOLFSSL_MSG("write ack records");
while (recordNumberList != NULL) {
WOLFSSL_MSG_EX("epoch %d seq %d", recordNumberList->epoch,
recordNumberList->seq);
c64toa(&recordNumberList->epoch, ackMessage);
ackMessage += OPAQUE64_LEN;
c64toa(&recordNumberList->seq, ackMessage);
@ -2561,10 +2600,13 @@ int DoDtls13Ack(WOLFSSL* ssl, const byte* input, word32 inputSize,
if (length % (DTLS13_RN_SIZE) != 0)
return PARSE_ERROR;
WOLFSSL_MSG("read ack records");
ackMessage = input + OPAQUE16_LEN;
for (i = 0; i < length; i += DTLS13_RN_SIZE) {
ato64(ackMessage + i, &epoch);
ato64(ackMessage + i + OPAQUE64_LEN, &seq);
WOLFSSL_MSG_EX("epoch %d seq %d", epoch, seq);
Dtls13RtxRemoveRecord(ssl, epoch, seq);
}
@ -2635,14 +2677,13 @@ int SendDtls13Ack(WOLFSSL* ssl)
if (ret != 0)
return ret;
ret = Dtls13WriteAckMessage(ssl, ssl->dtls13Rtx.seenRecords, &length);
if (ret != 0)
return ret;
output = GetOutputBuffer(ssl);
if (w64IsZero(ssl->dtls13EncryptEpoch->epochNumber)) {
ret = Dtls13WriteAckMessage(ssl, ssl->dtls13Rtx.seenRecords, &length);
if (ret != 0)
return ret;
output = GetOutputBuffer(ssl);
ret = Dtls13RlAddPlaintextHeader(ssl, output, ack, (word16)length);
if (ret != 0)
return ret;
@ -2650,13 +2691,6 @@ int SendDtls13Ack(WOLFSSL* ssl)
ssl->buffers.outputBuffer.length += length + DTLS_RECORD_HEADER_SZ;
}
else {
ret = Dtls13WriteAckMessage(ssl, ssl->dtls13Rtx.seenRecords, &length);
if (ret != 0)
return ret;
output = GetOutputBuffer(ssl);
outputSize = ssl->buffers.outputBuffer.bufferSize -
ssl->buffers.outputBuffer.idx -
ssl->buffers.outputBuffer.length;
@ -2797,4 +2831,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

@ -215,7 +215,6 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS
#ifdef WOLFSSL_DTLS
static int _DtlsCheckWindow(WOLFSSL* ssl);
static int _DtlsUpdateWindow(WOLFSSL* ssl);
#endif
#ifdef WOLFSSL_DTLS13
@ -16806,6 +16805,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;
@ -16973,7 +16974,7 @@ int wolfSSL_DtlsUpdateWindow(word16 cur_hi, word32 cur_lo,
return 1;
}
static int _DtlsUpdateWindow(WOLFSSL* ssl)
int DtlsUpdateWindow(WOLFSSL* ssl)
{
WOLFSSL_DTLS_PEERSEQ* peerSeq = ssl->keys.peerSeq;
word16 *next_hi;
@ -17039,7 +17040,13 @@ static int _DtlsUpdateWindow(WOLFSSL* ssl)
}
#ifdef WOLFSSL_DTLS13
static WC_INLINE int Dtls13UpdateWindow(WOLFSSL* ssl)
/* Update DTLS 1.3 window
* Return
* 0 on successful update
* <0 on error
*/
static int Dtls13UpdateWindow(WOLFSSL* ssl)
{
w64wrapper nextSeq, seq;
w64wrapper diff64;
@ -17047,14 +17054,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 +17094,7 @@ static WC_INLINE int Dtls13UpdateWindow(WOLFSSL* ssl)
}
window[wordIndex] |= (1 << wordOffset);
return 1;
return 0;
}
/* seq >= nextSeq, seq - nextSeq */
@ -17086,9 +17105,17 @@ static WC_INLINE int Dtls13UpdateWindow(WOLFSSL* ssl)
_DtlsUpdateWindowGTSeq(w64GetLow32(diff64), window);
w64Increment(&seq);
ssl->dtls13DecryptEpoch->nextPeerSeqNumber = seq;
e->nextPeerSeqNumber = seq;
return 1;
return 0;
}
int Dtls13UpdateWindowRecordRecvd(WOLFSSL* ssl)
{
int ret = Dtls13UpdateWindow(ssl);
if (ret != 0)
return ret;
return Dtls13RecordRecvd(ssl);
}
#endif /* WOLFSSL_DTLS13 */
@ -20714,31 +20741,32 @@ default:
/* the record layer is here */
case runProcessingOneRecord:
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
if (ssl->options.dtls) {
if (IsAtLeastTLSv1_3(ssl->version)) {
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;
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;
}
continue;
/* Only update the window once we enter stateful parsing */
if (ssl->options.dtlsStateful) {
ret = Dtls13UpdateWindowRecordRecvd(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
}
}
}
ret = Dtls13UpdateWindow(ssl);
if (ret != 1) {
WOLFSSL_ERROR(ret);
return ret;
}
ret = Dtls13RecordRecvd(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
return ret;
else if (IsDtlsNotSctpMode(ssl)) {
DtlsUpdateWindow(ssl);
}
}
#endif /* WOLFSSL_DTLS13 */
@ -20773,16 +20801,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 +20821,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 +20830,21 @@ 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 || ret == WC_PENDING_E) {
/* Reset timeout as we have received a valid
* DTLS handshake message */
ssl->dtls_timeout = ssl->dtls_timeout_init;
}
else {
if (SendFatalAlertOnly(ssl, ret)
== SOCKET_ERROR_E) {
ret = SOCKET_ERROR_E;
}
}
}
#endif
#ifdef WOLFSSL_DTLS13
@ -34214,8 +34236,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 +34745,11 @@ 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,
NULL);
if (ret != 0 || !ssl->options.dtlsStateful) {
int alertType = TranslateErrorToAlert(ret);
if (alertType != invalid_alert) {
@ -34735,6 +34766,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,9 @@ 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
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
ssl->options.noPskDheKe = 0;
#ifdef HAVE_SUPPORTED_CURVES

View File

@ -8722,7 +8722,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;
@ -8802,12 +8802,7 @@ int TLSX_KeyShare_Parse(WOLFSSL* ssl, const byte* input, word16 length,
return ret;
}
#ifdef HAVE_PQC
/* For post-quantum groups, do this in TLSX_PopulateExtensions(). */
if (!WOLFSSL_NAMED_GROUP_IS_PQC(group))
#endif
ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL, &ssl->extensions);
ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL, &ssl->extensions);
if (ret == 0)
ssl->session->namedGroup = ssl->namedGroup = group;
}
@ -9632,6 +9627,7 @@ int TLSX_KeyShare_Setup(WOLFSSL *ssl, KeyShareEntry* clientKSE)
serverKSE->keLen = clientKSE->keLen;
clientKSE->ke = NULL;
clientKSE->keLen = 0;
ssl->namedGroup = serverKSE->group;
TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap);
extension->data = (void *)serverKSE;
@ -12968,19 +12964,8 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
namedGroup = kse->group;
}
if (namedGroup != WOLFSSL_NAMED_GROUP_INVALID) {
#ifdef HAVE_PQC
/* For KEMs, the key share has already been generated, but not
* if we are resuming. */
if (!WOLFSSL_NAMED_GROUP_IS_PQC(namedGroup)
#ifdef HAVE_SESSION_TICKET
|| ssl->options.resuming
#endif /* HAVE_SESSION_TICKET */
)
#endif /* HAVE_PQC */
{
ret = TLSX_KeyShare_Use(ssl, namedGroup, 0, NULL, NULL,
&ssl->extensions);
}
ret = TLSX_KeyShare_Use(ssl, namedGroup, 0, NULL, NULL,
&ssl->extensions);
if (ret != 0)
return ret;
}

View File

@ -4410,10 +4410,37 @@ 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 */
ret = TLSX_KeyShare_Empty(ssl);
if (ret != 0)
return ret;
args->length = lenWithoutExts;
ret = TLSX_GetRequestSize(ssl, client_hello, &args->length);
if (ret != 0)
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");
}
#endif
}
/* Total message size. */
args->sendSz = args->length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
@ -6624,12 +6651,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, NULL);
if (ret != 0 || !ssl->options.dtlsStateful) {
*inOutIdx += helloSz;
goto exit_dch;
}
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 */
@ -13223,17 +13259,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

@ -34625,6 +34625,7 @@ static void keyLog_callback(const WOLFSSL* ssl, const char* line )
fp = XFOPEN("./MyKeyLog.txt", "a");
XFWRITE( line, 1, strlen(line),fp);
XFWRITE( (void*)&lf,1,1,fp);
XFFLUSH(fp);
XFCLOSE(fp);
}
@ -65238,6 +65239,317 @@ static int test_revoked_loaded_int_cert(void)
return EXPECT_RESULT();
}
static int test_dtls13_frag_ch_pq(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
&& defined(WOLFSSL_DTLS_CH_FRAG) && defined(HAVE_LIBOQS)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
const char *test_str = "test";
int test_str_size;
byte buf[255];
int group = WOLFSSL_KYBER_LEVEL5;
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);
/* Add in a large post-quantum key share to make the CH long. */
ExpectIntEQ(wolfSSL_set_groups(ssl_c, &group, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, group), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectStrEQ(wolfSSL_get_curve_name(ssl_c), "KYBER_LEVEL5");
ExpectStrEQ(wolfSSL_get_curve_name(ssl_s), "KYBER_LEVEL5");
test_str_size = XSTRLEN("test") + 1;
ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size);
ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), test_str_size);
ExpectIntEQ(XSTRCMP((char*)buf, test_str), 0);
ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
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();
}
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(HAVE_LIBOQS)
static void test_tls13_pq_groups_ctx_ready(WOLFSSL_CTX* ctx)
{
int group = WOLFSSL_KYBER_LEVEL5;
AssertIntEQ(wolfSSL_CTX_set_groups(ctx, &group, 1), WOLFSSL_SUCCESS);
}
static void test_tls13_pq_groups_on_result(WOLFSSL* ssl)
{
AssertStrEQ(wolfSSL_get_curve_name(ssl), "KYBER_LEVEL5");
}
#endif
static int test_tls13_pq_groups(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(HAVE_LIBOQS)
callback_functions func_cb_client;
callback_functions func_cb_server;
XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
XMEMSET(&func_cb_server, 0, sizeof(callback_functions));
func_cb_client.method = wolfTLSv1_3_client_method;
func_cb_server.method = wolfTLSv1_3_server_method;
func_cb_client.ctx_ready = test_tls13_pq_groups_ctx_ready;
func_cb_client.on_result = test_tls13_pq_groups_on_result;
func_cb_server.on_result = test_tls13_pq_groups_on_result;
test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);
ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS);
ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
/*----------------------------------------------------------------------------*
| Main
*----------------------------------------------------------------------------*/
@ -66507,6 +66819,10 @@ 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_dtls13_frag_ch_pq),
TEST_DECL(test_dtls_empty_keyshare_with_cookie),
TEST_DECL(test_tls13_pq_groups),
/* This test needs to stay at the end to clean up any caches allocated. */
TEST_DECL(test_wolfSSL_Cleanup)
};

View File

@ -174,7 +174,7 @@
if (_ret != TEST_FAIL) { \
const char* _x = (const char*)(x); \
const char* _y = (const char*)(y); \
int _z = (_x && _y) ? strcmp(_x, _y) : -1; \
int _z = (_x && _y) ? XSTRCMP(_x, _y) : -1; \
Expect(_z op 0, ("%s " #op " %s", #x, #y), \
("\"%s\" " #er " \"%s\"", _x, _y));\
} \

View File

@ -170,6 +170,15 @@ static WC_INLINE int test_memio_write_cb(WOLFSSL *ssl, char *data, int sz,
if ((unsigned)(*len + sz) > TEST_MEMIO_BUF_SZ)
return WOLFSSL_CBIO_ERR_WANT_WRITE;
#ifdef WOLFSSL_DUMP_MEMIO_STREAM
{
WOLFSSL_BIO *dump_file = wolfSSL_BIO_new_file("test_memio.dump", "a");
if (dump_file != NULL) {
(void)wolfSSL_BIO_write(dump_file, data, sz);
wolfSSL_BIO_free(dump_file);
}
}
#endif
XMEMCPY(buf + *len, data, sz);
*len += sz;

View File

@ -4616,7 +4616,9 @@ 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
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 +4729,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 */
@ -5416,13 +5421,13 @@ struct WOLFSSL {
WOLFSSL_HEAP_HINT heap_hint;
#endif
#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER)
ClientHelloGoodCb chGoodCb; /* notify user we parsed a verified
* ClientHello */
void* chGoodCtx; /* user ClientHello cb context */
ClientHelloGoodCb chGoodCb; /* notify user we parsed a verified
* ClientHello that passed basic tests */
void* chGoodCtx; /* user ClientHello cb context */
#endif
#ifndef NO_HANDSHAKE_DONE_CB
HandShakeDoneCb hsDoneCb; /* notify user handshake done */
void* hsDoneCtx; /* user handshake cb context */
HandShakeDoneCb hsDoneCb; /* notify user handshake done */
void* hsDoneCtx; /* user handshake cb context */
#endif
#ifdef WOLFSSL_ASYNC_IO
#ifdef WOLFSSL_ASYNC_CRYPT
@ -6268,7 +6273,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, byte* tls13);
#endif /* !defined(NO_WOLFSSL_SERVER) */
#endif /* WOLFSSL_DTLS */
@ -6474,6 +6479,7 @@ WOLFSSL_LOCAL word32 nid2oid(int nid, int grp);
#ifdef WOLFSSL_DTLS
WOLFSSL_API int wolfSSL_DtlsUpdateWindow(word16 cur_hi, word32 cur_lo,
word16* next_hi, word32* next_lo, word32 *window);
WOLFSSL_LOCAL int DtlsUpdateWindow(WOLFSSL* ssl);
WOLFSSL_LOCAL void DtlsResetState(WOLFSSL *ssl);
WOLFSSL_LOCAL int DtlsIgnoreError(int err);
WOLFSSL_LOCAL void DtlsSetSeqNumForReply(WOLFSSL* ssl);
@ -6542,6 +6548,7 @@ WOLFSSL_LOCAL void Dtls13RtxFlushBuffered(WOLFSSL* ssl,
WOLFSSL_LOCAL int Dtls13RtxTimeout(WOLFSSL* ssl);
WOLFSSL_LOCAL int Dtls13ProcessBufferedMessages(WOLFSSL* ssl);
WOLFSSL_LOCAL int Dtls13CheckAEADFailLimit(WOLFSSL* ssl);
WOLFSSL_LOCAL int Dtls13UpdateWindowRecordRecvd(WOLFSSL* ssl);
#endif /* WOLFSSL_DTLS13 */
#ifdef WOLFSSL_STATIC_EPHEMERAL

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,15 @@ 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