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