gdi32: Add separate functions for releasing/freeing DCs to replace the standard GDI...
[wine] / dlls / crypt32 / store.c
1 /*
2  * Copyright 2002 Mike McCormack for CodeWeavers
3  * Copyright 2004-2006 Juan Lang
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
19  * FIXME:
20  * - The concept of physical stores and locations isn't implemented.  (This
21  *   doesn't mean registry stores et al aren't implemented.  See the PSDK for
22  *   registering and enumerating physical stores and locations.)
23  * - Many flags, options and whatnot are unimplemented.
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <assert.h>
30 #include <stdarg.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "winuser.h"
36 #include "wincrypt.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "wine/exception.h"
40 #include "crypt32_private.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
43
44 static const WINE_CONTEXT_INTERFACE gCertInterface = {
45     (CreateContextFunc)CertCreateCertificateContext,
46     (AddContextToStoreFunc)CertAddCertificateContextToStore,
47     (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
48     (DuplicateContextFunc)CertDuplicateCertificateContext,
49     (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
50     (EnumPropertiesFunc)CertEnumCertificateContextProperties,
51     (GetContextPropertyFunc)CertGetCertificateContextProperty,
52     (SetContextPropertyFunc)CertSetCertificateContextProperty,
53     (SerializeElementFunc)CertSerializeCertificateStoreElement,
54     (FreeContextFunc)CertFreeCertificateContext,
55     (DeleteContextFunc)CertDeleteCertificateFromStore,
56 };
57 PCWINE_CONTEXT_INTERFACE pCertInterface = &gCertInterface;
58
59 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
60     (CreateContextFunc)CertCreateCRLContext,
61     (AddContextToStoreFunc)CertAddCRLContextToStore,
62     (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
63     (DuplicateContextFunc)CertDuplicateCRLContext,
64     (EnumContextsInStoreFunc)CertEnumCRLsInStore,
65     (EnumPropertiesFunc)CertEnumCRLContextProperties,
66     (GetContextPropertyFunc)CertGetCRLContextProperty,
67     (SetContextPropertyFunc)CertSetCRLContextProperty,
68     (SerializeElementFunc)CertSerializeCRLStoreElement,
69     (FreeContextFunc)CertFreeCRLContext,
70     (DeleteContextFunc)CertDeleteCRLFromStore,
71 };
72 PCWINE_CONTEXT_INTERFACE pCRLInterface = &gCRLInterface;
73
74 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
75     (CreateContextFunc)CertCreateCTLContext,
76     (AddContextToStoreFunc)CertAddCTLContextToStore,
77     (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
78     (DuplicateContextFunc)CertDuplicateCTLContext,
79     (EnumContextsInStoreFunc)CertEnumCTLsInStore,
80     (EnumPropertiesFunc)CertEnumCTLContextProperties,
81     (GetContextPropertyFunc)CertGetCTLContextProperty,
82     (SetContextPropertyFunc)CertSetCTLContextProperty,
83     (SerializeElementFunc)CertSerializeCTLStoreElement,
84     (FreeContextFunc)CertFreeCTLContext,
85     (DeleteContextFunc)CertDeleteCTLFromStore,
86 };
87 PCWINE_CONTEXT_INTERFACE pCTLInterface = &gCTLInterface;
88
89 typedef struct _WINE_MEMSTORE
90 {
91     WINECRYPT_CERTSTORE hdr;
92     struct ContextList *certs;
93     struct ContextList *crls;
94 } WINE_MEMSTORE, *PWINE_MEMSTORE;
95
96 typedef struct _WINE_MSGSTOREINFO
97 {
98     DWORD      dwOpenFlags;
99     HCERTSTORE memStore;
100     HCRYPTMSG  msg;
101 } WINE_MSGSTOREINFO, *PWINE_MSGSTOREINFO;
102
103 void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, DWORD dwFlags,
104  CertStoreType type)
105 {
106     store->ref = 1;
107     store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
108     store->type = type;
109     store->dwOpenFlags = dwFlags;
110     store->properties = NULL;
111 }
112
113 void CRYPT_FreeStore(PWINECRYPT_CERTSTORE store)
114 {
115     if (store->properties)
116         ContextPropertyList_Free(store->properties);
117     CryptMemFree(store);
118 }
119
120 static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, void *cert,
121  void *toReplace, const void **ppStoreContext)
122 {
123     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
124     PCERT_CONTEXT context;
125
126     TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
127
128     context = (PCERT_CONTEXT)ContextList_Add(ms->certs, cert, toReplace);
129     if (context)
130     {
131         context->hCertStore = store;
132         if (ppStoreContext)
133             *ppStoreContext = CertDuplicateCertificateContext(context);
134     }
135     return context ? TRUE : FALSE;
136 }
137
138 static void *CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
139 {
140     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
141     void *ret;
142
143     TRACE("(%p, %p)\n", store, pPrev);
144
145     ret = ContextList_Enum(ms->certs, pPrev);
146     if (!ret)
147         SetLastError(CRYPT_E_NOT_FOUND);
148
149     TRACE("returning %p\n", ret);
150     return ret;
151 }
152
153 static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext)
154 {
155     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
156
157     ContextList_Delete(ms->certs, pCertContext);
158     return TRUE;
159 }
160
161 static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl,
162  void *toReplace, const void **ppStoreContext)
163 {
164     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
165     PCRL_CONTEXT context;
166
167     TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext);
168
169     context = (PCRL_CONTEXT)ContextList_Add(ms->crls, crl, toReplace);
170     if (context)
171     {
172         context->hCertStore = store;
173         if (ppStoreContext)
174             *ppStoreContext = CertDuplicateCRLContext(context);
175     }
176     return context ? TRUE : FALSE;
177 }
178
179 static void *CRYPT_MemEnumCrl(PWINECRYPT_CERTSTORE store, void *pPrev)
180 {
181     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
182     void *ret;
183
184     TRACE("(%p, %p)\n", store, pPrev);
185
186     ret = ContextList_Enum(ms->crls, pPrev);
187     if (!ret)
188         SetLastError(CRYPT_E_NOT_FOUND);
189
190     TRACE("returning %p\n", ret);
191     return ret;
192 }
193
194 static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext)
195 {
196     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
197
198     ContextList_Delete(ms->crls, pCrlContext);
199     return TRUE;
200 }
201
202 void CRYPT_EmptyStore(HCERTSTORE store)
203 {
204     PCCERT_CONTEXT cert;
205     PCCRL_CONTEXT crl;
206
207     do {
208         cert = CertEnumCertificatesInStore(store, NULL);
209         if (cert)
210             CertDeleteCertificateFromStore(cert);
211     } while (cert);
212     do {
213         crl = CertEnumCRLsInStore(store, NULL);
214         if (crl)
215             CertDeleteCRLFromStore(crl);
216     } while (crl);
217 }
218
219 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
220 {
221     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
222
223     TRACE("(%p, %08x)\n", store, dwFlags);
224     if (dwFlags)
225         FIXME("Unimplemented flags: %08x\n", dwFlags);
226
227     ContextList_Free(store->certs);
228     ContextList_Free(store->crls);
229     CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store);
230 }
231
232 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
233  DWORD dwFlags, const void *pvPara)
234 {
235     PWINE_MEMSTORE store;
236
237     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
238
239     if (dwFlags & CERT_STORE_DELETE_FLAG)
240     {
241         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
242         store = NULL;
243     }
244     else
245     {
246         store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
247         if (store)
248         {
249             memset(store, 0, sizeof(WINE_MEMSTORE));
250             CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeMem);
251             store->hdr.closeStore          = CRYPT_MemCloseStore;
252             store->hdr.certs.addContext    = CRYPT_MemAddCert;
253             store->hdr.certs.enumContext   = CRYPT_MemEnumCert;
254             store->hdr.certs.deleteContext = CRYPT_MemDeleteCert;
255             store->hdr.crls.addContext     = CRYPT_MemAddCrl;
256             store->hdr.crls.enumContext    = CRYPT_MemEnumCrl;
257             store->hdr.crls.deleteContext  = CRYPT_MemDeleteCrl;
258             store->hdr.control             = NULL;
259             store->certs = ContextList_Create(pCertInterface,
260              sizeof(CERT_CONTEXT));
261             store->crls = ContextList_Create(pCRLInterface,
262              sizeof(CRL_CONTEXT));
263             /* Mem store doesn't need crypto provider, so close it */
264             if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
265                 CryptReleaseContext(hCryptProv, 0);
266         }
267     }
268     return (PWINECRYPT_CERTSTORE)store;
269 }
270
271 /* FIXME: this isn't complete for the Root store, in which the top-level
272  * self-signed CA certs reside.  Adding a cert to the Root store should present
273  * the user with a dialog indicating the consequences of doing so, and asking
274  * the user to confirm whether the cert should be added.
275  */
276 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
277  DWORD dwFlags, const void *pvPara)
278 {
279     static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
280     LPCWSTR storeName = (LPCWSTR)pvPara;
281     LPWSTR storePath;
282     PWINECRYPT_CERTSTORE store = NULL;
283     HKEY root;
284     LPCWSTR base;
285     BOOL ret;
286
287     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
288      debugstr_w((LPCWSTR)pvPara));
289
290     if (!pvPara)
291     {
292         SetLastError(E_INVALIDARG);
293         return NULL;
294     }
295
296     ret = TRUE;
297     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
298     {
299     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
300         root = HKEY_LOCAL_MACHINE;
301         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
302         break;
303     case CERT_SYSTEM_STORE_CURRENT_USER:
304         root = HKEY_CURRENT_USER;
305         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
306         break;
307     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
308         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
309          * SystemCertificates
310          */
311         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
312          debugstr_w(storeName));
313         return NULL;
314     case CERT_SYSTEM_STORE_SERVICES:
315         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
316          * SystemCertificates
317          */
318         FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
319          debugstr_w(storeName));
320         return NULL;
321     case CERT_SYSTEM_STORE_USERS:
322         /* hku\user sid\Software\Microsoft\SystemCertificates */
323         FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
324          debugstr_w(storeName));
325         return NULL;
326     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
327         root = HKEY_CURRENT_USER;
328         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
329         break;
330     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
331         root = HKEY_LOCAL_MACHINE;
332         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
333         break;
334     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
335         /* hklm\Software\Microsoft\EnterpriseCertificates */
336         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
337          debugstr_w(storeName));
338         return NULL;
339     default:
340         SetLastError(E_INVALIDARG);
341         return NULL;
342     }
343
344     storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
345      sizeof(WCHAR));
346     if (storePath)
347     {
348         LONG rc;
349         HKEY key;
350         REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
351             KEY_ALL_ACCESS;
352
353         wsprintfW(storePath, fmt, base, storeName);
354         if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
355             rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
356         else
357         {
358             DWORD disp;
359
360             rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
361                                  &key, &disp);
362             if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
363                 disp == REG_OPENED_EXISTING_KEY)
364             {
365                 RegCloseKey(key);
366                 rc = ERROR_FILE_EXISTS;
367             }
368         }
369         if (!rc)
370         {
371             store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
372             RegCloseKey(key);
373         }
374         else
375             SetLastError(rc);
376         CryptMemFree(storePath);
377     }
378     return store;
379 }
380
381 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
382  DWORD dwFlags, const void *pvPara)
383 {
384     int len;
385     PWINECRYPT_CERTSTORE ret = NULL;
386
387     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
388      debugstr_a((LPCSTR)pvPara));
389
390     if (!pvPara)
391     {
392         SetLastError(ERROR_FILE_NOT_FOUND);
393         return NULL;
394     }
395     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
396     if (len)
397     {
398         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
399
400         if (storeName)
401         {
402             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
403             ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
404             CryptMemFree(storeName);
405         }
406     }
407     return ret;
408 }
409
410 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
411  DWORD dwFlags, const void *pvPara)
412 {
413     HCERTSTORE store = 0;
414     BOOL ret;
415
416     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
417      debugstr_w((LPCWSTR)pvPara));
418
419     if (!pvPara)
420     {
421         SetLastError(ERROR_FILE_NOT_FOUND);
422         return NULL;
423     }
424     /* This returns a different error than system registry stores if the
425      * location is invalid.
426      */
427     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
428     {
429     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
430     case CERT_SYSTEM_STORE_CURRENT_USER:
431     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
432     case CERT_SYSTEM_STORE_SERVICES:
433     case CERT_SYSTEM_STORE_USERS:
434     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
435     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
436     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
437         ret = TRUE;
438         break;
439     default:
440         SetLastError(ERROR_FILE_NOT_FOUND);
441         ret = FALSE;
442     }
443     if (ret)
444     {
445         HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
446          0, 0, dwFlags, pvPara);
447
448         if (regStore)
449         {
450             store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
451              CERT_STORE_CREATE_NEW_FLAG, NULL);
452             CertAddStoreToCollection(store, regStore,
453              dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
454              CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
455             CertCloseStore(regStore, 0);
456             /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
457              * stores.
458              */
459             if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
460              CERT_SYSTEM_STORE_CURRENT_USER)
461             {
462                 dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
463                 dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
464                 regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0,
465                  0, dwFlags, pvPara);
466                 if (regStore)
467                 {
468                     CertAddStoreToCollection(store, regStore,
469                      dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
470                      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
471                     CertCloseStore(regStore, 0);
472                 }
473             }
474             /* System store doesn't need crypto provider, so close it */
475             if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
476                 CryptReleaseContext(hCryptProv, 0);
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, 0,
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(dwFlags, memStore,
613                  &provInfo);
614                 /* Msg store doesn't need crypto provider, so close it */
615                 if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
616                     CryptReleaseContext(hCryptProv, 0);
617             }
618             else
619                 CertCloseStore(memStore, 0);
620         }
621         else
622             CertCloseStore(memStore, 0);
623     }
624     TRACE("returning %p\n", store);
625     return store;
626 }
627
628 static PWINECRYPT_CERTSTORE CRYPT_PKCSOpenStore(HCRYPTPROV hCryptProv,
629  DWORD dwFlags, const void *pvPara)
630 {
631     HCRYPTMSG msg;
632     PWINECRYPT_CERTSTORE store = NULL;
633     const CRYPT_DATA_BLOB *data = (const CRYPT_DATA_BLOB *)pvPara;
634     BOOL ret;
635     DWORD msgOpenFlags = dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG ? 0 :
636      CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
637
638     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
639
640     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, CMSG_SIGNED,
641      hCryptProv, NULL, NULL);
642     ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE);
643     if (!ret)
644     {
645         CryptMsgClose(msg);
646         msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, 0,
647          hCryptProv, NULL, NULL);
648         ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE);
649         if (ret)
650         {
651             DWORD type, size = sizeof(type);
652
653             /* Only signed messages are allowed, check type */
654             ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &size);
655             if (ret && type != CMSG_SIGNED)
656             {
657                 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
658                 ret = FALSE;
659             }
660         }
661     }
662     if (ret)
663         store = CRYPT_MsgOpenStore(0, dwFlags, msg);
664     CryptMsgClose(msg);
665     TRACE("returning %p\n", store);
666     return store;
667 }
668
669 static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv,
670  DWORD dwFlags, const void *pvPara)
671 {
672     if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
673         FIXME("(%ld, %08x, %p): stub\n", hCryptProv, dwFlags, pvPara);
674     else
675         FIXME("(%ld, %08x, %s): stub\n", hCryptProv, dwFlags,
676          debugstr_w((LPCWSTR)pvPara));
677     return NULL;
678 }
679
680 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
681  DWORD dwMsgAndCertEncodingType, HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags,
682  const void* pvPara)
683 {
684     WINECRYPT_CERTSTORE *hcs;
685     StoreOpenFunc openFunc = NULL;
686
687     TRACE("(%s, %08x, %08lx, %08x, %p)\n", debugstr_a(lpszStoreProvider),
688           dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
689
690     if (!HIWORD(lpszStoreProvider))
691     {
692         switch (LOWORD(lpszStoreProvider))
693         {
694         case (int)CERT_STORE_PROV_MSG:
695             openFunc = CRYPT_MsgOpenStore;
696             break;
697         case (int)CERT_STORE_PROV_MEMORY:
698             openFunc = CRYPT_MemOpenStore;
699             break;
700         case (int)CERT_STORE_PROV_FILE:
701             openFunc = CRYPT_FileOpenStore;
702             break;
703         case (int)CERT_STORE_PROV_PKCS7:
704             openFunc = CRYPT_PKCSOpenStore;
705             break;
706         case (int)CERT_STORE_PROV_REG:
707             openFunc = CRYPT_RegOpenStore;
708             break;
709         case (int)CERT_STORE_PROV_FILENAME_A:
710             openFunc = CRYPT_FileNameOpenStoreA;
711             break;
712         case (int)CERT_STORE_PROV_FILENAME_W:
713             openFunc = CRYPT_FileNameOpenStoreW;
714             break;
715         case (int)CERT_STORE_PROV_COLLECTION:
716             openFunc = CRYPT_CollectionOpenStore;
717             break;
718         case (int)CERT_STORE_PROV_SYSTEM_A:
719             openFunc = CRYPT_SysOpenStoreA;
720             break;
721         case (int)CERT_STORE_PROV_SYSTEM_W:
722             openFunc = CRYPT_SysOpenStoreW;
723             break;
724         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
725             openFunc = CRYPT_SysRegOpenStoreA;
726             break;
727         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
728             openFunc = CRYPT_SysRegOpenStoreW;
729             break;
730         case (int)CERT_STORE_PROV_PHYSICAL_W:
731             openFunc = CRYPT_PhysOpenStoreW;
732             break;
733         default:
734             if (LOWORD(lpszStoreProvider))
735                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
736         }
737     }
738     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
739         openFunc = CRYPT_MemOpenStore;
740     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_FILENAME_W))
741         openFunc = CRYPT_FileOpenStore;
742     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
743         openFunc = CRYPT_SysOpenStoreW;
744     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
745         openFunc = CRYPT_CollectionOpenStore;
746     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
747         openFunc = CRYPT_SysRegOpenStoreW;
748     else
749     {
750         FIXME("unimplemented type %s\n", lpszStoreProvider);
751         openFunc = NULL;
752     }
753
754     if (!openFunc)
755         hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
756          hCryptProv, dwFlags, pvPara);
757     else
758         hcs = openFunc(hCryptProv, dwFlags, pvPara);
759     return (HCERTSTORE)hcs;
760 }
761
762 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv,
763  LPCSTR szSubSystemProtocol)
764 {
765     if (!szSubSystemProtocol)
766     {
767         SetLastError(E_INVALIDARG);
768         return 0;
769     }
770     return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
771      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
772 }
773
774 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv,
775  LPCWSTR szSubSystemProtocol)
776 {
777     if (!szSubSystemProtocol)
778     {
779         SetLastError(E_INVALIDARG);
780         return 0;
781     }
782     return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
783      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
784 }
785
786 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
787              DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
788 {
789     FIXME("(%p,%d,%d,%d,%p,%08x) stub!\n", hCertStore, 
790           dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
791     return TRUE;
792 }
793
794 #define CertContext_CopyProperties(to, from) \
795  Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT))
796
797 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
798  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
799  PCCERT_CONTEXT *ppStoreContext)
800 {
801     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
802     BOOL ret = TRUE;
803     PCCERT_CONTEXT toAdd = NULL, existing = NULL;
804
805     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext,
806      dwAddDisposition, ppStoreContext);
807
808     /* Weird case to pass a test */
809     if (dwAddDisposition == 0)
810     {
811         SetLastError(STATUS_ACCESS_VIOLATION);
812         return FALSE;
813     }
814     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
815     {
816         BYTE hashToAdd[20];
817         DWORD size = sizeof(hashToAdd);
818
819         ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
820          hashToAdd, &size);
821         if (ret)
822         {
823             CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
824
825             existing = CertFindCertificateInStore(hCertStore,
826              pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
827              NULL);
828         }
829     }
830
831     switch (dwAddDisposition)
832     {
833     case CERT_STORE_ADD_ALWAYS:
834         toAdd = CertDuplicateCertificateContext(pCertContext);
835         break;
836     case CERT_STORE_ADD_NEW:
837         if (existing)
838         {
839             TRACE("found matching certificate, not adding\n");
840             SetLastError(CRYPT_E_EXISTS);
841             ret = FALSE;
842         }
843         else
844             toAdd = CertDuplicateCertificateContext(pCertContext);
845         break;
846     case CERT_STORE_ADD_REPLACE_EXISTING:
847         toAdd = CertDuplicateCertificateContext(pCertContext);
848         break;
849     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
850         toAdd = CertDuplicateCertificateContext(pCertContext);
851         if (existing)
852             CertContext_CopyProperties(toAdd, existing);
853         break;
854     case CERT_STORE_ADD_USE_EXISTING:
855         if (existing)
856         {
857             CertContext_CopyProperties(existing, pCertContext);
858             *ppStoreContext = CertDuplicateCertificateContext(existing);
859         }
860         else
861             toAdd = CertDuplicateCertificateContext(pCertContext);
862         break;
863     default:
864         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
865         ret = FALSE;
866     }
867
868     if (toAdd)
869     {
870         if (store)
871             ret = store->certs.addContext(store, (void *)toAdd,
872              (void *)existing, (const void **)ppStoreContext);
873         else if (ppStoreContext)
874             *ppStoreContext = CertDuplicateCertificateContext(toAdd);
875         CertFreeCertificateContext(toAdd);
876     }
877     CertFreeCertificateContext(existing);
878
879     TRACE("returning %d\n", ret);
880     return ret;
881 }
882
883 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
884  PCCERT_CONTEXT pPrev)
885 {
886     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
887     PCCERT_CONTEXT ret;
888
889     TRACE("(%p, %p)\n", hCertStore, pPrev);
890     if (!hCertStore)
891         ret = NULL;
892     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
893         ret = NULL;
894     else
895         ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
896     return ret;
897 }
898
899 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
900 {
901     BOOL ret;
902
903     TRACE("(%p)\n", pCertContext);
904
905     if (!pCertContext)
906         ret = TRUE;
907     else if (!pCertContext->hCertStore)
908     {
909         ret = TRUE;
910         CertFreeCertificateContext(pCertContext);
911     }
912     else
913     {
914         PWINECRYPT_CERTSTORE hcs =
915          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
916
917         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
918             ret = FALSE;
919         else
920             ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
921         CertFreeCertificateContext(pCertContext);
922     }
923     return ret;
924 }
925
926 #define CrlContext_CopyProperties(to, from) \
927  Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
928
929 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
930  PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
931  PCCRL_CONTEXT* ppStoreContext)
932 {
933     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
934     BOOL ret = TRUE;
935     PCCRL_CONTEXT toAdd = NULL, existing = NULL;
936
937     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCrlContext,
938      dwAddDisposition, ppStoreContext);
939
940     /* Weird case to pass a test */
941     if (dwAddDisposition == 0)
942     {
943         SetLastError(STATUS_ACCESS_VIOLATION);
944         return FALSE;
945     }
946     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
947     {
948         existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
949          pCrlContext, NULL);
950     }
951
952     switch (dwAddDisposition)
953     {
954     case CERT_STORE_ADD_ALWAYS:
955         toAdd = CertDuplicateCRLContext(pCrlContext);
956         break;
957     case CERT_STORE_ADD_NEW:
958         if (existing)
959         {
960             TRACE("found matching CRL, not adding\n");
961             SetLastError(CRYPT_E_EXISTS);
962             ret = FALSE;
963         }
964         else
965             toAdd = CertDuplicateCRLContext(pCrlContext);
966         break;
967     case CERT_STORE_ADD_NEWER:
968         if (existing)
969         {
970             LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
971              &pCrlContext->pCrlInfo->ThisUpdate);
972
973             if (newer < 0)
974                 toAdd = CertDuplicateCRLContext(pCrlContext);
975             else
976             {
977                 TRACE("existing CRL is newer, not adding\n");
978                 SetLastError(CRYPT_E_EXISTS);
979                 ret = FALSE;
980             }
981         }
982         else
983             toAdd = CertDuplicateCRLContext(pCrlContext);
984         break;
985     case CERT_STORE_ADD_REPLACE_EXISTING:
986         toAdd = CertDuplicateCRLContext(pCrlContext);
987         break;
988     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
989         toAdd = CertDuplicateCRLContext(pCrlContext);
990         if (existing)
991             CrlContext_CopyProperties(toAdd, existing);
992         break;
993     case CERT_STORE_ADD_USE_EXISTING:
994         if (existing)
995             CrlContext_CopyProperties(existing, pCrlContext);
996         break;
997     default:
998         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
999         ret = FALSE;
1000     }
1001
1002     if (toAdd)
1003     {
1004         if (store)
1005             ret = store->crls.addContext(store, (void *)toAdd,
1006              (void *)existing, (const void **)ppStoreContext);
1007         else if (ppStoreContext)
1008             *ppStoreContext = CertDuplicateCRLContext(toAdd);
1009         CertFreeCRLContext(toAdd);
1010     }
1011     CertFreeCRLContext(existing);
1012
1013     TRACE("returning %d\n", ret);
1014     return ret;
1015 }
1016
1017 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
1018 {
1019     BOOL ret;
1020
1021     TRACE("(%p)\n", pCrlContext);
1022
1023     if (!pCrlContext)
1024         ret = TRUE;
1025     else if (!pCrlContext->hCertStore)
1026     {
1027         ret = TRUE;
1028         CertFreeCRLContext(pCrlContext);
1029     }
1030     else
1031     {
1032         PWINECRYPT_CERTSTORE hcs =
1033          (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore;
1034
1035         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1036             ret = FALSE;
1037         else
1038             ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
1039         CertFreeCRLContext(pCrlContext);
1040     }
1041     return ret;
1042 }
1043
1044 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
1045  PCCRL_CONTEXT pPrev)
1046 {
1047     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1048     PCCRL_CONTEXT ret;
1049
1050     TRACE("(%p, %p)\n", hCertStore, pPrev);
1051     if (!hCertStore)
1052         ret = NULL;
1053     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1054         ret = NULL;
1055     else
1056         ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
1057     return ret;
1058 }
1059
1060 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
1061   const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
1062 {
1063     FIXME("(%08x, %p, %08x): stub\n", dwCertEncodingType, pbCtlEncoded,
1064      cbCtlEncoded);
1065     return NULL;
1066 }
1067
1068 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
1069  DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
1070  DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
1071 {
1072     FIXME("(%p, %08x, %p, %d, %08x, %p): stub\n", hCertStore,
1073      dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
1074      ppCtlContext);
1075     return FALSE;
1076 }
1077
1078 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
1079  PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
1080  PCCTL_CONTEXT* ppStoreContext)
1081 {
1082     FIXME("(%p, %p, %08x, %p): stub\n", hCertStore, pCtlContext,
1083      dwAddDisposition, ppStoreContext);
1084     return TRUE;
1085 }
1086
1087 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
1088 {
1089     FIXME("(%p): stub\n", pCtlContext );
1090     return pCtlContext;
1091 }
1092
1093 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
1094 {
1095     FIXME("(%p): stub\n", pCtlContext );
1096     return TRUE;
1097 }
1098
1099 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
1100 {
1101     FIXME("(%p): stub\n", pCtlContext);
1102     return TRUE;
1103 }
1104
1105 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
1106  PCCTL_CONTEXT pPrev)
1107 {
1108     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
1109     return NULL;
1110 }
1111
1112 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
1113 {
1114     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1115
1116     TRACE("(%p)\n", hCertStore);
1117
1118     if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
1119         InterlockedIncrement(&hcs->ref);
1120     return hCertStore;
1121 }
1122
1123 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1124 {
1125     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
1126
1127     TRACE("(%p, %08x)\n", hCertStore, dwFlags);
1128
1129     if( ! hCertStore )
1130         return TRUE;
1131
1132     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
1133         return FALSE;
1134
1135     if (InterlockedDecrement(&hcs->ref) == 0)
1136     {
1137         TRACE("%p's ref count is 0, freeing\n", hcs);
1138         hcs->dwMagic = 0;
1139         hcs->closeStore(hcs, dwFlags);
1140     }
1141     else
1142         TRACE("%p's ref count is %d\n", hcs, hcs->ref);
1143     return TRUE;
1144 }
1145
1146 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
1147  DWORD dwCtrlType, void const *pvCtrlPara)
1148 {
1149     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1150     BOOL ret;
1151
1152     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
1153      pvCtrlPara);
1154
1155     if (!hcs)
1156         ret = FALSE;
1157     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1158         ret = FALSE;
1159     else
1160     {
1161         if (hcs->control)
1162             ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
1163         else
1164             ret = TRUE;
1165     }
1166     return ret;
1167 }
1168
1169 BOOL WINAPI CertGetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1170  void *pvData, DWORD *pcbData)
1171 {
1172     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1173     BOOL ret = FALSE;
1174
1175     TRACE("(%p, %d, %p, %p)\n", hCertStore, dwPropId, pvData, pcbData);
1176
1177     switch (dwPropId)
1178     {
1179     case CERT_ACCESS_STATE_PROP_ID:
1180         if (!pvData)
1181         {
1182             *pcbData = sizeof(DWORD);
1183             ret = TRUE;
1184         }
1185         else if (*pcbData < sizeof(DWORD))
1186         {
1187             SetLastError(ERROR_MORE_DATA);
1188             *pcbData = sizeof(DWORD);
1189         }
1190         else
1191         {
1192             DWORD state = 0;
1193
1194             if (store->type != StoreTypeMem &&
1195              !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1196                 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1197             *(DWORD *)pvData = state;
1198             ret = TRUE;
1199         }
1200         break;
1201     default:
1202         if (store->properties)
1203         {
1204             CRYPT_DATA_BLOB blob;
1205
1206             ret = ContextPropertyList_FindProperty(store->properties, dwPropId,
1207              &blob);
1208             if (ret)
1209             {
1210                 if (!pvData)
1211                     *pcbData = blob.cbData;
1212                 else if (*pcbData < blob.cbData)
1213                 {
1214                     SetLastError(ERROR_MORE_DATA);
1215                     *pcbData = blob.cbData;
1216                     ret = FALSE;
1217                 }
1218                 else
1219                 {
1220                     memcpy(pvData, blob.pbData, blob.cbData);
1221                     *pcbData = blob.cbData;
1222                 }
1223             }
1224             else
1225                 SetLastError(CRYPT_E_NOT_FOUND);
1226         }
1227         else
1228             SetLastError(CRYPT_E_NOT_FOUND);
1229     }
1230     return ret;
1231 }
1232
1233 BOOL WINAPI CertSetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1234  DWORD dwFlags, const void *pvData)
1235 {
1236     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1237     BOOL ret = FALSE;
1238
1239     TRACE("(%p, %d, %08x, %p)\n", hCertStore, dwPropId, dwFlags, pvData);
1240
1241     if (!store->properties)
1242         store->properties = ContextPropertyList_Create();
1243     switch (dwPropId)
1244     {
1245     case CERT_ACCESS_STATE_PROP_ID:
1246         SetLastError(E_INVALIDARG);
1247         break;
1248     default:
1249         if (pvData)
1250         {
1251             const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvData;
1252
1253             ret = ContextPropertyList_SetProperty(store->properties, dwPropId,
1254              blob->pbData, blob->cbData);
1255         }
1256         else
1257         {
1258             ContextPropertyList_RemoveProperty(store->properties, dwPropId);
1259             ret = TRUE;
1260         }
1261     }
1262     return ret;
1263 }
1264
1265 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
1266  DWORD dwPropId)
1267 {
1268     FIXME("(%p, %d): stub\n", pCTLContext, dwPropId);
1269     return 0;
1270 }
1271
1272 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1273  DWORD dwPropId, void *pvData, DWORD *pcbData)
1274 {
1275     FIXME("(%p, %d, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
1276     return FALSE;
1277 }
1278
1279 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1280  DWORD dwPropId, DWORD dwFlags, const void *pvData)
1281 {
1282     FIXME("(%p, %d, %08x, %p): stub\n", pCTLContext, dwPropId, dwFlags,
1283      pvData);
1284     return FALSE;
1285 }
1286
1287 static LONG CRYPT_OpenParentStore(DWORD dwFlags,
1288     void *pvSystemStoreLocationPara, HKEY *key)
1289 {
1290     HKEY root;
1291     LPCWSTR base;
1292
1293     TRACE("(%08x, %p)\n", dwFlags, pvSystemStoreLocationPara);
1294
1295     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1296     {
1297     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1298         root = HKEY_LOCAL_MACHINE;
1299         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1300         break;
1301     case CERT_SYSTEM_STORE_CURRENT_USER:
1302         root = HKEY_CURRENT_USER;
1303         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1304         break;
1305     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1306         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1307          * SystemCertificates
1308          */
1309         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE\n");
1310         return ERROR_FILE_NOT_FOUND;
1311     case CERT_SYSTEM_STORE_SERVICES:
1312         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1313          * SystemCertificates
1314          */
1315         FIXME("CERT_SYSTEM_STORE_SERVICES\n");
1316         return ERROR_FILE_NOT_FOUND;
1317     case CERT_SYSTEM_STORE_USERS:
1318         /* hku\user sid\Software\Microsoft\SystemCertificates */
1319         FIXME("CERT_SYSTEM_STORE_USERS\n");
1320         return ERROR_FILE_NOT_FOUND;
1321     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1322         root = HKEY_CURRENT_USER;
1323         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1324         break;
1325     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1326         root = HKEY_LOCAL_MACHINE;
1327         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1328         break;
1329     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1330         /* hklm\Software\Microsoft\EnterpriseCertificates */
1331         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE\n");
1332         return ERROR_FILE_NOT_FOUND;
1333     default:
1334         return ERROR_FILE_NOT_FOUND;
1335     }
1336
1337     return RegOpenKeyExW(root, base, 0, KEY_READ, key);
1338 }
1339
1340 BOOL WINAPI CertEnumSystemStore(DWORD dwFlags, void *pvSystemStoreLocationPara,
1341     void *pvArg, PFN_CERT_ENUM_SYSTEM_STORE pfnEnum)
1342 {
1343     BOOL ret = FALSE;
1344     LONG rc;
1345     HKEY key;
1346
1347     TRACE("(%08x, %p, %p, %p)\n", dwFlags, pvSystemStoreLocationPara, pvArg,
1348         pfnEnum);
1349
1350     rc = CRYPT_OpenParentStore(dwFlags, pvArg, &key);
1351     if (!rc)
1352     {
1353         DWORD index = 0;
1354         CERT_SYSTEM_STORE_INFO info = { sizeof(info) };
1355
1356         ret = TRUE;
1357         do {
1358             WCHAR name[MAX_PATH];
1359             DWORD size = sizeof(name) / sizeof(name[0]);
1360
1361             rc = RegEnumKeyExW(key, index++, name, &size, NULL, NULL, NULL,
1362                 NULL);
1363             if (!rc)
1364                 ret = pfnEnum(name, 0, &info, NULL, pvArg);
1365         } while (ret && !rc);
1366         if (ret && rc != ERROR_NO_MORE_ITEMS)
1367             SetLastError(rc);
1368     }
1369     else
1370         SetLastError(rc);
1371     return ret;
1372 }