21#include <winpr/config.h>
23#include <winpr/atexit.h>
25#include <winpr/synch.h>
27#include <winpr/thread.h>
28#include <winpr/crypto.h>
32#include <openssl/ssl.h>
33#include <openssl/err.h>
35#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
36#include <openssl/provider.h>
40#define TAG WINPR_TAG("utils.ssl")
42static BOOL g_winpr_openssl_initialized_by_winpr = FALSE;
44#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
45static OSSL_PROVIDER* s_winpr_openssl_provider_fips =
nullptr;
46static OSSL_PROVIDER* s_winpr_openssl_provider_legacy =
nullptr;
47static OSSL_PROVIDER* s_winpr_openssl_provider_default =
nullptr;
56#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
58#define WINPR_OPENSSL_LOCKING_REQUIRED 1
60static int g_winpr_openssl_num_locks = 0;
61static HANDLE* g_winpr_openssl_locks =
nullptr;
63struct CRYPTO_dynlock_value
68#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
69static unsigned long _winpr_openssl_id(
void)
71 return (
unsigned long)GetCurrentThreadId();
75static void _winpr_openssl_locking(
int mode,
int type,
const char* file,
int line)
77 if (mode & CRYPTO_LOCK)
79 (void)WaitForSingleObject(g_winpr_openssl_locks[type], INFINITE);
83 (void)ReleaseMutex(g_winpr_openssl_locks[type]);
87static struct CRYPTO_dynlock_value* _winpr_openssl_dynlock_create(
const char* file,
int line)
89 struct CRYPTO_dynlock_value* dynlock;
91 if (!(dynlock = (
struct CRYPTO_dynlock_value*)malloc(
sizeof(
struct CRYPTO_dynlock_value))))
94 if (!(dynlock->mutex = CreateMutex(
nullptr, FALSE,
nullptr)))
103static void _winpr_openssl_dynlock_lock(
int mode,
struct CRYPTO_dynlock_value* dynlock,
104 const char* file,
int line)
106 if (mode & CRYPTO_LOCK)
108 (void)WaitForSingleObject(dynlock->mutex, INFINITE);
112 (void)ReleaseMutex(dynlock->mutex);
116static void _winpr_openssl_dynlock_destroy(
struct CRYPTO_dynlock_value* dynlock,
const char* file,
119 (void)CloseHandle(dynlock->mutex);
123static BOOL _winpr_openssl_initialize_locking(
void)
129 if (CRYPTO_get_locking_callback())
131 WLog_WARN(TAG,
"OpenSSL static locking callback is already set");
135 if ((count = CRYPTO_num_locks()) > 0)
139 if (!(locks = calloc(count,
sizeof(HANDLE))))
141 WLog_ERR(TAG,
"error allocating lock table");
145 for (
int i = 0; i < count; i++)
147 if (!(locks[i] = CreateMutex(
nullptr, FALSE,
nullptr)))
149 WLog_ERR(TAG,
"error creating lock #%d", i);
154 (void)CloseHandle(locks[i]);
162 g_winpr_openssl_locks = locks;
163 g_winpr_openssl_num_locks = count;
164 CRYPTO_set_locking_callback(_winpr_openssl_locking);
170 if (CRYPTO_get_dynlock_create_callback() || CRYPTO_get_dynlock_lock_callback() ||
171 CRYPTO_get_dynlock_destroy_callback())
173 WLog_WARN(TAG,
"dynamic locking callbacks are already set");
177 CRYPTO_set_dynlock_create_callback(_winpr_openssl_dynlock_create);
178 CRYPTO_set_dynlock_lock_callback(_winpr_openssl_dynlock_lock);
179 CRYPTO_set_dynlock_destroy_callback(_winpr_openssl_dynlock_destroy);
183#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
185 if (CRYPTO_get_id_callback())
187 WLog_WARN(TAG,
"OpenSSL id_callback is already set");
191 CRYPTO_set_id_callback(_winpr_openssl_id);
198static BOOL _winpr_openssl_cleanup_locking(
void)
201 if (CRYPTO_get_locking_callback() == _winpr_openssl_locking)
203 CRYPTO_set_locking_callback(
nullptr);
205 for (
int i = 0; i < g_winpr_openssl_num_locks; i++)
207 (void)CloseHandle(g_winpr_openssl_locks[i]);
210 g_winpr_openssl_num_locks = 0;
211 free(g_winpr_openssl_locks);
212 g_winpr_openssl_locks =
nullptr;
217 if (CRYPTO_get_dynlock_create_callback() == _winpr_openssl_dynlock_create)
219 CRYPTO_set_dynlock_create_callback(
nullptr);
222 if (CRYPTO_get_dynlock_lock_callback() == _winpr_openssl_dynlock_lock)
224 CRYPTO_set_dynlock_lock_callback(
nullptr);
227 if (CRYPTO_get_dynlock_destroy_callback() == _winpr_openssl_dynlock_destroy)
229 CRYPTO_set_dynlock_destroy_callback(
nullptr);
232#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
234 if (CRYPTO_get_id_callback() == _winpr_openssl_id)
236 CRYPTO_set_id_callback(
nullptr);
245static BOOL winpr_enable_fips(DWORD flags)
247 if (flags & WINPR_SSL_INIT_ENABLE_FIPS)
249#if (OPENSSL_VERSION_NUMBER < 0x10001000L) || defined(LIBRESSL_VERSION_NUMBER)
250 WLog_ERR(TAG,
"Openssl fips mode not available on openssl versions less than 1.0.1!");
253 WLog_DBG(TAG,
"Ensuring openssl fips mode is enabled");
255#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
256 s_winpr_openssl_provider_fips = OSSL_PROVIDER_load(
nullptr,
"fips");
257 if (s_winpr_openssl_provider_fips ==
nullptr)
259 WLog_WARN(TAG,
"OpenSSL FIPS provider failed to load");
261 if (!EVP_default_properties_is_fips_enabled(
nullptr))
263 if (FIPS_mode() != 1)
266#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
267 if (EVP_set_default_properties(
nullptr,
"fips=yes"))
269 if (FIPS_mode_set(1))
271 WLog_INFO(TAG,
"Openssl fips mode enabled!");
274 WLog_ERR(TAG,
"Openssl fips mode enable failed!");
285static void winpr_openssl_cleanup(
void)
287 winpr_CleanupSSL(WINPR_SSL_INIT_DEFAULT);
290static BOOL CALLBACK winpr_openssl_initialize(WINPR_ATTR_UNUSED
PINIT_ONCE once, PVOID param,
291 WINPR_ATTR_UNUSED PVOID* context)
293 DWORD flags = param ? *(PDWORD)param : WINPR_SSL_INIT_DEFAULT;
295 if (flags & WINPR_SSL_INIT_ALREADY_INITIALIZED)
300#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
302 if (flags & WINPR_SSL_INIT_ENABLE_LOCKING)
304 if (!_winpr_openssl_initialize_locking())
312#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
313 SSL_load_error_strings();
316 OpenSSL_add_all_digests();
317 OpenSSL_add_all_ciphers();
320 if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
321 OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS |
322 OPENSSL_INIT_ENGINE_ALL_BUILTIN,
328#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
330 s_winpr_openssl_provider_legacy = OSSL_PROVIDER_load(
nullptr,
"legacy");
331 if (s_winpr_openssl_provider_legacy ==
nullptr)
333 WLog_WARN(TAG,
"OpenSSL LEGACY provider failed to load, no md4 support available!");
335 s_winpr_openssl_provider_default = OSSL_PROVIDER_load(
nullptr,
"default");
336 if (s_winpr_openssl_provider_default ==
nullptr)
338 WLog_WARN(TAG,
"OpenSSL DEFAULT provider failed to load");
342 (void)winpr_atexit(winpr_openssl_cleanup);
343 g_winpr_openssl_initialized_by_winpr = TRUE;
349BOOL winpr_InitializeSSL(DWORD flags)
351 static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
353 if (!InitOnceExecuteOnce(&once, winpr_openssl_initialize, &flags,
nullptr))
356 return winpr_enable_fips(flags);
359#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
360static int unload(OSSL_PROVIDER* provider, WINPR_ATTR_UNUSED
void* data)
364 const char* name = OSSL_PROVIDER_get0_name(provider);
368 OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_get0_global_default();
369 const int rc = OSSL_PROVIDER_available(ctx, name);
372 OSSL_PROVIDER_unload(provider);
377BOOL winpr_CleanupSSL(DWORD flags)
379 if (flags & WINPR_SSL_CLEANUP_GLOBAL)
381 if (!g_winpr_openssl_initialized_by_winpr)
383 WLog_WARN(TAG,
"ssl was not initialized by winpr");
387 g_winpr_openssl_initialized_by_winpr = FALSE;
388#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
389 _winpr_openssl_cleanup_locking();
391#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
392 CRYPTO_cleanup_all_ex_data();
396#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
397 flags |= WINPR_SSL_CLEANUP_THREAD;
401#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
403 if (flags & WINPR_SSL_CLEANUP_THREAD)
405#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
408 ERR_remove_thread_state(
nullptr);
413#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
414 OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_get0_global_default();
416 OSSL_PROVIDER_do_all(ctx, unload,
nullptr);
422BOOL winpr_FIPSMode(
void)
424#if (OPENSSL_VERSION_NUMBER < 0x10001000L) || defined(LIBRESSL_VERSION_NUMBER)
426#elif defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
427 return (EVP_default_properties_is_fips_enabled(
nullptr) == 1);
429 return (FIPS_mode() == 1);
435BOOL winpr_InitializeSSL(DWORD flags)
440BOOL winpr_CleanupSSL(DWORD flags)
445BOOL winpr_FIPSMode(
void)