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