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