crypt32: Implement CertEnumCTLsInStore.
[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 = (PCERT_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 = (PCRL_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 = (PCTL_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 PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
333  DWORD dwFlags, const void *pvPara)
334 {
335     static const WCHAR rootW[] = { 'R','o','o','t',0 };
336     static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
337     LPCWSTR storeName = (LPCWSTR)pvPara;
338     LPWSTR storePath;
339     PWINECRYPT_CERTSTORE store = NULL;
340     HKEY root;
341     LPCWSTR base;
342
343     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
344      debugstr_w((LPCWSTR)pvPara));
345
346     if (!pvPara)
347     {
348         SetLastError(E_INVALIDARG);
349         return NULL;
350     }
351     if (!lstrcmpiW(storeName, rootW))
352         return CRYPT_RootOpenStore(hCryptProv, dwFlags);
353
354     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
355     {
356     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
357         root = HKEY_LOCAL_MACHINE;
358         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
359         break;
360     case CERT_SYSTEM_STORE_CURRENT_USER:
361         root = HKEY_CURRENT_USER;
362         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
363         break;
364     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
365         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
366          * SystemCertificates
367          */
368         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
369          debugstr_w(storeName));
370         return NULL;
371     case CERT_SYSTEM_STORE_SERVICES:
372         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
373          * SystemCertificates
374          */
375         FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
376          debugstr_w(storeName));
377         return NULL;
378     case CERT_SYSTEM_STORE_USERS:
379         /* hku\user sid\Software\Microsoft\SystemCertificates */
380         FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
381          debugstr_w(storeName));
382         return NULL;
383     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
384         root = HKEY_CURRENT_USER;
385         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
386         break;
387     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
388         root = HKEY_LOCAL_MACHINE;
389         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
390         break;
391     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
392         /* hklm\Software\Microsoft\EnterpriseCertificates */
393         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
394          debugstr_w(storeName));
395         return NULL;
396     default:
397         SetLastError(E_INVALIDARG);
398         return NULL;
399     }
400
401     storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
402      sizeof(WCHAR));
403     if (storePath)
404     {
405         LONG rc;
406         HKEY key;
407         REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
408             KEY_ALL_ACCESS;
409
410         wsprintfW(storePath, fmt, base, storeName);
411         if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
412             rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
413         else
414         {
415             DWORD disp;
416
417             rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
418                                  &key, &disp);
419             if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
420                 disp == REG_OPENED_EXISTING_KEY)
421             {
422                 RegCloseKey(key);
423                 rc = ERROR_FILE_EXISTS;
424             }
425         }
426         if (!rc)
427         {
428             store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
429             RegCloseKey(key);
430         }
431         else
432             SetLastError(rc);
433         CryptMemFree(storePath);
434     }
435     return store;
436 }
437
438 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
439  DWORD dwFlags, const void *pvPara)
440 {
441     int len;
442     PWINECRYPT_CERTSTORE ret = NULL;
443
444     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
445      debugstr_a((LPCSTR)pvPara));
446
447     if (!pvPara)
448     {
449         SetLastError(ERROR_FILE_NOT_FOUND);
450         return NULL;
451     }
452     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
453     if (len)
454     {
455         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
456
457         if (storeName)
458         {
459             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
460             ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
461             CryptMemFree(storeName);
462         }
463     }
464     return ret;
465 }
466
467 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
468  DWORD dwFlags, const void *pvPara)
469 {
470     HCERTSTORE store = 0;
471     BOOL ret;
472
473     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
474      debugstr_w((LPCWSTR)pvPara));
475
476     if (!pvPara)
477     {
478         SetLastError(ERROR_FILE_NOT_FOUND);
479         return NULL;
480     }
481     /* This returns a different error than system registry stores if the
482      * location is invalid.
483      */
484     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
485     {
486     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
487     case CERT_SYSTEM_STORE_CURRENT_USER:
488     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
489     case CERT_SYSTEM_STORE_SERVICES:
490     case CERT_SYSTEM_STORE_USERS:
491     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
492     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
493     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
494         ret = TRUE;
495         break;
496     default:
497         SetLastError(ERROR_FILE_NOT_FOUND);
498         ret = FALSE;
499     }
500     if (ret)
501     {
502         HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
503          0, 0, dwFlags, pvPara);
504
505         if (regStore)
506         {
507             store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
508              CERT_STORE_CREATE_NEW_FLAG, NULL);
509             CertAddStoreToCollection(store, regStore,
510              dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
511              CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
512             CertCloseStore(regStore, 0);
513             /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
514              * stores.
515              */
516             if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
517              CERT_SYSTEM_STORE_CURRENT_USER)
518             {
519                 dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
520                 dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
521                 regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0,
522                  0, dwFlags, pvPara);
523                 if (regStore)
524                 {
525                     CertAddStoreToCollection(store, regStore,
526                      dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
527                      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
528                     CertCloseStore(regStore, 0);
529                 }
530             }
531             /* System store doesn't need crypto provider, so close it */
532             if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
533                 CryptReleaseContext(hCryptProv, 0);
534         }
535     }
536     return (PWINECRYPT_CERTSTORE)store;
537 }
538
539 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
540  DWORD dwFlags, const void *pvPara)
541 {
542     int len;
543     PWINECRYPT_CERTSTORE ret = NULL;
544
545     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
546      debugstr_a((LPCSTR)pvPara));
547
548     if (!pvPara)
549     {
550         SetLastError(ERROR_FILE_NOT_FOUND);
551         return NULL;
552     }
553     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
554     if (len)
555     {
556         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
557
558         if (storeName)
559         {
560             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
561             ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
562             CryptMemFree(storeName);
563         }
564     }
565     return ret;
566 }
567
568 static void WINAPI CRYPT_MsgCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
569 {
570     HCRYPTMSG msg = hCertStore;
571
572     TRACE("(%p, %08x)\n", msg, dwFlags);
573     CryptMsgClose(msg);
574 }
575
576 static void *msgProvFuncs[] = {
577     CRYPT_MsgCloseStore,
578 };
579
580 static PWINECRYPT_CERTSTORE CRYPT_MsgOpenStore(HCRYPTPROV hCryptProv,
581  DWORD dwFlags, const void *pvPara)
582 {
583     PWINECRYPT_CERTSTORE store = NULL;
584     HCRYPTMSG msg = (HCRYPTMSG)pvPara;
585     PWINECRYPT_CERTSTORE memStore;
586
587     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
588
589     memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
590      CERT_STORE_CREATE_NEW_FLAG, NULL);
591     if (memStore)
592     {
593         BOOL ret;
594         DWORD size, count, i;
595
596         size = sizeof(count);
597         ret = CryptMsgGetParam(msg, CMSG_CERT_COUNT_PARAM, 0, &count, &size);
598         for (i = 0; ret && i < count; i++)
599         {
600             size = 0;
601             ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, NULL, &size);
602             if (ret)
603             {
604                 LPBYTE buf = CryptMemAlloc(size);
605
606                 if (buf)
607                 {
608                     ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, buf, &size);
609                     if (ret)
610                         ret = CertAddEncodedCertificateToStore(memStore,
611                          X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS,
612                          NULL);
613                     CryptMemFree(buf);
614                 }
615             }
616         }
617         size = sizeof(count);
618         ret = CryptMsgGetParam(msg, CMSG_CRL_COUNT_PARAM, 0, &count, &size);
619         for (i = 0; ret && i < count; i++)
620         {
621             size = 0;
622             ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, NULL, &size);
623             if (ret)
624             {
625                 LPBYTE buf = CryptMemAlloc(size);
626
627                 if (buf)
628                 {
629                     ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, buf, &size);
630                     if (ret)
631                         ret = CertAddEncodedCRLToStore(memStore,
632                          X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS,
633                          NULL);
634                     CryptMemFree(buf);
635                 }
636             }
637         }
638         if (ret)
639         {
640             CERT_STORE_PROV_INFO provInfo = { 0 };
641
642             provInfo.cbSize = sizeof(provInfo);
643             provInfo.cStoreProvFunc = sizeof(msgProvFuncs) /
644              sizeof(msgProvFuncs[0]);
645             provInfo.rgpvStoreProvFunc = msgProvFuncs;
646             provInfo.hStoreProv = CryptMsgDuplicate(msg);
647             store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo);
648             /* Msg store doesn't need crypto provider, so close it */
649             if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
650                 CryptReleaseContext(hCryptProv, 0);
651         }
652         else
653             CertCloseStore(memStore, 0);
654     }
655     TRACE("returning %p\n", store);
656     return store;
657 }
658
659 static PWINECRYPT_CERTSTORE CRYPT_PKCSOpenStore(HCRYPTPROV hCryptProv,
660  DWORD dwFlags, const void *pvPara)
661 {
662     HCRYPTMSG msg;
663     PWINECRYPT_CERTSTORE store = NULL;
664     const CRYPT_DATA_BLOB *data = (const CRYPT_DATA_BLOB *)pvPara;
665     BOOL ret;
666     DWORD msgOpenFlags = dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG ? 0 :
667      CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
668
669     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
670
671     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, CMSG_SIGNED,
672      hCryptProv, NULL, NULL);
673     ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE);
674     if (!ret)
675     {
676         CryptMsgClose(msg);
677         msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, 0,
678          hCryptProv, NULL, NULL);
679         ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE);
680         if (ret)
681         {
682             DWORD type, size = sizeof(type);
683
684             /* Only signed messages are allowed, check type */
685             ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &size);
686             if (ret && type != CMSG_SIGNED)
687             {
688                 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
689                 ret = FALSE;
690             }
691         }
692     }
693     if (ret)
694         store = CRYPT_MsgOpenStore(0, dwFlags, msg);
695     CryptMsgClose(msg);
696     TRACE("returning %p\n", store);
697     return store;
698 }
699
700 static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv,
701  DWORD dwFlags, const void *pvPara)
702 {
703     if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
704         FIXME("(%ld, %08x, %p): stub\n", hCryptProv, dwFlags, pvPara);
705     else
706         FIXME("(%ld, %08x, %s): stub\n", hCryptProv, dwFlags,
707          debugstr_w((LPCWSTR)pvPara));
708     return NULL;
709 }
710
711 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
712  DWORD dwMsgAndCertEncodingType, HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags,
713  const void* pvPara)
714 {
715     WINECRYPT_CERTSTORE *hcs;
716     StoreOpenFunc openFunc = NULL;
717
718     TRACE("(%s, %08x, %08lx, %08x, %p)\n", debugstr_a(lpszStoreProvider),
719           dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
720
721     if (!HIWORD(lpszStoreProvider))
722     {
723         switch (LOWORD(lpszStoreProvider))
724         {
725         case LOWORD(CERT_STORE_PROV_MSG):
726             openFunc = CRYPT_MsgOpenStore;
727             break;
728         case LOWORD(CERT_STORE_PROV_MEMORY):
729             openFunc = CRYPT_MemOpenStore;
730             break;
731         case LOWORD(CERT_STORE_PROV_FILE):
732             openFunc = CRYPT_FileOpenStore;
733             break;
734         case LOWORD(CERT_STORE_PROV_PKCS7):
735             openFunc = CRYPT_PKCSOpenStore;
736             break;
737         case LOWORD(CERT_STORE_PROV_REG):
738             openFunc = CRYPT_RegOpenStore;
739             break;
740         case LOWORD(CERT_STORE_PROV_FILENAME_A):
741             openFunc = CRYPT_FileNameOpenStoreA;
742             break;
743         case LOWORD(CERT_STORE_PROV_FILENAME_W):
744             openFunc = CRYPT_FileNameOpenStoreW;
745             break;
746         case LOWORD(CERT_STORE_PROV_COLLECTION):
747             openFunc = CRYPT_CollectionOpenStore;
748             break;
749         case LOWORD(CERT_STORE_PROV_SYSTEM_A):
750             openFunc = CRYPT_SysOpenStoreA;
751             break;
752         case LOWORD(CERT_STORE_PROV_SYSTEM_W):
753             openFunc = CRYPT_SysOpenStoreW;
754             break;
755         case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_A):
756             openFunc = CRYPT_SysRegOpenStoreA;
757             break;
758         case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_W):
759             openFunc = CRYPT_SysRegOpenStoreW;
760             break;
761         case LOWORD(CERT_STORE_PROV_PHYSICAL_W):
762             openFunc = CRYPT_PhysOpenStoreW;
763             break;
764         default:
765             if (LOWORD(lpszStoreProvider))
766                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
767         }
768     }
769     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
770         openFunc = CRYPT_MemOpenStore;
771     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_FILENAME_W))
772         openFunc = CRYPT_FileOpenStore;
773     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
774         openFunc = CRYPT_SysOpenStoreW;
775     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
776         openFunc = CRYPT_CollectionOpenStore;
777     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
778         openFunc = CRYPT_SysRegOpenStoreW;
779     else
780     {
781         FIXME("unimplemented type %s\n", lpszStoreProvider);
782         openFunc = NULL;
783     }
784
785     if (!openFunc)
786         hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
787          hCryptProv, dwFlags, pvPara);
788     else
789         hcs = openFunc(hCryptProv, dwFlags, pvPara);
790     return (HCERTSTORE)hcs;
791 }
792
793 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv,
794  LPCSTR szSubSystemProtocol)
795 {
796     if (!szSubSystemProtocol)
797     {
798         SetLastError(E_INVALIDARG);
799         return 0;
800     }
801     return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
802      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
803 }
804
805 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv,
806  LPCWSTR szSubSystemProtocol)
807 {
808     if (!szSubSystemProtocol)
809     {
810         SetLastError(E_INVALIDARG);
811         return 0;
812     }
813     return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
814      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
815 }
816
817 #define CertContext_CopyProperties(to, from) \
818  Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT))
819
820 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
821  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
822  PCCERT_CONTEXT *ppStoreContext)
823 {
824     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
825     BOOL ret = TRUE;
826     PCCERT_CONTEXT toAdd = NULL, existing = NULL;
827
828     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext,
829      dwAddDisposition, ppStoreContext);
830
831     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
832     {
833         BYTE hashToAdd[20];
834         DWORD size = sizeof(hashToAdd);
835
836         ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
837          hashToAdd, &size);
838         if (ret)
839         {
840             CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
841
842             existing = CertFindCertificateInStore(hCertStore,
843              pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
844              NULL);
845         }
846     }
847
848     switch (dwAddDisposition)
849     {
850     case CERT_STORE_ADD_ALWAYS:
851         toAdd = CertDuplicateCertificateContext(pCertContext);
852         break;
853     case CERT_STORE_ADD_NEW:
854         if (existing)
855         {
856             TRACE("found matching certificate, not adding\n");
857             SetLastError(CRYPT_E_EXISTS);
858             ret = FALSE;
859         }
860         else
861             toAdd = CertDuplicateCertificateContext(pCertContext);
862         break;
863     case CERT_STORE_ADD_REPLACE_EXISTING:
864         toAdd = CertDuplicateCertificateContext(pCertContext);
865         break;
866     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
867         toAdd = CertDuplicateCertificateContext(pCertContext);
868         if (existing)
869             CertContext_CopyProperties(toAdd, existing);
870         break;
871     case CERT_STORE_ADD_USE_EXISTING:
872         if (existing)
873         {
874             CertContext_CopyProperties(existing, pCertContext);
875             *ppStoreContext = CertDuplicateCertificateContext(existing);
876         }
877         else
878             toAdd = CertDuplicateCertificateContext(pCertContext);
879         break;
880     case CERT_STORE_ADD_NEWER:
881         if (existing)
882         {
883             if (CompareFileTime(&existing->pCertInfo->NotBefore,
884              &pCertContext->pCertInfo->NotBefore) >= 0)
885             {
886                 TRACE("existing certificate is newer, not adding\n");
887                 SetLastError(CRYPT_E_EXISTS);
888                 ret = FALSE;
889             }
890             else
891                 toAdd = CertDuplicateCertificateContext(pCertContext);
892         }
893         else
894             toAdd = CertDuplicateCertificateContext(pCertContext);
895         break;
896     default:
897         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
898         SetLastError(E_INVALIDARG);
899         ret = FALSE;
900     }
901
902     if (toAdd)
903     {
904         if (store)
905             ret = store->certs.addContext(store, (void *)toAdd,
906              (void *)existing, (const void **)ppStoreContext);
907         else if (ppStoreContext)
908             *ppStoreContext = CertDuplicateCertificateContext(toAdd);
909         CertFreeCertificateContext(toAdd);
910     }
911     CertFreeCertificateContext(existing);
912
913     TRACE("returning %d\n", ret);
914     return ret;
915 }
916
917 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
918  PCCERT_CONTEXT pPrev)
919 {
920     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
921     PCCERT_CONTEXT ret;
922
923     TRACE("(%p, %p)\n", hCertStore, pPrev);
924     if (!hCertStore)
925         ret = NULL;
926     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
927         ret = NULL;
928     else
929         ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
930     return ret;
931 }
932
933 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
934 {
935     BOOL ret;
936
937     TRACE("(%p)\n", pCertContext);
938
939     if (!pCertContext)
940         ret = TRUE;
941     else if (!pCertContext->hCertStore)
942     {
943         ret = TRUE;
944         CertFreeCertificateContext(pCertContext);
945     }
946     else
947     {
948         PWINECRYPT_CERTSTORE hcs =
949          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
950
951         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
952             ret = FALSE;
953         else
954             ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
955         CertFreeCertificateContext(pCertContext);
956     }
957     return ret;
958 }
959
960 #define CrlContext_CopyProperties(to, from) \
961  Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
962
963 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
964  PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
965  PCCRL_CONTEXT* ppStoreContext)
966 {
967     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
968     BOOL ret = TRUE;
969     PCCRL_CONTEXT toAdd = NULL, existing = NULL;
970
971     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCrlContext,
972      dwAddDisposition, ppStoreContext);
973
974     /* Weird case to pass a test */
975     if (dwAddDisposition == 0)
976     {
977         SetLastError(STATUS_ACCESS_VIOLATION);
978         return FALSE;
979     }
980     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
981     {
982         existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
983          pCrlContext, NULL);
984     }
985
986     switch (dwAddDisposition)
987     {
988     case CERT_STORE_ADD_ALWAYS:
989         toAdd = CertDuplicateCRLContext(pCrlContext);
990         break;
991     case CERT_STORE_ADD_NEW:
992         if (existing)
993         {
994             TRACE("found matching CRL, not adding\n");
995             SetLastError(CRYPT_E_EXISTS);
996             ret = FALSE;
997         }
998         else
999             toAdd = CertDuplicateCRLContext(pCrlContext);
1000         break;
1001     case CERT_STORE_ADD_NEWER:
1002         if (existing)
1003         {
1004             LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
1005              &pCrlContext->pCrlInfo->ThisUpdate);
1006
1007             if (newer < 0)
1008                 toAdd = CertDuplicateCRLContext(pCrlContext);
1009             else
1010             {
1011                 TRACE("existing CRL is newer, not adding\n");
1012                 SetLastError(CRYPT_E_EXISTS);
1013                 ret = FALSE;
1014             }
1015         }
1016         else
1017             toAdd = CertDuplicateCRLContext(pCrlContext);
1018         break;
1019     case CERT_STORE_ADD_REPLACE_EXISTING:
1020         toAdd = CertDuplicateCRLContext(pCrlContext);
1021         break;
1022     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
1023         toAdd = CertDuplicateCRLContext(pCrlContext);
1024         if (existing)
1025             CrlContext_CopyProperties(toAdd, existing);
1026         break;
1027     case CERT_STORE_ADD_USE_EXISTING:
1028         if (existing)
1029             CrlContext_CopyProperties(existing, pCrlContext);
1030         break;
1031     default:
1032         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
1033         ret = FALSE;
1034     }
1035
1036     if (toAdd)
1037     {
1038         if (store)
1039             ret = store->crls.addContext(store, (void *)toAdd,
1040              (void *)existing, (const void **)ppStoreContext);
1041         else if (ppStoreContext)
1042             *ppStoreContext = CertDuplicateCRLContext(toAdd);
1043         CertFreeCRLContext(toAdd);
1044     }
1045     CertFreeCRLContext(existing);
1046
1047     TRACE("returning %d\n", ret);
1048     return ret;
1049 }
1050
1051 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
1052 {
1053     BOOL ret;
1054
1055     TRACE("(%p)\n", pCrlContext);
1056
1057     if (!pCrlContext)
1058         ret = TRUE;
1059     else if (!pCrlContext->hCertStore)
1060     {
1061         ret = TRUE;
1062         CertFreeCRLContext(pCrlContext);
1063     }
1064     else
1065     {
1066         PWINECRYPT_CERTSTORE hcs =
1067          (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore;
1068
1069         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1070             ret = FALSE;
1071         else
1072             ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
1073         CertFreeCRLContext(pCrlContext);
1074     }
1075     return ret;
1076 }
1077
1078 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
1079  PCCRL_CONTEXT pPrev)
1080 {
1081     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1082     PCCRL_CONTEXT ret;
1083
1084     TRACE("(%p, %p)\n", hCertStore, pPrev);
1085     if (!hCertStore)
1086         ret = NULL;
1087     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1088         ret = NULL;
1089     else
1090         ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
1091     return ret;
1092 }
1093
1094 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
1095  PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
1096  PCCTL_CONTEXT* ppStoreContext)
1097 {
1098     FIXME("(%p, %p, %08x, %p): stub\n", hCertStore, pCtlContext,
1099      dwAddDisposition, ppStoreContext);
1100     return TRUE;
1101 }
1102
1103 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
1104 {
1105     FIXME("(%p): stub\n", pCtlContext);
1106     return TRUE;
1107 }
1108
1109 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
1110 {
1111     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1112
1113     TRACE("(%p)\n", hCertStore);
1114
1115     if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
1116         InterlockedIncrement(&hcs->ref);
1117     return hCertStore;
1118 }
1119
1120 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1121 {
1122     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
1123
1124     TRACE("(%p, %08x)\n", hCertStore, dwFlags);
1125
1126     if( ! hCertStore )
1127         return TRUE;
1128
1129     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
1130         return FALSE;
1131
1132     if (InterlockedDecrement(&hcs->ref) == 0)
1133     {
1134         TRACE("%p's ref count is 0, freeing\n", hcs);
1135         hcs->dwMagic = 0;
1136         hcs->closeStore(hcs, dwFlags);
1137     }
1138     else
1139         TRACE("%p's ref count is %d\n", hcs, hcs->ref);
1140     return TRUE;
1141 }
1142
1143 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
1144  DWORD dwCtrlType, void const *pvCtrlPara)
1145 {
1146     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1147     BOOL ret;
1148
1149     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
1150      pvCtrlPara);
1151
1152     if (!hcs)
1153         ret = FALSE;
1154     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1155         ret = FALSE;
1156     else
1157     {
1158         if (hcs->control)
1159             ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
1160         else
1161             ret = TRUE;
1162     }
1163     return ret;
1164 }
1165
1166 BOOL WINAPI CertGetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1167  void *pvData, DWORD *pcbData)
1168 {
1169     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1170     BOOL ret = FALSE;
1171
1172     TRACE("(%p, %d, %p, %p)\n", hCertStore, dwPropId, pvData, pcbData);
1173
1174     switch (dwPropId)
1175     {
1176     case CERT_ACCESS_STATE_PROP_ID:
1177         if (!pvData)
1178         {
1179             *pcbData = sizeof(DWORD);
1180             ret = TRUE;
1181         }
1182         else if (*pcbData < sizeof(DWORD))
1183         {
1184             SetLastError(ERROR_MORE_DATA);
1185             *pcbData = sizeof(DWORD);
1186         }
1187         else
1188         {
1189             DWORD state = 0;
1190
1191             if (store->type != StoreTypeMem &&
1192              !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1193                 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1194             *(DWORD *)pvData = state;
1195             ret = TRUE;
1196         }
1197         break;
1198     default:
1199         if (store->properties)
1200         {
1201             CRYPT_DATA_BLOB blob;
1202
1203             ret = ContextPropertyList_FindProperty(store->properties, dwPropId,
1204              &blob);
1205             if (ret)
1206             {
1207                 if (!pvData)
1208                     *pcbData = blob.cbData;
1209                 else if (*pcbData < blob.cbData)
1210                 {
1211                     SetLastError(ERROR_MORE_DATA);
1212                     *pcbData = blob.cbData;
1213                     ret = FALSE;
1214                 }
1215                 else
1216                 {
1217                     memcpy(pvData, blob.pbData, blob.cbData);
1218                     *pcbData = blob.cbData;
1219                 }
1220             }
1221             else
1222                 SetLastError(CRYPT_E_NOT_FOUND);
1223         }
1224         else
1225             SetLastError(CRYPT_E_NOT_FOUND);
1226     }
1227     return ret;
1228 }
1229
1230 BOOL WINAPI CertSetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1231  DWORD dwFlags, const void *pvData)
1232 {
1233     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1234     BOOL ret = FALSE;
1235
1236     TRACE("(%p, %d, %08x, %p)\n", hCertStore, dwPropId, dwFlags, pvData);
1237
1238     if (!store->properties)
1239         store->properties = ContextPropertyList_Create();
1240     switch (dwPropId)
1241     {
1242     case CERT_ACCESS_STATE_PROP_ID:
1243         SetLastError(E_INVALIDARG);
1244         break;
1245     default:
1246         if (pvData)
1247         {
1248             const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvData;
1249
1250             ret = ContextPropertyList_SetProperty(store->properties, dwPropId,
1251              blob->pbData, blob->cbData);
1252         }
1253         else
1254         {
1255             ContextPropertyList_RemoveProperty(store->properties, dwPropId);
1256             ret = TRUE;
1257         }
1258     }
1259     return ret;
1260 }
1261
1262 static LONG CRYPT_OpenParentStore(DWORD dwFlags,
1263     void *pvSystemStoreLocationPara, HKEY *key)
1264 {
1265     HKEY root;
1266     LPCWSTR base;
1267
1268     TRACE("(%08x, %p)\n", dwFlags, pvSystemStoreLocationPara);
1269
1270     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1271     {
1272     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1273         root = HKEY_LOCAL_MACHINE;
1274         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1275         break;
1276     case CERT_SYSTEM_STORE_CURRENT_USER:
1277         root = HKEY_CURRENT_USER;
1278         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1279         break;
1280     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1281         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1282          * SystemCertificates
1283          */
1284         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE\n");
1285         return ERROR_FILE_NOT_FOUND;
1286     case CERT_SYSTEM_STORE_SERVICES:
1287         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1288          * SystemCertificates
1289          */
1290         FIXME("CERT_SYSTEM_STORE_SERVICES\n");
1291         return ERROR_FILE_NOT_FOUND;
1292     case CERT_SYSTEM_STORE_USERS:
1293         /* hku\user sid\Software\Microsoft\SystemCertificates */
1294         FIXME("CERT_SYSTEM_STORE_USERS\n");
1295         return ERROR_FILE_NOT_FOUND;
1296     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1297         root = HKEY_CURRENT_USER;
1298         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1299         break;
1300     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1301         root = HKEY_LOCAL_MACHINE;
1302         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1303         break;
1304     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1305         /* hklm\Software\Microsoft\EnterpriseCertificates */
1306         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE\n");
1307         return ERROR_FILE_NOT_FOUND;
1308     default:
1309         return ERROR_FILE_NOT_FOUND;
1310     }
1311
1312     return RegOpenKeyExW(root, base, 0, KEY_READ, key);
1313 }
1314
1315 BOOL WINAPI CertEnumSystemStore(DWORD dwFlags, void *pvSystemStoreLocationPara,
1316     void *pvArg, PFN_CERT_ENUM_SYSTEM_STORE pfnEnum)
1317 {
1318     BOOL ret = FALSE;
1319     LONG rc;
1320     HKEY key;
1321
1322     TRACE("(%08x, %p, %p, %p)\n", dwFlags, pvSystemStoreLocationPara, pvArg,
1323         pfnEnum);
1324
1325     rc = CRYPT_OpenParentStore(dwFlags, pvArg, &key);
1326     if (!rc)
1327     {
1328         DWORD index = 0;
1329         CERT_SYSTEM_STORE_INFO info = { sizeof(info) };
1330
1331         ret = TRUE;
1332         do {
1333             WCHAR name[MAX_PATH];
1334             DWORD size = sizeof(name) / sizeof(name[0]);
1335
1336             rc = RegEnumKeyExW(key, index++, name, &size, NULL, NULL, NULL,
1337                 NULL);
1338             if (!rc)
1339                 ret = pfnEnum(name, 0, &info, NULL, pvArg);
1340         } while (ret && !rc);
1341         if (ret && rc != ERROR_NO_MORE_ITEMS)
1342             SetLastError(rc);
1343     }
1344     else
1345         SetLastError(rc);
1346     return ret;
1347 }