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