From 12a0624e4c275f14cee9a6b4f36e714d2ced8544 Mon Sep 17 00:00:00 2001 From: therandomstring Date: Wed, 07 May 2025 09:30:36 +0530 Subject: [PATCH] Merge commit from fork Fix transport accepting incorrect wildcards CVE: CVE-2024-47619 Upstream-Status: Backport [https://github.com/syslog-ng/syslog-ng/commit/12a0624e4c275f14cee9a6b4f36e714d2ced8544] Signed-off-by: Yogita Urade --- lib/transport/tests/CMakeLists.txt | 1 + lib/transport/tests/Makefile.am | 9 +- lib/transport/tests/test_tls_wildcard_match.c | 104 ++++++++++++++++++ lib/transport/tls-verifier.c | 86 +++++++++++++-- lib/transport/tls-verifier.h | 2 + 5 files changed, 190 insertions(+), 12 deletions(-) create mode 100644 lib/transport/tests/test_tls_wildcard_match.c diff --git a/lib/transport/tests/CMakeLists.txt b/lib/transport/tests/CMakeLists.txt index 834f456..ce1d033 100644 --- a/lib/transport/tests/CMakeLists.txt +++ b/lib/transport/tests/CMakeLists.txt @@ -3,3 +3,4 @@ add_unit_test(CRITERION TARGET test_transport_factory_id) add_unit_test(CRITERION TARGET test_transport_factory) add_unit_test(CRITERION TARGET test_transport_factory_registry) add_unit_test(CRITERION TARGET test_multitransport) +add_unit_test(CRITERION TARGET test_tls_wildcard_match) diff --git a/lib/transport/tests/Makefile.am b/lib/transport/tests/Makefile.am index 7eac994..ae2426c 100644 --- a/lib/transport/tests/Makefile.am +++ b/lib/transport/tests/Makefile.am @@ -3,7 +3,8 @@ lib_transport_tests_TESTS = \ lib/transport/tests/test_transport_factory_id \ lib/transport/tests/test_transport_factory \ lib/transport/tests/test_transport_factory_registry \ - lib/transport/tests/test_multitransport + lib/transport/tests/test_multitransport \ + lib/transport/tests/test_tls_wildcard_match EXTRA_DIST += lib/transport/tests/CMakeLists.txt @@ -38,3 +39,9 @@ lib_transport_tests_test_multitransport_CFLAGS = $(TEST_CFLAGS) \ lib_transport_tests_test_multitransport_LDADD = $(TEST_LDADD) lib_transport_tests_test_multitransport_SOURCES = \ lib/transport/tests/test_multitransport.c + +lib_transport_tests_test_tls_wildcard_match_CFLAGS = $(TEST_CFLAGS) \ + -I${top_srcdir}/lib/transport/tests +lib_transport_tests_test_tls_wildcard_match_LDADD = $(TEST_LDADD) +lib_transport_tests_test_tls_wildcard_match_SOURCES = \ + lib/transport/tests/test_tls_wildcard_match.c diff --git a/lib/transport/tests/test_tls_wildcard_match.c b/lib/transport/tests/test_tls_wildcard_match.c new file mode 100644 index 0000000..90cecb0 --- /dev/null +++ b/lib/transport/tests/test_tls_wildcard_match.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 One Identity LLC. + * Copyright (c) 2024 Franco Fichtner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + + +#include + +#include "transport/tls-verifier.h" + +TestSuite(tls_wildcard, .init = NULL, .fini = NULL); + +Test(tls_wildcard, test_wildcard_match_pattern_acceptance) +{ + cr_assert_eq(tls_wildcard_match("test", "test"), TRUE); + cr_assert_eq(tls_wildcard_match("test", "*"), TRUE); + cr_assert_eq(tls_wildcard_match("test", "t*t"), TRUE); + cr_assert_eq(tls_wildcard_match("test", "t*"), TRUE); + cr_assert_eq(tls_wildcard_match("", ""), TRUE); + cr_assert_eq(tls_wildcard_match("test.one", "test.one"), TRUE); + cr_assert_eq(tls_wildcard_match("test.one.two", "test.one.two"), TRUE); + cr_assert_eq(tls_wildcard_match("192.0.2.0", "192.0.2.0"), TRUE); + cr_assert_eq(tls_wildcard_match("2001:0000:130F:0000:0000:09C0:876A:130B", "2001:0000:130F:0000:0000:09C0:876A:130B"), + TRUE); + cr_assert_eq(tls_wildcard_match("2001:0000:130F:0000:0000:09C0:876A:130B", "2001:0:130F:0:0:9C0:876A:130B"), TRUE); + cr_assert_eq(tls_wildcard_match("2001:0:130F:0:0:9C0:876A:130B", "2001:0000:130F:0000:0000:09C0:876A:130B"), TRUE); + cr_assert_eq(tls_wildcard_match("2001:0000:130F::09C0:876A:130B", "2001:0000:130F:0000:0000:09C0:876A:130B"), TRUE); + cr_assert_eq(tls_wildcard_match("2001:0000:130F:0000:0000:09C0:876A:130B", "2001:0000:130F::09C0:876A:130B"), TRUE); + cr_assert_eq(tls_wildcard_match("2001:0000:130F:0000:0000:09C0:876A:130B", "2001:0:130F::9C0:876A:130B"), TRUE); + cr_assert_eq(tls_wildcard_match("2001:0:130F::9C0:876A:130B", "2001:0000:130F:0000:0000:09C0:876A:130B"), TRUE); +} + +Test(tls_wildcard, test_wildcard_match_wildcard_rejection) +{ + cr_assert_eq(tls_wildcard_match("test", "**"), FALSE); + cr_assert_eq(tls_wildcard_match("test", "*es*"), FALSE); + cr_assert_eq(tls_wildcard_match("test", "t*?"), FALSE); +} + +Test(tls_wildcard, test_wildcard_match_pattern_rejection) +{ + cr_assert_eq(tls_wildcard_match("test", "tset"), FALSE); + cr_assert_eq(tls_wildcard_match("test", "set"), FALSE); + cr_assert_eq(tls_wildcard_match("", "*"), FALSE); + cr_assert_eq(tls_wildcard_match("test", ""), FALSE); + cr_assert_eq(tls_wildcard_match("test.two", "test.one"), FALSE); +} + +Test(tls_wildcard, test_wildcard_match_format_rejection) +{ + cr_assert_eq(tls_wildcard_match("test.two", "test.*"), FALSE); + cr_assert_eq(tls_wildcard_match("test.two", "test.t*o"), FALSE); + cr_assert_eq(tls_wildcard_match("test", "test.two"), FALSE); + cr_assert_eq(tls_wildcard_match("test.two", "test"), FALSE); + cr_assert_eq(tls_wildcard_match("test.one.two", "test.one"), FALSE); + cr_assert_eq(tls_wildcard_match("test.one", "test.one.two"), FALSE); + cr_assert_eq(tls_wildcard_match("test.three", "three.test"), FALSE); + cr_assert_eq(tls_wildcard_match("test.one.two", "test.one.*"), FALSE); +} + +Test(tls_wildcard, test_wildcard_match_complex_rejection) +{ + cr_assert_eq(tls_wildcard_match("test.two", "test.???"), FALSE); + cr_assert_eq(tls_wildcard_match("test.one.two", "test.one.?wo"), FALSE); +} + +Test(tls_wildcard, test_ip_wildcard_rejection) +{ + cr_assert_eq(tls_wildcard_match("192.0.2.0", "*.0.2.0"), FALSE); + cr_assert_eq(tls_wildcard_match("2001:0000:130F:0000:0000:09C0:876A:130B", "*:0000:130F:0000:0000:09C0:876A:130B"), + FALSE); + cr_assert_eq(tls_wildcard_match("2001:0:130F::9C0:876A:130B", "*:0000:130F:0000:0000:09C0:876A:130B"), FALSE); +} + +Test(tls_wildcard, test_case_insensivity) +{ + cr_assert_eq(tls_wildcard_match("test", "TEST"), TRUE); + cr_assert_eq(tls_wildcard_match("TEST", "test"), TRUE); + cr_assert_eq(tls_wildcard_match("TeST", "TEst"), TRUE); + cr_assert_eq(tls_wildcard_match("test.one", "test.ONE"), TRUE); + cr_assert_eq(tls_wildcard_match("test.TWO", "test.two"), TRUE); + cr_assert_eq(tls_wildcard_match("test.three", "*T.three"), TRUE); + cr_assert_eq(tls_wildcard_match("2001:0000:130F:0000:0000:09C0:876A:130B", "2001:0000:130f:0000:0000:09c0:876a:130b"), + TRUE); +} diff --git a/lib/transport/tls-verifier.c b/lib/transport/tls-verifier.c index 606ad02..dde00d9 100644 --- a/lib/transport/tls-verifier.c +++ b/lib/transport/tls-verifier.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2024 One Identity LLC. + * Copyright (c) 2024 Franco Fichtner * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * @@ -75,7 +77,7 @@ tls_verifier_unref(TLSVerifier *self) /* helper functions */ -static gboolean +gboolean tls_wildcard_match(const gchar *host_name, const gchar *pattern) { gchar **pattern_parts, **hostname_parts; @@ -86,22 +88,84 @@ tls_wildcard_match(const gchar *host_name, const gchar *pattern) pattern_parts = g_strsplit(pattern, ".", 0); hostname_parts = g_strsplit(host_name, ".", 0); - for (i = 0; pattern_parts[i]; i++) + + if(g_strrstr(pattern, "\?")) + { + /* Glib would treat any question marks as jokers */ + success = FALSE; + } + else if (g_hostname_is_ip_address(host_name)) + { + /* no wildcards in IP */ + if (g_strrstr(pattern, "*")) + { + success = FALSE; + } + else + { + struct in6_addr host_buffer, pattern_buffer; + gint INET_TYPE, INET_ADDRLEN; + if(strstr(host_name, ":")) + { + INET_TYPE = AF_INET6; + INET_ADDRLEN = INET6_ADDRSTRLEN; + } + else + { + INET_TYPE = AF_INET; + INET_ADDRLEN = INET_ADDRSTRLEN; + } + char host_ip[INET_ADDRLEN], pattern_ip[INET_ADDRLEN]; + gint host_ip_ok = inet_pton(INET_TYPE, host_name, &host_buffer); + gint pattern_ip_ok = inet_pton(INET_TYPE, pattern, &pattern_buffer); + inet_ntop(INET_TYPE, &host_buffer, host_ip, INET_ADDRLEN); + inet_ntop(INET_TYPE, &pattern_buffer, pattern_ip, INET_ADDRLEN); + success = (host_ip_ok && pattern_ip_ok && strcmp(host_ip, pattern_ip) == 0); + } + } + else { - if (!hostname_parts[i]) + if (pattern_parts[0] == NULL) { - /* number of dot separated entries is not the same in the hostname and the pattern spec */ - goto exit; + if (hostname_parts[0] == NULL) + success = TRUE; + else + success = FALSE; } + else + { + success = TRUE; + for (i = 0; pattern_parts[i]; i++) + { + if (hostname_parts[i] == NULL) + { + /* number of dot separated entries is not the same in the hostname and the pattern spec */ + success = FALSE; + break; + } + char *wildcard_matched = g_strrstr(pattern_parts[i], "*"); + if (wildcard_matched && (i != 0 || wildcard_matched != strstr(pattern_parts[i], "*"))) + { + /* wildcard only on leftmost part and never as multiple wildcards as per both RFC 6125 and 9525 */ + success = FALSE; + break; + } - lower_pattern = g_ascii_strdown(pattern_parts[i], -1); - lower_hostname = g_ascii_strdown(hostname_parts[i], -1); + lower_pattern = g_ascii_strdown(pattern_parts[i], -1); + lower_hostname = g_ascii_strdown(hostname_parts[i], -1); - if (!g_pattern_match_simple(lower_pattern, lower_hostname)) - goto exit; + if (!g_pattern_match_simple(lower_pattern, lower_hostname)) + { + success = FALSE; + break; + } + } + if (hostname_parts[i]) + /* hostname has more parts than the pattern */ + success = FALSE; + } } - success = TRUE; -exit: + g_free(lower_pattern); g_free(lower_hostname); g_strfreev(pattern_parts); diff --git a/lib/transport/tls-verifier.h b/lib/transport/tls-verifier.h index 5642afa..98ab858 100644 --- a/lib/transport/tls-verifier.h +++ b/lib/transport/tls-verifier.h @@ -44,5 +44,7 @@ void tls_verifier_unref(TLSVerifier *self); gboolean tls_verify_certificate_name(X509 *cert, const gchar *hostname); +gboolean tls_wildcard_match(const gchar *host_name, const gchar *pattern); + #endif -- 2.40.0