]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: quic: inspect ALPN to install app_ops
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 12 Nov 2021 10:23:29 +0000 (11:23 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 18 Nov 2021 09:50:58 +0000 (10:50 +0100)
Remove the hardcoded initialization of h3 layer on mux init. Now the
ALPN is looked just after the SSL handshake. The app layer is then
installed if the ALPN negotiation returned a supported protocol.

This required to add a get_alpn on the ssl_quic layer which is just a
call to ssl_sock_get_alpn() from ssl_sock. This is mandatory to be able
to use conn_get_alpn().

include/haproxy/ssl_sock.h
src/mux_quic.c
src/ssl_sock.c
src/xprt_quic.c

index 3d0eee9b1a6c5257c5dc7fd941d4f24550f7e642..cd8d3b6a794091f391c29f20b8a13a6745ceae09 100644 (file)
@@ -60,6 +60,8 @@ void ssl_sock_destroy_bind_conf(struct bind_conf *bind_conf);
 int ssl_sock_prepare_srv_ctx(struct server *srv);
 void ssl_sock_free_srv_ctx(struct server *srv);
 void ssl_sock_free_all_ctx(struct bind_conf *bind_conf);
+int ssl_sock_get_alpn(const struct connection *conn, void *xprt_ctx,
+                      const char **str, int *len);
 int ssl_sock_load_ca(struct bind_conf *bind_conf);
 void ssl_sock_free_ca(struct bind_conf *bind_conf);
 int ssl_bio_and_sess_init(struct connection *conn, SSL_CTX *ssl_ctx,
index d870a68e23b7e858720599b88638031d328249f3..b15f1f7f32fdb0c7e0aebe1f132f628b93f99199 100644 (file)
@@ -502,7 +502,8 @@ void quic_mux_transport_params_update(struct qcc *qcc)
        /* Now that we have all the flow control information, we can finalize the application
         * context.
         */
-       qcc->app_ops->finalize(qcc->ctx);
+       if (qcc->app_ops)
+               qcc->app_ops->finalize(qcc->ctx);
 }
 
 /* Initialize the mux once it's attached. For outgoing connections, the context
@@ -570,9 +571,7 @@ static int qc_init(struct connection *conn, struct proxy *prx,
        qcc->conn->qc->qcc = qcc;
 
        /* Application layer initialization. */
-       qcc->app_ops = &h3_ops;
-       if (!qcc->app_ops->init(qcc))
-               goto fail;
+       qcc->app_ops = NULL;
 
        /* The transports parameters which control the data sent have been stored
         * in ->tx.params. The ones which control the received data are stored in
index 8b81ef8a464f4908ec4c0e9c667aa8e9d4cef82d..d53a3873f36b8e8bf0a0538c9c16677c0e19ac98 100644 (file)
@@ -6663,7 +6663,7 @@ unsigned int ssl_sock_get_verify_result(struct connection *conn)
  * freed by the caller. NPN is also checked if available since older versions
  * of openssl (1.0.1) which are more common in field only support this one.
  */
-static int ssl_sock_get_alpn(const struct connection *conn, void *xprt_ctx, const char **str, int *len)
+int ssl_sock_get_alpn(const struct connection *conn, void *xprt_ctx, const char **str, int *len)
 {
 #if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) || \
        defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
index 0fdc7aa8297e90790c23a6167a0b2af9e73da28b..d77540a7b696978dcb9c2c3b01133b0528a4fb19 100644 (file)
@@ -1590,6 +1590,9 @@ static forceinline void qc_ssl_dump_errors(struct connection *conn)
        }
 }
 
+int ssl_sock_get_alpn(const struct connection *conn, void *xprt_ctx,
+                      const char **str, int *len);
+
 /* Provide CRYPTO data to the TLS stack found at <data> with <len> as length
  * from <qel> encryption level with <ctx> as QUIC connection context.
  * Remaining parameter are there for debugging purposes.
@@ -1603,6 +1606,8 @@ static inline int qc_provide_cdata(struct quic_enc_level *el,
 {
        int ssl_err, state;
        struct quic_conn *qc;
+       const char *alpn;
+       int alpn_len;
 
        TRACE_ENTER(QUIC_EV_CONN_SSLDATA, ctx->conn);
        ssl_err = SSL_ERROR_NONE;
@@ -1659,6 +1664,19 @@ static inline int qc_provide_cdata(struct quic_enc_level *el,
                            QUIC_EV_CONN_HDSHK, ctx->conn, &state);
        }
 
+       conn_get_alpn(ctx->conn, &alpn, &alpn_len);
+       if (alpn_len >= 2 && memcmp(alpn, "h3", 2) == 0) {
+               qc->qcc->app_ops = &h3_ops;
+               if (!qc->qcc->app_ops->init(qc->qcc))
+                       goto err;
+       }
+       else {
+               /* TODO RFC9001 8.1. Protocol Negotiation
+                * must return no_application_protocol TLS alert
+                */
+               ABORT_NOW();
+       }
+
  out:
        TRACE_LEAVE(QUIC_EV_CONN_SSLDATA, ctx->conn);
        return 1;
@@ -4717,6 +4735,7 @@ static struct xprt_ops ssl_quic = {
        .start    = qc_xprt_start,
        .prepare_bind_conf = ssl_sock_prepare_bind_conf,
        .destroy_bind_conf = ssl_sock_destroy_bind_conf,
+       .get_alpn = ssl_sock_get_alpn,
        .name     = "QUIC",
 };