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