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