Fix DTLS 1.3 extSz out-of-bounds and word16 truncation on oversized certificate chains

This commit is contained in:
Reda Chouk
2026-03-30 18:08:38 +02:00
parent 24f9981877
commit 1653ecd07e
4 changed files with 112 additions and 3 deletions
+8
View File
@@ -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) {
@@ -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;
+5 -1
View File
@@ -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
}
@@ -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);
}
+95
View File
@@ -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();
}
+4 -2
View File
@@ -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), \
@@ -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 */