| /* | |
| * 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/exception.h" | |
| #include "crypt32_private.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(crypt); | |
| static const WINE_CONTEXT_INTERFACE gCertInterface = { | |
| (CreateContextFunc)CertCreateCertificateContext, | |
| (AddContextToStoreFunc)CertAddCertificateContextToStore, | |
| (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore, | |
| (EnumContextsInStoreFunc)CertEnumCertificatesInStore, | |
| (EnumPropertiesFunc)CertEnumCertificateContextProperties, | |
| (GetContextPropertyFunc)CertGetCertificateContextProperty, | |
| (SetContextPropertyFunc)CertSetCertificateContextProperty, | |
| (SerializeElementFunc)CertSerializeCertificateStoreElement, | |
| (DeleteContextFunc)CertDeleteCertificateFromStore, | |
| }; | |
| const WINE_CONTEXT_INTERFACE *pCertInterface = &gCertInterface; | |
| static const WINE_CONTEXT_INTERFACE gCRLInterface = { | |
| (CreateContextFunc)CertCreateCRLContext, | |
| (AddContextToStoreFunc)CertAddCRLContextToStore, | |
| (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore, | |
| (EnumContextsInStoreFunc)CertEnumCRLsInStore, | |
| (EnumPropertiesFunc)CertEnumCRLContextProperties, | |
| (GetContextPropertyFunc)CertGetCRLContextProperty, | |
| (SetContextPropertyFunc)CertSetCRLContextProperty, | |
| (SerializeElementFunc)CertSerializeCRLStoreElement, | |
| (DeleteContextFunc)CertDeleteCRLFromStore, | |
| }; | |
| const WINE_CONTEXT_INTERFACE *pCRLInterface = &gCRLInterface; | |
| static const WINE_CONTEXT_INTERFACE gCTLInterface = { | |
| (CreateContextFunc)CertCreateCTLContext, | |
| (AddContextToStoreFunc)CertAddCTLContextToStore, | |
| (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore, | |
| (EnumContextsInStoreFunc)CertEnumCTLsInStore, | |
| (EnumPropertiesFunc)CertEnumCTLContextProperties, | |
| (GetContextPropertyFunc)CertGetCTLContextProperty, | |
| (SetContextPropertyFunc)CertSetCTLContextProperty, | |
| (SerializeElementFunc)CertSerializeCTLStoreElement, | |
| (DeleteContextFunc)CertDeleteCTLFromStore, | |
| }; | |
| const WINE_CONTEXT_INTERFACE *pCTLInterface = &gCTLInterface; | |
| typedef struct _WINE_MEMSTORE | |
| { | |
| WINECRYPT_CERTSTORE hdr; | |
| CRITICAL_SECTION cs; | |
| struct list certs; | |
| struct list crls; | |
| struct list ctls; | |
| } WINE_MEMSTORE; | |
| void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, DWORD dwFlags, CertStoreType type, const store_vtbl_t *vtbl) | |
| { | |
| store->ref = 1; | |
| store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC; | |
| store->type = type; | |
| store->dwOpenFlags = dwFlags; | |
| store->vtbl = vtbl; | |
| store->properties = NULL; | |
| } | |
| void CRYPT_FreeStore(WINECRYPT_CERTSTORE *store) | |
| { | |
| if (store->properties) | |
| ContextPropertyList_Free(store->properties); | |
| store->dwMagic = 0; | |
| 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 MemStore_addContext(WINE_MEMSTORE *store, struct list *list, context_t *orig_context, | |
| context_t *existing, context_t **ret_context, BOOL use_link) | |
| { | |
| context_t *context; | |
| context = orig_context->vtbl->clone(orig_context, &store->hdr, use_link); | |
| if (!context) | |
| return FALSE; | |
| TRACE("adding %p\n", context); | |
| EnterCriticalSection(&store->cs); | |
| if (existing) { | |
| context->u.entry.prev = existing->u.entry.prev; | |
| context->u.entry.next = existing->u.entry.next; | |
| context->u.entry.prev->next = &context->u.entry; | |
| context->u.entry.next->prev = &context->u.entry; | |
| list_init(&existing->u.entry); | |
| if(!existing->ref) | |
| Context_Release(existing); | |
| }else { | |
| list_add_head(list, &context->u.entry); | |
| } | |
| LeaveCriticalSection(&store->cs); | |
| if(ret_context) | |
| *ret_context = context; | |
| else | |
| Context_Release(context); | |
| return TRUE; | |
| } | |
| static context_t *MemStore_enumContext(WINE_MEMSTORE *store, struct list *list, context_t *prev) | |
| { | |
| struct list *next; | |
| context_t *ret; | |
| EnterCriticalSection(&store->cs); | |
| if (prev) { | |
| next = list_next(list, &prev->u.entry); | |
| Context_Release(prev); | |
| }else { | |
| next = list_next(list, list); | |
| } | |
| LeaveCriticalSection(&store->cs); | |
| if (!next) { | |
| SetLastError(CRYPT_E_NOT_FOUND); | |
| return NULL; | |
| } | |
| ret = LIST_ENTRY(next, context_t, u.entry); | |
| Context_AddRef(ret); | |
| return ret; | |
| } | |
| static BOOL MemStore_deleteContext(WINE_MEMSTORE *store, context_t *context) | |
| { | |
| BOOL in_list = FALSE; | |
| EnterCriticalSection(&store->cs); | |
| if (!list_empty(&context->u.entry)) { | |
| list_remove(&context->u.entry); | |
| list_init(&context->u.entry); | |
| in_list = TRUE; | |
| } | |
| LeaveCriticalSection(&store->cs); | |
| if(in_list && !context->ref) | |
| Context_Free(context); | |
| return TRUE; | |
| } | |
| static void free_contexts(struct list *list) | |
| { | |
| context_t *context, *next; | |
| LIST_FOR_EACH_ENTRY_SAFE(context, next, list, context_t, u.entry) | |
| { | |
| TRACE("freeing %p\n", context); | |
| list_remove(&context->u.entry); | |
| Context_Free(context); | |
| } | |
| } | |
| static void MemStore_releaseContext(WINECRYPT_CERTSTORE *store, context_t *context) | |
| { | |
| /* Free the context only if it's not in a list. Otherwise it may be reused later. */ | |
| if(list_empty(&context->u.entry)) | |
| Context_Free(context); | |
| } | |
| static BOOL MemStore_addCert(WINECRYPT_CERTSTORE *store, context_t *cert, | |
| context_t *toReplace, context_t **ppStoreContext, BOOL use_link) | |
| { | |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; | |
| TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext); | |
| return MemStore_addContext(ms, &ms->certs, cert, toReplace, ppStoreContext, use_link); | |
| } | |
| static context_t *MemStore_enumCert(WINECRYPT_CERTSTORE *store, context_t *prev) | |
| { | |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; | |
| TRACE("(%p, %p)\n", store, prev); | |
| return MemStore_enumContext(ms, &ms->certs, prev); | |
| } | |
| static BOOL MemStore_deleteCert(WINECRYPT_CERTSTORE *store, context_t *context) | |
| { | |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; | |
| TRACE("(%p, %p)\n", store, context); | |
| return MemStore_deleteContext(ms, context); | |
| } | |
| static BOOL MemStore_addCRL(WINECRYPT_CERTSTORE *store, context_t *crl, | |
| context_t *toReplace, context_t **ppStoreContext, BOOL use_link) | |
| { | |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; | |
| TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext); | |
| return MemStore_addContext(ms, &ms->crls, crl, toReplace, ppStoreContext, use_link); | |
| } | |
| static context_t *MemStore_enumCRL(WINECRYPT_CERTSTORE *store, context_t *prev) | |
| { | |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; | |
| TRACE("(%p, %p)\n", store, prev); | |
| return MemStore_enumContext(ms, &ms->crls, prev); | |
| } | |
| static BOOL MemStore_deleteCRL(WINECRYPT_CERTSTORE *store, context_t *context) | |
| { | |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; | |
| TRACE("(%p, %p)\n", store, context); | |
| return MemStore_deleteContext(ms, context); | |
| } | |
| static BOOL MemStore_addCTL(WINECRYPT_CERTSTORE *store, context_t *ctl, | |
| context_t *toReplace, context_t **ppStoreContext, BOOL use_link) | |
| { | |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; | |
| TRACE("(%p, %p, %p, %p)\n", store, ctl, toReplace, ppStoreContext); | |
| return MemStore_addContext(ms, &ms->ctls, ctl, toReplace, ppStoreContext, use_link); | |
| } | |
| static context_t *MemStore_enumCTL(WINECRYPT_CERTSTORE *store, context_t *prev) | |
| { | |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; | |
| TRACE("(%p, %p)\n", store, prev); | |
| return MemStore_enumContext(ms, &ms->ctls, prev); | |
| } | |
| static BOOL MemStore_deleteCTL(WINECRYPT_CERTSTORE *store, context_t *context) | |
| { | |
| WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; | |
| TRACE("(%p, %p)\n", store, context); | |
| return MemStore_deleteContext(ms, context); | |
| } | |
| static void MemStore_addref(WINECRYPT_CERTSTORE *store) | |
| { | |
| LONG ref = InterlockedIncrement(&store->ref); | |
| TRACE("ref = %d\n", ref); | |
| } | |
| static DWORD MemStore_release(WINECRYPT_CERTSTORE *cert_store, DWORD flags) | |
| { | |
| WINE_MEMSTORE *store = (WINE_MEMSTORE*)cert_store; | |
| LONG ref; | |
| if(flags & ~CERT_CLOSE_STORE_CHECK_FLAG) | |
| FIXME("Unimplemented flags %x\n", flags); | |
| ref = InterlockedDecrement(&store->hdr.ref); | |
| TRACE("(%p) ref=%d\n", store, ref); | |
| if(ref) | |
| return (flags & CERT_CLOSE_STORE_CHECK_FLAG) ? CRYPT_E_PENDING_CLOSE : ERROR_SUCCESS; | |
| free_contexts(&store->certs); | |
| free_contexts(&store->crls); | |
| free_contexts(&store->ctls); | |
| store->cs.DebugInfo->Spare[0] = 0; | |
| DeleteCriticalSection(&store->cs); | |
| CRYPT_FreeStore(&store->hdr); | |
| return ERROR_SUCCESS; | |
| } | |
| static BOOL MemStore_control(WINECRYPT_CERTSTORE *store, DWORD dwFlags, | |
| DWORD dwCtrlType, void const *pvCtrlPara) | |
| { | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return FALSE; | |
| } | |
| static const store_vtbl_t MemStoreVtbl = { | |
| MemStore_addref, | |
| MemStore_release, | |
| MemStore_releaseContext, | |
| MemStore_control, | |
| { | |
| MemStore_addCert, | |
| MemStore_enumCert, | |
| MemStore_deleteCert | |
| }, { | |
| MemStore_addCRL, | |
| MemStore_enumCRL, | |
| MemStore_deleteCRL | |
| }, { | |
| MemStore_addCTL, | |
| MemStore_enumCTL, | |
| MemStore_deleteCTL | |
| } | |
| }; | |
| static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, | |
| DWORD dwFlags, const void *pvPara) | |
| { | |
| WINE_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, &MemStoreVtbl); | |
| InitializeCriticalSection(&store->cs); | |
| store->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ContextList.cs"); | |
| list_init(&store->certs); | |
| list_init(&store->crls); | |
| list_init(&store->ctls); | |
| /* Mem store doesn't need crypto provider, so close it */ | |
| if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) | |
| CryptReleaseContext(hCryptProv, 0); | |
| } | |
| } | |
| return (WINECRYPT_CERTSTORE*)store; | |
| } | |
| static const WCHAR rootW[] = { 'R','o','o','t',0 }; | |
| static WINECRYPT_CERTSTORE *CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv, | |
| DWORD dwFlags, const void *pvPara) | |
| { | |
| static const WCHAR fmt[] = { '%','s','\\','%','s',0 }; | |
| LPCWSTR storeName = pvPara; | |
| LPWSTR storePath; | |
| WINECRYPT_CERTSTORE *store = NULL; | |
| HKEY root; | |
| LPCWSTR base; | |
| TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, | |
| debugstr_w(pvPara)); | |
| if (!pvPara) | |
| { | |
| SetLastError(E_INVALIDARG); | |
| return NULL; | |
| } | |
| switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) | |
| { | |
| case CERT_SYSTEM_STORE_LOCAL_MACHINE: | |
| root = HKEY_LOCAL_MACHINE; | |
| base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; | |
| /* If the HKLM\Root certs are requested, expressing system certs into the registry */ | |
| if (!lstrcmpiW(storeName, rootW)) | |
| CRYPT_ImportSystemRootCertsToReg(); | |
| 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 WINECRYPT_CERTSTORE *CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv, | |
| DWORD dwFlags, const void *pvPara) | |
| { | |
| int len; | |
| WINECRYPT_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 WINECRYPT_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 WINECRYPT_CERTSTORE *CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv, | |
| DWORD dwFlags, const void *pvPara) | |
| { | |
| int len; | |
| WINECRYPT_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 WINECRYPT_CERTSTORE *CRYPT_MsgOpenStore(HCRYPTPROV hCryptProv, | |
| DWORD dwFlags, const void *pvPara) | |
| { | |
| WINECRYPT_CERTSTORE *store = NULL; | |
| HCRYPTMSG msg = (HCRYPTMSG)pvPara; | |
| WINECRYPT_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 WINECRYPT_CERTSTORE *CRYPT_PKCSOpenStore(HCRYPTPROV hCryptProv, | |
| DWORD dwFlags, const void *pvPara) | |
| { | |
| HCRYPTMSG msg; | |
| WINECRYPT_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 WINECRYPT_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 (WINECRYPT_CERTSTORE*)store; | |
| } | |
| static WINECRYPT_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); | |
| } | |
| PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrev) | |
| { | |
| cert_t *prev = pPrev ? cert_from_ptr(pPrev) : NULL, *ret; | |
| WINECRYPT_CERTSTORE *hcs = hCertStore; | |
| TRACE("(%p, %p)\n", hCertStore, pPrev); | |
| if (!hCertStore) | |
| ret = NULL; | |
| else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) | |
| ret = NULL; | |
| else | |
| ret = (cert_t*)hcs->vtbl->certs.enumContext(hcs, prev ? &prev->base : NULL); | |
| return ret ? &ret->ctx : NULL; | |
| } | |
| BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext) | |
| { | |
| WINECRYPT_CERTSTORE *hcs; | |
| TRACE("(%p)\n", pCertContext); | |
| if (!pCertContext) | |
| return TRUE; | |
| hcs = pCertContext->hCertStore; | |
| if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) | |
| return FALSE; | |
| return hcs->vtbl->certs.delete(hcs, &cert_from_ptr(pCertContext)->base); | |
| } | |
| BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore, | |
| PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition, | |
| PCCRL_CONTEXT* ppStoreContext) | |
| { | |
| WINECRYPT_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); | |
| Context_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) | |
| Context_CopyProperties(toAdd, existing); | |
| break; | |
| case CERT_STORE_ADD_USE_EXISTING: | |
| if (existing) | |
| { | |
| Context_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) { | |
| context_t *ret_context; | |
| ret = store->vtbl->crls.addContext(store, context_from_ptr(toAdd), | |
| existing ? context_from_ptr(existing) : NULL, ppStoreContext ? &ret_context : NULL, FALSE); | |
| if (ret && ppStoreContext) | |
| *ppStoreContext = context_ptr(ret_context); | |
| }else if (ppStoreContext) { | |
| *ppStoreContext = CertDuplicateCRLContext(toAdd); | |
| } | |
| CertFreeCRLContext(toAdd); | |
| } | |
| if (existing) | |
| CertFreeCRLContext(existing); | |
| TRACE("returning %d\n", ret); | |
| return ret; | |
| } | |
| BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext) | |
| { | |
| WINECRYPT_CERTSTORE *hcs; | |
| BOOL ret; | |
| TRACE("(%p)\n", pCrlContext); | |
| if (!pCrlContext) | |
| return TRUE; | |
| hcs = pCrlContext->hCertStore; | |
| if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) | |
| return FALSE; | |
| ret = hcs->vtbl->crls.delete(hcs, &crl_from_ptr(pCrlContext)->base); | |
| if (ret) | |
| ret = CertFreeCRLContext(pCrlContext); | |
| return ret; | |
| } | |
| PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore, PCCRL_CONTEXT pPrev) | |
| { | |
| crl_t *ret, *prev = pPrev ? crl_from_ptr(pPrev) : NULL; | |
| WINECRYPT_CERTSTORE *hcs = hCertStore; | |
| TRACE("(%p, %p)\n", hCertStore, pPrev); | |
| if (!hCertStore) | |
| ret = NULL; | |
| else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) | |
| ret = NULL; | |
| else | |
| ret = (crl_t*)hcs->vtbl->crls.enumContext(hcs, prev ? &prev->base : NULL); | |
| return ret ? &ret->ctx : NULL; | |
| } | |
| HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore) | |
| { | |
| WINECRYPT_CERTSTORE *hcs = hCertStore; | |
| TRACE("(%p)\n", hCertStore); | |
| if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC) | |
| hcs->vtbl->addref(hcs); | |
| return hCertStore; | |
| } | |
| BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) | |
| { | |
| WINECRYPT_CERTSTORE *hcs = hCertStore; | |
| DWORD res; | |
| TRACE("(%p, %08x)\n", hCertStore, dwFlags); | |
| if( ! hCertStore ) | |
| return TRUE; | |
| if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC ) | |
| return FALSE; | |
| res = hcs->vtbl->release(hcs, dwFlags); | |
| if (res != ERROR_SUCCESS) { | |
| SetLastError(res); | |
| return FALSE; | |
| } | |
| 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->vtbl->control) | |
| ret = hcs->vtbl->control(hcs, dwFlags, dwCtrlType, pvCtrlPara); | |
| else | |
| ret = TRUE; | |
| } | |
| return ret; | |
| } | |
| BOOL WINAPI CertGetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId, | |
| void *pvData, DWORD *pcbData) | |
| { | |
| WINECRYPT_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) | |
| { | |
| WINECRYPT_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; | |
| } | |
| BOOL WINAPI CertRegisterSystemStore(const void *pvSystemStore, DWORD dwFlags, | |
| PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved) | |
| { | |
| HCERTSTORE hstore; | |
| if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG ) | |
| { | |
| FIXME("(%p, %08x, %p, %p): flag not supported\n", pvSystemStore, dwFlags, pStoreInfo, pvReserved); | |
| return FALSE; | |
| } | |
| TRACE("(%s, %08x, %p, %p)\n", debugstr_w(pvSystemStore), dwFlags, pStoreInfo, pvReserved); | |
| hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, 0, dwFlags, pvSystemStore); | |
| if (hstore) | |
| { | |
| CertCloseStore(hstore, 0); | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| BOOL WINAPI CertUnregisterSystemStore(void *pvSystemStore, DWORD dwFlags) | |
| { | |
| HCERTSTORE hstore; | |
| if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) | |
| { | |
| FIXME("(%p, %08x): flag not supported\n", pvSystemStore, dwFlags); | |
| return FALSE; | |
| } | |
| TRACE("(%s, %08x)\n", debugstr_w(pvSystemStore), dwFlags); | |
| hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, 0, dwFlags | CERT_STORE_OPEN_EXISTING_FLAG, pvSystemStore); | |
| if (hstore == NULL) | |
| return FALSE; | |
| hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, 0, dwFlags | CERT_STORE_DELETE_FLAG, pvSystemStore); | |
| if (hstore == NULL && GetLastError() == 0) | |
| return TRUE; | |
| return FALSE; | |
| } | |
| static void EmptyStore_addref(WINECRYPT_CERTSTORE *store) | |
| { | |
| TRACE("(%p)\n", store); | |
| } | |
| static DWORD EmptyStore_release(WINECRYPT_CERTSTORE *store, DWORD flags) | |
| { | |
| TRACE("(%p)\n", store); | |
| return E_UNEXPECTED; | |
| } | |
| static void EmptyStore_releaseContext(WINECRYPT_CERTSTORE *store, context_t *context) | |
| { | |
| Context_Free(context); | |
| } | |
| static BOOL EmptyStore_add(WINECRYPT_CERTSTORE *store, context_t *context, | |
| context_t *replace, context_t **ret_context, BOOL use_link) | |
| { | |
| TRACE("(%p, %p, %p, %p)\n", store, context, replace, ret_context); | |
| /* FIXME: We should clone the context */ | |
| if(ret_context) { | |
| Context_AddRef(context); | |
| *ret_context = context; | |
| } | |
| return TRUE; | |
| } | |
| static context_t *EmptyStore_enum(WINECRYPT_CERTSTORE *store, context_t *prev) | |
| { | |
| TRACE("(%p, %p)\n", store, prev); | |
| SetLastError(CRYPT_E_NOT_FOUND); | |
| return NULL; | |
| } | |
| static BOOL EmptyStore_delete(WINECRYPT_CERTSTORE *store, context_t *context) | |
| { | |
| return TRUE; | |
| } | |
| static BOOL EmptyStore_control(WINECRYPT_CERTSTORE *store, DWORD flags, DWORD ctrl_type, void const *ctrl_para) | |
| { | |
| TRACE("()\n"); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return FALSE; | |
| } | |
| static const store_vtbl_t EmptyStoreVtbl = { | |
| EmptyStore_addref, | |
| EmptyStore_release, | |
| EmptyStore_releaseContext, | |
| EmptyStore_control, | |
| { | |
| EmptyStore_add, | |
| EmptyStore_enum, | |
| EmptyStore_delete | |
| }, { | |
| EmptyStore_add, | |
| EmptyStore_enum, | |
| EmptyStore_delete | |
| }, { | |
| EmptyStore_add, | |
| EmptyStore_enum, | |
| EmptyStore_delete | |
| } | |
| }; | |
| WINECRYPT_CERTSTORE empty_store; | |
| void init_empty_store(void) | |
| { | |
| CRYPT_InitStore(&empty_store, CERT_STORE_READONLY_FLAG, StoreTypeEmpty, &EmptyStoreVtbl); | |
| } |