From f4aa91a35a476c2f8f15bb31d1a6d65da976b8f1 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Tue, 16 Jun 2026 22:47:44 +0300 Subject: [PATCH 1/4] Port System.Net.Http to OpenBSD --- .../opensslshim.c | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/native/libs/System.Security.Cryptography.Native/opensslshim.c b/src/native/libs/System.Security.Cryptography.Native/opensslshim.c index 98477b07f0f2fd..d3bc9dadd701a1 100644 --- a/src/native/libs/System.Security.Cryptography.Native/opensslshim.c +++ b/src/native/libs/System.Security.Cryptography.Native/opensslshim.c @@ -8,6 +8,12 @@ #include #include +#if defined(__OpenBSD__) +#include +#include +#include +#endif + #include "opensslshim.h" #include "pal_atomic.h" @@ -54,6 +60,94 @@ static void DlOpen(const char* libraryName) } } +#if defined(__OpenBSD__) +// OpenBSD's base system ships LibreSSL, which does not implement the full +// OpenSSL 3.x surface the shim requires. The OpenSSL ports install in parallel +// under /usr/local/lib/eopenssl/ using their own SONAME numbering (for +// example libssl.so.37.0 for the 3.5 flavor). Locate the newest eopenssl +// directory and load its libssl by absolute path so the matching libcrypto +// resolves via the library's RUNPATH. +static void DlOpenNewestEopenssl(void) +{ + static const char libDir[] = "/usr/local/lib"; + static const char dirPrefix[] = "eopenssl"; + static const char sslPrefix[] = "libssl.so."; + + DIR* dir = opendir(libDir); + if (dir == NULL) + { + return; + } + + // Find the eopenssl* subdirectory with the highest numeric suffix. + char bestDir[NAME_MAX + 1] = { 0 }; + long bestDirVersion = -1; + struct dirent* entry; + while ((entry = readdir(dir)) != NULL) + { + if (strncmp(entry->d_name, dirPrefix, sizeof(dirPrefix) - 1) != 0) + { + continue; + } + + const char* suffix = entry->d_name + sizeof(dirPrefix) - 1; + char* end; + long version = strtol(suffix, &end, 10); + if (suffix != end && *end == '\0' && version > bestDirVersion) + { + bestDirVersion = version; + strncpy(bestDir, entry->d_name, sizeof(bestDir) - 1); + } + } + closedir(dir); + + if (bestDirVersion < 0) + { + return; + } + + char dirPath[PATH_MAX]; + int written = snprintf(dirPath, sizeof(dirPath), "%s/%s", libDir, bestDir); + if (written < 0 || (size_t)written >= sizeof(dirPath)) + { + return; + } + + dir = opendir(dirPath); + if (dir == NULL) + { + return; + } + + // Each eopenssl directory ships a single versioned libssl, so use the + // first libssl.so. entry found. + char libName[NAME_MAX + 1] = { 0 }; + while ((entry = readdir(dir)) != NULL) + { + if (strncmp(entry->d_name, sslPrefix, sizeof(sslPrefix) - 1) == 0) + { + strncpy(libName, entry->d_name, sizeof(libName) - 1); + break; + } + } + closedir(dir); + + if (libName[0] == '\0') + { + return; + } + + char libPath[PATH_MAX]; + written = snprintf(libPath, sizeof(libPath), "%s/%s", dirPath, libName); + if (written < 0 || (size_t)written >= sizeof(libPath)) + { + return; + } + + DlOpen(libPath); +} +#endif + static void OpenLibraryOnce(void) { // If there is an override of the version specified using the DOTNET_OPENSSL_VERSION_OVERRIDE @@ -111,6 +205,12 @@ static void OpenLibraryOnce(void) { DlOpen(MAKELIB("111")); } +#elif defined(__OpenBSD__) + // OpenBSD base is LibreSSL; load the OpenSSL ports build from /usr/local/lib/eopenssl. + if (libssl == NULL) + { + DlOpenNewestEopenssl(); + } #endif if (libssl == NULL) From 2218165aa31478f916b2439d7ff2ddff15d7ef69 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Tue, 16 Jun 2026 22:49:13 +0300 Subject: [PATCH 2/4] . --- src/libraries/System.Net.Http/src/System.Net.Http.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index c2a4d472ccaa09..ec879372f6fb78 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -1,7 +1,7 @@  - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-solaris;$(NetCoreAppCurrent)-haiku;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent) + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)-openbsd;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-solaris;$(NetCoreAppCurrent)-haiku;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent) true $(DefineConstants);HTTP_DLL false From c10306f330ff89a350b2e7c6e02e58a6fb7e94c2 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Wed, 17 Jun 2026 00:53:41 +0300 Subject: [PATCH 3/4] . --- eng/versioning.targets | 1 + 1 file changed, 1 insertion(+) diff --git a/eng/versioning.targets b/eng/versioning.targets index 46bf2743bbd82f..baa004f690cc11 100644 --- a/eng/versioning.targets +++ b/eng/versioning.targets @@ -81,6 +81,7 @@ + From 67a06ff490fcee9a1d2dfa3c2156aed020a69d8d Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Fri, 19 Jun 2026 04:33:48 +0300 Subject: [PATCH 4/4] Address CR feedback --- .../opensslshim.c | 91 ++++++++++--------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/src/native/libs/System.Security.Cryptography.Native/opensslshim.c b/src/native/libs/System.Security.Cryptography.Native/opensslshim.c index d3bc9dadd701a1..92931fb813b30e 100644 --- a/src/native/libs/System.Security.Cryptography.Native/opensslshim.c +++ b/src/native/libs/System.Security.Cryptography.Native/opensslshim.c @@ -63,71 +63,57 @@ static void DlOpen(const char* libraryName) #if defined(__OpenBSD__) // OpenBSD's base system ships LibreSSL, which does not implement the full // OpenSSL 3.x surface the shim requires. The OpenSSL ports install in parallel -// under /usr/local/lib/eopenssl/ using their own SONAME numbering (for -// example libssl.so.37.0 for the 3.5 flavor). Locate the newest eopenssl -// directory and load its libssl by absolute path so the matching libcrypto -// resolves via the library's RUNPATH. -static void DlOpenNewestEopenssl(void) +// under /usr/local/lib/eopenssl/, where is the OpenSSL version (e.g. +// eopenssl35 for OpenSSL 3.5). Each directory ships libssl with its own SONAME +// (for example libssl.so.37.0), bumped independently of the version number, so +// the SONAME is discovered within the requested directory rather than hardcoded. +// The library is opened by absolute path so the matching libcrypto resolves via +// the library's RUNPATH. +static void DlOpenEOpenSsl(const char* eopensslVersion) { static const char libDir[] = "/usr/local/lib"; static const char dirPrefix[] = "eopenssl"; static const char sslPrefix[] = "libssl.so."; - DIR* dir = opendir(libDir); + char dirPath[PATH_MAX]; + int written = snprintf(dirPath, sizeof(dirPath), "%s/%s%s", libDir, dirPrefix, eopensslVersion); + if (written < 0 || (size_t)written >= sizeof(dirPath)) + { + return; + } + + DIR* dir = opendir(dirPath); if (dir == NULL) { return; } - // Find the eopenssl* subdirectory with the highest numeric suffix. - char bestDir[NAME_MAX + 1] = { 0 }; - long bestDirVersion = -1; + // Pick the highest libssl.so.. in case more than one is present. + char libName[NAME_MAX + 1] = { 0 }; + long bestMajor = -1; + long bestMinor = -1; struct dirent* entry; while ((entry = readdir(dir)) != NULL) { - if (strncmp(entry->d_name, dirPrefix, sizeof(dirPrefix) - 1) != 0) + if (strncmp(entry->d_name, sslPrefix, sizeof(sslPrefix) - 1) != 0) { continue; } - const char* suffix = entry->d_name + sizeof(dirPrefix) - 1; + const char* version = entry->d_name + sizeof(sslPrefix) - 1; char* end; - long version = strtol(suffix, &end, 10); - if (suffix != end && *end == '\0' && version > bestDirVersion) + long major = strtol(version, &end, 10); + if (end == version) { - bestDirVersion = version; - strncpy(bestDir, entry->d_name, sizeof(bestDir) - 1); + continue; } - } - closedir(dir); - - if (bestDirVersion < 0) - { - return; - } - - char dirPath[PATH_MAX]; - int written = snprintf(dirPath, sizeof(dirPath), "%s/%s", libDir, bestDir); - if (written < 0 || (size_t)written >= sizeof(dirPath)) - { - return; - } - dir = opendir(dirPath); - if (dir == NULL) - { - return; - } - - // Each eopenssl directory ships a single versioned libssl, so use the - // first libssl.so. entry found. - char libName[NAME_MAX + 1] = { 0 }; - while ((entry = readdir(dir)) != NULL) - { - if (strncmp(entry->d_name, sslPrefix, sizeof(sslPrefix) - 1) == 0) + long minor = (*end == '.') ? strtol(end + 1, &end, 10) : 0; + if (major > bestMajor || (major == bestMajor && minor > bestMinor)) { + bestMajor = major; + bestMinor = minor; strncpy(libName, entry->d_name, sizeof(libName) - 1); - break; } } closedir(dir); @@ -158,9 +144,14 @@ static void OpenLibraryOnce(void) if ((versionOverride != NULL) && strnlen(versionOverride, MaxVersionStringLength + 1) <= MaxVersionStringLength) { +#if defined(__OpenBSD__) + // On OpenBSD the override selects the eopenssl ports directory. + DlOpenEOpenSsl(versionOverride); +#else char soName[sizeof(SONAME_BASE) + MaxVersionStringLength] = SONAME_BASE; strcat(soName, versionOverride); DlOpen(soName); +#endif } #ifdef TARGET_ANDROID @@ -207,9 +198,23 @@ static void OpenLibraryOnce(void) } #elif defined(__OpenBSD__) // OpenBSD base is LibreSSL; load the OpenSSL ports build from /usr/local/lib/eopenssl. + // Probe the known package directories explicitly, preferring 3.x and trying 4.0 last. + if (libssl == NULL) + { + // OpenSSL 3.6 from ports + DlOpenEOpenSsl("36"); + } + + if (libssl == NULL) + { + // OpenSSL 3.5 from ports + DlOpenEOpenSsl("35"); + } + if (libssl == NULL) { - DlOpenNewestEopenssl(); + // OpenSSL 4.0 from ports (probed but not preferred) + DlOpenEOpenSsl("40"); } #endif