Skip to content

Commit 0c9b639

Browse files
authored
Merge pull request #10103 from gasbytes/fix-dtls13-oversized-cert-chain
Fix DTLS 1.3 extSz out-of-bounds and word16 truncation on oversized certificate chains
2 parents d278da0 + 1653ecd commit 0c9b639

File tree

4 files changed

+112
-3
lines changed

4 files changed

+112
-3
lines changed

src/dtls13.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,10 @@ static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
10421042
Dtls13FreeFragmentsBuffer(ssl);
10431043
return outputSz;
10441044
}
1045+
if ((word32)outputSz > WOLFSSL_MAX_16BIT) {
1046+
Dtls13FreeFragmentsBuffer(ssl);
1047+
return BUFFER_E;
1048+
}
10451049

10461050
ret = CheckAvailableSize(ssl, outputSz);
10471051
if (ret != 0) {
@@ -1636,6 +1640,10 @@ static int Dtls13RtxSendBuffered(WOLFSSL* ssl)
16361640
if (!w64IsZero(r->epoch))
16371641
sendSz += MAX_MSG_EXTRA;
16381642

1643+
if ((word32)sendSz > WOLFSSL_MAX_16BIT) {
1644+
return BUFFER_E;
1645+
}
1646+
16391647
ret = CheckAvailableSize(ssl, sendSz);
16401648
if (ret != 0)
16411649
return ret;

src/tls13.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9291,7 +9291,7 @@ static int SendTls13Certificate(WOLFSSL* ssl)
92919291
break;
92929292
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
92939293
!defined(NO_WOLFSSL_SERVER)
9294-
if (MAX_CERT_EXTENSIONS > extIdx)
9294+
if (extIdx + 1 < MAX_CERT_EXTENSIONS)
92959295
extIdx++;
92969296
#endif
92979297
}
@@ -9324,6 +9324,10 @@ static int SendTls13Certificate(WOLFSSL* ssl)
93249324
/* DTLS1.3 uses a separate variable and logic for fragments */
93259325
ssl->options.buildingMsg = 0;
93269326
ssl->fragOffset = 0;
9327+
if ((word32)sendSz > WOLFSSL_MAX_16BIT || i > WOLFSSL_MAX_16BIT) {
9328+
WOLFSSL_MSG("Send Cert DTLS size exceeds word16");
9329+
return BUFFER_E;
9330+
}
93279331
ret = Dtls13HandshakeSend(ssl, output, (word16)sendSz, (word16)i,
93289332
certificate, 1);
93299333
}

tests/api/test_dtls.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2814,3 +2814,98 @@ int test_dtls13_no_session_id_echo(void)
28142814
#endif
28152815
return EXPECT_RESULT();
28162816
}
2817+
2818+
/* Test that a DTLS 1.3 handshake with an oversized certificate chain does
2819+
* not crash or cause out-of-bounds access in SendTls13Certificate. */
2820+
int test_dtls13_oversized_cert_chain(void)
2821+
{
2822+
EXPECT_DECLS;
2823+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
2824+
&& !defined(NO_FILESYSTEM) && !defined(NO_RSA)
2825+
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
2826+
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
2827+
struct test_memio_ctx test_ctx;
2828+
XFILE f = XBADFILE;
2829+
long sz = 0;
2830+
byte *cert = NULL;
2831+
byte *chain = NULL;
2832+
int copies, off, i;
2833+
2834+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
2835+
2836+
/* Read server cert */
2837+
f = XFOPEN(svrCertFile, "rb");
2838+
ExpectTrue(f != XBADFILE);
2839+
if (EXPECT_SUCCESS()) {
2840+
(void)XFSEEK(f, 0, XSEEK_END);
2841+
sz = XFTELL(f);
2842+
(void)XFSEEK(f, 0, XSEEK_SET);
2843+
}
2844+
ExpectTrue(sz > 0);
2845+
cert = (byte*)XMALLOC((size_t)(sz + 1), NULL, DYNAMIC_TYPE_TMP_BUFFER);
2846+
ExpectNotNull(cert);
2847+
if (EXPECT_SUCCESS())
2848+
ExpectIntEQ((int)XFREAD(cert, 1, (size_t)sz, f), (int)sz);
2849+
if (f != XBADFILE)
2850+
XFCLOSE(f);
2851+
2852+
/* Build an oversized chain by duplicating the cert */
2853+
copies = EXPECT_SUCCESS() ? (int)(70000 / sz) + 2 : 0;
2854+
chain = (byte*)XMALLOC((size_t)(sz * copies + 1), NULL,
2855+
DYNAMIC_TYPE_TMP_BUFFER);
2856+
ExpectNotNull(chain);
2857+
off = 0;
2858+
if (EXPECT_SUCCESS()) {
2859+
for (i = 0; i < copies; i++) {
2860+
XMEMCPY(chain + off, cert, (size_t)sz);
2861+
off += (int)sz;
2862+
}
2863+
}
2864+
2865+
/* Server context: load the oversized chain */
2866+
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfDTLSv1_3_server_method()));
2867+
ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx_s,
2868+
chain, (long)off), WOLFSSL_SUCCESS);
2869+
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
2870+
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
2871+
if (EXPECT_SUCCESS()) {
2872+
wolfSSL_SetIORecv(ctx_s, test_memio_read_cb);
2873+
wolfSSL_SetIOSend(ctx_s, test_memio_write_cb);
2874+
}
2875+
2876+
/* Client context: no verification (chain certs are duplicates) */
2877+
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfDTLSv1_3_client_method()));
2878+
if (EXPECT_SUCCESS()) {
2879+
wolfSSL_CTX_set_verify(ctx_c, WOLFSSL_VERIFY_NONE, NULL);
2880+
wolfSSL_SetIORecv(ctx_c, test_memio_read_cb);
2881+
wolfSSL_SetIOSend(ctx_c, test_memio_write_cb);
2882+
}
2883+
2884+
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
2885+
if (EXPECT_SUCCESS()) {
2886+
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
2887+
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
2888+
}
2889+
2890+
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
2891+
if (EXPECT_SUCCESS()) {
2892+
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
2893+
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
2894+
}
2895+
2896+
/* Handshake must not crash. If SendTls13Certificate mishandles the
2897+
* oversized chain this will trigger a wild pointer dereference or stack
2898+
* overflow resulting with the test failing.
2899+
* The correct behaviour either returns BUFFER_E or succeeds
2900+
* if the build config truncated the chain during loading. */
2901+
(void)test_memio_do_handshake(ssl_c, ssl_s, 10, NULL);
2902+
2903+
wolfSSL_free(ssl_c);
2904+
wolfSSL_free(ssl_s);
2905+
wolfSSL_CTX_free(ctx_c);
2906+
wolfSSL_CTX_free(ctx_s);
2907+
XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2908+
XFREE(chain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2909+
#endif
2910+
return EXPECT_RESULT();
2911+
}

tests/api/test_dtls.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ int test_dtls_mtu_fragment_headroom(void);
5353
int test_dtls_mtu_split_messages(void);
5454
int test_dtls13_min_rtx_interval(void);
5555
int test_dtls13_no_session_id_echo(void);
56+
int test_dtls13_oversized_cert_chain(void);
5657

5758
#define TEST_DTLS_DECLS \
5859
TEST_DECL_GROUP("dtls", test_dtls12_basic_connection_id), \
@@ -84,6 +85,7 @@ int test_dtls13_no_session_id_echo(void);
8485
TEST_DECL_GROUP("dtls", test_dtls_mtu_fragment_headroom), \
8586
TEST_DECL_GROUP("dtls", test_dtls_mtu_split_messages), \
8687
TEST_DECL_GROUP("dtls", test_dtls_memio_wolfio_stateless), \
87-
TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \
88-
TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo)
88+
TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \
89+
TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo), \
90+
TEST_DECL_GROUP("dtls", test_dtls13_oversized_cert_chain)
8991
#endif /* TESTS_API_DTLS_H */

0 commit comments

Comments
 (0)