mirror of https://github.com/wolfSSL/wolfssl.git
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.pull/4907/head
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
|
||||
|
|
Loading…
Reference in New Issue