crypt32: Keep reference to store in contexts.

This commit is contained in:
Jacek Caban 2013-10-18 10:50:43 +02:00 committed by Alexandre Julliard
parent 610c863e75
commit 9fb1e4d675
9 changed files with 190 additions and 60 deletions

View File

@ -124,7 +124,7 @@ static context_t *Cert_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOO
cert_t *cert;
if(use_link) {
cert = (cert_t*)Context_CreateLinkContext(sizeof(CERT_CONTEXT), context);
cert = (cert_t*)Context_CreateLinkContext(sizeof(CERT_CONTEXT), context, store);
if(!cert)
return NULL;
}else {
@ -133,7 +133,7 @@ static context_t *Cert_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOO
DWORD size = 0;
BOOL res;
new_context = Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl);
new_context = Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl, store);
if(!new_context)
return NULL;
cert = cert_from_ptr(new_context);
@ -270,12 +270,10 @@ BOOL WINAPI add_cert_to_store(WINECRYPT_CERTSTORE *store, const CERT_CONTEXT *ce
if(inherit_props)
Context_CopyProperties(context_ptr(new_context), existing);
if(ret_context) {
Context_AddRef(new_context);
if(ret_context)
*ret_context = context_ptr(new_context);
}else if(new_context) {
else if(new_context)
Context_Release(new_context);
}
TRACE("returning %d\n", ret);
return ret;
@ -335,7 +333,7 @@ PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
{
BYTE *data = NULL;
cert = Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl);
cert = Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl, &empty_store);
if (!cert)
goto end;
data = CryptMemAlloc(cbCertEncoded);

View File

@ -71,6 +71,12 @@ static DWORD Collection_release(WINECRYPT_CERTSTORE *store, DWORD flags)
return ERROR_SUCCESS;
}
static void Collection_releaseContext(WINECRYPT_CERTSTORE *store, context_t *context)
{
/* We don't cache context links, so just free them. */
Context_Free(context);
}
static context_t *CRYPT_CollectionCreateContextFromChild(WINE_COLLECTIONSTORE *store,
WINE_STORE_LIST_ENTRY *storeEntry, context_t *child)
{
@ -256,14 +262,11 @@ static BOOL Collection_deleteCert(WINECRYPT_CERTSTORE *store, context_t *context
{
cert_t *cert = (cert_t*)context;
cert_t *linked;
BOOL ret;
TRACE("(%p, %p)\n", store, cert);
linked = (cert_t*)context->linked;
ret = CertDeleteCertificateFromStore(&linked->ctx);
Context_Release(&cert->base);
return ret;
return CertDeleteCertificateFromStore(&linked->ctx);
}
static BOOL Collection_addCRL(WINECRYPT_CERTSTORE *store, context_t *crl,
@ -327,14 +330,11 @@ static context_t *Collection_enumCRL(WINECRYPT_CERTSTORE *store, context_t *prev
static BOOL Collection_deleteCRL(WINECRYPT_CERTSTORE *store, context_t *context)
{
crl_t *crl = (crl_t*)context, *linked;
BOOL ret;
TRACE("(%p, %p)\n", store, crl);
linked = (crl_t*)context->linked;
ret = CertDeleteCRLFromStore(&linked->ctx);
Context_Release(&crl->base);
return ret;
return CertDeleteCRLFromStore(&linked->ctx);
}
static BOOL Collection_addCTL(WINECRYPT_CERTSTORE *store, context_t *ctl,
@ -398,14 +398,11 @@ static context_t *Collection_enumCTL(WINECRYPT_CERTSTORE *store, context_t *prev
static BOOL Collection_deleteCTL(WINECRYPT_CERTSTORE *store, context_t *context)
{
ctl_t *ctl = (ctl_t*)context, *linked;
BOOL ret;
TRACE("(%p, %p)\n", store, ctl);
linked = (ctl_t*)context->linked;
ret = CertDeleteCTLFromStore(&linked->ctx);
Context_Release(&ctl->base);
return ret;
return CertDeleteCTLFromStore(&linked->ctx);
}
static BOOL Collection_control(WINECRYPT_CERTSTORE *cert_store, DWORD dwFlags,
@ -448,6 +445,7 @@ static BOOL Collection_control(WINECRYPT_CERTSTORE *cert_store, DWORD dwFlags,
static const store_vtbl_t CollectionStoreVtbl = {
Collection_addref,
Collection_release,
Collection_releaseContext,
Collection_control,
{
Collection_addCert,

View File

@ -25,7 +25,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(context);
void *Context_CreateDataContext(size_t contextSize, const context_vtbl_t *vtbl)
void *Context_CreateDataContext(size_t contextSize, const context_vtbl_t *vtbl, WINECRYPT_CERTSTORE *store)
{
context_t *context;
@ -33,9 +33,6 @@ void *Context_CreateDataContext(size_t contextSize, const context_vtbl_t *vtbl)
if (!context)
return NULL;
context->vtbl = vtbl;
context->ref = 1;
context->linked = NULL;
context->properties = ContextPropertyList_Create();
if (!context->properties)
{
@ -43,11 +40,18 @@ void *Context_CreateDataContext(size_t contextSize, const context_vtbl_t *vtbl)
return NULL;
}
context->vtbl = vtbl;
context->ref = 1;
context->linked = NULL;
store->vtbl->addref(store);
context->store = store;
TRACE("returning %p\n", context);
return context_ptr(context);
}
context_t *Context_CreateLinkContext(unsigned int contextSize, context_t *linked)
context_t *Context_CreateLinkContext(unsigned int contextSize, context_t *linked, WINECRYPT_CERTSTORE *store)
{
context_t *context;
@ -64,36 +68,54 @@ context_t *Context_CreateLinkContext(unsigned int contextSize, context_t *linked
context->properties = linked->properties;
Context_AddRef(linked);
store->vtbl->addref(store);
context->store = store;
TRACE("returning %p\n", context);
return context;
}
void Context_AddRef(context_t *context)
{
InterlockedIncrement(&context->ref);
LONG ref = InterlockedIncrement(&context->ref);
TRACE("(%p) ref=%d\n", context, context->ref);
if(ref == 1) {
/* This is the first external (non-store) reference. Increase store ref cnt. */
context->store->vtbl->addref(context->store);
}
}
void Context_Free(context_t *context)
{
TRACE("(%p)\n", context);
assert(!context->ref);
if (!context->linked) {
ContextPropertyList_Free(context->properties);
context->vtbl->free(context);
}else {
Context_Release(context->linked);
}
CryptMemFree(context);
}
void Context_Release(context_t *context)
{
if (context->ref <= 0)
{
ERR("%p's ref count is %d\n", context, context->ref);
LONG ref = InterlockedDecrement(&context->ref);
TRACE("(%p) ref=%d\n", context, ref);
assert(ref >= 0);
if (!ref) {
/* This is the last reference, but the context still may be in a store.
* We release our store reference, but leave it up to store to free or keep the context. */
context->store->vtbl->releaseContext(context->store, context);
context->store->vtbl->release(context->store, 0);
}
if (InterlockedDecrement(&context->ref) == 0)
{
TRACE("freeing %p\n", context);
if (!context->linked)
{
ContextPropertyList_Free(context->properties);
context->vtbl->free(context);
} else {
Context_Release(context->linked);
}
CryptMemFree(context);
}
else
TRACE("%p's ref count is %d\n", context, context->ref);
}
void Context_CopyProperties(const void *to, const void *from)

View File

@ -46,7 +46,7 @@ static context_t *CRL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL
return NULL;
}
crl = (crl_t*)Context_CreateLinkContext(sizeof(CRL_CONTEXT), context);
crl = (crl_t*)Context_CreateLinkContext(sizeof(CRL_CONTEXT), context, store);
if(!crl)
return NULL;
@ -82,7 +82,7 @@ PCCRL_CONTEXT WINAPI CertCreateCRLContext(DWORD dwCertEncodingType,
{
BYTE *data = NULL;
crl = Context_CreateDataContext(sizeof(CRL_CONTEXT), &crl_vtbl);
crl = Context_CreateDataContext(sizeof(CRL_CONTEXT), &crl_vtbl, &empty_store);
if (!crl)
goto end;
data = CryptMemAlloc(cbCrlEncoded);

View File

@ -174,6 +174,7 @@ typedef struct {
struct _context_t {
const context_vtbl_t *vtbl;
LONG ref;
struct WINE_CRYPTCERTSTORE *store;
struct _context_t *linked;
CONTEXT_PROPERTY_LIST *properties;
union {
@ -297,6 +298,7 @@ typedef enum _CertStoreType {
typedef struct {
void (*addref)(struct WINE_CRYPTCERTSTORE*);
DWORD (*release)(struct WINE_CRYPTCERTSTORE*,DWORD);
void (*releaseContext)(struct WINE_CRYPTCERTSTORE*,context_t*);
BOOL (*control)(struct WINE_CRYPTCERTSTORE*,DWORD,DWORD,void const*);
CONTEXT_FUNCS certs;
CONTEXT_FUNCS crls;
@ -387,24 +389,21 @@ DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indent,
* which should be one of CERT_CONTEXT, CRL_CONTEXT, or CTL_CONTEXT.
* Free with Context_Release.
*/
void *Context_CreateDataContext(size_t contextSize, const context_vtbl_t *vtbl) DECLSPEC_HIDDEN;
void *Context_CreateDataContext(size_t contextSize, const context_vtbl_t *vtbl, struct WINE_CRYPTCERTSTORE*) DECLSPEC_HIDDEN;
/* Creates a new link context. The context refers to linked
* rather than owning its own properties. If addRef is TRUE (which ordinarily
* it should be) linked is addref'd.
* Free with Context_Release.
*/
context_t *Context_CreateLinkContext(unsigned contextSize, context_t *linked) DECLSPEC_HIDDEN;
context_t *Context_CreateLinkContext(unsigned contextSize, context_t *linked, struct WINE_CRYPTCERTSTORE*) DECLSPEC_HIDDEN;
/* Copies properties from fromContext to toContext. */
void Context_CopyProperties(const void *to, const void *from) DECLSPEC_HIDDEN;
void Context_AddRef(context_t*) DECLSPEC_HIDDEN;
/* Decrements context's ref count. If context is a link context, releases its
* linked context as well.
*/
void Context_Release(context_t *context) DECLSPEC_HIDDEN;
void Context_Free(context_t*) DECLSPEC_HIDDEN;
/**
* Context property list functions

View File

@ -48,7 +48,7 @@ static context_t *CTL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL
return NULL;
}
ctl = (ctl_t*)Context_CreateLinkContext(sizeof(CTL_CONTEXT), context);
ctl = (ctl_t*)Context_CreateLinkContext(sizeof(CTL_CONTEXT), context, store);
if(!ctl)
return NULL;
@ -440,7 +440,7 @@ PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwMsgAndCertEncodingType,
&ctlInfo, &size);
if (ret)
{
ctl = Context_CreateDataContext(sizeof(CTL_CONTEXT), &ctl_vtbl);
ctl = Context_CreateDataContext(sizeof(CTL_CONTEXT), &ctl_vtbl, &empty_store);
if (ctl)
{
BYTE *data = CryptMemAlloc(cbCtlEncoded);

View File

@ -15,7 +15,10 @@
* 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"
@ -68,6 +71,13 @@ static DWORD ProvStore_release(WINECRYPT_CERTSTORE *cert_store, DWORD flags)
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)
{
@ -277,6 +287,7 @@ static BOOL ProvStore_control(WINECRYPT_CERTSTORE *cert_store, DWORD dwFlags, DW
static const store_vtbl_t ProvStoreVtbl = {
ProvStore_addref,
ProvStore_release,
ProvStore_releaseContext,
ProvStore_control,
{
ProvStore_addCert,

View File

@ -160,17 +160,17 @@ static BOOL MemStore_addContext(WINE_MEMSTORE *store, struct list *list, context
context->u.entry.prev->next = &context->u.entry;
context->u.entry.next->prev = &context->u.entry;
list_init(&existing->u.entry);
Context_Release(existing);
if(!existing->ref)
Context_Release(existing);
}else {
list_add_head(list, &context->u.entry);
}
LeaveCriticalSection(&store->cs);
if(ret_context) {
Context_AddRef(context);
if(ret_context)
*ret_context = context;
}
else
Context_Release(context);
return TRUE;
}
@ -210,8 +210,8 @@ static BOOL MemStore_deleteContext(WINE_MEMSTORE *store, context_t *context)
}
LeaveCriticalSection(&store->cs);
if(in_list)
Context_Release(context);
if(in_list && !context->ref)
Context_Free(context);
return TRUE;
}
@ -223,10 +223,17 @@ static void free_contexts(struct list *list)
{
TRACE("freeing %p\n", context);
list_remove(&context->u.entry);
Context_Release(context);
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)
{
@ -348,6 +355,7 @@ static BOOL MemStore_control(WINECRYPT_CERTSTORE *store, DWORD dwFlags,
static const store_vtbl_t MemStoreVtbl = {
MemStore_addref,
MemStore_release,
MemStore_releaseContext,
MemStore_control,
{
MemStore_addCert,
@ -1401,6 +1409,11 @@ static DWORD EmptyStore_release(WINECRYPT_CERTSTORE *store, DWORD flags)
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)
{
@ -1439,6 +1452,7 @@ static BOOL EmptyStore_control(WINECRYPT_CERTSTORE *store, DWORD flags, DWORD ct
static const store_vtbl_t EmptyStoreVtbl = {
EmptyStore_addref,
EmptyStore_release,
EmptyStore_releaseContext,
EmptyStore_control,
{
EmptyStore_add,

View File

@ -93,6 +93,26 @@ static const BYTE bigCert2[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
static const BYTE signedCTLWithCTLInnerContent[] = {
0x30,0x82,0x01,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,
0xa0,0x82,0x01,0x00,0x30,0x81,0xfd,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,
0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x30,0x06,0x09,
0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x01,0xa0,0x23,0x30,0x21,0x30,0x00,
0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,
0x30,0x5a,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,
0x00,0x31,0x81,0xb5,0x30,0x81,0xb2,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,
0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,
0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,
0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0xa0,0x3b,0x30,0x18,0x06,0x09,0x2a,0x86,
0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31,0x0b,0x06,0x09,0x2b,0x06,0x01,0x04,
0x01,0x82,0x37,0x0a,0x01,0x30,0x1f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
0x01,0x09,0x04,0x31,0x12,0x04,0x10,0x54,0x71,0xbc,0xe1,0x56,0x31,0xa2,0xf9,
0x65,0x70,0x34,0xf8,0xe2,0xe9,0xb4,0xf4,0x30,0x04,0x06,0x00,0x05,0x00,0x04,
0x40,0x2f,0x1b,0x9f,0x5a,0x4a,0x15,0x73,0xfa,0xb1,0x93,0x3d,0x09,0x52,0xdf,
0x6b,0x98,0x4b,0x13,0x5e,0xe7,0xbf,0x65,0xf4,0x9c,0xc2,0xb1,0x77,0x09,0xb1,
0x66,0x4d,0x72,0x0d,0xb1,0x1a,0x50,0x20,0xe0,0x57,0xa2,0x39,0xc7,0xcd,0x7f,
0x8e,0xe7,0x5f,0x76,0x2b,0xd1,0x6a,0x82,0xb3,0x30,0x25,0x61,0xf6,0x25,0x23,
0x57,0x6c,0x0b,0x47,0xb8 };
static BOOL (WINAPI *pCertAddStoreToCollection)(HCERTSTORE,HCERTSTORE,DWORD,DWORD);
@ -2571,6 +2591,9 @@ static void testEmptyStore(void)
static void testCloseStore(void)
{
const CERT_CONTEXT *cert;
const CRL_CONTEXT *crl;
const CTL_CONTEXT *ctl;
HCERTSTORE store, store2;
BOOL res;
@ -2592,6 +2615,71 @@ static void testCloseStore(void)
res = CertCloseStore(store2, CERT_CLOSE_STORE_CHECK_FLAG);
ok(res, "CertCloseStore failed\n");
store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
ok(store != NULL, "CertOpenStore failed\n");
res = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, bigCert,
sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &cert);
ok(res, "CertAddEncodedCertificateToStore failed\n");
/* There is still a reference from cert */
res = CertCloseStore(store, CERT_CLOSE_STORE_CHECK_FLAG);
ok(!res && GetLastError() == CRYPT_E_PENDING_CLOSE, "CertCloseStore failed\n");
res = CertFreeCertificateContext(cert);
ok(res, "CertFreeCertificateContext failed\n");
store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
ok(store != NULL, "CertOpenStore failed\n");
res = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, signedCRL,
sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, &crl);
ok(res, "CertAddEncodedCRLToStore failed\n");
/* There is still a reference from CRL */
res = CertCloseStore(store, CERT_CLOSE_STORE_CHECK_FLAG);
ok(!res && GetLastError() == CRYPT_E_PENDING_CLOSE, "CertCloseStore failed\n");
res = CertFreeCRLContext(crl);
ok(res, "CertFreeCRLContext failed\n");
store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
ok(store != NULL, "CertOpenStore failed\n");
res = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, signedCTLWithCTLInnerContent,
sizeof(signedCTLWithCTLInnerContent), CERT_STORE_ADD_ALWAYS, &ctl);
ok(res, "CertAddEncodedCTLToStore failed\n");
/* There is still a reference from CTL */
res = CertCloseStore(store, CERT_CLOSE_STORE_CHECK_FLAG);
ok(!res && GetLastError() == CRYPT_E_PENDING_CLOSE, "CertCloseStore returned: %x(%u)\n", res, GetLastError());
res = CertFreeCTLContext(ctl);
ok(res, "CertFreeCTLContext failed\n");
/* Add all kinds of contexts, then release external references and make sure that store is properly closed. */
store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
ok(store != NULL, "CertOpenStore failed\n");
res = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, bigCert,
sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &cert);
ok(res, "CertAddEncodedCertificateToStore failed\n");
res = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, signedCRL,
sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, &crl);
ok(res, "CertAddEncodedCRLToStore failed\n");
res = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, signedCTLWithCTLInnerContent,
sizeof(signedCTLWithCTLInnerContent), CERT_STORE_ADD_ALWAYS, &ctl);
ok(res, "CertAddEncodedCTLToStore failed\n");
CertFreeCertificateContext(cert);
CertFreeCRLContext(crl);
CertFreeCTLContext(ctl);
res = CertCloseStore(store, CERT_CLOSE_STORE_CHECK_FLAG);
ok(res, "CertCloseStore failed\n");
}
static void test_I_UpdateStore(void)