kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[wine] / dlls / crypt32 / tests / cert.c
1 /*
2  * crypt32 cert functions tests
3  *
4  * Copyright 2005 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <windef.h>
25 #include <winbase.h>
26 #include <winreg.h>
27 #include <winerror.h>
28 #include <wincrypt.h>
29
30 #include "wine/test.h"
31
32 /* The following aren't defined in wincrypt.h, as they're "reserved" */
33 #define CERT_CERT_PROP_ID 32
34 #define CERT_CRL_PROP_ID  33
35 #define CERT_CTL_PROP_ID  34
36
37 struct CertPropIDHeader
38 {
39     DWORD propID;
40     DWORD unknown1;
41     DWORD cb;
42 };
43
44 static BOOL (WINAPI * pCryptVerifyCertificateSignatureEx)
45                         (HCRYPTPROV, DWORD, DWORD, void *, DWORD, void *, DWORD, void *);
46
47 #define CRYPT_GET_PROC(func)                                       \
48     p ## func = (void *)GetProcAddress(hCrypt32, #func);           \
49     if(!p ## func)                                                 \
50         trace("GetProcAddress(hCrypt32, \"%s\") failed\n", #func); \
51
52 static void init_function_pointers(void)
53 {
54     HMODULE hCrypt32;
55
56     pCryptVerifyCertificateSignatureEx = NULL;
57
58     hCrypt32 = GetModuleHandleA("crypt32.dll");
59     assert(hCrypt32);
60
61     CRYPT_GET_PROC(CryptVerifyCertificateSignatureEx);
62 }
63
64 static void testCryptHashCert(void)
65 {
66     static const BYTE emptyHash[] = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b,
67      0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07,
68      0x09 };
69     static const BYTE knownHash[] = { 0xae, 0x9d, 0xbf, 0x6d, 0xf5, 0x46, 0xee,
70      0x8b, 0xc5, 0x7a, 0x13, 0xba, 0xc2, 0xb1, 0x04, 0xf2, 0xbf, 0x52, 0xa8,
71      0xa2 };
72     static const BYTE toHash[] = "abcdefghijklmnopqrstuvwxyz0123456789.,;!?:";
73     BOOL ret;
74     BYTE hash[20];
75     DWORD hashLen = sizeof(hash);
76
77     /* NULL buffer and nonzero length crashes
78     ret = CryptHashCertificate(0, 0, 0, NULL, size, hash, &hashLen);
79        empty hash length also crashes
80     ret = CryptHashCertificate(0, 0, 0, buf, size, hash, NULL);
81      */
82     /* Test empty hash */
83     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), NULL,
84      &hashLen);
85     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
86     ok(hashLen == sizeof(hash),
87      "Got unexpected size of hash %ld, expected %d\n", hashLen, sizeof(hash));
88     /* Test with empty buffer */
89     ret = CryptHashCertificate(0, 0, 0, NULL, 0, hash, &hashLen);
90     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
91     ok(!memcmp(hash, emptyHash, sizeof(emptyHash)),
92      "Unexpected hash of nothing\n");
93     /* Test a known value */
94     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), hash,
95      &hashLen);
96     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
97     ok(!memcmp(hash, knownHash, sizeof(knownHash)), "Unexpected hash\n");
98 }
99
100 static const BYTE emptyCert[] = { 0x30, 0x00 };
101 static const BYTE bigCert[] = "\x30\x7a\x02\x01\x01\x30\x02\x06\x00"
102  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e\x20\x4c"
103  "\x61\x6e\x67\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30"
104  "\x30\x30\x30\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30"
105  "\x30\x5a\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e"
106  "\x20\x4c\x61\x6e\x67\x00\x30\x07\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14"
107  "\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01"
108  "\x01";
109 static const BYTE signedBigCert[] = {
110  0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
111  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
112  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
113  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
114  0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
115  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
116  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
117  0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
118  0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
119  0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
120  0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
121  0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
122 static const BYTE serializedCert[] = { 0x20, 0x00, 0x00, 0x00,
123  0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x7a, 0x02, 0x01, 0x01,
124  0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
125  0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67,
126  0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31,
127  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
128  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15,
129  0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75,
130  0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06,
131  0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
132  0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02,
133  0x01, 0x01 };
134 static const BYTE signedCRL[] = { 0x30, 0x45, 0x30, 0x2c, 0x30, 0x02, 0x06,
135  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
136  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
137  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
138  0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c,
139  0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
140
141 static void testMemStore(void)
142 {
143     HCERTSTORE store1, store2;
144     PCCERT_CONTEXT context;
145     BOOL ret;
146
147     /* NULL provider */
148     store1 = CertOpenStore(0, 0, 0, 0, NULL);
149     ok(!store1 && GetLastError() == ERROR_FILE_NOT_FOUND,
150      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
151     /* weird flags */
152     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
153      CERT_STORE_DELETE_FLAG, NULL);
154     ok(!store1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
155      "Expected ERROR_CALL_NOT_IMPLEMENTED, got %ld\n", GetLastError());
156
157     /* normal */
158     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
159      CERT_STORE_CREATE_NEW_FLAG, NULL);
160     ok(store1 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
161     /* open existing doesn't */
162     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
163      CERT_STORE_OPEN_EXISTING_FLAG, NULL);
164     ok(store2 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
165     ok(store1 != store2, "Expected different stores\n");
166
167     /* add a bogus (empty) cert */
168     context = NULL;
169     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, emptyCert,
170      sizeof(emptyCert), CERT_STORE_ADD_ALWAYS, &context);
171     /* Windows returns CRYPT_E_ASN1_EOD, but accept CRYPT_E_ASN1_CORRUPT as
172      * well (because matching errors is tough in this case)
173      */
174     ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || GetLastError() ==
175      CRYPT_E_ASN1_CORRUPT),
176      "Expected CRYPT_E_ASN1_EOD or CRYPT_E_ASN1_CORRUPT, got %08lx\n",
177      GetLastError());
178     /* add a "signed" cert--the signature isn't a real signature, so this adds
179      * without any check of the signature's validity
180      */
181     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
182      signedBigCert, sizeof(signedBigCert), CERT_STORE_ADD_ALWAYS, &context);
183     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
184     ok(context != NULL, "Expected a valid cert context\n");
185     if (context)
186     {
187         ok(context->cbCertEncoded == sizeof(signedBigCert),
188          "Expected cert of %d bytes, got %ld\n", sizeof(signedBigCert),
189          context->cbCertEncoded);
190         ok(!memcmp(context->pbCertEncoded, signedBigCert,
191          sizeof(signedBigCert)), "Unexpected encoded cert in context\n");
192         /* remove it, the rest of the tests will work on an unsigned cert */
193         ret = CertDeleteCertificateFromStore(context);
194         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
195          GetLastError());
196     }
197     /* try adding a "signed" CRL as a cert */
198     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
199      signedCRL, sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, &context);
200     ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || GetLastError() ==
201      CRYPT_E_ASN1_CORRUPT),
202      "Expected CRYPT_E_ASN1_BADTAG or CRYPT_E_ASN1_CORRUPT, got %08lx\n",
203      GetLastError());
204     /* add a cert to store1 */
205     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert,
206      sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, &context);
207     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
208     ok(context != NULL, "Expected a valid cert context\n");
209     if (context)
210     {
211         DWORD size;
212         BYTE *buf;
213
214         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
215          "Expected cert of %d bytes, got %ld\n", sizeof(bigCert) - 1,
216          context->cbCertEncoded);
217         ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert) - 1),
218          "Unexpected encoded cert in context\n");
219         ok(context->hCertStore == store1, "Unexpected store\n");
220
221         /* check serializing this element */
222         /* These crash
223         ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, NULL);
224         ret = CertSerializeCertificateStoreElement(context, 0, NULL, NULL);
225         ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, &size);
226          */
227         /* apparently flags are ignored */
228         ret = CertSerializeCertificateStoreElement(context, 1, NULL, &size);
229         ok(ret, "CertSerializeCertificateStoreElement failed: %08lx\n",
230          GetLastError());
231         buf = HeapAlloc(GetProcessHeap(), 0, size);
232         if (buf)
233         {
234             ret = CertSerializeCertificateStoreElement(context, 0, buf, &size);
235             ok(size == sizeof(serializedCert), "Expected size %d, got %ld\n",
236              sizeof(serializedCert), size);
237             ok(!memcmp(serializedCert, buf, size),
238              "Unexpected serialized cert\n");
239             HeapFree(GetProcessHeap(), 0, buf);
240         }
241
242         ret = CertFreeCertificateContext(context);
243         ok(ret, "CertFreeCertificateContext failed: %08lx\n", GetLastError());
244     }
245     /* verify the cert's in store1 */
246     context = CertEnumCertificatesInStore(store1, NULL);
247     ok(context != NULL, "Expected a valid context\n");
248     context = CertEnumCertificatesInStore(store1, context);
249     ok(!context && GetLastError() == CRYPT_E_NOT_FOUND,
250      "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
251     /* verify store2 (the "open existing" mem store) is still empty */
252     context = CertEnumCertificatesInStore(store2, NULL);
253     ok(!context, "Expected an empty store\n");
254     /* delete the cert from store1, and check it's empty */
255     context = CertEnumCertificatesInStore(store1, NULL);
256     if (context)
257     {
258         /* Deleting a bitwise copy crashes with an access to an uninitialized
259          * pointer, so a cert context has some special data out there in memory
260          * someplace
261         CERT_CONTEXT copy;
262         memcpy(&copy, context, sizeof(copy));
263         ret = CertDeleteCertificateFromStore(&copy);
264          */
265         PCCERT_CONTEXT copy = CertDuplicateCertificateContext(context);
266
267         ok(copy != NULL, "CertDuplicateCertificateContext failed: %08lx\n",
268          GetLastError());
269         ret = CertDeleteCertificateFromStore(context);
270         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
271          GetLastError());
272         /* try deleting a copy */
273         ret = CertDeleteCertificateFromStore(copy);
274         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
275          GetLastError());
276         /* check that the store is empty */
277         context = CertEnumCertificatesInStore(store1, NULL);
278         ok(!context, "Expected an empty store\n");
279     }
280
281     /* close an empty store */
282     ret = CertCloseStore(NULL, 0);
283     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
284     ret = CertCloseStore(store1, 0);
285     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
286     ret = CertCloseStore(store2, 0);
287     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
288
289     /* This seems nonsensical, but you can open a read-only mem store, only
290      * it isn't read-only
291      */
292     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
293      CERT_STORE_READONLY_FLAG, NULL);
294     ok(store1 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
295     /* yep, this succeeds */
296     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert,
297      sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, &context);
298     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
299     ok(context != NULL, "Expected a valid cert context\n");
300     if (context)
301     {
302         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
303          "Expected cert of %d bytes, got %ld\n", sizeof(bigCert) - 1,
304          context->cbCertEncoded);
305         ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert) - 1),
306          "Unexpected encoded cert in context\n");
307         ok(context->hCertStore == store1, "Unexpected store\n");
308         ret = CertDeleteCertificateFromStore(context);
309         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
310          GetLastError());
311     }
312     CertCloseStore(store1, 0);
313 }
314
315 static const BYTE bigCert2[] = "\x30\x7a\x02\x01\x01\x30\x02\x06\x00"
316  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x41\x6c\x65\x78\x20\x4c"
317  "\x61\x6e\x67\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30"
318  "\x30\x30\x30\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30"
319  "\x30\x5a\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x41\x6c\x65\x78"
320  "\x20\x4c\x61\x6e\x67\x00\x30\x07\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14"
321  "\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01"
322  "\x01";
323
324 static void testCollectionStore(void)
325 {
326     HCERTSTORE store1, store2, collection, collection2;
327     PCCERT_CONTEXT context;
328     BOOL ret;
329
330     collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
331      CERT_STORE_CREATE_NEW_FLAG, NULL);
332
333     /* Try adding a cert to any empty collection */
334     ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
335      bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
336     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
337      "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
338      GetLastError());
339
340     /* Create and add a cert to a memory store */
341     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
342      CERT_STORE_CREATE_NEW_FLAG, NULL);
343     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
344      bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
345     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
346     /* Add the memory store to the collection, without allowing adding */
347     ret = CertAddStoreToCollection(collection, store1, 0, 0);
348     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
349     /* Verify the cert is in the collection */
350     context = CertEnumCertificatesInStore(collection, NULL);
351     ok(context != NULL, "Expected a valid context\n");
352     if (context)
353     {
354         ok(context->hCertStore == collection, "Unexpected store\n");
355         CertFreeCertificateContext(context);
356     }
357     /* Check that adding to the collection isn't allowed */
358     ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
359      bigCert2, sizeof(bigCert2) - 1, CERT_STORE_ADD_ALWAYS, NULL);
360     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
361      "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
362      GetLastError());
363
364     /* Create a new memory store */
365     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
366      CERT_STORE_CREATE_NEW_FLAG, NULL);
367     /* Try adding a store to a non-collection store */
368     ret = CertAddStoreToCollection(store1, store2,
369      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
370     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
371      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
372      GetLastError());
373     /* Try adding some bogus stores */
374     /* This crashes in Windows
375     ret = CertAddStoreToCollection(0, store2,
376      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
377      */
378     /* This "succeeds"... */
379     ret = CertAddStoreToCollection(collection, 0,
380      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
381     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
382     /* while this crashes.
383     ret = CertAddStoreToCollection(collection, 1,
384      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
385      */
386
387     /* Add it to the collection, this time allowing adding */
388     ret = CertAddStoreToCollection(collection, store2,
389      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
390     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
391     /* Check that adding to the collection is allowed */
392     ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
393      bigCert2, sizeof(bigCert2) - 1, CERT_STORE_ADD_ALWAYS, NULL);
394     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
395     /* Now check that it was actually added to store2 */
396     context = CertEnumCertificatesInStore(store2, NULL);
397     ok(context != NULL, "Expected a valid context\n");
398     if (context)
399     {
400         ok(context->hCertStore == store2, "Unexpected store\n");
401         CertFreeCertificateContext(context);
402     }
403     /* Check that the collection has both bigCert and bigCert2.  bigCert comes
404      * first because store1 was added first.
405      */
406     context = CertEnumCertificatesInStore(collection, NULL);
407     ok(context != NULL, "Expected a valid context\n");
408     if (context)
409     {
410         ok(context->hCertStore == collection, "Unexpected store\n");
411         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
412          "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
413          context->cbCertEncoded);
414         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
415          "Unexpected cert\n");
416         context = CertEnumCertificatesInStore(collection, context);
417         ok(context != NULL, "Expected a valid context\n");
418         if (context)
419         {
420             ok(context->hCertStore == collection, "Unexpected store\n");
421             ok(context->cbCertEncoded == sizeof(bigCert2) - 1,
422              "Expected size %d, got %ld\n", sizeof(bigCert2) - 1,
423              context->cbCertEncoded);
424             ok(!memcmp(context->pbCertEncoded, bigCert2,
425              context->cbCertEncoded), "Unexpected cert\n");
426             context = CertEnumCertificatesInStore(collection, context);
427             ok(!context, "Unexpected cert\n");
428         }
429     }
430     /* close store2, and check that the collection is unmodified */
431     CertCloseStore(store2, 0);
432     context = CertEnumCertificatesInStore(collection, NULL);
433     ok(context != NULL, "Expected a valid context\n");
434     if (context)
435     {
436         ok(context->hCertStore == collection, "Unexpected store\n");
437         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
438          "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
439          context->cbCertEncoded);
440         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
441          "Unexpected cert\n");
442         context = CertEnumCertificatesInStore(collection, context);
443         ok(context != NULL, "Expected a valid context\n");
444         if (context)
445         {
446             ok(context->hCertStore == collection, "Unexpected store\n");
447             ok(context->cbCertEncoded == sizeof(bigCert2) - 1,
448              "Expected size %d, got %ld\n", sizeof(bigCert2) - 1,
449              context->cbCertEncoded);
450             ok(!memcmp(context->pbCertEncoded, bigCert2,
451              context->cbCertEncoded), "Unexpected cert\n");
452             context = CertEnumCertificatesInStore(collection, context);
453             ok(!context, "Unexpected cert\n");
454         }
455     }
456
457     /* Adding a collection to a collection is legal */
458     collection2 = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
459      CERT_STORE_CREATE_NEW_FLAG, NULL);
460     ret = CertAddStoreToCollection(collection2, collection,
461      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
462     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
463     /* check the contents of collection2 */
464     context = CertEnumCertificatesInStore(collection2, NULL);
465     ok(context != NULL, "Expected a valid context\n");
466     if (context)
467     {
468         ok(context->hCertStore == collection2, "Unexpected store\n");
469         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
470          "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
471          context->cbCertEncoded);
472         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
473          "Unexpected cert\n");
474         context = CertEnumCertificatesInStore(collection2, context);
475         ok(context != NULL, "Expected a valid context\n");
476         if (context)
477         {
478             ok(context->hCertStore == collection2, "Unexpected store\n");
479             ok(context->cbCertEncoded == sizeof(bigCert2) - 1,
480              "Expected size %d, got %ld\n", sizeof(bigCert2) - 1,
481              context->cbCertEncoded);
482             ok(!memcmp(context->pbCertEncoded, bigCert2,
483              context->cbCertEncoded), "Unexpected cert\n");
484             context = CertEnumCertificatesInStore(collection2, context);
485             ok(!context, "Unexpected cert\n");
486         }
487     }
488
489     /* I'd like to test closing the collection in the middle of enumeration,
490      * but my tests have been inconsistent.  The first time calling
491      * CertEnumCertificatesInStore on a closed collection succeeded, while the
492      * second crashed.  So anything appears to be fair game.
493      * I'd also like to test removing a store from a collection in the middle
494      * of an enumeration, but my tests in Windows have been inconclusive.
495      * In one scenario it worked.  In another scenario, about a third of the
496      * time this leads to "random" crashes elsewhere in the code.  This
497      * probably means this is not allowed.
498      */
499
500     CertCloseStore(store1, 0);
501     CertCloseStore(collection, 0);
502     CertCloseStore(collection2, 0);
503
504     /* Add the same cert to two memory stores, then put them in a collection */
505     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
506      CERT_STORE_CREATE_NEW_FLAG, NULL);
507     ok(store1 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
508     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
509      CERT_STORE_CREATE_NEW_FLAG, NULL);
510     ok(store2 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
511
512     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
513      bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
514     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
515     ret = CertAddEncodedCertificateToStore(store2, X509_ASN_ENCODING,
516      bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
517     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
518     collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
519      CERT_STORE_CREATE_NEW_FLAG, NULL);
520     ok(collection != 0, "CertOpenStore failed: %08lx\n", GetLastError());
521
522     ret = CertAddStoreToCollection(collection, store1,
523      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
524     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
525     ret = CertAddStoreToCollection(collection, store2,
526      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
527     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
528
529     /* Check that the collection has two copies of the same cert */
530     context = CertEnumCertificatesInStore(collection, NULL);
531     ok(context != NULL, "Expected a valid context\n");
532     if (context)
533     {
534         ok(context->hCertStore == collection, "Unexpected store\n");
535         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
536          "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
537          context->cbCertEncoded);
538         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
539          "Unexpected cert\n");
540         context = CertEnumCertificatesInStore(collection, context);
541         ok(context != NULL, "Expected a valid context\n");
542         if (context)
543         {
544             ok(context->hCertStore == collection, "Unexpected store\n");
545             ok(context->cbCertEncoded == sizeof(bigCert) - 1,
546              "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
547              context->cbCertEncoded);
548             ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
549              "Unexpected cert\n");
550             context = CertEnumCertificatesInStore(collection, context);
551             ok(context == NULL, "Unexpected cert\n");
552         }
553     }
554
555     /* The following would check whether I can delete an identical cert, rather
556      * than one enumerated from the store.  It crashes, so that means I must
557      * only call CertDeleteCertificateFromStore with contexts enumerated from
558      * the store.
559     context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
560      sizeof(bigCert) - 1);
561     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
562      GetLastError());
563     if (context)
564     {
565         ret = CertDeleteCertificateFromStore(collection, context);
566         printf("ret is %d, GetLastError is %08lx\n", ret, GetLastError());
567         CertFreeCertificateContext(context);
568     }
569      */
570
571     /* Now check deleting from the collection. */
572     context = CertEnumCertificatesInStore(collection, NULL);
573     ok(context != NULL, "Expected a valid context\n");
574     if (context)
575     {
576         CertDeleteCertificateFromStore(context);
577         /* store1 should now be empty */
578         context = CertEnumCertificatesInStore(store1, NULL);
579         ok(!context, "Unexpected cert\n");
580         /* and there should be one certificate in the collection */
581         context = CertEnumCertificatesInStore(collection, NULL);
582         ok(context != NULL, "Expected a valid cert\n");
583         if (context)
584         {
585             ok(context->hCertStore == collection, "Unexpected store\n");
586             ok(context->cbCertEncoded == sizeof(bigCert) - 1,
587              "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
588              context->cbCertEncoded);
589             ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
590              "Unexpected cert\n");
591         }
592         context = CertEnumCertificatesInStore(collection, context);
593         ok(context == NULL, "Unexpected cert\n");
594     }
595
596     /* Finally, test removing stores from the collection.  No return value, so
597      * it's a bit funny to test.
598      */
599     /* This crashes
600     CertRemoveStoreFromCollection(NULL, NULL);
601      */
602     /* This "succeeds," no crash, no last error set */
603     SetLastError(0xdeadbeef);
604     CertRemoveStoreFromCollection(store2, collection);
605     ok(GetLastError() == 0xdeadbeef,
606      "Didn't expect an error to be set: %08lx\n", GetLastError());
607
608     /* After removing store2, the collection should be empty */
609     SetLastError(0xdeadbeef);
610     CertRemoveStoreFromCollection(collection, store2);
611     ok(GetLastError() == 0xdeadbeef,
612      "Didn't expect an error to be set: %08lx\n", GetLastError());
613     context = CertEnumCertificatesInStore(collection, NULL);
614     ok(!context, "Unexpected cert\n");
615
616     CertCloseStore(collection, 0);
617     CertCloseStore(store2, 0);
618     CertCloseStore(store1, 0);
619 }
620
621 /* Looks for the property with ID propID in the buffer buf.  Returns a pointer
622  * to its header if found, NULL if not.
623  */
624 static const struct CertPropIDHeader *findPropID(const BYTE *buf, DWORD size,
625  DWORD propID)
626 {
627     const struct CertPropIDHeader *ret = NULL;
628     BOOL failed = FALSE;
629
630     while (size && !ret && !failed)
631     {
632         if (size < sizeof(struct CertPropIDHeader))
633             failed = TRUE;
634         else
635         {
636             const struct CertPropIDHeader *hdr =
637              (const struct CertPropIDHeader *)buf;
638
639             size -= sizeof(struct CertPropIDHeader);
640             buf += sizeof(struct CertPropIDHeader);
641             if (size < hdr->cb)
642                 failed = TRUE;
643             else if (hdr->propID == propID)
644                 ret = hdr;
645             else
646             {
647                 buf += hdr->cb;
648                 size -= hdr->cb;
649             }
650         }
651     }
652     return ret;
653 }
654
655 typedef DWORD (WINAPI *SHDeleteKeyAFunc)(HKEY, LPCSTR);
656
657 static void testRegStore(void)
658 {
659     static const char tempKey[] = "Software\\Wine\\CryptTemp";
660     HCERTSTORE store;
661     LONG rc;
662     HKEY key = NULL;
663     DWORD disp;
664
665     store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, NULL);
666     ok(!store && GetLastError() == ERROR_INVALID_HANDLE,
667      "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
668     store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
669     ok(!store && GetLastError() == ERROR_INVALID_HANDLE,
670      "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
671
672     /* Opening up any old key works.. */
673     key = HKEY_CURRENT_USER;
674     store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
675     /* Not sure if this is a bug in DuplicateHandle, marking todo_wine for now
676      */
677     todo_wine ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
678     CertCloseStore(store, 0);
679
680     rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS,
681      NULL, &key, NULL);
682     ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
683     if (key)
684     {
685         BOOL ret;
686         BYTE hash[20];
687         DWORD size, i;
688         static const char certificates[] = "Certificates\\";
689         char subKeyName[sizeof(certificates) + 20 * 2 + 1], *ptr;
690         HKEY subKey;
691         PCCERT_CONTEXT context;
692
693         store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
694         ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
695         /* Add a certificate.  It isn't persisted right away, since it's only
696          * added to the cache..
697          */
698         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
699          bigCert2, sizeof(bigCert2) - 1, CERT_STORE_ADD_ALWAYS, NULL);
700         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
701          GetLastError());
702         /* so flush the cache to force a commit.. */
703         ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
704         ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
705         /* and check that the expected subkey was written. */
706         size = sizeof(hash);
707         ret = CryptHashCertificate(0, 0, 0, bigCert2, sizeof(bigCert2) - 1,
708          hash, &size);
709         ok(ret, "CryptHashCertificate failed: %ld\n", GetLastError());
710         strcpy(subKeyName, certificates);
711         for (i = 0, ptr = subKeyName + sizeof(certificates) - 1; i < size;
712          i++, ptr += 2)
713             sprintf(ptr, "%02X", hash[i]);
714         rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
715          &subKey, NULL);
716         ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
717         if (subKey)
718         {
719             LPBYTE buf;
720
721             size = 0;
722             RegQueryValueExA(subKey, "Blob", NULL, NULL, NULL, &size);
723             buf = HeapAlloc(GetProcessHeap(), 0, size);
724             if (buf)
725             {
726                 rc = RegQueryValueExA(subKey, "Blob", NULL, NULL, buf, &size);
727                 ok(!rc, "RegQueryValueExA failed: %ld\n", rc);
728                 if (!rc)
729                 {
730                     const struct CertPropIDHeader *hdr;
731
732                     /* Both the hash and the cert should be present */
733                     hdr = findPropID(buf, size, CERT_CERT_PROP_ID);
734                     ok(hdr != NULL, "Expected to find a cert property\n");
735                     if (hdr)
736                     {
737                         ok(hdr->cb == sizeof(bigCert2) - 1,
738                          "Unexpected size %ld of cert property, expected %d\n",
739                          hdr->cb, sizeof(bigCert2) - 1);
740                         ok(!memcmp((BYTE *)hdr + sizeof(*hdr), bigCert2,
741                          hdr->cb), "Unexpected cert in cert property\n");
742                     }
743                     hdr = findPropID(buf, size, CERT_HASH_PROP_ID);
744                     ok(hdr != NULL, "Expected to find a hash property\n");
745                     if (hdr)
746                     {
747                         ok(hdr->cb == sizeof(hash),
748                          "Unexpected size %ld of hash property, expected %d\n",
749                          hdr->cb, sizeof(hash));
750                         ok(!memcmp((BYTE *)hdr + sizeof(*hdr), hash,
751                          hdr->cb), "Unexpected hash in cert property\n");
752                     }
753                 }
754                 HeapFree(GetProcessHeap(), 0, buf);
755             }
756             RegCloseKey(subKey);
757         }
758
759         /* Remove the existing context */
760         context = CertEnumCertificatesInStore(store, NULL);
761         ok(context != NULL, "Expected a cert context\n");
762         if (context)
763             CertDeleteCertificateFromStore(context);
764         ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
765         ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
766
767         /* Add a serialized cert with a bogus hash directly to the registry */
768         memset(hash, 0, sizeof(hash));
769         strcpy(subKeyName, certificates);
770         for (i = 0, ptr = subKeyName + sizeof(certificates) - 1;
771          i < sizeof(hash); i++, ptr += 2)
772             sprintf(ptr, "%02X", hash[i]);
773         rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
774          &subKey, NULL);
775         ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
776         if (subKey)
777         {
778             BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) +
779              sizeof(bigCert) - 1], *ptr;
780             DWORD certCount = 0;
781             struct CertPropIDHeader *hdr;
782
783             hdr = (struct CertPropIDHeader *)buf;
784             hdr->propID = CERT_HASH_PROP_ID;
785             hdr->unknown1 = 1;
786             hdr->cb = sizeof(hash);
787             ptr = buf + sizeof(*hdr);
788             memcpy(ptr, hash, sizeof(hash));
789             ptr += sizeof(hash);
790             hdr = (struct CertPropIDHeader *)ptr;
791             hdr->propID = CERT_CERT_PROP_ID;
792             hdr->unknown1 = 1;
793             hdr->cb = sizeof(bigCert) - 1;
794             ptr += sizeof(*hdr);
795             memcpy(ptr, bigCert, sizeof(bigCert) - 1);
796
797             rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
798              sizeof(buf));
799             ok(!rc, "RegSetValueExA failed: %ld\n", rc);
800
801             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
802             ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
803
804             /* Make sure the bogus hash cert gets loaded. */
805             certCount = 0;
806             context = NULL;
807             do {
808                 context = CertEnumCertificatesInStore(store, context);
809                 if (context)
810                     certCount++;
811             } while (context != NULL);
812             ok(certCount == 1, "Expected 1 certificates, got %ld\n", certCount);
813
814             RegCloseKey(subKey);
815         }
816
817         /* Add another serialized cert directly to the registry, this time
818          * under the correct key name (named with the correct hash value).
819          */
820         size = sizeof(hash);
821         ret = CryptHashCertificate(0, 0, 0, bigCert2,
822          sizeof(bigCert2) - 1, hash, &size);
823         ok(ret, "CryptHashCertificate failed: %ld\n", GetLastError());
824         strcpy(subKeyName, certificates);
825         for (i = 0, ptr = subKeyName + sizeof(certificates) - 1;
826          i < sizeof(hash); i++, ptr += 2)
827             sprintf(ptr, "%02X", hash[i]);
828         rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
829          &subKey, NULL);
830         ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
831         if (subKey)
832         {
833             BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) +
834              sizeof(bigCert2) - 1], *ptr;
835             DWORD certCount = 0;
836             PCCERT_CONTEXT context;
837             struct CertPropIDHeader *hdr;
838
839             /* First try with a bogus hash... */
840             hdr = (struct CertPropIDHeader *)buf;
841             hdr->propID = CERT_HASH_PROP_ID;
842             hdr->unknown1 = 1;
843             hdr->cb = sizeof(hash);
844             ptr = buf + sizeof(*hdr);
845             memset(ptr, 0, sizeof(hash));
846             ptr += sizeof(hash);
847             hdr = (struct CertPropIDHeader *)ptr;
848             hdr->propID = CERT_CERT_PROP_ID;
849             hdr->unknown1 = 1;
850             hdr->cb = sizeof(bigCert2) - 1;
851             ptr += sizeof(*hdr);
852             memcpy(ptr, bigCert2, sizeof(bigCert2) - 1);
853
854             rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
855              sizeof(buf));
856             ok(!rc, "RegSetValueExA failed: %ld\n", rc);
857
858             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
859             ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
860
861             /* and make sure just one cert still gets loaded. */
862             certCount = 0;
863             context = NULL;
864             do {
865                 context = CertEnumCertificatesInStore(store, context);
866                 if (context)
867                     certCount++;
868             } while (context != NULL);
869             ok(certCount == 1, "Expected 1 certificates, got %ld\n", certCount);
870
871             /* Try again with the correct hash... */
872             ptr = buf + sizeof(*hdr);
873             memcpy(ptr, hash, sizeof(hash));
874
875             rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
876              sizeof(buf));
877             ok(!rc, "RegSetValueExA failed: %ld\n", rc);
878
879             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
880             ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
881
882             /* and make sure two certs get loaded. */
883             certCount = 0;
884             context = NULL;
885             do {
886                 context = CertEnumCertificatesInStore(store, context);
887                 if (context)
888                     certCount++;
889             } while (context != NULL);
890             ok(certCount == 2, "Expected 2 certificates, got %ld\n", certCount);
891
892             RegCloseKey(subKey);
893         }
894         CertCloseStore(store, 0);
895         /* Is delete allowed on a reg store? */
896         store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0,
897          CERT_STORE_DELETE_FLAG, key);
898         ok(store == NULL, "Expected NULL return from CERT_STORE_DELETE_FLAG\n");
899         ok(GetLastError() == 0, "CertOpenStore failed: %08lx\n",
900          GetLastError());
901
902         RegCloseKey(key);
903     }
904     /* The CertOpenStore with CERT_STORE_DELETE_FLAG above will delete the
905      * contents of the key, but not the key itself.
906      */
907     rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS,
908      NULL, &key, &disp);
909     ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
910     ok(disp == REG_OPENED_EXISTING_KEY,
911      "Expected REG_OPENED_EXISTING_KEY, got %ld\n", disp);
912     if (!rc)
913     {
914         RegCloseKey(key);
915         rc = RegDeleteKeyA(HKEY_CURRENT_USER, tempKey);
916         if (rc)
917         {
918             HMODULE shlwapi = LoadLibraryA("shlwapi");
919
920             /* Use shlwapi's SHDeleteKeyA to _really_ blow away the key,
921              * otherwise subsequent tests will fail.
922              */
923             if (shlwapi)
924             {
925                 SHDeleteKeyAFunc pSHDeleteKeyA =
926                  (SHDeleteKeyAFunc)GetProcAddress(shlwapi, "SHDeleteKeyA");
927
928                 if (pSHDeleteKeyA)
929                     pSHDeleteKeyA(HKEY_CURRENT_USER, tempKey);
930                 FreeLibrary(shlwapi);
931             }
932         }
933     }
934 }
935
936 static const char MyA[] = { 'M','y',0,0 };
937 static const WCHAR MyW[] = { 'M','y',0 };
938 static const WCHAR BogusW[] = { 'B','o','g','u','s',0 };
939 static const WCHAR BogusPathW[] = { 'S','o','f','t','w','a','r','e','\\',
940  'M','i','c','r','o','s','o','f','t','\\','S','y','s','t','e','m','C','e','r',
941  't','i','f','i','c','a','t','e','s','\\','B','o','g','u','s',0 };
942
943 static void testSystemRegStore(void)
944 {
945     HCERTSTORE store, memStore;
946
947     /* Check with a UNICODE name */
948     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
949      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW);
950     /* Not all OSes support CERT_STORE_PROV_SYSTEM_REGISTRY, so don't continue
951      * testing if they don't.
952      */
953     if (!store)
954         return;
955
956     /* Check that it isn't a collection store */
957     memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
958      CERT_STORE_CREATE_NEW_FLAG, NULL);
959     if (memStore)
960     {
961         BOOL ret = CertAddStoreToCollection(store, memStore, 0, 0);
962
963         ok(!ret && GetLastError() ==
964          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
965          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
966          GetLastError());
967         CertCloseStore(memStore, 0);
968     }
969     CertCloseStore(store, 0);
970
971     /* Check opening a bogus store */
972     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
973      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW);
974     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
975      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
976     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
977      CERT_SYSTEM_STORE_CURRENT_USER, BogusW);
978     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
979     if (store)
980         CertCloseStore(store, 0);
981     /* Now check whether deleting is allowed */
982     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
983      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
984     RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
985
986     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, 0, NULL);
987     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
988      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
989      GetLastError());
990     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
991      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA);
992     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
993      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
994      GetLastError());
995     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
996      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW);
997     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
998      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
999      GetLastError());
1000     /* The name is expected to be UNICODE, check with an ASCII name */
1001     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
1002      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA);
1003     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1004      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1005 }
1006
1007 static void testSystemStore(void)
1008 {
1009     static const WCHAR baskslashW[] = { '\\',0 };
1010     HCERTSTORE store;
1011     WCHAR keyName[MAX_PATH];
1012     HKEY key;
1013     LONG rc;
1014
1015     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, 0, NULL);
1016     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1017      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1018     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1019      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA);
1020     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1021      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1022     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1023      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW);
1024     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1025      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1026     /* The name is expected to be UNICODE, first check with an ASCII name */
1027     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1028      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA);
1029     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1030      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1031     /* Create the expected key */
1032     lstrcpyW(keyName, CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH);
1033     lstrcatW(keyName, baskslashW);
1034     lstrcatW(keyName, MyW);
1035     rc = RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
1036      NULL, &key, NULL);
1037     ok(!rc, "RegCreateKeyEx failed: %ld\n", rc);
1038     if (!rc)
1039         RegCloseKey(key);
1040     /* Check opening with a UNICODE name, specifying the create new flag */
1041     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1042      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_CREATE_NEW_FLAG, MyW);
1043     ok(!store && GetLastError() == ERROR_FILE_EXISTS,
1044      "Expected ERROR_FILE_EXISTS, got %08lx\n", GetLastError());
1045     /* Now check opening with a UNICODE name, this time opening existing */
1046     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1047      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW);
1048     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1049     if (store)
1050     {
1051         HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1052          CERT_STORE_CREATE_NEW_FLAG, NULL);
1053
1054         /* Check that it's a collection store */
1055         if (memStore)
1056         {
1057             BOOL ret = CertAddStoreToCollection(store, memStore, 0, 0);
1058
1059             /* FIXME: this'll fail on NT4, but what error will it give? */
1060             ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
1061             CertCloseStore(memStore, 0);
1062         }
1063         CertCloseStore(store, 0);
1064     }
1065
1066     /* Check opening a bogus store */
1067     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1068      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW);
1069     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1070      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1071     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1072      CERT_SYSTEM_STORE_CURRENT_USER, BogusW);
1073     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1074     if (store)
1075         CertCloseStore(store, 0);
1076     /* Now check whether deleting is allowed */
1077     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1078      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
1079     RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
1080 }
1081
1082 static void testCertOpenSystemStore(void)
1083 {
1084     HCERTSTORE store;
1085
1086     store = CertOpenSystemStoreW(0, NULL);
1087     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1088      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1089      GetLastError());
1090     /* This succeeds, and on WinXP at least, the Bogus key is created under
1091      * HKCU (but not under HKLM, even when run as an administrator.)
1092      */
1093     store = CertOpenSystemStoreW(0, BogusW);
1094     ok(store != 0, "CertOpenSystemStore failed: %08lx\n", GetLastError());
1095     if (store)
1096         CertCloseStore(store, 0);
1097     /* Delete it so other tests succeed next time around */
1098     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1099      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
1100     RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
1101 }
1102
1103 static void checkHash(const BYTE *data, DWORD dataLen, ALG_ID algID,
1104  PCCERT_CONTEXT context, DWORD propID)
1105 {
1106     BYTE hash[20] = { 0 }, hashProperty[20];
1107     BOOL ret;
1108     DWORD size;
1109
1110     memset(hash, 0, sizeof(hash));
1111     memset(hashProperty, 0, sizeof(hashProperty));
1112     size = sizeof(hash);
1113     ret = CryptHashCertificate(0, algID, 0, data, dataLen, hash, &size);
1114     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1115     ret = CertGetCertificateContextProperty(context, propID, hashProperty,
1116      &size);
1117     ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1118      GetLastError());
1119     ok(!memcmp(hash, hashProperty, size), "Unexpected hash for property %ld\n",
1120      propID);
1121 }
1122
1123 static void testCertProperties(void)
1124 {
1125     PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING,
1126      bigCert, sizeof(bigCert) - 1);
1127
1128     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
1129      GetLastError());
1130     if (context)
1131     {
1132         DWORD propID, numProps, access, size;
1133         BOOL ret;
1134         BYTE hash[20] = { 0 }, hashProperty[20];
1135         CRYPT_DATA_BLOB blob;
1136
1137         /* This crashes
1138         propID = CertEnumCertificateContextProperties(NULL, 0);
1139          */
1140
1141         propID = 0;
1142         numProps = 0;
1143         do {
1144             propID = CertEnumCertificateContextProperties(context, propID);
1145             if (propID)
1146                 numProps++;
1147         } while (propID != 0);
1148         ok(numProps == 0, "Expected 0 properties, got %ld\n", numProps);
1149
1150         /* Tests with a NULL cert context.  Prop ID 0 fails.. */
1151         ret = CertSetCertificateContextProperty(NULL, 0, 0, NULL);
1152         ok(!ret && GetLastError() ==
1153          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1154          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1155          GetLastError());
1156         /* while this just crashes.
1157         ret = CertSetCertificateContextProperty(NULL,
1158          CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
1159          */
1160
1161         ret = CertSetCertificateContextProperty(context, 0, 0, NULL);
1162         ok(!ret && GetLastError() ==
1163          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1164          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1165          GetLastError());
1166         /* Can't set the cert property directly, this crashes.
1167         ret = CertSetCertificateContextProperty(context,
1168          CERT_CERT_PROP_ID, 0, bigCert2);
1169          */
1170
1171         /* These all crash.
1172         ret = CertGetCertificateContextProperty(context,
1173          CERT_ACCESS_STATE_PROP_ID, 0, NULL);
1174         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, 
1175          NULL, NULL);
1176         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, 
1177          hashProperty, NULL);
1178          */
1179         /* A missing prop */
1180         size = 0;
1181         ret = CertGetCertificateContextProperty(context,
1182          CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
1183         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
1184          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
1185         /* And, an implicit property */
1186         size = sizeof(access);
1187         ret = CertGetCertificateContextProperty(context,
1188          CERT_ACCESS_STATE_PROP_ID, &access, &size);
1189         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1190          GetLastError());
1191         ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG),
1192          "Didn't expect a persisted cert\n");
1193         /* Trying to set this "read only" property crashes.
1194         access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1195         ret = CertSetCertificateContextProperty(context,
1196          CERT_ACCESS_STATE_PROP_ID, 0, &access);
1197          */
1198
1199         /* Can I set the hash to an invalid hash? */
1200         blob.pbData = hash;
1201         blob.cbData = sizeof(hash);
1202         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1203          &blob);
1204         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1205          GetLastError());
1206         size = sizeof(hashProperty);
1207         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1208          hashProperty, &size);
1209         ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n");
1210         /* Delete the (bogus) hash, and get the real one */
1211         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1212          NULL);
1213         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1214          GetLastError());
1215         checkHash(bigCert, sizeof(bigCert) - 1, CALG_SHA1, context,
1216          CERT_HASH_PROP_ID);
1217
1218         /* Now that the hash property is set, we should get one property when
1219          * enumerating.
1220          */
1221         propID = 0;
1222         numProps = 0;
1223         do {
1224             propID = CertEnumCertificateContextProperties(context, propID);
1225             if (propID)
1226                 numProps++;
1227         } while (propID != 0);
1228         ok(numProps == 1, "Expected 1 properties, got %ld\n", numProps);
1229
1230         /* Check a few other implicit properties */
1231         checkHash(bigCert, sizeof(bigCert) - 1, CALG_MD5, context,
1232          CERT_MD5_HASH_PROP_ID);
1233         checkHash(
1234          context->pCertInfo->Subject.pbData,
1235          context->pCertInfo->Subject.cbData,
1236          CALG_MD5, context, CERT_SUBJECT_NAME_MD5_HASH_PROP_ID);
1237         checkHash(
1238          context->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
1239          context->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
1240          CALG_MD5, context, CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID);
1241
1242         /* Odd: this doesn't fail on other certificates, so there must be
1243          * something weird about this cert that causes it to fail.
1244          */
1245         size = 0;
1246         ret = CertGetCertificateContextProperty(context,
1247          CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1248         todo_wine ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1249          "Expected ERROR_INVALID_DATA, got %08lx\n", GetLastError());
1250
1251         CertFreeCertificateContext(context);
1252     }
1253 }
1254
1255 static void testAddSerialized(void)
1256 {
1257     BOOL ret;
1258     HCERTSTORE store;
1259     BYTE buf[sizeof(struct CertPropIDHeader) * 2 + 20 + sizeof(bigCert) - 1] =
1260      { 0 };
1261     BYTE hash[20];
1262     struct CertPropIDHeader *hdr;
1263     PCCERT_CONTEXT context;
1264
1265     ret = CertAddSerializedElementToStore(0, NULL, 0, 0, 0, 0, NULL, NULL);
1266     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1267      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1268
1269     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1270      CERT_STORE_CREATE_NEW_FLAG, NULL);
1271     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1272
1273     ret = CertAddSerializedElementToStore(store, NULL, 0, 0, 0, 0, NULL, NULL);
1274     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1275      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1276
1277     /* Test with an empty property */
1278     hdr = (struct CertPropIDHeader *)buf;
1279     hdr->propID = CERT_CERT_PROP_ID;
1280     hdr->unknown1 = 1;
1281     hdr->cb = 0;
1282     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1283      NULL, NULL);
1284     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1285      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1286      GetLastError());
1287     /* Test with a bad size in property header */
1288     hdr->cb = sizeof(bigCert) - 2;
1289     memcpy(buf + sizeof(struct CertPropIDHeader), bigCert, sizeof(bigCert) - 1);
1290     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1291      NULL, NULL);
1292     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1293      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1294      GetLastError());
1295     ret = CertAddSerializedElementToStore(store, buf,
1296      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 0, NULL,
1297      NULL);
1298     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1299      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1300      GetLastError());
1301     ret = CertAddSerializedElementToStore(store, buf,
1302      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1303      0, 0, NULL, NULL);
1304     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1305      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1306      GetLastError());
1307     /* Kosher size in property header, but no context type */
1308     hdr->cb = sizeof(bigCert) - 1;
1309     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1310      NULL, NULL);
1311     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1312      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1313      GetLastError());
1314     ret = CertAddSerializedElementToStore(store, buf,
1315      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 0, NULL,
1316      NULL);
1317     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1318      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1319      GetLastError());
1320     ret = CertAddSerializedElementToStore(store, buf,
1321      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1322      0, 0, NULL, NULL);
1323     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1324      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1325      GetLastError());
1326     /* With a bad context type */
1327     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1328      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1329     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1330      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1331      GetLastError());
1332     ret = CertAddSerializedElementToStore(store, buf,
1333      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1334      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1335     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1336      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1337      GetLastError());
1338     ret = CertAddSerializedElementToStore(store, buf,
1339      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1340      0, CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1341     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1342      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1343      GetLastError());
1344     /* Bad unknown field, good type */
1345     hdr->unknown1 = 2;
1346     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1347      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1348     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1349      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1350     ret = CertAddSerializedElementToStore(store, buf,
1351      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1352      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1353     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1354      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1355     ret = CertAddSerializedElementToStore(store, buf,
1356      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1357      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1358     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1359      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1360     /* Most everything okay, but bad add disposition */
1361     hdr->unknown1 = 1;
1362     /* This crashes
1363     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1364      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1365      * as does this
1366     ret = CertAddSerializedElementToStore(store, buf,
1367      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1368      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1369      */
1370     /* Everything okay, but buffer's too big */
1371     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1372      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1373     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1374     /* Everything okay, check it's not re-added */
1375     ret = CertAddSerializedElementToStore(store, buf,
1376      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1377      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1378     ok(!ret && GetLastError() == CRYPT_E_EXISTS,
1379      "Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
1380
1381     context = CertEnumCertificatesInStore(store, NULL);
1382     ok(context != NULL, "Expected a cert\n");
1383     if (context)
1384         CertDeleteCertificateFromStore(context);
1385
1386     /* Try adding with a bogus hash.  Oddly enough, it succeeds, and the hash,
1387      * when queried, is the real hash rather than the bogus hash.
1388      */
1389     hdr = (struct CertPropIDHeader *)(buf + sizeof(struct CertPropIDHeader) +
1390      sizeof(bigCert) - 1);
1391     hdr->propID = CERT_HASH_PROP_ID;
1392     hdr->unknown1 = 1;
1393     hdr->cb = sizeof(hash);
1394     memset(hash, 0xc, sizeof(hash));
1395     memcpy((LPBYTE)hdr + sizeof(struct CertPropIDHeader), hash, sizeof(hash));
1396     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1397      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL,
1398      (const void **)&context);
1399     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1400     if (context)
1401     {
1402         BYTE hashVal[20], realHash[20];
1403         DWORD size = sizeof(hashVal);
1404
1405         ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert) - 1,
1406          realHash, &size);
1407         ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1408         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1409          hashVal, &size);
1410         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1411          GetLastError());
1412         ok(!memcmp(hashVal, realHash, size), "Unexpected hash\n");
1413         CertFreeCertificateContext(context);
1414     }
1415
1416     CertCloseStore(store, 0);
1417 }
1418
1419 static const char cspName[] = "WineCryptTemp";
1420
1421 static void verifySig(HCRYPTPROV csp, const BYTE *toSign, size_t toSignLen,
1422  const BYTE *sig, size_t sigLen)
1423 {
1424     HCRYPTHASH hash;
1425     BOOL ret = CryptCreateHash(csp, CALG_SHA1, 0, 0, &hash);
1426
1427     ok(ret, "CryptCreateHash failed: %08lx\n", GetLastError());
1428     if (ret)
1429     {
1430         BYTE mySig[64];
1431         DWORD mySigSize = sizeof(mySig);
1432
1433         ret = CryptHashData(hash, toSign, toSignLen, 0);
1434         ok(ret, "CryptHashData failed: %08lx\n", GetLastError());
1435         /* use the A variant so the test can run on Win9x */
1436         ret = CryptSignHashA(hash, AT_SIGNATURE, NULL, 0, mySig, &mySigSize);
1437         ok(ret, "CryptSignHash failed: %08lx\n", GetLastError());
1438         if (ret)
1439         {
1440             ok(mySigSize == sigLen, "Expected sig length %d, got %ld\n",
1441              sigLen, mySigSize);
1442             ok(!memcmp(mySig, sig, sigLen), "Unexpected signature\n");
1443         }
1444         CryptDestroyHash(hash);
1445     }
1446 }
1447
1448 /* Tests signing the certificate described by toBeSigned with the CSP passed in,
1449  * using the algorithm with OID sigOID.  The CSP is assumed to be empty, and a
1450  * keyset named AT_SIGNATURE will be added to it.  The signing key will be
1451  * stored in *key, and the signature will be stored in sig.  sigLen should be
1452  * at least 64 bytes.
1453  */
1454 static void testSignCert(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
1455  LPCSTR sigOID, HCRYPTKEY *key, BYTE *sig, DWORD *sigLen)
1456 {
1457     BOOL ret;
1458     DWORD size = 0;
1459     CRYPT_ALGORITHM_IDENTIFIER algoID = { NULL, { 0, NULL } };
1460
1461     /* These all crash
1462     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
1463     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, &size);
1464     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
1465      NULL, NULL, NULL, &size);
1466      */
1467     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
1468      &algoID, NULL, NULL, &size);
1469     ok(!ret && GetLastError() == NTE_BAD_ALGID, 
1470      "Expected NTE_BAD_ALGID, got %08lx\n", GetLastError());
1471     algoID.pszObjId = (LPSTR)sigOID;
1472     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
1473      &algoID, NULL, NULL, &size);
1474     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1475      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
1476     ret = CryptSignCertificate(0, AT_SIGNATURE, 0, toBeSigned->pbData,
1477      toBeSigned->cbData, &algoID, NULL, NULL, &size);
1478     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1479      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
1480
1481     /* No keys exist in the new CSP yet.. */
1482     ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
1483      toBeSigned->cbData, &algoID, NULL, NULL, &size);
1484     ok(!ret && (GetLastError() == NTE_BAD_KEYSET || GetLastError() ==
1485      NTE_NO_KEY), "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %08lx\n",
1486      GetLastError());
1487     ret = CryptGenKey(csp, AT_SIGNATURE, 0, key);
1488     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
1489     if (ret)
1490     {
1491         ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
1492          toBeSigned->cbData, &algoID, NULL, NULL, &size);
1493         ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
1494         ok(size <= *sigLen, "Expected size <= %ld, got %ld\n", *sigLen, size);
1495         if (ret)
1496         {
1497             ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
1498              toBeSigned->cbData, &algoID, NULL, sig, &size);
1499             ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
1500             if (ret)
1501             {
1502                 *sigLen = size;
1503                 verifySig(csp, toBeSigned->pbData, toBeSigned->cbData, sig,
1504                  size);
1505             }
1506         }
1507     }
1508 }
1509
1510 static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
1511  LPCSTR sigOID, const BYTE *sig, DWORD sigLen)
1512 {
1513     CERT_SIGNED_CONTENT_INFO info;
1514     LPBYTE cert = NULL;
1515     DWORD size = 0;
1516     BOOL ret;
1517
1518     if(pCryptVerifyCertificateSignatureEx) {
1519         ret = pCryptVerifyCertificateSignatureEx(0, 0, 0, NULL, 0, NULL, 0, NULL);
1520         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1521          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1522          GetLastError());
1523         ret = pCryptVerifyCertificateSignatureEx(csp, 0, 0, NULL, 0, NULL, 0, NULL);
1524         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1525          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1526         GetLastError());
1527         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, 0, NULL, 0,
1528          NULL, 0, NULL);
1529         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1530          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1531          GetLastError());
1532         /* This crashes
1533         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1534          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, NULL, 0, NULL, 0, NULL);
1535          */
1536     }
1537     info.ToBeSigned.cbData = toBeSigned->cbData;
1538     info.ToBeSigned.pbData = toBeSigned->pbData;
1539     info.SignatureAlgorithm.pszObjId = (LPSTR)sigOID;
1540     info.SignatureAlgorithm.Parameters.cbData = 0;
1541     info.Signature.cbData = sigLen;
1542     info.Signature.pbData = (BYTE *)sig;
1543     info.Signature.cUnusedBits = 0;
1544     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, &info,
1545      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&cert, &size);
1546     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1547     if (cert)
1548     {
1549         CRYPT_DATA_BLOB certBlob = { 0, NULL };
1550         PCERT_PUBLIC_KEY_INFO pubKeyInfo = NULL;
1551
1552         if(pCryptVerifyCertificateSignatureEx) {
1553             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1554              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
1555             ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1556              "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
1557             certBlob.cbData = 1;
1558             certBlob.pbData = (void *)0xdeadbeef;
1559             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1560              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
1561             ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1562              "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1563             certBlob.cbData = size;
1564             certBlob.pbData = cert;
1565             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1566              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
1567             ok(!ret && GetLastError() ==
1568              HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1569              "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1570              GetLastError());
1571             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1572              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
1573              CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL, NULL, 0, NULL);
1574             ok(!ret && GetLastError() ==
1575              HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1576              "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1577              GetLastError());
1578             /* This crashes
1579             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1580              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
1581              CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, NULL, 0, NULL);
1582              */
1583         }
1584         CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
1585          (LPSTR)sigOID, 0, NULL, NULL, &size);
1586         pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, size);
1587         if (pubKeyInfo)
1588         {
1589             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
1590              X509_ASN_ENCODING, (LPSTR)sigOID, 0, NULL, pubKeyInfo, &size);
1591             ok(ret, "CryptExportKey failed: %08lx\n", GetLastError());
1592             if (ret && pCryptVerifyCertificateSignatureEx)
1593             {
1594                 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1595                  CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
1596                  CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pubKeyInfo, 0, NULL);
1597                 ok(ret, "CryptVerifyCertificateSignatureEx failed: %08lx\n",
1598                  GetLastError());
1599             }
1600             HeapFree(GetProcessHeap(), 0, pubKeyInfo);
1601         }
1602         LocalFree(cert);
1603     }
1604 }
1605
1606 static void testCertSigs(void)
1607 {
1608     HCRYPTPROV csp;
1609     CRYPT_DATA_BLOB toBeSigned = { sizeof(emptyCert), (LPBYTE)emptyCert };
1610     BOOL ret;
1611     HCRYPTKEY key;
1612     BYTE sig[64];
1613     DWORD sigSize = sizeof(sig);
1614
1615     /* Just in case a previous run failed, delete this thing */
1616     CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
1617      CRYPT_DELETEKEYSET);
1618     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
1619      CRYPT_NEWKEYSET);
1620     ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError());
1621
1622     testSignCert(csp, &toBeSigned, szOID_RSA_SHA1RSA, &key, sig, &sigSize);
1623     testVerifyCertSig(csp, &toBeSigned, szOID_RSA_SHA1RSA, sig, sigSize);
1624
1625     CryptDestroyKey(key);
1626     CryptReleaseContext(csp, 0);
1627     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
1628      CRYPT_DELETEKEYSET);
1629 }
1630
1631 START_TEST(cert)
1632 {
1633     init_function_pointers();
1634
1635     testCryptHashCert();
1636
1637     /* various combinations of CertOpenStore */
1638     testMemStore();
1639     testCollectionStore();
1640     testRegStore();
1641     testSystemRegStore();
1642     testSystemStore();
1643
1644     testCertOpenSystemStore();
1645
1646     testCertProperties();
1647     testAddSerialized();
1648
1649     testCertSigs();
1650 }