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