Fixed gcc 4.0 warnings.
[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 <stdio.h>
22 #include <stdarg.h>
23 #include <windef.h>
24 #include <winbase.h>
25 #include <winreg.h>
26 #include <winerror.h>
27 #include <wincrypt.h>
28
29 #include "wine/test.h"
30
31 /* The following aren't defined in wincrypt.h, as they're "reserved" */
32 #define CERT_CERT_PROP_ID 32
33 #define CERT_CRL_PROP_ID  33
34 #define CERT_CTL_PROP_ID  34
35
36 struct CertPropIDHeader
37 {
38     DWORD propID;
39     DWORD unknown1;
40     DWORD cb;
41 };
42
43 static void testCryptHashCert(void)
44 {
45     static const BYTE emptyHash[] = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b,
46      0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07,
47      0x09 };
48     static const BYTE knownHash[] = { 0xae, 0x9d, 0xbf, 0x6d, 0xf5, 0x46, 0xee,
49      0x8b, 0xc5, 0x7a, 0x13, 0xba, 0xc2, 0xb1, 0x04, 0xf2, 0xbf, 0x52, 0xa8,
50      0xa2 };
51     static const BYTE toHash[] = "abcdefghijklmnopqrstuvwxyz0123456789.,;!?:";
52     BOOL ret;
53     BYTE hash[20];
54     DWORD hashLen = sizeof(hash);
55
56     /* NULL buffer and nonzero length crashes
57     ret = CryptHashCertificate(0, 0, 0, NULL, size, hash, &hashLen);
58        empty hash length also crashes
59     ret = CryptHashCertificate(0, 0, 0, buf, size, hash, NULL);
60      */
61     /* Test empty hash */
62     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), NULL,
63      &hashLen);
64     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
65     ok(hashLen == sizeof(hash),
66      "Got unexpected size of hash %ld, expected %d\n", hashLen, sizeof(hash));
67     /* Test with empty buffer */
68     ret = CryptHashCertificate(0, 0, 0, NULL, 0, hash, &hashLen);
69     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
70     ok(!memcmp(hash, emptyHash, sizeof(emptyHash)),
71      "Unexpected hash of nothing\n");
72     /* Test a known value */
73     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), hash,
74      &hashLen);
75     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
76     ok(!memcmp(hash, knownHash, sizeof(knownHash)), "Unexpected hash\n");
77 }
78
79 static const BYTE emptyCert[] = { 0x30, 0x00 };
80 static const BYTE bigCert[] = "\x30\x7a\x02\x01\x01\x30\x02\x06\x00"
81  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e\x20\x4c"
82  "\x61\x6e\x67\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30"
83  "\x30\x30\x30\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30"
84  "\x30\x5a\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e"
85  "\x20\x4c\x61\x6e\x67\x00\x30\x07\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14"
86  "\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01"
87  "\x01";
88 static const BYTE signedBigCert[] = {
89  0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
90  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
91  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
92  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
93  0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
94  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
95  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
96  0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
97  0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
98  0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
99  0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
100  0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
101 static const BYTE serializedCert[] = { 0x20, 0x00, 0x00, 0x00,
102  0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x7a, 0x02, 0x01, 0x01,
103  0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
104  0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67,
105  0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31,
106  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
107  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15,
108  0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75,
109  0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06,
110  0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
111  0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02,
112  0x01, 0x01 };
113 static const BYTE signedCRL[] = { 0x30, 0x45, 0x30, 0x2c, 0x30, 0x02, 0x06,
114  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
115  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
116  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
117  0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c,
118  0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
119
120 static void testMemStore(void)
121 {
122     HCERTSTORE store1, store2;
123     PCCERT_CONTEXT context;
124     BOOL ret;
125
126     /* NULL provider */
127     store1 = CertOpenStore(0, 0, 0, 0, NULL);
128     ok(!store1 && GetLastError() == ERROR_FILE_NOT_FOUND,
129      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
130     /* weird flags */
131     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
132      CERT_STORE_DELETE_FLAG, NULL);
133     ok(!store1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
134      "Expected ERROR_CALL_NOT_IMPLEMENTED, got %ld\n", GetLastError());
135
136     /* normal */
137     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
138      CERT_STORE_CREATE_NEW_FLAG, NULL);
139     ok(store1 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
140     /* open existing doesn't */
141     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
142      CERT_STORE_OPEN_EXISTING_FLAG, NULL);
143     ok(store2 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
144     ok(store1 != store2, "Expected different stores\n");
145
146     /* add a bogus (empty) cert */
147     context = NULL;
148     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, emptyCert,
149      sizeof(emptyCert), CERT_STORE_ADD_ALWAYS, &context);
150     /* Windows returns CRYPT_E_ASN1_EOD, but accept CRYPT_E_ASN1_CORRUPT as
151      * well (because matching errors is tough in this case)
152      */
153     ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || GetLastError() ==
154      CRYPT_E_ASN1_CORRUPT),
155      "Expected CRYPT_E_ASN1_EOD or CRYPT_E_ASN1_CORRUPT, got %08lx\n",
156      GetLastError());
157     /* add a "signed" cert--the signature isn't a real signature, so this adds
158      * without any check of the signature's validity
159      */
160     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
161      signedBigCert, sizeof(signedBigCert), CERT_STORE_ADD_ALWAYS, &context);
162     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
163     ok(context != NULL, "Expected a valid cert context\n");
164     if (context)
165     {
166         ok(context->cbCertEncoded == sizeof(signedBigCert),
167          "Expected cert of %d bytes, got %ld\n", sizeof(signedBigCert),
168          context->cbCertEncoded);
169         ok(!memcmp(context->pbCertEncoded, signedBigCert,
170          sizeof(signedBigCert)), "Unexpected encoded cert in context\n");
171         /* remove it, the rest of the tests will work on an unsigned cert */
172         ret = CertDeleteCertificateFromStore(context);
173         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
174          GetLastError());
175     }
176     /* try adding a "signed" CRL as a cert */
177     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
178      signedCRL, sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, &context);
179     ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || GetLastError() ==
180      CRYPT_E_ASN1_CORRUPT),
181      "Expected CRYPT_E_ASN1_BADTAG or CRYPT_E_ASN1_CORRUPT, got %08lx\n",
182      GetLastError());
183     /* add a cert to store1 */
184     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert,
185      sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, &context);
186     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
187     ok(context != NULL, "Expected a valid cert context\n");
188     if (context)
189     {
190         DWORD size;
191         BYTE *buf;
192
193         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
194          "Expected cert of %d bytes, got %ld\n", sizeof(bigCert) - 1,
195          context->cbCertEncoded);
196         ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert) - 1),
197          "Unexpected encoded cert in context\n");
198         ok(context->hCertStore == store1, "Unexpected store\n");
199
200         /* check serializing this element */
201         /* These crash
202         ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, NULL);
203         ret = CertSerializeCertificateStoreElement(context, 0, NULL, NULL);
204         ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, &size);
205          */
206         /* apparently flags are ignored */
207         ret = CertSerializeCertificateStoreElement(context, 1, NULL, &size);
208         ok(ret, "CertSerializeCertificateStoreElement failed: %08lx\n",
209          GetLastError());
210         buf = HeapAlloc(GetProcessHeap(), 0, size);
211         if (buf)
212         {
213             ret = CertSerializeCertificateStoreElement(context, 0, buf, &size);
214             ok(size == sizeof(serializedCert), "Expected size %d, got %ld\n",
215              sizeof(serializedCert), size);
216             ok(!memcmp(serializedCert, buf, size),
217              "Unexpected serialized cert\n");
218             HeapFree(GetProcessHeap(), 0, buf);
219         }
220
221         ret = CertFreeCertificateContext(context);
222         ok(ret, "CertFreeCertificateContext failed: %08lx\n", GetLastError());
223     }
224     /* verify the cert's in store1 */
225     context = CertEnumCertificatesInStore(store1, NULL);
226     ok(context != NULL, "Expected a valid context\n");
227     context = CertEnumCertificatesInStore(store1, context);
228     ok(!context && GetLastError() == CRYPT_E_NOT_FOUND,
229      "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
230     /* verify store2 (the "open existing" mem store) is still empty */
231     context = CertEnumCertificatesInStore(store2, NULL);
232     ok(!context, "Expected an empty store\n");
233     /* delete the cert from store1, and check it's empty */
234     context = CertEnumCertificatesInStore(store1, NULL);
235     if (context)
236     {
237         /* Deleting a bitwise copy crashes with an access to an uninitialized
238          * pointer, so a cert context has some special data out there in memory
239          * someplace
240         CERT_CONTEXT copy;
241         memcpy(&copy, context, sizeof(copy));
242         ret = CertDeleteCertificateFromStore(&copy);
243          */
244         PCCERT_CONTEXT copy = CertDuplicateCertificateContext(context);
245
246         ok(copy != NULL, "CertDuplicateCertificateContext failed: %08lx\n",
247          GetLastError());
248         ret = CertDeleteCertificateFromStore(context);
249         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
250          GetLastError());
251         /* try deleting a copy */
252         ret = CertDeleteCertificateFromStore(copy);
253         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
254          GetLastError());
255         /* check that the store is empty */
256         context = CertEnumCertificatesInStore(store1, NULL);
257         ok(!context, "Expected an empty store\n");
258     }
259
260     /* close an empty store */
261     ret = CertCloseStore(NULL, 0);
262     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
263     ret = CertCloseStore(store1, 0);
264     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
265     ret = CertCloseStore(store2, 0);
266     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
267
268     /* This seems nonsensical, but you can open a read-only mem store, only
269      * it isn't read-only
270      */
271     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
272      CERT_STORE_READONLY_FLAG, NULL);
273     ok(store1 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
274     /* yep, this succeeds */
275     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert,
276      sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, &context);
277     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
278     ok(context != NULL, "Expected a valid cert context\n");
279     if (context)
280     {
281         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
282          "Expected cert of %d bytes, got %ld\n", sizeof(bigCert) - 1,
283          context->cbCertEncoded);
284         ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert) - 1),
285          "Unexpected encoded cert in context\n");
286         ok(context->hCertStore == store1, "Unexpected store\n");
287         ret = CertDeleteCertificateFromStore(context);
288         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
289          GetLastError());
290     }
291     CertCloseStore(store1, 0);
292 }
293
294 static const BYTE bigCert2[] = "\x30\x7a\x02\x01\x01\x30\x02\x06\x00"
295  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x41\x6c\x65\x78\x20\x4c"
296  "\x61\x6e\x67\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30"
297  "\x30\x30\x30\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30"
298  "\x30\x5a\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x41\x6c\x65\x78"
299  "\x20\x4c\x61\x6e\x67\x00\x30\x07\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14"
300  "\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01"
301  "\x01";
302
303 static void testCollectionStore(void)
304 {
305     HCERTSTORE store1, store2, collection, collection2;
306     PCCERT_CONTEXT context;
307     BOOL ret;
308
309     collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
310      CERT_STORE_CREATE_NEW_FLAG, NULL);
311
312     /* Try adding a cert to any empty collection */
313     ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
314      bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
315     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
316      "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
317      GetLastError());
318
319     /* Create and add a cert to a memory store */
320     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
321      CERT_STORE_CREATE_NEW_FLAG, NULL);
322     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
323      bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
324     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
325     /* Add the memory store to the collection, without allowing adding */
326     ret = CertAddStoreToCollection(collection, store1, 0, 0);
327     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
328     /* Verify the cert is in the collection */
329     context = CertEnumCertificatesInStore(collection, NULL);
330     ok(context != NULL, "Expected a valid context\n");
331     if (context)
332     {
333         ok(context->hCertStore == collection, "Unexpected store\n");
334         CertFreeCertificateContext(context);
335     }
336     /* Check that adding to the collection isn't allowed */
337     ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
338      bigCert2, sizeof(bigCert2) - 1, CERT_STORE_ADD_ALWAYS, NULL);
339     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
340      "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
341      GetLastError());
342
343     /* Create a new memory store */
344     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
345      CERT_STORE_CREATE_NEW_FLAG, NULL);
346     /* Try adding a store to a non-collection store */
347     ret = CertAddStoreToCollection(store1, store2,
348      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
349     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
350      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
351      GetLastError());
352     /* Try adding some bogus stores */
353     /* This crashes in Windows
354     ret = CertAddStoreToCollection(0, store2,
355      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
356      */
357     /* This "succeeds"... */
358     ret = CertAddStoreToCollection(collection, 0,
359      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
360     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
361     /* while this crashes.
362     ret = CertAddStoreToCollection(collection, 1,
363      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
364      */
365
366     /* Add it to the collection, this time allowing adding */
367     ret = CertAddStoreToCollection(collection, store2,
368      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
369     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
370     /* Check that adding to the collection is allowed */
371     ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
372      bigCert2, sizeof(bigCert2) - 1, CERT_STORE_ADD_ALWAYS, NULL);
373     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
374     /* Now check that it was actually added to store2 */
375     context = CertEnumCertificatesInStore(store2, NULL);
376     ok(context != NULL, "Expected a valid context\n");
377     if (context)
378     {
379         ok(context->hCertStore == store2, "Unexpected store\n");
380         CertFreeCertificateContext(context);
381     }
382     /* Check that the collection has both bigCert and bigCert2.  bigCert comes
383      * first because store1 was added first.
384      */
385     context = CertEnumCertificatesInStore(collection, NULL);
386     ok(context != NULL, "Expected a valid context\n");
387     if (context)
388     {
389         ok(context->hCertStore == collection, "Unexpected store\n");
390         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
391          "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
392          context->cbCertEncoded);
393         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
394          "Unexpected cert\n");
395         context = CertEnumCertificatesInStore(collection, context);
396         ok(context != NULL, "Expected a valid context\n");
397         if (context)
398         {
399             ok(context->hCertStore == collection, "Unexpected store\n");
400             ok(context->cbCertEncoded == sizeof(bigCert2) - 1,
401              "Expected size %d, got %ld\n", sizeof(bigCert2) - 1,
402              context->cbCertEncoded);
403             ok(!memcmp(context->pbCertEncoded, bigCert2,
404              context->cbCertEncoded), "Unexpected cert\n");
405             context = CertEnumCertificatesInStore(collection, context);
406             ok(!context, "Unexpected cert\n");
407         }
408     }
409     /* close store2, and check that the collection is unmodified */
410     CertCloseStore(store2, 0);
411     context = CertEnumCertificatesInStore(collection, NULL);
412     ok(context != NULL, "Expected a valid context\n");
413     if (context)
414     {
415         ok(context->hCertStore == collection, "Unexpected store\n");
416         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
417          "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
418          context->cbCertEncoded);
419         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
420          "Unexpected cert\n");
421         context = CertEnumCertificatesInStore(collection, context);
422         ok(context != NULL, "Expected a valid context\n");
423         if (context)
424         {
425             ok(context->hCertStore == collection, "Unexpected store\n");
426             ok(context->cbCertEncoded == sizeof(bigCert2) - 1,
427              "Expected size %d, got %ld\n", sizeof(bigCert2) - 1,
428              context->cbCertEncoded);
429             ok(!memcmp(context->pbCertEncoded, bigCert2,
430              context->cbCertEncoded), "Unexpected cert\n");
431             context = CertEnumCertificatesInStore(collection, context);
432             ok(!context, "Unexpected cert\n");
433         }
434     }
435
436     /* Adding a collection to a collection is legal */
437     collection2 = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
438      CERT_STORE_CREATE_NEW_FLAG, NULL);
439     ret = CertAddStoreToCollection(collection2, collection,
440      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
441     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
442     /* check the contents of collection2 */
443     context = CertEnumCertificatesInStore(collection2, NULL);
444     ok(context != NULL, "Expected a valid context\n");
445     if (context)
446     {
447         ok(context->hCertStore == collection2, "Unexpected store\n");
448         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
449          "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
450          context->cbCertEncoded);
451         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
452          "Unexpected cert\n");
453         context = CertEnumCertificatesInStore(collection2, context);
454         ok(context != NULL, "Expected a valid context\n");
455         if (context)
456         {
457             ok(context->hCertStore == collection2, "Unexpected store\n");
458             ok(context->cbCertEncoded == sizeof(bigCert2) - 1,
459              "Expected size %d, got %ld\n", sizeof(bigCert2) - 1,
460              context->cbCertEncoded);
461             ok(!memcmp(context->pbCertEncoded, bigCert2,
462              context->cbCertEncoded), "Unexpected cert\n");
463             context = CertEnumCertificatesInStore(collection2, context);
464             ok(!context, "Unexpected cert\n");
465         }
466     }
467
468     /* I'd like to test closing the collection in the middle of enumeration,
469      * but my tests have been inconsistent.  The first time calling
470      * CertEnumCertificatesInStore on a closed collection succeeded, while the
471      * second crashed.  So anything appears to be fair game.
472      * I'd also like to test removing a store from a collection in the middle
473      * of an enumeration, but my tests in Windows have been inconclusive.
474      * In one scenario it worked.  In another scenario, about a third of the
475      * time this leads to "random" crashes elsewhere in the code.  This
476      * probably means this is not allowed.
477      */
478
479     CertCloseStore(store1, 0);
480     CertCloseStore(collection, 0);
481     CertCloseStore(collection2, 0);
482
483     /* Add the same cert to two memory stores, then put them in a collection */
484     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
485      CERT_STORE_CREATE_NEW_FLAG, NULL);
486     ok(store1 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
487     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
488      CERT_STORE_CREATE_NEW_FLAG, NULL);
489     ok(store2 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
490
491     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
492      bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
493     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
494     ret = CertAddEncodedCertificateToStore(store2, X509_ASN_ENCODING,
495      bigCert, sizeof(bigCert) - 1, CERT_STORE_ADD_ALWAYS, NULL);
496     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
497     collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
498      CERT_STORE_CREATE_NEW_FLAG, NULL);
499     ok(collection != 0, "CertOpenStore failed: %08lx\n", GetLastError());
500
501     ret = CertAddStoreToCollection(collection, store1,
502      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
503     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
504     ret = CertAddStoreToCollection(collection, store2,
505      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
506     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
507
508     /* Check that the collection has two copies of the same cert */
509     context = CertEnumCertificatesInStore(collection, NULL);
510     ok(context != NULL, "Expected a valid context\n");
511     if (context)
512     {
513         ok(context->hCertStore == collection, "Unexpected store\n");
514         ok(context->cbCertEncoded == sizeof(bigCert) - 1,
515          "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
516          context->cbCertEncoded);
517         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
518          "Unexpected cert\n");
519         context = CertEnumCertificatesInStore(collection, context);
520         ok(context != NULL, "Expected a valid context\n");
521         if (context)
522         {
523             ok(context->hCertStore == collection, "Unexpected store\n");
524             ok(context->cbCertEncoded == sizeof(bigCert) - 1,
525              "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
526              context->cbCertEncoded);
527             ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
528              "Unexpected cert\n");
529             context = CertEnumCertificatesInStore(collection, context);
530             ok(context == NULL, "Unexpected cert\n");
531         }
532     }
533
534     /* The following would check whether I can delete an identical cert, rather
535      * than one enumerated from the store.  It crashes, so that means I must
536      * only call CertDeleteCertificateFromStore with contexts enumerated from
537      * the store.
538     context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
539      sizeof(bigCert) - 1);
540     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
541      GetLastError());
542     if (context)
543     {
544         ret = CertDeleteCertificateFromStore(collection, context);
545         printf("ret is %d, GetLastError is %08lx\n", ret, GetLastError());
546         CertFreeCertificateContext(context);
547     }
548      */
549
550     /* Now check deleting from the collection. */
551     context = CertEnumCertificatesInStore(collection, NULL);
552     ok(context != NULL, "Expected a valid context\n");
553     if (context)
554     {
555         CertDeleteCertificateFromStore(context);
556         /* store1 should now be empty */
557         context = CertEnumCertificatesInStore(store1, NULL);
558         ok(!context, "Unexpected cert\n");
559         /* and there should be one certificate in the collection */
560         context = CertEnumCertificatesInStore(collection, NULL);
561         ok(context != NULL, "Expected a valid cert\n");
562         if (context)
563         {
564             ok(context->hCertStore == collection, "Unexpected store\n");
565             ok(context->cbCertEncoded == sizeof(bigCert) - 1,
566              "Expected size %d, got %ld\n", sizeof(bigCert) - 1,
567              context->cbCertEncoded);
568             ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
569              "Unexpected cert\n");
570         }
571         context = CertEnumCertificatesInStore(collection, context);
572         ok(context == NULL, "Unexpected cert\n");
573     }
574
575     /* Finally, test removing stores from the collection.  No return value, so
576      * it's a bit funny to test.
577      */
578     /* This crashes
579     CertRemoveStoreFromCollection(NULL, NULL);
580      */
581     /* This "succeeds," no crash, no last error set */
582     SetLastError(0xdeadbeef);
583     CertRemoveStoreFromCollection(store2, collection);
584     ok(GetLastError() == 0xdeadbeef,
585      "Didn't expect an error to be set: %08lx\n", GetLastError());
586
587     /* After removing store2, the collection should be empty */
588     SetLastError(0xdeadbeef);
589     CertRemoveStoreFromCollection(collection, store2);
590     ok(GetLastError() == 0xdeadbeef,
591      "Didn't expect an error to be set: %08lx\n", GetLastError());
592     context = CertEnumCertificatesInStore(collection, NULL);
593     ok(!context, "Unexpected cert\n");
594
595     CertCloseStore(collection, 0);
596     CertCloseStore(store2, 0);
597     CertCloseStore(store1, 0);
598 }
599
600 /* Looks for the property with ID propID in the buffer buf.  Returns a pointer
601  * to its header if found, NULL if not.
602  */
603 static const struct CertPropIDHeader *findPropID(const BYTE *buf, DWORD size,
604  DWORD propID)
605 {
606     const struct CertPropIDHeader *ret = NULL;
607     BOOL failed = FALSE;
608
609     while (size && !ret && !failed)
610     {
611         if (size < sizeof(struct CertPropIDHeader))
612             failed = TRUE;
613         else
614         {
615             const struct CertPropIDHeader *hdr =
616              (const struct CertPropIDHeader *)buf;
617
618             size -= sizeof(struct CertPropIDHeader);
619             buf += sizeof(struct CertPropIDHeader);
620             if (size < hdr->cb)
621                 failed = TRUE;
622             else if (hdr->propID == propID)
623                 ret = hdr;
624             else
625             {
626                 buf += hdr->cb;
627                 size -= hdr->cb;
628             }
629         }
630     }
631     return ret;
632 }
633
634 typedef DWORD (WINAPI *SHDeleteKeyAFunc)(HKEY, LPCSTR);
635
636 static void testRegStore(void)
637 {
638     static const char tempKey[] = "Software\\Wine\\CryptTemp";
639     HCERTSTORE store;
640     LONG rc;
641     HKEY key = NULL;
642     DWORD disp;
643
644     store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, NULL);
645     ok(!store && GetLastError() == ERROR_INVALID_HANDLE,
646      "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
647     store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
648     ok(!store && GetLastError() == ERROR_INVALID_HANDLE,
649      "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
650
651     /* Opening up any old key works.. */
652     key = HKEY_CURRENT_USER;
653     store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
654     /* Not sure if this is a bug in DuplicateHandle, marking todo_wine for now
655      */
656     todo_wine ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
657     CertCloseStore(store, 0);
658
659     rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS,
660      NULL, &key, NULL);
661     ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
662     if (key)
663     {
664         BOOL ret;
665         BYTE hash[20];
666         DWORD size, i;
667         static const char certificates[] = "Certificates\\";
668         char subKeyName[sizeof(certificates) + 20 * 2 + 1], *ptr;
669         HKEY subKey;
670         PCCERT_CONTEXT context;
671
672         store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
673         ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
674         /* Add a certificate.  It isn't persisted right away, since it's only
675          * added to the cache..
676          */
677         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
678          bigCert2, sizeof(bigCert2) - 1, CERT_STORE_ADD_ALWAYS, NULL);
679         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
680          GetLastError());
681         /* so flush the cache to force a commit.. */
682         ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
683         ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
684         /* and check that the expected subkey was written. */
685         size = sizeof(hash);
686         ret = CryptHashCertificate(0, 0, 0, bigCert2, sizeof(bigCert2) - 1,
687          hash, &size);
688         ok(ret, "CryptHashCertificate failed: %ld\n", GetLastError());
689         strcpy(subKeyName, certificates);
690         for (i = 0, ptr = subKeyName + sizeof(certificates) - 1; i < size;
691          i++, ptr += 2)
692             sprintf(ptr, "%02X", hash[i]);
693         rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
694          &subKey, NULL);
695         ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
696         if (subKey)
697         {
698             LPBYTE buf;
699
700             size = 0;
701             RegQueryValueExA(subKey, "Blob", NULL, NULL, NULL, &size);
702             buf = HeapAlloc(GetProcessHeap(), 0, size);
703             if (buf)
704             {
705                 rc = RegQueryValueExA(subKey, "Blob", NULL, NULL, buf, &size);
706                 ok(!rc, "RegQueryValueExA failed: %ld\n", rc);
707                 if (!rc)
708                 {
709                     const struct CertPropIDHeader *hdr;
710
711                     /* Both the hash and the cert should be present */
712                     hdr = findPropID(buf, size, CERT_CERT_PROP_ID);
713                     ok(hdr != NULL, "Expected to find a cert property\n");
714                     if (hdr)
715                     {
716                         ok(hdr->cb == sizeof(bigCert2) - 1,
717                          "Unexpected size %ld of cert property, expected %d\n",
718                          hdr->cb, sizeof(bigCert2) - 1);
719                         ok(!memcmp((BYTE *)hdr + sizeof(*hdr), bigCert2,
720                          hdr->cb), "Unexpected cert in cert property\n");
721                     }
722                     hdr = findPropID(buf, size, CERT_HASH_PROP_ID);
723                     ok(hdr != NULL, "Expected to find a hash property\n");
724                     if (hdr)
725                     {
726                         ok(hdr->cb == sizeof(hash),
727                          "Unexpected size %ld of hash property, expected %d\n",
728                          hdr->cb, sizeof(hash));
729                         ok(!memcmp((BYTE *)hdr + sizeof(*hdr), hash,
730                          hdr->cb), "Unexpected hash in cert property\n");
731                     }
732                 }
733                 HeapFree(GetProcessHeap(), 0, buf);
734             }
735             RegCloseKey(subKey);
736         }
737
738         /* Remove the existing context */
739         context = CertEnumCertificatesInStore(store, NULL);
740         ok(context != NULL, "Expected a cert context\n");
741         if (context)
742             CertDeleteCertificateFromStore(context);
743         ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
744         ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
745
746         /* Add a serialized cert with a bogus hash directly to the registry */
747         memset(hash, 0, sizeof(hash));
748         strcpy(subKeyName, certificates);
749         for (i = 0, ptr = subKeyName + sizeof(certificates) - 1;
750          i < sizeof(hash); i++, ptr += 2)
751             sprintf(ptr, "%02X", hash[i]);
752         rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
753          &subKey, NULL);
754         ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
755         if (subKey)
756         {
757             BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) +
758              sizeof(bigCert) - 1], *ptr;
759             DWORD certCount = 0;
760             struct CertPropIDHeader *hdr;
761
762             hdr = (struct CertPropIDHeader *)buf;
763             hdr->propID = CERT_HASH_PROP_ID;
764             hdr->unknown1 = 1;
765             hdr->cb = sizeof(hash);
766             ptr = buf + sizeof(*hdr);
767             memcpy(ptr, hash, sizeof(hash));
768             ptr += sizeof(hash);
769             hdr = (struct CertPropIDHeader *)ptr;
770             hdr->propID = CERT_CERT_PROP_ID;
771             hdr->unknown1 = 1;
772             hdr->cb = sizeof(bigCert) - 1;
773             ptr += sizeof(*hdr);
774             memcpy(ptr, bigCert, sizeof(bigCert) - 1);
775
776             rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
777              sizeof(buf));
778             ok(!rc, "RegSetValueExA failed: %ld\n", rc);
779
780             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
781             ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
782
783             /* Make sure the bogus hash cert gets loaded. */
784             certCount = 0;
785             context = NULL;
786             do {
787                 context = CertEnumCertificatesInStore(store, context);
788                 if (context)
789                     certCount++;
790             } while (context != NULL);
791             ok(certCount == 1, "Expected 1 certificates, got %ld\n", certCount);
792
793             RegCloseKey(subKey);
794         }
795
796         /* Add another serialized cert directly to the registry, this time
797          * under the correct key name (named with the correct hash value).
798          */
799         size = sizeof(hash);
800         ret = CryptHashCertificate(0, 0, 0, bigCert2,
801          sizeof(bigCert2) - 1, hash, &size);
802         ok(ret, "CryptHashCertificate failed: %ld\n", GetLastError());
803         strcpy(subKeyName, certificates);
804         for (i = 0, ptr = subKeyName + sizeof(certificates) - 1;
805          i < sizeof(hash); i++, ptr += 2)
806             sprintf(ptr, "%02X", hash[i]);
807         rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
808          &subKey, NULL);
809         ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
810         if (subKey)
811         {
812             BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) +
813              sizeof(bigCert2) - 1], *ptr;
814             DWORD certCount = 0;
815             PCCERT_CONTEXT context;
816             struct CertPropIDHeader *hdr;
817
818             /* First try with a bogus hash... */
819             hdr = (struct CertPropIDHeader *)buf;
820             hdr->propID = CERT_HASH_PROP_ID;
821             hdr->unknown1 = 1;
822             hdr->cb = sizeof(hash);
823             ptr = buf + sizeof(*hdr);
824             memset(ptr, 0, sizeof(hash));
825             ptr += sizeof(hash);
826             hdr = (struct CertPropIDHeader *)ptr;
827             hdr->propID = CERT_CERT_PROP_ID;
828             hdr->unknown1 = 1;
829             hdr->cb = sizeof(bigCert2) - 1;
830             ptr += sizeof(*hdr);
831             memcpy(ptr, bigCert2, sizeof(bigCert2) - 1);
832
833             rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
834              sizeof(buf));
835             ok(!rc, "RegSetValueExA failed: %ld\n", rc);
836
837             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
838             ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
839
840             /* and make sure just one cert still gets loaded. */
841             certCount = 0;
842             context = NULL;
843             do {
844                 context = CertEnumCertificatesInStore(store, context);
845                 if (context)
846                     certCount++;
847             } while (context != NULL);
848             ok(certCount == 1, "Expected 1 certificates, got %ld\n", certCount);
849
850             /* Try again with the correct hash... */
851             ptr = buf + sizeof(*hdr);
852             memcpy(ptr, hash, sizeof(hash));
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 two certs get 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 == 2, "Expected 2 certificates, got %ld\n", certCount);
870
871             RegCloseKey(subKey);
872         }
873         CertCloseStore(store, 0);
874         /* Is delete allowed on a reg store? */
875         store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0,
876          CERT_STORE_DELETE_FLAG, key);
877         ok(store == NULL, "Expected NULL return from CERT_STORE_DELETE_FLAG\n");
878         ok(GetLastError() == 0, "CertOpenStore failed: %08lx\n",
879          GetLastError());
880
881         RegCloseKey(key);
882     }
883     /* The CertOpenStore with CERT_STORE_DELETE_FLAG above will delete the
884      * contents of the key, but not the key itself.
885      */
886     rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS,
887      NULL, &key, &disp);
888     ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
889     ok(disp == REG_OPENED_EXISTING_KEY,
890      "Expected REG_OPENED_EXISTING_KEY, got %ld\n", disp);
891     if (!rc)
892     {
893         RegCloseKey(key);
894         rc = RegDeleteKeyA(HKEY_CURRENT_USER, tempKey);
895         if (rc)
896         {
897             HMODULE shlwapi = LoadLibraryA("shlwapi");
898
899             /* Use shlwapi's SHDeleteKeyA to _really_ blow away the key,
900              * otherwise subsequent tests will fail.
901              */
902             if (shlwapi)
903             {
904                 SHDeleteKeyAFunc pSHDeleteKeyA =
905                  (SHDeleteKeyAFunc)GetProcAddress(shlwapi, "SHDeleteKeyA");
906
907                 if (pSHDeleteKeyA)
908                     pSHDeleteKeyA(HKEY_CURRENT_USER, tempKey);
909                 FreeLibrary(shlwapi);
910             }
911         }
912     }
913 }
914
915 static const char MyA[] = { 'M','y',0,0 };
916 static const WCHAR MyW[] = { 'M','y',0 };
917 static const WCHAR BogusW[] = { 'B','o','g','u','s',0 };
918 static const WCHAR BogusPathW[] = { 'S','o','f','t','w','a','r','e','\\',
919  'M','i','c','r','o','s','o','f','t','\\','S','y','s','t','e','m','C','e','r',
920  't','i','f','i','c','a','t','e','s','\\','B','o','g','u','s',0 };
921
922 static void testSystemRegStore(void)
923 {
924     HCERTSTORE store, memStore;
925
926     /* Check with a UNICODE name */
927     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
928      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW);
929     /* Not all OSes support CERT_STORE_PROV_SYSTEM_REGISTRY, so don't continue
930      * testing if they don't.
931      */
932     if (!store)
933         return;
934
935     /* Check that it isn't a collection store */
936     memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
937      CERT_STORE_CREATE_NEW_FLAG, NULL);
938     if (memStore)
939     {
940         BOOL ret = CertAddStoreToCollection(store, memStore, 0, 0);
941
942         ok(!ret && GetLastError() ==
943          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
944          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
945          GetLastError());
946         CertCloseStore(memStore, 0);
947     }
948     CertCloseStore(store, 0);
949
950     /* Check opening a bogus store */
951     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
952      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW);
953     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
954      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
955     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
956      CERT_SYSTEM_STORE_CURRENT_USER, BogusW);
957     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
958     if (store)
959         CertCloseStore(store, 0);
960     /* Now check whether deleting is allowed */
961     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
962      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
963     RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
964
965     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, 0, NULL);
966     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
967      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
968      GetLastError());
969     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
970      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA);
971     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
972      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
973      GetLastError());
974     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
975      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW);
976     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
977      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
978      GetLastError());
979     /* The name is expected to be UNICODE, check with an ASCII name */
980     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
981      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA);
982     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
983      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
984 }
985
986 static void testSystemStore(void)
987 {
988     static const WCHAR baskslashW[] = { '\\',0 };
989     HCERTSTORE store;
990     WCHAR keyName[MAX_PATH];
991     HKEY key;
992     LONG rc;
993
994     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, 0, NULL);
995     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
996      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
997     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
998      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA);
999     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1000      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1001     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1002      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW);
1003     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1004      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1005     /* The name is expected to be UNICODE, first check with an ASCII name */
1006     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1007      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA);
1008     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1009      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1010     /* Create the expected key */
1011     lstrcpyW(keyName, CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH);
1012     lstrcatW(keyName, baskslashW);
1013     lstrcatW(keyName, MyW);
1014     rc = RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
1015      NULL, &key, NULL);
1016     ok(!rc, "RegCreateKeyEx failed: %ld\n", rc);
1017     if (!rc)
1018         RegCloseKey(key);
1019     /* Check opening with a UNICODE name, specifying the create new flag */
1020     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1021      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_CREATE_NEW_FLAG, MyW);
1022     ok(!store && GetLastError() == ERROR_FILE_EXISTS,
1023      "Expected ERROR_FILE_EXISTS, got %08lx\n", GetLastError());
1024     /* Now check opening with a UNICODE name, this time opening existing */
1025     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1026      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW);
1027     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1028     if (store)
1029     {
1030         HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1031          CERT_STORE_CREATE_NEW_FLAG, NULL);
1032
1033         /* Check that it's a collection store */
1034         if (memStore)
1035         {
1036             BOOL ret = CertAddStoreToCollection(store, memStore, 0, 0);
1037
1038             /* FIXME: this'll fail on NT4, but what error will it give? */
1039             ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
1040             CertCloseStore(memStore, 0);
1041         }
1042         CertCloseStore(store, 0);
1043     }
1044
1045     /* Check opening a bogus store */
1046     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1047      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW);
1048     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1049      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1050     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1051      CERT_SYSTEM_STORE_CURRENT_USER, BogusW);
1052     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1053     if (store)
1054         CertCloseStore(store, 0);
1055     /* Now check whether deleting is allowed */
1056     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1057      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
1058     RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
1059 }
1060
1061 static void testCertOpenSystemStore(void)
1062 {
1063     HCERTSTORE store;
1064
1065     store = CertOpenSystemStoreW(0, NULL);
1066     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1067      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1068      GetLastError());
1069     /* This succeeds, and on WinXP at least, the Bogus key is created under
1070      * HKCU (but not under HKLM, even when run as an administrator.)
1071      */
1072     store = CertOpenSystemStoreW(0, BogusW);
1073     ok(store != 0, "CertOpenSystemStore failed: %08lx\n", GetLastError());
1074     if (store)
1075         CertCloseStore(store, 0);
1076     /* Delete it so other tests succeed next time around */
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 testCertProperties(void)
1083 {
1084     PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING,
1085      bigCert, sizeof(bigCert) - 1);
1086
1087     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
1088      GetLastError());
1089     if (context)
1090     {
1091         DWORD propID, numProps, access, size;
1092         BOOL ret;
1093         BYTE hash[20] = { 0 }, hashProperty[20];
1094         CRYPT_DATA_BLOB blob;
1095
1096         /* This crashes
1097         propID = CertEnumCertificateContextProperties(NULL, 0);
1098          */
1099
1100         propID = 0;
1101         numProps = 0;
1102         do {
1103             propID = CertEnumCertificateContextProperties(context, propID);
1104             if (propID)
1105                 numProps++;
1106         } while (propID != 0);
1107         ok(numProps == 0, "Expected 0 properties, got %ld\n", numProps);
1108
1109         /* Tests with a NULL cert context.  Prop ID 0 fails.. */
1110         ret = CertSetCertificateContextProperty(NULL, 0, 0, NULL);
1111         ok(!ret && GetLastError() ==
1112          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1113          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1114          GetLastError());
1115         /* while this just crashes.
1116         ret = CertSetCertificateContextProperty(NULL,
1117          CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
1118          */
1119
1120         ret = CertSetCertificateContextProperty(context, 0, 0, NULL);
1121         ok(!ret && GetLastError() ==
1122          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1123          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1124          GetLastError());
1125         /* Can't set the cert property directly, this crashes.
1126         ret = CertSetCertificateContextProperty(context,
1127          CERT_CERT_PROP_ID, 0, bigCert2);
1128          */
1129
1130         /* This crashes.
1131         ret = CertGetCertificateContextProperty(context,
1132          CERT_ACCESS_STATE_PROP_ID, 0, NULL);
1133          */
1134         size = sizeof(access);
1135         ret = CertGetCertificateContextProperty(context,
1136          CERT_ACCESS_STATE_PROP_ID, &access, &size);
1137         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1138          GetLastError());
1139         ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG),
1140          "Didn't expect a persisted cert\n");
1141         /* Trying to set this "read only" property crashes.
1142         access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1143         ret = CertSetCertificateContextProperty(context,
1144          CERT_ACCESS_STATE_PROP_ID, 0, &access);
1145          */
1146
1147         /* Can I set the hash to an invalid hash? */
1148         blob.pbData = hash;
1149         blob.cbData = sizeof(hash);
1150         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1151          &blob);
1152         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1153          GetLastError());
1154         size = sizeof(hashProperty);
1155         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1156          hashProperty, &size);
1157         ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n");
1158         /* Delete the (bogus) hash, and get the real one */
1159         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1160          NULL);
1161         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1162          GetLastError());
1163         size = sizeof(hash);
1164         ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert) - 1,
1165          hash, &size);
1166         ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1167         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1168          hashProperty, &size);
1169         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1170          GetLastError());
1171         ok(!memcmp(hash, hashProperty, sizeof(hash)), "Unexpected hash\n");
1172
1173         /* Now that the hash property is set, we should get one property when
1174          * enumerating.
1175          */
1176         propID = 0;
1177         numProps = 0;
1178         do {
1179             propID = CertEnumCertificateContextProperties(context, propID);
1180             if (propID)
1181                 numProps++;
1182         } while (propID != 0);
1183         ok(numProps == 1, "Expected 1 properties, got %ld\n", numProps);
1184
1185         CertFreeCertificateContext(context);
1186     }
1187 }
1188
1189 static void testAddSerialized(void)
1190 {
1191     BOOL ret;
1192     HCERTSTORE store;
1193     BYTE buf[sizeof(struct CertPropIDHeader) * 2 + 20 + sizeof(bigCert) - 1] =
1194      { 0 };
1195     BYTE hash[20];
1196     struct CertPropIDHeader *hdr;
1197     PCCERT_CONTEXT context;
1198
1199     ret = CertAddSerializedElementToStore(0, NULL, 0, 0, 0, 0, NULL, NULL);
1200     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1201      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1202
1203     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1204      CERT_STORE_CREATE_NEW_FLAG, NULL);
1205     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1206
1207     ret = CertAddSerializedElementToStore(store, NULL, 0, 0, 0, 0, NULL, NULL);
1208     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1209      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1210
1211     /* Test with an empty property */
1212     hdr = (struct CertPropIDHeader *)buf;
1213     hdr->propID = CERT_CERT_PROP_ID;
1214     hdr->unknown1 = 1;
1215     hdr->cb = 0;
1216     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1217      NULL, NULL);
1218     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1219      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1220      GetLastError());
1221     /* Test with a bad size in property header */
1222     hdr->cb = sizeof(bigCert) - 2;
1223     memcpy(buf + sizeof(struct CertPropIDHeader), bigCert, sizeof(bigCert) - 1);
1224     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1225      NULL, NULL);
1226     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1227      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1228      GetLastError());
1229     ret = CertAddSerializedElementToStore(store, buf,
1230      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 0, NULL,
1231      NULL);
1232     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1233      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1234      GetLastError());
1235     ret = CertAddSerializedElementToStore(store, buf,
1236      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1237      0, 0, NULL, NULL);
1238     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1239      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1240      GetLastError());
1241     /* Kosher size in property header, but no context type */
1242     hdr->cb = sizeof(bigCert) - 1;
1243     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1244      NULL, NULL);
1245     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1246      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1247      GetLastError());
1248     ret = CertAddSerializedElementToStore(store, buf,
1249      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 0, NULL,
1250      NULL);
1251     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1252      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1253      GetLastError());
1254     ret = CertAddSerializedElementToStore(store, buf,
1255      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1256      0, 0, NULL, NULL);
1257     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1258      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1259      GetLastError());
1260     /* With a bad context type */
1261     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1262      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1263     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1264      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1265      GetLastError());
1266     ret = CertAddSerializedElementToStore(store, buf,
1267      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1268      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1269     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1270      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1271      GetLastError());
1272     ret = CertAddSerializedElementToStore(store, buf,
1273      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1274      0, CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1275     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1276      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1277      GetLastError());
1278     /* Bad unknown field, good type */
1279     hdr->unknown1 = 2;
1280     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1281      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1282     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1283      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1284     ret = CertAddSerializedElementToStore(store, buf,
1285      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1286      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1287     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1288      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1289     ret = CertAddSerializedElementToStore(store, buf,
1290      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1291      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1292     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1293      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1294     /* Most everything okay, but bad add disposition */
1295     hdr->unknown1 = 1;
1296     /* This crashes
1297     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1298      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1299      * as does this
1300     ret = CertAddSerializedElementToStore(store, buf,
1301      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1302      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1303      */
1304     /* Everything okay, but buffer's too big */
1305     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1306      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1307     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1308     /* Everything okay, check it's not re-added */
1309     ret = CertAddSerializedElementToStore(store, buf,
1310      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1311      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1312     ok(!ret && GetLastError() == CRYPT_E_EXISTS,
1313      "Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
1314
1315     context = CertEnumCertificatesInStore(store, NULL);
1316     ok(context != NULL, "Expected a cert\n");
1317     if (context)
1318         CertDeleteCertificateFromStore(context);
1319
1320     /* Try adding with a bogus hash.  Oddly enough, it succeeds, and the hash,
1321      * when queried, is the real hash rather than the bogus hash.
1322      */
1323     hdr = (struct CertPropIDHeader *)(buf + sizeof(struct CertPropIDHeader) +
1324      sizeof(bigCert) - 1);
1325     hdr->propID = CERT_HASH_PROP_ID;
1326     hdr->unknown1 = 1;
1327     hdr->cb = sizeof(hash);
1328     memset(hash, 0xc, sizeof(hash));
1329     memcpy((LPBYTE)hdr + sizeof(struct CertPropIDHeader), hash, sizeof(hash));
1330     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1331      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL,
1332      (const void **)&context);
1333     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1334     if (context)
1335     {
1336         BYTE hashVal[20], realHash[20];
1337         DWORD size = sizeof(hashVal);
1338
1339         ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert) - 1,
1340          realHash, &size);
1341         ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1342         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1343          hashVal, &size);
1344         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1345          GetLastError());
1346         ok(!memcmp(hashVal, realHash, size), "Unexpected hash\n");
1347     }
1348
1349     CertCloseStore(store, 0);
1350 }
1351
1352 START_TEST(cert)
1353 {
1354     testCryptHashCert();
1355
1356     /* various combinations of CertOpenStore */
1357     testMemStore();
1358     testCollectionStore();
1359     testRegStore();
1360     testSystemRegStore();
1361     testSystemStore();
1362
1363     testCertOpenSystemStore();
1364
1365     testCertProperties();
1366     testAddSerialized();
1367 }