Commit 2c1f8b3e9f for strongswan.org

commit 2c1f8b3e9fa2cdda8d9f0cb117b21713da14e11f
Author: raghu netrakar <raghu@security.bugqore.com>
Date:   Wed Oct 14 11:33:36 2026 +0530

    Cast char to unsigned char before passing it to ctype functions

    As also noted in the man page, ctype functions (isprint, isalpha,
    isspace, ...) require an argument that is representable as `unsigned char`
    or equal to EOF.  `char` is signed on most platforms, so a byte >= 0x80
    is sign extended and passed as a negative value, which is technically
    undefined behavior and may read out of bounds of the classification table
    on libcs that index it directly without covering negative values as well.

    Closes strongswan/strongswan#3176

diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
index cc0daf40bd..145bc2e5f5 100644
--- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
+++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
@@ -658,7 +658,7 @@ static char* sanitize(char *str)

 	while (pos && *pos)
 	{
-		if (!isprint(*pos))
+		if (!isprint((u_char)*pos))
 		{
 			*pos = '?';
 		}
diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
index be753254f9..7a42e7ccbc 100644
--- a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
+++ b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
@@ -1208,7 +1208,7 @@ int builtin_vfprintf(FILE *stream, const char *format, va_list ap)
 		{
 			if (pos[0] == '\e' && pos[1] == '[' && pos[4] == 'm')
 			{
-				if (isdigit(pos[3]))
+				if (isdigit((u_char)pos[3]))
 				{
 					if (pos[2] == '3' || pos[2] == '4')
 					{
diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c
index ccab4062ef..92cb37c51a 100644
--- a/src/libstrongswan/utils/utils.c
+++ b/src/libstrongswan/utils/utils.c
@@ -193,7 +193,7 @@ void closefrom(int low_fd)
 			for (offset = 0; offset < len; offset += entry->d_reclen)
 			{
 				entry = (struct linux_dirent64*)(buffer + offset);
-				if (!isdigit(entry->d_name[0]))
+				if (!isdigit((u_char)entry->d_name[0]))
 				{
 					continue;
 				}
@@ -229,7 +229,7 @@ void closefrom(int low_fd)
 #endif
 		while ((entry = readdir(dir)))
 		{
-			if (!isdigit(entry->d_name[0]))
+			if (!isdigit((u_char)entry->d_name[0]))
 			{
 				continue;
 			}
diff --git a/src/libstrongswan/utils/utils/path.c b/src/libstrongswan/utils/utils/path.c
index f209f50496..6fb5b344b8 100644
--- a/src/libstrongswan/utils/utils/path.c
+++ b/src/libstrongswan/utils/utils/path.c
@@ -93,7 +93,7 @@ char *path_dirname(const char *path)
 #ifdef WIN32
 		if (path && strlen(path))
 		{
-			if ((isalpha(path[0]) && path[1] == ':'))
+			if ((isalpha((u_char)path[0]) && path[1] == ':'))
 			{	/* if just a drive letter given, return that as dirname */
 				return chunk_clone(chunk_from_chars(path[0], ':', 0)).ptr;
 			}
@@ -151,7 +151,7 @@ bool path_absolute(const char *path)
 	{	/* UNC */
 		return TRUE;
 	}
-	if (strlen(path) && isalpha(path[0]) && path[1] == ':')
+	if (strlen(path) && isalpha((u_char)path[0]) && path[1] == ':')
 	{	/* drive letter */
 		return TRUE;
 	}