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