23e4a3c178fe16159514b674fd236982c02fe3b7
[reactos.git] / reactos / lib / crypt32 / cert.c
1 /*
2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2004,2005 Juan Lang
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * FIXME:
20 * - As you can see in the stubs below, support for CRLs and CTLs is missing.
21 * Mostly this should be copy-paste work, and some code (e.g. extended
22 * properties) could be shared between them.
23 * - Opening a cert store provider should be morphed to support loading
24 * external DLLs.
25 * - The concept of physical stores and locations isn't implemented. (This
26 * doesn't mean registry stores et al aren't implemented. See the PSDK for
27 * registering and enumerating physical stores and locations.)
28 * - Many flags, options and whatnot are unimplemented.
29 */
30 #include <assert.h>
31 #include <stdarg.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "winreg.h"
36 #include "winuser.h"
37 #include "wincrypt.h"
38 #include "wine/debug.h"
39 #include "wine/list.h"
40 #include "excpt.h"
41 #include "wine/exception.h"
42 #include "crypt32_private.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
45
46 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
47 /* The following aren't defined in wincrypt.h, as they're "reserved" */
48 #define CERT_CERT_PROP_ID 32
49 #define CERT_CRL_PROP_ID 33
50 #define CERT_CTL_PROP_ID 34
51
52 /* Some typedefs that make it easier to abstract which type of context we're
53 * working with.
54 */
55 typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType,
56 const BYTE *pbCertEncoded, DWORD cbCertEncoded);
57 typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore,
58 const void *context, DWORD dwAddDisposition, const void **ppStoreContext);
59 typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore,
60 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
61 DWORD dwAddDisposition, const void **ppContext);
62 typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore,
63 const void *pPrevContext);
64 typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context,
65 DWORD dwPropID, void *pvData, DWORD *pcbData);
66 typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context,
67 DWORD dwPropID, DWORD dwFlags, const void *pvData);
68 typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags,
69 BYTE *pbElement, DWORD *pcbElement);
70 typedef BOOL (WINAPI *FreeContextFunc)(const void *context);
71 typedef BOOL (WINAPI *DeleteContextFunc)(const void *context);
72
73 /* An abstract context (certificate, CRL, or CTL) interface */
74 typedef struct _WINE_CONTEXT_INTERFACE
75 {
76 CreateContextFunc create;
77 AddContextToStoreFunc addContextToStore;
78 AddEncodedContextToStoreFunc addEncodedToStore;
79 EnumContextsInStoreFunc enumContextsInStore;
80 GetContextPropertyFunc getProp;
81 SetContextPropertyFunc setProp;
82 SerializeElementFunc serialize;
83 FreeContextFunc free;
84 DeleteContextFunc deleteFromStore;
85 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
86
87 static const WINE_CONTEXT_INTERFACE gCertInterface = {
88 (CreateContextFunc)CertCreateCertificateContext,
89 (AddContextToStoreFunc)CertAddCertificateContextToStore,
90 (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
91 (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
92 (GetContextPropertyFunc)CertGetCertificateContextProperty,
93 (SetContextPropertyFunc)CertSetCertificateContextProperty,
94 (SerializeElementFunc)CertSerializeCertificateStoreElement,
95 (FreeContextFunc)CertFreeCertificateContext,
96 (DeleteContextFunc)CertDeleteCertificateFromStore,
97 };
98
99 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
100 (CreateContextFunc)CertCreateCRLContext,
101 (AddContextToStoreFunc)CertAddCRLContextToStore,
102 (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
103 (EnumContextsInStoreFunc)CertEnumCRLsInStore,
104 (GetContextPropertyFunc)CertGetCRLContextProperty,
105 (SetContextPropertyFunc)CertSetCRLContextProperty,
106 (SerializeElementFunc)CertSerializeCRLStoreElement,
107 (FreeContextFunc)CertFreeCRLContext,
108 (DeleteContextFunc)CertDeleteCRLFromStore,
109 };
110
111 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
112 (CreateContextFunc)CertCreateCTLContext,
113 (AddContextToStoreFunc)CertAddCTLContextToStore,
114 (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
115 (EnumContextsInStoreFunc)CertEnumCTLsInStore,
116 (GetContextPropertyFunc)CertGetCTLContextProperty,
117 (SetContextPropertyFunc)CertSetCTLContextProperty,
118 (SerializeElementFunc)CertSerializeCTLStoreElement,
119 (FreeContextFunc)CertFreeCTLContext,
120 (DeleteContextFunc)CertDeleteCTLFromStore,
121 };
122
123 struct WINE_CRYPTCERTSTORE;
124
125 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
126 DWORD dwFlags, const void *pvPara);
127
128 struct _WINE_CERT_CONTEXT_REF;
129
130 /* Called to enumerate the next certificate in a store. The returned pointer
131 * must be newly allocated (via CryptMemAlloc): CertFreeCertificateContext
132 * frees it.
133 */
134 typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc)
135 (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev);
136
137 struct _WINE_CERT_CONTEXT;
138
139 /* Called to create a new reference to an existing cert context. Should call
140 * CRYPT_InitCertRef to make sure the reference count is properly updated.
141 * If the store does not provide any additional allocated data (that is, does
142 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
143 * this.
144 */
145 typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc)
146 (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store);
147
148 /* Optional, called when a cert context reference is being freed. Don't free
149 * the ref pointer itself, CertFreeCertificateContext does that.
150 */
151 typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref);
152
153 typedef enum _CertStoreType {
154 StoreTypeMem,
155 StoreTypeCollection,
156 StoreTypeReg,
157 StoreTypeDummy,
158 } CertStoreType;
159
160 /* A cert store is polymorphic through the use of function pointers. A type
161 * is still needed to distinguish collection stores from other types.
162 * On the function pointers:
163 * - closeStore is called when the store's ref count becomes 0
164 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
165 * - control is optional, but should be implemented by any store that supports
166 * persistence
167 */
168 typedef struct WINE_CRYPTCERTSTORE
169 {
170 DWORD dwMagic;
171 LONG ref;
172 DWORD dwOpenFlags;
173 HCRYPTPROV cryptProv;
174 CertStoreType type;
175 PFN_CERT_STORE_PROV_CLOSE closeStore;
176 PFN_CERT_STORE_PROV_WRITE_CERT addCert;
177 CreateRefFunc createCertRef;
178 EnumCertFunc enumCert;
179 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
180 FreeCertFunc freeCert; /* optional */
181 PFN_CERT_STORE_PROV_CONTROL control; /* optional */
182 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
183
184 /* A certificate context has pointers to data that are owned by this module,
185 * so rather than duplicate the data every time a certificate context is
186 * copied, I keep a reference count to the data. Thus I have two data
187 * structures, the "true" certificate context (that has the reference count)
188 * and a reference certificate context, that has a pointer to the true context.
189 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
190 * with the reference version.
191 */
192 typedef struct _WINE_CERT_CONTEXT
193 {
194 CERT_CONTEXT cert;
195 LONG ref;
196 CRITICAL_SECTION cs;
197 struct list extendedProperties;
198 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
199
200 typedef struct _WINE_CERT_CONTEXT_REF
201 {
202 CERT_CONTEXT cert;
203 WINE_CERT_CONTEXT *context;
204 } WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF;
205
206 /* An extended certificate property in serialized form is prefixed by this
207 * header.
208 */
209 typedef struct _WINE_CERT_PROP_HEADER
210 {
211 DWORD propID;
212 DWORD unknown; /* always 1 */
213 DWORD cb;
214 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
215
216 /* Stores an extended property in a cert. */
217 typedef struct _WINE_CERT_PROPERTY
218 {
219 WINE_CERT_PROP_HEADER hdr;
220 LPBYTE pbData;
221 struct list entry;
222 } WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY;
223
224 /* A mem store has a list of these. They're also returned by the mem store
225 * during enumeration.
226 */
227 typedef struct _WINE_CERT_LIST_ENTRY
228 {
229 WINE_CERT_CONTEXT_REF cert;
230 struct list entry;
231 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
232
233 typedef struct _WINE_MEMSTORE
234 {
235 WINECRYPT_CERTSTORE hdr;
236 CRITICAL_SECTION cs;
237 struct list certs;
238 } WINE_MEMSTORE, *PWINE_MEMSTORE;
239
240 typedef struct _WINE_HASH_TO_DELETE
241 {
242 BYTE hash[20];
243 struct list entry;
244 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
245
246 /* Returned by a reg store during enumeration. */
247 typedef struct _WINE_REG_CERT_CONTEXT
248 {
249 WINE_CERT_CONTEXT_REF cert;
250 PWINE_CERT_CONTEXT_REF childContext;
251 } WINE_REG_CERT_CONTEXT, *PWINE_REG_CERT_CONTEXT;
252
253 typedef struct _WINE_REGSTORE
254 {
255 WINECRYPT_CERTSTORE hdr;
256 PWINECRYPT_CERTSTORE memStore;
257 HKEY key;
258 BOOL dirty;
259 CRITICAL_SECTION cs;
260 struct list certsToDelete;
261 } WINE_REGSTORE, *PWINE_REGSTORE;
262
263 typedef struct _WINE_STORE_LIST_ENTRY
264 {
265 PWINECRYPT_CERTSTORE store;
266 DWORD dwUpdateFlags;
267 DWORD dwPriority;
268 struct list entry;
269 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
270
271 /* Returned by a collection store during enumeration.
272 * Note: relies on the list entry being valid after use, which a number of
273 * conditions might make untrue (reentrancy, closing a collection store before
274 * continuing an enumeration on it, ...). The tests seem to indicate this
275 * sort of unsafety is okay, since Windows isn't well-behaved in these
276 * scenarios either.
277 */
278 typedef struct _WINE_COLLECTION_CERT_CONTEXT
279 {
280 WINE_CERT_CONTEXT_REF cert;
281 PWINE_STORE_LIST_ENTRY entry;
282 PWINE_CERT_CONTEXT_REF childContext;
283 } WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT;
284
285 typedef struct _WINE_COLLECTIONSTORE
286 {
287 WINECRYPT_CERTSTORE hdr;
288 CRITICAL_SECTION cs;
289 struct list stores;
290 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
291
292 /* Like CertGetCertificateContextProperty, but operates directly on the
293 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
294 * are handled by CertGetCertificateContextProperty, and are particular to the
295 * store in which the property exists (which is separate from the context.)
296 */
297 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
298 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
299
300 /* Like CertSetCertificateContextProperty, but operates directly on the
301 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
302 * CertSetCertificateContextProperty anyway.
303 */
304 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
305 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData);
306
307 /* Helper function for store reading functions and
308 * CertAddSerializedElementToStore. Returns a context of the appropriate type
309 * if it can, or NULL otherwise. Doesn't validate any of the properties in
310 * the serialized context (for example, bad hashes are retained.)
311 * *pdwContentType is set to the type of the returned context.
312 */
313 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
314 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
315
316 /* filter for page-fault exceptions */
317 static WINE_EXCEPTION_FILTER(page_fault)
318 {
319 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
320 return EXCEPTION_EXECUTE_HANDLER;
321 return EXCEPTION_CONTINUE_SEARCH;
322 }
323
324 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
325 DWORD dwFlags, CertStoreType type)
326 {
327 store->ref = 1;
328 store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
329 store->type = type;
330 if (!hCryptProv)
331 {
332 hCryptProv = CRYPT_GetDefaultProvider();
333 dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
334 }
335 store->cryptProv = hCryptProv;
336 store->dwOpenFlags = dwFlags;
337 }
338
339 /* Initializes the reference ref to point to pCertContext, which is assumed to
340 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
341 * Also sets the hCertStore member of the reference to store.
342 */
343 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
344 PWINE_CERT_CONTEXT context, HCERTSTORE store)
345 {
346 TRACE("(%p, %p)\n", ref, context);
347 memcpy(&ref->cert, context, sizeof(ref->cert));
348 ref->context = context;
349 InterlockedIncrement(&context->ref);
350 TRACE("%p's ref count is %ld\n", context, context->ref);
351 ref->cert.hCertStore = store;
352 }
353
354 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
355 HCERTSTORE store)
356 {
357 PWINE_CERT_CONTEXT_REF pCertRef = CryptMemAlloc(
358 sizeof(WINE_CERT_CONTEXT_REF));
359
360 TRACE("(%p, %p)\n", context, store);
361 if (pCertRef)
362 CRYPT_InitCertRef(pCertRef, context, store);
363 return pCertRef;
364 }
365
366 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
367 DWORD dwAddDisposition)
368 {
369 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
370 BOOL add = FALSE, ret;
371
372 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
373
374 switch (dwAddDisposition)
375 {
376 case CERT_STORE_ADD_ALWAYS:
377 add = TRUE;
378 break;
379 case CERT_STORE_ADD_NEW:
380 {
381 BYTE hashToAdd[20], hash[20];
382 DWORD size = sizeof(hashToAdd);
383
384 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
385 CERT_HASH_PROP_ID, hashToAdd, &size);
386 if (ret)
387 {
388 PWINE_CERT_LIST_ENTRY cursor;
389
390 /* Add if no cert with the same hash is found. */
391 add = TRUE;
392 EnterCriticalSection(&ms->cs);
393 LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
394 {
395 size = sizeof(hash);
396 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
397 CERT_HASH_PROP_ID, hash, &size);
398 if (ret && !memcmp(hashToAdd, hash, size))
399 {
400 TRACE("found matching certificate, not adding\n");
401 SetLastError(CRYPT_E_EXISTS);
402 add = FALSE;
403 break;
404 }
405 }
406 LeaveCriticalSection(&ms->cs);
407 }
408 break;
409 }
410 case CERT_STORE_ADD_REPLACE_EXISTING:
411 {
412 BYTE hashToAdd[20], hash[20];
413 DWORD size = sizeof(hashToAdd);
414
415 add = TRUE;
416 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
417 CERT_HASH_PROP_ID, hashToAdd, &size);
418 if (ret)
419 {
420 PWINE_CERT_LIST_ENTRY cursor, next;
421
422 /* Look for existing cert to delete */
423 EnterCriticalSection(&ms->cs);
424 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs,
425 WINE_CERT_LIST_ENTRY, entry)
426 {
427 size = sizeof(hash);
428 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
429 CERT_HASH_PROP_ID, hash, &size);
430 if (ret && !memcmp(hashToAdd, hash, size))
431 {
432 TRACE("found matching certificate, replacing\n");
433 list_remove(&cursor->entry);
434 CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
435 break;
436 }
437 }
438 LeaveCriticalSection(&ms->cs);
439 }
440 break;
441 }
442 default:
443 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
444 add = FALSE;
445 }
446 if (add)
447 {
448 PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc(
449 sizeof(WINE_CERT_LIST_ENTRY));
450
451 if (entry)
452 {
453 TRACE("adding %p\n", entry);
454 CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store);
455 list_init(&entry->entry);
456 EnterCriticalSection(&ms->cs);
457 list_add_tail(&ms->certs, &entry->entry);
458 LeaveCriticalSection(&ms->cs);
459 ret = TRUE;
460 }
461 else
462 ret = FALSE;
463 }
464 else
465 ret = FALSE;
466 TRACE("returning %d\n", ret);
467 return ret;
468 }
469
470 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
471 PWINE_CERT_CONTEXT_REF pPrev)
472 {
473 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
474 PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
475 struct list *listNext;
476
477 TRACE("(%p, %p)\n", store, pPrev);
478 EnterCriticalSection(&ms->cs);
479 if (prevEntry)
480 {
481 listNext = list_next(&ms->certs, &prevEntry->entry);
482 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
483 }
484 else
485 listNext = list_next(&ms->certs, &ms->certs);
486 if (listNext)
487 {
488 ret = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY));
489 if (ret)
490 {
491 memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
492 sizeof(WINE_CERT_LIST_ENTRY));
493 InterlockedIncrement(&ret->cert.context->ref);
494 }
495 }
496 else
497 {
498 SetLastError(CRYPT_E_NOT_FOUND);
499 ret = NULL;
500 }
501 LeaveCriticalSection(&ms->cs);
502
503 TRACE("returning %p\n", ret);
504 return (PWINE_CERT_CONTEXT_REF)ret;
505 }
506
507 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref);
508
509 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
510 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
511 {
512 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
513 WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
514 PWINE_CERT_LIST_ENTRY cert, next;
515 BOOL ret = TRUE;
516
517 /* Find the entry associated with the passed-in context, since the
518 * passed-in context may not be a list entry itself (e.g. if it came from
519 * CertDuplicateCertificateContext.) Pointing to the same context is
520 * a sufficient test of equality.
521 */
522 EnterCriticalSection(&store->cs);
523 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
524 entry)
525 {
526 if (cert->cert.context == ref->context)
527 {
528 TRACE("removing %p\n", cert);
529 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
530 * protected.
531 */
532 list_remove(&cert->entry);
533 /* FIXME: generally I should do the following, otherwise there is
534 * a memory leak. But doing so when called by
535 * CertDeleteCertificateFromStore results in a double free, so
536 * leaving commented for now.
537 ret = CertFreeCertificateContext((PCCERT_CONTEXT)cert);
538 */
539 cert->entry.prev = cert->entry.next = &store->certs;
540 break;
541 }
542 }
543 LeaveCriticalSection(&store->cs);
544 return ret;
545 }
546
547 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
548 {
549 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
550 PWINE_CERT_LIST_ENTRY cert, next;
551
552 TRACE("(%p, %08lx)\n", store, dwFlags);
553 if (dwFlags)
554 FIXME("Unimplemented flags: %08lx\n", dwFlags);
555
556 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
557 * pointer if its ref-count reaches zero. That's okay here because there
558 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
559 * of the CertListEntry.
560 */
561 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
562 entry)
563 {
564 TRACE("removing %p\n", cert);
565 list_remove(&cert->entry);
566 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
567 }
568 DeleteCriticalSection(&store->cs);
569 CryptMemFree(store);
570 }
571
572 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
573 DWORD dwFlags, const void *pvPara)
574 {
575 PWINE_MEMSTORE store;
576
577 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
578
579 if (dwFlags & CERT_STORE_DELETE_FLAG)
580 {
581 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
582 store = NULL;
583 }
584 else
585 {
586 store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
587 if (store)
588 {
589 memset(store, 0, sizeof(WINE_MEMSTORE));
590 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
591 store->hdr.closeStore = CRYPT_MemCloseStore;
592 store->hdr.addCert = CRYPT_MemAddCert;
593 store->hdr.createCertRef = CRYPT_CreateCertRef;
594 store->hdr.enumCert = CRYPT_MemEnumCert;
595 store->hdr.deleteCert = CRYPT_MemDeleteCert;
596 store->hdr.freeCert = NULL;
597 InitializeCriticalSection(&store->cs);
598 list_init(&store->certs);
599 }
600 }
601 return (PWINECRYPT_CERTSTORE)store;
602 }
603
604 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
605 PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
606 {
607 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
608 PWINE_STORE_LIST_ENTRY entry, next;
609 BOOL ret;
610
611 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
612
613 ret = FALSE;
614 EnterCriticalSection(&cs->cs);
615 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
616 entry)
617 {
618 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
619 {
620 ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
621 break;
622 }
623 }
624 LeaveCriticalSection(&cs->cs);
625 SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
626 return ret;
627 }
628
629 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
630 PWINE_CERT_CONTEXT context, HCERTSTORE store)
631 {
632 PWINE_COLLECTION_CERT_CONTEXT ret = CryptMemAlloc(
633 sizeof(WINE_COLLECTION_CERT_CONTEXT));
634
635 if (ret)
636 {
637 /* Initialize to empty for now, just make sure the size is right */
638 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
639 ret->entry = NULL;
640 ret->childContext = NULL;
641 }
642 return (PWINE_CERT_CONTEXT_REF)ret;
643 }
644
645 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
646 {
647 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
648 PWINE_STORE_LIST_ENTRY entry, next;
649
650 TRACE("(%p, %08lx)\n", store, dwFlags);
651
652 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
653 entry)
654 {
655 TRACE("closing %p\n", entry);
656 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
657 CryptMemFree(entry);
658 }
659 DeleteCriticalSection(&cs->cs);
660 CryptMemFree(cs);
661 }
662
663 /* Advances a collection enumeration by one cert, if possible, where advancing
664 * means:
665 * - calling the current store's enumeration function once, and returning
666 * the enumerated cert if one is returned
667 * - moving to the next store if the current store has no more items, and
668 * recursively calling itself to get the next item.
669 * Returns NULL if the collection contains no more items or on error.
670 * Assumes the collection store's lock is held.
671 */
672 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
673 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
674 PWINE_COLLECTION_CERT_CONTEXT pPrev)
675 {
676 PWINE_COLLECTION_CERT_CONTEXT ret;
677 PWINE_CERT_CONTEXT_REF child;
678 struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
679
680 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
681
682 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
683 pPrev ? pPrev->childContext : NULL);
684 if (pPrev)
685 {
686 pPrev->childContext = NULL;
687 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
688 pPrev = NULL;
689 }
690 if (child)
691 {
692 ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
693 child->context, store);
694 if (ret)
695 {
696 ret->entry = storeEntry;
697 ret->childContext = child;
698 }
699 else
700 CertFreeCertificateContext((PCCERT_CONTEXT)child);
701 }
702 else
703 {
704 if (storeNext)
705 {
706 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
707 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
708 }
709 else
710 {
711 SetLastError(CRYPT_E_NOT_FOUND);
712 ret = NULL;
713 }
714 }
715 TRACE("returning %p\n", ret);
716 return ret;
717 }
718
719 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
720 PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
721 {
722 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
723 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
724 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
725
726 TRACE("(%p, %p)\n", store, pPrev);
727
728 if (prevEntry)
729 {
730 EnterCriticalSection(&cs->cs);
731 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
732 LeaveCriticalSection(&cs->cs);
733 }
734 else
735 {
736 EnterCriticalSection(&cs->cs);
737 if (!list_empty(&cs->stores))
738 {
739 PWINE_STORE_LIST_ENTRY storeEntry;
740
741 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
742 entry);
743 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
744 }
745 else
746 {
747 SetLastError(CRYPT_E_NOT_FOUND);
748 ret = NULL;
749 }
750 LeaveCriticalSection(&cs->cs);
751 }
752 TRACE("returning %p\n", ret);
753 return (PWINE_CERT_CONTEXT_REF)ret;
754 }
755
756 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
757 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
758 {
759 PWINE_COLLECTION_CERT_CONTEXT context =
760 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
761 BOOL ret;
762
763 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
764
765 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
766 if (ret)
767 context->childContext = NULL;
768 return ret;
769 }
770
771 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
772 {
773 PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
774
775 TRACE("(%p)\n", ref);
776
777 if (context->childContext)
778 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
779 }
780
781 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
782 DWORD dwFlags, const void *pvPara)
783 {
784 PWINE_COLLECTIONSTORE store;
785
786 if (dwFlags & CERT_STORE_DELETE_FLAG)
787 {
788 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
789 store = NULL;
790 }
791 else
792 {
793 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
794 if (store)
795 {
796 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
797 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
798 StoreTypeCollection);
799 store->hdr.closeStore = CRYPT_CollectionCloseStore;
800 store->hdr.addCert = CRYPT_CollectionAddCert;
801 store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
802 store->hdr.enumCert = CRYPT_CollectionEnumCert;
803 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
804 store->hdr.freeCert = CRYPT_CollectionFreeCert;
805 InitializeCriticalSection(&store->cs);
806 list_init(&store->stores);
807 }
808 }
809 return (PWINECRYPT_CERTSTORE)store;
810 }
811
812 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
813 {
814 static const WCHAR fmt[] = { '%','0','2','X',0 };
815 DWORD i;
816
817 assert(hash);
818 assert(asciiHash);
819
820 for (i = 0; i < 20; i++)
821 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
822 }
823
824 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
825 0 };
826 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
827 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
828 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
829
830 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key,
831 DWORD contextType)
832 {
833 LONG rc;
834 DWORD index = 0;
835 WCHAR subKeyName[MAX_PATH];
836
837 do {
838 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
839
840 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
841 NULL);
842 if (!rc)
843 {
844 HKEY subKey;
845
846 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
847 if (!rc)
848 {
849 LPBYTE buf = NULL;
850
851 size = 0;
852 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
853 if (!rc)
854 buf = CryptMemAlloc(size);
855 if (buf)
856 {
857 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
858 &size);
859 if (!rc)
860 {
861 const void *context;
862 DWORD addedType;
863
864 TRACE("Adding cert with hash %s\n",
865 debugstr_w(subKeyName));
866 context = CRYPT_ReadSerializedElement(buf, size,
867 contextType, &addedType);
868 if (context)
869 {
870 const WINE_CONTEXT_INTERFACE *contextInterface;
871 BYTE hash[20];
872
873 switch (addedType)
874 {
875 case CERT_STORE_CERTIFICATE_CONTEXT:
876 contextInterface = &gCertInterface;
877 break;
878 case CERT_STORE_CRL_CONTEXT:
879 contextInterface = &gCRLInterface;
880 break;
881 case CERT_STORE_CTL_CONTEXT:
882 contextInterface = &gCTLInterface;
883 break;
884 default:
885 contextInterface = NULL;
886 }
887 if (contextInterface)
888 {
889 size = sizeof(hash);
890 if (contextInterface->getProp(context,
891 CERT_HASH_PROP_ID, hash, &size))
892 {
893 WCHAR asciiHash[20 * 2 + 1];
894
895 CRYPT_HashToStr(hash, asciiHash);
896 TRACE("comparing %s\n",
897 debugstr_w(asciiHash));
898 TRACE("with %s\n", debugstr_w(subKeyName));
899 if (!lstrcmpW(asciiHash, subKeyName))
900 {
901 TRACE("hash matches, adding\n");
902 contextInterface->addContextToStore(
903 store, context,
904 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
905 }
906 else
907 TRACE("hash doesn't match, ignoring\n");
908 }
909 contextInterface->free(context);
910 }
911 }
912 }
913 CryptMemFree(buf);
914 }
915 RegCloseKey(subKey);
916 }
917 /* Ignore intermediate errors, continue enumerating */
918 rc = ERROR_SUCCESS;
919 }
920 } while (!rc);
921 }
922
923 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store)
924 {
925 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
926 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
927 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
928 DWORD i;
929
930 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
931 {
932 HKEY key;
933 LONG rc;
934
935 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
936 &key, NULL);
937 if (!rc)
938 {
939 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
940 RegCloseKey(key);
941 }
942 }
943 }
944
945 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
946 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
947 DWORD len)
948 {
949 WCHAR asciiHash[20 * 2 + 1];
950 LONG rc;
951 HKEY subKey;
952 BOOL ret;
953
954 CRYPT_HashToStr(hash, asciiHash);
955 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
956 &subKey, NULL);
957 if (!rc)
958 {
959 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
960 RegCloseKey(subKey);
961 }
962 if (!rc)
963 ret = TRUE;
964 else
965 {
966 SetLastError(rc);
967 ret = FALSE;
968 }
969 return ret;
970 }
971
972 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
973 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
974 {
975 const void *context = NULL;
976 BOOL ret;
977
978 do {
979 context = contextInterface->enumContextsInStore(memStore, context);
980 if (context)
981 {
982 BYTE hash[20];
983 DWORD hashSize = sizeof(hash);
984
985 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
986 &hashSize);
987 if (ret)
988 {
989 DWORD size = 0;
990 LPBYTE buf = NULL;
991
992 ret = contextInterface->serialize(context, 0, NULL, &size);
993 if (size)
994 buf = CryptMemAlloc(size);
995 if (buf)
996 {
997 ret = contextInterface->serialize(context, 0, buf, &size);
998 if (ret)
999 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1000 }
1001 CryptMemFree(buf);
1002 }
1003 }
1004 else
1005 ret = TRUE;
1006 } while (ret && context != NULL);
1007 if (context)
1008 contextInterface->free(context);
1009 return ret;
1010 }
1011
1012 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTORE store)
1013 {
1014 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1015 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1016 &gCRLInterface, &gCTLInterface };
1017 struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1018 BOOL ret = TRUE;
1019 DWORD i;
1020
1021 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1022 {
1023 HKEY key;
1024 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1025 KEY_ALL_ACCESS, NULL, &key, NULL);
1026
1027 if (!rc)
1028 {
1029 if (listToDelete[i])
1030 {
1031 PWINE_HASH_TO_DELETE toDelete, next;
1032 WCHAR asciiHash[20 * 2 + 1];
1033
1034 EnterCriticalSection(&store->cs);
1035 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1036 WINE_HASH_TO_DELETE, entry)
1037 {
1038 LONG rc;
1039
1040 CRYPT_HashToStr(toDelete->hash, asciiHash);
1041 TRACE("Removing %s\n", debugstr_w(asciiHash));
1042 rc = RegDeleteKeyW(key, asciiHash);
1043 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1044 {
1045 SetLastError(rc);
1046 ret = FALSE;
1047 }
1048 list_remove(&toDelete->entry);
1049 CryptMemFree(toDelete);
1050 }
1051 LeaveCriticalSection(&store->cs);
1052 }
1053 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1054 store->memStore);
1055 RegCloseKey(key);
1056 }
1057 else
1058 {
1059 SetLastError(rc);
1060 ret = FALSE;
1061 }
1062 }
1063 return ret;
1064 }
1065
1066 /* If force is true or the registry store is dirty, writes the contents of the
1067 * store to the registry.
1068 */
1069 static BOOL CRYPT_RegFlushStore(PWINE_REGSTORE store, BOOL force)
1070 {
1071 BOOL ret;
1072
1073 if (store->dirty || force)
1074 ret = CRYPT_RegWriteToReg(store);
1075 else
1076 ret = TRUE;
1077 return ret;
1078 }
1079
1080 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1081 {
1082 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1083
1084 TRACE("(%p, %08lx)\n", store, dwFlags);
1085 if (dwFlags)
1086 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1087
1088 CRYPT_RegFlushStore(store, FALSE);
1089 /* certsToDelete should already be cleared by this point */
1090 store->memStore->closeStore(store->memStore, 0);
1091 RegCloseKey(store->key);
1092 DeleteCriticalSection(&store->cs);
1093 CryptMemFree(store);
1094 }
1095
1096 static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
1097 DWORD dwAddDisposition)
1098 {
1099 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1100 BOOL ret;
1101
1102 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition);
1103
1104 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1105 {
1106 SetLastError(ERROR_ACCESS_DENIED);
1107 ret = FALSE;
1108 }
1109 else
1110 {
1111 ret = store->memStore->addCert(store->memStore, cert, dwAddDisposition);
1112 if (ret)
1113 store->dirty = TRUE;
1114 }
1115 return ret;
1116 }
1117
1118 static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef(
1119 PWINE_CERT_CONTEXT context, HCERTSTORE store)
1120 {
1121 PWINE_REG_CERT_CONTEXT ret = CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT));
1122
1123 if (ret)
1124 {
1125 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
1126 ret->childContext = NULL;
1127 }
1128 return (PWINE_CERT_CONTEXT_REF)ret;
1129 }
1130
1131 static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store,
1132 PWINE_CERT_CONTEXT_REF pPrev)
1133 {
1134 PWINE_REGSTORE rs = (PWINE_REGSTORE)store;
1135 PWINE_CERT_CONTEXT_REF child;
1136 PWINE_REG_CERT_CONTEXT prev = (PWINE_REG_CERT_CONTEXT)pPrev, ret = NULL;
1137
1138 TRACE("(%p, %p)\n", store, pPrev);
1139
1140 child = rs->memStore->enumCert(rs->memStore, prev ? prev->childContext
1141 : NULL);
1142 if (prev)
1143 {
1144 prev->childContext = NULL;
1145 CertFreeCertificateContext((PCCERT_CONTEXT)prev);
1146 prev = NULL;
1147 }
1148 if (child)
1149 {
1150 ret = (PWINE_REG_CERT_CONTEXT)CRYPT_RegCreateCertRef(child->context,
1151 store);
1152 if (ret)
1153 ret->childContext = child;
1154 else
1155 CertFreeCertificateContext((PCCERT_CONTEXT)child);
1156 }
1157 return (PWINE_CERT_CONTEXT_REF)ret;
1158 }
1159
1160 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1161 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1162 {
1163 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1164 BOOL ret;
1165
1166 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1167
1168 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1169 {
1170 SetLastError(ERROR_ACCESS_DENIED);
1171 ret = FALSE;
1172 }
1173 else
1174 {
1175 PWINE_HASH_TO_DELETE toDelete =
1176 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1177
1178 if (toDelete)
1179 {
1180 DWORD size = sizeof(toDelete->hash);
1181
1182 ret = CertGetCertificateContextProperty(pCertContext,
1183 CERT_HASH_PROP_ID, toDelete->hash, &size);
1184 if (ret)
1185 {
1186 list_init(&toDelete->entry);
1187 EnterCriticalSection(&store->cs);
1188 list_add_tail(&store->certsToDelete, &toDelete->entry);
1189 LeaveCriticalSection(&store->cs);
1190 ret = store->memStore->deleteCert(store->memStore, pCertContext,
1191 dwFlags);
1192 }
1193 else
1194 CryptMemFree(toDelete);
1195 }
1196 else
1197 ret = FALSE;
1198 if (ret)
1199 store->dirty = TRUE;
1200 }
1201 return ret;
1202 }
1203
1204 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref)
1205 {
1206 PWINE_REG_CERT_CONTEXT context = (PWINE_REG_CERT_CONTEXT)ref;
1207
1208 TRACE("(%p)\n", ref);
1209
1210 if (context->childContext)
1211 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
1212 }
1213
1214 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1215 DWORD dwCtrlType, void const *pvCtrlPara)
1216 {
1217 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1218 BOOL ret;
1219
1220 switch (dwCtrlType)
1221 {
1222 case CERT_STORE_CTRL_RESYNC:
1223 CRYPT_RegFlushStore(store, FALSE);
1224 store->memStore->closeStore(store->memStore, 0);
1225 store->memStore = CRYPT_MemOpenStore(store->hdr.cryptProv,
1226 store->hdr.dwOpenFlags, NULL);
1227 if (store->memStore)
1228 {
1229 CRYPT_RegReadFromReg(store);
1230 ret = TRUE;
1231 }
1232 else
1233 ret = FALSE;
1234 break;
1235 case CERT_STORE_CTRL_COMMIT:
1236 ret = CRYPT_RegFlushStore(store,
1237 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1238 break;
1239 default:
1240 FIXME("%ld: stub\n", dwCtrlType);
1241 ret = FALSE;
1242 }
1243 return ret;
1244 }
1245
1246 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1247 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1248 {
1249 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1250 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1251 HKEY hSubKey = 0;
1252
1253 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1254
1255 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1256 if (!dwRet)
1257 {
1258 /* Find how many subkeys there are */
1259 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1260 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1261 if (!dwRet)
1262 {
1263 dwMaxSubkeyLen++;
1264 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1265 {
1266 /* Name too big: alloc a buffer for it */
1267 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1268 }
1269
1270 if (!lpszName)
1271 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1272 else
1273 {
1274 /* Recursively delete all the subkeys */
1275 for (i = 0; i < dwKeyCount && !dwRet; i++)
1276 {
1277 dwSize = dwMaxSubkeyLen;
1278 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1279 NULL, NULL, NULL);
1280 if (!dwRet)
1281 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1282 }
1283
1284 if (lpszName != szNameBuf)
1285 {
1286 /* Free buffer if allocated */
1287 CryptMemFree(lpszName);
1288 }
1289 }
1290 }
1291
1292 RegCloseKey(hSubKey);
1293 if (!dwRet)
1294 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1295 }
1296 return dwRet;
1297 }
1298
1299 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1300 DWORD dwFlags, const void *pvPara)
1301 {
1302 PWINE_REGSTORE store = NULL;
1303
1304 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1305
1306 if (dwFlags & CERT_STORE_DELETE_FLAG)
1307 {
1308 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1309
1310 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1311 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1312 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1313 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1314 if (rc == ERROR_NO_MORE_ITEMS)
1315 rc = ERROR_SUCCESS;
1316 SetLastError(rc);
1317 }
1318 else
1319 {
1320 HKEY key;
1321
1322 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1323 GetCurrentProcess(), (LPHANDLE)&key,
1324 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1325 TRUE, 0))
1326 {
1327 PWINECRYPT_CERTSTORE memStore;
1328
1329 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1330 if (memStore)
1331 {
1332 store = CryptMemAlloc(sizeof(WINE_REGSTORE));
1333 if (store)
1334 {
1335 memset(store, 0, sizeof(WINE_REGSTORE));
1336 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
1337 StoreTypeReg);
1338 store->hdr.closeStore = CRYPT_RegCloseStore;
1339 store->hdr.addCert = CRYPT_RegAddCert;
1340 store->hdr.createCertRef = CRYPT_RegCreateCertRef;
1341 store->hdr.enumCert = CRYPT_RegEnumCert;
1342 store->hdr.deleteCert = CRYPT_RegDeleteCert;
1343 store->hdr.freeCert = CRYPT_RegFreeCert;
1344 store->hdr.control = CRYPT_RegControl;
1345 store->memStore = memStore;
1346 store->key = key;
1347 InitializeCriticalSection(&store->cs);
1348 list_init(&store->certsToDelete);
1349 CRYPT_RegReadFromReg(store);
1350 store->dirty = FALSE;
1351 }
1352 }
1353 }
1354 }
1355 TRACE("returning %p\n", store);
1356 return (WINECRYPT_CERTSTORE *)store;
1357 }
1358
1359 /* FIXME: this isn't complete for the Root store, in which the top-level
1360 * self-signed CA certs reside. Adding a cert to the Root store should present
1361 * the user with a dialog indicating the consequences of doing so, and asking
1362 * the user to confirm whether the cert should be added.
1363 */
1364 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1365 DWORD dwFlags, const void *pvPara)
1366 {
1367 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1368 LPCWSTR storeName = (LPCWSTR)pvPara;
1369 LPWSTR storePath;
1370 PWINECRYPT_CERTSTORE store = NULL;
1371 HKEY root;
1372 LPCWSTR base;
1373 BOOL ret;
1374
1375 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1376 debugstr_w((LPCWSTR)pvPara));
1377
1378 if (!pvPara)
1379 {
1380 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1381 return NULL;
1382 }
1383
1384 ret = TRUE;
1385 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1386 {
1387 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1388 root = HKEY_LOCAL_MACHINE;
1389 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1390 break;
1391 case CERT_SYSTEM_STORE_CURRENT_USER:
1392 root = HKEY_CURRENT_USER;
1393 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1394 break;
1395 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1396 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1397 * SystemCertificates
1398 */
1399 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1400 debugstr_w(storeName));
1401 return NULL;
1402 case CERT_SYSTEM_STORE_SERVICES:
1403 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1404 * SystemCertificates
1405 */
1406 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1407 debugstr_w(storeName));
1408 return NULL;
1409 case CERT_SYSTEM_STORE_USERS:
1410 /* hku\user sid\Software\Microsoft\SystemCertificates */
1411 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1412 debugstr_w(storeName));
1413 return NULL;
1414 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1415 root = HKEY_CURRENT_USER;
1416 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1417 break;
1418 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1419 root = HKEY_LOCAL_MACHINE;
1420 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1421 break;
1422 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1423 /* hklm\Software\Microsoft\EnterpriseCertificates */
1424 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1425 debugstr_w(storeName));
1426 return NULL;
1427 default:
1428 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1429 return NULL;
1430 }
1431
1432 storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1433 sizeof(WCHAR));
1434 if (storePath)
1435 {
1436 LONG rc;
1437 HKEY key;
1438 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1439 KEY_ALL_ACCESS;
1440
1441 wsprintfW(storePath, fmt, base, storeName);
1442 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1443 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1444 else
1445 {
1446 DWORD disp;
1447
1448 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1449 &key, &disp);
1450 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1451 disp == REG_OPENED_EXISTING_KEY)
1452 {
1453 RegCloseKey(key);
1454 rc = ERROR_FILE_EXISTS;
1455 }
1456 }
1457 if (!rc)
1458 {
1459 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1460 RegCloseKey(key);
1461 }
1462 else
1463 SetLastError(rc);
1464 CryptMemFree(storePath);
1465 }
1466 return store;
1467 }
1468
1469 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1470 DWORD dwFlags, const void *pvPara)
1471 {
1472 int len;
1473 PWINECRYPT_CERTSTORE ret = NULL;
1474
1475 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1476 debugstr_a((LPCSTR)pvPara));
1477
1478 if (!pvPara)
1479 {
1480 SetLastError(ERROR_FILE_NOT_FOUND);
1481 return NULL;
1482 }
1483 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1484 if (len)
1485 {
1486 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1487
1488 if (storeName)
1489 {
1490 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1491 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1492 CryptMemFree(storeName);
1493 }
1494 }
1495 return ret;
1496 }
1497
1498 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1499 DWORD dwFlags, const void *pvPara)
1500 {
1501 HCERTSTORE store = 0;
1502 BOOL ret;
1503
1504 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1505 debugstr_w((LPCWSTR)pvPara));
1506
1507 if (!pvPara)
1508 {
1509 SetLastError(ERROR_FILE_NOT_FOUND);
1510 return NULL;
1511 }
1512 /* This returns a different error than system registry stores if the
1513 * location is invalid.
1514 */
1515 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1516 {
1517 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1518 case CERT_SYSTEM_STORE_CURRENT_USER:
1519 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1520 case CERT_SYSTEM_STORE_SERVICES:
1521 case CERT_SYSTEM_STORE_USERS:
1522 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1523 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1524 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1525 ret = TRUE;
1526 break;
1527 default:
1528 SetLastError(ERROR_FILE_NOT_FOUND);
1529 ret = FALSE;
1530 }
1531 if (ret)
1532 {
1533 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1534 0, hCryptProv, dwFlags, pvPara);
1535
1536 if (regStore)
1537 {
1538 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1539 CERT_STORE_CREATE_NEW_FLAG, NULL);
1540 if (store)
1541 {
1542 CertAddStoreToCollection(store, regStore,
1543 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1544 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1545 CertCloseStore(regStore, 0);
1546 }
1547 }
1548 }
1549 return (PWINECRYPT_CERTSTORE)store;
1550 }
1551
1552 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1553 DWORD dwFlags, const void *pvPara)
1554 {
1555 int len;
1556 PWINECRYPT_CERTSTORE ret = NULL;
1557
1558 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1559 debugstr_a((LPCSTR)pvPara));
1560
1561 if (!pvPara)
1562 {
1563 SetLastError(ERROR_FILE_NOT_FOUND);
1564 return NULL;
1565 }
1566 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1567 if (len)
1568 {
1569 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1570
1571 if (storeName)
1572 {
1573 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1574 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1575 CryptMemFree(storeName);
1576 }
1577 }
1578 return ret;
1579 }
1580
1581 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1582 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1583 const void* pvPara)
1584 {
1585 WINECRYPT_CERTSTORE *hcs;
1586 StoreOpenFunc openFunc = NULL;
1587
1588 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1589 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1590
1591 if (!HIWORD(lpszStoreProvider))
1592 {
1593 switch (LOWORD(lpszStoreProvider))
1594 {
1595 case (int)CERT_STORE_PROV_MEMORY:
1596 openFunc = CRYPT_MemOpenStore;
1597 break;
1598 case (int)CERT_STORE_PROV_REG:
1599 openFunc = CRYPT_RegOpenStore;
1600 break;
1601 case (int)CERT_STORE_PROV_COLLECTION:
1602 openFunc = CRYPT_CollectionOpenStore;
1603 break;
1604 case (int)CERT_STORE_PROV_SYSTEM_A:
1605 openFunc = CRYPT_SysOpenStoreA;
1606 break;
1607 case (int)CERT_STORE_PROV_SYSTEM_W:
1608 openFunc = CRYPT_SysOpenStoreW;
1609 break;
1610 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1611 openFunc = CRYPT_SysRegOpenStoreA;
1612 break;
1613 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1614 openFunc = CRYPT_SysRegOpenStoreW;
1615 break;
1616 default:
1617 if (LOWORD(lpszStoreProvider))
1618 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1619 }
1620 }
1621 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1622 openFunc = CRYPT_MemOpenStore;
1623 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1624 openFunc = CRYPT_SysOpenStoreW;
1625 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1626 openFunc = CRYPT_CollectionOpenStore;
1627 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1628 openFunc = CRYPT_SysRegOpenStoreW;
1629 else
1630 {
1631 FIXME("unimplemented type %s\n", lpszStoreProvider);
1632 openFunc = NULL;
1633 }
1634
1635 if (!openFunc)
1636 {
1637 /* FIXME: need to look for an installed provider for this type */
1638 SetLastError(ERROR_FILE_NOT_FOUND);
1639 hcs = NULL;
1640 }
1641 else
1642 hcs = openFunc(hCryptProv, dwFlags, pvPara);
1643 return (HCERTSTORE)hcs;
1644 }
1645
1646 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1647 LPCSTR szSubSystemProtocol)
1648 {
1649 HCERTSTORE ret = 0;
1650
1651 if (szSubSystemProtocol)
1652 {
1653 int len = MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, NULL,
1654 0);
1655 LPWSTR param = CryptMemAlloc(len * sizeof(WCHAR));
1656
1657 if (param)
1658 {
1659 MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, param, len);
1660 ret = CertOpenSystemStoreW(hProv, param);
1661 CryptMemFree(param);
1662 }
1663 }
1664 else
1665 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1666 return ret;
1667 }
1668
1669 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1670 LPCWSTR szSubSystemProtocol)
1671 {
1672 HCERTSTORE ret;
1673
1674 if (!szSubSystemProtocol)
1675 {
1676 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1677 return 0;
1678 }
1679
1680 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1681 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1682 * it fails.
1683 */
1684 ret = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, hProv,
1685 CERT_STORE_CREATE_NEW_FLAG, NULL);
1686 if (ret)
1687 {
1688 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1689 0, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE, szSubSystemProtocol);
1690
1691 if (store)
1692 {
1693 CertAddStoreToCollection(ret, store,
1694 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1695 CertCloseStore(store, 0);
1696 }
1697 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1698 0, hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1699 if (store)
1700 {
1701 CertAddStoreToCollection(ret, store,
1702 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1703 CertCloseStore(store, 0);
1704 }
1705 }
1706 return ret;
1707 }
1708
1709 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1710 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1711 {
1712 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
1713 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1714 return TRUE;
1715 }
1716
1717 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1718 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1719 {
1720 PCRL_CONTEXT pcrl;
1721 BYTE* data;
1722
1723 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1724
1725 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1726 pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) );
1727 if( !pcrl )
1728 return NULL;
1729
1730 data = CryptMemAlloc( cbCrlEncoded );
1731 if( !data )
1732 {
1733 CryptMemFree( pcrl );
1734 return NULL;
1735 }
1736
1737 pcrl->dwCertEncodingType = dwCertEncodingType;
1738 pcrl->pbCrlEncoded = data;
1739 pcrl->cbCrlEncoded = cbCrlEncoded;
1740 pcrl->pCrlInfo = NULL;
1741 pcrl->hCertStore = 0;
1742
1743 return pcrl;
1744 }
1745
1746 /* Decodes the encoded certificate and creates the certificate context for it.
1747 * The reference count is initially zero, so you must create a reference to it
1748 * to avoid leaking memory.
1749 */
1750 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1751 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1752 {
1753 PWINE_CERT_CONTEXT cert = NULL;
1754 BOOL ret;
1755 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1756 PCERT_INFO certInfo = NULL;
1757 DWORD size = 0;
1758
1759 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1760 cbCertEncoded);
1761
1762 /* First try to decode it as a signed cert. */
1763 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1764 cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1765 (BYTE *)&signedCert, &size);
1766 if (ret)
1767 {
1768 size = 0;
1769 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1770 signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData,
1771 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1772 (BYTE *)&certInfo, &size);
1773 LocalFree(signedCert);
1774 }
1775 /* Failing that, try it as an unsigned cert */
1776 if (!ret)
1777 {
1778 size = 0;
1779 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1780 pbCertEncoded, cbCertEncoded,
1781 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1782 (BYTE *)&certInfo, &size);
1783 }
1784 if (ret)
1785 {
1786 BYTE *data = NULL;
1787
1788 cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT));
1789 if (!cert)
1790 goto end;
1791 data = CryptMemAlloc(cbCertEncoded);
1792 if (!data)
1793 {
1794 CryptMemFree(cert);
1795 cert = NULL;
1796 goto end;
1797 }
1798 memcpy(data, pbCertEncoded, cbCertEncoded);
1799 cert->cert.dwCertEncodingType = dwCertEncodingType;
1800 cert->cert.pbCertEncoded = data;
1801 cert->cert.cbCertEncoded = cbCertEncoded;
1802 cert->cert.pCertInfo = certInfo;
1803 cert->cert.hCertStore = 0;
1804 cert->ref = 0;
1805 InitializeCriticalSection(&cert->cs);
1806 list_init(&cert->extendedProperties);
1807 }
1808
1809 end:
1810 return cert;
1811 }
1812
1813 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1814 {
1815 PWINE_CERT_PROPERTY prop, next;
1816
1817 CryptMemFree(context->cert.pbCertEncoded);
1818 LocalFree(context->cert.pCertInfo);
1819 DeleteCriticalSection(&context->cs);
1820 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1821 WINE_CERT_PROPERTY, entry)
1822 {
1823 list_remove(&prop->entry);
1824 CryptMemFree(prop->pbData);
1825 CryptMemFree(prop);
1826 }
1827 CryptMemFree(context);
1828 }
1829
1830 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1831 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1832 {
1833 PWINE_CERT_CONTEXT cert;
1834 PWINE_CERT_CONTEXT_REF ret = NULL;
1835
1836 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1837 cbCertEncoded);
1838
1839 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1840 cbCertEncoded);
1841 if (cert)
1842 ret = CRYPT_CreateCertRef(cert, 0);
1843 return (PCCERT_CONTEXT)ret;
1844 }
1845
1846 /* Since the properties are stored in a list, this is a tad inefficient
1847 * (O(n^2)) since I have to find the previous position every time.
1848 */
1849 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1850 DWORD dwPropId)
1851 {
1852 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1853 DWORD ret;
1854
1855 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1856
1857 EnterCriticalSection(&ref->context->cs);
1858 if (dwPropId)
1859 {
1860 PWINE_CERT_PROPERTY cursor = NULL;
1861
1862 LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1863 WINE_CERT_PROPERTY, entry)
1864 {
1865 if (cursor->hdr.propID == dwPropId)
1866 break;
1867 }
1868 if (cursor)
1869 {
1870 if (cursor->entry.next != &ref->context->extendedProperties)
1871 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1872 entry)->hdr.propID;
1873 else
1874 ret = 0;
1875 }
1876 else
1877 ret = 0;
1878 }
1879 else if (!list_empty(&ref->context->extendedProperties))
1880 ret = LIST_ENTRY(ref->context->extendedProperties.next,
1881 WINE_CERT_PROPERTY, entry)->hdr.propID;
1882 else
1883 ret = 0;
1884 LeaveCriticalSection(&ref->context->cs);
1885 return ret;
1886 }
1887
1888 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1889 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1890 {
1891 PWINE_CERT_PROPERTY prop;
1892 BOOL ret, found;
1893
1894 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1895
1896 EnterCriticalSection(&context->cs);
1897 ret = FALSE;
1898 found = FALSE;
1899 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1900 WINE_CERT_PROPERTY, entry)
1901 {
1902 if (prop->hdr.propID == dwPropId)
1903 {
1904 if (!pvData)
1905 {
1906 *pcbData = prop->hdr.cb;
1907 ret = TRUE;
1908 }
1909 else if (*pcbData < prop->hdr.cb)
1910 {
1911 SetLastError(ERROR_MORE_DATA);
1912 *pcbData = prop->hdr.cb;
1913 }
1914 else
1915 {
1916 memcpy(pvData, prop->pbData, prop->hdr.cb);
1917 *pcbData = prop->hdr.cb;
1918 ret = TRUE;
1919 }
1920 found = TRUE;
1921 }
1922 break;
1923 }
1924 if (!found)
1925 {
1926 /* Implicit properties */
1927 switch (dwPropId)
1928 {
1929 case CERT_SHA1_HASH_PROP_ID:
1930 ret = CryptHashCertificate(0, CALG_SHA1, 0,
1931 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1932 pcbData);
1933 if (ret)
1934 {
1935 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1936
1937 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1938 0, &blob);
1939 }
1940 break;
1941 case CERT_KEY_PROV_INFO_PROP_ID:
1942 case CERT_MD5_HASH_PROP_ID:
1943 case CERT_SIGNATURE_HASH_PROP_ID:
1944 case CERT_KEY_IDENTIFIER_PROP_ID:
1945 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1946 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1947 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1948 FIXME("implicit property %ld\n", dwPropId);
1949 break;
1950 }
1951 }
1952 LeaveCriticalSection(&context->cs);
1953 TRACE("returning %d\n", ret);
1954 return ret;
1955 }
1956
1957 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1958 DWORD dwPropId, void *pvData, DWORD *pcbData)
1959 {
1960 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1961 BOOL ret;
1962
1963 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1964
1965 /* Special cases for invalid/special prop IDs.
1966 */
1967 switch (dwPropId)
1968 {
1969 case 0:
1970 case CERT_CERT_PROP_ID:
1971 case CERT_CRL_PROP_ID:
1972 case CERT_CTL_PROP_ID:
1973 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1974 return FALSE;
1975 case CERT_ACCESS_STATE_PROP_ID:
1976 if (!pvData)
1977 {
1978 *pcbData = sizeof(DWORD);
1979 return TRUE;
1980 }
1981 else if (*pcbData < sizeof(DWORD))
1982 {
1983 SetLastError(ERROR_MORE_DATA);
1984 *pcbData = sizeof(DWORD);
1985 return FALSE;
1986 }
1987 else
1988 {
1989 DWORD state = 0;
1990
1991 if (pCertContext->hCertStore)
1992 {
1993 PWINECRYPT_CERTSTORE store =
1994 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1995
1996 /* Take advantage of knowledge of the stores to answer the
1997 * access state question
1998 */
1999 if (store->type != StoreTypeReg ||
2000 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2001 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2002 }
2003 *(DWORD *)pvData = state;
2004 return TRUE;
2005 }
2006 }
2007
2008 ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
2009 pvData, pcbData);
2010 TRACE("returning %d\n", ret);
2011 return ret;
2012 }
2013
2014 /* Copies cbData bytes from pbData to the context's property with ID
2015 * dwPropId.
2016 */
2017 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
2018 DWORD dwPropId, const BYTE *pbData, size_t cbData)
2019 {
2020 BOOL ret = FALSE;
2021 LPBYTE data;
2022
2023 if (cbData)
2024 {
2025 data = CryptMemAlloc(cbData);
2026 if (data)
2027 memcpy(data, pbData, cbData);
2028 }
2029 else
2030 data = NULL;
2031 if (!cbData || data)
2032 {
2033 PWINE_CERT_PROPERTY prop;
2034
2035 EnterCriticalSection(&context->cs);
2036 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
2037 WINE_CERT_PROPERTY, entry)
2038 {
2039 if (prop->hdr.propID == dwPropId)
2040 break;
2041 }
2042 if (prop && prop->entry.next != &context->extendedProperties)
2043 {
2044 CryptMemFree(prop->pbData);
2045 prop->hdr.cb = cbData;
2046 prop->pbData = cbData ? data : NULL;
2047 ret = TRUE;
2048 }
2049 else
2050 {
2051 prop = CryptMemAlloc(sizeof(WINE_CERT_PROPERTY));
2052 if (prop)
2053 {
2054 prop->hdr.propID = dwPropId;
2055 prop->hdr.unknown = 1;
2056 prop->hdr.cb = cbData;
2057 list_init(&prop->entry);
2058 prop->pbData = cbData ? data : NULL;
2059 list_add_tail(&context->extendedProperties, &prop->entry);
2060 ret = TRUE;
2061 }
2062 else
2063 CryptMemFree(data);
2064 }
2065 LeaveCriticalSection(&context->cs);
2066 }
2067 return ret;
2068 }
2069
2070 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2071 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2072 {
2073 BOOL ret = FALSE;
2074
2075 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2076
2077 if (!pvData)
2078 {
2079 PWINE_CERT_PROPERTY prop, next;
2080
2081 EnterCriticalSection(&context->cs);
2082 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2083 WINE_CERT_PROPERTY, entry)
2084 {
2085 if (prop->hdr.propID == dwPropId)
2086 {
2087 list_remove(&prop->entry);
2088 CryptMemFree(prop->pbData);
2089 CryptMemFree(prop);
2090 }
2091 }
2092 LeaveCriticalSection(&context->cs);
2093 ret = TRUE;
2094 }
2095 else
2096 {
2097 switch (dwPropId)
2098 {
2099 case CERT_AUTO_ENROLL_PROP_ID:
2100 case CERT_CTL_USAGE_PROP_ID:
2101 case CERT_DESCRIPTION_PROP_ID:
2102 case CERT_FRIENDLY_NAME_PROP_ID:
2103 case CERT_HASH_PROP_ID:
2104 case CERT_KEY_IDENTIFIER_PROP_ID:
2105 case CERT_MD5_HASH_PROP_ID:
2106 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2107 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2108 case CERT_PVK_FILE_PROP_ID:
2109 case CERT_SIGNATURE_HASH_PROP_ID:
2110 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2111 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2112 case CERT_ENROLLMENT_PROP_ID:
2113 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2114 case CERT_RENEWAL_PROP_ID:
2115 {
2116 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2117
2118 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2119 blob->pbData, blob->cbData);
2120 break;
2121 }
2122 case CERT_DATE_STAMP_PROP_ID:
2123 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2124 pvData, sizeof(FILETIME));
2125 break;
2126 default:
2127 FIXME("%ld: stub\n", dwPropId);
2128 }
2129 }
2130 TRACE("returning %d\n", ret);
2131 return ret;
2132 }
2133
2134 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2135 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2136 {
2137 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2138 BOOL ret;
2139
2140 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2141
2142 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2143 * crashes on most of these, I'll be safer.
2144 */
2145 switch (dwPropId)
2146 {
2147 case 0:
2148 case CERT_ACCESS_STATE_PROP_ID:
2149 case CERT_CERT_PROP_ID:
2150 case CERT_CRL_PROP_ID:
2151 case CERT_CTL_PROP_ID:
2152 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2153 return FALSE;
2154 }
2155 ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
2156 dwFlags, pvData);
2157 TRACE("returning %d\n", ret);
2158 return ret;
2159 }
2160
2161 /* Only the reference portion of the context is duplicated. The returned
2162 * context has the cert store set to 0, to prevent the store's certificate free
2163 * function from getting called on partial data.
2164 * FIXME: is this okay? Needs a test.
2165 */
2166 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2167 PCCERT_CONTEXT pCertContext)
2168 {
2169 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
2170
2171 TRACE("(%p)\n", pCertContext);
2172 if (ref)
2173 {
2174 ret = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF));
2175 if (ret)
2176 {
2177 memcpy(ret, ref, sizeof(*ret));
2178 ret->cert.hCertStore = 0;
2179 InterlockedIncrement(&ret->context->ref);
2180 }
2181 }
2182 else
2183 ret = NULL;
2184 return (PCCERT_CONTEXT)ret;
2185 }
2186
2187 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2188 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2189 PCCERT_CONTEXT *ppStoreContext)
2190 {
2191 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2192 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2193 PWINE_CERT_CONTEXT cert;
2194 BOOL ret;
2195
2196 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2197 dwAddDisposition, ppStoreContext);
2198
2199 /* FIXME: some tests needed to verify return codes */
2200 if (!store)
2201 {
2202 SetLastError(ERROR_INVALID_PARAMETER);
2203 return FALSE;
2204 }
2205 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2206 {
2207 SetLastError(ERROR_INVALID_PARAMETER);
2208 return FALSE;
2209 }
2210
2211 cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
2212 ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
2213 if (cert)
2214 {
2215 PWINE_CERT_PROPERTY prop;
2216
2217 ret = TRUE;
2218 EnterCriticalSection(&ref->context->cs);
2219 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2220 WINE_CERT_PROPERTY, entry)
2221 {
2222 ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
2223 prop->pbData, prop->hdr.cb);
2224 if (!ret)
2225 break;
2226 }
2227 LeaveCriticalSection(&ref->context->cs);
2228 if (ret)
2229 {
2230 ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
2231 if (ret && ppStoreContext)
2232 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
2233 hCertStore);
2234 }
2235 if (!ret)
2236 CRYPT_FreeCert(cert);
2237 }
2238 else
2239 ret = FALSE;
2240 return ret;
2241 }
2242
2243 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2244 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2245 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2246 {
2247 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2248 BOOL ret;
2249
2250 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2251 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2252
2253 if (!hcs)
2254 ret = FALSE;
2255 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2256 ret = FALSE;
2257 else
2258 {
2259 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2260 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2261
2262 if (cert)
2263 {
2264 ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
2265 if (ret && ppCertContext)
2266 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
2267 hCertStore);
2268 if (!ret)
2269 CRYPT_FreeCert(cert);
2270 }
2271 else
2272 ret = FALSE;
2273 }
2274 return ret;
2275 }
2276
2277 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2278 PCCERT_CONTEXT pPrev)
2279 {
2280 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2281 PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
2282 PCCERT_CONTEXT ret;
2283
2284 TRACE("(%p, %p)\n", hCertStore, pPrev);
2285 if (!hCertStore)
2286 ret = NULL;
2287 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2288 ret = NULL;
2289 else
2290 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
2291 return ret;
2292 }
2293
2294 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2295 {
2296 BOOL ret;
2297
2298 TRACE("(%p)\n", pCertContext);
2299
2300 if (!pCertContext)
2301 ret = TRUE;
2302 else if (!pCertContext->hCertStore)
2303 {
2304 ret = TRUE;
2305 CertFreeCertificateContext(pCertContext);
2306 }
2307 else
2308 {
2309 PWINECRYPT_CERTSTORE hcs =
2310 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2311
2312 if (!hcs)
2313 ret = TRUE;
2314 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2315 ret = FALSE;
2316 else
2317 {
2318 ret = hcs->deleteCert(hcs, pCertContext, 0);
2319 if (ret)
2320 CertFreeCertificateContext(pCertContext);
2321 }
2322 }
2323 return ret;
2324 }
2325
2326 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2327 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2328 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2329 {
2330 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2331 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2332 ppCrlContext);
2333 return FALSE;
2334 }
2335
2336 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2337 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2338 PCCRL_CONTEXT* ppStoreContext )
2339 {
2340 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2341 dwAddDisposition, ppStoreContext);
2342 return TRUE;
2343 }
2344
2345 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2346 {
2347 FIXME("%p\n", pCrlContext );
2348
2349 return TRUE;
2350 }
2351
2352 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2353 {
2354 FIXME("(%p): stub\n", pCrlContext);
2355 return TRUE;
2356 }
2357
2358 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2359 PCCRL_CONTEXT pPrev)
2360 {
2361 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2362 return NULL;
2363 }
2364
2365 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2366 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2367 {
2368 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2369 cbCtlEncoded);
2370 return NULL;
2371 }
2372
2373 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2374 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2375 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2376 {
2377 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2378 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2379 ppCtlContext);
2380 return FALSE;
2381 }
2382
2383 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2384 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2385 PCCTL_CONTEXT* ppStoreContext)
2386 {
2387 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2388 dwAddDisposition, ppStoreContext);
2389 return TRUE;
2390 }
2391
2392 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2393 {
2394 FIXME("(%p): stub\n", pCtlContext );
2395 return TRUE;
2396 }
2397
2398 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2399 {
2400 FIXME("(%p): stub\n", pCtlContext);
2401 return TRUE;
2402 }
2403
2404 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2405 PCCTL_CONTEXT pPrev)
2406 {
2407 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2408 return NULL;
2409 }
2410
2411
2412 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2413 {
2414 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2415
2416 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2417
2418 if( ! hCertStore )
2419 return TRUE;
2420
2421 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2422 return FALSE;
2423
2424 if (InterlockedDecrement(&hcs->ref) == 0)
2425 {
2426 TRACE("%p's ref count is 0, freeing\n", hcs);
2427 hcs->dwMagic = 0;
2428 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2429 CryptReleaseContext(hcs->cryptProv, 0);
2430 hcs->closeStore(hcs, dwFlags);
2431 }
2432 else
2433 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2434 return TRUE;
2435 }
2436
2437 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2438 DWORD dwCtrlType, void const *pvCtrlPara)
2439 {
2440 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2441 BOOL ret;
2442
2443 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2444 pvCtrlPara);
2445
2446 if (!hcs)
2447 ret = FALSE;
2448 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2449 ret = FALSE;
2450 else
2451 {
2452 if (hcs->control)
2453 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2454 else
2455 ret = TRUE;
2456 }
2457 return ret;
2458 }
2459
2460 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2461 DWORD dwPropId, void *pvData, DWORD *pcbData)
2462 {
2463 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2464 return FALSE;
2465 }
2466
2467 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2468 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2469 {
2470 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2471 pvData);
2472 return FALSE;
2473 }
2474
2475 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
2476 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2477 {
2478 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
2479 pcbElement);
2480 return FALSE;
2481 }
2482
2483 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2484 DWORD dwPropId, void *pvData, DWORD *pcbData)
2485 {
2486 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2487 return FALSE;
2488 }
2489
2490 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2491 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2492 {
2493 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2494 pvData);
2495 return FALSE;
2496 }
2497
2498 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
2499 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2500 {
2501 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
2502 pcbElement);
2503 return FALSE;
2504 }
2505
2506 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
2507 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2508 {
2509 BOOL ret;
2510
2511 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
2512 pcbElement);
2513
2514 if (pCertContext)
2515 {
2516 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2517 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
2518 pCertContext->cbCertEncoded;
2519 PWINE_CERT_PROPERTY prop;
2520
2521 EnterCriticalSection(&ref->context->cs);
2522 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2523 WINE_CERT_PROPERTY, entry)
2524 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
2525 if (!pbElement)
2526 {
2527 *pcbElement = bytesNeeded;
2528 ret = TRUE;
2529 }
2530 else if (*pcbElement < bytesNeeded)
2531 {
2532 *pcbElement = bytesNeeded;
2533 SetLastError(ERROR_MORE_DATA);
2534 ret = FALSE;
2535 }
2536 else
2537 {
2538 PWINE_CERT_PROP_HEADER hdr;
2539
2540 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2541 WINE_CERT_PROPERTY, entry)
2542 {
2543 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
2544 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2545 if (prop->hdr.cb)
2546 {
2547 memcpy(pbElement, prop->pbData, prop->hdr.cb);
2548 pbElement += prop->hdr.cb;
2549 }
2550 }
2551 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
2552 hdr->propID = CERT_CERT_PROP_ID;
2553 hdr->unknown = 1;
2554 hdr->cb = pCertContext->cbCertEncoded;
2555 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
2556 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
2557 ret = TRUE;
2558 }
2559 LeaveCriticalSection(&ref->context->cs);
2560 }
2561 else
2562 ret = FALSE;
2563 return ret;
2564 }
2565
2566 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2567 * to its header if a valid header is found, NULL if not. Valid means the
2568 * length of thte property won't overrun buf, and the unknown field is 1.
2569 */
2570 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
2571 DWORD size, DWORD propID)
2572 {
2573 const WINE_CERT_PROP_HEADER *ret = NULL;
2574 BOOL done = FALSE;
2575
2576 while (size && !ret && !done)
2577 {
2578 if (size < sizeof(WINE_CERT_PROP_HEADER))
2579 {
2580 SetLastError(CRYPT_E_FILE_ERROR);
2581 done = TRUE;
2582 }
2583 else
2584 {
2585 const WINE_CERT_PROP_HEADER *hdr =
2586 (const WINE_CERT_PROP_HEADER *)buf;
2587
2588 size -= sizeof(WINE_CERT_PROP_HEADER);
2589 buf += sizeof(WINE_CERT_PROP_HEADER);
2590 if (size < hdr->cb)
2591 {
2592 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2593 done = TRUE;
2594 }
2595 else if (!hdr->propID)
2596 {
2597 /* assume a zero prop ID means the data are uninitialized, so
2598 * stop looking.
2599 */
2600 done = TRUE;
2601 }
2602 else if (hdr->unknown != 1)
2603 {
2604 SetLastError(ERROR_FILE_NOT_FOUND);
2605 done = TRUE;
2606 }
2607 else if (hdr->propID == propID)
2608 ret = hdr;
2609 else
2610 {
2611 buf += hdr->cb;
2612 size -= hdr->cb;
2613 }
2614 }
2615 }
2616 return ret;
2617 }
2618
2619 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
2620 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
2621 {
2622 const void *context;
2623
2624 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
2625 pdwContentType);
2626
2627 if (!cbElement)
2628 {
2629 SetLastError(ERROR_END_OF_MEDIA);
2630 return NULL;
2631 }
2632
2633 __TRY
2634 {
2635 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2636 const WINE_CERT_PROP_HEADER *hdr = NULL;
2637 DWORD type = 0;
2638 BOOL ret;
2639
2640 ret = TRUE;
2641 context = NULL;
2642 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
2643 {
2644 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2645 if (hdr)
2646 type = CERT_STORE_CERTIFICATE_CONTEXT;
2647 else
2648 {
2649 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2650 if (hdr)
2651 type = CERT_STORE_CRL_CONTEXT;
2652 else
2653 {
2654 hdr = CRYPT_findPropID(pbElement, cbElement,
2655 CERT_CTL_PROP_ID);
2656 if (hdr)
2657 type = CERT_STORE_CTL_CONTEXT;
2658 }
2659 }
2660 }
2661 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
2662 {
2663 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2664 type = CERT_STORE_CERTIFICATE_CONTEXT;
2665 }
2666 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
2667 {
2668 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2669 type = CERT_STORE_CRL_CONTEXT;
2670 }
2671 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
2672 {
2673 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
2674 type = CERT_STORE_CTL_CONTEXT;
2675 }
2676
2677 switch (type)
2678 {
2679 case CERT_STORE_CERTIFICATE_CONTEXT:
2680 contextInterface = &gCertInterface;
2681 break;
2682 case CERT_STORE_CRL_CONTEXT:
2683 contextInterface = &gCRLInterface;
2684 break;
2685 case CERT_STORE_CTL_CONTEXT:
2686 contextInterface = &gCTLInterface;
2687 break;
2688 default:
2689 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2690 ret = FALSE;
2691 }
2692 if (!hdr)
2693 ret = FALSE;
2694
2695 if (ret)
2696 context = contextInterface->create(X509_ASN_ENCODING,
2697 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
2698 if (ret && context)
2699 {
2700 BOOL noMoreProps = FALSE;
2701
2702 while (!noMoreProps && ret)
2703 {
2704 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
2705 ret = FALSE;
2706 else
2707 {
2708 const WINE_CERT_PROP_HEADER *hdr =
2709 (const WINE_CERT_PROP_HEADER *)pbElement;
2710
2711 TRACE("prop is %ld\n", hdr->propID);
2712 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
2713 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2714 if (cbElement < hdr->cb)
2715 {
2716 SetLastError(HRESULT_FROM_WIN32(
2717 ERROR_INVALID_PARAMETER));
2718 ret = FALSE;
2719 }
2720 else if (!hdr->propID)
2721 {
2722 /* Like in CRYPT_findPropID, stop if the propID is zero
2723 */
2724 noMoreProps = TRUE;
2725 }
2726 else if (hdr->unknown != 1)
2727 {
2728 SetLastError(ERROR_FILE_NOT_FOUND);
2729 ret = FALSE;
2730 }
2731 else if (hdr->propID != CERT_CERT_PROP_ID &&
2732 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
2733 CERT_CTL_PROP_ID)
2734 {
2735 /* Have to create a blob for most types, but not
2736 * for all.. arghh.
2737 */
2738 switch (hdr->propID)
2739 {
2740 case CERT_AUTO_ENROLL_PROP_ID:
2741 case CERT_CTL_USAGE_PROP_ID:
2742 case CERT_DESCRIPTION_PROP_ID:
2743 case CERT_FRIENDLY_NAME_PROP_ID:
2744 case CERT_HASH_PROP_ID:
2745 case CERT_KEY_IDENTIFIER_PROP_ID:
2746 case CERT_MD5_HASH_PROP_ID:
2747 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2748 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2749 case CERT_PVK_FILE_PROP_ID:
2750 case CERT_SIGNATURE_HASH_PROP_ID:
2751 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2752 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2753 case CERT_ENROLLMENT_PROP_ID:
2754 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2755 case CERT_RENEWAL_PROP_ID:
2756 {
2757 CRYPT_DATA_BLOB blob = { hdr->cb,
2758 (LPBYTE)pbElement };
2759
2760 ret = contextInterface->setProp(context,
2761 hdr->propID, 0, &blob);
2762 break;
2763 }
2764 case CERT_DATE_STAMP_PROP_ID:
2765 ret = contextInterface->setProp(context,
2766 hdr->propID, 0, pbElement);
2767 break;
2768 default:
2769 FIXME("prop ID %ld: stub\n", hdr->propID);
2770 }
2771 }
2772 pbElement += hdr->cb;
2773 cbElement -= hdr->cb;
2774 if (!cbElement)
2775 noMoreProps = TRUE;
2776 }
2777 }
2778 if (ret)
2779 {
2780 if (pdwContentType)
2781 *pdwContentType = type;
2782 }
2783 else
2784 {
2785 contextInterface->free(context);
2786 context = NULL;
2787 }
2788 }
2789 }
2790 __EXCEPT(page_fault)
2791 {
2792 SetLastError(STATUS_ACCESS_VIOLATION);
2793 context = NULL;
2794 }
2795 __ENDTRY
2796 return context;
2797 }
2798
2799 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
2800 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
2801 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
2802 {
2803 const void *context;
2804 DWORD type;
2805 BOOL ret;
2806
2807 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
2808 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
2809 pdwContentType, ppvContext);
2810
2811 /* Call the internal function, then delete the hashes. Tests show this
2812 * function uses real hash values, not whatever's stored in the hash
2813 * property.
2814 */
2815 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
2816 dwContextTypeFlags, &type);
2817 if (context)
2818 {
2819 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2820
2821 switch (type)
2822 {
2823 case CERT_STORE_CERTIFICATE_CONTEXT:
2824 contextInterface = &gCertInterface;
2825 break;
2826 case CERT_STORE_CRL_CONTEXT:
2827 contextInterface = &gCRLInterface;
2828 break;
2829 case CERT_STORE_CTL_CONTEXT:
2830 contextInterface = &gCTLInterface;
2831 break;
2832 default:
2833 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2834 }
2835 if (contextInterface)
2836 {
2837 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2838 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2839 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2840 NULL);
2841 if (pdwContentType)
2842 *pdwContentType = type;
2843 ret = contextInterface->addContextToStore(hCertStore, context,
2844 dwAddDisposition, ppvContext);
2845 contextInterface->free(context);
2846 }
2847 else
2848 ret = FALSE;
2849 }
2850 else
2851 ret = FALSE;
2852 return ret;
2853 }
2854
2855 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref)
2856 {
2857 if (InterlockedDecrement(&ref->context->ref) == 0)
2858 {
2859 TRACE("%p's ref count is 0, freeing\n", ref->context);
2860 CRYPT_FreeCert(ref->context);
2861 }
2862 else
2863 TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref);
2864 }
2865
2866 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2867 {
2868 TRACE("(%p)\n", pCertContext);
2869
2870 if (pCertContext)
2871 {
2872 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2873 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2874
2875 CRYPT_UnrefCertificateContext(ref);
2876 if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2877 store->freeCert)
2878 store->freeCert(ref);
2879 TRACE("freeing %p\n", ref);
2880 CryptMemFree(ref);
2881 }
2882 return TRUE;
2883 }
2884
2885 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2886 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2887 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2888 {
2889 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2890 dwFlags, dwType, pvPara, pPrevCertContext);
2891 SetLastError(CRYPT_E_NOT_FOUND);
2892 return NULL;
2893 }
2894
2895 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2896 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2897 {
2898 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2899 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2900 PWINE_STORE_LIST_ENTRY entry;
2901 BOOL ret;
2902
2903 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2904 dwUpdateFlags, dwPriority);
2905
2906 if (!collection || !sibling)
2907 return TRUE;
2908 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2909 {
2910 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2911 return FALSE;
2912 }
2913 if (collection->hdr.type != StoreTypeCollection)
2914 {
2915 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2916 return FALSE;
2917 }
2918 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2919 {
2920 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2921 return FALSE;
2922 }
2923
2924 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2925 if (entry)
2926 {
2927 InterlockedIncrement(&sibling->ref);
2928 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2929 entry->store = sibling;
2930 entry->dwUpdateFlags = dwUpdateFlags;
2931 entry->dwPriority = dwPriority;
2932 list_init(&entry->entry);
2933 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2934 EnterCriticalSection(&collection->cs);
2935 if (dwPriority)
2936 {
2937 PWINE_STORE_LIST_ENTRY cursor;
2938 BOOL added = FALSE;
2939
2940 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2941 WINE_STORE_LIST_ENTRY, entry)
2942 {
2943 if (cursor->dwPriority < dwPriority)
2944 {
2945 list_add_before(&cursor->entry, &entry->entry);
2946 added = TRUE;
2947 break;
2948 }
2949 }
2950 if (!added)
2951 list_add_tail(&collection->stores, &entry->entry);
2952 }
2953 else
2954 list_add_tail(&collection->stores, &entry->entry);
2955 LeaveCriticalSection(&collection->cs);
2956 ret = TRUE;
2957 }
2958 else
2959 ret = FALSE;
2960 return ret;
2961 }
2962
2963 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2964 HCERTSTORE hSiblingStore)
2965 {
2966 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2967 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2968 PWINE_STORE_LIST_ENTRY store, next;
2969
2970 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2971
2972 if (!collection || !sibling)
2973 return;
2974 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2975 {
2976 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2977 return;
2978 }
2979 if (collection->hdr.type != StoreTypeCollection)
2980 return;
2981 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2982 {
2983 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2984 return;
2985 }
2986 EnterCriticalSection(&collection->cs);
2987 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2988 WINE_STORE_LIST_ENTRY, entry)
2989 {
2990 if (store->store == sibling)
2991 {
2992 list_remove(&store->entry);
2993 CertCloseStore(store->store, 0);
2994 CryptMemFree(store);
2995 break;
2996 }
2997 }
2998 LeaveCriticalSection(&collection->cs);
2999 }
3000
3001 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
3002 CRYPT_ATTRIBUTE rgAttr[])
3003 {
3004 PCRYPT_ATTRIBUTE ret = NULL;
3005 DWORD i;
3006
3007 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
3008
3009 if (!cAttr)
3010 return NULL;
3011 if (!pszObjId)
3012 {
3013 SetLastError(ERROR_INVALID_PARAMETER);
3014 return NULL;
3015 }
3016
3017 for (i = 0; !ret && i < cAttr; i++)
3018 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
3019 ret = &rgAttr[i];
3020 return ret;
3021 }
3022
3023 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
3024 CERT_EXTENSION rgExtensions[])
3025 {
3026 PCERT_EXTENSION ret = NULL;
3027 DWORD i;
3028
3029 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
3030
3031 if (!cExtensions)
3032 return NULL;
3033 if (!pszObjId)
3034 {
3035 SetLastError(ERROR_INVALID_PARAMETER);
3036 return NULL;
3037 }
3038
3039 for (i = 0; !ret && i < cExtensions; i++)
3040 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
3041 rgExtensions[i].pszObjId))
3042 ret = &rgExtensions[i];
3043 return ret;
3044 }
3045
3046 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
3047 {
3048 PCERT_RDN_ATTR ret = NULL;
3049 DWORD i, j;
3050
3051 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
3052
3053 if (!pszObjId)
3054 {
3055 SetLastError(ERROR_INVALID_PARAMETER);
3056 return NULL;
3057 }
3058
3059 for (i = 0; !ret && i < pName->cRDN; i++)
3060 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
3061 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
3062 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
3063 ret = &pName->rgRDN[i].rgRDNAttr[j];
3064 return ret;
3065 }
3066
3067 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
3068 PCERT_INFO pCertInfo)
3069 {
3070 FILETIME fileTime;
3071 LONG ret;
3072
3073 if (!pTimeToVerify)
3074 {
3075 SYSTEMTIME sysTime;
3076
3077 GetSystemTime(&sysTime);
3078 SystemTimeToFileTime(&sysTime, &fileTime);
3079 pTimeToVerify = &fileTime;
3080 }
3081 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
3082 {
3083 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
3084 if (ret < 0)
3085 ret = 0;
3086 }
3087 return ret;
3088 }
3089
3090 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
3091 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
3092 DWORD *pcbComputedHash)
3093 {
3094 BOOL ret = TRUE;
3095 HCRYPTHASH hHash = 0;
3096
3097 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
3098 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
3099
3100 if (!hCryptProv)
3101 hCryptProv = CRYPT_GetDefaultProvider();
3102 if (!Algid)
3103 Algid = CALG_SHA1;
3104 if (ret)
3105 {
3106 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
3107 if (ret)
3108 {
3109 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
3110 if (ret)
3111 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
3112 pcbComputedHash, 0);
3113 CryptDestroyHash(hHash);
3114 }
3115 }
3116 return ret;
3117 }
3118
3119 BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3120 DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
3121 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
3122 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
3123 {
3124 BOOL ret;
3125 ALG_ID algID;
3126 HCRYPTHASH hHash;
3127
3128 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv,
3129 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
3130 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
3131
3132 algID = CertOIDToAlgId(pSignatureAlgorithm->pszObjId);
3133 if (!algID)
3134 {
3135 SetLastError(NTE_BAD_ALGID);
3136 return FALSE;
3137 }
3138 if (!hCryptProv)
3139 {
3140 SetLastError(ERROR_INVALID_PARAMETER);
3141 return FALSE;
3142 }
3143
3144 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hHash);
3145 if (ret)
3146 {
3147 ret = CryptHashData(hHash, pbEncodedToBeSigned, cbEncodedToBeSigned, 0);
3148 if (ret)
3149 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
3150 pcbSignature);
3151 CryptDestroyHash(hHash);
3152 }
3153 return ret;
3154 }
3155
3156 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
3157 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
3158 PCERT_PUBLIC_KEY_INFO pPublicKey)
3159 {
3160 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
3161 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
3162 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
3163 }
3164
3165 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
3166 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
3167 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
3168 {
3169 BOOL ret = TRUE;
3170 CRYPT_DATA_BLOB subjectBlob;
3171
3172 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv,
3173 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
3174 dwFlags, pvReserved);
3175
3176 switch (dwSubjectType)
3177 {
3178 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
3179 {
3180 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
3181
3182 subjectBlob.pbData = blob->pbData;
3183 subjectBlob.cbData = blob->cbData;
3184 break;
3185 }
3186 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
3187 {
3188 PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
3189
3190 subjectBlob.pbData = context->pbCertEncoded;
3191 subjectBlob.cbData = context->cbCertEncoded;
3192 break;
3193 }
3194 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
3195 {
3196 PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
3197
3198 subjectBlob.pbData = context->pbCrlEncoded;
3199 subjectBlob.cbData = context->cbCrlEncoded;
3200 break;
3201 }
3202 default:
3203 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3204 ret = FALSE;
3205 }
3206
3207 if (ret)
3208 {
3209 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
3210 DWORD size = 0;
3211
3212 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
3213 subjectBlob.pbData, subjectBlob.cbData,
3214 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
3215 (BYTE *)&signedCert, &size);
3216 if (ret)
3217 {
3218 switch (dwIssuerType)
3219 {
3220 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
3221 {
3222 PCERT_PUBLIC_KEY_INFO pubKeyInfo =
3223 (PCERT_PUBLIC_KEY_INFO)pvIssuer;
3224 ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId);
3225
3226 if (algID)
3227 {
3228 HCRYPTKEY key;
3229
3230 ret = CryptImportPublicKeyInfoEx(hCryptProv,
3231 dwCertEncodingType, pubKeyInfo, algID, 0, NULL, &key);
3232 if (ret)
3233 {
3234 HCRYPTHASH hash;
3235
3236 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash);
3237 if (ret)
3238 {
3239 ret = CryptHashData(hash,
3240 signedCert->ToBeSigned.pbData,
3241 signedCert->ToBeSigned.cbData, 0);
3242 if (ret)
3243 {
3244 ret = CryptVerifySignatureW(hash,
3245 signedCert->Signature.pbData,
3246 signedCert->Signature.cbData, key, NULL, 0);
3247 }
3248 CryptDestroyHash(hash);
3249 }
3250 CryptDestroyKey(key);
3251 }
3252 }
3253 else
3254 {
3255 SetLastError(NTE_BAD_ALGID);
3256 ret = FALSE;
3257 }
3258 break;
3259 }
3260 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
3261 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
3262 FIXME("issuer type %ld: stub\n", dwIssuerType);
3263 ret = FALSE;
3264 break;
3265 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
3266 if (pvIssuer)
3267 {
3268 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3269 ret = FALSE;
3270 }
3271 else
3272 {
3273 FIXME("unimplemented for NULL signer\n");
3274 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3275 ret = FALSE;
3276 }
3277 break;
3278 default:
3279 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3280 ret = FALSE;
3281 }
3282 LocalFree(signedCert);
3283 }
3284 }
3285 return ret;
3286 }
3287
3288 HCRYPTOIDFUNCSET WINAPI CryptInitOIDFunctionSet(LPCSTR pszFuncName, DWORD dwFlags)
3289 {
3290 FIXME("stub: %s %lx\n", debugstr_a(pszFuncName), dwFlags);
3291 return NULL;
3292 }
3293
3294 BOOL WINAPI CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType,
3295 LPCSTR pszFuncName, LPCWSTR pwszDll)
3296 {
3297 FIXME("stub: %lx %s %s\n", dwEncodingType, debugstr_a(pszFuncName), debugstr_w(pwszDll));
3298 return FALSE;
3299 }