21#include <winpr/config.h>
24#include <winpr/synch.h>
26#include <winpr/thread.h>
27#include <winpr/crypto.h>
31#include <openssl/ssl.h>
32#include <openssl/err.h>
34#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
35#include <openssl/provider.h>
39#define TAG WINPR_TAG("utils.ssl")
41static BOOL g_winpr_openssl_initialized_by_winpr = FALSE;
43#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
44static OSSL_PROVIDER* s_winpr_openssl_provider_fips = NULL;
45static OSSL_PROVIDER* s_winpr_openssl_provider_legacy = NULL;
46static OSSL_PROVIDER* s_winpr_openssl_provider_default = NULL;
55#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
57#define WINPR_OPENSSL_LOCKING_REQUIRED 1
59static int g_winpr_openssl_num_locks = 0;
60static HANDLE* g_winpr_openssl_locks = NULL;
62struct CRYPTO_dynlock_value
67#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
68static unsigned long _winpr_openssl_id(
void)
70 return (
unsigned long)GetCurrentThreadId();
74static void _winpr_openssl_locking(
int mode,
int type,
const char* file,
int line)
76 if (mode & CRYPTO_LOCK)
78 (void)WaitForSingleObject(g_winpr_openssl_locks[type], INFINITE);
82 (void)ReleaseMutex(g_winpr_openssl_locks[type]);
86static struct CRYPTO_dynlock_value* _winpr_openssl_dynlock_create(
const char* file,
int line)
88 struct CRYPTO_dynlock_value* dynlock;
90 if (!(dynlock = (
struct CRYPTO_dynlock_value*)malloc(
sizeof(
struct CRYPTO_dynlock_value))))
93 if (!(dynlock->mutex = CreateMutex(NULL, FALSE, NULL)))
102static void _winpr_openssl_dynlock_lock(
int mode,
struct CRYPTO_dynlock_value* dynlock,
103 const char* file,
int line)
105 if (mode & CRYPTO_LOCK)
107 (void)WaitForSingleObject(dynlock->mutex, INFINITE);
111 (void)ReleaseMutex(dynlock->mutex);
115static void _winpr_openssl_dynlock_destroy(
struct CRYPTO_dynlock_value* dynlock,
const char* file,
118 (void)CloseHandle(dynlock->mutex);
122static BOOL _winpr_openssl_initialize_locking(
void)
128 if (CRYPTO_get_locking_callback())
130 WLog_WARN(TAG,
"OpenSSL static locking callback is already set");
134 if ((count = CRYPTO_num_locks()) > 0)
138 if (!(locks = calloc(count,
sizeof(HANDLE))))
140 WLog_ERR(TAG,
"error allocating lock table");
144 for (
int i = 0; i < count; i++)
146 if (!(locks[i] = CreateMutex(NULL, FALSE, NULL)))
148 WLog_ERR(TAG,
"error creating lock #%d", i);
153 (void)CloseHandle(locks[i]);
161 g_winpr_openssl_locks = locks;
162 g_winpr_openssl_num_locks = count;
163 CRYPTO_set_locking_callback(_winpr_openssl_locking);
169 if (CRYPTO_get_dynlock_create_callback() || CRYPTO_get_dynlock_lock_callback() ||
170 CRYPTO_get_dynlock_destroy_callback())
172 WLog_WARN(TAG,
"dynamic locking callbacks are already set");
176 CRYPTO_set_dynlock_create_callback(_winpr_openssl_dynlock_create);
177 CRYPTO_set_dynlock_lock_callback(_winpr_openssl_dynlock_lock);
178 CRYPTO_set_dynlock_destroy_callback(_winpr_openssl_dynlock_destroy);
182#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
184 if (CRYPTO_get_id_callback())
186 WLog_WARN(TAG,
"OpenSSL id_callback is already set");
190 CRYPTO_set_id_callback(_winpr_openssl_id);
197static BOOL _winpr_openssl_cleanup_locking(
void)
200 if (CRYPTO_get_locking_callback() == _winpr_openssl_locking)
202 CRYPTO_set_locking_callback(NULL);
204 for (
int i = 0; i < g_winpr_openssl_num_locks; i++)
206 (void)CloseHandle(g_winpr_openssl_locks[i]);
209 g_winpr_openssl_num_locks = 0;
210 free(g_winpr_openssl_locks);
211 g_winpr_openssl_locks = NULL;
216 if (CRYPTO_get_dynlock_create_callback() == _winpr_openssl_dynlock_create)
218 CRYPTO_set_dynlock_create_callback(NULL);
221 if (CRYPTO_get_dynlock_lock_callback() == _winpr_openssl_dynlock_lock)
223 CRYPTO_set_dynlock_lock_callback(NULL);
226 if (CRYPTO_get_dynlock_destroy_callback() == _winpr_openssl_dynlock_destroy)
228 CRYPTO_set_dynlock_destroy_callback(NULL);
231#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
233 if (CRYPTO_get_id_callback() == _winpr_openssl_id)
235 CRYPTO_set_id_callback(NULL);
244static BOOL winpr_enable_fips(DWORD flags)
246 if (flags & WINPR_SSL_INIT_ENABLE_FIPS)
248#if (OPENSSL_VERSION_NUMBER < 0x10001000L) || defined(LIBRESSL_VERSION_NUMBER)
249 WLog_ERR(TAG,
"Openssl fips mode not available on openssl versions less than 1.0.1!");
252 WLog_DBG(TAG,
"Ensuring openssl fips mode is enabled");
254#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
255 s_winpr_openssl_provider_fips = OSSL_PROVIDER_load(NULL,
"fips");
256 if (s_winpr_openssl_provider_fips == NULL)
258 WLog_WARN(TAG,
"OpenSSL FIPS provider failed to load");
260 if (!EVP_default_properties_is_fips_enabled(NULL))
262 if (FIPS_mode() != 1)
265#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
266 if (EVP_set_default_properties(NULL,
"fips=yes"))
268 if (FIPS_mode_set(1))
270 WLog_INFO(TAG,
"Openssl fips mode enabled!");
273 WLog_ERR(TAG,
"Openssl fips mode enable failed!");
284static void winpr_openssl_cleanup(
void)
286 winpr_CleanupSSL(WINPR_SSL_INIT_DEFAULT);
289static BOOL CALLBACK winpr_openssl_initialize(WINPR_ATTR_UNUSED
PINIT_ONCE once, PVOID param,
290 WINPR_ATTR_UNUSED PVOID* context)
292 DWORD flags = param ? *(PDWORD)param : WINPR_SSL_INIT_DEFAULT;
294 if (flags & WINPR_SSL_INIT_ALREADY_INITIALIZED)
299#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
301 if (flags & WINPR_SSL_INIT_ENABLE_LOCKING)
303 if (!_winpr_openssl_initialize_locking())
311#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
312 SSL_load_error_strings();
315 OpenSSL_add_all_digests();
316 OpenSSL_add_all_ciphers();
319 if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
320 OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS |
321 OPENSSL_INIT_ENGINE_ALL_BUILTIN,
327#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
329 s_winpr_openssl_provider_legacy = OSSL_PROVIDER_load(NULL,
"legacy");
330 if (s_winpr_openssl_provider_legacy == NULL)
332 WLog_WARN(TAG,
"OpenSSL LEGACY provider failed to load, no md4 support available!");
334 s_winpr_openssl_provider_default = OSSL_PROVIDER_load(NULL,
"default");
335 if (s_winpr_openssl_provider_default == NULL)
337 WLog_WARN(TAG,
"OpenSSL DEFAULT provider failed to load");
341 (void)atexit(winpr_openssl_cleanup);
342 g_winpr_openssl_initialized_by_winpr = TRUE;
348BOOL winpr_InitializeSSL(DWORD flags)
350 static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
352 if (!InitOnceExecuteOnce(&once, winpr_openssl_initialize, &flags, NULL))
355 return winpr_enable_fips(flags);
358#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
359static int unload(OSSL_PROVIDER* provider, WINPR_ATTR_UNUSED
void* data)
363 const char* name = OSSL_PROVIDER_get0_name(provider);
367 OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_get0_global_default();
368 const int rc = OSSL_PROVIDER_available(ctx, name);
371 OSSL_PROVIDER_unload(provider);
376BOOL winpr_CleanupSSL(DWORD flags)
378 if (flags & WINPR_SSL_CLEANUP_GLOBAL)
380 if (!g_winpr_openssl_initialized_by_winpr)
382 WLog_WARN(TAG,
"ssl was not initialized by winpr");
386 g_winpr_openssl_initialized_by_winpr = FALSE;
387#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
388 _winpr_openssl_cleanup_locking();
390#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
391 CRYPTO_cleanup_all_ex_data();
395#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
396 flags |= WINPR_SSL_CLEANUP_THREAD;
400#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
402 if (flags & WINPR_SSL_CLEANUP_THREAD)
404#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
407 ERR_remove_thread_state(NULL);
412#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
413 OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_get0_global_default();
414 OSSL_PROVIDER_do_all(ctx, unload, NULL);
420BOOL winpr_FIPSMode(
void)
422#if (OPENSSL_VERSION_NUMBER < 0x10001000L) || defined(LIBRESSL_VERSION_NUMBER)
424#elif defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
425 return (EVP_default_properties_is_fips_enabled(NULL) == 1);
427 return (FIPS_mode() == 1);
433BOOL winpr_InitializeSSL(DWORD flags)
438BOOL winpr_CleanupSSL(DWORD flags)
443BOOL winpr_FIPSMode(
void)