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