BUG/MEDIUM: quic: support some ciphersuites and curves related options

This patch impacts both the QUIC frontends and listeners.

Before this patch "ssl-default-bind-ciphersuites", "ssl-default-bind-curves",
were ignored by QUIC. For the backend, "ssl-default-server-ciphersuites"
and "ssl-default-server-curves" were not ignored but set from set
from ssl_quic_srv_new_ssl_ctx() which is QUIC specific, in place of
ssl_sock_init_srv() as this is done for TCP.

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

On frontend side, add support for "ssl-default-bind-ciphersuites" and
"ssl-default-bind-curves" global options and "ciphersuites" and "curves" "bind"
options. These options are taken into an account by ssl_quic_initial_ctx()
which inspects these four variable before calling SSL_CTX_set_ciphersuites()
and SSL_CTX_set_curves(). Note that the bind_conf struct is not modified
when no "ciphersuites" or "curves" option are used on "bind" lines.

Idem 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
This commit is contained in:
Frederic Lecaille 2025-11-25 20:45:27 +01:00
parent d506c03aa0
commit 3095fa27ab
3 changed files with 28 additions and 15 deletions

View 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 */

View 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;

View File

@ -12,12 +12,12 @@
#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
@ -742,8 +742,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) |
@ -760,7 +763,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,
@ -769,17 +773,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)
@ -826,11 +827,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))