From 89a8f3eb0a462e0e61127e6ed32b053394df9afb Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 10:19:26 -0700 Subject: [PATCH 01/11] Updated STS handling to require an explicit port in insecure-connection capability upgrades, ignoring incomplete policies without upgrading. --- src/common/sts.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/common/sts.c b/src/common/sts.c index d5dae4bf..9d57a905 100644 --- a/src/common/sts.c +++ b/src/common/sts.c @@ -553,15 +553,7 @@ sts_handle_capability (struct server *serv, const char *value) { if (!has_port) { - if (serv->port > 0) - { - port = (guint16) serv->port; - has_port = TRUE; - } - else - { - return FALSE; - } + return FALSE; } #ifdef USE_OPENSSL if (serv->sts_upgrade_in_progress) From b09e6a54055b39928dfa4928db0c7684eee76bb8 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 10:30:13 -0700 Subject: [PATCH 02/11] Updated STS policy handling to require an active connection port when already on TLS, ignoring any advertised port token before storing the profile. --- src/common/sts.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/sts.c b/src/common/sts.c index 9d57a905..010904dc 100644 --- a/src/common/sts.c +++ b/src/common/sts.c @@ -593,14 +593,15 @@ sts_handle_capability (struct server *serv, const char *value) { time_t now = time (NULL); time_t expires_at = now + (time_t) duration; - guint16 effective_port = serv->port > 0 ? (guint16) serv->port : port; + guint16 effective_port = 0; sts_profile *profile; - if (effective_port == 0) + if (serv->port <= 0) { return FALSE; } + effective_port = (guint16) serv->port; profile = sts_profile_new (hostname, effective_port, expires_at, duration, has_preload ? preload : FALSE); sts_profile_store (profile); From 3d8d3958ea27fe2388753c0976c941d49f03a97d Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 11:35:40 -0700 Subject: [PATCH 03/11] Updated STS parsing to treat duplicate port, duration, or preload keys as invalid by returning FALSE immediately when repeats are encountered. --- src/common/sts.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/common/sts.c b/src/common/sts.c index 010904dc..b336615d 100644 --- a/src/common/sts.c +++ b/src/common/sts.c @@ -338,7 +338,13 @@ sts_parse_value (const char *value, guint16 *port, guint64 *duration, gboolean * { gint64 port_value; - if (*has_port || !val) + if (*has_port) + { + g_strfreev (tokens); + return FALSE; + } + + if (!val) { continue; } @@ -354,7 +360,13 @@ sts_parse_value (const char *value, guint16 *port, guint64 *duration, gboolean * { guint64 duration_value; - if (*has_duration || !val) + if (*has_duration) + { + g_strfreev (tokens); + return FALSE; + } + + if (!val) { continue; } @@ -367,7 +379,8 @@ sts_parse_value (const char *value, guint16 *port, guint64 *duration, gboolean * { if (*has_preload) { - continue; + g_strfreev (tokens); + return FALSE; } *preload = TRUE; *has_preload = TRUE; From b9bc65e3c21c2a113d9c66ec8aae30dd0b7bc2ad Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 11:39:20 -0700 Subject: [PATCH 04/11] Updated STS parsing to only accept preload when it appears without a value, ignoring tokens like preload=0. --- src/common/sts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/sts.c b/src/common/sts.c index b336615d..6dd4869f 100644 --- a/src/common/sts.c +++ b/src/common/sts.c @@ -377,7 +377,7 @@ sts_parse_value (const char *value, guint16 *port, guint64 *duration, gboolean * } else if (!g_ascii_strcasecmp (key, "preload")) { - if (*has_preload) + if (*has_preload || val) { g_strfreev (tokens); return FALSE; From 78a00b5b880f4b3d7476f1ce57aadb0882427502 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 11:57:54 -0700 Subject: [PATCH 05/11] Updated STS policy handling to preserve any existing stored port on secure updates rather than overwriting it from the current TLS port, keeping secure-path updates focused on duration/preload. --- src/common/sts.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/common/sts.c b/src/common/sts.c index 6dd4869f..17ea0823 100644 --- a/src/common/sts.c +++ b/src/common/sts.c @@ -607,14 +607,15 @@ sts_handle_capability (struct server *serv, const char *value) time_t now = time (NULL); time_t expires_at = now + (time_t) duration; guint16 effective_port = 0; + sts_profile *existing_profile; sts_profile *profile; - if (serv->port <= 0) + existing_profile = sts_profile_lookup (hostname, now); + if (existing_profile) { - return FALSE; + effective_port = existing_profile->port; } - effective_port = (guint16) serv->port; profile = sts_profile_new (hostname, effective_port, expires_at, duration, has_preload ? preload : FALSE); sts_profile_store (profile); From eae5a209d384cf065c314262ce3af46ba8669796 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 11:58:13 -0700 Subject: [PATCH 06/11] Updated STS parsing to ignore preload tokens that include a value while preserving duplicate-preload rejection for valid tokens. --- src/common/sts.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/common/sts.c b/src/common/sts.c index 17ea0823..82c57ed2 100644 --- a/src/common/sts.c +++ b/src/common/sts.c @@ -377,7 +377,12 @@ sts_parse_value (const char *value, guint16 *port, guint64 *duration, gboolean * } else if (!g_ascii_strcasecmp (key, "preload")) { - if (*has_preload || val) + if (val) + { + continue; + } + + if (*has_preload) { g_strfreev (tokens); return FALSE; From 2ecf1c18fb897158dea1fb206bfd734b465b3815 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 12:41:32 -0700 Subject: [PATCH 07/11] Added STS value parsing in CAP ACK handling so sts= capability values are applied immediately before toggling capabilities. --- src/common/inbound.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/common/inbound.c b/src/common/inbound.c index fc1fa3cc..081b3185 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -1713,6 +1713,26 @@ void inbound_cap_ack (server *serv, char *nick, char *extensions, const message_tags_data *tags_data) { + if (extensions) + { + char **tokens = g_strsplit (extensions, " ", 0); + int i; + + for (i = 0; tokens[i]; i++) + { + char **parts = g_strsplit (tokens[i], "=", 2); + + if (!g_strcmp0 (parts[0], "sts") && parts[1] && parts[1][0]) + { + sts_handle_capability (serv, parts[1]); + } + + g_strfreev (parts); + } + + g_strfreev (tokens); + } + EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, nick, extensions, NULL, NULL, 0, tags_data->timestamp); From 3d030a96b7291454fb196b0842dbf0b3cf03e96c Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 12:42:04 -0700 Subject: [PATCH 08/11] =?UTF-8?q?Updated=20sts=5Fhandle=5Fcapability=20to?= =?UTF-8?q?=20return=20FALSE=20after=20logging=20the=20no=E2=80=91TLS=20wa?= =?UTF-8?q?rning,=20so=20the=20insecure=20upgrade=20path=20doesn=E2=80=99t?= =?UTF-8?q?=20stop=20capability=20negotiation;=20it=20still=20returns=20TR?= =?UTF-8?q?UE=20only=20when=20an=20STS=20upgrade/reconnect=20is=20initiate?= =?UTF-8?q?d=20or=20already=20in=20progress.=20Confirmed=20inbound=5Fcap?= =?UTF-8?q?=5Fls=20only=20returns=20early=20when=20sts=5Fupgrade=5Ftrigger?= =?UTF-8?q?ed=20is=20set=20by=20sts=5Fhandle=5Fcapability,=20which=20now?= =?UTF-8?q?=20only=20happens=20for=20real=20upgrade/reconnect=20initiation?= =?UTF-8?q?=20or=20in=E2=80=91progress=20upgrades.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/sts.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/sts.c b/src/common/sts.c index 82c57ed2..eef2a71b 100644 --- a/src/common/sts.c +++ b/src/common/sts.c @@ -588,12 +588,13 @@ sts_handle_capability (struct server *serv, const char *value) serv->disconnect (serv->server_session, FALSE, -1); serv->connect (serv, host_copy, (int) port, serv->no_login); } + return TRUE; #else PrintTextf (serv->server_session, _("STS upgrade requested for %s, but TLS is not available.\n"), hostname); + return FALSE; #endif - return TRUE; } if (!has_duration) From f58785c2e0aafbf4cde65a357c4cc5d1c8508289 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 12:42:22 -0700 Subject: [PATCH 09/11] Added an explicit diagnostic when an STS capability token lacks a value while keeping the ignore policy unchanged. --- src/common/inbound.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/common/inbound.c b/src/common/inbound.c index 081b3185..d3fd4139 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -1900,6 +1900,11 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str, { sts_upgrade_triggered |= sts_handle_capability (serv, value); } + else + { + PrintTextf (serv->server_session, + _("Invalid STS capability token without value")); + } continue; } From 983ae5337b9932b9572fb80e79d9535556af8aa9 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 12:57:07 -0700 Subject: [PATCH 10/11] Added a diagnostic message when an STS capability token is missing its value, while keeping the ignore behavior intact. --- src/common/inbound.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common/inbound.c b/src/common/inbound.c index d3fd4139..169d1689 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -1903,7 +1903,11 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str, else { PrintTextf (serv->server_session, +<<<<<<< ours _("Invalid STS capability token without value")); +======= + _("Invalid STS capability token without a value; ignoring.")); +>>>>>>> theirs } continue; } From 9aba312c8e4d5bfeda6873c6e98822222d24662b Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 4 Feb 2026 13:13:51 -0700 Subject: [PATCH 11/11] Resolved the merge conflict in STS capability handling by keeping the clearer warning message for missing values. --- src/common/inbound.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/common/inbound.c b/src/common/inbound.c index 169d1689..6cb27ba3 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -1903,11 +1903,7 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str, else { PrintTextf (serv->server_session, -<<<<<<< ours - _("Invalid STS capability token without value")); -======= _("Invalid STS capability token without a value; ignoring.")); ->>>>>>> theirs } continue; }