QUIC APL: Handle modes correctly
authorHugo Landau <hlandau@openssl.org>
Thu, 17 Aug 2023 09:00:02 +0000 (10:00 +0100)
committerTomas Mraz <tomas@openssl.org>
Tue, 29 Aug 2023 13:33:22 +0000 (15:33 +0200)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21764)

ssl/quic/quic_impl.c
ssl/ssl_lib.c
ssl/ssl_local.h

index 71bd5e865b525da18684dedf2c668f21cc50a1bd..2314cbb819c0f35a58edc6c87b77450084a5ffee 100644 (file)
@@ -1306,9 +1306,25 @@ long ossl_quic_ctrl(SSL *s, int cmd, long larg, void *parg)
     case DTLS_CTRL_HANDLE_TIMEOUT: /* DTLSv1_handle_timeout */
         /* For legacy compatibility with DTLS calls. */
         return ossl_quic_handle_events(s) == 1 ? 1 : -1;
+
+        /* Mask ctrls we shouldn't support for QUIC. */
+    case SSL_CTRL_GET_READ_AHEAD:
+    case SSL_CTRL_SET_READ_AHEAD:
+    case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
+    case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
+    case SSL_CTRL_SET_MAX_PIPELINES:
+        return 0;
+
     default:
-        /* Probably a TLS related ctrl. Defer to our internal SSL object */
-        return SSL_ctrl(ctx.qc->tls, cmd, larg, parg);
+        /*
+         * Probably a TLS related ctrl. Send back to the frontend SSL_ctrl
+         * implementation. Either SSL_ctrl will handle it itself by direct
+         * access into handshake layer state, or failing that, it will be passed
+         * to the handshake layer via the SSL_METHOD vtable. If the ctrl is not
+         * supported by anything, the handshake layer's ctrl method will finally
+         * return 0.
+         */
+        return ossl_ctrl_internal(&ctx.qc->ssl, cmd, larg, parg, /*no_quic=*/1);
     }
 }
 
index bda6a9c7beef2c44a2538a760bf46ea10c54a197..06efb4380acf591cbefdf69031210b54996ad7f4 100644 (file)
@@ -2899,22 +2899,37 @@ int SSL_new_session_ticket(SSL *s)
 }
 
 long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
+{
+    return ossl_ctrl_internal(s, cmd, larg, parg, /*no_quic=*/0);
+}
+
+long ossl_ctrl_internal(SSL *s, int cmd, long larg, void *parg, int no_quic)
 {
     long l;
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
-    /* TODO(QUIC FUTURE): Special handling for some ctrls will be needed */
-    if (sc == NULL)
-        return 0;
+    /*
+     * Routing of ctrl calls for QUIC is a little counterintuitive:
+     *
+     *   - Firstly (no_quic=0), we pass the ctrl directly to our QUIC
+     *     implementation in case it wants to handle the ctrl specially.
+     *
+     *   - If our QUIC implementation does not care about the ctrl, it
+     *     will reenter this function with no_quic=1 and we will try to handle
+     *     it directly using the QCSO SSL object stub (not the handshake layer
+     *     SSL object). This is important for e.g. the version configuration
+     *     ctrls below, which must use s->defltmeth (and not sc->defltmeth).
+     *
+     *   - If we don't handle a ctrl here specially, then processing is
+     *     redirected to the handshake layer SSL object.
+     */
+    if (!no_quic && IS_QUIC(s))
+        return s->method->ssl_ctrl(s, cmd, larg, parg);
 
     switch (cmd) {
     case SSL_CTRL_GET_READ_AHEAD:
-        if (IS_QUIC(s))
-            return 0;
         return RECORD_LAYER_get_read_ahead(&sc->rlayer);
     case SSL_CTRL_SET_READ_AHEAD:
-        if (IS_QUIC(s))
-            return 0;
         l = RECORD_LAYER_get_read_ahead(&sc->rlayer);
         RECORD_LAYER_set_read_ahead(&sc->rlayer, larg);
         return l;
@@ -2945,7 +2960,7 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
         sc->max_cert_list = (size_t)larg;
         return l;
     case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
-        if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH || IS_QUIC(s))
+        if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
             return 0;
 #ifndef OPENSSL_NO_KTLS
         if (sc->wbio != NULL && BIO_get_ktls_send(sc->wbio))
@@ -2957,12 +2972,12 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
         sc->rlayer.wrlmethod->set_max_frag_len(sc->rlayer.wrl, larg);
         return 1;
     case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
-        if ((size_t)larg > sc->max_send_fragment || larg == 0 || IS_QUIC(s))
+        if ((size_t)larg > sc->max_send_fragment || larg == 0)
             return 0;
         sc->split_send_fragment = larg;
         return 1;
     case SSL_CTRL_SET_MAX_PIPELINES:
-        if (larg < 1 || larg > SSL_MAX_PIPELINES || IS_QUIC(s))
+        if (larg < 1 || larg > SSL_MAX_PIPELINES)
             return 0;
         sc->max_pipelines = larg;
         if (sc->rlayer.rrlmethod->set_max_pipelines != NULL)
@@ -3007,7 +3022,10 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
     case SSL_CTRL_GET_MAX_PROTO_VERSION:
         return sc->max_proto_version;
     default:
-        return s->method->ssl_ctrl(s, cmd, larg, parg);
+        if (IS_QUIC(s))
+            return SSL_ctrl((SSL *)sc, cmd, larg, parg);
+        else
+            return s->method->ssl_ctrl(s, cmd, larg, parg);
     }
 }
 
index 4da83ab6928ea6e0f4e2a6e4068f5fa1ec75dee7..96d2f307616e22083f1931d57098c02d7c35aadf 100644 (file)
@@ -2999,6 +2999,8 @@ void ossl_ssl_set_custom_record_layer(SSL_CONNECTION *s,
                                       const OSSL_RECORD_METHOD *meth,
                                       void *rlarg);
 
+long ossl_ctrl_internal(SSL *s, int cmd, long larg, void *parg, int no_quic);
+
 /*
  * Options which no longer have any effect, but which can be implemented
  * as no-ops for QUIC.