416 lines
13 KiB
C
416 lines
13 KiB
C
/*
|
|
* 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 <assert.h>
|
|
|
|
#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;
|
|
}
|