Wine-0_9_1 vendor drop Added: vendor/wine/dlls/crypt32/ Added: vendor/wine/dlls/crypt32/current/ Added: vendor/wine/dlls/crypt32/current/Makefile.in Added: vendor/wine/dlls/crypt32/current/cert.c Added: vendor/wine/dlls/crypt32/current/crypt32.spec Added: vendor/wine/dlls/crypt32/current/crypt32_private.h Added: vendor/wine/dlls/crypt32/current/encode.c Added: vendor/wine/dlls/crypt32/current/main.c Added: vendor/wine/dlls/crypt32/current/protectdata.c _____
Added: vendor/wine/dlls/crypt32/current/Makefile.in --- vendor/wine/dlls/crypt32/current/Makefile.in 2005-11-17 20:49:37 UTC (rev 19307) +++ vendor/wine/dlls/crypt32/current/Makefile.in 2005-11-17 20:53:18 UTC (rev 19308) @@ -0,0 +1,20 @@
+EXTRADEFS = -D_CRYPT32_ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = crypt32.dll +IMPORTLIB = libcrypt32.$(IMPLIBEXT) +IMPORTS = user32 advapi32 kernel32 ntdll + +C_SRCS = \ + cert.c \ + encode.c \ + protectdata.c \ + main.c + +SUBDIRS = tests + +@MAKE_DLL_RULES@ + +### Dependencies: Property changes on: vendor/wine/dlls/crypt32/current/Makefile.in ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native _____
Added: vendor/wine/dlls/crypt32/current/cert.c --- vendor/wine/dlls/crypt32/current/cert.c 2005-11-17 20:49:37 UTC (rev 19307) +++ vendor/wine/dlls/crypt32/current/cert.c 2005-11-17 20:53:18 UTC (rev 19308) @@ -0,0 +1,3325 @@
+/* + * Copyright 2002 Mike McCormack for CodeWeavers + * Copyright 2004,2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * FIXME: + * - As you can see in the stubs below, support for CRLs and CTLs is missing. + * Mostly this should be copy-paste work, and some code (e.g. extended + * properties) could be shared between them. + * - Opening a cert store provider should be morphed to support loading + * external DLLs. + * - 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 <assert.h> +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "winuser.h" +#include "wincrypt.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "excpt.h" +#include "wine/exception.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +#define WINE_CRYPTCERTSTORE_MAGIC 0x74726563 +/* The following aren't defined in wincrypt.h, as they're "reserved" */ +#define CERT_CERT_PROP_ID 32 +#define CERT_CRL_PROP_ID 33 +#define CERT_CTL_PROP_ID 34 + +/* Some typedefs that make it easier to abstract which type of context we're + * working with. + */ +typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType, + const BYTE *pbCertEncoded, DWORD cbCertEncoded); +typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore, + const void *context, DWORD dwAddDisposition, const void **ppStoreContext); +typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwAddDisposition, const void **ppContext); +typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore, + const void *pPrevContext); +typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context, + DWORD dwPropID, void *pvData, DWORD *pcbData); +typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context, + DWORD dwPropID, DWORD dwFlags, const void *pvData); +typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags, + BYTE *pbElement, DWORD *pcbElement); +typedef BOOL (WINAPI *FreeContextFunc)(const void *context); +typedef BOOL (WINAPI *DeleteContextFunc)(const void *context); + +/* An abstract context (certificate, CRL, or CTL) interface */ +typedef struct _WINE_CONTEXT_INTERFACE +{ + CreateContextFunc create; + AddContextToStoreFunc addContextToStore; + AddEncodedContextToStoreFunc addEncodedToStore; + EnumContextsInStoreFunc enumContextsInStore; + GetContextPropertyFunc getProp; + SetContextPropertyFunc setProp; + SerializeElementFunc serialize; + FreeContextFunc free; + DeleteContextFunc deleteFromStore; +} WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE; + +static const WINE_CONTEXT_INTERFACE gCertInterface = { + (CreateContextFunc)CertCreateCertificateContext, + (AddContextToStoreFunc)CertAddCertificateContextToStore, + (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore, + (EnumContextsInStoreFunc)CertEnumCertificatesInStore, + (GetContextPropertyFunc)CertGetCertificateContextProperty, + (SetContextPropertyFunc)CertSetCertificateContextProperty, + (SerializeElementFunc)CertSerializeCertificateStoreElement, + (FreeContextFunc)CertFreeCertificateContext, + (DeleteContextFunc)CertDeleteCertificateFromStore, +}; + +static const WINE_CONTEXT_INTERFACE gCRLInterface = { + (CreateContextFunc)CertCreateCRLContext, + (AddContextToStoreFunc)CertAddCRLContextToStore, + (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore, + (EnumContextsInStoreFunc)CertEnumCRLsInStore, + (GetContextPropertyFunc)CertGetCRLContextProperty, + (SetContextPropertyFunc)CertSetCRLContextProperty, + (SerializeElementFunc)CertSerializeCRLStoreElement, + (FreeContextFunc)CertFreeCRLContext, + (DeleteContextFunc)CertDeleteCRLFromStore, +}; + +static const WINE_CONTEXT_INTERFACE gCTLInterface = { + (CreateContextFunc)CertCreateCTLContext, + (AddContextToStoreFunc)CertAddCTLContextToStore, + (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore, + (EnumContextsInStoreFunc)CertEnumCTLsInStore, + (GetContextPropertyFunc)CertGetCTLContextProperty, + (SetContextPropertyFunc)CertSetCTLContextProperty, + (SerializeElementFunc)CertSerializeCTLStoreElement, + (FreeContextFunc)CertFreeCTLContext, + (DeleteContextFunc)CertDeleteCTLFromStore, +}; + +struct WINE_CRYPTCERTSTORE; + +typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara); + +struct _WINE_CERT_CONTEXT_REF; + +/* Called to enumerate the next certificate in a store. The returned pointer + * must be newly allocated (via CryptMemAlloc): CertFreeCertificateContext + * frees it. + */ +typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc) + (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev); + +struct _WINE_CERT_CONTEXT; + +/* Called to create a new reference to an existing cert context. Should call + * CRYPT_InitCertRef to make sure the reference count is properly updated. + * If the store does not provide any additional allocated data (that is, does + * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for + * this. + */ +typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc) + (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store); + +/* Optional, called when a cert context reference is being freed. Don't free + * the ref pointer itself, CertFreeCertificateContext does that. + */ +typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref); + +typedef enum _CertStoreType { + StoreTypeMem, + StoreTypeCollection, + StoreTypeReg, + StoreTypeDummy, +} CertStoreType; + +/* A cert store is polymorphic through the use of function pointers. A type + * is still needed to distinguish collection stores from other types. + * On the function pointers: + * - closeStore is called when the store's ref count becomes 0 + * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter + * - control is optional, but should be implemented by any store that supports + * persistence + */ +typedef struct WINE_CRYPTCERTSTORE +{ + DWORD dwMagic; + LONG ref; + DWORD dwOpenFlags; + HCRYPTPROV cryptProv; + CertStoreType type; + PFN_CERT_STORE_PROV_CLOSE closeStore; + PFN_CERT_STORE_PROV_WRITE_CERT addCert; + CreateRefFunc createCertRef; + EnumCertFunc enumCert; + PFN_CERT_STORE_PROV_DELETE_CERT deleteCert; + FreeCertFunc freeCert; /* optional */ + PFN_CERT_STORE_PROV_CONTROL control; /* optional */ +} WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE; + +/* A certificate context has pointers to data that are owned by this module, + * so rather than duplicate the data every time a certificate context is + * copied, I keep a reference count to the data. Thus I have two data + * structures, the "true" certificate context (that has the reference count) + * and a reference certificate context, that has a pointer to the true context. + * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing + * with the reference version. + */ +typedef struct _WINE_CERT_CONTEXT +{ + CERT_CONTEXT cert; + LONG ref; + CRITICAL_SECTION cs; + struct list extendedProperties; +} WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT; + +typedef struct _WINE_CERT_CONTEXT_REF +{ + CERT_CONTEXT cert; + WINE_CERT_CONTEXT *context; +} WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF; + +/* An extended certificate property in serialized form is prefixed by this + * header. + */ +typedef struct _WINE_CERT_PROP_HEADER +{ + DWORD propID; + DWORD unknown; /* always 1 */ + DWORD cb; +} WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER; + +/* Stores an extended property in a cert. */ +typedef struct _WINE_CERT_PROPERTY +{ + WINE_CERT_PROP_HEADER hdr; + LPBYTE pbData; + struct list entry; +} WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY; + +/* A mem store has a list of these. They're also returned by the mem store + * during enumeration. + */ +typedef struct _WINE_CERT_LIST_ENTRY +{ + WINE_CERT_CONTEXT_REF cert; + struct list entry; +} WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY; + +typedef struct _WINE_MEMSTORE +{ + WINECRYPT_CERTSTORE hdr; + CRITICAL_SECTION cs; + struct list certs; +} WINE_MEMSTORE, *PWINE_MEMSTORE; + +typedef struct _WINE_HASH_TO_DELETE +{ + BYTE hash[20]; + struct list entry; +} WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE; + +/* Returned by a reg store during enumeration. */ +typedef struct _WINE_REG_CERT_CONTEXT +{ + WINE_CERT_CONTEXT_REF cert; + PWINE_CERT_CONTEXT_REF childContext; +} WINE_REG_CERT_CONTEXT, *PWINE_REG_CERT_CONTEXT; + +typedef struct _WINE_REGSTORE +{ + WINECRYPT_CERTSTORE hdr; + PWINECRYPT_CERTSTORE memStore; + HKEY key; + BOOL dirty; + CRITICAL_SECTION cs; + struct list certsToDelete; +} WINE_REGSTORE, *PWINE_REGSTORE; + +typedef struct _WINE_STORE_LIST_ENTRY +{ + PWINECRYPT_CERTSTORE store; + DWORD dwUpdateFlags; + DWORD dwPriority; + struct list entry; +} WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY; + +/* Returned by a collection store during enumeration. + * Note: relies on the list entry being valid after use, which a number of + * conditions might make untrue (reentrancy, closing a collection store before + * continuing an enumeration on it, ...). The tests seem to indicate this + * sort of unsafety is okay, since Windows isn't well-behaved in these + * scenarios either. + */ +typedef struct _WINE_COLLECTION_CERT_CONTEXT +{ + WINE_CERT_CONTEXT_REF cert; + PWINE_STORE_LIST_ENTRY entry; + PWINE_CERT_CONTEXT_REF childContext; +} WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT; + +typedef struct _WINE_COLLECTIONSTORE +{ + WINECRYPT_CERTSTORE hdr; + CRITICAL_SECTION cs; + struct list stores; +} WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE; + +/* Like CertGetCertificateContextProperty, but operates directly on the + * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they + * are handled by CertGetCertificateContextProperty, and are particular to the + * store in which the property exists (which is separate from the context.) + */ +static BOOL WINAPI CRYPT_GetCertificateContextProperty( + PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData); + +/* Like CertSetCertificateContextProperty, but operates directly on the + * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by + * CertSetCertificateContextProperty anyway. + */ +static BOOL WINAPI CRYPT_SetCertificateContextProperty( + PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData); + +/* Helper function for store reading functions and + * CertAddSerializedElementToStore. Returns a context of the appropriate type + * if it can, or NULL otherwise. Doesn't validate any of the properties in + * the serialized context (for example, bad hashes are retained.) + * *pdwContentType is set to the type of the returned context. + */ +static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement, + DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType); + +/* filter for page-fault exceptions */ +static WINE_EXCEPTION_FILTER(page_fault) +{ + if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) + return EXCEPTION_EXECUTE_HANDLER; + return EXCEPTION_CONTINUE_SEARCH; +} + +static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv, + DWORD dwFlags, CertStoreType type) +{ + store->ref = 1; + store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC; + store->type = type; + if (!hCryptProv) + { + hCryptProv = CRYPT_GetDefaultProvider(); + dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG; + } + store->cryptProv = hCryptProv; + store->dwOpenFlags = dwFlags; +} + +/* Initializes the reference ref to point to pCertContext, which is assumed to + * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count. + * Also sets the hCertStore member of the reference to store. + */ +static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref, + PWINE_CERT_CONTEXT context, HCERTSTORE store) +{ + TRACE("(%p, %p)\n", ref, context); + memcpy(&ref->cert, context, sizeof(ref->cert)); + ref->context = context; + InterlockedIncrement(&context->ref); + ref->cert.hCertStore = store; +} + +static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context, + HCERTSTORE store) +{ + PWINE_CERT_CONTEXT_REF pCertRef = CryptMemAlloc( + sizeof(WINE_CERT_CONTEXT_REF)); + + if (pCertRef) + CRYPT_InitCertRef(pCertRef, context, store); + return pCertRef; +} + +static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert, + DWORD dwAddDisposition) +{ + WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; + BOOL add = FALSE, ret; + + TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition); + + switch (dwAddDisposition) + { + case CERT_STORE_ADD_ALWAYS: + add = TRUE; + break; + case CERT_STORE_ADD_NEW: + { + BYTE hashToAdd[20], hash[20]; + DWORD size = sizeof(hashToAdd); + + ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert, + CERT_HASH_PROP_ID, hashToAdd, &size); + if (ret) + { + PWINE_CERT_LIST_ENTRY cursor; + + /* Add if no cert with the same hash is found. */ + add = TRUE; + EnterCriticalSection(&ms->cs); + LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry) + { + size = sizeof(hash); + ret = CertGetCertificateContextProperty(&cursor->cert.cert, + CERT_HASH_PROP_ID, hash, &size); + if (ret && !memcmp(hashToAdd, hash, size)) + { + TRACE("found matching certificate, not adding\n"); + SetLastError(CRYPT_E_EXISTS); + add = FALSE; + break; + } + } + LeaveCriticalSection(&ms->cs); + } + break; + } + case CERT_STORE_ADD_REPLACE_EXISTING: + { + BYTE hashToAdd[20], hash[20]; + DWORD size = sizeof(hashToAdd); + + add = TRUE; + ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert, + CERT_HASH_PROP_ID, hashToAdd, &size); + if (ret) + { + PWINE_CERT_LIST_ENTRY cursor, next; + + /* Look for existing cert to delete */ + EnterCriticalSection(&ms->cs); + LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs, + WINE_CERT_LIST_ENTRY, entry) + { + size = sizeof(hash); + ret = CertGetCertificateContextProperty(&cursor->cert.cert, + CERT_HASH_PROP_ID, hash, &size); + if (ret && !memcmp(hashToAdd, hash, size)) + { + TRACE("found matching certificate, replacing\n"); + list_remove(&cursor->entry); + CertFreeCertificateContext((PCCERT_CONTEXT)cursor); + break; + } + } + LeaveCriticalSection(&ms->cs); + } + break; + } + default: + FIXME("Unimplemented add disposition %ld\n", dwAddDisposition); + add = FALSE; + } + if (add) + { + PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc( + sizeof(WINE_CERT_LIST_ENTRY)); + + if (entry) + { + TRACE("adding %p\n", entry); + CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store); + list_init(&entry->entry); + EnterCriticalSection(&ms->cs); + list_add_tail(&ms->certs, &entry->entry); + LeaveCriticalSection(&ms->cs); + ret = TRUE; + } + else + ret = FALSE; + } + else + ret = FALSE; + return ret; +} + +static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, + PWINE_CERT_CONTEXT_REF pPrev) +{ + WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; + PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret; + struct list *listNext; + + TRACE("(%p, %p)\n", store, pPrev); + EnterCriticalSection(&ms->cs); + if (prevEntry) + { + listNext = list_next(&ms->certs, &prevEntry->entry); + CertFreeCertificateContext((PCCERT_CONTEXT)pPrev); + } + else + listNext = list_next(&ms->certs, &ms->certs); + if (listNext) + { + ret = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY)); + memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry), + sizeof(WINE_CERT_LIST_ENTRY)); + InterlockedIncrement(&ret->cert.context->ref); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + LeaveCriticalSection(&ms->cs); + + TRACE("returning %p\n", ret); + return (PWINE_CERT_CONTEXT_REF)ret; +} + +static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwFlags) +{ + WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore; + WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext; + PWINE_CERT_LIST_ENTRY cert, next; + BOOL ret; + + /* Find the entry associated with the passed-in context, since the + * passed-in context may not be a list entry itself (e.g. if it came from + * CertDuplicateCertificateContext.) Pointing to the same context is + * a sufficient test of equality. + */ + EnterCriticalSection(&store->cs); + LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY, + entry) + { + if (cert->cert.context == ref->context) + { + TRACE("removing %p\n", cert); + /* FIXME: this isn't entirely thread-safe, the entry itself isn't + * protected. + */ + list_remove(&cert->entry); + cert->entry.prev = cert->entry.next = &store->certs; + break; + } + } + ret = TRUE; + LeaveCriticalSection(&store->cs); + return ret; +} + +static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) +{ + WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore; + PWINE_CERT_LIST_ENTRY cert, next; + + TRACE("(%p, %08lx)\n", store, dwFlags); + if (dwFlags) + FIXME("Unimplemented flags: %08lx\n", dwFlags); + + /* Note that CertFreeCertificateContext calls HeapFree on the passed-in + * pointer if its ref-count reaches zero. That's okay here because there + * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion + * of the CertListEntry. + */ + LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY, + entry) + { + TRACE("removing %p\n", cert); + list_remove(&cert->entry); + CertFreeCertificateContext((PCCERT_CONTEXT)cert); + } + DeleteCriticalSection(&store->cs); + CryptMemFree(store); +} + +static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + PWINE_MEMSTORE store; + + TRACE("(%ld, %08lx, %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, hCryptProv, dwFlags, StoreTypeMem); + store->hdr.closeStore = CRYPT_MemCloseStore; + store->hdr.addCert = CRYPT_MemAddCert; + store->hdr.createCertRef = CRYPT_CreateCertRef; + store->hdr.enumCert = CRYPT_MemEnumCert; + store->hdr.deleteCert = CRYPT_MemDeleteCert; + store->hdr.freeCert = NULL; + InitializeCriticalSection(&store->cs); + list_init(&store->certs); + } + } + return (PWINECRYPT_CERTSTORE)store; +} + +static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store, + PCCERT_CONTEXT pCert, DWORD dwAddDisposition) +{ + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + PWINE_STORE_LIST_ENTRY entry, next; + BOOL ret; + + TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition); + + ret = FALSE; + EnterCriticalSection(&cs->cs); + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY, + entry) + { + if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG) + { + ret = entry->store->addCert(entry->store, pCert, dwAddDisposition); + break; + } + } + LeaveCriticalSection(&cs->cs); + SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)); + return ret; +} + +static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef( + PWINE_CERT_CONTEXT context, HCERTSTORE store) +{ + PWINE_COLLECTION_CERT_CONTEXT ret = CryptMemAlloc( + sizeof(WINE_COLLECTION_CERT_CONTEXT)); + + if (ret) + { + /* Initialize to empty for now, just make sure the size is right */ + CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store); + ret->entry = NULL; + ret->childContext = NULL; + } + return (PWINE_CERT_CONTEXT_REF)ret; +} + +static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags) +{ + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + PWINE_STORE_LIST_ENTRY entry, next; + + TRACE("(%p, %08lx)\n", store, dwFlags); + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY, + entry) + { + TRACE("closing %p\n", entry); + CertCloseStore((HCERTSTORE)entry->store, dwFlags); + CryptMemFree(entry); + } + DeleteCriticalSection(&cs->cs); + CryptMemFree(cs); +} + +/* Advances a collection enumeration by one cert, if possible, where advancing + * means: + * - calling the current store's enumeration function once, and returning + * the enumerated cert if one is returned + * - moving to the next store if the current store has no more items, and + * recursively calling itself to get the next item. + * Returns NULL if the collection contains no more items or on error. + * Assumes the collection store's lock is held. + */ +static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum( + PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry, + PWINE_COLLECTION_CERT_CONTEXT pPrev) +{ + PWINE_COLLECTION_CERT_CONTEXT ret; + PWINE_CERT_CONTEXT_REF child; + + TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev); + + if (pPrev) + { + child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store, + pPrev->childContext); + if (child) + { + ret = pPrev; + memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF)); + ret->cert.cert.hCertStore = (HCERTSTORE)store; + InterlockedIncrement(&ret->cert.context->ref); + ret->childContext = child; + } + else + { + struct list *storeNext = list_next(&store->stores, + &storeEntry->entry); + + pPrev->childContext = NULL; + CertFreeCertificateContext((PCCERT_CONTEXT)pPrev); + if (storeNext) + { + storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, + entry); + ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + } + } + else + { + child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store, + NULL); + if (child) + { + ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef( + child->context, store); + if (ret) + { + ret->entry = storeEntry; + ret->childContext = child; + } + else + CertFreeCertificateContext((PCCERT_CONTEXT)child); + } + else + { + struct list *storeNext = list_next(&store->stores, + &storeEntry->entry); + + if (storeNext) + { + storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, + entry); + ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + } + } + TRACE("returning %p\n", ret); + return ret; +} + +static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert( + PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev) +{ + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + PWINE_COLLECTION_CERT_CONTEXT prevEntry = + (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret; + + TRACE("(%p, %p)\n", store, pPrev); + + if (prevEntry) + { + EnterCriticalSection(&cs->cs); + ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry); + LeaveCriticalSection(&cs->cs); + } + else + { + EnterCriticalSection(&cs->cs); + if (!list_empty(&cs->stores)) + { + PWINE_STORE_LIST_ENTRY storeEntry; + + storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY, + entry); + ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + LeaveCriticalSection(&cs->cs); + } + TRACE("returning %p\n", ret); + return (PWINE_CERT_CONTEXT_REF)ret; +} + +static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwFlags) +{ + PWINE_COLLECTION_CERT_CONTEXT context = + (PWINE_COLLECTION_CERT_CONTEXT)pCertContext; + BOOL ret; + + TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags); + + ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext); + if (ret) + context->childContext = NULL; + return ret; +} + +static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref) +{ + PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref; + + TRACE("(%p)\n", ref); + + if (context->childContext) + CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext); +} + +static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + PWINE_COLLECTIONSTORE store; + + if (dwFlags & CERT_STORE_DELETE_FLAG) + { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + store = NULL; + } + else + { + store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE)); + if (store) + { + memset(store, 0, sizeof(WINE_COLLECTIONSTORE)); + CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, + StoreTypeCollection); + store->hdr.closeStore = CRYPT_CollectionCloseStore; + store->hdr.addCert = CRYPT_CollectionAddCert; + store->hdr.createCertRef = CRYPT_CollectionCreateCertRef; + store->hdr.enumCert = CRYPT_CollectionEnumCert; + store->hdr.deleteCert = CRYPT_CollectionDeleteCert; + store->hdr.freeCert = CRYPT_CollectionFreeCert; + InitializeCriticalSection(&store->cs); + list_init(&store->stores); + } + } + return (PWINECRYPT_CERTSTORE)store; +} + +static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash) +{ + static const WCHAR fmt[] = { '%','0','2','X',0 }; + DWORD i; + + assert(hash); + assert(asciiHash); + + for (i = 0; i < 20; i++) + wsprintfW(asciiHash + i * 2, fmt, hash[i]); +} + +static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s', + 0 }; +static const WCHAR CRLsW[] = { 'C','R','L','s',0 }; +static const WCHAR CTLsW[] = { 'C','T','L','s',0 }; +static const WCHAR BlobW[] = { 'B','l','o','b',0 }; + +static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key, + DWORD contextType) +{ + LONG rc; + DWORD index = 0; + WCHAR subKeyName[MAX_PATH]; + + do { + DWORD size = sizeof(subKeyName) / sizeof(WCHAR); + + rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL, + NULL); + if (!rc) + { + HKEY subKey; + + rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey); + if (!rc) + { + LPBYTE buf = NULL; + + size = 0; + rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size); + if (!rc) + buf = CryptMemAlloc(size); + if (buf) + { + rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf, + &size); + if (!rc) + { + const void *context; + DWORD addedType; + + TRACE("Adding cert with hash %s\n", + debugstr_w(subKeyName)); + context = CRYPT_ReadSerializedElement(buf, size, + contextType, &addedType); + if (context) + { + const WINE_CONTEXT_INTERFACE *contextInterface; + BYTE hash[20]; + + switch (addedType) + { + case CERT_STORE_CERTIFICATE_CONTEXT: + contextInterface = &gCertInterface; + break; + case CERT_STORE_CRL_CONTEXT: + contextInterface = &gCRLInterface; + break; + case CERT_STORE_CTL_CONTEXT: + contextInterface = &gCTLInterface; + break; + default: + contextInterface = NULL; + } + if (contextInterface) + { + size = sizeof(hash); + if (contextInterface->getProp(context, + CERT_HASH_PROP_ID, hash, &size)) + { + WCHAR asciiHash[20 * 2 + 1]; + + CRYPT_HashToStr(hash, asciiHash); + TRACE("comparing %s\n", + debugstr_w(asciiHash)); + TRACE("with %s\n", debugstr_w(subKeyName)); + if (!lstrcmpW(asciiHash, subKeyName)) + { + TRACE("hash matches, adding\n"); + contextInterface->addContextToStore( + store, context, + CERT_STORE_ADD_REPLACE_EXISTING, NULL); + } + else + { + TRACE("hash doesn't match, ignoring\n"); + contextInterface->free(context); + } + } + } + } + } + CryptMemFree(buf); + } + RegCloseKey(subKey); + } + /* Ignore intermediate errors, continue enumerating */ + rc = ERROR_SUCCESS; + } + } while (!rc); +} + +static void CRYPT_RegReadFromReg(PWINE_REGSTORE store) +{ + static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW }; + static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG, + CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG }; + DWORD i; + + for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++) + { + HKEY key; + LONG rc; + + rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL, + &key, NULL); + if (!rc) + { + CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]); + RegCloseKey(key); + } + } +} [truncated at 1000 lines; 9831 more skipped]