xref: /reactos/dll/win32/bcrypt/bcrypt_main.c (revision c3e0df06)
1 /*
2  * Copyright 2009 Henri Verbeet for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  */
19 
20 #include <wine/config.h>
21 #include <wine/port.h>
22 
23 #include <ntstatus.h>
24 #define WIN32_NO_STATUS
25 #include <windef.h>
26 #include <winbase.h>
27 #include <ntsecapi.h>
28 #include <bcrypt.h>
29 
30 #include <wine/debug.h>
31 #include <wine/unicode.h>
32 #include <wine/library.h>
33 
34 #ifdef SONAME_LIBMBEDTLS
35 #include <mbedtls/md.h>
36 #include <mbedtls/md5.h>
37 #include <mbedtls/sha1.h>
38 #include <mbedtls/sha256.h>
39 #include <mbedtls/sha512.h>
40 #endif
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt);
43 
44 static HINSTANCE instance;
45 
46 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
47 WINE_DECLARE_DEBUG_CHANNEL(winediag);
48 
49 static void *libgnutls_handle;
50 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
51 MAKE_FUNCPTR(gnutls_global_deinit);
52 MAKE_FUNCPTR(gnutls_global_init);
53 MAKE_FUNCPTR(gnutls_global_set_log_function);
54 MAKE_FUNCPTR(gnutls_global_set_log_level);
55 MAKE_FUNCPTR(gnutls_hash);
56 MAKE_FUNCPTR(gnutls_hash_deinit);
57 MAKE_FUNCPTR(gnutls_hash_init);
58 MAKE_FUNCPTR(gnutls_hmac);
59 MAKE_FUNCPTR(gnutls_hmac_deinit);
60 MAKE_FUNCPTR(gnutls_hmac_init);
61 MAKE_FUNCPTR(gnutls_perror);
62 #undef MAKE_FUNCPTR
63 
gnutls_log(int level,const char * msg)64 static void gnutls_log( int level, const char *msg )
65 {
66     TRACE( "<%d> %s", level, msg );
67 }
68 
gnutls_initialize(void)69 static BOOL gnutls_initialize(void)
70 {
71     int ret;
72 
73     if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
74     {
75         ERR_(winediag)( "failed to load libgnutls, no support for crypto hashes\n" );
76         return FALSE;
77     }
78 
79 #define LOAD_FUNCPTR(f) \
80     if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
81     { \
82         ERR( "failed to load %s\n", #f ); \
83         goto fail; \
84     }
85 
86     LOAD_FUNCPTR(gnutls_global_deinit)
87     LOAD_FUNCPTR(gnutls_global_init)
88     LOAD_FUNCPTR(gnutls_global_set_log_function)
89     LOAD_FUNCPTR(gnutls_global_set_log_level)
90     LOAD_FUNCPTR(gnutls_hash);
91     LOAD_FUNCPTR(gnutls_hash_deinit);
92     LOAD_FUNCPTR(gnutls_hash_init);
93     LOAD_FUNCPTR(gnutls_hmac);
94     LOAD_FUNCPTR(gnutls_hmac_deinit);
95     LOAD_FUNCPTR(gnutls_hmac_init);
96     LOAD_FUNCPTR(gnutls_perror)
97 #undef LOAD_FUNCPTR
98 
99     if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
100     {
101         pgnutls_perror( ret );
102         goto fail;
103     }
104 
105     if (TRACE_ON( bcrypt ))
106     {
107         pgnutls_global_set_log_level( 4 );
108         pgnutls_global_set_log_function( gnutls_log );
109     }
110 
111     return TRUE;
112 
113 fail:
114     wine_dlclose( libgnutls_handle, NULL, 0 );
115     libgnutls_handle = NULL;
116     return FALSE;
117 }
118 
gnutls_uninitialize(void)119 static void gnutls_uninitialize(void)
120 {
121     pgnutls_global_deinit();
122     wine_dlclose( libgnutls_handle, NULL, 0 );
123     libgnutls_handle = NULL;
124 }
125 #elif defined(SONAME_LIBMBEDTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H) && !defined(__REACTOS__)
126 WINE_DECLARE_DEBUG_CHANNEL(winediag);
127 
128 void *libmbedtls_handle;
129 
130 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
131 MAKE_FUNCPTR(mbedtls_md_init);
132 MAKE_FUNCPTR(mbedtls_md_setup);
133 MAKE_FUNCPTR(mbedtls_md_update);
134 MAKE_FUNCPTR(mbedtls_md_hmac_starts);
135 MAKE_FUNCPTR(mbedtls_md_hmac_finish);
136 MAKE_FUNCPTR(mbedtls_md_free);
137 MAKE_FUNCPTR(mbedtls_md5_init);
138 MAKE_FUNCPTR(mbedtls_md5_starts);
139 MAKE_FUNCPTR(mbedtls_md5_update);
140 MAKE_FUNCPTR(mbedtls_md5_finish);
141 MAKE_FUNCPTR(mbedtls_md5_free);
142 MAKE_FUNCPTR(mbedtls_sha1_init);
143 MAKE_FUNCPTR(mbedtls_sha1_starts);
144 MAKE_FUNCPTR(mbedtls_sha1_update);
145 MAKE_FUNCPTR(mbedtls_sha1_finish);
146 MAKE_FUNCPTR(mbedtls_sha1_free);
147 MAKE_FUNCPTR(mbedtls_sha256_init);
148 MAKE_FUNCPTR(mbedtls_sha256_starts);
149 MAKE_FUNCPTR(mbedtls_sha256_update);
150 MAKE_FUNCPTR(mbedtls_sha256_finish);
151 MAKE_FUNCPTR(mbedtls_sha256_free);
152 MAKE_FUNCPTR(mbedtls_sha512_init);
153 MAKE_FUNCPTR(mbedtls_sha512_starts);
154 MAKE_FUNCPTR(mbedtls_sha512_update);
155 MAKE_FUNCPTR(mbedtls_sha512_finish);
156 MAKE_FUNCPTR(mbedtls_sha512_free);
157 #undef MAKE_FUNCPTR
158 
159 #define mbedtls_md_init             pmbedtls_md_init
160 #define mbedtls_md_setup            pmbedtls_md_setup
161 #define mbedtls_md_update           pmbedtls_md_update
162 #define mbedtls_md_hmac_starts      pmbedtls_md_hmac_starts
163 #define mbedtls_md_hmac_finish      pmbedtls_md_hmac_finish
164 #define mbedtls_md_free             pmbedtls_md_free
165 #define mbedtls_md5_init            pmbedtls_md5_init
166 #define mbedtls_md5_starts          pmbedtls_md5_starts
167 #define mbedtls_md5_update          pmbedtls_md5_update
168 #define mbedtls_md5_finish          pmbedtls_md5_finish
169 #define mbedtls_md5_free            pmbedtls_md5_free
170 #define mbedtls_sha1_init           pmbedtls_sha1_init
171 #define mbedtls_sha1_starts         pmbedtls_sha1_starts
172 #define mbedtls_sha1_update         pmbedtls_sha1_update
173 #define mbedtls_sha1_finish         pmbedtls_sha1_finish
174 #define mbedtls_sha1_free           pmbedtls_sha1_free
175 #define mbedtls_sha256_init         pmbedtls_sha256_init
176 #define mbedtls_sha256_starts       pmbedtls_sha256_starts
177 #define mbedtls_sha256_update       pmbedtls_sha256_update
178 #define mbedtls_sha256_finish       pmbedtls_sha256_finish
179 #define mbedtls_sha256_free         pmbedtls_sha256_free
180 #define mbedtls_sha512_init         pmbedtls_sha512_init
181 #define mbedtls_sha512_starts       pmbedtls_sha512_starts
182 #define mbedtls_sha512_update       pmbedtls_sha512_update
183 #define mbedtls_sha512_finish       pmbedtls_sha512_finish
184 #define mbedtls_sha512_free         pmbedtls_sha512_free
185 
mbedtls_initialize(void)186 static BOOL mbedtls_initialize(void)
187 {
188     if (!(libmbedtls_handle = wine_dlopen( SONAME_LIBMBEDTLS, RTLD_NOW, NULL, 0 )))
189     {
190         ERR_(winediag)( "failed to load libmbedtls, no support for crypto hashes\n" );
191         return FALSE;
192     }
193 
194 #define LOAD_FUNCPTR(f) \
195     if (!(p##f = wine_dlsym( libmbedtls_handle, #f, NULL, 0 ))) \
196     { \
197         ERR( "failed to load %s\n", #f ); \
198         goto fail; \
199     }
200 
201     LOAD_FUNCPTR(mbedtls_md_init)
202     LOAD_FUNCPTR(mbedtls_md_setup)
203     LOAD_FUNCPTR(mbedtls_md_update)
204     LOAD_FUNCPTR(mbedtls_md_hmac_starts)
205     LOAD_FUNCPTR(mbedtls_md_hmac_finish)
206     LOAD_FUNCPTR(mbedtls_md_free);
207     LOAD_FUNCPTR(mbedtls_md5_init)
208     LOAD_FUNCPTR(mbedtls_md5_starts)
209     LOAD_FUNCPTR(mbedtls_md5_update)
210     LOAD_FUNCPTR(mbedtls_md5_finish)
211     LOAD_FUNCPTR(mbedtls_md5_free);
212     LOAD_FUNCPTR(mbedtls_sha1_init)
213     LOAD_FUNCPTR(mbedtls_sha1_starts)
214     LOAD_FUNCPTR(mbedtls_sha1_update)
215     LOAD_FUNCPTR(mbedtls_sha1_finish)
216     LOAD_FUNCPTR(mbedtls_sha1_free);
217     LOAD_FUNCPTR(mbedtls_sha256_init)
218     LOAD_FUNCPTR(mbedtls_sha256_starts)
219     LOAD_FUNCPTR(mbedtls_sha256_update)
220     LOAD_FUNCPTR(mbedtls_sha256_finish)
221     LOAD_FUNCPTR(mbedtls_sha256_free);
222     LOAD_FUNCPTR(mbedtls_sha512_init)
223     LOAD_FUNCPTR(mbedtls_sha512_starts)
224     LOAD_FUNCPTR(mbedtls_sha512_update)
225     LOAD_FUNCPTR(mbedtls_sha512_finish)
226     LOAD_FUNCPTR(mbedtls_sha512_free);
227 #undef LOAD_FUNCPTR
228 
229     return TRUE;
230 
231 fail:
232     wine_dlclose( libmbedtls_handle, NULL, 0 );
233     libmbedtls_handle = NULL;
234     return FALSE;
235 }
236 
mbedtls_uninitialize(void)237 static void mbedtls_uninitialize(void)
238 {
239     wine_dlclose( libmbedtls_handle, NULL, 0 );
240     libmbedtls_handle = NULL;
241 }
242 #endif /* SONAME_LIBMBEDTLS && !HAVE_COMMONCRYPTO_COMMONDIGEST_H && !__REACTOS__ */
243 
BCryptEnumAlgorithms(ULONG dwAlgOperations,ULONG * pAlgCount,BCRYPT_ALGORITHM_IDENTIFIER ** ppAlgList,ULONG dwFlags)244 NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
245                                      BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
246 {
247     FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
248 
249     *ppAlgList=NULL;
250     *pAlgCount=0;
251 
252     return STATUS_NOT_IMPLEMENTED;
253 }
254 
255 #define MAGIC_ALG  (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
256 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
257 struct object
258 {
259     ULONG magic;
260 };
261 
262 enum alg_id
263 {
264     ALG_ID_MD5,
265     ALG_ID_RNG,
266     ALG_ID_SHA1,
267     ALG_ID_SHA256,
268     ALG_ID_SHA384,
269     ALG_ID_SHA512,
270     ALG_ID_ECDSA_P256,
271     ALG_ID_ECDSA_P384,
272 };
273 
274 static const struct {
275     ULONG hash_length;
276     const WCHAR *alg_name;
277 } alg_props[] = {
278     /* ALG_ID_MD5    */ { 16, BCRYPT_MD5_ALGORITHM },
279     /* ALG_ID_RNG    */ {  0, BCRYPT_RNG_ALGORITHM },
280     /* ALG_ID_SHA1   */ { 20, BCRYPT_SHA1_ALGORITHM },
281     /* ALG_ID_SHA256 */ { 32, BCRYPT_SHA256_ALGORITHM },
282     /* ALG_ID_SHA384 */ { 48, BCRYPT_SHA384_ALGORITHM },
283     /* ALG_ID_SHA512 */ { 64, BCRYPT_SHA512_ALGORITHM },
284     /* ALG_ID_ECDSA_P256 */ { 0, BCRYPT_ECDSA_P256_ALGORITHM },
285     /* ALG_ID_ECDSA_P384 */ { 0, BCRYPT_ECDSA_P384_ALGORITHM },
286 };
287 
288 struct algorithm
289 {
290     struct object hdr;
291     enum alg_id   id;
292     BOOL hmac;
293 };
294 
BCryptGenRandom(BCRYPT_ALG_HANDLE handle,UCHAR * buffer,ULONG count,ULONG flags)295 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
296 {
297     const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
298     struct algorithm *algorithm = handle;
299 
300     TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
301 
302     if (!algorithm)
303     {
304         /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
305          * is set. In this case the preferred system RNG is used.
306          */
307         if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
308             return STATUS_INVALID_HANDLE;
309     }
310     else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
311         return STATUS_INVALID_HANDLE;
312 
313     if (!buffer)
314         return STATUS_INVALID_PARAMETER;
315 
316     if (flags & ~supported_flags)
317         FIXME("unsupported flags %08x\n", flags & ~supported_flags);
318 
319     if (algorithm)
320         FIXME("ignoring selected algorithm\n");
321 
322     /* When zero bytes are requested the function returns success too. */
323     if (!count)
324         return STATUS_SUCCESS;
325 
326     if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
327     {
328         if (RtlGenRandom(buffer, count))
329             return STATUS_SUCCESS;
330     }
331 
332     FIXME("called with unsupported parameters, returning error\n");
333     return STATUS_NOT_IMPLEMENTED;
334 }
335 
BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE * handle,LPCWSTR id,LPCWSTR implementation,DWORD flags)336 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
337 {
338     struct algorithm *alg;
339     enum alg_id alg_id;
340 
341     const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
342 
343     TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
344 
345     if (!handle || !id) return STATUS_INVALID_PARAMETER;
346     if (flags & ~supported_flags)
347     {
348         FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
349         return STATUS_NOT_IMPLEMENTED;
350     }
351 
352     if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
353     else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
354     else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG;
355     else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
356     else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
357     else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
358     else if (!strcmpW( id, BCRYPT_ECDSA_P256_ALGORITHM )) alg_id = ALG_ID_ECDSA_P256;
359     else if (!strcmpW( id, BCRYPT_ECDSA_P384_ALGORITHM )) alg_id = ALG_ID_ECDSA_P384;
360     else
361     {
362         FIXME( "algorithm %s not supported\n", debugstr_w(id) );
363         return STATUS_NOT_IMPLEMENTED;
364     }
365     if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
366     {
367         FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
368         return STATUS_NOT_IMPLEMENTED;
369     }
370 
371     if (!(alg = HeapAlloc( GetProcessHeap(), 0, sizeof(*alg) ))) return STATUS_NO_MEMORY;
372     alg->hdr.magic = MAGIC_ALG;
373     alg->id        = alg_id;
374     alg->hmac      = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
375 
376     *handle = alg;
377     return STATUS_SUCCESS;
378 }
379 
BCryptCloseAlgorithmProvider(BCRYPT_ALG_HANDLE handle,DWORD flags)380 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
381 {
382     struct algorithm *alg = handle;
383 
384     TRACE( "%p, %08x\n", handle, flags );
385 
386     if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
387     HeapFree( GetProcessHeap(), 0, alg );
388     return STATUS_SUCCESS;
389 }
390 
BCryptGetFipsAlgorithmMode(BOOLEAN * enabled)391 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
392 {
393     FIXME("%p - semi-stub\n", enabled);
394 
395     if (!enabled)
396         return STATUS_INVALID_PARAMETER;
397 
398     *enabled = FALSE;
399     return STATUS_SUCCESS;
400 }
401 
402 #ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H
403 struct hash
404 {
405     struct object hdr;
406     enum alg_id   alg_id;
407     BOOL hmac;
408     union
409     {
410         CC_MD5_CTX    md5_ctx;
411         CC_SHA1_CTX   sha1_ctx;
412         CC_SHA256_CTX sha256_ctx;
413         CC_SHA512_CTX sha512_ctx;
414         CCHmacContext hmac_ctx;
415     } u;
416 };
417 
hash_init(struct hash * hash)418 static NTSTATUS hash_init( struct hash *hash )
419 {
420     switch (hash->alg_id)
421     {
422     case ALG_ID_MD5:
423         CC_MD5_Init( &hash->u.md5_ctx );
424         break;
425 
426     case ALG_ID_SHA1:
427         CC_SHA1_Init( &hash->u.sha1_ctx );
428         break;
429 
430     case ALG_ID_SHA256:
431         CC_SHA256_Init( &hash->u.sha256_ctx );
432         break;
433 
434     case ALG_ID_SHA384:
435         CC_SHA384_Init( &hash->u.sha512_ctx );
436         break;
437 
438     case ALG_ID_SHA512:
439         CC_SHA512_Init( &hash->u.sha512_ctx );
440         break;
441 
442     default:
443         ERR( "unhandled id %u\n", hash->alg_id );
444         return STATUS_NOT_IMPLEMENTED;
445     }
446     return STATUS_SUCCESS;
447 }
448 
hmac_init(struct hash * hash,UCHAR * key,ULONG key_size)449 static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size )
450 {
451     CCHmacAlgorithm cc_algorithm;
452     switch (hash->alg_id)
453     {
454     case ALG_ID_MD5:
455         cc_algorithm = kCCHmacAlgMD5;
456         break;
457 
458     case ALG_ID_SHA1:
459         cc_algorithm = kCCHmacAlgSHA1;
460         break;
461 
462     case ALG_ID_SHA256:
463         cc_algorithm = kCCHmacAlgSHA256;
464         break;
465 
466     case ALG_ID_SHA384:
467         cc_algorithm = kCCHmacAlgSHA384;
468         break;
469 
470     case ALG_ID_SHA512:
471         cc_algorithm = kCCHmacAlgSHA512;
472         break;
473 
474     default:
475         ERR( "unhandled id %u\n", hash->alg_id );
476         return STATUS_NOT_IMPLEMENTED;
477     }
478 
479     CCHmacInit( &hash->u.hmac_ctx, cc_algorithm, key, key_size );
480     return STATUS_SUCCESS;
481 }
482 
483 
hash_update(struct hash * hash,UCHAR * input,ULONG size)484 static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
485 {
486     switch (hash->alg_id)
487     {
488     case ALG_ID_MD5:
489         CC_MD5_Update( &hash->u.md5_ctx, input, size );
490         break;
491 
492     case ALG_ID_SHA1:
493         CC_SHA1_Update( &hash->u.sha1_ctx, input, size );
494         break;
495 
496     case ALG_ID_SHA256:
497         CC_SHA256_Update( &hash->u.sha256_ctx, input, size );
498         break;
499 
500     case ALG_ID_SHA384:
501         CC_SHA384_Update( &hash->u.sha512_ctx, input, size );
502         break;
503 
504     case ALG_ID_SHA512:
505         CC_SHA512_Update( &hash->u.sha512_ctx, input, size );
506         break;
507 
508     default:
509         ERR( "unhandled id %u\n", hash->alg_id );
510         return STATUS_NOT_IMPLEMENTED;
511     }
512     return STATUS_SUCCESS;
513 }
514 
hmac_update(struct hash * hash,UCHAR * input,ULONG size)515 static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size )
516 {
517     CCHmacUpdate( &hash->u.hmac_ctx, input, size );
518     return STATUS_SUCCESS;
519 }
520 
hash_finish(struct hash * hash,UCHAR * output,ULONG size)521 static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
522 {
523     switch (hash->alg_id)
524     {
525     case ALG_ID_MD5:
526         CC_MD5_Final( output, &hash->u.md5_ctx );
527         break;
528 
529     case ALG_ID_SHA1:
530         CC_SHA1_Final( output, &hash->u.sha1_ctx );
531         break;
532 
533     case ALG_ID_SHA256:
534         CC_SHA256_Final( output, &hash->u.sha256_ctx );
535         break;
536 
537     case ALG_ID_SHA384:
538         CC_SHA384_Final( output, &hash->u.sha512_ctx );
539         break;
540 
541     case ALG_ID_SHA512:
542         CC_SHA512_Final( output, &hash->u.sha512_ctx );
543         break;
544 
545     default:
546         ERR( "unhandled id %u\n", hash->alg_id );
547         break;
548     }
549     return STATUS_SUCCESS;
550 }
551 
hmac_finish(struct hash * hash,UCHAR * output,ULONG size)552 static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size )
553 {
554     CCHmacFinal( &hash->u.hmac_ctx, output );
555 
556     return STATUS_SUCCESS;
557 }
558 #elif defined(HAVE_GNUTLS_HASH)
559 struct hash
560 {
561     struct object    hdr;
562     enum alg_id      alg_id;
563     BOOL hmac;
564     union
565     {
566         gnutls_hash_hd_t hash_handle;
567         gnutls_hmac_hd_t hmac_handle;
568     } u;
569 };
570 
hash_init(struct hash * hash)571 static NTSTATUS hash_init( struct hash *hash )
572 {
573     gnutls_digest_algorithm_t alg;
574 
575     if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
576 
577     switch (hash->alg_id)
578     {
579     case ALG_ID_MD5:
580         alg = GNUTLS_DIG_MD5;
581         break;
582     case ALG_ID_SHA1:
583         alg = GNUTLS_DIG_SHA1;
584         break;
585 
586     case ALG_ID_SHA256:
587         alg = GNUTLS_DIG_SHA256;
588         break;
589 
590     case ALG_ID_SHA384:
591         alg = GNUTLS_DIG_SHA384;
592         break;
593 
594     case ALG_ID_SHA512:
595         alg = GNUTLS_DIG_SHA512;
596         break;
597 
598     default:
599         ERR( "unhandled id %u\n", hash->alg_id );
600         return STATUS_NOT_IMPLEMENTED;
601     }
602 
603     if (pgnutls_hash_init( &hash->u.hash_handle, alg )) return STATUS_INTERNAL_ERROR;
604     return STATUS_SUCCESS;
605 }
606 
hmac_init(struct hash * hash,UCHAR * key,ULONG key_size)607 static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size )
608 {
609     gnutls_mac_algorithm_t alg;
610 
611     if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
612 
613     switch (hash->alg_id)
614     {
615     case ALG_ID_MD5:
616         alg = GNUTLS_MAC_MD5;
617         break;
618     case ALG_ID_SHA1:
619         alg = GNUTLS_MAC_SHA1;
620         break;
621 
622     case ALG_ID_SHA256:
623         alg = GNUTLS_MAC_SHA256;
624         break;
625 
626     case ALG_ID_SHA384:
627         alg = GNUTLS_MAC_SHA384;
628         break;
629 
630     case ALG_ID_SHA512:
631         alg = GNUTLS_MAC_SHA512;
632         break;
633 
634     default:
635         ERR( "unhandled id %u\n", hash->alg_id );
636         return STATUS_NOT_IMPLEMENTED;
637     }
638 
639     if (pgnutls_hmac_init( &hash->u.hmac_handle, alg, key, key_size )) return STATUS_INTERNAL_ERROR;
640     return STATUS_SUCCESS;
641 }
642 
hash_update(struct hash * hash,UCHAR * input,ULONG size)643 static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
644 {
645     if (pgnutls_hash( hash->u.hash_handle, input, size )) return STATUS_INTERNAL_ERROR;
646     return STATUS_SUCCESS;
647 }
648 
hmac_update(struct hash * hash,UCHAR * input,ULONG size)649 static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size )
650 {
651     if (pgnutls_hmac( hash->u.hmac_handle, input, size )) return STATUS_INTERNAL_ERROR;
652     return STATUS_SUCCESS;
653 }
654 
hash_finish(struct hash * hash,UCHAR * output,ULONG size)655 static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
656 {
657     pgnutls_hash_deinit( hash->u.hash_handle, output );
658     return STATUS_SUCCESS;
659 }
660 
hmac_finish(struct hash * hash,UCHAR * output,ULONG size)661 static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size )
662 {
663     pgnutls_hmac_deinit( hash->u.hmac_handle, output );
664     return STATUS_SUCCESS;
665 }
666 #elif defined(SONAME_LIBMBEDTLS)
667 struct hash
668 {
669     struct object hdr;
670     BOOL hmac;
671     enum alg_id   alg_id;
672     union
673     {
674         mbedtls_md5_context    md5_ctx;
675         mbedtls_sha1_context   sha1_ctx;
676         mbedtls_sha256_context sha256_ctx;
677         mbedtls_sha512_context sha512_ctx;
678         mbedtls_md_context_t   hmac_ctx;
679     } u;
680 };
681 
hash_init(struct hash * hash)682 static NTSTATUS hash_init( struct hash *hash )
683 {
684 #ifndef __REACTOS__
685     if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
686 #endif
687     switch (hash->alg_id)
688     {
689     case ALG_ID_MD5:
690         mbedtls_md5_init(&hash->u.md5_ctx);
691         mbedtls_md5_starts(&hash->u.md5_ctx);
692         break;
693 
694     case ALG_ID_SHA1:
695         mbedtls_sha1_init(&hash->u.sha1_ctx);
696         mbedtls_sha1_starts(&hash->u.sha1_ctx);
697         break;
698 
699     case ALG_ID_SHA256:
700         mbedtls_sha256_init(&hash->u.sha256_ctx);
701         mbedtls_sha256_starts(&hash->u.sha256_ctx, FALSE);
702         break;
703 
704     case ALG_ID_SHA384:
705     case ALG_ID_SHA512:
706         mbedtls_sha512_init(&hash->u.sha512_ctx);
707         mbedtls_sha512_starts(&hash->u.sha512_ctx, hash->alg_id==ALG_ID_SHA384);
708         break;
709 
710     default:
711         ERR( "unhandled id %u\n", hash->alg_id );
712         return STATUS_NOT_IMPLEMENTED;
713     }
714 
715     return STATUS_SUCCESS;
716 }
717 
hmac_init(struct hash * hash,UCHAR * key,ULONG key_size)718 static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size )
719 {
720     const mbedtls_md_info_t *md_info;
721     mbedtls_md_type_t md_type;
722     int ret;
723 #ifndef __REACTOS__
724     if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
725 #endif
726     mbedtls_md_init(&hash->u.hmac_ctx);
727     switch (hash->alg_id)
728     {
729     case ALG_ID_MD5:
730         md_type = MBEDTLS_MD_MD5;
731         break;
732 
733     case ALG_ID_SHA1:
734         md_type = MBEDTLS_MD_SHA1;
735         break;
736 
737     case ALG_ID_SHA256:
738         md_type = MBEDTLS_MD_SHA256;
739         break;
740 
741     case ALG_ID_SHA384:
742         md_type = MBEDTLS_MD_SHA384;
743         break;
744 
745     case ALG_ID_SHA512:
746         md_type = MBEDTLS_MD_SHA512;
747         break;
748 
749     default:
750         ERR("unhandled id %u\n", hash->alg_id);
751         return STATUS_NOT_IMPLEMENTED;
752     }
753     if ((md_info = mbedtls_md_info_from_type(md_type)) == NULL)
754     {
755         mbedtls_md_free(&hash->u.hmac_ctx);
756         return STATUS_INTERNAL_ERROR;
757     }
758 
759     if ((ret = mbedtls_md_setup(&hash->u.hmac_ctx, md_info, 1)) != 0)
760     {
761         mbedtls_md_free(&hash->u.hmac_ctx);
762         return STATUS_INTERNAL_ERROR;
763     }
764 
765     mbedtls_md_hmac_starts(&hash->u.hmac_ctx, key, key_size);
766 
767     return STATUS_SUCCESS;
768 }
769 
hash_update(struct hash * hash,UCHAR * input,ULONG size)770 static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
771 {
772 #ifndef __REACTOS__
773     if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
774 #endif
775     switch (hash->alg_id)
776     {
777     case ALG_ID_MD5:
778         mbedtls_md5_update(&hash->u.md5_ctx, input, size);
779         break;
780 
781     case ALG_ID_SHA1:
782         mbedtls_sha1_update(&hash->u.sha1_ctx, input, size);
783         break;
784 
785     case ALG_ID_SHA256:
786         mbedtls_sha256_update(&hash->u.sha256_ctx, input, size);
787         break;
788 
789     case ALG_ID_SHA384:
790     case ALG_ID_SHA512:
791         mbedtls_sha512_update(&hash->u.sha512_ctx, input, size);
792         break;
793 
794     default:
795         ERR( "unhandled id %u\n", hash->alg_id );
796         return STATUS_NOT_IMPLEMENTED;
797     }
798 
799     return STATUS_SUCCESS;
800 }
801 
hmac_update(struct hash * hash,UCHAR * input,ULONG size)802 static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size )
803 {
804 #ifndef __REACTOS__
805     if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
806 #endif
807     mbedtls_md_update(&hash->u.hmac_ctx, input, size);
808 
809     return STATUS_SUCCESS;
810 }
811 
hash_finish(struct hash * hash,UCHAR * output,ULONG size)812 static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
813 {
814 #ifndef __REACTOS__
815     if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
816 #endif
817     switch (hash->alg_id)
818     {
819     case ALG_ID_MD5:
820         mbedtls_md5_finish(&hash->u.md5_ctx, output);
821         mbedtls_md5_free(&hash->u.md5_ctx);
822         break;
823 
824     case ALG_ID_SHA1:
825         mbedtls_sha1_finish(&hash->u.sha1_ctx, output);
826         mbedtls_sha1_free(&hash->u.sha1_ctx);
827         break;
828 
829     case ALG_ID_SHA256:
830         mbedtls_sha256_finish(&hash->u.sha256_ctx, output);
831         mbedtls_sha256_free(&hash->u.sha256_ctx);
832         break;
833 
834     case ALG_ID_SHA384:
835     case ALG_ID_SHA512:
836         mbedtls_sha512_finish(&hash->u.sha512_ctx, output);
837         mbedtls_sha512_free(&hash->u.sha512_ctx);
838         break;
839 
840     default:
841         ERR( "unhandled id %u\n", hash->alg_id );
842         return STATUS_NOT_IMPLEMENTED;
843     }
844 
845     return STATUS_SUCCESS;
846 }
847 
hmac_finish(struct hash * hash,UCHAR * output,ULONG size)848 static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size )
849 {
850 #ifndef __REACTOS__
851     if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
852 #endif
853     mbedtls_md_hmac_finish(&hash->u.hmac_ctx, output);
854     mbedtls_md_free(&hash->u.hmac_ctx);
855 
856     return STATUS_SUCCESS;
857 }
858 #endif
859 
860 #define OBJECT_LENGTH_MD5       274
861 #define OBJECT_LENGTH_SHA1      278
862 #define OBJECT_LENGTH_SHA256    286
863 #define OBJECT_LENGTH_SHA384    382
864 #define OBJECT_LENGTH_SHA512    382
865 
generic_alg_property(enum alg_id id,const WCHAR * prop,UCHAR * buf,ULONG size,ULONG * ret_size)866 static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
867 {
868     if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
869     {
870         *ret_size = sizeof(ULONG);
871         if (size < sizeof(ULONG))
872             return STATUS_BUFFER_TOO_SMALL;
873         if(buf)
874             *(ULONG*)buf = alg_props[id].hash_length;
875         return STATUS_SUCCESS;
876     }
877 
878     if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
879     {
880         *ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
881         if (size < *ret_size)
882             return STATUS_BUFFER_TOO_SMALL;
883         if(buf)
884             memcpy(buf, alg_props[id].alg_name, *ret_size);
885         return STATUS_SUCCESS;
886     }
887 
888     return STATUS_NOT_IMPLEMENTED;
889 }
890 
get_alg_property(enum alg_id id,const WCHAR * prop,UCHAR * buf,ULONG size,ULONG * ret_size)891 static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
892 {
893     NTSTATUS status;
894     ULONG value;
895 
896     status = generic_alg_property( id, prop, buf, size, ret_size );
897     if (status != STATUS_NOT_IMPLEMENTED)
898         return status;
899 
900     switch (id)
901     {
902     case ALG_ID_MD5:
903         if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
904         {
905             value = OBJECT_LENGTH_MD5;
906             break;
907         }
908         FIXME( "unsupported md5 algorithm property %s\n", debugstr_w(prop) );
909         return STATUS_NOT_IMPLEMENTED;
910 
911     case ALG_ID_RNG:
912         if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH )) return STATUS_NOT_SUPPORTED;
913         FIXME( "unsupported rng algorithm property %s\n", debugstr_w(prop) );
914         return STATUS_NOT_IMPLEMENTED;
915 
916     case ALG_ID_SHA1:
917         if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
918         {
919             value = OBJECT_LENGTH_SHA1;
920             break;
921         }
922         FIXME( "unsupported sha1 algorithm property %s\n", debugstr_w(prop) );
923         return STATUS_NOT_IMPLEMENTED;
924 
925     case ALG_ID_SHA256:
926         if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
927         {
928             value = OBJECT_LENGTH_SHA256;
929             break;
930         }
931         FIXME( "unsupported sha256 algorithm property %s\n", debugstr_w(prop) );
932         return STATUS_NOT_IMPLEMENTED;
933 
934     case ALG_ID_SHA384:
935         if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
936         {
937             value = OBJECT_LENGTH_SHA384;
938             break;
939         }
940         FIXME( "unsupported sha384 algorithm property %s\n", debugstr_w(prop) );
941         return STATUS_NOT_IMPLEMENTED;
942 
943     case ALG_ID_SHA512:
944         if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
945         {
946             value = OBJECT_LENGTH_SHA512;
947             break;
948         }
949         FIXME( "unsupported sha512 algorithm property %s\n", debugstr_w(prop) );
950         return STATUS_NOT_IMPLEMENTED;
951 
952     default:
953         FIXME( "unsupported algorithm %u\n", id );
954         return STATUS_NOT_IMPLEMENTED;
955     }
956 
957     if (size < sizeof(ULONG))
958     {
959         *ret_size = sizeof(ULONG);
960         return STATUS_BUFFER_TOO_SMALL;
961     }
962     if (buf) *(ULONG *)buf = value;
963     *ret_size = sizeof(ULONG);
964 
965     return STATUS_SUCCESS;
966 }
967 
get_hash_property(enum alg_id id,const WCHAR * prop,UCHAR * buf,ULONG size,ULONG * ret_size)968 static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
969 {
970     NTSTATUS status;
971 
972     status = generic_alg_property( id, prop, buf, size, ret_size );
973     if (status == STATUS_NOT_IMPLEMENTED)
974         FIXME( "unsupported property %s\n", debugstr_w(prop) );
975     return status;
976 }
977 
BCryptGetProperty(BCRYPT_HANDLE handle,LPCWSTR prop,UCHAR * buffer,ULONG count,ULONG * res,ULONG flags)978 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
979 {
980     struct object *object = handle;
981 
982     TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
983 
984     if (!object) return STATUS_INVALID_HANDLE;
985     if (!prop || !res) return STATUS_INVALID_PARAMETER;
986 
987     switch (object->magic)
988     {
989     case MAGIC_ALG:
990     {
991         const struct algorithm *alg = (const struct algorithm *)object;
992         return get_alg_property( alg->id, prop, buffer, count, res );
993     }
994     case MAGIC_HASH:
995     {
996         const struct hash *hash = (const struct hash *)object;
997         return get_hash_property( hash->alg_id, prop, buffer, count, res );
998     }
999     default:
1000         WARN( "unknown magic %08x\n", object->magic );
1001         return STATUS_INVALID_HANDLE;
1002     }
1003 }
1004 
BCryptCreateHash(BCRYPT_ALG_HANDLE algorithm,BCRYPT_HASH_HANDLE * handle,UCHAR * object,ULONG objectlen,UCHAR * secret,ULONG secretlen,ULONG flags)1005 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
1006                                   UCHAR *secret, ULONG secretlen, ULONG flags )
1007 {
1008     struct algorithm *alg = algorithm;
1009     struct hash *hash;
1010     NTSTATUS status;
1011 
1012     TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
1013            secret, secretlen, flags );
1014     if (flags)
1015     {
1016         FIXME( "unimplemented flags %08x\n", flags );
1017         return STATUS_NOT_IMPLEMENTED;
1018     }
1019 
1020     if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
1021     if (object) FIXME( "ignoring object buffer\n" );
1022 
1023     if (!(hash = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash) ))) return STATUS_NO_MEMORY;
1024     hash->hdr.magic = MAGIC_HASH;
1025     hash->alg_id    = alg->id;
1026     hash->hmac      = alg->hmac;
1027 
1028     if (hash->hmac)
1029     {
1030         status = hmac_init( hash, secret, secretlen );
1031     }
1032     else
1033     {
1034         status = hash_init( hash );
1035     }
1036 
1037     if (status != STATUS_SUCCESS)
1038     {
1039         HeapFree( GetProcessHeap(), 0, hash );
1040         return status;
1041     }
1042 
1043     *handle = hash;
1044     return STATUS_SUCCESS;
1045 }
1046 
BCryptDestroyHash(BCRYPT_HASH_HANDLE handle)1047 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
1048 {
1049     struct hash *hash = handle;
1050 
1051     TRACE( "%p\n", handle );
1052 
1053     if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
1054     HeapFree( GetProcessHeap(), 0, hash );
1055     return STATUS_SUCCESS;
1056 }
1057 
BCryptHashData(BCRYPT_HASH_HANDLE handle,UCHAR * input,ULONG size,ULONG flags)1058 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
1059 {
1060     struct hash *hash = handle;
1061 
1062     TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
1063 
1064     if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
1065     if (!input) return STATUS_SUCCESS;
1066 
1067     if (hash->hmac)
1068     {
1069         return hmac_update( hash, input, size );
1070     }
1071     else
1072     {
1073         return hash_update( hash, input, size );
1074     }
1075 }
1076 
BCryptFinishHash(BCRYPT_HASH_HANDLE handle,UCHAR * output,ULONG size,ULONG flags)1077 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
1078 {
1079     struct hash *hash = handle;
1080 
1081     TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
1082 
1083     if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
1084     if (!output) return STATUS_INVALID_PARAMETER;
1085 
1086     if (hash->hmac)
1087     {
1088         return hmac_finish( hash, output, size );
1089     }
1090     else
1091     {
1092         return hash_finish( hash, output, size );
1093     }
1094 }
1095 
BCryptHash(BCRYPT_ALG_HANDLE algorithm,UCHAR * secret,ULONG secretlen,UCHAR * input,ULONG inputlen,UCHAR * output,ULONG outputlen)1096 NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
1097                             UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
1098 {
1099     NTSTATUS status;
1100     BCRYPT_HASH_HANDLE handle;
1101 
1102     TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
1103            input, inputlen, output, outputlen );
1104 
1105     status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
1106     if (status != STATUS_SUCCESS)
1107     {
1108         return status;
1109     }
1110 
1111     status = BCryptHashData( handle, input, inputlen, 0 );
1112     if (status != STATUS_SUCCESS)
1113     {
1114         BCryptDestroyHash( handle );
1115         return status;
1116     }
1117 
1118     status = BCryptFinishHash( handle, output, outputlen, 0 );
1119     if (status != STATUS_SUCCESS)
1120     {
1121         BCryptDestroyHash( handle );
1122         return status;
1123     }
1124 
1125     return BCryptDestroyHash( handle );
1126 }
1127 
DllMain(HINSTANCE hinst,DWORD reason,LPVOID reserved)1128 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
1129 {
1130     switch (reason)
1131     {
1132     case DLL_PROCESS_ATTACH:
1133         instance = hinst;
1134         DisableThreadLibraryCalls( hinst );
1135 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
1136         gnutls_initialize();
1137 #elif defined(SONAME_LIBMBEDTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H) && !defined(__REACTOS__)
1138         mbedtls_initialize();
1139 #endif
1140         break;
1141 
1142     case DLL_PROCESS_DETACH:
1143         if (reserved) break;
1144 #if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
1145         gnutls_uninitialize();
1146 #elif defined(SONAME_LIBMBEDTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H) && !defined(__REACTOS__)
1147         mbedtls_uninitialize();
1148 #endif
1149         break;
1150     }
1151     return TRUE;
1152 }
1153