Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ add_option("WOLFSSL_DTLS_CID"
"no" "yes;no")

if(WOLFSSL_DTLS_CID)
if(NOT WOLFSSL_DTLS13)
message(FATAL_ERROR "CID are supported only for DTLSv1.3")
if(NOT WOLFSSL_DTLS)
message(FATAL_ERROR "CID requires DTLS")
endif()
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_DTLS_CID")
endif()
Expand Down
22 changes: 22 additions & 0 deletions src/dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,28 @@ int wolfSSL_dtls_cid_set(WOLFSSL* ssl, unsigned char* cid, unsigned int size)
return WOLFSSL_SUCCESS;
}

/* Replace the CID we use when sending records, after the peer provided a new
* one in a NewConnectionId message (RFC 9147 Section 9). */
int DtlsCidReplaceTx(WOLFSSL* ssl, const byte* cid, byte size)
{
CIDInfo* cidInfo;
ConnectionID* newCid;

if (ssl == NULL || cid == NULL || size == 0)
return BAD_FUNC_ARG;

cidInfo = DtlsCidGetInfo(ssl);
if (cidInfo == NULL)
return BAD_STATE_E;

newCid = DtlsCidNew(cid, size, ssl->heap);
if (newCid == NULL)
return MEMORY_ERROR;
XFREE(cidInfo->tx, ssl->heap, DYNAMIC_TYPE_TLSX);
cidInfo->tx = newCid;
return 0;
}

int wolfSSL_dtls_cid_get_rx_size(WOLFSSL* ssl, unsigned int* size)
{
return DtlsCidGetSize(ssl, size, 1);
Expand Down
103 changes: 103 additions & 0 deletions src/dtls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ static byte Dtls13TypeIsEncrypted(enum HandShakeType hs_type)
case finished:
case certificate_status:
case key_update:
case request_connection_id:
case new_connection_id:
case change_cipher_hs:
case message_hash:
case no_shake:
Expand Down Expand Up @@ -330,6 +332,11 @@ static byte Dtls13RtxMsgNeedsAck(WOLFSSL* ssl, enum HandShakeType hs)
if (hs == session_ticket || hs == key_update)
return 1;

#ifdef WOLFSSL_DTLS_CID
if (hs == request_connection_id || hs == new_connection_id)
return 1;
#endif

return 0;
}

Expand Down Expand Up @@ -1806,6 +1813,8 @@ int Dtls13CheckEpoch(WOLFSSL* ssl, enum HandShakeType type)
case change_cipher_hs:
case key_update:
case session_ticket:
case request_connection_id:
case new_connection_id:
if (!w64GTE(ssl->keys.curEpoch64, t0Epoch)) {
WOLFSSL_MSG("Msg should be epoch 3+");
WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E);
Expand Down Expand Up @@ -2915,6 +2924,100 @@ int DoDtls13KeyUpdateAck(WOLFSSL* ssl)
return ret;
}

#ifdef WOLFSSL_DTLS_CID
/* RequestConnectionId: struct { uint8 num_cids; } (RFC 9147 Section 9).
* Responding with NewConnectionId is a SHOULD; we never send records with a
* CID of our choosing, so we ignore the request. */
int DoDtls13RequestConnectionId(WOLFSSL* ssl, const byte* input,
word32* inOutIdx, word32 size)
{
(void)ssl;
(void)input;

if (size != OPAQUE8_LEN) {
WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR);
return BUFFER_ERROR;
}

*inOutIdx += size;
return 0;
}

/* NewConnectionId:
* struct {
* ConnectionId cids<0..2^16-1>;
* ConnectionIdUsage usage;
* } (RFC 9147 Section 9), where ConnectionId is opaque<0..2^8-1>. */
int DoDtls13NewConnectionId(WOLFSSL* ssl, const byte* input,
word32* inOutIdx, word32 size)
{
word32 idx = *inOutIdx;
const byte* newCid = NULL;
byte newCidLen = 0;
word16 cidsLen;
word32 i;
byte usage;
int ret;

if (size < OPAQUE16_LEN + OPAQUE8_LEN) {
WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR);
return BUFFER_ERROR;
}

ato16(input + idx, &cidsLen);
idx += OPAQUE16_LEN;

if ((word32)cidsLen + OPAQUE16_LEN + OPAQUE8_LEN != size) {
WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR);
return BUFFER_ERROR;
}

/* walk the cids list, remembering the first non-empty CID */
for (i = 0; i < cidsLen;) {
byte cidLen = input[idx + i];

i += OPAQUE8_LEN;
if (i + cidLen > cidsLen) {
WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR);
return BUFFER_ERROR;
}
if (newCid == NULL && cidLen > 0) {
newCid = input + idx + i;
newCidLen = cidLen;
}
i += cidLen;
}
idx += cidsLen;

usage = input[idx];
idx += OPAQUE8_LEN;

if (usage != cid_immediate && usage != cid_spare) {
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}

if (usage == cid_immediate) {
/* one of the new CIDs MUST be used immediately for all future
* records */
if (newCid == NULL) {
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
/* replace before the ACK for this record is sent so that the ACK
* already uses the new CID */
ret = DtlsCidReplaceTx(ssl, newCid, newCidLen);
if (ret != 0)
return ret;
}
/* cid_spare: we MAY simply discard the CIDs and keep using the
* current one */

*inOutIdx = idx;
return 0;
}
#endif /* WOLFSSL_DTLS_CID */

int DoDtls13Ack(WOLFSSL* ssl, const byte* input, word32 inputSize,
word32* processedSize)
{
Expand Down
65 changes: 59 additions & 6 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -11884,6 +11884,8 @@ int MsgCheckEncryption(WOLFSSL* ssl, byte type, byte encrypted)
case finished:
case certificate_status:
case key_update:
case request_connection_id:
case new_connection_id:
if (!encrypted) {
WOLFSSL_MSG("Message always has to be encrypted");
WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E);
Expand Down Expand Up @@ -11944,6 +11946,8 @@ int MsgCheckEncryption(WOLFSSL* ssl, byte type, byte encrypted)
case key_update:
case encrypted_extensions:
case end_of_early_data:
case request_connection_id:
case new_connection_id:
case message_hash:
case no_shake:
default:
Expand Down Expand Up @@ -11992,6 +11996,8 @@ static int MsgCheckBoundary(const WOLFSSL* ssl, byte type,
case certificate_status:
case key_update:
case change_cipher_hs:
case request_connection_id:
case new_connection_id:
break;
case server_hello_done:
case message_hash:
Expand Down Expand Up @@ -12029,6 +12035,8 @@ static int MsgCheckBoundary(const WOLFSSL* ssl, byte type,
case hello_retry_request:
case encrypted_extensions:
case key_update:
case request_connection_id:
case new_connection_id:
case message_hash:
case no_shake:
default:
Expand Down Expand Up @@ -12065,6 +12073,8 @@ static int MsgCheckBoundary(const WOLFSSL* ssl, byte type,
case key_update:
case change_cipher_hs:
break;
case request_connection_id:
case new_connection_id:
case message_hash:
case no_shake:
default:
Expand Down Expand Up @@ -22994,14 +23004,46 @@ static void dtlsClearPeer(WOLFSSL_SOCKADDR* peer)
peer->bufSz = 0;
}

static int dtlsRecordIsNewest(WOLFSSL* ssl)
{
WOLFSSL_DTLS_PEERSEQ* peerSeq;

#ifdef WOLFSSL_DTLS13
if (IsAtLeastTLSv1_3(ssl->version)) {
Dtls13Epoch* e = ssl->dtls13DecryptEpoch;

if (!w64Equal(ssl->keys.curEpoch64, ssl->dtls13PeerEpoch))
return w64GT(ssl->keys.curEpoch64, ssl->dtls13PeerEpoch);
if (e == NULL || !w64Equal(ssl->keys.curEpoch64, e->epochNumber))
e = Dtls13GetEpoch(ssl, ssl->keys.curEpoch64);
if (e == NULL)
return 0;
return w64GTE(ssl->keys.curSeq, e->nextPeerSeqNumber);
}
#endif

peerSeq = ssl->keys.peerSeq;
#ifdef WOLFSSL_MULTICAST
if (ssl->options.haveMcast)
return 1;
#endif

if (ssl->keys.curEpoch != peerSeq->nextEpoch)
return ssl->keys.curEpoch > peerSeq->nextEpoch;
if (ssl->keys.curSeq_hi != peerSeq->nextSeq_hi)
return ssl->keys.curSeq_hi > peerSeq->nextSeq_hi;
return ssl->keys.curSeq_lo >= peerSeq->nextSeq_lo;
}


/**
* @brief Handle pending peer during record processing.
* @param ssl WOLFSSL object.
* @param deprotected 0 when we have not decrypted the record yet
* 1 when we have decrypted and verified the record
* @param isNewest 1 when the record is newer than any previously received
*/
static void dtlsProcessPendingPeer(WOLFSSL* ssl, int deprotected)
static void dtlsProcessPendingPeer(WOLFSSL* ssl, int deprotected, int isNewest)
{
if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) {
if (!deprotected) {
Expand All @@ -23019,9 +23061,11 @@ static void dtlsProcessPendingPeer(WOLFSSL* ssl, int deprotected)
}
else {
/* Pending peer present and record deprotected. Update the peer. */
(void)wolfSSL_dtls_set_peer(ssl,
ssl->buffers.dtlsCtx.pendingPeer.sa,
ssl->buffers.dtlsCtx.pendingPeer.sz);
if (isNewest) {
(void)wolfSSL_dtls_set_peer(ssl,
ssl->buffers.dtlsCtx.pendingPeer.sa,
ssl->buffers.dtlsCtx.pendingPeer.sz);
}
ssl->buffers.dtlsCtx.processingPendingRecord = 0;
dtlsClearPeer(&ssl->buffers.dtlsCtx.pendingPeer);
}
Expand Down Expand Up @@ -23410,7 +23454,7 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
#ifdef WOLFSSL_DTLS
#ifdef WOLFSSL_DTLS_CID
if (ssl->options.dtls)
dtlsProcessPendingPeer(ssl, 0);
dtlsProcessPendingPeer(ssl, 0, 0);
#endif
if (ssl->options.dtls && DtlsShouldDrop(ssl, ret)) {
DropAndRestartProcessReply(ssl);
Expand Down Expand Up @@ -23729,6 +23773,9 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
case runProcessingOneRecord:
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
#ifdef WOLFSSL_DTLS_CID
int dtlsPeerNewer = 1;
#endif
#ifdef WOLFSSL_DTLS13
if (IsAtLeastTLSv1_3(ssl->version)) {
if (!Dtls13CheckWindow(ssl)) {
Expand All @@ -23747,6 +23794,9 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)

/* Only update the window once we enter stateful parsing */
if (ssl->options.dtlsStateful) {
#ifdef WOLFSSL_DTLS_CID
dtlsPeerNewer = dtlsRecordIsNewest(ssl);
#endif
ret = Dtls13UpdateWindowRecordRecvd(ssl);
if (ret != 0) {
WOLFSSL_ERROR(ret);
Expand All @@ -23757,12 +23807,15 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
else
#endif /* WOLFSSL_DTLS13 */
if (IsDtlsNotSctpMode(ssl)) {
#ifdef WOLFSSL_DTLS_CID
dtlsPeerNewer = dtlsRecordIsNewest(ssl);
#endif
DtlsUpdateWindow(ssl);
}
#ifdef WOLFSSL_DTLS_CID
/* Update the peer if we were able to de-protect the message */
if (IsEncryptionOn(ssl, 0))
dtlsProcessPendingPeer(ssl, 1);
dtlsProcessPendingPeer(ssl, 1, dtlsPeerNewer);
#endif
}
#endif /* WOLFSSL_DTLS */
Expand Down
Loading
Loading