Commit 5c56a7f5ef for openssl.org

commit 5c56a7f5ef993d3b0a4b8ee4ed31366949a542b6
Author: Andrew Dinh <andrewd@openssl.org>
Date:   Mon Sep 7 23:47:41 2026 -0400

    Port script_68

    Assisted-by: Claude:claude-sonnet-5
    Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Merge-date: Mon Oct  5 10:18:47 2026
    Merged-from: https://github.com/openssl/openssl/pull/32786

diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c
index e9d59c4c17..154e8164ed 100644
--- a/test/quic_multistream_test.c
+++ b/test/quic_multistream_test.c
@@ -2568,22 +2568,7 @@ static int script_68_inject_handshake(struct helper *h, unsigned char *msg,

 /* Send a CertificateRequest message post-handshake */
 static const struct script_op script_68[] = {
-    OP_S_SET_INJECT_HANDSHAKE(script_68_inject_handshake),
-    OP_C_SET_ALPN("ossltest"),
-    OP_C_CONNECT_WAIT(),
-    OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE),
-
-    OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)),
-    OP_C_WRITE(a, "apple", 5),
-    OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)),
-    OP_S_READ_EXPECT(a, "apple", 5),
-
-    OP_SET_INJECT_WORD(1, 0),
-    OP_S_NEW_TICKET(),
-    OP_S_WRITE(a, "orange", 6),
-
-    OP_C_EXPECT_CONN_CLOSE_INFO(OSSL_QUIC_ERR_PROTOCOL_VIOLATION, 0, 0),
-
+    /* test moved to test/radix/quic_tests.c */
     OP_END
 };

diff --git a/test/radix/quic_ops.c b/test/radix/quic_ops.c
index b4bd59e9ec..f1e6147842 100644
--- a/test/radix/quic_ops.c
+++ b/test/radix/quic_ops.c
@@ -1375,7 +1375,7 @@ struct radix_fault_st {
     uint64_t word0, word1;
     /* Handshake message mutator state. */
     unsigned char *handbuf;
-    size_t handbuflen;
+    size_t handbuflen, handbufalloc;
     radix_fault_handshake_cb hcb;
 };

@@ -1495,6 +1495,73 @@ static int radix_fault_prepend_frame(RADIX_FAULT *fault,
     return 1;
 }

+#define RADIX_FAULT_GROWTH_ALLOWANCE 1024
+
+static int radix_fault_handshake_mutate(const unsigned char *msgin,
+    size_t msginlen,
+    unsigned char **msgout, size_t *msgoutlen,
+    void *arg)
+{
+    RADIX_FAULT *fault = arg;
+    unsigned char *buf;
+
+    buf = OPENSSL_malloc(msginlen + RADIX_FAULT_GROWTH_ALLOWANCE);
+    if (buf == NULL)
+        return 0;
+
+    OPENSSL_free(fault->handbuf);
+    fault->handbuf = buf;
+    fault->handbuflen = msginlen;
+    fault->handbufalloc = msginlen + RADIX_FAULT_GROWTH_ALLOWANCE;
+    memcpy(buf, msgin, msginlen);
+
+    if (fault->hcb != NULL && !fault->hcb(fault, buf, fault->handbuflen))
+        return 0;
+
+    *msgout = buf;
+    *msgoutlen = fault->handbuflen;
+
+    return 1;
+}
+
+static void radix_fault_handshake_finish(void *arg)
+{
+    RADIX_FAULT *fault = arg;
+
+    OPENSSL_free(fault->handbuf);
+    fault->handbuf = NULL;
+}
+
+static int radix_fault_resize_handshake(RADIX_FAULT *fault, size_t newlen)
+{
+    unsigned char *buf;
+    size_t oldlen = fault->handbuflen;
+
+    if (fault->handbufalloc == 0 || newlen > fault->handbufalloc)
+        return 0;
+
+    buf = fault->handbuf;
+
+    if (newlen > oldlen)
+        memset(buf + oldlen, 0, newlen - oldlen);
+
+    fault->handbuflen = newlen;
+
+    return 1;
+}
+
+static int radix_fault_resize_message(RADIX_FAULT *fault, size_t newlen)
+{
+    if (!radix_fault_resize_handshake(fault, newlen + SSL3_HM_HEADER_LENGTH))
+        return 0;
+
+    fault->handbuf[1] = (unsigned char)((newlen >> 16) & 0xff);
+    fault->handbuf[2] = (unsigned char)((newlen >> 8) & 0xff);
+    fault->handbuf[3] = (unsigned char)((newlen) & 0xff);
+
+    return 1;
+}
+
 DEF_FUNC(hf_set_inject_plain)
 {
     int ok = 0;
@@ -1533,45 +1600,6 @@ err:
     return ok;
 }

-/*
- * ossl_statem_mutate_handshake_cb: intercepts an outgoing TLS handshake
- * message on the crypto stream before it is queued for transmission.
- */
-static int radix_fault_handshake_mutate(const unsigned char *msgin,
-    size_t msginlen,
-    unsigned char **msgout,
-    size_t *msgoutlen,
-    void *arg)
-{
-    RADIX_FAULT *fault = arg;
-    unsigned char *buf;
-
-    buf = OPENSSL_malloc(msginlen);
-    if (buf == NULL)
-        return 0;
-
-    OPENSSL_free(fault->handbuf);
-    fault->handbuf = buf;
-    fault->handbuflen = msginlen;
-    memcpy(buf, msgin, msginlen);
-
-    if (fault->hcb != NULL && !fault->hcb(fault, buf, fault->handbuflen))
-        return 0;
-
-    *msgout = buf;
-    *msgoutlen = fault->handbuflen;
-
-    return 1;
-}
-
-static void radix_fault_handshake_finish(void *arg)
-{
-    RADIX_FAULT *fault = arg;
-
-    OPENSSL_free(fault->handbuf);
-    fault->handbuf = NULL;
-}
-
 /*
  * Arms the handshake mutator callback without attaching it to any
  * connection yet. Used by scripts that need to intercept a server's very
@@ -1598,6 +1626,45 @@ err:
     return ok;
 }

+DEF_FUNC(hf_set_inject_handshake)
+{
+    int ok = 0;
+    SSL *ssl;
+    void *cbptr;
+
+    F_POP(cbptr);
+    REQUIRE_SSL(ssl);
+
+    OPENSSL_free(radix_fault.handbuf);
+    radix_fault.handbuf = NULL;
+    radix_fault.handbuflen = 0;
+    radix_fault.handbufalloc = 0;
+    radix_fault.hcb = radix_fault_ptr_to_handshake_cb(cbptr);
+
+    if (!TEST_true(ossl_statem_set_mutator(ssl, radix_fault_handshake_mutate,
+            radix_fault_handshake_finish, &radix_fault)))
+        goto err;
+
+    ok = 1;
+err:
+    return ok;
+}
+
+DEF_FUNC(hf_new_ticket)
+{
+    int ok = 0;
+    SSL *ssl;
+
+    REQUIRE_SSL(ssl);
+
+    if (!TEST_true(SSL_new_session_ticket(ssl)))
+        goto err;
+
+    ok = 1;
+err:
+    return ok;
+}
+
 DEF_FUNC(hf_push_stream_id_plus_one)
 {
     int ok = 0;
@@ -1978,6 +2045,15 @@ err:
     (OP_PUSH_P(radix_fault_handshake_cb_to_ptr(cb)), \
         OP_FUNC(hf_set_inject_handshake_cb))

+#define OP_SET_INJECT_HANDSHAKE(name, cb)               \
+    (OP_SELECT_SSL(0, name),                            \
+        OP_PUSH_P(radix_fault_handshake_cb_to_ptr(cb)), \
+        OP_FUNC(hf_set_inject_handshake))
+
+#define OP_NEW_TICKET(name)  \
+    (OP_SELECT_SSL(0, name), \
+        OP_FUNC(hf_new_ticket))
+
 #define OP_PUSH_STREAM_ID_PLUS_ONE(name) \
     (OP_SELECT_SSL(0, name),             \
         OP_FUNC(hf_push_stream_id_plus_one))
diff --git a/test/radix/quic_tests.c b/test/radix/quic_tests.c
index a137a29851..7e9573346b 100644
--- a/test/radix/quic_tests.c
+++ b/test/radix/quic_tests.c
@@ -3841,8 +3841,76 @@ DEF_SCRIPT(script_67, "Fault injection - large MAX_DATA")
     OP_READ_EXPECT(Sa, "Strawberry", 10);
 }

-DEF_SCRIPT(script_68, "place holder for multistrem script_68")
+static int script_68_inject_handshake(RADIX_FAULT *fault, unsigned char *msg,
+    size_t msglen)
+{
+    const unsigned char *data;
+    size_t datalen;
+    const unsigned char certreq[] = {
+        SSL3_MT_CERTIFICATE_REQUEST, /* CertificateRequest message */
+        0, 0, 12, /* Length of message */
+        1, 1, /* certificate_request_context */
+        0, 8, /* Extensions block length */
+        0, TLSEXT_TYPE_signature_algorithms, /* sig_algs extension*/
+        0, 4, /* 4 bytes of sig algs extension*/
+        0, 2, /* sigalgs list is 2 bytes long */
+        8, 4 /* rsa_pss_rsae_sha256 */
+    };
+    const unsigned char keyupdate[] = {
+        SSL3_MT_KEY_UPDATE, /* KeyUpdate message */
+        0, 0, 1, /* Length of message */
+        SSL_KEY_UPDATE_NOT_REQUESTED /* update_not_requested */
+    };
+
+    /* We transform the NewSessionTicket message into something else */
+    switch (fault->word0) {
+    case 0:
+        return 1;
+
+    case 1:
+        /* CertificateRequest message */
+        data = certreq;
+        datalen = sizeof(certreq);
+        break;
+
+    case 2:
+        /* KeyUpdate message */
+        data = keyupdate;
+        datalen = sizeof(keyupdate);
+        break;
+
+    default:
+        return 0;
+    }
+
+    if (!TEST_true(radix_fault_resize_message(fault,
+            datalen - SSL3_HM_HEADER_LENGTH)))
+        return 0;
+
+    memcpy(msg, data, datalen);
+
+    return 1;
+}
+
+DEF_SCRIPT(script_68, "Send a CertificateRequest message post-handshake")
 {
+    OP_SIMPLE_PAIR_CONN_ND();
+    OP_ACCEPT_CONN_WAIT_ND(L, S, 0);
+
+    OP_SET_INJECT_HANDSHAKE(S, script_68_inject_handshake);
+
+    OP_NEW_STREAM(C, Ca, 0);
+    OP_WRITE(Ca, "apple", 5);
+    OP_ACCEPT_STREAM_WAIT(S, Sa, 0);
+    OP_READ_EXPECT(Sa, "apple", 5);
+
+    OP_ENGINE_TICK_DISABLE(S);
+    OP_SET_INJECT_WORD(1, 0);
+    OP_NEW_TICKET(S);
+    OP_WRITE(Sa, "orange", 6);
+    OP_ENGINE_TICK_ENABLE(S);
+
+    OP_EXPECT_CONN_CLOSE_INFO(C, OSSL_QUIC_ERR_PROTOCOL_VIOLATION, 0, 0);
 }

 DEF_SCRIPT(script_69, "place holder for multistrem script_69")