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