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