diff --git a/src/dtls13.c b/src/dtls13.c index 7eac849de3..3591d67b45 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -363,6 +363,14 @@ int Dtls13ProcessBufferedMessages(WOLFSSL* ssl) if (!msg->ready) break; +#ifndef WOLFSSL_DISABLE_EARLY_SANITY_CHECKS + ret = MsgCheckEncryption(ssl, msg->type, msg->encrypted); + if (ret != 0) { + SendAlert(ssl, alert_fatal, unexpected_message); + break; + } +#endif + /* We may have DTLS <=1.2 msgs stored from before we knew which version * we were going to use. Interpret correctly. */ if (IsAtLeastTLSv1_3(ssl->version)) { @@ -1622,6 +1630,13 @@ static int _Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32 size, if (ret != 0) return PARSE_ERROR; + /* Need idx + fragLength as we don't advance the inputBuffer idx value */ + ret = EarlySanityCheckMsgReceived(ssl, handshakeType, idx + fragLength); + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.acceptState < TLS13_ACCEPT_FIRST_REPLY_DONE) { if (handshakeType != client_hello) { diff --git a/src/internal.c b/src/internal.c index fec764be5f..60d221f740 100644 --- a/src/internal.c +++ b/src/internal.c @@ -547,7 +547,7 @@ int IsAtLeastTLSv1_3(const ProtocolVersion pv) return ret; } -int IsEncryptionOn(WOLFSSL* ssl, int isSend) +int IsEncryptionOn(const WOLFSSL* ssl, int isSend) { #ifdef WOLFSSL_DTLS /* For DTLS, epoch 0 is always not encrypted. */ @@ -4688,7 +4688,7 @@ static void SetDigest(WOLFSSL* ssl, int hashAlgo) #endif /* !NO_CERTS */ #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) -static word32 MacSize(WOLFSSL* ssl) +static word32 MacSize(const WOLFSSL* ssl) { #ifdef HAVE_TRUNCATED_HMAC word32 digestSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ @@ -8972,7 +8972,8 @@ static void DtlsMsgAssembleCompleteMessage(DtlsMsg* msg) } int DtlsMsgSet(DtlsMsg* msg, word32 seq, word16 epoch, const byte* data, byte type, - word32 fragOffset, word32 fragSz, void* heap, word32 totalLen) + word32 fragOffset, word32 fragSz, void* heap, word32 totalLen, + byte encrypted) { word32 fragOffsetEnd = fragOffset + fragSz; @@ -8993,11 +8994,13 @@ int DtlsMsgSet(DtlsMsg* msg, word32 seq, word16 epoch, const byte* data, byte ty WOLFSSL_ERROR_VERBOSE(SEQUENCE_ERROR); return SEQUENCE_ERROR; } + msg->encrypted = msg->encrypted && encrypted; } else { msg->type = type; msg->epoch = epoch; msg->seq = seq; + msg->encrypted = encrypted; } if (msg->fragBucketList == NULL) { @@ -9118,6 +9121,7 @@ void DtlsMsgStore(WOLFSSL* ssl, word16 epoch, word32 seq, const byte* data, */ DtlsMsg* head = ssl->dtls_rx_msg_list; + byte encrypted = ssl->keys.decryptedCur == 1; WOLFSSL_ENTER("DtlsMsgStore"); if (head != NULL) { @@ -9126,7 +9130,7 @@ void DtlsMsgStore(WOLFSSL* ssl, word16 epoch, word32 seq, const byte* data, cur = DtlsMsgNew(dataSz, 0, heap); if (cur != NULL) { if (DtlsMsgSet(cur, seq, epoch, data, type, - fragOffset, fragSz, heap, dataSz) < 0) { + fragOffset, fragSz, heap, dataSz, encrypted) < 0) { DtlsMsgDelete(cur, heap); } else { @@ -9138,13 +9142,13 @@ void DtlsMsgStore(WOLFSSL* ssl, word16 epoch, word32 seq, const byte* data, else { /* If this fails, the data is just dropped. */ DtlsMsgSet(cur, seq, epoch, data, type, fragOffset, - fragSz, heap, dataSz); + fragSz, heap, dataSz, encrypted); } } else { head = DtlsMsgNew(dataSz, 0, heap); if (DtlsMsgSet(head, seq, epoch, data, type, fragOffset, - fragSz, heap, dataSz) < 0) { + fragSz, heap, dataSz, encrypted) < 0) { DtlsMsgDelete(head, heap); head = NULL; } @@ -10714,6 +10718,297 @@ int CheckAvailableSize(WOLFSSL *ssl, int size) return 0; } +#ifndef WOLFSSL_DISABLE_EARLY_SANITY_CHECKS + +int MsgCheckEncryption(WOLFSSL* ssl, byte type, byte encrypted) +{ +#ifdef WOLFSSL_QUIC + /* QUIC protects messages outside of the TLS scope */ + if (WOLFSSL_IS_QUIC(ssl) && IsAtLeastTLSv1_3(ssl->version)) + return 0; +#endif + /* Verify which messages always have to be encrypted */ + if (IsAtLeastTLSv1_3(ssl->version)) { + switch ((enum HandShakeType)type) { + case client_hello: + case server_hello: + case hello_verify_request: + case hello_retry_request: + case change_cipher_hs: + if (encrypted) { + WOLFSSL_MSG("Message can not be encrypted"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + break; + case hello_request: + case session_ticket: + case end_of_early_data: + case encrypted_extensions: + case certificate: + case server_key_exchange: + case certificate_request: + case server_hello_done: + case certificate_verify: + case client_key_exchange: + case finished: + case certificate_status: + case key_update: + if (!encrypted) { + WOLFSSL_MSG("Message always has to be encrypted"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + break; + case message_hash: + case no_shake: + default: + WOLFSSL_MSG("Unknown message type"); + WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E); + return SANITY_MSG_E; + } + } + else { + switch ((enum HandShakeType)type) { + case client_hello: + if ((IsSCR(ssl) || ssl->options.handShakeDone) && !encrypted) { + WOLFSSL_MSG("Message has to be encrypted for SCR"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + break; + case server_hello: + case hello_verify_request: + case hello_retry_request: + case certificate: + case server_key_exchange: + case certificate_request: + case server_hello_done: + case certificate_verify: + case client_key_exchange: + case certificate_status: + case session_ticket: + case change_cipher_hs: + if (IsSCR(ssl)) { + if (!encrypted) { + WOLFSSL_MSG("Message has to be encrypted during SCR"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + } + else if (encrypted) { + WOLFSSL_MSG("Message can not be encrypted in regular " + "handshake"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + break; + case hello_request: + case finished: + if (!encrypted) { + WOLFSSL_MSG("Message always has to be encrypted"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + break; + case key_update: + case encrypted_extensions: + case end_of_early_data: + case message_hash: + case no_shake: + default: + WOLFSSL_MSG("Unknown message type"); + WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E); + return SANITY_MSG_E; + } + } + return 0; +} + +static WC_INLINE int isLastMsg(const WOLFSSL* ssl, word32 msgSz) +{ + word32 extra = 0; + if (IsEncryptionOn(ssl, 0)) { + extra = ssl->keys.padSz; +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) + extra += MacSize(ssl); +#endif + } + return (ssl->buffers.inputBuffer.idx - ssl->curStartIdx) + msgSz + extra + == ssl->curSize; +} + +/* Check if the msg is the last msg in a record. This is also an easy way + * to check that a record doesn't span different key boundaries. */ +static int MsgCheckBoundary(const WOLFSSL* ssl, byte type, + byte version_negotiated, word32 msgSz) +{ + if (version_negotiated) { + if (IsAtLeastTLSv1_3(ssl->version)) { + switch ((enum HandShakeType)type) { + case hello_request: + case client_hello: + case server_hello: + case hello_verify_request: + case hello_retry_request: + case finished: + case end_of_early_data: + if (!isLastMsg(ssl, msgSz)) { + WOLFSSL_MSG("Message type is not last in record"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + break; + case session_ticket: + case encrypted_extensions: + case certificate: + case server_key_exchange: + case certificate_request: + case certificate_verify: + case client_key_exchange: + case certificate_status: + case key_update: + case change_cipher_hs: + break; + case server_hello_done: + case message_hash: + case no_shake: + default: + WOLFSSL_MSG("Unknown message type"); + WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E); + return SANITY_MSG_E; + } + } + else { + switch ((enum HandShakeType)type) { + case hello_request: + case client_hello: + case hello_verify_request: + if (!isLastMsg(ssl, msgSz)) { + WOLFSSL_MSG("Message type is not last in record"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + break; + case server_hello: + case session_ticket: + case end_of_early_data: + case certificate: + case server_key_exchange: + case certificate_request: + case server_hello_done: + case certificate_verify: + case client_key_exchange: + case finished: + case certificate_status: + case change_cipher_hs: + break; + case hello_retry_request: + case encrypted_extensions: + case key_update: + case message_hash: + case no_shake: + default: + WOLFSSL_MSG("Unknown message type"); + WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E); + return SANITY_MSG_E; + } + } + } + else { + switch ((enum HandShakeType)type) { + case hello_request: + case client_hello: + case hello_verify_request: + if (!isLastMsg(ssl, msgSz)) { + WOLFSSL_MSG("Message type is not last in record"); + WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E); + return OUT_OF_ORDER_E; + } + break; + case server_hello: + case session_ticket: + case end_of_early_data: + case hello_retry_request: + case encrypted_extensions: + case certificate: + case server_key_exchange: + case certificate_request: + case server_hello_done: + case certificate_verify: + case client_key_exchange: + case finished: + case certificate_status: + case key_update: + case change_cipher_hs: + break; + case message_hash: + case no_shake: + default: + WOLFSSL_MSG("Unknown message type"); + WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E); + return SANITY_MSG_E; + } + } + return 0; +} + +#endif /* WOLFSSL_DISABLE_EARLY_SANITY_CHECKS */ + +/** + * This check is performed as soon as the handshake message type becomes known. + * These checks can not be delayed and need to be performed when the msg is + * received and not when it is processed (fragmentation may cause messages to + * be processed at a later time). This function CAN NOT be called on stored + * messages as it relies on the state of the WOLFSSL object right after + * receiving the message. + * + * @param ssl The current connection + * @param type The enum HandShakeType of the current message + * @param msgSz Size of the current message + * @return + */ +int EarlySanityCheckMsgReceived(WOLFSSL* ssl, byte type, word32 msgSz) +{ + int ret = 0; +#ifndef WOLFSSL_DISABLE_EARLY_SANITY_CHECKS + byte version_negotiated = 0; + + WOLFSSL_ENTER("EarlySanityCheckMsgReceived"); + +#ifdef WOLFSSL_DTLS + /* Version has only been negotiated after we either send or process a + * ServerHello message */ + if (ssl->options.dtls) + version_negotiated = ssl->options.serverState >= SERVER_HELLO_COMPLETE; + else +#endif + version_negotiated = 1; + + if (version_negotiated) + ret = MsgCheckEncryption(ssl, type, ssl->keys.decryptedCur == 1); + + if (ret == 0) + ret = MsgCheckBoundary(ssl, type, version_negotiated, msgSz); + + if (ret != 0 +#ifdef WOLFSSL_DTLS + && ssl->options.dtls && ssl->options.dtlsStateful +#endif + ) + SendAlert(ssl, alert_fatal, unexpected_message); + + WOLFSSL_LEAVE("EarlySanityCheckMsgReceived", ret); +#else + (void)ssl; + (void)type; + (void)msgSz; +#endif + + return ret; +} + #ifdef WOLFSSL_DTLS13 static int GetInputData(WOLFSSL *ssl, word32 size); static int GetDtls13RecordHeader(WOLFSSL* ssl, word32* inOutIdx, @@ -15785,7 +16080,6 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, return 0; } - /* Make sure no duplicates, no fast forward, or other problems; 0 on success */ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) { @@ -16649,6 +16943,12 @@ static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, return PARSE_ERROR; } + ret = EarlySanityCheckMsgReceived(ssl, type, size); + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + if (size > MAX_HANDSHAKE_SZ) { WOLFSSL_MSG("Handshake message too large"); WOLFSSL_ERROR_VERBOSE(HANDSHAKE_SIZE_ERROR); @@ -16672,6 +16972,13 @@ static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, return PARSE_ERROR; } + ret = EarlySanityCheckMsgReceived(ssl, type, + min(inputLength - HANDSHAKE_HEADER_SZ, size)); + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + /* Cap the maximum size of a handshake message to something reasonable. * By default is the maximum size of a certificate message assuming * nine 2048-bit RSA certificates in the chain. */ @@ -16710,6 +17017,13 @@ static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (inputLength > pendSz) inputLength = pendSz; + ret = EarlySanityCheckMsgReceived(ssl, ssl->arrays->pendingMsgType, + inputLength); + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + #ifdef WOLFSSL_ASYNC_CRYPT if (ssl->error != WC_PENDING_E) #endif @@ -17264,6 +17578,14 @@ int DtlsMsgDrain(WOLFSSL* ssl) item->ready && ret == 0) { word32 idx = 0; + #ifndef WOLFSSL_DISABLE_EARLY_SANITY_CHECKS + ret = MsgCheckEncryption(ssl, item->type, item->encrypted); + if (ret != 0) { + SendAlert(ssl, alert_fatal, unexpected_message); + break; + } + #endif + #ifdef WOLFSSL_NO_TLS12 ret = DoTls13HandShakeMsgType(ssl, item->fullMsg, &idx, item->type, item->sz, item->sz); @@ -17313,6 +17635,12 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, return PARSE_ERROR; } + ret = EarlySanityCheckMsgReceived(ssl, type, fragSz); + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + /* Cap the maximum size of a handshake message to something reasonable. * By default is the maximum size of a certificate message assuming * nine 2048-bit RSA certificates in the chain. */ @@ -20270,7 +20598,6 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) { int ret = 0, type = internal_error, readSz; int atomicUser = 0; - word32 startIdx = 0; #if defined(WOLFSSL_DTLS) int used; #endif @@ -20562,7 +20889,8 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) ssl->keys.padSz = 0; ssl->options.processReply = verifyEncryptedMessage; - startIdx = ssl->buffers.inputBuffer.idx; /* in case > 1 msg per */ + /* in case > 1 msg per record */ + ssl->curStartIdx = ssl->buffers.inputBuffer.idx; FALL_THROUGH; /* verify digest of encrypted message */ @@ -20906,7 +21234,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) /* 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 ((ssl->curSize - ssl->keys.padSz - - (ssl->buffers.inputBuffer.idx - startIdx) - + (ssl->buffers.inputBuffer.idx - ssl->curStartIdx) - MacSize(ssl) > MAX_PLAINTEXT_SZ) #ifdef WOLFSSL_ASYNC_CRYPT && ssl->buffers.inputBuffer.length != @@ -20928,7 +21256,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) * 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) + (ssl->buffers.inputBuffer.idx - ssl->curStartIdx) > MAX_PLAINTEXT_SZ #ifdef WOLFSSL_ASYNC_CRYPT && ssl->buffers.inputBuffer.length != @@ -21332,7 +21660,8 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) return ret; } /* more messages per record */ - else if ((ssl->buffers.inputBuffer.idx - startIdx) < ssl->curSize) { + else if ((ssl->buffers.inputBuffer.idx - ssl->curStartIdx) + < ssl->curSize) { WOLFSSL_MSG("More messages in record"); ssl->options.processReply = runProcessingOneMessage; diff --git a/src/tls13.c b/src/tls13.c index 0329b5d553..d16a5761f5 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -11787,8 +11787,6 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, WOLFSSL_ENTER("DoTls13HandShakeMsg"); if (ssl->arrays == NULL) { - - if (GetHandshakeHeader(ssl, input, inOutIdx, &type, &size, totalSz) != 0) { SendAlert(ssl, alert_fatal, unexpected_message); @@ -11796,6 +11794,12 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, return PARSE_ERROR; } + ret = EarlySanityCheckMsgReceived(ssl, type, size); + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + return DoTls13HandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); } @@ -11812,6 +11816,13 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, return PARSE_ERROR; } + ret = EarlySanityCheckMsgReceived(ssl, type, + min(inputLength - HANDSHAKE_HEADER_SZ, size)); + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + /* Cap the maximum size of a handshake message to something reasonable. * By default is the maximum size of a certificate message assuming * nine 2048-bit RSA certificates in the chain. */ @@ -11847,6 +11858,14 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, inputLength = ssl->arrays->pendingMsgSz - ssl->arrays->pendingMsgOffset; } + + ret = EarlySanityCheckMsgReceived(ssl, ssl->arrays->pendingMsgType, + inputLength); + if (ret != 0) { + WOLFSSL_ERROR(ret); + return ret; + } + XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset, input + *inOutIdx, inputLength); ssl->arrays->pendingMsgOffset += inputLength; diff --git a/tests/api.c b/tests/api.c index 9399244441..98e627b946 100644 --- a/tests/api.c +++ b/tests/api.c @@ -61806,6 +61806,7 @@ static word32 test_wolfSSL_dtls_stateless_HashWOLFSSL(const WOLFSSL* ssl) sslCopy.buffers.outputBuffer.offset = 0; sslCopy.error = 0; sslCopy.curSize = 0; + sslCopy.curStartIdx = 0; sslCopy.keys.curSeq_lo = 0; XMEMSET(&sslCopy.curRL, 0, sizeof(sslCopy.curRL)); #ifdef WOLFSSL_DTLS13 @@ -67470,7 +67471,11 @@ static int test_TLSX_CA_NAMES_bad_extension(void) } ExpectIntEQ(wolfSSL_connect(ssl_c), -1); +#ifndef WOLFSSL_DISABLE_EARLY_SANITY_CHECKS + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), OUT_OF_ORDER_E); +#else ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), BUFFER_ERROR); +#endif wolfSSL_free(ssl_c); ssl_c = NULL; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 533b25e6b3..f59da64fa0 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -5146,6 +5146,7 @@ typedef struct DtlsMsg { byte type; byte fragBucketListCount; byte ready:1; + byte encrypted:1; } DtlsMsg; @@ -5475,6 +5476,7 @@ struct WOLFSSL { word32 timeout; /* session timeout */ word32 fragOffset; /* fragment offset */ word16 curSize; + word32 curStartIdx; byte verifyDepth; RecordLayerHeader curRL; MsgsReceived msgsReceived; /* peer messages received */ @@ -6110,7 +6112,7 @@ WOLFSSL_LOCAL int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side); WOLFSSL_LOCAL int IsTLS(const WOLFSSL* ssl); WOLFSSL_LOCAL int IsAtLeastTLSv1_2(const WOLFSSL* ssl); WOLFSSL_LOCAL int IsAtLeastTLSv1_3(ProtocolVersion pv); -WOLFSSL_LOCAL int IsEncryptionOn(WOLFSSL* ssl, int isSend); +WOLFSSL_LOCAL int IsEncryptionOn(const WOLFSSL* ssl, int isSend); WOLFSSL_LOCAL int TLSv1_3_Capable(WOLFSSL* ssl); WOLFSSL_LOCAL void FreeHandshakeResources(WOLFSSL* ssl); @@ -6232,6 +6234,9 @@ WOLFSSL_LOCAL int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, WOLFSSL_LOCAL void FreeArrays(WOLFSSL* ssl, int keep); WOLFSSL_LOCAL int CheckAvailableSize(WOLFSSL *ssl, int size); WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); +WOLFSSL_LOCAL int MsgCheckEncryption(WOLFSSL* ssl, byte type, byte encrypted); +WOLFSSL_LOCAL int EarlySanityCheckMsgReceived(WOLFSSL* ssl, byte type, + word32 msgSz); #if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) WOLFSSL_LOCAL void DoCertFatalAlert(WOLFSSL* ssl, int ret); #endif @@ -6271,7 +6276,7 @@ WOLFSSL_LOCAL int cipherExtraData(WOLFSSL* ssl); WOLFSSL_LOCAL int DtlsMsgSet(DtlsMsg* msg, word32 seq, word16 epoch, const byte* data, byte type, word32 fragOffset, word32 fragSz, void* heap, - word32 totalLen); + word32 totalLen, byte encrypted); /* Use WOLFSSL_API to enable src/api.c testing */ WOLFSSL_API DtlsMsg* DtlsMsgFind(DtlsMsg* head, word16 epoch, word32 seq);