Implement registry stores.
[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         /* There seems to be a bug in the registry code, not sure if it's a
887          * race condition in the recurse delete key implementation here, or if
888          * it's elsewhere in wine.  Marking todo_wine for now.
889          */
890         todo_wine ok(!rc, "RegDeleteKeyA failed: %ld\n", rc);
891         if (rc)
892         {
893             HMODULE shlwapi = LoadLibraryA("shlwapi");
894
895             /* Use shlwapi's SHDeleteKeyA to _really_ blow away the key,
896              * otherwise subsequent tests will fail.
897              */
898             if (shlwapi)
899             {
900                 SHDeleteKeyAFunc pSHDeleteKeyA =
901                  (SHDeleteKeyAFunc)GetProcAddress(shlwapi, "SHDeleteKeyA");
902
903                 if (pSHDeleteKeyA)
904                     pSHDeleteKeyA(HKEY_CURRENT_USER, tempKey);
905                 FreeLibrary(shlwapi);
906             }
907         }
908     }
909 }
910
911 static void testCertProperties(void)
912 {
913     PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING,
914      bigCert, sizeof(bigCert) - 1);
915
916     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
917      GetLastError());
918     if (context)
919     {
920         DWORD propID, numProps, access, size;
921         BOOL ret;
922         BYTE hash[20] = { 0 }, hashProperty[20];
923         CRYPT_DATA_BLOB blob;
924
925         /* This crashes
926         propID = CertEnumCertificateContextProperties(NULL, 0);
927          */
928
929         propID = 0;
930         numProps = 0;
931         do {
932             propID = CertEnumCertificateContextProperties(context, propID);
933             if (propID)
934                 numProps++;
935         } while (propID != 0);
936         ok(numProps == 0, "Expected 0 properties, got %ld\n", numProps);
937
938         /* Tests with a NULL cert context.  Prop ID 0 fails.. */
939         ret = CertSetCertificateContextProperty(NULL, 0, 0, NULL);
940         ok(!ret && GetLastError() ==
941          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
942          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
943          GetLastError());
944         /* while this just crashes.
945         ret = CertSetCertificateContextProperty(NULL,
946          CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
947          */
948
949         ret = CertSetCertificateContextProperty(context, 0, 0, NULL);
950         ok(!ret && GetLastError() ==
951          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
952          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
953          GetLastError());
954         /* Can't set the cert property directly, this crashes.
955         ret = CertSetCertificateContextProperty(context,
956          CERT_CERT_PROP_ID, 0, bigCert2);
957          */
958
959         /* This crashes.
960         ret = CertGetCertificateContextProperty(context,
961          CERT_ACCESS_STATE_PROP_ID, 0, NULL);
962          */
963         size = sizeof(access);
964         ret = CertGetCertificateContextProperty(context,
965          CERT_ACCESS_STATE_PROP_ID, &access, &size);
966         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
967          GetLastError());
968         ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG),
969          "Didn't expect a persisted cert\n");
970         /* Trying to set this "read only" property crashes.
971         access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
972         ret = CertSetCertificateContextProperty(context,
973          CERT_ACCESS_STATE_PROP_ID, 0, &access);
974          */
975
976         /* Can I set the hash to an invalid hash? */
977         blob.pbData = hash;
978         blob.cbData = sizeof(hash);
979         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
980          &blob);
981         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
982          GetLastError());
983         size = sizeof(hashProperty);
984         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
985          hashProperty, &size);
986         ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n");
987         /* Delete the (bogus) hash, and get the real one */
988         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
989          NULL);
990         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
991          GetLastError());
992         size = sizeof(hash);
993         ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert) - 1,
994          hash, &size);
995         ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
996         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
997          hashProperty, &size);
998         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
999          GetLastError());
1000         ok(!memcmp(hash, hashProperty, sizeof(hash)), "Unexpected hash\n");
1001
1002         /* Now that the hash property is set, we should get one property when
1003          * enumerating.
1004          */
1005         propID = 0;
1006         numProps = 0;
1007         do {
1008             propID = CertEnumCertificateContextProperties(context, propID);
1009             if (propID)
1010                 numProps++;
1011         } while (propID != 0);
1012         ok(numProps == 1, "Expected 1 properties, got %ld\n", numProps);
1013
1014         CertFreeCertificateContext(context);
1015     }
1016 }
1017
1018 static void testAddSerialized(void)
1019 {
1020     BOOL ret;
1021     HCERTSTORE store;
1022     BYTE buf[sizeof(struct CertPropIDHeader) * 2 + 20 + sizeof(bigCert) - 1] =
1023      { 0 };
1024     BYTE hash[20];
1025     struct CertPropIDHeader *hdr;
1026     PCCERT_CONTEXT context;
1027
1028     ret = CertAddSerializedElementToStore(0, NULL, 0, 0, 0, 0, NULL, NULL);
1029     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1030      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1031
1032     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1033      CERT_STORE_CREATE_NEW_FLAG, NULL);
1034     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1035
1036     ret = CertAddSerializedElementToStore(store, NULL, 0, 0, 0, 0, NULL, NULL);
1037     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1038      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1039
1040     /* Test with an empty property */
1041     hdr = (struct CertPropIDHeader *)buf;
1042     hdr->propID = CERT_CERT_PROP_ID;
1043     hdr->unknown1 = 1;
1044     hdr->cb = 0;
1045     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1046      NULL, NULL);
1047     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1048      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1049      GetLastError());
1050     /* Test with a bad size in property header */
1051     hdr->cb = sizeof(bigCert) - 2;
1052     memcpy(buf + sizeof(struct CertPropIDHeader), bigCert, sizeof(bigCert) - 1);
1053     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1054      NULL, NULL);
1055     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1056      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1057      GetLastError());
1058     ret = CertAddSerializedElementToStore(store, buf,
1059      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 0, NULL,
1060      NULL);
1061     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1062      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1063      GetLastError());
1064     ret = CertAddSerializedElementToStore(store, buf,
1065      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1066      0, 0, NULL, NULL);
1067     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1068      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1069      GetLastError());
1070     /* Kosher size in property header, but no context type */
1071     hdr->cb = sizeof(bigCert) - 1;
1072     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1073      NULL, NULL);
1074     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1075      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1076      GetLastError());
1077     ret = CertAddSerializedElementToStore(store, buf,
1078      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 0, NULL,
1079      NULL);
1080     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1081      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1082      GetLastError());
1083     ret = CertAddSerializedElementToStore(store, buf,
1084      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1085      0, 0, NULL, NULL);
1086     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1087      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1088      GetLastError());
1089     /* With a bad context type */
1090     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1091      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1092     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1093      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1094      GetLastError());
1095     ret = CertAddSerializedElementToStore(store, buf,
1096      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1097      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1098     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1099      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1100      GetLastError());
1101     ret = CertAddSerializedElementToStore(store, buf,
1102      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1103      0, CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1104     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1105      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1106      GetLastError());
1107     /* Bad unknown field, good type */
1108     hdr->unknown1 = 2;
1109     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1110      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1111     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1112      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1113     ret = CertAddSerializedElementToStore(store, buf,
1114      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1115      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1116     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1117      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1118     ret = CertAddSerializedElementToStore(store, buf,
1119      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1120      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1121     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1122      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1123     /* Most everything okay, but bad add disposition */
1124     hdr->unknown1 = 1;
1125     /* This crashes
1126     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1127      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1128      * as does this
1129     ret = CertAddSerializedElementToStore(store, buf,
1130      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, 0, 0, 
1131      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1132      */
1133     /* Everything okay, but buffer's too big */
1134     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1135      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1136     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1137     /* Everything okay, check it's not re-added */
1138     ret = CertAddSerializedElementToStore(store, buf,
1139      sizeof(struct CertPropIDHeader) + sizeof(bigCert) - 1, CERT_STORE_ADD_NEW,
1140      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1141     ok(!ret && GetLastError() == CRYPT_E_EXISTS,
1142      "Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
1143
1144     context = CertEnumCertificatesInStore(store, NULL);
1145     ok(context != NULL, "Expected a cert\n");
1146     if (context)
1147         CertDeleteCertificateFromStore(context);
1148
1149     /* Try adding with a bogus hash.  Oddly enough, it succeeds, and the hash,
1150      * when queried, is the real hash rather than the bogus hash.
1151      */
1152     hdr = (struct CertPropIDHeader *)(buf + sizeof(struct CertPropIDHeader) +
1153      sizeof(bigCert) - 1);
1154     hdr->propID = CERT_HASH_PROP_ID;
1155     hdr->unknown1 = 1;
1156     hdr->cb = sizeof(hash);
1157     memset(hash, 0xc, sizeof(hash));
1158     memcpy((LPBYTE)hdr + sizeof(struct CertPropIDHeader), hash, sizeof(hash));
1159     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1160      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL,
1161      (const void **)&context);
1162     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1163     if (context)
1164     {
1165         BYTE hashVal[20], realHash[20];
1166         DWORD size = sizeof(hashVal);
1167
1168         ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert) - 1,
1169          realHash, &size);
1170         ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1171         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1172          hashVal, &size);
1173         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1174          GetLastError());
1175         ok(!memcmp(hashVal, realHash, size), "Unexpected hash\n");
1176     }
1177
1178     CertCloseStore(store, 0);
1179 }
1180
1181 START_TEST(cert)
1182 {
1183     testCryptHashCert();
1184
1185     /* various combinations of CertOpenStore */
1186     testMemStore();
1187     testCollectionStore();
1188     testRegStore();
1189
1190     testCertProperties();
1191     testAddSerialized();
1192 }