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