| /* |
| * Copyright 2002 Mike McCormack for CodeWeavers |
| * Copyright 2004-2006 Juan Lang |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| * |
| * FIXME: |
| * - The concept of physical stores and locations isn't implemented. (This |
| * doesn't mean registry stores et al aren't implemented. See the PSDK for |
| * registering and enumerating physical stores and locations.) |
| * - Many flags, options and whatnot are unimplemented. |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <assert.h> |
| #include <stdarg.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winnls.h" |
| #include "winreg.h" |
| #include "winuser.h" |
| #include "wincrypt.h" |
| #include "wine/debug.h" |
| #include "wine/list.h" |
| #include "wine/exception.h" |
| #include "crypt32_private.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(crypt); |
| |
| static const WINE_CONTEXT_INTERFACE gCertInterface = { |
| (CreateContextFunc)CertCreateCertificateContext, |
| (AddContextToStoreFunc)CertAddCertificateContextToStore, |
| (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore, |
| (DuplicateContextFunc)CertDuplicateCertificateContext, |
| (EnumContextsInStoreFunc)CertEnumCertificatesInStore, |
| (EnumPropertiesFunc)CertEnumCertificateContextProperties, |
| (GetContextPropertyFunc)CertGetCertificateContextProperty, |
| (SetContextPropertyFunc)CertSetCertificateContextProperty, |
| (SerializeElementFunc)CertSerializeCertificateStoreElement, |
| (FreeContextFunc)CertFreeCertificateContext, |
| (DeleteContextFunc)CertDeleteCertificateFromStore, |
| }; |
| PCWINE_CONTEXT_INTERFACE pCertInterface = &gCertInterface; |
| |
| static const WINE_CONTEXT_INTERFACE gCRLInterface = { |
| (CreateContextFunc)CertCreateCRLContext, |
| (AddContextToStoreFunc)CertAddCRLContextToStore, |
| (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore, |
| (DuplicateContextFunc)CertDuplicateCRLContext, |
| (EnumContextsInStoreFunc)CertEnumCRLsInStore, |
| (EnumPropertiesFunc)CertEnumCRLContextProperties, |
| (GetContextPropertyFunc)CertGetCRLContextProperty, |
| (SetContextPropertyFunc)CertSetCRLContextProperty, |
| (SerializeElementFunc)CertSerializeCRLStoreElement, |
| (FreeContextFunc)CertFreeCRLContext, |
| (DeleteContextFunc)CertDeleteCRLFromStore, |
| }; |
| PCWINE_CONTEXT_INTERFACE pCRLInterface = &gCRLInterface; |
| |
| static const WINE_CONTEXT_INTERFACE gCTLInterface = { |
| (CreateContextFunc)CertCreateCTLContext, |
| (AddContextToStoreFunc)CertAddCTLContextToStore, |
| (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore, |
| (DuplicateContextFunc)CertDuplicateCTLContext, |
| (EnumContextsInStoreFunc)CertEnumCTLsInStore, |
| (EnumPropertiesFunc)CertEnumCTLContextProperties, |
| (GetContextPropertyFunc)CertGetCTLContextProperty, |
| (SetContextPropertyFunc)CertSetCTLContextProperty, |
| (SerializeElementFunc)CertSerializeCTLStoreElement, |
| (FreeContextFunc)CertFreeCTLContext, |
| (DeleteContextFunc)CertDeleteCTLFromStore, |
| }; |
| PCWINE_CONTEXT_INTERFACE pCTLInterface = &gCTLInterface; |
| |
| typedef struct _WINE_MEMSTORE |
| { |
| WINECRYPT_CERTSTORE hdr; |
| struct ContextList *certs; |
| struct ContextList *crls; |
| struct ContextList *ctls; |
| } WINE_MEMSTORE, *PWINE_MEMSTORE; |
| |
| void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, DWORD dwFlags, |
| CertStoreType type) |
| { |
| store->ref = 1; |
| store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC; |
| store->type = type; |
| store->dwOpenFlags = dwFlags; |
| store->properties = NULL; |
| } |
| |
| void CRYPT_FreeStore(PWINECRYPT_CERTSTORE store) |
| { |
| if (store->properties) |
| ContextPropertyList_Free(store->properties); |
| CryptMemFree(store); |
| } |
| |
| BOOL WINAPI I_CertUpdateStore(HCERTSTORE store1, HCERTSTORE store2, DWORD unk0, |
| DWORD unk1) |
| { |
| static BOOL warned = FALSE; |
| const WINE_CONTEXT_INTERFACE * const interfaces[] = { pCertInterface, |
| pCRLInterface, pCTLInterface }; |
| DWORD i; |
| |
| TRACE("(%p, %p, %08x, %08x)\n", store1, store2, unk0, unk1); |
| if (!warned) |
| { |
| FIXME("semi-stub\n"); |
| warned = TRUE; |
| } |
| |
| /* Poor-man's resync: empty first store, then add everything from second |
| * store to it. |
| */ |
| for (i = 0; i < sizeof(interfaces) / sizeof(interfaces[0]); i++) |
| { |
| const void *context; |
| |
| do { |
| context = interfaces[i]->enumContextsInStore(store1, NULL); |
| if (context) |
| interfaces[i]->deleteFromStore(context); |
| } while (context); |
| do { |
| context = interfaces[i]->enumContextsInStore(store2, context); |
| if (context) |
| interfaces[i]->addContextToStore(store1, context, |
| CERT_STORE_ADD_ALWAYS, NULL); |
| } while (context); |
| } |
| return TRUE; |
| } |
| |
| static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, void *cert, |
| void *toReplace, const void **ppStoreContext) |
| { |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; |
| PCERT_CONTEXT context; |
| |
| TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext); |
| |
| context = ContextList_Add(ms->certs, cert, toReplace); |
| if (context) |
| { |
| context->hCertStore = store; |
| if (ppStoreContext) |
| *ppStoreContext = CertDuplicateCertificateContext(context); |
| } |
| return context ? TRUE : FALSE; |
| } |
| |
| static void *CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) |
| { |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; |
| void *ret; |
| |
| TRACE("(%p, %p)\n", store, pPrev); |
| |
| ret = ContextList_Enum(ms->certs, pPrev); |
| if (!ret) |
| SetLastError(CRYPT_E_NOT_FOUND); |
| |
| TRACE("returning %p\n", ret); |
| return ret; |
| } |
| |
| static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext) |
| { |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; |
| BOOL ret; |
| |
| if (ContextList_Remove(ms->certs, pCertContext)) |
| ret = CertFreeCertificateContext(pCertContext); |
| else |
| ret = TRUE; |
| return ret; |
| } |
| |
| static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl, |
| void *toReplace, const void **ppStoreContext) |
| { |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; |
| PCRL_CONTEXT context; |
| |
| TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext); |
| |
| context = ContextList_Add(ms->crls, crl, toReplace); |
| if (context) |
| { |
| context->hCertStore = store; |
| if (ppStoreContext) |
| *ppStoreContext = CertDuplicateCRLContext(context); |
| } |
| return context ? TRUE : FALSE; |
| } |
| |
| static void *CRYPT_MemEnumCrl(PWINECRYPT_CERTSTORE store, void *pPrev) |
| { |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; |
| void *ret; |
| |
| TRACE("(%p, %p)\n", store, pPrev); |
| |
| ret = ContextList_Enum(ms->crls, pPrev); |
| if (!ret) |
| SetLastError(CRYPT_E_NOT_FOUND); |
| |
| TRACE("returning %p\n", ret); |
| return ret; |
| } |
| |
| static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext) |
| { |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; |
| BOOL ret; |
| |
| if (ContextList_Remove(ms->crls, pCrlContext)) |
| ret = CertFreeCRLContext(pCrlContext); |
| else |
| ret = TRUE; |
| return ret; |
| } |
| |
| static BOOL CRYPT_MemAddCtl(PWINECRYPT_CERTSTORE store, void *ctl, |
| void *toReplace, const void **ppStoreContext) |
| { |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; |
| PCTL_CONTEXT context; |
| |
| TRACE("(%p, %p, %p, %p)\n", store, ctl, toReplace, ppStoreContext); |
| |
| context = ContextList_Add(ms->ctls, ctl, toReplace); |
| if (context) |
| { |
| context->hCertStore = store; |
| if (ppStoreContext) |
| *ppStoreContext = CertDuplicateCTLContext(context); |
| } |
| return context ? TRUE : FALSE; |
| } |
| |
| static void *CRYPT_MemEnumCtl(PWINECRYPT_CERTSTORE store, void *pPrev) |
| { |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; |
| void *ret; |
| |
| TRACE("(%p, %p)\n", store, pPrev); |
| |
| ret = ContextList_Enum(ms->ctls, pPrev); |
| if (!ret) |
| SetLastError(CRYPT_E_NOT_FOUND); |
| |
| TRACE("returning %p\n", ret); |
| return ret; |
| } |
| |
| static BOOL CRYPT_MemDeleteCtl(PWINECRYPT_CERTSTORE store, void *pCtlContext) |
| { |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; |
| BOOL ret; |
| |
| if (ContextList_Remove(ms->ctls, pCtlContext)) |
| ret = CertFreeCTLContext(pCtlContext); |
| else |
| ret = TRUE; |
| return ret; |
| } |
| |
| static BOOL WINAPI CRYPT_MemControl(HCERTSTORE hCertStore, DWORD dwFlags, |
| DWORD dwCtrlType, void const *pvCtrlPara) |
| { |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| return FALSE; |
| } |
| |
| static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) |
| { |
| WINE_MEMSTORE *store = hCertStore; |
| |
| TRACE("(%p, %08x)\n", store, dwFlags); |
| if (dwFlags) |
| FIXME("Unimplemented flags: %08x\n", dwFlags); |
| |
| ContextList_Free(store->certs); |
| ContextList_Free(store->crls); |
| ContextList_Free(store->ctls); |
| CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store); |
| } |
| |
| static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| PWINE_MEMSTORE store; |
| |
| TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); |
| |
| if (dwFlags & CERT_STORE_DELETE_FLAG) |
| { |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| store = NULL; |
| } |
| else |
| { |
| store = CryptMemAlloc(sizeof(WINE_MEMSTORE)); |
| if (store) |
| { |
| memset(store, 0, sizeof(WINE_MEMSTORE)); |
| CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeMem); |
| store->hdr.closeStore = CRYPT_MemCloseStore; |
| store->hdr.certs.addContext = CRYPT_MemAddCert; |
| store->hdr.certs.enumContext = CRYPT_MemEnumCert; |
| store->hdr.certs.deleteContext = CRYPT_MemDeleteCert; |
| store->hdr.crls.addContext = CRYPT_MemAddCrl; |
| store->hdr.crls.enumContext = CRYPT_MemEnumCrl; |
| store->hdr.crls.deleteContext = CRYPT_MemDeleteCrl; |
| store->hdr.ctls.addContext = CRYPT_MemAddCtl; |
| store->hdr.ctls.enumContext = CRYPT_MemEnumCtl; |
| store->hdr.ctls.deleteContext = CRYPT_MemDeleteCtl; |
| store->hdr.control = CRYPT_MemControl; |
| store->certs = ContextList_Create(pCertInterface, |
| sizeof(CERT_CONTEXT)); |
| store->crls = ContextList_Create(pCRLInterface, |
| sizeof(CRL_CONTEXT)); |
| store->ctls = ContextList_Create(pCTLInterface, |
| sizeof(CTL_CONTEXT)); |
| /* Mem store doesn't need crypto provider, so close it */ |
| if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) |
| CryptReleaseContext(hCryptProv, 0); |
| } |
| } |
| return (PWINECRYPT_CERTSTORE)store; |
| } |
| |
| static const WCHAR rootW[] = { 'R','o','o','t',0 }; |
| |
| static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| static const WCHAR fmt[] = { '%','s','\\','%','s',0 }; |
| LPCWSTR storeName = pvPara; |
| LPWSTR storePath; |
| PWINECRYPT_CERTSTORE store = NULL; |
| HKEY root; |
| LPCWSTR base; |
| |
| TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, |
| debugstr_w(pvPara)); |
| |
| if (!pvPara) |
| { |
| SetLastError(E_INVALIDARG); |
| return NULL; |
| } |
| /* FIXME: In Windows, the root store (even the current user location) is |
| * protected: adding to it or removing from it present a user interface, |
| * and the keys are owned by the system process, not the current user. |
| * Wine's registry doesn't implement access controls, so a similar |
| * mechanism isn't possible yet. |
| */ |
| if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) == |
| CERT_SYSTEM_STORE_LOCAL_MACHINE && !lstrcmpiW(storeName, rootW)) |
| return CRYPT_RootOpenStore(hCryptProv, dwFlags); |
| |
| switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) |
| { |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE: |
| root = HKEY_LOCAL_MACHINE; |
| base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; |
| break; |
| case CERT_SYSTEM_STORE_CURRENT_USER: |
| root = HKEY_CURRENT_USER; |
| base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; |
| break; |
| case CERT_SYSTEM_STORE_CURRENT_SERVICE: |
| /* hklm\Software\Microsoft\Cryptography\Services\servicename\ |
| * SystemCertificates |
| */ |
| FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n", |
| debugstr_w(storeName)); |
| return NULL; |
| case CERT_SYSTEM_STORE_SERVICES: |
| /* hklm\Software\Microsoft\Cryptography\Services\servicename\ |
| * SystemCertificates |
| */ |
| FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n", |
| debugstr_w(storeName)); |
| return NULL; |
| case CERT_SYSTEM_STORE_USERS: |
| /* hku\user sid\Software\Microsoft\SystemCertificates */ |
| FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n", |
| debugstr_w(storeName)); |
| return NULL; |
| case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY: |
| root = HKEY_CURRENT_USER; |
| base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; |
| break; |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY: |
| root = HKEY_LOCAL_MACHINE; |
| base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; |
| break; |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE: |
| /* hklm\Software\Microsoft\EnterpriseCertificates */ |
| FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n", |
| debugstr_w(storeName)); |
| return NULL; |
| default: |
| SetLastError(E_INVALIDARG); |
| return NULL; |
| } |
| |
| storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) * |
| sizeof(WCHAR)); |
| if (storePath) |
| { |
| LONG rc; |
| HKEY key; |
| REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : |
| KEY_ALL_ACCESS; |
| |
| wsprintfW(storePath, fmt, base, storeName); |
| if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG) |
| rc = RegOpenKeyExW(root, storePath, 0, sam, &key); |
| else |
| { |
| DWORD disp; |
| |
| rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL, |
| &key, &disp); |
| if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG && |
| disp == REG_OPENED_EXISTING_KEY) |
| { |
| RegCloseKey(key); |
| rc = ERROR_FILE_EXISTS; |
| } |
| } |
| if (!rc) |
| { |
| store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key); |
| RegCloseKey(key); |
| } |
| else |
| SetLastError(rc); |
| CryptMemFree(storePath); |
| } |
| return store; |
| } |
| |
| static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| int len; |
| PWINECRYPT_CERTSTORE ret = NULL; |
| |
| TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, |
| debugstr_a(pvPara)); |
| |
| if (!pvPara) |
| { |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return NULL; |
| } |
| len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0); |
| if (len) |
| { |
| LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); |
| |
| if (storeName) |
| { |
| MultiByteToWideChar(CP_ACP, 0, pvPara, -1, storeName, len); |
| ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName); |
| CryptMemFree(storeName); |
| } |
| } |
| return ret; |
| } |
| |
| static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| HCERTSTORE store = 0; |
| BOOL ret; |
| |
| TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, |
| debugstr_w(pvPara)); |
| |
| if (!pvPara) |
| { |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return NULL; |
| } |
| /* This returns a different error than system registry stores if the |
| * location is invalid. |
| */ |
| switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) |
| { |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE: |
| case CERT_SYSTEM_STORE_CURRENT_USER: |
| case CERT_SYSTEM_STORE_CURRENT_SERVICE: |
| case CERT_SYSTEM_STORE_SERVICES: |
| case CERT_SYSTEM_STORE_USERS: |
| case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY: |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY: |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE: |
| ret = TRUE; |
| break; |
| default: |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| ret = FALSE; |
| } |
| if (ret) |
| { |
| HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, |
| 0, 0, dwFlags, pvPara); |
| |
| if (regStore) |
| { |
| store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, |
| CERT_STORE_CREATE_NEW_FLAG, NULL); |
| CertAddStoreToCollection(store, regStore, |
| dwFlags & CERT_STORE_READONLY_FLAG ? 0 : |
| CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); |
| CertCloseStore(regStore, 0); |
| /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM |
| * stores. |
| */ |
| if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) == |
| CERT_SYSTEM_STORE_CURRENT_USER) |
| { |
| dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER; |
| dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE; |
| regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, |
| 0, dwFlags, pvPara); |
| if (regStore) |
| { |
| CertAddStoreToCollection(store, regStore, |
| dwFlags & CERT_STORE_READONLY_FLAG ? 0 : |
| CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); |
| CertCloseStore(regStore, 0); |
| } |
| } |
| /* System store doesn't need crypto provider, so close it */ |
| if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) |
| CryptReleaseContext(hCryptProv, 0); |
| } |
| } |
| return store; |
| } |
| |
| static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| int len; |
| PWINECRYPT_CERTSTORE ret = NULL; |
| |
| TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, |
| debugstr_a(pvPara)); |
| |
| if (!pvPara) |
| { |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return NULL; |
| } |
| len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0); |
| if (len) |
| { |
| LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); |
| |
| if (storeName) |
| { |
| MultiByteToWideChar(CP_ACP, 0, pvPara, -1, storeName, len); |
| ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName); |
| CryptMemFree(storeName); |
| } |
| } |
| return ret; |
| } |
| |
| static void WINAPI CRYPT_MsgCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) |
| { |
| HCRYPTMSG msg = hCertStore; |
| |
| TRACE("(%p, %08x)\n", msg, dwFlags); |
| CryptMsgClose(msg); |
| } |
| |
| static void *msgProvFuncs[] = { |
| CRYPT_MsgCloseStore, |
| }; |
| |
| static PWINECRYPT_CERTSTORE CRYPT_MsgOpenStore(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| PWINECRYPT_CERTSTORE store = NULL; |
| HCRYPTMSG msg = (HCRYPTMSG)pvPara; |
| PWINECRYPT_CERTSTORE memStore; |
| |
| TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); |
| |
| memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, |
| CERT_STORE_CREATE_NEW_FLAG, NULL); |
| if (memStore) |
| { |
| BOOL ret; |
| DWORD size, count, i; |
| |
| size = sizeof(count); |
| ret = CryptMsgGetParam(msg, CMSG_CERT_COUNT_PARAM, 0, &count, &size); |
| for (i = 0; ret && i < count; i++) |
| { |
| size = 0; |
| ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, NULL, &size); |
| if (ret) |
| { |
| LPBYTE buf = CryptMemAlloc(size); |
| |
| if (buf) |
| { |
| ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, buf, &size); |
| if (ret) |
| ret = CertAddEncodedCertificateToStore(memStore, |
| X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS, |
| NULL); |
| CryptMemFree(buf); |
| } |
| } |
| } |
| size = sizeof(count); |
| ret = CryptMsgGetParam(msg, CMSG_CRL_COUNT_PARAM, 0, &count, &size); |
| for (i = 0; ret && i < count; i++) |
| { |
| size = 0; |
| ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, NULL, &size); |
| if (ret) |
| { |
| LPBYTE buf = CryptMemAlloc(size); |
| |
| if (buf) |
| { |
| ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, buf, &size); |
| if (ret) |
| ret = CertAddEncodedCRLToStore(memStore, |
| X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS, |
| NULL); |
| CryptMemFree(buf); |
| } |
| } |
| } |
| if (ret) |
| { |
| CERT_STORE_PROV_INFO provInfo = { 0 }; |
| |
| provInfo.cbSize = sizeof(provInfo); |
| provInfo.cStoreProvFunc = sizeof(msgProvFuncs) / |
| sizeof(msgProvFuncs[0]); |
| provInfo.rgpvStoreProvFunc = msgProvFuncs; |
| provInfo.hStoreProv = CryptMsgDuplicate(msg); |
| store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo); |
| /* Msg store doesn't need crypto provider, so close it */ |
| if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) |
| CryptReleaseContext(hCryptProv, 0); |
| } |
| else |
| CertCloseStore(memStore, 0); |
| } |
| TRACE("returning %p\n", store); |
| return store; |
| } |
| |
| static PWINECRYPT_CERTSTORE CRYPT_PKCSOpenStore(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| HCRYPTMSG msg; |
| PWINECRYPT_CERTSTORE store = NULL; |
| const CRYPT_DATA_BLOB *data = pvPara; |
| BOOL ret; |
| DWORD msgOpenFlags = dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG ? 0 : |
| CMSG_CRYPT_RELEASE_CONTEXT_FLAG; |
| |
| TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); |
| |
| msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, CMSG_SIGNED, |
| hCryptProv, NULL, NULL); |
| ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE); |
| if (!ret) |
| { |
| CryptMsgClose(msg); |
| msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, 0, |
| hCryptProv, NULL, NULL); |
| ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE); |
| if (ret) |
| { |
| DWORD type, size = sizeof(type); |
| |
| /* Only signed messages are allowed, check type */ |
| ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &size); |
| if (ret && type != CMSG_SIGNED) |
| { |
| SetLastError(CRYPT_E_INVALID_MSG_TYPE); |
| ret = FALSE; |
| } |
| } |
| } |
| if (ret) |
| store = CRYPT_MsgOpenStore(0, dwFlags, msg); |
| CryptMsgClose(msg); |
| TRACE("returning %p\n", store); |
| return store; |
| } |
| |
| static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) |
| FIXME("(%ld, %08x, %p): stub\n", hCryptProv, dwFlags, pvPara); |
| else |
| FIXME("(%ld, %08x, %s): stub\n", hCryptProv, dwFlags, |
| debugstr_w(pvPara)); |
| return NULL; |
| } |
| |
| HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, |
| DWORD dwMsgAndCertEncodingType, HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, |
| const void* pvPara) |
| { |
| WINECRYPT_CERTSTORE *hcs; |
| StoreOpenFunc openFunc = NULL; |
| |
| TRACE("(%s, %08x, %08lx, %08x, %p)\n", debugstr_a(lpszStoreProvider), |
| dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara); |
| |
| if (IS_INTOID(lpszStoreProvider)) |
| { |
| switch (LOWORD(lpszStoreProvider)) |
| { |
| case LOWORD(CERT_STORE_PROV_MSG): |
| openFunc = CRYPT_MsgOpenStore; |
| break; |
| case LOWORD(CERT_STORE_PROV_MEMORY): |
| openFunc = CRYPT_MemOpenStore; |
| break; |
| case LOWORD(CERT_STORE_PROV_FILE): |
| openFunc = CRYPT_FileOpenStore; |
| break; |
| case LOWORD(CERT_STORE_PROV_PKCS7): |
| openFunc = CRYPT_PKCSOpenStore; |
| break; |
| case LOWORD(CERT_STORE_PROV_REG): |
| openFunc = CRYPT_RegOpenStore; |
| break; |
| case LOWORD(CERT_STORE_PROV_FILENAME_A): |
| openFunc = CRYPT_FileNameOpenStoreA; |
| break; |
| case LOWORD(CERT_STORE_PROV_FILENAME_W): |
| openFunc = CRYPT_FileNameOpenStoreW; |
| break; |
| case LOWORD(CERT_STORE_PROV_COLLECTION): |
| openFunc = CRYPT_CollectionOpenStore; |
| break; |
| case LOWORD(CERT_STORE_PROV_SYSTEM_A): |
| openFunc = CRYPT_SysOpenStoreA; |
| break; |
| case LOWORD(CERT_STORE_PROV_SYSTEM_W): |
| openFunc = CRYPT_SysOpenStoreW; |
| break; |
| case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_A): |
| openFunc = CRYPT_SysRegOpenStoreA; |
| break; |
| case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_W): |
| openFunc = CRYPT_SysRegOpenStoreW; |
| break; |
| case LOWORD(CERT_STORE_PROV_PHYSICAL_W): |
| openFunc = CRYPT_PhysOpenStoreW; |
| break; |
| default: |
| if (LOWORD(lpszStoreProvider)) |
| FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider)); |
| } |
| } |
| else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY)) |
| openFunc = CRYPT_MemOpenStore; |
| else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_FILENAME_W)) |
| openFunc = CRYPT_FileOpenStore; |
| else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM)) |
| openFunc = CRYPT_SysOpenStoreW; |
| else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION)) |
| openFunc = CRYPT_CollectionOpenStore; |
| else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY)) |
| openFunc = CRYPT_SysRegOpenStoreW; |
| else |
| { |
| FIXME("unimplemented type %s\n", lpszStoreProvider); |
| openFunc = NULL; |
| } |
| |
| if (!openFunc) |
| hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType, |
| hCryptProv, dwFlags, pvPara); |
| else |
| hcs = openFunc(hCryptProv, dwFlags, pvPara); |
| return hcs; |
| } |
| |
| HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv, |
| LPCSTR szSubSystemProtocol) |
| { |
| if (!szSubSystemProtocol) |
| { |
| SetLastError(E_INVALIDARG); |
| return 0; |
| } |
| return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv, |
| CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol); |
| } |
| |
| HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv, |
| LPCWSTR szSubSystemProtocol) |
| { |
| if (!szSubSystemProtocol) |
| { |
| SetLastError(E_INVALIDARG); |
| return 0; |
| } |
| return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv, |
| CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol); |
| } |
| |
| #define CertContext_CopyProperties(to, from) \ |
| Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT)) |
| |
| BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, |
| PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition, |
| PCCERT_CONTEXT *ppStoreContext) |
| { |
| PWINECRYPT_CERTSTORE store = hCertStore; |
| BOOL ret = TRUE; |
| PCCERT_CONTEXT toAdd = NULL, existing = NULL; |
| |
| TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext, |
| dwAddDisposition, ppStoreContext); |
| |
| switch (dwAddDisposition) |
| { |
| case CERT_STORE_ADD_ALWAYS: |
| break; |
| case CERT_STORE_ADD_NEW: |
| case CERT_STORE_ADD_REPLACE_EXISTING: |
| case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: |
| case CERT_STORE_ADD_USE_EXISTING: |
| case CERT_STORE_ADD_NEWER: |
| case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES: |
| { |
| BYTE hashToAdd[20]; |
| DWORD size = sizeof(hashToAdd); |
| |
| ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID, |
| hashToAdd, &size); |
| if (ret) |
| { |
| CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd }; |
| |
| existing = CertFindCertificateInStore(hCertStore, |
| pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob, |
| NULL); |
| } |
| break; |
| } |
| default: |
| FIXME("Unimplemented add disposition %d\n", dwAddDisposition); |
| SetLastError(E_INVALIDARG); |
| ret = FALSE; |
| } |
| |
| switch (dwAddDisposition) |
| { |
| case CERT_STORE_ADD_ALWAYS: |
| toAdd = CertDuplicateCertificateContext(pCertContext); |
| break; |
| case CERT_STORE_ADD_NEW: |
| if (existing) |
| { |
| TRACE("found matching certificate, not adding\n"); |
| SetLastError(CRYPT_E_EXISTS); |
| ret = FALSE; |
| } |
| else |
| toAdd = CertDuplicateCertificateContext(pCertContext); |
| break; |
| case CERT_STORE_ADD_REPLACE_EXISTING: |
| toAdd = CertDuplicateCertificateContext(pCertContext); |
| break; |
| case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: |
| toAdd = CertDuplicateCertificateContext(pCertContext); |
| if (existing) |
| CertContext_CopyProperties(toAdd, existing); |
| break; |
| case CERT_STORE_ADD_USE_EXISTING: |
| if (existing) |
| { |
| CertContext_CopyProperties(existing, pCertContext); |
| if (ppStoreContext) |
| *ppStoreContext = CertDuplicateCertificateContext(existing); |
| } |
| else |
| toAdd = CertDuplicateCertificateContext(pCertContext); |
| break; |
| case CERT_STORE_ADD_NEWER: |
| if (existing) |
| { |
| if (CompareFileTime(&existing->pCertInfo->NotBefore, |
| &pCertContext->pCertInfo->NotBefore) >= 0) |
| { |
| TRACE("existing certificate is newer, not adding\n"); |
| SetLastError(CRYPT_E_EXISTS); |
| ret = FALSE; |
| } |
| else |
| toAdd = CertDuplicateCertificateContext(pCertContext); |
| } |
| else |
| toAdd = CertDuplicateCertificateContext(pCertContext); |
| break; |
| case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES: |
| if (existing) |
| { |
| if (CompareFileTime(&existing->pCertInfo->NotBefore, |
| &pCertContext->pCertInfo->NotBefore) >= 0) |
| { |
| TRACE("existing certificate is newer, not adding\n"); |
| SetLastError(CRYPT_E_EXISTS); |
| ret = FALSE; |
| } |
| else |
| { |
| toAdd = CertDuplicateCertificateContext(pCertContext); |
| CertContext_CopyProperties(toAdd, existing); |
| } |
| } |
| else |
| toAdd = CertDuplicateCertificateContext(pCertContext); |
| break; |
| } |
| |
| if (toAdd) |
| { |
| if (store) |
| ret = store->certs.addContext(store, (void *)toAdd, |
| (void *)existing, (const void **)ppStoreContext); |
| else if (ppStoreContext) |
| *ppStoreContext = CertDuplicateCertificateContext(toAdd); |
| CertFreeCertificateContext(toAdd); |
| } |
| CertFreeCertificateContext(existing); |
| |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore, |
| PCCERT_CONTEXT pPrev) |
| { |
| WINECRYPT_CERTSTORE *hcs = hCertStore; |
| PCCERT_CONTEXT ret; |
| |
| TRACE("(%p, %p)\n", hCertStore, pPrev); |
| if (!hCertStore) |
| ret = NULL; |
| else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) |
| ret = NULL; |
| else |
| ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev); |
| return ret; |
| } |
| |
| BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext) |
| { |
| BOOL ret; |
| |
| TRACE("(%p)\n", pCertContext); |
| |
| if (!pCertContext) |
| ret = TRUE; |
| else if (!pCertContext->hCertStore) |
| ret = CertFreeCertificateContext(pCertContext); |
| else |
| { |
| PWINECRYPT_CERTSTORE hcs = pCertContext->hCertStore; |
| |
| if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) |
| ret = FALSE; |
| else |
| ret = hcs->certs.deleteContext(hcs, (void *)pCertContext); |
| if (ret) |
| ret = CertFreeCertificateContext(pCertContext); |
| } |
| return ret; |
| } |
| |
| #define CrlContext_CopyProperties(to, from) \ |
| Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT)) |
| |
| BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore, |
| PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition, |
| PCCRL_CONTEXT* ppStoreContext) |
| { |
| PWINECRYPT_CERTSTORE store = hCertStore; |
| BOOL ret = TRUE; |
| PCCRL_CONTEXT toAdd = NULL, existing = NULL; |
| |
| TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCrlContext, |
| dwAddDisposition, ppStoreContext); |
| |
| /* Weird case to pass a test */ |
| if (dwAddDisposition == 0) |
| { |
| SetLastError(STATUS_ACCESS_VIOLATION); |
| return FALSE; |
| } |
| if (dwAddDisposition != CERT_STORE_ADD_ALWAYS) |
| { |
| existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING, |
| pCrlContext, NULL); |
| } |
| |
| switch (dwAddDisposition) |
| { |
| case CERT_STORE_ADD_ALWAYS: |
| toAdd = CertDuplicateCRLContext(pCrlContext); |
| break; |
| case CERT_STORE_ADD_NEW: |
| if (existing) |
| { |
| TRACE("found matching CRL, not adding\n"); |
| SetLastError(CRYPT_E_EXISTS); |
| ret = FALSE; |
| } |
| else |
| toAdd = CertDuplicateCRLContext(pCrlContext); |
| break; |
| case CERT_STORE_ADD_NEWER: |
| if (existing) |
| { |
| LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate, |
| &pCrlContext->pCrlInfo->ThisUpdate); |
| |
| if (newer < 0) |
| toAdd = CertDuplicateCRLContext(pCrlContext); |
| else |
| { |
| TRACE("existing CRL is newer, not adding\n"); |
| SetLastError(CRYPT_E_EXISTS); |
| ret = FALSE; |
| } |
| } |
| else |
| toAdd = CertDuplicateCRLContext(pCrlContext); |
| break; |
| case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES: |
| if (existing) |
| { |
| LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate, |
| &pCrlContext->pCrlInfo->ThisUpdate); |
| |
| if (newer < 0) |
| { |
| toAdd = CertDuplicateCRLContext(pCrlContext); |
| CrlContext_CopyProperties(toAdd, existing); |
| } |
| else |
| { |
| TRACE("existing CRL is newer, not adding\n"); |
| SetLastError(CRYPT_E_EXISTS); |
| ret = FALSE; |
| } |
| } |
| else |
| toAdd = CertDuplicateCRLContext(pCrlContext); |
| break; |
| case CERT_STORE_ADD_REPLACE_EXISTING: |
| toAdd = CertDuplicateCRLContext(pCrlContext); |
| break; |
| case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: |
| toAdd = CertDuplicateCRLContext(pCrlContext); |
| if (existing) |
| CrlContext_CopyProperties(toAdd, existing); |
| break; |
| case CERT_STORE_ADD_USE_EXISTING: |
| if (existing) |
| { |
| CrlContext_CopyProperties(existing, pCrlContext); |
| if (ppStoreContext) |
| *ppStoreContext = CertDuplicateCRLContext(existing); |
| } |
| else |
| toAdd = CertDuplicateCRLContext(pCrlContext); |
| break; |
| default: |
| FIXME("Unimplemented add disposition %d\n", dwAddDisposition); |
| ret = FALSE; |
| } |
| |
| if (toAdd) |
| { |
| if (store) |
| ret = store->crls.addContext(store, (void *)toAdd, |
| (void *)existing, (const void **)ppStoreContext); |
| else if (ppStoreContext) |
| *ppStoreContext = CertDuplicateCRLContext(toAdd); |
| CertFreeCRLContext(toAdd); |
| } |
| CertFreeCRLContext(existing); |
| |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext) |
| { |
| BOOL ret; |
| |
| TRACE("(%p)\n", pCrlContext); |
| |
| if (!pCrlContext) |
| ret = TRUE; |
| else if (!pCrlContext->hCertStore) |
| ret = CertFreeCRLContext(pCrlContext); |
| else |
| { |
| PWINECRYPT_CERTSTORE hcs = pCrlContext->hCertStore; |
| |
| if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) |
| ret = FALSE; |
| else |
| ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext); |
| if (ret) |
| ret = CertFreeCRLContext(pCrlContext); |
| } |
| return ret; |
| } |
| |
| PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore, |
| PCCRL_CONTEXT pPrev) |
| { |
| WINECRYPT_CERTSTORE *hcs = hCertStore; |
| PCCRL_CONTEXT ret; |
| |
| TRACE("(%p, %p)\n", hCertStore, pPrev); |
| if (!hCertStore) |
| ret = NULL; |
| else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) |
| ret = NULL; |
| else |
| ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev); |
| return ret; |
| } |
| |
| HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore) |
| { |
| WINECRYPT_CERTSTORE *hcs = hCertStore; |
| |
| TRACE("(%p)\n", hCertStore); |
| |
| if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC) |
| InterlockedIncrement(&hcs->ref); |
| return hCertStore; |
| } |
| |
| BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) |
| { |
| WINECRYPT_CERTSTORE *hcs = hCertStore; |
| |
| TRACE("(%p, %08x)\n", hCertStore, dwFlags); |
| |
| if( ! hCertStore ) |
| return TRUE; |
| |
| if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC ) |
| return FALSE; |
| |
| if (hcs->ref <= 0) |
| ERR("%p's ref count is %d\n", hcs, hcs->ref); |
| if (InterlockedDecrement(&hcs->ref) == 0) |
| { |
| TRACE("%p's ref count is 0, freeing\n", hcs); |
| hcs->dwMagic = 0; |
| hcs->closeStore(hcs, dwFlags); |
| } |
| else |
| TRACE("%p's ref count is %d\n", hcs, hcs->ref); |
| return TRUE; |
| } |
| |
| BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags, |
| DWORD dwCtrlType, void const *pvCtrlPara) |
| { |
| WINECRYPT_CERTSTORE *hcs = hCertStore; |
| BOOL ret; |
| |
| TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, |
| pvCtrlPara); |
| |
| if (!hcs) |
| ret = FALSE; |
| else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) |
| ret = FALSE; |
| else |
| { |
| if (hcs->control) |
| ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara); |
| else |
| ret = TRUE; |
| } |
| return ret; |
| } |
| |
| BOOL WINAPI CertGetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId, |
| void *pvData, DWORD *pcbData) |
| { |
| PWINECRYPT_CERTSTORE store = hCertStore; |
| BOOL ret = FALSE; |
| |
| TRACE("(%p, %d, %p, %p)\n", hCertStore, dwPropId, pvData, pcbData); |
| |
| switch (dwPropId) |
| { |
| case CERT_ACCESS_STATE_PROP_ID: |
| if (!pvData) |
| { |
| *pcbData = sizeof(DWORD); |
| ret = TRUE; |
| } |
| else if (*pcbData < sizeof(DWORD)) |
| { |
| SetLastError(ERROR_MORE_DATA); |
| *pcbData = sizeof(DWORD); |
| } |
| else |
| { |
| DWORD state = 0; |
| |
| if (store->type != StoreTypeMem && |
| !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG)) |
| state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG; |
| *(DWORD *)pvData = state; |
| ret = TRUE; |
| } |
| break; |
| default: |
| if (store->properties) |
| { |
| CRYPT_DATA_BLOB blob; |
| |
| ret = ContextPropertyList_FindProperty(store->properties, dwPropId, |
| &blob); |
| if (ret) |
| { |
| if (!pvData) |
| *pcbData = blob.cbData; |
| else if (*pcbData < blob.cbData) |
| { |
| SetLastError(ERROR_MORE_DATA); |
| *pcbData = blob.cbData; |
| ret = FALSE; |
| } |
| else |
| { |
| memcpy(pvData, blob.pbData, blob.cbData); |
| *pcbData = blob.cbData; |
| } |
| } |
| else |
| SetLastError(CRYPT_E_NOT_FOUND); |
| } |
| else |
| SetLastError(CRYPT_E_NOT_FOUND); |
| } |
| return ret; |
| } |
| |
| BOOL WINAPI CertSetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId, |
| DWORD dwFlags, const void *pvData) |
| { |
| PWINECRYPT_CERTSTORE store = hCertStore; |
| BOOL ret = FALSE; |
| |
| TRACE("(%p, %d, %08x, %p)\n", hCertStore, dwPropId, dwFlags, pvData); |
| |
| if (!store->properties) |
| store->properties = ContextPropertyList_Create(); |
| switch (dwPropId) |
| { |
| case CERT_ACCESS_STATE_PROP_ID: |
| SetLastError(E_INVALIDARG); |
| break; |
| default: |
| if (pvData) |
| { |
| const CRYPT_DATA_BLOB *blob = pvData; |
| |
| ret = ContextPropertyList_SetProperty(store->properties, dwPropId, |
| blob->pbData, blob->cbData); |
| } |
| else |
| { |
| ContextPropertyList_RemoveProperty(store->properties, dwPropId); |
| ret = TRUE; |
| } |
| } |
| return ret; |
| } |
| |
| static LONG CRYPT_OpenParentStore(DWORD dwFlags, |
| void *pvSystemStoreLocationPara, HKEY *key) |
| { |
| HKEY root; |
| LPCWSTR base; |
| |
| TRACE("(%08x, %p)\n", dwFlags, pvSystemStoreLocationPara); |
| |
| switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) |
| { |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE: |
| root = HKEY_LOCAL_MACHINE; |
| base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; |
| break; |
| case CERT_SYSTEM_STORE_CURRENT_USER: |
| root = HKEY_CURRENT_USER; |
| base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; |
| break; |
| case CERT_SYSTEM_STORE_CURRENT_SERVICE: |
| /* hklm\Software\Microsoft\Cryptography\Services\servicename\ |
| * SystemCertificates |
| */ |
| FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE\n"); |
| return ERROR_FILE_NOT_FOUND; |
| case CERT_SYSTEM_STORE_SERVICES: |
| /* hklm\Software\Microsoft\Cryptography\Services\servicename\ |
| * SystemCertificates |
| */ |
| FIXME("CERT_SYSTEM_STORE_SERVICES\n"); |
| return ERROR_FILE_NOT_FOUND; |
| case CERT_SYSTEM_STORE_USERS: |
| /* hku\user sid\Software\Microsoft\SystemCertificates */ |
| FIXME("CERT_SYSTEM_STORE_USERS\n"); |
| return ERROR_FILE_NOT_FOUND; |
| case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY: |
| root = HKEY_CURRENT_USER; |
| base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; |
| break; |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY: |
| root = HKEY_LOCAL_MACHINE; |
| base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; |
| break; |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE: |
| /* hklm\Software\Microsoft\EnterpriseCertificates */ |
| FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE\n"); |
| return ERROR_FILE_NOT_FOUND; |
| default: |
| return ERROR_FILE_NOT_FOUND; |
| } |
| |
| return RegOpenKeyExW(root, base, 0, KEY_READ, key); |
| } |
| |
| BOOL WINAPI CertEnumSystemStore(DWORD dwFlags, void *pvSystemStoreLocationPara, |
| void *pvArg, PFN_CERT_ENUM_SYSTEM_STORE pfnEnum) |
| { |
| BOOL ret = FALSE; |
| LONG rc; |
| HKEY key; |
| CERT_SYSTEM_STORE_INFO info = { sizeof(info) }; |
| |
| TRACE("(%08x, %p, %p, %p)\n", dwFlags, pvSystemStoreLocationPara, pvArg, |
| pfnEnum); |
| |
| rc = CRYPT_OpenParentStore(dwFlags, pvArg, &key); |
| if (!rc) |
| { |
| DWORD index = 0; |
| |
| ret = TRUE; |
| do { |
| WCHAR name[MAX_PATH]; |
| DWORD size = sizeof(name) / sizeof(name[0]); |
| |
| rc = RegEnumKeyExW(key, index++, name, &size, NULL, NULL, NULL, |
| NULL); |
| if (!rc) |
| ret = pfnEnum(name, dwFlags, &info, NULL, pvArg); |
| } while (ret && !rc); |
| if (ret && rc != ERROR_NO_MORE_ITEMS) |
| SetLastError(rc); |
| } |
| else |
| SetLastError(rc); |
| /* Include root store for the local machine location (it isn't in the |
| * registry) |
| */ |
| if (ret && (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) == |
| CERT_SYSTEM_STORE_LOCAL_MACHINE) |
| ret = pfnEnum(rootW, dwFlags, &info, NULL, pvArg); |
| return ret; |
| } |
| |
| BOOL WINAPI CertEnumPhysicalStore(const void *pvSystemStore, DWORD dwFlags, |
| void *pvArg, PFN_CERT_ENUM_PHYSICAL_STORE pfnEnum) |
| { |
| if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) |
| FIXME("(%p, %08x, %p, %p): stub\n", pvSystemStore, dwFlags, pvArg, |
| pfnEnum); |
| else |
| FIXME("(%s, %08x, %p, %p): stub\n", debugstr_w(pvSystemStore), |
| dwFlags, pvArg, |
| pfnEnum); |
| return FALSE; |
| } |