@@ -33418,6 +33418,197 @@ static int test_ocsp_callback_fails(void)
3341833418 defined(HAVE_OCSP) && \
3341933419 defined(HAVE_CERTIFICATE_STATUS_REQUEST) */
3342033420
33421+ /* ---------------------------------------------------------------------------
33422+ * Tests for non-blocking OCSP with fragmented handshake messages.
33423+ *
33424+ * Reproducer for: https://github.com/wolfSSL/wolfssl/pull/9957
33425+ *
33426+ * When WOLFSSL_NONBLOCK_OCSP is enabled without WOLFSSL_ASYNC_CRYPT and the
33427+ * Certificate handshake message is fragmented (due to a low MFL), the
33428+ * pendingMsg buffer was incorrectly freed after DoTls13HandShakeMsgType
33429+ * returned OCSP_WANT_READ. On re-entry the assembled certificate data is
33430+ * gone, causing BUFFER_ERROR.
33431+ *
33432+ * The same pattern applies to the TLS 1.2 code path in DoHandShakeMsg
33433+ * (internal.c).
33434+ *
33435+ * Strategy: use an OCSP IO callback that always returns WANT_READ. Step
33436+ * through the handshake and verify we keep getting OCSP_WANT_READ (the
33437+ * buffer is preserved) rather than BUFFER_ERROR (the buffer was freed).
33438+ * --------------------------------------------------------------------------- */
33439+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
33440+ defined(HAVE_OCSP) && defined(WOLFSSL_NONBLOCK_OCSP) && \
33441+ defined(HAVE_MAX_FRAGMENT)
33442+
33443+ static int test_ocsp_nonblock_frag_cb(void* ctx, const char* url, int urlSz,
33444+ unsigned char* request, int requestSz, unsigned char** response)
33445+ {
33446+ (void)ctx;
33447+ (void)url;
33448+ (void)urlSz;
33449+ (void)request;
33450+ (void)requestSz;
33451+ (void)response;
33452+ return WOLFSSL_CBIO_ERR_WANT_READ;
33453+ }
33454+
33455+ static void test_ocsp_nonblock_frag_resp_free(void* ctx,
33456+ unsigned char* response)
33457+ {
33458+ (void)ctx;
33459+ (void)response;
33460+ }
33461+
33462+ static int test_ocsp_nonblock_frag_do_handshake(WOLFSSL* ssl_c,
33463+ WOLFSSL* ssl_s, int max_rounds)
33464+ {
33465+ byte hs_c = 0, hs_s = 0;
33466+ int ret, err;
33467+
33468+ while (!(hs_c && hs_s) && max_rounds-- > 0) {
33469+ if (!hs_c) {
33470+ ret = wolfSSL_connect(ssl_c);
33471+ if (ret == WOLFSSL_SUCCESS) {
33472+ hs_c = 1;
33473+ }
33474+ else {
33475+ err = wolfSSL_get_error(ssl_c, ret);
33476+ if (err == WC_NO_ERR_TRACE(BUFFER_ERROR))
33477+ return BUFFER_ERROR;
33478+ if (err != WOLFSSL_ERROR_WANT_READ &&
33479+ err != WOLFSSL_ERROR_WANT_WRITE &&
33480+ err != WC_NO_ERR_TRACE(OCSP_WANT_READ)) {
33481+ return err;
33482+ }
33483+ }
33484+ }
33485+ if (!hs_s) {
33486+ ret = wolfSSL_accept(ssl_s);
33487+ if (ret == WOLFSSL_SUCCESS) {
33488+ hs_s = 1;
33489+ }
33490+ else {
33491+ err = wolfSSL_get_error(ssl_s, ret);
33492+ if (err == WC_NO_ERR_TRACE(BUFFER_ERROR))
33493+ return BUFFER_ERROR;
33494+ if (err != WOLFSSL_ERROR_WANT_READ &&
33495+ err != WOLFSSL_ERROR_WANT_WRITE &&
33496+ err != WC_NO_ERR_TRACE(OCSP_WANT_READ)) {
33497+ return err;
33498+ }
33499+ }
33500+ }
33501+ }
33502+ if (hs_c && hs_s)
33503+ return 0;
33504+ return WOLFSSL_ERROR_WANT_READ;
33505+ }
33506+
33507+ #if defined(WOLFSSL_TLS13)
33508+ static int test_tls13_nonblock_ocsp_fragment(void)
33509+ {
33510+ EXPECT_DECLS;
33511+ WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
33512+ WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
33513+ struct test_memio_ctx test_ctx;
33514+ int ret;
33515+
33516+ XMEMSET(&test_ctx, 0, sizeof(test_ctx));
33517+
33518+ ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
33519+ wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
33520+
33521+ ExpectIntEQ(wolfSSL_CTX_EnableOCSP(ctx_c,
33522+ WOLFSSL_OCSP_CHECKALL | WOLFSSL_OCSP_URL_OVERRIDE), WOLFSSL_SUCCESS);
33523+ ExpectIntEQ(wolfSSL_CTX_SetOCSP_OverrideURL(ctx_c, "http://127.0.0.1:0"),
33524+ WOLFSSL_SUCCESS);
33525+ ExpectIntEQ(wolfSSL_CTX_SetOCSP_Cb(ctx_c,
33526+ test_ocsp_nonblock_frag_cb, test_ocsp_nonblock_frag_resp_free, NULL),
33527+ WOLFSSL_SUCCESS);
33528+
33529+ /* MFL 1024 — small enough to fragment a typical Certificate message */
33530+ ExpectIntEQ(wolfSSL_UseMaxFragment(ssl_c, WOLFSSL_MFL_2_10),
33531+ WOLFSSL_SUCCESS);
33532+
33533+ if (EXPECT_SUCCESS()) {
33534+ ret = test_ocsp_nonblock_frag_do_handshake(ssl_c, ssl_s, 20);
33535+ /* Handshake won't complete (OCSP never finishes), but the critical
33536+ * assertion is that we never got BUFFER_ERROR. */
33537+ ExpectIntNE(ret, BUFFER_ERROR);
33538+ }
33539+
33540+ wolfSSL_free(ssl_c);
33541+ wolfSSL_free(ssl_s);
33542+ wolfSSL_CTX_free(ctx_c);
33543+ wolfSSL_CTX_free(ctx_s);
33544+
33545+ return EXPECT_RESULT();
33546+ }
33547+ #else
33548+ static int test_tls13_nonblock_ocsp_fragment(void)
33549+ {
33550+ return TEST_SKIPPED;
33551+ }
33552+ #endif /* WOLFSSL_TLS13 */
33553+
33554+ #if !defined(WOLFSSL_NO_TLS12)
33555+ static int test_tls12_nonblock_ocsp_fragment(void)
33556+ {
33557+ EXPECT_DECLS;
33558+ WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
33559+ WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
33560+ struct test_memio_ctx test_ctx;
33561+ int ret;
33562+
33563+ XMEMSET(&test_ctx, 0, sizeof(test_ctx));
33564+
33565+ ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
33566+ wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
33567+
33568+ ExpectIntEQ(wolfSSL_CTX_EnableOCSP(ctx_c,
33569+ WOLFSSL_OCSP_CHECKALL | WOLFSSL_OCSP_URL_OVERRIDE), WOLFSSL_SUCCESS);
33570+ ExpectIntEQ(wolfSSL_CTX_SetOCSP_OverrideURL(ctx_c, "http://127.0.0.1:0"),
33571+ WOLFSSL_SUCCESS);
33572+ ExpectIntEQ(wolfSSL_CTX_SetOCSP_Cb(ctx_c,
33573+ test_ocsp_nonblock_frag_cb, test_ocsp_nonblock_frag_resp_free, NULL),
33574+ WOLFSSL_SUCCESS);
33575+
33576+ /* MFL 1024 — small enough to fragment a typical Certificate message */
33577+ ExpectIntEQ(wolfSSL_UseMaxFragment(ssl_c, WOLFSSL_MFL_2_10),
33578+ WOLFSSL_SUCCESS);
33579+
33580+ if (EXPECT_SUCCESS()) {
33581+ ret = test_ocsp_nonblock_frag_do_handshake(ssl_c, ssl_s, 20);
33582+ ExpectIntNE(ret, BUFFER_ERROR);
33583+ }
33584+
33585+ wolfSSL_free(ssl_c);
33586+ wolfSSL_free(ssl_s);
33587+ wolfSSL_CTX_free(ctx_c);
33588+ wolfSSL_CTX_free(ctx_s);
33589+
33590+ return EXPECT_RESULT();
33591+ }
33592+ #else
33593+ static int test_tls12_nonblock_ocsp_fragment(void)
33594+ {
33595+ return TEST_SKIPPED;
33596+ }
33597+ #endif /* !WOLFSSL_NO_TLS12 */
33598+
33599+ #else /* !HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES || !HAVE_OCSP ||
33600+ * !WOLFSSL_NONBLOCK_OCSP || !HAVE_MAX_FRAGMENT */
33601+ static int test_tls13_nonblock_ocsp_fragment(void)
33602+ {
33603+ return TEST_SKIPPED;
33604+ }
33605+ static int test_tls12_nonblock_ocsp_fragment(void)
33606+ {
33607+ return TEST_SKIPPED;
33608+ }
33609+ #endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES && HAVE_OCSP &&
33610+ * WOLFSSL_NONBLOCK_OCSP && HAVE_MAX_FRAGMENT */
33611+
3342133612#ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES
3342233613static int test_wolfSSL_SSLDisableRead_recv(WOLFSSL *ssl, char *buf, int sz,
3342333614 void *ctx)
@@ -34411,6 +34602,10 @@ TEST_CASE testCases[] = {
3441134602 TEST_DECL(test_self_signed_stapling),
3441234603 TEST_DECL(test_ocsp_callback_fails),
3441334604
34605+ /* Non-blocking OCSP with fragmented handshake (PR #9957) */
34606+ TEST_DECL(test_tls13_nonblock_ocsp_fragment),
34607+ TEST_DECL(test_tls12_nonblock_ocsp_fragment),
34608+
3441434609 /* Multicast */
3441534610 TEST_DECL(test_wolfSSL_mcast),
3441634611
0 commit comments