server: Store the attributes in the object_attributes structure.
[wine.git] / dlls / bcrypt / bcrypt_main.c
blob227399f56b6a02a89245478d4412d317a82d6d8f
1 /*
2 * Copyright 2009 Henri Verbeet for CodeWeavers
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.
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.
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
20 #include "config.h"
21 #include "wine/port.h"
23 #include <stdarg.h>
24 #ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H
25 #include <CommonCrypto/CommonDigest.h>
26 #elif defined(SONAME_LIBGNUTLS)
27 #include <gnutls/gnutls.h>
28 #include <gnutls/crypto.h>
29 #endif
31 #include "ntstatus.h"
32 #define WIN32_NO_STATUS
33 #include "windef.h"
34 #include "winbase.h"
35 #include "ntsecapi.h"
36 #include "bcrypt.h"
38 #include "wine/debug.h"
39 #include "wine/library.h"
40 #include "wine/unicode.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(bcrypt);
44 static HINSTANCE instance;
46 #if defined(SONAME_LIBGNUTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
47 WINE_DECLARE_DEBUG_CHANNEL(winediag);
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_perror);
59 #undef MAKE_FUNCPTR
61 static void gnutls_log( int level, const char *msg )
63 TRACE( "<%d> %s", level, msg );
66 static BOOL gnutls_initialize(void)
68 int ret;
70 if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
72 ERR_(winediag)( "failed to load libgnutls, no support for crypto hashes\n" );
73 return FALSE;
76 #define LOAD_FUNCPTR(f) \
77 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
78 { \
79 ERR( "failed to load %s\n", #f ); \
80 goto fail; \
83 LOAD_FUNCPTR(gnutls_global_deinit)
84 LOAD_FUNCPTR(gnutls_global_init)
85 LOAD_FUNCPTR(gnutls_global_set_log_function)
86 LOAD_FUNCPTR(gnutls_global_set_log_level)
87 LOAD_FUNCPTR(gnutls_hash);
88 LOAD_FUNCPTR(gnutls_hash_deinit);
89 LOAD_FUNCPTR(gnutls_hash_init);
90 LOAD_FUNCPTR(gnutls_perror)
91 #undef LOAD_FUNCPTR
93 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
95 pgnutls_perror( ret );
96 goto fail;
99 if (TRACE_ON( bcrypt ))
101 pgnutls_global_set_log_level( 4 );
102 pgnutls_global_set_log_function( gnutls_log );
105 return TRUE;
107 fail:
108 wine_dlclose( libgnutls_handle, NULL, 0 );
109 libgnutls_handle = NULL;
110 return FALSE;
113 static void gnutls_uninitialize(void)
115 pgnutls_global_deinit();
116 wine_dlclose( libgnutls_handle, NULL, 0 );
117 libgnutls_handle = NULL;
119 #endif /* SONAME_LIBGNUTLS && !HAVE_COMMONCRYPTO_COMMONDIGEST_H */
121 NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
122 BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
124 FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
126 *ppAlgList=NULL;
127 *pAlgCount=0;
129 return STATUS_NOT_IMPLEMENTED;
132 NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE algorithm, UCHAR *buffer, ULONG count, ULONG flags)
134 const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
135 TRACE("%p, %p, %u, %08x - semi-stub\n", algorithm, buffer, count, flags);
137 if (!algorithm)
139 /* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
140 * is set. In this case the preferred system RNG is used.
142 if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
143 return STATUS_INVALID_HANDLE;
145 if (!buffer)
146 return STATUS_INVALID_PARAMETER;
148 if (flags & ~supported_flags)
149 FIXME("unsupported flags %08x\n", flags & ~supported_flags);
151 if (algorithm)
152 FIXME("ignoring selected algorithm\n");
154 /* When zero bytes are requested the function returns success too. */
155 if (!count)
156 return STATUS_SUCCESS;
158 if (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG)
160 if (RtlGenRandom(buffer, count))
161 return STATUS_SUCCESS;
164 FIXME("called with unsupported parameters, returning error\n");
165 return STATUS_NOT_IMPLEMENTED;
168 #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
169 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
170 struct object
172 ULONG magic;
175 enum alg_id
177 ALG_ID_SHA1 = 1,
178 ALG_ID_SHA256 = 2,
179 ALG_ID_SHA384 = 3,
180 ALG_ID_SHA512 = 4
183 struct algorithm
185 struct object hdr;
186 enum alg_id id;
189 NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
191 struct algorithm *alg;
192 enum alg_id alg_id;
194 TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
196 if (!handle || !id) return STATUS_INVALID_PARAMETER;
197 if (flags)
199 FIXME( "unimplemented flags %08x\n", flags );
200 return STATUS_NOT_IMPLEMENTED;
203 if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
204 else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
205 else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
206 else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
207 else
209 FIXME( "algorithm %s not supported\n", debugstr_w(id) );
210 return STATUS_NOT_IMPLEMENTED;
212 if (!implementation || strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
214 FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
215 return STATUS_NOT_IMPLEMENTED;
218 if (!(alg = HeapAlloc( GetProcessHeap(), 0, sizeof(*alg) ))) return STATUS_NO_MEMORY;
219 alg->hdr.magic = MAGIC_ALG;
220 alg->id = alg_id;
222 *handle = alg;
223 return STATUS_SUCCESS;
226 NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
228 struct algorithm *alg = handle;
230 TRACE( "%p, %08x\n", handle, flags );
232 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
233 HeapFree( GetProcessHeap(), 0, alg );
234 return STATUS_SUCCESS;
237 NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
239 FIXME("%p - semi-stub\n", enabled);
241 if (!enabled)
242 return STATUS_INVALID_PARAMETER;
244 *enabled = FALSE;
245 return STATUS_SUCCESS;
248 #ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H
249 struct hash
251 struct object hdr;
252 enum alg_id alg_id;
253 union
255 CC_SHA1_CTX sha1_ctx;
256 CC_SHA256_CTX sha256_ctx;
257 CC_SHA512_CTX sha512_ctx;
258 } u;
261 static NTSTATUS hash_init( struct hash *hash )
263 switch (hash->alg_id)
265 case ALG_ID_SHA1:
266 CC_SHA1_Init( &hash->u.sha1_ctx );
267 break;
269 case ALG_ID_SHA256:
270 CC_SHA256_Init( &hash->u.sha256_ctx );
271 break;
273 case ALG_ID_SHA384:
274 CC_SHA384_Init( &hash->u.sha512_ctx );
275 break;
277 case ALG_ID_SHA512:
278 CC_SHA512_Init( &hash->u.sha512_ctx );
279 break;
281 default:
282 ERR( "unhandled id %u\n", hash->alg_id );
283 return STATUS_NOT_IMPLEMENTED;
285 return STATUS_SUCCESS;
288 static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
290 switch (hash->alg_id)
292 case ALG_ID_SHA1:
293 CC_SHA1_Update( &hash->u.sha1_ctx, input, size );
294 break;
296 case ALG_ID_SHA256:
297 CC_SHA256_Update( &hash->u.sha256_ctx, input, size );
298 break;
300 case ALG_ID_SHA384:
301 CC_SHA384_Update( &hash->u.sha512_ctx, input, size );
302 break;
304 case ALG_ID_SHA512:
305 CC_SHA512_Update( &hash->u.sha512_ctx, input, size );
306 break;
308 default:
309 ERR( "unhandled id %u\n", hash->alg_id );
310 return STATUS_NOT_IMPLEMENTED;
312 return STATUS_SUCCESS;
315 static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
317 switch (hash->alg_id)
319 case ALG_ID_SHA1:
320 CC_SHA1_Final( output, &hash->u.sha1_ctx );
321 break;
323 case ALG_ID_SHA256:
324 CC_SHA256_Final( output, &hash->u.sha256_ctx );
325 break;
327 case ALG_ID_SHA384:
328 CC_SHA384_Final( output, &hash->u.sha512_ctx );
329 break;
331 case ALG_ID_SHA512:
332 CC_SHA512_Final( output, &hash->u.sha512_ctx );
333 break;
335 default:
336 ERR( "unhandled id %u\n", hash->alg_id );
337 break;
339 return STATUS_SUCCESS;
341 #elif defined(SONAME_LIBGNUTLS)
342 struct hash
344 struct object hdr;
345 enum alg_id alg_id;
346 gnutls_hash_hd_t handle;
349 static NTSTATUS hash_init( struct hash *hash )
351 gnutls_digest_algorithm_t alg;
353 if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
355 switch (hash->alg_id)
357 case ALG_ID_SHA1:
358 alg = GNUTLS_DIG_SHA1;
359 break;
361 case ALG_ID_SHA256:
362 alg = GNUTLS_DIG_SHA256;
363 break;
365 case ALG_ID_SHA384:
366 alg = GNUTLS_DIG_SHA384;
367 break;
369 case ALG_ID_SHA512:
370 alg = GNUTLS_DIG_SHA512;
371 break;
373 default:
374 ERR( "unhandled id %u\n", hash->alg_id );
375 return STATUS_NOT_IMPLEMENTED;
378 if (pgnutls_hash_init( &hash->handle, alg )) return STATUS_INTERNAL_ERROR;
379 return STATUS_SUCCESS;
382 static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
384 if (pgnutls_hash( hash->handle, input, size )) return STATUS_INTERNAL_ERROR;
385 return STATUS_SUCCESS;
388 static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
390 pgnutls_hash_deinit( hash->handle, output );
391 return STATUS_SUCCESS;
393 #else
394 struct hash
396 struct object hdr;
397 enum alg_id alg_id;
400 static NTSTATUS hash_init( struct hash *hash )
402 ERR( "support for hashes not available at build time\n" );
403 return STATUS_NOT_IMPLEMENTED;
406 static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
408 ERR( "support for hashes not available at build time\n" );
409 return STATUS_NOT_IMPLEMENTED;
412 static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
414 ERR( "support for hashes not available at build time\n" );
415 return STATUS_NOT_IMPLEMENTED;
417 #endif
419 #define OBJECT_LENGTH_SHA1 278
420 #define OBJECT_LENGTH_SHA256 286
421 #define OBJECT_LENGTH_SHA384 382
422 #define OBJECT_LENGTH_SHA512 382
424 #define HASH_DIGEST_LENGTH_SHA1 20
425 #define HASH_DIGEST_LENGTH_SHA256 32
426 #define HASH_DIGEST_LENGTH_SHA384 48
427 #define HASH_DIGEST_LENGTH_SHA512 64
429 static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
431 ULONG value;
433 switch (id)
435 case ALG_ID_SHA1:
436 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
438 value = OBJECT_LENGTH_SHA1;
439 break;
441 FIXME( "unsupported sha1 algorithm property %s\n", debugstr_w(prop) );
442 return STATUS_NOT_IMPLEMENTED;
444 case ALG_ID_SHA256:
445 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
447 value = OBJECT_LENGTH_SHA256;
448 break;
450 FIXME( "unsupported sha256 algorithm property %s\n", debugstr_w(prop) );
451 return STATUS_NOT_IMPLEMENTED;
453 case ALG_ID_SHA384:
454 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
456 value = OBJECT_LENGTH_SHA384;
457 break;
459 FIXME( "unsupported sha384 algorithm property %s\n", debugstr_w(prop) );
460 return STATUS_NOT_IMPLEMENTED;
462 case ALG_ID_SHA512:
463 if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
465 value = OBJECT_LENGTH_SHA512;
466 break;
468 FIXME( "unsupported sha512 algorithm property %s\n", debugstr_w(prop) );
469 return STATUS_NOT_IMPLEMENTED;
471 default:
472 FIXME( "unsupported algorithm %u\n", id );
473 return STATUS_NOT_IMPLEMENTED;
476 if (size < sizeof(ULONG))
478 *ret_size = sizeof(ULONG);
479 return STATUS_BUFFER_TOO_SMALL;
481 if (buf) *(ULONG *)buf = value;
482 *ret_size = sizeof(ULONG);
484 return STATUS_SUCCESS;
487 static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
489 ULONG value;
491 switch (id)
493 case ALG_ID_SHA1:
494 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
496 value = HASH_DIGEST_LENGTH_SHA1;
497 break;
499 FIXME( "unsupported sha1 hash property %s\n", debugstr_w(prop) );
500 return STATUS_NOT_IMPLEMENTED;
502 case ALG_ID_SHA256:
503 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
505 value = HASH_DIGEST_LENGTH_SHA256;
506 break;
508 FIXME( "unsupported sha256 hash property %s\n", debugstr_w(prop) );
509 return STATUS_NOT_IMPLEMENTED;
511 case ALG_ID_SHA384:
512 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
514 value = HASH_DIGEST_LENGTH_SHA384;
515 break;
517 FIXME( "unsupported sha384 hash property %s\n", debugstr_w(prop) );
518 return STATUS_NOT_IMPLEMENTED;
520 case ALG_ID_SHA512:
521 if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
523 value = HASH_DIGEST_LENGTH_SHA512;
524 break;
526 FIXME( "unsupported sha512 hash property %s\n", debugstr_w(prop) );
527 return STATUS_NOT_IMPLEMENTED;
529 default:
530 FIXME( "unsupported hash %u\n", id );
531 return STATUS_NOT_IMPLEMENTED;
534 if (size < sizeof(ULONG))
536 *ret_size = sizeof(ULONG);
537 return STATUS_BUFFER_TOO_SMALL;
539 if (buf) *(ULONG *)buf = value;
540 *ret_size = sizeof(ULONG);
542 return STATUS_SUCCESS;
545 NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
547 struct object *object = handle;
549 TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
551 if (!object) return STATUS_INVALID_HANDLE;
552 if (!prop || !res) return STATUS_INVALID_PARAMETER;
554 switch (object->magic)
556 case MAGIC_ALG:
558 const struct algorithm *alg = (const struct algorithm *)object;
559 return get_alg_property( alg->id, prop, buffer, count, res );
561 case MAGIC_HASH:
563 const struct hash *hash = (const struct hash *)object;
564 return get_hash_property( hash->alg_id, prop, buffer, count, res );
566 default:
567 WARN( "unknown magic %08x", object->magic );
568 return STATUS_INVALID_HANDLE;
572 NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
573 UCHAR *secret, ULONG secretlen, ULONG flags )
575 struct algorithm *alg = algorithm;
576 struct hash *hash;
577 NTSTATUS status;
579 TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
580 secret, secretlen, flags );
581 if (flags)
583 FIXME( "unimplemented flags %08x\n", flags );
584 return STATUS_NOT_IMPLEMENTED;
587 if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
588 if (object) FIXME( "ignoring object buffer\n" );
590 if (!(hash = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash) ))) return STATUS_NO_MEMORY;
591 hash->hdr.magic = MAGIC_HASH;
592 hash->alg_id = alg->id;
593 if ((status = hash_init( hash )) != STATUS_SUCCESS)
595 HeapFree( GetProcessHeap(), 0, hash );
596 return status;
599 *handle = hash;
600 return STATUS_SUCCESS;
603 NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
605 struct hash *hash = handle;
607 TRACE( "%p\n", handle );
609 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
610 HeapFree( GetProcessHeap(), 0, hash );
611 return STATUS_SUCCESS;
614 NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
616 struct hash *hash = handle;
618 TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
620 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
621 if (!input) return STATUS_INVALID_PARAMETER;
623 return hash_update( hash, input, size );
626 NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
628 struct hash *hash = handle;
630 TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
632 if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
633 if (!output) return STATUS_INVALID_PARAMETER;
635 return hash_finish( hash, output, size );
638 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
640 switch (reason)
642 case DLL_PROCESS_ATTACH:
643 instance = hinst;
644 DisableThreadLibraryCalls( hinst );
645 #if defined(SONAME_LIBGNUTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
646 gnutls_initialize();
647 #endif
648 break;
650 case DLL_PROCESS_DETACH:
651 if (reserved) break;
652 #if defined(SONAME_LIBGNUTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
653 gnutls_uninitialize();
654 #endif
655 break;
657 return TRUE;