Rework options handling
authorHugo Landau <hlandau@openssl.org>
Mon, 3 Jul 2023 15:24:54 +0000 (16:24 +0100)
committerPauli <pauli@openssl.org>
Tue, 4 Jul 2023 23:03:04 +0000 (09:03 +1000)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20061)

doc/man3/SSL_CTX_set_options.pod
ssl/quic/quic_channel.c
ssl/quic/quic_impl.c
ssl/quic/quic_local.h
ssl/ssl_local.h

index 3605c7e6427f1cdee0571142bdc3620fc7340783..dd30873f3665541601df93a59114325884495612 100644 (file)
@@ -469,8 +469,6 @@ These options apply to SSL objects referencing a QUIC connection:
 
 =back
 
-Other options do not have an effect and will be ignored.
-
 These options apply to SSL objects referencing a QUIC stream:
 
 =over 4
@@ -479,14 +477,20 @@ These options apply to SSL objects referencing a QUIC stream:
 
 =back
 
-Other options do not have an effect and will be ignored.
+Options on QUIC connections are initialized from the options set on SSL_CTX
+before a QUIC connection SSL object is created. Options on QUIC streams are
+initialised from the options configured on the QUIC connection SSL object
+they are created from.
+
+Setting options which relate to QUIC streams on a QUIC connection SSL object has
+no direct effect on the QUIC connection SSL object itself, but will change the
+options set on the default stream (if there is one) and will also determine the
+default options set on any future streams which are created.
 
-If an SSL object is a QUIC connection object with a default stream attached,
-only the stream-relevant options are applied. If it is a QUIC connection
-without a default stream, the stream-relevant options are ignored.
+Other options not mentioned above do not have an effect and will be ignored.
 
-Connection and stream relevant options are initialized from the options
-set on SSL_CTX before the connection or stream objects are created.
+Options which relate to QUIC streams may also be set directly on QUIC stream SSL
+objects. Setting connection-related options on such an object has no effect.
 
 =head1 RETURN VALUES
 
index fe04dffa34d156b98f98701068aa28f88e4ece7a..576782c4f164f3f6e8db3c33ec7f5148078e3050 100644 (file)
@@ -2700,19 +2700,14 @@ static int ch_init_new_stream(QUIC_CHANNEL *ch, QUIC_STREAM *qs,
     int server_init = ossl_quic_stream_is_server_init(qs);
     int local_init = (ch->is_server == server_init);
     int is_uni = !ossl_quic_stream_is_bidi(qs);
-    int cleanse = (ch->tls->ctx->options & SSL_OP_CLEANSE_PLAINTEXT) != 0;
 
-    if (can_send) {
+    if (can_send)
         if ((qs->sstream = ossl_quic_sstream_new(INIT_APP_BUF_LEN)) == NULL)
             goto err;
-        ossl_quic_sstream_set_cleanse(qs->sstream, cleanse);
-    }
 
-    if (can_recv) {
+    if (can_recv)
         if ((qs->rstream = ossl_quic_rstream_new(NULL, NULL, 0)) == NULL)
             goto err;
-        ossl_quic_rstream_set_cleanse(qs->rstream, cleanse);
-    }
 
     /* TXFC */
     if (!ossl_quic_txfc_init(&qs->txfc, &ch->conn_txfc))
index 696a660cd4d21c0da4f3a02cc4064e751bebf62b..4866f52562fad5dcef8637af41ac2a93d6258376 100644 (file)
@@ -331,7 +331,7 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
     sc->s3.flags |= TLS1_FLAGS_QUIC;
 
     /* Restrict options derived from the SSL_CTX. */
-    sc->options &= OSSL_QUIC_PERMITTED_OPTIONS;
+    sc->options &= OSSL_QUIC_PERMITTED_OPTIONS_CONN;
     sc->pha_enabled = 0;
 
 #if defined(OPENSSL_THREADS)
@@ -349,6 +349,7 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
 
     qc->default_stream_mode     = SSL_DEFAULT_STREAM_MODE_AUTO_BIDI;
     qc->default_ssl_mode        = qc->ssl.ctx->mode;
+    qc->default_ssl_options     = qc->ssl.ctx->options & OSSL_QUIC_PERMITTED_OPTIONS;
     qc->default_blocking        = 1;
     qc->blocking                = 1;
     qc->incoming_stream_policy  = SSL_INCOMING_STREAM_POLICY_AUTO;
@@ -616,38 +617,70 @@ static void qc_set_default_xso(QUIC_CONNECTION *qc, QUIC_XSO *xso, int touch)
         SSL_free(&old_xso->ssl);
 }
 
-/* SSL_set_options */
+QUIC_NEEDS_LOCK
+static void xso_update_options(QUIC_XSO *xso)
+{
+    int cleanse = ((xso->ssl_options & SSL_OP_CLEANSE_PLAINTEXT) != 0);
+
+    if (xso->stream->rstream != NULL)
+        ossl_quic_rstream_set_cleanse(xso->stream->rstream, cleanse);
+
+    if (xso->stream->sstream != NULL)
+        ossl_quic_sstream_set_cleanse(xso->stream->sstream, cleanse);
+}
+
+/*
+ * SSL_set_options
+ * ---------------
+ *
+ * Setting options on a QCSO
+ *   - configures the handshake-layer options;
+ *   - configures the default data-plane options for new streams;
+ *   - configures the data-plane options on the default XSO, if there is one.
+ *
+ * Setting options on a QSSO
+ *   - configures data-plane options for that stream only.
+ */
 QUIC_TAKES_LOCK
 static uint64_t quic_mask_or_options(SSL *ssl, uint64_t mask_value, uint64_t or_value)
 {
     QCTX ctx;
-    uint64_t options;
+    uint64_t hs_mask_value, hs_or_value, ret;
 
     if (!expect_quic(ssl, &ctx))
         return 0;
 
     quic_lock(ctx.qc);
 
-    /*
-     * Currently most options that we permit are handled in the handshake
-     * layer.
-     */
-    or_value &= OSSL_QUIC_PERMITTED_OPTIONS;
+    if (!ctx.is_stream) {
+        /*
+         * If we were called on the connection, we apply any handshake option
+         * changes.
+         */
+        hs_mask_value = (mask_value & OSSL_QUIC_PERMITTED_OPTIONS_CONN);
+        hs_or_value   = (or_value   & OSSL_QUIC_PERMITTED_OPTIONS_CONN);
 
-    SSL_clear_options(ctx.qc->tls, mask_value);
-    options = SSL_set_options(ctx.qc->tls, or_value);
+        SSL_clear_options(ctx.qc->tls, hs_mask_value);
+        SSL_set_options(ctx.qc->tls, hs_or_value);
 
-    if (ctx.xso != NULL && ctx.xso->stream != NULL) {
-        int cleanse = ((options & SSL_OP_CLEANSE_PLAINTEXT) != 0);
+        /* Update defaults for new streams. */
+        ctx.qc->default_ssl_options
+            = ((ctx.qc->default_ssl_options & ~mask_value) | or_value)
+              & OSSL_QUIC_PERMITTED_OPTIONS;
+    }
 
-        if (ctx.xso->stream->rstream != NULL)
-            ossl_quic_rstream_set_cleanse(ctx.xso->stream->rstream, cleanse);
-        if (ctx.xso->stream->sstream != NULL)
-            ossl_quic_sstream_set_cleanse(ctx.xso->stream->sstream, cleanse);
+    if (ctx.xso != NULL) {
+        ctx.xso->ssl_options
+            = ((ctx.xso->ssl_options & ~mask_value) | or_value)
+            & OSSL_QUIC_PERMITTED_OPTIONS_STREAM;
+
+        xso_update_options(ctx.xso);
     }
 
+    ret = ctx.is_stream ? ctx.xso->ssl_options : ctx.qc->default_ssl_options;
+
     quic_unlock(ctx.qc);
-    return options;
+    return ret;
 }
 
 uint64_t ossl_quic_set_options(SSL *ssl, uint64_t options)
@@ -1542,11 +1575,14 @@ static QUIC_XSO *create_xso_from_stream(QUIC_CONNECTION *qc, QUIC_STREAM *qs)
     xso->conn       = qc;
     xso->blocking   = qc->default_blocking;
     xso->ssl_mode   = qc->default_ssl_mode;
+    xso->ssl_options
+        = qc->default_ssl_options & OSSL_QUIC_PERMITTED_OPTIONS_STREAM;
     xso->last_error = SSL_ERROR_NONE;
 
     xso->stream     = qs;
 
     ++qc->num_xso;
+    xso_update_options(xso);
     return xso;
 
 err:
index 547c47de055432e161590fc46dda3210ecd77258..7e257825c86c563ccedca386c315c79aaf733bd7 100644 (file)
@@ -85,6 +85,9 @@ struct quic_xso_st {
     /* SSL_set_mode */
     uint32_t                        ssl_mode;
 
+    /* SSL_set_options */
+    uint64_t                        ssl_options;
+
     /*
      * Last 'normal' error during an app-level I/O operation, used by
      * SSL_get_error(); used to track data-path errors like SSL_ERROR_WANT_READ
@@ -185,6 +188,9 @@ struct quic_conn_st {
     /* SSL_set_mode. This is not used directly but inherited by new XSOs. */
     uint32_t                        default_ssl_mode;
 
+    /* SSL_set_options. This is not used directly but inherited by new XSOs. */
+    uint64_t                        default_ssl_options;
+
     /* SSL_set_incoming_stream_policy. */
     int                             incoming_stream_policy;
     uint64_t                        incoming_stream_aec;
index a24ec27e5a858845c5e11559761f37bd120d79fb..82747f6dfb477c6f8a09ab4753136f2af24d919c 100644 (file)
@@ -3044,8 +3044,8 @@ void ossl_ssl_set_custom_record_layer(SSL_CONNECTION *s,
      SSL_OP_LEGACY_SERVER_CONNECT             | \
      SSL_OP_IGNORE_UNEXPECTED_EOF             )
 
-/* Total mask of options permitted or ignored under QUIC. */
-#define OSSL_QUIC_PERMITTED_OPTIONS             \
+/* Total mask of connection-level options permitted or ignored under QUIC. */
+#define OSSL_QUIC_PERMITTED_OPTIONS_CONN        \
     (OSSL_LEGACY_SSL_OPTIONS                  | \
      OSSL_TLS1_2_OPTIONS                      | \
      SSL_OP_CIPHER_SERVER_PREFERENCE          | \
@@ -3053,9 +3053,19 @@ void ossl_ssl_set_custom_record_layer(SSL_CONNECTION *s,
      SSL_OP_NO_TX_CERTIFICATE_COMPRESSION     | \
      SSL_OP_NO_RX_CERTIFICATE_COMPRESSION     | \
      SSL_OP_PRIORITIZE_CHACHA                 | \
-     SSL_OP_CLEANSE_PLAINTEXT                 | \
      SSL_OP_NO_QUERY_MTU                      | \
      SSL_OP_NO_TICKET                         | \
      SSL_OP_NO_ANTI_REPLAY                    )
 
+/* Total mask of stream-level options permitted or ignored under QUIC. */
+#define OSSL_QUIC_PERMITTED_OPTIONS_STREAM      \
+    (OSSL_LEGACY_SSL_OPTIONS                  | \
+     OSSL_TLS1_2_OPTIONS                      | \
+     SSL_OP_CLEANSE_PLAINTEXT                 )
+
+/* Total mask of options permitted on either connections or streams. */
+#define OSSL_QUIC_PERMITTED_OPTIONS             \
+    (OSSL_QUIC_PERMITTED_OPTIONS_CONN |         \
+     OSSL_QUIC_PERMITTED_OPTIONS_STREAM)
+
 #endif