]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
QUIC APL: Revise SSL_pending and SSL_has_pending handling for s_client compat
authorHugo Landau <hlandau@openssl.org>
Thu, 28 Mar 2024 09:00:13 +0000 (09:00 +0000)
committerTomas Mraz <tomas@openssl.org>
Wed, 10 Apr 2024 13:48:35 +0000 (15:48 +0200)
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24040)

(cherry picked from commit 7c33eb1e7fd3248ad29c172b5b4c0658a7be3adc)

ssl/quic/quic_impl.c

index c4c332b203eabeb881de2fb1e9cf77ec75597369..62ebcd29aa89874505be30ca4d44fd82136ba4e2 100644 (file)
@@ -25,7 +25,7 @@ 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_for_write(QCTX *ctx);
-static int qc_wait_for_default_xso_for_read(QCTX *ctx);
+static int qc_wait_for_default_xso_for_read(QCTX *ctx, int peek);
 static void quic_lock(QUIC_CONNECTION *qc);
 static void quic_unlock(QUIC_CONNECTION *qc);
 static void quic_lock_for_io(QCTX *ctx);
@@ -268,7 +268,7 @@ static int ossl_unused expect_quic_with_stream_lock(const SSL *s, int remote_ini
             if (!qc_try_create_default_xso_for_write(ctx))
                 goto err;
         } else {
-            if (!qc_wait_for_default_xso_for_read(ctx))
+            if (!qc_wait_for_default_xso_for_read(ctx, /*peek=*/0))
                 goto err;
         }
 
@@ -1851,7 +1851,7 @@ static int quic_wait_for_stream(void *arg)
 }
 
 QUIC_NEEDS_LOCK
-static int qc_wait_for_default_xso_for_read(QCTX *ctx)
+static int qc_wait_for_default_xso_for_read(QCTX *ctx, int peek)
 {
     /* Called on a QCSO and we don't currently have a default stream. */
     uint64_t expect_id;
@@ -1893,6 +1893,9 @@ static int qc_wait_for_default_xso_for_read(QCTX *ctx)
     }
 
     if (qs == NULL) {
+        if (peek)
+            return 0;
+
         if (!qc_blocking_mode(qc))
             /* Non-blocking mode, so just bail immediately. */
             return QUIC_RAISE_NORMAL_ERROR(ctx, SSL_ERROR_WANT_READ);
@@ -2524,10 +2527,19 @@ int ossl_quic_write_flags(SSL *s, const void *buf, size_t len,
 
     *written = 0;
 
-    if (!expect_quic_with_stream_lock(s, /*remote_init=*/0, /*io=*/1, &ctx))
-        return 0;
+    if (len == 0) {
+        /* Do not autocreate default XSO for zero-length writes. */
+        if (!expect_quic(s, &ctx))
+            return 0;
+
+        quic_lock_for_io(&ctx);
+    } else {
+        if (!expect_quic_with_stream_lock(s, /*remote_init=*/0, /*io=*/1, &ctx))
+            return 0;
+    }
 
-    partial_write = ((ctx.xso->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 0);
+    partial_write = ((ctx.xso != NULL)
+        ? ((ctx.xso->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 0) : 0);
 
     if ((flags & ~SSL_WRITE_FLAG_CONCLUDE) != 0) {
         ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_UNSUPPORTED_WRITE_FLAG, NULL);
@@ -2549,7 +2561,7 @@ int ossl_quic_write_flags(SSL *s, const void *buf, size_t len,
     }
 
     /* Ensure correct stream state, stream send part not concluded, etc. */
-    if (!quic_validate_for_write(ctx.xso, &err)) {
+    if (len > 0 && !quic_validate_for_write(ctx.xso, &err)) {
         ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, err, NULL);
         goto out;
     }
@@ -2753,7 +2765,7 @@ static int quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read, int peek
          * 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)) {
+        if (!qc_wait_for_default_xso_for_read(&ctx, /*peek=*/0)) {
             ret = 0; /* error already raised here */
             goto out;
         }
@@ -2840,8 +2852,6 @@ static size_t ossl_quic_pending_int(const SSL *s, int check_channel)
 {
     QCTX ctx;
     size_t avail = 0;
-    int fin = 0;
-
 
     if (!expect_quic(s, &ctx))
         return 0;
@@ -2849,21 +2859,26 @@ static size_t ossl_quic_pending_int(const SSL *s, int check_channel)
     quic_lock(ctx.qc);
 
     if (ctx.xso == NULL) {
-        QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_NO_STREAM, NULL);
-        goto out;
+        /* No XSO yet, but there might be a default XSO eligible to be created. */
+        if (qc_wait_for_default_xso_for_read(&ctx, /*peek=*/1)) {
+            ctx.xso = ctx.qc->default_xso;
+        } else {
+            QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_NO_STREAM, NULL);
+            goto out;
+        }
     }
 
-    if (ctx.xso->stream == NULL
-        || !ossl_quic_stream_has_recv_buffer(ctx.xso->stream)) {
+    if (ctx.xso->stream == NULL) {
         QUIC_RAISE_NON_NORMAL_ERROR(&ctx, ERR_R_INTERNAL_ERROR, NULL);
         goto out;
     }
 
-    if (!ossl_quic_rstream_available(ctx.xso->stream->rstream, &avail, &fin))
-        avail = 0;
-
-    if (avail == 0 && check_channel && ossl_quic_channel_has_pending(ctx.qc->ch))
-        avail = 1;
+    if (check_channel)
+        avail = ossl_quic_stream_recv_pending(ctx.xso->stream)
+             || ossl_quic_channel_has_pending(ctx.qc->ch)
+             || ossl_quic_channel_is_term_any(ctx.qc->ch);
+    else
+        avail = ossl_quic_stream_recv_pending(ctx.xso->stream);
 
 out:
     quic_unlock(ctx.qc);