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