FreeRDP
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 
41 static BOOL g_winpr_openssl_initialized_by_winpr = FALSE;
42 
43 #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
44 static OSSL_PROVIDER* s_winpr_openssl_provider_fips = NULL;
45 static OSSL_PROVIDER* s_winpr_openssl_provider_legacy = NULL;
46 static 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 
59 static int g_winpr_openssl_num_locks = 0;
60 static HANDLE* g_winpr_openssl_locks = NULL;
61 
62 struct CRYPTO_dynlock_value
63 {
64  HANDLE mutex;
65 };
66 
67 #if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
68 static unsigned long _winpr_openssl_id(void)
69 {
70  return (unsigned long)GetCurrentThreadId();
71 }
72 #endif
73 
74 static 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 
86 static 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 
102 static 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 
115 static 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 
122 static 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 
197 static 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 
244 static 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 failled 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 
284 static void winpr_openssl_cleanup(void)
285 {
286  winpr_CleanupSSL(WINPR_SSL_INIT_DEFAULT);
287 }
288 
289 static BOOL CALLBACK winpr_openssl_initialize(PINIT_ONCE once, PVOID param, PVOID* context)
290 {
291  DWORD flags = param ? *(PDWORD)param : WINPR_SSL_INIT_DEFAULT;
292 
293  if (flags & WINPR_SSL_INIT_ALREADY_INITIALIZED)
294  {
295  return TRUE;
296  }
297 
298 #ifdef WINPR_OPENSSL_LOCKING_REQUIRED
299 
300  if (flags & WINPR_SSL_INIT_ENABLE_LOCKING)
301  {
302  if (!_winpr_openssl_initialize_locking())
303  {
304  return FALSE;
305  }
306  }
307 
308 #endif
309  /* SSL_load_error_strings() is void */
310 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
311  SSL_load_error_strings();
312  /* SSL_library_init() always returns "1" */
313  SSL_library_init();
314  OpenSSL_add_all_digests();
315  OpenSSL_add_all_ciphers();
316 #else
317 
318  if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
319  OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS |
320  OPENSSL_INIT_ENGINE_ALL_BUILTIN,
321  NULL) != 1)
322  return FALSE;
323 
324 #endif
325 
326 #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
327  /* The legacy provider is needed for MD4. */
328  s_winpr_openssl_provider_legacy = OSSL_PROVIDER_load(NULL, "legacy");
329  if (s_winpr_openssl_provider_legacy == NULL)
330  {
331  WLog_WARN(TAG, "OpenSSL LEGACY provider failed to load, no md4 support available!");
332  }
333  s_winpr_openssl_provider_default = OSSL_PROVIDER_load(NULL, "default");
334  if (s_winpr_openssl_provider_default == NULL)
335  {
336  WLog_WARN(TAG, "OpenSSL DEFAULT provider failed to load");
337  }
338 #endif
339 
340  (void)atexit(winpr_openssl_cleanup);
341  g_winpr_openssl_initialized_by_winpr = TRUE;
342  return TRUE;
343 }
344 
345 /* exported functions */
346 
347 BOOL winpr_InitializeSSL(DWORD flags)
348 {
349  static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
350 
351  if (!InitOnceExecuteOnce(&once, winpr_openssl_initialize, &flags, NULL))
352  return FALSE;
353 
354  return winpr_enable_fips(flags);
355 }
356 
357 #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
358 static int unload(OSSL_PROVIDER* provider, void* data)
359 {
360  if (!provider)
361  return 1;
362  const char* name = OSSL_PROVIDER_get0_name(provider);
363  if (!name)
364  return 1;
365 
366  OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_get0_global_default();
367  const int rc = OSSL_PROVIDER_available(ctx, name);
368  if (rc < 1)
369  return 1;
370  OSSL_PROVIDER_unload(provider);
371  return 1;
372 }
373 #endif
374 
375 BOOL winpr_CleanupSSL(DWORD flags)
376 {
377  if (flags & WINPR_SSL_CLEANUP_GLOBAL)
378  {
379  if (!g_winpr_openssl_initialized_by_winpr)
380  {
381  WLog_WARN(TAG, "ssl was not initialized by winpr");
382  return FALSE;
383  }
384 
385  g_winpr_openssl_initialized_by_winpr = FALSE;
386 #ifdef WINPR_OPENSSL_LOCKING_REQUIRED
387  _winpr_openssl_cleanup_locking();
388 #endif
389 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
390  CRYPTO_cleanup_all_ex_data();
391  ERR_free_strings();
392  EVP_cleanup();
393 #endif
394 #ifdef WINPR_OPENSSL_LOCKING_REQUIRED
395  flags |= WINPR_SSL_CLEANUP_THREAD;
396 #endif
397  }
398 
399 #ifdef WINPR_OPENSSL_LOCKING_REQUIRED
400 
401  if (flags & WINPR_SSL_CLEANUP_THREAD)
402  {
403 #if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER)
404  ERR_remove_state(0);
405 #else
406  ERR_remove_thread_state(NULL);
407 #endif
408  }
409 
410 #endif
411 #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
412  OSSL_LIB_CTX* ctx = OSSL_LIB_CTX_get0_global_default();
413  OSSL_PROVIDER_do_all(ctx, unload, NULL);
414 #endif
415 
416  return TRUE;
417 }
418 
419 BOOL winpr_FIPSMode(void)
420 {
421 #if (OPENSSL_VERSION_NUMBER < 0x10001000L) || defined(LIBRESSL_VERSION_NUMBER)
422  return FALSE;
423 #elif defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
424  return (EVP_default_properties_is_fips_enabled(NULL) == 1);
425 #else
426  return (FIPS_mode() == 1);
427 #endif
428 }
429 
430 #else
431 
432 BOOL winpr_InitializeSSL(DWORD flags)
433 {
434  return TRUE;
435 }
436 
437 BOOL winpr_CleanupSSL(DWORD flags)
438 {
439  return TRUE;
440 }
441 
442 BOOL winpr_FIPSMode(void)
443 {
444  return FALSE;
445 }
446 
447 #endif