riched20: Merge the richole object with the text services object.
[wine.git] / dlls / dssenh / main.c
blob82822e4daec2417d3111378cc723ca091739dcc8
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"
34 #include "wine/heap.h"
36 static HINSTANCE instance;
38 WINE_DEFAULT_DEBUG_CHANNEL(dssenh);
40 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
41 struct key
43 DWORD magic;
44 DWORD algid;
45 DWORD flags;
46 BCRYPT_ALG_HANDLE alg_handle;
47 BCRYPT_KEY_HANDLE handle;
50 #define MAGIC_CONTAINER (('C' << 24) | ('O' << 16) | ('N' << 8) | 'T')
51 struct container
53 DWORD magic;
54 DWORD flags;
55 struct key *exch_key;
56 struct key *sign_key;
57 char name[MAX_PATH];
60 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
61 struct hash
63 DWORD magic;
64 BCRYPT_HASH_HANDLE handle;
65 DWORD len;
66 UCHAR value[64];
67 BOOL finished;
70 static const char dss_path_fmt[] = "Software\\Wine\\Crypto\\DSS\\%s";
72 static BOOL create_container_regkey( struct container *container, REGSAM sam, HKEY *hkey )
74 char path[sizeof(dss_path_fmt) + MAX_PATH];
75 HKEY rootkey;
77 sprintf( path, dss_path_fmt, container->name );
79 if (container->flags & CRYPT_MACHINE_KEYSET)
80 rootkey = HKEY_LOCAL_MACHINE;
81 else
82 rootkey = HKEY_CURRENT_USER;
84 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
85 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
86 return !RegCreateKeyExA( rootkey, path, 0, NULL, REG_OPTION_NON_VOLATILE, sam, NULL, hkey, NULL );
89 static struct container *create_key_container( const char *name, DWORD flags )
91 struct container *ret;
93 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
94 ret->magic = MAGIC_CONTAINER;
95 ret->flags = flags;
96 if (name) strcpy( ret->name, name );
98 if (!(flags & CRYPT_VERIFYCONTEXT))
100 HKEY hkey;
101 if (create_container_regkey( ret, KEY_WRITE, &hkey )) RegCloseKey( hkey );
103 return ret;
106 static BOOL open_container_regkey( const char *name, DWORD flags, REGSAM access, HKEY *hkey )
108 char path[sizeof(dss_path_fmt) + MAX_PATH];
109 HKEY rootkey;
111 sprintf( path, dss_path_fmt, name );
113 if (flags & CRYPT_MACHINE_KEYSET)
114 rootkey = HKEY_LOCAL_MACHINE;
115 else
116 rootkey = HKEY_CURRENT_USER;
118 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
119 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
120 return !RegOpenKeyExA( rootkey, path, 0, access, hkey );
123 static const WCHAR *map_keyspec_to_keypair_name( DWORD keyspec )
125 const WCHAR *name;
127 switch (keyspec)
129 case AT_KEYEXCHANGE:
130 name = L"KeyExchangeKeyPair";
131 break;
132 case AT_SIGNATURE:
133 name = L"SignatureKeyPair";
134 break;
135 default:
136 ERR( "invalid key spec %u\n", keyspec );
137 return NULL;
139 return name;
142 static struct key *create_key( ALG_ID algid, DWORD flags )
144 struct key *ret;
145 const WCHAR *alg;
147 switch (algid)
149 case AT_SIGNATURE:
150 case CALG_DSS_SIGN:
151 alg = BCRYPT_DSA_ALGORITHM;
152 break;
154 default:
155 FIXME( "unhandled algorithm %08x\n", algid );
156 return NULL;
159 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
161 ret->magic = MAGIC_KEY;
162 ret->algid = algid;
163 ret->flags = flags;
164 if (BCryptOpenAlgorithmProvider( &ret->alg_handle, alg, MS_PRIMITIVE_PROVIDER, 0 ))
166 heap_free( ret );
167 return NULL;
169 return ret;
172 static void destroy_key( struct key *key )
174 if (!key) return;
175 BCryptDestroyKey( key->handle );
176 BCryptCloseAlgorithmProvider( key->alg_handle, 0 );
177 key->magic = 0;
178 heap_free( key );
181 static struct key *import_key( DWORD keyspec, BYTE *data, DWORD len )
183 struct key *ret;
185 if (!(ret = create_key( keyspec, 0 ))) return NULL;
187 if (BCryptImportKeyPair( ret->alg_handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, &ret->handle, data, len, 0 ))
189 WARN( "failed to import key\n" );
190 destroy_key( ret );
191 return NULL;
193 return ret;
196 static struct key *read_key( HKEY hkey, DWORD keyspec, DWORD flags )
198 const WCHAR *value;
199 DWORD type, len;
200 BYTE *data;
201 DATA_BLOB blob_in, blob_out;
202 struct key *ret = NULL;
204 if (!(value = map_keyspec_to_keypair_name( keyspec ))) return NULL;
205 if (RegQueryValueExW( hkey, value, 0, &type, NULL, &len )) return NULL;
206 if (!(data = heap_alloc( len ))) return NULL;
208 if (!RegQueryValueExW( hkey, value, 0, &type, data, &len ))
210 blob_in.pbData = data;
211 blob_in.cbData = len;
212 if (CryptUnprotectData( &blob_in, NULL, NULL, NULL, NULL, flags, &blob_out ))
214 ret = import_key( keyspec, blob_out.pbData, blob_out.cbData );
215 LocalFree( blob_out.pbData );
219 heap_free( data );
220 return ret;
223 static void destroy_container( struct container *container )
225 if (!container) return;
226 destroy_key( container->exch_key );
227 destroy_key( container->sign_key );
228 container->magic = 0;
229 heap_free( container );
232 static struct container *read_key_container( const char *name, DWORD flags )
234 DWORD protect_flags = (flags & CRYPT_MACHINE_KEYSET) ? CRYPTPROTECT_LOCAL_MACHINE : 0;
235 struct container *ret;
236 HKEY hkey;
238 if (!open_container_regkey( name, flags, KEY_READ, &hkey )) return NULL;
240 if ((ret = create_key_container( name, flags )))
242 ret->exch_key = read_key( hkey, AT_KEYEXCHANGE, protect_flags );
243 ret->sign_key = read_key( hkey, AT_SIGNATURE, protect_flags );
246 RegCloseKey( hkey );
247 return ret;
250 static void delete_key_container( const char *name, DWORD flags )
252 char path[sizeof(dss_path_fmt) + MAX_PATH];
253 HKEY rootkey;
255 sprintf( path, dss_path_fmt, name );
257 if (flags & CRYPT_MACHINE_KEYSET)
258 rootkey = HKEY_LOCAL_MACHINE;
259 else
260 rootkey = HKEY_CURRENT_USER;
262 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
263 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
264 RegDeleteKeyExA( rootkey, path, 0, 0 );
267 BOOL WINAPI CPAcquireContext( HCRYPTPROV *ret_prov, LPSTR container, DWORD flags, PVTableProvStruc vtable )
269 struct container *ret;
270 char name[MAX_PATH];
272 TRACE( "%p, %s, %08x, %p\n", ret_prov, debugstr_a(container), flags, vtable );
274 if (container && *container)
276 if (lstrlenA( container ) >= sizeof(name)) return FALSE;
277 lstrcpyA( name, container );
279 else
281 DWORD len = sizeof(name);
282 if (!GetUserNameA( name, &len )) return FALSE;
285 switch (flags)
287 case 0:
288 case 0 | CRYPT_MACHINE_KEYSET:
289 ret = read_key_container( name, flags );
290 break;
292 case CRYPT_NEWKEYSET:
293 case CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET:
294 if ((ret = read_key_container( name, flags )))
296 heap_free( ret );
297 SetLastError( NTE_EXISTS );
298 return FALSE;
300 ret = create_key_container( name, flags );
301 break;
303 case CRYPT_VERIFYCONTEXT:
304 case CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET:
305 ret = create_key_container( "", flags );
306 break;
308 case CRYPT_DELETEKEYSET:
309 case CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET:
310 delete_key_container( name, flags );
311 *ret_prov = 0;
312 return TRUE;
314 default:
315 FIXME( "unsupported flags %08x\n", flags );
316 return FALSE;
319 if (!ret) return FALSE;
320 *ret_prov = (HCRYPTPROV)ret;
321 return TRUE;
324 BOOL WINAPI CPReleaseContext( HCRYPTPROV hprov, DWORD flags )
326 struct container *container = (struct container *)hprov;
328 TRACE( "%p, %08x\n", (void *)hprov, flags );
330 if (container->magic != MAGIC_CONTAINER) return FALSE;
331 destroy_container( container );
332 return TRUE;
335 BOOL WINAPI CPGetProvParam( HCRYPTPROV hprov, DWORD param, BYTE *data, DWORD *len, DWORD flags )
337 return FALSE;
340 static BOOL store_key_pair( struct key *key, HKEY hkey, DWORD keyspec, DWORD flags )
342 const WCHAR *value;
343 DATA_BLOB blob_in, blob_out;
344 DWORD len;
345 BYTE *data;
346 BOOL ret = TRUE;
348 if (!key) return TRUE;
349 if (!(value = map_keyspec_to_keypair_name( keyspec ))) return FALSE;
351 if (BCryptExportKey( key->handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, NULL, 0, &len, 0 )) return FALSE;
352 if (!(data = heap_alloc( len ))) return FALSE;
354 if (!BCryptExportKey( key->handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, data, len, &len, 0 ))
356 blob_in.pbData = data;
357 blob_in.cbData = len;
358 if ((ret = CryptProtectData( &blob_in, NULL, NULL, NULL, NULL, flags, &blob_out )))
360 ret = !RegSetValueExW( hkey, value, 0, REG_BINARY, blob_out.pbData, blob_out.cbData );
361 LocalFree( blob_out.pbData );
365 heap_free( data );
366 return ret;
369 static BOOL store_key_container_keys( struct container *container )
371 HKEY hkey;
372 DWORD flags;
373 BOOL ret;
375 if (container->flags & CRYPT_MACHINE_KEYSET)
376 flags = CRYPTPROTECT_LOCAL_MACHINE;
377 else
378 flags = 0;
380 if (!create_container_regkey( container, KEY_WRITE, &hkey )) return FALSE;
382 ret = store_key_pair( container->exch_key, hkey, AT_KEYEXCHANGE, flags );
383 if (ret) store_key_pair( container->sign_key, hkey, AT_SIGNATURE, flags );
384 RegCloseKey( hkey );
385 return ret;
388 static struct key *duplicate_key( const struct key *key )
390 struct key *ret;
392 if (!(ret = create_key( key->algid, key->flags ))) return NULL;
394 if (BCryptDuplicateKey( key->handle, &ret->handle, NULL, 0, 0 ))
396 heap_free( ret );
397 return NULL;
399 return ret;
402 static BOOL generate_key( struct container *container, ALG_ID algid, DWORD bitlen, DWORD flags, HCRYPTKEY *ret_key )
404 struct key *key, *sign_key;
405 NTSTATUS status;
407 if (!(key = create_key( algid, flags ))) return FALSE;
409 if ((status = BCryptGenerateKeyPair( key->alg_handle, &key->handle, bitlen, 0 )))
411 ERR( "failed to generate key %08x\n", status );
412 destroy_key( key );
413 return FALSE;
415 if ((status = BCryptFinalizeKeyPair( key->handle, 0 )))
417 ERR( "failed to finalize key %08x\n", status );
418 destroy_key( key );
419 return FALSE;
422 switch (algid)
424 case AT_SIGNATURE:
425 case CALG_DSS_SIGN:
426 if (!(sign_key = duplicate_key( key )))
428 destroy_key( key );
429 return FALSE;
431 destroy_key( container->sign_key );
432 container->sign_key = sign_key;
433 break;
435 default:
436 FIXME( "unhandled algorithm %08x\n", algid );
437 return FALSE;
440 if (!store_key_container_keys( container )) return FALSE;
442 *ret_key = (HCRYPTKEY)key;
443 return TRUE;
446 BOOL WINAPI CPGenKey( HCRYPTPROV hprov, ALG_ID algid, DWORD flags, HCRYPTKEY *ret_key )
448 static const unsigned int supported_key_lengths[] = { 512, 768, 1024 };
449 struct container *container = (struct container *)hprov;
450 ULONG i, bitlen = HIWORD(flags) ? HIWORD(flags) : 1024;
452 TRACE( "%p, %08x, %08x, %p\n", (void *)hprov, algid, flags, ret_key );
454 if (container->magic != MAGIC_CONTAINER) return FALSE;
456 if (bitlen % 2)
458 SetLastError( STATUS_INVALID_PARAMETER );
459 return FALSE;
461 for (i = 0; i < ARRAY_SIZE(supported_key_lengths); i++)
463 if (bitlen == supported_key_lengths[i]) break;
465 if (i >= ARRAY_SIZE(supported_key_lengths))
467 SetLastError( NTE_BAD_FLAGS );
468 return FALSE;
471 return generate_key( container, algid, bitlen, LOWORD(flags), ret_key );
474 BOOL WINAPI CPDestroyKey( HCRYPTPROV hprov, HCRYPTKEY hkey )
476 struct key *key = (struct key *)hkey;
478 TRACE( "%p, %p\n", (void *)hprov, (void *)hkey );
480 if (key->magic != MAGIC_KEY)
482 SetLastError( NTE_BAD_KEY );
483 return FALSE;
486 destroy_key( key );
487 return TRUE;
490 #define MAGIC_DSS1 ('D' | ('S' << 8) | ('S' << 16) | ('1' << 24))
491 #define MAGIC_DSS2 ('D' | ('S' << 8) | ('S' << 16) | ('2' << 24))
492 #define MAGIC_DSS3 ('D' | ('S' << 8) | ('S' << 16) | ('3' << 24))
494 static BOOL import_key_dss2( struct container *container, ALG_ID algid, const BYTE *data, DWORD len, DWORD flags,
495 HCRYPTKEY *ret_key )
497 const BLOBHEADER *hdr = (const BLOBHEADER *)data;
498 const DSSPUBKEY *pubkey = (const DSSPUBKEY *)(hdr + 1);
499 const WCHAR *type;
500 struct key *key, *exch_key, *sign_key;
501 NTSTATUS status;
503 if (len < sizeof(*hdr) + sizeof(*pubkey)) return FALSE;
505 switch (pubkey->magic)
507 case MAGIC_DSS1:
508 type = LEGACY_DSA_V2_PUBLIC_BLOB;
509 break;
511 case MAGIC_DSS2:
512 type = LEGACY_DSA_V2_PRIVATE_BLOB;
513 break;
515 default:
516 FIXME( "unsupported key magic %08x\n", pubkey->magic );
517 return FALSE;
520 if (!(key = create_key( CALG_DSS_SIGN, flags ))) return FALSE;
522 if ((status = BCryptImportKeyPair( key->alg_handle, NULL, type, &key->handle, (UCHAR *)data, len, 0 )))
524 TRACE( "failed to import key %08x\n", status );
525 destroy_key( key );
526 return FALSE;
529 if (!wcscmp(type, LEGACY_DSA_V2_PRIVATE_BLOB))
531 switch (algid)
533 case AT_KEYEXCHANGE:
534 case CALG_DH_SF:
535 if (!(exch_key = duplicate_key( key )))
537 destroy_key( key );
538 return FALSE;
540 destroy_key( container->exch_key );
541 container->exch_key = exch_key;
542 break;
544 case AT_SIGNATURE:
545 case CALG_DSS_SIGN:
546 if (!(sign_key = duplicate_key( key )))
548 destroy_key( key );
549 return FALSE;
551 destroy_key( container->sign_key );
552 container->sign_key = sign_key;
553 break;
555 default:
556 FIXME( "unhandled key algorithm %u\n", algid );
557 destroy_key( key );
558 return FALSE;
561 if (!store_key_container_keys( container )) return FALSE;
564 *ret_key = (HCRYPTKEY)key;
565 return TRUE;
568 static BOOL import_key_dss3( struct container *container, ALG_ID algid, const BYTE *data, DWORD len, DWORD flags,
569 HCRYPTKEY *ret_key )
571 const BLOBHEADER *hdr = (const BLOBHEADER *)data;
572 const DSSPUBKEY_VER3 *pubkey = (const DSSPUBKEY_VER3 *)(hdr + 1);
573 BCRYPT_DSA_KEY_BLOB *blob;
574 struct key *key;
575 BYTE *src, *dst;
576 ULONG i, size, size_q;
577 NTSTATUS status;
579 if (len < sizeof(*hdr) + sizeof(*pubkey)) return FALSE;
581 switch (pubkey->magic)
583 case MAGIC_DSS3:
584 break;
586 default:
587 FIXME( "unsupported key magic %08x\n", pubkey->magic );
588 return FALSE;
591 if ((size_q = pubkey->bitlenQ / 8) > sizeof(blob->q))
593 FIXME( "q too large\n" );
594 return FALSE;
597 if (!(key = create_key( CALG_DSS_SIGN, flags ))) return FALSE;
599 size = sizeof(*blob) + (pubkey->bitlenP / 8) * 3;
600 if (!(blob = heap_alloc_zero( size )))
602 destroy_key( key );
603 return FALSE;
605 blob->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC;
606 blob->cbKey = pubkey->bitlenP / 8;
607 memcpy( blob->Count, &pubkey->DSSSeed.counter, sizeof(blob->Count) );
608 memcpy( blob->Seed, pubkey->DSSSeed.seed, sizeof(blob->Seed) );
610 /* q */
611 src = (BYTE *)(pubkey + 1) + blob->cbKey;
612 for (i = 0; i < size_q; i++) blob->q[i] = src[size_q - i - 1];
614 /* p */
615 src -= blob->cbKey;
616 dst = (BYTE *)(blob + 1);
617 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
619 /* g */
620 src += blob->cbKey + size_q;
621 dst += blob->cbKey;
622 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
624 /* y */
625 src += blob->cbKey + pubkey->bitlenJ / 8;
626 dst += blob->cbKey;
627 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
629 if ((status = BCryptImportKeyPair( key->alg_handle, NULL, BCRYPT_DSA_PUBLIC_BLOB, &key->handle, (UCHAR *)blob,
630 size, 0 )))
632 WARN( "failed to import key %08x\n", status );
633 destroy_key( key );
634 heap_free( blob );
635 return FALSE;
638 heap_free( blob );
639 *ret_key = (HCRYPTKEY)key;
640 return TRUE;
643 BOOL WINAPI CPImportKey( HCRYPTPROV hprov, const BYTE *data, DWORD len, HCRYPTKEY hpubkey, DWORD flags,
644 HCRYPTKEY *ret_key )
646 struct container *container = (struct container *)hprov;
647 const BLOBHEADER *hdr;
648 BOOL ret;
650 TRACE( "%p, %p, %u, %p, %08x, %p\n", (void *)hprov, data, len, (void *)hpubkey, flags, ret_key );
652 if (container->magic != MAGIC_CONTAINER) return FALSE;
653 if (len < sizeof(*hdr)) return FALSE;
655 hdr = (const BLOBHEADER *)data;
656 if ((hdr->bType != PRIVATEKEYBLOB && hdr->bType != PUBLICKEYBLOB) || hdr->aiKeyAlg != CALG_DSS_SIGN)
658 FIXME( "bType %u aiKeyAlg %08x not supported\n", hdr->bType, hdr->aiKeyAlg );
659 return FALSE;
662 switch (hdr->bVersion)
664 case 2:
665 ret = import_key_dss2( container, hdr->aiKeyAlg, data, len, flags, ret_key );
666 break;
668 case 3:
669 ret = import_key_dss3( container, hdr->aiKeyAlg, data, len, flags, ret_key );
670 break;
672 default:
673 FIXME( "version %u not supported\n", hdr->bVersion );
674 return FALSE;
677 return ret;
680 BOOL WINAPI CPExportKey( HCRYPTPROV hprov, HCRYPTKEY hkey, HCRYPTKEY hexpkey, DWORD blobtype, DWORD flags,
681 BYTE *data, DWORD *len )
683 struct key *key = (struct key *)hkey;
684 const WCHAR *type;
686 TRACE( "%p, %p, %p, %08x, %08x, %p, %p\n", (void *)hprov, (void *)hkey, (void *)hexpkey, blobtype, flags,
687 data, len );
689 if (key->magic != MAGIC_KEY) return FALSE;
690 if (hexpkey)
692 FIXME( "export key not supported\n" );
693 return FALSE;
695 if (flags)
697 FIXME( "flags %08x not supported\n", flags );
698 return FALSE;
701 switch (blobtype)
703 case PUBLICKEYBLOB:
704 type = LEGACY_DSA_V2_PUBLIC_BLOB;
705 break;
707 case PRIVATEKEYBLOB:
708 type = LEGACY_DSA_V2_PRIVATE_BLOB;
709 break;
711 default:
712 FIXME( "blob type %u not supported\n", blobtype );
713 return FALSE;
716 return !BCryptExportKey( key->handle, NULL, type, data, *len, len, 0 );
719 BOOL WINAPI CPDuplicateKey( HCRYPTPROV hprov, HCRYPTKEY hkey, DWORD *reserved, DWORD flags, HCRYPTKEY *ret_key )
721 struct key *key = (struct key *)hkey, *ret;
723 TRACE( "%p, %p, %p, %08x, %p\n", (void *)hprov, (void *)hkey, reserved, flags, ret_key );
725 if (key->magic != MAGIC_KEY) return FALSE;
727 if (!(ret = duplicate_key( key ))) return FALSE;
728 *ret_key = (HCRYPTKEY)ret;
729 return TRUE;
732 BOOL WINAPI CPGetUserKey( HCRYPTPROV hprov, DWORD keyspec, HCRYPTKEY *ret_key )
734 struct container *container = (struct container *)hprov;
735 BOOL ret = FALSE;
737 TRACE( "%p, %08x, %p\n", (void *)hprov, keyspec, ret_key );
739 if (container->magic != MAGIC_CONTAINER) return FALSE;
741 switch (keyspec)
743 case AT_KEYEXCHANGE:
744 if (!container->exch_key) SetLastError( NTE_NO_KEY );
745 else if ((*ret_key = (HCRYPTKEY)duplicate_key( container->exch_key ))) ret = TRUE;
746 break;
748 case AT_SIGNATURE:
749 if (!container->sign_key) SetLastError( NTE_NO_KEY );
750 else if ((*ret_key = (HCRYPTKEY)duplicate_key( container->sign_key ))) ret = TRUE;
751 break;
753 default:
754 SetLastError( NTE_NO_KEY );
755 return FALSE;
758 return ret;
761 BOOL WINAPI CPGenRandom( HCRYPTPROV hprov, DWORD len, BYTE *buffer )
763 struct container *container = (struct container *)hprov;
765 TRACE( "%p, %u, %p\n", (void *)hprov, len, buffer );
767 if (container->magic != MAGIC_CONTAINER) return FALSE;
769 return RtlGenRandom( buffer, len );
772 static struct hash *create_hash( ALG_ID algid )
774 struct hash *ret;
775 BCRYPT_ALG_HANDLE alg_handle;
776 const WCHAR *alg;
777 DWORD len;
779 switch (algid)
781 case CALG_MD5:
782 alg = BCRYPT_MD5_ALGORITHM;
783 len = 16;
784 break;
786 case CALG_SHA1:
787 alg = BCRYPT_SHA1_ALGORITHM;
788 len = 20;
789 break;
791 default:
792 FIXME( "unhandled algorithm %u\n", algid );
793 return NULL;
796 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
798 ret->magic = MAGIC_HASH;
799 ret->len = len;
800 if (BCryptOpenAlgorithmProvider( &alg_handle, alg, MS_PRIMITIVE_PROVIDER, 0 ))
802 heap_free( ret );
803 return NULL;
805 if (BCryptCreateHash( alg_handle, &ret->handle, NULL, 0, NULL, 0, 0 ))
807 BCryptCloseAlgorithmProvider( alg_handle, 0 );
808 heap_free( ret );
809 return NULL;
812 BCryptCloseAlgorithmProvider( alg_handle, 0 );
813 return ret;
816 BOOL WINAPI CPCreateHash( HCRYPTPROV hprov, ALG_ID algid, HCRYPTKEY hkey, DWORD flags, HCRYPTHASH *ret_hash )
818 struct hash *hash;
820 TRACE( "%p, %08x, %p, %08x, %p\n", (void *)hprov, algid, (void *)hkey, flags, ret_hash );
822 switch (algid)
824 case CALG_MD5:
825 case CALG_SHA1:
826 break;
828 default:
829 FIXME( "algorithm %u not supported\n", algid );
830 SetLastError( NTE_BAD_ALGID );
831 return FALSE;
834 if (!(hash = create_hash( algid ))) return FALSE;
836 *ret_hash = (HCRYPTHASH)hash;
837 return TRUE;
840 static void destroy_hash( struct hash *hash )
842 if (!hash) return;
843 BCryptDestroyHash( hash->handle );
844 hash->magic = 0;
845 heap_free( hash );
848 BOOL WINAPI CPDestroyHash( HCRYPTPROV hprov, HCRYPTHASH hhash )
850 struct hash *hash = (struct hash *)hhash;
852 TRACE( "%p, %p\n", (void *)hprov, (void *)hhash);
854 if (hash->magic != MAGIC_HASH)
856 SetLastError( NTE_BAD_HASH );
857 return FALSE;
860 destroy_hash( hash );
861 return TRUE;
864 static struct hash *duplicate_hash( const struct hash *hash )
866 struct hash *ret;
868 if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
870 ret->magic = hash->magic;
871 ret->len = hash->len;
872 if (BCryptDuplicateHash( hash->handle, &ret->handle, NULL, 0, 0 ))
874 heap_free( ret );
875 return NULL;
877 memcpy( ret->value, hash->value, sizeof(hash->value) );
878 ret->finished = hash->finished;
879 return ret;
882 BOOL WINAPI CPDuplicateHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD *reserved, DWORD flags, HCRYPTHASH *ret_hash )
884 struct hash *hash = (struct hash *)hhash, *ret;
886 TRACE( "%p, %p, %p, %08x, %p\n", (void *)hprov, (void *)hhash, reserved, flags, ret_hash );
888 if (hash->magic != MAGIC_HASH) return FALSE;
890 if (!(ret = duplicate_hash( hash ))) return FALSE;
891 *ret_hash = (HCRYPTHASH)ret;
892 return TRUE;
895 BOOL WINAPI CPHashData( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *data, DWORD len, DWORD flags )
897 struct hash *hash = (struct hash *)hhash;
899 TRACE("%p, %p, %p, %u, %08x\n", (void *)hprov, (void *)hhash, data, len, flags );
901 if (hash->magic != MAGIC_HASH) return FALSE;
903 if (hash->finished)
905 SetLastError( NTE_BAD_HASH_STATE );
906 return FALSE;
908 return !BCryptHashData( hash->handle, (UCHAR *)data, len, 0 );
911 BOOL WINAPI CPGetHashParam( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD param, BYTE *data, DWORD *len, DWORD flags )
913 struct hash *hash = (struct hash *)hhash;
915 TRACE( "%p, %p, %08x, %p, %p, %08x\n", (void *)hprov, (void *)hhash, param, data, len, flags );
917 if (hash->magic != MAGIC_HASH) return FALSE;
919 switch (param)
921 case HP_HASHSIZE:
922 if (sizeof(hash->len) > *len)
924 *len = sizeof(hash->len);
925 SetLastError( ERROR_MORE_DATA );
926 return FALSE;
928 *(DWORD *)data = hash->len;
929 *len = sizeof(hash->len);
930 return TRUE;
932 case HP_HASHVAL:
933 if (!hash->finished)
935 if (BCryptFinishHash( hash->handle, hash->value, hash->len, 0 )) return FALSE;
936 hash->finished = TRUE;
938 if (hash->len > *len)
940 *len = hash->len;
941 SetLastError( ERROR_MORE_DATA );
942 return FALSE;
944 memcpy( data, hash->value, hash->len );
945 *len = hash->len;
946 return TRUE;
948 default:
949 SetLastError( NTE_BAD_TYPE );
950 return FALSE;
954 BOOL WINAPI CPSetHashParam( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD param, const BYTE *data, DWORD flags )
956 struct hash *hash = (struct hash *)hhash;
958 TRACE( "%p, %p, %08x, %p, %08x\n", (void *)hprov, (void *)hhash, param, data, flags );
960 if (hash->magic != MAGIC_HASH) return FALSE;
962 switch (param)
964 case HP_HASHVAL:
965 memcpy( hash->value, data, hash->len );
966 return TRUE;
968 default:
969 FIXME( "param %u not supported\n", param );
970 SetLastError( NTE_BAD_TYPE );
971 return FALSE;
975 BOOL WINAPI CPDeriveKey( HCRYPTPROV hprov, ALG_ID algid, HCRYPTHASH hhash, DWORD flags, HCRYPTKEY *ret_key )
977 return FALSE;
980 static DWORD get_signature_length( DWORD algid )
982 switch (algid)
984 case AT_SIGNATURE:
985 case CALG_DSS_SIGN: return 40;
986 default:
987 FIXME( "unhandled algorithm %u\n", algid );
988 return 0;
992 #define MAX_HASH_LEN 20
993 BOOL WINAPI CPSignHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD keyspec, const WCHAR *desc, DWORD flags, BYTE *sig,
994 DWORD *siglen )
996 struct container *container = (struct container *)hprov;
997 struct hash *hash = (struct hash *)hhash;
998 ULONG len;
1000 TRACE( "%p, %p, %u, %s, %08x, %p, %p\n", (void *)hprov, (void *)hhash, keyspec, debugstr_w(desc), flags, sig,
1001 siglen );
1003 if (container->magic != MAGIC_CONTAINER || !container->sign_key) return FALSE;
1004 if (hash->magic != MAGIC_HASH) return FALSE;
1006 if (!(len = get_signature_length( container->sign_key->algid ))) return FALSE;
1007 if (*siglen < len)
1009 *siglen = len;
1010 return TRUE;
1013 return !BCryptSignHash( container->sign_key->handle, NULL, hash->value, hash->len, sig, *siglen, siglen, 0 );
1016 BOOL WINAPI CPVerifySignature( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *sig, DWORD siglen, HCRYPTKEY hpubkey,
1017 const WCHAR *desc, DWORD flags )
1019 struct hash *hash = (struct hash *)hhash;
1020 struct key *key = (struct key *)hpubkey;
1022 TRACE( "%p, %p, %p, %u %p, %s, %08x\n", (void *)hprov, (void *)hhash, sig, siglen, (void *)hpubkey,
1023 debugstr_w(desc), flags );
1025 if (hash->magic != MAGIC_HASH || key->magic != MAGIC_KEY) return FALSE;
1026 if (flags)
1028 FIXME( "flags %08x not supported\n", flags );
1029 return FALSE;
1032 return !BCryptVerifySignature( key->handle, NULL, hash->value, hash->len, (UCHAR *)sig, siglen, 0 );
1035 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1037 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1039 switch (fdwReason)
1041 case DLL_PROCESS_ATTACH:
1042 instance = hinstDLL;
1043 DisableThreadLibraryCalls(hinstDLL);
1044 break;
1046 return TRUE;
1049 /*****************************************************
1050 * DllRegisterServer (DSSENH.@)
1052 HRESULT WINAPI DllRegisterServer(void)
1054 return __wine_register_resources( instance );
1057 /*****************************************************
1058 * DllUnregisterServer (DSSENH.@)
1060 HRESULT WINAPI DllUnregisterServer(void)
1062 return __wine_unregister_resources( instance );