wine.inf: We should not override existing associations.
[wine/hacks.git] / dlls / crypt32 / store.c
blob0aaa89d88ba8f69c6cc80ac6585b9e4d8e6f95f5
1 /*
2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2004-2006 Juan Lang
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * FIXME:
20 * - The concept of physical stores and locations isn't implemented. (This
21 * doesn't mean registry stores et al aren't implemented. See the PSDK for
22 * registering and enumerating physical stores and locations.)
23 * - Many flags, options and whatnot are unimplemented.
26 #include <assert.h>
27 #include <stdarg.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winnls.h"
31 #include "winreg.h"
32 #include "winuser.h"
33 #include "wincrypt.h"
34 #include "wine/debug.h"
35 #include "wine/list.h"
36 #include "excpt.h"
37 #include "wine/exception.h"
38 #include "crypt32_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
42 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
44 static const WINE_CONTEXT_INTERFACE gCertInterface = {
45 (CreateContextFunc)CertCreateCertificateContext,
46 (AddContextToStoreFunc)CertAddCertificateContextToStore,
47 (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
48 (DuplicateContextFunc)CertDuplicateCertificateContext,
49 (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
50 (EnumPropertiesFunc)CertEnumCertificateContextProperties,
51 (GetContextPropertyFunc)CertGetCertificateContextProperty,
52 (SetContextPropertyFunc)CertSetCertificateContextProperty,
53 (SerializeElementFunc)CertSerializeCertificateStoreElement,
54 (FreeContextFunc)CertFreeCertificateContext,
55 (DeleteContextFunc)CertDeleteCertificateFromStore,
57 PCWINE_CONTEXT_INTERFACE pCertInterface = &gCertInterface;
59 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
60 (CreateContextFunc)CertCreateCRLContext,
61 (AddContextToStoreFunc)CertAddCRLContextToStore,
62 (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
63 (DuplicateContextFunc)CertDuplicateCRLContext,
64 (EnumContextsInStoreFunc)CertEnumCRLsInStore,
65 (EnumPropertiesFunc)CertEnumCRLContextProperties,
66 (GetContextPropertyFunc)CertGetCRLContextProperty,
67 (SetContextPropertyFunc)CertSetCRLContextProperty,
68 (SerializeElementFunc)CertSerializeCRLStoreElement,
69 (FreeContextFunc)CertFreeCRLContext,
70 (DeleteContextFunc)CertDeleteCRLFromStore,
72 PCWINE_CONTEXT_INTERFACE pCRLInterface = &gCRLInterface;
74 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
75 (CreateContextFunc)CertCreateCTLContext,
76 (AddContextToStoreFunc)CertAddCTLContextToStore,
77 (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
78 (DuplicateContextFunc)CertDuplicateCTLContext,
79 (EnumContextsInStoreFunc)CertEnumCTLsInStore,
80 (EnumPropertiesFunc)CertEnumCTLContextProperties,
81 (GetContextPropertyFunc)CertGetCTLContextProperty,
82 (SetContextPropertyFunc)CertSetCTLContextProperty,
83 (SerializeElementFunc)CertSerializeCTLStoreElement,
84 (FreeContextFunc)CertFreeCTLContext,
85 (DeleteContextFunc)CertDeleteCTLFromStore,
87 PCWINE_CONTEXT_INTERFACE pCTLInterface = &gCTLInterface;
89 struct WINE_CRYPTCERTSTORE;
91 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
92 DWORD dwFlags, const void *pvPara);
94 /* Called to enumerate the next context in a store. */
95 typedef void * (*EnumFunc)(struct WINE_CRYPTCERTSTORE *store, void *pPrev);
97 /* Called to add a context to a store. If toReplace is not NULL,
98 * context replaces toReplace in the store, and access checks should not be
99 * performed. Otherwise context is a new context, and it should only be
100 * added if the store allows it. If ppStoreContext is not NULL, the added
101 * context should be returned in *ppStoreContext.
103 typedef BOOL (*AddFunc)(struct WINE_CRYPTCERTSTORE *store, void *context,
104 void *toReplace, const void **ppStoreContext);
106 typedef BOOL (*DeleteFunc)(struct WINE_CRYPTCERTSTORE *store, void *context);
108 typedef struct _CONTEXT_STORE
110 AddFunc addContext;
111 EnumFunc enumContext;
112 DeleteFunc deleteContext;
113 } CONTEXT_STORE, *PCONTEXT_STORE;
115 typedef enum _CertStoreType {
116 StoreTypeMem,
117 StoreTypeCollection,
118 StoreTypeProvider,
119 } CertStoreType;
121 /* A cert store is polymorphic through the use of function pointers. A type
122 * is still needed to distinguish collection stores from other types.
123 * On the function pointers:
124 * - closeStore is called when the store's ref count becomes 0
125 * - control is optional, but should be implemented by any store that supports
126 * persistence
128 typedef struct WINE_CRYPTCERTSTORE
130 DWORD dwMagic;
131 LONG ref;
132 DWORD dwOpenFlags;
133 HCRYPTPROV cryptProv;
134 CertStoreType type;
135 PFN_CERT_STORE_PROV_CLOSE closeStore;
136 CONTEXT_STORE certs;
137 CONTEXT_STORE crls;
138 PFN_CERT_STORE_PROV_CONTROL control; /* optional */
139 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
141 typedef struct _WINE_MEMSTORE
143 WINECRYPT_CERTSTORE hdr;
144 struct ContextList *certs;
145 struct ContextList *crls;
146 } WINE_MEMSTORE, *PWINE_MEMSTORE;
148 typedef struct _WINE_HASH_TO_DELETE
150 BYTE hash[20];
151 struct list entry;
152 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
154 typedef struct _WINE_REGSTOREINFO
156 DWORD dwOpenFlags;
157 HCRYPTPROV cryptProv;
158 PWINECRYPT_CERTSTORE memStore;
159 HKEY key;
160 BOOL dirty;
161 CRITICAL_SECTION cs;
162 struct list certsToDelete;
163 struct list crlsToDelete;
164 } WINE_REGSTOREINFO, *PWINE_REGSTOREINFO;
166 typedef struct _WINE_FILESTOREINFO
168 DWORD dwOpenFlags;
169 HCRYPTPROV cryptProv;
170 PWINECRYPT_CERTSTORE memStore;
171 HANDLE file;
172 BOOL dirty;
173 } WINE_FILESTOREINFO, *PWINE_FILESTOREINFO;
175 typedef struct _WINE_STORE_LIST_ENTRY
177 PWINECRYPT_CERTSTORE store;
178 DWORD dwUpdateFlags;
179 DWORD dwPriority;
180 struct list entry;
181 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
183 typedef struct _WINE_COLLECTIONSTORE
185 WINECRYPT_CERTSTORE hdr;
186 CRITICAL_SECTION cs;
187 struct list stores;
188 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
190 typedef struct _WINE_PROVIDERSTORE
192 WINECRYPT_CERTSTORE hdr;
193 DWORD dwStoreProvFlags;
194 PWINECRYPT_CERTSTORE memStore;
195 HCERTSTOREPROV hStoreProv;
196 PFN_CERT_STORE_PROV_CLOSE provCloseStore;
197 PFN_CERT_STORE_PROV_WRITE_CERT provWriteCert;
198 PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert;
199 PFN_CERT_STORE_PROV_WRITE_CRL provWriteCrl;
200 PFN_CERT_STORE_PROV_DELETE_CRL provDeleteCrl;
201 PFN_CERT_STORE_PROV_CONTROL provControl;
202 } WINE_PROVIDERSTORE, *PWINE_PROVIDERSTORE;
204 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
205 DWORD dwFlags, CertStoreType type)
207 store->ref = 1;
208 store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
209 store->type = type;
210 if (!hCryptProv)
212 hCryptProv = CRYPT_GetDefaultProvider();
213 dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
215 store->cryptProv = hCryptProv;
216 store->dwOpenFlags = dwFlags;
219 static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, void *cert,
220 void *toReplace, const void **ppStoreContext)
222 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
223 PCERT_CONTEXT context;
225 TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
227 context = (PCERT_CONTEXT)ContextList_Add(ms->certs, cert, toReplace);
228 if (context)
230 context->hCertStore = store;
231 if (ppStoreContext)
232 *ppStoreContext = CertDuplicateCertificateContext(context);
234 return context ? TRUE : FALSE;
237 static void *CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
239 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
240 void *ret;
242 TRACE("(%p, %p)\n", store, pPrev);
244 ret = ContextList_Enum(ms->certs, pPrev);
245 if (!ret)
246 SetLastError(CRYPT_E_NOT_FOUND);
248 TRACE("returning %p\n", ret);
249 return ret;
252 static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext)
254 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
256 ContextList_Delete(ms->certs, pCertContext);
257 return TRUE;
260 static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl,
261 void *toReplace, const void **ppStoreContext)
263 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
264 PCRL_CONTEXT context;
266 TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext);
268 context = (PCRL_CONTEXT)ContextList_Add(ms->crls, crl, toReplace);
269 if (context)
271 context->hCertStore = store;
272 if (ppStoreContext)
273 *ppStoreContext = CertDuplicateCRLContext(context);
275 return context ? TRUE : FALSE;
278 static void *CRYPT_MemEnumCrl(PWINECRYPT_CERTSTORE store, void *pPrev)
280 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
281 void *ret;
283 TRACE("(%p, %p)\n", store, pPrev);
285 ret = ContextList_Enum(ms->crls, pPrev);
286 if (!ret)
287 SetLastError(CRYPT_E_NOT_FOUND);
289 TRACE("returning %p\n", ret);
290 return ret;
293 static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext)
295 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
297 ContextList_Delete(ms->crls, pCrlContext);
298 return TRUE;
301 static void CRYPT_MemEmptyStore(PWINE_MEMSTORE store)
303 ContextList_Empty(store->certs);
304 ContextList_Empty(store->crls);
307 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
309 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
311 TRACE("(%p, %08lx)\n", store, dwFlags);
312 if (dwFlags)
313 FIXME("Unimplemented flags: %08lx\n", dwFlags);
315 ContextList_Free(store->certs);
316 ContextList_Free(store->crls);
317 CryptMemFree(store);
320 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
321 DWORD dwFlags, const void *pvPara)
323 PWINE_MEMSTORE store;
325 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
327 if (dwFlags & CERT_STORE_DELETE_FLAG)
329 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
330 store = NULL;
332 else
334 store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
335 if (store)
337 memset(store, 0, sizeof(WINE_MEMSTORE));
338 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
339 store->hdr.closeStore = CRYPT_MemCloseStore;
340 store->hdr.certs.addContext = CRYPT_MemAddCert;
341 store->hdr.certs.enumContext = CRYPT_MemEnumCert;
342 store->hdr.certs.deleteContext = CRYPT_MemDeleteCert;
343 store->hdr.crls.addContext = CRYPT_MemAddCrl;
344 store->hdr.crls.enumContext = CRYPT_MemEnumCrl;
345 store->hdr.crls.deleteContext = CRYPT_MemDeleteCrl;
346 store->hdr.control = NULL;
347 store->certs = ContextList_Create(pCertInterface,
348 sizeof(CERT_CONTEXT));
349 store->crls = ContextList_Create(pCRLInterface,
350 sizeof(CRL_CONTEXT));
353 return (PWINECRYPT_CERTSTORE)store;
356 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
358 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
359 PWINE_STORE_LIST_ENTRY entry, next;
361 TRACE("(%p, %08lx)\n", store, dwFlags);
363 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
364 entry)
366 TRACE("closing %p\n", entry);
367 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
368 CryptMemFree(entry);
370 DeleteCriticalSection(&cs->cs);
371 CryptMemFree(cs);
374 static void *CRYPT_CollectionCreateContextFromChild(PWINE_COLLECTIONSTORE store,
375 PWINE_STORE_LIST_ENTRY storeEntry, void *child, size_t contextSize,
376 BOOL addRef)
378 void *ret = Context_CreateLinkContext(contextSize, child,
379 sizeof(PWINE_STORE_LIST_ENTRY), addRef);
381 if (ret)
382 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(ret, contextSize)
383 = storeEntry;
385 return ret;
388 static BOOL CRYPT_CollectionAddContext(PWINE_COLLECTIONSTORE store,
389 unsigned int contextStoreOffset, void *context, void *toReplace, unsigned int contextSize,
390 void **pChildContext)
392 BOOL ret;
393 void *childContext = NULL;
394 PWINE_STORE_LIST_ENTRY storeEntry = NULL;
396 TRACE("(%p, %d, %p, %p, %d)\n", store, contextStoreOffset, context,
397 toReplace, contextSize);
399 ret = FALSE;
400 if (toReplace)
402 void *existingLinked = Context_GetLinkedContext(toReplace, contextSize);
403 PCONTEXT_STORE contextStore;
405 storeEntry = *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(toReplace,
406 contextSize);
407 contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store +
408 contextStoreOffset);
409 ret = contextStore->addContext(storeEntry->store, context,
410 existingLinked, (const void **)&childContext);
412 else
414 PWINE_STORE_LIST_ENTRY entry, next;
416 EnterCriticalSection(&store->cs);
417 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores,
418 WINE_STORE_LIST_ENTRY, entry)
420 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
422 PCONTEXT_STORE contextStore = (PCONTEXT_STORE)(
423 (LPBYTE)entry->store + contextStoreOffset);
425 storeEntry = entry;
426 ret = contextStore->addContext(entry->store, context, NULL,
427 (const void **)&childContext);
428 break;
431 LeaveCriticalSection(&store->cs);
432 if (!storeEntry)
433 SetLastError(E_ACCESSDENIED);
435 *pChildContext = childContext;
436 return ret;
439 /* Advances a collection enumeration by one context, if possible, where
440 * advancing means:
441 * - calling the current store's enumeration function once, and returning
442 * the enumerated context if one is returned
443 * - moving to the next store if the current store has no more items, and
444 * recursively calling itself to get the next item.
445 * Returns NULL if the collection contains no more items or on error.
446 * Assumes the collection store's lock is held.
448 static void *CRYPT_CollectionAdvanceEnum(PWINE_COLLECTIONSTORE store,
449 PWINE_STORE_LIST_ENTRY storeEntry, size_t contextStoreOffset,
450 PCWINE_CONTEXT_INTERFACE contextInterface, void *pPrev, size_t contextSize)
452 void *ret, *child;
453 struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
454 PCONTEXT_STORE contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store +
455 contextStoreOffset);
457 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
459 if (pPrev)
461 /* Ref-counting funny business: "duplicate" (addref) the child, because
462 * the free(pPrev) below can cause the ref count to become negative.
464 child = Context_GetLinkedContext(pPrev, contextSize);
465 contextInterface->duplicate(child);
466 child = contextStore->enumContext(storeEntry->store, child);
467 contextInterface->free(pPrev);
468 pPrev = NULL;
470 else
471 child = storeEntry->store->certs.enumContext(storeEntry->store, NULL);
472 if (child)
473 ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child,
474 contextSize, FALSE);
475 else
477 if (storeNext)
478 ret = CRYPT_CollectionAdvanceEnum(store, LIST_ENTRY(storeNext,
479 WINE_STORE_LIST_ENTRY, entry), contextStoreOffset,
480 contextInterface, NULL, contextSize);
481 else
483 SetLastError(CRYPT_E_NOT_FOUND);
484 ret = NULL;
487 TRACE("returning %p\n", ret);
488 return ret;
491 static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, void *cert,
492 void *toReplace, const void **ppStoreContext)
494 BOOL ret;
495 void *childContext = NULL;
496 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
498 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs),
499 cert, toReplace, sizeof(CERT_CONTEXT), &childContext);
500 if (ppStoreContext && childContext)
502 PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
503 Context_GetExtra(childContext, sizeof(CERT_CONTEXT));
504 PCERT_CONTEXT context =
505 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
506 sizeof(CERT_CONTEXT), TRUE);
508 if (context)
509 context->hCertStore = store;
510 *ppStoreContext = context;
512 CertFreeCertificateContext((PCCERT_CONTEXT)childContext);
513 return ret;
516 static void *CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
518 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
519 void *ret;
521 TRACE("(%p, %p)\n", store, pPrev);
523 EnterCriticalSection(&cs->cs);
524 if (pPrev)
526 PWINE_STORE_LIST_ENTRY storeEntry =
527 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
528 sizeof(CERT_CONTEXT));
530 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
531 offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, pPrev,
532 sizeof(CERT_CONTEXT));
534 else
536 if (!list_empty(&cs->stores))
538 PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
539 WINE_STORE_LIST_ENTRY, entry);
541 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
542 offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, NULL,
543 sizeof(CERT_CONTEXT));
545 else
547 SetLastError(CRYPT_E_NOT_FOUND);
548 ret = NULL;
551 LeaveCriticalSection(&cs->cs);
552 if (ret)
553 ((PCERT_CONTEXT)ret)->hCertStore = store;
554 TRACE("returning %p\n", ret);
555 return ret;
558 static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store,
559 void *pCertContext)
561 BOOL ret;
563 TRACE("(%p, %p)\n", store, pCertContext);
565 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)
566 Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT)));
567 return ret;
570 static BOOL CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store, void *crl,
571 void *toReplace, const void **ppStoreContext)
573 BOOL ret;
574 void *childContext = NULL;
575 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
577 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls),
578 crl, toReplace, sizeof(CRL_CONTEXT), &childContext);
579 if (ppStoreContext && childContext)
581 PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
582 Context_GetExtra(childContext, sizeof(CRL_CONTEXT));
583 PCRL_CONTEXT context =
584 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
585 sizeof(CRL_CONTEXT), TRUE);
587 if (context)
588 context->hCertStore = store;
589 *ppStoreContext = context;
591 CertFreeCRLContext((PCCRL_CONTEXT)childContext);
592 return ret;
595 static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev)
597 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
598 void *ret;
600 TRACE("(%p, %p)\n", store, pPrev);
602 EnterCriticalSection(&cs->cs);
603 if (pPrev)
605 PWINE_STORE_LIST_ENTRY storeEntry =
606 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
607 sizeof(CRL_CONTEXT));
609 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
610 offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, pPrev,
611 sizeof(CRL_CONTEXT));
613 else
615 if (!list_empty(&cs->stores))
617 PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
618 WINE_STORE_LIST_ENTRY, entry);
620 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
621 offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, NULL,
622 sizeof(CRL_CONTEXT));
624 else
626 SetLastError(CRYPT_E_NOT_FOUND);
627 ret = NULL;
630 LeaveCriticalSection(&cs->cs);
631 if (ret)
632 ((PCRL_CONTEXT)ret)->hCertStore = store;
633 TRACE("returning %p\n", ret);
634 return ret;
637 static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store,
638 void *pCrlContext)
640 BOOL ret;
642 TRACE("(%p, %p)\n", store, pCrlContext);
644 ret = CertDeleteCRLFromStore((PCCRL_CONTEXT)
645 Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT)));
646 return ret;
649 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
650 DWORD dwFlags, const void *pvPara)
652 PWINE_COLLECTIONSTORE store;
654 if (dwFlags & CERT_STORE_DELETE_FLAG)
656 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
657 store = NULL;
659 else
661 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
662 if (store)
664 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
665 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
666 StoreTypeCollection);
667 store->hdr.closeStore = CRYPT_CollectionCloseStore;
668 store->hdr.certs.addContext = CRYPT_CollectionAddCert;
669 store->hdr.certs.enumContext = CRYPT_CollectionEnumCert;
670 store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert;
671 store->hdr.crls.addContext = CRYPT_CollectionAddCRL;
672 store->hdr.crls.enumContext = CRYPT_CollectionEnumCRL;
673 store->hdr.crls.deleteContext = CRYPT_CollectionDeleteCRL;
674 InitializeCriticalSection(&store->cs);
675 list_init(&store->stores);
678 return (PWINECRYPT_CERTSTORE)store;
681 static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
683 PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
685 TRACE("(%p, %08lx)\n", store, dwFlags);
687 if (store->provCloseStore)
688 store->provCloseStore(store->hStoreProv, dwFlags);
689 if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG))
690 CertCloseStore(store->memStore, dwFlags);
691 CryptMemFree(store);
694 static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, void *cert,
695 void *toReplace, const void **ppStoreContext)
697 PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
698 BOOL ret;
700 TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
702 if (toReplace)
703 ret = ps->memStore->certs.addContext(ps->memStore, cert, toReplace,
704 (const void **)ppStoreContext);
705 else
707 ret = TRUE;
708 if (ps->provWriteCert)
709 ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert,
710 CERT_STORE_PROV_WRITE_ADD_FLAG);
711 if (ret)
712 ret = ps->memStore->certs.addContext(ps->memStore, cert, NULL,
713 (const void **)ppStoreContext);
715 /* dirty trick: replace the returned context's hCertStore with
716 * store.
718 if (ppStoreContext)
719 (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store;
720 return ret;
723 static void *CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
725 PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
726 void *ret;
728 ret = ps->memStore->certs.enumContext(ps->memStore, pPrev);
729 if (ret)
731 /* same dirty trick: replace the returned context's hCertStore with
732 * store.
734 ((PCERT_CONTEXT)ret)->hCertStore = store;
736 return ret;
739 static BOOL CRYPT_ProvDeleteCert(PWINECRYPT_CERTSTORE store, void *cert)
741 PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
742 BOOL ret = TRUE;
744 TRACE("(%p, %p)\n", store, cert);
746 if (ps->provDeleteCert)
747 ret = ps->provDeleteCert(ps->hStoreProv, cert, 0);
748 if (ret)
749 ret = ps->memStore->certs.deleteContext(ps->memStore, cert);
750 return ret;
753 static BOOL CRYPT_ProvAddCRL(PWINECRYPT_CERTSTORE store, void *crl,
754 void *toReplace, const void **ppStoreContext)
756 PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
757 BOOL ret;
759 TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext);
761 if (toReplace)
762 ret = ps->memStore->crls.addContext(ps->memStore, crl, toReplace,
763 (const void **)ppStoreContext);
764 else
766 if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
768 SetLastError(ERROR_ACCESS_DENIED);
769 ret = FALSE;
771 else
773 ret = TRUE;
774 if (ps->provWriteCrl)
775 ret = ps->provWriteCrl(ps->hStoreProv, (PCCRL_CONTEXT)crl,
776 CERT_STORE_PROV_WRITE_ADD_FLAG);
777 if (ret)
778 ret = ps->memStore->crls.addContext(ps->memStore, crl, NULL,
779 (const void **)ppStoreContext);
782 /* dirty trick: replace the returned context's hCertStore with
783 * store.
785 if (ppStoreContext)
786 (*(PCRL_CONTEXT *)ppStoreContext)->hCertStore = store;
787 return ret;
790 static void *CRYPT_ProvEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev)
792 PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
793 void *ret;
795 ret = ps->memStore->crls.enumContext(ps->memStore, pPrev);
796 if (ret)
798 /* same dirty trick: replace the returned context's hCertStore with
799 * store.
801 ((PCERT_CONTEXT)ret)->hCertStore = store;
803 return ret;
806 static BOOL CRYPT_ProvDeleteCRL(PWINECRYPT_CERTSTORE store, void *crl)
808 PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
809 BOOL ret = TRUE;
811 TRACE("(%p, %p)\n", store, crl);
813 if (ps->provDeleteCrl)
814 ret = ps->provDeleteCrl(ps->hStoreProv, crl, 0);
815 if (ret)
816 ret = ps->memStore->crls.deleteContext(ps->memStore, crl);
817 return ret;
820 static BOOL WINAPI CRYPT_ProvControl(HCERTSTORE hCertStore, DWORD dwFlags,
821 DWORD dwCtrlType, void const *pvCtrlPara)
823 PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
824 BOOL ret = TRUE;
826 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
827 pvCtrlPara);
829 if (store->provControl)
830 ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType,
831 pvCtrlPara);
832 return ret;
835 static PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv,
836 DWORD dwFlags, PWINECRYPT_CERTSTORE memStore, PCERT_STORE_PROV_INFO pProvInfo)
838 PWINE_PROVIDERSTORE ret = (PWINE_PROVIDERSTORE)CryptMemAlloc(
839 sizeof(WINE_PROVIDERSTORE));
841 if (ret)
843 CRYPT_InitStore(&ret->hdr, hCryptProv, dwFlags,
844 StoreTypeProvider);
845 ret->dwStoreProvFlags = pProvInfo->dwStoreProvFlags;
846 if (ret->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)
848 CertCloseStore(memStore, 0);
849 ret->memStore = NULL;
851 else
852 ret->memStore = memStore;
853 ret->hStoreProv = pProvInfo->hStoreProv;
854 ret->hdr.closeStore = CRYPT_ProvCloseStore;
855 ret->hdr.certs.addContext = CRYPT_ProvAddCert;
856 ret->hdr.certs.enumContext = CRYPT_ProvEnumCert;
857 ret->hdr.certs.deleteContext = CRYPT_ProvDeleteCert;
858 ret->hdr.crls.addContext = CRYPT_ProvAddCRL;
859 ret->hdr.crls.enumContext = CRYPT_ProvEnumCRL;
860 ret->hdr.crls.deleteContext = CRYPT_ProvDeleteCRL;
861 ret->hdr.control = CRYPT_ProvControl;
862 if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC)
863 ret->provCloseStore =
864 pProvInfo->rgpvStoreProvFunc[CERT_STORE_PROV_CLOSE_FUNC];
865 else
866 ret->provCloseStore = NULL;
867 if (pProvInfo->cStoreProvFunc >
868 CERT_STORE_PROV_WRITE_CERT_FUNC)
869 ret->provWriteCert = pProvInfo->rgpvStoreProvFunc[
870 CERT_STORE_PROV_WRITE_CERT_FUNC];
871 else
872 ret->provWriteCert = NULL;
873 if (pProvInfo->cStoreProvFunc >
874 CERT_STORE_PROV_DELETE_CERT_FUNC)
875 ret->provDeleteCert = pProvInfo->rgpvStoreProvFunc[
876 CERT_STORE_PROV_DELETE_CERT_FUNC];
877 else
878 ret->provDeleteCert = NULL;
879 if (pProvInfo->cStoreProvFunc >
880 CERT_STORE_PROV_WRITE_CRL_FUNC)
881 ret->provWriteCrl = pProvInfo->rgpvStoreProvFunc[
882 CERT_STORE_PROV_WRITE_CRL_FUNC];
883 else
884 ret->provWriteCert = NULL;
885 if (pProvInfo->cStoreProvFunc >
886 CERT_STORE_PROV_DELETE_CRL_FUNC)
887 ret->provDeleteCrl = pProvInfo->rgpvStoreProvFunc[
888 CERT_STORE_PROV_DELETE_CRL_FUNC];
889 else
890 ret->provDeleteCert = NULL;
891 if (pProvInfo->cStoreProvFunc >
892 CERT_STORE_PROV_CONTROL_FUNC)
893 ret->provControl = pProvInfo->rgpvStoreProvFunc[
894 CERT_STORE_PROV_CONTROL_FUNC];
895 else
896 ret->provControl = NULL;
898 return (PWINECRYPT_CERTSTORE)ret;
901 static PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider,
902 DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara)
904 static HCRYPTOIDFUNCSET set = NULL;
905 PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc;
906 HCRYPTOIDFUNCADDR hFunc;
907 PWINECRYPT_CERTSTORE ret = NULL;
909 if (!set)
910 set = CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0);
911 CryptGetOIDFunctionAddress(set, dwEncodingType, lpszStoreProvider, 0,
912 (void **)&provOpenFunc, &hFunc);
913 if (provOpenFunc)
915 CERT_STORE_PROV_INFO provInfo = { 0 };
917 provInfo.cbSize = sizeof(provInfo);
918 if (dwFlags & CERT_STORE_DELETE_FLAG)
919 provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
920 dwFlags, pvPara, NULL, &provInfo);
921 else
923 HCERTSTORE memStore;
925 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
926 CERT_STORE_CREATE_NEW_FLAG, NULL);
927 if (memStore)
929 if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
930 dwFlags, pvPara, memStore, &provInfo))
931 ret = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
932 &provInfo);
933 else
934 CertCloseStore(memStore, 0);
937 CryptFreeOIDFunctionAddress(hFunc, 0);
939 else
940 SetLastError(ERROR_FILE_NOT_FOUND);
941 return ret;
944 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
946 static const WCHAR fmt[] = { '%','0','2','X',0 };
947 DWORD i;
949 assert(hash);
950 assert(asciiHash);
952 for (i = 0; i < 20; i++)
953 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
956 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
957 0 };
958 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
959 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
960 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
962 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTOREINFO store, HKEY key,
963 DWORD contextType)
965 LONG rc;
966 DWORD index = 0;
967 WCHAR subKeyName[MAX_PATH];
969 do {
970 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
972 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
973 NULL);
974 if (!rc)
976 HKEY subKey;
978 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
979 if (!rc)
981 LPBYTE buf = NULL;
983 size = 0;
984 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
985 if (!rc)
986 buf = CryptMemAlloc(size);
987 if (buf)
989 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
990 &size);
991 if (!rc)
993 const void *context;
994 DWORD addedType;
996 TRACE("Adding cert with hash %s\n",
997 debugstr_w(subKeyName));
998 context = CRYPT_ReadSerializedElement(buf, size,
999 contextType, &addedType);
1000 if (context)
1002 const WINE_CONTEXT_INTERFACE *contextInterface;
1003 BYTE hash[20];
1005 switch (addedType)
1007 case CERT_STORE_CERTIFICATE_CONTEXT:
1008 contextInterface = &gCertInterface;
1009 break;
1010 case CERT_STORE_CRL_CONTEXT:
1011 contextInterface = &gCRLInterface;
1012 break;
1013 case CERT_STORE_CTL_CONTEXT:
1014 contextInterface = &gCTLInterface;
1015 break;
1016 default:
1017 contextInterface = NULL;
1019 if (contextInterface)
1021 size = sizeof(hash);
1022 if (contextInterface->getProp(context,
1023 CERT_HASH_PROP_ID, hash, &size))
1025 WCHAR asciiHash[20 * 2 + 1];
1027 CRYPT_HashToStr(hash, asciiHash);
1028 TRACE("comparing %s\n",
1029 debugstr_w(asciiHash));
1030 TRACE("with %s\n", debugstr_w(subKeyName));
1031 if (!lstrcmpW(asciiHash, subKeyName))
1033 TRACE("hash matches, adding\n");
1034 contextInterface->addContextToStore(
1035 store->memStore, context,
1036 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
1038 else
1039 TRACE("hash doesn't match, ignoring\n");
1041 contextInterface->free(context);
1045 CryptMemFree(buf);
1047 RegCloseKey(subKey);
1049 /* Ignore intermediate errors, continue enumerating */
1050 rc = ERROR_SUCCESS;
1052 } while (!rc);
1055 static void CRYPT_RegReadFromReg(PWINE_REGSTOREINFO store)
1057 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1058 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
1059 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
1060 DWORD i;
1062 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1064 HKEY key;
1065 LONG rc;
1067 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
1068 &key, NULL);
1069 if (!rc)
1071 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
1072 RegCloseKey(key);
1077 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
1078 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
1079 DWORD len)
1081 WCHAR asciiHash[20 * 2 + 1];
1082 LONG rc;
1083 HKEY subKey;
1084 BOOL ret;
1086 CRYPT_HashToStr(hash, asciiHash);
1087 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
1088 &subKey, NULL);
1089 if (!rc)
1091 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
1092 RegCloseKey(subKey);
1094 if (!rc)
1095 ret = TRUE;
1096 else
1098 SetLastError(rc);
1099 ret = FALSE;
1101 return ret;
1104 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
1105 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
1107 const void *context = NULL;
1108 BOOL ret;
1110 do {
1111 context = contextInterface->enumContextsInStore(memStore, context);
1112 if (context)
1114 BYTE hash[20];
1115 DWORD hashSize = sizeof(hash);
1117 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1118 &hashSize);
1119 if (ret)
1121 DWORD size = 0;
1122 LPBYTE buf = NULL;
1124 ret = contextInterface->serialize(context, 0, NULL, &size);
1125 if (size)
1126 buf = CryptMemAlloc(size);
1127 if (buf)
1129 ret = contextInterface->serialize(context, 0, buf, &size);
1130 if (ret)
1131 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1133 CryptMemFree(buf);
1136 else
1137 ret = TRUE;
1138 } while (ret && context != NULL);
1139 if (context)
1140 contextInterface->free(context);
1141 return ret;
1144 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store)
1146 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1147 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1148 &gCRLInterface, &gCTLInterface };
1149 struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete,
1150 NULL };
1151 BOOL ret = TRUE;
1152 DWORD i;
1154 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1156 HKEY key;
1157 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1158 KEY_ALL_ACCESS, NULL, &key, NULL);
1160 if (!rc)
1162 if (listToDelete[i])
1164 PWINE_HASH_TO_DELETE toDelete, next;
1165 WCHAR asciiHash[20 * 2 + 1];
1167 EnterCriticalSection(&store->cs);
1168 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1169 WINE_HASH_TO_DELETE, entry)
1171 LONG rc;
1173 CRYPT_HashToStr(toDelete->hash, asciiHash);
1174 TRACE("Removing %s\n", debugstr_w(asciiHash));
1175 rc = RegDeleteKeyW(key, asciiHash);
1176 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1178 SetLastError(rc);
1179 ret = FALSE;
1181 list_remove(&toDelete->entry);
1182 CryptMemFree(toDelete);
1184 LeaveCriticalSection(&store->cs);
1186 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1187 store->memStore);
1188 RegCloseKey(key);
1190 else
1192 SetLastError(rc);
1193 ret = FALSE;
1196 return ret;
1199 /* If force is true or the registry store is dirty, writes the contents of the
1200 * store to the registry.
1202 static BOOL CRYPT_RegFlushStore(PWINE_REGSTOREINFO store, BOOL force)
1204 BOOL ret;
1206 TRACE("(%p, %d)\n", store, force);
1208 if (store->dirty || force)
1209 ret = CRYPT_RegWriteToReg(store);
1210 else
1211 ret = TRUE;
1212 return ret;
1215 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1217 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1219 TRACE("(%p, %08lx)\n", store, dwFlags);
1220 if (dwFlags)
1221 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1223 CRYPT_RegFlushStore(store, FALSE);
1224 RegCloseKey(store->key);
1225 DeleteCriticalSection(&store->cs);
1226 CryptMemFree(store);
1229 static BOOL WINAPI CRYPT_RegWriteContext(PWINE_REGSTOREINFO store,
1230 const void *context, DWORD dwFlags)
1232 BOOL ret;
1234 if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG)
1236 store->dirty = TRUE;
1237 ret = TRUE;
1239 else
1240 ret = FALSE;
1241 return ret;
1244 static BOOL CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store,
1245 struct list *deleteList, const void *context,
1246 PCWINE_CONTEXT_INTERFACE contextInterface)
1248 BOOL ret;
1250 if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG)
1252 SetLastError(ERROR_ACCESS_DENIED);
1253 ret = FALSE;
1255 else
1257 PWINE_HASH_TO_DELETE toDelete =
1258 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1260 if (toDelete)
1262 DWORD size = sizeof(toDelete->hash);
1264 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID,
1265 toDelete->hash, &size);
1266 if (ret)
1268 EnterCriticalSection(&store->cs);
1269 list_add_tail(deleteList, &toDelete->entry);
1270 LeaveCriticalSection(&store->cs);
1272 else
1274 CryptMemFree(toDelete);
1275 ret = FALSE;
1278 else
1279 ret = FALSE;
1280 if (ret)
1281 store->dirty = TRUE;
1283 return ret;
1286 static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore,
1287 PCCERT_CONTEXT cert, DWORD dwFlags)
1289 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1291 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags);
1293 return CRYPT_RegWriteContext(store, cert, dwFlags);
1296 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1297 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1299 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1301 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1303 return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext,
1304 pCertInterface);
1307 static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore,
1308 PCCRL_CONTEXT crl, DWORD dwFlags)
1310 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1312 TRACE("(%p, %p, %ld)\n", hCertStore, crl, dwFlags);
1314 return CRYPT_RegWriteContext(store, crl, dwFlags);
1317 static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore,
1318 PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
1320 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1322 TRACE("(%p, %p, %08lx)\n", store, pCrlContext, dwFlags);
1324 return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext,
1325 pCRLInterface);
1328 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1329 DWORD dwCtrlType, void const *pvCtrlPara)
1331 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1332 BOOL ret;
1334 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
1335 pvCtrlPara);
1337 switch (dwCtrlType)
1339 case CERT_STORE_CTRL_RESYNC:
1340 CRYPT_RegFlushStore(store, FALSE);
1341 CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore);
1342 CRYPT_RegReadFromReg(store);
1343 ret = TRUE;
1344 break;
1345 case CERT_STORE_CTRL_COMMIT:
1346 ret = CRYPT_RegFlushStore(store,
1347 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1348 break;
1349 default:
1350 FIXME("%ld: stub\n", dwCtrlType);
1351 ret = FALSE;
1353 return ret;
1356 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1357 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1359 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1360 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1361 HKEY hSubKey = 0;
1363 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1365 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1366 if (!dwRet)
1368 /* Find how many subkeys there are */
1369 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1370 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1371 if (!dwRet)
1373 dwMaxSubkeyLen++;
1374 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1376 /* Name too big: alloc a buffer for it */
1377 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1380 if (!lpszName)
1381 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1382 else
1384 /* Recursively delete all the subkeys */
1385 for (i = 0; i < dwKeyCount && !dwRet; i++)
1387 dwSize = dwMaxSubkeyLen;
1388 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1389 NULL, NULL, NULL);
1390 if (!dwRet)
1391 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1394 if (lpszName != szNameBuf)
1396 /* Free buffer if allocated */
1397 CryptMemFree(lpszName);
1402 RegCloseKey(hSubKey);
1403 if (!dwRet)
1404 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1406 return dwRet;
1409 static void *regProvFuncs[] = {
1410 CRYPT_RegCloseStore,
1411 NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
1412 CRYPT_RegWriteCert,
1413 CRYPT_RegDeleteCert,
1414 NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
1415 NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
1416 CRYPT_RegWriteCRL,
1417 CRYPT_RegDeleteCRL,
1418 NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
1419 NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
1420 NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
1421 NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
1422 NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
1423 CRYPT_RegControl,
1426 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1427 DWORD dwFlags, const void *pvPara)
1429 PWINECRYPT_CERTSTORE store = NULL;
1431 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1433 if (dwFlags & CERT_STORE_DELETE_FLAG)
1435 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1437 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1438 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1439 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1440 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1441 if (rc == ERROR_NO_MORE_ITEMS)
1442 rc = ERROR_SUCCESS;
1443 SetLastError(rc);
1445 else
1447 HKEY key;
1449 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1450 GetCurrentProcess(), (LPHANDLE)&key,
1451 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1452 TRUE, 0))
1454 PWINECRYPT_CERTSTORE memStore;
1456 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1457 if (memStore)
1459 PWINE_REGSTOREINFO regInfo = CryptMemAlloc(
1460 sizeof(WINE_REGSTOREINFO));
1462 if (regInfo)
1464 CERT_STORE_PROV_INFO provInfo = { 0 };
1466 regInfo->dwOpenFlags = dwFlags;
1467 regInfo->cryptProv = hCryptProv;
1468 regInfo->memStore = memStore;
1469 regInfo->key = key;
1470 InitializeCriticalSection(&regInfo->cs);
1471 list_init(&regInfo->certsToDelete);
1472 list_init(&regInfo->crlsToDelete);
1473 CRYPT_RegReadFromReg(regInfo);
1474 regInfo->dirty = FALSE;
1475 provInfo.cbSize = sizeof(provInfo);
1476 provInfo.cStoreProvFunc = sizeof(regProvFuncs) /
1477 sizeof(regProvFuncs[0]);
1478 provInfo.rgpvStoreProvFunc = regProvFuncs;
1479 provInfo.hStoreProv = regInfo;
1480 store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
1481 &provInfo);
1486 TRACE("returning %p\n", store);
1487 return store;
1490 /* FIXME: this isn't complete for the Root store, in which the top-level
1491 * self-signed CA certs reside. Adding a cert to the Root store should present
1492 * the user with a dialog indicating the consequences of doing so, and asking
1493 * the user to confirm whether the cert should be added.
1495 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1496 DWORD dwFlags, const void *pvPara)
1498 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1499 LPCWSTR storeName = (LPCWSTR)pvPara;
1500 LPWSTR storePath;
1501 PWINECRYPT_CERTSTORE store = NULL;
1502 HKEY root;
1503 LPCWSTR base;
1504 BOOL ret;
1506 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1507 debugstr_w((LPCWSTR)pvPara));
1509 if (!pvPara)
1511 SetLastError(E_INVALIDARG);
1512 return NULL;
1515 ret = TRUE;
1516 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1518 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1519 root = HKEY_LOCAL_MACHINE;
1520 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1521 break;
1522 case CERT_SYSTEM_STORE_CURRENT_USER:
1523 root = HKEY_CURRENT_USER;
1524 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1525 break;
1526 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1527 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1528 * SystemCertificates
1530 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1531 debugstr_w(storeName));
1532 return NULL;
1533 case CERT_SYSTEM_STORE_SERVICES:
1534 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1535 * SystemCertificates
1537 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1538 debugstr_w(storeName));
1539 return NULL;
1540 case CERT_SYSTEM_STORE_USERS:
1541 /* hku\user sid\Software\Microsoft\SystemCertificates */
1542 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1543 debugstr_w(storeName));
1544 return NULL;
1545 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1546 root = HKEY_CURRENT_USER;
1547 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1548 break;
1549 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1550 root = HKEY_LOCAL_MACHINE;
1551 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1552 break;
1553 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1554 /* hklm\Software\Microsoft\EnterpriseCertificates */
1555 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1556 debugstr_w(storeName));
1557 return NULL;
1558 default:
1559 SetLastError(E_INVALIDARG);
1560 return NULL;
1563 storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1564 sizeof(WCHAR));
1565 if (storePath)
1567 LONG rc;
1568 HKEY key;
1569 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1570 KEY_ALL_ACCESS;
1572 wsprintfW(storePath, fmt, base, storeName);
1573 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1574 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1575 else
1577 DWORD disp;
1579 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1580 &key, &disp);
1581 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1582 disp == REG_OPENED_EXISTING_KEY)
1584 RegCloseKey(key);
1585 rc = ERROR_FILE_EXISTS;
1588 if (!rc)
1590 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1591 RegCloseKey(key);
1593 else
1594 SetLastError(rc);
1595 CryptMemFree(storePath);
1597 return store;
1600 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1601 DWORD dwFlags, const void *pvPara)
1603 int len;
1604 PWINECRYPT_CERTSTORE ret = NULL;
1606 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1607 debugstr_a((LPCSTR)pvPara));
1609 if (!pvPara)
1611 SetLastError(ERROR_FILE_NOT_FOUND);
1612 return NULL;
1614 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1615 if (len)
1617 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1619 if (storeName)
1621 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1622 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1623 CryptMemFree(storeName);
1626 return ret;
1629 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1630 DWORD dwFlags, const void *pvPara)
1632 HCERTSTORE store = 0;
1633 BOOL ret;
1635 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1636 debugstr_w((LPCWSTR)pvPara));
1638 if (!pvPara)
1640 SetLastError(ERROR_FILE_NOT_FOUND);
1641 return NULL;
1643 /* This returns a different error than system registry stores if the
1644 * location is invalid.
1646 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1648 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1649 case CERT_SYSTEM_STORE_CURRENT_USER:
1650 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1651 case CERT_SYSTEM_STORE_SERVICES:
1652 case CERT_SYSTEM_STORE_USERS:
1653 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1654 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1655 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1656 ret = TRUE;
1657 break;
1658 default:
1659 SetLastError(ERROR_FILE_NOT_FOUND);
1660 ret = FALSE;
1662 if (ret)
1664 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1665 0, hCryptProv, dwFlags, pvPara);
1667 if (regStore)
1669 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1670 CERT_STORE_CREATE_NEW_FLAG, NULL);
1671 CertAddStoreToCollection(store, regStore,
1672 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1673 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1674 CertCloseStore(regStore, 0);
1675 /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
1676 * stores.
1678 if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
1679 CERT_SYSTEM_STORE_CURRENT_USER)
1681 dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
1682 dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
1683 regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0,
1684 hCryptProv, dwFlags, pvPara);
1685 if (regStore)
1687 CertAddStoreToCollection(store, regStore,
1688 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1689 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1690 CertCloseStore(regStore, 0);
1695 return (PWINECRYPT_CERTSTORE)store;
1698 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1699 DWORD dwFlags, const void *pvPara)
1701 int len;
1702 PWINECRYPT_CERTSTORE ret = NULL;
1704 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1705 debugstr_a((LPCSTR)pvPara));
1707 if (!pvPara)
1709 SetLastError(ERROR_FILE_NOT_FOUND);
1710 return NULL;
1712 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1713 if (len)
1715 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1717 if (storeName)
1719 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1720 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1721 CryptMemFree(storeName);
1724 return ret;
1727 static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1729 PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1731 TRACE("(%p, %08lx)\n", store, dwFlags);
1732 if (store->dirty)
1733 CRYPT_WriteSerializedFile(store->file, store->memStore);
1734 CertCloseStore(store->memStore, dwFlags);
1735 CloseHandle(store->file);
1736 CryptMemFree(store);
1739 static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore,
1740 PCCERT_CONTEXT cert, DWORD dwFlags)
1742 PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1744 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags);
1745 store->dirty = TRUE;
1746 return TRUE;
1749 static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore,
1750 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1752 PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1754 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
1755 store->dirty = TRUE;
1756 return TRUE;
1759 static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore,
1760 PCCRL_CONTEXT crl, DWORD dwFlags)
1762 PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1764 TRACE("(%p, %p, %ld)\n", hCertStore, crl, dwFlags);
1765 store->dirty = TRUE;
1766 return TRUE;
1769 static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore,
1770 PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
1772 PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1774 TRACE("(%p, %p, %08lx)\n", hCertStore, pCrlContext, dwFlags);
1775 store->dirty = TRUE;
1776 return TRUE;
1779 static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags,
1780 DWORD dwCtrlType, void const *pvCtrlPara)
1782 PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1783 BOOL ret;
1785 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
1786 pvCtrlPara);
1788 switch (dwCtrlType)
1790 case CERT_STORE_CTRL_RESYNC:
1791 CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore);
1792 CRYPT_ReadSerializedFile(store->file, store);
1793 ret = TRUE;
1794 break;
1795 case CERT_STORE_CTRL_COMMIT:
1796 if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
1798 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1799 ret = FALSE;
1801 else if (store->dirty)
1802 ret = CRYPT_WriteSerializedFile(store->file, store->memStore);
1803 else
1804 ret = TRUE;
1805 break;
1806 default:
1807 FIXME("%ld: stub\n", dwCtrlType);
1808 ret = FALSE;
1810 return ret;
1813 static void *fileProvFuncs[] = {
1814 CRYPT_FileCloseStore,
1815 NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
1816 CRYPT_FileWriteCert,
1817 CRYPT_FileDeleteCert,
1818 NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
1819 NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
1820 CRYPT_FileWriteCRL,
1821 CRYPT_FileDeleteCRL,
1822 NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
1823 NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
1824 NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
1825 NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
1826 NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
1827 CRYPT_FileControl,
1830 static PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv,
1831 DWORD dwFlags, const void *pvPara)
1833 PWINECRYPT_CERTSTORE store = NULL;
1834 HANDLE file = (HANDLE)pvPara;
1836 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1838 if (!pvPara)
1840 SetLastError(ERROR_INVALID_HANDLE);
1841 return NULL;
1843 if (dwFlags & CERT_STORE_DELETE_FLAG)
1845 SetLastError(E_INVALIDARG);
1846 return NULL;
1848 if ((dwFlags & CERT_STORE_READONLY_FLAG) &&
1849 (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
1851 SetLastError(E_INVALIDARG);
1852 return NULL;
1855 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1856 GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ?
1857 GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0))
1859 PWINECRYPT_CERTSTORE memStore;
1861 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1862 if (memStore)
1864 if (CRYPT_ReadSerializedFile(file, memStore))
1866 PWINE_FILESTOREINFO info = CryptMemAlloc(
1867 sizeof(WINE_FILESTOREINFO));
1869 if (info)
1871 CERT_STORE_PROV_INFO provInfo = { 0 };
1873 info->dwOpenFlags = dwFlags;
1874 info->cryptProv = hCryptProv;
1875 info->memStore = memStore;
1876 info->file = file;
1877 info->dirty = FALSE;
1878 provInfo.cbSize = sizeof(provInfo);
1879 provInfo.cStoreProvFunc = sizeof(fileProvFuncs) /
1880 sizeof(fileProvFuncs[0]);
1881 provInfo.rgpvStoreProvFunc = fileProvFuncs;
1882 provInfo.hStoreProv = info;
1883 store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
1884 &provInfo);
1889 TRACE("returning %p\n", store);
1890 return store;
1893 static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
1894 DWORD dwFlags, const void *pvPara)
1896 HCERTSTORE store = 0;
1897 LPCWSTR fileName = (LPCWSTR)pvPara;
1898 DWORD access, create;
1899 HANDLE file;
1901 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName));
1903 if (!fileName)
1905 SetLastError(ERROR_PATH_NOT_FOUND);
1906 return NULL;
1908 if (!(dwFlags & (CERT_FILE_STORE_COMMIT_ENABLE_FLAG |
1909 CERT_STORE_READONLY_FLAG)))
1911 SetLastError(ERROR_FILE_NOT_FOUND);
1912 return NULL;
1915 access = GENERIC_READ;
1916 if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
1917 access |= GENERIC_WRITE;
1918 if (dwFlags & CERT_STORE_CREATE_NEW_FLAG)
1919 create = CREATE_NEW;
1920 else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1921 create = OPEN_EXISTING;
1922 else
1923 create = OPEN_ALWAYS;
1924 file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create,
1925 FILE_ATTRIBUTE_NORMAL, NULL);
1926 if (file != INVALID_HANDLE_VALUE)
1928 /* FIXME: need to check whether it's a serialized store; if not, fall
1929 * back to a PKCS#7 signed message, then to a single serialized cert.
1931 store = CertOpenStore(CERT_STORE_PROV_FILE, 0, hCryptProv, dwFlags,
1932 file);
1933 CloseHandle(file);
1935 return (PWINECRYPT_CERTSTORE)store;
1938 static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
1939 DWORD dwFlags, const void *pvPara)
1941 int len;
1942 PWINECRYPT_CERTSTORE ret = NULL;
1944 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1945 debugstr_a((LPCSTR)pvPara));
1947 if (!pvPara)
1949 SetLastError(ERROR_FILE_NOT_FOUND);
1950 return NULL;
1952 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1953 if (len)
1955 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1957 if (storeName)
1959 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1960 ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName);
1961 CryptMemFree(storeName);
1964 return ret;
1967 static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv,
1968 DWORD dwFlags, const void *pvPara)
1970 if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
1971 FIXME("(%ld, %08lx, %p): stub\n", hCryptProv, dwFlags, pvPara);
1972 else
1973 FIXME("(%ld, %08lx, %s): stub\n", hCryptProv, dwFlags,
1974 debugstr_w((LPCWSTR)pvPara));
1975 return NULL;
1978 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1979 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1980 const void* pvPara)
1982 WINECRYPT_CERTSTORE *hcs;
1983 StoreOpenFunc openFunc = NULL;
1985 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1986 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1988 if (!HIWORD(lpszStoreProvider))
1990 switch (LOWORD(lpszStoreProvider))
1992 case (int)CERT_STORE_PROV_MEMORY:
1993 openFunc = CRYPT_MemOpenStore;
1994 break;
1995 case (int)CERT_STORE_PROV_FILE:
1996 openFunc = CRYPT_FileOpenStore;
1997 break;
1998 case (int)CERT_STORE_PROV_REG:
1999 openFunc = CRYPT_RegOpenStore;
2000 break;
2001 case (int)CERT_STORE_PROV_FILENAME_A:
2002 openFunc = CRYPT_FileNameOpenStoreA;
2003 break;
2004 case (int)CERT_STORE_PROV_FILENAME_W:
2005 openFunc = CRYPT_FileNameOpenStoreW;
2006 break;
2007 case (int)CERT_STORE_PROV_COLLECTION:
2008 openFunc = CRYPT_CollectionOpenStore;
2009 break;
2010 case (int)CERT_STORE_PROV_SYSTEM_A:
2011 openFunc = CRYPT_SysOpenStoreA;
2012 break;
2013 case (int)CERT_STORE_PROV_SYSTEM_W:
2014 openFunc = CRYPT_SysOpenStoreW;
2015 break;
2016 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
2017 openFunc = CRYPT_SysRegOpenStoreA;
2018 break;
2019 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
2020 openFunc = CRYPT_SysRegOpenStoreW;
2021 break;
2022 case (int)CERT_STORE_PROV_PHYSICAL_W:
2023 openFunc = CRYPT_PhysOpenStoreW;
2024 break;
2025 default:
2026 if (LOWORD(lpszStoreProvider))
2027 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
2030 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
2031 openFunc = CRYPT_MemOpenStore;
2032 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_FILENAME_W))
2033 openFunc = CRYPT_FileOpenStore;
2034 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
2035 openFunc = CRYPT_SysOpenStoreW;
2036 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
2037 openFunc = CRYPT_CollectionOpenStore;
2038 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
2039 openFunc = CRYPT_SysRegOpenStoreW;
2040 else
2042 FIXME("unimplemented type %s\n", lpszStoreProvider);
2043 openFunc = NULL;
2046 if (!openFunc)
2047 hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
2048 hCryptProv, dwFlags, pvPara);
2049 else
2050 hcs = openFunc(hCryptProv, dwFlags, pvPara);
2051 return (HCERTSTORE)hcs;
2054 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
2055 LPCSTR szSubSystemProtocol)
2057 if (!szSubSystemProtocol)
2059 SetLastError(E_INVALIDARG);
2060 return 0;
2062 return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
2063 CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
2066 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
2067 LPCWSTR szSubSystemProtocol)
2069 if (!szSubSystemProtocol)
2071 SetLastError(E_INVALIDARG);
2072 return 0;
2074 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
2075 CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
2078 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
2079 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
2081 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
2082 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
2083 return TRUE;
2086 DWORD CertStore_GetAccessState(HCERTSTORE hCertStore)
2088 DWORD state = 0;
2090 if (hCertStore)
2092 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2094 if (store->type != StoreTypeMem &&
2095 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2096 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2098 return state;
2101 #define CertContext_CopyProperties(to, from) \
2102 Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT))
2104 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2105 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2106 PCCERT_CONTEXT *ppStoreContext)
2108 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2109 BOOL ret = TRUE;
2110 PCCERT_CONTEXT toAdd = NULL, existing = NULL;
2112 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2113 dwAddDisposition, ppStoreContext);
2115 /* Weird case to pass a test */
2116 if (dwAddDisposition == 0)
2118 SetLastError(STATUS_ACCESS_VIOLATION);
2119 return FALSE;
2121 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
2123 BYTE hashToAdd[20];
2124 DWORD size = sizeof(hashToAdd);
2126 ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
2127 hashToAdd, &size);
2128 if (ret)
2130 CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
2132 existing = CertFindCertificateInStore(hCertStore,
2133 pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
2134 NULL);
2138 switch (dwAddDisposition)
2140 case CERT_STORE_ADD_ALWAYS:
2141 toAdd = CertDuplicateCertificateContext(pCertContext);
2142 break;
2143 case CERT_STORE_ADD_NEW:
2144 if (existing)
2146 TRACE("found matching certificate, not adding\n");
2147 SetLastError(CRYPT_E_EXISTS);
2148 ret = FALSE;
2150 else
2151 toAdd = CertDuplicateCertificateContext(pCertContext);
2152 break;
2153 case CERT_STORE_ADD_REPLACE_EXISTING:
2154 toAdd = CertDuplicateCertificateContext(pCertContext);
2155 break;
2156 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
2157 toAdd = CertDuplicateCertificateContext(pCertContext);
2158 if (existing)
2159 CertContext_CopyProperties(toAdd, existing);
2160 break;
2161 case CERT_STORE_ADD_USE_EXISTING:
2162 if (existing)
2163 CertContext_CopyProperties(existing, pCertContext);
2164 break;
2165 default:
2166 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
2167 ret = FALSE;
2170 if (toAdd)
2172 if (store)
2173 ret = store->certs.addContext(store, (void *)toAdd,
2174 (void *)existing, (const void **)ppStoreContext);
2175 else if (ppStoreContext)
2176 *ppStoreContext = CertDuplicateCertificateContext(toAdd);
2177 CertFreeCertificateContext(toAdd);
2179 CertFreeCertificateContext(existing);
2181 TRACE("returning %d\n", ret);
2182 return ret;
2185 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2186 PCCERT_CONTEXT pPrev)
2188 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2189 PCCERT_CONTEXT ret;
2191 TRACE("(%p, %p)\n", hCertStore, pPrev);
2192 if (!hCertStore)
2193 ret = NULL;
2194 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2195 ret = NULL;
2196 else
2197 ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
2198 return ret;
2201 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2203 BOOL ret;
2205 TRACE("(%p)\n", pCertContext);
2207 if (!pCertContext)
2208 ret = TRUE;
2209 else if (!pCertContext->hCertStore)
2211 ret = TRUE;
2212 CertFreeCertificateContext(pCertContext);
2214 else
2216 PWINECRYPT_CERTSTORE hcs =
2217 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2219 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2220 ret = FALSE;
2221 else
2222 ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
2223 CertFreeCertificateContext(pCertContext);
2225 return ret;
2228 #define CrlContext_CopyProperties(to, from) \
2229 Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
2231 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
2232 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2233 PCCRL_CONTEXT* ppStoreContext)
2235 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2236 BOOL ret = TRUE;
2237 PCCRL_CONTEXT toAdd = NULL, existing = NULL;
2239 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCrlContext,
2240 dwAddDisposition, ppStoreContext);
2242 /* Weird case to pass a test */
2243 if (dwAddDisposition == 0)
2245 SetLastError(STATUS_ACCESS_VIOLATION);
2246 return FALSE;
2248 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
2250 existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
2251 pCrlContext, NULL);
2254 switch (dwAddDisposition)
2256 case CERT_STORE_ADD_ALWAYS:
2257 toAdd = CertDuplicateCRLContext(pCrlContext);
2258 break;
2259 case CERT_STORE_ADD_NEW:
2260 if (existing)
2262 TRACE("found matching CRL, not adding\n");
2263 SetLastError(CRYPT_E_EXISTS);
2264 ret = FALSE;
2266 else
2267 toAdd = CertDuplicateCRLContext(pCrlContext);
2268 break;
2269 case CERT_STORE_ADD_NEWER:
2270 if (existing)
2272 LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
2273 &pCrlContext->pCrlInfo->ThisUpdate);
2275 if (newer < 0)
2276 toAdd = CertDuplicateCRLContext(pCrlContext);
2277 else
2279 TRACE("existing CRL is newer, not adding\n");
2280 SetLastError(CRYPT_E_EXISTS);
2281 ret = FALSE;
2284 else
2285 toAdd = CertDuplicateCRLContext(pCrlContext);
2286 break;
2287 case CERT_STORE_ADD_REPLACE_EXISTING:
2288 toAdd = CertDuplicateCRLContext(pCrlContext);
2289 break;
2290 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
2291 toAdd = CertDuplicateCRLContext(pCrlContext);
2292 if (existing)
2293 CrlContext_CopyProperties(toAdd, existing);
2294 break;
2295 case CERT_STORE_ADD_USE_EXISTING:
2296 if (existing)
2297 CrlContext_CopyProperties(existing, pCrlContext);
2298 break;
2299 default:
2300 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
2301 ret = FALSE;
2304 if (toAdd)
2306 if (store)
2307 ret = store->crls.addContext(store, (void *)toAdd,
2308 (void *)existing, (const void **)ppStoreContext);
2309 else if (ppStoreContext)
2310 *ppStoreContext = CertDuplicateCRLContext(toAdd);
2311 CertFreeCRLContext(toAdd);
2313 CertFreeCRLContext(existing);
2315 TRACE("returning %d\n", ret);
2316 return ret;
2319 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2321 BOOL ret;
2323 TRACE("(%p)\n", pCrlContext);
2325 if (!pCrlContext)
2326 ret = TRUE;
2327 else if (!pCrlContext->hCertStore)
2329 ret = TRUE;
2330 CertFreeCRLContext(pCrlContext);
2332 else
2334 PWINECRYPT_CERTSTORE hcs =
2335 (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore;
2337 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2338 ret = FALSE;
2339 else
2340 ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
2341 CertFreeCRLContext(pCrlContext);
2343 return ret;
2346 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2347 PCCRL_CONTEXT pPrev)
2349 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2350 PCCRL_CONTEXT ret;
2352 TRACE("(%p, %p)\n", hCertStore, pPrev);
2353 if (!hCertStore)
2354 ret = NULL;
2355 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2356 ret = NULL;
2357 else
2358 ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
2359 return ret;
2362 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2363 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2365 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2366 cbCtlEncoded);
2367 return NULL;
2370 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2371 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2372 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2374 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2375 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2376 ppCtlContext);
2377 return FALSE;
2380 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2381 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2382 PCCTL_CONTEXT* ppStoreContext)
2384 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2385 dwAddDisposition, ppStoreContext);
2386 return TRUE;
2389 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
2391 FIXME("(%p): stub\n", pCtlContext );
2392 return pCtlContext;
2395 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2397 FIXME("(%p): stub\n", pCtlContext );
2398 return TRUE;
2401 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2403 FIXME("(%p): stub\n", pCtlContext);
2404 return TRUE;
2407 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2408 PCCTL_CONTEXT pPrev)
2410 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2411 return NULL;
2414 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
2416 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2418 TRACE("(%p)\n", hCertStore);
2420 if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
2421 InterlockedIncrement(&hcs->ref);
2422 return hCertStore;
2425 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2427 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2429 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2431 if( ! hCertStore )
2432 return TRUE;
2434 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2435 return FALSE;
2437 if (InterlockedDecrement(&hcs->ref) == 0)
2439 TRACE("%p's ref count is 0, freeing\n", hcs);
2440 hcs->dwMagic = 0;
2441 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2442 CryptReleaseContext(hcs->cryptProv, 0);
2443 hcs->closeStore(hcs, dwFlags);
2445 else
2446 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2447 return TRUE;
2450 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2451 DWORD dwCtrlType, void const *pvCtrlPara)
2453 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2454 BOOL ret;
2456 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2457 pvCtrlPara);
2459 if (!hcs)
2460 ret = FALSE;
2461 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2462 ret = FALSE;
2463 else
2465 if (hcs->control)
2466 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2467 else
2468 ret = TRUE;
2470 return ret;
2473 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
2474 DWORD dwPropId)
2476 FIXME("(%p, %ld): stub\n", pCTLContext, dwPropId);
2477 return 0;
2480 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2481 DWORD dwPropId, void *pvData, DWORD *pcbData)
2483 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2484 return FALSE;
2487 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2488 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2490 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2491 pvData);
2492 return FALSE;
2495 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2496 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2498 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2499 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2500 PWINE_STORE_LIST_ENTRY entry;
2501 BOOL ret;
2503 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2504 dwUpdateFlags, dwPriority);
2506 if (!collection || !sibling)
2507 return TRUE;
2508 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2510 SetLastError(E_INVALIDARG);
2511 return FALSE;
2513 if (collection->hdr.type != StoreTypeCollection)
2515 SetLastError(E_INVALIDARG);
2516 return FALSE;
2518 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2520 SetLastError(E_INVALIDARG);
2521 return FALSE;
2524 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2525 if (entry)
2527 InterlockedIncrement(&sibling->ref);
2528 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2529 entry->store = sibling;
2530 entry->dwUpdateFlags = dwUpdateFlags;
2531 entry->dwPriority = dwPriority;
2532 list_init(&entry->entry);
2533 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2534 EnterCriticalSection(&collection->cs);
2535 if (dwPriority)
2537 PWINE_STORE_LIST_ENTRY cursor;
2538 BOOL added = FALSE;
2540 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2541 WINE_STORE_LIST_ENTRY, entry)
2543 if (cursor->dwPriority < dwPriority)
2545 list_add_before(&cursor->entry, &entry->entry);
2546 added = TRUE;
2547 break;
2550 if (!added)
2551 list_add_tail(&collection->stores, &entry->entry);
2553 else
2554 list_add_tail(&collection->stores, &entry->entry);
2555 LeaveCriticalSection(&collection->cs);
2556 ret = TRUE;
2558 else
2559 ret = FALSE;
2560 return ret;
2563 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2564 HCERTSTORE hSiblingStore)
2566 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2567 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2568 PWINE_STORE_LIST_ENTRY store, next;
2570 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2572 if (!collection || !sibling)
2573 return;
2574 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2576 SetLastError(E_INVALIDARG);
2577 return;
2579 if (collection->hdr.type != StoreTypeCollection)
2580 return;
2581 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2583 SetLastError(E_INVALIDARG);
2584 return;
2586 EnterCriticalSection(&collection->cs);
2587 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2588 WINE_STORE_LIST_ENTRY, entry)
2590 if (store->store == sibling)
2592 list_remove(&store->entry);
2593 CertCloseStore(store->store, 0);
2594 CryptMemFree(store);
2595 break;
2598 LeaveCriticalSection(&collection->cs);