comctl32: A couple fixes for tab icon offsets.
[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 testGetSubjectCert(void)
265 {
266     HCERTSTORE store;
267
268     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
269      CERT_STORE_CREATE_NEW_FLAG, NULL);
270     ok(store != NULL, "CertOpenStore failed: %ld\n", GetLastError());
271     if (store != NULL)
272     {
273         PCCERT_CONTEXT context1, context2;
274         CERT_INFO info = { 0 };
275         BOOL ret;
276
277         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
278          bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
279         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
280          GetLastError());
281         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
282          bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, &context1);
283         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
284          GetLastError());
285         ok(context1 != NULL, "Expected a context\n");
286         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
287          certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, NULL);
288         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
289          GetLastError());
290
291         context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
292          NULL);
293         ok(!context2 && GetLastError() ==
294          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
295          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
296          GetLastError());
297         context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
298          &info);
299         ok(!context2 && GetLastError() == CRYPT_E_NOT_FOUND,
300          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
301         info.SerialNumber.cbData = sizeof(serialNum);
302         info.SerialNumber.pbData = (LPBYTE)serialNum;
303         context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
304          &info);
305         ok(!context2 && GetLastError() == CRYPT_E_NOT_FOUND,
306          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
307         info.Issuer.cbData = sizeof(subjectName2);
308         info.Issuer.pbData = (LPBYTE)subjectName2;
309         context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
310          &info);
311         ok(context2 != NULL,
312          "CertGetSubjectCertificateFromStore failed: %08lx\n", GetLastError());
313         /* Not only should this find a context, but it should be the same
314          * (same address) as context1.
315          */
316         ok(context1 == context2, "Expected identical context addresses\n");
317         CertFreeCertificateContext(context2);
318
319         CertFreeCertificateContext(context1);
320         CertCloseStore(store, 0);
321     }
322 }
323
324 static void testMemStore(void)
325 {
326     HCERTSTORE store1, store2;
327     PCCERT_CONTEXT context;
328     BOOL ret;
329
330     /* NULL provider */
331     store1 = CertOpenStore(0, 0, 0, 0, NULL);
332     ok(!store1 && GetLastError() == ERROR_FILE_NOT_FOUND,
333      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
334     /* weird flags */
335     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
336      CERT_STORE_DELETE_FLAG, NULL);
337     ok(!store1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
338      "Expected ERROR_CALL_NOT_IMPLEMENTED, got %ld\n", GetLastError());
339
340     /* normal */
341     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
342      CERT_STORE_CREATE_NEW_FLAG, NULL);
343     ok(store1 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
344     /* open existing doesn't */
345     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
346      CERT_STORE_OPEN_EXISTING_FLAG, NULL);
347     ok(store2 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
348     ok(store1 != store2, "Expected different stores\n");
349
350     /* add a bogus (empty) cert */
351     context = NULL;
352     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, emptyCert,
353      sizeof(emptyCert), CERT_STORE_ADD_ALWAYS, &context);
354     /* Windows returns CRYPT_E_ASN1_EOD, but accept CRYPT_E_ASN1_CORRUPT as
355      * well (because matching errors is tough in this case)
356      */
357     ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || GetLastError() ==
358      CRYPT_E_ASN1_CORRUPT),
359      "Expected CRYPT_E_ASN1_EOD or CRYPT_E_ASN1_CORRUPT, got %08lx\n",
360      GetLastError());
361     /* add a "signed" cert--the signature isn't a real signature, so this adds
362      * without any check of the signature's validity
363      */
364     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
365      signedBigCert, sizeof(signedBigCert), CERT_STORE_ADD_ALWAYS, &context);
366     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
367     ok(context != NULL, "Expected a valid cert context\n");
368     if (context)
369     {
370         ok(context->cbCertEncoded == sizeof(signedBigCert),
371          "Expected cert of %d bytes, got %ld\n", sizeof(signedBigCert),
372          context->cbCertEncoded);
373         ok(!memcmp(context->pbCertEncoded, signedBigCert,
374          sizeof(signedBigCert)), "Unexpected encoded cert in context\n");
375         /* remove it, the rest of the tests will work on an unsigned cert */
376         ret = CertDeleteCertificateFromStore(context);
377         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
378          GetLastError());
379     }
380     /* try adding a "signed" CRL as a cert */
381     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
382      signedCRL, sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, &context);
383     ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || GetLastError() ==
384      CRYPT_E_ASN1_CORRUPT),
385      "Expected CRYPT_E_ASN1_BADTAG or CRYPT_E_ASN1_CORRUPT, got %08lx\n",
386      GetLastError());
387     /* add a cert to store1 */
388     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert,
389      sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context);
390     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
391     ok(context != NULL, "Expected a valid cert context\n");
392     if (context)
393     {
394         DWORD size;
395         BYTE *buf;
396
397         ok(context->cbCertEncoded == sizeof(bigCert),
398          "Expected cert of %d bytes, got %ld\n", sizeof(bigCert),
399          context->cbCertEncoded);
400         ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)),
401          "Unexpected encoded cert in context\n");
402         ok(context->hCertStore == store1, "Unexpected store\n");
403
404         /* check serializing this element */
405         /* These crash
406         ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, NULL);
407         ret = CertSerializeCertificateStoreElement(context, 0, NULL, NULL);
408         ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, &size);
409          */
410         /* apparently flags are ignored */
411         ret = CertSerializeCertificateStoreElement(context, 1, NULL, &size);
412         ok(ret, "CertSerializeCertificateStoreElement failed: %08lx\n",
413          GetLastError());
414         buf = HeapAlloc(GetProcessHeap(), 0, size);
415         if (buf)
416         {
417             ret = CertSerializeCertificateStoreElement(context, 0, buf, &size);
418             ok(size == sizeof(serializedCert), "Expected size %d, got %ld\n",
419              sizeof(serializedCert), size);
420             ok(!memcmp(serializedCert, buf, size),
421              "Unexpected serialized cert\n");
422             HeapFree(GetProcessHeap(), 0, buf);
423         }
424
425         ret = CertFreeCertificateContext(context);
426         ok(ret, "CertFreeCertificateContext failed: %08lx\n", GetLastError());
427     }
428     /* verify the cert's in store1 */
429     context = CertEnumCertificatesInStore(store1, NULL);
430     ok(context != NULL, "Expected a valid context\n");
431     context = CertEnumCertificatesInStore(store1, context);
432     ok(!context && GetLastError() == CRYPT_E_NOT_FOUND,
433      "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
434     /* verify store2 (the "open existing" mem store) is still empty */
435     context = CertEnumCertificatesInStore(store2, NULL);
436     ok(!context, "Expected an empty store\n");
437     /* delete the cert from store1, and check it's empty */
438     context = CertEnumCertificatesInStore(store1, NULL);
439     if (context)
440     {
441         /* Deleting a bitwise copy crashes with an access to an uninitialized
442          * pointer, so a cert context has some special data out there in memory
443          * someplace
444         CERT_CONTEXT copy;
445         memcpy(&copy, context, sizeof(copy));
446         ret = CertDeleteCertificateFromStore(&copy);
447          */
448         PCCERT_CONTEXT copy = CertDuplicateCertificateContext(context);
449
450         ok(copy != NULL, "CertDuplicateCertificateContext failed: %08lx\n",
451          GetLastError());
452         ret = CertDeleteCertificateFromStore(context);
453         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
454          GetLastError());
455         /* try deleting a copy */
456         ret = CertDeleteCertificateFromStore(copy);
457         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
458          GetLastError());
459         /* check that the store is empty */
460         context = CertEnumCertificatesInStore(store1, NULL);
461         ok(!context, "Expected an empty store\n");
462     }
463
464     /* close an empty store */
465     ret = CertCloseStore(NULL, 0);
466     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
467     ret = CertCloseStore(store1, 0);
468     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
469     ret = CertCloseStore(store2, 0);
470     ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
471
472     /* This seems nonsensical, but you can open a read-only mem store, only
473      * it isn't read-only
474      */
475     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
476      CERT_STORE_READONLY_FLAG, NULL);
477     ok(store1 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
478     /* yep, this succeeds */
479     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert,
480      sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context);
481     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
482     ok(context != NULL, "Expected a valid cert context\n");
483     if (context)
484     {
485         ok(context->cbCertEncoded == sizeof(bigCert),
486          "Expected cert of %d bytes, got %ld\n", sizeof(bigCert),
487          context->cbCertEncoded);
488         ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)),
489          "Unexpected encoded cert in context\n");
490         ok(context->hCertStore == store1, "Unexpected store\n");
491         ret = CertDeleteCertificateFromStore(context);
492         ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
493          GetLastError());
494     }
495     CertCloseStore(store1, 0);
496 }
497
498 static void testCollectionStore(void)
499 {
500     HCERTSTORE store1, store2, collection, collection2;
501     PCCERT_CONTEXT context;
502     BOOL ret;
503
504     collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
505      CERT_STORE_CREATE_NEW_FLAG, NULL);
506
507     /* Try adding a cert to any empty collection */
508     ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
509      bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
510     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
511      "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
512      GetLastError());
513
514     /* Create and add a cert to a memory store */
515     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
516      CERT_STORE_CREATE_NEW_FLAG, NULL);
517     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
518      bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
519     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
520     /* Add the memory store to the collection, without allowing adding */
521     ret = CertAddStoreToCollection(collection, store1, 0, 0);
522     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
523     /* Verify the cert is in the collection */
524     context = CertEnumCertificatesInStore(collection, NULL);
525     ok(context != NULL, "Expected a valid context\n");
526     if (context)
527     {
528         ok(context->hCertStore == collection, "Unexpected store\n");
529         CertFreeCertificateContext(context);
530     }
531     /* Check that adding to the collection isn't allowed */
532     ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
533      bigCert2, sizeof(bigCert2), CERT_STORE_ADD_ALWAYS, NULL);
534     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
535      "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
536      GetLastError());
537
538     /* Create a new memory store */
539     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
540      CERT_STORE_CREATE_NEW_FLAG, NULL);
541     /* Try adding a store to a non-collection store */
542     ret = CertAddStoreToCollection(store1, store2,
543      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
544     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
545      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
546      GetLastError());
547     /* Try adding some bogus stores */
548     /* This crashes in Windows
549     ret = CertAddStoreToCollection(0, store2,
550      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
551      */
552     /* This "succeeds"... */
553     ret = CertAddStoreToCollection(collection, 0,
554      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
555     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
556     /* while this crashes.
557     ret = CertAddStoreToCollection(collection, 1,
558      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
559      */
560
561     /* Add it to the collection, this time allowing adding */
562     ret = CertAddStoreToCollection(collection, store2,
563      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
564     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
565     /* Check that adding to the collection is allowed */
566     ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
567      bigCert2, sizeof(bigCert2), CERT_STORE_ADD_ALWAYS, NULL);
568     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
569     /* Now check that it was actually added to store2 */
570     context = CertEnumCertificatesInStore(store2, NULL);
571     ok(context != NULL, "Expected a valid context\n");
572     if (context)
573     {
574         ok(context->hCertStore == store2, "Unexpected store\n");
575         CertFreeCertificateContext(context);
576     }
577     /* Check that the collection has both bigCert and bigCert2.  bigCert comes
578      * first because store1 was added first.
579      */
580     context = CertEnumCertificatesInStore(collection, NULL);
581     ok(context != NULL, "Expected a valid context\n");
582     if (context)
583     {
584         ok(context->hCertStore == collection, "Unexpected store\n");
585         ok(context->cbCertEncoded == sizeof(bigCert),
586          "Expected size %d, got %ld\n", sizeof(bigCert),
587          context->cbCertEncoded);
588         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
589          "Unexpected cert\n");
590         context = CertEnumCertificatesInStore(collection, context);
591         ok(context != NULL, "Expected a valid context\n");
592         if (context)
593         {
594             ok(context->hCertStore == collection, "Unexpected store\n");
595             ok(context->cbCertEncoded == sizeof(bigCert2),
596              "Expected size %d, got %ld\n", sizeof(bigCert2),
597              context->cbCertEncoded);
598             ok(!memcmp(context->pbCertEncoded, bigCert2,
599              context->cbCertEncoded), "Unexpected cert\n");
600             context = CertEnumCertificatesInStore(collection, context);
601             ok(!context, "Unexpected cert\n");
602         }
603     }
604     /* close store2, and check that the collection is unmodified */
605     CertCloseStore(store2, 0);
606     context = CertEnumCertificatesInStore(collection, NULL);
607     ok(context != NULL, "Expected a valid context\n");
608     if (context)
609     {
610         ok(context->hCertStore == collection, "Unexpected store\n");
611         ok(context->cbCertEncoded == sizeof(bigCert),
612          "Expected size %d, got %ld\n", sizeof(bigCert),
613          context->cbCertEncoded);
614         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
615          "Unexpected cert\n");
616         context = CertEnumCertificatesInStore(collection, context);
617         ok(context != NULL, "Expected a valid context\n");
618         if (context)
619         {
620             ok(context->hCertStore == collection, "Unexpected store\n");
621             ok(context->cbCertEncoded == sizeof(bigCert2),
622              "Expected size %d, got %ld\n", sizeof(bigCert2),
623              context->cbCertEncoded);
624             ok(!memcmp(context->pbCertEncoded, bigCert2,
625              context->cbCertEncoded), "Unexpected cert\n");
626             context = CertEnumCertificatesInStore(collection, context);
627             ok(!context, "Unexpected cert\n");
628         }
629     }
630
631     /* Adding a collection to a collection is legal */
632     collection2 = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
633      CERT_STORE_CREATE_NEW_FLAG, NULL);
634     ret = CertAddStoreToCollection(collection2, collection,
635      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
636     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
637     /* check the contents of collection2 */
638     context = CertEnumCertificatesInStore(collection2, NULL);
639     ok(context != NULL, "Expected a valid context\n");
640     if (context)
641     {
642         ok(context->hCertStore == collection2, "Unexpected store\n");
643         ok(context->cbCertEncoded == sizeof(bigCert),
644          "Expected size %d, got %ld\n", sizeof(bigCert),
645          context->cbCertEncoded);
646         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
647          "Unexpected cert\n");
648         context = CertEnumCertificatesInStore(collection2, context);
649         ok(context != NULL, "Expected a valid context\n");
650         if (context)
651         {
652             ok(context->hCertStore == collection2, "Unexpected store\n");
653             ok(context->cbCertEncoded == sizeof(bigCert2),
654              "Expected size %d, got %ld\n", sizeof(bigCert2),
655              context->cbCertEncoded);
656             ok(!memcmp(context->pbCertEncoded, bigCert2,
657              context->cbCertEncoded), "Unexpected cert\n");
658             context = CertEnumCertificatesInStore(collection2, context);
659             ok(!context, "Unexpected cert\n");
660         }
661     }
662
663     /* I'd like to test closing the collection in the middle of enumeration,
664      * but my tests have been inconsistent.  The first time calling
665      * CertEnumCertificatesInStore on a closed collection succeeded, while the
666      * second crashed.  So anything appears to be fair game.
667      * I'd also like to test removing a store from a collection in the middle
668      * of an enumeration, but my tests in Windows have been inconclusive.
669      * In one scenario it worked.  In another scenario, about a third of the
670      * time this leads to "random" crashes elsewhere in the code.  This
671      * probably means this is not allowed.
672      */
673
674     CertCloseStore(store1, 0);
675     CertCloseStore(collection, 0);
676     CertCloseStore(collection2, 0);
677
678     /* Add the same cert to two memory stores, then put them in a collection */
679     store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
680      CERT_STORE_CREATE_NEW_FLAG, NULL);
681     ok(store1 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
682     store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
683      CERT_STORE_CREATE_NEW_FLAG, NULL);
684     ok(store2 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
685
686     ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
687      bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
688     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
689     ret = CertAddEncodedCertificateToStore(store2, X509_ASN_ENCODING,
690      bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
691     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
692     collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
693      CERT_STORE_CREATE_NEW_FLAG, NULL);
694     ok(collection != 0, "CertOpenStore failed: %08lx\n", GetLastError());
695
696     ret = CertAddStoreToCollection(collection, store1,
697      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
698     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
699     ret = CertAddStoreToCollection(collection, store2,
700      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
701     ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
702
703     /* Check that the collection has two copies of the same cert */
704     context = CertEnumCertificatesInStore(collection, NULL);
705     ok(context != NULL, "Expected a valid context\n");
706     if (context)
707     {
708         ok(context->hCertStore == collection, "Unexpected store\n");
709         ok(context->cbCertEncoded == sizeof(bigCert),
710          "Expected size %d, got %ld\n", sizeof(bigCert),
711          context->cbCertEncoded);
712         ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
713          "Unexpected cert\n");
714         context = CertEnumCertificatesInStore(collection, context);
715         ok(context != NULL, "Expected a valid context\n");
716         if (context)
717         {
718             ok(context->hCertStore == collection, "Unexpected store\n");
719             ok(context->cbCertEncoded == sizeof(bigCert),
720              "Expected size %d, got %ld\n", sizeof(bigCert),
721              context->cbCertEncoded);
722             ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
723              "Unexpected cert\n");
724             context = CertEnumCertificatesInStore(collection, context);
725             ok(context == NULL, "Unexpected cert\n");
726         }
727     }
728
729     /* The following would check whether I can delete an identical cert, rather
730      * than one enumerated from the store.  It crashes, so that means I must
731      * only call CertDeleteCertificateFromStore with contexts enumerated from
732      * the store.
733     context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
734      sizeof(bigCert));
735     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
736      GetLastError());
737     if (context)
738     {
739         ret = CertDeleteCertificateFromStore(collection, context);
740         printf("ret is %d, GetLastError is %08lx\n", ret, GetLastError());
741         CertFreeCertificateContext(context);
742     }
743      */
744
745     /* Now check deleting from the collection. */
746     context = CertEnumCertificatesInStore(collection, NULL);
747     ok(context != NULL, "Expected a valid context\n");
748     if (context)
749     {
750         CertDeleteCertificateFromStore(context);
751         /* store1 should now be empty */
752         context = CertEnumCertificatesInStore(store1, NULL);
753         ok(!context, "Unexpected cert\n");
754         /* and there should be one certificate in the collection */
755         context = CertEnumCertificatesInStore(collection, NULL);
756         ok(context != NULL, "Expected a valid cert\n");
757         if (context)
758         {
759             ok(context->hCertStore == collection, "Unexpected store\n");
760             ok(context->cbCertEncoded == sizeof(bigCert),
761              "Expected size %d, got %ld\n", sizeof(bigCert),
762              context->cbCertEncoded);
763             ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
764              "Unexpected cert\n");
765         }
766         context = CertEnumCertificatesInStore(collection, context);
767         ok(context == NULL, "Unexpected cert\n");
768     }
769
770     /* Finally, test removing stores from the collection.  No return value, so
771      * it's a bit funny to test.
772      */
773     /* This crashes
774     CertRemoveStoreFromCollection(NULL, NULL);
775      */
776     /* This "succeeds," no crash, no last error set */
777     SetLastError(0xdeadbeef);
778     CertRemoveStoreFromCollection(store2, collection);
779     ok(GetLastError() == 0xdeadbeef,
780      "Didn't expect an error to be set: %08lx\n", GetLastError());
781
782     /* After removing store2, the collection should be empty */
783     SetLastError(0xdeadbeef);
784     CertRemoveStoreFromCollection(collection, store2);
785     ok(GetLastError() == 0xdeadbeef,
786      "Didn't expect an error to be set: %08lx\n", GetLastError());
787     context = CertEnumCertificatesInStore(collection, NULL);
788     ok(!context, "Unexpected cert\n");
789
790     CertCloseStore(collection, 0);
791     CertCloseStore(store2, 0);
792     CertCloseStore(store1, 0);
793 }
794
795 /* Looks for the property with ID propID in the buffer buf.  Returns a pointer
796  * to its header if found, NULL if not.
797  */
798 static const struct CertPropIDHeader *findPropID(const BYTE *buf, DWORD size,
799  DWORD propID)
800 {
801     const struct CertPropIDHeader *ret = NULL;
802     BOOL failed = FALSE;
803
804     while (size && !ret && !failed)
805     {
806         if (size < sizeof(struct CertPropIDHeader))
807             failed = TRUE;
808         else
809         {
810             const struct CertPropIDHeader *hdr =
811              (const struct CertPropIDHeader *)buf;
812
813             size -= sizeof(struct CertPropIDHeader);
814             buf += sizeof(struct CertPropIDHeader);
815             if (size < hdr->cb)
816                 failed = TRUE;
817             else if (hdr->propID == propID)
818                 ret = hdr;
819             else
820             {
821                 buf += hdr->cb;
822                 size -= hdr->cb;
823             }
824         }
825     }
826     return ret;
827 }
828
829 typedef DWORD (WINAPI *SHDeleteKeyAFunc)(HKEY, LPCSTR);
830
831 static void testRegStore(void)
832 {
833     static const char tempKey[] = "Software\\Wine\\CryptTemp";
834     HCERTSTORE store;
835     LONG rc;
836     HKEY key = NULL;
837     DWORD disp;
838
839     store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, NULL);
840     ok(!store && GetLastError() == ERROR_INVALID_HANDLE,
841      "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
842     store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
843     ok(!store && GetLastError() == ERROR_INVALID_HANDLE,
844      "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
845
846     /* Opening up any old key works.. */
847     key = HKEY_CURRENT_USER;
848     store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
849     /* Not sure if this is a bug in DuplicateHandle, marking todo_wine for now
850      */
851     todo_wine ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
852     CertCloseStore(store, 0);
853
854     rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS,
855      NULL, &key, NULL);
856     ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
857     if (key)
858     {
859         BOOL ret;
860         BYTE hash[20];
861         DWORD size, i;
862         static const char certificates[] = "Certificates\\";
863         char subKeyName[sizeof(certificates) + 20 * 2 + 1], *ptr;
864         HKEY subKey;
865         PCCERT_CONTEXT context;
866
867         store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
868         ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
869         /* Add a certificate.  It isn't persisted right away, since it's only
870          * added to the cache..
871          */
872         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
873          bigCert2, sizeof(bigCert2), CERT_STORE_ADD_ALWAYS, NULL);
874         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
875          GetLastError());
876         /* so flush the cache to force a commit.. */
877         ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
878         ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
879         /* and check that the expected subkey was written. */
880         size = sizeof(hash);
881         ret = CryptHashCertificate(0, 0, 0, bigCert2, sizeof(bigCert2),
882          hash, &size);
883         ok(ret, "CryptHashCertificate failed: %ld\n", GetLastError());
884         strcpy(subKeyName, certificates);
885         for (i = 0, ptr = subKeyName + sizeof(certificates) - 1; i < size;
886          i++, ptr += 2)
887             sprintf(ptr, "%02X", hash[i]);
888         rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
889          &subKey, NULL);
890         ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
891         if (subKey)
892         {
893             LPBYTE buf;
894
895             size = 0;
896             RegQueryValueExA(subKey, "Blob", NULL, NULL, NULL, &size);
897             buf = HeapAlloc(GetProcessHeap(), 0, size);
898             if (buf)
899             {
900                 rc = RegQueryValueExA(subKey, "Blob", NULL, NULL, buf, &size);
901                 ok(!rc, "RegQueryValueExA failed: %ld\n", rc);
902                 if (!rc)
903                 {
904                     const struct CertPropIDHeader *hdr;
905
906                     /* Both the hash and the cert should be present */
907                     hdr = findPropID(buf, size, CERT_CERT_PROP_ID);
908                     ok(hdr != NULL, "Expected to find a cert property\n");
909                     if (hdr)
910                     {
911                         ok(hdr->cb == sizeof(bigCert2),
912                          "Unexpected size %ld of cert property, expected %d\n",
913                          hdr->cb, sizeof(bigCert2));
914                         ok(!memcmp((BYTE *)hdr + sizeof(*hdr), bigCert2,
915                          hdr->cb), "Unexpected cert in cert property\n");
916                     }
917                     hdr = findPropID(buf, size, CERT_HASH_PROP_ID);
918                     ok(hdr != NULL, "Expected to find a hash property\n");
919                     if (hdr)
920                     {
921                         ok(hdr->cb == sizeof(hash),
922                          "Unexpected size %ld of hash property, expected %d\n",
923                          hdr->cb, sizeof(hash));
924                         ok(!memcmp((BYTE *)hdr + sizeof(*hdr), hash,
925                          hdr->cb), "Unexpected hash in cert property\n");
926                     }
927                 }
928                 HeapFree(GetProcessHeap(), 0, buf);
929             }
930             RegCloseKey(subKey);
931         }
932
933         /* Remove the existing context */
934         context = CertEnumCertificatesInStore(store, NULL);
935         ok(context != NULL, "Expected a cert context\n");
936         if (context)
937             CertDeleteCertificateFromStore(context);
938         ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
939         ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
940
941         /* Add a serialized cert with a bogus hash directly to the registry */
942         memset(hash, 0, sizeof(hash));
943         strcpy(subKeyName, certificates);
944         for (i = 0, ptr = subKeyName + sizeof(certificates) - 1;
945          i < sizeof(hash); i++, ptr += 2)
946             sprintf(ptr, "%02X", hash[i]);
947         rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
948          &subKey, NULL);
949         ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
950         if (subKey)
951         {
952             BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) +
953              sizeof(bigCert)], *ptr;
954             DWORD certCount = 0;
955             struct CertPropIDHeader *hdr;
956
957             hdr = (struct CertPropIDHeader *)buf;
958             hdr->propID = CERT_HASH_PROP_ID;
959             hdr->unknown1 = 1;
960             hdr->cb = sizeof(hash);
961             ptr = buf + sizeof(*hdr);
962             memcpy(ptr, hash, sizeof(hash));
963             ptr += sizeof(hash);
964             hdr = (struct CertPropIDHeader *)ptr;
965             hdr->propID = CERT_CERT_PROP_ID;
966             hdr->unknown1 = 1;
967             hdr->cb = sizeof(bigCert);
968             ptr += sizeof(*hdr);
969             memcpy(ptr, bigCert, sizeof(bigCert));
970
971             rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
972              sizeof(buf));
973             ok(!rc, "RegSetValueExA failed: %ld\n", rc);
974
975             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
976             ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
977
978             /* Make sure the bogus hash cert gets loaded. */
979             certCount = 0;
980             context = NULL;
981             do {
982                 context = CertEnumCertificatesInStore(store, context);
983                 if (context)
984                     certCount++;
985             } while (context != NULL);
986             ok(certCount == 1, "Expected 1 certificates, got %ld\n", certCount);
987
988             RegCloseKey(subKey);
989         }
990
991         /* Add another serialized cert directly to the registry, this time
992          * under the correct key name (named with the correct hash value).
993          */
994         size = sizeof(hash);
995         ret = CryptHashCertificate(0, 0, 0, bigCert2,
996          sizeof(bigCert2), hash, &size);
997         ok(ret, "CryptHashCertificate failed: %ld\n", GetLastError());
998         strcpy(subKeyName, certificates);
999         for (i = 0, ptr = subKeyName + sizeof(certificates) - 1;
1000          i < sizeof(hash); i++, ptr += 2)
1001             sprintf(ptr, "%02X", hash[i]);
1002         rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
1003          &subKey, NULL);
1004         ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
1005         if (subKey)
1006         {
1007             BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) +
1008              sizeof(bigCert2)], *ptr;
1009             DWORD certCount = 0;
1010             PCCERT_CONTEXT context;
1011             struct CertPropIDHeader *hdr;
1012
1013             /* First try with a bogus hash... */
1014             hdr = (struct CertPropIDHeader *)buf;
1015             hdr->propID = CERT_HASH_PROP_ID;
1016             hdr->unknown1 = 1;
1017             hdr->cb = sizeof(hash);
1018             ptr = buf + sizeof(*hdr);
1019             memset(ptr, 0, sizeof(hash));
1020             ptr += sizeof(hash);
1021             hdr = (struct CertPropIDHeader *)ptr;
1022             hdr->propID = CERT_CERT_PROP_ID;
1023             hdr->unknown1 = 1;
1024             hdr->cb = sizeof(bigCert2);
1025             ptr += sizeof(*hdr);
1026             memcpy(ptr, bigCert2, sizeof(bigCert2));
1027
1028             rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
1029              sizeof(buf));
1030             ok(!rc, "RegSetValueExA failed: %ld\n", rc);
1031
1032             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
1033             ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
1034
1035             /* and make sure just one cert still gets loaded. */
1036             certCount = 0;
1037             context = NULL;
1038             do {
1039                 context = CertEnumCertificatesInStore(store, context);
1040                 if (context)
1041                     certCount++;
1042             } while (context != NULL);
1043             ok(certCount == 1, "Expected 1 certificates, got %ld\n", certCount);
1044
1045             /* Try again with the correct hash... */
1046             ptr = buf + sizeof(*hdr);
1047             memcpy(ptr, hash, sizeof(hash));
1048
1049             rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
1050              sizeof(buf));
1051             ok(!rc, "RegSetValueExA failed: %ld\n", rc);
1052
1053             ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
1054             ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
1055
1056             /* and make sure two certs get loaded. */
1057             certCount = 0;
1058             context = NULL;
1059             do {
1060                 context = CertEnumCertificatesInStore(store, context);
1061                 if (context)
1062                     certCount++;
1063             } while (context != NULL);
1064             ok(certCount == 2, "Expected 2 certificates, got %ld\n", certCount);
1065
1066             RegCloseKey(subKey);
1067         }
1068         CertCloseStore(store, 0);
1069         /* Is delete allowed on a reg store? */
1070         store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0,
1071          CERT_STORE_DELETE_FLAG, key);
1072         ok(store == NULL, "Expected NULL return from CERT_STORE_DELETE_FLAG\n");
1073         ok(GetLastError() == 0, "CertOpenStore failed: %08lx\n",
1074          GetLastError());
1075
1076         RegCloseKey(key);
1077     }
1078     /* The CertOpenStore with CERT_STORE_DELETE_FLAG above will delete the
1079      * contents of the key, but not the key itself.
1080      */
1081     rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS,
1082      NULL, &key, &disp);
1083     ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
1084     ok(disp == REG_OPENED_EXISTING_KEY,
1085      "Expected REG_OPENED_EXISTING_KEY, got %ld\n", disp);
1086     if (!rc)
1087     {
1088         RegCloseKey(key);
1089         rc = RegDeleteKeyA(HKEY_CURRENT_USER, tempKey);
1090         if (rc)
1091         {
1092             HMODULE shlwapi = LoadLibraryA("shlwapi");
1093
1094             /* Use shlwapi's SHDeleteKeyA to _really_ blow away the key,
1095              * otherwise subsequent tests will fail.
1096              */
1097             if (shlwapi)
1098             {
1099                 SHDeleteKeyAFunc pSHDeleteKeyA =
1100                  (SHDeleteKeyAFunc)GetProcAddress(shlwapi, "SHDeleteKeyA");
1101
1102                 if (pSHDeleteKeyA)
1103                     pSHDeleteKeyA(HKEY_CURRENT_USER, tempKey);
1104                 FreeLibrary(shlwapi);
1105             }
1106         }
1107     }
1108 }
1109
1110 static const char MyA[] = { 'M','y',0,0 };
1111 static const WCHAR MyW[] = { 'M','y',0 };
1112 static const WCHAR BogusW[] = { 'B','o','g','u','s',0 };
1113 static const WCHAR BogusPathW[] = { 'S','o','f','t','w','a','r','e','\\',
1114  'M','i','c','r','o','s','o','f','t','\\','S','y','s','t','e','m','C','e','r',
1115  't','i','f','i','c','a','t','e','s','\\','B','o','g','u','s',0 };
1116
1117 static void testSystemRegStore(void)
1118 {
1119     HCERTSTORE store, memStore;
1120
1121     /* Check with a UNICODE name */
1122     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
1123      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW);
1124     /* Not all OSes support CERT_STORE_PROV_SYSTEM_REGISTRY, so don't continue
1125      * testing if they don't.
1126      */
1127     if (!store)
1128         return;
1129
1130     /* Check that it isn't a collection store */
1131     memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1132      CERT_STORE_CREATE_NEW_FLAG, NULL);
1133     if (memStore)
1134     {
1135         BOOL ret = CertAddStoreToCollection(store, memStore, 0, 0);
1136
1137         ok(!ret && GetLastError() ==
1138          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1139          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1140          GetLastError());
1141         CertCloseStore(memStore, 0);
1142     }
1143     CertCloseStore(store, 0);
1144
1145     /* Check opening a bogus store */
1146     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
1147      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW);
1148     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1149      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1150     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
1151      CERT_SYSTEM_STORE_CURRENT_USER, BogusW);
1152     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1153     if (store)
1154         CertCloseStore(store, 0);
1155     /* Now check whether deleting is allowed */
1156     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
1157      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
1158     RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
1159
1160     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, 0, NULL);
1161     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1162      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1163      GetLastError());
1164     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
1165      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA);
1166     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1167      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1168      GetLastError());
1169     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
1170      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW);
1171     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1172      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1173      GetLastError());
1174     /* The name is expected to be UNICODE, check with an ASCII name */
1175     store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
1176      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA);
1177     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1178      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1179 }
1180
1181 static void testSystemStore(void)
1182 {
1183     static const WCHAR baskslashW[] = { '\\',0 };
1184     HCERTSTORE store;
1185     WCHAR keyName[MAX_PATH];
1186     HKEY key;
1187     LONG rc;
1188
1189     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, 0, NULL);
1190     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1191      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1192     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1193      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA);
1194     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1195      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1196     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1197      CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW);
1198     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1199      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1200     /* The name is expected to be UNICODE, first check with an ASCII name */
1201     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1202      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA);
1203     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1204      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1205     /* Create the expected key */
1206     lstrcpyW(keyName, CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH);
1207     lstrcatW(keyName, baskslashW);
1208     lstrcatW(keyName, MyW);
1209     rc = RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
1210      NULL, &key, NULL);
1211     ok(!rc, "RegCreateKeyEx failed: %ld\n", rc);
1212     if (!rc)
1213         RegCloseKey(key);
1214     /* Check opening with a UNICODE name, specifying the create new flag */
1215     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1216      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_CREATE_NEW_FLAG, MyW);
1217     ok(!store && GetLastError() == ERROR_FILE_EXISTS,
1218      "Expected ERROR_FILE_EXISTS, got %08lx\n", GetLastError());
1219     /* Now check opening with a UNICODE name, this time opening existing */
1220     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1221      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW);
1222     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1223     if (store)
1224     {
1225         HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1226          CERT_STORE_CREATE_NEW_FLAG, NULL);
1227
1228         /* Check that it's a collection store */
1229         if (memStore)
1230         {
1231             BOOL ret = CertAddStoreToCollection(store, memStore, 0, 0);
1232
1233             /* FIXME: this'll fail on NT4, but what error will it give? */
1234             ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
1235             CertCloseStore(memStore, 0);
1236         }
1237         CertCloseStore(store, 0);
1238     }
1239
1240     /* Check opening a bogus store */
1241     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1242      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW);
1243     ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1244      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1245     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1246      CERT_SYSTEM_STORE_CURRENT_USER, BogusW);
1247     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1248     if (store)
1249         CertCloseStore(store, 0);
1250     /* Now check whether deleting is allowed */
1251     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1252      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
1253     RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
1254 }
1255
1256 static void testCertOpenSystemStore(void)
1257 {
1258     HCERTSTORE store;
1259
1260     store = CertOpenSystemStoreW(0, NULL);
1261     ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1262      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1263      GetLastError());
1264     /* This succeeds, and on WinXP at least, the Bogus key is created under
1265      * HKCU (but not under HKLM, even when run as an administrator.)
1266      */
1267     store = CertOpenSystemStoreW(0, BogusW);
1268     ok(store != 0, "CertOpenSystemStore failed: %08lx\n", GetLastError());
1269     if (store)
1270         CertCloseStore(store, 0);
1271     /* Delete it so other tests succeed next time around */
1272     store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1273      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
1274     RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
1275 }
1276
1277 static void checkHash(const BYTE *data, DWORD dataLen, ALG_ID algID,
1278  PCCERT_CONTEXT context, DWORD propID)
1279 {
1280     BYTE hash[20] = { 0 }, hashProperty[20];
1281     BOOL ret;
1282     DWORD size;
1283
1284     memset(hash, 0, sizeof(hash));
1285     memset(hashProperty, 0, sizeof(hashProperty));
1286     size = sizeof(hash);
1287     ret = CryptHashCertificate(0, algID, 0, data, dataLen, hash, &size);
1288     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1289     ret = CertGetCertificateContextProperty(context, propID, hashProperty,
1290      &size);
1291     ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1292      GetLastError());
1293     ok(!memcmp(hash, hashProperty, size), "Unexpected hash for property %ld\n",
1294      propID);
1295 }
1296
1297 static void testCertProperties(void)
1298 {
1299     PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING,
1300      bigCert, sizeof(bigCert));
1301
1302     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
1303      GetLastError());
1304     if (context)
1305     {
1306         DWORD propID, numProps, access, size;
1307         BOOL ret;
1308         BYTE hash[20] = { 0 }, hashProperty[20];
1309         CRYPT_DATA_BLOB blob;
1310
1311         /* This crashes
1312         propID = CertEnumCertificateContextProperties(NULL, 0);
1313          */
1314
1315         propID = 0;
1316         numProps = 0;
1317         do {
1318             propID = CertEnumCertificateContextProperties(context, propID);
1319             if (propID)
1320                 numProps++;
1321         } while (propID != 0);
1322         ok(numProps == 0, "Expected 0 properties, got %ld\n", numProps);
1323
1324         /* Tests with a NULL cert context.  Prop ID 0 fails.. */
1325         ret = CertSetCertificateContextProperty(NULL, 0, 0, NULL);
1326         ok(!ret && GetLastError() ==
1327          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1328          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1329          GetLastError());
1330         /* while this just crashes.
1331         ret = CertSetCertificateContextProperty(NULL,
1332          CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
1333          */
1334
1335         ret = CertSetCertificateContextProperty(context, 0, 0, NULL);
1336         ok(!ret && GetLastError() ==
1337          HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1338          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1339          GetLastError());
1340         /* Can't set the cert property directly, this crashes.
1341         ret = CertSetCertificateContextProperty(context,
1342          CERT_CERT_PROP_ID, 0, bigCert2);
1343          */
1344
1345         /* These all crash.
1346         ret = CertGetCertificateContextProperty(context,
1347          CERT_ACCESS_STATE_PROP_ID, 0, NULL);
1348         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, 
1349          NULL, NULL);
1350         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, 
1351          hashProperty, NULL);
1352          */
1353         /* A missing prop */
1354         size = 0;
1355         ret = CertGetCertificateContextProperty(context,
1356          CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
1357         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
1358          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
1359         /* And, an implicit property */
1360         size = sizeof(access);
1361         ret = CertGetCertificateContextProperty(context,
1362          CERT_ACCESS_STATE_PROP_ID, &access, &size);
1363         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1364          GetLastError());
1365         ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG),
1366          "Didn't expect a persisted cert\n");
1367         /* Trying to set this "read only" property crashes.
1368         access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1369         ret = CertSetCertificateContextProperty(context,
1370          CERT_ACCESS_STATE_PROP_ID, 0, &access);
1371          */
1372
1373         /* Can I set the hash to an invalid hash? */
1374         blob.pbData = hash;
1375         blob.cbData = sizeof(hash);
1376         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1377          &blob);
1378         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1379          GetLastError());
1380         size = sizeof(hashProperty);
1381         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1382          hashProperty, &size);
1383         ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n");
1384         /* Delete the (bogus) hash, and get the real one */
1385         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1386          NULL);
1387         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1388          GetLastError());
1389         checkHash(bigCert, sizeof(bigCert), CALG_SHA1, context,
1390          CERT_HASH_PROP_ID);
1391
1392         /* Now that the hash property is set, we should get one property when
1393          * enumerating.
1394          */
1395         propID = 0;
1396         numProps = 0;
1397         do {
1398             propID = CertEnumCertificateContextProperties(context, propID);
1399             if (propID)
1400                 numProps++;
1401         } while (propID != 0);
1402         ok(numProps == 1, "Expected 1 properties, got %ld\n", numProps);
1403
1404         /* Check a few other implicit properties */
1405         checkHash(bigCert, sizeof(bigCert), CALG_MD5, context,
1406          CERT_MD5_HASH_PROP_ID);
1407         checkHash(
1408          context->pCertInfo->Subject.pbData,
1409          context->pCertInfo->Subject.cbData,
1410          CALG_MD5, context, CERT_SUBJECT_NAME_MD5_HASH_PROP_ID);
1411         checkHash(
1412          context->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
1413          context->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
1414          CALG_MD5, context, CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID);
1415
1416         /* Odd: this doesn't fail on other certificates, so there must be
1417          * something weird about this cert that causes it to fail.
1418          */
1419         size = 0;
1420         ret = CertGetCertificateContextProperty(context,
1421          CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1422         todo_wine ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1423          "Expected ERROR_INVALID_DATA, got %08lx\n", GetLastError());
1424
1425         CertFreeCertificateContext(context);
1426     }
1427 }
1428
1429 static void testAddSerialized(void)
1430 {
1431     BOOL ret;
1432     HCERTSTORE store;
1433     BYTE buf[sizeof(struct CertPropIDHeader) * 2 + 20 + sizeof(bigCert)] =
1434      { 0 };
1435     BYTE hash[20];
1436     struct CertPropIDHeader *hdr;
1437     PCCERT_CONTEXT context;
1438
1439     ret = CertAddSerializedElementToStore(0, NULL, 0, 0, 0, 0, NULL, NULL);
1440     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1441      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1442
1443     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1444      CERT_STORE_CREATE_NEW_FLAG, NULL);
1445     ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1446
1447     ret = CertAddSerializedElementToStore(store, NULL, 0, 0, 0, 0, NULL, NULL);
1448     ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1449      "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1450
1451     /* Test with an empty property */
1452     hdr = (struct CertPropIDHeader *)buf;
1453     hdr->propID = CERT_CERT_PROP_ID;
1454     hdr->unknown1 = 1;
1455     hdr->cb = 0;
1456     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1457      NULL, NULL);
1458     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1459      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1460      GetLastError());
1461     /* Test with a bad size in property header */
1462     hdr->cb = sizeof(bigCert) - 1;
1463     memcpy(buf + sizeof(struct CertPropIDHeader), bigCert, sizeof(bigCert));
1464     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1465      NULL, NULL);
1466     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1467      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1468      GetLastError());
1469     ret = CertAddSerializedElementToStore(store, buf,
1470      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 0, NULL,
1471      NULL);
1472     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1473      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1474      GetLastError());
1475     ret = CertAddSerializedElementToStore(store, buf,
1476      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1477      0, 0, NULL, NULL);
1478     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1479      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1480      GetLastError());
1481     /* Kosher size in property header, but no context type */
1482     hdr->cb = sizeof(bigCert);
1483     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1484      NULL, NULL);
1485     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1486      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1487      GetLastError());
1488     ret = CertAddSerializedElementToStore(store, buf,
1489      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 0, NULL,
1490      NULL);
1491     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1492      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1493      GetLastError());
1494     ret = CertAddSerializedElementToStore(store, buf,
1495      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1496      0, 0, NULL, NULL);
1497     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1498      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1499      GetLastError());
1500     /* With a bad context type */
1501     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1502      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1503     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1504      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1505      GetLastError());
1506     ret = CertAddSerializedElementToStore(store, buf,
1507      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 
1508      CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1509     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1510      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1511      GetLastError());
1512     ret = CertAddSerializedElementToStore(store, buf,
1513      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1514      0, CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1515     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1516      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1517      GetLastError());
1518     /* Bad unknown field, good type */
1519     hdr->unknown1 = 2;
1520     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1521      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1522     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1523      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1524     ret = CertAddSerializedElementToStore(store, buf,
1525      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 
1526      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1527     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1528      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1529     ret = CertAddSerializedElementToStore(store, buf,
1530      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1531      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1532     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1533      "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1534     /* Most everything okay, but bad add disposition */
1535     hdr->unknown1 = 1;
1536     /* This crashes
1537     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 
1538      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1539      * as does this
1540     ret = CertAddSerializedElementToStore(store, buf,
1541      sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 
1542      CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1543      */
1544     /* Everything okay, but buffer's too big */
1545     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1546      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1547     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1548     /* Everything okay, check it's not re-added */
1549     ret = CertAddSerializedElementToStore(store, buf,
1550      sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1551      0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1552     ok(!ret && GetLastError() == CRYPT_E_EXISTS,
1553      "Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
1554
1555     context = CertEnumCertificatesInStore(store, NULL);
1556     ok(context != NULL, "Expected a cert\n");
1557     if (context)
1558         CertDeleteCertificateFromStore(context);
1559
1560     /* Try adding with a bogus hash.  Oddly enough, it succeeds, and the hash,
1561      * when queried, is the real hash rather than the bogus hash.
1562      */
1563     hdr = (struct CertPropIDHeader *)(buf + sizeof(struct CertPropIDHeader) +
1564      sizeof(bigCert));
1565     hdr->propID = CERT_HASH_PROP_ID;
1566     hdr->unknown1 = 1;
1567     hdr->cb = sizeof(hash);
1568     memset(hash, 0xc, sizeof(hash));
1569     memcpy((LPBYTE)hdr + sizeof(struct CertPropIDHeader), hash, sizeof(hash));
1570     ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1571      CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL,
1572      (const void **)&context);
1573     ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1574     if (context)
1575     {
1576         BYTE hashVal[20], realHash[20];
1577         DWORD size = sizeof(hashVal);
1578
1579         ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert),
1580          realHash, &size);
1581         ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1582         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1583          hashVal, &size);
1584         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1585          GetLastError());
1586         ok(!memcmp(hashVal, realHash, size), "Unexpected hash\n");
1587         CertFreeCertificateContext(context);
1588     }
1589
1590     CertCloseStore(store, 0);
1591 }
1592
1593 START_TEST(store)
1594 {
1595     testDupCert();
1596     testFindCert();
1597     testGetSubjectCert();
1598
1599     /* various combinations of CertOpenStore */
1600     testMemStore();
1601     testCollectionStore();
1602     testRegStore();
1603     testSystemRegStore();
1604     testSystemStore();
1605
1606     testCertOpenSystemStore();
1607
1608     testCertProperties();
1609     testAddSerialized();
1610 }