2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2004-2006 Juan Lang
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.
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.
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
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.
27 #include "wine/port.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "wine/exception.h"
40 #include "crypt32_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
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,
57 PCWINE_CONTEXT_INTERFACE pCertInterface = &gCertInterface;
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,
72 PCWINE_CONTEXT_INTERFACE pCRLInterface = &gCRLInterface;
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,
87 PCWINE_CONTEXT_INTERFACE pCTLInterface = &gCTLInterface;
89 typedef struct _WINE_MEMSTORE
91 WINECRYPT_CERTSTORE hdr;
92 struct ContextList *certs;
93 struct ContextList *crls;
94 struct ContextList *ctls;
95 } WINE_MEMSTORE, *PWINE_MEMSTORE;
97 void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, DWORD dwFlags,
101 store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
103 store->dwOpenFlags = dwFlags;
104 store->properties = NULL;
107 void CRYPT_FreeStore(PWINECRYPT_CERTSTORE store)
109 if (store->properties)
110 ContextPropertyList_Free(store->properties);
114 BOOL WINAPI I_CertUpdateStore(HCERTSTORE store1, HCERTSTORE store2, DWORD unk0,
117 static BOOL warned = FALSE;
118 const WINE_CONTEXT_INTERFACE * const interfaces[] = { pCertInterface,
119 pCRLInterface, pCTLInterface };
122 TRACE("(%p, %p, %08x, %08x)\n", store1, store2, unk0, unk1);
125 FIXME("semi-stub\n");
129 /* Poor-man's resync: empty first store, then add everything from second
132 for (i = 0; i < sizeof(interfaces) / sizeof(interfaces[0]); i++)
137 context = interfaces[i]->enumContextsInStore(store1, NULL);
139 interfaces[i]->deleteFromStore(context);
142 context = interfaces[i]->enumContextsInStore(store2, context);
144 interfaces[i]->addContextToStore(store1, context,
145 CERT_STORE_ADD_ALWAYS, NULL);
151 static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, void *cert,
152 void *toReplace, const void **ppStoreContext)
154 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
155 PCERT_CONTEXT context;
157 TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
159 context = ContextList_Add(ms->certs, cert, toReplace);
162 context->hCertStore = store;
164 *ppStoreContext = CertDuplicateCertificateContext(context);
166 return context ? TRUE : FALSE;
169 static void *CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
171 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
174 TRACE("(%p, %p)\n", store, pPrev);
176 ret = ContextList_Enum(ms->certs, pPrev);
178 SetLastError(CRYPT_E_NOT_FOUND);
180 TRACE("returning %p\n", ret);
184 static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext)
186 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
189 if (ContextList_Remove(ms->certs, pCertContext))
190 ret = CertFreeCertificateContext(pCertContext);
196 static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl,
197 void *toReplace, const void **ppStoreContext)
199 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
200 PCRL_CONTEXT context;
202 TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext);
204 context = ContextList_Add(ms->crls, crl, toReplace);
207 context->hCertStore = store;
209 *ppStoreContext = CertDuplicateCRLContext(context);
211 return context ? TRUE : FALSE;
214 static void *CRYPT_MemEnumCrl(PWINECRYPT_CERTSTORE store, void *pPrev)
216 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
219 TRACE("(%p, %p)\n", store, pPrev);
221 ret = ContextList_Enum(ms->crls, pPrev);
223 SetLastError(CRYPT_E_NOT_FOUND);
225 TRACE("returning %p\n", ret);
229 static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext)
231 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
234 if (ContextList_Remove(ms->crls, pCrlContext))
235 ret = CertFreeCRLContext(pCrlContext);
241 static BOOL CRYPT_MemAddCtl(PWINECRYPT_CERTSTORE store, void *ctl,
242 void *toReplace, const void **ppStoreContext)
244 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
245 PCTL_CONTEXT context;
247 TRACE("(%p, %p, %p, %p)\n", store, ctl, toReplace, ppStoreContext);
249 context = ContextList_Add(ms->ctls, ctl, toReplace);
252 context->hCertStore = store;
254 *ppStoreContext = CertDuplicateCTLContext(context);
256 return context ? TRUE : FALSE;
259 static void *CRYPT_MemEnumCtl(PWINECRYPT_CERTSTORE store, void *pPrev)
261 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
264 TRACE("(%p, %p)\n", store, pPrev);
266 ret = ContextList_Enum(ms->ctls, pPrev);
268 SetLastError(CRYPT_E_NOT_FOUND);
270 TRACE("returning %p\n", ret);
274 static BOOL CRYPT_MemDeleteCtl(PWINECRYPT_CERTSTORE store, void *pCtlContext)
276 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
279 if (ContextList_Remove(ms->ctls, pCtlContext))
280 ret = CertFreeCTLContext(pCtlContext);
286 static BOOL WINAPI CRYPT_MemControl(HCERTSTORE hCertStore, DWORD dwFlags,
287 DWORD dwCtrlType, void const *pvCtrlPara)
289 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
293 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
295 WINE_MEMSTORE *store = hCertStore;
297 TRACE("(%p, %08x)\n", store, dwFlags);
299 FIXME("Unimplemented flags: %08x\n", dwFlags);
301 ContextList_Free(store->certs);
302 ContextList_Free(store->crls);
303 ContextList_Free(store->ctls);
304 CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store);
307 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
308 DWORD dwFlags, const void *pvPara)
310 PWINE_MEMSTORE store;
312 TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
314 if (dwFlags & CERT_STORE_DELETE_FLAG)
316 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
321 store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
324 memset(store, 0, sizeof(WINE_MEMSTORE));
325 CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeMem);
326 store->hdr.closeStore = CRYPT_MemCloseStore;
327 store->hdr.certs.addContext = CRYPT_MemAddCert;
328 store->hdr.certs.enumContext = CRYPT_MemEnumCert;
329 store->hdr.certs.deleteContext = CRYPT_MemDeleteCert;
330 store->hdr.crls.addContext = CRYPT_MemAddCrl;
331 store->hdr.crls.enumContext = CRYPT_MemEnumCrl;
332 store->hdr.crls.deleteContext = CRYPT_MemDeleteCrl;
333 store->hdr.ctls.addContext = CRYPT_MemAddCtl;
334 store->hdr.ctls.enumContext = CRYPT_MemEnumCtl;
335 store->hdr.ctls.deleteContext = CRYPT_MemDeleteCtl;
336 store->hdr.control = CRYPT_MemControl;
337 store->certs = ContextList_Create(pCertInterface,
338 sizeof(CERT_CONTEXT));
339 store->crls = ContextList_Create(pCRLInterface,
340 sizeof(CRL_CONTEXT));
341 store->ctls = ContextList_Create(pCTLInterface,
342 sizeof(CTL_CONTEXT));
343 /* Mem store doesn't need crypto provider, so close it */
344 if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
345 CryptReleaseContext(hCryptProv, 0);
348 return (PWINECRYPT_CERTSTORE)store;
351 static const WCHAR rootW[] = { 'R','o','o','t',0 };
353 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
354 DWORD dwFlags, const void *pvPara)
356 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
357 LPCWSTR storeName = pvPara;
359 PWINECRYPT_CERTSTORE store = NULL;
363 TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
368 SetLastError(E_INVALIDARG);
371 /* FIXME: In Windows, the root store (even the current user location) is
372 * protected: adding to it or removing from it present a user interface,
373 * and the keys are owned by the system process, not the current user.
374 * Wine's registry doesn't implement access controls, so a similar
375 * mechanism isn't possible yet.
377 if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
378 CERT_SYSTEM_STORE_LOCAL_MACHINE && !lstrcmpiW(storeName, rootW))
379 return CRYPT_RootOpenStore(hCryptProv, dwFlags);
381 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
383 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
384 root = HKEY_LOCAL_MACHINE;
385 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
387 case CERT_SYSTEM_STORE_CURRENT_USER:
388 root = HKEY_CURRENT_USER;
389 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
391 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
392 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
395 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
396 debugstr_w(storeName));
398 case CERT_SYSTEM_STORE_SERVICES:
399 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
402 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
403 debugstr_w(storeName));
405 case CERT_SYSTEM_STORE_USERS:
406 /* hku\user sid\Software\Microsoft\SystemCertificates */
407 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
408 debugstr_w(storeName));
410 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
411 root = HKEY_CURRENT_USER;
412 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
414 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
415 root = HKEY_LOCAL_MACHINE;
416 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
418 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
419 /* hklm\Software\Microsoft\EnterpriseCertificates */
420 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
421 debugstr_w(storeName));
424 SetLastError(E_INVALIDARG);
428 storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
434 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
437 wsprintfW(storePath, fmt, base, storeName);
438 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
439 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
444 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
446 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
447 disp == REG_OPENED_EXISTING_KEY)
450 rc = ERROR_FILE_EXISTS;
455 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
460 CryptMemFree(storePath);
465 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
466 DWORD dwFlags, const void *pvPara)
469 PWINECRYPT_CERTSTORE ret = NULL;
471 TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
476 SetLastError(ERROR_FILE_NOT_FOUND);
479 len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
482 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
486 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, storeName, len);
487 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
488 CryptMemFree(storeName);
494 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
495 DWORD dwFlags, const void *pvPara)
497 HCERTSTORE store = 0;
500 TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
505 SetLastError(ERROR_FILE_NOT_FOUND);
508 /* This returns a different error than system registry stores if the
509 * location is invalid.
511 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
513 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
514 case CERT_SYSTEM_STORE_CURRENT_USER:
515 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
516 case CERT_SYSTEM_STORE_SERVICES:
517 case CERT_SYSTEM_STORE_USERS:
518 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
519 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
520 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
524 SetLastError(ERROR_FILE_NOT_FOUND);
529 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
530 0, 0, dwFlags, pvPara);
534 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
535 CERT_STORE_CREATE_NEW_FLAG, NULL);
536 CertAddStoreToCollection(store, regStore,
537 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
538 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
539 CertCloseStore(regStore, 0);
540 /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
543 if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
544 CERT_SYSTEM_STORE_CURRENT_USER)
546 dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
547 dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
548 regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0,
552 CertAddStoreToCollection(store, regStore,
553 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
554 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
555 CertCloseStore(regStore, 0);
558 /* System store doesn't need crypto provider, so close it */
559 if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
560 CryptReleaseContext(hCryptProv, 0);
566 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
567 DWORD dwFlags, const void *pvPara)
570 PWINECRYPT_CERTSTORE ret = NULL;
572 TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
577 SetLastError(ERROR_FILE_NOT_FOUND);
580 len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
583 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
587 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, storeName, len);
588 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
589 CryptMemFree(storeName);
595 static void WINAPI CRYPT_MsgCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
597 HCRYPTMSG msg = hCertStore;
599 TRACE("(%p, %08x)\n", msg, dwFlags);
603 static void *msgProvFuncs[] = {
607 static PWINECRYPT_CERTSTORE CRYPT_MsgOpenStore(HCRYPTPROV hCryptProv,
608 DWORD dwFlags, const void *pvPara)
610 PWINECRYPT_CERTSTORE store = NULL;
611 HCRYPTMSG msg = (HCRYPTMSG)pvPara;
612 PWINECRYPT_CERTSTORE memStore;
614 TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
616 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
617 CERT_STORE_CREATE_NEW_FLAG, NULL);
621 DWORD size, count, i;
623 size = sizeof(count);
624 ret = CryptMsgGetParam(msg, CMSG_CERT_COUNT_PARAM, 0, &count, &size);
625 for (i = 0; ret && i < count; i++)
628 ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, NULL, &size);
631 LPBYTE buf = CryptMemAlloc(size);
635 ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, buf, &size);
637 ret = CertAddEncodedCertificateToStore(memStore,
638 X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS,
644 size = sizeof(count);
645 ret = CryptMsgGetParam(msg, CMSG_CRL_COUNT_PARAM, 0, &count, &size);
646 for (i = 0; ret && i < count; i++)
649 ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, NULL, &size);
652 LPBYTE buf = CryptMemAlloc(size);
656 ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, buf, &size);
658 ret = CertAddEncodedCRLToStore(memStore,
659 X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS,
667 CERT_STORE_PROV_INFO provInfo = { 0 };
669 provInfo.cbSize = sizeof(provInfo);
670 provInfo.cStoreProvFunc = sizeof(msgProvFuncs) /
671 sizeof(msgProvFuncs[0]);
672 provInfo.rgpvStoreProvFunc = msgProvFuncs;
673 provInfo.hStoreProv = CryptMsgDuplicate(msg);
674 store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo);
675 /* Msg store doesn't need crypto provider, so close it */
676 if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
677 CryptReleaseContext(hCryptProv, 0);
680 CertCloseStore(memStore, 0);
682 TRACE("returning %p\n", store);
686 static PWINECRYPT_CERTSTORE CRYPT_PKCSOpenStore(HCRYPTPROV hCryptProv,
687 DWORD dwFlags, const void *pvPara)
690 PWINECRYPT_CERTSTORE store = NULL;
691 const CRYPT_DATA_BLOB *data = pvPara;
693 DWORD msgOpenFlags = dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG ? 0 :
694 CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
696 TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
698 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, CMSG_SIGNED,
699 hCryptProv, NULL, NULL);
700 ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE);
704 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, 0,
705 hCryptProv, NULL, NULL);
706 ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE);
709 DWORD type, size = sizeof(type);
711 /* Only signed messages are allowed, check type */
712 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &size);
713 if (ret && type != CMSG_SIGNED)
715 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
721 store = CRYPT_MsgOpenStore(0, dwFlags, msg);
723 TRACE("returning %p\n", store);
727 static PWINECRYPT_CERTSTORE CRYPT_SerializedOpenStore(HCRYPTPROV hCryptProv,
728 DWORD dwFlags, const void *pvPara)
731 const CRYPT_DATA_BLOB *data = pvPara;
733 TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
735 if (dwFlags & CERT_STORE_DELETE_FLAG)
737 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
741 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
742 CERT_STORE_CREATE_NEW_FLAG, NULL);
745 if (!CRYPT_ReadSerializedStoreFromBlob(data, store))
747 CertCloseStore(store, 0);
751 TRACE("returning %p\n", store);
752 return (PWINECRYPT_CERTSTORE)store;
755 static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv,
756 DWORD dwFlags, const void *pvPara)
758 if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
759 FIXME("(%ld, %08x, %p): stub\n", hCryptProv, dwFlags, pvPara);
761 FIXME("(%ld, %08x, %s): stub\n", hCryptProv, dwFlags,
766 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
767 DWORD dwMsgAndCertEncodingType, HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags,
770 WINECRYPT_CERTSTORE *hcs;
771 StoreOpenFunc openFunc = NULL;
773 TRACE("(%s, %08x, %08lx, %08x, %p)\n", debugstr_a(lpszStoreProvider),
774 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
776 if (IS_INTOID(lpszStoreProvider))
778 switch (LOWORD(lpszStoreProvider))
780 case LOWORD(CERT_STORE_PROV_MSG):
781 openFunc = CRYPT_MsgOpenStore;
783 case LOWORD(CERT_STORE_PROV_MEMORY):
784 openFunc = CRYPT_MemOpenStore;
786 case LOWORD(CERT_STORE_PROV_FILE):
787 openFunc = CRYPT_FileOpenStore;
789 case LOWORD(CERT_STORE_PROV_PKCS7):
790 openFunc = CRYPT_PKCSOpenStore;
792 case LOWORD(CERT_STORE_PROV_SERIALIZED):
793 openFunc = CRYPT_SerializedOpenStore;
795 case LOWORD(CERT_STORE_PROV_REG):
796 openFunc = CRYPT_RegOpenStore;
798 case LOWORD(CERT_STORE_PROV_FILENAME_A):
799 openFunc = CRYPT_FileNameOpenStoreA;
801 case LOWORD(CERT_STORE_PROV_FILENAME_W):
802 openFunc = CRYPT_FileNameOpenStoreW;
804 case LOWORD(CERT_STORE_PROV_COLLECTION):
805 openFunc = CRYPT_CollectionOpenStore;
807 case LOWORD(CERT_STORE_PROV_SYSTEM_A):
808 openFunc = CRYPT_SysOpenStoreA;
810 case LOWORD(CERT_STORE_PROV_SYSTEM_W):
811 openFunc = CRYPT_SysOpenStoreW;
813 case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_A):
814 openFunc = CRYPT_SysRegOpenStoreA;
816 case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_W):
817 openFunc = CRYPT_SysRegOpenStoreW;
819 case LOWORD(CERT_STORE_PROV_PHYSICAL_W):
820 openFunc = CRYPT_PhysOpenStoreW;
823 if (LOWORD(lpszStoreProvider))
824 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
827 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
828 openFunc = CRYPT_MemOpenStore;
829 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_FILENAME_W))
830 openFunc = CRYPT_FileOpenStore;
831 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
832 openFunc = CRYPT_SysOpenStoreW;
833 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_PKCS7))
834 openFunc = CRYPT_PKCSOpenStore;
835 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SERIALIZED))
836 openFunc = CRYPT_SerializedOpenStore;
837 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
838 openFunc = CRYPT_CollectionOpenStore;
839 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
840 openFunc = CRYPT_SysRegOpenStoreW;
843 FIXME("unimplemented type %s\n", lpszStoreProvider);
848 hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
849 hCryptProv, dwFlags, pvPara);
851 hcs = openFunc(hCryptProv, dwFlags, pvPara);
855 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv,
856 LPCSTR szSubSystemProtocol)
858 if (!szSubSystemProtocol)
860 SetLastError(E_INVALIDARG);
863 return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
864 CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
867 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv,
868 LPCWSTR szSubSystemProtocol)
870 if (!szSubSystemProtocol)
872 SetLastError(E_INVALIDARG);
875 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
876 CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
879 #define CertContext_CopyProperties(to, from) \
880 Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT))
882 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
883 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
884 PCCERT_CONTEXT *ppStoreContext)
886 PWINECRYPT_CERTSTORE store = hCertStore;
888 PCCERT_CONTEXT toAdd = NULL, existing = NULL;
890 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext,
891 dwAddDisposition, ppStoreContext);
893 switch (dwAddDisposition)
895 case CERT_STORE_ADD_ALWAYS:
897 case CERT_STORE_ADD_NEW:
898 case CERT_STORE_ADD_REPLACE_EXISTING:
899 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
900 case CERT_STORE_ADD_USE_EXISTING:
901 case CERT_STORE_ADD_NEWER:
902 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
905 DWORD size = sizeof(hashToAdd);
907 ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
911 CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
913 existing = CertFindCertificateInStore(hCertStore,
914 pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
920 FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
921 SetLastError(E_INVALIDARG);
925 switch (dwAddDisposition)
927 case CERT_STORE_ADD_ALWAYS:
928 toAdd = CertDuplicateCertificateContext(pCertContext);
930 case CERT_STORE_ADD_NEW:
933 TRACE("found matching certificate, not adding\n");
934 SetLastError(CRYPT_E_EXISTS);
938 toAdd = CertDuplicateCertificateContext(pCertContext);
940 case CERT_STORE_ADD_REPLACE_EXISTING:
941 toAdd = CertDuplicateCertificateContext(pCertContext);
943 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
944 toAdd = CertDuplicateCertificateContext(pCertContext);
946 CertContext_CopyProperties(toAdd, existing);
948 case CERT_STORE_ADD_USE_EXISTING:
951 CertContext_CopyProperties(existing, pCertContext);
953 *ppStoreContext = CertDuplicateCertificateContext(existing);
956 toAdd = CertDuplicateCertificateContext(pCertContext);
958 case CERT_STORE_ADD_NEWER:
961 if (CompareFileTime(&existing->pCertInfo->NotBefore,
962 &pCertContext->pCertInfo->NotBefore) >= 0)
964 TRACE("existing certificate is newer, not adding\n");
965 SetLastError(CRYPT_E_EXISTS);
969 toAdd = CertDuplicateCertificateContext(pCertContext);
972 toAdd = CertDuplicateCertificateContext(pCertContext);
974 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
977 if (CompareFileTime(&existing->pCertInfo->NotBefore,
978 &pCertContext->pCertInfo->NotBefore) >= 0)
980 TRACE("existing certificate is newer, not adding\n");
981 SetLastError(CRYPT_E_EXISTS);
986 toAdd = CertDuplicateCertificateContext(pCertContext);
987 CertContext_CopyProperties(toAdd, existing);
991 toAdd = CertDuplicateCertificateContext(pCertContext);
998 ret = store->certs.addContext(store, (void *)toAdd,
999 (void *)existing, (const void **)ppStoreContext);
1000 else if (ppStoreContext)
1001 *ppStoreContext = CertDuplicateCertificateContext(toAdd);
1002 CertFreeCertificateContext(toAdd);
1004 CertFreeCertificateContext(existing);
1006 TRACE("returning %d\n", ret);
1010 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
1011 PCCERT_CONTEXT pPrev)
1013 WINECRYPT_CERTSTORE *hcs = hCertStore;
1016 TRACE("(%p, %p)\n", hCertStore, pPrev);
1019 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1022 ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
1026 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
1030 TRACE("(%p)\n", pCertContext);
1034 else if (!pCertContext->hCertStore)
1035 ret = CertFreeCertificateContext(pCertContext);
1038 PWINECRYPT_CERTSTORE hcs = pCertContext->hCertStore;
1040 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1043 ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
1045 ret = CertFreeCertificateContext(pCertContext);
1050 #define CrlContext_CopyProperties(to, from) \
1051 Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
1053 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
1054 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
1055 PCCRL_CONTEXT* ppStoreContext)
1057 PWINECRYPT_CERTSTORE store = hCertStore;
1059 PCCRL_CONTEXT toAdd = NULL, existing = NULL;
1061 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCrlContext,
1062 dwAddDisposition, ppStoreContext);
1064 /* Weird case to pass a test */
1065 if (dwAddDisposition == 0)
1067 SetLastError(STATUS_ACCESS_VIOLATION);
1070 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
1072 existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
1076 switch (dwAddDisposition)
1078 case CERT_STORE_ADD_ALWAYS:
1079 toAdd = CertDuplicateCRLContext(pCrlContext);
1081 case CERT_STORE_ADD_NEW:
1084 TRACE("found matching CRL, not adding\n");
1085 SetLastError(CRYPT_E_EXISTS);
1089 toAdd = CertDuplicateCRLContext(pCrlContext);
1091 case CERT_STORE_ADD_NEWER:
1094 LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
1095 &pCrlContext->pCrlInfo->ThisUpdate);
1098 toAdd = CertDuplicateCRLContext(pCrlContext);
1101 TRACE("existing CRL is newer, not adding\n");
1102 SetLastError(CRYPT_E_EXISTS);
1107 toAdd = CertDuplicateCRLContext(pCrlContext);
1109 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
1112 LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
1113 &pCrlContext->pCrlInfo->ThisUpdate);
1117 toAdd = CertDuplicateCRLContext(pCrlContext);
1118 CrlContext_CopyProperties(toAdd, existing);
1122 TRACE("existing CRL is newer, not adding\n");
1123 SetLastError(CRYPT_E_EXISTS);
1128 toAdd = CertDuplicateCRLContext(pCrlContext);
1130 case CERT_STORE_ADD_REPLACE_EXISTING:
1131 toAdd = CertDuplicateCRLContext(pCrlContext);
1133 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
1134 toAdd = CertDuplicateCRLContext(pCrlContext);
1136 CrlContext_CopyProperties(toAdd, existing);
1138 case CERT_STORE_ADD_USE_EXISTING:
1141 CrlContext_CopyProperties(existing, pCrlContext);
1143 *ppStoreContext = CertDuplicateCRLContext(existing);
1146 toAdd = CertDuplicateCRLContext(pCrlContext);
1149 FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
1156 ret = store->crls.addContext(store, (void *)toAdd,
1157 (void *)existing, (const void **)ppStoreContext);
1158 else if (ppStoreContext)
1159 *ppStoreContext = CertDuplicateCRLContext(toAdd);
1160 CertFreeCRLContext(toAdd);
1162 CertFreeCRLContext(existing);
1164 TRACE("returning %d\n", ret);
1168 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
1172 TRACE("(%p)\n", pCrlContext);
1176 else if (!pCrlContext->hCertStore)
1177 ret = CertFreeCRLContext(pCrlContext);
1180 PWINECRYPT_CERTSTORE hcs = pCrlContext->hCertStore;
1182 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1185 ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
1187 ret = CertFreeCRLContext(pCrlContext);
1192 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
1193 PCCRL_CONTEXT pPrev)
1195 WINECRYPT_CERTSTORE *hcs = hCertStore;
1198 TRACE("(%p, %p)\n", hCertStore, pPrev);
1201 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1204 ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
1208 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
1210 WINECRYPT_CERTSTORE *hcs = hCertStore;
1212 TRACE("(%p)\n", hCertStore);
1214 if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
1215 InterlockedIncrement(&hcs->ref);
1219 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1221 WINECRYPT_CERTSTORE *hcs = hCertStore;
1223 TRACE("(%p, %08x)\n", hCertStore, dwFlags);
1228 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
1232 ERR("%p's ref count is %d\n", hcs, hcs->ref);
1233 if (InterlockedDecrement(&hcs->ref) == 0)
1235 TRACE("%p's ref count is 0, freeing\n", hcs);
1237 hcs->closeStore(hcs, dwFlags);
1240 TRACE("%p's ref count is %d\n", hcs, hcs->ref);
1244 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
1245 DWORD dwCtrlType, void const *pvCtrlPara)
1247 WINECRYPT_CERTSTORE *hcs = hCertStore;
1250 TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
1255 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1260 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
1267 BOOL WINAPI CertGetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1268 void *pvData, DWORD *pcbData)
1270 PWINECRYPT_CERTSTORE store = hCertStore;
1273 TRACE("(%p, %d, %p, %p)\n", hCertStore, dwPropId, pvData, pcbData);
1277 case CERT_ACCESS_STATE_PROP_ID:
1280 *pcbData = sizeof(DWORD);
1283 else if (*pcbData < sizeof(DWORD))
1285 SetLastError(ERROR_MORE_DATA);
1286 *pcbData = sizeof(DWORD);
1292 if (store->type != StoreTypeMem &&
1293 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1294 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1295 *(DWORD *)pvData = state;
1300 if (store->properties)
1302 CRYPT_DATA_BLOB blob;
1304 ret = ContextPropertyList_FindProperty(store->properties, dwPropId,
1309 *pcbData = blob.cbData;
1310 else if (*pcbData < blob.cbData)
1312 SetLastError(ERROR_MORE_DATA);
1313 *pcbData = blob.cbData;
1318 memcpy(pvData, blob.pbData, blob.cbData);
1319 *pcbData = blob.cbData;
1323 SetLastError(CRYPT_E_NOT_FOUND);
1326 SetLastError(CRYPT_E_NOT_FOUND);
1331 BOOL WINAPI CertSetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId,
1332 DWORD dwFlags, const void *pvData)
1334 PWINECRYPT_CERTSTORE store = hCertStore;
1337 TRACE("(%p, %d, %08x, %p)\n", hCertStore, dwPropId, dwFlags, pvData);
1339 if (!store->properties)
1340 store->properties = ContextPropertyList_Create();
1343 case CERT_ACCESS_STATE_PROP_ID:
1344 SetLastError(E_INVALIDARG);
1349 const CRYPT_DATA_BLOB *blob = pvData;
1351 ret = ContextPropertyList_SetProperty(store->properties, dwPropId,
1352 blob->pbData, blob->cbData);
1356 ContextPropertyList_RemoveProperty(store->properties, dwPropId);
1363 static LONG CRYPT_OpenParentStore(DWORD dwFlags,
1364 void *pvSystemStoreLocationPara, HKEY *key)
1369 TRACE("(%08x, %p)\n", dwFlags, pvSystemStoreLocationPara);
1371 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1373 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1374 root = HKEY_LOCAL_MACHINE;
1375 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1377 case CERT_SYSTEM_STORE_CURRENT_USER:
1378 root = HKEY_CURRENT_USER;
1379 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1381 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1382 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1383 * SystemCertificates
1385 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE\n");
1386 return ERROR_FILE_NOT_FOUND;
1387 case CERT_SYSTEM_STORE_SERVICES:
1388 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1389 * SystemCertificates
1391 FIXME("CERT_SYSTEM_STORE_SERVICES\n");
1392 return ERROR_FILE_NOT_FOUND;
1393 case CERT_SYSTEM_STORE_USERS:
1394 /* hku\user sid\Software\Microsoft\SystemCertificates */
1395 FIXME("CERT_SYSTEM_STORE_USERS\n");
1396 return ERROR_FILE_NOT_FOUND;
1397 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1398 root = HKEY_CURRENT_USER;
1399 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1401 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1402 root = HKEY_LOCAL_MACHINE;
1403 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1405 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1406 /* hklm\Software\Microsoft\EnterpriseCertificates */
1407 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE\n");
1408 return ERROR_FILE_NOT_FOUND;
1410 return ERROR_FILE_NOT_FOUND;
1413 return RegOpenKeyExW(root, base, 0, KEY_READ, key);
1416 BOOL WINAPI CertEnumSystemStore(DWORD dwFlags, void *pvSystemStoreLocationPara,
1417 void *pvArg, PFN_CERT_ENUM_SYSTEM_STORE pfnEnum)
1422 CERT_SYSTEM_STORE_INFO info = { sizeof(info) };
1424 TRACE("(%08x, %p, %p, %p)\n", dwFlags, pvSystemStoreLocationPara, pvArg,
1427 rc = CRYPT_OpenParentStore(dwFlags, pvArg, &key);
1434 WCHAR name[MAX_PATH];
1435 DWORD size = sizeof(name) / sizeof(name[0]);
1437 rc = RegEnumKeyExW(key, index++, name, &size, NULL, NULL, NULL,
1440 ret = pfnEnum(name, dwFlags, &info, NULL, pvArg);
1441 } while (ret && !rc);
1442 if (ret && rc != ERROR_NO_MORE_ITEMS)
1447 /* Include root store for the local machine location (it isn't in the
1450 if (ret && (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
1451 CERT_SYSTEM_STORE_LOCAL_MACHINE)
1452 ret = pfnEnum(rootW, dwFlags, &info, NULL, pvArg);
1456 BOOL WINAPI CertEnumPhysicalStore(const void *pvSystemStore, DWORD dwFlags,
1457 void *pvArg, PFN_CERT_ENUM_PHYSICAL_STORE pfnEnum)
1459 if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
1460 FIXME("(%p, %08x, %p, %p): stub\n", pvSystemStore, dwFlags, pvArg,
1463 FIXME("(%s, %08x, %p, %p): stub\n", debugstr_w(pvSystemStore),