added crypt32 (still not complete, from wine 0.91)
Modified: trunk/reactos/baseaddress.xml
Modified: trunk/reactos/lib/advapi32/crypt/crypt.c
Added: trunk/reactos/lib/crypt32/
Added: trunk/reactos/lib/crypt32/cert.c
Added: trunk/reactos/lib/crypt32/crypt32.def
Added: trunk/reactos/lib/crypt32/crypt32.rc
Added: trunk/reactos/lib/crypt32/crypt32.xml
Added: trunk/reactos/lib/crypt32/crypt32_private.h
Added: trunk/reactos/lib/crypt32/encode.c
Added: trunk/reactos/lib/crypt32/main.c
Added: trunk/reactos/lib/crypt32/precomp.h
Added: trunk/reactos/lib/crypt32/protectdata.c
Modified: trunk/reactos/lib/directory.xml
Modified: trunk/reactos/w32api/include/wincrypt.h

Modified: trunk/reactos/baseaddress.xml
--- trunk/reactos/baseaddress.xml	2005-11-17 20:16:02 UTC (rev 19303)
+++ trunk/reactos/baseaddress.xml	2005-11-17 20:17:53 UTC (rev 19304)
@@ -104,6 +104,7 @@
 <property name="BASEADDRESS_OLE32" value="0x77a50000" />
 <property name="BASEADDRESS_WS2_32" value="0x77aa0000" />
 <property name="BASEADDRESS_OLEPRO32" value="0x77aa0000" />
+<property name="BASEADDRESS_CRYPT32" value="0x77aa1000" />
 <property name="BASEADDRESS_ADVAPI32" value="0x77dc0000" />
 <property name="BASEADDRESS_USER32" value="0x77e50000" />
 <property name="BASEADDRESS_GDI32" value="0x77f10000" />

Modified: trunk/reactos/lib/advapi32/crypt/crypt.c
--- trunk/reactos/lib/advapi32/crypt/crypt.c	2005-11-17 20:16:02 UTC (rev 19303)
+++ trunk/reactos/lib/advapi32/crypt/crypt.c	2005-11-17 20:17:53 UTC (rev 19304)
@@ -1480,7 +1480,7 @@
  *  Success: TRUE
  *  Failure: FALSE
  */
-BOOL WINAPI CryptHashData (HCRYPTHASH hHash, BYTE *pbData, DWORD dwDataLen, DWORD dwFlags)
+BOOL WINAPI CryptHashData (HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags)
 {
 	PCRYPTHASH hash = (PCRYPTHASH)hHash;
 	PCRYPTPROV prov;

Added: trunk/reactos/lib/crypt32/cert.c
--- trunk/reactos/lib/crypt32/cert.c	2005-11-17 20:16:02 UTC (rev 19303)
+++ trunk/reactos/lib/crypt32/cert.c	2005-11-17 20:17:53 UTC (rev 19304)
@@ -0,0 +1,3315 @@
+/*
+ * 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 "precomp.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);
+        }
+    }
+}
+
+/* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
+static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
+ DWORD len)
+{
+    WCHAR asciiHash[20 * 2 + 1];
+    LONG rc;
+    HKEY subKey;
+    BOOL ret;
+
+    CRYPT_HashToStr(hash, asciiHash);
+    rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
+     &subKey, NULL);
+    if (!rc)
+    {
+        rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
[truncated at 1000 lines; 10343 more skipped]