crypt32/tests: Write-strings warnings test.
[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 %ld\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 %ld\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: %ld\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: %ld\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 %08lx\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: %08lx\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 %ld\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: %08lx\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 %08lx\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: %08lx\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 %ld\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: %08lx\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 %ld\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: %08lx\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 %08lx\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: %08lx\n",
221          GetLastError());
222         ret = CertDeleteCertificateFromStore(context);
223         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
224          GetLastError());
225         /* try deleting a copy */
226         ret = CertDeleteCertificateFromStore(copy);
227         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\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: %ld\n", GetLastError());
237     ret = CertCloseStore(store1, 0);
238     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
239     ret = CertCloseStore(store2, 0);
240     ok(ret, "CertCloseStore failed: %ld\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: %ld\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: %08lx\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 %ld\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: %08lx\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 %08lx\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: %08lx\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: %08lx\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 %08lx\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 %08lx\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: %08lx\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: %08lx\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: %08lx\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 %ld\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 %ld\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 %ld\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 %ld\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: %08lx\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 %ld\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 %ld\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: %08lx\n", GetLastError());
442     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
443      CERT_STORE_CREATE_NEW_FLAG, NULL);
444     ok(store2 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
445
446     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
447      bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
448     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
449     ret = CertAddEncodedCertificateToStore(store2, X509_ASN_ENCODING,
450      bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
451     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
452     collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
453      CERT_STORE_CREATE_NEW_FLAG, NULL);
454     ok(collection != 0, "CertOpenStore failed: %08lx\n", GetLastError());
455
456     ret = CertAddStoreToCollection(collection, store1,
457      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
458     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
459     ret = CertAddStoreToCollection(collection, store2,
460      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
461     ok(ret, "CertAddStoreToCollection failed: %08lx\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 %ld\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 %ld\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: %08lx\n",
494      GetLastError());
495     if (context)
496     {
497         ret = CertDeleteCertificateFromStore(collection, context);
498         printf("ret is %d, GetLastError is %08lx\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 %ld\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: %08lx\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: %08lx\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 %ld\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 %ld\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: %08lx\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: %ld\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: %08lx\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: %08lx\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: %08lx\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: %ld\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: %ld\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: %ld\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 %ld of cert property\n", hdr->cb);
670                         ok(!memcmp((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 %ld of hash property\n", hdr->cb);
679                         ok(!memcmp((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: %08lx\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: %ld\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: %ld\n", rc);
729
730             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
731             ok(ret, "CertControlStore failed: %08lx\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 %ld\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: %ld\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: %ld\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: %ld\n", rc);
786
787             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
788             ok(ret, "CertControlStore failed: %08lx\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 %ld\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: %ld\n", rc);
807
808             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
809             ok(ret, "CertControlStore failed: %08lx\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 %ld\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: %08lx\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: %ld\n", rc);
839     ok(disp == REG_OPENED_EXISTING_KEY,
840      "Expected REG_OPENED_EXISTING_KEY, got %ld\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 %08lx\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 %08lx\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: %08lx\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 %08lx\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 %08lx\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 %08lx\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 %08lx\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 %08lx\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 %08lx\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 %08lx\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 %08lx\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: %ld\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 %08lx\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: %08lx\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: %08lx\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 %08lx\n", GetLastError());
995     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
996      CERT_SYSTEM_STORE_CURRENT_USER, BogusW);
997     ok(store != 0, "CertOpenStore failed: %08lx\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 void testCertOpenSystemStore(void)
1007 {
1008     HCERTSTORE store;
1009
1010     store = CertOpenSystemStoreW(0, NULL);
1011     ok(!store && GetLastError() == E_INVALIDARG,
1012      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1013     /* This succeeds, and on WinXP at least, the Bogus key is created under
1014      * HKCU (but not under HKLM, even when run as an administrator.)
1015      */
1016     store = CertOpenSystemStoreW(0, BogusW);
1017     ok(store != 0, "CertOpenSystemStore failed: %08lx\n", GetLastError());
1018     if (store)
1019         CertCloseStore(store, 0);
1020     /* Delete it so other tests succeed next time around */
1021     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1022      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
1023     RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
1024 }
1025
1026 static void testAddSerialized(void)
1027 {
1028     BOOL ret;
1029     HCERTSTORE store;
1030     BYTE buf[sizeof(struct CertPropIDHeader) * 2 + 20 + sizeof(bigCert)] =
1031      { 0 };
1032     BYTE hash[20];
1033     struct CertPropIDHeader *hdr;
1034     PCCERT_CONTEXT context;
1035
1036     ret = CertAddSerializedElementToStore(0, NULL, 0, 0, 0, 0, NULL, NULL);
1037     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1038      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1039
1040     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1041      CERT_STORE_CREATE_NEW_FLAG, NULL);
1042     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1043
1044     ret = CertAddSerializedElementToStore(store, NULL, 0, 0, 0, 0, NULL, NULL);
1045     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1046      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1047
1048     /* Test with an empty property */
1049     hdr = (struct CertPropIDHeader *)buf;
1050     hdr->propID = CERT_CERT_PROP_ID;
1051     hdr->unknown1 = 1;
1052     hdr->cb = 0;
1053     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1054      NULL, NULL);
1055     ok(!ret && GetLastError() == E_INVALIDARG,
1056      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1057     /* Test with a bad size in property header */
1058     hdr->cb = sizeof(bigCert) - 1;
1059     memcpy(buf + sizeof(struct CertPropIDHeader), bigCert, sizeof(bigCert));
1060     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1061      NULL, NULL);
1062     ok(!ret && GetLastError() == E_INVALIDARG,
1063      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1064     ret = CertAddSerializedElementToStore(store, buf,
1065      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 0, NULL,
1066      NULL);
1067     ok(!ret && GetLastError() == E_INVALIDARG,
1068      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1069     ret = CertAddSerializedElementToStore(store, buf,
1070      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1071      0, 0, NULL, NULL);
1072     ok(!ret && GetLastError() == E_INVALIDARG,
1073      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1074     /* Kosher size in property header, but no context type */
1075     hdr->cb = sizeof(bigCert);
1076     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1077      NULL, NULL);
1078     ok(!ret && GetLastError() == E_INVALIDARG,
1079      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1080     ret = CertAddSerializedElementToStore(store, buf,
1081      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 0, NULL,
1082      NULL);
1083     ok(!ret && GetLastError() == E_INVALIDARG,
1084      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1085     ret = CertAddSerializedElementToStore(store, buf,
1086      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1087      0, 0, NULL, NULL);
1088     ok(!ret && GetLastError() == E_INVALIDARG,
1089      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1090     /* With a bad context type */
1091     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1092      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1093     ok(!ret && GetLastError() == E_INVALIDARG,
1094      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1095     ret = CertAddSerializedElementToStore(store, buf,
1096      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 
1097      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1098     ok(!ret && GetLastError() == E_INVALIDARG,
1099      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1100     ret = CertAddSerializedElementToStore(store, buf,
1101      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1102      0, CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1103     ok(!ret && GetLastError() == E_INVALIDARG,
1104      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1105     /* Bad unknown field, good type */
1106     hdr->unknown1 = 2;
1107     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1108      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1109     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1110      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1111     ret = CertAddSerializedElementToStore(store, buf,
1112      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 
1113      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1114     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1115      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1116     ret = CertAddSerializedElementToStore(store, buf,
1117      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1118      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1119     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1120      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1121     /* Most everything okay, but bad add disposition */
1122     hdr->unknown1 = 1;
1123     /* This crashes
1124     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1125      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1126      * as does this
1127     ret = CertAddSerializedElementToStore(store, buf,
1128      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 
1129      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1130      */
1131     /* Everything okay, but buffer's too big */
1132     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1133      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1134     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1135     /* Everything okay, check it's not re-added */
1136     ret = CertAddSerializedElementToStore(store, buf,
1137      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1138      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1139     ok(!ret && GetLastError() == CRYPT_E_EXISTS,
1140      "Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
1141
1142     context = CertEnumCertificatesInStore(store, NULL);
1143     ok(context != NULL, "Expected a cert\n");
1144     if (context)
1145         CertDeleteCertificateFromStore(context);
1146
1147     /* Try adding with a bogus hash.  Oddly enough, it succeeds, and the hash,
1148      * when queried, is the real hash rather than the bogus hash.
1149      */
1150     hdr = (struct CertPropIDHeader *)(buf + sizeof(struct CertPropIDHeader) +
1151      sizeof(bigCert));
1152     hdr->propID = CERT_HASH_PROP_ID;
1153     hdr->unknown1 = 1;
1154     hdr->cb = sizeof(hash);
1155     memset(hash, 0xc, sizeof(hash));
1156     memcpy((LPBYTE)hdr + sizeof(struct CertPropIDHeader), hash, sizeof(hash));
1157     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1158      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL,
1159      (const void **)&context);
1160     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1161     if (context)
1162     {
1163         BYTE hashVal[20], realHash[20];
1164         DWORD size = sizeof(hashVal);
1165
1166         ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert),
1167          realHash, &size);
1168         ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1169         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1170          hashVal, &size);
1171         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1172          GetLastError());
1173         ok(!memcmp(hashVal, realHash, size), "Unexpected hash\n");
1174         CertFreeCertificateContext(context);
1175     }
1176
1177     CertCloseStore(store, 0);
1178 }
1179
1180 START_TEST(store)
1181 {
1182     /* various combinations of CertOpenStore */
1183     testMemStore();
1184     testCollectionStore();
1185     testRegStore();
1186     testSystemRegStore();
1187     testSystemStore();
1188
1189     testCertOpenSystemStore();
1190
1191     testAddSerialized();
1192 }