Skip to content

Commit 2354ea1

Browse files
authored
Merge pull request #9513 from rizlik/dtls_header_fix
fix DTLS header headroom accounting
2 parents 0fae0a7 + 149bf19 commit 2354ea1

File tree

7 files changed

+396
-92
lines changed

7 files changed

+396
-92
lines changed

src/dtls13.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -979,31 +979,35 @@ static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
979979
{
980980
int fragLength, rlHeaderLength;
981981
int remainingSize, maxFragment;
982-
int recordLength;
982+
int recordLength, outputSz;
983983
byte isEncrypted;
984984
byte* output;
985985
int ret;
986986

987987
isEncrypted = Dtls13TypeIsEncrypted(
988988
(enum HandShakeType)ssl->dtls13FragHandshakeType);
989989
rlHeaderLength = Dtls13GetRlHeaderLength(ssl, isEncrypted);
990-
maxFragment = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
990+
maxFragment = wolfssl_local_GetMaxPlaintextSize(ssl);
991991

992992
remainingSize = ssl->dtls13MessageLength - ssl->dtls13FragOffset;
993993

994994
while (remainingSize > 0) {
995995

996-
fragLength = maxFragment - rlHeaderLength - DTLS_HANDSHAKE_HEADER_SZ;
997-
998-
recordLength = maxFragment;
996+
fragLength = maxFragment - DTLS_HANDSHAKE_HEADER_SZ;
999997

1000998
if (fragLength > remainingSize) {
1001999
fragLength = remainingSize;
1002-
recordLength =
1003-
fragLength + rlHeaderLength + DTLS_HANDSHAKE_HEADER_SZ;
10041000
}
10051001

1006-
ret = CheckAvailableSize(ssl, recordLength + MAX_MSG_EXTRA);
1002+
recordLength = fragLength + rlHeaderLength + DTLS_HANDSHAKE_HEADER_SZ;
1003+
outputSz = wolfssl_local_GetRecordSize(ssl,
1004+
fragLength + DTLS_HANDSHAKE_HEADER_SZ, isEncrypted);
1005+
if (outputSz < 0) {
1006+
Dtls13FreeFragmentsBuffer(ssl);
1007+
return recordLength;
1008+
}
1009+
1010+
ret = CheckAvailableSize(ssl, outputSz);
10071011
if (ret != 0) {
10081012
Dtls13FreeFragmentsBuffer(ssl);
10091013
return ret;
@@ -1025,7 +1029,7 @@ static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
10251029

10261030
ret = Dtls13SendOneFragmentRtx(ssl,
10271031
(enum HandShakeType)ssl->dtls13FragHandshakeType,
1028-
(word16)recordLength + MAX_MSG_EXTRA, output, (word32)recordLength, 0);
1032+
(word16)outputSz, output, (word32)recordLength, 0);
10291033
if (ret == WC_NO_ERR_TRACE(WANT_WRITE)) {
10301034
ssl->dtls13FragOffset += fragLength;
10311035
return ret;
@@ -2018,7 +2022,7 @@ int Dtls13HandshakeSend(WOLFSSL* ssl, byte* message, word16 outputSize,
20182022
return ret;
20192023
}
20202024

2021-
maxFrag = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
2025+
maxFrag = wolfssl_local_GetMaxPlaintextSize(ssl);
20222026
maxLen = length;
20232027

20242028
if (handshakeType == key_update)

src/internal.c

Lines changed: 138 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -10759,7 +10759,13 @@ static int SendHandshakeMsg(WOLFSSL* ssl, byte* input, word32 inputSz,
1075910759
inputSz += HANDSHAKE_HEADER_SZ;
1076010760
rHdrSz = RECORD_HEADER_SZ;
1076110761
}
10762-
maxFrag = wolfSSL_GetMaxFragSize(ssl, (int)inputSz);
10762+
maxFrag = wolfssl_local_GetMaxPlaintextSize(ssl);
10763+
#ifdef WOLFSSL_DTLS
10764+
if (ssl->options.dtls) {
10765+
/* In DTLS the handshake header is per fragment */
10766+
maxFrag -= DTLS_HANDSHAKE_HEADER_SZ;
10767+
}
10768+
#endif
1076310769

1076410770
/* Make sure input is not the ssl output buffer as this
1076510771
* function doesn't handle that */
@@ -24819,9 +24825,12 @@ int SendCertificate(WOLFSSL* ssl)
2481924825
if (ssl->fragOffset != 0)
2482024826
length -= (ssl->fragOffset + headerSz);
2482124827

24822-
maxFragment = MAX_RECORD_SIZE;
2482324828

24824-
maxFragment = (word32)wolfSSL_GetMaxFragSize(ssl, (int)maxFragment);
24829+
maxFragment = (word32)wolfssl_local_GetMaxPlaintextSize(ssl);
24830+
if (ssl->options.dtls)
24831+
maxFragment -= DTLS_HANDSHAKE_HEADER_SZ;
24832+
else
24833+
maxFragment -= HANDSHAKE_HEADER_SZ;
2482524834

2482624835
while (length > 0 && ret == 0) {
2482724836
byte* output = NULL;
@@ -25598,27 +25607,6 @@ int IsSCR(WOLFSSL* ssl)
2559825607
}
2559925608

2560025609

25601-
#ifdef WOLFSSL_DTLS
25602-
static int ModifyForMTU(WOLFSSL* ssl, int buffSz, int outputSz, int mtuSz)
25603-
{
25604-
int recordExtra = outputSz - buffSz;
25605-
25606-
(void)ssl;
25607-
25608-
if (recordExtra > 0 && outputSz > mtuSz) {
25609-
buffSz = mtuSz - recordExtra;
25610-
#ifndef WOLFSSL_AEAD_ONLY
25611-
/* Subtract a block size to be certain that returned fragment
25612-
* size won't get more padding. */
25613-
if (ssl->specs.cipher_type == block)
25614-
buffSz -= ssl->specs.block_size;
25615-
#endif
25616-
}
25617-
25618-
return buffSz;
25619-
}
25620-
#endif /* WOLFSSL_DTLS */
25621-
2562225610
#if !defined(NO_TLS) && defined(WOLFSSL_TLS13) && \
2562325611
!defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
2562425612
/*
@@ -25996,31 +25984,33 @@ int SendData(WOLFSSL* ssl, const void* data, size_t sz)
2599625984
}
2599725985
#endif /* WOLFSSL_DTLS13 */
2599825986

25999-
buffSz = wolfSSL_GetMaxFragSize(ssl, (word32)sz - sent);
26000-
2600125987
if (sent == (word32)sz) break;
2600225988

26003-
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_DTLS_SIZE_CHECK)
26004-
if (ssl->options.dtls && ((size_t)buffSz < (word32)sz - sent)) {
26005-
error = DTLS_SIZE_ERROR;
26006-
ssl->error = error;
26007-
WOLFSSL_ERROR(error);
26008-
return error;
26009-
}
26010-
#endif
26011-
outputSz = buffSz + COMP_EXTRA + DTLS_RECORD_HEADER_SZ;
26012-
if (IsEncryptionOn(ssl, 1) || ssl->options.tls1_3)
26013-
outputSz += cipherExtraData(ssl);
26014-
26015-
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID)
25989+
buffSz = (word32)sz - sent;
25990+
outputSz = wolfssl_local_GetRecordSize(ssl, (word32)buffSz, 1);
25991+
#if defined(WOLFSSL_DTLS)
2601625992
if (ssl->options.dtls) {
26017-
byte cidSz = 0;
26018-
if ((cidSz = DtlsGetCidTxSize(ssl)) > 0)
26019-
outputSz += cidSz + 1; /* +1 for inner content type */
26020-
}
25993+
#if defined(WOLFSSL_DTLS_MTU)
25994+
int mtu = ssl->dtlsMtuSz;
25995+
#else
25996+
int mtu = MAX_MTU;
2602125997
#endif
25998+
if (outputSz > mtu) {
25999+
#if defined(WOLFSSL_NO_DTLS_SIZE_CHECK)
26000+
/* split instead of error out */
26001+
buffSz = min(buffSz, wolfssl_local_GetMaxPlaintextSize(ssl));
26002+
outputSz = wolfssl_local_GetRecordSize(ssl, (word32)buffSz, 1);
26003+
#else
26004+
error = DTLS_SIZE_ERROR;
26005+
ssl->error = error;
26006+
WOLFSSL_ERROR(error);
26007+
return error;
26008+
#endif /* WOLFSSL_NO_DTLS_SIZE_CHECK */
26009+
}
26010+
}
26011+
#endif /* WOLFSSL_DTLS */
2602226012

26023-
/* check for available size */
26013+
/* check for available size, it does also DTLS MTU checks */
2602426014
if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
2602526015
return (ssl->error = ret);
2602626016

@@ -41838,53 +41828,125 @@ int wolfSSL_AsyncPush(WOLFSSL* ssl, WC_ASYNC_DEV* asyncDev)
4183841828

4183941829
#endif /* WOLFSSL_ASYNC_CRYPT */
4184041830

41831+
#if !defined(NO_TLS)
41832+
/** Return the record size for sending payloadSz of data
41833+
* @param ssl WOLFSSL object
41834+
* @param payloadSz Size of data to be sent in record
41835+
* @param isEncrypted 1 if encryption is on, 0 if not
41836+
* @return Record size for sending payloadSz of data
41837+
*/
41838+
int wolfssl_local_GetRecordSize(WOLFSSL *ssl, int payloadSz, int isEncrypted)
41839+
{
41840+
int recordSz;
4184141841

41842+
if (ssl == NULL)
41843+
return BAD_FUNC_ARG;
41844+
41845+
if (isEncrypted) {
41846+
recordSz = BuildMessage(ssl, NULL, 0, NULL, payloadSz, application_data,
41847+
0, 1, 0, CUR_ORDER);
41848+
/* use a safe upper bound in case of error */
41849+
if (recordSz < 0) {
41850+
recordSz = payloadSz + RECORD_HEADER_SZ
41851+
+ cipherExtraData(ssl) + COMP_EXTRA;
41852+
if (ssl->options.dtls) {
41853+
recordSz += DTLS_RECORD_EXTRA;
41854+
}
41855+
}
41856+
}
41857+
else {
41858+
recordSz = payloadSz + RECORD_HEADER_SZ;
41859+
if (ssl->options.dtls) {
41860+
recordSz += DTLS_RECORD_EXTRA;
41861+
}
41862+
}
41863+
return recordSz;
41864+
}
41865+
#endif
41866+
41867+
/** Return the maximum plaintext size for the current Max Fragment and MTU.
41868+
* @param ssl WOLFSSL object containing ciphersuite information.
41869+
* @return Max plaintext size for current MTU
41870+
*/
41871+
int wolfssl_local_GetMaxPlaintextSize(WOLFSSL *ssl)
41872+
{
41873+
int maxFrag;
41874+
41875+
if (ssl == NULL)
41876+
return BAD_FUNC_ARG;
41877+
41878+
maxFrag = wolfSSL_GetMaxFragSize(ssl);
41879+
41880+
#if defined(WOLFSSL_DTLS)
41881+
if (IsDtlsNotSctpMode(ssl)) {
41882+
int recordSz;
41883+
int mtu;
41884+
41885+
#if defined(WOLFSSL_DTLS_MTU)
41886+
mtu = ssl->dtlsMtuSz;
41887+
#else
41888+
mtu = MAX_MTU;
41889+
#endif
41890+
41891+
recordSz = wolfssl_local_GetRecordSize(ssl, maxFrag,
41892+
IsEncryptionOn(ssl, 1));
41893+
/* record size of maxFrag fits in MTU */
41894+
if (recordSz <= mtu) {
41895+
return maxFrag;
41896+
}
41897+
41898+
/* adjust plaintext size to fit in MTU */
41899+
maxFrag -= (recordSz - mtu);
41900+
if (maxFrag <= 0) {
41901+
WOLFSSL_MSG("MTU too small for any plaintext");
41902+
return DTLS_SIZE_ERROR;
41903+
}
41904+
41905+
#ifndef WOLFSSL_AEAD_ONLY
41906+
/* For block ciphers, reducing maxFrag may change padding alignment,
41907+
* causing the record to still exceed MTU. Iterate to find exact fit.
41908+
* Converges in at most 2 iterations due to bounded padding variance. */
41909+
if (ssl->specs.cipher_type == block) {
41910+
int iter;
41911+
for (iter = 0; iter < 2; iter++) {
41912+
recordSz = wolfssl_local_GetRecordSize(ssl, maxFrag,
41913+
IsEncryptionOn(ssl, 1));
41914+
if (recordSz <= mtu)
41915+
break;
41916+
maxFrag -= (recordSz - mtu);
41917+
}
41918+
if (recordSz > mtu) {
41919+
/* this should never happen */
41920+
WOLFSSL_MSG("Failed to fit record in MTU after padding adjust");
41921+
return DTLS_SIZE_ERROR;
41922+
}
41923+
}
41924+
#endif
41925+
}
41926+
#endif /* WOLFSSL_DTLS */
41927+
41928+
return maxFrag;
41929+
}
4184241930
/**
4184341931
* Return the max fragment size. This is essentially the maximum
4184441932
* fragment_length available.
4184541933
* @param ssl WOLFSSL object containing ciphersuite information.
41846-
* @param maxFragment The amount of space we want to check is available. This
41847-
* is only the fragment length WITHOUT the (D)TLS headers.
4184841934
* @return Max fragment size
4184941935
*/
41850-
int wolfSSL_GetMaxFragSize(WOLFSSL* ssl, int maxFragment)
41936+
int wolfSSL_GetMaxFragSize(WOLFSSL* ssl)
4185141937
{
41852-
(void) ssl; /* Avoid compiler warnings */
41938+
int maxFragment;
4185341939

41854-
if (maxFragment > MAX_RECORD_SIZE) {
41855-
maxFragment = MAX_RECORD_SIZE;
41856-
}
41940+
if (ssl == NULL)
41941+
return BAD_FUNC_ARG;
41942+
41943+
maxFragment = MAX_RECORD_SIZE;
4185741944

4185841945
#ifdef HAVE_MAX_FRAGMENT
4185941946
if ((ssl->max_fragment != 0) && ((word16)maxFragment > ssl->max_fragment)) {
4186041947
maxFragment = ssl->max_fragment;
4186141948
}
4186241949
#endif /* HAVE_MAX_FRAGMENT */
41863-
#ifdef WOLFSSL_DTLS
41864-
if (IsDtlsNotSctpMode(ssl)) {
41865-
int outputSz, mtuSz;
41866-
41867-
/* Given a input buffer size of maxFragment, how big will the
41868-
* encrypted output be? */
41869-
if (IsEncryptionOn(ssl, 1)) {
41870-
outputSz = BuildMessage(ssl, NULL, 0, NULL,
41871-
maxFragment + DTLS_HANDSHAKE_HEADER_SZ,
41872-
application_data, 0, 1, 0, CUR_ORDER);
41873-
}
41874-
else {
41875-
outputSz = maxFragment + DTLS_RECORD_HEADER_SZ +
41876-
DTLS_HANDSHAKE_HEADER_SZ;
41877-
}
41878-
41879-
/* Readjust maxFragment for MTU size. */
41880-
#if defined(WOLFSSL_DTLS_MTU)
41881-
mtuSz = ssl->dtlsMtuSz;
41882-
#else
41883-
mtuSz = MAX_MTU;
41884-
#endif
41885-
maxFragment = ModifyForMTU(ssl, maxFragment, outputSz, mtuSz);
41886-
}
41887-
#endif
4188841950

4188941951
return maxFragment;
4189041952
}

src/ssl.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2905,7 +2905,7 @@ int wolfSSL_GetMaxOutputSize(WOLFSSL* ssl)
29052905
return BAD_FUNC_ARG;
29062906
}
29072907

2908-
return wolfSSL_GetMaxFragSize(ssl, OUTPUT_RECORD_SIZE);
2908+
return min(OUTPUT_RECORD_SIZE, wolfssl_local_GetMaxPlaintextSize(ssl));
29092909
}
29102910

29112911

@@ -2925,8 +2925,7 @@ int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz)
29252925
if (inSz > maxSize)
29262926
return INPUT_SIZE_E;
29272927

2928-
return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0,
2929-
CUR_ORDER);
2928+
return wolfssl_local_GetRecordSize(ssl, inSz, 1);
29302929
}
29312930

29322931

src/tls13.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4522,7 +4522,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
45224522

45234523
{
45244524
#ifdef WOLFSSL_DTLS_CH_FRAG
4525-
word16 maxFrag = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
4525+
word16 maxFrag = wolfssl_local_GetMaxPlaintextSize(ssl);
45264526
word16 lenWithoutExts = args->length;
45274527
#endif
45284528

@@ -8881,7 +8881,7 @@ static int SendTls13Certificate(WOLFSSL* ssl)
88818881
if (ssl->fragOffset != 0)
88828882
length -= (ssl->fragOffset + headerSz);
88838883

8884-
maxFragment = (word32)wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
8884+
maxFragment = (word32)wolfssl_local_GetMaxPlaintextSize(ssl);
88858885

88868886
extIdx = 0;
88878887

0 commit comments

Comments
 (0)