dssenh: Use SecureZeroMemory to clear magic fields.
[wine.git] / dlls / dssenh / main.c
blob6772d062fc583a807cdc777698cb6c2a927867fd
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 /* Ensure compiler doesn't optimize out the assignment with 0. */
166 SecureZeroMemory( &key->magic, sizeof(key->magic) );
167 free( key );
170 static struct key *import_key( DWORD keyspec, BYTE *data, DWORD len )
172 struct key *ret;
174 if (!(ret = create_key( keyspec, 0 ))) return NULL;
176 if (BCryptImportKeyPair( BCRYPT_DSA_ALG_HANDLE, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, &ret->handle, data, len, 0 ))
178 WARN( "failed to import key\n" );
179 destroy_key( ret );
180 return NULL;
182 return ret;
185 static struct key *read_key( HKEY hkey, DWORD keyspec, DWORD flags )
187 const WCHAR *value;
188 DWORD type, len;
189 BYTE *data;
190 DATA_BLOB blob_in, blob_out;
191 struct key *ret = NULL;
193 if (!(value = map_keyspec_to_keypair_name( keyspec ))) return NULL;
194 if (RegQueryValueExW( hkey, value, 0, &type, NULL, &len )) return NULL;
195 if (!(data = malloc( len ))) return NULL;
197 if (!RegQueryValueExW( hkey, value, 0, &type, data, &len ))
199 blob_in.pbData = data;
200 blob_in.cbData = len;
201 if (CryptUnprotectData( &blob_in, NULL, NULL, NULL, NULL, flags, &blob_out ))
203 ret = import_key( keyspec, blob_out.pbData, blob_out.cbData );
204 LocalFree( blob_out.pbData );
208 free( data );
209 return ret;
212 static void destroy_container( struct container *container )
214 if (!container) return;
215 destroy_key( container->exch_key );
216 destroy_key( container->sign_key );
217 /* Ensure compiler doesn't optimize out the assignment with 0. */
218 SecureZeroMemory( &container->magic, sizeof(container->magic) );
219 free( container );
222 static struct container *read_key_container( const char *name, DWORD flags )
224 DWORD protect_flags = (flags & CRYPT_MACHINE_KEYSET) ? CRYPTPROTECT_LOCAL_MACHINE : 0;
225 struct container *ret;
226 HKEY hkey;
228 if (!open_container_regkey( name, flags, KEY_READ, &hkey )) return NULL;
230 if ((ret = create_key_container( name, flags )))
232 ret->exch_key = read_key( hkey, AT_KEYEXCHANGE, protect_flags );
233 ret->sign_key = read_key( hkey, AT_SIGNATURE, protect_flags );
236 RegCloseKey( hkey );
237 return ret;
240 static void delete_key_container( const char *name, DWORD flags )
242 char path[sizeof(dss_path_fmt) + MAX_PATH];
243 HKEY rootkey;
245 sprintf( path, dss_path_fmt, name );
247 if (flags & CRYPT_MACHINE_KEYSET)
248 rootkey = HKEY_LOCAL_MACHINE;
249 else
250 rootkey = HKEY_CURRENT_USER;
252 /* @@ Wine registry key: HKLM\Software\Wine\Crypto\DSS */
253 /* @@ Wine registry key: HKCU\Software\Wine\Crypto\DSS */
254 RegDeleteKeyExA( rootkey, path, 0, 0 );
257 BOOL WINAPI CPAcquireContext( HCRYPTPROV *ret_prov, LPSTR container, DWORD flags, PVTableProvStruc vtable )
259 struct container *ret;
260 char name[MAX_PATH];
262 TRACE( "%p, %s, %08lx, %p\n", ret_prov, debugstr_a(container), flags, vtable );
264 if (container && *container)
266 if (lstrlenA( container ) >= sizeof(name)) return FALSE;
267 lstrcpyA( name, container );
269 else
271 DWORD len = sizeof(name);
272 if (!GetUserNameA( name, &len )) return FALSE;
275 switch (flags)
277 case 0:
278 case 0 | CRYPT_MACHINE_KEYSET:
279 if (!(ret = read_key_container( name, flags )))
280 SetLastError( NTE_BAD_KEYSET );
281 break;
283 case CRYPT_NEWKEYSET:
284 case CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET:
285 if ((ret = read_key_container( name, flags )))
287 free( ret );
288 SetLastError( NTE_EXISTS );
289 return FALSE;
291 ret = create_key_container( name, flags );
292 break;
294 case CRYPT_VERIFYCONTEXT:
295 case CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET:
296 ret = create_key_container( "", flags );
297 break;
299 case CRYPT_DELETEKEYSET:
300 case CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET:
301 delete_key_container( name, flags );
302 *ret_prov = 0;
303 return TRUE;
305 default:
306 FIXME( "unsupported flags %08lx\n", flags );
307 return FALSE;
310 if (!ret) return FALSE;
311 *ret_prov = (HCRYPTPROV)ret;
312 return TRUE;
315 BOOL WINAPI CPReleaseContext( HCRYPTPROV hprov, DWORD flags )
317 struct container *container = (struct container *)hprov;
319 TRACE( "%p, %08lx\n", (void *)hprov, flags );
321 if (container->magic != MAGIC_CONTAINER) return FALSE;
322 destroy_container( container );
323 return TRUE;
326 BOOL WINAPI CPGetProvParam( HCRYPTPROV hprov, DWORD param, BYTE *data, DWORD *len, DWORD flags )
328 return FALSE;
331 static BOOL store_key_pair( struct key *key, HKEY hkey, DWORD keyspec, DWORD flags )
333 const WCHAR *value;
334 DATA_BLOB blob_in, blob_out;
335 DWORD len;
336 BYTE *data;
337 BOOL ret = TRUE;
339 if (!key) return TRUE;
340 if (!(value = map_keyspec_to_keypair_name( keyspec ))) return FALSE;
342 if (BCryptExportKey( key->handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, NULL, 0, &len, 0 )) return FALSE;
343 if (!(data = malloc( len ))) return FALSE;
345 if (!BCryptExportKey( key->handle, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, data, len, &len, 0 ))
347 blob_in.pbData = data;
348 blob_in.cbData = len;
349 if ((ret = CryptProtectData( &blob_in, NULL, NULL, NULL, NULL, flags, &blob_out )))
351 ret = !RegSetValueExW( hkey, value, 0, REG_BINARY, blob_out.pbData, blob_out.cbData );
352 LocalFree( blob_out.pbData );
356 free( data );
357 return ret;
360 static BOOL store_key_container_keys( struct container *container )
362 HKEY hkey;
363 DWORD flags;
364 BOOL ret;
366 if (container->flags & CRYPT_MACHINE_KEYSET)
367 flags = CRYPTPROTECT_LOCAL_MACHINE;
368 else
369 flags = 0;
371 if (!create_container_regkey( container, KEY_WRITE, &hkey )) return FALSE;
373 ret = store_key_pair( container->exch_key, hkey, AT_KEYEXCHANGE, flags );
374 if (ret) store_key_pair( container->sign_key, hkey, AT_SIGNATURE, flags );
375 RegCloseKey( hkey );
376 return ret;
379 static struct key *duplicate_key( const struct key *key )
381 struct key *ret;
383 if (!(ret = create_key( key->algid, key->flags ))) return NULL;
385 if (BCryptDuplicateKey( key->handle, &ret->handle, NULL, 0, 0 ))
387 free( ret );
388 return NULL;
390 return ret;
393 static BOOL generate_key( struct container *container, ALG_ID algid, DWORD bitlen, DWORD flags, HCRYPTKEY *ret_key )
395 struct key *key, *sign_key;
396 NTSTATUS status;
398 if (!(key = create_key( algid, flags ))) return FALSE;
400 if ((status = BCryptGenerateKeyPair( BCRYPT_DSA_ALG_HANDLE, &key->handle, bitlen, 0 )))
402 ERR( "failed to generate key %08lx\n", status );
403 destroy_key( key );
404 return FALSE;
406 if ((status = BCryptFinalizeKeyPair( key->handle, 0 )))
408 ERR( "failed to finalize key %08lx\n", status );
409 destroy_key( key );
410 return FALSE;
413 switch (algid)
415 case AT_SIGNATURE:
416 case CALG_DSS_SIGN:
417 if (!(sign_key = duplicate_key( key )))
419 destroy_key( key );
420 return FALSE;
422 destroy_key( container->sign_key );
423 container->sign_key = sign_key;
424 break;
426 default:
427 FIXME( "unhandled algorithm %08x\n", algid );
428 return FALSE;
431 if (!store_key_container_keys( container )) return FALSE;
433 *ret_key = (HCRYPTKEY)key;
434 return TRUE;
437 BOOL WINAPI CPGenKey( HCRYPTPROV hprov, ALG_ID algid, DWORD flags, HCRYPTKEY *ret_key )
439 static const unsigned int supported_key_lengths[] = { 512, 768, 1024 };
440 struct container *container = (struct container *)hprov;
441 ULONG i, bitlen = HIWORD(flags) ? HIWORD(flags) : 1024;
443 TRACE( "%p, %08x, %08lx, %p\n", (void *)hprov, algid, flags, ret_key );
445 if (container->magic != MAGIC_CONTAINER) return FALSE;
447 if (bitlen % 2)
449 SetLastError( STATUS_INVALID_PARAMETER );
450 return FALSE;
452 for (i = 0; i < ARRAY_SIZE(supported_key_lengths); i++)
454 if (bitlen == supported_key_lengths[i]) break;
456 if (i >= ARRAY_SIZE(supported_key_lengths))
458 SetLastError( NTE_BAD_FLAGS );
459 return FALSE;
462 return generate_key( container, algid, bitlen, LOWORD(flags), ret_key );
465 BOOL WINAPI CPDestroyKey( HCRYPTPROV hprov, HCRYPTKEY hkey )
467 struct key *key = (struct key *)hkey;
469 TRACE( "%p, %p\n", (void *)hprov, (void *)hkey );
471 if (key->magic != MAGIC_KEY)
473 SetLastError( NTE_BAD_KEY );
474 return FALSE;
477 destroy_key( key );
478 return TRUE;
481 #define MAGIC_DSS1 ('D' | ('S' << 8) | ('S' << 16) | ('1' << 24))
482 #define MAGIC_DSS2 ('D' | ('S' << 8) | ('S' << 16) | ('2' << 24))
483 #define MAGIC_DSS3 ('D' | ('S' << 8) | ('S' << 16) | ('3' << 24))
485 static BOOL import_key_dss2( struct container *container, ALG_ID algid, const BYTE *data, DWORD len, DWORD flags,
486 HCRYPTKEY *ret_key )
488 const BLOBHEADER *hdr = (const BLOBHEADER *)data;
489 const DSSPUBKEY *pubkey = (const DSSPUBKEY *)(hdr + 1);
490 const WCHAR *type;
491 struct key *key, *exch_key, *sign_key;
492 NTSTATUS status;
494 if (len < sizeof(*hdr) + sizeof(*pubkey)) return FALSE;
496 switch (pubkey->magic)
498 case MAGIC_DSS1:
499 type = LEGACY_DSA_V2_PUBLIC_BLOB;
500 break;
502 case MAGIC_DSS2:
503 type = LEGACY_DSA_V2_PRIVATE_BLOB;
504 break;
506 default:
507 FIXME( "unsupported key magic %08lx\n", pubkey->magic );
508 return FALSE;
511 if (!(key = create_key( CALG_DSS_SIGN, flags ))) return FALSE;
513 if ((status = BCryptImportKeyPair( BCRYPT_DSA_ALG_HANDLE, NULL, type, &key->handle, (UCHAR *)data, len, 0 )))
515 TRACE( "failed to import key %08lx\n", status );
516 destroy_key( key );
517 return FALSE;
520 if (!wcscmp(type, LEGACY_DSA_V2_PRIVATE_BLOB))
522 switch (algid)
524 case AT_KEYEXCHANGE:
525 case CALG_DH_SF:
526 if (!(exch_key = duplicate_key( key )))
528 destroy_key( key );
529 return FALSE;
531 destroy_key( container->exch_key );
532 container->exch_key = exch_key;
533 break;
535 case AT_SIGNATURE:
536 case CALG_DSS_SIGN:
537 if (!(sign_key = duplicate_key( key )))
539 destroy_key( key );
540 return FALSE;
542 destroy_key( container->sign_key );
543 container->sign_key = sign_key;
544 break;
546 default:
547 FIXME( "unhandled key algorithm %u\n", algid );
548 destroy_key( key );
549 return FALSE;
552 if (!store_key_container_keys( container )) return FALSE;
555 *ret_key = (HCRYPTKEY)key;
556 return TRUE;
559 static BOOL import_key_dss3( struct container *container, ALG_ID algid, const BYTE *data, DWORD len, DWORD flags,
560 HCRYPTKEY *ret_key )
562 const BLOBHEADER *hdr = (const BLOBHEADER *)data;
563 const DSSPUBKEY_VER3 *pubkey = (const DSSPUBKEY_VER3 *)(hdr + 1);
564 BCRYPT_DSA_KEY_BLOB *blob;
565 struct key *key;
566 BYTE *src, *dst;
567 ULONG i, size, size_q;
568 NTSTATUS status;
570 if (len < sizeof(*hdr) + sizeof(*pubkey)) return FALSE;
572 switch (pubkey->magic)
574 case MAGIC_DSS3:
575 break;
577 default:
578 FIXME( "unsupported key magic %08lx\n", pubkey->magic );
579 return FALSE;
582 if ((size_q = pubkey->bitlenQ / 8) > sizeof(blob->q))
584 FIXME( "q too large\n" );
585 return FALSE;
588 if (!(key = create_key( CALG_DSS_SIGN, flags ))) return FALSE;
590 size = sizeof(*blob) + (pubkey->bitlenP / 8) * 3;
591 if (!(blob = calloc( 1, size )))
593 destroy_key( key );
594 return FALSE;
596 blob->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC;
597 blob->cbKey = pubkey->bitlenP / 8;
598 memcpy( blob->Count, &pubkey->DSSSeed.counter, sizeof(blob->Count) );
599 memcpy( blob->Seed, pubkey->DSSSeed.seed, sizeof(blob->Seed) );
601 /* q */
602 src = (BYTE *)(pubkey + 1) + blob->cbKey;
603 for (i = 0; i < size_q; i++) blob->q[i] = src[size_q - i - 1];
605 /* p */
606 src -= blob->cbKey;
607 dst = (BYTE *)(blob + 1);
608 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
610 /* g */
611 src += blob->cbKey + size_q;
612 dst += blob->cbKey;
613 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
615 /* y */
616 src += blob->cbKey + pubkey->bitlenJ / 8;
617 dst += blob->cbKey;
618 for (i = 0; i < blob->cbKey; i++) dst[i] = src[blob->cbKey - i - 1];
620 if ((status = BCryptImportKeyPair( BCRYPT_DSA_ALG_HANDLE, NULL, BCRYPT_DSA_PUBLIC_BLOB, &key->handle,
621 (UCHAR *)blob, size, 0 )))
623 WARN( "failed to import key %08lx\n", status );
624 destroy_key( key );
625 free( blob );
626 return FALSE;
629 free( blob );
630 *ret_key = (HCRYPTKEY)key;
631 return TRUE;
634 BOOL WINAPI CPImportKey( HCRYPTPROV hprov, const BYTE *data, DWORD len, HCRYPTKEY hpubkey, DWORD flags,
635 HCRYPTKEY *ret_key )
637 struct container *container = (struct container *)hprov;
638 const BLOBHEADER *hdr;
639 BOOL ret;
641 TRACE( "%p, %p, %lu, %p, %08lx, %p\n", (void *)hprov, data, len, (void *)hpubkey, flags, ret_key );
643 if (container->magic != MAGIC_CONTAINER) return FALSE;
644 if (len < sizeof(*hdr)) return FALSE;
646 hdr = (const BLOBHEADER *)data;
647 if ((hdr->bType != PRIVATEKEYBLOB && hdr->bType != PUBLICKEYBLOB) || hdr->aiKeyAlg != CALG_DSS_SIGN)
649 FIXME( "bType %u aiKeyAlg %08x not supported\n", hdr->bType, hdr->aiKeyAlg );
650 return FALSE;
653 switch (hdr->bVersion)
655 case 2:
656 ret = import_key_dss2( container, hdr->aiKeyAlg, data, len, flags, ret_key );
657 break;
659 case 3:
660 ret = import_key_dss3( container, hdr->aiKeyAlg, data, len, flags, ret_key );
661 break;
663 default:
664 FIXME( "version %u not supported\n", hdr->bVersion );
665 return FALSE;
668 return ret;
671 BOOL WINAPI CPExportKey( HCRYPTPROV hprov, HCRYPTKEY hkey, HCRYPTKEY hexpkey, DWORD blobtype, DWORD flags,
672 BYTE *data, DWORD *len )
674 struct key *key = (struct key *)hkey;
675 const WCHAR *type;
677 TRACE( "%p, %p, %p, %08lx, %08lx, %p, %p\n", (void *)hprov, (void *)hkey, (void *)hexpkey, blobtype, flags,
678 data, len );
680 if (key->magic != MAGIC_KEY) return FALSE;
681 if (hexpkey)
683 FIXME( "export key not supported\n" );
684 return FALSE;
686 if (flags)
688 FIXME( "flags %08lx not supported\n", flags );
689 return FALSE;
692 switch (blobtype)
694 case PUBLICKEYBLOB:
695 type = LEGACY_DSA_V2_PUBLIC_BLOB;
696 break;
698 case PRIVATEKEYBLOB:
699 type = LEGACY_DSA_V2_PRIVATE_BLOB;
700 break;
702 default:
703 FIXME( "blob type %lu not supported\n", blobtype );
704 return FALSE;
707 return !BCryptExportKey( key->handle, NULL, type, data, *len, len, 0 );
710 BOOL WINAPI CPDuplicateKey( HCRYPTPROV hprov, HCRYPTKEY hkey, DWORD *reserved, DWORD flags, HCRYPTKEY *ret_key )
712 struct key *key = (struct key *)hkey, *ret;
714 TRACE( "%p, %p, %p, %08lx, %p\n", (void *)hprov, (void *)hkey, reserved, flags, ret_key );
716 if (key->magic != MAGIC_KEY) return FALSE;
718 if (!(ret = duplicate_key( key ))) return FALSE;
719 *ret_key = (HCRYPTKEY)ret;
720 return TRUE;
723 BOOL WINAPI CPGetUserKey( HCRYPTPROV hprov, DWORD keyspec, HCRYPTKEY *ret_key )
725 struct container *container = (struct container *)hprov;
726 BOOL ret = FALSE;
728 TRACE( "%p, %08lx, %p\n", (void *)hprov, keyspec, ret_key );
730 if (container->magic != MAGIC_CONTAINER) return FALSE;
732 switch (keyspec)
734 case AT_KEYEXCHANGE:
735 if (!container->exch_key) SetLastError( NTE_NO_KEY );
736 else if ((*ret_key = (HCRYPTKEY)duplicate_key( container->exch_key ))) ret = TRUE;
737 break;
739 case AT_SIGNATURE:
740 if (!container->sign_key) SetLastError( NTE_NO_KEY );
741 else if ((*ret_key = (HCRYPTKEY)duplicate_key( container->sign_key ))) ret = TRUE;
742 break;
744 default:
745 SetLastError( NTE_NO_KEY );
746 return FALSE;
749 return ret;
752 BOOL WINAPI CPGenRandom( HCRYPTPROV hprov, DWORD len, BYTE *buffer )
754 struct container *container = (struct container *)hprov;
756 TRACE( "%p, %lu, %p\n", (void *)hprov, len, buffer );
758 if (container->magic != MAGIC_CONTAINER) return FALSE;
760 return RtlGenRandom( buffer, len );
763 static struct hash *create_hash( ALG_ID algid )
765 struct hash *ret;
766 BCRYPT_ALG_HANDLE alg_handle;
767 DWORD len;
769 switch (algid)
771 case CALG_MD5:
772 alg_handle = BCRYPT_MD5_ALG_HANDLE;
773 len = 16;
774 break;
776 case CALG_SHA1:
777 alg_handle = BCRYPT_SHA1_ALG_HANDLE;
778 len = 20;
779 break;
781 default:
782 FIXME( "unhandled algorithm %u\n", algid );
783 return NULL;
786 if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL;
788 ret->magic = MAGIC_HASH;
789 ret->len = len;
790 if (BCryptCreateHash( alg_handle, &ret->handle, NULL, 0, NULL, 0, 0 ))
792 free( ret );
793 return NULL;
795 return ret;
798 BOOL WINAPI CPCreateHash( HCRYPTPROV hprov, ALG_ID algid, HCRYPTKEY hkey, DWORD flags, HCRYPTHASH *ret_hash )
800 struct hash *hash;
802 TRACE( "%p, %08x, %p, %08lx, %p\n", (void *)hprov, algid, (void *)hkey, flags, ret_hash );
804 switch (algid)
806 case CALG_MD5:
807 case CALG_SHA1:
808 break;
810 default:
811 FIXME( "algorithm %u not supported\n", algid );
812 SetLastError( NTE_BAD_ALGID );
813 return FALSE;
816 if (!(hash = create_hash( algid ))) return FALSE;
818 *ret_hash = (HCRYPTHASH)hash;
819 return TRUE;
822 static void destroy_hash( struct hash *hash )
824 if (!hash) return;
825 BCryptDestroyHash( hash->handle );
826 /* Ensure compiler doesn't optimize out the assignment with 0. */
827 SecureZeroMemory( &hash->magic, sizeof(hash->magic) );
828 free( hash );
831 BOOL WINAPI CPDestroyHash( HCRYPTPROV hprov, HCRYPTHASH hhash )
833 struct hash *hash = (struct hash *)hhash;
835 TRACE( "%p, %p\n", (void *)hprov, (void *)hhash);
837 if (hash->magic != MAGIC_HASH)
839 SetLastError( NTE_BAD_HASH );
840 return FALSE;
843 destroy_hash( hash );
844 return TRUE;
847 static struct hash *duplicate_hash( const struct hash *hash )
849 struct hash *ret;
851 if (!(ret = malloc( sizeof(*ret) ))) return NULL;
853 ret->magic = hash->magic;
854 ret->len = hash->len;
855 if (BCryptDuplicateHash( hash->handle, &ret->handle, NULL, 0, 0 ))
857 free( ret );
858 return NULL;
860 memcpy( ret->value, hash->value, sizeof(hash->value) );
861 ret->finished = hash->finished;
862 return ret;
865 BOOL WINAPI CPDuplicateHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD *reserved, DWORD flags, HCRYPTHASH *ret_hash )
867 struct hash *hash = (struct hash *)hhash, *ret;
869 TRACE( "%p, %p, %p, %08lx, %p\n", (void *)hprov, (void *)hhash, reserved, flags, ret_hash );
871 if (hash->magic != MAGIC_HASH) return FALSE;
873 if (!(ret = duplicate_hash( hash ))) return FALSE;
874 *ret_hash = (HCRYPTHASH)ret;
875 return TRUE;
878 BOOL WINAPI CPHashData( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *data, DWORD len, DWORD flags )
880 struct hash *hash = (struct hash *)hhash;
882 TRACE("%p, %p, %p, %lu, %08lx\n", (void *)hprov, (void *)hhash, data, len, flags );
884 if (hash->magic != MAGIC_HASH) return FALSE;
886 if (hash->finished)
888 SetLastError( NTE_BAD_HASH_STATE );
889 return FALSE;
891 return !BCryptHashData( hash->handle, (UCHAR *)data, len, 0 );
894 BOOL WINAPI CPGetHashParam( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD param, BYTE *data, DWORD *len, DWORD flags )
896 struct hash *hash = (struct hash *)hhash;
898 TRACE( "%p, %p, %08lx, %p, %p, %08lx\n", (void *)hprov, (void *)hhash, param, data, len, flags );
900 if (hash->magic != MAGIC_HASH) return FALSE;
902 switch (param)
904 case HP_HASHSIZE:
905 if (sizeof(hash->len) > *len)
907 *len = sizeof(hash->len);
908 SetLastError( ERROR_MORE_DATA );
909 return FALSE;
911 *(DWORD *)data = hash->len;
912 *len = sizeof(hash->len);
913 return TRUE;
915 case HP_HASHVAL:
916 if (!hash->finished)
918 if (BCryptFinishHash( hash->handle, hash->value, hash->len, 0 )) return FALSE;
919 hash->finished = TRUE;
921 if (hash->len > *len)
923 *len = hash->len;
924 SetLastError( ERROR_MORE_DATA );
925 return FALSE;
927 if (data) memcpy( data, hash->value, hash->len );
928 *len = hash->len;
929 return TRUE;
931 default:
932 SetLastError( NTE_BAD_TYPE );
933 return FALSE;
937 BOOL WINAPI CPSetHashParam( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD param, const BYTE *data, DWORD flags )
939 struct hash *hash = (struct hash *)hhash;
941 TRACE( "%p, %p, %08lx, %p, %08lx\n", (void *)hprov, (void *)hhash, param, data, flags );
943 if (hash->magic != MAGIC_HASH) return FALSE;
945 switch (param)
947 case HP_HASHVAL:
948 memcpy( hash->value, data, hash->len );
949 return TRUE;
951 default:
952 FIXME( "param %lu not supported\n", param );
953 SetLastError( NTE_BAD_TYPE );
954 return FALSE;
958 BOOL WINAPI CPDeriveKey( HCRYPTPROV hprov, ALG_ID algid, HCRYPTHASH hhash, DWORD flags, HCRYPTKEY *ret_key )
960 return FALSE;
963 static DWORD get_signature_length( DWORD algid )
965 switch (algid)
967 case AT_SIGNATURE:
968 case CALG_DSS_SIGN: return 40;
969 default:
970 FIXME( "unhandled algorithm %lu\n", algid );
971 return 0;
975 #define MAX_HASH_LEN 20
976 BOOL WINAPI CPSignHash( HCRYPTPROV hprov, HCRYPTHASH hhash, DWORD keyspec, const WCHAR *desc, DWORD flags, BYTE *sig,
977 DWORD *siglen )
979 struct container *container = (struct container *)hprov;
980 struct hash *hash = (struct hash *)hhash;
981 ULONG len;
983 TRACE( "%p, %p, %lu, %s, %08lx, %p, %p\n", (void *)hprov, (void *)hhash, keyspec, debugstr_w(desc), flags, sig,
984 siglen );
986 if (container->magic != MAGIC_CONTAINER || !container->sign_key) return FALSE;
987 if (hash->magic != MAGIC_HASH) return FALSE;
989 if (!(len = get_signature_length( container->sign_key->algid ))) return FALSE;
990 if (*siglen < len)
992 *siglen = len;
993 return TRUE;
996 return !BCryptSignHash( container->sign_key->handle, NULL, hash->value, hash->len, sig, *siglen, siglen, 0 );
999 BOOL WINAPI CPVerifySignature( HCRYPTPROV hprov, HCRYPTHASH hhash, const BYTE *sig, DWORD siglen, HCRYPTKEY hpubkey,
1000 const WCHAR *desc, DWORD flags )
1002 struct hash *hash = (struct hash *)hhash;
1003 struct key *key = (struct key *)hpubkey;
1005 TRACE( "%p, %p, %p, %lu %p, %s, %08lx\n", (void *)hprov, (void *)hhash, sig, siglen, (void *)hpubkey,
1006 debugstr_w(desc), flags );
1008 if (hash->magic != MAGIC_HASH || key->magic != MAGIC_KEY) return FALSE;
1009 if (flags)
1011 FIXME( "flags %08lx not supported\n", flags );
1012 return FALSE;
1015 return !BCryptVerifySignature( key->handle, NULL, hash->value, hash->len, (UCHAR *)sig, siglen, 0 );