forked from wolfSSL/wolfssl
dtls13: support fragmentation, sending and receiving
This commit implements the core of the header parsing, building, and the sending and receiving routines that handle fragmentation and defragmentation. * In DTLSv1.3 the header used for protected messages is a variable-length header, and it is described RFC9147 Section 4. * Fragmentation happens after building the full message, if necessary. If the underlying I/O can't send a fragment because of a WANT_WRITE error, the sending of fragments will continue in the next invocation of wolfSSL_connect/wolfSSL_accept/wolfSSL_write. In this case the message is saved in a buffer inside the WolfSSL object. * Defragmentation works like DTLSv1.2 defragmentation, and re-use most of the same code. * The Dtls13AddHeaders() function does not add the record layer header, but it lefts space for it. It is eventually placed by BuildTls13Message() to allow easier management of sequence numbers.
This commit is contained in:
committed by
David Garske
parent
173077b142
commit
d079662765
1107
src/dtls13.c
1107
src/dtls13.c
File diff suppressed because it is too large
Load Diff
488
src/internal.c
488
src/internal.c
@ -506,8 +506,16 @@ static WC_INLINE int IsEncryptionOn(WOLFSSL* ssl, int isSend)
|
||||
{
|
||||
#ifdef WOLFSSL_DTLS
|
||||
/* For DTLS, epoch 0 is always not encrypted. */
|
||||
if (ssl->options.dtls && !isSend && ssl->keys.curEpoch == 0)
|
||||
return 0;
|
||||
if (ssl->options.dtls && !isSend) {
|
||||
if (!IsAtLeastTLSv1_3(ssl->version) && ssl->keys.curEpoch == 0)
|
||||
return 0;
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
else if (IsAtLeastTLSv1_3(ssl->version)
|
||||
&& w64IsZero(ssl->keys.curEpoch64))
|
||||
return 0;
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
return ssl->keys.encryptionOn &&
|
||||
@ -7425,8 +7433,8 @@ void FreeHandshakeResources(WOLFSSL* ssl)
|
||||
WOLFSSL_ENTER("FreeHandshakeResources");
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
/* DTLS_POOL */
|
||||
if (ssl->options.dtls) {
|
||||
/* DTLS_POOL (DTLSv1.3 flushes the queue autonomously) */
|
||||
if (ssl->options.dtls && !IsAtLeastTLSv1_3(ssl->version)) {
|
||||
DtlsMsgPoolReset(ssl);
|
||||
DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap);
|
||||
ssl->dtls_rx_msg_list = NULL;
|
||||
@ -8759,8 +8767,19 @@ int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz)
|
||||
#endif
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (ssl->options.dtls) {
|
||||
adj += DTLS_RECORD_EXTRA;
|
||||
sz -= DTLS_RECORD_EXTRA;
|
||||
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
word16 dtls_record_extra;
|
||||
dtls_record_extra = Dtls13GetRlHeaderLength(IsEncryptionOn(ssl, 1));
|
||||
dtls_record_extra -= RECORD_HEADER_SZ;
|
||||
|
||||
adj += dtls_record_extra;
|
||||
sz -= dtls_record_extra;
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
} else {
|
||||
adj += DTLS_RECORD_EXTRA;
|
||||
sz -= DTLS_RECORD_EXTRA;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -8784,6 +8803,12 @@ int HashInput(WOLFSSL* ssl, const byte* input, int sz)
|
||||
if (ssl->options.dtls) {
|
||||
adj -= DTLS_HANDSHAKE_EXTRA;
|
||||
sz += DTLS_HANDSHAKE_EXTRA;
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (IsAtLeastTLSv1_3(ssl->version))
|
||||
return Dtls13HashHandshake(ssl, adj, sz);
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -9466,7 +9491,12 @@ int CheckAvailableSize(WOLFSSL *ssl, int size)
|
||||
#else
|
||||
ssl->dtls_expected_rx
|
||||
#endif
|
||||
) {
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* DTLS1.3 uses the output buffer to store the full message and deal
|
||||
with fragmentation later in dtls13HandshakeSend() */
|
||||
&& !IsAtLeastTLSv1_3(ssl->version)
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
) {
|
||||
WOLFSSL_MSG("CheckAvailableSize() called with size greater than MTU.");
|
||||
return DTLS_SIZE_ERROR;
|
||||
}
|
||||
@ -9482,15 +9512,171 @@ int CheckAvailableSize(WOLFSSL *ssl, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
static int GetDtls13RecordHeader(WOLFSSL* ssl, const byte* input,
|
||||
word32* inOutIdx, RecordLayerHeader* rh, word16* size)
|
||||
{
|
||||
|
||||
Dtls13UnifiedHdrInfo hdrInfo;
|
||||
w64wrapper epochNumber;
|
||||
byte epochBits;
|
||||
int readSize;
|
||||
int ret;
|
||||
|
||||
readSize = ssl->buffers.inputBuffer.length - *inOutIdx;
|
||||
|
||||
epochBits = *input & EE_MASK;
|
||||
ret = Dtls13ReconstructEpochNumber(ssl, epochBits, &epochNumber);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
#ifdef WOLFSSL_DEBUG_TLS
|
||||
WOLFSSL_MSG_EX("reconstructed epoch number: %ld",
|
||||
epochNumber);
|
||||
#endif /* WOLFSSL_DEBUG_TLS */
|
||||
|
||||
/* protected records always use unified_headers in DTLSv1.3 */
|
||||
if (w64IsZero(epochNumber))
|
||||
return SEQUENCE_ERROR;
|
||||
|
||||
if (ssl->dtls13DecryptEpoch == NULL)
|
||||
return BAD_STATE_E;
|
||||
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
if (w64Equal(epochNumber, w64From32(0x0, DTLS13_EPOCH_EARLYDATA)) &&
|
||||
ssl->options.handShakeDone) {
|
||||
WOLFSSL_MSG("discarding early data after handshake");
|
||||
return SEQUENCE_ERROR;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
if (!w64Equal(ssl->dtls13DecryptEpoch->epochNumber, epochNumber)) {
|
||||
ret = Dtls13SetEpochKeys(ssl, epochNumber, DECRYPT_SIDE_ONLY);
|
||||
if (ret != 0)
|
||||
return SEQUENCE_ERROR;
|
||||
}
|
||||
|
||||
ret = Dtls13ParseUnifiedRecordLayer(ssl, input + *inOutIdx, readSize,
|
||||
&hdrInfo);
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
*size = hdrInfo.recordLength;
|
||||
c16toa(*size, rh->length);
|
||||
|
||||
/* type is implicit */
|
||||
rh->type = application_data;
|
||||
|
||||
/* version is implicit */
|
||||
rh->pvMajor = ssl->version.major;
|
||||
rh->pvMinor = DTLSv1_2_MINOR;
|
||||
|
||||
ssl->keys.curEpoch64 = epochNumber;
|
||||
|
||||
ret = Dtls13ReconstructSeqNumber(ssl, &hdrInfo, &ssl->keys.curSeq);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
#ifdef WOLFSSL_DEBUG_TLS
|
||||
WOLFSSL_MSG_EX("reconstructed seq number: %ld",
|
||||
ssl->keys.curSeq);
|
||||
#endif /* WOLFSSL_DEBUG_TLS */
|
||||
|
||||
*inOutIdx += hdrInfo.headerLength;
|
||||
ssl->dtls13CurRlLength = hdrInfo.headerLength;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
static int GetDtlsRecordHeader(WOLFSSL* ssl, const byte* input,
|
||||
word32* inOutIdx, RecordLayerHeader* rh, word16* size)
|
||||
{
|
||||
|
||||
#ifdef HAVE_FUZZER
|
||||
if (ssl->fuzzerCb)
|
||||
ssl->fuzzerCb(ssl, input + *inOutIdx, DTLS_RECORD_HEADER_SZ,
|
||||
FUZZ_HEAD, ssl->fuzzerCtx);
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
word32 read_size;
|
||||
|
||||
read_size = ssl->buffers.inputBuffer.length - *inOutIdx;
|
||||
|
||||
if (Dtls13IsUnifiedHeader(*(input + *inOutIdx))) {
|
||||
|
||||
/* version 1.3 already negotiated */
|
||||
if (ssl->options.tls1_3)
|
||||
return GetDtls13RecordHeader(ssl, input, inOutIdx, rh, size);
|
||||
|
||||
}
|
||||
|
||||
/* not a unified header, check that we have at least
|
||||
DTLS_RECORD_HEADER_SZ */
|
||||
if (read_size < DTLS_RECORD_HEADER_SZ)
|
||||
return LENGTH_ERROR;
|
||||
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
/* type and version in same spot */
|
||||
XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ);
|
||||
*inOutIdx += ENUM_LEN + VERSION_SZ;
|
||||
ato16(input + *inOutIdx, &ssl->keys.curEpoch);
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* only non protected message can use the DTLSPlaintext record header */
|
||||
if (ssl->options.tls1_3 && ssl->keys.curEpoch != 0)
|
||||
return SEQUENCE_ERROR;
|
||||
|
||||
w64Zero(&ssl->keys.curEpoch64);
|
||||
if (!w64IsZero(ssl->dtls13DecryptEpoch->epochNumber))
|
||||
Dtls13SetEpochKeys(ssl, ssl->keys.curEpoch64, DECRYPT_SIDE_ONLY);
|
||||
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
*inOutIdx += OPAQUE16_LEN;
|
||||
if (ssl->options.haveMcast) {
|
||||
#ifdef WOLFSSL_MULTICAST
|
||||
ssl->keys.curPeerId = input[*inOutIdx];
|
||||
ssl->keys.curSeq_hi = input[*inOutIdx+1];
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ato16(input + *inOutIdx, &ssl->keys.curSeq_hi);
|
||||
*inOutIdx += OPAQUE16_LEN;
|
||||
ato32(input + *inOutIdx, &ssl->keys.curSeq_lo);
|
||||
*inOutIdx += OPAQUE32_LEN; /* advance past rest of seq */
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* DTLSv1.3 PlainText records use DTLSv1.2 sequence number encoding. Update
|
||||
the DTLv1.3 word64 version as well */
|
||||
ssl->keys.curSeq = w64From32(ssl->keys.curSeq_hi, ssl->keys.curSeq_lo);
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
ato16(input + *inOutIdx, size);
|
||||
*inOutIdx += LENGTH_SZ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
/* do all verify and sanity checks on record header */
|
||||
static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
RecordLayerHeader* rh, word16 *size)
|
||||
{
|
||||
byte tls12minor;
|
||||
#ifdef WOLFSSL_DTLS
|
||||
int ret;
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
#ifdef OPENSSL_ALL
|
||||
word32 start = *inOutIdx;
|
||||
#endif
|
||||
|
||||
(void)tls12minor;
|
||||
|
||||
if (!ssl->options.dtls) {
|
||||
#ifdef HAVE_FUZZER
|
||||
if (ssl->fuzzerCb)
|
||||
@ -9503,34 +9689,16 @@ static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
}
|
||||
else {
|
||||
#ifdef WOLFSSL_DTLS
|
||||
#ifdef HAVE_FUZZER
|
||||
if (ssl->fuzzerCb)
|
||||
ssl->fuzzerCb(ssl, input + *inOutIdx, DTLS_RECORD_HEADER_SZ,
|
||||
FUZZ_HEAD, ssl->fuzzerCtx);
|
||||
#endif
|
||||
/* type and version in same sport */
|
||||
XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ);
|
||||
*inOutIdx += ENUM_LEN + VERSION_SZ;
|
||||
ato16(input + *inOutIdx, &ssl->keys.curEpoch);
|
||||
*inOutIdx += OPAQUE16_LEN;
|
||||
if (ssl->options.haveMcast) {
|
||||
#ifdef WOLFSSL_MULTICAST
|
||||
ssl->keys.curPeerId = input[*inOutIdx];
|
||||
ssl->keys.curSeq_hi = input[*inOutIdx+1];
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ato16(input + *inOutIdx, &ssl->keys.curSeq_hi);
|
||||
*inOutIdx += OPAQUE16_LEN;
|
||||
ato32(input + *inOutIdx, &ssl->keys.curSeq_lo);
|
||||
*inOutIdx += OPAQUE32_LEN; /* advance past rest of seq */
|
||||
ato16(input + *inOutIdx, size);
|
||||
*inOutIdx += LENGTH_SZ;
|
||||
ret = GetDtlsRecordHeader(ssl, input, inOutIdx, rh, size);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (IsDtlsNotSctpMode(ssl)) {
|
||||
/* DTLSv1.3 MUST check window after deprotecting to avoid timing channel
|
||||
(RFC9147 Section 4.5.1) */
|
||||
if (IsDtlsNotSctpMode(ssl) && !IsAtLeastTLSv1_3(ssl->version)) {
|
||||
if (!DtlsCheckWindow(ssl) ||
|
||||
(rh->type == application_data && ssl->keys.curEpoch == 0) ||
|
||||
(rh->type == alert && ssl->options.handShakeDone &&
|
||||
@ -14904,6 +15072,51 @@ static WC_INLINE int DtlsCheckWindow(WOLFSSL* ssl)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
static WC_INLINE int Dtls13CheckWindow(WOLFSSL* ssl)
|
||||
{
|
||||
w64wrapper nextSeq, seq;
|
||||
w64wrapper diff64;
|
||||
word32 *window;
|
||||
int wordOffset;
|
||||
int wordIndex;
|
||||
word32 diff;
|
||||
|
||||
if (ssl->dtls13DecryptEpoch == NULL) {
|
||||
WOLFSSL_MSG("Can't find decrypting epoch");
|
||||
return 0;
|
||||
}
|
||||
|
||||
nextSeq = ssl->dtls13DecryptEpoch->nextPeerSeqNumber;
|
||||
window = ssl->dtls13DecryptEpoch->window;
|
||||
seq = ssl->keys.curSeq;
|
||||
|
||||
if (w64GTE(seq, nextSeq))
|
||||
return 1;
|
||||
|
||||
/* seq < nextSeq, nextSeq - seq */
|
||||
diff64 = w64Sub(nextSeq, seq);
|
||||
|
||||
/* diff >= DTLS_SEQ_BITS, outside of the window */
|
||||
if (w64GT(diff64, w64From32(0, DTLS_SEQ_BITS)))
|
||||
return 0;
|
||||
|
||||
/* we are assuming DTLS_SEQ_BITS <= 2**32 */
|
||||
diff = w64GetLow32(diff64);
|
||||
|
||||
/* zero based index */
|
||||
diff--;
|
||||
|
||||
wordIndex = ((int)diff) / DTLS_WORD_BITS;
|
||||
wordOffset = ((int)diff) % DTLS_WORD_BITS;
|
||||
|
||||
if (window[wordIndex] & (1 << wordOffset))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
#ifdef WOLFSSL_MULTICAST
|
||||
static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first,
|
||||
@ -15050,6 +15263,60 @@ static WC_INLINE int DtlsUpdateWindow(WOLFSSL* ssl)
|
||||
return _DtlsUpdateWindow(ssl, next_hi, next_lo, window);
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
static WC_INLINE int Dtls13UpdateWindow(WOLFSSL* ssl)
|
||||
{
|
||||
w64wrapper nextSeq, seq;
|
||||
w64wrapper diff64;
|
||||
word32 *window;
|
||||
int wordOffset;
|
||||
int wordIndex;
|
||||
word32 diff;
|
||||
|
||||
if (ssl->dtls13DecryptEpoch == NULL) {
|
||||
WOLFSSL_MSG("Can't find decrypting Epoch");
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
|
||||
nextSeq = ssl->dtls13DecryptEpoch->nextPeerSeqNumber;
|
||||
window = ssl->dtls13DecryptEpoch->window;
|
||||
seq = ssl->keys.curSeq;
|
||||
|
||||
/* seq < nextSeq */
|
||||
if (w64LT(seq, nextSeq)) {
|
||||
diff64 = w64Sub(nextSeq, seq);
|
||||
|
||||
/* zero based index */
|
||||
w64Decrement(&diff64);
|
||||
|
||||
/* FIXME: check that diff64 < DTLS_WORDS_BITS */
|
||||
diff = w64GetLow32(diff64);
|
||||
wordIndex = ((int)diff) / DTLS_WORD_BITS;
|
||||
wordOffset = ((int)diff) % DTLS_WORD_BITS;
|
||||
|
||||
if (wordIndex >= WOLFSSL_DTLS_WINDOW_WORDS) {
|
||||
WOLFSSL_MSG("Invalid sequence number to Dtls13UpdateWindow");
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
|
||||
window[wordIndex] |= (1 << wordOffset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* seq >= nextSeq, seq - nextSeq */
|
||||
diff64 = w64Sub(seq, nextSeq);
|
||||
|
||||
/* as we are considering nextSeq inside the window, we should add + 1 */
|
||||
w64Increment(&diff64);
|
||||
DtlsUpdateWindowGTSeq(w64GetLow32(diff64), window);
|
||||
|
||||
w64Increment(&seq);
|
||||
ssl->dtls13DecryptEpoch->nextPeerSeqNumber = seq;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
|
||||
int DtlsMsgDrain(WOLFSSL* ssl)
|
||||
{
|
||||
@ -17468,8 +17735,15 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
||||
readSz = RECORD_HEADER_SZ;
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (ssl->options.dtls)
|
||||
if (ssl->options.dtls) {
|
||||
readSz = DTLS_RECORD_HEADER_SZ;
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.tls1_3) {
|
||||
/* dtls1.3 unified header can be as little as 2 bytes */
|
||||
readSz = DTLS_UNIFIED_HEADER_MIN_SZ;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* get header or return error */
|
||||
@ -17565,6 +17839,11 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
||||
/* get the record layer header */
|
||||
case getRecordLayerHeader:
|
||||
|
||||
/* DTLSv1.3 record numbers in the header are encrypted, and AAD
|
||||
* uses the unecrypted form. Because of this we need to modify the
|
||||
* header, decrypting the numbers inside
|
||||
* DtlsParseUnifiedRecordLayer(). This violates the const attribute
|
||||
* of the buffer parameter of GetRecordHeader() used here. */
|
||||
ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer,
|
||||
&ssl->buffers.inputBuffer.idx,
|
||||
&ssl->curRL, &ssl->curSize);
|
||||
@ -17785,11 +18064,22 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
||||
else
|
||||
{
|
||||
#ifdef WOLFSSL_TLS13
|
||||
byte *aad = (byte*)&ssl->curRL;
|
||||
word16 aad_size = RECORD_HEADER_SZ;
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls) {
|
||||
/* aad now points to the record header */
|
||||
aad = in->buffer +
|
||||
in->idx - ssl->dtls13CurRlLength;
|
||||
aad_size = ssl->dtls13CurRlLength;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
ret = DecryptTls13(ssl,
|
||||
in->buffer + in->idx,
|
||||
in->buffer + in->idx,
|
||||
ssl->curSize,
|
||||
(byte*)&ssl->curRL, RECORD_HEADER_SZ, 1);
|
||||
aad, aad_size, 1);
|
||||
#else
|
||||
ret = DECRYPT_ERROR;
|
||||
#endif /* WOLFSSL_TLS13 */
|
||||
@ -17816,6 +18106,15 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
||||
else {
|
||||
WOLFSSL_MSG("Decrypt failed");
|
||||
WOLFSSL_ERROR(ret);
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.tls1_3 && ssl->options.dtls) {
|
||||
WOLFSSL_MSG("DTLS: Ignoring decrypted failed record");
|
||||
ssl->options.processReply = doProcessInit;
|
||||
ssl->buffers.inputBuffer.idx =
|
||||
ssl->buffers.inputBuffer.length;
|
||||
return 0;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
if (ssl->options.tls1_3) {
|
||||
if (ssl->options.side == WOLFSSL_SERVER_END &&
|
||||
@ -17936,6 +18235,35 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
||||
|
||||
/* the record layer is here */
|
||||
case runProcessingOneRecord:
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls && 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;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = Dtls13UpdateWindow(ssl);
|
||||
if (ret != 1) {
|
||||
WOLFSSL_ERROR(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = Dtls13RecordRecvd(ssl);
|
||||
if (ret != 0) {
|
||||
WOLFSSL_ERROR(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
ssl->options.processReply = runProcessingOneMessage;
|
||||
FALL_THROUGH;
|
||||
|
||||
@ -17986,7 +18314,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (IsDtlsNotSctpMode(ssl)) {
|
||||
if (IsDtlsNotSctpMode(ssl) && !IsAtLeastTLSv1_3(ssl->version)) {
|
||||
DtlsUpdateWindow(ssl);
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
@ -17999,11 +18327,36 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
||||
/* debugging in DoHandShakeMsg */
|
||||
if (ssl->options.dtls) {
|
||||
#ifdef WOLFSSL_DTLS
|
||||
ret = DoDtlsHandShakeMsg(ssl,
|
||||
ssl->buffers.inputBuffer.buffer,
|
||||
&ssl->buffers.inputBuffer.idx,
|
||||
ssl->buffers.inputBuffer.length);
|
||||
if (!IsAtLeastTLSv1_3(ssl->version)) {
|
||||
ret = DoDtlsHandShakeMsg(ssl,
|
||||
ssl->buffers.inputBuffer.buffer,
|
||||
&ssl->buffers.inputBuffer.idx,
|
||||
ssl->buffers.inputBuffer.length);
|
||||
}
|
||||
#endif
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||
ret = Dtls13HandshakeRecv(ssl,
|
||||
ssl->buffers.inputBuffer.buffer,
|
||||
&ssl->buffers.inputBuffer.idx,
|
||||
ssl->buffers.inputBuffer.length);
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
if (ret == 0 &&
|
||||
ssl->options.side == WOLFSSL_SERVER_END &&
|
||||
ssl->earlyData > early_data_ext &&
|
||||
ssl->options.handShakeState == HANDSHAKE_DONE) {
|
||||
|
||||
/* return so wolfSSL_read_early_data can return
|
||||
exit */
|
||||
ssl->earlyData = no_early_data;
|
||||
ssl->options.processReply = doProcessInit;
|
||||
|
||||
return ZERO_RETURN;
|
||||
}
|
||||
#endif /* WOLFSSL_EARLY_DATA */
|
||||
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
}
|
||||
else if (!IsAtLeastTLSv1_3(ssl->version)
|
||||
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_TLS12)
|
||||
@ -20497,6 +20850,42 @@ int SendData(WOLFSSL* ssl, const void* data, int sz)
|
||||
byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls && ssl->options.tls1_3) {
|
||||
byte isEarlyData = 0;
|
||||
|
||||
if (ssl->dtls13EncryptEpoch == NULL)
|
||||
return ssl->error = BAD_STATE_E;
|
||||
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
isEarlyData = ssl->earlyData != no_early_data;
|
||||
#endif
|
||||
|
||||
if (isEarlyData) {
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
ret = Dtls13SetEpochKeys(ssl,
|
||||
w64From32(0x0, DTLS13_EPOCH_EARLYDATA), ENCRYPT_SIDE_ONLY);
|
||||
if (ret != 0) {
|
||||
WOLFSSL_MSG(
|
||||
"trying to send early data without epoch 1");
|
||||
ssl->error = BUILD_MSG_ERROR;
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
#endif /* WOLFSSL_EARLY_DATA */
|
||||
}
|
||||
else if (!w64Equal(
|
||||
ssl->dtls13EncryptEpoch->epochNumber,
|
||||
ssl->dtls13Epoch)) {
|
||||
ret = Dtls13SetEpochKeys(
|
||||
ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY);
|
||||
if (ret != 0) {
|
||||
ssl->error = BUILD_MSG_ERROR;
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (ssl->options.dtls) {
|
||||
buffSz = wolfSSL_GetMaxFragSize(ssl, sz - sent);
|
||||
@ -20840,12 +21229,33 @@ static int SendAlert_ex(WOLFSSL* ssl, int severity, int type)
|
||||
* TLS 1.3 encrypts handshake packets after the ServerHello
|
||||
*/
|
||||
if (IsEncryptionOn(ssl, 1)) {
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls
|
||||
&& IsAtLeastTLSv1_3(ssl->version)
|
||||
&& !w64Equal(ssl->dtls13EncryptEpoch->epochNumber, ssl->dtls13Epoch)) {
|
||||
ret = Dtls13SetEpochKeys(ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
sendSz = BuildMessage(ssl, output, outputSz, input, ALERT_SIZE, alert,
|
||||
0, 0, 0, CUR_ORDER);
|
||||
}
|
||||
else {
|
||||
|
||||
AddRecordHeader(output, ALERT_SIZE, alert, ssl, CUR_ORDER);
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
|
||||
ret = Dtls13RlAddPlaintextHeader(ssl, output, alert, ALERT_SIZE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
{
|
||||
AddRecordHeader(output, ALERT_SIZE, alert, ssl, CUR_ORDER);
|
||||
}
|
||||
|
||||
output += RECORD_HEADER_SZ;
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (ssl->options.dtls)
|
||||
|
11
src/keys.c
11
src/keys.c
@ -2081,6 +2081,15 @@ int SetCipherSpecs(WOLFSSL* ssl)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls &&
|
||||
ssl->version.major == DTLS_MAJOR &&
|
||||
ssl->version.minor <= DTLSv1_3_MINOR) {
|
||||
ssl->options.tls = 1;
|
||||
ssl->options.tls1_3 = 1;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
|
||||
if (IsAtLeastTLSv1_3(ssl->version) || ssl->specs.cipher_type != block)
|
||||
ssl->options.encThenMac = 0;
|
||||
@ -2966,7 +2975,7 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side)
|
||||
|
||||
#ifdef HAVE_SECURE_RENEGOTIATION
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (ret == 0 && ssl->options.dtls) {
|
||||
if (ret == 0 && ssl->options.dtls && !ssl->options.tls1_3) {
|
||||
if (wc_encrypt)
|
||||
wc_encrypt->src = keys == &ssl->keys ? KEYS : SCR;
|
||||
if (wc_decrypt)
|
||||
|
654
src/tls13.c
654
src/tls13.c
File diff suppressed because it is too large
Load Diff
@ -1294,6 +1294,8 @@ enum Misc {
|
||||
|
||||
DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */
|
||||
DTLS_RECORD_HEADER_SZ = 13, /* normal + epoch(2) + seq_num(6) */
|
||||
DTLS_UNIFIED_HEADER_MIN_SZ = 2,
|
||||
DTLS_RECORD_HEADER_MAX_SZ = 13,
|
||||
DTLS_HANDSHAKE_EXTRA = 8, /* diff from normal */
|
||||
DTLS_RECORD_EXTRA = 8, /* diff from normal */
|
||||
DTLS_HANDSHAKE_SEQ_SZ = 2, /* handshake header sequence number */
|
||||
@ -2256,6 +2258,12 @@ typedef struct Keys {
|
||||
word16 curEpoch; /* Received epoch in current record */
|
||||
word16 curSeq_hi; /* Received sequence in current record */
|
||||
word32 curSeq_lo;
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
w64wrapper curEpoch64; /* Received epoch in current record */
|
||||
w64wrapper curSeq;
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
#ifdef WOLFSSL_MULTICAST
|
||||
byte curPeerId; /* Received peer group ID in current record */
|
||||
#endif
|
||||
@ -4319,6 +4327,15 @@ typedef enum EarlyDataState {
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
|
||||
typedef struct Dtls13UnifiedHdrInfo {
|
||||
word16 recordLength;
|
||||
word16 headerLength;
|
||||
byte seqLo;
|
||||
byte seqHi;
|
||||
byte seqHiPresent:1;
|
||||
byte epochBits;
|
||||
} Dtls13UnifiedHdrInfo;
|
||||
|
||||
enum {
|
||||
DTLS13_EPOCH_EARLYDATA = 1,
|
||||
DTLS13_EPOCH_HANDSHAKE = 2,
|
||||
@ -4557,8 +4574,15 @@ struct WOLFSSL {
|
||||
w64wrapper dtls13Epoch;
|
||||
w64wrapper dtls13PeerEpoch;
|
||||
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
word16 dtls13CurRlLength;
|
||||
|
||||
/* used to store the message if it needs to be fragmented */
|
||||
buffer dtls13FragmentsBuffer;
|
||||
byte dtls13SendingFragments:1;
|
||||
word32 dtls13MessageLength;
|
||||
word32 dtls13FragOffset;
|
||||
byte dtls13FragHandshakeType;
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
#ifdef WOLFSSL_CALLBACKS
|
||||
TimeoutInfo timeoutInfo; /* info saved during handshake */
|
||||
@ -4842,7 +4866,10 @@ enum ContentType {
|
||||
change_cipher_spec = 20,
|
||||
alert = 21,
|
||||
handshake = 22,
|
||||
application_data = 23
|
||||
application_data = 23,
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
ack = 26,
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
};
|
||||
|
||||
|
||||
@ -5309,11 +5336,44 @@ WOLFSSL_LOCAL int Dtls13NewEpoch(WOLFSSL* ssl, w64wrapper epochNumber,
|
||||
int side);
|
||||
WOLFSSL_LOCAL int Dtls13SetEpochKeys(WOLFSSL* ssl, w64wrapper epochNumber,
|
||||
enum encrypt_side side);
|
||||
WOLFSSL_LOCAL int Dtls13GetSeq(WOLFSSL* ssl, int order, word32* seq,
|
||||
byte increment);
|
||||
WOLFSSL_LOCAL int Dtls13DeriveSnKeys(WOLFSSL* ssl, int provision);
|
||||
WOLFSSL_LOCAL int Dtls13SetRecordNumberKeys(WOLFSSL* ssl,
|
||||
enum encrypt_side side);
|
||||
|
||||
WOLFSSL_LOCAL int Dtls13AddHeaders(byte* output, word32 length,
|
||||
enum HandShakeType hs_type, WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL word16 Dtls13GetHeadersLength(enum HandShakeType type);
|
||||
WOLFSSL_LOCAL word16 Dtls13GetRlHeaderLength(byte is_encrypted);
|
||||
WOLFSSL_LOCAL int Dtls13RlAddCiphertextHeader(WOLFSSL* ssl, byte* out,
|
||||
word16 length);
|
||||
WOLFSSL_LOCAL int Dtls13RlAddPlaintextHeader(WOLFSSL* ssl, byte* out,
|
||||
enum ContentType content_type, word16 length);
|
||||
WOLFSSL_LOCAL int Dtls13EncryptRecordNumber(WOLFSSL* ssl, byte* hdr,
|
||||
word16 recordLength);
|
||||
WOLFSSL_LOCAL int Dtls13IsUnifiedHeader(byte header_flags);
|
||||
WOLFSSL_LOCAL int Dtls13ParseUnifiedRecordLayer(WOLFSSL* ssl, const byte* input,
|
||||
word16 input_size, Dtls13UnifiedHdrInfo* hdrInfo);
|
||||
WOLFSSL_LOCAL int Dtls13HandshakeSend(WOLFSSL* ssl, byte* output,
|
||||
word16 output_size, word16 length, enum HandShakeType handshake_type,
|
||||
int hash_output);
|
||||
WOLFSSL_LOCAL int Dtls13RecordRecvd(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input,
|
||||
word32* inOutIdx, word32 totalSz);
|
||||
WOLFSSL_LOCAL int Dtls13HandshakeAddHeader(WOLFSSL* ssl, byte* output,
|
||||
enum HandShakeType msg_type, word32 length);
|
||||
#define EE_MASK (0x3)
|
||||
WOLFSSL_LOCAL int Dtls13FragmentsContinue(WOLFSSL* ssl);
|
||||
|
||||
WOLFSSL_LOCAL int Dtls13ReconstructEpochNumber(WOLFSSL* ssl, byte epochBits,
|
||||
w64wrapper* epoch);
|
||||
WOLFSSL_LOCAL int Dtls13ReconstructSeqNumber(WOLFSSL* ssl,
|
||||
Dtls13UnifiedHdrInfo* hdrInfo, w64wrapper* out);
|
||||
WOLFSSL_LOCAL int Dtls13HashHandshake(WOLFSSL* ssl, const byte* output,
|
||||
word16 length);
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
#ifdef WOLFSSL_STATIC_EPHEMERAL
|
||||
WOLFSSL_LOCAL int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr);
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user