ddraw: Get rid of ddcomimpl.h.
[wine] / dlls / crypt32 / store.c
1 /*
2  * Copyright 2002 Mike McCormack for CodeWeavers
3  * Copyright 2004-2006 Juan Lang
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
19  * FIXME:
20  * - The concept of physical stores and locations isn't implemented.  (This
21  *   doesn't mean registry stores et al aren't implemented.  See the PSDK for
22  *   registering and enumerating physical stores and locations.)
23  * - Many flags, options and whatnot are unimplemented.
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <assert.h>
30 #include <stdarg.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "winuser.h"
36 #include "wincrypt.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "wine/exception.h"
40 #include "crypt32_private.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
43
44 static const WINE_CONTEXT_INTERFACE gCertInterface = {
45     (CreateContextFunc)CertCreateCertificateContext,
46     (AddContextToStoreFunc)CertAddCertificateContextToStore,
47     (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
48     (DuplicateContextFunc)CertDuplicateCertificateContext,
49     (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
50     (EnumPropertiesFunc)CertEnumCertificateContextProperties,
51     (GetContextPropertyFunc)CertGetCertificateContextProperty,
52     (SetContextPropertyFunc)CertSetCertificateContextProperty,
53     (SerializeElementFunc)CertSerializeCertificateStoreElement,
54     (FreeContextFunc)CertFreeCertificateContext,
55     (DeleteContextFunc)CertDeleteCertificateFromStore,
56 };
57 PCWINE_CONTEXT_INTERFACE pCertInterface = &gCertInterface;
58
59 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
60     (CreateContextFunc)CertCreateCRLContext,
61     (AddContextToStoreFunc)CertAddCRLContextToStore,
62     (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
63     (DuplicateContextFunc)CertDuplicateCRLContext,
64     (EnumContextsInStoreFunc)CertEnumCRLsInStore,
65     (EnumPropertiesFunc)CertEnumCRLContextProperties,
66     (GetContextPropertyFunc)CertGetCRLContextProperty,
67     (SetContextPropertyFunc)CertSetCRLContextProperty,
68     (SerializeElementFunc)CertSerializeCRLStoreElement,
69     (FreeContextFunc)CertFreeCRLContext,
70     (DeleteContextFunc)CertDeleteCRLFromStore,
71 };
72 PCWINE_CONTEXT_INTERFACE pCRLInterface = &gCRLInterface;
73
74 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
75     (CreateContextFunc)CertCreateCTLContext,
76     (AddContextToStoreFunc)CertAddCTLContextToStore,
77     (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
78     (DuplicateContextFunc)CertDuplicateCTLContext,
79     (EnumContextsInStoreFunc)CertEnumCTLsInStore,
80     (EnumPropertiesFunc)CertEnumCTLContextProperties,
81     (GetContextPropertyFunc)CertGetCTLContextProperty,
82     (SetContextPropertyFunc)CertSetCTLContextProperty,
83     (SerializeElementFunc)CertSerializeCTLStoreElement,
84     (FreeContextFunc)CertFreeCTLContext,
85     (DeleteContextFunc)CertDeleteCTLFromStore,
86 };
87 PCWINE_CONTEXT_INTERFACE pCTLInterface = &gCTLInterface;
88
89 typedef struct _WINE_MEMSTORE
90 {
91     WINECRYPT_CERTSTORE hdr;
92     struct ContextList *certs;
93     struct ContextList *crls;
94     struct ContextList *ctls;
95 } WINE_MEMSTORE, *PWINE_MEMSTORE;
96
97 void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, DWORD dwFlags,
98  CertStoreType type)
99 {
100     store->ref = 1;
101     store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
102     store->type = type;
103     store->dwOpenFlags = dwFlags;
104     store->properties = NULL;
105 }
106
107 void CRYPT_FreeStore(PWINECRYPT_CERTSTORE store)
108 {
109     if (store->properties)
110         ContextPropertyList_Free(store->properties);
111     CryptMemFree(store);
112 }
113
114 BOOL WINAPI I_CertUpdateStore(HCERTSTORE store1, HCERTSTORE store2, DWORD unk0,
115  DWORD unk1)
116 {
117     static BOOL warned = FALSE;
118     const WINE_CONTEXT_INTERFACE * const interfaces[] = { pCertInterface,
119      pCRLInterface, pCTLInterface };
120     DWORD i;
121
122     TRACE("(%p, %p, %08x, %08x)\n", store1, store2, unk0, unk1);
123     if (!warned)
124     {
125         FIXME("semi-stub\n");
126         warned = TRUE;
127     }
128
129     /* Poor-man's resync:  empty first store, then add everything from second
130      * store to it.
131      */
132     for (i = 0; i < sizeof(interfaces) / sizeof(interfaces[0]); i++)
133     {
134         const void *context;
135
136         do {
137             context = interfaces[i]->enumContextsInStore(store1, NULL);
138             if (context)
139                 interfaces[i]->deleteFromStore(context);
140         } while (context);
141         do {
142             context = interfaces[i]->enumContextsInStore(store2, context);
143             if (context)
144                 interfaces[i]->addContextToStore(store1, context,
145                  CERT_STORE_ADD_ALWAYS, NULL);
146         } while (context);
147     }
148     return TRUE;
149 }
150
151 static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, void *cert,
152  void *toReplace, const void **ppStoreContext)
153 {
154     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
155     PCERT_CONTEXT context;
156
157     TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
158
159     context = ContextList_Add(ms->certs, cert, toReplace);
160     if (context)
161     {
162         context->hCertStore = store;
163         if (ppStoreContext)
164             *ppStoreContext = CertDuplicateCertificateContext(context);
165     }
166     return context ? TRUE : FALSE;
167 }
168
169 static void *CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
170 {
171     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
172     void *ret;
173
174     TRACE("(%p, %p)\n", store, pPrev);
175
176     ret = ContextList_Enum(ms->certs, pPrev);
177     if (!ret)
178         SetLastError(CRYPT_E_NOT_FOUND);
179
180     TRACE("returning %p\n", ret);
181     return ret;
182 }
183
184 static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext)
185 {
186     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
187
188     ContextList_Delete(ms->certs, pCertContext);
189     return TRUE;
190 }
191
192 static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl,
193  void *toReplace, const void **ppStoreContext)
194 {
195     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
196     PCRL_CONTEXT context;
197
198     TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext);
199
200     context = ContextList_Add(ms->crls, crl, toReplace);
201     if (context)
202     {
203         context->hCertStore = store;
204         if (ppStoreContext)
205             *ppStoreContext = CertDuplicateCRLContext(context);
206     }
207     return context ? TRUE : FALSE;
208 }
209
210 static void *CRYPT_MemEnumCrl(PWINECRYPT_CERTSTORE store, void *pPrev)
211 {
212     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
213     void *ret;
214
215     TRACE("(%p, %p)\n", store, pPrev);
216
217     ret = ContextList_Enum(ms->crls, pPrev);
218     if (!ret)
219         SetLastError(CRYPT_E_NOT_FOUND);
220
221     TRACE("returning %p\n", ret);
222     return ret;
223 }
224
225 static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext)
226 {
227     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
228
229     ContextList_Delete(ms->crls, pCrlContext);
230     return TRUE;
231 }
232
233 static BOOL CRYPT_MemAddCtl(PWINECRYPT_CERTSTORE store, void *ctl,
234  void *toReplace, const void **ppStoreContext)
235 {
236     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
237     PCTL_CONTEXT context;
238
239     TRACE("(%p, %p, %p, %p)\n", store, ctl, toReplace, ppStoreContext);
240
241     context = ContextList_Add(ms->ctls, ctl, toReplace);
242     if (context)
243     {
244         context->hCertStore = store;
245         if (ppStoreContext)
246             *ppStoreContext = CertDuplicateCTLContext(context);
247     }
248     return context ? TRUE : FALSE;
249 }
250
251 static void *CRYPT_MemEnumCtl(PWINECRYPT_CERTSTORE store, void *pPrev)
252 {
253     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
254     void *ret;
255
256     TRACE("(%p, %p)\n", store, pPrev);
257
258     ret = ContextList_Enum(ms->ctls, pPrev);
259     if (!ret)
260         SetLastError(CRYPT_E_NOT_FOUND);
261
262     TRACE("returning %p\n", ret);
263     return ret;
264 }
265
266 static BOOL CRYPT_MemDeleteCtl(PWINECRYPT_CERTSTORE store, void *pCtlContext)
267 {
268     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
269
270     ContextList_Delete(ms->ctls, pCtlContext);
271     return TRUE;
272 }
273
274 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
275 {
276     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
277
278     TRACE("(%p, %08x)\n", store, dwFlags);
279     if (dwFlags)
280         FIXME("Unimplemented flags: %08x\n", dwFlags);
281
282     ContextList_Free(store->certs);
283     ContextList_Free(store->crls);
284     ContextList_Free(store->ctls);
285     CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store);
286 }
287
288 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
289  DWORD dwFlags, const void *pvPara)
290 {
291     PWINE_MEMSTORE store;
292
293     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
294
295     if (dwFlags & CERT_STORE_DELETE_FLAG)
296     {
297         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
298         store = NULL;
299     }
300     else
301     {
302         store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
303         if (store)
304         {
305             memset(store, 0, sizeof(WINE_MEMSTORE));
306             CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeMem);
307             store->hdr.closeStore          = CRYPT_MemCloseStore;
308             store->hdr.certs.addContext    = CRYPT_MemAddCert;
309             store->hdr.certs.enumContext   = CRYPT_MemEnumCert;
310             store->hdr.certs.deleteContext = CRYPT_MemDeleteCert;
311             store->hdr.crls.addContext     = CRYPT_MemAddCrl;
312             store->hdr.crls.enumContext    = CRYPT_MemEnumCrl;
313             store->hdr.crls.deleteContext  = CRYPT_MemDeleteCrl;
314             store->hdr.ctls.addContext     = CRYPT_MemAddCtl;
315             store->hdr.ctls.enumContext    = CRYPT_MemEnumCtl;
316             store->hdr.ctls.deleteContext  = CRYPT_MemDeleteCtl;
317             store->hdr.control             = NULL;
318             store->certs = ContextList_Create(pCertInterface,
319              sizeof(CERT_CONTEXT));
320             store->crls = ContextList_Create(pCRLInterface,
321              sizeof(CRL_CONTEXT));
322             store->ctls = ContextList_Create(pCTLInterface,
323              sizeof(CTL_CONTEXT));
324             /* Mem store doesn't need crypto provider, so close it */
325             if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
326                 CryptReleaseContext(hCryptProv, 0);
327         }
328     }
329     return (PWINECRYPT_CERTSTORE)store;
330 }
331
332 static const WCHAR rootW[] = { 'R','o','o','t',0 };
333
334 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
335  DWORD dwFlags, const void *pvPara)
336 {
337     static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
338     LPCWSTR storeName = (LPCWSTR)pvPara;
339     LPWSTR storePath;
340     PWINECRYPT_CERTSTORE store = NULL;
341     HKEY root;
342     LPCWSTR base;
343
344     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
345      debugstr_w((LPCWSTR)pvPara));
346
347     if (!pvPara)
348     {
349         SetLastError(E_INVALIDARG);
350         return NULL;
351     }
352     /* FIXME:  In Windows, the root store (even the current user location) is
353      * protected:  adding to it or removing from it present a user interface,
354      * and the keys are owned by the system process, not the current user.
355      * Wine's registry doesn't implement access controls, so a similar
356      * mechanism isn't possible yet.
357      */
358     if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
359      CERT_SYSTEM_STORE_LOCAL_MACHINE && !lstrcmpiW(storeName, rootW))
360         return CRYPT_RootOpenStore(hCryptProv, dwFlags);
361
362     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
363     {
364     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
365         root = HKEY_LOCAL_MACHINE;
366         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
367         break;
368     case CERT_SYSTEM_STORE_CURRENT_USER:
369         root = HKEY_CURRENT_USER;
370         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
371         break;
372     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
373         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
374          * SystemCertificates
375          */
376         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
377          debugstr_w(storeName));
378         return NULL;
379     case CERT_SYSTEM_STORE_SERVICES:
380         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
381          * SystemCertificates
382          */
383         FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
384          debugstr_w(storeName));
385         return NULL;
386     case CERT_SYSTEM_STORE_USERS:
387         /* hku\user sid\Software\Microsoft\SystemCertificates */
388         FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
389          debugstr_w(storeName));
390         return NULL;
391     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
392         root = HKEY_CURRENT_USER;
393         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
394         break;
395     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
396         root = HKEY_LOCAL_MACHINE;
397         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
398         break;
399     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
400         /* hklm\Software\Microsoft\EnterpriseCertificates */
401         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
402          debugstr_w(storeName));
403         return NULL;
404     default:
405         SetLastError(E_INVALIDARG);
406         return NULL;
407     }
408
409     storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
410      sizeof(WCHAR));
411     if (storePath)
412     {
413         LONG rc;
414         HKEY key;
415         REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
416             KEY_ALL_ACCESS;
417
418         wsprintfW(storePath, fmt, base, storeName);
419         if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
420             rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
421         else
422         {
423             DWORD disp;
424
425             rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
426                                  &key, &disp);
427             if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
428                 disp == REG_OPENED_EXISTING_KEY)
429             {
430                 RegCloseKey(key);
431                 rc = ERROR_FILE_EXISTS;
432             }
433         }
434         if (!rc)
435         {
436             store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
437             RegCloseKey(key);
438         }
439         else
440             SetLastError(rc);
441         CryptMemFree(storePath);
442     }
443     return store;
444 }
445
446 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
447  DWORD dwFlags, const void *pvPara)
448 {
449     int len;
450     PWINECRYPT_CERTSTORE ret = NULL;
451
452     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
453      debugstr_a((LPCSTR)pvPara));
454
455     if (!pvPara)
456     {
457         SetLastError(ERROR_FILE_NOT_FOUND);
458         return NULL;
459     }
460     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
461     if (len)
462     {
463         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
464
465         if (storeName)
466         {
467             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
468             ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
469             CryptMemFree(storeName);
470         }
471     }
472     return ret;
473 }
474
475 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
476  DWORD dwFlags, const void *pvPara)
477 {
478     HCERTSTORE store = 0;
479     BOOL ret;
480
481     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
482      debugstr_w((LPCWSTR)pvPara));
483
484     if (!pvPara)
485     {
486         SetLastError(ERROR_FILE_NOT_FOUND);
487         return NULL;
488     }
489     /* This returns a different error than system registry stores if the
490      * location is invalid.
491      */
492     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
493     {
494     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
495     case CERT_SYSTEM_STORE_CURRENT_USER:
496     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
497     case CERT_SYSTEM_STORE_SERVICES:
498     case CERT_SYSTEM_STORE_USERS:
499     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
500     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
501     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
502         ret = TRUE;
503         break;
504     default:
505         SetLastError(ERROR_FILE_NOT_FOUND);
506         ret = FALSE;
507     }
508     if (ret)
509     {
510         HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
511          0, 0, dwFlags, pvPara);
512
513         if (regStore)
514         {
515             store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
516              CERT_STORE_CREATE_NEW_FLAG, NULL);
517             CertAddStoreToCollection(store, regStore,
518              dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
519              CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
520             CertCloseStore(regStore, 0);
521             /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
522              * stores.
523              */
524             if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
525              CERT_SYSTEM_STORE_CURRENT_USER)
526             {
527                 dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
528                 dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
529                 regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0,
530                  0, dwFlags, pvPara);
531                 if (regStore)
532                 {
533                     CertAddStoreToCollection(store, regStore,
534                      dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
535                      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
536                     CertCloseStore(regStore, 0);
537                 }
538             }
539             /* System store doesn't need crypto provider, so close it */
540             if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
541                 CryptReleaseContext(hCryptProv, 0);
542         }
543     }
544     return (PWINECRYPT_CERTSTORE)store;
545 }
546
547 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
548  DWORD dwFlags, const void *pvPara)
549 {
550     int len;
551     PWINECRYPT_CERTSTORE ret = NULL;
552
553     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
554      debugstr_a((LPCSTR)pvPara));
555
556     if (!pvPara)
557     {
558         SetLastError(ERROR_FILE_NOT_FOUND);
559         return NULL;
560     }
561     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
562     if (len)
563     {
564         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
565
566         if (storeName)
567         {
568             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
569             ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
570             CryptMemFree(storeName);
571         }
572     }
573     return ret;
574 }
575
576 static void WINAPI CRYPT_MsgCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
577 {
578     HCRYPTMSG msg = hCertStore;
579
580     TRACE("(%p, %08x)\n", msg, dwFlags);
581     CryptMsgClose(msg);
582 }
583
584 static void *msgProvFuncs[] = {
585     CRYPT_MsgCloseStore,
586 };
587
588 static PWINECRYPT_CERTSTORE CRYPT_MsgOpenStore(HCRYPTPROV hCryptProv,
589  DWORD dwFlags, const void *pvPara)
590 {
591     PWINECRYPT_CERTSTORE store = NULL;
592     HCRYPTMSG msg = (HCRYPTMSG)pvPara;
593     PWINECRYPT_CERTSTORE memStore;
594
595     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
596
597     memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
598      CERT_STORE_CREATE_NEW_FLAG, NULL);
599     if (memStore)
600     {
601         BOOL ret;
602         DWORD size, count, i;
603
604         size = sizeof(count);
605         ret = CryptMsgGetParam(msg, CMSG_CERT_COUNT_PARAM, 0, &count, &size);
606         for (i = 0; ret && i < count; i++)
607         {
608             size = 0;
609             ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, NULL, &size);
610             if (ret)
611             {
612                 LPBYTE buf = CryptMemAlloc(size);
613
614                 if (buf)
615                 {
616                     ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, buf, &size);
617                     if (ret)
618                         ret = CertAddEncodedCertificateToStore(memStore,
619                          X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS,
620                          NULL);
621                     CryptMemFree(buf);
622                 }
623             }
624         }
625         size = sizeof(count);
626         ret = CryptMsgGetParam(msg, CMSG_CRL_COUNT_PARAM, 0, &count, &size);
627         for (i = 0; ret && i < count; i++)
628         {
629             size = 0;
630             ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, NULL, &size);
631             if (ret)
632             {
633                 LPBYTE buf = CryptMemAlloc(size);
634
635                 if (buf)
636                 {
637                     ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, buf, &size);
638                     if (ret)
639                         ret = CertAddEncodedCRLToStore(memStore,
640                          X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS,
641                          NULL);
642                     CryptMemFree(buf);
643                 }
644             }
645         }
646         if (ret)
647         {
648             CERT_STORE_PROV_INFO provInfo = { 0 };
649
650             provInfo.cbSize = sizeof(provInfo);
651             provInfo.cStoreProvFunc = sizeof(msgProvFuncs) /
652              sizeof(msgProvFuncs[0]);
653             provInfo.rgpvStoreProvFunc = msgProvFuncs;
654             provInfo.hStoreProv = CryptMsgDuplicate(msg);
655             store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo);
656             /* Msg store doesn't need crypto provider, so close it */
657             if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
658                 CryptReleaseContext(hCryptProv, 0);
659         }
660         else
661             CertCloseStore(memStore, 0);
662     }
663     TRACE("returning %p\n", store);
664     return store;
665 }
666
667 static PWINECRYPT_CERTSTORE CRYPT_PKCSOpenStore(HCRYPTPROV hCryptProv,
668  DWORD dwFlags, const void *pvPara)
669 {
670     HCRYPTMSG msg;
671     PWINECRYPT_CERTSTORE store = NULL;
672     const CRYPT_DATA_BLOB *data = (const CRYPT_DATA_BLOB *)pvPara;
673     BOOL ret;
674     DWORD msgOpenFlags = dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG ? 0 :
675      CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
676
677     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
678
679     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, CMSG_SIGNED,
680      hCryptProv, NULL, NULL);
681     ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE);
682     if (!ret)
683     {
684         CryptMsgClose(msg);
685         msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, 0,
686          hCryptProv, NULL, NULL);
687         ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE);
688         if (ret)
689         {
690             DWORD type, size = sizeof(type);
691
692             /* Only signed messages are allowed, check type */
693             ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &size);
694             if (ret && type != CMSG_SIGNED)
695             {
696                 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
697                 ret = FALSE;
698             }
699         }
700     }
701     if (ret)
702         store = CRYPT_MsgOpenStore(0, dwFlags, msg);
703     CryptMsgClose(msg);
704     TRACE("returning %p\n", store);
705     return store;
706 }
707
708 static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv,
709  DWORD dwFlags, const void *pvPara)
710 {
711     if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
712         FIXME("(%ld, %08x, %p): stub\n", hCryptProv, dwFlags, pvPara);
713     else
714         FIXME("(%ld, %08x, %s): stub\n", hCryptProv, dwFlags,
715          debugstr_w((LPCWSTR)pvPara));
716     return NULL;
717 }
718
719 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
720  DWORD dwMsgAndCertEncodingType, HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags,
721  const void* pvPara)
722 {
723     WINECRYPT_CERTSTORE *hcs;
724     StoreOpenFunc openFunc = NULL;
725
726     TRACE("(%s, %08x, %08lx, %08x, %p)\n", debugstr_a(lpszStoreProvider),
727           dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
728
729     if (!HIWORD(lpszStoreProvider))
730     {
731         switch (LOWORD(lpszStoreProvider))
732         {
733         case LOWORD(CERT_STORE_PROV_MSG):
734             openFunc = CRYPT_MsgOpenStore;
735             break;
736         case LOWORD(CERT_STORE_PROV_MEMORY):
737             openFunc = CRYPT_MemOpenStore;
738             break;
739         case LOWORD(CERT_STORE_PROV_FILE):
740             openFunc = CRYPT_FileOpenStore;
741             break;
742         case LOWORD(CERT_STORE_PROV_PKCS7):
743             openFunc = CRYPT_PKCSOpenStore;
744             break;
745         case LOWORD(CERT_STORE_PROV_REG):
746             openFunc = CRYPT_RegOpenStore;
747             break;
748         case LOWORD(CERT_STORE_PROV_FILENAME_A):
749             openFunc = CRYPT_FileNameOpenStoreA;
750             break;
751         case LOWORD(CERT_STORE_PROV_FILENAME_W):
752             openFunc = CRYPT_FileNameOpenStoreW;
753             break;
754         case LOWORD(CERT_STORE_PROV_COLLECTION):
755             openFunc = CRYPT_CollectionOpenStore;
756             break;
757         case LOWORD(CERT_STORE_PROV_SYSTEM_A):
758             openFunc = CRYPT_SysOpenStoreA;
759             break;
760         case LOWORD(CERT_STORE_PROV_SYSTEM_W):
761             openFunc = CRYPT_SysOpenStoreW;
762             break;
763         case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_A):
764             openFunc = CRYPT_SysRegOpenStoreA;
765             break;
766         case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_W):
767             openFunc = CRYPT_SysRegOpenStoreW;
768             break;
769         case LOWORD(CERT_STORE_PROV_PHYSICAL_W):
770             openFunc = CRYPT_PhysOpenStoreW;
771             break;
772         default:
773             if (LOWORD(lpszStoreProvider))
774                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
775         }
776     }
777     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
778         openFunc = CRYPT_MemOpenStore;
779     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_FILENAME_W))
780         openFunc = CRYPT_FileOpenStore;
781     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
782         openFunc = CRYPT_SysOpenStoreW;
783     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
784         openFunc = CRYPT_CollectionOpenStore;
785     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
786         openFunc = CRYPT_SysRegOpenStoreW;
787     else
788     {
789         FIXME("unimplemented type %s\n", lpszStoreProvider);
790         openFunc = NULL;
791     }
792
793     if (!openFunc)
794         hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
795          hCryptProv, dwFlags, pvPara);
796     else
797         hcs = openFunc(hCryptProv, dwFlags, pvPara);
798     return (HCERTSTORE)hcs;
799 }
800
801 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv,
802  LPCSTR szSubSystemProtocol)
803 {
804     if (!szSubSystemProtocol)
805     {
806         SetLastError(E_INVALIDARG);
807         return 0;
808     }
809     return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
810      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
811 }
812
813 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv,
814  LPCWSTR szSubSystemProtocol)
815 {
816     if (!szSubSystemProtocol)
817     {
818         SetLastError(E_INVALIDARG);
819         return 0;
820     }
821     return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
822      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
823 }
824
825 #define CertContext_CopyProperties(to, from) \
826  Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT))
827
828 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
829  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
830  PCCERT_CONTEXT *ppStoreContext)
831 {
832     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
833     BOOL ret = TRUE;
834     PCCERT_CONTEXT toAdd = NULL, existing = NULL;
835
836     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext,
837      dwAddDisposition, ppStoreContext);
838
839     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
840     {
841         BYTE hashToAdd[20];
842         DWORD size = sizeof(hashToAdd);
843
844         ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
845          hashToAdd, &size);
846         if (ret)
847         {
848             CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
849
850             existing = CertFindCertificateInStore(hCertStore,
851              pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
852              NULL);
853         }
854     }
855
856     switch (dwAddDisposition)
857     {
858     case CERT_STORE_ADD_ALWAYS:
859         toAdd = CertDuplicateCertificateContext(pCertContext);
860         break;
861     case CERT_STORE_ADD_NEW:
862         if (existing)
863         {
864             TRACE("found matching certificate, not adding\n");
865             SetLastError(CRYPT_E_EXISTS);
866             ret = FALSE;
867         }
868         else
869             toAdd = CertDuplicateCertificateContext(pCertContext);
870         break;
871     case CERT_STORE_ADD_REPLACE_EXISTING:
872         toAdd = CertDuplicateCertificateContext(pCertContext);
873         break;
874     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
875         toAdd = CertDuplicateCertificateContext(pCertContext);
876         if (existing)
877             CertContext_CopyProperties(toAdd, existing);
878         break;
879     case CERT_STORE_ADD_USE_EXISTING:
880         if (existing)
881         {
882             CertContext_CopyProperties(existing, pCertContext);
883             *ppStoreContext = CertDuplicateCertificateContext(existing);
884         }
885         else
886             toAdd = CertDuplicateCertificateContext(pCertContext);
887         break;
888     case CERT_STORE_ADD_NEWER:
889         if (existing)
890         {
891             if (CompareFileTime(&existing->pCertInfo->NotBefore,
892              &pCertContext->pCertInfo->NotBefore) >= 0)
893             {
894                 TRACE("existing certificate is newer, not adding\n");
895                 SetLastError(CRYPT_E_EXISTS);
896                 ret = FALSE;
897             }
898             else
899                 toAdd = CertDuplicateCertificateContext(pCertContext);
900         }
901         else
902             toAdd = CertDuplicateCertificateContext(pCertContext);
903         break;
904     case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
905         if (existing)
906         {
907             if (CompareFileTime(&existing->pCertInfo->NotBefore,
908              &pCertContext->pCertInfo->NotBefore) >= 0)
909             {
910                 TRACE("existing certificate is newer, not adding\n");
911                 SetLastError(CRYPT_E_EXISTS);
912                 ret = FALSE;
913             }
914             else
915             {
916                 toAdd = CertDuplicateCertificateContext(pCertContext);
917                 CertContext_CopyProperties(toAdd, existing);
918             }
919         }
920         else
921             toAdd = CertDuplicateCertificateContext(pCertContext);
922         break;
923     default:
924         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
925         SetLastError(E_INVALIDARG);
926         ret = FALSE;
927     }
928
929     if (toAdd)
930     {
931         if (store)
932             ret = store->certs.addContext(store, (void *)toAdd,
933              (void *)existing, (const void **)ppStoreContext);
934         else if (ppStoreContext)
935             *ppStoreContext = CertDuplicateCertificateContext(toAdd);
936         CertFreeCertificateContext(toAdd);
937     }
938     CertFreeCertificateContext(existing);
939
940     TRACE("returning %d\n", ret);
941     return ret;
942 }
943
944 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
945  PCCERT_CONTEXT pPrev)
946 {
947     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
948     PCCERT_CONTEXT ret;
949
950     TRACE("(%p, %p)\n", hCertStore, pPrev);
951     if (!hCertStore)
952         ret = NULL;
953     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
954         ret = NULL;
955     else
956         ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
957     return ret;
958 }
959
960 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
961 {
962     BOOL ret;
963
964     TRACE("(%p)\n", pCertContext);
965
966     if (!pCertContext)
967         ret = TRUE;
968     else if (!pCertContext->hCertStore)
969     {
970         ret = TRUE;
971         CertFreeCertificateContext(pCertContext);
972     }
973     else
974     {
975         PWINECRYPT_CERTSTORE hcs =
976          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
977
978         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
979             ret = FALSE;
980         else
981             ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
982         CertFreeCertificateContext(pCertContext);
983     }
984     return ret;
985 }
986
987 #define CrlContext_CopyProperties(to, from) \
988  Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
989
990 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
991  PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
992  PCCRL_CONTEXT* ppStoreContext)
993 {
994     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
995     BOOL ret = TRUE;
996     PCCRL_CONTEXT toAdd = NULL, existing = NULL;
997
998     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCrlContext,
999      dwAddDisposition, ppStoreContext);
1000
1001     /* Weird case to pass a test */
1002     if (dwAddDisposition == 0)
1003     {
1004         SetLastError(STATUS_ACCESS_VIOLATION);
1005         return FALSE;
1006     }
1007     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
1008     {
1009         existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
1010          pCrlContext, NULL);
1011     }
1012
1013     switch (dwAddDisposition)
1014     {
1015     case CERT_STORE_ADD_ALWAYS:
1016         toAdd = CertDuplicateCRLContext(pCrlContext);
1017         break;
1018     case CERT_STORE_ADD_NEW:
1019         if (existing)
1020         {
1021             TRACE("found matching CRL, not adding\n");
1022             SetLastError(CRYPT_E_EXISTS);
1023             ret = FALSE;
1024         }
1025         else
1026             toAdd = CertDuplicateCRLContext(pCrlContext);
1027         break;
1028     case CERT_STORE_ADD_NEWER:
1029         if (existing)
1030         {
1031             LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
1032              &pCrlContext->pCrlInfo->ThisUpdate);
1033
1034             if (newer < 0)
1035                 toAdd = CertDuplicateCRLContext(pCrlContext);
1036             else
1037             {
1038                 TRACE("existing CRL is newer, not adding\n");
1039                 SetLastError(CRYPT_E_EXISTS);
1040                 ret = FALSE;
1041             }
1042         }
1043         else
1044             toAdd = CertDuplicateCRLContext(pCrlContext);
1045         break;
1046     case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
1047         if (existing)
1048         {
1049             LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
1050              &pCrlContext->pCrlInfo->ThisUpdate);
1051
1052             if (newer < 0)
1053             {
1054                 toAdd = CertDuplicateCRLContext(pCrlContext);
1055                 CrlContext_CopyProperties(toAdd, existing);
1056             }
1057             else
1058             {
1059                 TRACE("existing CRL is newer, not adding\n");
1060                 SetLastError(CRYPT_E_EXISTS);
1061                 ret = FALSE;
1062             }
1063         }
1064         else
1065             toAdd = CertDuplicateCRLContext(pCrlContext);
1066         break;
1067     case CERT_STORE_ADD_REPLACE_EXISTING:
1068         toAdd = CertDuplicateCRLContext(pCrlContext);
1069         break;
1070     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
1071         toAdd = CertDuplicateCRLContext(pCrlContext);
1072         if (existing)
1073             CrlContext_CopyProperties(toAdd, existing);
1074         break;
1075     case CERT_STORE_ADD_USE_EXISTING:
1076         if (existing)
1077             CrlContext_CopyProperties(existing, pCrlContext);
1078         break;
1079     default:
1080         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
1081         ret = FALSE;
1082     }
1083
1084     if (toAdd)
1085     {
1086         if (store)
1087             ret = store->crls.addContext(store, (void *)toAdd,
1088              (void *)existing, (const void **)ppStoreContext);
1089         else if (ppStoreContext)
1090             *ppStoreContext = CertDuplicateCRLContext(toAdd);
1091         CertFreeCRLContext(toAdd);
1092     }
1093     CertFreeCRLContext(existing);
1094
1095     TRACE("returning %d\n", ret);
1096     return ret;
1097 }
1098
1099 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
1100 {
1101     BOOL ret;
1102
1103     TRACE("(%p)\n", pCrlContext);
1104
1105     if (!pCrlContext)
1106         ret = TRUE;
1107     else if (!pCrlContext->hCertStore)
1108     {
1109         ret = TRUE;
1110         CertFreeCRLContext(pCrlContext);
1111     }
1112     else
1113     {
1114         PWINECRYPT_CERTSTORE hcs =
1115          (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore;
1116
1117         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1118             ret = FALSE;
1119         else
1120             ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
1121         CertFreeCRLContext(pCrlContext);
1122     }
1123     return ret;
1124 }
1125
1126 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
1127  PCCRL_CONTEXT pPrev)
1128 {
1129     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1130     PCCRL_CONTEXT ret;
1131
1132     TRACE("(%p, %p)\n", hCertStore, pPrev);
1133     if (!hCertStore)
1134         ret = NULL;
1135     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1136         ret = NULL;
1137     else
1138         ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
1139     return ret;
1140 }
1141
1142 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
1143 {
1144     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1145
1146     TRACE("(%p)\n", hCertStore);
1147
1148     if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
1149         InterlockedIncrement(&hcs->ref);
1150     return hCertStore;
1151 }
1152
1153 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1154 {
1155     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
1156
1157     TRACE("(%p, %08x)\n", hCertStore, dwFlags);
1158
1159     if( ! hCertStore )
1160         return TRUE;
1161
1162     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
1163         return FALSE;
1164
1165     if (InterlockedDecrement(&hcs->ref) == 0)
1166     {
1167         TRACE("%p's ref count is 0, freeing\n", hcs);
1168         hcs->dwMagic = 0;
1169         hcs->closeStore(hcs, dwFlags);
1170     }
1171     else
1172         TRACE("%p's ref count is %d\n", hcs, hcs->ref);
1173     return TRUE;
1174 }
1175
1176 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
1177  DWORD dwCtrlType, void const *pvCtrlPara)
1178 {
1179     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1180     BOOL ret;
1181
1182     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
1183      pvCtrlPara);
1184
1185     if (!hcs)
1186         ret = FALSE;
1187     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1188         ret = FALSE;
1189     else
1190     {
1191         if (hcs->control)
1192             ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
1193         else
1194             ret = TRUE;
1195     }
1196     return ret;
1197 }
1198
1199 BOOL WINAPI CertGetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1200  void *pvData, DWORD *pcbData)
1201 {
1202     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1203     BOOL ret = FALSE;
1204
1205     TRACE("(%p, %d, %p, %p)\n", hCertStore, dwPropId, pvData, pcbData);
1206
1207     switch (dwPropId)
1208     {
1209     case CERT_ACCESS_STATE_PROP_ID:
1210         if (!pvData)
1211         {
1212             *pcbData = sizeof(DWORD);
1213             ret = TRUE;
1214         }
1215         else if (*pcbData < sizeof(DWORD))
1216         {
1217             SetLastError(ERROR_MORE_DATA);
1218             *pcbData = sizeof(DWORD);
1219         }
1220         else
1221         {
1222             DWORD state = 0;
1223
1224             if (store->type != StoreTypeMem &&
1225              !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1226                 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1227             *(DWORD *)pvData = state;
1228             ret = TRUE;
1229         }
1230         break;
1231     default:
1232         if (store->properties)
1233         {
1234             CRYPT_DATA_BLOB blob;
1235
1236             ret = ContextPropertyList_FindProperty(store->properties, dwPropId,
1237              &blob);
1238             if (ret)
1239             {
1240                 if (!pvData)
1241                     *pcbData = blob.cbData;
1242                 else if (*pcbData < blob.cbData)
1243                 {
1244                     SetLastError(ERROR_MORE_DATA);
1245                     *pcbData = blob.cbData;
1246                     ret = FALSE;
1247                 }
1248                 else
1249                 {
1250                     memcpy(pvData, blob.pbData, blob.cbData);
1251                     *pcbData = blob.cbData;
1252                 }
1253             }
1254             else
1255                 SetLastError(CRYPT_E_NOT_FOUND);
1256         }
1257         else
1258             SetLastError(CRYPT_E_NOT_FOUND);
1259     }
1260     return ret;
1261 }
1262
1263 BOOL WINAPI CertSetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1264  DWORD dwFlags, const void *pvData)
1265 {
1266     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1267     BOOL ret = FALSE;
1268
1269     TRACE("(%p, %d, %08x, %p)\n", hCertStore, dwPropId, dwFlags, pvData);
1270
1271     if (!store->properties)
1272         store->properties = ContextPropertyList_Create();
1273     switch (dwPropId)
1274     {
1275     case CERT_ACCESS_STATE_PROP_ID:
1276         SetLastError(E_INVALIDARG);
1277         break;
1278     default:
1279         if (pvData)
1280         {
1281             const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvData;
1282
1283             ret = ContextPropertyList_SetProperty(store->properties, dwPropId,
1284              blob->pbData, blob->cbData);
1285         }
1286         else
1287         {
1288             ContextPropertyList_RemoveProperty(store->properties, dwPropId);
1289             ret = TRUE;
1290         }
1291     }
1292     return ret;
1293 }
1294
1295 static LONG CRYPT_OpenParentStore(DWORD dwFlags,
1296     void *pvSystemStoreLocationPara, HKEY *key)
1297 {
1298     HKEY root;
1299     LPCWSTR base;
1300
1301     TRACE("(%08x, %p)\n", dwFlags, pvSystemStoreLocationPara);
1302
1303     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1304     {
1305     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1306         root = HKEY_LOCAL_MACHINE;
1307         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1308         break;
1309     case CERT_SYSTEM_STORE_CURRENT_USER:
1310         root = HKEY_CURRENT_USER;
1311         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1312         break;
1313     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1314         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1315          * SystemCertificates
1316          */
1317         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE\n");
1318         return ERROR_FILE_NOT_FOUND;
1319     case CERT_SYSTEM_STORE_SERVICES:
1320         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1321          * SystemCertificates
1322          */
1323         FIXME("CERT_SYSTEM_STORE_SERVICES\n");
1324         return ERROR_FILE_NOT_FOUND;
1325     case CERT_SYSTEM_STORE_USERS:
1326         /* hku\user sid\Software\Microsoft\SystemCertificates */
1327         FIXME("CERT_SYSTEM_STORE_USERS\n");
1328         return ERROR_FILE_NOT_FOUND;
1329     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1330         root = HKEY_CURRENT_USER;
1331         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1332         break;
1333     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1334         root = HKEY_LOCAL_MACHINE;
1335         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1336         break;
1337     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1338         /* hklm\Software\Microsoft\EnterpriseCertificates */
1339         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE\n");
1340         return ERROR_FILE_NOT_FOUND;
1341     default:
1342         return ERROR_FILE_NOT_FOUND;
1343     }
1344
1345     return RegOpenKeyExW(root, base, 0, KEY_READ, key);
1346 }
1347
1348 BOOL WINAPI CertEnumSystemStore(DWORD dwFlags, void *pvSystemStoreLocationPara,
1349     void *pvArg, PFN_CERT_ENUM_SYSTEM_STORE pfnEnum)
1350 {
1351     BOOL ret = FALSE;
1352     LONG rc;
1353     HKEY key;
1354     CERT_SYSTEM_STORE_INFO info = { sizeof(info) };
1355
1356     TRACE("(%08x, %p, %p, %p)\n", dwFlags, pvSystemStoreLocationPara, pvArg,
1357         pfnEnum);
1358
1359     rc = CRYPT_OpenParentStore(dwFlags, pvArg, &key);
1360     if (!rc)
1361     {
1362         DWORD index = 0;
1363
1364         ret = TRUE;
1365         do {
1366             WCHAR name[MAX_PATH];
1367             DWORD size = sizeof(name) / sizeof(name[0]);
1368
1369             rc = RegEnumKeyExW(key, index++, name, &size, NULL, NULL, NULL,
1370                 NULL);
1371             if (!rc)
1372                 ret = pfnEnum(name, dwFlags, &info, NULL, pvArg);
1373         } while (ret && !rc);
1374         if (ret && rc != ERROR_NO_MORE_ITEMS)
1375             SetLastError(rc);
1376     }
1377     else
1378         SetLastError(rc);
1379     /* Include root store for the local machine location (it isn't in the
1380      * registry)
1381      */
1382     if (ret && (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
1383      CERT_SYSTEM_STORE_LOCAL_MACHINE)
1384         ret = pfnEnum(rootW, dwFlags, &info, NULL, pvArg);
1385     return ret;
1386 }
1387
1388 BOOL WINAPI CertEnumPhysicalStore(const void *pvSystemStore, DWORD dwFlags,
1389  void *pvArg, PFN_CERT_ENUM_PHYSICAL_STORE pfnEnum)
1390 {
1391     if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
1392         FIXME("(%p, %08x, %p, %p): stub\n", pvSystemStore, dwFlags, pvArg,
1393          pfnEnum);
1394     else
1395         FIXME("(%s, %08x, %p, %p): stub\n", debugstr_w((LPCWSTR)pvSystemStore),
1396          dwFlags, pvArg,
1397          pfnEnum);
1398     return FALSE;
1399 }