/* * Copyright 2004-2007 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 */ #include #include #include "windef.h" #include "winbase.h" #include "wincrypt.h" #include "wine/debug.h" #include "crypt32_private.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); typedef struct _WINE_PROVIDERSTORE { WINECRYPT_CERTSTORE hdr; DWORD dwStoreProvFlags; WINECRYPT_CERTSTORE *memStore; HCERTSTOREPROV hStoreProv; PFN_CERT_STORE_PROV_CLOSE provCloseStore; PFN_CERT_STORE_PROV_WRITE_CERT provWriteCert; PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert; PFN_CERT_STORE_PROV_WRITE_CRL provWriteCrl; PFN_CERT_STORE_PROV_DELETE_CRL provDeleteCrl; PFN_CERT_STORE_PROV_WRITE_CTL provWriteCtl; PFN_CERT_STORE_PROV_DELETE_CTL provDeleteCtl; PFN_CERT_STORE_PROV_CONTROL provControl; } WINE_PROVIDERSTORE; static void ProvStore_addref(WINECRYPT_CERTSTORE *store) { LONG ref = InterlockedIncrement(&store->ref); TRACE("ref = %d\n", ref); } static DWORD ProvStore_release(WINECRYPT_CERTSTORE *cert_store, DWORD flags) { WINE_PROVIDERSTORE *store = (WINE_PROVIDERSTORE*)cert_store; LONG ref; if(flags) FIXME("Unimplemented flags %x\n", flags); ref = InterlockedDecrement(&store->hdr.ref); TRACE("(%p) ref=%d\n", store, ref); if(ref) return ERROR_SUCCESS; if (store->provCloseStore) store->provCloseStore(store->hStoreProv, flags); if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)) store->memStore->vtbl->release(store->memStore, flags); CRYPT_FreeStore(&store->hdr); return ERROR_SUCCESS; } static void ProvStore_releaseContext(WINECRYPT_CERTSTORE *store, context_t *context) { /* As long as we don't have contexts properly stored (and hack around hCertStore in add* and enum* functions), this function should never be called. */ assert(0); } static BOOL ProvStore_addCert(WINECRYPT_CERTSTORE *store, context_t *cert, context_t *toReplace, context_t **ppStoreContext, BOOL use_link) { WINE_PROVIDERSTORE *ps = (WINE_PROVIDERSTORE*)store; BOOL ret; TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext); if (toReplace) ret = ps->memStore->vtbl->certs.addContext(ps->memStore, cert, toReplace, ppStoreContext, TRUE); else { ret = TRUE; if (ps->provWriteCert) ret = ps->provWriteCert(ps->hStoreProv, context_ptr(cert), CERT_STORE_PROV_WRITE_ADD_FLAG); if (ret) ret = ps->memStore->vtbl->certs.addContext(ps->memStore, cert, NULL, ppStoreContext, TRUE); } /* dirty trick: replace the returned context's hCertStore with * store. */ if (ret && ppStoreContext) (*(cert_t**)ppStoreContext)->ctx.hCertStore = store; return ret; } static context_t *ProvStore_enumCert(WINECRYPT_CERTSTORE *store, context_t *prev) { WINE_PROVIDERSTORE *ps = (WINE_PROVIDERSTORE*)store; cert_t *ret; ret = (cert_t*)ps->memStore->vtbl->certs.enumContext(ps->memStore, prev); if (!ret) return NULL; /* same dirty trick: replace the returned context's hCertStore with * store. */ ret->ctx.hCertStore = store; return &ret->base; } static BOOL ProvStore_deleteCert(WINECRYPT_CERTSTORE *store, context_t *context) { WINE_PROVIDERSTORE *ps = (WINE_PROVIDERSTORE*)store; BOOL ret = TRUE; TRACE("(%p, %p)\n", store, context); if (ps->provDeleteCert) ret = ps->provDeleteCert(ps->hStoreProv, context_ptr(context), 0); if (ret) ret = ps->memStore->vtbl->certs.delete(ps->memStore, context); return ret; } static BOOL ProvStore_addCRL(WINECRYPT_CERTSTORE *store, context_t *crl, context_t *toReplace, context_t **ppStoreContext, BOOL use_link) { WINE_PROVIDERSTORE *ps = (WINE_PROVIDERSTORE*)store; BOOL ret; TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext); if (toReplace) ret = ps->memStore->vtbl->crls.addContext(ps->memStore, crl, toReplace, ppStoreContext, TRUE); else { if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) { SetLastError(ERROR_ACCESS_DENIED); ret = FALSE; } else { ret = TRUE; if (ps->provWriteCrl) ret = ps->provWriteCrl(ps->hStoreProv, context_ptr(crl), CERT_STORE_PROV_WRITE_ADD_FLAG); if (ret) ret = ps->memStore->vtbl->crls.addContext(ps->memStore, crl, NULL, ppStoreContext, TRUE); } } /* dirty trick: replace the returned context's hCertStore with * store. */ if (ret && ppStoreContext) (*(crl_t**)ppStoreContext)->ctx.hCertStore = store; return ret; } static context_t *ProvStore_enumCRL(WINECRYPT_CERTSTORE *store, context_t *prev) { WINE_PROVIDERSTORE *ps = (WINE_PROVIDERSTORE*)store; crl_t *ret; ret = (crl_t*)ps->memStore->vtbl->crls.enumContext(ps->memStore, prev); if (!ret) return NULL; /* same dirty trick: replace the returned context's hCertStore with * store. */ ret->ctx.hCertStore = store; return &ret->base; } static BOOL ProvStore_deleteCRL(WINECRYPT_CERTSTORE *store, context_t *crl) { WINE_PROVIDERSTORE *ps = (WINE_PROVIDERSTORE*)store; BOOL ret = TRUE; TRACE("(%p, %p)\n", store, crl); if (ps->provDeleteCrl) ret = ps->provDeleteCrl(ps->hStoreProv, context_ptr(crl), 0); if (ret) ret = ps->memStore->vtbl->crls.delete(ps->memStore, crl); return ret; } static BOOL ProvStore_addCTL(WINECRYPT_CERTSTORE *store, context_t *ctl, context_t *toReplace, context_t **ppStoreContext, BOOL use_link) { WINE_PROVIDERSTORE *ps = (WINE_PROVIDERSTORE*)store; BOOL ret; TRACE("(%p, %p, %p, %p)\n", store, ctl, toReplace, ppStoreContext); if (toReplace) ret = ps->memStore->vtbl->ctls.addContext(ps->memStore, ctl, toReplace, ppStoreContext, TRUE); else { if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) { SetLastError(ERROR_ACCESS_DENIED); ret = FALSE; } else { ret = TRUE; if (ps->provWriteCtl) ret = ps->provWriteCtl(ps->hStoreProv, context_ptr(ctl), CERT_STORE_PROV_WRITE_ADD_FLAG); if (ret) ret = ps->memStore->vtbl->ctls.addContext(ps->memStore, ctl, NULL, ppStoreContext, TRUE); } } /* dirty trick: replace the returned context's hCertStore with * store. */ if (ret && ppStoreContext) (*(ctl_t**)ppStoreContext)->ctx.hCertStore = store; return ret; } static context_t *ProvStore_enumCTL(WINECRYPT_CERTSTORE *store, context_t *prev) { WINE_PROVIDERSTORE *ps = (WINE_PROVIDERSTORE*)store; ctl_t *ret; ret = (ctl_t*)ps->memStore->vtbl->ctls.enumContext(ps->memStore, prev); if (!ret) return NULL; /* same dirty trick: replace the returned context's hCertStore with * store. */ ret->ctx.hCertStore = store; return &ret->base; } static BOOL ProvStore_deleteCTL(WINECRYPT_CERTSTORE *store, context_t *ctl) { WINE_PROVIDERSTORE *ps = (WINE_PROVIDERSTORE*)store; BOOL ret = TRUE; TRACE("(%p, %p)\n", store, ctl); if (ps->provDeleteCtl) ret = ps->provDeleteCtl(ps->hStoreProv, context_ptr(ctl), 0); if (ret) ret = ps->memStore->vtbl->ctls.delete(ps->memStore, ctl); return ret; } static BOOL ProvStore_control(WINECRYPT_CERTSTORE *cert_store, DWORD dwFlags, DWORD dwCtrlType, void const *pvCtrlPara) { WINE_PROVIDERSTORE *store = (WINE_PROVIDERSTORE*)cert_store; BOOL ret = TRUE; TRACE("(%p, %08x, %d, %p)\n", store, dwFlags, dwCtrlType, pvCtrlPara); if (store->provControl) ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType, pvCtrlPara); return ret; } static const store_vtbl_t ProvStoreVtbl = { ProvStore_addref, ProvStore_release, ProvStore_releaseContext, ProvStore_control, { ProvStore_addCert, ProvStore_enumCert, ProvStore_deleteCert }, { ProvStore_addCRL, ProvStore_enumCRL, ProvStore_deleteCRL }, { ProvStore_addCTL, ProvStore_enumCTL, ProvStore_deleteCTL } }; WINECRYPT_CERTSTORE *CRYPT_ProvCreateStore(DWORD dwFlags, WINECRYPT_CERTSTORE *memStore, const CERT_STORE_PROV_INFO *pProvInfo) { WINE_PROVIDERSTORE *ret = CryptMemAlloc(sizeof(WINE_PROVIDERSTORE)); if (ret) { CRYPT_InitStore(&ret->hdr, dwFlags, StoreTypeProvider, &ProvStoreVtbl); ret->dwStoreProvFlags = pProvInfo->dwStoreProvFlags; if (ret->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG) { CertCloseStore(memStore, 0); ret->memStore = NULL; } else ret->memStore = memStore; ret->hStoreProv = pProvInfo->hStoreProv; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC) ret->provCloseStore = pProvInfo->rgpvStoreProvFunc[CERT_STORE_PROV_CLOSE_FUNC]; else ret->provCloseStore = NULL; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_WRITE_CERT_FUNC) ret->provWriteCert = pProvInfo->rgpvStoreProvFunc[ CERT_STORE_PROV_WRITE_CERT_FUNC]; else ret->provWriteCert = NULL; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_DELETE_CERT_FUNC) ret->provDeleteCert = pProvInfo->rgpvStoreProvFunc[ CERT_STORE_PROV_DELETE_CERT_FUNC]; else ret->provDeleteCert = NULL; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_WRITE_CRL_FUNC) ret->provWriteCrl = pProvInfo->rgpvStoreProvFunc[ CERT_STORE_PROV_WRITE_CRL_FUNC]; else ret->provWriteCrl = NULL; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_DELETE_CRL_FUNC) ret->provDeleteCrl = pProvInfo->rgpvStoreProvFunc[ CERT_STORE_PROV_DELETE_CRL_FUNC]; else ret->provDeleteCrl = NULL; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_WRITE_CTL_FUNC) ret->provWriteCtl = pProvInfo->rgpvStoreProvFunc[ CERT_STORE_PROV_WRITE_CTL_FUNC]; else ret->provWriteCtl = NULL; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_DELETE_CTL_FUNC) ret->provDeleteCtl = pProvInfo->rgpvStoreProvFunc[ CERT_STORE_PROV_DELETE_CTL_FUNC]; else ret->provDeleteCtl = NULL; if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CONTROL_FUNC) ret->provControl = pProvInfo->rgpvStoreProvFunc[ CERT_STORE_PROV_CONTROL_FUNC]; else ret->provControl = NULL; } return (WINECRYPT_CERTSTORE*)ret; } WINECRYPT_CERTSTORE *CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider, DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara) { static HCRYPTOIDFUNCSET set = NULL; PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc; HCRYPTOIDFUNCADDR hFunc; WINECRYPT_CERTSTORE *ret = NULL; if (!set) set = CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0); CryptGetOIDFunctionAddress(set, dwEncodingType, lpszStoreProvider, 0, (void **)&provOpenFunc, &hFunc); if (provOpenFunc) { CERT_STORE_PROV_INFO provInfo = { 0 }; provInfo.cbSize = sizeof(provInfo); if (dwFlags & CERT_STORE_DELETE_FLAG) provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv, dwFlags, pvPara, NULL, &provInfo); else { HCERTSTORE memStore; memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); if (memStore) { if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv, dwFlags, pvPara, memStore, &provInfo)) ret = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo); else CertCloseStore(memStore, 0); } } CryptFreeOIDFunctionAddress(hFunc, 0); } else SetLastError(ERROR_FILE_NOT_FOUND); return ret; }