shell32: Declare some functions static.
[wine] / dlls / crypt32 / store.c
1 /*
2  * Copyright 2002 Mike McCormack for CodeWeavers
3  * Copyright 2004-2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
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.
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <assert.h>
30 #include <stdarg.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "winuser.h"
36 #include "wincrypt.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "excpt.h"
40 #include "wine/exception.h"
41 #include "crypt32_private.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
44
45 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
46
47 static const WINE_CONTEXT_INTERFACE gCertInterface = {
48     (CreateContextFunc)CertCreateCertificateContext,
49     (AddContextToStoreFunc)CertAddCertificateContextToStore,
50     (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
51     (DuplicateContextFunc)CertDuplicateCertificateContext,
52     (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
53     (EnumPropertiesFunc)CertEnumCertificateContextProperties,
54     (GetContextPropertyFunc)CertGetCertificateContextProperty,
55     (SetContextPropertyFunc)CertSetCertificateContextProperty,
56     (SerializeElementFunc)CertSerializeCertificateStoreElement,
57     (FreeContextFunc)CertFreeCertificateContext,
58     (DeleteContextFunc)CertDeleteCertificateFromStore,
59 };
60 PCWINE_CONTEXT_INTERFACE pCertInterface = &gCertInterface;
61
62 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
63     (CreateContextFunc)CertCreateCRLContext,
64     (AddContextToStoreFunc)CertAddCRLContextToStore,
65     (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
66     (DuplicateContextFunc)CertDuplicateCRLContext,
67     (EnumContextsInStoreFunc)CertEnumCRLsInStore,
68     (EnumPropertiesFunc)CertEnumCRLContextProperties,
69     (GetContextPropertyFunc)CertGetCRLContextProperty,
70     (SetContextPropertyFunc)CertSetCRLContextProperty,
71     (SerializeElementFunc)CertSerializeCRLStoreElement,
72     (FreeContextFunc)CertFreeCRLContext,
73     (DeleteContextFunc)CertDeleteCRLFromStore,
74 };
75 PCWINE_CONTEXT_INTERFACE pCRLInterface = &gCRLInterface;
76
77 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
78     (CreateContextFunc)CertCreateCTLContext,
79     (AddContextToStoreFunc)CertAddCTLContextToStore,
80     (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
81     (DuplicateContextFunc)CertDuplicateCTLContext,
82     (EnumContextsInStoreFunc)CertEnumCTLsInStore,
83     (EnumPropertiesFunc)CertEnumCTLContextProperties,
84     (GetContextPropertyFunc)CertGetCTLContextProperty,
85     (SetContextPropertyFunc)CertSetCTLContextProperty,
86     (SerializeElementFunc)CertSerializeCTLStoreElement,
87     (FreeContextFunc)CertFreeCTLContext,
88     (DeleteContextFunc)CertDeleteCTLFromStore,
89 };
90 PCWINE_CONTEXT_INTERFACE pCTLInterface = &gCTLInterface;
91
92 struct WINE_CRYPTCERTSTORE;
93
94 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
95  DWORD dwFlags, const void *pvPara);
96
97 /* Called to enumerate the next context in a store. */
98 typedef void * (*EnumFunc)(struct WINE_CRYPTCERTSTORE *store, void *pPrev);
99
100 /* Called to add a context to a store.  If toReplace is not NULL,
101  * context replaces toReplace in the store, and access checks should not be
102  * performed.  Otherwise context is a new context, and it should only be
103  * added if the store allows it.  If ppStoreContext is not NULL, the added
104  * context should be returned in *ppStoreContext.
105  */
106 typedef BOOL (*AddFunc)(struct WINE_CRYPTCERTSTORE *store, void *context,
107  void *toReplace, const void **ppStoreContext);
108
109 typedef BOOL (*DeleteFunc)(struct WINE_CRYPTCERTSTORE *store, void *context);
110
111 typedef struct _CONTEXT_STORE
112 {
113     AddFunc    addContext;
114     EnumFunc   enumContext;
115     DeleteFunc deleteContext;
116 } CONTEXT_STORE, *PCONTEXT_STORE;
117
118 typedef enum _CertStoreType {
119     StoreTypeMem,
120     StoreTypeCollection,
121     StoreTypeProvider,
122 } CertStoreType;
123
124 /* A cert store is polymorphic through the use of function pointers.  A type
125  * is still needed to distinguish collection stores from other types.
126  * On the function pointers:
127  * - closeStore is called when the store's ref count becomes 0
128  * - control is optional, but should be implemented by any store that supports
129  *   persistence
130  */
131 typedef struct WINE_CRYPTCERTSTORE
132 {
133     DWORD                       dwMagic;
134     LONG                        ref;
135     DWORD                       dwOpenFlags;
136     HCRYPTPROV                  cryptProv;
137     CertStoreType               type;
138     PFN_CERT_STORE_PROV_CLOSE   closeStore;
139     CONTEXT_STORE               certs;
140     CONTEXT_STORE               crls;
141     PFN_CERT_STORE_PROV_CONTROL control; /* optional */
142 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
143
144 typedef struct _WINE_MEMSTORE
145 {
146     WINECRYPT_CERTSTORE hdr;
147     struct ContextList *certs;
148     struct ContextList *crls;
149 } WINE_MEMSTORE, *PWINE_MEMSTORE;
150
151 typedef struct _WINE_HASH_TO_DELETE
152 {
153     BYTE        hash[20];
154     struct list entry;
155 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
156
157 typedef struct _WINE_REGSTOREINFO
158 {
159     DWORD                dwOpenFlags;
160     HCRYPTPROV           cryptProv;
161     PWINECRYPT_CERTSTORE memStore;
162     HKEY                 key;
163     BOOL                 dirty;
164     CRITICAL_SECTION     cs;
165     struct list          certsToDelete;
166     struct list          crlsToDelete;
167 } WINE_REGSTOREINFO, *PWINE_REGSTOREINFO;
168
169 typedef struct _WINE_FILESTOREINFO
170 {
171     DWORD                dwOpenFlags;
172     HCRYPTPROV           cryptProv;
173     PWINECRYPT_CERTSTORE memStore;
174     HANDLE               file;
175     BOOL                 dirty;
176 } WINE_FILESTOREINFO, *PWINE_FILESTOREINFO;
177
178 typedef struct _WINE_STORE_LIST_ENTRY
179 {
180     PWINECRYPT_CERTSTORE store;
181     DWORD                dwUpdateFlags;
182     DWORD                dwPriority;
183     struct list          entry;
184 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
185
186 typedef struct _WINE_COLLECTIONSTORE
187 {
188     WINECRYPT_CERTSTORE hdr;
189     CRITICAL_SECTION    cs;
190     struct list         stores;
191 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
192
193 typedef struct _WINE_PROVIDERSTORE
194 {
195     WINECRYPT_CERTSTORE             hdr;
196     DWORD                           dwStoreProvFlags;
197     PWINECRYPT_CERTSTORE            memStore;
198     HCERTSTOREPROV                  hStoreProv;
199     PFN_CERT_STORE_PROV_CLOSE       provCloseStore;
200     PFN_CERT_STORE_PROV_WRITE_CERT  provWriteCert;
201     PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert;
202     PFN_CERT_STORE_PROV_WRITE_CRL   provWriteCrl;
203     PFN_CERT_STORE_PROV_DELETE_CRL  provDeleteCrl;
204     PFN_CERT_STORE_PROV_CONTROL     provControl;
205 } WINE_PROVIDERSTORE, *PWINE_PROVIDERSTORE;
206
207 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
208  DWORD dwFlags, CertStoreType type)
209 {
210     store->ref = 1;
211     store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
212     store->type = type;
213     if (!hCryptProv)
214     {
215         hCryptProv = CRYPT_GetDefaultProvider();
216         dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
217     }
218     store->cryptProv = hCryptProv;
219     store->dwOpenFlags = dwFlags;
220 }
221
222 static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, void *cert,
223  void *toReplace, const void **ppStoreContext)
224 {
225     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
226     PCERT_CONTEXT context;
227
228     TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
229
230     context = (PCERT_CONTEXT)ContextList_Add(ms->certs, cert, toReplace);
231     if (context)
232     {
233         context->hCertStore = store;
234         if (ppStoreContext)
235             *ppStoreContext = CertDuplicateCertificateContext(context);
236     }
237     return context ? TRUE : FALSE;
238 }
239
240 static void *CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
241 {
242     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
243     void *ret;
244
245     TRACE("(%p, %p)\n", store, pPrev);
246
247     ret = ContextList_Enum(ms->certs, pPrev);
248     if (!ret)
249         SetLastError(CRYPT_E_NOT_FOUND);
250
251     TRACE("returning %p\n", ret);
252     return ret;
253 }
254
255 static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext)
256 {
257     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
258
259     ContextList_Delete(ms->certs, pCertContext);
260     return TRUE;
261 }
262
263 static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl,
264  void *toReplace, const void **ppStoreContext)
265 {
266     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
267     PCRL_CONTEXT context;
268
269     TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext);
270
271     context = (PCRL_CONTEXT)ContextList_Add(ms->crls, crl, toReplace);
272     if (context)
273     {
274         context->hCertStore = store;
275         if (ppStoreContext)
276             *ppStoreContext = CertDuplicateCRLContext(context);
277     }
278     return context ? TRUE : FALSE;
279 }
280
281 static void *CRYPT_MemEnumCrl(PWINECRYPT_CERTSTORE store, void *pPrev)
282 {
283     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
284     void *ret;
285
286     TRACE("(%p, %p)\n", store, pPrev);
287
288     ret = ContextList_Enum(ms->crls, pPrev);
289     if (!ret)
290         SetLastError(CRYPT_E_NOT_FOUND);
291
292     TRACE("returning %p\n", ret);
293     return ret;
294 }
295
296 static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext)
297 {
298     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
299
300     ContextList_Delete(ms->crls, pCrlContext);
301     return TRUE;
302 }
303
304 static void CRYPT_MemEmptyStore(PWINE_MEMSTORE store)
305 {
306     ContextList_Empty(store->certs);
307     ContextList_Empty(store->crls);
308 }
309
310 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
311 {
312     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
313
314     TRACE("(%p, %08x)\n", store, dwFlags);
315     if (dwFlags)
316         FIXME("Unimplemented flags: %08x\n", dwFlags);
317
318     ContextList_Free(store->certs);
319     ContextList_Free(store->crls);
320     CryptMemFree(store);
321 }
322
323 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
324  DWORD dwFlags, const void *pvPara)
325 {
326     PWINE_MEMSTORE store;
327
328     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
329
330     if (dwFlags & CERT_STORE_DELETE_FLAG)
331     {
332         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
333         store = NULL;
334     }
335     else
336     {
337         store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
338         if (store)
339         {
340             memset(store, 0, sizeof(WINE_MEMSTORE));
341             CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
342             store->hdr.closeStore          = CRYPT_MemCloseStore;
343             store->hdr.certs.addContext    = CRYPT_MemAddCert;
344             store->hdr.certs.enumContext   = CRYPT_MemEnumCert;
345             store->hdr.certs.deleteContext = CRYPT_MemDeleteCert;
346             store->hdr.crls.addContext     = CRYPT_MemAddCrl;
347             store->hdr.crls.enumContext    = CRYPT_MemEnumCrl;
348             store->hdr.crls.deleteContext  = CRYPT_MemDeleteCrl;
349             store->hdr.control             = NULL;
350             store->certs = ContextList_Create(pCertInterface,
351              sizeof(CERT_CONTEXT));
352             store->crls = ContextList_Create(pCRLInterface,
353              sizeof(CRL_CONTEXT));
354         }
355     }
356     return (PWINECRYPT_CERTSTORE)store;
357 }
358
359 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
360 {
361     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
362     PWINE_STORE_LIST_ENTRY entry, next;
363
364     TRACE("(%p, %08x)\n", store, dwFlags);
365
366     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
367      entry)
368     {
369         TRACE("closing %p\n", entry);
370         CertCloseStore((HCERTSTORE)entry->store, dwFlags);
371         CryptMemFree(entry);
372     }
373     DeleteCriticalSection(&cs->cs);
374     CryptMemFree(cs);
375 }
376
377 static void *CRYPT_CollectionCreateContextFromChild(PWINE_COLLECTIONSTORE store,
378  PWINE_STORE_LIST_ENTRY storeEntry, void *child, size_t contextSize,
379  BOOL addRef)
380 {
381     void *ret = Context_CreateLinkContext(contextSize, child,
382      sizeof(PWINE_STORE_LIST_ENTRY), addRef);
383
384     if (ret)
385         *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(ret, contextSize)
386          = storeEntry;
387
388     return ret;
389 }
390
391 static BOOL CRYPT_CollectionAddContext(PWINE_COLLECTIONSTORE store,
392  unsigned int contextStoreOffset, void *context, void *toReplace, unsigned int contextSize,
393  void **pChildContext)
394 {
395     BOOL ret;
396     void *childContext = NULL;
397     PWINE_STORE_LIST_ENTRY storeEntry = NULL;
398
399     TRACE("(%p, %d, %p, %p, %d)\n", store, contextStoreOffset, context,
400      toReplace, contextSize);
401
402     ret = FALSE;
403     if (toReplace)
404     {
405         void *existingLinked = Context_GetLinkedContext(toReplace, contextSize);
406         PCONTEXT_STORE contextStore;
407
408         storeEntry = *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(toReplace,
409          contextSize);
410         contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store +
411          contextStoreOffset);
412         ret = contextStore->addContext(storeEntry->store, context,
413          existingLinked, (const void **)&childContext);
414     }
415     else
416     {
417         PWINE_STORE_LIST_ENTRY entry, next;
418
419         EnterCriticalSection(&store->cs);
420         LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores,
421          WINE_STORE_LIST_ENTRY, entry)
422         {
423             if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
424             {
425                 PCONTEXT_STORE contextStore = (PCONTEXT_STORE)(
426                  (LPBYTE)entry->store + contextStoreOffset);
427
428                 storeEntry = entry;
429                 ret = contextStore->addContext(entry->store, context, NULL,
430                  (const void **)&childContext);
431                 break;
432             }
433         }
434         LeaveCriticalSection(&store->cs);
435         if (!storeEntry)
436             SetLastError(E_ACCESSDENIED);
437     }
438     *pChildContext = childContext;
439     return ret;
440 }
441
442 /* Advances a collection enumeration by one context, if possible, where
443  * advancing means:
444  * - calling the current store's enumeration function once, and returning
445  *   the enumerated context if one is returned
446  * - moving to the next store if the current store has no more items, and
447  *   recursively calling itself to get the next item.
448  * Returns NULL if the collection contains no more items or on error.
449  * Assumes the collection store's lock is held.
450  */
451 static void *CRYPT_CollectionAdvanceEnum(PWINE_COLLECTIONSTORE store,
452  PWINE_STORE_LIST_ENTRY storeEntry, size_t contextStoreOffset,
453  PCWINE_CONTEXT_INTERFACE contextInterface, void *pPrev, size_t contextSize)
454 {
455     void *ret, *child;
456     struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
457     PCONTEXT_STORE contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store +
458      contextStoreOffset);
459
460     TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
461
462     if (pPrev)
463     {
464         /* Ref-counting funny business: "duplicate" (addref) the child, because
465          * the free(pPrev) below can cause the ref count to become negative.
466          */
467         child = Context_GetLinkedContext(pPrev, contextSize);
468         contextInterface->duplicate(child);
469         child = contextStore->enumContext(storeEntry->store, child);
470         contextInterface->free(pPrev);
471         pPrev = NULL;
472     }
473     else
474         child = storeEntry->store->certs.enumContext(storeEntry->store, NULL);
475     if (child)
476         ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child,
477          contextSize, FALSE);
478     else
479     {
480         if (storeNext)
481             ret = CRYPT_CollectionAdvanceEnum(store, LIST_ENTRY(storeNext,
482              WINE_STORE_LIST_ENTRY, entry), contextStoreOffset,
483              contextInterface, NULL, contextSize);
484         else
485         {
486             SetLastError(CRYPT_E_NOT_FOUND);
487             ret = NULL;
488         }
489     }
490     TRACE("returning %p\n", ret);
491     return ret;
492 }
493
494 static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, void *cert,
495  void *toReplace, const void **ppStoreContext)
496 {
497     BOOL ret;
498     void *childContext = NULL;
499     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
500
501     ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs),
502      cert, toReplace, sizeof(CERT_CONTEXT), &childContext);
503     if (ppStoreContext && childContext)
504     {
505         PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
506          Context_GetExtra(childContext, sizeof(CERT_CONTEXT));
507         PCERT_CONTEXT context =
508          CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
509          sizeof(CERT_CONTEXT), TRUE);
510
511         if (context)
512             context->hCertStore = store;
513         *ppStoreContext = context;
514     }
515     CertFreeCertificateContext((PCCERT_CONTEXT)childContext);
516     return ret;
517 }
518
519 static void *CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
520 {
521     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
522     void *ret;
523
524     TRACE("(%p, %p)\n", store, pPrev);
525
526     EnterCriticalSection(&cs->cs);
527     if (pPrev)
528     {
529         PWINE_STORE_LIST_ENTRY storeEntry =
530          *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
531          sizeof(CERT_CONTEXT));
532
533         ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
534          offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, pPrev,
535          sizeof(CERT_CONTEXT));
536     }
537     else
538     {
539         if (!list_empty(&cs->stores))
540         {
541             PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
542              WINE_STORE_LIST_ENTRY, entry);
543
544             ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
545              offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, NULL,
546              sizeof(CERT_CONTEXT));
547         }
548         else
549         {
550             SetLastError(CRYPT_E_NOT_FOUND);
551             ret = NULL;
552         }
553     }
554     LeaveCriticalSection(&cs->cs);
555     if (ret)
556         ((PCERT_CONTEXT)ret)->hCertStore = store;
557     TRACE("returning %p\n", ret);
558     return ret;
559 }
560
561 static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store,
562  void *pCertContext)
563 {
564     BOOL ret;
565
566     TRACE("(%p, %p)\n", store, pCertContext);
567
568     ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)
569      Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT)));
570     return ret;
571 }
572
573 static BOOL CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store, void *crl,
574  void *toReplace, const void **ppStoreContext)
575 {
576     BOOL ret;
577     void *childContext = NULL;
578     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
579
580     ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls),
581      crl, toReplace, sizeof(CRL_CONTEXT), &childContext);
582     if (ppStoreContext && childContext)
583     {
584         PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
585          Context_GetExtra(childContext, sizeof(CRL_CONTEXT));
586         PCRL_CONTEXT context =
587          CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
588          sizeof(CRL_CONTEXT), TRUE);
589
590         if (context)
591             context->hCertStore = store;
592         *ppStoreContext = context;
593     }
594     CertFreeCRLContext((PCCRL_CONTEXT)childContext);
595     return ret;
596 }
597
598 static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev)
599 {
600     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
601     void *ret;
602
603     TRACE("(%p, %p)\n", store, pPrev);
604
605     EnterCriticalSection(&cs->cs);
606     if (pPrev)
607     {
608         PWINE_STORE_LIST_ENTRY storeEntry =
609          *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
610          sizeof(CRL_CONTEXT));
611
612         ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
613          offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, pPrev,
614          sizeof(CRL_CONTEXT));
615     }
616     else
617     {
618         if (!list_empty(&cs->stores))
619         {
620             PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
621              WINE_STORE_LIST_ENTRY, entry);
622
623             ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
624              offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, NULL,
625              sizeof(CRL_CONTEXT));
626         }
627         else
628         {
629             SetLastError(CRYPT_E_NOT_FOUND);
630             ret = NULL;
631         }
632     }
633     LeaveCriticalSection(&cs->cs);
634     if (ret)
635         ((PCRL_CONTEXT)ret)->hCertStore = store;
636     TRACE("returning %p\n", ret);
637     return ret;
638 }
639
640 static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store,
641  void *pCrlContext)
642 {
643     BOOL ret;
644
645     TRACE("(%p, %p)\n", store, pCrlContext);
646
647     ret = CertDeleteCRLFromStore((PCCRL_CONTEXT)
648      Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT)));
649     return ret;
650 }
651
652 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
653  DWORD dwFlags, const void *pvPara)
654 {
655     PWINE_COLLECTIONSTORE store;
656
657     if (dwFlags & CERT_STORE_DELETE_FLAG)
658     {
659         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
660         store = NULL;
661     }
662     else
663     {
664         store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
665         if (store)
666         {
667             memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
668             CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
669              StoreTypeCollection);
670             store->hdr.closeStore          = CRYPT_CollectionCloseStore;
671             store->hdr.certs.addContext    = CRYPT_CollectionAddCert;
672             store->hdr.certs.enumContext   = CRYPT_CollectionEnumCert;
673             store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert;
674             store->hdr.crls.addContext     = CRYPT_CollectionAddCRL;
675             store->hdr.crls.enumContext    = CRYPT_CollectionEnumCRL;
676             store->hdr.crls.deleteContext  = CRYPT_CollectionDeleteCRL;
677             InitializeCriticalSection(&store->cs);
678             list_init(&store->stores);
679         }
680     }
681     return (PWINECRYPT_CERTSTORE)store;
682 }
683
684 static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
685 {
686     PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
687
688     TRACE("(%p, %08x)\n", store, dwFlags);
689
690     if (store->provCloseStore)
691         store->provCloseStore(store->hStoreProv, dwFlags);
692     if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG))
693         CertCloseStore(store->memStore, dwFlags);
694     CryptMemFree(store);
695 }
696
697 static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, void *cert,
698  void *toReplace, const void **ppStoreContext)
699 {
700     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
701     BOOL ret;
702
703     TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
704
705     if (toReplace)
706         ret = ps->memStore->certs.addContext(ps->memStore, cert, toReplace,
707          (const void **)ppStoreContext);
708     else
709     {
710         ret = TRUE;
711         if (ps->provWriteCert)
712             ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert,
713              CERT_STORE_PROV_WRITE_ADD_FLAG);
714         if (ret)
715             ret = ps->memStore->certs.addContext(ps->memStore, cert, NULL,
716              (const void **)ppStoreContext);
717     }
718     /* dirty trick: replace the returned context's hCertStore with
719      * store.
720      */
721     if (ppStoreContext)
722         (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store;
723     return ret;
724 }
725
726 static void *CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
727 {
728     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
729     void *ret;
730
731     ret = ps->memStore->certs.enumContext(ps->memStore, pPrev);
732     if (ret)
733     {
734         /* same dirty trick: replace the returned context's hCertStore with
735          * store.
736          */
737         ((PCERT_CONTEXT)ret)->hCertStore = store;
738     }
739     return ret;
740 }
741
742 static BOOL CRYPT_ProvDeleteCert(PWINECRYPT_CERTSTORE store, void *cert)
743 {
744     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
745     BOOL ret = TRUE;
746
747     TRACE("(%p, %p)\n", store, cert);
748
749     if (ps->provDeleteCert)
750         ret = ps->provDeleteCert(ps->hStoreProv, cert, 0);
751     if (ret)
752         ret = ps->memStore->certs.deleteContext(ps->memStore, cert);
753     return ret;
754 }
755
756 static BOOL CRYPT_ProvAddCRL(PWINECRYPT_CERTSTORE store, void *crl,
757  void *toReplace, const void **ppStoreContext)
758 {
759     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
760     BOOL ret;
761
762     TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext);
763
764     if (toReplace)
765         ret = ps->memStore->crls.addContext(ps->memStore, crl, toReplace,
766          (const void **)ppStoreContext);
767     else
768     {
769         if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
770         {
771             SetLastError(ERROR_ACCESS_DENIED);
772             ret = FALSE;
773         }
774         else
775         {
776             ret = TRUE;
777             if (ps->provWriteCrl)
778                 ret = ps->provWriteCrl(ps->hStoreProv, (PCCRL_CONTEXT)crl,
779                  CERT_STORE_PROV_WRITE_ADD_FLAG);
780             if (ret)
781                 ret = ps->memStore->crls.addContext(ps->memStore, crl, NULL,
782                  (const void **)ppStoreContext);
783         }
784     }
785     /* dirty trick: replace the returned context's hCertStore with
786      * store.
787      */
788     if (ppStoreContext)
789         (*(PCRL_CONTEXT *)ppStoreContext)->hCertStore = store;
790     return ret;
791 }
792
793 static void *CRYPT_ProvEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev)
794 {
795     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
796     void *ret;
797
798     ret = ps->memStore->crls.enumContext(ps->memStore, pPrev);
799     if (ret)
800     {
801         /* same dirty trick: replace the returned context's hCertStore with
802          * store.
803          */
804         ((PCERT_CONTEXT)ret)->hCertStore = store;
805     }
806     return ret;
807 }
808
809 static BOOL CRYPT_ProvDeleteCRL(PWINECRYPT_CERTSTORE store, void *crl)
810 {
811     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
812     BOOL ret = TRUE;
813
814     TRACE("(%p, %p)\n", store, crl);
815
816     if (ps->provDeleteCrl)
817         ret = ps->provDeleteCrl(ps->hStoreProv, crl, 0);
818     if (ret)
819         ret = ps->memStore->crls.deleteContext(ps->memStore, crl);
820     return ret;
821 }
822
823 static BOOL WINAPI CRYPT_ProvControl(HCERTSTORE hCertStore, DWORD dwFlags,
824  DWORD dwCtrlType, void const *pvCtrlPara)
825 {
826     PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
827     BOOL ret = TRUE;
828
829     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
830      pvCtrlPara);
831
832     if (store->provControl)
833         ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType,
834          pvCtrlPara);
835     return ret;
836 }
837
838 static PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv,
839  DWORD dwFlags, PWINECRYPT_CERTSTORE memStore, PCERT_STORE_PROV_INFO pProvInfo)
840 {
841     PWINE_PROVIDERSTORE ret = (PWINE_PROVIDERSTORE)CryptMemAlloc(
842      sizeof(WINE_PROVIDERSTORE));
843
844     if (ret)
845     {
846         CRYPT_InitStore(&ret->hdr, hCryptProv, dwFlags,
847          StoreTypeProvider);
848         ret->dwStoreProvFlags = pProvInfo->dwStoreProvFlags;
849         if (ret->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)
850         {
851             CertCloseStore(memStore, 0);
852             ret->memStore = NULL;
853         }
854         else
855             ret->memStore = memStore;
856         ret->hStoreProv = pProvInfo->hStoreProv;
857         ret->hdr.closeStore = CRYPT_ProvCloseStore;
858         ret->hdr.certs.addContext = CRYPT_ProvAddCert;
859         ret->hdr.certs.enumContext = CRYPT_ProvEnumCert;
860         ret->hdr.certs.deleteContext = CRYPT_ProvDeleteCert;
861         ret->hdr.crls.addContext = CRYPT_ProvAddCRL;
862         ret->hdr.crls.enumContext = CRYPT_ProvEnumCRL;
863         ret->hdr.crls.deleteContext = CRYPT_ProvDeleteCRL;
864         ret->hdr.control = CRYPT_ProvControl;
865         if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC)
866             ret->provCloseStore =
867              pProvInfo->rgpvStoreProvFunc[CERT_STORE_PROV_CLOSE_FUNC];
868         else
869             ret->provCloseStore = NULL;
870         if (pProvInfo->cStoreProvFunc >
871          CERT_STORE_PROV_WRITE_CERT_FUNC)
872             ret->provWriteCert = pProvInfo->rgpvStoreProvFunc[
873              CERT_STORE_PROV_WRITE_CERT_FUNC];
874         else
875             ret->provWriteCert = NULL;
876         if (pProvInfo->cStoreProvFunc >
877          CERT_STORE_PROV_DELETE_CERT_FUNC)
878             ret->provDeleteCert = pProvInfo->rgpvStoreProvFunc[
879              CERT_STORE_PROV_DELETE_CERT_FUNC];
880         else
881             ret->provDeleteCert = NULL;
882         if (pProvInfo->cStoreProvFunc >
883          CERT_STORE_PROV_WRITE_CRL_FUNC)
884             ret->provWriteCrl = pProvInfo->rgpvStoreProvFunc[
885              CERT_STORE_PROV_WRITE_CRL_FUNC];
886         else
887             ret->provWriteCert = NULL;
888         if (pProvInfo->cStoreProvFunc >
889          CERT_STORE_PROV_DELETE_CRL_FUNC)
890             ret->provDeleteCrl = pProvInfo->rgpvStoreProvFunc[
891              CERT_STORE_PROV_DELETE_CRL_FUNC];
892         else
893             ret->provDeleteCert = NULL;
894         if (pProvInfo->cStoreProvFunc >
895          CERT_STORE_PROV_CONTROL_FUNC)
896             ret->provControl = pProvInfo->rgpvStoreProvFunc[
897              CERT_STORE_PROV_CONTROL_FUNC];
898         else
899             ret->provControl = NULL;
900     }
901     return (PWINECRYPT_CERTSTORE)ret;
902 }
903
904 static PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider,
905  DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara)
906 {
907     static HCRYPTOIDFUNCSET set = NULL;
908     PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc;
909     HCRYPTOIDFUNCADDR hFunc;
910     PWINECRYPT_CERTSTORE ret = NULL;
911
912     if (!set)
913         set = CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0);
914     CryptGetOIDFunctionAddress(set, dwEncodingType, lpszStoreProvider, 0,
915      (void **)&provOpenFunc, &hFunc);
916     if (provOpenFunc)
917     {
918         CERT_STORE_PROV_INFO provInfo = { 0 };
919
920         provInfo.cbSize = sizeof(provInfo);
921         if (dwFlags & CERT_STORE_DELETE_FLAG)
922             provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
923              dwFlags, pvPara, NULL, &provInfo);
924         else
925         {
926             HCERTSTORE memStore;
927
928             memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
929              CERT_STORE_CREATE_NEW_FLAG, NULL);
930             if (memStore)
931             {
932                 if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
933                  dwFlags, pvPara, memStore, &provInfo))
934                     ret = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
935                      &provInfo);
936                 else
937                     CertCloseStore(memStore, 0);
938             }
939         }
940         CryptFreeOIDFunctionAddress(hFunc, 0);
941     }
942     else
943         SetLastError(ERROR_FILE_NOT_FOUND);
944     return ret;
945 }
946
947 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
948 {
949     static const WCHAR fmt[] = { '%','0','2','X',0 };
950     DWORD i;
951
952     assert(hash);
953     assert(asciiHash);
954
955     for (i = 0; i < 20; i++)
956         wsprintfW(asciiHash + i * 2, fmt, hash[i]);
957 }
958
959 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
960  0 };
961 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
962 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
963 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
964
965 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTOREINFO store, HKEY key,
966  DWORD contextType)
967 {
968     LONG rc;
969     DWORD index = 0;
970     WCHAR subKeyName[MAX_PATH];
971
972     do {
973         DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
974
975         rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
976          NULL);
977         if (!rc)
978         {
979             HKEY subKey;
980
981             rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
982             if (!rc)
983             {
984                 LPBYTE buf = NULL;
985
986                 size = 0;
987                 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
988                 if (!rc)
989                     buf = CryptMemAlloc(size);
990                 if (buf)
991                 {
992                     rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
993                      &size);
994                     if (!rc)
995                     {
996                         const void *context;
997                         DWORD addedType;
998
999                         TRACE("Adding cert with hash %s\n",
1000                          debugstr_w(subKeyName));
1001                         context = CRYPT_ReadSerializedElement(buf, size,
1002                          contextType, &addedType);
1003                         if (context)
1004                         {
1005                             const WINE_CONTEXT_INTERFACE *contextInterface;
1006                             BYTE hash[20];
1007
1008                             switch (addedType)
1009                             {
1010                             case CERT_STORE_CERTIFICATE_CONTEXT:
1011                                 contextInterface = &gCertInterface;
1012                                 break;
1013                             case CERT_STORE_CRL_CONTEXT:
1014                                 contextInterface = &gCRLInterface;
1015                                 break;
1016                             case CERT_STORE_CTL_CONTEXT:
1017                                 contextInterface = &gCTLInterface;
1018                                 break;
1019                             default:
1020                                 contextInterface = NULL;
1021                             }
1022                             if (contextInterface)
1023                             {
1024                                 size = sizeof(hash);
1025                                 if (contextInterface->getProp(context,
1026                                  CERT_HASH_PROP_ID, hash, &size))
1027                                 {
1028                                     WCHAR asciiHash[20 * 2 + 1];
1029
1030                                     CRYPT_HashToStr(hash, asciiHash);
1031                                     TRACE("comparing %s\n",
1032                                      debugstr_w(asciiHash));
1033                                     TRACE("with %s\n", debugstr_w(subKeyName));
1034                                     if (!lstrcmpW(asciiHash, subKeyName))
1035                                     {
1036                                         TRACE("hash matches, adding\n");
1037                                         contextInterface->addContextToStore(
1038                                          store->memStore, context,
1039                                          CERT_STORE_ADD_REPLACE_EXISTING, NULL);
1040                                     }
1041                                     else
1042                                         TRACE("hash doesn't match, ignoring\n");
1043                                 }
1044                                 contextInterface->free(context);
1045                             }
1046                         }
1047                     }
1048                     CryptMemFree(buf);
1049                 }
1050                 RegCloseKey(subKey);
1051             }
1052             /* Ignore intermediate errors, continue enumerating */
1053             rc = ERROR_SUCCESS;
1054         }
1055     } while (!rc);
1056 }
1057
1058 static void CRYPT_RegReadFromReg(PWINE_REGSTOREINFO store)
1059 {
1060     static const WCHAR * const subKeys[] = { CertsW, CRLsW, CTLsW };
1061     static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
1062      CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
1063     DWORD i;
1064
1065     for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1066     {
1067         HKEY key;
1068         LONG rc;
1069
1070         rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
1071          &key, NULL);
1072         if (!rc)
1073         {
1074             CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
1075             RegCloseKey(key);
1076         }
1077     }
1078 }
1079
1080 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
1081 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
1082  DWORD len)
1083 {
1084     WCHAR asciiHash[20 * 2 + 1];
1085     LONG rc;
1086     HKEY subKey;
1087     BOOL ret;
1088
1089     CRYPT_HashToStr(hash, asciiHash);
1090     rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
1091      &subKey, NULL);
1092     if (!rc)
1093     {
1094         rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
1095         RegCloseKey(subKey);
1096     }
1097     if (!rc)
1098         ret = TRUE;
1099     else
1100     {
1101         SetLastError(rc);
1102         ret = FALSE;
1103     }
1104     return ret;
1105 }
1106
1107 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
1108  const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
1109 {
1110     const void *context = NULL;
1111     BOOL ret;
1112
1113     do {
1114         context = contextInterface->enumContextsInStore(memStore, context);
1115         if (context)
1116         {
1117             BYTE hash[20];
1118             DWORD hashSize = sizeof(hash);
1119
1120             ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1121              &hashSize);
1122             if (ret)
1123             {
1124                 DWORD size = 0;
1125                 LPBYTE buf = NULL;
1126
1127                 ret = contextInterface->serialize(context, 0, NULL, &size);
1128                 if (size)
1129                     buf = CryptMemAlloc(size);
1130                 if (buf)
1131                 {
1132                     ret = contextInterface->serialize(context, 0, buf, &size);
1133                     if (ret)
1134                         ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1135                 }
1136                 CryptMemFree(buf);
1137             }
1138         }
1139         else
1140             ret = TRUE;
1141     } while (ret && context != NULL);
1142     if (context)
1143         contextInterface->free(context);
1144     return ret;
1145 }
1146
1147 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store)
1148 {
1149     static const WCHAR * const subKeys[] = { CertsW, CRLsW, CTLsW };
1150     static const WINE_CONTEXT_INTERFACE * const interfaces[] = { &gCertInterface,
1151      &gCRLInterface, &gCTLInterface };
1152     struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete,
1153      NULL };
1154     BOOL ret = TRUE;
1155     DWORD i;
1156
1157     for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1158     {
1159         HKEY key;
1160         LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1161          KEY_ALL_ACCESS, NULL, &key, NULL);
1162
1163         if (!rc)
1164         {
1165             if (listToDelete[i])
1166             {
1167                 PWINE_HASH_TO_DELETE toDelete, next;
1168                 WCHAR asciiHash[20 * 2 + 1];
1169
1170                 EnterCriticalSection(&store->cs);
1171                 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1172                  WINE_HASH_TO_DELETE, entry)
1173                 {
1174                     LONG rc;
1175
1176                     CRYPT_HashToStr(toDelete->hash, asciiHash);
1177                     TRACE("Removing %s\n", debugstr_w(asciiHash));
1178                     rc = RegDeleteKeyW(key, asciiHash);
1179                     if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1180                     {
1181                         SetLastError(rc);
1182                         ret = FALSE;
1183                     }
1184                     list_remove(&toDelete->entry);
1185                     CryptMemFree(toDelete);
1186                 }
1187                 LeaveCriticalSection(&store->cs);
1188             }
1189             ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1190              store->memStore);
1191             RegCloseKey(key);
1192         }
1193         else
1194         {
1195             SetLastError(rc);
1196             ret = FALSE;
1197         }
1198     }
1199     return ret;
1200 }
1201
1202 /* If force is true or the registry store is dirty, writes the contents of the
1203  * store to the registry.
1204  */
1205 static BOOL CRYPT_RegFlushStore(PWINE_REGSTOREINFO store, BOOL force)
1206 {
1207     BOOL ret;
1208
1209     TRACE("(%p, %d)\n", store, force);
1210
1211     if (store->dirty || force)
1212         ret = CRYPT_RegWriteToReg(store);
1213     else
1214         ret = TRUE;
1215     return ret;
1216 }
1217
1218 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1219 {
1220     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1221
1222     TRACE("(%p, %08x)\n", store, dwFlags);
1223     if (dwFlags)
1224         FIXME("Unimplemented flags: %08x\n", dwFlags);
1225
1226     CRYPT_RegFlushStore(store, FALSE);
1227     RegCloseKey(store->key);
1228     DeleteCriticalSection(&store->cs);
1229     CryptMemFree(store);
1230 }
1231
1232 static BOOL WINAPI CRYPT_RegWriteContext(PWINE_REGSTOREINFO store,
1233  const void *context, DWORD dwFlags)
1234 {
1235     BOOL ret;
1236
1237     if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG)
1238     {
1239         store->dirty = TRUE;
1240         ret = TRUE;
1241     }
1242     else
1243         ret = FALSE;
1244     return ret;
1245 }
1246
1247 static BOOL CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store,
1248  struct list *deleteList, const void *context,
1249  PCWINE_CONTEXT_INTERFACE contextInterface)
1250 {
1251     BOOL ret;
1252
1253     if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG)
1254     {
1255         SetLastError(ERROR_ACCESS_DENIED);
1256         ret = FALSE;
1257     }
1258     else
1259     {
1260         PWINE_HASH_TO_DELETE toDelete =
1261          CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1262
1263         if (toDelete)
1264         {
1265             DWORD size = sizeof(toDelete->hash);
1266
1267             ret = contextInterface->getProp(context, CERT_HASH_PROP_ID,
1268              toDelete->hash, &size);
1269             if (ret)
1270             {
1271                 EnterCriticalSection(&store->cs);
1272                 list_add_tail(deleteList, &toDelete->entry);
1273                 LeaveCriticalSection(&store->cs);
1274             }
1275             else
1276             {
1277                 CryptMemFree(toDelete);
1278                 ret = FALSE;
1279             }
1280         }
1281         else
1282             ret = FALSE;
1283         if (ret)
1284             store->dirty = TRUE;
1285     }
1286     return ret;
1287 }
1288
1289 static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore,
1290  PCCERT_CONTEXT cert, DWORD dwFlags)
1291 {
1292     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1293
1294     TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags);
1295
1296     return CRYPT_RegWriteContext(store, cert, dwFlags);
1297 }
1298
1299 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1300  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1301 {
1302     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1303
1304     TRACE("(%p, %p, %08x)\n", store, pCertContext, dwFlags);
1305
1306     return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext,
1307      pCertInterface);
1308 }
1309
1310 static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore,
1311  PCCRL_CONTEXT crl, DWORD dwFlags)
1312 {
1313     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1314
1315     TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags);
1316
1317     return CRYPT_RegWriteContext(store, crl, dwFlags);
1318 }
1319
1320 static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore,
1321  PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
1322 {
1323     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1324
1325     TRACE("(%p, %p, %08x)\n", store, pCrlContext, dwFlags);
1326
1327     return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext,
1328      pCRLInterface);
1329 }
1330
1331 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1332  DWORD dwCtrlType, void const *pvCtrlPara)
1333 {
1334     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1335     BOOL ret;
1336
1337     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
1338      pvCtrlPara);
1339
1340     switch (dwCtrlType)
1341     {
1342     case CERT_STORE_CTRL_RESYNC:
1343         CRYPT_RegFlushStore(store, FALSE);
1344         CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore);
1345         CRYPT_RegReadFromReg(store);
1346         ret = TRUE;
1347         break;
1348     case CERT_STORE_CTRL_COMMIT:
1349         ret = CRYPT_RegFlushStore(store,
1350          dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1351         break;
1352     default:
1353         FIXME("%d: stub\n", dwCtrlType);
1354         ret = FALSE;
1355     }
1356     return ret;
1357 }
1358
1359 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1360 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1361 {
1362     DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1363     WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1364     HKEY hSubKey = 0;
1365
1366     TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1367
1368     dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1369     if (!dwRet)
1370     {
1371         /* Find how many subkeys there are */
1372         dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1373          &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1374         if (!dwRet)
1375         {
1376             dwMaxSubkeyLen++;
1377             if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1378             {
1379                 /* Name too big: alloc a buffer for it */
1380                 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1381             }
1382
1383             if (!lpszName)
1384                 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1385             else
1386             {
1387                 /* Recursively delete all the subkeys */
1388                 for (i = 0; i < dwKeyCount && !dwRet; i++)
1389                 {
1390                     dwSize = dwMaxSubkeyLen;
1391                     dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1392                      NULL, NULL, NULL);
1393                     if (!dwRet)
1394                         dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1395                 }
1396
1397                 if (lpszName != szNameBuf)
1398                 {
1399                     /* Free buffer if allocated */
1400                     CryptMemFree(lpszName);
1401                 }
1402             }
1403         }
1404
1405         RegCloseKey(hSubKey);
1406         if (!dwRet)
1407             dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1408     }
1409     return dwRet;
1410 }
1411
1412 static void *regProvFuncs[] = {
1413     CRYPT_RegCloseStore,
1414     NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
1415     CRYPT_RegWriteCert,
1416     CRYPT_RegDeleteCert,
1417     NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
1418     NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
1419     CRYPT_RegWriteCRL,
1420     CRYPT_RegDeleteCRL,
1421     NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
1422     NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
1423     NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
1424     NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
1425     NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
1426     CRYPT_RegControl,
1427 };
1428
1429 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1430  DWORD dwFlags, const void *pvPara)
1431 {
1432     PWINECRYPT_CERTSTORE store = NULL;
1433
1434     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
1435
1436     if (dwFlags & CERT_STORE_DELETE_FLAG)
1437     {
1438         DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1439
1440         if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1441             rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1442         if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1443             rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1444         if (rc == ERROR_NO_MORE_ITEMS)
1445             rc = ERROR_SUCCESS;
1446         SetLastError(rc);
1447     }
1448     else
1449     {
1450         HKEY key;
1451
1452         if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1453          GetCurrentProcess(), (LPHANDLE)&key,
1454          dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1455          TRUE, 0))
1456         {
1457             PWINECRYPT_CERTSTORE memStore;
1458
1459             memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1460             if (memStore)
1461             {
1462                 PWINE_REGSTOREINFO regInfo = CryptMemAlloc(
1463                  sizeof(WINE_REGSTOREINFO));
1464
1465                 if (regInfo)
1466                 {
1467                     CERT_STORE_PROV_INFO provInfo = { 0 };
1468
1469                     regInfo->dwOpenFlags = dwFlags;
1470                     regInfo->cryptProv = hCryptProv;
1471                     regInfo->memStore = memStore;
1472                     regInfo->key = key;
1473                     InitializeCriticalSection(&regInfo->cs);
1474                     list_init(&regInfo->certsToDelete);
1475                     list_init(&regInfo->crlsToDelete);
1476                     CRYPT_RegReadFromReg(regInfo);
1477                     regInfo->dirty = FALSE;
1478                     provInfo.cbSize = sizeof(provInfo);
1479                     provInfo.cStoreProvFunc = sizeof(regProvFuncs) /
1480                      sizeof(regProvFuncs[0]);
1481                     provInfo.rgpvStoreProvFunc = regProvFuncs;
1482                     provInfo.hStoreProv = regInfo;
1483                     store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
1484                      &provInfo);
1485                 }
1486             }
1487         }
1488     }
1489     TRACE("returning %p\n", store);
1490     return store;
1491 }
1492
1493 /* FIXME: this isn't complete for the Root store, in which the top-level
1494  * self-signed CA certs reside.  Adding a cert to the Root store should present
1495  * the user with a dialog indicating the consequences of doing so, and asking
1496  * the user to confirm whether the cert should be added.
1497  */
1498 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1499  DWORD dwFlags, const void *pvPara)
1500 {
1501     static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1502     LPCWSTR storeName = (LPCWSTR)pvPara;
1503     LPWSTR storePath;
1504     PWINECRYPT_CERTSTORE store = NULL;
1505     HKEY root;
1506     LPCWSTR base;
1507     BOOL ret;
1508
1509     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
1510      debugstr_w((LPCWSTR)pvPara));
1511
1512     if (!pvPara)
1513     {
1514         SetLastError(E_INVALIDARG);
1515         return NULL;
1516     }
1517
1518     ret = TRUE;
1519     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1520     {
1521     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1522         root = HKEY_LOCAL_MACHINE;
1523         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1524         break;
1525     case CERT_SYSTEM_STORE_CURRENT_USER:
1526         root = HKEY_CURRENT_USER;
1527         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1528         break;
1529     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1530         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1531          * SystemCertificates
1532          */
1533         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1534          debugstr_w(storeName));
1535         return NULL;
1536     case CERT_SYSTEM_STORE_SERVICES:
1537         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1538          * SystemCertificates
1539          */
1540         FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1541          debugstr_w(storeName));
1542         return NULL;
1543     case CERT_SYSTEM_STORE_USERS:
1544         /* hku\user sid\Software\Microsoft\SystemCertificates */
1545         FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1546          debugstr_w(storeName));
1547         return NULL;
1548     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1549         root = HKEY_CURRENT_USER;
1550         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1551         break;
1552     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1553         root = HKEY_LOCAL_MACHINE;
1554         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1555         break;
1556     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1557         /* hklm\Software\Microsoft\EnterpriseCertificates */
1558         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1559          debugstr_w(storeName));
1560         return NULL;
1561     default:
1562         SetLastError(E_INVALIDARG);
1563         return NULL;
1564     }
1565
1566     storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1567      sizeof(WCHAR));
1568     if (storePath)
1569     {
1570         LONG rc;
1571         HKEY key;
1572         REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1573             KEY_ALL_ACCESS;
1574
1575         wsprintfW(storePath, fmt, base, storeName);
1576         if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1577             rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1578         else
1579         {
1580             DWORD disp;
1581
1582             rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1583                                  &key, &disp);
1584             if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1585                 disp == REG_OPENED_EXISTING_KEY)
1586             {
1587                 RegCloseKey(key);
1588                 rc = ERROR_FILE_EXISTS;
1589             }
1590         }
1591         if (!rc)
1592         {
1593             store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1594             RegCloseKey(key);
1595         }
1596         else
1597             SetLastError(rc);
1598         CryptMemFree(storePath);
1599     }
1600     return store;
1601 }
1602
1603 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1604  DWORD dwFlags, const void *pvPara)
1605 {
1606     int len;
1607     PWINECRYPT_CERTSTORE ret = NULL;
1608
1609     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
1610      debugstr_a((LPCSTR)pvPara));
1611
1612     if (!pvPara)
1613     {
1614         SetLastError(ERROR_FILE_NOT_FOUND);
1615         return NULL;
1616     }
1617     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1618     if (len)
1619     {
1620         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1621
1622         if (storeName)
1623         {
1624             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1625             ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1626             CryptMemFree(storeName);
1627         }
1628     }
1629     return ret;
1630 }
1631
1632 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1633  DWORD dwFlags, const void *pvPara)
1634 {
1635     HCERTSTORE store = 0;
1636     BOOL ret;
1637
1638     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
1639      debugstr_w((LPCWSTR)pvPara));
1640
1641     if (!pvPara)
1642     {
1643         SetLastError(ERROR_FILE_NOT_FOUND);
1644         return NULL;
1645     }
1646     /* This returns a different error than system registry stores if the
1647      * location is invalid.
1648      */
1649     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1650     {
1651     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1652     case CERT_SYSTEM_STORE_CURRENT_USER:
1653     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1654     case CERT_SYSTEM_STORE_SERVICES:
1655     case CERT_SYSTEM_STORE_USERS:
1656     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1657     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1658     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1659         ret = TRUE;
1660         break;
1661     default:
1662         SetLastError(ERROR_FILE_NOT_FOUND);
1663         ret = FALSE;
1664     }
1665     if (ret)
1666     {
1667         HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1668          0, hCryptProv, dwFlags, pvPara);
1669
1670         if (regStore)
1671         {
1672             store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1673              CERT_STORE_CREATE_NEW_FLAG, NULL);
1674             CertAddStoreToCollection(store, regStore,
1675              dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1676              CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1677             CertCloseStore(regStore, 0);
1678             /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
1679              * stores.
1680              */
1681             if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
1682              CERT_SYSTEM_STORE_CURRENT_USER)
1683             {
1684                 dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
1685                 dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
1686                 regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0,
1687                  hCryptProv, dwFlags, pvPara);
1688                 if (regStore)
1689                 {
1690                     CertAddStoreToCollection(store, regStore,
1691                      dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1692                      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1693                     CertCloseStore(regStore, 0);
1694                 }
1695             }
1696         }
1697     }
1698     return (PWINECRYPT_CERTSTORE)store;
1699 }
1700
1701 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1702  DWORD dwFlags, const void *pvPara)
1703 {
1704     int len;
1705     PWINECRYPT_CERTSTORE ret = NULL;
1706
1707     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
1708      debugstr_a((LPCSTR)pvPara));
1709
1710     if (!pvPara)
1711     {
1712         SetLastError(ERROR_FILE_NOT_FOUND);
1713         return NULL;
1714     }
1715     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1716     if (len)
1717     {
1718         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1719
1720         if (storeName)
1721         {
1722             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1723             ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1724             CryptMemFree(storeName);
1725         }
1726     }
1727     return ret;
1728 }
1729
1730 static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1731 {
1732     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1733
1734     TRACE("(%p, %08x)\n", store, dwFlags);
1735     if (store->dirty)
1736         CRYPT_WriteSerializedFile(store->file, store->memStore);
1737     CertCloseStore(store->memStore, dwFlags);
1738     CloseHandle(store->file);
1739     CryptMemFree(store);
1740 }
1741
1742 static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore,
1743  PCCERT_CONTEXT cert, DWORD dwFlags)
1744 {
1745     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1746
1747     TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags);
1748     store->dirty = TRUE;
1749     return TRUE;
1750 }
1751
1752 static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore,
1753  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1754 {
1755     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1756
1757     TRACE("(%p, %p, %08x)\n", hCertStore, pCertContext, dwFlags);
1758     store->dirty = TRUE;
1759     return TRUE;
1760 }
1761
1762 static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore,
1763  PCCRL_CONTEXT crl, DWORD dwFlags)
1764 {
1765     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1766
1767     TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags);
1768     store->dirty = TRUE;
1769     return TRUE;
1770 }
1771
1772 static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore,
1773  PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
1774 {
1775     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1776
1777     TRACE("(%p, %p, %08x)\n", hCertStore, pCrlContext, dwFlags);
1778     store->dirty = TRUE;
1779     return TRUE;
1780 }
1781
1782 static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags,
1783  DWORD dwCtrlType, void const *pvCtrlPara)
1784 {
1785     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
1786     BOOL ret;
1787
1788     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
1789      pvCtrlPara);
1790
1791     switch (dwCtrlType)
1792     {
1793     case CERT_STORE_CTRL_RESYNC:
1794         CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore);
1795         CRYPT_ReadSerializedFile(store->file, store);
1796         ret = TRUE;
1797         break;
1798     case CERT_STORE_CTRL_COMMIT:
1799         if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
1800         {
1801             SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1802             ret = FALSE;
1803         }
1804         else if (store->dirty)
1805             ret = CRYPT_WriteSerializedFile(store->file, store->memStore);
1806         else
1807             ret = TRUE;
1808         break;
1809     default:
1810         FIXME("%d: stub\n", dwCtrlType);
1811         ret = FALSE;
1812     }
1813     return ret;
1814 }
1815
1816 static void *fileProvFuncs[] = {
1817     CRYPT_FileCloseStore,
1818     NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
1819     CRYPT_FileWriteCert,
1820     CRYPT_FileDeleteCert,
1821     NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
1822     NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
1823     CRYPT_FileWriteCRL,
1824     CRYPT_FileDeleteCRL,
1825     NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
1826     NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
1827     NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
1828     NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
1829     NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
1830     CRYPT_FileControl,
1831 };
1832
1833 static PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv,
1834  DWORD dwFlags, const void *pvPara)
1835 {
1836     PWINECRYPT_CERTSTORE store = NULL;
1837     HANDLE file = (HANDLE)pvPara;
1838
1839     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
1840
1841     if (!pvPara)
1842     {
1843         SetLastError(ERROR_INVALID_HANDLE);
1844         return NULL;
1845     }
1846     if (dwFlags & CERT_STORE_DELETE_FLAG)
1847     {
1848         SetLastError(E_INVALIDARG);
1849         return NULL;
1850     }
1851     if ((dwFlags & CERT_STORE_READONLY_FLAG) &&
1852      (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
1853     {
1854         SetLastError(E_INVALIDARG);
1855         return NULL;
1856     }
1857
1858     if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1859      GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ?
1860      GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0))
1861     {
1862         PWINECRYPT_CERTSTORE memStore;
1863
1864         memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1865         if (memStore)
1866         {
1867             if (CRYPT_ReadSerializedFile(file, memStore))
1868             {
1869                 PWINE_FILESTOREINFO info = CryptMemAlloc(
1870                  sizeof(WINE_FILESTOREINFO));
1871
1872                 if (info)
1873                 {
1874                     CERT_STORE_PROV_INFO provInfo = { 0 };
1875
1876                     info->dwOpenFlags = dwFlags;
1877                     info->cryptProv = hCryptProv;
1878                     info->memStore = memStore;
1879                     info->file = file;
1880                     info->dirty = FALSE;
1881                     provInfo.cbSize = sizeof(provInfo);
1882                     provInfo.cStoreProvFunc = sizeof(fileProvFuncs) /
1883                      sizeof(fileProvFuncs[0]);
1884                     provInfo.rgpvStoreProvFunc = fileProvFuncs;
1885                     provInfo.hStoreProv = info;
1886                     store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
1887                      &provInfo);
1888                 }
1889             }
1890         }
1891     }
1892     TRACE("returning %p\n", store);
1893     return store;
1894 }
1895
1896 static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
1897  DWORD dwFlags, const void *pvPara)
1898 {
1899     HCERTSTORE store = 0;
1900     LPCWSTR fileName = (LPCWSTR)pvPara;
1901     DWORD access, create;
1902     HANDLE file;
1903
1904     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName));
1905
1906     if (!fileName)
1907     {
1908         SetLastError(ERROR_PATH_NOT_FOUND);
1909         return NULL;
1910     }
1911     if (!(dwFlags & (CERT_FILE_STORE_COMMIT_ENABLE_FLAG |
1912      CERT_STORE_READONLY_FLAG)))
1913     {
1914         SetLastError(ERROR_FILE_NOT_FOUND);
1915         return NULL;
1916     }
1917
1918     access = GENERIC_READ;
1919     if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
1920         access |= GENERIC_WRITE;
1921     if (dwFlags & CERT_STORE_CREATE_NEW_FLAG)
1922         create = CREATE_NEW;
1923     else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1924         create = OPEN_EXISTING;
1925     else
1926         create = OPEN_ALWAYS;
1927     file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create,
1928      FILE_ATTRIBUTE_NORMAL, NULL);
1929     if (file != INVALID_HANDLE_VALUE)
1930     {
1931         /* FIXME: need to check whether it's a serialized store; if not, fall
1932          * back to a PKCS#7 signed message, then to a single serialized cert.
1933          */
1934         store = CertOpenStore(CERT_STORE_PROV_FILE, 0, hCryptProv, dwFlags,
1935          file);
1936         CloseHandle(file);
1937     }
1938     return (PWINECRYPT_CERTSTORE)store;
1939 }
1940
1941 static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
1942  DWORD dwFlags, const void *pvPara)
1943 {
1944     int len;
1945     PWINECRYPT_CERTSTORE ret = NULL;
1946
1947     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
1948      debugstr_a((LPCSTR)pvPara));
1949
1950     if (!pvPara)
1951     {
1952         SetLastError(ERROR_FILE_NOT_FOUND);
1953         return NULL;
1954     }
1955     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1956     if (len)
1957     {
1958         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1959
1960         if (storeName)
1961         {
1962             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1963             ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName);
1964             CryptMemFree(storeName);
1965         }
1966     }
1967     return ret;
1968 }
1969
1970 static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv,
1971  DWORD dwFlags, const void *pvPara)
1972 {
1973     if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
1974         FIXME("(%ld, %08x, %p): stub\n", hCryptProv, dwFlags, pvPara);
1975     else
1976         FIXME("(%ld, %08x, %s): stub\n", hCryptProv, dwFlags,
1977          debugstr_w((LPCWSTR)pvPara));
1978     return NULL;
1979 }
1980
1981 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1982  DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1983  const void* pvPara)
1984 {
1985     WINECRYPT_CERTSTORE *hcs;
1986     StoreOpenFunc openFunc = NULL;
1987
1988     TRACE("(%s, %08x, %08lx, %08x, %p)\n", debugstr_a(lpszStoreProvider),
1989           dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1990
1991     if (!HIWORD(lpszStoreProvider))
1992     {
1993         switch (LOWORD(lpszStoreProvider))
1994         {
1995         case (int)CERT_STORE_PROV_MEMORY:
1996             openFunc = CRYPT_MemOpenStore;
1997             break;
1998         case (int)CERT_STORE_PROV_FILE:
1999             openFunc = CRYPT_FileOpenStore;
2000             break;
2001         case (int)CERT_STORE_PROV_REG:
2002             openFunc = CRYPT_RegOpenStore;
2003             break;
2004         case (int)CERT_STORE_PROV_FILENAME_A:
2005             openFunc = CRYPT_FileNameOpenStoreA;
2006             break;
2007         case (int)CERT_STORE_PROV_FILENAME_W:
2008             openFunc = CRYPT_FileNameOpenStoreW;
2009             break;
2010         case (int)CERT_STORE_PROV_COLLECTION:
2011             openFunc = CRYPT_CollectionOpenStore;
2012             break;
2013         case (int)CERT_STORE_PROV_SYSTEM_A:
2014             openFunc = CRYPT_SysOpenStoreA;
2015             break;
2016         case (int)CERT_STORE_PROV_SYSTEM_W:
2017             openFunc = CRYPT_SysOpenStoreW;
2018             break;
2019         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
2020             openFunc = CRYPT_SysRegOpenStoreA;
2021             break;
2022         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
2023             openFunc = CRYPT_SysRegOpenStoreW;
2024             break;
2025         case (int)CERT_STORE_PROV_PHYSICAL_W:
2026             openFunc = CRYPT_PhysOpenStoreW;
2027             break;
2028         default:
2029             if (LOWORD(lpszStoreProvider))
2030                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
2031         }
2032     }
2033     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
2034         openFunc = CRYPT_MemOpenStore;
2035     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_FILENAME_W))
2036         openFunc = CRYPT_FileOpenStore;
2037     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
2038         openFunc = CRYPT_SysOpenStoreW;
2039     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
2040         openFunc = CRYPT_CollectionOpenStore;
2041     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
2042         openFunc = CRYPT_SysRegOpenStoreW;
2043     else
2044     {
2045         FIXME("unimplemented type %s\n", lpszStoreProvider);
2046         openFunc = NULL;
2047     }
2048
2049     if (!openFunc)
2050         hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
2051          hCryptProv, dwFlags, pvPara);
2052     else
2053         hcs = openFunc(hCryptProv, dwFlags, pvPara);
2054     return (HCERTSTORE)hcs;
2055 }
2056
2057 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
2058  LPCSTR szSubSystemProtocol)
2059 {
2060     if (!szSubSystemProtocol)
2061     {
2062         SetLastError(E_INVALIDARG);
2063         return 0;
2064     }
2065     return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
2066      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
2067 }
2068
2069 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
2070  LPCWSTR szSubSystemProtocol)
2071 {
2072     if (!szSubSystemProtocol)
2073     {
2074         SetLastError(E_INVALIDARG);
2075         return 0;
2076     }
2077     return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
2078      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
2079 }
2080
2081 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
2082              DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
2083 {
2084     FIXME("(%p,%d,%d,%d,%p,%08x) stub!\n", hCertStore, 
2085           dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
2086     return TRUE;
2087 }
2088
2089 DWORD CertStore_GetAccessState(HCERTSTORE hCertStore)
2090 {
2091     DWORD state = 0;
2092
2093     if (hCertStore)
2094     {
2095         PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2096
2097         if (store->type != StoreTypeMem &&
2098          !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2099             state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2100     }
2101     return state;
2102 }
2103
2104 #define CertContext_CopyProperties(to, from) \
2105  Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT))
2106
2107 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2108  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2109  PCCERT_CONTEXT *ppStoreContext)
2110 {
2111     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2112     BOOL ret = TRUE;
2113     PCCERT_CONTEXT toAdd = NULL, existing = NULL;
2114
2115     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext,
2116      dwAddDisposition, ppStoreContext);
2117
2118     /* Weird case to pass a test */
2119     if (dwAddDisposition == 0)
2120     {
2121         SetLastError(STATUS_ACCESS_VIOLATION);
2122         return FALSE;
2123     }
2124     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
2125     {
2126         BYTE hashToAdd[20];
2127         DWORD size = sizeof(hashToAdd);
2128
2129         ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
2130          hashToAdd, &size);
2131         if (ret)
2132         {
2133             CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
2134
2135             existing = CertFindCertificateInStore(hCertStore,
2136              pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
2137              NULL);
2138         }
2139     }
2140
2141     switch (dwAddDisposition)
2142     {
2143     case CERT_STORE_ADD_ALWAYS:
2144         toAdd = CertDuplicateCertificateContext(pCertContext);
2145         break;
2146     case CERT_STORE_ADD_NEW:
2147         if (existing)
2148         {
2149             TRACE("found matching certificate, not adding\n");
2150             SetLastError(CRYPT_E_EXISTS);
2151             ret = FALSE;
2152         }
2153         else
2154             toAdd = CertDuplicateCertificateContext(pCertContext);
2155         break;
2156     case CERT_STORE_ADD_REPLACE_EXISTING:
2157         toAdd = CertDuplicateCertificateContext(pCertContext);
2158         break;
2159     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
2160         toAdd = CertDuplicateCertificateContext(pCertContext);
2161         if (existing)
2162             CertContext_CopyProperties(toAdd, existing);
2163         break;
2164     case CERT_STORE_ADD_USE_EXISTING:
2165         if (existing)
2166             CertContext_CopyProperties(existing, pCertContext);
2167         break;
2168     default:
2169         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
2170         ret = FALSE;
2171     }
2172
2173     if (toAdd)
2174     {
2175         if (store)
2176             ret = store->certs.addContext(store, (void *)toAdd,
2177              (void *)existing, (const void **)ppStoreContext);
2178         else if (ppStoreContext)
2179             *ppStoreContext = CertDuplicateCertificateContext(toAdd);
2180         CertFreeCertificateContext(toAdd);
2181     }
2182     CertFreeCertificateContext(existing);
2183
2184     TRACE("returning %d\n", ret);
2185     return ret;
2186 }
2187
2188 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2189  PCCERT_CONTEXT pPrev)
2190 {
2191     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2192     PCCERT_CONTEXT ret;
2193
2194     TRACE("(%p, %p)\n", hCertStore, pPrev);
2195     if (!hCertStore)
2196         ret = NULL;
2197     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2198         ret = NULL;
2199     else
2200         ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
2201     return ret;
2202 }
2203
2204 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2205 {
2206     BOOL ret;
2207
2208     TRACE("(%p)\n", pCertContext);
2209
2210     if (!pCertContext)
2211         ret = TRUE;
2212     else if (!pCertContext->hCertStore)
2213     {
2214         ret = TRUE;
2215         CertFreeCertificateContext(pCertContext);
2216     }
2217     else
2218     {
2219         PWINECRYPT_CERTSTORE hcs =
2220          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2221
2222         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2223             ret = FALSE;
2224         else
2225             ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
2226         CertFreeCertificateContext(pCertContext);
2227     }
2228     return ret;
2229 }
2230
2231 #define CrlContext_CopyProperties(to, from) \
2232  Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
2233
2234 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
2235  PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2236  PCCRL_CONTEXT* ppStoreContext)
2237 {
2238     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2239     BOOL ret = TRUE;
2240     PCCRL_CONTEXT toAdd = NULL, existing = NULL;
2241
2242     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCrlContext,
2243      dwAddDisposition, ppStoreContext);
2244
2245     /* Weird case to pass a test */
2246     if (dwAddDisposition == 0)
2247     {
2248         SetLastError(STATUS_ACCESS_VIOLATION);
2249         return FALSE;
2250     }
2251     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
2252     {
2253         existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
2254          pCrlContext, NULL);
2255     }
2256
2257     switch (dwAddDisposition)
2258     {
2259     case CERT_STORE_ADD_ALWAYS:
2260         toAdd = CertDuplicateCRLContext(pCrlContext);
2261         break;
2262     case CERT_STORE_ADD_NEW:
2263         if (existing)
2264         {
2265             TRACE("found matching CRL, not adding\n");
2266             SetLastError(CRYPT_E_EXISTS);
2267             ret = FALSE;
2268         }
2269         else
2270             toAdd = CertDuplicateCRLContext(pCrlContext);
2271         break;
2272     case CERT_STORE_ADD_NEWER:
2273         if (existing)
2274         {
2275             LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
2276              &pCrlContext->pCrlInfo->ThisUpdate);
2277
2278             if (newer < 0)
2279                 toAdd = CertDuplicateCRLContext(pCrlContext);
2280             else
2281             {
2282                 TRACE("existing CRL is newer, not adding\n");
2283                 SetLastError(CRYPT_E_EXISTS);
2284                 ret = FALSE;
2285             }
2286         }
2287         else
2288             toAdd = CertDuplicateCRLContext(pCrlContext);
2289         break;
2290     case CERT_STORE_ADD_REPLACE_EXISTING:
2291         toAdd = CertDuplicateCRLContext(pCrlContext);
2292         break;
2293     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
2294         toAdd = CertDuplicateCRLContext(pCrlContext);
2295         if (existing)
2296             CrlContext_CopyProperties(toAdd, existing);
2297         break;
2298     case CERT_STORE_ADD_USE_EXISTING:
2299         if (existing)
2300             CrlContext_CopyProperties(existing, pCrlContext);
2301         break;
2302     default:
2303         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
2304         ret = FALSE;
2305     }
2306
2307     if (toAdd)
2308     {
2309         if (store)
2310             ret = store->crls.addContext(store, (void *)toAdd,
2311              (void *)existing, (const void **)ppStoreContext);
2312         else if (ppStoreContext)
2313             *ppStoreContext = CertDuplicateCRLContext(toAdd);
2314         CertFreeCRLContext(toAdd);
2315     }
2316     CertFreeCRLContext(existing);
2317
2318     TRACE("returning %d\n", ret);
2319     return ret;
2320 }
2321
2322 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2323 {
2324     BOOL ret;
2325
2326     TRACE("(%p)\n", pCrlContext);
2327
2328     if (!pCrlContext)
2329         ret = TRUE;
2330     else if (!pCrlContext->hCertStore)
2331     {
2332         ret = TRUE;
2333         CertFreeCRLContext(pCrlContext);
2334     }
2335     else
2336     {
2337         PWINECRYPT_CERTSTORE hcs =
2338          (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore;
2339
2340         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2341             ret = FALSE;
2342         else
2343             ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
2344         CertFreeCRLContext(pCrlContext);
2345     }
2346     return ret;
2347 }
2348
2349 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2350  PCCRL_CONTEXT pPrev)
2351 {
2352     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2353     PCCRL_CONTEXT ret;
2354
2355     TRACE("(%p, %p)\n", hCertStore, pPrev);
2356     if (!hCertStore)
2357         ret = NULL;
2358     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2359         ret = NULL;
2360     else
2361         ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
2362     return ret;
2363 }
2364
2365 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2366   const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2367 {
2368     FIXME("(%08x, %p, %08x): 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, %08x, %p, %d, %08x, %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, %08x, %p): stub\n", hCertStore, pCtlContext,
2388      dwAddDisposition, ppStoreContext);
2389     return TRUE;
2390 }
2391
2392 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
2393 {
2394     FIXME("(%p): stub\n", pCtlContext );
2395     return pCtlContext;
2396 }
2397
2398 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2399 {
2400     FIXME("(%p): stub\n", pCtlContext );
2401     return TRUE;
2402 }
2403
2404 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2405 {
2406     FIXME("(%p): stub\n", pCtlContext);
2407     return TRUE;
2408 }
2409
2410 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2411  PCCTL_CONTEXT pPrev)
2412 {
2413     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2414     return NULL;
2415 }
2416
2417 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
2418 {
2419     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2420
2421     TRACE("(%p)\n", hCertStore);
2422
2423     if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
2424         InterlockedIncrement(&hcs->ref);
2425     return hCertStore;
2426 }
2427
2428 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2429 {
2430     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2431
2432     TRACE("(%p, %08x)\n", hCertStore, dwFlags);
2433
2434     if( ! hCertStore )
2435         return TRUE;
2436
2437     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2438         return FALSE;
2439
2440     if (InterlockedDecrement(&hcs->ref) == 0)
2441     {
2442         TRACE("%p's ref count is 0, freeing\n", hcs);
2443         hcs->dwMagic = 0;
2444         if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2445             CryptReleaseContext(hcs->cryptProv, 0);
2446         hcs->closeStore(hcs, dwFlags);
2447     }
2448     else
2449         TRACE("%p's ref count is %d\n", hcs, hcs->ref);
2450     return TRUE;
2451 }
2452
2453 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2454  DWORD dwCtrlType, void const *pvCtrlPara)
2455 {
2456     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2457     BOOL ret;
2458
2459     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
2460      pvCtrlPara);
2461
2462     if (!hcs)
2463         ret = FALSE;
2464     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2465         ret = FALSE;
2466     else
2467     {
2468         if (hcs->control)
2469             ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2470         else
2471             ret = TRUE;
2472     }
2473     return ret;
2474 }
2475
2476 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
2477  DWORD dwPropId)
2478 {
2479     FIXME("(%p, %d): stub\n", pCTLContext, dwPropId);
2480     return 0;
2481 }
2482
2483 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2484  DWORD dwPropId, void *pvData, DWORD *pcbData)
2485 {
2486     FIXME("(%p, %d, %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, %d, %08x, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2494      pvData);
2495     return FALSE;
2496 }
2497
2498 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2499  HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2500 {
2501     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2502     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2503     PWINE_STORE_LIST_ENTRY entry;
2504     BOOL ret;
2505
2506     TRACE("(%p, %p, %08x, %d)\n", hCollectionStore, hSiblingStore,
2507      dwUpdateFlags, dwPriority);
2508
2509     if (!collection || !sibling)
2510         return TRUE;
2511     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2512     {
2513         SetLastError(E_INVALIDARG);
2514         return FALSE;
2515     }
2516     if (collection->hdr.type != StoreTypeCollection)
2517     {
2518         SetLastError(E_INVALIDARG);
2519         return FALSE;
2520     }
2521     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2522     {
2523         SetLastError(E_INVALIDARG);
2524         return FALSE;
2525     }
2526
2527     entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2528     if (entry)
2529     {
2530         InterlockedIncrement(&sibling->ref);
2531         TRACE("sibling %p's ref count is %d\n", sibling, sibling->ref);
2532         entry->store = sibling;
2533         entry->dwUpdateFlags = dwUpdateFlags;
2534         entry->dwPriority = dwPriority;
2535         list_init(&entry->entry);
2536         TRACE("%p: adding %p, priority %d\n", collection, entry, dwPriority);
2537         EnterCriticalSection(&collection->cs);
2538         if (dwPriority)
2539         {
2540             PWINE_STORE_LIST_ENTRY cursor;
2541             BOOL added = FALSE;
2542
2543             LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2544              WINE_STORE_LIST_ENTRY, entry)
2545             {
2546                 if (cursor->dwPriority < dwPriority)
2547                 {
2548                     list_add_before(&cursor->entry, &entry->entry);
2549                     added = TRUE;
2550                     break;
2551                 }
2552             }
2553             if (!added)
2554                 list_add_tail(&collection->stores, &entry->entry);
2555         }
2556         else
2557             list_add_tail(&collection->stores, &entry->entry);
2558         LeaveCriticalSection(&collection->cs);
2559         ret = TRUE;
2560     }
2561     else
2562         ret = FALSE;
2563     return ret;
2564 }
2565
2566 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2567  HCERTSTORE hSiblingStore)
2568 {
2569     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2570     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2571     PWINE_STORE_LIST_ENTRY store, next;
2572
2573     TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2574
2575     if (!collection || !sibling)
2576         return;
2577     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2578     {
2579         SetLastError(E_INVALIDARG);
2580         return;
2581     }
2582     if (collection->hdr.type != StoreTypeCollection)
2583         return;
2584     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2585     {
2586         SetLastError(E_INVALIDARG);
2587         return;
2588     }
2589     EnterCriticalSection(&collection->cs);
2590     LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2591      WINE_STORE_LIST_ENTRY, entry)
2592     {
2593         if (store->store == sibling)
2594         {
2595             list_remove(&store->entry);
2596             CertCloseStore(store->store, 0);
2597             CryptMemFree(store);
2598             break;
2599         }
2600     }
2601     LeaveCriticalSection(&collection->cs);
2602 }