|  | /* | 
|  | * 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_SerializedOpenStore(HCRYPTPROV hCryptProv, | 
|  | DWORD dwFlags, const void *pvPara) | 
|  | { | 
|  | HCERTSTORE store; | 
|  | const CRYPT_DATA_BLOB *data = pvPara; | 
|  |  | 
|  | TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); | 
|  |  | 
|  | if (dwFlags & CERT_STORE_DELETE_FLAG) | 
|  | { | 
|  | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, | 
|  | CERT_STORE_CREATE_NEW_FLAG, NULL); | 
|  | if (store) | 
|  | { | 
|  | if (!CRYPT_ReadSerializedStoreFromBlob(data, store)) | 
|  | { | 
|  | CertCloseStore(store, 0); | 
|  | store = NULL; | 
|  | } | 
|  | } | 
|  | TRACE("returning %p\n", store); | 
|  | return (PWINECRYPT_CERTSTORE)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_SERIALIZED): | 
|  | openFunc = CRYPT_SerializedOpenStore; | 
|  | 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_PKCS7)) | 
|  | openFunc = CRYPT_PKCSOpenStore; | 
|  | else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SERIALIZED)) | 
|  | openFunc = CRYPT_SerializedOpenStore; | 
|  | 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; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI CertRegisterPhysicalStore(const void *pvSystemStore, DWORD dwFlags, | 
|  | LPCWSTR pwszStoreName, PCERT_PHYSICAL_STORE_INFO pStoreInfo, void *pvReserved) | 
|  | { | 
|  | if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) | 
|  | FIXME("(%p, %08x, %s, %p, %p): stub\n", pvSystemStore, dwFlags, | 
|  | debugstr_w(pwszStoreName), pStoreInfo, pvReserved); | 
|  | else | 
|  | FIXME("(%s, %08x, %s, %p, %p): stub\n", debugstr_w(pvSystemStore), | 
|  | dwFlags, debugstr_w(pwszStoreName), pStoreInfo, pvReserved); | 
|  | return FALSE; | 
|  | } |