wined3d: Create a VBO before returning memory.
[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 = 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     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
786     {
787         BYTE hashToAdd[20];
788         DWORD size = sizeof(hashToAdd);
789
790         ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
791          hashToAdd, &size);
792         if (ret)
793         {
794             CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
795
796             existing = CertFindCertificateInStore(hCertStore,
797              pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
798              NULL);
799         }
800     }
801
802     switch (dwAddDisposition)
803     {
804     case CERT_STORE_ADD_ALWAYS:
805         toAdd = CertDuplicateCertificateContext(pCertContext);
806         break;
807     case CERT_STORE_ADD_NEW:
808         if (existing)
809         {
810             TRACE("found matching certificate, not adding\n");
811             SetLastError(CRYPT_E_EXISTS);
812             ret = FALSE;
813         }
814         else
815             toAdd = CertDuplicateCertificateContext(pCertContext);
816         break;
817     case CERT_STORE_ADD_REPLACE_EXISTING:
818         toAdd = CertDuplicateCertificateContext(pCertContext);
819         break;
820     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
821         toAdd = CertDuplicateCertificateContext(pCertContext);
822         if (existing)
823             CertContext_CopyProperties(toAdd, existing);
824         break;
825     case CERT_STORE_ADD_USE_EXISTING:
826         if (existing)
827         {
828             CertContext_CopyProperties(existing, pCertContext);
829             *ppStoreContext = CertDuplicateCertificateContext(existing);
830         }
831         else
832             toAdd = CertDuplicateCertificateContext(pCertContext);
833         break;
834     case CERT_STORE_ADD_NEWER:
835         if (existing)
836         {
837             if (CompareFileTime(&existing->pCertInfo->NotBefore,
838              &pCertContext->pCertInfo->NotBefore) >= 0)
839             {
840                 TRACE("existing certificate is newer, not adding\n");
841                 SetLastError(CRYPT_E_EXISTS);
842                 ret = FALSE;
843             }
844             else
845                 toAdd = CertDuplicateCertificateContext(pCertContext);
846         }
847         else
848             toAdd = CertDuplicateCertificateContext(pCertContext);
849         break;
850     default:
851         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
852         SetLastError(E_INVALIDARG);
853         ret = FALSE;
854     }
855
856     if (toAdd)
857     {
858         if (store)
859             ret = store->certs.addContext(store, (void *)toAdd,
860              (void *)existing, (const void **)ppStoreContext);
861         else if (ppStoreContext)
862             *ppStoreContext = CertDuplicateCertificateContext(toAdd);
863         CertFreeCertificateContext(toAdd);
864     }
865     CertFreeCertificateContext(existing);
866
867     TRACE("returning %d\n", ret);
868     return ret;
869 }
870
871 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
872  PCCERT_CONTEXT pPrev)
873 {
874     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
875     PCCERT_CONTEXT ret;
876
877     TRACE("(%p, %p)\n", hCertStore, pPrev);
878     if (!hCertStore)
879         ret = NULL;
880     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
881         ret = NULL;
882     else
883         ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
884     return ret;
885 }
886
887 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
888 {
889     BOOL ret;
890
891     TRACE("(%p)\n", pCertContext);
892
893     if (!pCertContext)
894         ret = TRUE;
895     else if (!pCertContext->hCertStore)
896     {
897         ret = TRUE;
898         CertFreeCertificateContext(pCertContext);
899     }
900     else
901     {
902         PWINECRYPT_CERTSTORE hcs =
903          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
904
905         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
906             ret = FALSE;
907         else
908             ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
909         CertFreeCertificateContext(pCertContext);
910     }
911     return ret;
912 }
913
914 #define CrlContext_CopyProperties(to, from) \
915  Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
916
917 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
918  PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
919  PCCRL_CONTEXT* ppStoreContext)
920 {
921     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
922     BOOL ret = TRUE;
923     PCCRL_CONTEXT toAdd = NULL, existing = NULL;
924
925     TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCrlContext,
926      dwAddDisposition, ppStoreContext);
927
928     /* Weird case to pass a test */
929     if (dwAddDisposition == 0)
930     {
931         SetLastError(STATUS_ACCESS_VIOLATION);
932         return FALSE;
933     }
934     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
935     {
936         existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
937          pCrlContext, NULL);
938     }
939
940     switch (dwAddDisposition)
941     {
942     case CERT_STORE_ADD_ALWAYS:
943         toAdd = CertDuplicateCRLContext(pCrlContext);
944         break;
945     case CERT_STORE_ADD_NEW:
946         if (existing)
947         {
948             TRACE("found matching CRL, not adding\n");
949             SetLastError(CRYPT_E_EXISTS);
950             ret = FALSE;
951         }
952         else
953             toAdd = CertDuplicateCRLContext(pCrlContext);
954         break;
955     case CERT_STORE_ADD_NEWER:
956         if (existing)
957         {
958             LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
959              &pCrlContext->pCrlInfo->ThisUpdate);
960
961             if (newer < 0)
962                 toAdd = CertDuplicateCRLContext(pCrlContext);
963             else
964             {
965                 TRACE("existing CRL is newer, not adding\n");
966                 SetLastError(CRYPT_E_EXISTS);
967                 ret = FALSE;
968             }
969         }
970         else
971             toAdd = CertDuplicateCRLContext(pCrlContext);
972         break;
973     case CERT_STORE_ADD_REPLACE_EXISTING:
974         toAdd = CertDuplicateCRLContext(pCrlContext);
975         break;
976     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
977         toAdd = CertDuplicateCRLContext(pCrlContext);
978         if (existing)
979             CrlContext_CopyProperties(toAdd, existing);
980         break;
981     case CERT_STORE_ADD_USE_EXISTING:
982         if (existing)
983             CrlContext_CopyProperties(existing, pCrlContext);
984         break;
985     default:
986         FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
987         ret = FALSE;
988     }
989
990     if (toAdd)
991     {
992         if (store)
993             ret = store->crls.addContext(store, (void *)toAdd,
994              (void *)existing, (const void **)ppStoreContext);
995         else if (ppStoreContext)
996             *ppStoreContext = CertDuplicateCRLContext(toAdd);
997         CertFreeCRLContext(toAdd);
998     }
999     CertFreeCRLContext(existing);
1000
1001     TRACE("returning %d\n", ret);
1002     return ret;
1003 }
1004
1005 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
1006 {
1007     BOOL ret;
1008
1009     TRACE("(%p)\n", pCrlContext);
1010
1011     if (!pCrlContext)
1012         ret = TRUE;
1013     else if (!pCrlContext->hCertStore)
1014     {
1015         ret = TRUE;
1016         CertFreeCRLContext(pCrlContext);
1017     }
1018     else
1019     {
1020         PWINECRYPT_CERTSTORE hcs =
1021          (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore;
1022
1023         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1024             ret = FALSE;
1025         else
1026             ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
1027         CertFreeCRLContext(pCrlContext);
1028     }
1029     return ret;
1030 }
1031
1032 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
1033  PCCRL_CONTEXT pPrev)
1034 {
1035     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1036     PCCRL_CONTEXT ret;
1037
1038     TRACE("(%p, %p)\n", hCertStore, pPrev);
1039     if (!hCertStore)
1040         ret = NULL;
1041     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1042         ret = NULL;
1043     else
1044         ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
1045     return ret;
1046 }
1047
1048 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
1049   const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
1050 {
1051     FIXME("(%08x, %p, %08x): stub\n", dwCertEncodingType, pbCtlEncoded,
1052      cbCtlEncoded);
1053     return NULL;
1054 }
1055
1056 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
1057  DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
1058  DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
1059 {
1060     FIXME("(%p, %08x, %p, %d, %08x, %p): stub\n", hCertStore,
1061      dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
1062      ppCtlContext);
1063     return FALSE;
1064 }
1065
1066 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
1067  PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
1068  PCCTL_CONTEXT* ppStoreContext)
1069 {
1070     FIXME("(%p, %p, %08x, %p): stub\n", hCertStore, pCtlContext,
1071      dwAddDisposition, ppStoreContext);
1072     return TRUE;
1073 }
1074
1075 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
1076 {
1077     FIXME("(%p): stub\n", pCtlContext );
1078     return pCtlContext;
1079 }
1080
1081 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
1082 {
1083     FIXME("(%p): stub\n", pCtlContext );
1084     return TRUE;
1085 }
1086
1087 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
1088 {
1089     FIXME("(%p): stub\n", pCtlContext);
1090     return TRUE;
1091 }
1092
1093 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
1094  PCCTL_CONTEXT pPrev)
1095 {
1096     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
1097     return NULL;
1098 }
1099
1100 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
1101 {
1102     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1103
1104     TRACE("(%p)\n", hCertStore);
1105
1106     if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
1107         InterlockedIncrement(&hcs->ref);
1108     return hCertStore;
1109 }
1110
1111 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1112 {
1113     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
1114
1115     TRACE("(%p, %08x)\n", hCertStore, dwFlags);
1116
1117     if( ! hCertStore )
1118         return TRUE;
1119
1120     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
1121         return FALSE;
1122
1123     if (InterlockedDecrement(&hcs->ref) == 0)
1124     {
1125         TRACE("%p's ref count is 0, freeing\n", hcs);
1126         hcs->dwMagic = 0;
1127         hcs->closeStore(hcs, dwFlags);
1128     }
1129     else
1130         TRACE("%p's ref count is %d\n", hcs, hcs->ref);
1131     return TRUE;
1132 }
1133
1134 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
1135  DWORD dwCtrlType, void const *pvCtrlPara)
1136 {
1137     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1138     BOOL ret;
1139
1140     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
1141      pvCtrlPara);
1142
1143     if (!hcs)
1144         ret = FALSE;
1145     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1146         ret = FALSE;
1147     else
1148     {
1149         if (hcs->control)
1150             ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
1151         else
1152             ret = TRUE;
1153     }
1154     return ret;
1155 }
1156
1157 BOOL WINAPI CertGetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1158  void *pvData, DWORD *pcbData)
1159 {
1160     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1161     BOOL ret = FALSE;
1162
1163     TRACE("(%p, %d, %p, %p)\n", hCertStore, dwPropId, pvData, pcbData);
1164
1165     switch (dwPropId)
1166     {
1167     case CERT_ACCESS_STATE_PROP_ID:
1168         if (!pvData)
1169         {
1170             *pcbData = sizeof(DWORD);
1171             ret = TRUE;
1172         }
1173         else if (*pcbData < sizeof(DWORD))
1174         {
1175             SetLastError(ERROR_MORE_DATA);
1176             *pcbData = sizeof(DWORD);
1177         }
1178         else
1179         {
1180             DWORD state = 0;
1181
1182             if (store->type != StoreTypeMem &&
1183              !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1184                 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1185             *(DWORD *)pvData = state;
1186             ret = TRUE;
1187         }
1188         break;
1189     default:
1190         if (store->properties)
1191         {
1192             CRYPT_DATA_BLOB blob;
1193
1194             ret = ContextPropertyList_FindProperty(store->properties, dwPropId,
1195              &blob);
1196             if (ret)
1197             {
1198                 if (!pvData)
1199                     *pcbData = blob.cbData;
1200                 else if (*pcbData < blob.cbData)
1201                 {
1202                     SetLastError(ERROR_MORE_DATA);
1203                     *pcbData = blob.cbData;
1204                     ret = FALSE;
1205                 }
1206                 else
1207                 {
1208                     memcpy(pvData, blob.pbData, blob.cbData);
1209                     *pcbData = blob.cbData;
1210                 }
1211             }
1212             else
1213                 SetLastError(CRYPT_E_NOT_FOUND);
1214         }
1215         else
1216             SetLastError(CRYPT_E_NOT_FOUND);
1217     }
1218     return ret;
1219 }
1220
1221 BOOL WINAPI CertSetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1222  DWORD dwFlags, const void *pvData)
1223 {
1224     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1225     BOOL ret = FALSE;
1226
1227     TRACE("(%p, %d, %08x, %p)\n", hCertStore, dwPropId, dwFlags, pvData);
1228
1229     if (!store->properties)
1230         store->properties = ContextPropertyList_Create();
1231     switch (dwPropId)
1232     {
1233     case CERT_ACCESS_STATE_PROP_ID:
1234         SetLastError(E_INVALIDARG);
1235         break;
1236     default:
1237         if (pvData)
1238         {
1239             const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvData;
1240
1241             ret = ContextPropertyList_SetProperty(store->properties, dwPropId,
1242              blob->pbData, blob->cbData);
1243         }
1244         else
1245         {
1246             ContextPropertyList_RemoveProperty(store->properties, dwPropId);
1247             ret = TRUE;
1248         }
1249     }
1250     return ret;
1251 }
1252
1253 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
1254  DWORD dwPropId)
1255 {
1256     FIXME("(%p, %d): stub\n", pCTLContext, dwPropId);
1257     return 0;
1258 }
1259
1260 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1261  DWORD dwPropId, void *pvData, DWORD *pcbData)
1262 {
1263     FIXME("(%p, %d, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
1264     return FALSE;
1265 }
1266
1267 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1268  DWORD dwPropId, DWORD dwFlags, const void *pvData)
1269 {
1270     FIXME("(%p, %d, %08x, %p): stub\n", pCTLContext, dwPropId, dwFlags,
1271      pvData);
1272     return FALSE;
1273 }
1274
1275 static LONG CRYPT_OpenParentStore(DWORD dwFlags,
1276     void *pvSystemStoreLocationPara, HKEY *key)
1277 {
1278     HKEY root;
1279     LPCWSTR base;
1280
1281     TRACE("(%08x, %p)\n", dwFlags, pvSystemStoreLocationPara);
1282
1283     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1284     {
1285     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1286         root = HKEY_LOCAL_MACHINE;
1287         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1288         break;
1289     case CERT_SYSTEM_STORE_CURRENT_USER:
1290         root = HKEY_CURRENT_USER;
1291         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1292         break;
1293     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1294         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1295          * SystemCertificates
1296          */
1297         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE\n");
1298         return ERROR_FILE_NOT_FOUND;
1299     case CERT_SYSTEM_STORE_SERVICES:
1300         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1301          * SystemCertificates
1302          */
1303         FIXME("CERT_SYSTEM_STORE_SERVICES\n");
1304         return ERROR_FILE_NOT_FOUND;
1305     case CERT_SYSTEM_STORE_USERS:
1306         /* hku\user sid\Software\Microsoft\SystemCertificates */
1307         FIXME("CERT_SYSTEM_STORE_USERS\n");
1308         return ERROR_FILE_NOT_FOUND;
1309     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1310         root = HKEY_CURRENT_USER;
1311         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1312         break;
1313     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1314         root = HKEY_LOCAL_MACHINE;
1315         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1316         break;
1317     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1318         /* hklm\Software\Microsoft\EnterpriseCertificates */
1319         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE\n");
1320         return ERROR_FILE_NOT_FOUND;
1321     default:
1322         return ERROR_FILE_NOT_FOUND;
1323     }
1324
1325     return RegOpenKeyExW(root, base, 0, KEY_READ, key);
1326 }
1327
1328 BOOL WINAPI CertEnumSystemStore(DWORD dwFlags, void *pvSystemStoreLocationPara,
1329     void *pvArg, PFN_CERT_ENUM_SYSTEM_STORE pfnEnum)
1330 {
1331     BOOL ret = FALSE;
1332     LONG rc;
1333     HKEY key;
1334
1335     TRACE("(%08x, %p, %p, %p)\n", dwFlags, pvSystemStoreLocationPara, pvArg,
1336         pfnEnum);
1337
1338     rc = CRYPT_OpenParentStore(dwFlags, pvArg, &key);
1339     if (!rc)
1340     {
1341         DWORD index = 0;
1342         CERT_SYSTEM_STORE_INFO info = { sizeof(info) };
1343
1344         ret = TRUE;
1345         do {
1346             WCHAR name[MAX_PATH];
1347             DWORD size = sizeof(name) / sizeof(name[0]);
1348
1349             rc = RegEnumKeyExW(key, index++, name, &size, NULL, NULL, NULL,
1350                 NULL);
1351             if (!rc)
1352                 ret = pfnEnum(name, 0, &info, NULL, pvArg);
1353         } while (ret && !rc);
1354         if (ret && rc != ERROR_NO_MORE_ITEMS)
1355             SetLastError(rc);
1356     }
1357     else
1358         SetLastError(rc);
1359     return ret;
1360 }