| /* |
| * 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 <stdarg.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wincrypt.h" |
| #include "wine/debug.h" |
| #include "wine/list.h" |
| #include "crypt32_private.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(crypt); |
| |
| typedef struct _WINE_PROVIDERSTORE |
| { |
| WINECRYPT_CERTSTORE hdr; |
| DWORD dwStoreProvFlags; |
| PWINECRYPT_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, *PWINE_PROVIDERSTORE; |
| |
| static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) |
| { |
| PWINE_PROVIDERSTORE store = hCertStore; |
| |
| TRACE("(%p, %08x)\n", store, dwFlags); |
| |
| if (store->provCloseStore) |
| store->provCloseStore(store->hStoreProv, dwFlags); |
| if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)) |
| CertCloseStore(store->memStore, dwFlags); |
| CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store); |
| } |
| |
| static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, void *cert, |
| void *toReplace, const void **ppStoreContext) |
| { |
| PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; |
| BOOL ret; |
| |
| TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext); |
| |
| if (toReplace) |
| ret = ps->memStore->certs.addContext(ps->memStore, cert, toReplace, |
| ppStoreContext); |
| else |
| { |
| ret = TRUE; |
| if (ps->provWriteCert) |
| ret = ps->provWriteCert(ps->hStoreProv, cert, |
| CERT_STORE_PROV_WRITE_ADD_FLAG); |
| if (ret) |
| ret = ps->memStore->certs.addContext(ps->memStore, cert, NULL, |
| ppStoreContext); |
| } |
| /* dirty trick: replace the returned context's hCertStore with |
| * store. |
| */ |
| if (ret && ppStoreContext) |
| (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store; |
| return ret; |
| } |
| |
| static void *CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) |
| { |
| PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; |
| void *ret; |
| |
| ret = ps->memStore->certs.enumContext(ps->memStore, pPrev); |
| if (ret) |
| { |
| /* same dirty trick: replace the returned context's hCertStore with |
| * store. |
| */ |
| ((PCERT_CONTEXT)ret)->hCertStore = store; |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_ProvDeleteCert(PWINECRYPT_CERTSTORE store, void *cert) |
| { |
| PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; |
| BOOL ret = TRUE; |
| |
| TRACE("(%p, %p)\n", store, cert); |
| |
| if (ps->provDeleteCert) |
| ret = ps->provDeleteCert(ps->hStoreProv, cert, 0); |
| if (ret) |
| ret = ps->memStore->certs.deleteContext(ps->memStore, cert); |
| return ret; |
| } |
| |
| static BOOL CRYPT_ProvAddCRL(PWINECRYPT_CERTSTORE store, void *crl, |
| void *toReplace, const void **ppStoreContext) |
| { |
| PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; |
| BOOL ret; |
| |
| TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext); |
| |
| if (toReplace) |
| ret = ps->memStore->crls.addContext(ps->memStore, crl, toReplace, |
| ppStoreContext); |
| 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, crl, |
| CERT_STORE_PROV_WRITE_ADD_FLAG); |
| if (ret) |
| ret = ps->memStore->crls.addContext(ps->memStore, crl, NULL, |
| ppStoreContext); |
| } |
| } |
| /* dirty trick: replace the returned context's hCertStore with |
| * store. |
| */ |
| if (ret && ppStoreContext) |
| (*(PCRL_CONTEXT *)ppStoreContext)->hCertStore = store; |
| return ret; |
| } |
| |
| static void *CRYPT_ProvEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev) |
| { |
| PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; |
| void *ret; |
| |
| ret = ps->memStore->crls.enumContext(ps->memStore, pPrev); |
| if (ret) |
| { |
| /* same dirty trick: replace the returned context's hCertStore with |
| * store. |
| */ |
| ((PCRL_CONTEXT)ret)->hCertStore = store; |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_ProvDeleteCRL(PWINECRYPT_CERTSTORE store, void *crl) |
| { |
| PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; |
| BOOL ret = TRUE; |
| |
| TRACE("(%p, %p)\n", store, crl); |
| |
| if (ps->provDeleteCrl) |
| ret = ps->provDeleteCrl(ps->hStoreProv, crl, 0); |
| if (ret) |
| ret = ps->memStore->crls.deleteContext(ps->memStore, crl); |
| return ret; |
| } |
| |
| static BOOL CRYPT_ProvAddCTL(PWINECRYPT_CERTSTORE store, void *ctl, |
| void *toReplace, const void **ppStoreContext) |
| { |
| PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; |
| BOOL ret; |
| |
| TRACE("(%p, %p, %p, %p)\n", store, ctl, toReplace, ppStoreContext); |
| |
| if (toReplace) |
| ret = ps->memStore->ctls.addContext(ps->memStore, ctl, toReplace, |
| ppStoreContext); |
| 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, ctl, |
| CERT_STORE_PROV_WRITE_ADD_FLAG); |
| if (ret) |
| ret = ps->memStore->ctls.addContext(ps->memStore, ctl, NULL, |
| ppStoreContext); |
| } |
| } |
| /* dirty trick: replace the returned context's hCertStore with |
| * store. |
| */ |
| if (ret && ppStoreContext) |
| (*(PCTL_CONTEXT *)ppStoreContext)->hCertStore = store; |
| return ret; |
| } |
| |
| static void *CRYPT_ProvEnumCTL(PWINECRYPT_CERTSTORE store, void *pPrev) |
| { |
| PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; |
| void *ret; |
| |
| ret = ps->memStore->ctls.enumContext(ps->memStore, pPrev); |
| if (ret) |
| { |
| /* same dirty trick: replace the returned context's hCertStore with |
| * store. |
| */ |
| ((PCTL_CONTEXT)ret)->hCertStore = store; |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_ProvDeleteCTL(PWINECRYPT_CERTSTORE store, void *ctl) |
| { |
| PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; |
| BOOL ret = TRUE; |
| |
| TRACE("(%p, %p)\n", store, ctl); |
| |
| if (ps->provDeleteCtl) |
| ret = ps->provDeleteCtl(ps->hStoreProv, ctl, 0); |
| if (ret) |
| ret = ps->memStore->ctls.deleteContext(ps->memStore, ctl); |
| return ret; |
| } |
| |
| static BOOL WINAPI CRYPT_ProvControl(HCERTSTORE hCertStore, DWORD dwFlags, |
| DWORD dwCtrlType, void const *pvCtrlPara) |
| { |
| PWINE_PROVIDERSTORE store = hCertStore; |
| BOOL ret = TRUE; |
| |
| TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, |
| pvCtrlPara); |
| |
| if (store->provControl) |
| ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType, |
| pvCtrlPara); |
| return ret; |
| } |
| |
| PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(DWORD dwFlags, |
| PWINECRYPT_CERTSTORE memStore, const CERT_STORE_PROV_INFO *pProvInfo) |
| { |
| PWINE_PROVIDERSTORE ret = CryptMemAlloc(sizeof(WINE_PROVIDERSTORE)); |
| |
| if (ret) |
| { |
| CRYPT_InitStore(&ret->hdr, dwFlags, StoreTypeProvider); |
| 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; |
| ret->hdr.closeStore = CRYPT_ProvCloseStore; |
| ret->hdr.certs.addContext = CRYPT_ProvAddCert; |
| ret->hdr.certs.enumContext = CRYPT_ProvEnumCert; |
| ret->hdr.certs.deleteContext = CRYPT_ProvDeleteCert; |
| ret->hdr.crls.addContext = CRYPT_ProvAddCRL; |
| ret->hdr.crls.enumContext = CRYPT_ProvEnumCRL; |
| ret->hdr.crls.deleteContext = CRYPT_ProvDeleteCRL; |
| ret->hdr.ctls.addContext = CRYPT_ProvAddCTL; |
| ret->hdr.ctls.enumContext = CRYPT_ProvEnumCTL; |
| ret->hdr.ctls.deleteContext = CRYPT_ProvDeleteCTL; |
| ret->hdr.control = CRYPT_ProvControl; |
| 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 (PWINECRYPT_CERTSTORE)ret; |
| } |
| |
| PWINECRYPT_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; |
| PWINECRYPT_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; |
| } |