From 0729382ba2d7cc8f5234cb09ec5b6ae693bf5b74 Mon Sep 17 00:00:00 2001 From: Bram Matthys Date: Thu, 24 Jul 2025 14:47:49 +0200 Subject: [PATCH] Rename ::ecdh-curves to groups and add X25519MLKEM768 to group list. Post-quantum cryptography (PQC). Release notes will follow later. --- autoconf/m4/unreal.m4 | 20 +++++++++++++ configure | 48 ++++++++++++++++++++++++++++++ configure.ac | 1 + include/config.h | 16 +++++----- include/setup.h.in | 3 ++ include/struct.h | 2 +- src/conf.c | 18 ++++++------ src/tls.c | 68 +++++++++++++++++++++++++++---------------- 8 files changed, 134 insertions(+), 42 deletions(-) diff --git a/autoconf/m4/unreal.m4 b/autoconf/m4/unreal.m4 index 283ac239d..f77a28853 100644 --- a/autoconf/m4/unreal.m4 +++ b/autoconf/m4/unreal.m4 @@ -241,6 +241,26 @@ else fi ]) +AC_DEFUN([CHECK_SSL_CTX_SET1_GROUPS_LIST], +[ +AC_MSG_CHECKING([for SSL_CTX_set1_groups_list in SSL library]) +AC_LANG_PUSH(C) +SAVE_LIBS="$LIBS" +LIBS="$LIBS $CRYPTOLIB" +AC_TRY_LINK([#include ], + [SSL_CTX *ctx = NULL; SSL_CTX_set1_groups_list(ctx, "test");], + has_function=1, + has_function=0) +LIBS="$SAVE_LIBS" +AC_LANG_POP(C) +if test $has_function = 1; then + AC_MSG_RESULT([yes]) + AC_DEFINE([HAS_SSL_CTX_SET1_GROUPS_LIST], [], [Define if ssl library has SSL_CTX_set1_groups_list]) +else + AC_MSG_RESULT([no]) +fi +]) + AC_DEFUN([CHECK_SSL_CTX_SET_MIN_PROTO_VERSION], [ AC_MSG_CHECKING([for SSL_CTX_set_min_proto_version in SSL library]) diff --git a/configure b/configure index 197953121..f3d4228d4 100755 --- a/configure +++ b/configure @@ -7418,6 +7418,54 @@ printf "%s\n" "no" >&6; } fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL_CTX_set1_groups_list in SSL library" >&5 +printf %s "checking for SSL_CTX_set1_groups_list in SSL library... " >&6; } +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +SAVE_LIBS="$LIBS" +LIBS="$LIBS $CRYPTOLIB" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ +SSL_CTX *ctx = NULL; SSL_CTX_set1_groups_list(ctx, "test"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + has_function=1 +else $as_nop + has_function=0 +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS="$SAVE_LIBS" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test $has_function = 1; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAS_SSL_CTX_SET1_GROUPS_LIST /**/" >>confdefs.h + +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL_CTX_set_min_proto_version in SSL library" >&5 printf %s "checking for SSL_CTX_set_min_proto_version in SSL library... " >&6; } ac_ext=c diff --git a/configure.ac b/configure.ac index d050ad5ff..399e0453d 100644 --- a/configure.ac +++ b/configure.ac @@ -574,6 +574,7 @@ AC_ARG_WITH(system-cares, [AS_HELP_STRING([--without-system-cares], [Use bundled AC_ARG_WITH(system-jansson, [AS_HELP_STRING([--without-system-jansson], [Use bundled version instead of system jansson. Normally autodetected via pkg-config.])], [], [with_system_jansson=yes]) CHECK_SSL CHECK_SSL_CTX_SET1_CURVES_LIST +CHECK_SSL_CTX_SET1_GROUPS_LIST CHECK_SSL_CTX_SET_MIN_PROTO_VERSION CHECK_SSL_CTX_SET_SECURITY_LEVEL CHECK_ASN1_TIME_diff diff --git a/include/config.h b/include/config.h index 885bc5b83..7885b2048 100644 --- a/include/config.h +++ b/include/config.h @@ -265,14 +265,16 @@ */ #define UNREALIRCD_DEFAULT_CIPHERSUITES "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256" -/* Default TLS curves for ECDH(E) - * This can be changed via set::ssl::options::ecdh-curve in the config file. - * The UNREALIRCD_DEFAULT_ECDH_CURVES_PRIMARY is tried first, and then the - * UNREALIRCD_DEFAULT_ECDH_CURVES_SECONDARY, since tha latter requires - * openssl 1.1.0 or newer. +/* Default TLS groups (previously only curves) + * This can be changed via set::ssl::options::groups (previously ::ecdh-curves) + * in the config file. By default we try these (in this order): + * UNREALIRCD_DEFAULT_TLS_GROUPS_PRIMARY requires OpenSSL 3.5.0 + * UNREALIRCD_DEFAULT_TLS_GROUPS_SECONDARY requires OpenSSL 1.1.0 + * UNREALIRCD_DEFAULT_TLS_GROUPS_TERTIARY is the last fallback option */ -#define UNREALIRCD_DEFAULT_ECDH_CURVES_PRIMARY "X25519:secp521r1:secp384r1:prime256v1" -#define UNREALIRCD_DEFAULT_ECDH_CURVES_SECONDARY "secp521r1:secp384r1:prime256v1" +#define UNREALIRCD_DEFAULT_TLS_GROUPS_PRIMARY "X25519MLKEM768:X25519:secp521r1:secp384r1:prime256v1" +#define UNREALIRCD_DEFAULT_TLS_GROUPS_SECONDARY "X25519:secp521r1:secp384r1:prime256v1" +#define UNREALIRCD_DEFAULT_TLS_GROUPS_TERTIARY "secp521r1:secp384r1:prime256v1" /* These can be changed via set::central-spamfilter::url and ::feed */ #define DEFAULT_CENTRAL_SPAMFILTER_URL_OPEN_ACCESS "https://spamfilter.unrealircd.org/spamfilter/v6/$feed/central_spamfilter.conf" diff --git a/include/setup.h.in b/include/setup.h.in index 521eb1d7f..737e63cbc 100644 --- a/include/setup.h.in +++ b/include/setup.h.in @@ -37,6 +37,9 @@ /* Define if ssl library has SSL_CTX_set1_curves_list */ #undef HAS_SSL_CTX_SET1_CURVES_LIST +/* Define if ssl library has SSL_CTX_set1_groups_list */ +#undef HAS_SSL_CTX_SET1_GROUPS_LIST + /* Define if ssl library has SSL_CTX_set_min_proto_version */ #undef HAS_SSL_CTX_SET_MIN_PROTO_VERSION diff --git a/include/struct.h b/include/struct.h index 3d7746faf..18a9a41fd 100644 --- a/include/struct.h +++ b/include/struct.h @@ -1853,7 +1853,7 @@ struct TLSOptions { unsigned int protocols; char *ciphers; char *ciphersuites; - char *ecdh_curves; + char *groups; char *outdated_protocols; char *outdated_ciphers; long options; diff --git a/src/conf.c b/src/conf.c index eb2867de9..8d2270b1d 100644 --- a/src/conf.c +++ b/src/conf.c @@ -7248,14 +7248,14 @@ void test_tlsblock(ConfigFile *conf, ConfigEntry *cep, int *totalerrors) { CheckNull(cepp); } - else if (!strcmp(cepp->name, "ecdh-curves")) + else if (!strcmp(cepp->name, "groups") || !strcmp(cepp->name, "ecdh-curves")) { CheckNull(cepp); #ifndef HAS_SSL_CTX_SET1_CURVES_LIST - config_error("ecdh-curves specified but your OpenSSL/LibreSSL library does not " - "support setting curves manually by name. Either upgrade to a " - "newer library version or remove the 'ecdh-curves' directive " - "from your configuration file"); + config_error("%s specified but your OpenSSL/LibreSSL library does not " + "support setting groups or curves. Either upgrade to a " + "newer library version or remove the '%s' directive " + "from your configuration file", cepp->name, cepp->name); errors++; #endif } @@ -7475,7 +7475,7 @@ void free_tls_options(TLSOptions *tlsoptions) safe_free(tlsoptions->trusted_ca_file); safe_free(tlsoptions->ciphers); safe_free(tlsoptions->ciphersuites); - safe_free(tlsoptions->ecdh_curves); + safe_free(tlsoptions->groups); safe_free(tlsoptions->outdated_protocols); safe_free(tlsoptions->outdated_ciphers); memset(tlsoptions, 0, sizeof(TLSOptions)); @@ -7496,7 +7496,7 @@ void conf_tlsblock(ConfigFile *conf, ConfigEntry *cep, TLSOptions *tlsoptions) tlsoptions->protocols = tempiConf.tls_options->protocols; safe_strdup(tlsoptions->ciphers, tempiConf.tls_options->ciphers); safe_strdup(tlsoptions->ciphersuites, tempiConf.tls_options->ciphersuites); - safe_strdup(tlsoptions->ecdh_curves, tempiConf.tls_options->ecdh_curves); + safe_strdup(tlsoptions->groups, tempiConf.tls_options->groups); safe_strdup(tlsoptions->outdated_protocols, tempiConf.tls_options->outdated_protocols); safe_strdup(tlsoptions->outdated_ciphers, tempiConf.tls_options->outdated_ciphers); tlsoptions->options = tempiConf.tls_options->options; @@ -7519,9 +7519,9 @@ void conf_tlsblock(ConfigFile *conf, ConfigEntry *cep, TLSOptions *tlsoptions) { safe_strdup(tlsoptions->ciphersuites, cepp->value); } - else if (!strcmp(cepp->name, "ecdh-curves")) + else if (!strcmp(cepp->name, "groups") || !strcmp(cepp->name, "ecdh-curves")) { - safe_strdup(tlsoptions->ecdh_curves, cepp->value); + safe_strdup(tlsoptions->groups, cepp->value); } else if (!strcmp(cepp->name, "protocols")) { diff --git a/src/tls.c b/src/tls.c index 6d10d7a2b..c59232c1f 100644 --- a/src/tls.c +++ b/src/tls.c @@ -271,6 +271,21 @@ void disable_ssl_protocols(SSL_CTX *ctx, TLSOptions *tlsoptions) #endif } +/* Set TLS groups. This is an internal function that is used to + * prevent some ifdef mess. And yes, in OpenSSL 3.5.x and later + * they map to the same, but in OpenSSL 3.2.x-3.4.x they didn't. + */ +static int unrealircd_set_tls_groups(SSL_CTX *ctx, const char *groups) +{ +#if defined(HAS_SSL_CTX_SET1_GROUPS_LIST) + return SSL_CTX_set1_groups_list(ctx, groups); +#elif defined(HAS_SSL_CTX_SET1_CURVES_LIST) + return SSL_CTX_set1_curves_list(ctx, groups); +#else + return 0; +#endif +} + /** Initialize TLS context * @param tlsoptions The ::tls-options configuration * @param server Set to 1 if we are initializing a server, 0 for client. @@ -445,50 +460,53 @@ SSL_CTX *init_ctx(TLSOptions *tlsoptions, int server) * do anything then, since auto ecdh is the default. */ #endif -#ifdef HAS_SSL_CTX_SET1_CURVES_LIST - /* Let's see if we need to (and can) set specific curves */ - if (tlsoptions->ecdh_curves == NULL) +#if defined(HAS_SSL_CTX_SET1_CURVES_LIST) || defined(HAS_SSL_CTX_SET1_GROUPS_LIST) + /* Let's see if we need to set specific TLS groups */ + if (tlsoptions->groups == NULL) { /* This means try the defaults.. */ - if (!SSL_CTX_set1_curves_list(ctx, UNREALIRCD_DEFAULT_ECDH_CURVES_PRIMARY)) + if (!unrealircd_set_tls_groups(ctx, UNREALIRCD_DEFAULT_TLS_GROUPS_PRIMARY)) { - if (!SSL_CTX_set1_curves_list(ctx, UNREALIRCD_DEFAULT_ECDH_CURVES_SECONDARY)) + if (!unrealircd_set_tls_groups(ctx, UNREALIRCD_DEFAULT_TLS_GROUPS_SECONDARY)) { - unreal_log(ULOG_ERROR, "config", "TLS_INVALID_ECDH_CURVES_LIST", NULL, - "Failed to set ecdh-curves to either " - "'$ecdh_curves_list_primary' or '$ecdh_curves_list_secondary'.\n" - "$tls_error.all\n" - "It's strange that neither curves list worked. " - "Please report at https://bugs.unrealircd.org/ !", - log_data_string("ecdh_curves_list_primary", UNREALIRCD_DEFAULT_ECDH_CURVES_PRIMARY), - log_data_string("ecdh_curves_list_secondary", UNREALIRCD_DEFAULT_ECDH_CURVES_SECONDARY), - log_data_tls_error()); - goto fail; + if (!unrealircd_set_tls_groups(ctx, UNREALIRCD_DEFAULT_TLS_GROUPS_TERTIARY)) + { + unreal_log(ULOG_ERROR, "config", "TLS_INVALID_TLS_GROUPS_LIST", NULL, + "Failed to set groups / ecdh-curves to either " + "'$tls_groups_primary', '$tls_groups_secondary' or '$tls_groups_tertiary'.\n" + "$tls_error.all\n" + "It's strange that none of the three worked. " + "Please report at https://bugs.unrealircd.org/ !", + log_data_string("tls_groups_primary", UNREALIRCD_DEFAULT_TLS_GROUPS_PRIMARY), + log_data_string("tls_groups_secondary", UNREALIRCD_DEFAULT_TLS_GROUPS_SECONDARY), + log_data_string("tls_groups_tertiary", UNREALIRCD_DEFAULT_TLS_GROUPS_TERTIARY), + log_data_tls_error()); + goto fail; + } } } } else { - /* Config-specified curves */ - if (!SSL_CTX_set1_curves_list(ctx, tlsoptions->ecdh_curves)) + /* User-configured TLS groups */ + if (!unrealircd_set_tls_groups(ctx, tlsoptions->groups)) { - unreal_log(ULOG_ERROR, "config", "TLS_INVALID_ECDH_CURVES_LIST", NULL, - "Failed to set ecdh-curves '$ecdh_curves_list'\n$tls_error.all\n" - "HINT: To get a list of supported curves with the appropriate names, " - "run 'openssl ecparam -list_curves' on the server. " + unreal_log(ULOG_ERROR, "config", "TLS_INVALID_TLS_GROUPS_LIST", NULL, + "Failed to set groups / ecdh-curves '$tls_groups'\n$tls_error.all\n" + "HINT: To get a list of supported names, run 'openssl ecparam -list_curves' on the server. " "Separate multiple curves by colon, for example: " - "ecdh-curves \"secp521r1:secp384r1\".", - log_data_string("ecdh_curves_list", tlsoptions->ecdh_curves), + "groups \"secp521r1:secp384r1\".", + log_data_string("tls_groups", tlsoptions->groups), log_data_tls_error()); goto fail; } } #else - if (tlsoptions->ecdh_curves) + if (tlsoptions->groups) { /* We try to avoid this in the config code, but better have * it here too than be sorry if someone screws up: */ - unreal_log(ULOG_ERROR, "config", "BUG_ECDH_CURVES", NULL, + unreal_log(ULOG_ERROR, "config", "BUG_TLS_GROUPS", NULL, "ecdh-curves specified but not supported by library -- BAD!"); goto fail; }