]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: quic: do not set first the default QUIC curves
authorFrederic Lecaille <flecaille@haproxy.com>
Tue, 25 Nov 2025 19:45:27 +0000 (20:45 +0100)
committerFrederic Lecaille <flecaille@haproxy.com>
Mon, 8 Dec 2025 09:40:59 +0000 (10:40 +0100)
This patch impacts both the QUIC frontends and listeners.

Note that "ssl-default-bind-ciphersuites", "ssl-default-bind-curves",
are not ignored by QUIC by the frontend. This is also the case for the
backends with "ssl-default-server-ciphersuites" and "ssl-default-server-curves".

These settings are set by ssl_sock_prepare_ctx() for the frontends and
by ssl_sock_prepare_srv_ssl_ctx() for the backends. But ssl_quic_initial_ctx()
first sets the default QUIC frontends (see <quic_ciphers> and <quic_groups>)
before these ssl_sock.c function are called, leading some TLS stack to
refuse them if they do not support them. This is the case for some OpenSSL 3.5
stack with FIPS support. They do not support X25519.

To fix this, set the default QUIC ciphersuites and curves only if not already
set by the settings mentioned above.

Rename <quic_ciphers> global variable to <default_quic_ciphersuites>
and <quic_groups> to <default_quic_curves> to reflect the OpenSSL API naming.

These options are taken into an account by ssl_quic_initial_ctx()
which inspects these four variable before calling SSL_CTX_set_ciphersuites()
with <default_quic_ciphersuites> as parameter and SSL_CTX_set_curves() with
<default_quic_curves> as parameter if needed, that is to say, if no ciphersuites
and curves were set by "ssl-default-bind-ciphersuites", "ssl-default-bind-curves"
as global options  or "ciphersuites", "curves" as "bind" line options.
Note that the bind_conf struct is not modified when no "ciphersuites" or
"curves" option are used on "bind" lines.

On backend side, rely on ssl_sock_init_srv() to set the server ciphersuites
and curves. This function is modified to use respectively <default_quic_ciphersuites>
and <default_quic_curves> if no ciphersuites  and curves were set by
"ssl-default-server-ciphersuites", "ssl-default-server-curves" as global options
or "ciphersuites", "curves" as "server" line options.

Thank to @rwagoner for having reported this issue in GH #3194 when using
an OpenSSL 3.5.4 stack with FIPS support.

Must be backported as far as 2.6

include/haproxy/quic_ssl-t.h
src/cfgparse-ssl.c
src/quic_ssl.c

index 3c057c6f0ca5f87eeab9c607dd46f1e553816185..addcf51c7219d7f114610de7a39d20005090be5b 100644 (file)
@@ -17,5 +17,7 @@
 #include <haproxy/pool-t.h>
 
 extern struct pool_head *pool_head_quic_ssl_sock_ctx;
+extern const char *default_quic_ciphersuites;
+extern const char *default_quic_curves;
 
 #endif /* _HAPROXY_QUIC_SSL_T_H */
index 3b694def09a2d78b5088570e25a72e4d7fb9220e..e5e539c082ebaad7a4dc08a5fedd7dd6dac3b619 100644 (file)
@@ -38,6 +38,7 @@
 #include <haproxy/errors.h>
 #include <haproxy/listener.h>
 #include <haproxy/openssl-compat.h>
+#include <haproxy/quic_ssl-t.h>
 #include <haproxy/ssl_sock.h>
 #include <haproxy/ssl_utils.h>
 #include <haproxy/tools.h>
@@ -1751,6 +1752,13 @@ static int ssl_sock_init_srv(struct server *s)
                if (!s->ssl_ctx.ciphersuites)
                        return 1;
        }
+#endif
+#ifdef USE_QUIC
+       if (srv_is_quic(s) && !s->ssl_ctx.ciphersuites) {
+               s->ssl_ctx.ciphersuites = strdup(default_quic_ciphersuites);
+               if (!s->ssl_ctx.ciphersuites)
+                       return 1;
+       }
 #endif
        s->ssl_ctx.options |= global_ssl.connect_default_ssloptions;
        s->ssl_ctx.methods.flags |= global_ssl.connect_default_sslmethods.flags;
@@ -1784,6 +1792,13 @@ static int ssl_sock_init_srv(struct server *s)
                        return 1;
        }
 #endif
+#ifdef USE_QUIC
+       if (srv_is_quic(s) && !s->ssl_ctx.curves) {
+               s->ssl_ctx.curves = strdup(default_quic_curves);
+               if (!s->ssl_ctx.curves)
+                       return 1;
+       }
+#endif
 
        if (global_ssl.renegotiate && !s->ssl_ctx.renegotiate)
                s->ssl_ctx.renegotiate = global_ssl.renegotiate;
index c1fcfe23bb3135f9d90b7394aa7cea1311a4478a..d115660b8e5cd0a39aa44935f3e86dfb3569f932 100644 (file)
 #include <haproxy/trace.h>
 
 DECLARE_TYPED_POOL(pool_head_quic_ssl_sock_ctx, "quic_ssl_sock_ctx", struct ssl_sock_ctx);
-const char *quic_ciphers = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384"
+const char *default_quic_ciphersuites = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384"
                            ":TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256";
 #ifdef HAVE_OPENSSL_QUIC
-const char *quic_groups = "X25519:P-256:P-384:P-521:X25519MLKEM768";
+const char *default_quic_curves = "X25519:P-256:P-384:P-521:X25519MLKEM768";
 #else
-const char *quic_groups = "X25519:P-256:P-384:P-521";
+const char *default_quic_curves = "X25519:P-256:P-384:P-521";
 #endif
 
 
@@ -741,8 +741,11 @@ static SSL_QUIC_METHOD ha_quic_method = {
  */
 int ssl_quic_initial_ctx(struct bind_conf *bind_conf)
 {
-       struct ssl_bind_conf __maybe_unused *ssl_conf_cur;
        int cfgerr = 0;
+       const char *ciphersuites = bind_conf->ssl_conf.ciphersuites ?
+               bind_conf->ssl_conf.ciphersuites : default_quic_ciphersuites;
+       const char *curves = bind_conf->ssl_conf.curves ?
+               bind_conf->ssl_conf.curves : default_quic_curves;
 
        long options =
                (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
@@ -759,7 +762,8 @@ int ssl_quic_initial_ctx(struct bind_conf *bind_conf)
        SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
        SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
        SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
-       if (SSL_CTX_set_ciphersuites(ctx, quic_ciphers) != 1) {
+               
+       if (SSL_CTX_set_ciphersuites(ctx, ciphersuites) != 1) {
                ha_warning("Binding [%s:%d] for %s %s: default QUIC cipher"
                           " suites setting failed.\n",
                           bind_conf->file, bind_conf->line,
@@ -768,17 +772,14 @@ int ssl_quic_initial_ctx(struct bind_conf *bind_conf)
                cfgerr++;
        }
 
-#ifndef HAVE_OPENSSL_QUICTLS
-       /* TODO: this should also work with QUICTLS */
-       if (SSL_CTX_set1_groups_list(ctx, quic_groups) != 1) {
+       if (SSL_CTX_set1_curves_list(ctx, curves) != 1) {
                ha_warning("Binding [%s:%d] for %s %s: default QUIC cipher"
-                          " groups setting failed.\n",
+                          " curves setting failed.\n",
                           bind_conf->file, bind_conf->line,
                           proxy_type_str(bind_conf->frontend),
                           bind_conf->frontend->id);
                cfgerr++;
        }
-#endif
 
        if (bind_conf->ssl_conf.early_data) {
 #if !defined(HAVE_SSL_0RTT_QUIC)
@@ -825,11 +826,6 @@ SSL_CTX *ssl_quic_srv_new_ssl_ctx(void)
 
        SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
        SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
-       if (SSL_CTX_set_ciphersuites(ctx, quic_ciphers) != 1)
-               goto err;
-
-       if (SSL_CTX_set1_groups_list(ctx, quic_groups) != 1)
-               goto err;
 
 #ifdef USE_QUIC_OPENSSL_COMPAT
        if (!quic_tls_compat_init(NULL, ctx))