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