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