QUIC CHANNEL, APL: Reject policy handling
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)

include/internal/quic_channel.h
ssl/quic/quic_channel.c
ssl/quic/quic_channel_local.h
ssl/quic/quic_impl.c

index 74b347378259148d71aeb557c64bc6ffb17faf00..32e5a57fd94ab8d66a33dcb83fe42d29388d2e54 100644 (file)
@@ -299,6 +299,23 @@ QUIC_STREAM *ossl_quic_channel_new_stream_local(QUIC_CHANNEL *ch, int is_uni);
 QUIC_STREAM *ossl_quic_channel_new_stream_remote(QUIC_CHANNEL *ch,
                                                  uint64_t stream_id);
 
+/*
+ * Configures incoming stream auto-reject. If enabled, incoming streams have
+ * both their sending and receiving parts automatically rejected using
+ * STOP_SENDING and STREAM_RESET frames. aec is the application error
+ * code to be used for those frames.
+ */
+void ossl_quic_channel_set_incoming_stream_auto_reject(QUIC_CHANNEL *ch,
+                                                       int enable,
+                                                       uint64_t aec);
+
+/*
+ * Causes the channel to reject the sending and receiving parts of a stream,
+ * as though autorejected. Can be used if a stream has already been
+ * accepted.
+ */
+void ossl_quic_channel_reject_stream(QUIC_CHANNEL *ch, QUIC_STREAM *qs);
+
 # endif
 
 #endif
index f11139132fa62792d52bb642cf85bfd3895d4102..3e099e9d93967a2fdfc9ce186f598f428c22c4cd 100644 (file)
@@ -2342,10 +2342,32 @@ QUIC_STREAM *ossl_quic_channel_new_stream_remote(QUIC_CHANNEL *ch,
     if (!ch_init_new_stream(ch, qs, /*can_send=*/!is_uni, /*can_recv=*/1))
         goto err;
 
-    ossl_quic_stream_map_push_accept_queue(&ch->qsm, qs);
+    if (ch->incoming_stream_auto_reject)
+        ossl_quic_channel_reject_stream(ch, qs);
+    else
+        ossl_quic_stream_map_push_accept_queue(&ch->qsm, qs);
+
     return qs;
 
 err:
     ossl_quic_stream_map_release(&ch->qsm, qs);
     return NULL;
 }
+
+void ossl_quic_channel_set_incoming_stream_auto_reject(QUIC_CHANNEL *ch,
+                                                       int enable,
+                                                       uint64_t aec)
+{
+    ch->incoming_stream_auto_reject     = (enable != 0);
+    ch->incoming_stream_auto_reject_aec = aec;
+}
+
+void ossl_quic_channel_reject_stream(QUIC_CHANNEL *ch, QUIC_STREAM *qs)
+{
+    ossl_quic_stream_stop_sending(qs, ch->incoming_stream_auto_reject_aec);
+    ossl_quic_stream_reset(qs, ch->incoming_stream_auto_reject_aec);
+
+    qs->deleted = 1;
+
+    ossl_quic_stream_map_update_state(&ch->qsm, qs);
+}
index 3645c277ddae1ec199ed068a6520e59a971ab33d..a1ce833f56052557f5ee4996bcfe9f24e698d08a 100644 (file)
@@ -167,6 +167,12 @@ struct quic_channel_st {
     uint64_t                        next_local_stream_ordinal_bidi;
     uint64_t                        next_local_stream_ordinal_uni;
 
+    /*
+     * Application error code to be used for STOP_SENDING/RESET_STREAM frames
+     * used to autoreject incoming streams.
+     */
+    uint64_t                        incoming_stream_auto_reject_aec;
+
     /* Valid if we are in the TERMINATING or TERMINATED states. */
     QUIC_TERMINATE_CAUSE            terminate_cause;
 
@@ -290,6 +296,9 @@ struct quic_channel_st {
      * 10.1).
      */
     unsigned int                    have_sent_ack_eliciting_since_rx    : 1;
+
+    /* Should incoming streams automatically be rejected? */
+    unsigned int                    incoming_stream_auto_reject         : 1;
 };
 
 # endif
index 840dcfed96748c41f4cad5bd2c032dbfd4ae2cf4..2dd5a4f91f5704f2e1f00806c23f1c3eef051227 100644 (file)
@@ -25,6 +25,9 @@ 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);
+static void qc_update_reject_policy(QUIC_CONNECTION *qc);
+static void qc_touch_default_xso(QUIC_CONNECTION *qc);
+static void qc_set_default_xso(QUIC_CONNECTION *qc, QUIC_XSO *xso, int touch);
 
 /*
  * QUIC Front-End I/O API: Common Utilities
@@ -303,6 +306,8 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
     if (!create_channel(qc))
         goto err;
 
+    qc_update_reject_policy(qc);
+
     /*
      * We do not create the default XSO yet. The reason for this is that the
      * stream ID of the default XSO will depend on whether the stream is client
@@ -458,6 +463,21 @@ void ossl_quic_conn_force_assist_thread_wake(SSL *s)
         ossl_quic_thread_assist_notify_deadline_changed(&ctx.qc->thread_assist);
 }
 
+QUIC_NEEDS_LOCK
+static void qc_touch_default_xso(QUIC_CONNECTION *qc)
+{
+    qc->default_xso_created = 1;
+    qc_update_reject_policy(qc);
+}
+
+QUIC_NEEDS_LOCK
+static void qc_set_default_xso(QUIC_CONNECTION *qc, QUIC_XSO *xso, int touch)
+{
+    qc->default_xso = xso;
+    if (touch)
+        qc_touch_default_xso(qc);
+}
+
 /*
  * QUIC Front-End I/O API: Network BIO Configuration
  * =================================================
@@ -1170,11 +1190,12 @@ static int qc_try_create_default_xso_for_write(QUIC_CONNECTION *qc)
     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);
+    qc_set_default_xso(qc, (QUIC_XSO *)ossl_quic_conn_stream_new(&qc->ssl, flags),
+                       /*touch=*/0);
     if (qc->default_xso == NULL)
         return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
 
-    qc->default_xso_created = 1;
+    qc_touch_default_xso(qc);
     return 1;
 }
 
@@ -1267,11 +1288,11 @@ static int qc_wait_for_default_xso_for_read(QUIC_CONNECTION *qc)
      * We now have qs != NULL. Make it the default stream, creating the
      * necessary XSO.
      */
-    qc->default_xso = create_xso_from_stream(qc, qs);
+    qc_set_default_xso(qc, create_xso_from_stream(qc, qs), /*touch=*/0);
     if (qc->default_xso == NULL)
         return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
 
-    qc->default_xso_created = 1;
+    qc_touch_default_xso(qc); /* inhibits default XSO */
     return 1;
 }
 
@@ -1326,7 +1347,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 */
+    qc_touch_default_xso(ctx.qc); /* inhibits default XSO */
     quic_unlock(ctx.qc);
     return &xso->ssl;
 
@@ -2055,11 +2076,9 @@ SSL *ossl_quic_detach_stream(SSL *s)
 
     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;
+    xso = ctx.qc->default_xso;
+    qc_set_default_xso(ctx.qc, NULL, /*touch=*/1);
 
     quic_unlock(ctx.qc);
 
@@ -2090,10 +2109,8 @@ int ossl_quic_attach_stream(SSL *conn, SSL *stream)
                                            "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;
+    qc_set_default_xso(ctx.qc, (QUIC_XSO *)stream, /*touch=*/1);
 
     quic_unlock(ctx.qc);
     return 1;
@@ -2103,6 +2120,33 @@ int ossl_quic_attach_stream(SSL *conn, SSL *stream)
  * SSL_set_incoming_stream_reject_policy
  * -------------------------------------
  */
+QUIC_NEEDS_LOCK
+static int qc_get_effective_incoming_stream_reject_policy(QUIC_CONNECTION *qc)
+{
+    switch (qc->incoming_stream_reject_policy) {
+        case SSL_INCOMING_STREAM_REJECT_POLICY_AUTO:
+            if ((qc->default_xso == NULL && !qc->default_xso_created)
+                || qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_NONE)
+                return SSL_INCOMING_STREAM_REJECT_POLICY_ACCEPT;
+            else
+                return SSL_INCOMING_STREAM_REJECT_POLICY_REJECT;
+
+        default:
+            return qc->incoming_stream_reject_policy;
+    }
+}
+
+QUIC_NEEDS_LOCK
+static void qc_update_reject_policy(QUIC_CONNECTION *qc)
+{
+    int policy = qc_get_effective_incoming_stream_reject_policy(qc);
+    int enable_reject = (policy == SSL_INCOMING_STREAM_REJECT_POLICY_REJECT);
+
+    ossl_quic_channel_set_incoming_stream_auto_reject(qc->ch,
+                                                      enable_reject,
+                                                      qc->incoming_stream_reject_aec);
+}
+
 QUIC_TAKES_LOCK
 int ossl_quic_set_incoming_stream_reject_policy(SSL *s, int policy,
                                                 uint64_t aec)
@@ -2128,6 +2172,7 @@ int ossl_quic_set_incoming_stream_reject_policy(SSL *s, int policy,
         break;
     }
 
+    qc_update_reject_policy(ctx.qc);
     quic_unlock(ctx.qc);
     return ret;
 }
@@ -2136,22 +2181,6 @@ int ossl_quic_set_incoming_stream_reject_policy(SSL *s, int policy,
  * SSL_accept_stream
  * -----------------
  */
-QUIC_NEEDS_LOCK
-static int qc_get_effective_incoming_stream_reject_policy(QUIC_CONNECTION *qc)
-{
-    switch (qc->incoming_stream_reject_policy) {
-        case SSL_INCOMING_STREAM_REJECT_POLICY_AUTO:
-            if ((qc->default_xso == NULL && qc->default_xso_created)
-                || qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_NONE)
-                return SSL_INCOMING_STREAM_REJECT_POLICY_ACCEPT;
-            else
-                return SSL_INCOMING_STREAM_REJECT_POLICY_REJECT;
-
-        default:
-            return qc->incoming_stream_reject_policy;
-    }
-}
-
 struct wait_for_incoming_stream_args {
     QUIC_CONNECTION *qc;
     QUIC_STREAM     *qs;
@@ -2228,7 +2257,7 @@ SSL *ossl_quic_accept_stream(SSL *s, uint64_t flags)
     new_s = &xso->ssl;
 
     /* Calling this function inhibits default XSO autocreation. */
-    ctx.qc->default_xso_created = 1;
+    qc_touch_default_xso(ctx.qc); /* inhibits default XSO */
 
 out:
     quic_unlock(ctx.qc);