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