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