Make Crypt32 tests loadable on Win98.
[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 testCertProperties(void)
1104 {
1105     PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING,
1106      bigCert, sizeof(bigCert) - 1);
1107
1108     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
1109      GetLastError());
1110     if (context)
1111     {
1112         DWORD propID, numProps, access, size;
1113         BOOL ret;
1114         BYTE hash[20] = { 0 }, hashProperty[20];
1115         CRYPT_DATA_BLOB blob;
1116
1117         /* This crashes
1118         propID = CertEnumCertificateContextProperties(NULL, 0);
1119          */
1120
1121         propID = 0;
1122         numProps = 0;
1123         do {
1124             propID = CertEnumCertificateContextProperties(context, propID);
1125             if (propID)
1126                 numProps++;
1127         } while (propID != 0);
1128         ok(numProps == 0, "Expected 0 properties, got %ld\n", numProps);
1129
1130         /* Tests with a NULL cert context.  Prop ID 0 fails.. */
1131         ret = CertSetCertificateContextProperty(NULL, 0, 0, NULL);
1132         ok(!ret && GetLastError() ==
1133          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1134          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1135          GetLastError());
1136         /* while this just crashes.
1137         ret = CertSetCertificateContextProperty(NULL,
1138          CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
1139          */
1140
1141         ret = CertSetCertificateContextProperty(context, 0, 0, NULL);
1142         ok(!ret && GetLastError() ==
1143          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1144          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1145          GetLastError());
1146         /* Can't set the cert property directly, this crashes.
1147         ret = CertSetCertificateContextProperty(context,
1148          CERT_CERT_PROP_ID, 0, bigCert2);
1149          */
1150
1151         /* This crashes.
1152         ret = CertGetCertificateContextProperty(context,
1153          CERT_ACCESS_STATE_PROP_ID, 0, NULL);
1154          */
1155         size = sizeof(access);
1156         ret = CertGetCertificateContextProperty(context,
1157          CERT_ACCESS_STATE_PROP_ID, &access, &size);
1158         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1159          GetLastError());
1160         ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG),
1161          "Didn't expect a persisted cert\n");
1162         /* Trying to set this "read only" property crashes.
1163         access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1164         ret = CertSetCertificateContextProperty(context,
1165          CERT_ACCESS_STATE_PROP_ID, 0, &access);
1166          */
1167
1168         /* Can I set the hash to an invalid hash? */
1169         blob.pbData = hash;
1170         blob.cbData = sizeof(hash);
1171         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1172          &blob);
1173         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1174          GetLastError());
1175         size = sizeof(hashProperty);
1176         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1177          hashProperty, &size);
1178         ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n");
1179         /* Delete the (bogus) hash, and get the real one */
1180         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1181          NULL);
1182         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1183          GetLastError());
1184         size = sizeof(hash);
1185         ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert) - 1,
1186          hash, &size);
1187         ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1188         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1189          hashProperty, &size);
1190         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1191          GetLastError());
1192         ok(!memcmp(hash, hashProperty, sizeof(hash)), "Unexpected hash\n");
1193
1194         /* Now that the hash property is set, we should get one property when
1195          * enumerating.
1196          */
1197         propID = 0;
1198         numProps = 0;
1199         do {
1200             propID = CertEnumCertificateContextProperties(context, propID);
1201             if (propID)
1202                 numProps++;
1203         } while (propID != 0);
1204         ok(numProps == 1, "Expected 1 properties, got %ld\n", numProps);
1205
1206         CertFreeCertificateContext(context);
1207     }
1208 }
1209
1210 static void testAddSerialized(void)
1211 {
1212     BOOL ret;
1213     HCERTSTORE store;
1214     BYTE buf[sizeof(struct CertPropIDHeader) * 2 + 20 + sizeof(bigCert) - 1] =
1215      { 0 };
1216     BYTE hash[20];
1217     struct CertPropIDHeader *hdr;
1218     PCCERT_CONTEXT context;
1219
1220     ret = CertAddSerializedElementToStore(0, NULL, 0, 0, 0, 0, NULL, NULL);
1221     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1222      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1223
1224     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1225      CERT_STORE_CREATE_NEW_FLAG, NULL);
1226     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1227
1228     ret = CertAddSerializedElementToStore(store, NULL, 0, 0, 0, 0, NULL, NULL);
1229     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1230      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1231
1232     /* Test with an empty property */
1233     hdr = (struct CertPropIDHeader *)buf;
1234     hdr->propID = CERT_CERT_PROP_ID;
1235     hdr->unknown1 = 1;
1236     hdr->cb = 0;
1237     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1238      NULL, NULL);
1239     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1240      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1241      GetLastError());
1242     /* Test with a bad size in property header */
1243     hdr->cb = sizeof(bigCert) - 2;
1244     memcpy(buf + sizeof(struct CertPropIDHeader), bigCert, sizeof(bigCert) - 1);
1245     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1246      NULL, NULL);
1247     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1248      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1249      GetLastError());
1250     ret = CertAddSerializedElementToStore(store, buf,
1251      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 0, NULL,
1252      NULL);
1253     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1254      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1255      GetLastError());
1256     ret = CertAddSerializedElementToStore(store, buf,
1257      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1258      0, 0, NULL, NULL);
1259     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1260      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1261      GetLastError());
1262     /* Kosher size in property header, but no context type */
1263     hdr->cb = sizeof(bigCert) - 1;
1264     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1265      NULL, NULL);
1266     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1267      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1268      GetLastError());
1269     ret = CertAddSerializedElementToStore(store, buf,
1270      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 0, NULL,
1271      NULL);
1272     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1273      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1274      GetLastError());
1275     ret = CertAddSerializedElementToStore(store, buf,
1276      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1277      0, 0, NULL, NULL);
1278     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1279      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1280      GetLastError());
1281     /* With a bad context type */
1282     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1283      CERT_STORE_CRL_CONTEXT_FLAG, 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     ret = CertAddSerializedElementToStore(store, buf,
1288      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1289      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1290     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1291      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1292      GetLastError());
1293     ret = CertAddSerializedElementToStore(store, buf,
1294      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1295      0, CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1296     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1297      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1298      GetLastError());
1299     /* Bad unknown field, good type */
1300     hdr->unknown1 = 2;
1301     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1302      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1303     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1304      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1305     ret = CertAddSerializedElementToStore(store, buf,
1306      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1307      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1308     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1309      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1310     ret = CertAddSerializedElementToStore(store, buf,
1311      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1312      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1313     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1314      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1315     /* Most everything okay, but bad add disposition */
1316     hdr->unknown1 = 1;
1317     /* This crashes
1318     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1319      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1320      * as does this
1321     ret = CertAddSerializedElementToStore(store, buf,
1322      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1323      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1324      */
1325     /* Everything okay, but buffer's too big */
1326     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1327      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1328     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1329     /* Everything okay, check it's not re-added */
1330     ret = CertAddSerializedElementToStore(store, buf,
1331      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1332      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1333     ok(!ret && GetLastError() == CRYPT_E_EXISTS,
1334      "Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
1335
1336     context = CertEnumCertificatesInStore(store, NULL);
1337     ok(context != NULL, "Expected a cert\n");
1338     if (context)
1339         CertDeleteCertificateFromStore(context);
1340
1341     /* Try adding with a bogus hash.  Oddly enough, it succeeds, and the hash,
1342      * when queried, is the real hash rather than the bogus hash.
1343      */
1344     hdr = (struct CertPropIDHeader *)(buf + sizeof(struct CertPropIDHeader) +
1345      sizeof(bigCert) - 1);
1346     hdr->propID = CERT_HASH_PROP_ID;
1347     hdr->unknown1 = 1;
1348     hdr->cb = sizeof(hash);
1349     memset(hash, 0xc, sizeof(hash));
1350     memcpy((LPBYTE)hdr + sizeof(struct CertPropIDHeader), hash, sizeof(hash));
1351     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1352      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL,
1353      (const void **)&context);
1354     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1355     if (context)
1356     {
1357         BYTE hashVal[20], realHash[20];
1358         DWORD size = sizeof(hashVal);
1359
1360         ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert) - 1,
1361          realHash, &size);
1362         ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1363         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1364          hashVal, &size);
1365         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1366          GetLastError());
1367         ok(!memcmp(hashVal, realHash, size), "Unexpected hash\n");
1368     }
1369
1370     CertCloseStore(store, 0);
1371 }
1372
1373 static const char cspName[] = "WineCryptTemp";
1374
1375 static void verifySig(HCRYPTPROV csp, const BYTE *toSign, size_t toSignLen,
1376  const BYTE *sig, size_t sigLen)
1377 {
1378     HCRYPTHASH hash;
1379     BOOL ret = CryptCreateHash(csp, CALG_SHA1, 0, 0, &hash);
1380
1381     ok(ret, "CryptCreateHash failed: %08lx\n", GetLastError());
1382     if (ret)
1383     {
1384         BYTE mySig[64];
1385         DWORD mySigSize = sizeof(mySig);
1386
1387         ret = CryptHashData(hash, toSign, toSignLen, 0);
1388         ok(ret, "CryptHashData failed: %08lx\n", GetLastError());
1389         /* use the A variant so the test can run on Win9x */
1390         ret = CryptSignHashA(hash, AT_SIGNATURE, NULL, 0, mySig, &mySigSize);
1391         ok(ret, "CryptSignHash failed: %08lx\n", GetLastError());
1392         if (ret)
1393         {
1394             ok(mySigSize == sigLen, "Expected sig length %d, got %ld\n",
1395              sigLen, mySigSize);
1396             ok(!memcmp(mySig, sig, sigLen), "Unexpected signature\n");
1397         }
1398         CryptDestroyHash(hash);
1399     }
1400 }
1401
1402 /* Tests signing the certificate described by toBeSigned with the CSP passed in,
1403  * using the algorithm with OID sigOID.  The CSP is assumed to be empty, and a
1404  * keyset named AT_SIGNATURE will be added to it.  The signing key will be
1405  * stored in *key, and the signature will be stored in sig.  sigLen should be
1406  * at least 64 bytes.
1407  */
1408 static void testSignCert(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
1409  LPCSTR sigOID, HCRYPTKEY *key, BYTE *sig, DWORD *sigLen)
1410 {
1411     BOOL ret;
1412     DWORD size = 0;
1413     CRYPT_ALGORITHM_IDENTIFIER algoID = { NULL, { 0, NULL } };
1414
1415     /* These all crash
1416     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
1417     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, &size);
1418     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
1419      NULL, NULL, NULL, &size);
1420      */
1421     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
1422      &algoID, NULL, NULL, &size);
1423     ok(!ret && GetLastError() == NTE_BAD_ALGID, 
1424      "Expected NTE_BAD_ALGID, got %08lx\n", GetLastError());
1425     algoID.pszObjId = (LPSTR)sigOID;
1426     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
1427      &algoID, NULL, NULL, &size);
1428     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1429      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
1430     ret = CryptSignCertificate(0, AT_SIGNATURE, 0, toBeSigned->pbData,
1431      toBeSigned->cbData, &algoID, NULL, NULL, &size);
1432     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1433      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
1434
1435     /* No keys exist in the new CSP yet.. */
1436     ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
1437      toBeSigned->cbData, &algoID, NULL, NULL, &size);
1438     ok(!ret && (GetLastError() == NTE_BAD_KEYSET || GetLastError() ==
1439      NTE_NO_KEY), "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %08lx\n",
1440      GetLastError());
1441     ret = CryptGenKey(csp, AT_SIGNATURE, 0, key);
1442     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
1443     if (ret)
1444     {
1445         ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
1446          toBeSigned->cbData, &algoID, NULL, NULL, &size);
1447         ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
1448         ok(size <= *sigLen, "Expected size <= %ld, got %ld\n", *sigLen, size);
1449         if (ret)
1450         {
1451             ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
1452              toBeSigned->cbData, &algoID, NULL, sig, &size);
1453             ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
1454             if (ret)
1455             {
1456                 *sigLen = size;
1457                 verifySig(csp, toBeSigned->pbData, toBeSigned->cbData, sig,
1458                  size);
1459             }
1460         }
1461     }
1462 }
1463
1464 static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
1465  LPCSTR sigOID, const BYTE *sig, DWORD sigLen)
1466 {
1467     CERT_SIGNED_CONTENT_INFO info;
1468     LPBYTE cert = NULL;
1469     DWORD size = 0;
1470     BOOL ret;
1471
1472     ret = pCryptVerifyCertificateSignatureEx(0, 0, 0, NULL, 0, NULL, 0, NULL);
1473     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1474      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1475      GetLastError());
1476     ret = pCryptVerifyCertificateSignatureEx(csp, 0, 0, NULL, 0, NULL, 0, NULL);
1477     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1478      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1479      GetLastError());
1480     ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, 0, NULL, 0,
1481      NULL, 0, NULL);
1482     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1483      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1484      GetLastError());
1485     /* This crashes
1486     ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1487      CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, NULL, 0, NULL, 0, NULL);
1488      */
1489     info.ToBeSigned.cbData = toBeSigned->cbData;
1490     info.ToBeSigned.pbData = toBeSigned->pbData;
1491     info.SignatureAlgorithm.pszObjId = (LPSTR)sigOID;
1492     info.SignatureAlgorithm.Parameters.cbData = 0;
1493     info.Signature.cbData = sigLen;
1494     info.Signature.pbData = (BYTE *)sig;
1495     info.Signature.cUnusedBits = 0;
1496     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, &info,
1497      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&cert, &size);
1498     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1499     if (cert)
1500     {
1501         CRYPT_DATA_BLOB certBlob = { 0, NULL };
1502         PCERT_PUBLIC_KEY_INFO pubKeyInfo = NULL;
1503
1504         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1505          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
1506         ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1507          "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
1508         certBlob.cbData = 1;
1509         certBlob.pbData = (void *)0xdeadbeef;
1510         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1511          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
1512         ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1513          "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1514         certBlob.cbData = size;
1515         certBlob.pbData = cert;
1516         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1517          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
1518         ok(!ret && GetLastError() ==
1519          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1520          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1521          GetLastError());
1522         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1523          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
1524          CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL, NULL, 0, NULL);
1525         ok(!ret && GetLastError() ==
1526          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1527          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1528          GetLastError());
1529         /* This crashes
1530         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1531          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
1532          CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, NULL, 0, NULL);
1533          */
1534         CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
1535          (LPSTR)sigOID, 0, NULL, NULL, &size);
1536         pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, size);
1537         if (pubKeyInfo)
1538         {
1539             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
1540              X509_ASN_ENCODING, (LPSTR)sigOID, 0, NULL, pubKeyInfo, &size);
1541             ok(ret, "CryptExportKey failed: %08lx\n", GetLastError());
1542             if (ret)
1543             {
1544                 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1545                  CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
1546                  CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pubKeyInfo, 0, NULL);
1547                 ok(ret, "CryptVerifyCertificateSignatureEx failed: %08lx\n",
1548                  GetLastError());
1549             }
1550             HeapFree(GetProcessHeap(), 0, pubKeyInfo);
1551         }
1552         LocalFree(cert);
1553     }
1554 }
1555
1556 static void testCertSigs(void)
1557 {
1558     HCRYPTPROV csp;
1559     CRYPT_DATA_BLOB toBeSigned = { sizeof(emptyCert), (LPBYTE)emptyCert };
1560     BOOL ret;
1561     HCRYPTKEY key;
1562     BYTE sig[64];
1563     DWORD sigSize = sizeof(sig);
1564
1565     /* Just in case a previous run failed, delete this thing */
1566     CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
1567      CRYPT_DELETEKEYSET);
1568     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
1569      CRYPT_NEWKEYSET);
1570     ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError());
1571
1572     testSignCert(csp, &toBeSigned, szOID_RSA_SHA1RSA, &key, sig, &sigSize);
1573     testVerifyCertSig(csp, &toBeSigned, szOID_RSA_SHA1RSA, sig, sigSize);
1574
1575     CryptDestroyKey(key);
1576     CryptReleaseContext(csp, 0);
1577     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
1578      CRYPT_DELETEKEYSET);
1579 }
1580
1581 START_TEST(cert)
1582 {
1583     init_function_pointers();
1584
1585     testCryptHashCert();
1586
1587     /* various combinations of CertOpenStore */
1588     testMemStore();
1589     testCollectionStore();
1590     testRegStore();
1591     testSystemRegStore();
1592     testSystemStore();
1593
1594     testCertOpenSystemStore();
1595
1596     testCertProperties();
1597     testAddSerialized();
1598
1599     testCertSigs();
1600 }