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