wintrust: Add a helper function to initialize chain creation parameters.
[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 #define CertContext_CopyProperties(to, from) \
785  Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT))
786
787 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
788  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
789  PCCERT_CONTEXT *ppStoreContext)
790 {
791     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
792     BOOL ret = TRUE;
793     PCCERT_CONTEXT toAdd = NULL, existing = NULL;
794
795     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext,
796      dwAddDisposition, ppStoreContext);
797
798     /* Weird case to pass a test */
799     if (dwAddDisposition == 0)
800     {
801         SetLastError(STATUS_ACCESS_VIOLATION);
802         return FALSE;
803     }
804     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
805     {
806         BYTE hashToAdd[20];
807         DWORD size = sizeof(hashToAdd);
808
809         ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
810          hashToAdd, &size);
811         if (ret)
812         {
813             CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
814
815             existing = CertFindCertificateInStore(hCertStore,
816              pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
817              NULL);
818         }
819     }
820
821     switch (dwAddDisposition)
822     {
823     case CERT_STORE_ADD_ALWAYS:
824         toAdd = CertDuplicateCertificateContext(pCertContext);
825         break;
826     case CERT_STORE_ADD_NEW:
827         if (existing)
828         {
829             TRACE("found matching certificate, not adding\n");
830             SetLastError(CRYPT_E_EXISTS);
831             ret = FALSE;
832         }
833         else
834             toAdd = CertDuplicateCertificateContext(pCertContext);
835         break;
836     case CERT_STORE_ADD_REPLACE_EXISTING:
837         toAdd = CertDuplicateCertificateContext(pCertContext);
838         break;
839     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
840         toAdd = CertDuplicateCertificateContext(pCertContext);
841         if (existing)
842             CertContext_CopyProperties(toAdd, existing);
843         break;
844     case CERT_STORE_ADD_USE_EXISTING:
845         if (existing)
846         {
847             CertContext_CopyProperties(existing, pCertContext);
848             *ppStoreContext = CertDuplicateCertificateContext(existing);
849         }
850         else
851             toAdd = CertDuplicateCertificateContext(pCertContext);
852         break;
853     default:
854         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
855         ret = FALSE;
856     }
857
858     if (toAdd)
859     {
860         if (store)
861             ret = store->certs.addContext(store, (void *)toAdd,
862              (void *)existing, (const void **)ppStoreContext);
863         else if (ppStoreContext)
864             *ppStoreContext = CertDuplicateCertificateContext(toAdd);
865         CertFreeCertificateContext(toAdd);
866     }
867     CertFreeCertificateContext(existing);
868
869     TRACE("returning %d\n", ret);
870     return ret;
871 }
872
873 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
874  PCCERT_CONTEXT pPrev)
875 {
876     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
877     PCCERT_CONTEXT ret;
878
879     TRACE("(%p, %p)\n", hCertStore, pPrev);
880     if (!hCertStore)
881         ret = NULL;
882     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
883         ret = NULL;
884     else
885         ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
886     return ret;
887 }
888
889 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
890 {
891     BOOL ret;
892
893     TRACE("(%p)\n", pCertContext);
894
895     if (!pCertContext)
896         ret = TRUE;
897     else if (!pCertContext->hCertStore)
898     {
899         ret = TRUE;
900         CertFreeCertificateContext(pCertContext);
901     }
902     else
903     {
904         PWINECRYPT_CERTSTORE hcs =
905          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
906
907         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
908             ret = FALSE;
909         else
910             ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
911         CertFreeCertificateContext(pCertContext);
912     }
913     return ret;
914 }
915
916 #define CrlContext_CopyProperties(to, from) \
917  Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
918
919 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
920  PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
921  PCCRL_CONTEXT* ppStoreContext)
922 {
923     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
924     BOOL ret = TRUE;
925     PCCRL_CONTEXT toAdd = NULL, existing = NULL;
926
927     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCrlContext,
928      dwAddDisposition, ppStoreContext);
929
930     /* Weird case to pass a test */
931     if (dwAddDisposition == 0)
932     {
933         SetLastError(STATUS_ACCESS_VIOLATION);
934         return FALSE;
935     }
936     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
937     {
938         existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
939          pCrlContext, NULL);
940     }
941
942     switch (dwAddDisposition)
943     {
944     case CERT_STORE_ADD_ALWAYS:
945         toAdd = CertDuplicateCRLContext(pCrlContext);
946         break;
947     case CERT_STORE_ADD_NEW:
948         if (existing)
949         {
950             TRACE("found matching CRL, not adding\n");
951             SetLastError(CRYPT_E_EXISTS);
952             ret = FALSE;
953         }
954         else
955             toAdd = CertDuplicateCRLContext(pCrlContext);
956         break;
957     case CERT_STORE_ADD_NEWER:
958         if (existing)
959         {
960             LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
961              &pCrlContext->pCrlInfo->ThisUpdate);
962
963             if (newer < 0)
964                 toAdd = CertDuplicateCRLContext(pCrlContext);
965             else
966             {
967                 TRACE("existing CRL is newer, not adding\n");
968                 SetLastError(CRYPT_E_EXISTS);
969                 ret = FALSE;
970             }
971         }
972         else
973             toAdd = CertDuplicateCRLContext(pCrlContext);
974         break;
975     case CERT_STORE_ADD_REPLACE_EXISTING:
976         toAdd = CertDuplicateCRLContext(pCrlContext);
977         break;
978     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
979         toAdd = CertDuplicateCRLContext(pCrlContext);
980         if (existing)
981             CrlContext_CopyProperties(toAdd, existing);
982         break;
983     case CERT_STORE_ADD_USE_EXISTING:
984         if (existing)
985             CrlContext_CopyProperties(existing, pCrlContext);
986         break;
987     default:
988         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
989         ret = FALSE;
990     }
991
992     if (toAdd)
993     {
994         if (store)
995             ret = store->crls.addContext(store, (void *)toAdd,
996              (void *)existing, (const void **)ppStoreContext);
997         else if (ppStoreContext)
998             *ppStoreContext = CertDuplicateCRLContext(toAdd);
999         CertFreeCRLContext(toAdd);
1000     }
1001     CertFreeCRLContext(existing);
1002
1003     TRACE("returning %d\n", ret);
1004     return ret;
1005 }
1006
1007 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
1008 {
1009     BOOL ret;
1010
1011     TRACE("(%p)\n", pCrlContext);
1012
1013     if (!pCrlContext)
1014         ret = TRUE;
1015     else if (!pCrlContext->hCertStore)
1016     {
1017         ret = TRUE;
1018         CertFreeCRLContext(pCrlContext);
1019     }
1020     else
1021     {
1022         PWINECRYPT_CERTSTORE hcs =
1023          (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore;
1024
1025         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1026             ret = FALSE;
1027         else
1028             ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
1029         CertFreeCRLContext(pCrlContext);
1030     }
1031     return ret;
1032 }
1033
1034 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
1035  PCCRL_CONTEXT pPrev)
1036 {
1037     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1038     PCCRL_CONTEXT ret;
1039
1040     TRACE("(%p, %p)\n", hCertStore, pPrev);
1041     if (!hCertStore)
1042         ret = NULL;
1043     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1044         ret = NULL;
1045     else
1046         ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
1047     return ret;
1048 }
1049
1050 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
1051   const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
1052 {
1053     FIXME("(%08x, %p, %08x): stub\n", dwCertEncodingType, pbCtlEncoded,
1054      cbCtlEncoded);
1055     return NULL;
1056 }
1057
1058 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
1059  DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
1060  DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
1061 {
1062     FIXME("(%p, %08x, %p, %d, %08x, %p): stub\n", hCertStore,
1063      dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
1064      ppCtlContext);
1065     return FALSE;
1066 }
1067
1068 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
1069  PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
1070  PCCTL_CONTEXT* ppStoreContext)
1071 {
1072     FIXME("(%p, %p, %08x, %p): stub\n", hCertStore, pCtlContext,
1073      dwAddDisposition, ppStoreContext);
1074     return TRUE;
1075 }
1076
1077 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
1078 {
1079     FIXME("(%p): stub\n", pCtlContext );
1080     return pCtlContext;
1081 }
1082
1083 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
1084 {
1085     FIXME("(%p): stub\n", pCtlContext );
1086     return TRUE;
1087 }
1088
1089 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
1090 {
1091     FIXME("(%p): stub\n", pCtlContext);
1092     return TRUE;
1093 }
1094
1095 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
1096  PCCTL_CONTEXT pPrev)
1097 {
1098     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
1099     return NULL;
1100 }
1101
1102 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
1103 {
1104     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1105
1106     TRACE("(%p)\n", hCertStore);
1107
1108     if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
1109         InterlockedIncrement(&hcs->ref);
1110     return hCertStore;
1111 }
1112
1113 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1114 {
1115     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
1116
1117     TRACE("(%p, %08x)\n", hCertStore, dwFlags);
1118
1119     if( ! hCertStore )
1120         return TRUE;
1121
1122     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
1123         return FALSE;
1124
1125     if (InterlockedDecrement(&hcs->ref) == 0)
1126     {
1127         TRACE("%p's ref count is 0, freeing\n", hcs);
1128         hcs->dwMagic = 0;
1129         hcs->closeStore(hcs, dwFlags);
1130     }
1131     else
1132         TRACE("%p's ref count is %d\n", hcs, hcs->ref);
1133     return TRUE;
1134 }
1135
1136 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
1137  DWORD dwCtrlType, void const *pvCtrlPara)
1138 {
1139     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1140     BOOL ret;
1141
1142     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
1143      pvCtrlPara);
1144
1145     if (!hcs)
1146         ret = FALSE;
1147     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1148         ret = FALSE;
1149     else
1150     {
1151         if (hcs->control)
1152             ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
1153         else
1154             ret = TRUE;
1155     }
1156     return ret;
1157 }
1158
1159 BOOL WINAPI CertGetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1160  void *pvData, DWORD *pcbData)
1161 {
1162     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1163     BOOL ret = FALSE;
1164
1165     TRACE("(%p, %d, %p, %p)\n", hCertStore, dwPropId, pvData, pcbData);
1166
1167     switch (dwPropId)
1168     {
1169     case CERT_ACCESS_STATE_PROP_ID:
1170         if (!pvData)
1171         {
1172             *pcbData = sizeof(DWORD);
1173             ret = TRUE;
1174         }
1175         else if (*pcbData < sizeof(DWORD))
1176         {
1177             SetLastError(ERROR_MORE_DATA);
1178             *pcbData = sizeof(DWORD);
1179         }
1180         else
1181         {
1182             DWORD state = 0;
1183
1184             if (store->type != StoreTypeMem &&
1185              !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1186                 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1187             *(DWORD *)pvData = state;
1188             ret = TRUE;
1189         }
1190         break;
1191     default:
1192         if (store->properties)
1193         {
1194             CRYPT_DATA_BLOB blob;
1195
1196             ret = ContextPropertyList_FindProperty(store->properties, dwPropId,
1197              &blob);
1198             if (ret)
1199             {
1200                 if (!pvData)
1201                     *pcbData = blob.cbData;
1202                 else if (*pcbData < blob.cbData)
1203                 {
1204                     SetLastError(ERROR_MORE_DATA);
1205                     *pcbData = blob.cbData;
1206                     ret = FALSE;
1207                 }
1208                 else
1209                 {
1210                     memcpy(pvData, blob.pbData, blob.cbData);
1211                     *pcbData = blob.cbData;
1212                 }
1213             }
1214             else
1215                 SetLastError(CRYPT_E_NOT_FOUND);
1216         }
1217         else
1218             SetLastError(CRYPT_E_NOT_FOUND);
1219     }
1220     return ret;
1221 }
1222
1223 BOOL WINAPI CertSetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1224  DWORD dwFlags, const void *pvData)
1225 {
1226     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1227     BOOL ret = FALSE;
1228
1229     TRACE("(%p, %d, %08x, %p)\n", hCertStore, dwPropId, dwFlags, pvData);
1230
1231     if (!store->properties)
1232         store->properties = ContextPropertyList_Create();
1233     switch (dwPropId)
1234     {
1235     case CERT_ACCESS_STATE_PROP_ID:
1236         SetLastError(E_INVALIDARG);
1237         break;
1238     default:
1239         if (pvData)
1240         {
1241             const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvData;
1242
1243             ret = ContextPropertyList_SetProperty(store->properties, dwPropId,
1244              blob->pbData, blob->cbData);
1245         }
1246         else
1247         {
1248             ContextPropertyList_RemoveProperty(store->properties, dwPropId);
1249             ret = TRUE;
1250         }
1251     }
1252     return ret;
1253 }
1254
1255 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
1256  DWORD dwPropId)
1257 {
1258     FIXME("(%p, %d): stub\n", pCTLContext, dwPropId);
1259     return 0;
1260 }
1261
1262 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1263  DWORD dwPropId, void *pvData, DWORD *pcbData)
1264 {
1265     FIXME("(%p, %d, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
1266     return FALSE;
1267 }
1268
1269 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1270  DWORD dwPropId, DWORD dwFlags, const void *pvData)
1271 {
1272     FIXME("(%p, %d, %08x, %p): stub\n", pCTLContext, dwPropId, dwFlags,
1273      pvData);
1274     return FALSE;
1275 }
1276
1277 static LONG CRYPT_OpenParentStore(DWORD dwFlags,
1278     void *pvSystemStoreLocationPara, HKEY *key)
1279 {
1280     HKEY root;
1281     LPCWSTR base;
1282
1283     TRACE("(%08x, %p)\n", dwFlags, pvSystemStoreLocationPara);
1284
1285     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1286     {
1287     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1288         root = HKEY_LOCAL_MACHINE;
1289         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1290         break;
1291     case CERT_SYSTEM_STORE_CURRENT_USER:
1292         root = HKEY_CURRENT_USER;
1293         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1294         break;
1295     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1296         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1297          * SystemCertificates
1298          */
1299         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE\n");
1300         return ERROR_FILE_NOT_FOUND;
1301     case CERT_SYSTEM_STORE_SERVICES:
1302         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1303          * SystemCertificates
1304          */
1305         FIXME("CERT_SYSTEM_STORE_SERVICES\n");
1306         return ERROR_FILE_NOT_FOUND;
1307     case CERT_SYSTEM_STORE_USERS:
1308         /* hku\user sid\Software\Microsoft\SystemCertificates */
1309         FIXME("CERT_SYSTEM_STORE_USERS\n");
1310         return ERROR_FILE_NOT_FOUND;
1311     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1312         root = HKEY_CURRENT_USER;
1313         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1314         break;
1315     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1316         root = HKEY_LOCAL_MACHINE;
1317         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1318         break;
1319     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1320         /* hklm\Software\Microsoft\EnterpriseCertificates */
1321         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE\n");
1322         return ERROR_FILE_NOT_FOUND;
1323     default:
1324         return ERROR_FILE_NOT_FOUND;
1325     }
1326
1327     return RegOpenKeyExW(root, base, 0, KEY_READ, key);
1328 }
1329
1330 BOOL WINAPI CertEnumSystemStore(DWORD dwFlags, void *pvSystemStoreLocationPara,
1331     void *pvArg, PFN_CERT_ENUM_SYSTEM_STORE pfnEnum)
1332 {
1333     BOOL ret = FALSE;
1334     LONG rc;
1335     HKEY key;
1336
1337     TRACE("(%08x, %p, %p, %p)\n", dwFlags, pvSystemStoreLocationPara, pvArg,
1338         pfnEnum);
1339
1340     rc = CRYPT_OpenParentStore(dwFlags, pvArg, &key);
1341     if (!rc)
1342     {
1343         DWORD index = 0;
1344         CERT_SYSTEM_STORE_INFO info = { sizeof(info) };
1345
1346         ret = TRUE;
1347         do {
1348             WCHAR name[MAX_PATH];
1349             DWORD size = sizeof(name) / sizeof(name[0]);
1350
1351             rc = RegEnumKeyExW(key, index++, name, &size, NULL, NULL, NULL,
1352                 NULL);
1353             if (!rc)
1354                 ret = pfnEnum(name, 0, &info, NULL, pvArg);
1355         } while (ret && !rc);
1356         if (ret && rc != ERROR_NO_MORE_ITEMS)
1357             SetLastError(rc);
1358     }
1359     else
1360         SetLastError(rc);
1361     return ret;
1362 }