hidclass.sys: Return STATUS_INVALID_USER_BUFFER if buffer_len is 0.
[wine.git] / dlls / dssenh / main.c
blob8344b5a321b0d0bef2cbb53335d7558ae19ad503
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 WINE_DEFAULT_DEBUG_CHANNEL(dssenh);
38 #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0')
39 struct key
41 DWORD magic;
42 DWORD algid;
43 DWORD flags;
44 BCRYPT_ALG_HANDLE alg_handle;
45 BCRYPT_KEY_HANDLE handle;
48 #define MAGIC_CONTAINER (('C' << 24) | ('O' << 16) | ('N' << 8) | 'T')
49 struct container
51 DWORD magic;
52 DWORD flags;
53 struct key *exch_key;
54 struct key *sign_key;
55 char name[MAX_PATH];
58 #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
59 struct hash
61 DWORD magic;
62 BCRYPT_HASH_HANDLE handle;
63 DWORD len;
64 UCHAR value[64];
65 BOOL finished;
68 static const char dss_path_fmt[] = "Software\\Wine\\Crypto\\DSS\\%s";
70 static BOOL create_container_regkey( struct container *container, REGSAM sam, HKEY *hkey )
72 char path[sizeof(dss_path_fmt) + MAX_PATH];
73 HKEY rootkey;
75 sprintf( path, dss_path_fmt, container->name );
77 if (container->flags & CRYPT_MACHINE_KEYSET)
78 rootkey = HKEY_LOCAL_MACHINE;
79 else
80 rootkey = HKEY_CURRENT_USER;
82 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
83 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
84 return !RegCreateKeyExA( rootkey, path, 0, NULL, REG_OPTION_NON_VOLATILE, sam, NULL, hkey, NULL );
87 static struct container *create_key_container( const char *name, DWORD flags )
89 struct container *ret;
91 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
92 ret->magic = MAGIC_CONTAINER;
93 ret->flags = flags;
94 if (name) strcpy( ret->name, name );
96 if (!(flags & CRYPT_VERIFYCONTEXT))
98 HKEY hkey;
99 if (create_container_regkey( ret, KEY_WRITE, &hkey )) RegCloseKey( hkey );
101 return ret;
104 static BOOL open_container_regkey( const char *name, DWORD flags, REGSAM access, HKEY *hkey )
106 char path[sizeof(dss_path_fmt) + MAX_PATH];
107 HKEY rootkey;
109 sprintf( path, dss_path_fmt, name );
111 if (flags & CRYPT_MACHINE_KEYSET)
112 rootkey = HKEY_LOCAL_MACHINE;
113 else
114 rootkey = HKEY_CURRENT_USER;
116 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
117 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
118 return !RegOpenKeyExA( rootkey, path, 0, access, hkey );
121 static const WCHAR *map_keyspec_to_keypair_name( DWORD keyspec )
123 const WCHAR *name;
125 switch (keyspec)
127 case AT_KEYEXCHANGE:
128 name = L"KeyExchangeKeyPair";
129 break;
130 case AT_SIGNATURE:
131 name = L"SignatureKeyPair";
132 break;
133 default:
134 ERR( "invalid key spec %u\n", keyspec );
135 return NULL;
137 return name;
140 static struct key *create_key( ALG_ID algid, DWORD flags )
142 struct key *ret;
143 const WCHAR *alg;
145 switch (algid)
147 case AT_SIGNATURE:
148 case CALG_DSS_SIGN:
149 alg = BCRYPT_DSA_ALGORITHM;
150 break;
152 default:
153 FIXME( "unhandled algorithm %08x\n", algid );
154 return NULL;
157 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
159 ret->magic = MAGIC_KEY;
160 ret->algid = algid;
161 ret->flags = flags;
162 if (BCryptOpenAlgorithmProvider( &ret->alg_handle, alg, MS_PRIMITIVE_PROVIDER, 0 ))
164 heap_free( ret );
165 return NULL;
167 return ret;
170 static void destroy_key( struct key *key )
172 if (!key) return;
173 BCryptDestroyKey( key->handle );
174 BCryptCloseAlgorithmProvider( key->alg_handle, 0 );
175 key->magic = 0;
176 heap_free( key );
179 static struct key *import_key( DWORD keyspec, BYTE *data, DWORD len )
181 struct key *ret;
183 if (!(ret = create_key( keyspec, 0 ))) return NULL;
185 if (BCryptImportKeyPair( ret->alg_handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, &ret->handle, data, len, 0 ))
187 WARN( "failed to import key\n" );
188 destroy_key( ret );
189 return NULL;
191 return ret;
194 static struct key *read_key( HKEY hkey, DWORD keyspec, DWORD flags )
196 const WCHAR *value;
197 DWORD type, len;
198 BYTE *data;
199 DATA_BLOB blob_in, blob_out;
200 struct key *ret = NULL;
202 if (!(value = map_keyspec_to_keypair_name( keyspec ))) return NULL;
203 if (RegQueryValueExW( hkey, value, 0, &type, NULL, &len )) return NULL;
204 if (!(data = heap_alloc( len ))) return NULL;
206 if (!RegQueryValueExW( hkey, value, 0, &type, data, &len ))
208 blob_in.pbData = data;
209 blob_in.cbData = len;
210 if (CryptUnprotectData( &blob_in, NULL, NULL, NULL, NULL, flags, &blob_out ))
212 ret = import_key( keyspec, blob_out.pbData, blob_out.cbData );
213 LocalFree( blob_out.pbData );
217 heap_free( data );
218 return ret;
221 static void destroy_container( struct container *container )
223 if (!container) return;
224 destroy_key( container->exch_key );
225 destroy_key( container->sign_key );
226 container->magic = 0;
227 heap_free( container );
230 static struct container *read_key_container( const char *name, DWORD flags )
232 DWORD protect_flags = (flags & CRYPT_MACHINE_KEYSET) ? CRYPTPROTECT_LOCAL_MACHINE : 0;
233 struct container *ret;
234 HKEY hkey;
236 if (!open_container_regkey( name, flags, KEY_READ, &hkey )) return NULL;
238 if ((ret = create_key_container( name, flags )))
240 ret->exch_key = read_key( hkey, AT_KEYEXCHANGE, protect_flags );
241 ret->sign_key = read_key( hkey, AT_SIGNATURE, protect_flags );
244 RegCloseKey( hkey );
245 return ret;
248 static void delete_key_container( const char *name, DWORD flags )
250 char path[sizeof(dss_path_fmt) + MAX_PATH];
251 HKEY rootkey;
253 sprintf( path, dss_path_fmt, name );
255 if (flags & CRYPT_MACHINE_KEYSET)
256 rootkey = HKEY_LOCAL_MACHINE;
257 else
258 rootkey = HKEY_CURRENT_USER;
260 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
261 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
262 RegDeleteKeyExA( rootkey, path, 0, 0 );
265 BOOL WINAPI CPAcquireContext( HCRYPTPROV *ret_prov, LPSTR container, DWORD flags, PVTableProvStruc vtable )
267 struct container *ret;
268 char name[MAX_PATH];
270 TRACE( "%p, %s, %08x, %p\n", ret_prov, debugstr_a(container), flags, vtable );
272 if (container && *container)
274 if (lstrlenA( container ) >= sizeof(name)) return FALSE;
275 lstrcpyA( name, container );
277 else
279 DWORD len = sizeof(name);
280 if (!GetUserNameA( name, &len )) return FALSE;
283 switch (flags)
285 case 0:
286 case 0 | CRYPT_MACHINE_KEYSET:
287 if (!(ret = read_key_container( name, flags )))
288 SetLastError( NTE_BAD_KEYSET );
289 break;
291 case CRYPT_NEWKEYSET:
292 case CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET:
293 if ((ret = read_key_container( name, flags )))
295 heap_free( ret );
296 SetLastError( NTE_EXISTS );
297 return FALSE;
299 ret = create_key_container( name, flags );
300 break;
302 case CRYPT_VERIFYCONTEXT:
303 case CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET:
304 ret = create_key_container( "", flags );
305 break;
307 case CRYPT_DELETEKEYSET:
308 case CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET:
309 delete_key_container( name, flags );
310 *ret_prov = 0;
311 return TRUE;
313 default:
314 FIXME( "unsupported flags %08x\n", flags );
315 return FALSE;
318 if (!ret) return FALSE;
319 *ret_prov = (HCRYPTPROV)ret;
320 return TRUE;
323 BOOL WINAPI CPReleaseContext( HCRYPTPROV hprov, DWORD flags )
325 struct container *container = (struct container *)hprov;
327 TRACE( "%p, %08x\n", (void *)hprov, flags );
329 if (container->magic != MAGIC_CONTAINER) return FALSE;
330 destroy_container( container );
331 return TRUE;
334 BOOL WINAPI CPGetProvParam( HCRYPTPROV hprov, DWORD param, BYTE *data, DWORD *len, DWORD flags )
336 return FALSE;
339 static BOOL store_key_pair( struct key *key, HKEY hkey, DWORD keyspec, DWORD flags )
341 const WCHAR *value;
342 DATA_BLOB blob_in, blob_out;
343 DWORD len;
344 BYTE *data;
345 BOOL ret = TRUE;
347 if (!key) return TRUE;
348 if (!(value = map_keyspec_to_keypair_name( keyspec ))) return FALSE;
350 if (BCryptExportKey( key->handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, NULL, 0, &len, 0 )) return FALSE;
351 if (!(data = heap_alloc( len ))) return FALSE;
353 if (!BCryptExportKey( key->handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, data, len, &len, 0 ))
355 blob_in.pbData = data;
356 blob_in.cbData = len;
357 if ((ret = CryptProtectData( &blob_in, NULL, NULL, NULL, NULL, flags, &blob_out )))
359 ret = !RegSetValueExW( hkey, value, 0, REG_BINARY, blob_out.pbData, blob_out.cbData );
360 LocalFree( blob_out.pbData );
364 heap_free( data );
365 return ret;
368 static BOOL store_key_container_keys( struct container *container )
370 HKEY hkey;
371 DWORD flags;
372 BOOL ret;
374 if (container->flags & CRYPT_MACHINE_KEYSET)
375 flags = CRYPTPROTECT_LOCAL_MACHINE;
376 else
377 flags = 0;
379 if (!create_container_regkey( container, KEY_WRITE, &hkey )) return FALSE;
381 ret = store_key_pair( container->exch_key, hkey, AT_KEYEXCHANGE, flags );
382 if (ret) store_key_pair( container->sign_key, hkey, AT_SIGNATURE, flags );
383 RegCloseKey( hkey );
384 return ret;
387 static struct key *duplicate_key( const struct key *key )
389 struct key *ret;
391 if (!(ret = create_key( key->algid, key->flags ))) return NULL;
393 if (BCryptDuplicateKey( key->handle, &ret->handle, NULL, 0, 0 ))
395 heap_free( ret );
396 return NULL;
398 return ret;
401 static BOOL generate_key( struct container *container, ALG_ID algid, DWORD bitlen, DWORD flags, HCRYPTKEY *ret_key )
403 struct key *key, *sign_key;
404 NTSTATUS status;
406 if (!(key = create_key( algid, flags ))) return FALSE;
408 if ((status = BCryptGenerateKeyPair( key->alg_handle, &key->handle, bitlen, 0 )))
410 ERR( "failed to generate key %08x\n", status );
411 destroy_key( key );
412 return FALSE;
414 if ((status = BCryptFinalizeKeyPair( key->handle, 0 )))
416 ERR( "failed to finalize key %08x\n", status );
417 destroy_key( key );
418 return FALSE;
421 switch (algid)
423 case AT_SIGNATURE:
424 case CALG_DSS_SIGN:
425 if (!(sign_key = duplicate_key( key )))
427 destroy_key( key );
428 return FALSE;
430 destroy_key( container->sign_key );
431 container->sign_key = sign_key;
432 break;
434 default:
435 FIXME( "unhandled algorithm %08x\n", algid );
436 return FALSE;
439 if (!store_key_container_keys( container )) return FALSE;
441 *ret_key = (HCRYPTKEY)key;
442 return TRUE;
445 BOOL WINAPI CPGenKey( HCRYPTPROV hprov, ALG_ID algid, DWORD flags, HCRYPTKEY *ret_key )
447 static const unsigned int supported_key_lengths[] = { 512, 768, 1024 };
448 struct container *container = (struct container *)hprov;
449 ULONG i, bitlen = HIWORD(flags) ? HIWORD(flags) : 1024;
451 TRACE( "%p, %08x, %08x, %p\n", (void *)hprov, algid, flags, ret_key );
453 if (container->magic != MAGIC_CONTAINER) return FALSE;
455 if (bitlen % 2)
457 SetLastError( STATUS_INVALID_PARAMETER );
458 return FALSE;
460 for (i = 0; i < ARRAY_SIZE(supported_key_lengths); i++)
462 if (bitlen == supported_key_lengths[i]) break;
464 if (i >= ARRAY_SIZE(supported_key_lengths))
466 SetLastError( NTE_BAD_FLAGS );
467 return FALSE;
470 return generate_key( container, algid, bitlen, LOWORD(flags), ret_key );
473 BOOL WINAPI CPDestroyKey( HCRYPTPROV hprov, HCRYPTKEY hkey )
475 struct key *key = (struct key *)hkey;
477 TRACE( "%p, %p\n", (void *)hprov, (void *)hkey );
479 if (key->magic != MAGIC_KEY)
481 SetLastError( NTE_BAD_KEY );
482 return FALSE;
485 destroy_key( key );
486 return TRUE;
489 #define MAGIC_DSS1 ('D' | ('S' << 8) | ('S' << 16) | ('1' << 24))
490 #define MAGIC_DSS2 ('D' | ('S' << 8) | ('S' << 16) | ('2' << 24))
491 #define MAGIC_DSS3 ('D' | ('S' << 8) | ('S' << 16) | ('3' << 24))
493 static BOOL import_key_dss2( struct container *container, ALG_ID algid, const BYTE *data, DWORD len, DWORD flags,
494 HCRYPTKEY *ret_key )
496 const BLOBHEADER *hdr = (const BLOBHEADER *)data;
497 const DSSPUBKEY *pubkey = (const DSSPUBKEY *)(hdr + 1);
498 const WCHAR *type;
499 struct key *key, *exch_key, *sign_key;
500 NTSTATUS status;
502 if (len < sizeof(*hdr) + sizeof(*pubkey)) return FALSE;
504 switch (pubkey->magic)
506 case MAGIC_DSS1:
507 type = LEGACY_DSA_V2_PUBLIC_BLOB;
508 break;
510 case MAGIC_DSS2:
511 type = LEGACY_DSA_V2_PRIVATE_BLOB;
512 break;
514 default:
515 FIXME( "unsupported key magic %08x\n", pubkey->magic );
516 return FALSE;
519 if (!(key = create_key( CALG_DSS_SIGN, flags ))) return FALSE;
521 if ((status = BCryptImportKeyPair( key->alg_handle, NULL, type, &key->handle, (UCHAR *)data, len, 0 )))
523 TRACE( "failed to import key %08x\n", status );
524 destroy_key( key );
525 return FALSE;
528 if (!wcscmp(type, LEGACY_DSA_V2_PRIVATE_BLOB))
530 switch (algid)
532 case AT_KEYEXCHANGE:
533 case CALG_DH_SF:
534 if (!(exch_key = duplicate_key( key )))
536 destroy_key( key );
537 return FALSE;
539 destroy_key( container->exch_key );
540 container->exch_key = exch_key;
541 break;
543 case AT_SIGNATURE:
544 case CALG_DSS_SIGN:
545 if (!(sign_key = duplicate_key( key )))
547 destroy_key( key );
548 return FALSE;
550 destroy_key( container->sign_key );
551 container->sign_key = sign_key;
552 break;
554 default:
555 FIXME( "unhandled key algorithm %u\n", algid );
556 destroy_key( key );
557 return FALSE;
560 if (!store_key_container_keys( container )) return FALSE;
563 *ret_key = (HCRYPTKEY)key;
564 return TRUE;
567 static BOOL import_key_dss3( struct container *container, ALG_ID algid, const BYTE *data, DWORD len, DWORD flags,
568 HCRYPTKEY *ret_key )
570 const BLOBHEADER *hdr = (const BLOBHEADER *)data;
571 const DSSPUBKEY_VER3 *pubkey = (const DSSPUBKEY_VER3 *)(hdr + 1);
572 BCRYPT_DSA_KEY_BLOB *blob;
573 struct key *key;
574 BYTE *src, *dst;
575 ULONG i, size, size_q;
576 NTSTATUS status;
578 if (len < sizeof(*hdr) + sizeof(*pubkey)) return FALSE;
580 switch (pubkey->magic)
582 case MAGIC_DSS3:
583 break;
585 default:
586 FIXME( "unsupported key magic %08x\n", pubkey->magic );
587 return FALSE;
590 if ((size_q = pubkey->bitlenQ / 8) > sizeof(blob->q))
592 FIXME( "q too large\n" );
593 return FALSE;
596 if (!(key = create_key( CALG_DSS_SIGN, flags ))) return FALSE;
598 size = sizeof(*blob) + (pubkey->bitlenP / 8) * 3;
599 if (!(blob = heap_alloc_zero( size )))
601 destroy_key( key );
602 return FALSE;
604 blob->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC;
605 blob->cbKey = pubkey->bitlenP / 8;
606 memcpy( blob->Count, &pubkey->DSSSeed.counter, sizeof(blob->Count) );
607 memcpy( blob->Seed, pubkey->DSSSeed.seed, sizeof(blob->Seed) );
609 /* q */
610 src = (BYTE *)(pubkey + 1) + blob->cbKey;
611 for (i = 0; i < size_q; i++) blob->q[i] = src[size_q - i - 1];
613 /* p */
614 src -= blob->cbKey;
615 dst = (BYTE *)(blob + 1);
616 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
618 /* g */
619 src += blob->cbKey + size_q;
620 dst += blob->cbKey;
621 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
623 /* y */
624 src += blob->cbKey + pubkey->bitlenJ / 8;
625 dst += blob->cbKey;
626 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
628 if ((status = BCryptImportKeyPair( key->alg_handle, NULL, BCRYPT_DSA_PUBLIC_BLOB, &key->handle, (UCHAR *)blob,
629 size, 0 )))
631 WARN( "failed to import key %08x\n", status );
632 destroy_key( key );
633 heap_free( blob );
634 return FALSE;
637 heap_free( blob );
638 *ret_key = (HCRYPTKEY)key;
639 return TRUE;
642 BOOL WINAPI CPImportKey( HCRYPTPROV hprov, const BYTE *data, DWORD len, HCRYPTKEY hpubkey, DWORD flags,
643 HCRYPTKEY *ret_key )
645 struct container *container = (struct container *)hprov;
646 const BLOBHEADER *hdr;
647 BOOL ret;
649 TRACE( "%p, %p, %u, %p, %08x, %p\n", (void *)hprov, data, len, (void *)hpubkey, flags, ret_key );
651 if (container->magic != MAGIC_CONTAINER) return FALSE;
652 if (len < sizeof(*hdr)) return FALSE;
654 hdr = (const BLOBHEADER *)data;
655 if ((hdr->bType != PRIVATEKEYBLOB && hdr->bType != PUBLICKEYBLOB) || hdr->aiKeyAlg != CALG_DSS_SIGN)
657 FIXME( "bType %u aiKeyAlg %08x not supported\n", hdr->bType, hdr->aiKeyAlg );
658 return FALSE;
661 switch (hdr->bVersion)
663 case 2:
664 ret = import_key_dss2( container, hdr->aiKeyAlg, data, len, flags, ret_key );
665 break;
667 case 3:
668 ret = import_key_dss3( container, hdr->aiKeyAlg, data, len, flags, ret_key );
669 break;
671 default:
672 FIXME( "version %u not supported\n", hdr->bVersion );
673 return FALSE;
676 return ret;
679 BOOL WINAPI CPExportKey( HCRYPTPROV hprov, HCRYPTKEY hkey, HCRYPTKEY hexpkey, DWORD blobtype, DWORD flags,
680 BYTE *data, DWORD *len )
682 struct key *key = (struct key *)hkey;
683 const WCHAR *type;
685 TRACE( "%p, %p, %p, %08x, %08x, %p, %p\n", (void *)hprov, (void *)hkey, (void *)hexpkey, blobtype, flags,
686 data, len );
688 if (key->magic != MAGIC_KEY) return FALSE;
689 if (hexpkey)
691 FIXME( "export key not supported\n" );
692 return FALSE;
694 if (flags)
696 FIXME( "flags %08x not supported\n", flags );
697 return FALSE;
700 switch (blobtype)
702 case PUBLICKEYBLOB:
703 type = LEGACY_DSA_V2_PUBLIC_BLOB;
704 break;
706 case PRIVATEKEYBLOB:
707 type = LEGACY_DSA_V2_PRIVATE_BLOB;
708 break;
710 default:
711 FIXME( "blob type %u not supported\n", blobtype );
712 return FALSE;
715 return !BCryptExportKey( key->handle, NULL, type, data, *len, len, 0 );
718 BOOL WINAPI CPDuplicateKey( HCRYPTPROV hprov, HCRYPTKEY hkey, DWORD *reserved, DWORD flags, HCRYPTKEY *ret_key )
720 struct key *key = (struct key *)hkey, *ret;
722 TRACE( "%p, %p, %p, %08x, %p\n", (void *)hprov, (void *)hkey, reserved, flags, ret_key );
724 if (key->magic != MAGIC_KEY) return FALSE;
726 if (!(ret = duplicate_key( key ))) return FALSE;
727 *ret_key = (HCRYPTKEY)ret;
728 return TRUE;
731 BOOL WINAPI CPGetUserKey( HCRYPTPROV hprov, DWORD keyspec, HCRYPTKEY *ret_key )
733 struct container *container = (struct container *)hprov;
734 BOOL ret = FALSE;
736 TRACE( "%p, %08x, %p\n", (void *)hprov, keyspec, ret_key );
738 if (container->magic != MAGIC_CONTAINER) return FALSE;
740 switch (keyspec)
742 case AT_KEYEXCHANGE:
743 if (!container->exch_key) SetLastError( NTE_NO_KEY );
744 else if ((*ret_key = (HCRYPTKEY)duplicate_key( container->exch_key ))) ret = TRUE;
745 break;
747 case AT_SIGNATURE:
748 if (!container->sign_key) SetLastError( NTE_NO_KEY );
749 else if ((*ret_key = (HCRYPTKEY)duplicate_key( container->sign_key ))) ret = TRUE;
750 break;
752 default:
753 SetLastError( NTE_NO_KEY );
754 return FALSE;
757 return ret;
760 BOOL WINAPI CPGenRandom( HCRYPTPROV hprov, DWORD len, BYTE *buffer )
762 struct container *container = (struct container *)hprov;
764 TRACE( "%p, %u, %p\n", (void *)hprov, len, buffer );
766 if (container->magic != MAGIC_CONTAINER) return FALSE;
768 return RtlGenRandom( buffer, len );
771 static struct hash *create_hash( ALG_ID algid )
773 struct hash *ret;
774 BCRYPT_ALG_HANDLE alg_handle;
775 const WCHAR *alg;
776 DWORD len;
778 switch (algid)
780 case CALG_MD5:
781 alg = BCRYPT_MD5_ALGORITHM;
782 len = 16;
783 break;
785 case CALG_SHA1:
786 alg = BCRYPT_SHA1_ALGORITHM;
787 len = 20;
788 break;
790 default:
791 FIXME( "unhandled algorithm %u\n", algid );
792 return NULL;
795 if (!(ret = heap_alloc_zero( sizeof(*ret) ))) return NULL;
797 ret->magic = MAGIC_HASH;
798 ret->len = len;
799 if (BCryptOpenAlgorithmProvider( &alg_handle, alg, MS_PRIMITIVE_PROVIDER, 0 ))
801 heap_free( ret );
802 return NULL;
804 if (BCryptCreateHash( alg_handle, &ret->handle, NULL, 0, NULL, 0, 0 ))
806 BCryptCloseAlgorithmProvider( alg_handle, 0 );
807 heap_free( ret );
808 return NULL;
811 BCryptCloseAlgorithmProvider( alg_handle, 0 );
812 return ret;
815 BOOL WINAPI CPCreateHash( HCRYPTPROV hprov, ALG_ID algid, HCRYPTKEY hkey, DWORD flags, HCRYPTHASH *ret_hash )
817 struct hash *hash;
819 TRACE( "%p, %08x, %p, %08x, %p\n", (void *)hprov, algid, (void *)hkey, flags, ret_hash );
821 switch (algid)
823 case CALG_MD5:
824 case CALG_SHA1:
825 break;
827 default:
828 FIXME( "algorithm %u not supported\n", algid );
829 SetLastError( NTE_BAD_ALGID );
830 return FALSE;
833 if (!(hash = create_hash( algid ))) return FALSE;
835 *ret_hash = (HCRYPTHASH)hash;
836 return TRUE;
839 static void destroy_hash( struct hash *hash )
841 if (!hash) return;
842 BCryptDestroyHash( hash->handle );
843 hash->magic = 0;
844 heap_free( hash );
847 BOOL WINAPI CPDestroyHash( HCRYPTPROV hprov, HCRYPTHASH hhash )
849 struct hash *hash = (struct hash *)hhash;
851 TRACE( "%p, %p\n", (void *)hprov, (void *)hhash);
853 if (hash->magic != MAGIC_HASH)
855 SetLastError( NTE_BAD_HASH );
856 return FALSE;
859 destroy_hash( hash );
860 return TRUE;
863 static struct hash *duplicate_hash( const struct hash *hash )
865 struct hash *ret;
867 if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
869 ret->magic = hash->magic;
870 ret->len = hash->len;
871 if (BCryptDuplicateHash( hash->handle, &ret->handle, NULL, 0, 0 ))
873 heap_free( ret );
874 return NULL;
876 memcpy( ret->value, hash->value, sizeof(hash->value) );
877 ret->finished = hash->finished;
878 return ret;
881 BOOL WINAPI CPDuplicateHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD *reserved, DWORD flags, HCRYPTHASH *ret_hash )
883 struct hash *hash = (struct hash *)hhash, *ret;
885 TRACE( "%p, %p, %p, %08x, %p\n", (void *)hprov, (void *)hhash, reserved, flags, ret_hash );
887 if (hash->magic != MAGIC_HASH) return FALSE;
889 if (!(ret = duplicate_hash( hash ))) return FALSE;
890 *ret_hash = (HCRYPTHASH)ret;
891 return TRUE;
894 BOOL WINAPI CPHashData( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *data, DWORD len, DWORD flags )
896 struct hash *hash = (struct hash *)hhash;
898 TRACE("%p, %p, %p, %u, %08x\n", (void *)hprov, (void *)hhash, data, len, flags );
900 if (hash->magic != MAGIC_HASH) return FALSE;
902 if (hash->finished)
904 SetLastError( NTE_BAD_HASH_STATE );
905 return FALSE;
907 return !BCryptHashData( hash->handle, (UCHAR *)data, len, 0 );
910 BOOL WINAPI CPGetHashParam( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD param, BYTE *data, DWORD *len, DWORD flags )
912 struct hash *hash = (struct hash *)hhash;
914 TRACE( "%p, %p, %08x, %p, %p, %08x\n", (void *)hprov, (void *)hhash, param, data, len, flags );
916 if (hash->magic != MAGIC_HASH) return FALSE;
918 switch (param)
920 case HP_HASHSIZE:
921 if (sizeof(hash->len) > *len)
923 *len = sizeof(hash->len);
924 SetLastError( ERROR_MORE_DATA );
925 return FALSE;
927 *(DWORD *)data = hash->len;
928 *len = sizeof(hash->len);
929 return TRUE;
931 case HP_HASHVAL:
932 if (!hash->finished)
934 if (BCryptFinishHash( hash->handle, hash->value, hash->len, 0 )) return FALSE;
935 hash->finished = TRUE;
937 if (hash->len > *len)
939 *len = hash->len;
940 SetLastError( ERROR_MORE_DATA );
941 return FALSE;
943 if (data) memcpy( data, hash->value, hash->len );
944 *len = hash->len;
945 return TRUE;
947 default:
948 SetLastError( NTE_BAD_TYPE );
949 return FALSE;
953 BOOL WINAPI CPSetHashParam( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD param, const BYTE *data, DWORD flags )
955 struct hash *hash = (struct hash *)hhash;
957 TRACE( "%p, %p, %08x, %p, %08x\n", (void *)hprov, (void *)hhash, param, data, flags );
959 if (hash->magic != MAGIC_HASH) return FALSE;
961 switch (param)
963 case HP_HASHVAL:
964 memcpy( hash->value, data, hash->len );
965 return TRUE;
967 default:
968 FIXME( "param %u not supported\n", param );
969 SetLastError( NTE_BAD_TYPE );
970 return FALSE;
974 BOOL WINAPI CPDeriveKey( HCRYPTPROV hprov, ALG_ID algid, HCRYPTHASH hhash, DWORD flags, HCRYPTKEY *ret_key )
976 return FALSE;
979 static DWORD get_signature_length( DWORD algid )
981 switch (algid)
983 case AT_SIGNATURE:
984 case CALG_DSS_SIGN: return 40;
985 default:
986 FIXME( "unhandled algorithm %u\n", algid );
987 return 0;
991 #define MAX_HASH_LEN 20
992 BOOL WINAPI CPSignHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD keyspec, const WCHAR *desc, DWORD flags, BYTE *sig,
993 DWORD *siglen )
995 struct container *container = (struct container *)hprov;
996 struct hash *hash = (struct hash *)hhash;
997 ULONG len;
999 TRACE( "%p, %p, %u, %s, %08x, %p, %p\n", (void *)hprov, (void *)hhash, keyspec, debugstr_w(desc), flags, sig,
1000 siglen );
1002 if (container->magic != MAGIC_CONTAINER || !container->sign_key) return FALSE;
1003 if (hash->magic != MAGIC_HASH) return FALSE;
1005 if (!(len = get_signature_length( container->sign_key->algid ))) return FALSE;
1006 if (*siglen < len)
1008 *siglen = len;
1009 return TRUE;
1012 return !BCryptSignHash( container->sign_key->handle, NULL, hash->value, hash->len, sig, *siglen, siglen, 0 );
1015 BOOL WINAPI CPVerifySignature( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *sig, DWORD siglen, HCRYPTKEY hpubkey,
1016 const WCHAR *desc, DWORD flags )
1018 struct hash *hash = (struct hash *)hhash;
1019 struct key *key = (struct key *)hpubkey;
1021 TRACE( "%p, %p, %p, %u %p, %s, %08x\n", (void *)hprov, (void *)hhash, sig, siglen, (void *)hpubkey,
1022 debugstr_w(desc), flags );
1024 if (hash->magic != MAGIC_HASH || key->magic != MAGIC_KEY) return FALSE;
1025 if (flags)
1027 FIXME( "flags %08x not supported\n", flags );
1028 return FALSE;
1031 return !BCryptVerifySignature( key->handle, NULL, hash->value, hash->len, (UCHAR *)sig, siglen, 0 );