QUIC FIN Support: Various fixes
[openssl.git] / ssl / quic / quic_impl.c
index b6df5f778b65fec6e71e861eb08ebd0a5d51c967..5448e32e73faa4cca8259b52eb849b8ab885d8d6 100644 (file)
 #include <openssl/sslerr.h>
 #include <crypto/rand.h>
 #include "quic_local.h"
-#include "internal/quic_dummy_handshake.h"
+#include "internal/quic_tls.h"
 #include "internal/quic_rx_depack.h"
 #include "internal/quic_error.h"
 #include "internal/time.h"
 
 static void aon_write_finish(QUIC_CONNECTION *qc);
+static int ensure_channel(QUIC_CONNECTION *qc);
 
 /*
  * QUIC Front-End I/O API: Common Utilities
@@ -118,6 +119,7 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
 {
     QUIC_CONNECTION *qc = NULL;
     SSL *ssl_base = NULL;
+    SSL_CONNECTION *sc = NULL;
 
     qc = OPENSSL_zalloc(sizeof(*qc));
     if (qc == NULL)
@@ -125,15 +127,20 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
 
     /* Initialise the QUIC_CONNECTION's stub header. */
     ssl_base = &qc->ssl;
-    if (!ossl_ssl_init(ssl_base, ctx, SSL_TYPE_QUIC_CONNECTION)) {
+    if (!ossl_ssl_init(ssl_base, ctx, ctx->method, SSL_TYPE_QUIC_CONNECTION)) {
         ssl_base = NULL;
         goto err;
     }
 
+    qc->tls = ossl_ssl_connection_new_int(ctx, TLS_method());
+    if (qc->tls == NULL || (sc = SSL_CONNECTION_FROM_SSL(qc->tls)) == NULL)
+         goto err;
+
     /* Channel is not created yet. */
     qc->ssl_mode   = qc->ssl.ctx->mode;
     qc->last_error = SSL_ERROR_NONE;
     qc->blocking   = 1;
+
     return ssl_base;
 
 err:
@@ -152,7 +159,12 @@ void ossl_quic_free(SSL *s)
 
     ossl_quic_channel_free(qc->ch);
 
+    BIO_free(qc->net_rbio);
+    BIO_free(qc->net_wbio);
+
     /* Note: SSL_free calls OPENSSL_free(qc) for us */
+
+    SSL_free(qc->tls);
 }
 
 /* SSL method init */
@@ -181,7 +193,7 @@ int ossl_quic_reset(SSL *s)
     if (!expect_quic_conn(qc))
         return 0;
 
-    /* Currently a no-op. */
+    /* TODO(QUIC); Currently a no-op. */
     return 1;
 }
 
@@ -193,7 +205,7 @@ int ossl_quic_clear(SSL *s)
     if (!expect_quic_conn(qc))
         return 0;
 
-    /* Currently a no-op. */
+    /* TODO(QUIC): Currently a no-op. */
     return 1;
 }
 
@@ -260,7 +272,7 @@ int ossl_quic_clear(SSL *s)
  */
 static int csm_analyse_init_peer_addr(BIO *net_wbio, BIO_ADDR *peer)
 {
-    if (!BIO_dgram_get_peer(net_wbio, peer))
+    if (BIO_dgram_get_peer(net_wbio, peer) <= 0)
         return 0;
 
     return 1;
@@ -271,9 +283,10 @@ void ossl_quic_conn_set0_net_rbio(QUIC_CONNECTION *qc, BIO *net_rbio)
     if (qc->net_rbio == net_rbio)
         return;
 
-    if (qc->ch != NULL && !ossl_quic_channel_set0_net_rbio(qc->ch, net_rbio))
+    if (qc->ch != NULL && !ossl_quic_channel_set_net_rbio(qc->ch, net_rbio))
         return;
 
+    BIO_free(qc->net_rbio);
     qc->net_rbio = net_rbio;
 
     /*
@@ -298,9 +311,10 @@ void ossl_quic_conn_set0_net_wbio(QUIC_CONNECTION *qc, BIO *net_wbio)
     if (qc->net_wbio == net_wbio)
         return;
 
-    if (qc->ch != NULL && !ossl_quic_channel_set0_net_wbio(qc->ch, net_wbio))
+    if (qc->ch != NULL && !ossl_quic_channel_set_net_wbio(qc->ch, net_wbio))
         return;
 
+    BIO_free(qc->net_wbio);
     qc->net_wbio = net_wbio;
 
     if (net_wbio != NULL) {
@@ -406,7 +420,7 @@ int ossl_quic_tick(QUIC_CONNECTION *qc)
  */
 int ossl_quic_get_tick_timeout(QUIC_CONNECTION *qc, struct timeval *tv)
 {
-    OSSL_TIME now, deadline = ossl_time_infinite();
+    OSSL_TIME deadline = ossl_time_infinite();
 
     if (qc->ch != NULL)
         deadline
@@ -418,14 +432,7 @@ int ossl_quic_get_tick_timeout(QUIC_CONNECTION *qc, struct timeval *tv)
         return 1;
     }
 
-    now = ossl_time_now();
-    if (ossl_time_compare(now, deadline) >= 0) {
-        tv->tv_sec  = 0;
-        tv->tv_usec = 0;
-        return 1;
-    }
-
-    *tv = ossl_time_to_timeval(ossl_time_subtract(deadline, now));
+    *tv = ossl_time_to_timeval(ossl_time_subtract(deadline, ossl_time_now()));
     return 1;
 }
 
@@ -447,22 +454,22 @@ int ossl_quic_get_wpoll_descriptor(QUIC_CONNECTION *qc, BIO_POLL_DESCRIPTOR *des
     return BIO_get_wpoll_descriptor(qc->net_wbio, desc);
 }
 
-/* SSL_want_net_read */
-int ossl_quic_get_want_net_read(QUIC_CONNECTION *qc)
+/* SSL_net_read_desired */
+int ossl_quic_get_net_read_desired(QUIC_CONNECTION *qc)
 {
     if (qc->ch == NULL)
         return 0;
 
-    return ossl_quic_reactor_want_net_read(ossl_quic_channel_get_reactor(qc->ch));
+    return ossl_quic_reactor_net_read_desired(ossl_quic_channel_get_reactor(qc->ch));
 }
 
-/* SSL_want_net_write */
-int ossl_quic_get_want_net_write(QUIC_CONNECTION *qc)
+/* SSL_net_write_desired */
+int ossl_quic_get_net_write_desired(QUIC_CONNECTION *qc)
 {
     if (qc->ch == NULL)
         return 0;
 
-    return ossl_quic_reactor_want_net_write(ossl_quic_channel_get_reactor(qc->ch));
+    return ossl_quic_reactor_net_write_desired(ossl_quic_channel_get_reactor(qc->ch));
 }
 
 /*
@@ -480,27 +487,37 @@ int ossl_quic_get_want_net_write(QUIC_CONNECTION *qc)
  */
 
 /* SSL_shutdown */
-int ossl_quic_shutdown(SSL *s)
+static int quic_shutdown_wait(void *arg)
 {
-    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
-
-    if (!expect_quic_conn(qc))
-        return 0;
-
-    if (qc->ch != NULL)
-        ossl_quic_channel_local_close(qc->ch);
+    QUIC_CONNECTION *qc = arg;
 
-    return 1;
+    return qc->ch == NULL || ossl_quic_channel_is_terminated(qc->ch);
 }
 
-/* SSL_ctrl */
-static void fixup_mode_change(QUIC_CONNECTION *qc)
+int ossl_quic_conn_shutdown(QUIC_CONNECTION *qc, uint64_t flags,
+                            const SSL_SHUTDOWN_EX_ARGS *args,
+                            size_t args_len)
 {
-    /* If enabling EPW mode, cancel any AON write */
-    if ((qc->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 0)
-        aon_write_finish(qc);
+    if (!ensure_channel(qc))
+        return -1;
+
+    ossl_quic_channel_local_close(qc->ch,
+                                  args != NULL ? args->quic_error_code : 0);
+
+    /* TODO(QUIC): !SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH */
+
+    if (ossl_quic_channel_is_terminated(qc->ch))
+        return 1;
+
+    if (blocking_mode(qc) && (flags & SSL_SHUTDOWN_FLAG_RAPID) == 0)
+        block_until_pred(qc, quic_shutdown_wait, NULL, 0);
+    else
+        ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(qc->ch));
+
+    return ossl_quic_channel_is_terminated(qc->ch);
 }
 
+/* SSL_ctrl */
 long ossl_quic_ctrl(SSL *s, int cmd, long larg, void *parg)
 {
     QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
@@ -510,12 +527,14 @@ long ossl_quic_ctrl(SSL *s, int cmd, long larg, void *parg)
 
     switch (cmd) {
     case SSL_CTRL_MODE:
+        /* Cannot enable EPW while AON write in progress. */
+        if (qc->aon_write_in_progress)
+            larg &= ~SSL_MODE_ENABLE_PARTIAL_WRITE;
+
         qc->ssl_mode |= (uint32_t)larg;
-        fixup_mode_change(qc);
         return qc->ssl_mode;
     case SSL_CTRL_CLEAR_MODE:
         qc->ssl_mode &= ~(uint32_t)larg;
-        fixup_mode_change(qc);
         return qc->ssl_mode;
     default:
         return 0;
@@ -564,20 +583,15 @@ static int configure_channel(QUIC_CONNECTION *qc)
 {
     assert(qc->ch != NULL);
 
-    if (!ossl_quic_channel_set0_net_rbio(qc->ch, qc->net_rbio)
-        || !ossl_quic_channel_set0_net_wbio(qc->ch, qc->net_wbio)
+    if (!ossl_quic_channel_set_net_rbio(qc->ch, qc->net_rbio)
+        || !ossl_quic_channel_set_net_wbio(qc->ch, qc->net_wbio)
         || !ossl_quic_channel_set_peer_addr(qc->ch, &qc->init_peer_addr))
         return 0;
 
     return 1;
 }
 
-/*
- * Creates a channel and configures it with the information we have accumulated
- * via calls made to us from the application prior to starting a handshake
- * attempt.
- */
-static int ensure_channel_and_start(QUIC_CONNECTION *qc)
+static int ensure_channel(QUIC_CONNECTION *qc)
 {
     QUIC_CHANNEL_ARGS args = {0};
 
@@ -587,11 +601,25 @@ static int ensure_channel_and_start(QUIC_CONNECTION *qc)
     args.libctx     = qc->ssl.ctx->libctx;
     args.propq      = qc->ssl.ctx->propq;
     args.is_server  = 0;
+    args.tls        = qc->tls;
 
     qc->ch = ossl_quic_channel_new(&args);
     if (qc->ch == NULL)
         return 0;
 
+    return 1;
+}
+
+/*
+ * Creates a channel and configures it with the information we have accumulated
+ * via calls made to us from the application prior to starting a handshake
+ * attempt.
+ */
+static int ensure_channel_and_start(QUIC_CONNECTION *qc)
+{
+    if (!ensure_channel(qc))
+        return 0;
+
     if (!configure_channel(qc)
         || !ossl_quic_channel_start(qc->ch)) {
         ossl_quic_channel_free(qc->ch);
@@ -614,29 +642,39 @@ int ossl_quic_do_handshake(QUIC_CONNECTION *qc)
 {
     int ret;
 
-    fprintf(stderr, "# handshake begin\n");
+    if (qc->ch != NULL && ossl_quic_channel_is_handshake_complete(qc->ch))
+        /* Handshake already completed. */
+        return 1;
 
     if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch))
         return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
 
-    if (BIO_ADDR_family(&qc->init_peer_addr) == AF_UNSPEC)
+    if (BIO_ADDR_family(&qc->init_peer_addr) == AF_UNSPEC) {
         /* Peer address must have been set. */
-        return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_PASSED_INVALID_ARGUMENT, NULL);
+        QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_PASSED_INVALID_ARGUMENT, NULL);
+        return -1; /* Non-protocol error */
+    }
 
-    if (qc->as_server)
+    if (qc->as_server) {
         /* TODO(QUIC): Server mode not currently supported */
-        return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_PASSED_INVALID_ARGUMENT, NULL);
+        QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_PASSED_INVALID_ARGUMENT, NULL);
+        return -1; /* Non-protocol error */
+    }
 
-    if (qc->net_rbio == NULL || qc->net_wbio == NULL)
+    if (qc->net_rbio == NULL || qc->net_wbio == NULL) {
         /* Need read and write BIOs. */
-        return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_PASSED_INVALID_ARGUMENT, NULL);
+        QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_PASSED_INVALID_ARGUMENT, NULL);
+        return -1; /* Non-protocol error */
+    }
 
     /*
      * Start connection process. Note we may come here multiple times in
      * non-blocking mode, which is fine.
      */
-    if (!ensure_channel_and_start(qc))
-        return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
+    if (!ensure_channel_and_start(qc)) {
+        QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
+        return -1; /* Non-protocol error */
+    }
 
     if (ossl_quic_channel_is_handshake_complete(qc->ch))
         /* The handshake is now done. */
@@ -649,16 +687,27 @@ int ossl_quic_do_handshake(QUIC_CONNECTION *qc)
         args.qc     = qc;
 
         ret = block_until_pred(qc, quic_handshake_wait, &args, 0);
-        if (!ossl_quic_channel_is_active(qc->ch))
-            return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
-        else if (ret <= 0)
-            return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
+        if (!ossl_quic_channel_is_active(qc->ch)) {
+            QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
+            return 0; /* Shutdown before completion */
+        } else if (ret <= 0) {
+            QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
+            return -1; /* Non-protocol error */
+        }
 
         assert(ossl_quic_channel_is_handshake_complete(qc->ch));
         return 1;
     } else {
+        /* Try to advance the reactor. */
+        ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(qc->ch));
+
+        if (ossl_quic_channel_is_handshake_complete(qc->ch))
+            /* The handshake is now done. */
+            return 1;
+
         /* Otherwise, indicate that the handshake isn't done yet. */
-        return QUIC_RAISE_NORMAL_ERROR(qc, SSL_ERROR_WANT_READ);
+        QUIC_RAISE_NORMAL_ERROR(qc, SSL_ERROR_WANT_READ);
+        return -1; /* Non-protocol error */
     }
 }
 
@@ -707,6 +756,7 @@ int ossl_quic_accept(SSL *s)
  *   (BIO/)SSL_read             => ossl_quic_read
  *   (BIO/)SSL_write            => ossl_quic_write
  *         SSL_pending          => ossl_quic_pending
+ *         SSL_stream_conclude  => ossl_quic_conn_stream_conclude
  */
 
 /* SSL_get_error */
@@ -776,7 +826,7 @@ static int quic_write_again(void *arg)
     args->len           -= actual_written;
     args->total_written += actual_written;
 
-    if (actual_written == 0)
+    if (args->len == 0)
         /* Written everything, done. */
         return 1;
 
@@ -829,6 +879,10 @@ static int quic_write_blocking(QUIC_CONNECTION *qc, const void *buf, size_t len,
     return 1;
 }
 
+/*
+ * Functions to manage All-or-Nothing (AON) (that is, non-ENABLE_PARTIAL_WRITE)
+ * write semantics.
+ */
 static void aon_write_begin(QUIC_CONNECTION *qc, const unsigned char *buf,
                             size_t buf_len, size_t already_sent)
 {
@@ -859,8 +913,8 @@ static int quic_write_nonblocking_aon(QUIC_CONNECTION *qc, const void *buf,
     if (qc->aon_write_in_progress) {
         /*
          * We are in the middle of an AON write (i.e., a previous write did not
-         * manage to append all data to the SSTREAM and we have EPW mode
-         * disabled.)
+         * manage to append all data to the SSTREAM and we have Enable Partial
+         * Write (EPW) mode disabled.)
          */
         if ((!accept_moving_buffer && qc->aon_buf_base != buf)
             || len != qc->aon_buf_len)
@@ -958,13 +1012,16 @@ int ossl_quic_write(SSL *s, const void *buf, size_t len, size_t *written)
     if (!expect_quic_conn(qc))
         return 0;
 
-    /* If we haven't started the handshake, do so automatically. */
-    if (!qc->started && !ossl_quic_do_handshake(qc))
-        return 0;
-
     if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch))
         return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
 
+    /*
+     * If we haven't finished the handshake, try to advance it.
+     * We don't accept writes until the handshake is completed.
+     */
+    if (ossl_quic_do_handshake(qc) < 1)
+        return 0;
+
     if (qc->stream0 == NULL || qc->stream0->sstream == NULL)
         return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
 
@@ -997,6 +1054,10 @@ static int quic_read_actual(QUIC_CONNECTION *qc,
 {
     int is_fin = 0;
 
+    /* If the receive part of the stream is over, issue EOF. */
+    if (stream->recv_fin_retired)
+        return QUIC_RAISE_NORMAL_ERROR(qc, SSL_ERROR_ZERO_RETURN);
+
     if (stream->rstream == NULL)
         return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
 
@@ -1020,6 +1081,7 @@ static int quic_read_actual(QUIC_CONNECTION *qc,
              * the peer).
              */
             OSSL_RTT_INFO rtt_info;
+
             ossl_statm_get_rtt_info(ossl_quic_channel_get_statm(qc->ch), &rtt_info);
 
             if (!ossl_quic_rxfc_on_retire(&qc->stream0->rxfc, *bytes_read,
@@ -1042,9 +1104,11 @@ static int quic_read_again(void *arg)
 {
     struct quic_read_again_args *args = arg;
 
-    if (!ossl_quic_channel_is_active(args->qc->ch))
+    if (!ossl_quic_channel_is_active(args->qc->ch)) {
         /* If connection is torn down due to an error while blocking, stop. */
-        return -2;
+        QUIC_RAISE_NON_NORMAL_ERROR(args->qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
+        return -1;
+    }
 
     if (!quic_read_actual(args->qc, args->stream,
                           args->buf, args->len, args->bytes_read,
@@ -1055,7 +1119,7 @@ static int quic_read_again(void *arg)
         /* got at least one byte, the SSL_read op can finish now */
         return 1;
 
-    return 0; /* did not write anything, keep trying */
+    return 0; /* did not read anything, keep trying */
 }
 
 static int quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read, int peek)
@@ -1072,15 +1136,15 @@ static int quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read, int peek
     if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch))
         return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
 
-    /* If we haven't started the handshake, do so automatically. */
-    if (!qc->started && !ossl_quic_do_handshake(qc))
-        return 0;
+    /* If we haven't finished the handshake, try to advance it. */
+    if (ossl_quic_do_handshake(qc) < 1)
+        return 0; /* ossl_quic_do_handshake raised error here */
 
     if (qc->stream0 == NULL)
         return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
 
     if (!quic_read_actual(qc, qc->stream0, buf, len, bytes_read, peek))
-        return 0;
+        return 0; /* quic_read_actual raised error here */
 
     if (*bytes_read > 0) {
         /*
@@ -1103,15 +1167,16 @@ static int quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read, int peek
         args.peek       = peek;
 
         res = block_until_pred(qc, quic_read_again, &args, 0);
-        if (res <= 0) {
-            if (!ossl_quic_channel_is_active(qc->ch))
-                return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
-            else
-                return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
-        }
-    }
+        if (res == 0)
+            return QUIC_RAISE_NON_NORMAL_ERROR(qc, ERR_R_INTERNAL_ERROR, NULL);
+        else if (res < 0)
+            return 0; /* quic_read_again raised error here */
 
-    return 1;
+        return 1;
+    } else {
+        /* We did not get any bytes and are not in blocking mode. */
+        return QUIC_RAISE_NORMAL_ERROR(qc, SSL_ERROR_WANT_READ);
+    }
 }
 
 int ossl_quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read)
@@ -1147,6 +1212,26 @@ size_t ossl_quic_pending(const SSL *s)
     return avail;
 }
 
+/*
+ * SSL_stream_conclude
+ * -------------------
+ */
+int ossl_quic_conn_stream_conclude(QUIC_CONNECTION *qc)
+{
+    QUIC_STREAM *qs = qc->stream0;
+
+    if (qs == NULL || qs->sstream == NULL)
+        return 0;
+
+    if (!ossl_quic_channel_is_active(qc->ch)
+        || ossl_quic_sstream_get_final_size(qs->sstream, NULL))
+        return 1;
+
+    ossl_quic_sstream_fin(qs->sstream);
+    quic_post_write(qc, 1, 1);
+    return 1;
+}
+
 /*
  * QUIC Front-End I/O API: SSL_CTX Management
  * ==========================================
@@ -1156,23 +1241,18 @@ long ossl_quic_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
 {
     switch (cmd) {
     default:
-        return 0;
+        return ssl3_ctx_ctrl(ctx, cmd, larg, parg);
     }
 }
 
 long ossl_quic_callback_ctrl(SSL *s, int cmd, void (*fp) (void))
 {
-    return 0;
+    return ssl3_callback_ctrl(s, cmd, fp);
 }
 
 long ossl_quic_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void))
 {
-    return 0;
-}
-
-QUIC_CONNECTION *ossl_quic_conn_from_ssl(SSL *ssl)
-{
-    return QUIC_CONNECTION_FROM_SSL(ssl);
+    return ssl3_ctx_callback_ctrl(ctx, cmd, fp);
 }
 
 int ossl_quic_renegotiate_check(SSL *ssl, int initok)
@@ -1184,6 +1264,8 @@ int ossl_quic_renegotiate_check(SSL *ssl, int initok)
 /*
  * This is the subset of TLS1.3 ciphers which can be used with QUIC and which we
  * actually support.
+ *
+ * TODO(QUIC): CCM support
  */
 static SSL_CIPHER tls13_quic_ciphers[] = {
     {