FreeRDP
Loading...
Searching...
No Matches
ssl.c
1
21#include <winpr/config.h>
22
23#include <winpr/crt.h>
24#include <winpr/synch.h>
25#include <winpr/ssl.h>
26#include <winpr/thread.h>
27#include <winpr/crypto.h>
28
29#ifdef WITH_OPENSSL
30
31#include <openssl/ssl.h>
32#include <openssl/err.h>
33
34#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
35#include <openssl/provider.h>
36#endif
37
38#include "../log.h"
39#define TAG WINPR_TAG("utils.ssl")
40
41static BOOL g_winpr_openssl_initialized_by_winpr = FALSE;
42
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;
47#endif
48
55#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
56
57#define WINPR_OPENSSL_LOCKING_REQUIRED 1
58
59static int g_winpr_openssl_num_locks = 0;
60static HANDLE* g_winpr_openssl_locks = NULL;
61
62struct CRYPTO_dynlock_value
63{
64 HANDLE mutex;
65};
66
67#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
68static unsigned long _winpr_openssl_id(void)
69{
70 return (unsigned long)GetCurrentThreadId();
71}
72#endif
73
74static void _winpr_openssl_locking(int mode, int type, const char* file, int line)
75{
76 if (mode & CRYPTO_LOCK)
77 {
78 (void)WaitForSingleObject(g_winpr_openssl_locks[type], INFINITE);
79 }
80 else
81 {
82 (void)ReleaseMutex(g_winpr_openssl_locks[type]);
83 }
84}
85
86static struct CRYPTO_dynlock_value* _winpr_openssl_dynlock_create(const char* file, int line)
87{
88 struct CRYPTO_dynlock_value* dynlock;
89
90 if (!(dynlock = (struct CRYPTO_dynlock_value*)malloc(sizeof(struct CRYPTO_dynlock_value))))
91 return NULL;
92
93 if (!(dynlock->mutex = CreateMutex(NULL, FALSE, NULL)))
94 {
95 free(dynlock);
96 return NULL;
97 }
98
99 return dynlock;
100}
101
102static void _winpr_openssl_dynlock_lock(int mode, struct CRYPTO_dynlock_value* dynlock,
103 const char* file, int line)
104{
105 if (mode & CRYPTO_LOCK)
106 {
107 (void)WaitForSingleObject(dynlock->mutex, INFINITE);
108 }
109 else
110 {
111 (void)ReleaseMutex(dynlock->mutex);
112 }
113}
114
115static void _winpr_openssl_dynlock_destroy(struct CRYPTO_dynlock_value* dynlock, const char* file,
116 int line)
117{
118 (void)CloseHandle(dynlock->mutex);
119 free(dynlock);
120}
121
122static BOOL _winpr_openssl_initialize_locking(void)
123{
124 int count;
125
126 /* OpenSSL static locking */
127
128 if (CRYPTO_get_locking_callback())
129 {
130 WLog_WARN(TAG, "OpenSSL static locking callback is already set");
131 }
132 else
133 {
134 if ((count = CRYPTO_num_locks()) > 0)
135 {
136 HANDLE* locks;
137
138 if (!(locks = calloc(count, sizeof(HANDLE))))
139 {
140 WLog_ERR(TAG, "error allocating lock table");
141 return FALSE;
142 }
143
144 for (int i = 0; i < count; i++)
145 {
146 if (!(locks[i] = CreateMutex(NULL, FALSE, NULL)))
147 {
148 WLog_ERR(TAG, "error creating lock #%d", i);
149
150 while (i--)
151 {
152 if (locks[i])
153 (void)CloseHandle(locks[i]);
154 }
155
156 free(locks);
157 return FALSE;
158 }
159 }
160
161 g_winpr_openssl_locks = locks;
162 g_winpr_openssl_num_locks = count;
163 CRYPTO_set_locking_callback(_winpr_openssl_locking);
164 }
165 }
166
167 /* OpenSSL dynamic locking */
168
169 if (CRYPTO_get_dynlock_create_callback() || CRYPTO_get_dynlock_lock_callback() ||
170 CRYPTO_get_dynlock_destroy_callback())
171 {
172 WLog_WARN(TAG, "dynamic locking callbacks are already set");
173 }
174 else
175 {
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);
179 }
180
181 /* Use the deprecated CRYPTO_get_id_callback() if building against OpenSSL < 1.0.0 */
182#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
183
184 if (CRYPTO_get_id_callback())
185 {
186 WLog_WARN(TAG, "OpenSSL id_callback is already set");
187 }
188 else
189 {
190 CRYPTO_set_id_callback(_winpr_openssl_id);
191 }
192
193#endif
194 return TRUE;
195}
196
197static BOOL _winpr_openssl_cleanup_locking(void)
198{
199 /* undo our static locking modifications */
200 if (CRYPTO_get_locking_callback() == _winpr_openssl_locking)
201 {
202 CRYPTO_set_locking_callback(NULL);
203
204 for (int i = 0; i < g_winpr_openssl_num_locks; i++)
205 {
206 (void)CloseHandle(g_winpr_openssl_locks[i]);
207 }
208
209 g_winpr_openssl_num_locks = 0;
210 free(g_winpr_openssl_locks);
211 g_winpr_openssl_locks = NULL;
212 }
213
214 /* unset our dynamic locking callbacks */
215
216 if (CRYPTO_get_dynlock_create_callback() == _winpr_openssl_dynlock_create)
217 {
218 CRYPTO_set_dynlock_create_callback(NULL);
219 }
220
221 if (CRYPTO_get_dynlock_lock_callback() == _winpr_openssl_dynlock_lock)
222 {
223 CRYPTO_set_dynlock_lock_callback(NULL);
224 }
225
226 if (CRYPTO_get_dynlock_destroy_callback() == _winpr_openssl_dynlock_destroy)
227 {
228 CRYPTO_set_dynlock_destroy_callback(NULL);
229 }
230
231#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
232
233 if (CRYPTO_get_id_callback() == _winpr_openssl_id)
234 {
235 CRYPTO_set_id_callback(NULL);
236 }
237
238#endif
239 return TRUE;
240}
241
242#endif /* OpenSSL < 1.1.0 */
243
244static BOOL winpr_enable_fips(DWORD flags)
245{
246 if (flags & WINPR_SSL_INIT_ENABLE_FIPS)
247 {
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!");
250 return FALSE;
251#else
252 WLog_DBG(TAG, "Ensuring openssl fips mode is enabled");
253
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)
257 {
258 WLog_WARN(TAG, "OpenSSL FIPS provider failed to load");
259 }
260 if (!EVP_default_properties_is_fips_enabled(NULL))
261#else
262 if (FIPS_mode() != 1)
263#endif
264 {
265#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
266 if (EVP_set_default_properties(NULL, "fips=yes"))
267#else
268 if (FIPS_mode_set(1))
269#endif
270 WLog_INFO(TAG, "Openssl fips mode enabled!");
271 else
272 {
273 WLog_ERR(TAG, "Openssl fips mode enable failed!");
274 return FALSE;
275 }
276 }
277
278#endif
279 }
280
281 return TRUE;
282}
283
284static void winpr_openssl_cleanup(void)
285{
286 winpr_CleanupSSL(WINPR_SSL_INIT_DEFAULT);
287}
288
289static BOOL CALLBACK winpr_openssl_initialize(WINPR_ATTR_UNUSED PINIT_ONCE once, PVOID param,
290 WINPR_ATTR_UNUSED PVOID* context)
291{
292 DWORD flags = param ? *(PDWORD)param : WINPR_SSL_INIT_DEFAULT;
293
294 if (flags & WINPR_SSL_INIT_ALREADY_INITIALIZED)
295 {
296 return TRUE;
297 }
298
299#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
300
301 if (flags & WINPR_SSL_INIT_ENABLE_LOCKING)
302 {
303 if (!_winpr_openssl_initialize_locking())
304 {
305 return FALSE;
306 }
307 }
308
309#endif
310 /* SSL_load_error_strings() is void */
311#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
312 SSL_load_error_strings();
313 /* SSL_library_init() always returns "1" */
314 SSL_library_init();
315 OpenSSL_add_all_digests();
316 OpenSSL_add_all_ciphers();
317#else
318
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,
322 NULL) != 1)
323 return FALSE;
324
325#endif
326
327#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
328 /* The legacy provider is needed for MD4. */
329 s_winpr_openssl_provider_legacy = OSSL_PROVIDER_load(NULL, "legacy");
330 if (s_winpr_openssl_provider_legacy == NULL)
331 {
332 WLog_WARN(TAG, "OpenSSL LEGACY provider failed to load, no md4 support available!");
333 }
334 s_winpr_openssl_provider_default = OSSL_PROVIDER_load(NULL, "default");
335 if (s_winpr_openssl_provider_default == NULL)
336 {
337 WLog_WARN(TAG, "OpenSSL DEFAULT provider failed to load");
338 }
339#endif
340
341 (void)atexit(winpr_openssl_cleanup);
342 g_winpr_openssl_initialized_by_winpr = TRUE;
343 return TRUE;
344}
345
346/* exported functions */
347
348BOOL winpr_InitializeSSL(DWORD flags)
349{
350 static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
351
352 if (!InitOnceExecuteOnce(&once, winpr_openssl_initialize, &flags, NULL))
353 return FALSE;
354
355 return winpr_enable_fips(flags);
356}
357
358#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
359static int unload(OSSL_PROVIDER* provider, WINPR_ATTR_UNUSED void* data)
360{
361 if (!provider)
362 return 1;
363 const char* name = OSSL_PROVIDER_get0_name(provider);
364 if (!name)
365 return 1;
366
367 OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_get0_global_default();
368 const int rc = OSSL_PROVIDER_available(ctx, name);
369 if (rc < 1)
370 return 1;
371 OSSL_PROVIDER_unload(provider);
372 return 1;
373}
374#endif
375
376BOOL winpr_CleanupSSL(DWORD flags)
377{
378 if (flags & WINPR_SSL_CLEANUP_GLOBAL)
379 {
380 if (!g_winpr_openssl_initialized_by_winpr)
381 {
382 WLog_WARN(TAG, "ssl was not initialized by winpr");
383 return FALSE;
384 }
385
386 g_winpr_openssl_initialized_by_winpr = FALSE;
387#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
388 _winpr_openssl_cleanup_locking();
389#endif
390#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
391 CRYPTO_cleanup_all_ex_data();
392 ERR_free_strings();
393 EVP_cleanup();
394#endif
395#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
396 flags |= WINPR_SSL_CLEANUP_THREAD;
397#endif
398 }
399
400#ifdef WINPR_OPENSSL_LOCKING_REQUIRED
401
402 if (flags & WINPR_SSL_CLEANUP_THREAD)
403 {
404#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
405 ERR_remove_state(0);
406#else
407 ERR_remove_thread_state(NULL);
408#endif
409 }
410
411#endif
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);
415#endif
416
417 return TRUE;
418}
419
420BOOL winpr_FIPSMode(void)
421{
422#if (OPENSSL_VERSION_NUMBER < 0x10001000L) || defined(LIBRESSL_VERSION_NUMBER)
423 return FALSE;
424#elif defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
425 return (EVP_default_properties_is_fips_enabled(NULL) == 1);
426#else
427 return (FIPS_mode() == 1);
428#endif
429}
430
431#else
432
433BOOL winpr_InitializeSSL(DWORD flags)
434{
435 return TRUE;
436}
437
438BOOL winpr_CleanupSSL(DWORD flags)
439{
440 return TRUE;
441}
442
443BOOL winpr_FIPSMode(void)
444{
445 return FALSE;
446}
447
448#endif