mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-01-26 20:32:19 +01:00
Merge pull request #9513 from rizlik/dtls_header_fix
fix DTLS header headroom accounting
This commit is contained in:
24
src/dtls13.c
24
src/dtls13.c
@@ -979,7 +979,7 @@ static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
|
||||
{
|
||||
int fragLength, rlHeaderLength;
|
||||
int remainingSize, maxFragment;
|
||||
int recordLength;
|
||||
int recordLength, outputSz;
|
||||
byte isEncrypted;
|
||||
byte* output;
|
||||
int ret;
|
||||
@@ -987,23 +987,27 @@ static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
|
||||
isEncrypted = Dtls13TypeIsEncrypted(
|
||||
(enum HandShakeType)ssl->dtls13FragHandshakeType);
|
||||
rlHeaderLength = Dtls13GetRlHeaderLength(ssl, isEncrypted);
|
||||
maxFragment = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
|
||||
maxFragment = wolfssl_local_GetMaxPlaintextSize(ssl);
|
||||
|
||||
remainingSize = ssl->dtls13MessageLength - ssl->dtls13FragOffset;
|
||||
|
||||
while (remainingSize > 0) {
|
||||
|
||||
fragLength = maxFragment - rlHeaderLength - DTLS_HANDSHAKE_HEADER_SZ;
|
||||
|
||||
recordLength = maxFragment;
|
||||
fragLength = maxFragment - DTLS_HANDSHAKE_HEADER_SZ;
|
||||
|
||||
if (fragLength > remainingSize) {
|
||||
fragLength = remainingSize;
|
||||
recordLength =
|
||||
fragLength + rlHeaderLength + DTLS_HANDSHAKE_HEADER_SZ;
|
||||
}
|
||||
|
||||
ret = CheckAvailableSize(ssl, recordLength + MAX_MSG_EXTRA);
|
||||
recordLength = fragLength + rlHeaderLength + DTLS_HANDSHAKE_HEADER_SZ;
|
||||
outputSz = wolfssl_local_GetRecordSize(ssl,
|
||||
fragLength + DTLS_HANDSHAKE_HEADER_SZ, isEncrypted);
|
||||
if (outputSz < 0) {
|
||||
Dtls13FreeFragmentsBuffer(ssl);
|
||||
return recordLength;
|
||||
}
|
||||
|
||||
ret = CheckAvailableSize(ssl, outputSz);
|
||||
if (ret != 0) {
|
||||
Dtls13FreeFragmentsBuffer(ssl);
|
||||
return ret;
|
||||
@@ -1025,7 +1029,7 @@ static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
|
||||
|
||||
ret = Dtls13SendOneFragmentRtx(ssl,
|
||||
(enum HandShakeType)ssl->dtls13FragHandshakeType,
|
||||
(word16)recordLength + MAX_MSG_EXTRA, output, (word32)recordLength, 0);
|
||||
(word16)outputSz, output, (word32)recordLength, 0);
|
||||
if (ret == WC_NO_ERR_TRACE(WANT_WRITE)) {
|
||||
ssl->dtls13FragOffset += fragLength;
|
||||
return ret;
|
||||
@@ -2018,7 +2022,7 @@ int Dtls13HandshakeSend(WOLFSSL* ssl, byte* message, word16 outputSize,
|
||||
return ret;
|
||||
}
|
||||
|
||||
maxFrag = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
|
||||
maxFrag = wolfssl_local_GetMaxPlaintextSize(ssl);
|
||||
maxLen = length;
|
||||
|
||||
if (handshakeType == key_update)
|
||||
|
||||
214
src/internal.c
214
src/internal.c
@@ -10759,7 +10759,13 @@ static int SendHandshakeMsg(WOLFSSL* ssl, byte* input, word32 inputSz,
|
||||
inputSz += HANDSHAKE_HEADER_SZ;
|
||||
rHdrSz = RECORD_HEADER_SZ;
|
||||
}
|
||||
maxFrag = wolfSSL_GetMaxFragSize(ssl, (int)inputSz);
|
||||
maxFrag = wolfssl_local_GetMaxPlaintextSize(ssl);
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (ssl->options.dtls) {
|
||||
/* In DTLS the handshake header is per fragment */
|
||||
maxFrag -= DTLS_HANDSHAKE_HEADER_SZ;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure input is not the ssl output buffer as this
|
||||
* function doesn't handle that */
|
||||
@@ -24819,9 +24825,12 @@ int SendCertificate(WOLFSSL* ssl)
|
||||
if (ssl->fragOffset != 0)
|
||||
length -= (ssl->fragOffset + headerSz);
|
||||
|
||||
maxFragment = MAX_RECORD_SIZE;
|
||||
|
||||
maxFragment = (word32)wolfSSL_GetMaxFragSize(ssl, (int)maxFragment);
|
||||
maxFragment = (word32)wolfssl_local_GetMaxPlaintextSize(ssl);
|
||||
if (ssl->options.dtls)
|
||||
maxFragment -= DTLS_HANDSHAKE_HEADER_SZ;
|
||||
else
|
||||
maxFragment -= HANDSHAKE_HEADER_SZ;
|
||||
|
||||
while (length > 0 && ret == 0) {
|
||||
byte* output = NULL;
|
||||
@@ -25598,27 +25607,6 @@ int IsSCR(WOLFSSL* ssl)
|
||||
}
|
||||
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
static int ModifyForMTU(WOLFSSL* ssl, int buffSz, int outputSz, int mtuSz)
|
||||
{
|
||||
int recordExtra = outputSz - buffSz;
|
||||
|
||||
(void)ssl;
|
||||
|
||||
if (recordExtra > 0 && outputSz > mtuSz) {
|
||||
buffSz = mtuSz - recordExtra;
|
||||
#ifndef WOLFSSL_AEAD_ONLY
|
||||
/* Subtract a block size to be certain that returned fragment
|
||||
* size won't get more padding. */
|
||||
if (ssl->specs.cipher_type == block)
|
||||
buffSz -= ssl->specs.block_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
return buffSz;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
#if !defined(NO_TLS) && defined(WOLFSSL_TLS13) && \
|
||||
!defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
|
||||
/*
|
||||
@@ -25996,31 +25984,33 @@ int SendData(WOLFSSL* ssl, const void* data, size_t sz)
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
buffSz = wolfSSL_GetMaxFragSize(ssl, (word32)sz - sent);
|
||||
|
||||
if (sent == (word32)sz) break;
|
||||
|
||||
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_DTLS_SIZE_CHECK)
|
||||
if (ssl->options.dtls && ((size_t)buffSz < (word32)sz - sent)) {
|
||||
error = DTLS_SIZE_ERROR;
|
||||
ssl->error = error;
|
||||
WOLFSSL_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
outputSz = buffSz + COMP_EXTRA + DTLS_RECORD_HEADER_SZ;
|
||||
if (IsEncryptionOn(ssl, 1) || ssl->options.tls1_3)
|
||||
outputSz += cipherExtraData(ssl);
|
||||
|
||||
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID)
|
||||
buffSz = (word32)sz - sent;
|
||||
outputSz = wolfssl_local_GetRecordSize(ssl, (word32)buffSz, 1);
|
||||
#if defined(WOLFSSL_DTLS)
|
||||
if (ssl->options.dtls) {
|
||||
byte cidSz = 0;
|
||||
if ((cidSz = DtlsGetCidTxSize(ssl)) > 0)
|
||||
outputSz += cidSz + 1; /* +1 for inner content type */
|
||||
}
|
||||
#if defined(WOLFSSL_DTLS_MTU)
|
||||
int mtu = ssl->dtlsMtuSz;
|
||||
#else
|
||||
int mtu = MAX_MTU;
|
||||
#endif
|
||||
if (outputSz > mtu) {
|
||||
#if defined(WOLFSSL_NO_DTLS_SIZE_CHECK)
|
||||
/* split instead of error out */
|
||||
buffSz = min(buffSz, wolfssl_local_GetMaxPlaintextSize(ssl));
|
||||
outputSz = wolfssl_local_GetRecordSize(ssl, (word32)buffSz, 1);
|
||||
#else
|
||||
error = DTLS_SIZE_ERROR;
|
||||
ssl->error = error;
|
||||
WOLFSSL_ERROR(error);
|
||||
return error;
|
||||
#endif /* WOLFSSL_NO_DTLS_SIZE_CHECK */
|
||||
}
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
/* check for available size */
|
||||
/* check for available size, it does also DTLS MTU checks */
|
||||
if ((ret = CheckAvailableSize(ssl, outputSz)) != 0)
|
||||
return (ssl->error = ret);
|
||||
|
||||
@@ -41838,53 +41828,125 @@ int wolfSSL_AsyncPush(WOLFSSL* ssl, WC_ASYNC_DEV* asyncDev)
|
||||
|
||||
#endif /* WOLFSSL_ASYNC_CRYPT */
|
||||
|
||||
#if !defined(NO_TLS)
|
||||
/** Return the record size for sending payloadSz of data
|
||||
* @param ssl WOLFSSL object
|
||||
* @param payloadSz Size of data to be sent in record
|
||||
* @param isEncrypted 1 if encryption is on, 0 if not
|
||||
* @return Record size for sending payloadSz of data
|
||||
*/
|
||||
int wolfssl_local_GetRecordSize(WOLFSSL *ssl, int payloadSz, int isEncrypted)
|
||||
{
|
||||
int recordSz;
|
||||
|
||||
if (ssl == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
if (isEncrypted) {
|
||||
recordSz = BuildMessage(ssl, NULL, 0, NULL, payloadSz, application_data,
|
||||
0, 1, 0, CUR_ORDER);
|
||||
/* use a safe upper bound in case of error */
|
||||
if (recordSz < 0) {
|
||||
recordSz = payloadSz + RECORD_HEADER_SZ
|
||||
+ cipherExtraData(ssl) + COMP_EXTRA;
|
||||
if (ssl->options.dtls) {
|
||||
recordSz += DTLS_RECORD_EXTRA;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
recordSz = payloadSz + RECORD_HEADER_SZ;
|
||||
if (ssl->options.dtls) {
|
||||
recordSz += DTLS_RECORD_EXTRA;
|
||||
}
|
||||
}
|
||||
return recordSz;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Return the maximum plaintext size for the current Max Fragment and MTU.
|
||||
* @param ssl WOLFSSL object containing ciphersuite information.
|
||||
* @return Max plaintext size for current MTU
|
||||
*/
|
||||
int wolfssl_local_GetMaxPlaintextSize(WOLFSSL *ssl)
|
||||
{
|
||||
int maxFrag;
|
||||
|
||||
if (ssl == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
maxFrag = wolfSSL_GetMaxFragSize(ssl);
|
||||
|
||||
#if defined(WOLFSSL_DTLS)
|
||||
if (IsDtlsNotSctpMode(ssl)) {
|
||||
int recordSz;
|
||||
int mtu;
|
||||
|
||||
#if defined(WOLFSSL_DTLS_MTU)
|
||||
mtu = ssl->dtlsMtuSz;
|
||||
#else
|
||||
mtu = MAX_MTU;
|
||||
#endif
|
||||
|
||||
recordSz = wolfssl_local_GetRecordSize(ssl, maxFrag,
|
||||
IsEncryptionOn(ssl, 1));
|
||||
/* record size of maxFrag fits in MTU */
|
||||
if (recordSz <= mtu) {
|
||||
return maxFrag;
|
||||
}
|
||||
|
||||
/* adjust plaintext size to fit in MTU */
|
||||
maxFrag -= (recordSz - mtu);
|
||||
if (maxFrag <= 0) {
|
||||
WOLFSSL_MSG("MTU too small for any plaintext");
|
||||
return DTLS_SIZE_ERROR;
|
||||
}
|
||||
|
||||
#ifndef WOLFSSL_AEAD_ONLY
|
||||
/* For block ciphers, reducing maxFrag may change padding alignment,
|
||||
* causing the record to still exceed MTU. Iterate to find exact fit.
|
||||
* Converges in at most 2 iterations due to bounded padding variance. */
|
||||
if (ssl->specs.cipher_type == block) {
|
||||
int iter;
|
||||
for (iter = 0; iter < 2; iter++) {
|
||||
recordSz = wolfssl_local_GetRecordSize(ssl, maxFrag,
|
||||
IsEncryptionOn(ssl, 1));
|
||||
if (recordSz <= mtu)
|
||||
break;
|
||||
maxFrag -= (recordSz - mtu);
|
||||
}
|
||||
if (recordSz > mtu) {
|
||||
/* this should never happen */
|
||||
WOLFSSL_MSG("Failed to fit record in MTU after padding adjust");
|
||||
return DTLS_SIZE_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
return maxFrag;
|
||||
}
|
||||
/**
|
||||
* Return the max fragment size. This is essentially the maximum
|
||||
* fragment_length available.
|
||||
* @param ssl WOLFSSL object containing ciphersuite information.
|
||||
* @param maxFragment The amount of space we want to check is available. This
|
||||
* is only the fragment length WITHOUT the (D)TLS headers.
|
||||
* @return Max fragment size
|
||||
*/
|
||||
int wolfSSL_GetMaxFragSize(WOLFSSL* ssl, int maxFragment)
|
||||
int wolfSSL_GetMaxFragSize(WOLFSSL* ssl)
|
||||
{
|
||||
(void) ssl; /* Avoid compiler warnings */
|
||||
int maxFragment;
|
||||
|
||||
if (maxFragment > MAX_RECORD_SIZE) {
|
||||
maxFragment = MAX_RECORD_SIZE;
|
||||
}
|
||||
if (ssl == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
maxFragment = MAX_RECORD_SIZE;
|
||||
|
||||
#ifdef HAVE_MAX_FRAGMENT
|
||||
if ((ssl->max_fragment != 0) && ((word16)maxFragment > ssl->max_fragment)) {
|
||||
maxFragment = ssl->max_fragment;
|
||||
}
|
||||
#endif /* HAVE_MAX_FRAGMENT */
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (IsDtlsNotSctpMode(ssl)) {
|
||||
int outputSz, mtuSz;
|
||||
|
||||
/* Given a input buffer size of maxFragment, how big will the
|
||||
* encrypted output be? */
|
||||
if (IsEncryptionOn(ssl, 1)) {
|
||||
outputSz = BuildMessage(ssl, NULL, 0, NULL,
|
||||
maxFragment + DTLS_HANDSHAKE_HEADER_SZ,
|
||||
application_data, 0, 1, 0, CUR_ORDER);
|
||||
}
|
||||
else {
|
||||
outputSz = maxFragment + DTLS_RECORD_HEADER_SZ +
|
||||
DTLS_HANDSHAKE_HEADER_SZ;
|
||||
}
|
||||
|
||||
/* Readjust maxFragment for MTU size. */
|
||||
#if defined(WOLFSSL_DTLS_MTU)
|
||||
mtuSz = ssl->dtlsMtuSz;
|
||||
#else
|
||||
mtuSz = MAX_MTU;
|
||||
#endif
|
||||
maxFragment = ModifyForMTU(ssl, maxFragment, outputSz, mtuSz);
|
||||
}
|
||||
#endif
|
||||
|
||||
return maxFragment;
|
||||
}
|
||||
|
||||
@@ -2905,7 +2905,7 @@ int wolfSSL_GetMaxOutputSize(WOLFSSL* ssl)
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
return wolfSSL_GetMaxFragSize(ssl, OUTPUT_RECORD_SIZE);
|
||||
return min(OUTPUT_RECORD_SIZE, wolfssl_local_GetMaxPlaintextSize(ssl));
|
||||
}
|
||||
|
||||
|
||||
@@ -2925,8 +2925,7 @@ int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz)
|
||||
if (inSz > maxSize)
|
||||
return INPUT_SIZE_E;
|
||||
|
||||
return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0,
|
||||
CUR_ORDER);
|
||||
return wolfssl_local_GetRecordSize(ssl, inSz, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4522,7 +4522,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
|
||||
{
|
||||
#ifdef WOLFSSL_DTLS_CH_FRAG
|
||||
word16 maxFrag = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
|
||||
word16 maxFrag = wolfssl_local_GetMaxPlaintextSize(ssl);
|
||||
word16 lenWithoutExts = args->length;
|
||||
#endif
|
||||
|
||||
@@ -8881,7 +8881,7 @@ static int SendTls13Certificate(WOLFSSL* ssl)
|
||||
if (ssl->fragOffset != 0)
|
||||
length -= (ssl->fragOffset + headerSz);
|
||||
|
||||
maxFragment = (word32)wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
|
||||
maxFragment = (word32)wolfssl_local_GetMaxPlaintextSize(ssl);
|
||||
|
||||
extIdx = 0;
|
||||
|
||||
|
||||
@@ -1487,6 +1487,125 @@ int test_records_span_network_boundaries(void)
|
||||
#endif /* defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
!defined(WOLFSSL_NO_TLS12) */
|
||||
|
||||
int test_dtls_mtu_fragment_headroom(void)
|
||||
{
|
||||
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
defined(WOLFSSL_DTLS_MTU) && defined(HAVE_AESGCM) && defined(HAVE_ECC) && \
|
||||
!defined(WOLFSSL_NO_DTLS_SIZE_CHECK)
|
||||
EXPECT_DECLS;
|
||||
struct {
|
||||
method_provider client_meth;
|
||||
method_provider server_meth;
|
||||
const char* cipher;
|
||||
int use_cid;
|
||||
} params[] = {
|
||||
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13)
|
||||
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
|
||||
"TLS13-AES128-GCM-SHA256", 0 },
|
||||
#ifdef WOLFSSL_DTLS_CID
|
||||
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
|
||||
"TLS13-AES128-GCM-SHA256", 1 },
|
||||
#endif
|
||||
#endif
|
||||
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)
|
||||
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
|
||||
"ECDHE-RSA-AES128-GCM-SHA256", 0 },
|
||||
#ifdef WOLFSSL_DTLS_CID
|
||||
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
|
||||
"ECDHE-RSA-AES128-GCM-SHA256", 1 },
|
||||
#endif
|
||||
#if !defined(WOLFSSL_AEAD_ONLY) && !defined(NO_AES) && !defined(NO_SHA)
|
||||
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
|
||||
"ECDHE-RSA-AES128-SHA", 0 },
|
||||
#ifdef WOLFSSL_DTLS_CID
|
||||
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
|
||||
"ECDHE-RSA-AES128-SHA", 1 },
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < XELEM_CNT(params) && EXPECT_SUCCESS(); i++) {
|
||||
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
|
||||
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
unsigned char payload[33];
|
||||
word16 mtu;
|
||||
int recordLen;
|
||||
int overhead;
|
||||
int ret;
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
XMEMSET(payload, 'A', sizeof(payload));
|
||||
|
||||
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
||||
params[i].client_meth, params[i].server_meth),
|
||||
0);
|
||||
|
||||
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, params[i].cipher), 1);
|
||||
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, params[i].cipher), 1);
|
||||
|
||||
#ifdef WOLFSSL_DTLS_CID
|
||||
if (params[i].use_cid) {
|
||||
unsigned char cid_c[] = { 0,1,2,3 };
|
||||
unsigned char cid_s[] = { 4,5,6,7,8,9 };
|
||||
ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_c), 1);
|
||||
ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_s), 1);
|
||||
ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_c, cid_s, (int)sizeof(cid_s)),
|
||||
1);
|
||||
ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_s, cid_c, (int)sizeof(cid_c)),
|
||||
1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Complete handshake and clear any leftover records. */
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
test_memio_clear_buffer(&test_ctx, 1);
|
||||
test_memio_clear_buffer(&test_ctx, 0);
|
||||
|
||||
/* Measure application-data record overhead. */
|
||||
ExpectIntEQ(wolfSSL_write(ssl_c, payload, 32), 32);
|
||||
ExpectIntEQ(test_ctx.s_msg_count, 1);
|
||||
recordLen = test_ctx.s_len;
|
||||
ExpectIntGT(recordLen, 32);
|
||||
overhead = recordLen - 32;
|
||||
|
||||
/* Reset buffers before MTU-limited send. */
|
||||
test_memio_clear_buffer(&test_ctx, 0);
|
||||
test_memio_clear_buffer(&test_ctx, 1);
|
||||
|
||||
/* Set MTU to overhead + 32 bytes of payload. */
|
||||
mtu = (word16)(overhead + 32);
|
||||
ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, mtu), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_s, mtu), WOLFSSL_SUCCESS);
|
||||
|
||||
/* With the tightened MTU, we should still be able to send 32 bytes. */
|
||||
ExpectIntEQ(wolfSSL_write(ssl_c, payload, 32), 32);
|
||||
ExpectIntEQ(test_ctx.s_msg_count, 1);
|
||||
recordLen = test_ctx.s_len;
|
||||
ExpectIntEQ(recordLen, overhead + 32);
|
||||
ExpectIntLE(recordLen, mtu);
|
||||
|
||||
/* Underestimation: drop MTU by 1 and expect DTLS_SIZE_ERROR. */
|
||||
test_memio_clear_buffer(&test_ctx, 0);
|
||||
test_memio_clear_buffer(&test_ctx, 1);
|
||||
ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, mtu - 1), WOLFSSL_SUCCESS);
|
||||
ret = wolfSSL_write(ssl_c, payload, 32);
|
||||
ExpectIntNE(ret, 32);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, ret), DTLS_SIZE_ERROR);
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
}
|
||||
return EXPECT_RESULT();
|
||||
#else
|
||||
return TEST_SKIPPED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int test_dtls_rtx_across_epoch_change(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
@@ -2257,3 +2376,116 @@ int test_dtls_memio_wolfio_stateless(void)
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
int test_dtls_mtu_split_messages(void)
|
||||
{
|
||||
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_NO_DTLS_SIZE_CHECK) && \
|
||||
defined(HAVE_AESGCM) && defined(HAVE_ECC)
|
||||
EXPECT_DECLS;
|
||||
struct {
|
||||
method_provider client_meth;
|
||||
method_provider server_meth;
|
||||
const char* cipher;
|
||||
} params[] = {
|
||||
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13)
|
||||
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
|
||||
"TLS13-AES128-GCM-SHA256" },
|
||||
#endif
|
||||
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)
|
||||
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
|
||||
"ECDHE-RSA-AES128-GCM-SHA256" },
|
||||
#if !defined(WOLFSSL_AEAD_ONLY) && !defined(NO_AES) && !defined(NO_SHA)
|
||||
/* Block cipher test */
|
||||
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
|
||||
"ECDHE-RSA-AES128-SHA" },
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < XELEM_CNT(params) && EXPECT_SUCCESS(); i++) {
|
||||
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
|
||||
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
/* Payload larger than typical MTU to force splitting */
|
||||
unsigned char payload[200];
|
||||
unsigned char readBuf[200];
|
||||
word16 mtu;
|
||||
int recordLen;
|
||||
int overhead;
|
||||
int totalRead;
|
||||
int ret;
|
||||
int j;
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
XMEMSET(payload, 'A', sizeof(payload));
|
||||
|
||||
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
||||
params[i].client_meth, params[i].server_meth),
|
||||
0);
|
||||
|
||||
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, params[i].cipher), 1);
|
||||
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, params[i].cipher), 1);
|
||||
|
||||
/* Complete handshake and clear any leftover records. */
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
test_memio_clear_buffer(&test_ctx, 1);
|
||||
test_memio_clear_buffer(&test_ctx, 0);
|
||||
|
||||
/* Measure application-data record overhead with small payload. */
|
||||
ExpectIntEQ(wolfSSL_write(ssl_c, payload, 32), 32);
|
||||
ExpectIntEQ(test_ctx.s_msg_count, 1);
|
||||
recordLen = test_ctx.s_len;
|
||||
ExpectIntGT(recordLen, 32);
|
||||
overhead = recordLen - 32;
|
||||
|
||||
/* Reset buffers before MTU-limited send. */
|
||||
test_memio_clear_buffer(&test_ctx, 0);
|
||||
test_memio_clear_buffer(&test_ctx, 1);
|
||||
|
||||
/* Set MTU to allow only ~50 bytes of payload per record.
|
||||
* This ensures a 200-byte payload must be split into multiple msgs. */
|
||||
mtu = (word16)(overhead + 50);
|
||||
ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, mtu), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_s, mtu), WOLFSSL_SUCCESS);
|
||||
|
||||
/* Write payload larger than MTU allows in single record.
|
||||
* With WOLFSSL_NO_DTLS_SIZE_CHECK, this should split into multiple
|
||||
* messages instead of returning DTLS_SIZE_ERROR. */
|
||||
ExpectIntEQ(wolfSSL_write(ssl_c, payload, (int)sizeof(payload)),
|
||||
(int)sizeof(payload));
|
||||
|
||||
/* Verify multiple messages were sent */
|
||||
ExpectIntGT(test_ctx.s_msg_count, 1);
|
||||
|
||||
/* Each record should fit within MTU */
|
||||
for (j = 0; j < test_ctx.s_msg_count && EXPECT_SUCCESS(); j++) {
|
||||
ExpectIntLE(test_ctx.s_msg_sizes[j], mtu);
|
||||
}
|
||||
|
||||
/* Read all data on server side and verify it matches */
|
||||
totalRead = 0;
|
||||
while (totalRead < (int)sizeof(payload) && EXPECT_SUCCESS()) {
|
||||
ret = wolfSSL_read(ssl_s, readBuf + totalRead,
|
||||
(int)sizeof(readBuf) - totalRead);
|
||||
if (ret > 0) {
|
||||
totalRead += ret;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ExpectIntEQ(totalRead, (int)sizeof(payload));
|
||||
ExpectIntEQ(XMEMCMP(payload, readBuf, sizeof(payload)), 0);
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
}
|
||||
return EXPECT_RESULT();
|
||||
#else
|
||||
return TEST_SKIPPED;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ int test_dtls_timeout(void);
|
||||
int test_dtls_certreq_order(void);
|
||||
int test_dtls_memio_wolfio(void);
|
||||
int test_dtls_memio_wolfio_stateless(void);
|
||||
int test_dtls_mtu_fragment_headroom(void);
|
||||
int test_dtls_mtu_split_messages(void);
|
||||
|
||||
#define TEST_DTLS_DECLS \
|
||||
TEST_DECL_GROUP("dtls", test_dtls12_basic_connection_id), \
|
||||
@@ -73,5 +75,7 @@ int test_dtls_memio_wolfio_stateless(void);
|
||||
TEST_DECL_GROUP("dtls", test_dtls_certreq_order), \
|
||||
TEST_DECL_GROUP("dtls", test_dtls_timeout), \
|
||||
TEST_DECL_GROUP("dtls", test_dtls_memio_wolfio), \
|
||||
TEST_DECL_GROUP("dtls", test_dtls_mtu_fragment_headroom), \
|
||||
TEST_DECL_GROUP("dtls", test_dtls_mtu_split_messages), \
|
||||
TEST_DECL_GROUP("dtls", test_dtls_memio_wolfio_stateless)
|
||||
#endif /* TESTS_API_DTLS_H */
|
||||
|
||||
@@ -6596,7 +6596,10 @@ WOLFSSL_LOCAL int VerifyClientSuite(word16 havePSK, byte cipherSuite0,
|
||||
byte cipherSuite);
|
||||
|
||||
WOLFSSL_LOCAL int SetTicket(WOLFSSL* ssl, const byte* ticket, word32 length);
|
||||
WOLFSSL_LOCAL int wolfSSL_GetMaxFragSize(WOLFSSL* ssl, int maxFragment);
|
||||
WOLFSSL_LOCAL int wolfssl_local_GetRecordSize(WOLFSSL *ssl, int payloadSz,
|
||||
int isEncrypted);
|
||||
WOLFSSL_LOCAL int wolfssl_local_GetMaxPlaintextSize(WOLFSSL *ssl);
|
||||
WOLFSSL_LOCAL int wolfSSL_GetMaxFragSize(WOLFSSL* ssl);
|
||||
|
||||
#if defined(WOLFSSL_IOTSAFE) && defined(HAVE_PK_CALLBACKS)
|
||||
WOLFSSL_LOCAL IOTSAFE *wolfSSL_get_iotsafe_ctx(WOLFSSL *ssl);
|
||||
|
||||
Reference in New Issue
Block a user