store.c

来自「一个类似windows」· C语言 代码 · 共 1,949 行 · 第 1/5 页

C
1,949
字号
/*
 * Copyright 2002 Mike McCormack for CodeWeavers
 * Copyright 2004-2006 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.
 * - 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

/* 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;

/* Called to enumerate the next certificate in a store. */
typedef struct _WINE_CERT_CONTEXT * (*EnumCertFunc)
 (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT *pPrev);

/* Called to add a new certificate context to a store.  If ppStoreContext is
 * not NULL, the added context should be returned in *ppStoreContext.
 */
typedef BOOL (*AddCertFunc)(struct WINE_CRYPTCERTSTORE *store,
 struct _WINE_CERT_CONTEXT *context, DWORD dwAddDisposition,
 PCCERT_CONTEXT *ppStoreContext);

typedef enum _CertStoreType {
    StoreTypeMem,
    StoreTypeCollection,
    StoreTypeProvider,
} 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
 * - 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;
    AddCertFunc                     addCert;
    EnumCertFunc                    enumCert;
    PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
    PFN_CERT_STORE_PROV_CONTROL     control;    /* optional */
} WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;

typedef enum _ContextType {
    ContextTypeData,
    ContextTypeLink,
} ContextType;

/* A certificate context.  This is the base type, and the two real types
 * (data and link) derive from it.  Each one can be cast to a PCCERT_CONTEXT.
 */
typedef struct _WINE_CERT_CONTEXT
{
    CERT_CONTEXT cert;
    LONG         ref;
    ContextType  type;
} WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
typedef const struct _WINE_CERT_CONTEXT PCWINE_CERT_CONTEXT;

typedef struct _WINE_CERT_CONTEXT_DATA
{
    CERT_CONTEXT           cert;
    LONG                   ref;
    ContextType            type; /* always ContextTypeData */
    PCONTEXT_PROPERTY_LIST properties;
} WINE_CERT_CONTEXT_DATA, *PWINE_CERT_CONTEXT_DATA;
typedef const struct _WINE_CERT_CONTEXT_DATA PCWINE_CERT_CONTEXT_DATA;

typedef struct _WINE_CERT_CONTEXT_LINK
{
    CERT_CONTEXT       cert;
    LONG               ref;
    ContextType        type; /* always ContextTypeLink */
    PWINE_CERT_CONTEXT linked;
} WINE_CERT_CONTEXT_LINK, *PWINE_CERT_CONTEXT_LINK;
typedef const struct _WINE_CERT_CONTEXT_LINK PCWINE_CERT_CONTEXT_LINK;

/* 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_LINK 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;

typedef struct _WINE_REGSTOREINFO
{
    DWORD                dwOpenFlags;
    HCRYPTPROV           cryptProv;
    PWINECRYPT_CERTSTORE memStore;
    HKEY                 key;
    BOOL                 dirty;
    CRITICAL_SECTION     cs;
    struct list          certsToDelete;
} WINE_REGSTOREINFO, *PWINE_REGSTOREINFO;

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_LINK  cert;
    PWINE_STORE_LIST_ENTRY storeEntry;
} 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;

typedef struct _WINE_PROVIDERSTORE
{
    WINECRYPT_CERTSTORE             hdr;
    DWORD                           dwStoreProvFlags;
    PWINECRYPT_CERTSTORE            memStore;
    HCERTSTOREPROV                  hStoreProv;
    PFN_CERT_STORE_PROV_CLOSE       provCloseStore;
    PFN_CERT_STORE_PROV_WRITE_CERT  provWriteCert;
    PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert;
    PFN_CERT_STORE_PROV_CONTROL     provControl;
} WINE_PROVIDERSTORE, *PWINE_PROVIDERSTORE;

/* Internal version of CertGetCertificateContextProperty that gets properties
 * directly from the context (or the context it's linked to, depending on its
 * type.) Doesn't handle 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);

/* Internal version of CertSetCertificateContextProperty that sets properties
 * directly on the context (or the context it's linked to, depending on its
 * type.) 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);

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 context, and increments context's
 * reference count.  Also sets the hCertStore member of the reference to store.
 */
static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_LINK ref,
 PWINE_CERT_CONTEXT context, HCERTSTORE store)
{
    TRACE("(%p, %p)\n", ref, context);
    memcpy(&ref->cert, context, sizeof(ref->cert));
    ref->ref = 1;
    ref->type = ContextTypeLink;
    ref->linked = context;
    InterlockedIncrement(&context->ref);
    TRACE("%p's ref count is %ld\n", context, context->ref);
    ref->cert.hCertStore = store;
}

static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store,
 PWINE_CERT_CONTEXT cert, DWORD dwAddDisposition,
 PCCERT_CONTEXT *ppStoreContext)
{
    WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
    BOOL add = FALSE, ret;
    PCCERT_CONTEXT existing = NULL;

    TRACE("(%p, %p, %ld, %p)\n", store, cert, dwAddDisposition, ppStoreContext);

    if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
    {
        BYTE hashToAdd[20];
        DWORD size = sizeof(hashToAdd);

        ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)cert,
         CERT_HASH_PROP_ID, hashToAdd, &size);
        if (ret)
        {
            CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };

            existing = CertFindCertificateInStore(store,
             cert->cert.dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
             NULL);
        }
    }
    switch (dwAddDisposition)
    {
    case CERT_STORE_ADD_ALWAYS:
        add = TRUE;
        break;
    case CERT_STORE_ADD_NEW:
    {
        if (existing)
        {
            TRACE("found matching certificate, not adding\n");
            SetLastError(CRYPT_E_EXISTS);
            add = FALSE;
        }
        else
            add = TRUE;
        break;
    }
    case CERT_STORE_ADD_REPLACE_EXISTING:
    {
        add = TRUE;
        if (existing)
        {
            TRACE("found matching certificate, replacing\n");
            CertDeleteCertificateFromStore(existing);
        }
        break;
    }
    default:
        FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
        add = FALSE;
    }
    if (existing)
        CertFreeCertificateContext(existing);
    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)cert, store);
            EnterCriticalSection(&ms->cs);
            list_add_tail(&ms->certs, &entry->entry);
            LeaveCriticalSection(&ms->cs);
            if (ppStoreContext)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?