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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/dtls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,10 @@ static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
Dtls13FreeFragmentsBuffer(ssl);
return outputSz;
}
if ((word32)outputSz > WOLFSSL_MAX_16BIT) {
Dtls13FreeFragmentsBuffer(ssl);
return BUFFER_E;
}

ret = CheckAvailableSize(ssl, outputSz);
if (ret != 0) {
Expand Down Expand Up @@ -1636,6 +1640,10 @@ static int Dtls13RtxSendBuffered(WOLFSSL* ssl)
if (!w64IsZero(r->epoch))
sendSz += MAX_MSG_EXTRA;

if ((word32)sendSz > WOLFSSL_MAX_16BIT) {
return BUFFER_E;
}

ret = CheckAvailableSize(ssl, sendSz);
if (ret != 0)
return ret;
Expand Down
6 changes: 5 additions & 1 deletion src/tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -9291,7 +9291,7 @@ static int SendTls13Certificate(WOLFSSL* ssl)
break;
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
!defined(NO_WOLFSSL_SERVER)
if (MAX_CERT_EXTENSIONS > extIdx)
if (extIdx + 1 < MAX_CERT_EXTENSIONS)
extIdx++;
#endif
}
Expand Down Expand Up @@ -9324,6 +9324,10 @@ static int SendTls13Certificate(WOLFSSL* ssl)
/* DTLS1.3 uses a separate variable and logic for fragments */
ssl->options.buildingMsg = 0;
ssl->fragOffset = 0;
if ((word32)sendSz > WOLFSSL_MAX_16BIT || i > WOLFSSL_MAX_16BIT) {
WOLFSSL_MSG("Send Cert DTLS size exceeds word16");
return BUFFER_E;
}
ret = Dtls13HandshakeSend(ssl, output, (word16)sendSz, (word16)i,
certificate, 1);
}
Expand Down
95 changes: 95 additions & 0 deletions tests/api/test_dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -2814,3 +2814,98 @@ int test_dtls13_no_session_id_echo(void)
#endif
return EXPECT_RESULT();
}

/* Test that a DTLS 1.3 handshake with an oversized certificate chain does
* not crash or cause out-of-bounds access in SendTls13Certificate. */
int test_dtls13_oversized_cert_chain(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
&& !defined(NO_FILESYSTEM) && !defined(NO_RSA)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
XFILE f = XBADFILE;
long sz = 0;
byte *cert = NULL;
byte *chain = NULL;
int copies, off, i;

XMEMSET(&test_ctx, 0, sizeof(test_ctx));

/* Read server cert */
f = XFOPEN(svrCertFile, "rb");
ExpectTrue(f != XBADFILE);
if (EXPECT_SUCCESS()) {
(void)XFSEEK(f, 0, XSEEK_END);
sz = XFTELL(f);
(void)XFSEEK(f, 0, XSEEK_SET);
}
ExpectTrue(sz > 0);
cert = (byte*)XMALLOC((size_t)(sz + 1), NULL, DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(cert);
if (EXPECT_SUCCESS())
ExpectIntEQ((int)XFREAD(cert, 1, (size_t)sz, f), (int)sz);
if (f != XBADFILE)
XFCLOSE(f);

/* Build an oversized chain by duplicating the cert */
copies = EXPECT_SUCCESS() ? (int)(70000 / sz) + 2 : 0;
chain = (byte*)XMALLOC((size_t)(sz * copies + 1), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(chain);
off = 0;
if (EXPECT_SUCCESS()) {
for (i = 0; i < copies; i++) {
XMEMCPY(chain + off, cert, (size_t)sz);
off += (int)sz;
}
}

/* Server context: load the oversized chain */
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfDTLSv1_3_server_method()));
ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx_s,
chain, (long)off), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
if (EXPECT_SUCCESS()) {
wolfSSL_SetIORecv(ctx_s, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_s, test_memio_write_cb);
}

/* Client context: no verification (chain certs are duplicates) */
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfDTLSv1_3_client_method()));
if (EXPECT_SUCCESS()) {
wolfSSL_CTX_set_verify(ctx_c, WOLFSSL_VERIFY_NONE, NULL);
wolfSSL_SetIORecv(ctx_c, test_memio_read_cb);
wolfSSL_SetIOSend(ctx_c, test_memio_write_cb);
}

ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
if (EXPECT_SUCCESS()) {
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
}

ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
if (EXPECT_SUCCESS()) {
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
}

/* Handshake must not crash. If SendTls13Certificate mishandles the
* oversized chain this will trigger a wild pointer dereference or stack
* overflow resulting with the test failing.
* The correct behaviour either returns BUFFER_E or succeeds
* if the build config truncated the chain during loading. */
(void)test_memio_do_handshake(ssl_c, ssl_s, 10, NULL);

wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(chain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
}
6 changes: 4 additions & 2 deletions tests/api/test_dtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ int test_dtls_mtu_fragment_headroom(void);
int test_dtls_mtu_split_messages(void);
int test_dtls13_min_rtx_interval(void);
int test_dtls13_no_session_id_echo(void);
int test_dtls13_oversized_cert_chain(void);

#define TEST_DTLS_DECLS \
TEST_DECL_GROUP("dtls", test_dtls12_basic_connection_id), \
Expand Down Expand Up @@ -84,6 +85,7 @@ int test_dtls13_no_session_id_echo(void);
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), \
TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \
TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo)
TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \
TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo), \
TEST_DECL_GROUP("dtls", test_dtls13_oversized_cert_chain)
#endif /* TESTS_API_DTLS_H */
Loading