Package: release.debian.org Severity: normal Tags: bullseye X-Debbugs-Cc: ngi...@packages.debian.org, debian.a...@manchmal.in-ulm.de Control: affects -1 + src:ngircd User: release.debian....@packages.debian.org Usertags: pu
[ Reason ] Fix one major and two more "Oh, that's not good" issues. It was agreed upon with security team to handle them via SPU. 1. In a TLS-based server-server connection, the server certificate is not validated. github issue: https://github.com/ngircd/ngircd/issues/120 For reasons neither upstream or I understand, a CVE number request was rejected. 2. In a server-server connection, a connection may still use plain text despite the connection ought to be TLS-based. Fix: https://github.com/ngircd/ngircd/commit/21c1751b045b0be49e584a4ba191a330e0c381bb Debian bug: https://bugs.debian.org/1067237 3. Some IRC services might send an empty string for the hostname to implement the "uncloak host" functionality, leading to a protocol violation in subsequent "WHOIS" or other commands against the ngircd server. Fix: https://github.com/ngircd/ngircd/commit/1118b0e77ca961a7b082f90cb124210eca8fb6bd [ Impact ] 1. Server-server links are prone to MITM attacks even when using TLS. 2. Downgrade attacks. 3. Client confusion, possibly crash. [ Tests ] 1. The unstable version of ngircd now has an autopkgtest for that situation. For a test, it was manually backported, and it passed. It's not included however to keep the change small. 2./3. No test in particular, but the change is small. Also, a private IRC network using ngircd with Debian bookworm was already upgraded in April, using a preliminary release. No technical issues were found, only documentation needed a little clarification (included). [ Risks ] 1. This might break flawed configurations, most notably if the peer's certificate has expired and/or cannot be verified against the configured trust store. The ngircd.NEWS and ngircd.README.Debian files have been updated. 2./3. No risks are to be expected. [ Checklist ] [x] *all* changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in (old)stable [x] the issue is verified as fixed in unstable (27~rc1-1, 2024-04-13) [ Changes ] All the changes were cherry-pick from upstream. 1. Whopping 19 patches, prefixed "S2S-TLS" 2. patch Respect-SSLConnect-option 3. patch METADATA-Fix-unsetting-cloakhost Also the mentioned changes to documentation in debian/ [ Other info ] The same story will follow for bookworm in a moment. In fact, bullseye and bookworm have the same version of ngircd at the moment. Regards, Christoph
diff -Nru ngircd-26.1/debian/changelog ngircd-26.1/debian/changelog --- ngircd-26.1/debian/changelog 2021-01-02 23:17:19.000000000 +0100 +++ ngircd-26.1/debian/changelog 2024-05-01 11:00:00.000000000 +0200 @@ -1,3 +1,13 @@ +ngircd (26.1-1+deb11u1) bullseye; urgency=high + + * Cherry-pick "Respect "SSLConnect" option for incoming + connections". Closes: #1067237 + * Cherry-pick "Support for server certificate validation on server + links [S2S-TLS]" + * Cherry-pick "METADATA: Fix unsetting "cloakhost"" + + -- Christoph Biedl <debian.a...@manchmal.in-ulm.de> Wed, 01 May 2024 11:00:00 +0200 + ngircd (26.1-1) unstable; urgency=medium * New upstream version 26.1 diff -Nru ngircd-26.1/debian/ngircd.conf ngircd-26.1/debian/ngircd.conf --- ngircd-26.1/debian/ngircd.conf 2021-01-02 23:17:19.000000000 +0100 +++ ngircd-26.1/debian/ngircd.conf 2024-05-01 11:00:00.000000000 +0200 @@ -273,6 +273,14 @@ # is only available when ngIRCd is compiled with support for SSL! # So don't forget to remove the ";" above if this is the case ... + # SSL Trusted CA Certificates File for verifying peer certificates. + # (Default: not set; so no certificates are trusted) + ;CAFile = /etc/ssl/certs/ca-certificates.crt + + # Certificate Revocation File (for marking otherwise valid + # certficates as invalid) + ;CRLFile = /etc/ssl/CA/crl.pem + # SSL Server Key Certificate ;CertFile = /etc/ssl/certs/server.crt @@ -366,6 +374,10 @@ # Connect to the remote server using TLS/SSL (Default: false) ;SSLConnect = yes + # Verify the TLS certificate presented by the remote server + # (Default: yes) + ;SSLVerify = yes + # Define a (case insensitive) list of masks matching nicknames that # should be treated as IRC services when introduced via this remote # server, separated by commas (","). diff -Nru ngircd-26.1/debian/ngircd.NEWS ngircd-26.1/debian/ngircd.NEWS --- ngircd-26.1/debian/ngircd.NEWS 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/ngircd.NEWS 2024-05-01 11:00:00.000000000 +0200 @@ -0,0 +1,8 @@ +ngircd (26.1-1+deb11u1) bullseye; urgency=high + + * This version introduces x509 certificate validation on TLS-based + server-server links. Existing configurations will likely break, for + details see </usr/share/doc/ngircd/README.Debian>, starting at + "TLS-based server-server links". + + -- Christoph Biedl <debian.a...@manchmal.in-ulm.de> Wed, 01 May 2024 11:00:00 +0200 diff -Nru ngircd-26.1/debian/ngircd.README.Debian ngircd-26.1/debian/ngircd.README.Debian --- ngircd-26.1/debian/ngircd.README.Debian 2021-01-02 21:46:42.000000000 +0100 +++ ngircd-26.1/debian/ngircd.README.Debian 2024-05-01 11:00:00.000000000 +0200 @@ -34,6 +34,25 @@ ngircd.service the daemon will not be able to load the files. +TLS-based server-server links +----------------------------- +When linking two ngircd servers, the connection should be TLS-based for +obvious reasons. To do so, edit ngircd.conf: + +* Enable SSLConnect in each [Server] stanza. +* Define CAFile in the [SSL] stanza. Note that by default *no* + certificate is trusted. + If the peers's certificate was signed by one of the well-known + certificate authorities: Use the suggested value + "/etc/ssl/certs/ca-certificates.crt" and install the ca-certificate + package. + Else set the value to the respective CA's certificate file. + +Verfication can be disabled entirely on a per-link base by setting +SSLVerify to false. This is strongly discouraged as you will lose all +security by that. + + DH parameters file ------------------ It is suggested to create a DH params file. If missing, ngIRCd will diff -Nru ngircd-26.1/debian/patches/0001-Respect-SSLConnect-option-for-incoming-connections.patch ngircd-26.1/debian/patches/0001-Respect-SSLConnect-option-for-incoming-connections.patch --- ngircd-26.1/debian/patches/0001-Respect-SSLConnect-option-for-incoming-connections.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0001-Respect-SSLConnect-option-for-incoming-connections.patch 2024-04-02 21:15:49.000000000 +0200 @@ -0,0 +1,43 @@ +From d09dc33e7d0f148ff9c0afff905414cc13d636fc Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Mon, 1 Jan 2024 18:20:26 +0100 +Subject: [PATCH 01/20] Respect "SSLConnect" option for incoming connections +Bug-Debian: https://bugs.debian.org/1067237 + +Don't accept incoming plain-text ("non SSL") server connections for +servers configured with "SSLConnect" enabled. + +If "SSLConnect" is not set for an incoming connection the server still +accepts both plain-text and encrypted connections. + +This change prevents an authenticated client-server being able to force +the server-server to send its password on a plain-text connection when +SSL/TLS was intended. + +(cherry picked from commit 21c1751b045b0be49e584a4ba191a330e0c381bb) +--- + src/ngircd/irc-server.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/src/ngircd/irc-server.c ++++ b/src/ngircd/irc-server.c +@@ -87,6 +87,19 @@ + return DISCONNECTED; + } + ++#ifdef SSL_SUPPORT ++ /* Does this server require an SSL connection? */ ++ if (Conf_Server[i].SSLConnect && ++ !(Conn_Options(Client_Conn(Client)) & CONN_SSL)) { ++ Log(LOG_ERR, ++ "Connection %d: Server \"%s\" requires a secure connection!", ++ Client_Conn(Client), Req->argv[0]); ++ Conn_Close(Client_Conn(Client), NULL, ++ "Secure connection required", true); ++ return DISCONNECTED; ++ } ++#endif ++ + /* Check server password */ + if (strcmp(Conn_Password(Client_Conn(Client)), + Conf_Server[i].pwd_in) != 0) { diff -Nru ngircd-26.1/debian/patches/0001-S2S-SSL-GnuTLS-Enable-CRL-verification_26.1.patch ngircd-26.1/debian/patches/0001-S2S-SSL-GnuTLS-Enable-CRL-verification_26.1.patch --- ngircd-26.1/debian/patches/0001-S2S-SSL-GnuTLS-Enable-CRL-verification_26.1.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0001-S2S-SSL-GnuTLS-Enable-CRL-verification_26.1.patch 2024-04-15 14:09:13.000000000 +0200 @@ -0,0 +1,21 @@ +From edb8fce8719efb0d887c72495e540d60a3bf4ed7 Mon Sep 17 00:00:00 2001 +From: Christoph Biedl <ngircd.a...@manchmal.in-ulm.de> +Date: Sun, 31 Mar 2024 00:36:53 +0100 +Subject: [PATCH] S2S-SSL/GnuTLS: Enable CRL verification + +(cherry picked from commit b2c9049af20b12f2fde08f4af0a35968404effdb) +--- + src/ngircd/conn-ssl.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -524,6 +524,8 @@ + return false; + + gnutls_certificate_set_dh_params(x509_cred, dh_params); ++ gnutls_certificate_set_flags(x509_cred, GNUTLS_CERTIFICATE_VERIFY_CRLS); ++ + err = gnutls_certificate_set_x509_key_file(x509_cred, cert_file, Conf_SSLOptions.KeyFile, GNUTLS_X509_FMT_PEM); + if (err < 0) { + Log(LOG_ERR, diff -Nru ngircd-26.1/debian/patches/0002-Support-for-server-certificate-validation-on-server-.patch ngircd-26.1/debian/patches/0002-Support-for-server-certificate-validation-on-server-.patch --- ngircd-26.1/debian/patches/0002-Support-for-server-certificate-validation-on-server-.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0002-Support-for-server-certificate-validation-on-server-.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,682 @@ +From 315125a8bcf6d80c969a3310c43b486b0e422e5b Mon Sep 17 00:00:00 2001 +From: Christoph Biedl <ngircd.a...@manchmal.in-ulm.de> +Date: Sun, 2 Nov 2014 14:48:34 +0100 +Subject: [PATCH 02/20] Support for server certificate validation on server + links [S2S-TLS] + +This patch provides code to validate the server certificate in +server links, defeating nasty man-in-the-middle attacks on server +links. + +Features: + +- Check whether the certificate is signed by a trusted certificate + authority (CA). +- Check the host name, including wildcard certificates and Subject + Alternative Names. +- Optionally check against a certificate revocation list (CRL). +- Implementation for both OpenSSL and GnuTLS linkage. + +Left for another day: + +- Parameterize the TLS parameter of an outbound connection. Currently, + it's hardcoded to disable all versions before TLSv1.1. +- Using certificate as CA-certificate. They work for GnuTLS only but + perhaps this should rather raise an error there, too. +- Optional OCSP checking. +- Checking client certificates. Code is there but this first needs some + consideration about the use cases. This could replace all other + authentication methods, for both client-server and server-server + connections. + +This patch is based on a patch by Florian Westphal from 2009, which +implemented this for OpenSSL only: + + From: Florian Westphal <f...@strlen.de> + Date: Mon, 18 May 2009 00:29:02 +0200 + Subject: SSL/TLS: Add initial certificate support to OpenSSL backend + +Commit message modified by Alex Barton. + +Closes #120, "Server links using TLS/SSL need certificate validation". +Supersedes PR #8, "Options for verifying and requiring SSL client +certificates", which had (incomplete?) code for OpenSSL, no GnuTLS. + +(cherry picked from commit 817937b218c4b57515f54216ebc936cd69df0aae) +--- + doc/sample-ngircd.conf.tmpl | 11 ++ + man/ngircd.conf.5.tmpl | 10 ++ + src/ngircd/conf.c | 27 ++- + src/ngircd/conf.h | 3 + + src/ngircd/conn-ssl.c | 323 ++++++++++++++++++++++++++++++++++-- + src/ngircd/conn.c | 21 +++ + src/ngircd/conn.h | 3 +- + 7 files changed, 385 insertions(+), 13 deletions(-) + +--- a/doc/sample-ngircd.conf.tmpl ++++ b/doc/sample-ngircd.conf.tmpl +@@ -266,6 +266,13 @@ + # is only available when ngIRCd is compiled with support for SSL! + # So don't forget to remove the ";" above if this is the case ... + ++ # SSL Trusted CA Certificates File (for verifying peer certificates) ++ ;CAFile = /etc/ssl/CA/cacert.pem ++ ++ # Certificate Revocation File (for marking otherwise valid ++ # certficates as invalid) ++ ;CRLFile = /etc/ssl/CA/crl.pem ++ + # SSL Server Key Certificate + ;CertFile = :ETCDIR:/ssl/server-cert.pem + +@@ -357,6 +364,10 @@ + # Connect to the remote server using TLS/SSL (Default: false) + ;SSLConnect = yes + ++ # Verify the TLS certificate presented by the remote server ++ # (Default: yes) ++ ;SSLVerify = yes ++ + # Define a (case insensitive) list of masks matching nicknames that + # should be treated as IRC services when introduced via this remote + # server, separated by commas (","). +--- a/man/ngircd.conf.5.tmpl ++++ b/man/ngircd.conf.5.tmpl +@@ -385,6 +385,13 @@ + section. Please note that this whole section is only recognized by ngIRCd + when it is compiled with support for SSL using OpenSSL or GnuTLS! + .TP ++\fBCAFile (string)\fR ++Filename pointing to the Trusted CA Certificates. This is required for ++verifying peer certificates. ++.TP ++\fBCRLFile (string)\fR ++Filename of Certificate Revocation List. ++.TP + \fBCertFile\fR (string) + SSL Certificate file of the private server key. + .TP +@@ -479,6 +486,9 @@ + \fBSSLConnect\fR (boolean) + Connect to the remote server using TLS/SSL. Default: false. + .TP ++\fBSSLVerify\fR (boolean) ++Verify the TLS certificate presented by the remote server. Default: yes. ++.TP + \fBServiceMask\fR (string) + Define a (case insensitive) list of masks matching nicknames that should be + treated as IRC services when introduced via this remote server, separated +--- a/src/ngircd/conf.c ++++ b/src/ngircd/conf.c +@@ -112,6 +112,12 @@ + free(Conf_SSLOptions.CertFile); + Conf_SSLOptions.CertFile = NULL; + ++ free(Conf_SSLOptions.CAFile); ++ Conf_SSLOptions.CAFile = NULL; ++ ++ free(Conf_SSLOptions.CRLFile); ++ Conf_SSLOptions.CRLFile = NULL; ++ + free(Conf_SSLOptions.DHFile); + Conf_SSLOptions.DHFile = NULL; + array_free_wipe(&Conf_SSLOptions.KeyFilePassword); +@@ -464,7 +470,10 @@ + printf( " Host = %s\n", Conf_Server[i].host ); + printf( " Port = %u\n", (unsigned int)Conf_Server[i].port ); + #ifdef SSL_SUPPORT +- printf( " SSLConnect = %s\n", Conf_Server[i].SSLConnect?"yes":"no"); ++ printf(" SSLConnect = %s\n", ++ yesno_to_str(Conf_Server[i].SSLConnect)); ++ printf(" SSLVerify = %s\n", ++ yesno_to_str(Conf_Server[i].SSLVerify)); + #endif + printf( " MyPassword = %s\n", Conf_Server[i].pwd_in ); + printf( " PeerPassword = %s\n", Conf_Server[i].pwd_out ); +@@ -1774,6 +1783,16 @@ + Conf_SSLOptions.CipherList = strdup_warn(Arg); + return; + } ++ if (strcasecmp(Var, "CAFile") == 0) { ++ assert(Conf_SSLOptions.CAFile == NULL); ++ Conf_SSLOptions.CAFile = strdup_warn(Arg); ++ return; ++ } ++ if (strcasecmp(Var, "CRLFile") == 0) { ++ assert(Conf_SSLOptions.CRLFile == NULL); ++ Conf_SSLOptions.CRLFile = strdup_warn(Arg); ++ return; ++ } + + Config_Error_Section(File, Line, Var, "SSL"); + } +@@ -1904,7 +1923,11 @@ + if( strcasecmp( Var, "SSLConnect" ) == 0 ) { + New_Server.SSLConnect = Check_ArgIsTrue(Arg); + return; +- } ++ } ++ if (strcasecmp(Var, "SSLVerify") == 0) { ++ New_Server.SSLVerify = Check_ArgIsTrue(Arg); ++ return; ++ } + #endif + if( strcasecmp( Var, "Group" ) == 0 ) { + /* Server group */ +--- a/src/ngircd/conf.h ++++ b/src/ngircd/conf.h +@@ -61,6 +61,7 @@ + ng_ipaddr_t dst_addr[2]; /**< List of addresses to connect to */ + #ifdef SSL_SUPPORT + bool SSLConnect; /**< Establish connection using SSL? */ ++ bool SSLVerify; /**< Verify server certificate using CA? */ + #endif + char svs_mask[CLIENT_ID_LEN]; /**< Mask of nicknames that should be + treated and counted as services */ +@@ -76,6 +77,8 @@ + array ListenPorts; /**< Array of listening SSL ports */ + array KeyFilePassword; /**< Key file password */ + char *CipherList; /**< Set SSL cipher list to use */ ++ char *CAFile; /**< Trusted CA certificates file */ ++ char *CRLFile; /**< Certificate revocation file */ + }; + #endif + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -43,13 +43,17 @@ + #include <openssl/err.h> + #include <openssl/rand.h> + #include <openssl/dh.h> ++#include <openssl/x509v3.h> + + static SSL_CTX * ssl_ctx; + static DH *dh_params; + + static bool ConnSSL_LoadServerKey_openssl PARAMS(( SSL_CTX *c )); ++static bool ConnSSL_SetVerifyProperties_openssl PARAMS((SSL_CTX * c)); + #endif + ++#define MAX_CERT_CHAIN_LENGTH 10 /* XXX: do not hardcode */ ++ + #ifdef HAVE_LIBGNUTLS + #include <sys/types.h> + #include <sys/stat.h> +@@ -74,6 +78,7 @@ + static gnutls_dh_params_t dh_params; + static gnutls_priority_t priorities_cache = NULL; + static bool ConnSSL_LoadServerKey_gnutls PARAMS(( void )); ++static bool ConnSSL_SetVerifyProperties_gnutls PARAMS((void)); + #endif + + #define SHA256_STRING_LEN (32 * 2 + 1) +@@ -131,10 +136,38 @@ + /** + * Log OpenSSL error message. + * ++ * @param level The log level + * @param msg The error message. + * @param info Additional information text or NULL. + */ + static void ++LogOpenSSL_CertInfo(int level, X509 * cert, const char *msg) ++{ ++ BIO *mem; ++ char *memptr; ++ long len; ++ ++ assert(cert); ++ assert(msg); ++ ++ if (!cert) ++ return; ++ mem = BIO_new(BIO_s_mem()); ++ if (!mem) ++ return; ++ X509_NAME_print_ex(mem, X509_get_subject_name(cert), 4, ++ XN_FLAG_ONELINE); ++ X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 4, XN_FLAG_ONELINE); ++ if (BIO_write(mem, "", 1) == 1) { ++ len = BIO_get_mem_data(mem, &memptr); ++ if (memptr && len > 0) ++ Log(level, "%s: \"%s\"", msg, memptr); ++ } ++ (void)BIO_set_close(mem, BIO_CLOSE); ++ BIO_free(mem); ++} ++ ++static void + LogOpenSSLError(const char *error, const char *info) + { + unsigned long err = ERR_get_error(); +@@ -176,9 +209,16 @@ + + + static int +-Verify_openssl(UNUSED int preverify_ok, UNUSED X509_STORE_CTX *x509_ctx) ++Verify_openssl(int preverify_ok, X509_STORE_CTX * ctx) + { +- return 1; ++ int err; ++ ++ if (!preverify_ok) { ++ err = X509_STORE_CTX_get_error(ctx); ++ Log(LOG_ERR, "Certificate validation failed: %s", ++ X509_verify_cert_error_string(err)); ++ } ++ return preverify_ok; + } + #endif + +@@ -354,7 +394,12 @@ + } + + SSL_CTX_set_session_id_context(newctx, (unsigned char *)"ngircd", 6); +- SSL_CTX_set_options(newctx, SSL_OP_SINGLE_DH_USE|SSL_OP_NO_SSLv2); ++ if (!ConnSSL_SetVerifyProperties_openssl(newctx)) ++ goto out; ++ SSL_CTX_set_options(newctx, ++ SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | ++ SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | ++ SSL_OP_NO_COMPRESSION); + SSL_CTX_set_mode(newctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_CTX_set_verify(newctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, + Verify_openssl); +@@ -394,6 +439,9 @@ + goto out; + } + ++ if (!ConnSSL_SetVerifyProperties_gnutls()) ++ goto out; ++ + Log(LOG_INFO, "GnuTLS %s initialized.", gnutls_check_version(NULL)); + initialized = true; + return true; +@@ -406,6 +454,37 @@ + + #ifdef HAVE_LIBGNUTLS + static bool ++ConnSSL_SetVerifyProperties_gnutls(void) ++{ ++ int err; ++ ++ if (!Conf_SSLOptions.CAFile) ++ return true; ++ ++ err = gnutls_certificate_set_x509_trust_file(x509_cred, ++ Conf_SSLOptions.CAFile, ++ GNUTLS_X509_FMT_PEM); ++ if (err < 0) { ++ Log(LOG_ERR, "Failed to load x509 trust file %s: %s", ++ Conf_SSLOptions.CAFile, gnutls_strerror(err)); ++ return false; ++ } ++ if (Conf_SSLOptions.CRLFile) { ++ err = ++ gnutls_certificate_set_x509_crl_file(x509_cred, ++ Conf_SSLOptions.CRLFile, ++ GNUTLS_X509_FMT_PEM); ++ if (err < 0) { ++ Log(LOG_ERR, "Failed to load x509 crl file %s: %s", ++ Conf_SSLOptions.CRLFile, gnutls_strerror(err)); ++ return false; ++ } ++ } ++ return true; ++} ++ ++ ++static bool + ConnSSL_LoadServerKey_gnutls(void) + { + int err; +@@ -531,6 +610,56 @@ + } + + ++static bool ++ConnSSL_SetVerifyProperties_openssl(SSL_CTX * ctx) ++{ ++ X509_STORE *store = NULL; ++ X509_LOOKUP *lookup; ++ int verify_flags = SSL_VERIFY_PEER; ++ bool ret = false; ++ ++ if (!Conf_SSLOptions.CAFile) ++ return true; ++ ++ if (SSL_CTX_load_verify_locations(ctx, Conf_SSLOptions.CAFile, NULL) != ++ 1) { ++ LogOpenSSLError("SSL_CTX_load_verify_locations", NULL); ++ goto out; ++ } ++ ++ if (Conf_SSLOptions.CRLFile) { ++ X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); ++ X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); ++ SSL_CTX_set1_param(ctx, param); ++ ++ store = SSL_CTX_get_cert_store(ctx); ++ assert(store); ++ lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); ++ if (!lookup) { ++ LogOpenSSLError("X509_STORE_add_lookup", ++ Conf_SSLOptions.CRLFile); ++ goto out; ++ } ++ ++ if (X509_load_crl_file ++ (lookup, Conf_SSLOptions.CRLFile, X509_FILETYPE_PEM) != 1) { ++ LogOpenSSLError("X509_load_crl_file", ++ Conf_SSLOptions.CRLFile); ++ goto out; ++ } ++ } ++ ++ SSL_CTX_set_verify(ctx, verify_flags, Verify_openssl); ++ SSL_CTX_set_verify_depth(ctx, MAX_CERT_CHAIN_LENGTH); ++ ret = true; ++out: ++ if (Conf_SSLOptions.CRLFile) ++ free(Conf_SSLOptions.CRLFile); ++ Conf_SSLOptions.CRLFile = NULL; ++ return ret; ++} ++ ++ + #endif + static bool + ConnSSL_Init_SSL(CONNECTION *c) +@@ -602,7 +731,7 @@ + + + bool +-ConnSSL_PrepareConnect(CONNECTION *c, UNUSED CONF_SERVER *s) ++ConnSSL_PrepareConnect(CONNECTION * c, CONF_SERVER * s) + { + bool ret; + #ifdef HAVE_LIBGNUTLS +@@ -613,7 +742,7 @@ + Log(LOG_ERR, "Failed to initialize new SSL session: %s", + gnutls_strerror(err)); + return false; +- } ++ } + #endif + ret = ConnSSL_Init_SSL(c); + if (!ret) +@@ -621,7 +750,23 @@ + Conn_OPTION_ADD(c, CONN_SSL_CONNECT); + #ifdef HAVE_LIBSSL + assert(c->ssl_state.ssl); +- SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL); ++ if (s->SSLVerify) { ++ X509_VERIFY_PARAM *param = NULL; ++ param = SSL_get0_param(c->ssl_state.ssl); ++ X509_VERIFY_PARAM_set_hostflags(param, ++ X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); ++Log(LOG_ERR, "DEBUG: Setting up hostname verification for '%s'", s->host); ++ int err = X509_VERIFY_PARAM_set1_host(param, s->host, 0); ++ if (err != 1) { ++ Log(LOG_ERR, ++ "Cannot set up hostname verification for '%s': %u", ++ s->host, err); ++ return false; ++ } ++ SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_PEER, ++ Verify_openssl); ++ } else ++ SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL); + #endif + return true; + } +@@ -720,18 +865,102 @@ + } + + ++#ifdef HAVE_LIBGNUTLS ++static void * ++LogMalloc(size_t s) ++{ ++ void *mem = malloc(s); ++ if (!mem) ++ Log(LOG_ERR, "Out of memory: Could not allocate %lu byte", ++ (unsigned long)s); ++ return mem; ++} ++ ++ + static void +-ConnSSL_LogCertInfo( CONNECTION *c ) ++LogGnuTLS_CertInfo(int level, gnutls_x509_crt_t cert, const char *msg) + { ++ char *dn, *issuer_dn; ++ size_t size = 0; ++ int err = gnutls_x509_crt_get_dn(cert, NULL, &size); ++ if (size == 0) { ++ Log(LOG_ERR, "gnutls_x509_crt_get_dn: size == 0"); ++ return; ++ } ++ if (err && err != GNUTLS_E_SHORT_MEMORY_BUFFER) ++ goto err_crt_get; ++ dn = LogMalloc(size); ++ if (!dn) ++ return; ++ err = gnutls_x509_crt_get_dn(cert, dn, &size); ++ if (err) ++ goto err_crt_get; ++ gnutls_x509_crt_get_issuer_dn(cert, NULL, &size); ++ assert(size); ++ issuer_dn = LogMalloc(size); ++ if (!issuer_dn) { ++ Log(level, "%s: Distinguished Name: %s", msg, dn); ++ free(dn); ++ return; ++ } ++ gnutls_x509_crt_get_issuer_dn(cert, issuer_dn, &size); ++ Log(level, "%s: Distinguished Name: \"%s\", Issuer \"%s\"", msg, dn, ++ issuer_dn); ++ free(dn); ++ free(issuer_dn); ++ return; ++ ++ err_crt_get: ++ Log(LOG_ERR, "gnutls_x509_crt_get_dn: %s", gnutls_strerror(err)); ++ return; ++} ++#endif ++ ++ ++static void ++ConnSSL_LogCertInfo( CONNECTION * c, bool connect) ++{ ++ bool cert_seen = false, cert_ok = false; ++ char msg[128]; + #ifdef HAVE_LIBSSL ++ const char *comp_alg = "no compression"; ++ const void *comp; ++ X509 *peer_cert = NULL; + SSL *ssl = c->ssl_state.ssl; + + assert(ssl); + +- Log(LOG_INFO, "Connection %d: initialized %s using cipher %s.", +- c->sock, SSL_get_version(ssl), SSL_get_cipher(ssl)); ++ comp = SSL_get_current_compression(ssl); ++ if (comp) ++ comp_alg = SSL_COMP_get_name(comp); ++ Log(LOG_INFO, "Connection %d: initialized %s using cipher %s, %s.", ++ c->sock, SSL_get_version(ssl), SSL_get_cipher(ssl), comp_alg); ++ peer_cert = SSL_get_peer_certificate(ssl); ++ if (peer_cert && connect) { ++ cert_seen = true; ++ /* Client: Check server certificate */ ++ int err = SSL_get_verify_result(ssl); ++ if (err == X509_V_OK) { ++ const char *peername = SSL_get0_peername(ssl); ++ if (peername != NULL) ++ cert_ok = true; ++ ++ Log(LOG_ERR, "X509_V_OK, peername = '%s'", peername); ++ ++ } else ++ Log(LOG_ERR, "Certificate validation failed: %s", ++ X509_verify_cert_error_string(err)); ++ snprintf(msg, sizeof(msg), "%svalid peer certificate", ++ cert_ok ? "" : "in"); ++ LogOpenSSL_CertInfo(cert_ok ? LOG_DEBUG : LOG_ERR, peer_cert, ++ msg); ++ ++ X509_free(peer_cert); ++ } + #endif + #ifdef HAVE_LIBGNUTLS ++ unsigned int status; ++ gnutls_credentials_type_t cred; + gnutls_session_t sess = c->ssl_state.gnutls_session; + gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess); + +@@ -740,7 +969,81 @@ + gnutls_protocol_get_name(gnutls_protocol_get_version(sess)), + gnutls_cipher_get_name(cipher), + gnutls_mac_get_name(gnutls_mac_get(sess))); ++ cred = gnutls_auth_get_type(c->ssl_state.gnutls_session); ++ if (cred == GNUTLS_CRD_CERTIFICATE && connect) { ++ cert_seen = true; ++ int verify = ++ gnutls_certificate_verify_peers2(c-> ++ ssl_state.gnutls_session, ++ &status); ++Log(LOG_ERR, "DEBUG: verify = %d", verify); ++ if (verify < 0) { ++ Log(LOG_ERR, ++ "gnutls_certificate_verify_peers2 failed: %s", ++ gnutls_strerror(verify)); ++ goto done_cn_validation; ++ } else if (status) { ++ gnutls_datum_t out; ++ ++ if (gnutls_certificate_verification_status_print ++ (status, gnutls_certificate_type_get(sess), &out, ++ 0) == GNUTLS_E_SUCCESS) { ++ Log(LOG_ERR, ++ "Certificate validation failed: %s", ++ out.data); ++ gnutls_free(out.data); ++ } ++ } ++Log(LOG_ERR, "DEBUG: status = %d", status); ++ ++ gnutls_x509_crt_t cert; ++ unsigned cert_list_size; ++ const gnutls_datum_t *cert_list = ++ gnutls_certificate_get_peers(sess, &cert_list_size); ++ if (!cert_list || cert_list_size == 0) { ++ Log(LOG_ERR, "No certificates found"); ++ goto done_cn_validation; ++ } ++ int err = gnutls_x509_crt_init(&cert); ++ if (err < 0) { ++ Log(LOG_ERR, ++ "Failed to initialize x509 certificate: %s", ++ gnutls_strerror(err)); ++ goto done_cn_validation; ++ } ++ err = gnutls_x509_crt_import(cert, cert_list, ++ GNUTLS_X509_FMT_DER); ++ if (err < 0) { ++ Log(LOG_ERR, "Failed to parse the certificate: %s", ++ gnutls_strerror(err)); ++ goto done_cn_validation; ++ } ++ err = gnutls_x509_crt_check_hostname(cert, c->host); ++ if (err == 0) ++ Log(LOG_ERR, ++ "Failed to verify the hostname, expected \"%s\"", ++ c->host); ++ else ++ cert_ok = verify == 0 && status == 0; ++ ++ snprintf(msg, sizeof(msg), "%svalid peer certificate", ++ cert_ok ? "" : "in"); ++ LogGnuTLS_CertInfo(cert_ok ? LOG_DEBUG : LOG_ERR, cert, msg); ++ ++ gnutls_x509_crt_deinit(cert); ++done_cn_validation: ++ ; ++ } + #endif ++ /* ++ * can be used later to check if connection was authenticated, e.g. ++ * if inbound connection tries to register itself as server. ++ * Could also restrict /OPER to authenticated connections, etc. ++ */ ++ if (cert_ok) ++ Conn_OPTION_ADD(c, CONN_SSL_PEERCERT_OK); ++ if (!cert_seen) ++ Log(LOG_INFO, "Peer did not present a certificate"); + } + + +@@ -879,7 +1182,7 @@ + (void)ConnSSL_InitCertFp(c); + + Conn_OPTION_DEL(c, (CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_CONNECT)); +- ConnSSL_LogCertInfo(c); ++ ConnSSL_LogCertInfo(c, connect); + + Conn_StartLogin(CONNECTION2ID(c)); + return 1; +--- a/src/ngircd/conn.c ++++ b/src/ngircd/conn.c +@@ -2546,6 +2546,7 @@ + cb_connserver_login_ssl(int sock, short unused) + { + CONN_ID idx = Socket2Index(sock); ++ int serveridx; + + (void) unused; + +@@ -2564,10 +2565,30 @@ + return; + } + ++ serveridx = Conf_GetServer(idx); ++ assert(serveridx >= 0); ++ if (serveridx < 0) ++ goto err; ++ + Log( LOG_INFO, "SSL connection %d with \"%s:%d\" established.", idx, + My_Connections[idx].host, Conf_Server[Conf_GetServer( idx )].port ); + ++ if (!Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_PEERCERT_OK)) { ++ if (Conf_Server[serveridx].SSLVerify) { ++ Log(LOG_ERR, ++ "SSLVerify enabled for %d, but peer certificate check failed", ++ idx); ++ goto err; ++ } ++ Log(LOG_WARNING, ++ "Peer certificate check failed for %d, but SSLVerify is disabled, continuing", ++ idx); ++ } + server_login(idx); ++ return; ++ err: ++ Log(LOG_ERR, "SSL connection on socket %d failed!", sock); ++ Conn_Close(idx, "Can't connect!", NULL, false); + } + + +--- a/src/ngircd/conn.h ++++ b/src/ngircd/conn.h +@@ -40,7 +40,8 @@ + #define CONN_SSL 32 /* this connection is SSL encrypted */ + #define CONN_SSL_WANT_WRITE 64 /* SSL/TLS library needs to write protocol data */ + #define CONN_SSL_WANT_READ 128 /* SSL/TLS library needs to read protocol data */ +-#define CONN_SSL_FLAGS_ALL (CONN_SSL_CONNECT|CONN_SSL|CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ) ++#define CONN_SSL_PEERCERT_OK 256 /* peer presented a valid certificate (used to check inbound server auth */ ++#define CONN_SSL_FLAGS_ALL (CONN_SSL_CONNECT|CONN_SSL|CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_PEERCERT_OK) + #endif + typedef int CONN_ID; + diff -Nru ngircd-26.1/debian/patches/0003-S2S-TLS-Add-missing-CAFile-and-CRLFile-options-to-co.patch ngircd-26.1/debian/patches/0003-S2S-TLS-Add-missing-CAFile-and-CRLFile-options-to-co.patch --- ngircd-26.1/debian/patches/0003-S2S-TLS-Add-missing-CAFile-and-CRLFile-options-to-co.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0003-S2S-TLS-Add-missing-CAFile-and-CRLFile-options-to-co.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,28 @@ +From 6a5d4ddeb6aaa63b958aed6ad9a84b1400530ecc Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Sat, 16 Dec 2023 16:29:05 +0100 +Subject: [PATCH 03/20] S2S-TLS: Add missing CAFile and CRLFile options to + "configtest" output + +(cherry picked from commit 5ca567a18caf699f93495ba2bc3749fb5f65383b) +--- + src/ngircd/conf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/src/ngircd/conf.c ++++ b/src/ngircd/conf.c +@@ -441,10 +441,14 @@ + + #ifdef SSL_SUPPORT + puts("[SSL]"); ++ printf(" CAFile = %s\n", Conf_SSLOptions.CAFile ++ ? Conf_SSLOptions.CAFile : ""); + printf(" CertFile = %s\n", Conf_SSLOptions.CertFile + ? Conf_SSLOptions.CertFile : ""); + printf(" CipherList = %s\n", Conf_SSLOptions.CipherList ? + Conf_SSLOptions.CipherList : DEFAULT_CIPHERS); ++ printf(" CRLFile = %s\n", Conf_SSLOptions.CRLFile ++ ? Conf_SSLOptions.CRLFile : ""); + printf(" DHFile = %s\n", Conf_SSLOptions.DHFile + ? Conf_SSLOptions.DHFile : ""); + printf(" KeyFile = %s\n", Conf_SSLOptions.KeyFile diff -Nru ngircd-26.1/debian/patches/0004-S2S-TLS-Remove-leftover-debug-messages.patch ngircd-26.1/debian/patches/0004-S2S-TLS-Remove-leftover-debug-messages.patch --- ngircd-26.1/debian/patches/0004-S2S-TLS-Remove-leftover-debug-messages.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0004-S2S-TLS-Remove-leftover-debug-messages.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,47 @@ +From c6c9edfe6ccc99d18cad039f7c10525a79566081 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Sat, 16 Dec 2023 16:30:06 +0100 +Subject: [PATCH 04/20] S2S-TLS: Remove leftover debug messages + +(cherry picked from commit 8f8bef9faee96a6033e8719fd38167017299847a) +--- + src/ngircd/conn-ssl.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -755,7 +755,6 @@ + param = SSL_get0_param(c->ssl_state.ssl); + X509_VERIFY_PARAM_set_hostflags(param, + X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); +-Log(LOG_ERR, "DEBUG: Setting up hostname verification for '%s'", s->host); + int err = X509_VERIFY_PARAM_set1_host(param, s->host, 0); + if (err != 1) { + Log(LOG_ERR, +@@ -944,9 +943,7 @@ + const char *peername = SSL_get0_peername(ssl); + if (peername != NULL) + cert_ok = true; +- +- Log(LOG_ERR, "X509_V_OK, peername = '%s'", peername); +- ++ LogDebug("X509_V_OK, peername = '%s'", peername); + } else + Log(LOG_ERR, "Certificate validation failed: %s", + X509_verify_cert_error_string(err)); +@@ -976,7 +973,6 @@ + gnutls_certificate_verify_peers2(c-> + ssl_state.gnutls_session, + &status); +-Log(LOG_ERR, "DEBUG: verify = %d", verify); + if (verify < 0) { + Log(LOG_ERR, + "gnutls_certificate_verify_peers2 failed: %s", +@@ -994,7 +990,6 @@ + gnutls_free(out.data); + } + } +-Log(LOG_ERR, "DEBUG: status = %d", status); + + gnutls_x509_crt_t cert; + unsigned cert_list_size; diff -Nru ngircd-26.1/debian/patches/0005-S2S-TLS-OpenSSL-Always-setup-host-name-verification.patch ngircd-26.1/debian/patches/0005-S2S-TLS-OpenSSL-Always-setup-host-name-verification.patch --- ngircd-26.1/debian/patches/0005-S2S-TLS-OpenSSL-Always-setup-host-name-verification.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0005-S2S-TLS-OpenSSL-Always-setup-host-name-verification.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,58 @@ +From d7c7b67c0921f2f78350cd2983f38f386d560d1d Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Mon, 1 Jan 2024 19:58:35 +0100 +Subject: [PATCH 05/20] S2S-TLS/OpenSSL: Always setup host name verification + +Setup host name verification even when the "SSLVerify" option is +disabled, because even then the peer can present a valid certificate and +validation would always(!) fail because of the missing host name +verification setup. + +(cherry picked from commit 84b019b11f761b71c8239d60e7f8db0b82a55df3) +--- + src/ngircd/conn-ssl.c | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -748,25 +748,27 @@ + if (!ret) + return false; + Conn_OPTION_ADD(c, CONN_SSL_CONNECT); ++ + #ifdef HAVE_LIBSSL + assert(c->ssl_state.ssl); +- if (s->SSLVerify) { +- X509_VERIFY_PARAM *param = NULL; +- param = SSL_get0_param(c->ssl_state.ssl); +- X509_VERIFY_PARAM_set_hostflags(param, +- X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); +- int err = X509_VERIFY_PARAM_set1_host(param, s->host, 0); +- if (err != 1) { +- Log(LOG_ERR, +- "Cannot set up hostname verification for '%s': %u", +- s->host, err); +- return false; +- } ++ ++ X509_VERIFY_PARAM *param = SSL_get0_param(c->ssl_state.ssl); ++ X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); ++ int err = X509_VERIFY_PARAM_set1_host(param, s->host, 0); ++ if (err != 1) { ++ Log(LOG_ERR, ++ "Cannot set up hostname verification for '%s': %u", ++ s->host, err); ++ return false; ++ } ++ ++ if (s->SSLVerify) + SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_PEER, + Verify_openssl); +- } else ++ else + SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL); + #endif ++ + return true; + } + diff -Nru ngircd-26.1/debian/patches/0006-S2S-TLS-OpenSSL-Set-the-verification-flags-only-once.patch ngircd-26.1/debian/patches/0006-S2S-TLS-OpenSSL-Set-the-verification-flags-only-once.patch --- ngircd-26.1/debian/patches/0006-S2S-TLS-OpenSSL-Set-the-verification-flags-only-once.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0006-S2S-TLS-OpenSSL-Set-the-verification-flags-only-once.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,45 @@ +From 9fa5c1908e866d9480bfaf0516111c4741adbd59 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Tue, 2 Jan 2024 20:55:15 +0100 +Subject: [PATCH 06/20] S2S-TLS/OpenSSL: Set the verification flags only once + +Set the verification flags in the ConnSSL_SetVerifyProperties_openssl +function only, don't override them in ConnSSL_InitLibrary() afterwards. + +No functional changes, now ConnSSL_SetVerifyProperties_openssl() sets +exactly the parameters which ConnSSL_InitLibrary() always overwrote ... + +(cherry picked from commit 08647ab1e7cf0d034f2d8987a3cac3201af84e02) +--- + src/ngircd/conn-ssl.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -401,8 +401,6 @@ + SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | + SSL_OP_NO_COMPRESSION); + SSL_CTX_set_mode(newctx, SSL_MODE_ENABLE_PARTIAL_WRITE); +- SSL_CTX_set_verify(newctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, +- Verify_openssl); + SSL_CTX_free(ssl_ctx); + ssl_ctx = newctx; + Log(LOG_INFO, "%s initialized.", OpenSSL_version(OPENSSL_VERSION)); +@@ -615,7 +613,6 @@ + { + X509_STORE *store = NULL; + X509_LOOKUP *lookup; +- int verify_flags = SSL_VERIFY_PEER; + bool ret = false; + + if (!Conf_SSLOptions.CAFile) +@@ -649,7 +646,8 @@ + } + } + +- SSL_CTX_set_verify(ctx, verify_flags, Verify_openssl); ++ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, ++ Verify_openssl); + SSL_CTX_set_verify_depth(ctx, MAX_CERT_CHAIN_LENGTH); + ret = true; + out: diff -Nru ngircd-26.1/debian/patches/0007-S2S-TLS-OpenSSL-Fix-handling-of-certificate-informat.patch ngircd-26.1/debian/patches/0007-S2S-TLS-OpenSSL-Fix-handling-of-certificate-informat.patch --- ngircd-26.1/debian/patches/0007-S2S-TLS-OpenSSL-Fix-handling-of-certificate-informat.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0007-S2S-TLS-OpenSSL-Fix-handling-of-certificate-informat.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,81 @@ +From 0bdc552ffe5c47be83c646b61e9a7d211d4568a6 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Tue, 2 Jan 2024 21:10:17 +0100 +Subject: [PATCH 07/20] S2S-TLS/OpenSSL: Fix handling of certificate + information for incoming connections + +Show proper certificate information for incoming connections, too, and +not "peer did not present a certificate", regardless if the client sent +a certificate or not. + +And free the client certificate structure "peer_cert" on incoming +connections as well! + +(cherry picked from commit 679505aab9fea21b27a3d4bbf99cf2a16cf3d3d5) +--- + src/ngircd/conn-ssl.c | 46 ++++++++++++++++++++++++++++--------------- + 1 file changed, 30 insertions(+), 16 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -935,22 +935,36 @@ + Log(LOG_INFO, "Connection %d: initialized %s using cipher %s, %s.", + c->sock, SSL_get_version(ssl), SSL_get_cipher(ssl), comp_alg); + peer_cert = SSL_get_peer_certificate(ssl); +- if (peer_cert && connect) { ++ if (peer_cert) { + cert_seen = true; +- /* Client: Check server certificate */ +- int err = SSL_get_verify_result(ssl); +- if (err == X509_V_OK) { +- const char *peername = SSL_get0_peername(ssl); +- if (peername != NULL) +- cert_ok = true; +- LogDebug("X509_V_OK, peername = '%s'", peername); +- } else +- Log(LOG_ERR, "Certificate validation failed: %s", +- X509_verify_cert_error_string(err)); +- snprintf(msg, sizeof(msg), "%svalid peer certificate", +- cert_ok ? "" : "in"); +- LogOpenSSL_CertInfo(cert_ok ? LOG_DEBUG : LOG_ERR, peer_cert, +- msg); ++ ++ if (connect) { ++ /* Outgoing connection. Verify the remote server! */ ++ int err = SSL_get_verify_result(ssl); ++ if (err == X509_V_OK) { ++ const char *peername = SSL_get0_peername(ssl); ++ if (peername != NULL) ++ cert_ok = true; ++ LogDebug("X509_V_OK, peername = '%s'", peername); ++ } else ++ Log(LOG_WARNING, "Certificate validation failed: %s!", ++ X509_verify_cert_error_string(err)); ++ ++ snprintf(msg, sizeof(msg), "Got %svalid server certificate", ++ cert_ok ? "" : "in"); ++ LogOpenSSL_CertInfo(LOG_INFO, peer_cert, msg); ++ } else { ++ /* Incoming connection. ++ * Accept all certificates, don't depend on their ++ * validity: for example, we don't know the hostname ++ * to check, because we not yet even know if this is a ++ * server connection at all and if so, which one, so we ++ * don't know a host name to look for. On the other ++ * hand we want client certificates, for example for ++ * "CertFP" authentication with services ... */ ++ LogOpenSSL_CertInfo(LOG_INFO, peer_cert, ++ "Got unchecked client certificate"); ++ } + + X509_free(peer_cert); + } +@@ -1038,7 +1052,7 @@ + if (cert_ok) + Conn_OPTION_ADD(c, CONN_SSL_PEERCERT_OK); + if (!cert_seen) +- Log(LOG_INFO, "Peer did not present a certificate"); ++ Log(LOG_INFO, "Peer did not present a certificate."); + } + + diff -Nru ngircd-26.1/debian/patches/0008-S2S-TLS-OpenSSL-Postpone-verification-of-TLS-session.patch ngircd-26.1/debian/patches/0008-S2S-TLS-OpenSSL-Postpone-verification-of-TLS-session.patch --- ngircd-26.1/debian/patches/0008-S2S-TLS-OpenSSL-Postpone-verification-of-TLS-session.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0008-S2S-TLS-OpenSSL-Postpone-verification-of-TLS-session.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,72 @@ +From 1a63a5e98b1dfe3a6e31dd6206585a1476f7d242 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Tue, 2 Jan 2024 22:02:46 +0100 +Subject: [PATCH 08/20] S2S-TLS/OpenSSL: Postpone verification of TLS session + right before server handshake + +The verify callback in OpenSSL is called pretty early, and at that time +it is not possible yet to check which connection it belongs to, and some +connections may have relaxed requirements. + +So always return success in the Verify_openssl() callback, and postpone +validation of the TLS session until starting the server handshake in +cb_connserver_login_ssl(), when we know which server this connection +belongs to and which options (like "SSLVerify") are in effect. + +The code doing this was already present in cb_connserver_login_ssl(), +but this patch adds a more prominent comment to the function. + +(cherry picked from commit 3db3b47fc7172a69b7d99d66eddb07a323dc6e74) +--- + src/ngircd/conn-ssl.c | 21 +++++++++++++++------ + src/ngircd/conn.c | 7 +++++++ + 2 files changed, 22 insertions(+), 6 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -211,14 +211,23 @@ + static int + Verify_openssl(int preverify_ok, X509_STORE_CTX * ctx) + { +- int err; +- ++#ifdef DEBUG + if (!preverify_ok) { +- err = X509_STORE_CTX_get_error(ctx); +- Log(LOG_ERR, "Certificate validation failed: %s", +- X509_verify_cert_error_string(err)); ++ int err = X509_STORE_CTX_get_error(ctx); ++ LogDebug("Certificate validation failed: %s", ++ X509_verify_cert_error_string(err)); + } +- return preverify_ok; ++#else ++ (void)preverify_ok; ++ (void)ctx; ++#endif ++ ++ /* Always(!) return success as we have to deal with invalid ++ * (self-signed, expired, ...) client certificates and with invalid ++ * server certificates when "SSLVerify" is disabled, which we don't ++ * know at this stage. Therefore we postpone this check, it will be ++ * (and has to be!) handled in cb_connserver_login_ssl(). */ ++ return 1; + } + #endif + +--- a/src/ngircd/conn.c ++++ b/src/ngircd/conn.c +@@ -2539,6 +2539,13 @@ + /** + * IO callback for new outgoing SSL-enabled server connections. + * ++ * IMPORTANT: The SSL session has been validated before, but all errors have ++ * been ignored so far! The reason for this is that the generic SSL code has no ++ * idea if the new session actually belongs to a server, as this only becomes ++ * clear when the remote peer sends its PASS command (and we have to handle ++ * invalid client certificates!). Therefore, it is important to check the ++ * status of the SSL session first before continuing the server handshake here! ++ * + * @param sock Socket descriptor. + * @param unused (ignored IO specification) + */ diff -Nru ngircd-26.1/debian/patches/0009-S2S-TLS-OpenSSL-Streamline-logging.patch ngircd-26.1/debian/patches/0009-S2S-TLS-OpenSSL-Streamline-logging.patch --- ngircd-26.1/debian/patches/0009-S2S-TLS-OpenSSL-Streamline-logging.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0009-S2S-TLS-OpenSSL-Streamline-logging.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,93 @@ +From 51a6339a8e766f1dee0915e6aea022986eab7306 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Tue, 2 Jan 2024 22:13:42 +0100 +Subject: [PATCH 09/20] S2S-TLS/OpenSSL: Streamline logging + +This includes simplifying cb_connserver_login_ssl() a bit, we do not +have to code for invalid state which was ruled out by an assert() and +therefore can get rid of the goto altogether (and don't log the same +error twice with different messages). + +(cherry picked from commit 02bb99b0242ade8af78f957aa1657561374ef1d6) +--- + src/ngircd/conn-ssl.c | 15 +++++++++------ + src/ngircd/conn.c | 25 +++++++++++-------------- + 2 files changed, 20 insertions(+), 20 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -155,13 +155,13 @@ + mem = BIO_new(BIO_s_mem()); + if (!mem) + return; +- X509_NAME_print_ex(mem, X509_get_subject_name(cert), 4, ++ X509_NAME_print_ex(mem, X509_get_subject_name(cert), 0, + XN_FLAG_ONELINE); +- X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 4, XN_FLAG_ONELINE); ++ X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_ONELINE); + if (BIO_write(mem, "", 1) == 1) { + len = BIO_get_mem_data(mem, &memptr); + if (memptr && len > 0) +- Log(level, "%s: \"%s\"", msg, memptr); ++ Log(level, "%s: \"%s\".", msg, memptr); + } + (void)BIO_set_close(mem, BIO_CLOSE); + BIO_free(mem); +@@ -832,9 +832,12 @@ + "SSL error, client disconnected [in %s()]!", + fname); + break; +- case -1: /* low level socket I/O error, check errno */ +- Log(LOG_ERR, "SSL error: %s [in %s()]!", +- strerror(real_errno), fname); ++ case -1: ++ /* Low level socket I/O error, check errno. But ++ * we don't need to log this here, the generic ++ * connection layer will take care of it. */ ++ LogDebug("SSL error: %s [in %s()]!", ++ strerror(real_errno), fname); + } + } + break; +--- a/src/ngircd/conn.c ++++ b/src/ngircd/conn.c +@@ -2574,28 +2574,25 @@ + + serveridx = Conf_GetServer(idx); + assert(serveridx >= 0); +- if (serveridx < 0) +- goto err; +- +- Log( LOG_INFO, "SSL connection %d with \"%s:%d\" established.", idx, +- My_Connections[idx].host, Conf_Server[Conf_GetServer( idx )].port ); + ++ /* The SSL handshake is done, but validation results were ignored so ++ * far, so let's see where we are: */ ++ LogDebug("SSL handshake on socket %d done.", idx); + if (!Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_PEERCERT_OK)) { + if (Conf_Server[serveridx].SSLVerify) { + Log(LOG_ERR, +- "SSLVerify enabled for %d, but peer certificate check failed", +- idx); +- goto err; ++ "Peer certificate check failed for \"%s\" on connection %d!", ++ My_Connections[idx].host, idx); ++ Conn_Close(idx, "Valid certificate required", ++ NULL, false); ++ return; + } + Log(LOG_WARNING, +- "Peer certificate check failed for %d, but SSLVerify is disabled, continuing", +- idx); ++ "Peer certificate check failed for \"%s\" on connection %d, but \"SSLVerify\" is disabled. Continuing ...", ++ My_Connections[idx].host, idx); + } ++ LogDebug("Server certificate accepted, continuing server login ..."); + server_login(idx); +- return; +- err: +- Log(LOG_ERR, "SSL connection on socket %d failed!", sock); +- Conn_Close(idx, "Can't connect!", NULL, false); + } + + diff -Nru ngircd-26.1/debian/patches/0010-S2S-TLS-Fix-formatting-and-sort-new-SSL-options-in-n.patch ngircd-26.1/debian/patches/0010-S2S-TLS-Fix-formatting-and-sort-new-SSL-options-in-n.patch --- ngircd-26.1/debian/patches/0010-S2S-TLS-Fix-formatting-and-sort-new-SSL-options-in-n.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0010-S2S-TLS-Fix-formatting-and-sort-new-SSL-options-in-n.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,38 @@ +From c9247d7031c4f92d583035ea29a182b3dd8b478d Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Wed, 3 Jan 2024 15:40:58 +0100 +Subject: [PATCH 10/20] S2S-TLS: Fix formatting and sort new SSL options in + ngircd.conf manual page + +(cherry picked from commit 58ee4df2ae2e4e59ae8909b69670825229158da8) +--- + man/ngircd.conf.5.tmpl | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/man/ngircd.conf.5.tmpl ++++ b/man/ngircd.conf.5.tmpl +@@ -385,13 +385,10 @@ + section. Please note that this whole section is only recognized by ngIRCd + when it is compiled with support for SSL using OpenSSL or GnuTLS! + .TP +-\fBCAFile (string)\fR ++\fBCAFile\fR (string) + Filename pointing to the Trusted CA Certificates. This is required for + verifying peer certificates. + .TP +-\fBCRLFile (string)\fR +-Filename of Certificate Revocation List. +-.TP + \fBCertFile\fR (string) + SSL Certificate file of the private server key. + .TP +@@ -401,6 +398,9 @@ + Please see 'man 1ssl ciphers' (OpenSSL) and 'man 3 gnutls_priority_init' + (GnuTLS) for details. + .TP ++\fBCRLFile\fR (string) ++Filename of Certificate Revocation List. ++.TP + \fBDHFile\fR (string) + Name of the Diffie-Hellman Parameter file. Can be created with GnuTLS + "certtool \-\-generate-dh-params" or "openssl dhparam". If this file is not diff -Nru ngircd-26.1/debian/patches/0011-S2S-TLS-MAX_CERT_CHAIN_LENGTH-is-only-used-by-OpenSS.patch ngircd-26.1/debian/patches/0011-S2S-TLS-MAX_CERT_CHAIN_LENGTH-is-only-used-by-OpenSS.patch --- ngircd-26.1/debian/patches/0011-S2S-TLS-MAX_CERT_CHAIN_LENGTH-is-only-used-by-OpenSS.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0011-S2S-TLS-MAX_CERT_CHAIN_LENGTH-is-only-used-by-OpenSS.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,30 @@ +From 9653e891d5aa9b9182f10eb5b737242de0ccada9 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Fri, 5 Jan 2024 22:17:12 +0100 +Subject: [PATCH 11/20] S2S-TLS: MAX_CERT_CHAIN_LENGTH is only used by OpenSSL + +(cherry picked from commit c8589e9890742c377c78595131ef1cdc8d784c66) +--- + src/ngircd/conn-ssl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -45,6 +45,8 @@ + #include <openssl/dh.h> + #include <openssl/x509v3.h> + ++#define MAX_CERT_CHAIN_LENGTH 10 /* XXX: do not hardcode */ ++ + static SSL_CTX * ssl_ctx; + static DH *dh_params; + +@@ -52,8 +54,6 @@ + static bool ConnSSL_SetVerifyProperties_openssl PARAMS((SSL_CTX * c)); + #endif + +-#define MAX_CERT_CHAIN_LENGTH 10 /* XXX: do not hardcode */ +- + #ifdef HAVE_LIBGNUTLS + #include <sys/types.h> + #include <sys/stat.h> diff -Nru ngircd-26.1/debian/patches/0012-S2S-TLS-GnuTLS-Update-SSL-code-for-GnuTLS-certificat.patch ngircd-26.1/debian/patches/0012-S2S-TLS-GnuTLS-Update-SSL-code-for-GnuTLS-certificat.patch --- ngircd-26.1/debian/patches/0012-S2S-TLS-GnuTLS-Update-SSL-code-for-GnuTLS-certificat.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0012-S2S-TLS-GnuTLS-Update-SSL-code-for-GnuTLS-certificat.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,27 @@ +From 8676c743246aaebe6d45f0978812c154ecfa25dd Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Fri, 5 Jan 2024 22:23:53 +0100 +Subject: [PATCH 12/20] S2S-TLS/GnuTLS: Update SSL code for GnuTLS certificate + reloading + +Without this, the S2S-TLS-Patch not even compiles with GnuTLS because +of the "new" GnuTLS certificate reload support implemented in commit +eead4a63 ("x509_cred_slot"). + +(cherry picked from commit 0e176b557037b583f408229b518646804b33d745) +--- + src/ngircd/conn-ssl.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -468,6 +468,9 @@ + if (!Conf_SSLOptions.CAFile) + return true; + ++ x509_cred_slot *slot = array_get(&x509_creds, sizeof(x509_cred_slot), x509_cred_idx); ++ gnutls_certificate_credentials_t x509_cred = slot->x509_cred; ++ + err = gnutls_certificate_set_x509_trust_file(x509_cred, + Conf_SSLOptions.CAFile, + GNUTLS_X509_FMT_PEM); diff -Nru ngircd-26.1/debian/patches/0013-S2S-TLS-GnuTLS-Fix-handling-of-certificate-informati.patch ngircd-26.1/debian/patches/0013-S2S-TLS-GnuTLS-Fix-handling-of-certificate-informati.patch --- ngircd-26.1/debian/patches/0013-S2S-TLS-GnuTLS-Fix-handling-of-certificate-informati.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0013-S2S-TLS-GnuTLS-Fix-handling-of-certificate-informati.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,118 @@ +From a1e391b1148b2e2cb406423473dc89ff28b7cdba Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Fri, 5 Jan 2024 22:29:40 +0100 +Subject: [PATCH 13/20] S2S-TLS/GnuTLS: Fix handling of certificate information + for incoming connections + +Show proper certificate information for incoming connections, too, and +not "peer did not present a certificate", regardless if the client sent +a certificate or not. + +This change is for GnuTLS and similar to what was implemented in commit +for OpenSSL in "S2S-TLS/OpenSSL: Fix handling of certificate information +for incoming connections". + +(cherry picked from commit 509ff6032686662328f4ecb0c5c287a34e929c53) +--- + src/ngircd/conn-ssl.c | 75 ++++++++++++++++++++++++------------------- + 1 file changed, 42 insertions(+), 33 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -747,6 +747,7 @@ + #ifdef HAVE_LIBGNUTLS + int err; + ++ (void)s; + err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_CLIENT); + if (err) { + Log(LOG_ERR, "Failed to initialize new SSL session: %s", +@@ -996,29 +997,8 @@ + gnutls_cipher_get_name(cipher), + gnutls_mac_get_name(gnutls_mac_get(sess))); + cred = gnutls_auth_get_type(c->ssl_state.gnutls_session); +- if (cred == GNUTLS_CRD_CERTIFICATE && connect) { ++ if (cred == GNUTLS_CRD_CERTIFICATE) { + cert_seen = true; +- int verify = +- gnutls_certificate_verify_peers2(c-> +- ssl_state.gnutls_session, +- &status); +- if (verify < 0) { +- Log(LOG_ERR, +- "gnutls_certificate_verify_peers2 failed: %s", +- gnutls_strerror(verify)); +- goto done_cn_validation; +- } else if (status) { +- gnutls_datum_t out; +- +- if (gnutls_certificate_verification_status_print +- (status, gnutls_certificate_type_get(sess), &out, +- 0) == GNUTLS_E_SUCCESS) { +- Log(LOG_ERR, +- "Certificate validation failed: %s", +- out.data); +- gnutls_free(out.data); +- } +- } + + gnutls_x509_crt_t cert; + unsigned cert_list_size; +@@ -1042,17 +1022,46 @@ + gnutls_strerror(err)); + goto done_cn_validation; + } +- err = gnutls_x509_crt_check_hostname(cert, c->host); +- if (err == 0) +- Log(LOG_ERR, +- "Failed to verify the hostname, expected \"%s\"", +- c->host); +- else +- cert_ok = verify == 0 && status == 0; +- +- snprintf(msg, sizeof(msg), "%svalid peer certificate", +- cert_ok ? "" : "in"); +- LogGnuTLS_CertInfo(cert_ok ? LOG_DEBUG : LOG_ERR, cert, msg); ++ ++ if (connect) { ++ int verify = ++ gnutls_certificate_verify_peers2(c-> ++ ssl_state.gnutls_session, ++ &status); ++ if (verify < 0) { ++ Log(LOG_ERR, ++ "gnutls_certificate_verify_peers2 failed: %s", ++ gnutls_strerror(verify)); ++ goto done_cn_validation; ++ } else if (status) { ++ gnutls_datum_t out; ++ ++ if (gnutls_certificate_verification_status_print ++ (status, gnutls_certificate_type_get(sess), &out, ++ 0) == GNUTLS_E_SUCCESS) { ++ Log(LOG_ERR, ++ "Certificate validation failed: %s", ++ out.data); ++ gnutls_free(out.data); ++ } ++ } ++ ++ err = gnutls_x509_crt_check_hostname(cert, c->host); ++ if (err == 0) ++ Log(LOG_ERR, ++ "Failed to verify the hostname, expected \"%s\"", ++ c->host); ++ else ++ cert_ok = verify == 0 && status == 0; ++ ++ snprintf(msg, sizeof(msg), "Got %svalid server certificate", ++ cert_ok ? "" : "in"); ++ LogGnuTLS_CertInfo(LOG_INFO, cert, msg); ++ } else { ++ /* Incoming connection. Please see comments for OpenSSL! */ ++ LogGnuTLS_CertInfo(LOG_INFO, cert, ++ "Got unchecked peer certificate"); ++ } + + gnutls_x509_crt_deinit(cert); + done_cn_validation: diff -Nru ngircd-26.1/debian/patches/0014-S2S-TLS-GnuTLS-Streamline-logging.patch ngircd-26.1/debian/patches/0014-S2S-TLS-GnuTLS-Streamline-logging.patch --- ngircd-26.1/debian/patches/0014-S2S-TLS-GnuTLS-Streamline-logging.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0014-S2S-TLS-GnuTLS-Streamline-logging.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,49 @@ +From e092877d9ad69f0cb4dea10bf546e561dd6a1abd Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Fri, 5 Jan 2024 22:31:32 +0100 +Subject: [PATCH 14/20] S2S-TLS/GnuTLS: Streamline logging + +(cherry picked from commit 663972c88d3ae3e3226fe6f95ca1113694ce0618) +--- + src/ngircd/conn-ssl.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -869,8 +869,10 @@ + default: + assert(code < 0); + if (gnutls_error_is_fatal(code)) { +- Log(LOG_ERR, "SSL error: %s [%s].", +- gnutls_strerror(code), fname); ++ /* We don't need to log this here, the generic ++ * connection layer will take care of it. */ ++ LogDebug("SSL error: %s [%s].", ++ gnutls_strerror(code), fname); + ConnSSL_Free(c); + return -1; + } +@@ -914,12 +916,12 @@ + assert(size); + issuer_dn = LogMalloc(size); + if (!issuer_dn) { +- Log(level, "%s: Distinguished Name: %s", msg, dn); ++ Log(level, "%s: Distinguished Name \"%s\".", msg, dn); + free(dn); + return; + } + gnutls_x509_crt_get_issuer_dn(cert, issuer_dn, &size); +- Log(level, "%s: Distinguished Name: \"%s\", Issuer \"%s\"", msg, dn, ++ Log(level, "%s: Distinguished Name \"%s\", Issuer \"%s\".", msg, dn, + issuer_dn); + free(dn); + free(issuer_dn); +@@ -979,7 +981,7 @@ + * hand we want client certificates, for example for + * "CertFP" authentication with services ... */ + LogOpenSSL_CertInfo(LOG_INFO, peer_cert, +- "Got unchecked client certificate"); ++ "Got unchecked peer certificate"); + } + + X509_free(peer_cert); diff -Nru ngircd-26.1/debian/patches/0015-S2S-TLS-Verify-the-TLS-certificates-by-default.patch ngircd-26.1/debian/patches/0015-S2S-TLS-Verify-the-TLS-certificates-by-default.patch --- ngircd-26.1/debian/patches/0015-S2S-TLS-Verify-the-TLS-certificates-by-default.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0015-S2S-TLS-Verify-the-TLS-certificates-by-default.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,27 @@ +From 7086f4d15e240f5394b0b3e24d100f9c4fe4c792 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Sat, 6 Jan 2024 15:55:54 +0100 +Subject: [PATCH 15/20] S2S-TLS: Verify the TLS certificates by default + +This is already mentioned as the default in the manual page and the +sample configuration file, but was actually not enabled in the code! + +(cherry picked from commit 180e2ec1359378172135472148c99a2d14e873cc) +--- + src/ngircd/conf.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/src/ngircd/conf.c ++++ b/src/ngircd/conf.c +@@ -2298,6 +2298,11 @@ + Proc_InitStruct(&Server->res_stat); + Server->conn_id = NONE; + memset(&Server->bind_addr, 0, sizeof(Server->bind_addr)); ++ ++#ifdef SSL_SUPPORT ++ /* Verify SSL connections by default! */ ++ Server->SSLVerify = true; ++#endif + } + + /* -eof- */ diff -Nru ngircd-26.1/debian/patches/0016-S2S-TLS-GnuTLS-Fix-handling-of-connections-without-p.patch ngircd-26.1/debian/patches/0016-S2S-TLS-GnuTLS-Fix-handling-of-connections-without-p.patch --- ngircd-26.1/debian/patches/0016-S2S-TLS-GnuTLS-Fix-handling-of-connections-without-p.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0016-S2S-TLS-GnuTLS-Fix-handling-of-connections-without-p.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,34 @@ +From 0f866fd27333c6d92fa514ba05b2a47d129357e2 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Sat, 6 Jan 2024 19:57:50 +0100 +Subject: [PATCH 16/20] S2S-TLS/GnuTLS: Fix handling of connections without + peer certificates + +(cherry picked from commit 8cef3ce42cd645a3ffb0e1eded52b8b77bb8caff) +--- + src/ngircd/conn-ssl.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/src/ngircd/conn-ssl.c ++++ b/src/ngircd/conn-ssl.c +@@ -1000,16 +1000,15 @@ + gnutls_mac_get_name(gnutls_mac_get(sess))); + cred = gnutls_auth_get_type(c->ssl_state.gnutls_session); + if (cred == GNUTLS_CRD_CERTIFICATE) { +- cert_seen = true; +- + gnutls_x509_crt_t cert; + unsigned cert_list_size; + const gnutls_datum_t *cert_list = + gnutls_certificate_get_peers(sess, &cert_list_size); +- if (!cert_list || cert_list_size == 0) { +- Log(LOG_ERR, "No certificates found"); ++ ++ if (!cert_list || cert_list_size == 0) + goto done_cn_validation; +- } ++ ++ cert_seen = true; + int err = gnutls_x509_crt_init(&cert); + if (err < 0) { + Log(LOG_ERR, diff -Nru ngircd-26.1/debian/patches/0017-S2S-TLS-Convert-SSL.txt-to-Markdown-and-update-infor.patch ngircd-26.1/debian/patches/0017-S2S-TLS-Convert-SSL.txt-to-Markdown-and-update-infor.patch --- ngircd-26.1/debian/patches/0017-S2S-TLS-Convert-SSL.txt-to-Markdown-and-update-infor.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0017-S2S-TLS-Convert-SSL.txt-to-Markdown-and-update-infor.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,246 @@ +From b04ed224cf95c0f31849d3683412cb937cc00efc Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Mon, 8 Jan 2024 18:31:30 +0100 +Subject: [PATCH 17/20] S2S-TLS: Convert SSL.txt to Markdown and update + information given + +No longer describe creating self-signed certificates or using "stunnel", +as both is not recommended. + +(cherry picked from commit b826fad15871f73435328b1d77fd364838389adb) +--- + INSTALL.md | 2 +- + doc/Makefile.am | 2 +- + doc/SSL.md | 80 +++++++++++++++++++++++++++++++++++ + doc/SSL.txt | 108 ------------------------------------------------ + 4 files changed, 82 insertions(+), 110 deletions(-) + create mode 100644 doc/SSL.md + delete mode 100644 doc/SSL.txt + +--- a/INSTALL.md ++++ b/INSTALL.md +@@ -347,7 +347,7 @@ + - `--with-gnutls[=<path>]` + + Enable support for SSL/TLS using OpenSSL or GnuTLS libraries. +- See `doc/SSL.txt` for details. ++ See `doc/SSL.md` for details. + + - IPv6: + +--- a/doc/Makefile.am ++++ b/doc/Makefile.am +@@ -33,7 +33,7 @@ + README-Interix.txt \ + RFC.txt \ + Services.txt \ +- SSL.txt ++ SSL.md + + doc_templates = sample-ngircd.conf.tmpl + +--- /dev/null ++++ b/doc/SSL.md +@@ -0,0 +1,80 @@ ++# [ngIRCd](https://ngircd.barton.de) - SSL/TLS Encrypted Connections ++ ++ngIRCd supports SSL/TLS encrypted connections using the *OpenSSL* or *GnuTLS* ++libraries. Both encrypted server-server links as well as client-server links ++are supported. ++ ++SSL is a compile-time option which is disabled by default. Use one of these ++options of the ./configure script to enable it: ++ ++- `--with-openssl`: enable SSL support using OpenSSL. ++- `--with-gnutls`: enable SSL support using GnuTLS. ++ ++You can check the output of `ngircd --version` to validate if your executable ++includes support for SSL or not: "+SSL" must be listed in the feature flags. ++ ++You also need a SSL key and certificate, for example using Let's Encrypt, which ++is out of the scope of this document. ++ ++From a feature point of view, ngIRCds support for both libraries is ++comparable. The only major difference (at this time) is that ngIRCd with GnuTLS ++does not support password protected private keys. ++ ++## Configuration ++ ++SSL-encrypted connections and plain-text connects can't run on the same network ++port (which is a limitation of the IRC protocol); therefore you have to define ++separate port(s) in your `[SSL]` block in the configuration file. ++ ++A minimal configuration for *accepting* SSL-encrypted client & server ++connections looks like this: ++ ++``` ini ++[SSL] ++CertFile = /etc/ssl/certs/my-fullchain.pem ++KeyFile = /etc/ssl/certs/my-privkey.pem ++Ports = 6697, 6698 ++``` ++ ++In this case, the server only deals with *incoming* connections and never has to ++validate SSL certificates itself, and therefore no "Certificate Authorities" are ++needed. ++ ++If you want to use *outgoing* SSL-connections to other servers, you need to add: ++ ++``` ini ++[SSL] ++... ++CAFile = /etc/ssl/certs/ca-certificates.crt ++DHFile = /etc/ngircd/dhparams.pem ++ ++[SERVER] ++... ++SSLConnect = yes ++``` ++ ++The `CAFile` option configures a file listing all the certificates of the ++trusted Certificate Authorities. ++ ++The Diffie-Hellman parameters file `dhparams.pem` can be created like this: ++ ++- OpenSSL: `openssl dhparam -2 -out /etc/ngircd/dhparams.pem 4096` ++- GnuTLS: `certtool --generate-dh-params --bits 4096 --outfile /etc/ngircd/dhparams.pem` ++ ++Note that enabling `SSLConnect` not only enforces SSL-encrypted links for ++*outgoing* connections to other servers, but for *incoming* connections as well: ++If a server configured with `SSLConnect = yes` tries to connect on a plain-text ++connection, it won't be accepted to prevent data leakage! Therefore you should ++set this for *all* servers you expect to use SSL-encrypted connections! ++ ++## Accepting untrusted Remote Certificates ++ ++If you are using self-signed certificates or otherwise invalid certificates, ++which ngIRCd would reject by default, you can force ngIRCd to skip certificate ++validation on a per-server basis and continue establishing outgoing connections ++to the respective peer by setting `SSLVerify = no` in the `[SERVER]` block of ++this remote server in your configuration. ++ ++But please think twice before doing so: the established connection is still ++encrypted but the remote site is *not verified at all* and man-in-the-middle ++attacks are possible! +--- a/doc/SSL.txt ++++ /dev/null +@@ -1,108 +0,0 @@ +- +- ngIRCd - Next Generation IRC Server +- +- (c)2001-2008 Alexander Barton, +- a...@barton.de, http://www.barton.de/ +- +- ngIRCd is free software and published under the +- terms of the GNU General Public License. +- +- -- SSL.txt -- +- +- +-ngIRCd supports SSL/TLSv1 encrypted connections using the OpenSSL or GnuTLS +-libraries. Both encrypted server-server links as well as client-server links +-are supported. +- +-SSL is a compile-time option which is disabled by default. Use one of these +-options of the ./configure script to enable it: +- +- --with-openssl enable SSL support using OpenSSL +- --with-gnutls enable SSL support using GnuTLS +- +-You also need a key/certificate, see below for how to create a self-signed one. +- +-From a feature point of view, ngIRCds support for both libraries is +-comparable. The only major difference (at this time) is that ngircd with gnutls +-does not support password protected private keys. +- +-Configuration +-~~~~~~~~~~~~~ +- +-To enable SSL connections a separate port must be configured: it is NOT +-possible to handle unencrypted and encrypted connections on the same port! +-This is a limitation of the IRC protocol ... +- +-You have to set (at least) the following configuration variables in the +-[SSL] section of ngircd.conf(5): Ports, KeyFile, and CertFile. +- +-Now IRC clients are able to connect using SSL on the configured port(s). +-(Using port 6697 for encrypted connections is common.) +- +-To enable encrypted server-server links, you have to additionally set +-SSLConnect to "yes" in the corresponding [SERVER] section. +- +- +-Creating a self-signed certificate +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-OpenSSL: +- +-Creating a self-signed certificate and key: +- $ openssl req -newkey rsa:2048 -x509 -keyout server-key.pem -out server-cert.pem -days 1461 +-Create DH parameters (optional): +- $ openssl dhparam -2 -out dhparams.pem 4096 +- +-GnuTLS: +- +-Creating a self-signed certificate and key: +- $ certtool --generate-privkey --bits 2048 --outfile server-key.pem +- $ certtool --generate-self-signed --load-privkey server-key.pem --outfile server-cert.pem +-Create DH parameters (optional): +- $ certtool --generate-dh-params --bits 4096 --outfile dhparams.pem +- +- +-Alternate approach using stunnel(1) +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-Alternatively (or if you are using ngIRCd compiled without support +-for GnuTLS/OpenSSL), you can use external programs/tools like stunnel(1) to +-get SSL encrypted connections: +- +- <http://stunnel.mirt.net/> +- <http://www.stunnel.org/> +- +-Stefan Sperling (stefan at binarchy dot net) mailed the following text as a +-short "how-to", thanks Stefan! +- +-=== snip === +- ! This guide applies to stunnel 4.x ! +- +- Put this in your stunnel.conf: +- +- [ircs] +- accept = 6667 +- connect = 6668 +- +- This makes stunnel listen for incoming connections +- on port 6667 and forward decrypted data to port 6668. +- We call the connection 'ircs'. Stunnel will use this +- name when logging connection attempts via syslog. +- You can also use the name in /etc/hosts.{allow,deny} +- if you run tcp-wrappers. +- +- To make sure ngircd is listening on the port where +- the decrypted data arrives, set +- +- Ports = 6668 +- +- in your ngircd.conf. +- +- Start stunnel and restart ngircd. +- +- That's it. +- Don't forget to activate ssl support in your irc client ;) +- The main drawback of this approach compared to using builtin ssl +- is that from ngIRCds point of view, all ssl-enabled client connections will +- originate from the host running stunnel. +-=== snip === +--- a/doc/Makefile.in ++++ b/doc/Makefile.in +@@ -248,7 +248,7 @@ + README-Interix.txt \ + RFC.txt \ + Services.txt \ +- SSL.txt ++ SSL.md + + doc_templates = sample-ngircd.conf.tmpl + generated_docs = sample-ngircd.conf diff -Nru ngircd-26.1/debian/patches/0018-S2S-TLS-Add-notice-to-INSTALL.md.patch ngircd-26.1/debian/patches/0018-S2S-TLS-Add-notice-to-INSTALL.md.patch --- ngircd-26.1/debian/patches/0018-S2S-TLS-Add-notice-to-INSTALL.md.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0018-S2S-TLS-Add-notice-to-INSTALL.md.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,33 @@ +From e8ffea49c26f298b3317fb765f7e6fb378db3923 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Thu, 11 Jan 2024 14:24:22 +0100 +Subject: [PATCH 18/20] S2S-TLS: Add notice to INSTALL.md + +(cherry picked from commit 6b27eabf5bdbc6bf6f71d7b1e7d059dfeab6849b) +--- + INSTALL.md | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/INSTALL.md ++++ b/INSTALL.md +@@ -12,6 +12,20 @@ + + ## Upgrade Information + ++This section lists important updates and breaking changes that you should be ++aware of *before* starting the upgrade: ++ ++- **Attention**: ++ Starting with release 27, ngIRCd validates SSL/TLS certificates on outgoing ++ server-server links by default and drops(!) connections when the remote ++ certificate is invalid (for example self-signed, expired, not matching the ++ host name, ...). Therefore you have to make sure that all relevant ++ *certificates are valid* (or to disable certificate validation on this ++ connection using the new `SSLVerify = false` setting in the affected ++ `[Server]` block, where the remote certificate is not valid and you can not ++ fix this issue). ++ And this change was backported to this ngIRCd release! ++ + Differences to version 25 + + - **Attention**: diff -Nru ngircd-26.1/debian/patches/0019-S2S-TLS-Fix-make-check-in-separate-build-directory.patch ngircd-26.1/debian/patches/0019-S2S-TLS-Fix-make-check-in-separate-build-directory.patch --- ngircd-26.1/debian/patches/0019-S2S-TLS-Fix-make-check-in-separate-build-directory.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0019-S2S-TLS-Fix-make-check-in-separate-build-directory.patch 2024-04-15 14:09:06.000000000 +0200 @@ -0,0 +1,35 @@ +From e4937e6ed3a13408f8e0f57124aa784de4299147 Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Sat, 10 Feb 2024 00:14:33 +0100 +Subject: [PATCH 19/20] S2S-TLS: Fix "make check" in separate build directory + +(cherry picked from commit b9d6a2f49c4b3607c69b298cc770c0c945f627f6) +--- + src/testsuite/prep-server3 | 9 +++++---- + src/testsuite/switch-server3 | 9 ++++----- + 2 files changed, 9 insertions(+), 9 deletions(-) + +--- a/src/testsuite/prep-server3 ++++ b/src/testsuite/prep-server3 +@@ -1,4 +1,5 @@ +-#!/bin/sh +-cp ssl/cert-my-first-domain-tld.pem ssl/cert.pem +-cp ssl/key-my-first-domain-tld.pem ssl/key.pem +-cp ssl/dhparams-my-first-domain-tld.pem ssl/dhparams.pem ++#!/bin/sh -e ++mkdir -p ssl ++cp "${srcdir}"/ssl/cert-my-first-domain-tld.pem ssl/cert.pem ++cp "${srcdir}"/ssl/key-my-first-domain-tld.pem ssl/key.pem ++cp "${srcdir}"/ssl/dhparams-my-first-domain-tld.pem ssl/dhparams.pem +--- a/src/testsuite/switch-server3 ++++ b/src/testsuite/switch-server3 +@@ -1,5 +1,4 @@ +-#!/bin/sh +-cp ssl/cert-my-second-domain-tld.pem ssl/cert.pem +-cp ssl/key-my-second-domain-tld.pem ssl/key.pem +-cp ssl/dhparams-my-second-domain-tld.pem ssl/dhparams.pem +-# -eof- ++#!/bin/sh -e ++cp "${srcdir}"/ssl/cert-my-second-domain-tld.pem ssl/cert.pem ++cp "${srcdir}"/ssl/key-my-second-domain-tld.pem ssl/key.pem ++cp "${srcdir}"/ssl/dhparams-my-second-domain-tld.pem ssl/dhparams.pem diff -Nru ngircd-26.1/debian/patches/0020-METADATA-Fix-unsetting-cloakhost.patch ngircd-26.1/debian/patches/0020-METADATA-Fix-unsetting-cloakhost.patch --- ngircd-26.1/debian/patches/0020-METADATA-Fix-unsetting-cloakhost.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/0020-METADATA-Fix-unsetting-cloakhost.patch 2024-04-15 14:09:13.000000000 +0200 @@ -0,0 +1,28 @@ +From fe5f1666983f2ef7499b0454fc30ae36edc29f5e Mon Sep 17 00:00:00 2001 +From: Alexander Barton <a...@barton.de> +Date: Sun, 17 Mar 2024 15:55:39 +0100 +Subject: [PATCH 20/20] METADATA: Fix unsetting "cloakhost" + +Correctly re-generate the "cloaked hostname" when removing the +"cloakhost" using an empty string by passing down NULL instead of the +empty string, which results in protocol violations (for example on +WHOIS). + +(cherry picked from commit 1118b0e77ca961a7b082f90cb124210eca8fb6bd) +--- + src/ngircd/irc-metadata.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/src/ngircd/irc-metadata.c ++++ b/src/ngircd/irc-metadata.c +@@ -72,7 +72,9 @@ + } + + if (strcasecmp(Req->argv[1], "cloakhost") == 0) { +- Client_UpdateCloakedHostname(target, prefix, Req->argv[2]); ++ /* Set or remove a "cloaked hostname". */ ++ Client_UpdateCloakedHostname(target, prefix, ++ *Req->argv[2] ? Req->argv[2] : NULL); + if (Client_Conn(target) > NONE && Client_HasMode(target, 'x')) + IRC_WriteStrClientPrefix(target, prefix, + RPL_HOSTHIDDEN_MSG, Client_ID(target), diff -Nru ngircd-26.1/debian/patches/1713563399.rel-27-rc1-6-g3e3f6cbe.clarify-that-cafile-is-not-set-by-default.patch ngircd-26.1/debian/patches/1713563399.rel-27-rc1-6-g3e3f6cbe.clarify-that-cafile-is-not-set-by-default.patch --- ngircd-26.1/debian/patches/1713563399.rel-27-rc1-6-g3e3f6cbe.clarify-that-cafile-is-not-set-by-default.patch 1970-01-01 01:00:00.000000000 +0100 +++ ngircd-26.1/debian/patches/1713563399.rel-27-rc1-6-g3e3f6cbe.clarify-that-cafile-is-not-set-by-default.patch 2024-05-01 11:00:00.000000000 +0200 @@ -0,0 +1,28 @@ +Subject: Clarify that "CAFile" is not set by default +Origin: rel-27-rc1-6-g3e3f6cbe +Upstream-Author: Alexander Barton <a...@barton.de> +Date: Fri Apr 19 23:49:59 2024 +0200 + +--- a/doc/sample-ngircd.conf.tmpl ++++ b/doc/sample-ngircd.conf.tmpl +@@ -266,7 +266,8 @@ + # is only available when ngIRCd is compiled with support for SSL! + # So don't forget to remove the ";" above if this is the case ... + +- # SSL Trusted CA Certificates File (for verifying peer certificates) ++ # SSL Trusted CA Certificates File for verifying peer certificates. ++ # (Default: not set; so no certificates are trusted) + ;CAFile = /etc/ssl/CA/cacert.pem + + # Certificate Revocation File (for marking otherwise valid +--- a/man/ngircd.conf.5.tmpl ++++ b/man/ngircd.conf.5.tmpl +@@ -387,7 +387,7 @@ + .TP + \fBCAFile\fR (string) + Filename pointing to the Trusted CA Certificates. This is required for +-verifying peer certificates. ++verifying peer certificates. Default: not set, so no certificates are trusted. + .TP + \fBCertFile\fR (string) + SSL Certificate file of the private server key. diff -Nru ngircd-26.1/debian/patches/series ngircd-26.1/debian/patches/series --- ngircd-26.1/debian/patches/series 2021-01-02 21:48:41.000000000 +0100 +++ ngircd-26.1/debian/patches/series 2024-05-01 11:00:00.000000000 +0200 @@ -1,2 +1,26 @@ +# cherry-picked from upstream +0001-Respect-SSLConnect-option-for-incoming-connections.patch +0002-Support-for-server-certificate-validation-on-server-.patch +0003-S2S-TLS-Add-missing-CAFile-and-CRLFile-options-to-co.patch +0004-S2S-TLS-Remove-leftover-debug-messages.patch +0005-S2S-TLS-OpenSSL-Always-setup-host-name-verification.patch +0006-S2S-TLS-OpenSSL-Set-the-verification-flags-only-once.patch +0007-S2S-TLS-OpenSSL-Fix-handling-of-certificate-informat.patch +0008-S2S-TLS-OpenSSL-Postpone-verification-of-TLS-session.patch +0009-S2S-TLS-OpenSSL-Streamline-logging.patch +0010-S2S-TLS-Fix-formatting-and-sort-new-SSL-options-in-n.patch +0011-S2S-TLS-MAX_CERT_CHAIN_LENGTH-is-only-used-by-OpenSS.patch +0012-S2S-TLS-GnuTLS-Update-SSL-code-for-GnuTLS-certificat.patch +0013-S2S-TLS-GnuTLS-Fix-handling-of-certificate-informati.patch +0014-S2S-TLS-GnuTLS-Streamline-logging.patch +0015-S2S-TLS-Verify-the-TLS-certificates-by-default.patch +0016-S2S-TLS-GnuTLS-Fix-handling-of-connections-without-p.patch +0017-S2S-TLS-Convert-SSL.txt-to-Markdown-and-update-infor.patch +0018-S2S-TLS-Add-notice-to-INSTALL.md.patch +0019-S2S-TLS-Fix-make-check-in-separate-build-directory.patch +0020-METADATA-Fix-unsetting-cloakhost.patch +0001-S2S-SSL-GnuTLS-Enable-CRL-verification_26.1.patch +1713563399.rel-27-rc1-6-g3e3f6cbe.clarify-that-cafile-is-not-set-by-default.patch + # patches that should go upstream fix-race-in-testsuite.patch
signature.asc
Description: PGP signature