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