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