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 diff --git a/src/native/libs/System.Security.Cryptography.Native/opensslshim.c b/src/native/libs/System.Security.Cryptography.Native/opensslshim.c index 98477b07f0f2fd..92931fb813b30e 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,80 @@ 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/, 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."; + + 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; + } + + // 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, sslPrefix, sizeof(sslPrefix) - 1) != 0) + { + continue; + } + + const char* version = entry->d_name + sizeof(sslPrefix) - 1; + char* end; + long major = strtol(version, &end, 10); + if (end == version) + { + continue; + } + + 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); + } + } + 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 @@ -64,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 @@ -111,6 +196,26 @@ static void OpenLibraryOnce(void) { DlOpen(MAKELIB("111")); } +#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) + { + // OpenSSL 4.0 from ports (probed but not preferred) + DlOpenEOpenSsl("40"); + } #endif if (libssl == NULL)