uiautomationcore: Add support for UIA_ProviderDescriptionPropertyId.
[wine.git] / dlls / dssenh / main.c
blob887319d0a9df4477aeaabf902b4d5eb0c12ee734
1 /*
2 * Copyright 2008 Maarten Lankhorst
3 * Copyright 2020 Hans Leidekker for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
22 #include "ntstatus.h"
23 #define WIN32_NO_STATUS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wincrypt.h"
27 #include "winreg.h"
28 #include "bcrypt.h"
29 #include "objbase.h"
30 #include "rpcproxy.h"
31 #include "ntsecapi.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dssenh);
37 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
38 struct key
40 DWORD magic;
41 DWORD algid;
42 DWORD flags;
43 BCRYPT_KEY_HANDLE handle;
46 #define MAGIC_CONTAINER (('C' << 24) | ('O' << 16) | ('N' << 8) | 'T')
47 struct container
49 DWORD magic;
50 DWORD flags;
51 struct key *exch_key;
52 struct key *sign_key;
53 char name[MAX_PATH];
56 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
57 struct hash
59 DWORD magic;
60 BCRYPT_HASH_HANDLE handle;
61 DWORD len;
62 UCHAR value[64];
63 BOOL finished;
66 static const char dss_path_fmt[] = "Software\\Wine\\Crypto\\DSS\\%s";
68 static BOOL create_container_regkey( struct container *container, REGSAM sam, HKEY *hkey )
70 char path[sizeof(dss_path_fmt) + MAX_PATH];
71 HKEY rootkey;
73 sprintf( path, dss_path_fmt, container->name );
75 if (container->flags & CRYPT_MACHINE_KEYSET)
76 rootkey = HKEY_LOCAL_MACHINE;
77 else
78 rootkey = HKEY_CURRENT_USER;
80 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
81 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
82 return !RegCreateKeyExA( rootkey, path, 0, NULL, REG_OPTION_NON_VOLATILE, sam, NULL, hkey, NULL );
85 static struct container *create_key_container( const char *name, DWORD flags )
87 struct container *ret;
89 if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL;
90 ret->magic = MAGIC_CONTAINER;
91 ret->flags = flags;
92 if (name) strcpy( ret->name, name );
94 if (!(flags & CRYPT_VERIFYCONTEXT))
96 HKEY hkey;
97 if (create_container_regkey( ret, KEY_WRITE, &hkey )) RegCloseKey( hkey );
99 return ret;
102 static BOOL open_container_regkey( const char *name, DWORD flags, REGSAM access, HKEY *hkey )
104 char path[sizeof(dss_path_fmt) + MAX_PATH];
105 HKEY rootkey;
107 sprintf( path, dss_path_fmt, name );
109 if (flags & CRYPT_MACHINE_KEYSET)
110 rootkey = HKEY_LOCAL_MACHINE;
111 else
112 rootkey = HKEY_CURRENT_USER;
114 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
115 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
116 return !RegOpenKeyExA( rootkey, path, 0, access, hkey );
119 static const WCHAR *map_keyspec_to_keypair_name( DWORD keyspec )
121 const WCHAR *name;
123 switch (keyspec)
125 case AT_KEYEXCHANGE:
126 name = L"KeyExchangeKeyPair";
127 break;
128 case AT_SIGNATURE:
129 name = L"SignatureKeyPair";
130 break;
131 default:
132 ERR( "invalid key spec %lu\n", keyspec );
133 return NULL;
135 return name;
138 static struct key *create_key( ALG_ID algid, DWORD flags )
140 struct key *ret;
142 switch (algid)
144 case AT_SIGNATURE:
145 case CALG_DSS_SIGN:
146 break;
148 default:
149 FIXME( "unhandled algorithm %08x\n", algid );
150 return NULL;
153 if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL;
155 ret->magic = MAGIC_KEY;
156 ret->algid = algid;
157 ret->flags = flags;
158 return ret;
161 static void destroy_key( struct key *key )
163 if (!key) return;
164 BCryptDestroyKey( key->handle );
165 key->magic = 0;
166 free( key );
169 static struct key *import_key( DWORD keyspec, BYTE *data, DWORD len )
171 struct key *ret;
173 if (!(ret = create_key( keyspec, 0 ))) return NULL;
175 if (BCryptImportKeyPair( BCRYPT_DSA_ALG_HANDLE, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, &ret->handle, data, len, 0 ))
177 WARN( "failed to import key\n" );
178 destroy_key( ret );
179 return NULL;
181 return ret;
184 static struct key *read_key( HKEY hkey, DWORD keyspec, DWORD flags )
186 const WCHAR *value;
187 DWORD type, len;
188 BYTE *data;
189 DATA_BLOB blob_in, blob_out;
190 struct key *ret = NULL;
192 if (!(value = map_keyspec_to_keypair_name( keyspec ))) return NULL;
193 if (RegQueryValueExW( hkey, value, 0, &type, NULL, &len )) return NULL;
194 if (!(data = malloc( len ))) return NULL;
196 if (!RegQueryValueExW( hkey, value, 0, &type, data, &len ))
198 blob_in.pbData = data;
199 blob_in.cbData = len;
200 if (CryptUnprotectData( &blob_in, NULL, NULL, NULL, NULL, flags, &blob_out ))
202 ret = import_key( keyspec, blob_out.pbData, blob_out.cbData );
203 LocalFree( blob_out.pbData );
207 free( data );
208 return ret;
211 static void destroy_container( struct container *container )
213 if (!container) return;
214 destroy_key( container->exch_key );
215 destroy_key( container->sign_key );
216 container->magic = 0;
217 free( container );
220 static struct container *read_key_container( const char *name, DWORD flags )
222 DWORD protect_flags = (flags & CRYPT_MACHINE_KEYSET) ? CRYPTPROTECT_LOCAL_MACHINE : 0;
223 struct container *ret;
224 HKEY hkey;
226 if (!open_container_regkey( name, flags, KEY_READ, &hkey )) return NULL;
228 if ((ret = create_key_container( name, flags )))
230 ret->exch_key = read_key( hkey, AT_KEYEXCHANGE, protect_flags );
231 ret->sign_key = read_key( hkey, AT_SIGNATURE, protect_flags );
234 RegCloseKey( hkey );
235 return ret;
238 static void delete_key_container( const char *name, DWORD flags )
240 char path[sizeof(dss_path_fmt) + MAX_PATH];
241 HKEY rootkey;
243 sprintf( path, dss_path_fmt, name );
245 if (flags & CRYPT_MACHINE_KEYSET)
246 rootkey = HKEY_LOCAL_MACHINE;
247 else
248 rootkey = HKEY_CURRENT_USER;
250 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
251 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
252 RegDeleteKeyExA( rootkey, path, 0, 0 );
255 BOOL WINAPI CPAcquireContext( HCRYPTPROV *ret_prov, LPSTR container, DWORD flags, PVTableProvStruc vtable )
257 struct container *ret;
258 char name[MAX_PATH];
260 TRACE( "%p, %s, %08lx, %p\n", ret_prov, debugstr_a(container), flags, vtable );
262 if (container && *container)
264 if (lstrlenA( container ) >= sizeof(name)) return FALSE;
265 lstrcpyA( name, container );
267 else
269 DWORD len = sizeof(name);
270 if (!GetUserNameA( name, &len )) return FALSE;
273 switch (flags)
275 case 0:
276 case 0 | CRYPT_MACHINE_KEYSET:
277 if (!(ret = read_key_container( name, flags )))
278 SetLastError( NTE_BAD_KEYSET );
279 break;
281 case CRYPT_NEWKEYSET:
282 case CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET:
283 if ((ret = read_key_container( name, flags )))
285 free( ret );
286 SetLastError( NTE_EXISTS );
287 return FALSE;
289 ret = create_key_container( name, flags );
290 break;
292 case CRYPT_VERIFYCONTEXT:
293 case CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET:
294 ret = create_key_container( "", flags );
295 break;
297 case CRYPT_DELETEKEYSET:
298 case CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET:
299 delete_key_container( name, flags );
300 *ret_prov = 0;
301 return TRUE;
303 default:
304 FIXME( "unsupported flags %08lx\n", flags );
305 return FALSE;
308 if (!ret) return FALSE;
309 *ret_prov = (HCRYPTPROV)ret;
310 return TRUE;
313 BOOL WINAPI CPReleaseContext( HCRYPTPROV hprov, DWORD flags )
315 struct container *container = (struct container *)hprov;
317 TRACE( "%p, %08lx\n", (void *)hprov, flags );
319 if (container->magic != MAGIC_CONTAINER) return FALSE;
320 destroy_container( container );
321 return TRUE;
324 BOOL WINAPI CPGetProvParam( HCRYPTPROV hprov, DWORD param, BYTE *data, DWORD *len, DWORD flags )
326 return FALSE;
329 static BOOL store_key_pair( struct key *key, HKEY hkey, DWORD keyspec, DWORD flags )
331 const WCHAR *value;
332 DATA_BLOB blob_in, blob_out;
333 DWORD len;
334 BYTE *data;
335 BOOL ret = TRUE;
337 if (!key) return TRUE;
338 if (!(value = map_keyspec_to_keypair_name( keyspec ))) return FALSE;
340 if (BCryptExportKey( key->handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, NULL, 0, &len, 0 )) return FALSE;
341 if (!(data = malloc( len ))) return FALSE;
343 if (!BCryptExportKey( key->handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, data, len, &len, 0 ))
345 blob_in.pbData = data;
346 blob_in.cbData = len;
347 if ((ret = CryptProtectData( &blob_in, NULL, NULL, NULL, NULL, flags, &blob_out )))
349 ret = !RegSetValueExW( hkey, value, 0, REG_BINARY, blob_out.pbData, blob_out.cbData );
350 LocalFree( blob_out.pbData );
354 free( data );
355 return ret;
358 static BOOL store_key_container_keys( struct container *container )
360 HKEY hkey;
361 DWORD flags;
362 BOOL ret;
364 if (container->flags & CRYPT_MACHINE_KEYSET)
365 flags = CRYPTPROTECT_LOCAL_MACHINE;
366 else
367 flags = 0;
369 if (!create_container_regkey( container, KEY_WRITE, &hkey )) return FALSE;
371 ret = store_key_pair( container->exch_key, hkey, AT_KEYEXCHANGE, flags );
372 if (ret) store_key_pair( container->sign_key, hkey, AT_SIGNATURE, flags );
373 RegCloseKey( hkey );
374 return ret;
377 static struct key *duplicate_key( const struct key *key )
379 struct key *ret;
381 if (!(ret = create_key( key->algid, key->flags ))) return NULL;
383 if (BCryptDuplicateKey( key->handle, &ret->handle, NULL, 0, 0 ))
385 free( ret );
386 return NULL;
388 return ret;
391 static BOOL generate_key( struct container *container, ALG_ID algid, DWORD bitlen, DWORD flags, HCRYPTKEY *ret_key )
393 struct key *key, *sign_key;
394 NTSTATUS status;
396 if (!(key = create_key( algid, flags ))) return FALSE;
398 if ((status = BCryptGenerateKeyPair( BCRYPT_DSA_ALG_HANDLE, &key->handle, bitlen, 0 )))
400 ERR( "failed to generate key %08lx\n", status );
401 destroy_key( key );
402 return FALSE;
404 if ((status = BCryptFinalizeKeyPair( key->handle, 0 )))
406 ERR( "failed to finalize key %08lx\n", status );
407 destroy_key( key );
408 return FALSE;
411 switch (algid)
413 case AT_SIGNATURE:
414 case CALG_DSS_SIGN:
415 if (!(sign_key = duplicate_key( key )))
417 destroy_key( key );
418 return FALSE;
420 destroy_key( container->sign_key );
421 container->sign_key = sign_key;
422 break;
424 default:
425 FIXME( "unhandled algorithm %08x\n", algid );
426 return FALSE;
429 if (!store_key_container_keys( container )) return FALSE;
431 *ret_key = (HCRYPTKEY)key;
432 return TRUE;
435 BOOL WINAPI CPGenKey( HCRYPTPROV hprov, ALG_ID algid, DWORD flags, HCRYPTKEY *ret_key )
437 static const unsigned int supported_key_lengths[] = { 512, 768, 1024 };
438 struct container *container = (struct container *)hprov;
439 ULONG i, bitlen = HIWORD(flags) ? HIWORD(flags) : 1024;
441 TRACE( "%p, %08x, %08lx, %p\n", (void *)hprov, algid, flags, ret_key );
443 if (container->magic != MAGIC_CONTAINER) return FALSE;
445 if (bitlen % 2)
447 SetLastError( STATUS_INVALID_PARAMETER );
448 return FALSE;
450 for (i = 0; i < ARRAY_SIZE(supported_key_lengths); i++)
452 if (bitlen == supported_key_lengths[i]) break;
454 if (i >= ARRAY_SIZE(supported_key_lengths))
456 SetLastError( NTE_BAD_FLAGS );
457 return FALSE;
460 return generate_key( container, algid, bitlen, LOWORD(flags), ret_key );
463 BOOL WINAPI CPDestroyKey( HCRYPTPROV hprov, HCRYPTKEY hkey )
465 struct key *key = (struct key *)hkey;
467 TRACE( "%p, %p\n", (void *)hprov, (void *)hkey );
469 if (key->magic != MAGIC_KEY)
471 SetLastError( NTE_BAD_KEY );
472 return FALSE;
475 destroy_key( key );
476 return TRUE;
479 #define MAGIC_DSS1 ('D' | ('S' << 8) | ('S' << 16) | ('1' << 24))
480 #define MAGIC_DSS2 ('D' | ('S' << 8) | ('S' << 16) | ('2' << 24))
481 #define MAGIC_DSS3 ('D' | ('S' << 8) | ('S' << 16) | ('3' << 24))
483 static BOOL import_key_dss2( struct container *container, ALG_ID algid, const BYTE *data, DWORD len, DWORD flags,
484 HCRYPTKEY *ret_key )
486 const BLOBHEADER *hdr = (const BLOBHEADER *)data;
487 const DSSPUBKEY *pubkey = (const DSSPUBKEY *)(hdr + 1);
488 const WCHAR *type;
489 struct key *key, *exch_key, *sign_key;
490 NTSTATUS status;
492 if (len < sizeof(*hdr) + sizeof(*pubkey)) return FALSE;
494 switch (pubkey->magic)
496 case MAGIC_DSS1:
497 type = LEGACY_DSA_V2_PUBLIC_BLOB;
498 break;
500 case MAGIC_DSS2:
501 type = LEGACY_DSA_V2_PRIVATE_BLOB;
502 break;
504 default:
505 FIXME( "unsupported key magic %08lx\n", pubkey->magic );
506 return FALSE;
509 if (!(key = create_key( CALG_DSS_SIGN, flags ))) return FALSE;
511 if ((status = BCryptImportKeyPair( BCRYPT_DSA_ALG_HANDLE, NULL, type, &key->handle, (UCHAR *)data, len, 0 )))
513 TRACE( "failed to import key %08lx\n", status );
514 destroy_key( key );
515 return FALSE;
518 if (!wcscmp(type, LEGACY_DSA_V2_PRIVATE_BLOB))
520 switch (algid)
522 case AT_KEYEXCHANGE:
523 case CALG_DH_SF:
524 if (!(exch_key = duplicate_key( key )))
526 destroy_key( key );
527 return FALSE;
529 destroy_key( container->exch_key );
530 container->exch_key = exch_key;
531 break;
533 case AT_SIGNATURE:
534 case CALG_DSS_SIGN:
535 if (!(sign_key = duplicate_key( key )))
537 destroy_key( key );
538 return FALSE;
540 destroy_key( container->sign_key );
541 container->sign_key = sign_key;
542 break;
544 default:
545 FIXME( "unhandled key algorithm %u\n", algid );
546 destroy_key( key );
547 return FALSE;
550 if (!store_key_container_keys( container )) return FALSE;
553 *ret_key = (HCRYPTKEY)key;
554 return TRUE;
557 static BOOL import_key_dss3( struct container *container, ALG_ID algid, const BYTE *data, DWORD len, DWORD flags,
558 HCRYPTKEY *ret_key )
560 const BLOBHEADER *hdr = (const BLOBHEADER *)data;
561 const DSSPUBKEY_VER3 *pubkey = (const DSSPUBKEY_VER3 *)(hdr + 1);
562 BCRYPT_DSA_KEY_BLOB *blob;
563 struct key *key;
564 BYTE *src, *dst;
565 ULONG i, size, size_q;
566 NTSTATUS status;
568 if (len < sizeof(*hdr) + sizeof(*pubkey)) return FALSE;
570 switch (pubkey->magic)
572 case MAGIC_DSS3:
573 break;
575 default:
576 FIXME( "unsupported key magic %08lx\n", pubkey->magic );
577 return FALSE;
580 if ((size_q = pubkey->bitlenQ / 8) > sizeof(blob->q))
582 FIXME( "q too large\n" );
583 return FALSE;
586 if (!(key = create_key( CALG_DSS_SIGN, flags ))) return FALSE;
588 size = sizeof(*blob) + (pubkey->bitlenP / 8) * 3;
589 if (!(blob = calloc( 1, size )))
591 destroy_key( key );
592 return FALSE;
594 blob->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC;
595 blob->cbKey = pubkey->bitlenP / 8;
596 memcpy( blob->Count, &pubkey->DSSSeed.counter, sizeof(blob->Count) );
597 memcpy( blob->Seed, pubkey->DSSSeed.seed, sizeof(blob->Seed) );
599 /* q */
600 src = (BYTE *)(pubkey + 1) + blob->cbKey;
601 for (i = 0; i < size_q; i++) blob->q[i] = src[size_q - i - 1];
603 /* p */
604 src -= blob->cbKey;
605 dst = (BYTE *)(blob + 1);
606 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
608 /* g */
609 src += blob->cbKey + size_q;
610 dst += blob->cbKey;
611 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
613 /* y */
614 src += blob->cbKey + pubkey->bitlenJ / 8;
615 dst += blob->cbKey;
616 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
618 if ((status = BCryptImportKeyPair( BCRYPT_DSA_ALG_HANDLE, NULL, BCRYPT_DSA_PUBLIC_BLOB, &key->handle,
619 (UCHAR *)blob, size, 0 )))
621 WARN( "failed to import key %08lx\n", status );
622 destroy_key( key );
623 free( blob );
624 return FALSE;
627 free( blob );
628 *ret_key = (HCRYPTKEY)key;
629 return TRUE;
632 BOOL WINAPI CPImportKey( HCRYPTPROV hprov, const BYTE *data, DWORD len, HCRYPTKEY hpubkey, DWORD flags,
633 HCRYPTKEY *ret_key )
635 struct container *container = (struct container *)hprov;
636 const BLOBHEADER *hdr;
637 BOOL ret;
639 TRACE( "%p, %p, %lu, %p, %08lx, %p\n", (void *)hprov, data, len, (void *)hpubkey, flags, ret_key );
641 if (container->magic != MAGIC_CONTAINER) return FALSE;
642 if (len < sizeof(*hdr)) return FALSE;
644 hdr = (const BLOBHEADER *)data;
645 if ((hdr->bType != PRIVATEKEYBLOB && hdr->bType != PUBLICKEYBLOB) || hdr->aiKeyAlg != CALG_DSS_SIGN)
647 FIXME( "bType %u aiKeyAlg %08x not supported\n", hdr->bType, hdr->aiKeyAlg );
648 return FALSE;
651 switch (hdr->bVersion)
653 case 2:
654 ret = import_key_dss2( container, hdr->aiKeyAlg, data, len, flags, ret_key );
655 break;
657 case 3:
658 ret = import_key_dss3( container, hdr->aiKeyAlg, data, len, flags, ret_key );
659 break;
661 default:
662 FIXME( "version %u not supported\n", hdr->bVersion );
663 return FALSE;
666 return ret;
669 BOOL WINAPI CPExportKey( HCRYPTPROV hprov, HCRYPTKEY hkey, HCRYPTKEY hexpkey, DWORD blobtype, DWORD flags,
670 BYTE *data, DWORD *len )
672 struct key *key = (struct key *)hkey;
673 const WCHAR *type;
675 TRACE( "%p, %p, %p, %08lx, %08lx, %p, %p\n", (void *)hprov, (void *)hkey, (void *)hexpkey, blobtype, flags,
676 data, len );
678 if (key->magic != MAGIC_KEY) return FALSE;
679 if (hexpkey)
681 FIXME( "export key not supported\n" );
682 return FALSE;
684 if (flags)
686 FIXME( "flags %08lx not supported\n", flags );
687 return FALSE;
690 switch (blobtype)
692 case PUBLICKEYBLOB:
693 type = LEGACY_DSA_V2_PUBLIC_BLOB;
694 break;
696 case PRIVATEKEYBLOB:
697 type = LEGACY_DSA_V2_PRIVATE_BLOB;
698 break;
700 default:
701 FIXME( "blob type %lu not supported\n", blobtype );
702 return FALSE;
705 return !BCryptExportKey( key->handle, NULL, type, data, *len, len, 0 );
708 BOOL WINAPI CPDuplicateKey( HCRYPTPROV hprov, HCRYPTKEY hkey, DWORD *reserved, DWORD flags, HCRYPTKEY *ret_key )
710 struct key *key = (struct key *)hkey, *ret;
712 TRACE( "%p, %p, %p, %08lx, %p\n", (void *)hprov, (void *)hkey, reserved, flags, ret_key );
714 if (key->magic != MAGIC_KEY) return FALSE;
716 if (!(ret = duplicate_key( key ))) return FALSE;
717 *ret_key = (HCRYPTKEY)ret;
718 return TRUE;
721 BOOL WINAPI CPGetUserKey( HCRYPTPROV hprov, DWORD keyspec, HCRYPTKEY *ret_key )
723 struct container *container = (struct container *)hprov;
724 BOOL ret = FALSE;
726 TRACE( "%p, %08lx, %p\n", (void *)hprov, keyspec, ret_key );
728 if (container->magic != MAGIC_CONTAINER) return FALSE;
730 switch (keyspec)
732 case AT_KEYEXCHANGE:
733 if (!container->exch_key) SetLastError( NTE_NO_KEY );
734 else if ((*ret_key = (HCRYPTKEY)duplicate_key( container->exch_key ))) ret = TRUE;
735 break;
737 case AT_SIGNATURE:
738 if (!container->sign_key) SetLastError( NTE_NO_KEY );
739 else if ((*ret_key = (HCRYPTKEY)duplicate_key( container->sign_key ))) ret = TRUE;
740 break;
742 default:
743 SetLastError( NTE_NO_KEY );
744 return FALSE;
747 return ret;
750 BOOL WINAPI CPGenRandom( HCRYPTPROV hprov, DWORD len, BYTE *buffer )
752 struct container *container = (struct container *)hprov;
754 TRACE( "%p, %lu, %p\n", (void *)hprov, len, buffer );
756 if (container->magic != MAGIC_CONTAINER) return FALSE;
758 return RtlGenRandom( buffer, len );
761 static struct hash *create_hash( ALG_ID algid )
763 struct hash *ret;
764 BCRYPT_ALG_HANDLE alg_handle;
765 DWORD len;
767 switch (algid)
769 case CALG_MD5:
770 alg_handle = BCRYPT_MD5_ALG_HANDLE;
771 len = 16;
772 break;
774 case CALG_SHA1:
775 alg_handle = BCRYPT_SHA1_ALG_HANDLE;
776 len = 20;
777 break;
779 default:
780 FIXME( "unhandled algorithm %u\n", algid );
781 return NULL;
784 if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL;
786 ret->magic = MAGIC_HASH;
787 ret->len = len;
788 if (BCryptCreateHash( alg_handle, &ret->handle, NULL, 0, NULL, 0, 0 ))
790 free( ret );
791 return NULL;
793 return ret;
796 BOOL WINAPI CPCreateHash( HCRYPTPROV hprov, ALG_ID algid, HCRYPTKEY hkey, DWORD flags, HCRYPTHASH *ret_hash )
798 struct hash *hash;
800 TRACE( "%p, %08x, %p, %08lx, %p\n", (void *)hprov, algid, (void *)hkey, flags, ret_hash );
802 switch (algid)
804 case CALG_MD5:
805 case CALG_SHA1:
806 break;
808 default:
809 FIXME( "algorithm %u not supported\n", algid );
810 SetLastError( NTE_BAD_ALGID );
811 return FALSE;
814 if (!(hash = create_hash( algid ))) return FALSE;
816 *ret_hash = (HCRYPTHASH)hash;
817 return TRUE;
820 static void destroy_hash( struct hash *hash )
822 if (!hash) return;
823 BCryptDestroyHash( hash->handle );
824 hash->magic = 0;
825 free( hash );
828 BOOL WINAPI CPDestroyHash( HCRYPTPROV hprov, HCRYPTHASH hhash )
830 struct hash *hash = (struct hash *)hhash;
832 TRACE( "%p, %p\n", (void *)hprov, (void *)hhash);
834 if (hash->magic != MAGIC_HASH)
836 SetLastError( NTE_BAD_HASH );
837 return FALSE;
840 destroy_hash( hash );
841 return TRUE;
844 static struct hash *duplicate_hash( const struct hash *hash )
846 struct hash *ret;
848 if (!(ret = malloc( sizeof(*ret) ))) return NULL;
850 ret->magic = hash->magic;
851 ret->len = hash->len;
852 if (BCryptDuplicateHash( hash->handle, &ret->handle, NULL, 0, 0 ))
854 free( ret );
855 return NULL;
857 memcpy( ret->value, hash->value, sizeof(hash->value) );
858 ret->finished = hash->finished;
859 return ret;
862 BOOL WINAPI CPDuplicateHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD *reserved, DWORD flags, HCRYPTHASH *ret_hash )
864 struct hash *hash = (struct hash *)hhash, *ret;
866 TRACE( "%p, %p, %p, %08lx, %p\n", (void *)hprov, (void *)hhash, reserved, flags, ret_hash );
868 if (hash->magic != MAGIC_HASH) return FALSE;
870 if (!(ret = duplicate_hash( hash ))) return FALSE;
871 *ret_hash = (HCRYPTHASH)ret;
872 return TRUE;
875 BOOL WINAPI CPHashData( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *data, DWORD len, DWORD flags )
877 struct hash *hash = (struct hash *)hhash;
879 TRACE("%p, %p, %p, %lu, %08lx\n", (void *)hprov, (void *)hhash, data, len, flags );
881 if (hash->magic != MAGIC_HASH) return FALSE;
883 if (hash->finished)
885 SetLastError( NTE_BAD_HASH_STATE );
886 return FALSE;
888 return !BCryptHashData( hash->handle, (UCHAR *)data, len, 0 );
891 BOOL WINAPI CPGetHashParam( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD param, BYTE *data, DWORD *len, DWORD flags )
893 struct hash *hash = (struct hash *)hhash;
895 TRACE( "%p, %p, %08lx, %p, %p, %08lx\n", (void *)hprov, (void *)hhash, param, data, len, flags );
897 if (hash->magic != MAGIC_HASH) return FALSE;
899 switch (param)
901 case HP_HASHSIZE:
902 if (sizeof(hash->len) > *len)
904 *len = sizeof(hash->len);
905 SetLastError( ERROR_MORE_DATA );
906 return FALSE;
908 *(DWORD *)data = hash->len;
909 *len = sizeof(hash->len);
910 return TRUE;
912 case HP_HASHVAL:
913 if (!hash->finished)
915 if (BCryptFinishHash( hash->handle, hash->value, hash->len, 0 )) return FALSE;
916 hash->finished = TRUE;
918 if (hash->len > *len)
920 *len = hash->len;
921 SetLastError( ERROR_MORE_DATA );
922 return FALSE;
924 if (data) memcpy( data, hash->value, hash->len );
925 *len = hash->len;
926 return TRUE;
928 default:
929 SetLastError( NTE_BAD_TYPE );
930 return FALSE;
934 BOOL WINAPI CPSetHashParam( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD param, const BYTE *data, DWORD flags )
936 struct hash *hash = (struct hash *)hhash;
938 TRACE( "%p, %p, %08lx, %p, %08lx\n", (void *)hprov, (void *)hhash, param, data, flags );
940 if (hash->magic != MAGIC_HASH) return FALSE;
942 switch (param)
944 case HP_HASHVAL:
945 memcpy( hash->value, data, hash->len );
946 return TRUE;
948 default:
949 FIXME( "param %lu not supported\n", param );
950 SetLastError( NTE_BAD_TYPE );
951 return FALSE;
955 BOOL WINAPI CPDeriveKey( HCRYPTPROV hprov, ALG_ID algid, HCRYPTHASH hhash, DWORD flags, HCRYPTKEY *ret_key )
957 return FALSE;
960 static DWORD get_signature_length( DWORD algid )
962 switch (algid)
964 case AT_SIGNATURE:
965 case CALG_DSS_SIGN: return 40;
966 default:
967 FIXME( "unhandled algorithm %lu\n", algid );
968 return 0;
972 #define MAX_HASH_LEN 20
973 BOOL WINAPI CPSignHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD keyspec, const WCHAR *desc, DWORD flags, BYTE *sig,
974 DWORD *siglen )
976 struct container *container = (struct container *)hprov;
977 struct hash *hash = (struct hash *)hhash;
978 ULONG len;
980 TRACE( "%p, %p, %lu, %s, %08lx, %p, %p\n", (void *)hprov, (void *)hhash, keyspec, debugstr_w(desc), flags, sig,
981 siglen );
983 if (container->magic != MAGIC_CONTAINER || !container->sign_key) return FALSE;
984 if (hash->magic != MAGIC_HASH) return FALSE;
986 if (!(len = get_signature_length( container->sign_key->algid ))) return FALSE;
987 if (*siglen < len)
989 *siglen = len;
990 return TRUE;
993 return !BCryptSignHash( container->sign_key->handle, NULL, hash->value, hash->len, sig, *siglen, siglen, 0 );
996 BOOL WINAPI CPVerifySignature( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *sig, DWORD siglen, HCRYPTKEY hpubkey,
997 const WCHAR *desc, DWORD flags )
999 struct hash *hash = (struct hash *)hhash;
1000 struct key *key = (struct key *)hpubkey;
1002 TRACE( "%p, %p, %p, %lu %p, %s, %08lx\n", (void *)hprov, (void *)hhash, sig, siglen, (void *)hpubkey,
1003 debugstr_w(desc), flags );
1005 if (hash->magic != MAGIC_HASH || key->magic != MAGIC_KEY) return FALSE;
1006 if (flags)
1008 FIXME( "flags %08lx not supported\n", flags );
1009 return FALSE;
1012 return !BCryptVerifySignature( key->handle, NULL, hash->value, hash->len, (UCHAR *)sig, siglen, 0 );