/* * 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 #include #include "windef.h" #include "winbase.h" #include "winnls.h" #include "winreg.h" #include "winternl.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 < ARRAY_SIZE(interfaces); 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 = ARRAY_SIZE(msgProvFuncs); 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 (!_strnicmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY, -1)) openFunc = CRYPT_MemOpenStore; else if (!_strnicmp(lpszStoreProvider, sz_CERT_STORE_PROV_FILENAME_W, -1)) openFunc = CRYPT_FileOpenStore; else if (!_strnicmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM, -1)) openFunc = CRYPT_SysOpenStoreW; else if (!_strnicmp(lpszStoreProvider, sz_CERT_STORE_PROV_PKCS7, -1)) openFunc = CRYPT_PKCSOpenStore; else if (!_strnicmp(lpszStoreProvider, sz_CERT_STORE_PROV_SERIALIZED, -1)) openFunc = CRYPT_SerializedOpenStore; else if (!_strnicmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION, -1)) openFunc = CRYPT_CollectionOpenStore; else if (!_strnicmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY, -1)) 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 = ARRAY_SIZE(name); 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 CertUnregisterPhysicalStore(const void *pvSystemStore, DWORD dwFlags, LPCWSTR pwszStoreName) { FIXME("(%p, %08x, %s): stub\n", pvSystemStore, dwFlags, debugstr_w(pwszStoreName)); return TRUE; } 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(const 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); }