QUIC DISPATCH/APL: Implement SSL_set_default_stream_mode, default XSO refactor
authorHugo Landau <hlandau@openssl.org>
Tue, 18 Apr 2023 18:30:55 +0000 (19:30 +0100)
committerHugo Landau <hlandau@openssl.org>
Fri, 12 May 2023 13:47:12 +0000 (14:47 +0100)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20765)

crypto/err/openssl.txt
include/internal/quic_channel.h
include/internal/quic_ssl.h
include/openssl/ssl.h.in
include/openssl/sslerr.h
ssl/quic/quic_impl.c
ssl/quic/quic_local.h
ssl/ssl_err.c
ssl/ssl_lib.c
util/libssl.num

index 8545eaab96578036836f5592b29cebe9bacdcfc8..036a0e738d7543c63da4f7ca89e06b19d86ebe0c 100644 (file)
@@ -1465,6 +1465,7 @@ SSL_R_NO_SHARED_CIPHER:193:no shared cipher
 SSL_R_NO_SHARED_GROUPS:410:no shared groups
 SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS:376:no shared signature algorithms
 SSL_R_NO_SRTP_PROFILES:359:no srtp profiles
+SSL_R_NO_STREAM:355:no stream
 SSL_R_NO_SUITABLE_DIGEST_ALGORITHM:297:no suitable digest algorithm
 SSL_R_NO_SUITABLE_GROUPS:295:no suitable groups
 SSL_R_NO_SUITABLE_KEY_SHARE:101:no suitable key share
index 084c465c3add3dde46c44ee70a556bf1815dac92..74b347378259148d71aeb557c64bc6ffb17faf00 100644 (file)
  */
 #  define QUIC_TAKES_LOCK
 
+/*
+ * The function acquires the channel mutex and leaves it acquired
+ * when returning success.
+ *
+ * Any function tagged with this has the following precondition and
+ * postcondition:
+ *
+ *   Precondition: must not hold channel mutex (unchecked)
+ *   Postcondition: channel mutex is held by calling thread
+ *      or function returned failure
+ */
+#  define QUIC_ACQUIRES_LOCK
+
 #  define QUIC_TODO_LOCK
 
 #  define QUIC_CHANNEL_STATE_IDLE                        0
index 0ccb1c5526aabc4dde5613d837a9d696b324d2dc..986cd0e0d02ee11334e24700487e03626812041d 100644 (file)
@@ -69,6 +69,9 @@ __owur SSL *ossl_quic_conn_stream_new(SSL *s, uint64_t flags);
 __owur SSL *ossl_quic_get0_connection(SSL *s);
 __owur int ossl_quic_get_stream_type(SSL *s);
 __owur uint64_t ossl_quic_get_stream_id(SSL *s);
+__owur int ossl_quic_set_default_stream_mode(SSL *s, uint32_t mode);
+__owur SSL *ossl_quic_detach_stream(SSL *s);
+__owur int ossl_quic_attach_stream(SSL *conn, SSL *stream);
 
 /*
  * Used to override ossl_time_now() for debug purposes. Must be called before
index 8d82bf6b5aae6846402020aa960a044c5e629ec2..c5ab10581643866fb6f9c7d30d60a80d7605204f 100644 (file)
@@ -2277,6 +2277,14 @@ __owur int SSL_get_stream_type(SSL *s);
 
 __owur uint64_t SSL_get_stream_id(SSL *s);
 
+#define SSL_DEFAULT_STREAM_MODE_NONE        0
+#define SSL_DEFAULT_STREAM_MODE_AUTO_BIDI   1
+#define SSL_DEFAULT_STREAM_MODE_AUTO_UNI    2
+__owur int SSL_set_default_stream_mode(SSL *s, uint32_t mode);
+
+__owur SSL *SSL_detach_stream(SSL *s);
+__owur int SSL_attach_stream(SSL *conn, SSL *stream);
+
 #define SSL_STREAM_FLAG_UNI     (1U << 0)
 __owur SSL *SSL_new_stream(SSL *s, uint64_t flags);
 
index 94cb60f8be62600cb41d68ffb64d033d229a9ea9..d8c97c7666e87b4632efd3e60a176d05a517f2bb 100644 (file)
 # define SSL_R_NO_SHARED_GROUPS                           410
 # define SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS             376
 # define SSL_R_NO_SRTP_PROFILES                           359
+# define SSL_R_NO_STREAM                                  355
 # define SSL_R_NO_SUITABLE_DIGEST_ALGORITHM               297
 # define SSL_R_NO_SUITABLE_GROUPS                         295
 # define SSL_R_NO_SUITABLE_KEY_SHARE                      101
 # define SSL_R_WRONG_VERSION_NUMBER                       267
 # define SSL_R_X509_LIB                                   268
 # define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS           269
+# define SSL_R_CONN_USE_ONLY                              411
 
 #endif
index 6a28c00c75ec0572ab18a30060288eaec11a4ef6..4550ee3be0c3b6923231166c24a9f38d202fb41d 100644 (file)
 static void aon_write_finish(QUIC_XSO *xso);
 static int create_channel(QUIC_CONNECTION *qc);
 static QUIC_XSO *create_xso_from_stream(QUIC_CONNECTION *qc, QUIC_STREAM *qs);
-static int qc_try_create_default_xso(QUIC_CONNECTION *qc, int remote_init);
+static int qc_try_create_default_xso_for_write(QUIC_CONNECTION *qc);
+static int qc_wait_for_default_xso_for_read(QUIC_CONNECTION *qc);
+static void quic_lock(QUIC_CONNECTION *qc);
+static void quic_unlock(QUIC_CONNECTION *qc);
+static int quic_do_handshake(QUIC_CONNECTION *qc);
 
 /*
  * QUIC Front-End I/O API: Common Utilities
@@ -136,7 +140,7 @@ static int expect_quic(const SSL *s, QCTX *ctx)
     ctx->is_stream  = 0;
 
     if (s == NULL)
-        return QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL);
+        return QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_PASSED_NULL_PARAMETER, NULL);
 
     switch (s->type) {
     case SSL_TYPE_QUIC_CONNECTION:
@@ -165,22 +169,50 @@ static int expect_quic(const SSL *s, QCTX *ctx)
  *
  * remote_init determines if we expect the default XSO to be remotely created or
  * not. If it is -1, do not instantiate a default XSO if one does not yet exist.
+ *
+ * Channel mutex is acquired and retained on success.
  */
-static int ossl_unused expect_quic_with_stream(const SSL *s, int remote_init,
-                                               QCTX *ctx)
+QUIC_ACQUIRES_LOCK
+static int ossl_unused expect_quic_with_stream_lock(const SSL *s, int remote_init,
+                                                    QCTX *ctx)
 {
     if (!expect_quic(s, ctx))
         return 0;
 
+    quic_lock(ctx->qc);
+
     if (ctx->xso == NULL && remote_init >= 0) {
-        qc_try_create_default_xso(ctx->qc, remote_init);
+        if (ossl_quic_channel_is_term_any(ctx->qc->ch)) {
+            QUIC_RAISE_NON_NORMAL_ERROR(ctx->qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
+            goto err;
+        }
+
+        /* If we haven't finished the handshake, try to advance it. */
+        if (quic_do_handshake(ctx->qc) < 1)
+            /* ossl_quic_do_handshake raised error here */
+            goto err;
+
+        if (remote_init == 0) {
+            if (!qc_try_create_default_xso_for_write(ctx->qc))
+                goto err;
+        } else {
+            if (!qc_wait_for_default_xso_for_read(ctx->qc))
+                goto err;
+        }
+
         ctx->xso = ctx->qc->default_xso;
     }
 
-    if (ctx->xso == NULL)
-        return QUIC_RAISE_NON_NORMAL_ERROR(ctx->qc, ERR_R_INTERNAL_ERROR, NULL);
+    if (ctx->xso == NULL) {
+        QUIC_RAISE_NON_NORMAL_ERROR(ctx->qc, SSL_R_NO_STREAM, NULL);
+        goto err;
+    }
+
+    return 1; /* lock held */
 
-    return 1;
+err:
+    quic_unlock(ctx->qc);
+    return 0;
 }
 
 /*
@@ -193,7 +225,7 @@ static int ossl_unused expect_quic_conn_only(const SSL *s, QCTX *ctx)
         return 0;
 
     if (ctx->is_stream)
-        return QUIC_RAISE_NON_NORMAL_ERROR(ctx->qc, ERR_R_INTERNAL_ERROR, NULL);
+        return QUIC_RAISE_NON_NORMAL_ERROR(ctx->qc, SSL_R_CONN_USE_ONLY, NULL);
 
     return 1;
 }
@@ -261,6 +293,7 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
     qc->as_server       = 0; /* TODO(QUIC): server support */
     qc->as_server_state = qc->as_server;
 
+    qc->default_stream_mode     = SSL_DEFAULT_STREAM_MODE_AUTO_BIDI;
     qc->default_ssl_mode        = qc->ssl.ctx->mode;
     qc->default_blocking        = 1;
     qc->last_error              = SSL_ERROR_NONE;
@@ -1119,50 +1152,123 @@ int ossl_quic_accept(SSL *s)
  * exists). Note that this is NOT an error condition.
  */
 QUIC_NEEDS_LOCK
-static int qc_try_create_default_xso(QUIC_CONNECTION *qc, int remote_init)
+static int qc_try_create_default_xso_for_write(QUIC_CONNECTION *qc)
 {
-    QUIC_STREAM *qs;
+    uint64_t flags = 0;
 
-    if (qc->default_xso != NULL)
-        qc->default_xso_created = 1;
-
-    if (qc->default_xso_created)
+    if (qc->default_xso_created
+        || qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_NONE)
         /*
          * We only do this once. If the user detaches a previously created
          * default XSO we don't auto-create another one.
          */
-        return 0;
+        return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_NO_STREAM, NULL);
 
-    if (!remote_init) {
-        /*
-         * We are writing to the stream first, so this is a locally-initiated
-         * stream.
-         */
-        qc->default_xso = (QUIC_XSO *)ossl_quic_conn_stream_new(&qc->ssl, 0);
-        if (qc->default_xso == NULL)
-            return 0;
-    } else {
-        /*
-         * Client is reading first. This means it is expecting to get data on a
-         * stream the peer writes to first, meaning this is a remotely-initiated
-         * stream. Ordinarily, we wait for the RXDP to handle a STREAM frame to
-         * create such a stream. But in this case, special case it and create
-         * the bookkeeping structures for the first peer-initiated bidirectional
-         * stream so the client can start to wait on it.
-         */
-       qs = ossl_quic_channel_new_stream_remote(qc->ch,
-                                                QUIC_STREAM_INITIATOR_SERVER
-                                                | QUIC_STREAM_DIR_BIDI);
-       if (qs == NULL)
-           return 0;
-
-        qc->default_xso = create_xso_from_stream(qc, qs);
-        if (qc->default_xso == NULL) {
-            ossl_quic_stream_map_release(ossl_quic_channel_get_qsm(qc->ch), qs);
+    /* Create a locally-initiated stream. */
+    if (qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_AUTO_UNI)
+        flags |= SSL_STREAM_FLAG_UNI;
+
+    qc->default_xso = (QUIC_XSO *)ossl_quic_conn_stream_new(&qc->ssl, flags);
+    if (qc->default_xso == NULL)
+        return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
+
+    qc->default_xso_created = 1;
+    return 1;
+}
+
+struct quic_wait_for_stream_args {
+    QUIC_CONNECTION *qc;
+    QUIC_STREAM     *qs;
+    uint64_t        expect_id;
+};
+
+QUIC_NEEDS_LOCK
+static int quic_wait_for_stream(void *arg)
+{
+    struct quic_wait_for_stream_args *args = arg;
+
+    if (!ossl_quic_channel_is_active(args->qc->ch)) {
+        /* If connection is torn down due to an error while blocking, stop. */
+        QUIC_RAISE_NON_NORMAL_ERROR(args->qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
+        return -1;
+    }
+
+    args->qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(args->qc->ch),
+                                              args->expect_id);
+    if (args->qs != NULL)
+        return 1; /* stream now exists */
+
+    return 0; /* did not get a stream, keep trying */
+}
+
+QUIC_NEEDS_LOCK
+static int qc_wait_for_default_xso_for_read(QUIC_CONNECTION *qc)
+{
+    /* Called on a QCSO and we don't currently have a default stream. */
+    uint64_t expect_id;
+    QUIC_STREAM *qs;
+    int res;
+    struct quic_wait_for_stream_args wargs;
+
+    /*
+     * If default stream functionality is disabled or we already detached
+     * one, don't make another default stream and just fail.
+     */
+    if (qc->default_xso_created
+        || qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_NONE)
+        return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_NO_STREAM, NULL);
+
+    /*
+     * The peer may have opened a stream since we last ticked. So tick and
+     * see if the stream with ordinal 0 (remote, bidi/uni based on stream
+     * mode) exists yet. QUIC stream IDs must be allocated in order, so the
+     * first stream created by a peer must have an ordinal of 0.
+     */
+    expect_id = qc->as_server
+        ? QUIC_STREAM_INITIATOR_CLIENT
+        : QUIC_STREAM_INITIATOR_SERVER;
+
+    expect_id |= (qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_AUTO_UNI)
+        ? QUIC_STREAM_DIR_UNI
+        : QUIC_STREAM_DIR_BIDI;
+
+    qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(qc->ch),
+                                        expect_id);
+    if (qs == NULL) {
+        ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(qc->ch), 0);
+
+        qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(qc->ch),
+                                            expect_id);
+    }
+
+    if (qs == NULL) {
+        if (!qc_blocking_mode(qc))
+            /* Non-blocking mode, so just bail immediately. */
+            return QUIC_RAISE_NORMAL_ERROR(qc, SSL_ERROR_WANT_READ);
+
+        /* Block until we have a stream. */
+        wargs.qc        = qc;
+        wargs.qs        = NULL;
+        wargs.expect_id = expect_id;
+
+        res = block_until_pred(qc, quic_wait_for_stream, &wargs, 0);
+        if (res == 0)
+            return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
+        else if (res < 0 || wargs.qs == NULL)
+            /* quic_wait_for_stream raised error here */
             return 0;
-        }
+
+        qs = wargs.qs;
     }
 
+    /*
+     * We now have qs != NULL. Make it the default stream, creating the
+     * necessary XSO.
+     */
+    qc->default_xso = create_xso_from_stream(qc, qs);
+    if (qc->default_xso == NULL)
+        return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
+
     qc->default_xso_created = 1;
     return 1;
 }
@@ -1218,6 +1324,7 @@ SSL *ossl_quic_conn_stream_new(SSL *s, uint64_t flags)
     if (xso == NULL)
         goto err;
 
+    ctx.qc->default_xso_created = 1; /* inhibits default XSO */
     quic_unlock(ctx.qc);
     return &xso->ssl;
 
@@ -1508,11 +1615,11 @@ int ossl_quic_write(SSL *s, const void *buf, size_t len, size_t *written)
 
     *written = 0;
 
-    if (!expect_quic_with_stream(s, /*remote_init=*/0, &ctx)) {
-        return 0;
-    }
+    if (len == 0)
+        return 1;
 
-    quic_lock(ctx.qc);
+    if (!expect_quic_with_stream_lock(s, /*remote_init=*/0, &ctx))
+        return 0;
 
     partial_write = ((ctx.xso->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 0);
 
@@ -1647,7 +1754,7 @@ static int quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read, int peek
 
     *bytes_read = 0;
 
-    if (!expect_quic_with_stream(s, /*remote_init=*/0, &ctx))
+    if (!expect_quic(s, &ctx))
         return 0;
 
     quic_lock(ctx.qc);
@@ -1663,6 +1770,21 @@ static int quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read, int peek
         goto out;
     }
 
+    if (ctx.xso == NULL) {
+        /*
+         * Called on a QCSO and we don't currently have a default stream.
+         *
+         * Wait until we get a stream initiated by the peer (blocking mode) or
+         * fail if we don't have one yet (non-blocking mode).
+         */
+        if (!qc_wait_for_default_xso_for_read(ctx.qc)) {
+            ret = 0; /* error already raised here */
+            goto out;
+        }
+
+        ctx.xso = ctx.qc->default_xso;
+    }
+
     if (ctx.xso->stream == NULL) {
         ret = QUIC_RAISE_NON_NORMAL_ERROR(ctx.qc, ERR_R_INTERNAL_ERROR, NULL);
         goto out;
@@ -1734,11 +1856,9 @@ static size_t ossl_quic_pending_int(const SSL *s)
     size_t avail = 0;
     int fin = 0;
 
-    if (!expect_quic_with_stream(s, /*remote_init=*/-1, &ctx))
+    if (!expect_quic_with_stream_lock(s, /*remote_init=*/-1, &ctx))
         return 0;
 
-    quic_lock(ctx.qc);
-
     if (ctx.xso->stream == NULL || ctx.xso->stream->rstream == NULL)
         /* Cannot raise errors here because we are const, just fail. */
         goto out;
@@ -1771,11 +1891,9 @@ int ossl_quic_conn_stream_conclude(SSL *s)
     QCTX ctx;
     QUIC_STREAM *qs;
 
-    if (!expect_quic_with_stream(s, /*remote_init=*/0, &ctx))
+    if (!expect_quic_with_stream_lock(s, /*remote_init=*/0, &ctx))
         return 0;
 
-    quic_lock(ctx.qc);
-
     qs = ctx.xso->stream;
 
     if (qs == NULL || qs->sstream == NULL) {
@@ -1874,11 +1992,105 @@ int ossl_quic_get_stream_type(SSL *s)
 uint64_t ossl_quic_get_stream_id(SSL *s)
 {
     QCTX ctx;
+    uint64_t id;
 
-    if (!expect_quic_with_stream(s, /*remote_init=*/-1, &ctx))
+    if (!expect_quic_with_stream_lock(s, /*remote_init=*/-1, &ctx))
         return UINT64_MAX;
 
-    return ctx.xso->stream->id;
+    id = ctx.xso->stream->id;
+    quic_unlock(ctx.qc);
+
+    return id;
+}
+
+/*
+ * SSL_set_default_stream_mode
+ * ---------------------------
+ */
+int ossl_quic_set_default_stream_mode(SSL *s, uint32_t mode)
+{
+    QCTX ctx;
+
+    if (!expect_quic_conn_only(s, &ctx))
+        return 0;
+
+    quic_lock(ctx.qc);
+
+    if (ctx.qc->default_xso_created)
+        return QUIC_RAISE_NON_NORMAL_ERROR(ctx.qc, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED,
+                                           "too late to change default stream mode");
+
+    switch (mode) {
+    case SSL_DEFAULT_STREAM_MODE_NONE:
+    case SSL_DEFAULT_STREAM_MODE_AUTO_BIDI:
+    case SSL_DEFAULT_STREAM_MODE_AUTO_UNI:
+        ctx.qc->default_stream_mode = mode;
+        break;
+    default:
+        quic_unlock(ctx.qc);
+        return QUIC_RAISE_NON_NORMAL_ERROR(ctx.qc, ERR_R_PASSED_INVALID_ARGUMENT,
+                                           "bad default stream type");
+    }
+
+    quic_unlock(ctx.qc);
+    return 1;
+}
+
+/*
+ * SSL_detach_stream
+ * -----------------
+ */
+SSL *ossl_quic_detach_stream(SSL *s)
+{
+    QCTX ctx;
+    QUIC_XSO *xso;
+
+    if (!expect_quic_conn_only(s, &ctx))
+        return NULL;
+
+    quic_lock(ctx.qc);
+
+    xso = ctx.qc->default_xso;
+    ctx.qc->default_xso = NULL;
+
+    /* Calling this function inhibits default XSO autocreation. */
+    ctx.qc->default_xso_created = 1;
+
+    quic_unlock(ctx.qc);
+
+    return &xso->ssl;
+}
+
+/*
+ * SSL_attach_stream
+ * -----------------
+ */
+int ossl_quic_attach_stream(SSL *conn, SSL *stream)
+{
+    QCTX ctx;
+
+    if (!expect_quic_conn_only(conn, &ctx))
+        return 0;
+
+    if (stream == NULL || stream->type != SSL_TYPE_QUIC_XSO)
+        return QUIC_RAISE_NON_NORMAL_ERROR(ctx.qc, ERR_R_PASSED_NULL_PARAMETER,
+                                           "stream to attach must be a valid QUIC stream");
+
+    quic_lock(ctx.qc);
+
+    if (ctx.qc->default_xso != NULL) {
+        quic_unlock(ctx.qc);
+        return QUIC_RAISE_NON_NORMAL_ERROR(ctx.qc, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED,
+                                           "connection already has a default stream");
+    }
+
+    ctx.qc->default_xso = (QUIC_XSO *)stream;
+
+    /* Calling this function inhibits default XSO autocreation. */
+    ctx.qc->default_xso_created = 1;
+
+    quic_unlock(ctx.qc);
+    return 1;
 }
 
 /*
index 1358a5596607af5278e6c511e08f47b4c64c4337..edc82a415e10d39054c7f15c879c0ec1d47fcdf8 100644 (file)
@@ -172,6 +172,9 @@ struct quic_conn_st {
     /* Have we created a default XSO yet? */
     unsigned int                    default_xso_created     : 1;
 
+    /* Default stream type. Defaults to SSL_DEFAULT_STREAM_MODE_AUTO_BIDI. */
+    uint32_t                        default_stream_mode;
+
     /* SSL_set_mode. This is not used directly but inherited by new XSOs. */
     uint32_t                        default_ssl_mode;
 
index f1464f7d64fc5d116fb827e470447684d64fcafe..520a29790577598122ba5e918a3799a6b4a01b57 100644 (file)
@@ -311,6 +311,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS),
     "no shared signature algorithms"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SRTP_PROFILES), "no srtp profiles"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_STREAM), "no stream"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SUITABLE_DIGEST_ALGORITHM),
     "no suitable digest algorithm"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SUITABLE_GROUPS), "no suitable groups"},
index a7e3682291a3fae1dc17a230eba7e3fd7025c8e2..c6cd2dabdae3a6c3ba25dd919aaa0abceac46e8c 100644 (file)
@@ -7352,6 +7352,42 @@ uint64_t SSL_get_stream_id(SSL *s)
 #endif
 }
 
+int SSL_set_default_stream_mode(SSL *s, uint32_t mode)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return 0;
+
+    return ossl_quic_set_default_stream_mode(s, mode);
+#else
+    return 0;
+#endif
+}
+
+SSL *SSL_detach_stream(SSL *s)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(s))
+        return NULL;
+
+    return ossl_quic_detach_stream(s);
+#else
+    return NULL;
+#endif
+}
+
+int SSL_attach_stream(SSL *conn, SSL *stream)
+{
+#ifndef OPENSSL_NO_QUIC
+    if (!IS_QUIC(conn))
+        return 0;
+
+    return ossl_quic_attach_stream(conn, stream);
+#else
+    return NULL;
+#endif
+}
+
 int SSL_add_expected_rpk(SSL *s, EVP_PKEY *rpk)
 {
     unsigned char *data = NULL;
index a52a034e20177da44bfeaf06399468a0cc0f3d9b..8427cd1273694c14f4e34f88a5914ee18bed3473 100644 (file)
@@ -564,3 +564,7 @@ SSL_new_stream                          ?   3_2_0   EXIST::FUNCTION:
 SSL_get0_connection                     ?      3_2_0   EXIST::FUNCTION:
 SSL_is_connection                       ?      3_2_0   EXIST::FUNCTION:
 SSL_get_stream_type                     ?      3_2_0   EXIST::FUNCTION:
+SSL_get_stream_id                       ?      3_2_0   EXIST::FUNCTION:
+SSL_set_default_stream_mode             ?      3_2_0   EXIST::FUNCTION:
+SSL_detach_stream                       ?      3_2_0   EXIST::FUNCTION:
+SSL_attach_stream                       ?      3_2_0   EXIST::FUNCTION: