2 * crypt32 cert store function tests
4 * Copyright 2005-2006 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
30 #include "wine/test.h"
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
37 struct CertPropIDHeader
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 signedBigCert[] = {
56 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
57 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
58 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
59 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
60 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
61 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
62 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
63 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
64 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
65 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
66 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
67 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
68 static const BYTE serializedCert[] = { 0x20, 0x00, 0x00, 0x00,
69 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x7a, 0x02, 0x01, 0x01,
70 0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
71 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67,
72 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31,
73 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
74 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15,
75 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75,
76 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06,
77 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
78 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02,
80 static const BYTE signedCRL[] = { 0x30, 0x45, 0x30, 0x2c, 0x30, 0x02, 0x06,
81 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
82 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
83 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
84 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c,
85 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
87 static void testDupCert(void)
91 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
92 CERT_STORE_CREATE_NEW_FLAG, NULL);
93 ok(store != NULL, "CertOpenStore failed: %ld\n", GetLastError());
96 PCCERT_CONTEXT context, dupContext;
99 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
100 bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context);
101 ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
103 ok(context != NULL, "Expected a valid cert context\n");
106 ok(context->cbCertEncoded == sizeof(bigCert),
107 "Expected cert of %d bytes, got %ld\n", sizeof(bigCert),
108 context->cbCertEncoded);
109 ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)),
110 "Unexpected encoded cert in context\n");
111 ok(context->hCertStore == store, "Unexpected store\n");
113 dupContext = CertDuplicateCertificateContext(context);
114 ok(dupContext != NULL, "Expected valid duplicate\n");
117 ok(dupContext->cbCertEncoded == sizeof(bigCert),
118 "Expected cert of %d bytes, got %ld\n", sizeof(bigCert),
119 dupContext->cbCertEncoded);
120 ok(!memcmp(dupContext->pbCertEncoded, bigCert,
122 "Unexpected encoded cert in context\n");
123 ok(dupContext->hCertStore == store, "Unexpected store\n");
124 CertFreeCertificateContext(dupContext);
126 CertFreeCertificateContext(context);
128 CertCloseStore(store, 0);
132 static void testMemStore(void)
134 HCERTSTORE store1, store2;
135 PCCERT_CONTEXT context;
139 store1 = CertOpenStore(0, 0, 0, 0, NULL);
140 ok(!store1 && GetLastError() == ERROR_FILE_NOT_FOUND,
141 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
143 store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
144 CERT_STORE_DELETE_FLAG, NULL);
145 ok(!store1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
146 "Expected ERROR_CALL_NOT_IMPLEMENTED, got %ld\n", GetLastError());
149 store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
150 CERT_STORE_CREATE_NEW_FLAG, NULL);
151 ok(store1 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
152 /* open existing doesn't */
153 store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
154 CERT_STORE_OPEN_EXISTING_FLAG, NULL);
155 ok(store2 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
156 ok(store1 != store2, "Expected different stores\n");
158 /* add a bogus (empty) cert */
160 ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, emptyCert,
161 sizeof(emptyCert), CERT_STORE_ADD_ALWAYS, &context);
162 /* Windows returns CRYPT_E_ASN1_EOD, but accept CRYPT_E_ASN1_CORRUPT as
163 * well (because matching errors is tough in this case)
165 ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || GetLastError() ==
166 CRYPT_E_ASN1_CORRUPT),
167 "Expected CRYPT_E_ASN1_EOD or CRYPT_E_ASN1_CORRUPT, got %08lx\n",
169 /* add a "signed" cert--the signature isn't a real signature, so this adds
170 * without any check of the signature's validity
172 ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
173 signedBigCert, sizeof(signedBigCert), CERT_STORE_ADD_ALWAYS, &context);
174 ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
175 ok(context != NULL, "Expected a valid cert context\n");
178 ok(context->cbCertEncoded == sizeof(signedBigCert),
179 "Expected cert of %d bytes, got %ld\n", sizeof(signedBigCert),
180 context->cbCertEncoded);
181 ok(!memcmp(context->pbCertEncoded, signedBigCert,
182 sizeof(signedBigCert)), "Unexpected encoded cert in context\n");
183 /* remove it, the rest of the tests will work on an unsigned cert */
184 ret = CertDeleteCertificateFromStore(context);
185 ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
188 /* try adding a "signed" CRL as a cert */
189 ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
190 signedCRL, sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, &context);
191 ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || GetLastError() ==
192 CRYPT_E_ASN1_CORRUPT),
193 "Expected CRYPT_E_ASN1_BADTAG or CRYPT_E_ASN1_CORRUPT, got %08lx\n",
195 /* add a cert to store1 */
196 ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert,
197 sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context);
198 ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
199 ok(context != NULL, "Expected a valid cert context\n");
205 ok(context->cbCertEncoded == sizeof(bigCert),
206 "Expected cert of %d bytes, got %ld\n", sizeof(bigCert),
207 context->cbCertEncoded);
208 ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)),
209 "Unexpected encoded cert in context\n");
210 ok(context->hCertStore == store1, "Unexpected store\n");
212 /* check serializing this element */
214 ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, NULL);
215 ret = CertSerializeCertificateStoreElement(context, 0, NULL, NULL);
216 ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, &size);
218 /* apparently flags are ignored */
219 ret = CertSerializeCertificateStoreElement(context, 1, NULL, &size);
220 ok(ret, "CertSerializeCertificateStoreElement failed: %08lx\n",
222 buf = HeapAlloc(GetProcessHeap(), 0, size);
225 ret = CertSerializeCertificateStoreElement(context, 0, buf, &size);
226 ok(size == sizeof(serializedCert), "Expected size %d, got %ld\n",
227 sizeof(serializedCert), size);
228 ok(!memcmp(serializedCert, buf, size),
229 "Unexpected serialized cert\n");
230 HeapFree(GetProcessHeap(), 0, buf);
233 ret = CertFreeCertificateContext(context);
234 ok(ret, "CertFreeCertificateContext failed: %08lx\n", GetLastError());
236 /* verify the cert's in store1 */
237 context = CertEnumCertificatesInStore(store1, NULL);
238 ok(context != NULL, "Expected a valid context\n");
239 context = CertEnumCertificatesInStore(store1, context);
240 ok(!context && GetLastError() == CRYPT_E_NOT_FOUND,
241 "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
242 /* verify store2 (the "open existing" mem store) is still empty */
243 context = CertEnumCertificatesInStore(store2, NULL);
244 ok(!context, "Expected an empty store\n");
245 /* delete the cert from store1, and check it's empty */
246 context = CertEnumCertificatesInStore(store1, NULL);
249 /* Deleting a bitwise copy crashes with an access to an uninitialized
250 * pointer, so a cert context has some special data out there in memory
253 memcpy(©, context, sizeof(copy));
254 ret = CertDeleteCertificateFromStore(©);
256 PCCERT_CONTEXT copy = CertDuplicateCertificateContext(context);
258 ok(copy != NULL, "CertDuplicateCertificateContext failed: %08lx\n",
260 ret = CertDeleteCertificateFromStore(context);
261 ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
263 /* try deleting a copy */
264 ret = CertDeleteCertificateFromStore(copy);
265 ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
267 /* check that the store is empty */
268 context = CertEnumCertificatesInStore(store1, NULL);
269 ok(!context, "Expected an empty store\n");
272 /* close an empty store */
273 ret = CertCloseStore(NULL, 0);
274 ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
275 ret = CertCloseStore(store1, 0);
276 ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
277 ret = CertCloseStore(store2, 0);
278 ok(ret, "CertCloseStore failed: %ld\n", GetLastError());
280 /* This seems nonsensical, but you can open a read-only mem store, only
283 store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
284 CERT_STORE_READONLY_FLAG, NULL);
285 ok(store1 != NULL, "CertOpenStore failed: %ld\n", GetLastError());
286 /* yep, this succeeds */
287 ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert,
288 sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context);
289 ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
290 ok(context != NULL, "Expected a valid cert context\n");
293 ok(context->cbCertEncoded == sizeof(bigCert),
294 "Expected cert of %d bytes, got %ld\n", sizeof(bigCert),
295 context->cbCertEncoded);
296 ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)),
297 "Unexpected encoded cert in context\n");
298 ok(context->hCertStore == store1, "Unexpected store\n");
299 ret = CertDeleteCertificateFromStore(context);
300 ok(ret, "CertDeleteCertificateFromStore failed: %08lx\n",
303 CertCloseStore(store1, 0);
306 static const BYTE bigCert2[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
307 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
308 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
309 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
310 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
311 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
312 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
313 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
314 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
315 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
317 static void testCollectionStore(void)
319 HCERTSTORE store1, store2, collection, collection2;
320 PCCERT_CONTEXT context;
323 collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
324 CERT_STORE_CREATE_NEW_FLAG, NULL);
326 /* Try adding a cert to any empty collection */
327 ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
328 bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
329 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
330 "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
333 /* Create and add a cert to a memory store */
334 store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
335 CERT_STORE_CREATE_NEW_FLAG, NULL);
336 ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
337 bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
338 ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
339 /* Add the memory store to the collection, without allowing adding */
340 ret = CertAddStoreToCollection(collection, store1, 0, 0);
341 ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
342 /* Verify the cert is in the collection */
343 context = CertEnumCertificatesInStore(collection, NULL);
344 ok(context != NULL, "Expected a valid context\n");
347 ok(context->hCertStore == collection, "Unexpected store\n");
348 CertFreeCertificateContext(context);
350 /* Check that adding to the collection isn't allowed */
351 ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
352 bigCert2, sizeof(bigCert2), CERT_STORE_ADD_ALWAYS, NULL);
353 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED),
354 "Expected HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), got %08lx\n",
357 /* Create a new memory store */
358 store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
359 CERT_STORE_CREATE_NEW_FLAG, NULL);
360 /* Try adding a store to a non-collection store */
361 ret = CertAddStoreToCollection(store1, store2,
362 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
363 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
364 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
366 /* Try adding some bogus stores */
367 /* This crashes in Windows
368 ret = CertAddStoreToCollection(0, store2,
369 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
371 /* This "succeeds"... */
372 ret = CertAddStoreToCollection(collection, 0,
373 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
374 ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
375 /* while this crashes.
376 ret = CertAddStoreToCollection(collection, 1,
377 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
380 /* Add it to the collection, this time allowing adding */
381 ret = CertAddStoreToCollection(collection, store2,
382 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
383 ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
384 /* Check that adding to the collection is allowed */
385 ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING,
386 bigCert2, sizeof(bigCert2), CERT_STORE_ADD_ALWAYS, NULL);
387 ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
388 /* Now check that it was actually added to store2 */
389 context = CertEnumCertificatesInStore(store2, NULL);
390 ok(context != NULL, "Expected a valid context\n");
393 ok(context->hCertStore == store2, "Unexpected store\n");
394 CertFreeCertificateContext(context);
396 /* Check that the collection has both bigCert and bigCert2. bigCert comes
397 * first because store1 was added first.
399 context = CertEnumCertificatesInStore(collection, NULL);
400 ok(context != NULL, "Expected a valid context\n");
403 ok(context->hCertStore == collection, "Unexpected store\n");
404 ok(context->cbCertEncoded == sizeof(bigCert),
405 "Expected size %d, got %ld\n", sizeof(bigCert),
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");
413 ok(context->hCertStore == collection, "Unexpected store\n");
414 ok(context->cbCertEncoded == sizeof(bigCert2),
415 "Expected size %d, got %ld\n", sizeof(bigCert2),
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");
423 /* close store2, and check that the collection is unmodified */
424 CertCloseStore(store2, 0);
425 context = CertEnumCertificatesInStore(collection, NULL);
426 ok(context != NULL, "Expected a valid context\n");
429 ok(context->hCertStore == collection, "Unexpected store\n");
430 ok(context->cbCertEncoded == sizeof(bigCert),
431 "Expected size %d, got %ld\n", sizeof(bigCert),
432 context->cbCertEncoded);
433 ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
434 "Unexpected cert\n");
435 context = CertEnumCertificatesInStore(collection, context);
436 ok(context != NULL, "Expected a valid context\n");
439 ok(context->hCertStore == collection, "Unexpected store\n");
440 ok(context->cbCertEncoded == sizeof(bigCert2),
441 "Expected size %d, got %ld\n", sizeof(bigCert2),
442 context->cbCertEncoded);
443 ok(!memcmp(context->pbCertEncoded, bigCert2,
444 context->cbCertEncoded), "Unexpected cert\n");
445 context = CertEnumCertificatesInStore(collection, context);
446 ok(!context, "Unexpected cert\n");
450 /* Adding a collection to a collection is legal */
451 collection2 = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
452 CERT_STORE_CREATE_NEW_FLAG, NULL);
453 ret = CertAddStoreToCollection(collection2, collection,
454 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
455 ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
456 /* check the contents of collection2 */
457 context = CertEnumCertificatesInStore(collection2, NULL);
458 ok(context != NULL, "Expected a valid context\n");
461 ok(context->hCertStore == collection2, "Unexpected store\n");
462 ok(context->cbCertEncoded == sizeof(bigCert),
463 "Expected size %d, got %ld\n", sizeof(bigCert),
464 context->cbCertEncoded);
465 ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
466 "Unexpected cert\n");
467 context = CertEnumCertificatesInStore(collection2, context);
468 ok(context != NULL, "Expected a valid context\n");
471 ok(context->hCertStore == collection2, "Unexpected store\n");
472 ok(context->cbCertEncoded == sizeof(bigCert2),
473 "Expected size %d, got %ld\n", sizeof(bigCert2),
474 context->cbCertEncoded);
475 ok(!memcmp(context->pbCertEncoded, bigCert2,
476 context->cbCertEncoded), "Unexpected cert\n");
477 context = CertEnumCertificatesInStore(collection2, context);
478 ok(!context, "Unexpected cert\n");
482 /* I'd like to test closing the collection in the middle of enumeration,
483 * but my tests have been inconsistent. The first time calling
484 * CertEnumCertificatesInStore on a closed collection succeeded, while the
485 * second crashed. So anything appears to be fair game.
486 * I'd also like to test removing a store from a collection in the middle
487 * of an enumeration, but my tests in Windows have been inconclusive.
488 * In one scenario it worked. In another scenario, about a third of the
489 * time this leads to "random" crashes elsewhere in the code. This
490 * probably means this is not allowed.
493 CertCloseStore(store1, 0);
494 CertCloseStore(collection, 0);
495 CertCloseStore(collection2, 0);
497 /* Add the same cert to two memory stores, then put them in a collection */
498 store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
499 CERT_STORE_CREATE_NEW_FLAG, NULL);
500 ok(store1 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
501 store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
502 CERT_STORE_CREATE_NEW_FLAG, NULL);
503 ok(store2 != 0, "CertOpenStore failed: %08lx\n", GetLastError());
505 ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING,
506 bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
507 ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
508 ret = CertAddEncodedCertificateToStore(store2, X509_ASN_ENCODING,
509 bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
510 ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n", GetLastError());
511 collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
512 CERT_STORE_CREATE_NEW_FLAG, NULL);
513 ok(collection != 0, "CertOpenStore failed: %08lx\n", GetLastError());
515 ret = CertAddStoreToCollection(collection, store1,
516 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
517 ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
518 ret = CertAddStoreToCollection(collection, store2,
519 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
520 ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
522 /* Check that the collection has two copies of the same cert */
523 context = CertEnumCertificatesInStore(collection, NULL);
524 ok(context != NULL, "Expected a valid context\n");
527 ok(context->hCertStore == collection, "Unexpected store\n");
528 ok(context->cbCertEncoded == sizeof(bigCert),
529 "Expected size %d, got %ld\n", sizeof(bigCert),
530 context->cbCertEncoded);
531 ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
532 "Unexpected cert\n");
533 context = CertEnumCertificatesInStore(collection, context);
534 ok(context != NULL, "Expected a valid context\n");
537 ok(context->hCertStore == collection, "Unexpected store\n");
538 ok(context->cbCertEncoded == sizeof(bigCert),
539 "Expected size %d, got %ld\n", sizeof(bigCert),
540 context->cbCertEncoded);
541 ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
542 "Unexpected cert\n");
543 context = CertEnumCertificatesInStore(collection, context);
544 ok(context == NULL, "Unexpected cert\n");
548 /* The following would check whether I can delete an identical cert, rather
549 * than one enumerated from the store. It crashes, so that means I must
550 * only call CertDeleteCertificateFromStore with contexts enumerated from
552 context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
554 ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
558 ret = CertDeleteCertificateFromStore(collection, context);
559 printf("ret is %d, GetLastError is %08lx\n", ret, GetLastError());
560 CertFreeCertificateContext(context);
564 /* Now check deleting from the collection. */
565 context = CertEnumCertificatesInStore(collection, NULL);
566 ok(context != NULL, "Expected a valid context\n");
569 CertDeleteCertificateFromStore(context);
570 /* store1 should now be empty */
571 context = CertEnumCertificatesInStore(store1, NULL);
572 ok(!context, "Unexpected cert\n");
573 /* and there should be one certificate in the collection */
574 context = CertEnumCertificatesInStore(collection, NULL);
575 ok(context != NULL, "Expected a valid cert\n");
578 ok(context->hCertStore == collection, "Unexpected store\n");
579 ok(context->cbCertEncoded == sizeof(bigCert),
580 "Expected size %d, got %ld\n", sizeof(bigCert),
581 context->cbCertEncoded);
582 ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded),
583 "Unexpected cert\n");
585 context = CertEnumCertificatesInStore(collection, context);
586 ok(context == NULL, "Unexpected cert\n");
589 /* Finally, test removing stores from the collection. No return value, so
590 * it's a bit funny to test.
593 CertRemoveStoreFromCollection(NULL, NULL);
595 /* This "succeeds," no crash, no last error set */
596 SetLastError(0xdeadbeef);
597 CertRemoveStoreFromCollection(store2, collection);
598 ok(GetLastError() == 0xdeadbeef,
599 "Didn't expect an error to be set: %08lx\n", GetLastError());
601 /* After removing store2, the collection should be empty */
602 SetLastError(0xdeadbeef);
603 CertRemoveStoreFromCollection(collection, store2);
604 ok(GetLastError() == 0xdeadbeef,
605 "Didn't expect an error to be set: %08lx\n", GetLastError());
606 context = CertEnumCertificatesInStore(collection, NULL);
607 ok(!context, "Unexpected cert\n");
609 CertCloseStore(collection, 0);
610 CertCloseStore(store2, 0);
611 CertCloseStore(store1, 0);
614 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
615 * to its header if found, NULL if not.
617 static const struct CertPropIDHeader *findPropID(const BYTE *buf, DWORD size,
620 const struct CertPropIDHeader *ret = NULL;
623 while (size && !ret && !failed)
625 if (size < sizeof(struct CertPropIDHeader))
629 const struct CertPropIDHeader *hdr =
630 (const struct CertPropIDHeader *)buf;
632 size -= sizeof(struct CertPropIDHeader);
633 buf += sizeof(struct CertPropIDHeader);
636 else if (hdr->propID == propID)
648 typedef DWORD (WINAPI *SHDeleteKeyAFunc)(HKEY, LPCSTR);
650 static void testRegStore(void)
652 static const char tempKey[] = "Software\\Wine\\CryptTemp";
658 store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, NULL);
659 ok(!store && GetLastError() == ERROR_INVALID_HANDLE,
660 "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
661 store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
662 ok(!store && GetLastError() == ERROR_INVALID_HANDLE,
663 "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
665 /* Opening up any old key works.. */
666 key = HKEY_CURRENT_USER;
667 store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
668 /* Not sure if this is a bug in DuplicateHandle, marking todo_wine for now
670 todo_wine ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
671 CertCloseStore(store, 0);
673 rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS,
675 ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
681 static const char certificates[] = "Certificates\\";
682 char subKeyName[sizeof(certificates) + 20 * 2 + 1], *ptr;
684 PCCERT_CONTEXT context;
686 store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key);
687 ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
688 /* Add a certificate. It isn't persisted right away, since it's only
689 * added to the cache..
691 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
692 bigCert2, sizeof(bigCert2), CERT_STORE_ADD_ALWAYS, NULL);
693 ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
695 /* so flush the cache to force a commit.. */
696 ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
697 ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
698 /* and check that the expected subkey was written. */
700 ret = CryptHashCertificate(0, 0, 0, bigCert2, sizeof(bigCert2),
702 ok(ret, "CryptHashCertificate failed: %ld\n", GetLastError());
703 strcpy(subKeyName, certificates);
704 for (i = 0, ptr = subKeyName + sizeof(certificates) - 1; i < size;
706 sprintf(ptr, "%02X", hash[i]);
707 rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
709 ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
715 RegQueryValueExA(subKey, "Blob", NULL, NULL, NULL, &size);
716 buf = HeapAlloc(GetProcessHeap(), 0, size);
719 rc = RegQueryValueExA(subKey, "Blob", NULL, NULL, buf, &size);
720 ok(!rc, "RegQueryValueExA failed: %ld\n", rc);
723 const struct CertPropIDHeader *hdr;
725 /* Both the hash and the cert should be present */
726 hdr = findPropID(buf, size, CERT_CERT_PROP_ID);
727 ok(hdr != NULL, "Expected to find a cert property\n");
730 ok(hdr->cb == sizeof(bigCert2),
731 "Unexpected size %ld of cert property, expected %d\n",
732 hdr->cb, sizeof(bigCert2));
733 ok(!memcmp((BYTE *)hdr + sizeof(*hdr), bigCert2,
734 hdr->cb), "Unexpected cert in cert property\n");
736 hdr = findPropID(buf, size, CERT_HASH_PROP_ID);
737 ok(hdr != NULL, "Expected to find a hash property\n");
740 ok(hdr->cb == sizeof(hash),
741 "Unexpected size %ld of hash property, expected %d\n",
742 hdr->cb, sizeof(hash));
743 ok(!memcmp((BYTE *)hdr + sizeof(*hdr), hash,
744 hdr->cb), "Unexpected hash in cert property\n");
747 HeapFree(GetProcessHeap(), 0, buf);
752 /* Remove the existing context */
753 context = CertEnumCertificatesInStore(store, NULL);
754 ok(context != NULL, "Expected a cert context\n");
756 CertDeleteCertificateFromStore(context);
757 ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
758 ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
760 /* Add a serialized cert with a bogus hash directly to the registry */
761 memset(hash, 0, sizeof(hash));
762 strcpy(subKeyName, certificates);
763 for (i = 0, ptr = subKeyName + sizeof(certificates) - 1;
764 i < sizeof(hash); i++, ptr += 2)
765 sprintf(ptr, "%02X", hash[i]);
766 rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
768 ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
771 BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) +
772 sizeof(bigCert)], *ptr;
774 struct CertPropIDHeader *hdr;
776 hdr = (struct CertPropIDHeader *)buf;
777 hdr->propID = CERT_HASH_PROP_ID;
779 hdr->cb = sizeof(hash);
780 ptr = buf + sizeof(*hdr);
781 memcpy(ptr, hash, sizeof(hash));
783 hdr = (struct CertPropIDHeader *)ptr;
784 hdr->propID = CERT_CERT_PROP_ID;
786 hdr->cb = sizeof(bigCert);
788 memcpy(ptr, bigCert, sizeof(bigCert));
790 rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
792 ok(!rc, "RegSetValueExA failed: %ld\n", rc);
794 ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
795 ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
797 /* Make sure the bogus hash cert gets loaded. */
801 context = CertEnumCertificatesInStore(store, context);
804 } while (context != NULL);
805 ok(certCount == 1, "Expected 1 certificates, got %ld\n", certCount);
810 /* Add another serialized cert directly to the registry, this time
811 * under the correct key name (named with the correct hash value).
814 ret = CryptHashCertificate(0, 0, 0, bigCert2,
815 sizeof(bigCert2), hash, &size);
816 ok(ret, "CryptHashCertificate failed: %ld\n", GetLastError());
817 strcpy(subKeyName, certificates);
818 for (i = 0, ptr = subKeyName + sizeof(certificates) - 1;
819 i < sizeof(hash); i++, ptr += 2)
820 sprintf(ptr, "%02X", hash[i]);
821 rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
823 ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
826 BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) +
827 sizeof(bigCert2)], *ptr;
829 PCCERT_CONTEXT context;
830 struct CertPropIDHeader *hdr;
832 /* First try with a bogus hash... */
833 hdr = (struct CertPropIDHeader *)buf;
834 hdr->propID = CERT_HASH_PROP_ID;
836 hdr->cb = sizeof(hash);
837 ptr = buf + sizeof(*hdr);
838 memset(ptr, 0, sizeof(hash));
840 hdr = (struct CertPropIDHeader *)ptr;
841 hdr->propID = CERT_CERT_PROP_ID;
843 hdr->cb = sizeof(bigCert2);
845 memcpy(ptr, bigCert2, sizeof(bigCert2));
847 rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
849 ok(!rc, "RegSetValueExA failed: %ld\n", rc);
851 ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
852 ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
854 /* and make sure just one cert still gets loaded. */
858 context = CertEnumCertificatesInStore(store, context);
861 } while (context != NULL);
862 ok(certCount == 1, "Expected 1 certificates, got %ld\n", certCount);
864 /* Try again with the correct hash... */
865 ptr = buf + sizeof(*hdr);
866 memcpy(ptr, hash, sizeof(hash));
868 rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf,
870 ok(!rc, "RegSetValueExA failed: %ld\n", rc);
872 ret = CertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL);
873 ok(ret, "CertControlStore failed: %08lx\n", GetLastError());
875 /* and make sure two certs get loaded. */
879 context = CertEnumCertificatesInStore(store, context);
882 } while (context != NULL);
883 ok(certCount == 2, "Expected 2 certificates, got %ld\n", certCount);
887 CertCloseStore(store, 0);
888 /* Is delete allowed on a reg store? */
889 store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0,
890 CERT_STORE_DELETE_FLAG, key);
891 ok(store == NULL, "Expected NULL return from CERT_STORE_DELETE_FLAG\n");
892 ok(GetLastError() == 0, "CertOpenStore failed: %08lx\n",
897 /* The CertOpenStore with CERT_STORE_DELETE_FLAG above will delete the
898 * contents of the key, but not the key itself.
900 rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS,
902 ok(!rc, "RegCreateKeyExA failed: %ld\n", rc);
903 ok(disp == REG_OPENED_EXISTING_KEY,
904 "Expected REG_OPENED_EXISTING_KEY, got %ld\n", disp);
908 rc = RegDeleteKeyA(HKEY_CURRENT_USER, tempKey);
911 HMODULE shlwapi = LoadLibraryA("shlwapi");
913 /* Use shlwapi's SHDeleteKeyA to _really_ blow away the key,
914 * otherwise subsequent tests will fail.
918 SHDeleteKeyAFunc pSHDeleteKeyA =
919 (SHDeleteKeyAFunc)GetProcAddress(shlwapi, "SHDeleteKeyA");
922 pSHDeleteKeyA(HKEY_CURRENT_USER, tempKey);
923 FreeLibrary(shlwapi);
929 static const char MyA[] = { 'M','y',0,0 };
930 static const WCHAR MyW[] = { 'M','y',0 };
931 static const WCHAR BogusW[] = { 'B','o','g','u','s',0 };
932 static const WCHAR BogusPathW[] = { 'S','o','f','t','w','a','r','e','\\',
933 'M','i','c','r','o','s','o','f','t','\\','S','y','s','t','e','m','C','e','r',
934 't','i','f','i','c','a','t','e','s','\\','B','o','g','u','s',0 };
936 static void testSystemRegStore(void)
938 HCERTSTORE store, memStore;
940 /* Check with a UNICODE name */
941 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
942 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW);
943 /* Not all OSes support CERT_STORE_PROV_SYSTEM_REGISTRY, so don't continue
944 * testing if they don't.
949 /* Check that it isn't a collection store */
950 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
951 CERT_STORE_CREATE_NEW_FLAG, NULL);
954 BOOL ret = CertAddStoreToCollection(store, memStore, 0, 0);
956 ok(!ret && GetLastError() ==
957 HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
958 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
960 CertCloseStore(memStore, 0);
962 CertCloseStore(store, 0);
964 /* Check opening a bogus store */
965 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
966 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW);
967 ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
968 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
969 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
970 CERT_SYSTEM_STORE_CURRENT_USER, BogusW);
971 ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
973 CertCloseStore(store, 0);
974 /* Now check whether deleting is allowed */
975 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
976 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
977 RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
979 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, 0, NULL);
980 ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
981 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
983 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
984 CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA);
985 ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
986 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
988 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
989 CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW);
990 ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
991 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
993 /* The name is expected to be UNICODE, check with an ASCII name */
994 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0,
995 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA);
996 ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
997 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1000 static void testSystemStore(void)
1002 static const WCHAR baskslashW[] = { '\\',0 };
1004 WCHAR keyName[MAX_PATH];
1008 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, 0, NULL);
1009 ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1010 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1011 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1012 CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA);
1013 ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1014 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1015 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1016 CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW);
1017 ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1018 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1019 /* The name is expected to be UNICODE, first check with an ASCII name */
1020 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1021 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA);
1022 ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1023 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1024 /* Create the expected key */
1025 lstrcpyW(keyName, CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH);
1026 lstrcatW(keyName, baskslashW);
1027 lstrcatW(keyName, MyW);
1028 rc = RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ,
1030 ok(!rc, "RegCreateKeyEx failed: %ld\n", rc);
1033 /* Check opening with a UNICODE name, specifying the create new flag */
1034 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1035 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_CREATE_NEW_FLAG, MyW);
1036 ok(!store && GetLastError() == ERROR_FILE_EXISTS,
1037 "Expected ERROR_FILE_EXISTS, got %08lx\n", GetLastError());
1038 /* Now check opening with a UNICODE name, this time opening existing */
1039 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1040 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW);
1041 ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1044 HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1045 CERT_STORE_CREATE_NEW_FLAG, NULL);
1047 /* Check that it's a collection store */
1050 BOOL ret = CertAddStoreToCollection(store, memStore, 0, 0);
1052 /* FIXME: this'll fail on NT4, but what error will it give? */
1053 ok(ret, "CertAddStoreToCollection failed: %08lx\n", GetLastError());
1054 CertCloseStore(memStore, 0);
1056 CertCloseStore(store, 0);
1059 /* Check opening a bogus store */
1060 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1061 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW);
1062 ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND,
1063 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1064 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1065 CERT_SYSTEM_STORE_CURRENT_USER, BogusW);
1066 ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1068 CertCloseStore(store, 0);
1069 /* Now check whether deleting is allowed */
1070 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1071 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
1072 RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
1075 static void testCertOpenSystemStore(void)
1079 store = CertOpenSystemStoreW(0, NULL);
1080 ok(!store && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1081 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1083 /* This succeeds, and on WinXP at least, the Bogus key is created under
1084 * HKCU (but not under HKLM, even when run as an administrator.)
1086 store = CertOpenSystemStoreW(0, BogusW);
1087 ok(store != 0, "CertOpenSystemStore failed: %08lx\n", GetLastError());
1089 CertCloseStore(store, 0);
1090 /* Delete it so other tests succeed next time around */
1091 store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
1092 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW);
1093 RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
1096 static void checkHash(const BYTE *data, DWORD dataLen, ALG_ID algID,
1097 PCCERT_CONTEXT context, DWORD propID)
1099 BYTE hash[20] = { 0 }, hashProperty[20];
1103 memset(hash, 0, sizeof(hash));
1104 memset(hashProperty, 0, sizeof(hashProperty));
1105 size = sizeof(hash);
1106 ret = CryptHashCertificate(0, algID, 0, data, dataLen, hash, &size);
1107 ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1108 ret = CertGetCertificateContextProperty(context, propID, hashProperty,
1110 ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1112 ok(!memcmp(hash, hashProperty, size), "Unexpected hash for property %ld\n",
1116 static void testCertProperties(void)
1118 PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING,
1119 bigCert, sizeof(bigCert));
1121 ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
1125 DWORD propID, numProps, access, size;
1127 BYTE hash[20] = { 0 }, hashProperty[20];
1128 CRYPT_DATA_BLOB blob;
1131 propID = CertEnumCertificateContextProperties(NULL, 0);
1137 propID = CertEnumCertificateContextProperties(context, propID);
1140 } while (propID != 0);
1141 ok(numProps == 0, "Expected 0 properties, got %ld\n", numProps);
1143 /* Tests with a NULL cert context. Prop ID 0 fails.. */
1144 ret = CertSetCertificateContextProperty(NULL, 0, 0, NULL);
1145 ok(!ret && GetLastError() ==
1146 HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1147 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1149 /* while this just crashes.
1150 ret = CertSetCertificateContextProperty(NULL,
1151 CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
1154 ret = CertSetCertificateContextProperty(context, 0, 0, NULL);
1155 ok(!ret && GetLastError() ==
1156 HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1157 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1159 /* Can't set the cert property directly, this crashes.
1160 ret = CertSetCertificateContextProperty(context,
1161 CERT_CERT_PROP_ID, 0, bigCert2);
1165 ret = CertGetCertificateContextProperty(context,
1166 CERT_ACCESS_STATE_PROP_ID, 0, NULL);
1167 ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1169 ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1170 hashProperty, NULL);
1172 /* A missing prop */
1174 ret = CertGetCertificateContextProperty(context,
1175 CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
1176 ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
1177 "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
1178 /* And, an implicit property */
1179 size = sizeof(access);
1180 ret = CertGetCertificateContextProperty(context,
1181 CERT_ACCESS_STATE_PROP_ID, &access, &size);
1182 ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1184 ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG),
1185 "Didn't expect a persisted cert\n");
1186 /* Trying to set this "read only" property crashes.
1187 access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1188 ret = CertSetCertificateContextProperty(context,
1189 CERT_ACCESS_STATE_PROP_ID, 0, &access);
1192 /* Can I set the hash to an invalid hash? */
1194 blob.cbData = sizeof(hash);
1195 ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1197 ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1199 size = sizeof(hashProperty);
1200 ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1201 hashProperty, &size);
1202 ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n");
1203 /* Delete the (bogus) hash, and get the real one */
1204 ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
1206 ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
1208 checkHash(bigCert, sizeof(bigCert), CALG_SHA1, context,
1211 /* Now that the hash property is set, we should get one property when
1217 propID = CertEnumCertificateContextProperties(context, propID);
1220 } while (propID != 0);
1221 ok(numProps == 1, "Expected 1 properties, got %ld\n", numProps);
1223 /* Check a few other implicit properties */
1224 checkHash(bigCert, sizeof(bigCert), CALG_MD5, context,
1225 CERT_MD5_HASH_PROP_ID);
1227 context->pCertInfo->Subject.pbData,
1228 context->pCertInfo->Subject.cbData,
1229 CALG_MD5, context, CERT_SUBJECT_NAME_MD5_HASH_PROP_ID);
1231 context->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
1232 context->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
1233 CALG_MD5, context, CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID);
1235 /* Odd: this doesn't fail on other certificates, so there must be
1236 * something weird about this cert that causes it to fail.
1239 ret = CertGetCertificateContextProperty(context,
1240 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1241 todo_wine ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1242 "Expected ERROR_INVALID_DATA, got %08lx\n", GetLastError());
1244 CertFreeCertificateContext(context);
1248 static void testAddSerialized(void)
1252 BYTE buf[sizeof(struct CertPropIDHeader) * 2 + 20 + sizeof(bigCert)] =
1255 struct CertPropIDHeader *hdr;
1256 PCCERT_CONTEXT context;
1258 ret = CertAddSerializedElementToStore(0, NULL, 0, 0, 0, 0, NULL, NULL);
1259 ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1260 "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1262 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1263 CERT_STORE_CREATE_NEW_FLAG, NULL);
1264 ok(store != 0, "CertOpenStore failed: %08lx\n", GetLastError());
1266 ret = CertAddSerializedElementToStore(store, NULL, 0, 0, 0, 0, NULL, NULL);
1267 ok(!ret && GetLastError() == ERROR_END_OF_MEDIA,
1268 "Expected ERROR_END_OF_MEDIA, got %08lx\n", GetLastError());
1270 /* Test with an empty property */
1271 hdr = (struct CertPropIDHeader *)buf;
1272 hdr->propID = CERT_CERT_PROP_ID;
1275 ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1277 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1278 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1280 /* Test with a bad size in property header */
1281 hdr->cb = sizeof(bigCert) - 1;
1282 memcpy(buf + sizeof(struct CertPropIDHeader), bigCert, sizeof(bigCert));
1283 ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1285 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1286 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1288 ret = CertAddSerializedElementToStore(store, buf,
1289 sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 0, NULL,
1291 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1292 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1294 ret = CertAddSerializedElementToStore(store, buf,
1295 sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1297 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1298 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1300 /* Kosher size in property header, but no context type */
1301 hdr->cb = sizeof(bigCert);
1302 ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0,
1304 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1305 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1307 ret = CertAddSerializedElementToStore(store, buf,
1308 sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 0, NULL,
1310 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1311 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1313 ret = CertAddSerializedElementToStore(store, buf,
1314 sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1316 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1317 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1319 /* With a bad context type */
1320 ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0,
1321 CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1322 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1323 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1325 ret = CertAddSerializedElementToStore(store, buf,
1326 sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0,
1327 CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1328 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1329 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1331 ret = CertAddSerializedElementToStore(store, buf,
1332 sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1333 0, CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL);
1334 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1335 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1337 /* Bad unknown field, good type */
1339 ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0,
1340 CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1341 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1342 "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1343 ret = CertAddSerializedElementToStore(store, buf,
1344 sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0,
1345 CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1346 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1347 "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1348 ret = CertAddSerializedElementToStore(store, buf,
1349 sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1350 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1351 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1352 "Expected ERROR_FILE_NOT_FOUND got %08lx\n", GetLastError());
1353 /* Most everything okay, but bad add disposition */
1356 ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0,
1357 CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1359 ret = CertAddSerializedElementToStore(store, buf,
1360 sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0,
1361 CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1363 /* Everything okay, but buffer's too big */
1364 ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1365 CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1366 ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1367 /* Everything okay, check it's not re-added */
1368 ret = CertAddSerializedElementToStore(store, buf,
1369 sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW,
1370 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL);
1371 ok(!ret && GetLastError() == CRYPT_E_EXISTS,
1372 "Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
1374 context = CertEnumCertificatesInStore(store, NULL);
1375 ok(context != NULL, "Expected a cert\n");
1377 CertDeleteCertificateFromStore(context);
1379 /* Try adding with a bogus hash. Oddly enough, it succeeds, and the hash,
1380 * when queried, is the real hash rather than the bogus hash.
1382 hdr = (struct CertPropIDHeader *)(buf + sizeof(struct CertPropIDHeader) +
1384 hdr->propID = CERT_HASH_PROP_ID;
1386 hdr->cb = sizeof(hash);
1387 memset(hash, 0xc, sizeof(hash));
1388 memcpy((LPBYTE)hdr + sizeof(struct CertPropIDHeader), hash, sizeof(hash));
1389 ret = CertAddSerializedElementToStore(store, buf, sizeof(buf),
1390 CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL,
1391 (const void **)&context);
1392 ok(ret, "CertAddSerializedElementToStore failed: %08lx\n", GetLastError());
1395 BYTE hashVal[20], realHash[20];
1396 DWORD size = sizeof(hashVal);
1398 ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert),
1400 ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
1401 ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
1403 ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1405 ok(!memcmp(hashVal, realHash, size), "Unexpected hash\n");
1406 CertFreeCertificateContext(context);
1409 CertCloseStore(store, 0);
1416 /* various combinations of CertOpenStore */
1418 testCollectionStore();
1420 testSystemRegStore();
1423 testCertOpenSystemStore();
1425 testCertProperties();
1426 testAddSerialized();