From 41f90c8fd7b64ea2749d6310cdb8a70d826dbae8 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Sun, 16 Apr 2006 19:12:28 +0000 Subject: [PATCH] Sync to Wine-0_9_10: Juan Lang - crypt32: Move context properties to a separate file. - crypt32: Move serialization functions to serialize.c. - crypt32: Implement CertGetValidUsages. - crypt32: Implement CertDuplicateStore. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync to Wine-0_9_9: Juan Lang - crypt32: implement CryptEnumOIDInfo and CryptFindOIDInfo. - implement CryptEnumOIDInfo and CryptFindOIDInfo - implement CertOIDToAlgId and CertAlgIdToOID using CryptFindOIDInfo - crypt32: Move certificate store functions to their own file. - crypt32: More encoding/decoding. Add support for encoding/decoding basic constraints and enhanced key usage, with tests. - crypt32: Move OIDToAlgID and AlgIDToOID to oid.c. - crypt32: Correct compile problem on gcc 2.95. - crypt32: Partially implement CertGetNameString. Henning Gerhardt - crypt32: Add German resource file. YunSong Hwang - crypt32: Add Korean translation. Alexander N. Sшrnes - Updated/new Norwegian Bokmеl resources. Eric Pouech - crypt32: Don't access a blob after freeing it. Sync to Wine-0_9_8: Juan Lang - crypt32: Fix a fixme, and remove an old comment. - crypt32: Output string type in trace. Alexandre Julliard - Include wine/port.h in files that use exceptions. Sync to Wine-0_9_7: Juan Lang - crypt32: Implement CertRDNValueToStrA and CertNameToStrA, with tests. - crypt32: Correct X509_NAME decoding, and more stringent tests. - crypt32: Implement CertRDNValueToStrW and CertNameToStrW, with tests. svn path=/trunk/; revision=21617 --- reactos/dll/win32/crypt32/cert.c | 3396 +++---------------- reactos/dll/win32/crypt32/crypt32.rbuild | 4 + reactos/dll/win32/crypt32/crypt32.rc | 33 +- reactos/dll/win32/crypt32/crypt32.spec | 33 +- reactos/dll/win32/crypt32/crypt32_De.rc | 166 + reactos/dll/win32/crypt32/crypt32_En.rc | 166 + reactos/dll/win32/crypt32/crypt32_Ko.rc | 167 + reactos/dll/win32/crypt32/crypt32_No.rc | 166 + reactos/dll/win32/crypt32/crypt32_private.h | 45 +- reactos/dll/win32/crypt32/cryptres.h | 163 + reactos/dll/win32/crypt32/encode.c | 304 +- reactos/dll/win32/crypt32/main.c | 136 +- reactos/dll/win32/crypt32/oid.c | 581 +++- reactos/dll/win32/crypt32/proplist.c | 215 ++ reactos/dll/win32/crypt32/serialize.c | 515 +++ reactos/dll/win32/crypt32/store.c | 2666 +++++++++++++++ reactos/dll/win32/crypt32/str.c | 441 +++ reactos/media/doc/README.WINE | 2 +- 18 files changed, 6057 insertions(+), 3142 deletions(-) create mode 100644 reactos/dll/win32/crypt32/crypt32_De.rc create mode 100644 reactos/dll/win32/crypt32/crypt32_En.rc create mode 100644 reactos/dll/win32/crypt32/crypt32_Ko.rc create mode 100644 reactos/dll/win32/crypt32/crypt32_No.rc create mode 100644 reactos/dll/win32/crypt32/cryptres.h create mode 100644 reactos/dll/win32/crypt32/proplist.c create mode 100644 reactos/dll/win32/crypt32/serialize.c create mode 100644 reactos/dll/win32/crypt32/store.c create mode 100644 reactos/dll/win32/crypt32/str.c diff --git a/reactos/dll/win32/crypt32/cert.c b/reactos/dll/win32/crypt32/cert.c index 4f822d190cf..52b8ce11511 100644 --- a/reactos/dll/win32/crypt32/cert.c +++ b/reactos/dll/win32/crypt32/cert.c @@ -1,6 +1,5 @@ /* - * Copyright 2002 Mike McCormack for CodeWeavers - * Copyright 2004,2005 Juan Lang + * 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 @@ -16,3005 +15,18 @@ * 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 #include #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); - -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); - TRACE("%p's ref count is %ld\n", context, 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)); - - TRACE("(%p, %p)\n", context, store); - 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; - TRACE("returning %d\n", ret); - 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)); - if (ret) - { - 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 void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref); - -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 = TRUE; - - /* 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); - /* FIXME: generally I should do the following, otherwise there is - * a memory leak. But doing so when called by - * CertDeleteCertificateFromStore results in a double free, so - * leaving commented for now. - ret = CertFreeCertificateContext((PCCERT_CONTEXT)cert); - */ - cert->entry.prev = cert->entry.next = &store->certs; - break; - } - } - 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; - struct list *storeNext = list_next(&store->stores, &storeEntry->entry); - - TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev); - - child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store, - pPrev ? pPrev->childContext : NULL); - if (pPrev) - { - pPrev->childContext = NULL; - CertFreeCertificateContext((PCCERT_CONTEXT)pPrev); - pPrev = 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 - { - 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); - RegCloseKey(subKey); - } - if (!rc) - ret = TRUE; - else - { - SetLastError(rc); - ret = FALSE; - } - return ret; -} - -static BOOL CRYPT_SerializeContextsToReg(HKEY key, - const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore) -{ - const void *context = NULL; - BOOL ret; - - do { - context = contextInterface->enumContextsInStore(memStore, context); - if (context) - { - BYTE hash[20]; - DWORD hashSize = sizeof(hash); - - ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash, - &hashSize); - if (ret) - { - DWORD size = 0; - LPBYTE buf = NULL; - - ret = contextInterface->serialize(context, 0, NULL, &size); - if (size) - buf = CryptMemAlloc(size); - if (buf) - { - ret = contextInterface->serialize(context, 0, buf, &size); - if (ret) - ret = CRYPT_WriteSerializedToReg(key, hash, buf, size); - } - CryptMemFree(buf); - } - } - else - ret = TRUE; - } while (ret && context != NULL); - if (context) - contextInterface->free(context); - return ret; -} - -static BOOL CRYPT_RegWriteToReg(PWINE_REGSTORE store) -{ - static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW }; - static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface, - &gCRLInterface, &gCTLInterface }; - struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL }; - BOOL ret = TRUE; - DWORD i; - - for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++) - { - HKEY key; - LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, - KEY_ALL_ACCESS, NULL, &key, NULL); - - if (!rc) - { - if (listToDelete[i]) - { - PWINE_HASH_TO_DELETE toDelete, next; - WCHAR asciiHash[20 * 2 + 1]; - - EnterCriticalSection(&store->cs); - LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i], - WINE_HASH_TO_DELETE, entry) - { - LONG rc; - - CRYPT_HashToStr(toDelete->hash, asciiHash); - TRACE("Removing %s\n", debugstr_w(asciiHash)); - rc = RegDeleteKeyW(key, asciiHash); - if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND) - { - SetLastError(rc); - ret = FALSE; - } - list_remove(&toDelete->entry); - CryptMemFree(toDelete); - } - LeaveCriticalSection(&store->cs); - } - ret = CRYPT_SerializeContextsToReg(key, interfaces[i], - store->memStore); - RegCloseKey(key); - } - else - { - SetLastError(rc); - ret = FALSE; - } - } - return ret; -} - -/* If force is true or the registry store is dirty, writes the contents of the - * store to the registry. - */ -static BOOL CRYPT_RegFlushStore(PWINE_REGSTORE store, BOOL force) -{ - BOOL ret; - - if (store->dirty || force) - ret = CRYPT_RegWriteToReg(store); - else - ret = TRUE; - return ret; -} - -static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) -{ - PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore; - - TRACE("(%p, %08lx)\n", store, dwFlags); - if (dwFlags) - FIXME("Unimplemented flags: %08lx\n", dwFlags); - - CRYPT_RegFlushStore(store, FALSE); - /* certsToDelete should already be cleared by this point */ - store->memStore->closeStore(store->memStore, 0); - RegCloseKey(store->key); - DeleteCriticalSection(&store->cs); - CryptMemFree(store); -} - -static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert, - DWORD dwAddDisposition) -{ - PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore; - BOOL ret; - - TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition); - - if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) - { - SetLastError(ERROR_ACCESS_DENIED); - ret = FALSE; - } - else - { - ret = store->memStore->addCert(store->memStore, cert, dwAddDisposition); - if (ret) - store->dirty = TRUE; - } - return ret; -} - -static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef( - PWINE_CERT_CONTEXT context, HCERTSTORE store) -{ - PWINE_REG_CERT_CONTEXT ret = CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT)); - - if (ret) - { - CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store); - ret->childContext = NULL; - } - return (PWINE_CERT_CONTEXT_REF)ret; -} - -static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store, - PWINE_CERT_CONTEXT_REF pPrev) -{ - PWINE_REGSTORE rs = (PWINE_REGSTORE)store; - PWINE_CERT_CONTEXT_REF child; - PWINE_REG_CERT_CONTEXT prev = (PWINE_REG_CERT_CONTEXT)pPrev, ret = NULL; - - TRACE("(%p, %p)\n", store, pPrev); - - child = rs->memStore->enumCert(rs->memStore, prev ? prev->childContext - : NULL); - if (prev) - { - prev->childContext = NULL; - CertFreeCertificateContext((PCCERT_CONTEXT)prev); - prev = NULL; - } - if (child) - { - ret = (PWINE_REG_CERT_CONTEXT)CRYPT_RegCreateCertRef(child->context, - store); - if (ret) - ret->childContext = child; - else - CertFreeCertificateContext((PCCERT_CONTEXT)child); - } - return (PWINE_CERT_CONTEXT_REF)ret; -} - -static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT pCertContext, DWORD dwFlags) -{ - PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore; - BOOL ret; - - TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags); - - if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) - { - SetLastError(ERROR_ACCESS_DENIED); - ret = FALSE; - } - else - { - PWINE_HASH_TO_DELETE toDelete = - CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE)); - - if (toDelete) - { - DWORD size = sizeof(toDelete->hash); - - ret = CertGetCertificateContextProperty(pCertContext, - CERT_HASH_PROP_ID, toDelete->hash, &size); - if (ret) - { - list_init(&toDelete->entry); - EnterCriticalSection(&store->cs); - list_add_tail(&store->certsToDelete, &toDelete->entry); - LeaveCriticalSection(&store->cs); - ret = store->memStore->deleteCert(store->memStore, pCertContext, - dwFlags); - } - else - CryptMemFree(toDelete); - } - else - ret = FALSE; - if (ret) - store->dirty = TRUE; - } - return ret; -} - -static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref) -{ - PWINE_REG_CERT_CONTEXT context = (PWINE_REG_CERT_CONTEXT)ref; - - TRACE("(%p)\n", ref); - - if (context->childContext) - CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext); -} - -static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags, - DWORD dwCtrlType, void const *pvCtrlPara) -{ - PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore; - BOOL ret; - - switch (dwCtrlType) - { - case CERT_STORE_CTRL_RESYNC: - CRYPT_RegFlushStore(store, FALSE); - store->memStore->closeStore(store->memStore, 0); - store->memStore = CRYPT_MemOpenStore(store->hdr.cryptProv, - store->hdr.dwOpenFlags, NULL); - if (store->memStore) - { - CRYPT_RegReadFromReg(store); - ret = TRUE; - } - else - ret = FALSE; - break; - case CERT_STORE_CTRL_COMMIT: - ret = CRYPT_RegFlushStore(store, - dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG); - break; - default: - FIXME("%ld: stub\n", dwCtrlType); - ret = FALSE; - } - return ret; -} - -/* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */ -static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey) -{ - DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i; - WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; - HKEY hSubKey = 0; - - TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey)); - - dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); - if (!dwRet) - { - /* Find how many subkeys there are */ - dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount, - &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); - if (!dwRet) - { - dwMaxSubkeyLen++; - if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR)) - { - /* Name too big: alloc a buffer for it */ - lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR)); - } - - if (!lpszName) - dwRet = ERROR_NOT_ENOUGH_MEMORY; - else - { - /* Recursively delete all the subkeys */ - for (i = 0; i < dwKeyCount && !dwRet; i++) - { - dwSize = dwMaxSubkeyLen; - dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, - NULL, NULL, NULL); - if (!dwRet) - dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName); - } - - if (lpszName != szNameBuf) - { - /* Free buffer if allocated */ - CryptMemFree(lpszName); - } - } - } - - RegCloseKey(hSubKey); - if (!dwRet) - dwRet = RegDeleteKeyW(hKey, lpszSubKey); - } - return dwRet; -} - -static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, - DWORD dwFlags, const void *pvPara) -{ - PWINE_REGSTORE store = NULL; - - TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara); - - if (dwFlags & CERT_STORE_DELETE_FLAG) - { - DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW); - - if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) - rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW); - if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) - rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW); - if (rc == ERROR_NO_MORE_ITEMS) - rc = ERROR_SUCCESS; - SetLastError(rc); - } - else - { - HKEY key; - - if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara, - GetCurrentProcess(), (LPHANDLE)&key, - dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS, - TRUE, 0)) - { - PWINECRYPT_CERTSTORE memStore; - - memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL); - if (memStore) - { - store = CryptMemAlloc(sizeof(WINE_REGSTORE)); - if (store) - { - memset(store, 0, sizeof(WINE_REGSTORE)); - CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, - StoreTypeReg); - store->hdr.closeStore = CRYPT_RegCloseStore; - store->hdr.addCert = CRYPT_RegAddCert; - store->hdr.createCertRef = CRYPT_RegCreateCertRef; - store->hdr.enumCert = CRYPT_RegEnumCert; - store->hdr.deleteCert = CRYPT_RegDeleteCert; - store->hdr.freeCert = CRYPT_RegFreeCert; - store->hdr.control = CRYPT_RegControl; - store->memStore = memStore; - store->key = key; - InitializeCriticalSection(&store->cs); - list_init(&store->certsToDelete); - CRYPT_RegReadFromReg(store); - store->dirty = FALSE; - } - } - } - } - TRACE("returning %p\n", store); - return (WINECRYPT_CERTSTORE *)store; -} - -/* FIXME: this isn't complete for the Root store, in which the top-level - * self-signed CA certs reside. Adding a cert to the Root store should present - * the user with a dialog indicating the consequences of doing so, and asking - * the user to confirm whether the cert should be added. - */ -static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv, - DWORD dwFlags, const void *pvPara) -{ - static const WCHAR fmt[] = { '%','s','\\','%','s',0 }; - LPCWSTR storeName = (LPCWSTR)pvPara; - LPWSTR storePath; - PWINECRYPT_CERTSTORE store = NULL; - HKEY root; - LPCWSTR base; - BOOL ret; - - TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, - debugstr_w((LPCWSTR)pvPara)); - - if (!pvPara) - { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return NULL; - } - - ret = TRUE; - switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) - { - case CERT_SYSTEM_STORE_LOCAL_MACHINE: - root = HKEY_LOCAL_MACHINE; - base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; - break; - case CERT_SYSTEM_STORE_CURRENT_USER: - root = HKEY_CURRENT_USER; - base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; - break; - case CERT_SYSTEM_STORE_CURRENT_SERVICE: - /* hklm\Software\Microsoft\Cryptography\Services\servicename\ - * SystemCertificates - */ - FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n", - debugstr_w(storeName)); - return NULL; - case CERT_SYSTEM_STORE_SERVICES: - /* hklm\Software\Microsoft\Cryptography\Services\servicename\ - * SystemCertificates - */ - FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n", - debugstr_w(storeName)); - return NULL; - case CERT_SYSTEM_STORE_USERS: - /* hku\user sid\Software\Microsoft\SystemCertificates */ - FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n", - debugstr_w(storeName)); - return NULL; - case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY: - root = HKEY_CURRENT_USER; - base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; - break; - case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY: - root = HKEY_LOCAL_MACHINE; - base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; - break; - case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE: - /* hklm\Software\Microsoft\EnterpriseCertificates */ - FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n", - debugstr_w(storeName)); - return NULL; - default: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return NULL; - } - - storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) * - sizeof(WCHAR)); - if (storePath) - { - LONG rc; - HKEY key; - REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : - KEY_ALL_ACCESS; - - wsprintfW(storePath, fmt, base, storeName); - if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG) - rc = RegOpenKeyExW(root, storePath, 0, sam, &key); - else - { - DWORD disp; - - rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL, - &key, &disp); - if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG && - disp == REG_OPENED_EXISTING_KEY) - { - RegCloseKey(key); - rc = ERROR_FILE_EXISTS; - } - } - if (!rc) - { - store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key); - RegCloseKey(key); - } - else - SetLastError(rc); - CryptMemFree(storePath); - } - return store; -} - -static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv, - DWORD dwFlags, const void *pvPara) -{ - int len; - PWINECRYPT_CERTSTORE ret = NULL; - - TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, - debugstr_a((LPCSTR)pvPara)); - - if (!pvPara) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return NULL; - } - len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0); - if (len) - { - LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); - - if (storeName) - { - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len); - ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName); - CryptMemFree(storeName); - } - } - return ret; -} - -static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv, - DWORD dwFlags, const void *pvPara) -{ - HCERTSTORE store = 0; - BOOL ret; - - TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, - debugstr_w((LPCWSTR)pvPara)); - - if (!pvPara) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return NULL; - } - /* This returns a different error than system registry stores if the - * location is invalid. - */ - switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) - { - case CERT_SYSTEM_STORE_LOCAL_MACHINE: - case CERT_SYSTEM_STORE_CURRENT_USER: - case CERT_SYSTEM_STORE_CURRENT_SERVICE: - case CERT_SYSTEM_STORE_SERVICES: - case CERT_SYSTEM_STORE_USERS: - case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY: - case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY: - case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE: - ret = TRUE; - break; - default: - SetLastError(ERROR_FILE_NOT_FOUND); - ret = FALSE; - } - if (ret) - { - HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, - 0, hCryptProv, dwFlags, pvPara); - - if (regStore) - { - store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, - CERT_STORE_CREATE_NEW_FLAG, NULL); - if (store) - { - CertAddStoreToCollection(store, regStore, - dwFlags & CERT_STORE_READONLY_FLAG ? 0 : - CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); - CertCloseStore(regStore, 0); - } - } - } - return (PWINECRYPT_CERTSTORE)store; -} - -static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv, - DWORD dwFlags, const void *pvPara) -{ - int len; - PWINECRYPT_CERTSTORE ret = NULL; - - TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, - debugstr_a((LPCSTR)pvPara)); - - if (!pvPara) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return NULL; - } - len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0); - if (len) - { - LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); - - if (storeName) - { - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len); - ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName); - CryptMemFree(storeName); - } - } - return ret; -} - -HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, - DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, - const void* pvPara) -{ - WINECRYPT_CERTSTORE *hcs; - StoreOpenFunc openFunc = NULL; - - TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider), - dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara); - - if (!HIWORD(lpszStoreProvider)) - { - switch (LOWORD(lpszStoreProvider)) - { - case (int)CERT_STORE_PROV_MEMORY: - openFunc = CRYPT_MemOpenStore; - break; - case (int)CERT_STORE_PROV_REG: - openFunc = CRYPT_RegOpenStore; - break; - case (int)CERT_STORE_PROV_COLLECTION: - openFunc = CRYPT_CollectionOpenStore; - break; - case (int)CERT_STORE_PROV_SYSTEM_A: - openFunc = CRYPT_SysOpenStoreA; - break; - case (int)CERT_STORE_PROV_SYSTEM_W: - openFunc = CRYPT_SysOpenStoreW; - break; - case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A: - openFunc = CRYPT_SysRegOpenStoreA; - break; - case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W: - openFunc = CRYPT_SysRegOpenStoreW; - break; - default: - if (LOWORD(lpszStoreProvider)) - FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider)); - } - } - else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY)) - openFunc = CRYPT_MemOpenStore; - else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM)) - openFunc = CRYPT_SysOpenStoreW; - else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION)) - openFunc = CRYPT_CollectionOpenStore; - else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY)) - openFunc = CRYPT_SysRegOpenStoreW; - else - { - FIXME("unimplemented type %s\n", lpszStoreProvider); - openFunc = NULL; - } - - if (!openFunc) - { - /* FIXME: need to look for an installed provider for this type */ - SetLastError(ERROR_FILE_NOT_FOUND); - hcs = NULL; - } - else - hcs = openFunc(hCryptProv, dwFlags, pvPara); - return (HCERTSTORE)hcs; -} - -HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv, - LPCSTR szSubSystemProtocol) -{ - HCERTSTORE ret = 0; - - if (szSubSystemProtocol) - { - int len = MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, NULL, - 0); - LPWSTR param = CryptMemAlloc(len * sizeof(WCHAR)); - - if (param) - { - MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, param, len); - ret = CertOpenSystemStoreW(hProv, param); - CryptMemFree(param); - } - } - else - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return ret; -} - -HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv, - LPCWSTR szSubSystemProtocol) -{ - HCERTSTORE ret; - - if (!szSubSystemProtocol) - { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return 0; - } - - /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and - * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any, - * it fails. - */ - ret = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, hProv, - CERT_STORE_CREATE_NEW_FLAG, NULL); - if (ret) - { - HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, - 0, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE, szSubSystemProtocol); - - if (store) - { - CertAddStoreToCollection(ret, store, - CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); - CertCloseStore(store, 0); - } - store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, - 0, hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol); - if (store) - { - CertAddStoreToCollection(ret, store, - CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); - CertCloseStore(store, 0); - } - } - return ret; -} - -BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType, - DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags) -{ - FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore, - dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags); - return TRUE; -} - -PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType, - const BYTE* pbCrlEncoded, DWORD cbCrlEncoded) -{ - PCRL_CONTEXT pcrl; - BYTE* data; - - TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded); - - /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */ - pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) ); - if( !pcrl ) - return NULL; - - data = CryptMemAlloc( cbCrlEncoded ); - if( !data ) - { - CryptMemFree( pcrl ); - return NULL; - } - - pcrl->dwCertEncodingType = dwCertEncodingType; - pcrl->pbCrlEncoded = data; - pcrl->cbCrlEncoded = cbCrlEncoded; - pcrl->pCrlInfo = NULL; - pcrl->hCertStore = 0; - - return pcrl; -} - -/* Decodes the encoded certificate and creates the certificate context for it. - * The reference count is initially zero, so you must create a reference to it - * to avoid leaking memory. - */ -static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext( - DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded) -{ - PWINE_CERT_CONTEXT cert = NULL; - BOOL ret; - PCERT_SIGNED_CONTENT_INFO signedCert = NULL; - PCERT_INFO certInfo = NULL; - DWORD size = 0; - - TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded, - cbCertEncoded); - - /* First try to decode it as a signed cert. */ - ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded, - cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, - (BYTE *)&signedCert, &size); - if (ret) - { - size = 0; - ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, - signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, - CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, - (BYTE *)&certInfo, &size); - LocalFree(signedCert); - } - /* Failing that, try it as an unsigned cert */ - if (!ret) - { - size = 0; - ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, - pbCertEncoded, cbCertEncoded, - CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, - (BYTE *)&certInfo, &size); - } - if (ret) - { - BYTE *data = NULL; - - cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT)); - if (!cert) - goto end; - data = CryptMemAlloc(cbCertEncoded); - if (!data) - { - CryptMemFree(cert); - cert = NULL; - goto end; - } - memcpy(data, pbCertEncoded, cbCertEncoded); - cert->cert.dwCertEncodingType = dwCertEncodingType; - cert->cert.pbCertEncoded = data; - cert->cert.cbCertEncoded = cbCertEncoded; - cert->cert.pCertInfo = certInfo; - cert->cert.hCertStore = 0; - cert->ref = 0; - InitializeCriticalSection(&cert->cs); - list_init(&cert->extendedProperties); - } - -end: - return cert; -} - -static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context) -{ - PWINE_CERT_PROPERTY prop, next; - - CryptMemFree(context->cert.pbCertEncoded); - LocalFree(context->cert.pCertInfo); - DeleteCriticalSection(&context->cs); - LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties, - WINE_CERT_PROPERTY, entry) - { - list_remove(&prop->entry); - CryptMemFree(prop->pbData); - CryptMemFree(prop); - } - CryptMemFree(context); -} - -PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType, - const BYTE *pbCertEncoded, DWORD cbCertEncoded) -{ - PWINE_CERT_CONTEXT cert; - PWINE_CERT_CONTEXT_REF ret = NULL; - - TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded, - cbCertEncoded); - - cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded, - cbCertEncoded); - if (cert) - ret = CRYPT_CreateCertRef(cert, 0); - return (PCCERT_CONTEXT)ret; -} - -/* Since the properties are stored in a list, this is a tad inefficient - * (O(n^2)) since I have to find the previous position every time. - */ -DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext, - DWORD dwPropId) -{ - PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext; - DWORD ret; - - TRACE("(%p, %ld)\n", pCertContext, dwPropId); - - EnterCriticalSection(&ref->context->cs); - if (dwPropId) - { - PWINE_CERT_PROPERTY cursor = NULL; - - LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties, - WINE_CERT_PROPERTY, entry) - { - if (cursor->hdr.propID == dwPropId) - break; - } - if (cursor) - { - if (cursor->entry.next != &ref->context->extendedProperties) - ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY, - entry)->hdr.propID; - else - ret = 0; - } - else - ret = 0; - } - else if (!list_empty(&ref->context->extendedProperties)) - ret = LIST_ENTRY(ref->context->extendedProperties.next, - WINE_CERT_PROPERTY, entry)->hdr.propID; - else - ret = 0; - LeaveCriticalSection(&ref->context->cs); - return ret; -} - -static BOOL CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context, DWORD dwPropId, - ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData, - DWORD *pcbData) -{ - BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData, - pcbData); - if (ret) - { - CRYPT_DATA_BLOB blob = { *pcbData, pvData }; - - ret = CRYPT_SetCertificateContextProperty(context, dwPropId, - 0, &blob); - } - return ret; -} - -static BOOL WINAPI CRYPT_GetCertificateContextProperty( - PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData) -{ - PWINE_CERT_PROPERTY prop; - BOOL ret, found; - - TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData); - - EnterCriticalSection(&context->cs); - ret = FALSE; - found = FALSE; - LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties, - WINE_CERT_PROPERTY, entry) - { - if (prop->hdr.propID == dwPropId) - { - if (!pvData) - { - *pcbData = prop->hdr.cb; - ret = TRUE; - } - else if (*pcbData < prop->hdr.cb) - { - SetLastError(ERROR_MORE_DATA); - *pcbData = prop->hdr.cb; - } - else - { - memcpy(pvData, prop->pbData, prop->hdr.cb); - *pcbData = prop->hdr.cb; - ret = TRUE; - } - found = TRUE; - } - break; - } - if (!found) - { - /* Implicit properties */ - switch (dwPropId) - { - case CERT_SHA1_HASH_PROP_ID: - ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_SHA1, - context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData, - pcbData); - break; - case CERT_MD5_HASH_PROP_ID: - ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5, - context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData, - pcbData); - break; - case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: - ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5, - context->cert.pCertInfo->Subject.pbData, - context->cert.pCertInfo->Subject.cbData, - pvData, pcbData); - break; - case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: - ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5, - context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, - context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, - pvData, pcbData); - break; - case CERT_SIGNATURE_HASH_PROP_ID: - case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID: - FIXME("implicit property %ld\n", dwPropId); - SetLastError(CRYPT_E_NOT_FOUND); - break; - default: - SetLastError(CRYPT_E_NOT_FOUND); - } - } - LeaveCriticalSection(&context->cs); - TRACE("returning %d\n", ret); - return ret; -} - -BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, - DWORD dwPropId, void *pvData, DWORD *pcbData) -{ - PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext; - BOOL ret; - - TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData); - - /* Special cases for invalid/special prop IDs. - */ - switch (dwPropId) - { - case 0: - case CERT_CERT_PROP_ID: - case CERT_CRL_PROP_ID: - case CERT_CTL_PROP_ID: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return FALSE; - case CERT_ACCESS_STATE_PROP_ID: - if (!pvData) - { - *pcbData = sizeof(DWORD); - return TRUE; - } - else if (*pcbData < sizeof(DWORD)) - { - SetLastError(ERROR_MORE_DATA); - *pcbData = sizeof(DWORD); - return FALSE; - } - else - { - DWORD state = 0; - - if (pCertContext->hCertStore) - { - PWINECRYPT_CERTSTORE store = - (PWINECRYPT_CERTSTORE)pCertContext->hCertStore; - - /* Take advantage of knowledge of the stores to answer the - * access state question - */ - if (store->type != StoreTypeReg || - !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG)) - state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG; - } - *(DWORD *)pvData = state; - return TRUE; - } - } - - ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId, - pvData, pcbData); - TRACE("returning %d\n", ret); - return ret; -} - -/* Copies cbData bytes from pbData to the context's property with ID - * dwPropId. - */ -static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context, - DWORD dwPropId, const BYTE *pbData, size_t cbData) -{ - BOOL ret = FALSE; - LPBYTE data; - - if (cbData) - { - data = CryptMemAlloc(cbData); - if (data) - memcpy(data, pbData, cbData); - } - else - data = NULL; - if (!cbData || data) - { - PWINE_CERT_PROPERTY prop; - - EnterCriticalSection(&context->cs); - LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties, - WINE_CERT_PROPERTY, entry) - { - if (prop->hdr.propID == dwPropId) - break; - } - if (prop && prop->entry.next != &context->extendedProperties) - { - CryptMemFree(prop->pbData); - prop->hdr.cb = cbData; - prop->pbData = cbData ? data : NULL; - ret = TRUE; - } - else - { - prop = CryptMemAlloc(sizeof(WINE_CERT_PROPERTY)); - if (prop) - { - prop->hdr.propID = dwPropId; - prop->hdr.unknown = 1; - prop->hdr.cb = cbData; - list_init(&prop->entry); - prop->pbData = cbData ? data : NULL; - list_add_tail(&context->extendedProperties, &prop->entry); - ret = TRUE; - } - else - CryptMemFree(data); - } - LeaveCriticalSection(&context->cs); - } - return ret; -} - -static BOOL WINAPI CRYPT_SetCertificateContextProperty( - PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData) -{ - BOOL ret = FALSE; - - TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData); - - if (!pvData) - { - PWINE_CERT_PROPERTY prop, next; - - EnterCriticalSection(&context->cs); - LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties, - WINE_CERT_PROPERTY, entry) - { - if (prop->hdr.propID == dwPropId) - { - list_remove(&prop->entry); - CryptMemFree(prop->pbData); - CryptMemFree(prop); - } - } - LeaveCriticalSection(&context->cs); - ret = TRUE; - } - else - { - switch (dwPropId) - { - case CERT_AUTO_ENROLL_PROP_ID: - case CERT_CTL_USAGE_PROP_ID: - case CERT_DESCRIPTION_PROP_ID: - case CERT_FRIENDLY_NAME_PROP_ID: - case CERT_HASH_PROP_ID: - case CERT_KEY_IDENTIFIER_PROP_ID: - case CERT_MD5_HASH_PROP_ID: - case CERT_NEXT_UPDATE_LOCATION_PROP_ID: - case CERT_PUBKEY_ALG_PARA_PROP_ID: - case CERT_PVK_FILE_PROP_ID: - case CERT_SIGNATURE_HASH_PROP_ID: - case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: - case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: - case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: - case CERT_ENROLLMENT_PROP_ID: - case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: - case CERT_RENEWAL_PROP_ID: - { - PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData; - - ret = CRYPT_SaveCertificateContextProperty(context, dwPropId, - blob->pbData, blob->cbData); - break; - } - case CERT_DATE_STAMP_PROP_ID: - ret = CRYPT_SaveCertificateContextProperty(context, dwPropId, - pvData, sizeof(FILETIME)); - break; - default: - FIXME("%ld: stub\n", dwPropId); - } - } - TRACE("returning %d\n", ret); - return ret; -} - -BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext, - DWORD dwPropId, DWORD dwFlags, const void *pvData) -{ - PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext; - BOOL ret; - - TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData); - - /* Handle special cases for "read-only"/invalid prop IDs. Windows just - * crashes on most of these, I'll be safer. - */ - switch (dwPropId) - { - case 0: - case CERT_ACCESS_STATE_PROP_ID: - case CERT_CERT_PROP_ID: - case CERT_CRL_PROP_ID: - case CERT_CTL_PROP_ID: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return FALSE; - } - ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId, - dwFlags, pvData); - TRACE("returning %d\n", ret); - return ret; -} - -/* Only the reference portion of the context is duplicated. The returned - * context has the cert store set to 0, to prevent the store's certificate free - * function from getting called on partial data. - * FIXME: is this okay? Needs a test. - */ -PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext( - PCCERT_CONTEXT pCertContext) -{ - PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret; - - TRACE("(%p)\n", pCertContext); - if (ref) - { - ret = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF)); - if (ret) - { - memcpy(ret, ref, sizeof(*ret)); - ret->cert.hCertStore = 0; - InterlockedIncrement(&ret->context->ref); - } - } - else - ret = NULL; - return (PCCERT_CONTEXT)ret; -} - -BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, - PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition, - PCCERT_CONTEXT *ppStoreContext) -{ - PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore; - PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext; - PWINE_CERT_CONTEXT cert; - BOOL ret; - - TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext, - dwAddDisposition, ppStoreContext); - - /* FIXME: some tests needed to verify return codes */ - if (!store) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType, - ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded); - if (cert) - { - PWINE_CERT_PROPERTY prop; - - ret = TRUE; - EnterCriticalSection(&ref->context->cs); - LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties, - WINE_CERT_PROPERTY, entry) - { - ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID, - prop->pbData, prop->hdr.cb); - if (!ret) - break; - } - LeaveCriticalSection(&ref->context->cs); - if (ret) - { - ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition); - if (ret && ppStoreContext) - *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert, - hCertStore); - } - if (!ret) - CRYPT_FreeCert(cert); - } - else - ret = FALSE; - return ret; -} - -BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore, - DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded, - DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext) -{ - WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore; - BOOL ret; - - TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType, - pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext); - - if (!hcs) - ret = FALSE; - else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - ret = FALSE; - else - { - PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext( - dwCertEncodingType, pbCertEncoded, cbCertEncoded); - - if (cert) - { - ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition); - if (ret && ppCertContext) - *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert, - hCertStore); - if (!ret) - CRYPT_FreeCert(cert); - } - else - ret = FALSE; - } - return ret; -} - -PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore, - PCCERT_CONTEXT pPrev) -{ - WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore; - PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev; - PCCERT_CONTEXT ret; - - TRACE("(%p, %p)\n", hCertStore, pPrev); - if (!hCertStore) - ret = NULL; - else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - ret = NULL; - else - ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev); - return ret; -} - -BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext) -{ - BOOL ret; - - TRACE("(%p)\n", pCertContext); - - if (!pCertContext) - ret = TRUE; - else if (!pCertContext->hCertStore) - { - ret = TRUE; - CertFreeCertificateContext(pCertContext); - } - else - { - PWINECRYPT_CERTSTORE hcs = - (PWINECRYPT_CERTSTORE)pCertContext->hCertStore; - - if (!hcs) - ret = TRUE; - else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - ret = FALSE; - else - { - ret = hcs->deleteCert(hcs, pCertContext, 0); - if (ret) - CertFreeCertificateContext(pCertContext); - } - } - return ret; -} - -BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore, - DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded, - DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext) -{ - FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore, - dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition, - ppCrlContext); - return FALSE; -} - -BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore, - PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition, - PCCRL_CONTEXT* ppStoreContext ) -{ - FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext, - dwAddDisposition, ppStoreContext); - return TRUE; -} - -BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext) -{ - FIXME("%p\n", pCrlContext ); - - return TRUE; -} - -BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext) -{ - FIXME("(%p): stub\n", pCrlContext); - return TRUE; -} - -PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore, - PCCRL_CONTEXT pPrev) -{ - FIXME("(%p, %p): stub\n", hCertStore, pPrev); - return NULL; -} - -PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType, - const BYTE* pbCtlEncoded, DWORD cbCtlEncoded) -{ - FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded, - cbCtlEncoded); - return NULL; -} - -BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore, - DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded, - DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext) -{ - FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore, - dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition, - ppCtlContext); - return FALSE; -} - -BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore, - PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition, - PCCTL_CONTEXT* ppStoreContext) -{ - FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext, - dwAddDisposition, ppStoreContext); - return TRUE; -} - -BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext) -{ - FIXME("(%p): stub\n", pCtlContext ); - return TRUE; -} - -BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext) -{ - FIXME("(%p): stub\n", pCtlContext); - return TRUE; -} - -PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore, - PCCTL_CONTEXT pPrev) -{ - FIXME("(%p, %p): stub\n", hCertStore, pPrev); - return NULL; -} - - -BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) -{ - WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore; - - TRACE("(%p, %08lx)\n", hCertStore, dwFlags); - - if( ! hCertStore ) - return TRUE; - - if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC ) - return FALSE; - - if (InterlockedDecrement(&hcs->ref) == 0) - { - TRACE("%p's ref count is 0, freeing\n", hcs); - hcs->dwMagic = 0; - if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) - CryptReleaseContext(hcs->cryptProv, 0); - hcs->closeStore(hcs, dwFlags); - } - else - TRACE("%p's ref count is %ld\n", hcs, hcs->ref); - return TRUE; -} - -BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags, - DWORD dwCtrlType, void const *pvCtrlPara) -{ - WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore; - BOOL ret; - - TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType, - pvCtrlPara); - - if (!hcs) - ret = FALSE; - else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - ret = FALSE; - else - { - if (hcs->control) - ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara); - else - ret = TRUE; - } - return ret; -} - -BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext, - DWORD dwPropId, void *pvData, DWORD *pcbData) -{ - FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData); - return FALSE; -} - -BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext, - DWORD dwPropId, DWORD dwFlags, const void *pvData) -{ - FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags, - pvData); - return FALSE; -} - -BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext, - DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) -{ - FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement, - pcbElement); - return FALSE; -} - -BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext, - DWORD dwPropId, void *pvData, DWORD *pcbData) -{ - FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData); - return FALSE; -} - -BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext, - DWORD dwPropId, DWORD dwFlags, const void *pvData) -{ - FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags, - pvData); - return FALSE; -} - -BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext, - DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) -{ - FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement, - pcbElement); - return FALSE; -} - -BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext, - DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) -{ - BOOL ret; - - TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement, - pcbElement); - - if (pCertContext) - { - PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext; - DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + - pCertContext->cbCertEncoded; - PWINE_CERT_PROPERTY prop; - - EnterCriticalSection(&ref->context->cs); - LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties, - WINE_CERT_PROPERTY, entry) - bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb; - if (!pbElement) - { - *pcbElement = bytesNeeded; - ret = TRUE; - } - else if (*pcbElement < bytesNeeded) - { - *pcbElement = bytesNeeded; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - PWINE_CERT_PROP_HEADER hdr; - - LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties, - WINE_CERT_PROPERTY, entry) - { - memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER)); - pbElement += sizeof(WINE_CERT_PROP_HEADER); - if (prop->hdr.cb) - { - memcpy(pbElement, prop->pbData, prop->hdr.cb); - pbElement += prop->hdr.cb; - } - } - hdr = (PWINE_CERT_PROP_HEADER)pbElement; - hdr->propID = CERT_CERT_PROP_ID; - hdr->unknown = 1; - hdr->cb = pCertContext->cbCertEncoded; - memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER), - pCertContext->pbCertEncoded, pCertContext->cbCertEncoded); - ret = TRUE; - } - LeaveCriticalSection(&ref->context->cs); - } - else - ret = FALSE; - return ret; -} - -/* Looks for the property with ID propID in the buffer buf. Returns a pointer - * to its header if a valid header is found, NULL if not. Valid means the - * length of thte property won't overrun buf, and the unknown field is 1. - */ -static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf, - DWORD size, DWORD propID) -{ - const WINE_CERT_PROP_HEADER *ret = NULL; - BOOL done = FALSE; - - while (size && !ret && !done) - { - if (size < sizeof(WINE_CERT_PROP_HEADER)) - { - SetLastError(CRYPT_E_FILE_ERROR); - done = TRUE; - } - else - { - const WINE_CERT_PROP_HEADER *hdr = - (const WINE_CERT_PROP_HEADER *)buf; - - size -= sizeof(WINE_CERT_PROP_HEADER); - buf += sizeof(WINE_CERT_PROP_HEADER); - if (size < hdr->cb) - { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - done = TRUE; - } - else if (!hdr->propID) - { - /* assume a zero prop ID means the data are uninitialized, so - * stop looking. - */ - done = TRUE; - } - else if (hdr->unknown != 1) - { - SetLastError(ERROR_FILE_NOT_FOUND); - done = TRUE; - } - else if (hdr->propID == propID) - ret = hdr; - else - { - buf += hdr->cb; - size -= hdr->cb; - } - } - } - return ret; -} - -static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement, - DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType) -{ - const void *context; - - TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags, - pdwContentType); - - if (!cbElement) - { - SetLastError(ERROR_END_OF_MEDIA); - return NULL; - } - - __TRY - { - const WINE_CONTEXT_INTERFACE *contextInterface = NULL; - const WINE_CERT_PROP_HEADER *hdr = NULL; - DWORD type = 0; - BOOL ret; - - ret = TRUE; - context = NULL; - if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG) - { - hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID); - if (hdr) - type = CERT_STORE_CERTIFICATE_CONTEXT; - else - { - hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID); - if (hdr) - type = CERT_STORE_CRL_CONTEXT; - else - { - hdr = CRYPT_findPropID(pbElement, cbElement, - CERT_CTL_PROP_ID); - if (hdr) - type = CERT_STORE_CTL_CONTEXT; - } - } - } - else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG) - { - hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID); - type = CERT_STORE_CERTIFICATE_CONTEXT; - } - else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG) - { - hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID); - type = CERT_STORE_CRL_CONTEXT; - } - else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG) - { - hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID); - type = CERT_STORE_CTL_CONTEXT; - } - - switch (type) - { - 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: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - ret = FALSE; - } - if (!hdr) - ret = FALSE; - - if (ret) - context = contextInterface->create(X509_ASN_ENCODING, - (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb); - if (ret && context) - { - BOOL noMoreProps = FALSE; - - while (!noMoreProps && ret) - { - if (cbElement < sizeof(WINE_CERT_PROP_HEADER)) - ret = FALSE; - else - { - const WINE_CERT_PROP_HEADER *hdr = - (const WINE_CERT_PROP_HEADER *)pbElement; - - TRACE("prop is %ld\n", hdr->propID); - cbElement -= sizeof(WINE_CERT_PROP_HEADER); - pbElement += sizeof(WINE_CERT_PROP_HEADER); - if (cbElement < hdr->cb) - { - SetLastError(HRESULT_FROM_WIN32( - ERROR_INVALID_PARAMETER)); - ret = FALSE; - } - else if (!hdr->propID) - { - /* Like in CRYPT_findPropID, stop if the propID is zero - */ - noMoreProps = TRUE; - } - else if (hdr->unknown != 1) - { - SetLastError(ERROR_FILE_NOT_FOUND); - ret = FALSE; - } - else if (hdr->propID != CERT_CERT_PROP_ID && - hdr->propID != CERT_CRL_PROP_ID && hdr->propID != - CERT_CTL_PROP_ID) - { - /* Have to create a blob for most types, but not - * for all.. arghh. - */ - switch (hdr->propID) - { - case CERT_AUTO_ENROLL_PROP_ID: - case CERT_CTL_USAGE_PROP_ID: - case CERT_DESCRIPTION_PROP_ID: - case CERT_FRIENDLY_NAME_PROP_ID: - case CERT_HASH_PROP_ID: - case CERT_KEY_IDENTIFIER_PROP_ID: - case CERT_MD5_HASH_PROP_ID: - case CERT_NEXT_UPDATE_LOCATION_PROP_ID: - case CERT_PUBKEY_ALG_PARA_PROP_ID: - case CERT_PVK_FILE_PROP_ID: - case CERT_SIGNATURE_HASH_PROP_ID: - case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: - case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: - case CERT_ENROLLMENT_PROP_ID: - case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: - case CERT_RENEWAL_PROP_ID: - { - CRYPT_DATA_BLOB blob = { hdr->cb, - (LPBYTE)pbElement }; - - ret = contextInterface->setProp(context, - hdr->propID, 0, &blob); - break; - } - case CERT_DATE_STAMP_PROP_ID: - ret = contextInterface->setProp(context, - hdr->propID, 0, pbElement); - break; - default: - FIXME("prop ID %ld: stub\n", hdr->propID); - } - } - pbElement += hdr->cb; - cbElement -= hdr->cb; - if (!cbElement) - noMoreProps = TRUE; - } - } - if (ret) - { - if (pdwContentType) - *pdwContentType = type; - } - else - { - contextInterface->free(context); - context = NULL; - } - } - } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - context = NULL; - } - __ENDTRY - return context; -} - -BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore, - const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags, - DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext) -{ - const void *context; - DWORD type; - BOOL ret; - - TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore, - pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags, - pdwContentType, ppvContext); - - /* Call the internal function, then delete the hashes. Tests show this - * function uses real hash values, not whatever's stored in the hash - * property. - */ - context = CRYPT_ReadSerializedElement(pbElement, cbElement, - dwContextTypeFlags, &type); - if (context) - { - const WINE_CONTEXT_INTERFACE *contextInterface = NULL; - - switch (type) - { - 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: - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - } - if (contextInterface) - { - contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL); - contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL); - contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0, - NULL); - if (pdwContentType) - *pdwContentType = type; - ret = contextInterface->addContextToStore(hCertStore, context, - dwAddDisposition, ppvContext); - contextInterface->free(context); - } - else - ret = FALSE; - } - else - ret = FALSE; - return ret; -} - -static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref) -{ - if (InterlockedDecrement(&ref->context->ref) == 0) - { - TRACE("%p's ref count is 0, freeing\n", ref->context); - CRYPT_FreeCert(ref->context); - } - else - TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref); -} - -BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext) -{ - TRACE("(%p)\n", pCertContext); - - if (pCertContext) - { - PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext; - PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore; - - CRYPT_UnrefCertificateContext(ref); - if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC && - store->freeCert) - store->freeCert(ref); - TRACE("freeing %p\n", ref); - CryptMemFree(ref); - } - return TRUE; -} - -PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, - DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, - const void *pvPara, PCCERT_CONTEXT pPrevCertContext) -{ - FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType, - dwFlags, dwType, pvPara, pPrevCertContext); - SetLastError(CRYPT_E_NOT_FOUND); - return NULL; -} - -BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore, - HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority) -{ - PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore; - WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore; - PWINE_STORE_LIST_ENTRY entry; - BOOL ret; - - TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore, - dwUpdateFlags, dwPriority); - - if (!collection || !sibling) - return TRUE; - if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return FALSE; - } - if (collection->hdr.type != StoreTypeCollection) - { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return FALSE; - } - if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return FALSE; - } - - entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY)); - if (entry) - { - InterlockedIncrement(&sibling->ref); - TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref); - entry->store = sibling; - entry->dwUpdateFlags = dwUpdateFlags; - entry->dwPriority = dwPriority; - list_init(&entry->entry); - TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority); - EnterCriticalSection(&collection->cs); - if (dwPriority) - { - PWINE_STORE_LIST_ENTRY cursor; - BOOL added = FALSE; - - LIST_FOR_EACH_ENTRY(cursor, &collection->stores, - WINE_STORE_LIST_ENTRY, entry) - { - if (cursor->dwPriority < dwPriority) - { - list_add_before(&cursor->entry, &entry->entry); - added = TRUE; - break; - } - } - if (!added) - list_add_tail(&collection->stores, &entry->entry); - } - else - list_add_tail(&collection->stores, &entry->entry); - LeaveCriticalSection(&collection->cs); - ret = TRUE; - } - else - ret = FALSE; - return ret; -} - -void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore, - HCERTSTORE hSiblingStore) -{ - PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore; - WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore; - PWINE_STORE_LIST_ENTRY store, next; - - TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore); - - if (!collection || !sibling) - return; - if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return; - } - if (collection->hdr.type != StoreTypeCollection) - return; - if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - { - SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); - return; - } - EnterCriticalSection(&collection->cs); - LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores, - WINE_STORE_LIST_ENTRY, entry) - { - if (store->store == sibling) - { - list_remove(&store->entry); - CertCloseStore(store->store, 0); - CryptMemFree(store); - break; - } - } - LeaveCriticalSection(&collection->cs); -} - PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr, CRYPT_ATTRIBUTE rgAttr[]) { @@ -3302,12 +314,402 @@ BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv, return ret; } -BOOL WINAPI CryptVerifyMessageSignature(/*PCRYPT_VERIFY_MESSAGE_PARA*/ void* pVerifyPara, - DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob, - BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert) +BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags, + PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage) { - FIXME("stub: %p, %ld, %p, %ld, %p, %p, %p\n", - pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob, - pbDecoded, pcbDecoded, ppSignerCert); - return FALSE; + PCERT_ENHKEY_USAGE usage = NULL; + DWORD bytesNeeded; + BOOL ret = TRUE; + + TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage); + + if (!pCertContext || !pcbUsage) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG)) + { + DWORD propSize = 0; + + if (CertGetCertificateContextProperty(pCertContext, + CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize)) + { + LPBYTE buf = CryptMemAlloc(propSize); + + if (buf) + { + if (CertGetCertificateContextProperty(pCertContext, + CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize)) + { + ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType, + X509_ENHANCED_KEY_USAGE, buf, propSize, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded); + } + CryptMemFree(buf); + } + } + } + if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG)) + { + PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE, + pCertContext->pCertInfo->cExtension, + pCertContext->pCertInfo->rgExtension); + + if (ext) + { + ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType, + X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded); + } + } + if (!usage) + { + /* If a particular location is specified, this should fail. Otherwise + * it should succeed with an empty usage. (This is true on Win2k and + * later, which we emulate.) + */ + if (dwFlags) + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = FALSE; + } + else + bytesNeeded = sizeof(CERT_ENHKEY_USAGE); + } + + if (ret) + { + if (!pUsage) + *pcbUsage = bytesNeeded; + else if (*pcbUsage < bytesNeeded) + { + SetLastError(ERROR_MORE_DATA); + *pcbUsage = bytesNeeded; + ret = FALSE; + } + else + { + *pcbUsage = bytesNeeded; + if (usage) + { + DWORD i; + LPSTR nextOID = (LPSTR)((LPBYTE)pUsage + + sizeof(CERT_ENHKEY_USAGE) + + usage->cUsageIdentifier * sizeof(LPSTR)); + + pUsage->cUsageIdentifier = usage->cUsageIdentifier; + pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage + + sizeof(CERT_ENHKEY_USAGE)); + for (i = 0; i < usage->cUsageIdentifier; i++) + { + pUsage->rgpszUsageIdentifier[i] = nextOID; + strcpy(nextOID, usage->rgpszUsageIdentifier[i]); + nextOID += strlen(nextOID) + 1; + } + } + else + pUsage->cUsageIdentifier = 0; + } + } + if (usage) + LocalFree(usage); + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, + PCERT_ENHKEY_USAGE pUsage) +{ + BOOL ret; + + TRACE("(%p, %p)\n", pCertContext, pUsage); + + if (pUsage) + { + CRYPT_DATA_BLOB blob = { 0, NULL }; + + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, + pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData); + if (ret) + { + ret = CertSetCertificateContextProperty(pCertContext, + CERT_ENHKEY_USAGE_PROP_ID, 0, &blob); + LocalFree(blob.pbData); + } + } + else + ret = CertSetCertificateContextProperty(pCertContext, + CERT_ENHKEY_USAGE_PROP_ID, 0, NULL); + return ret; +} + +BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext, + LPCSTR pszUsageIdentifier) +{ + BOOL ret; + DWORD size; + + TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier)); + + if (CertGetEnhancedKeyUsage(pCertContext, + CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size)) + { + PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size); + + if (usage) + { + ret = CertGetEnhancedKeyUsage(pCertContext, + CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size); + if (ret) + { + PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size + + sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1); + + if (newUsage) + { + LPSTR nextOID; + DWORD i; + + newUsage->rgpszUsageIdentifier = + (LPSTR *)((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE)); + nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier + + (usage->cUsageIdentifier + 1) * sizeof(LPSTR)); + for (i = 0; i < usage->cUsageIdentifier; i++) + { + newUsage->rgpszUsageIdentifier[i] = nextOID; + strcpy(nextOID, usage->rgpszUsageIdentifier[i]); + nextOID += strlen(nextOID) + 1; + } + newUsage->rgpszUsageIdentifier[i] = nextOID; + strcpy(nextOID, pszUsageIdentifier); + newUsage->cUsageIdentifier = i + 1; + ret = CertSetEnhancedKeyUsage(pCertContext, newUsage); + CryptMemFree(newUsage); + } + } + CryptMemFree(usage); + } + else + ret = FALSE; + } + else + { + PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) + + sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1); + + if (usage) + { + usage->rgpszUsageIdentifier = + (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE)); + usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage + + sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR)); + strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier); + usage->cUsageIdentifier = 1; + ret = CertSetEnhancedKeyUsage(pCertContext, usage); + CryptMemFree(usage); + } + else + ret = FALSE; + } + return ret; +} + +BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext, + LPCSTR pszUsageIdentifier) +{ + BOOL ret; + DWORD size; + CERT_ENHKEY_USAGE usage; + + TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier)); + + size = sizeof(usage); + ret = CertGetEnhancedKeyUsage(pCertContext, + CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size); + if (!ret && GetLastError() == ERROR_MORE_DATA) + { + PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size); + + if (pUsage) + { + ret = CertGetEnhancedKeyUsage(pCertContext, + CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size); + if (ret) + { + if (pUsage->cUsageIdentifier) + { + DWORD i; + BOOL found = FALSE; + + for (i = 0; i < pUsage->cUsageIdentifier; i++) + { + if (!strcmp(pUsage->rgpszUsageIdentifier[i], + pszUsageIdentifier)) + found = TRUE; + if (found && i < pUsage->cUsageIdentifier - 1) + pUsage->rgpszUsageIdentifier[i] = + pUsage->rgpszUsageIdentifier[i + 1]; + } + pUsage->cUsageIdentifier--; + /* Remove the usage if it's empty */ + if (pUsage->cUsageIdentifier) + ret = CertSetEnhancedKeyUsage(pCertContext, pUsage); + else + ret = CertSetEnhancedKeyUsage(pCertContext, NULL); + } + } + CryptMemFree(pUsage); + } + else + ret = FALSE; + } + else + { + /* it fit in an empty usage, therefore there's nothing to remove */ + ret = TRUE; + } + return ret; +} + +BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts, + int *cNumOIDSs, LPSTR *rghOIDs, DWORD *pcbOIDs) +{ + BOOL ret = TRUE; + DWORD i, cbOIDs = 0; + BOOL allUsagesValid = TRUE; + CERT_ENHKEY_USAGE validUsages = { 0, NULL }; + + TRACE("(%ld, %p, %p, %p, %ld)\n", cCerts, *rghCerts, cNumOIDSs, + rghOIDs, *pcbOIDs); + + for (i = 0; ret && i < cCerts; i++) + { + CERT_ENHKEY_USAGE usage; + DWORD size = sizeof(usage); + + ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size); + /* Success is deliberately ignored: it implies all usages are valid */ + if (!ret && GetLastError() == ERROR_MORE_DATA) + { + PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size); + + allUsagesValid = FALSE; + if (pUsage) + { + ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size); + if (ret) + { + if (!validUsages.cUsageIdentifier) + { + DWORD j; + + cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR); + validUsages.cUsageIdentifier = pUsage->cUsageIdentifier; + for (j = 0; j < validUsages.cUsageIdentifier; j++) + cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j]) + + 1; + validUsages.rgpszUsageIdentifier = + CryptMemAlloc(cbOIDs); + if (validUsages.rgpszUsageIdentifier) + { + LPSTR nextOID = (LPSTR) + ((LPBYTE)validUsages.rgpszUsageIdentifier + + validUsages.cUsageIdentifier * sizeof(LPSTR)); + + for (j = 0; j < validUsages.cUsageIdentifier; j++) + { + validUsages.rgpszUsageIdentifier[j] = nextOID; + lstrcpyA(validUsages.rgpszUsageIdentifier[j], + pUsage->rgpszUsageIdentifier[j]); + nextOID += lstrlenA(nextOID) + 1; + } + } + else + ret = FALSE; + } + else + { + DWORD j, k, validIndexes = 0, numRemoved = 0; + + /* Merge: build a bitmap of all the indexes of + * validUsages.rgpszUsageIdentifier that are in pUsage. + */ + for (j = 0; j < pUsage->cUsageIdentifier; j++) + { + for (k = 0; k < validUsages.cUsageIdentifier; k++) + { + if (!strcmp(pUsage->rgpszUsageIdentifier[j], + validUsages.rgpszUsageIdentifier[k])) + { + validIndexes |= (1 << k); + break; + } + } + } + /* Merge by removing from validUsages those that are + * not in the bitmap. + */ + for (j = 0; j < validUsages.cUsageIdentifier; j++) + { + if (!(validIndexes & (1 << j))) + { + if (j < validUsages.cUsageIdentifier - 1) + { + memcpy(&validUsages.rgpszUsageIdentifier[j], + &validUsages.rgpszUsageIdentifier[j + + numRemoved + 1], + (validUsages.cUsageIdentifier - numRemoved + - j - 1) * sizeof(LPSTR)); + cbOIDs -= lstrlenA( + validUsages.rgpszUsageIdentifier[j]) + 1 + + sizeof(LPSTR); + numRemoved++; + } + else + validUsages.cUsageIdentifier--; + } + } + } + } + CryptMemFree(pUsage); + } + else + ret = FALSE; + } + } + if (ret) + { + if (allUsagesValid) + { + *cNumOIDSs = -1; + *pcbOIDs = 0; + } + else + { + if (!rghOIDs || *pcbOIDs < cbOIDs) + { + *pcbOIDs = cbOIDs; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs + + validUsages.cUsageIdentifier * sizeof(LPSTR)); + + *pcbOIDs = cbOIDs; + *cNumOIDSs = validUsages.cUsageIdentifier; + for (i = 0; i < validUsages.cUsageIdentifier; i++) + { + rghOIDs[i] = nextOID; + lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]); + nextOID += lstrlenA(nextOID) + 1; + } + } + } + } + CryptMemFree(validUsages.rgpszUsageIdentifier); + return ret; } diff --git a/reactos/dll/win32/crypt32/crypt32.rbuild b/reactos/dll/win32/crypt32/crypt32.rbuild index 5e60131f731..26b946fd592 100644 --- a/reactos/dll/win32/crypt32/crypt32.rbuild +++ b/reactos/dll/win32/crypt32/crypt32.rbuild @@ -12,7 +12,11 @@ encode.c cert.c oid.c + proplist.c protectdata.c + serialize.c + store.c + str.c crypt32.rc crypt32.spec diff --git a/reactos/dll/win32/crypt32/crypt32.rc b/reactos/dll/win32/crypt32/crypt32.rc index af79f2ff1bf..412579b9cb7 100644 --- a/reactos/dll/win32/crypt32/crypt32.rc +++ b/reactos/dll/win32/crypt32/crypt32.rc @@ -1,7 +1,36 @@ -/* $Id$ */ +/* + * crypt32 dll resources + * + * Copyright (C) 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 + */ #define REACTOS_VERSION_DLL -#define REACTOS_STR_FILE_DESCRIPTION "Crypt\0" +#define REACTOS_STR_FILE_DESCRIPTION "CryptoAPI Library\0" #define REACTOS_STR_INTERNAL_NAME "crypt32\0" #define REACTOS_STR_ORIGINAL_FILENAME "crypt32.dll\0" + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "cryptres.h" + #include + +#include "crypt32_De.rc" +#include "crypt32_En.rc" +#include "crypt32_Ko.rc" +#include "crypt32_No.rc" diff --git a/reactos/dll/win32/crypt32/crypt32.spec b/reactos/dll/win32/crypt32/crypt32.spec index 897853c79ce..1273062d3cc 100644 --- a/reactos/dll/win32/crypt32/crypt32.spec +++ b/reactos/dll/win32/crypt32/crypt32.spec @@ -6,7 +6,7 @@ @ stdcall CertAddEncodedCertificateToStore(long long ptr long long ptr) @ stub CertAddEncodedCertificateToSystemStoreA @ stub CertAddEncodedCertificateToSystemStoreW -@ stub CertAddEnhancedKeyUsageIdentifier +@ stdcall CertAddEnhancedKeyUsageIdentifier(ptr str) @ stdcall CertAddSerializedElementToStore(ptr ptr long long long long ptr ptr) @ stdcall CertAddStoreToCollection(ptr ptr long long) @ stdcall CertAlgIdToOID(long) @@ -26,7 +26,7 @@ @ stub CertDuplicateCRLContext @ stub CertDuplicateCTLContext @ stdcall CertDuplicateCertificateContext(ptr) -@ stub CertDuplicateStore +@ stdcall CertDuplicateStore(ptr) @ stub CertEnumCRLContextProperties @ stdcall CertEnumCRLsInStore(ptr ptr) @ stub CertEnumCTLContextProperties @@ -49,23 +49,24 @@ @ stdcall CertGetCTLContextProperty(ptr long ptr ptr) @ stub CertGetCertificateChain @ stdcall CertGetCertificateContextProperty(ptr long ptr ptr) -@ stub CertGetEnhancedKeyUsage +@ stdcall CertGetEnhancedKeyUsage(ptr long ptr ptr) @ stub CertGetIntendedKeyUsage @ stub CertGetIssuerCertificateFromStore -@ stub CertGetNameStringA -@ stub CertGetNameStringW +@ stdcall CertGetNameStringA(ptr long long ptr ptr long) +@ stdcall CertGetNameStringW(ptr long long ptr ptr long) @ stub CertGetPublicKeyLength @ stub CertGetSubjectCertificateFromStore +@ stdcall CertGetValidUsages(long ptr ptr ptr ptr) @ stub CertIsRDNAttrsInCertificateName -@ stub CertNameToStrA -@ stub CertNameToStrW +@ stdcall CertNameToStrA(long ptr long ptr long) +@ stdcall CertNameToStrW(long ptr long ptr long) @ stdcall CertOIDToAlgId(str) @ stdcall CertOpenStore(str long long long ptr) @ stdcall CertOpenSystemStoreA(long str) @ stdcall CertOpenSystemStoreW(long wstr) -@ stub CertRDNValueToStrA -@ stub CertRDNValueToStrW -@ stub CertRemoveEnhancedKeyUsageIdentifier +@ stdcall CertRDNValueToStrA(long ptr ptr long) +@ stdcall CertRDNValueToStrW(long ptr ptr long) +@ stdcall CertRemoveEnhancedKeyUsageIdentifier(ptr str) @ stdcall CertRemoveStoreFromCollection(long long) @ stdcall CertSaveStore(long long long long ptr long) @ stdcall CertSerializeCRLStoreElement(ptr long ptr ptr) @@ -74,7 +75,7 @@ @ stdcall CertSetCRLContextProperty(ptr long long ptr) @ stdcall CertSetCTLContextProperty(ptr long long ptr) @ stdcall CertSetCertificateContextProperty(ptr long long ptr) -@ stub CertSetEnhancedKeyUsage +@ stdcall CertSetEnhancedKeyUsage(ptr ptr) @ stub CertStrToNameA @ stub CertStrToNameW @ stub CertVerifyCertificateChainPolicy @@ -98,12 +99,12 @@ @ stdcall CryptEncodeObjectEx(long str ptr long ptr ptr ptr) @ stub CryptEncryptMessage @ stub CryptEnumOIDFunction -@ stub CryptEnumOIDInfo +@ stdcall CryptEnumOIDInfo(long long ptr ptr) @ stub CryptEnumProvidersU @ stub CryptExportPKCS8 @ stdcall CryptExportPublicKeyInfo(long long long ptr ptr) @ stdcall CryptExportPublicKeyInfoEx(long long long str long ptr ptr ptr) -@ stub CryptFindOIDInfo +@ stdcall CryptFindOIDInfo(long ptr long) @ stub CryptFormatObject @ stdcall CryptFreeOIDFunctionAddress(long long) @ stub CryptGetAsyncParam @@ -140,6 +141,7 @@ @ stub CryptMsgUpdate @ stub CryptMsgVerifyCountersignatureEncoded @ stdcall CryptProtectData(ptr wstr ptr ptr ptr long ptr) +@ stdcall CryptQueryObject(long ptr long long long ptr ptr ptr ptr ptr ptr) @ stdcall CryptRegisterDefaultOIDFunction(long str long wstr) @ stdcall CryptRegisterOIDFunction(long str str wstr str) @ stub CryptRegisterOIDInfo @@ -178,10 +180,11 @@ @ stdcall I_CryptFreeTls(long long) @ stub I_CryptGetDefaultCryptProv @ stub I_CryptGetDefaultCryptProvForEncrypt -@ stub I_CryptGetOssGlobal +@ stdcall I_CryptGetOssGlobal(long) @ stdcall I_CryptGetTls(long) @ stub I_CryptInsertLruEntry -@ stub I_CryptInstallOssGlobal +@ stdcall I_CryptInstallAsn1Module(long long long) +@ stdcall I_CryptInstallOssGlobal(long long long) @ stub I_CryptReleaseLruEntry @ stdcall I_CryptSetTls(long ptr) @ stub I_CryptUninstallOssGlobal diff --git a/reactos/dll/win32/crypt32/crypt32_De.rc b/reactos/dll/win32/crypt32/crypt32_De.rc new file mode 100644 index 00000000000..81daada0c3d --- /dev/null +++ b/reactos/dll/win32/crypt32/crypt32_De.rc @@ -0,0 +1,166 @@ +/* + * crypt32 dll resources + * + * Copyright (C) 2006 Henning Gerhardt + * + * 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 + */ + +LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_AUTHORITY_KEY_ID "Autoritätsschlüsselkennung" + IDS_KEY_ATTRIBUTES "Schlüsselattribute" + IDS_KEY_USAGE_RESTRICTION "Schlüsselbenutzungseinschränkung" + IDS_SUBJECT_ALT_NAME "Alternativer Name des Antragsstellers" + IDS_ISSUER_ALT_NAME "Alternativer Name des Ausgebers" + IDS_BASIC_CONSTRAINTS "Grundsätzliche Einschränkungen" + IDS_KEY_USAGE "Schlüsselbenutzung" + IDS_CERT_POLICIES "Zertifikatsrichtlinien" + IDS_SUBJECT_KEY_IDENTIFIER "Schlüsselkennung des Antragsstellers" + IDS_CRL_REASON_CODE "CRL Grundcode" + IDS_CRL_DIST_POINTS "CRL Verteilungspunkte" + IDS_ENHANCED_KEY_USAGE "Erweiterte Schlüsselbenutzung" + IDS_AUTHORITY_INFO_ACCESS "Autoritätsinformationszugriff" + IDS_CERT_EXTENSIONS "Zertifikatserweiterung" + IDS_NEXT_UPDATE_LOCATION "Next Update Location" + IDS_YES_OR_NO_TRUST "Vertrauen oder nicht vertrauen" + IDS_EMAIL_ADDRESS "E-Mail-Adresse" + IDS_UNSTRUCTURED_NAME "Unstrukturierter Name" + IDS_CONTENT_TYPE "Inhaltstyp" + IDS_MESSAGE_DIGEST "Nachrichtenübersicht" + IDS_SIGNING_TIME "Signierungszeit" + IDS_COUNTER_SIGN "Gegensignatur" + IDS_CHALLENGE_PASSWORD "Challenge Password" + IDS_UNSTRUCTURED_ADDRESS "Unstrukturierte Adresse" + IDS_SMIME_CAPABILITIES "SMIME Möglichkeiten" + IDS_PREFER_SIGNED_DATA "Signierte Daten bevorzugen" + IDS_CPS "CPS" + IDS_USER_NOTICE "Benutzerbenachrichtung" + IDS_OCSP "Online Zertifikationsstatusprotokoll" + IDS_CA_ISSUER "Ausgeber des Zertifikationsautorität" + IDS_CERT_TEMPLATE_NAME "Zertifkationsvorlagenname" + IDS_CERT_TYPE "Zertifikationstyp" + IDS_CERT_MANIFOLD "Zertifikationsvervielfältigung" + IDS_NETSCAPE_CERT_TYPE "Netscape Zertifikationstyp" + IDS_NETSCAPE_BASE_URL "Netscape Basis-URL" + IDS_NETSCAPE_REVOCATION_URL "Netscape Sperrungs-URL" + IDS_NETSCAPE_CA_REVOCATION_URL "Netscape CA Sperrungs-URL" + IDS_NETSCAPE_CERT_RENEWAL_URL "Netscape Zertifikationsernerung-URL" + IDS_NETSCAPE_CA_POLICY_URL "Netscape CA Richtlinien-URL" + IDS_NETSCAPE_SSL_SERVER_NAME "Netscape SSL Servername" + IDS_NETSCAPE_COMMENT "Netscape Kommentar" + IDS_SPC_SP_AGENCY_INFO "SpcSp Agentur-Information" + IDS_SPC_FINANCIAL_CRITERIA "Spc Finanzielle Kriterien" + IDS_SPC_MINIMAL_CRITERIA "Spc Minimale Kriterien" + IDS_COUNTRY "Land/Region" + IDS_ORGANIZATION "Organisation" + IDS_ORGANIZATIONAL_UNIT "Organisationseinheit" + IDS_COMMON_NAME "Allgemeiner Name" + IDS_LOCALITY "Ort" + IDS_STATE_OR_PROVINCE "Bundesland oder Provinz" + IDS_TITLE "Titel" + IDS_GIVEN_NAME "Vorname" + IDS_INITIALS "Initialen" + IDS_SUR_NAME "Nachname" + IDS_DOMAIN_COMPONENT "Domänkomponente" + IDS_STREET_ADDRESS "Straße" + IDS_SERIAL_NUMBER "Seriennummer" + IDS_CA_VERSION "CA Version" + IDS_CROSS_CA_VERSION "Kreuz CA Version" + IDS_SERIALIZED_SIG_SERIAL_NUMBER "Serialisierte Signaturseriennummer" + IDS_PRINCIPAL_NAME "Prinzipalname" + IDS_WINDOWS_PRODUCT_UPDATE "Windows Produkt Aktualisierung" + IDS_ENROLLMENT_NAME_VALUE_PAIR "Wertepaar für Eintragungsname" + IDS_OS_VERSION "Betriebssystemversion" + IDS_ENROLLMENT_CSP "Eintragungs-CSP" + IDS_CRL_NUMBER "CRL Nummer" + IDS_DELTA_CRL_INDICATOR "Delta CRL Indikator" + IDS_ISSUING_DIST_POINT "Ausgeber des Verteilungspunktes" + IDS_FRESHEST_CRL "Aktuelle CRL" + IDS_NAME_CONSTRAINTS "Namenseinschränkungen" + IDS_POLICY_MAPPINGS "Richtlinienzuordnungen" + IDS_POLICY_CONSTRAINTS "Richtlinieneinschränkungen" + IDS_CROSS_CERT_DIST_POINTS "Verteilungspunkte für Kreuzzertifikate" + IDS_APPLICATION_POLICIES "Anwendungsrichtlinien" + IDS_APPLICATION_POLICY_MAPPINGS "Anwendungsrichtlinienzuordnungen" + IDS_APPLICATION_POLICY_CONSTRAINTS "Anweungsungsrichtlinieneinschränkungen" + IDS_CMC_DATA "CMC Daten" + IDS_CMC_RESPONSE "CMC Antwort" + IDS_UNSIGNED_CMC_REQUEST "Unsignierte CMC Antwort" + IDS_CMC_STATUS_INFO "CMC Statusinformation" + IDS_CMC_EXTENSIONS "CMC Erweiterungen" + IDS_CMC_ATTRIBUTES "CMC Attribute" + IDS_PKCS_7_DATA "PKCS 7 Daten" + IDS_PKCS_7_SIGNED "PKCS 7 signiert" + IDS_PKCS_7_ENVELOPED "PKCS 7 umhüllt" + IDS_PKCS_7_SIGNED_ENVELOPED "PKCS 7 signiert und umhüllt" + IDS_PKCS_7_DIGESTED "PKCS 7 Digested" + IDS_PKCS_7_ENCRYPTED "PKCS 7 verschlüsselt" + IDS_PREVIOUS_CA_CERT_HASH "Vorheriger CA Zertifikatshash" + IDS_CRL_VIRTUAL_BASE "Virtuelle Basis-CRL-Nummer" + IDS_CRL_NEXT_PUBLISH "Nächste CRL Veröffentlichung" + IDS_CA_EXCHANGE "CA Verschlüsselungszertifikat" + IDS_KEY_RECOVERY_AGENT "Agent zur Schlüsselwiederherstellung" + IDS_CERTIFICATE_TEMPLATE "Zertifikatsvorlageninformation" + IDS_ENTERPRISE_ROOT_OID "Unternehmensstamm-OID" + IDS_RDN_DUMMY_SIGNER "Attrapenunterzeichner" + IDS_ARCHIVED_KEY_ATTR "Verschlüsselter, privater Schlüssel" + IDS_CRL_SELF_CDP "Veröffentlichte CRL Standorte" + IDS_REQUIRE_CERT_CHAIN_POLICY "Erzwinge Zertifikatskettenrichtlinie" + IDS_TRANSACTION_ID "Transaktions-ID" + IDS_SENDER_NONCE "Sender einstweilen" + IDS_RECIPIENT_NONCE "Empfänger einstweilen" + IDS_REG_INFO "Registrierungsinformationen" + IDS_GET_CERTIFICATE "Bekomme Zertifikat" + IDS_GET_CRL "Bekomme CRL" + IDS_REVOKE_REQUEST "Anfrageablehnen" + IDS_QUERY_PENDING "Wartende Abfrage" + IDS_SORTED_CTL "Zertifikatsvertrauensliste" + IDS_ARCHIVED_KEY_CERT_HASH "Archivierter Schlüsselzertifikatshash" + IDS_PRIVATE_KEY_USAGE_PERIOD "Private Schlüsselbenutzungsdauer" + IDS_CLIENT_INFORMATION "Client Information" + IDS_SERVER_AUTHENTICATION "Server Authentifizierung" + IDS_CLIENT_AUTHENTICATION "Client Authentifizierung" + IDS_CODE_SIGNING "Codesignatur" + IDS_SECURE_EMAIL "Sichere E-Mail" + IDS_TIME_STAMPING "Zeitstempel" + IDS_MICROSOFT_TRUST_LIST_SIGNING "Microsoft Vertrauenslistensignatur" + IDS_MICROSOFT_TIME_STAMPING "Microsoft Zeitstempel" + IDS_IPSEC_END_SYSTEM "IP Sicherheitsendsystem" + IDS_IPSEC_TUNNEL "IP Sicherheitstunnelabschluss" + IDS_IPSEC_USER "IP Sicherheitsbenutzer" + IDS_EFS "Verschlüsseltes Dateisystem" + IDS_WHQL_CRYPTO "Windows Hardware Treiber Verifizierung" + IDS_NT5_CRYPTO "Windows System Komponenten Verifizierung" + IDS_OEM_WHQL_CRYPTO "OEM Windows System Komponenten Verifizierung" + IDS_EMBEDDED_NT_CRYPTO "Embedded Windows System Komponenten Verifizierung" + IDS_KEY_PACK_LICENSES "Schlüsselpaketlizenzen" + IDS_LICENSE_SERVER "Lizenzserver Verifizierung" + IDS_SMART_CARD_LOGON "Smartcard Login" + IDS_DIGITAL_RIGHTS "Digitale Rechte" + IDS_QUALIFIED_SUBORDINATION "Qualifizierte Unterordnung" + IDS_KEY_RECOVERY "Schlüsselwiederherstellung" + IDS_DOCUMENT_SIGNING "Dokumentensignatur" + IDS_IPSEC_IKE_INTERMEDIATE "dazwischenliegende IP Sicherheits-IKE" + IDS_FILE_RECOVERY "Dateiwiederherstellung" + IDS_ROOT_LIST_SIGNER "Stammlistengeber" + IDS_ANY_APPLICATION_POLICIES "Alle Anwendungsrichtlinien" + IDS_DS_EMAIL_REPLICATION "Verzeichnisdienst für E-Mail Replikation" + IDS_ENROLLMENT_AGENT "Agent für Zertifikationsanforderung" + IDS_LIFETIME_SIGNING "Lebensdauersignatur" + IDS_ANY_CERT_POLICY "Alle ausgegebenen Richtlinien" +} diff --git a/reactos/dll/win32/crypt32/crypt32_En.rc b/reactos/dll/win32/crypt32/crypt32_En.rc new file mode 100644 index 00000000000..5c02ba10f01 --- /dev/null +++ b/reactos/dll/win32/crypt32/crypt32_En.rc @@ -0,0 +1,166 @@ +/* + * crypt32 dll resources + * + * Copyright (C) 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 + */ + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_AUTHORITY_KEY_ID "Authority Key Identifier" + IDS_KEY_ATTRIBUTES "Key Attributes" + IDS_KEY_USAGE_RESTRICTION "Key Usage Restriction" + IDS_SUBJECT_ALT_NAME "Subject Alternative Name" + IDS_ISSUER_ALT_NAME "Issuer Alternative Name" + IDS_BASIC_CONSTRAINTS "Basic Constraints" + IDS_KEY_USAGE "Key Usage" + IDS_CERT_POLICIES "Certificate Policies" + IDS_SUBJECT_KEY_IDENTIFIER "Subject Key Identifier" + IDS_CRL_REASON_CODE "CRL Reason Code" + IDS_CRL_DIST_POINTS "CRL Distribution Points" + IDS_ENHANCED_KEY_USAGE "Enhanced Key Usage" + IDS_AUTHORITY_INFO_ACCESS "Authority Information Access" + IDS_CERT_EXTENSIONS "Certificate Extensions" + IDS_NEXT_UPDATE_LOCATION "Next Update Location" + IDS_YES_OR_NO_TRUST "Yes or No Trust" + IDS_EMAIL_ADDRESS "Email Address" + IDS_UNSTRUCTURED_NAME "Unstructured Name" + IDS_CONTENT_TYPE "Content Type" + IDS_MESSAGE_DIGEST "Message Digest" + IDS_SIGNING_TIME "Signing Time" + IDS_COUNTER_SIGN "Counter Sign" + IDS_CHALLENGE_PASSWORD "Challenge Password" + IDS_UNSTRUCTURED_ADDRESS "Unstructured Address" + IDS_SMIME_CAPABILITIES "SMIME Capabilities" + IDS_PREFER_SIGNED_DATA "Prefer Signed Data" + IDS_CPS "CPS" + IDS_USER_NOTICE "User Notice" + IDS_OCSP "On-line Certificate Status Protocol" + IDS_CA_ISSUER "Certification Authority Issuer" + IDS_CERT_TEMPLATE_NAME "Certification Template Name" + IDS_CERT_TYPE "Certificate Type" + IDS_CERT_MANIFOLD "Certificate Manifold" + IDS_NETSCAPE_CERT_TYPE "Netscape Cert Type" + IDS_NETSCAPE_BASE_URL "Netscape Base URL" + IDS_NETSCAPE_REVOCATION_URL "Netscape Revocation URL" + IDS_NETSCAPE_CA_REVOCATION_URL "Netscape CA Revocation URL" + IDS_NETSCAPE_CERT_RENEWAL_URL "Netscape Cert Renewal URL" + IDS_NETSCAPE_CA_POLICY_URL "Netscape CA Policy URL" + IDS_NETSCAPE_SSL_SERVER_NAME "Netscape SSL ServerName" + IDS_NETSCAPE_COMMENT "Netscape Comment" + IDS_SPC_SP_AGENCY_INFO "SpcSpAgencyInfo" + IDS_SPC_FINANCIAL_CRITERIA "SpcFinancialCriteria" + IDS_SPC_MINIMAL_CRITERIA "SpcMinimalCriteria" + IDS_COUNTRY "Country/Region" + IDS_ORGANIZATION "Organization" + IDS_ORGANIZATIONAL_UNIT "Organizational Unit" + IDS_COMMON_NAME "Common Name" + IDS_LOCALITY "Locality" + IDS_STATE_OR_PROVINCE "State or Province" + IDS_TITLE "Title" + IDS_GIVEN_NAME "Given Name" + IDS_INITIALS "Initials" + IDS_SUR_NAME "Sur Name" + IDS_DOMAIN_COMPONENT "Domain Component" + IDS_STREET_ADDRESS "Street Address" + IDS_SERIAL_NUMBER "Serial Number" + IDS_CA_VERSION "CA Version" + IDS_CROSS_CA_VERSION "Cross CA Version" + IDS_SERIALIZED_SIG_SERIAL_NUMBER "Serialized Signature Serial Number" + IDS_PRINCIPAL_NAME "Principal Name" + IDS_WINDOWS_PRODUCT_UPDATE "Windows Product Update" + IDS_ENROLLMENT_NAME_VALUE_PAIR "Enrollment Name Value Pair" + IDS_OS_VERSION "OS Version" + IDS_ENROLLMENT_CSP "Enrollment CSP" + IDS_CRL_NUMBER "CRL Number" + IDS_DELTA_CRL_INDICATOR "Delta CRL Indicator" + IDS_ISSUING_DIST_POINT "Issuing Distribution Point" + IDS_FRESHEST_CRL "Freshest CRL" + IDS_NAME_CONSTRAINTS "Name Constraints" + IDS_POLICY_MAPPINGS "Policy Mappings" + IDS_POLICY_CONSTRAINTS "Policy Constraints" + IDS_CROSS_CERT_DIST_POINTS "Cross-Certificate Distribution Points" + IDS_APPLICATION_POLICIES "Application Policies" + IDS_APPLICATION_POLICY_MAPPINGS "Application Policy Mappings" + IDS_APPLICATION_POLICY_CONSTRAINTS "Application Policy Constraints" + IDS_CMC_DATA "CMC Data" + IDS_CMC_RESPONSE "CMC Response" + IDS_UNSIGNED_CMC_REQUEST "Unsigned CMC Request" + IDS_CMC_STATUS_INFO "CMC Status Info" + IDS_CMC_EXTENSIONS "CMC Extensions" + IDS_CMC_ATTRIBUTES "CMC Attributes" + IDS_PKCS_7_DATA "PKCS 7 Data" + IDS_PKCS_7_SIGNED "PKCS 7 Signed" + IDS_PKCS_7_ENVELOPED "PKCS 7 Enveloped" + IDS_PKCS_7_SIGNED_ENVELOPED "PKCS 7 Signed Enveloped" + IDS_PKCS_7_DIGESTED "PKCS 7 Digested" + IDS_PKCS_7_ENCRYPTED "PKCS 7 Encrypted" + IDS_PREVIOUS_CA_CERT_HASH "Previous CA Certificate Hash" + IDS_CRL_VIRTUAL_BASE "Virtual Base CRL Number" + IDS_CRL_NEXT_PUBLISH "Next CRL Publish" + IDS_CA_EXCHANGE "CA Encryption Certificate" + IDS_KEY_RECOVERY_AGENT "Key Recovery Agent" + IDS_CERTIFICATE_TEMPLATE "Certificate Template Information" + IDS_ENTERPRISE_ROOT_OID "Enterprise Root OID" + IDS_RDN_DUMMY_SIGNER "Dummy Signer" + IDS_ARCHIVED_KEY_ATTR "Encrypted Private Key" + IDS_CRL_SELF_CDP "Published CRL Locations" + IDS_REQUIRE_CERT_CHAIN_POLICY "Enforce Certificate Chain Policy" + IDS_TRANSACTION_ID "Transaction Id" + IDS_SENDER_NONCE "Sender Nonce" + IDS_RECIPIENT_NONCE "Recipient Nonce" + IDS_REG_INFO "Reg Info" + IDS_GET_CERTIFICATE "Get Certificate" + IDS_GET_CRL "Get CRL" + IDS_REVOKE_REQUEST "Revoke Request" + IDS_QUERY_PENDING "Query Pending" + IDS_SORTED_CTL "Certificate Trust List" + IDS_ARCHIVED_KEY_CERT_HASH "Archived Key Certificate Hash" + IDS_PRIVATE_KEY_USAGE_PERIOD "Private Key Usage Period" + IDS_CLIENT_INFORMATION "Client Information" + IDS_SERVER_AUTHENTICATION "Server Authentication" + IDS_CLIENT_AUTHENTICATION "Client Authentication" + IDS_CODE_SIGNING "Code Signing" + IDS_SECURE_EMAIL "Secure Email" + IDS_TIME_STAMPING "Time Stamping" + IDS_MICROSOFT_TRUST_LIST_SIGNING "Microsoft Trust List Signing" + IDS_MICROSOFT_TIME_STAMPING "Microsoft Time Stamping" + IDS_IPSEC_END_SYSTEM "IP security end system" + IDS_IPSEC_TUNNEL "IP security tunnel termination" + IDS_IPSEC_USER "IP security user" + IDS_EFS "Encrypting File System" + IDS_WHQL_CRYPTO "Windows Hardware Driver Verification" + IDS_NT5_CRYPTO "Windows System Component Verification" + IDS_OEM_WHQL_CRYPTO "OEM Windows System Component Verification" + IDS_EMBEDDED_NT_CRYPTO "Embedded Windows System Component Verification" + IDS_KEY_PACK_LICENSES "Key Pack Licenses" + IDS_LICENSE_SERVER "License Server Verification" + IDS_SMART_CARD_LOGON "Smart Card Logon" + IDS_DIGITAL_RIGHTS "Digital Rights" + IDS_QUALIFIED_SUBORDINATION "Qualified Subordination" + IDS_KEY_RECOVERY "Key Recovery" + IDS_DOCUMENT_SIGNING "Document Signing" + IDS_IPSEC_IKE_INTERMEDIATE "IP security IKE intermediate" + IDS_FILE_RECOVERY "File Recovery" + IDS_ROOT_LIST_SIGNER "Root List Signer" + IDS_ANY_APPLICATION_POLICIES "All application policies" + IDS_DS_EMAIL_REPLICATION "Directory Service Email Replication" + IDS_ENROLLMENT_AGENT "Certificate Request Agent" + IDS_LIFETIME_SIGNING "Lifetime Signing" + IDS_ANY_CERT_POLICY "All issuance policies" +} diff --git a/reactos/dll/win32/crypt32/crypt32_Ko.rc b/reactos/dll/win32/crypt32/crypt32_Ko.rc new file mode 100644 index 00000000000..9054e8f918e --- /dev/null +++ b/reactos/dll/win32/crypt32/crypt32_Ko.rc @@ -0,0 +1,167 @@ +/* + * crypt32 dll resources + * + * Copyright (C) 2006 Juan Lang + * Copyright (C) 2006 YunSong Hwang + * + * 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 + */ + +LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_AUTHORITY_KEY_ID "Á¢±Ù Ű ½Äº°ÀÚ" + IDS_KEY_ATTRIBUTES "Ű ¼Ó¼º" + IDS_KEY_USAGE_RESTRICTION "Ű »ç¿ë Á¦ÇÑ" + IDS_SUBJECT_ALT_NAME "ÁÖÁ¦(subject) ´ëü À̸§" + IDS_ISSUER_ALT_NAME "¹ßÇàÀÚ ´ëü À̸§" + IDS_BASIC_CONSTRAINTS "±âº» Á¦¾à" + IDS_KEY_USAGE "Ű »ç¿ë¹ý" + IDS_CERT_POLICIES "ÀÎÁõ ¹æÄ§" + IDS_SUBJECT_KEY_IDENTIFIER "ÁÖÁ¦(Subject)Ű ½Äº°ÀÚ" + IDS_CRL_REASON_CODE "CRL ºÐº° ÄÚµå" + IDS_CRL_DIST_POINTS "CRL ¹èÆ÷ ÁöÁ¡" + IDS_ENHANCED_KEY_USAGE "È®ÀåµÈ Ű »ç¿ë¹ý" + IDS_AUTHORITY_INFO_ACCESS "±ÇÇÑ Á¤º¸ Á¢±Ù" + IDS_CERT_EXTENSIONS "ÀÎÁõ¼­ È®Àå(Certificate Extensions)" + IDS_NEXT_UPDATE_LOCATION "´ÙÀ½ ¾÷µ¥ÀÌÆ® À§Ä¡" + IDS_YES_OR_NO_TRUST "½Å·Ú(¿¹ ³ª ¾Æ´Ï¿À)" + IDS_EMAIL_ADDRESS "À̸ÞÀÏ ÁÖ¼Ò" + IDS_UNSTRUCTURED_NAME "ºñ±¸Á¶È­ À̸§" + IDS_CONTENT_TYPE "³»¿ë Çü½Ä" + IDS_MESSAGE_DIGEST "³»¿ë ¿ä¾à" + IDS_SIGNING_TIME "¼­¸í ½Ã°£" + IDS_COUNTER_SIGN "¿ª ¼­¸í(Counter Sign)" + IDS_CHALLENGE_PASSWORD "¾ÏÈ£ ¹Ù²Ù±â" + IDS_UNSTRUCTURED_ADDRESS "ºñ±¸Á¶È­ ÁÖ¼Ò" + IDS_SMIME_CAPABILITIES "SMIME Ư¼º" + IDS_PREFER_SIGNED_DATA "¼±È£ÇÏ´Â »çÀÎµÈ µ¥ÀÌŸ(Prefer Signed Data)" + IDS_CPS "CPS" + IDS_USER_NOTICE "»ç¿ëÀÚ ÅëÁö" + IDS_OCSP "¿Â¶óÀÎ ÀÎÁõ »óÅ ÇÁ·ÎÅäÄÝ" + IDS_CA_ISSUER "ÀÎÁõ¼­ Á¢±Ù ¹ßÇàÀÚ" + IDS_CERT_TEMPLATE_NAME "ÀÎÁõ ÇüÆÇ À̸§" + IDS_CERT_TYPE "ÀÎÁõ¼­ ÇüÅÂ" + IDS_CERT_MANIFOLD "ÀÎÁõ¼­ »çº»" + IDS_NETSCAPE_CERT_TYPE "³Ý½ºÄÉÀÌÇÁ ÀÎÁõ ÇüÅÂ" + IDS_NETSCAPE_BASE_URL "³Ý½ºÄÉÀÌÇÁ ±âº» À¥ÁÖ¼Ò" + IDS_NETSCAPE_REVOCATION_URL "³Ý½ºÄÉÀÌÇÁ Ãë¼Ò À¥ÁÖ¼Ò" + IDS_NETSCAPE_CA_REVOCATION_URL "³Ý½ºÄÉÀÌÇÁ CA Ãë¼Ò À¥ÁÖ¼Ò" + IDS_NETSCAPE_CERT_RENEWAL_URL "³Ý½ºÄÉÀÌÇÁ ÀÎÁõ¼­ Àç°³ À¥ÁÖ¼Ò" + IDS_NETSCAPE_CA_POLICY_URL "³Ý½ºÄÉÀÌÇÁ CA ¹æÄ§ URL" + IDS_NETSCAPE_SSL_SERVER_NAME "³Ý½ºÄÉÀÌÇÁ SSL ¼­¹öÀ̸§" + IDS_NETSCAPE_COMMENT "³Ý½ºÄÉÀÌÇÁ ¼³¸í" + IDS_SPC_SP_AGENCY_INFO "SpcSp°ü¸®ÀÚ Á¤º¸" + IDS_SPC_FINANCIAL_CRITERIA "SpcÀçÁ¤»ó ¿øÄ¢" + IDS_SPC_MINIMAL_CRITERIA "SpcÃÖ¼Ò ¿øÄ¢" + IDS_COUNTRY "³ª¶ó/Áö¿ª" + IDS_ORGANIZATION "´Üü" + IDS_ORGANIZATIONAL_UNIT "´Üü(Organizational Unit)" + IDS_COMMON_NAME "¾ÖĪ" + IDS_LOCALITY "¼ÒÀçÁö" + IDS_STATE_OR_PROVINCE "ÁÖ³ª Áö¹æ" + IDS_TITLE "Á¦¸ñ" + IDS_GIVEN_NAME "ÁÖ¾îÁø À̸§" + IDS_INITIALS "¸Ó¸´±ÛÀÚ" + IDS_SUR_NAME "¼º" + IDS_DOMAIN_COMPONENT "ÁÖ¼Ò ±¸¼º¿ä¼Ò" + IDS_STREET_ADDRESS "°Å¸® ÁÖ¼Ò" + IDS_SERIAL_NUMBER "½Ã¸®¾ó ¹øÈ£" + IDS_CA_VERSION "CA ¹öÁ¯" + IDS_CROSS_CA_VERSION "±³Â÷ CA ¹öÁ¯" + IDS_SERIALIZED_SIG_SERIAL_NUMBER "¿¬¼ÓµÈ(Serialized) ¼­¸í ½Ã¸®¾ó ³Ñ¹ö" + IDS_PRINCIPAL_NAME "ÁÖ¿äÇÑ À̸§" + IDS_WINDOWS_PRODUCT_UPDATE "À©µµ¿ìÁî Á¦Ç° ¾÷µ¥ÀÌÆ®" + IDS_ENROLLMENT_NAME_VALUE_PAIR "µî·Ï À̸§ °ªÀÇ ½Ö" + IDS_OS_VERSION "OS ¹öÁ¯" + IDS_ENROLLMENT_CSP "CSP µî·Ï" + IDS_CRL_NUMBER "CRL ¹øÈ£" + IDS_DELTA_CRL_INDICATOR "µ¨Å¸ CRL Ç¥½Ã±â" + IDS_ISSUING_DIST_POINT "¹ßÇàÀÚ ¹èÆ÷ À§Ä¡" + IDS_FRESHEST_CRL "ÃֽŠCRL" + IDS_NAME_CONSTRAINTS "À̸§ Á¦¾à" + IDS_POLICY_MAPPINGS "Á¤Ã¥ ´ëÀÀ" + IDS_POLICY_CONSTRAINTS "Á¤Ã¥ Á¦¾à" + IDS_CROSS_CERT_DIST_POINTS "»óÈ£ ÀÎÁõ ºÐ¹è À§Ä¡" + IDS_APPLICATION_POLICIES "Ç®±×¸² ¹æÄ§" + IDS_APPLICATION_POLICY_MAPPINGS "Ç®±×¸² Á¤Ã¥ ´ëÀÀ(Mappings)" + IDS_APPLICATION_POLICY_CONSTRAINTS "Ç®±×¸² Á¤Ã¥ Á¦¾à" + IDS_CMC_DATA "CMC µ¥ÀÌŸ" + IDS_CMC_RESPONSE "CMC ÀÀ´ä" + IDS_UNSIGNED_CMC_REQUEST "¼­¸íµÇÁö ¾ÊÀºCMC ¿äû" + IDS_CMC_STATUS_INFO "CMC »óÅ Á¤º¸" + IDS_CMC_EXTENSIONS "CMC È®Àå" + IDS_CMC_ATTRIBUTES "CMC ¼Ó¼º" + IDS_PKCS_7_DATA "PKCS 7 µ¥ÀÌŸ" + IDS_PKCS_7_SIGNED "PKCS 7 ¼­¸í" + IDS_PKCS_7_ENVELOPED "PKCS 7 ½Î°³" + IDS_PKCS_7_SIGNED_ENVELOPED "PKCS 7 ¼­¸íµÈ ½Î°³" + IDS_PKCS_7_DIGESTED "PKCS 7 ¿ä¾à" + IDS_PKCS_7_ENCRYPTED "PKCS 7 ¾Ïȣȭ" + IDS_PREVIOUS_CA_CERT_HASH "ÀÌÀüÀÇ CA ÀÎÁõ ÇØ½¬" + IDS_CRL_VIRTUAL_BASE "°¡»ó ±â¹Ý CRL ¼ýÀÚ(Virtual Base CRL Number)" + IDS_CRL_NEXT_PUBLISH "´ÙÀ½ CRL ¹ßÇà" + IDS_CA_EXCHANGE "CA ¾ÏÈ£ ÀÎÁõ" + IDS_KEY_RECOVERY_AGENT "Ű º¹±¸ °ü¸®ÀÚ" + IDS_CERTIFICATE_TEMPLATE "ÀÎÁõ ÁÖÇü(Template) Á¤º¸" + IDS_ENTERPRISE_ROOT_OID "±â¾÷ ·çÆ® OID" + IDS_RDN_DUMMY_SIGNER "°¡Â¥ »çÀÎÀÚ(Dummy Signer)" + IDS_ARCHIVED_KEY_ATTR "¾ÏȣȭµÈ °³ÀΠŰ" + IDS_CRL_SELF_CDP "¹ßÇàµÈ CRL À§Ä¡" + IDS_REQUIRE_CERT_CHAIN_POLICY "°­Á¦ ÀÎÁõ üÀÎ Á¤Ã¥(Enforce Certificate Chain Policy)" + IDS_TRANSACTION_ID "ó¸® Id" + IDS_SENDER_NONCE "Àӽà ¹ß¼ÛÀÎ" + IDS_RECIPIENT_NONCE "Àӽà ¼ö·ÉÀÎ" + IDS_REG_INFO "µî·Ï Á¤º¸" + IDS_GET_CERTIFICATE "ÀÎÁõ¼­ ¾ò±â" + IDS_GET_CRL "CRL ¾ò±â" + IDS_REVOKE_REQUEST "Ãë¼Ò ¿äû" + IDS_QUERY_PENDING "Áú¹®ÇÏ´Â Áß" + IDS_SORTED_CTL "ÀÎÁõµÈ ½Å·Ú ¸ñ·Ï" + IDS_ARCHIVED_KEY_CERT_HASH "¾ÐÃàµÈ Ű ÀÎÁõ ÇØ½¬" + IDS_PRIVATE_KEY_USAGE_PERIOD "°³ÀΠŰ »ç¿ë ±â°£" + IDS_CLIENT_INFORMATION "Ŭ¶óÀÌ¾ðÆ® Á¤º¸" + IDS_SERVER_AUTHENTICATION "¼­¹ö ÀÎÁõ" + IDS_CLIENT_AUTHENTICATION "Ŭ¶óÀÌ¾ðÆ® ÀÎÁõ" + IDS_CODE_SIGNING "ÄÚµå ¼­¸í" + IDS_SECURE_EMAIL "º¸¾È À̸ÞÀÏ" + IDS_TIME_STAMPING "½Ã°£ ³¯ÀÎ" + IDS_MICROSOFT_TRUST_LIST_SIGNING "¸¶ÀÌÅ©·Î¼ÒÇÁÆ® ½Å·Ú ¸ñ·Ï »çÀÎ" + IDS_MICROSOFT_TIME_STAMPING "¸¶ÀÌÅ©·Î¼ÒÇÁÆ® ½Ã°£ ³¯ÀÎ" + IDS_IPSEC_END_SYSTEM "IP º¸¾È Á¾´Ü ½Ã½ºÅÛ" + IDS_IPSEC_TUNNEL "IP º¸¾È ÅͳΠÁ¾·á(tunnel termination)" + IDS_IPSEC_USER "IP º¸¾È »ç¿ëÀÚ" + IDS_EFS "¾ÏȣȭµÈ ÆÄÀÏ ½Ã½ºÅÛ" + IDS_WHQL_CRYPTO "À©µµ¿ìÁî Çϵå¿þ¾î µå¶óÀ̹ö °ËÁõ" + IDS_NT5_CRYPTO "À©µµ¿ìÁî ½Ã½ºÅÛ ±¸¼º¿ä¼Ò °ËÁõ" + IDS_OEM_WHQL_CRYPTO "OEM À©µµ¿ìÁî ½Ã½ºÅÛ ±¸¼º¿ä¼Ò °ËÁõ" + IDS_EMBEDDED_NT_CRYPTO "³»ÀåµÈ À©µµ¿ìÁî ½Ã½ºÅÆ ±¸¼º¿ä¼Ò °ËÁß" + IDS_KEY_PACK_LICENSES "Ű ÆÑ ¶óÀ̼¾½º" + IDS_LICENSE_SERVER "¶óÀ̼¾½º ¼­¹ö °ËÁõ" + IDS_SMART_CARD_LOGON "½º¸¶Æ® Ä«µå ·Î±×ÀÎ" + IDS_DIGITAL_RIGHTS "µðÁöÅÐ ÀúÀÛ±Ç" + IDS_QUALIFIED_SUBORDINATION "ÀÚ°ÝÀÖ´Â Á¾¼Ó°ü°è" + IDS_KEY_RECOVERY "Ű º¹±¸" + IDS_DOCUMENT_SIGNING "¹®¼­ ¼­¸í" + IDS_IPSEC_IKE_INTERMEDIATE "IP º¸¾È IKE ¼ö´Ü(intermediate)" + IDS_FILE_RECOVERY "ÆÄÀÏ º¹±¸" + IDS_ROOT_LIST_SIGNER "·çÆ® ¸ñ·Ï ¼­¸íÀÚ" + IDS_ANY_APPLICATION_POLICIES "¸ðµç Ç®±×¸²ÀÇ ¹æÄ§" + IDS_DS_EMAIL_REPLICATION "µð·ºÅ丮 ¼­ºñ½º À̸ÞÀÏ ÀÀ´ä" + IDS_ENROLLMENT_AGENT "ÀÎÁõ ¿ä±¸ °ü¸®ÀÚ" + IDS_LIFETIME_SIGNING "Æò»ý ¼­¸í" + IDS_ANY_CERT_POLICY "¸ðµç ¹èÆ÷ ¹æÄ§" +} diff --git a/reactos/dll/win32/crypt32/crypt32_No.rc b/reactos/dll/win32/crypt32/crypt32_No.rc new file mode 100644 index 00000000000..3d2eb5aaa5b --- /dev/null +++ b/reactos/dll/win32/crypt32/crypt32_No.rc @@ -0,0 +1,166 @@ +/* + * crypt32 dll resources + * + * Copyright (C) 2006 Alexander N. Sørnes + * + * 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 + */ + +LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL + +STRINGTABLE DISCARDABLE +{ + IDS_AUTHORITY_KEY_ID "Identifiserer for autentiseringsnøkkel" + IDS_KEY_ATTRIBUTES "Nøkkelegenskaper" + IDS_KEY_USAGE_RESTRICTION "Begrensning av nøkkelbruk" + IDS_SUBJECT_ALT_NAME "Alternativt navn for emne" + IDS_ISSUER_ALT_NAME "Alternativt navn for utsteder" + IDS_BASIC_CONSTRAINTS "Basisbegrensninger" + IDS_KEY_USAGE "Nøkkelbruk" + IDS_CERT_POLICIES "Sertifikatholdninger" + IDS_SUBJECT_KEY_IDENTIFIER "Identifiserer for emnenøkkel" + IDS_CRL_REASON_CODE "CRL-grunnkode" + IDS_CRL_DIST_POINTS "CRL-distribusjonspunkter" + IDS_ENHANCED_KEY_USAGE "Forbedret nøkkelbruk" + IDS_AUTHORITY_INFO_ACCESS "Myndighet-informasjonstilgang" + IDS_CERT_EXTENSIONS "Sertifikatutvidelser" + IDS_NEXT_UPDATE_LOCATION "Neste oppdateringsplassering" + IDS_YES_OR_NO_TRUST "Ja eller nei tillit" + IDS_EMAIL_ADDRESS "E-postadresse" + IDS_UNSTRUCTURED_NAME "Ustrukturert navn" + IDS_CONTENT_TYPE "Innholdstype" + IDS_MESSAGE_DIGEST "Meldingssammendrag" + IDS_SIGNING_TIME "Signeringstidspunkt" + IDS_COUNTER_SIGN "Tellersymbol" + IDS_CHALLENGE_PASSWORD "Utfordre passord" + IDS_UNSTRUCTURED_ADDRESS "Ustrukturert adresse" + IDS_SMIME_CAPABILITIES "SMIME-evner" + IDS_PREFER_SIGNED_DATA "Fortrekk signert data" + IDS_CPS "CPS" + IDS_USER_NOTICE "Brukervarsel" + IDS_OCSP "On-line Certificate Status Protocol" + IDS_CA_ISSUER "Utsteder for sertifiseringsautoritet" + IDS_CERT_TEMPLATE_NAME "Navn på sertifiseringsmal" + IDS_CERT_TYPE "Sertifikattype" + IDS_CERT_MANIFOLD "Sertifikatmangfold" + IDS_NETSCAPE_CERT_TYPE "Netscape-sertifikattype" + IDS_NETSCAPE_BASE_URL "Netscape-basis-URL" + IDS_NETSCAPE_REVOCATION_URL "Netscape-tilbakekalling-URL" + IDS_NETSCAPE_CA_REVOCATION_URL "Netscape-CA-tilbakekalling-URLURL" + IDS_NETSCAPE_CERT_RENEWAL_URL "Netscape-sertifikatfornying-URL" + IDS_NETSCAPE_CA_POLICY_URL "Netscape-CA-politikk-URL" + IDS_NETSCAPE_SSL_SERVER_NAME "Netscape-SSL-tjenernavn" + IDS_NETSCAPE_COMMENT "Netscape-kommentar" + IDS_SPC_SP_AGENCY_INFO "SpcSpAgencyInfo" + IDS_SPC_FINANCIAL_CRITERIA "SpcFinancialCriteria" + IDS_SPC_MINIMAL_CRITERIA "SpcMinimalCriteria" + IDS_COUNTRY "Land/Region" + IDS_ORGANIZATION "Organisasjon" + IDS_ORGANIZATIONAL_UNIT "Organisasjonsell enhet" + IDS_COMMON_NAME "Vanlig navn" + IDS_LOCALITY "Lokalitet" + IDS_STATE_OR_PROVINCE "Fylke" + IDS_TITLE "Tittel" + IDS_GIVEN_NAME "Oppgitt navn" + IDS_INITIALS "Initialer" + IDS_SUR_NAME "Etternavn" + IDS_DOMAIN_COMPONENT "Domenekomponent" + IDS_STREET_ADDRESS "Gateadresse" + IDS_SERIAL_NUMBER "Serienummer" + IDS_CA_VERSION "CA-versjon" + IDS_CROSS_CA_VERSION "Kryss CA-versjon" + IDS_SERIALIZED_SIG_SERIAL_NUMBER "Serienummer for serialisert signatur" + IDS_PRINCIPAL_NAME "Hovednavn" + IDS_WINDOWS_PRODUCT_UPDATE "Windows-produktoppdatering" + IDS_ENROLLMENT_NAME_VALUE_PAIR "Innrullerings-navneverdipar" + IDS_OS_VERSION "OS-versjon" + IDS_ENROLLMENT_CSP "Innrullerings-CSP" + IDS_CRL_NUMBER "CRL-nummer" + IDS_DELTA_CRL_INDICATOR "Delta CRL-indikator" + IDS_ISSUING_DIST_POINT "Utsteder distribusjonspunkt" + IDS_FRESHEST_CRL "Nyeste CRL" + IDS_NAME_CONSTRAINTS "Navnebegrensninger" + IDS_POLICY_MAPPINGS "Framgangsmåtekartlegginger" + IDS_POLICY_CONSTRAINTS "Framgangsmåtebegresninger" + IDS_CROSS_CERT_DIST_POINTS "Distribusjonspunkter for kryss-sertifikat" + IDS_APPLICATION_POLICIES "Framgangsmåter for programmers" + IDS_APPLICATION_POLICY_MAPPINGS "Framgangsmåtekartlegginger for programmer" + IDS_APPLICATION_POLICY_CONSTRAINTS "Framgangsmåtebegrensninger for programmer" + IDS_CMC_DATA "CMC-data" + IDS_CMC_RESPONSE "CMS-svar" + IDS_UNSIGNED_CMC_REQUEST "Usignert CMC-forespørsel" + IDS_CMC_STATUS_INFO "CMC-statusinformasjon" + IDS_CMC_EXTENSIONS "CMC-utvidelser" + IDS_CMC_ATTRIBUTES "CMC-egenskaper" + IDS_PKCS_7_DATA "PKCS 7 Data" + IDS_PKCS_7_SIGNED "PKCS 7 Signert" + IDS_PKCS_7_ENVELOPED "PKCS 7 Innpakket" + IDS_PKCS_7_SIGNED_ENVELOPED "PKCS 7 Signert Innpakket" + IDS_PKCS_7_DIGESTED "PKCS 7 Fordøyet" + IDS_PKCS_7_ENCRYPTED "PKCS 7 Kryptert" + IDS_PREVIOUS_CA_CERT_HASH "Forrige CA-sertifikatlappskaus" + IDS_CRL_VIRTUAL_BASE "Virtuelt basis-CRL-nummer" + IDS_CRL_NEXT_PUBLISH "Neste CRL-utgiving" + IDS_CA_EXCHANGE "CA-krypteringssertifikat" + IDS_KEY_RECOVERY_AGENT "Agent for nøkkelgjenoppretting" + IDS_CERTIFICATE_TEMPLATE "Informasjon om sertifikatmal" + IDS_ENTERPRISE_ROOT_OID "Storselskap-rot-OID" + IDS_RDN_DUMMY_SIGNER "Tullesignerer" + IDS_ARCHIVED_KEY_ATTR "Kryptert privat nøkkel" + IDS_CRL_SELF_CDP "Publisert CRL-plasseringer" + IDS_REQUIRE_CERT_CHAIN_POLICY "Håndhev sertifikatlenkepolitikk" + IDS_TRANSACTION_ID "Transaksjons-id" + IDS_SENDER_NONCE "Gjeldende sender" + IDS_RECIPIENT_NONCE "Gjeldende mottaker" + IDS_REG_INFO "Reg info" + IDS_GET_CERTIFICATE "Hent sertifikat" + IDS_GET_CRL "Hent CRL" + IDS_REVOKE_REQUEST "Gjenoppliv forespørsel" + IDS_QUERY_PENDING "Spørring venter" + IDS_SORTED_CTL "Tillitsliste for sertifikater" + IDS_ARCHIVED_KEY_CERT_HASH "Arkivert nøkkelsertifikatlappskaus" + IDS_PRIVATE_KEY_USAGE_PERIOD "Privat nøkkelbrukperiode" + IDS_CLIENT_INFORMATION "Klientinformasjon" + IDS_SERVER_AUTHENTICATION "Tjenerautentisering" + IDS_CLIENT_AUTHENTICATION "Klientautentisering" + IDS_CODE_SIGNING "Kodesignering" + IDS_SECURE_EMAIL "Sikker e-post" + IDS_TIME_STAMPING "Tidsstempling" + IDS_MICROSOFT_TRUST_LIST_SIGNING "Microsoft tillitslistesignering" + IDS_MICROSOFT_TIME_STAMPING "Microsoft tidsstempling" + IDS_IPSEC_END_SYSTEM "IP-sikkerhetsendesystem" + IDS_IPSEC_TUNNEL "IP-sikkerhetstunnel-terminering" + IDS_IPSEC_USER "IP-sikkerhetsbruker" + IDS_EFS "Krypterer filsystem" + IDS_WHQL_CRYPTO "Windows maskinvaredriver-godkjenning" + IDS_NT5_CRYPTO "Windows sytemkomponent-godkjenning" + IDS_OEM_WHQL_CRYPTO "OEM Windows systemkomponent-godkjenning" + IDS_EMBEDDED_NT_CRYPTO "Innebygget Windows systemkomponent-godkjenning" + IDS_KEY_PACK_LICENSES "Nøkkelpakkelisenser" + IDS_LICENSE_SERVER "Lisenstjener-verifisering" + IDS_SMART_CARD_LOGON "Smart Card-pålogging" + IDS_DIGITAL_RIGHTS "Digitale rettigheter" + IDS_QUALIFIED_SUBORDINATION "Kvalifisert underordinering" + IDS_KEY_RECOVERY "Nøkkelgjenoppretting" + IDS_DOCUMENT_SIGNING "Dokumentsignering" + IDS_IPSEC_IKE_INTERMEDIATE "IP-sikkerhet IKE viderekommen" + IDS_FILE_RECOVERY "Filgjenoppretting" + IDS_ROOT_LIST_SIGNER "Rotlistesignerer" + IDS_ANY_APPLICATION_POLICIES "Alle framgangsmåter for programmer" + IDS_DS_EMAIL_REPLICATION "Katalogtjeneste e-postreplikering" + IDS_ENROLLMENT_AGENT "Agent for sertifikatforespørsler" + IDS_LIFETIME_SIGNING "Livstidsignering" + IDS_ANY_CERT_POLICY "Alle framgangsmåter for utsteding" +} diff --git a/reactos/dll/win32/crypt32/crypt32_private.h b/reactos/dll/win32/crypt32/crypt32_private.h index 1bf5f6fa210..25c41e4611b 100644 --- a/reactos/dll/win32/crypt32/crypt32_private.h +++ b/reactos/dll/win32/crypt32/crypt32_private.h @@ -19,12 +19,53 @@ #ifndef __CRYPT32_PRIVATE_H__ #define __CRYPT32_PRIVATE_H__ +/* 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 + /* Returns a handle to the default crypto provider; loads it if necessary. * Returns NULL on failure. */ HCRYPTPROV CRYPT_GetDefaultProvider(void); -void CRYPT_InitFunctionSets(void); -void CRYPT_FreeFunctionSets(void); +void crypt_oid_init(HINSTANCE hinst); +void crypt_oid_free(void); + +/* 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. + */ +const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, + DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType); + +/** + * Context property list functions + */ +struct _CONTEXT_PROPERTY_LIST; +typedef struct _CONTEXT_PROPERTY_LIST *PCONTEXT_PROPERTY_LIST; + +PCONTEXT_PROPERTY_LIST ContextPropertyList_Create(void); + +/* Searches for the property with ID id in the context. Returns TRUE if found, + * and copies the property's length and a pointer to its data to blob. + * Otherwise returns FALSE. + */ +BOOL ContextPropertyList_FindProperty(PCONTEXT_PROPERTY_LIST list, DWORD id, + PCRYPT_DATA_BLOB blob); + +BOOL ContextPropertyList_SetProperty(PCONTEXT_PROPERTY_LIST list, DWORD id, + const BYTE *pbData, size_t cbData); + +void ContextPropertyList_RemoveProperty(PCONTEXT_PROPERTY_LIST list, DWORD id); + +DWORD ContextPropertyList_EnumPropIDs(PCONTEXT_PROPERTY_LIST list, DWORD id); + +void ContextPropertyList_Copy(PCONTEXT_PROPERTY_LIST to, + PCONTEXT_PROPERTY_LIST from); + +void ContextPropertyList_Free(PCONTEXT_PROPERTY_LIST list); #endif diff --git a/reactos/dll/win32/crypt32/cryptres.h b/reactos/dll/win32/crypt32/cryptres.h new file mode 100644 index 00000000000..445be22162d --- /dev/null +++ b/reactos/dll/win32/crypt32/cryptres.h @@ -0,0 +1,163 @@ +/* + * Copyright 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 + */ +#ifndef __WINE_CRYPTRES_H__ +#define __WINE_CRYPTRES_H__ + +#define IDS_AUTHORITY_KEY_ID 1000 +#define IDS_KEY_ATTRIBUTES 1001 +#define IDS_KEY_USAGE_RESTRICTION 1002 +#define IDS_SUBJECT_ALT_NAME 1003 +#define IDS_ISSUER_ALT_NAME 1004 +#define IDS_BASIC_CONSTRAINTS 1005 +#define IDS_KEY_USAGE 1006 +#define IDS_CERT_POLICIES 1007 +#define IDS_SUBJECT_KEY_IDENTIFIER 1008 +#define IDS_CRL_REASON_CODE 1009 +#define IDS_CRL_DIST_POINTS 1010 +#define IDS_ENHANCED_KEY_USAGE 1011 +#define IDS_AUTHORITY_INFO_ACCESS 1012 +#define IDS_CERT_EXTENSIONS 1013 +#define IDS_NEXT_UPDATE_LOCATION 1014 +#define IDS_YES_OR_NO_TRUST 1015 +#define IDS_EMAIL_ADDRESS 1016 +#define IDS_UNSTRUCTURED_NAME 1017 +#define IDS_CONTENT_TYPE 1018 +#define IDS_MESSAGE_DIGEST 1019 +#define IDS_SIGNING_TIME 1020 +#define IDS_COUNTER_SIGN 1021 +#define IDS_CHALLENGE_PASSWORD 1022 +#define IDS_UNSTRUCTURED_ADDRESS 1023 +#define IDS_SMIME_CAPABILITIES 1024 +#define IDS_PREFER_SIGNED_DATA 1025 +#define IDS_CPS 1026 +#define IDS_USER_NOTICE 1027 +#define IDS_OCSP 1028 +#define IDS_CA_ISSUER 1029 +#define IDS_CERT_TEMPLATE_NAME 1030 +#define IDS_CERT_TYPE 1031 +#define IDS_CERT_MANIFOLD 1032 +#define IDS_NETSCAPE_CERT_TYPE 1033 +#define IDS_NETSCAPE_BASE_URL 1034 +#define IDS_NETSCAPE_REVOCATION_URL 1035 +#define IDS_NETSCAPE_CA_REVOCATION_URL 1036 +#define IDS_NETSCAPE_CERT_RENEWAL_URL 1037 +#define IDS_NETSCAPE_CA_POLICY_URL 1038 +#define IDS_NETSCAPE_SSL_SERVER_NAME 1039 +#define IDS_NETSCAPE_COMMENT 1040 +#define IDS_SPC_SP_AGENCY_INFO 1041 +#define IDS_SPC_FINANCIAL_CRITERIA 1042 +#define IDS_SPC_MINIMAL_CRITERIA 1043 +#define IDS_COUNTRY 1044 +#define IDS_ORGANIZATION 1045 +#define IDS_ORGANIZATIONAL_UNIT 1046 +#define IDS_COMMON_NAME 1047 +#define IDS_LOCALITY 1048 +#define IDS_STATE_OR_PROVINCE 1049 +#define IDS_TITLE 1050 +#define IDS_GIVEN_NAME 1051 +#define IDS_INITIALS 1052 +#define IDS_SUR_NAME 1053 +#define IDS_DOMAIN_COMPONENT 1054 +#define IDS_STREET_ADDRESS 1055 +#define IDS_SERIAL_NUMBER 1056 +#define IDS_CA_VERSION 1057 +#define IDS_CROSS_CA_VERSION 1058 +#define IDS_SERIALIZED_SIG_SERIAL_NUMBER 1059 +#define IDS_PRINCIPAL_NAME 1060 +#define IDS_WINDOWS_PRODUCT_UPDATE 1061 +#define IDS_ENROLLMENT_NAME_VALUE_PAIR 1062 +#define IDS_OS_VERSION 1063 +#define IDS_ENROLLMENT_CSP 1064 +#define IDS_CRL_NUMBER 1065 +#define IDS_DELTA_CRL_INDICATOR 1066 +#define IDS_ISSUING_DIST_POINT 1067 +#define IDS_FRESHEST_CRL 1068 +#define IDS_NAME_CONSTRAINTS 1069 +#define IDS_POLICY_MAPPINGS 1070 +#define IDS_POLICY_CONSTRAINTS 1071 +#define IDS_CROSS_CERT_DIST_POINTS 1072 +#define IDS_APPLICATION_POLICIES 1073 +#define IDS_APPLICATION_POLICY_MAPPINGS 1074 +#define IDS_APPLICATION_POLICY_CONSTRAINTS 1075 +#define IDS_CMC_DATA 1076 +#define IDS_CMC_RESPONSE 1077 +#define IDS_UNSIGNED_CMC_REQUEST 1078 +#define IDS_CMC_STATUS_INFO 1079 +#define IDS_CMC_EXTENSIONS 1080 +#define IDS_CMC_ATTRIBUTES 1081 +#define IDS_PKCS_7_DATA 1082 +#define IDS_PKCS_7_SIGNED 1083 +#define IDS_PKCS_7_ENVELOPED 1084 +#define IDS_PKCS_7_SIGNED_ENVELOPED 1085 +#define IDS_PKCS_7_DIGESTED 1086 +#define IDS_PKCS_7_ENCRYPTED 1087 +#define IDS_PREVIOUS_CA_CERT_HASH 1088 +#define IDS_CRL_VIRTUAL_BASE 1089 +#define IDS_CRL_NEXT_PUBLISH 1090 +#define IDS_CA_EXCHANGE 1091 +#define IDS_KEY_RECOVERY_AGENT 1092 +#define IDS_CERTIFICATE_TEMPLATE 1093 +#define IDS_ENTERPRISE_ROOT_OID 1094 +#define IDS_RDN_DUMMY_SIGNER 1095 +#define IDS_ARCHIVED_KEY_ATTR 1096 +#define IDS_CRL_SELF_CDP 1097 +#define IDS_REQUIRE_CERT_CHAIN_POLICY 1098 +#define IDS_TRANSACTION_ID 1099 +#define IDS_SENDER_NONCE 1100 +#define IDS_RECIPIENT_NONCE 1101 +#define IDS_REG_INFO 1102 +#define IDS_GET_CERTIFICATE 1103 +#define IDS_GET_CRL 1104 +#define IDS_REVOKE_REQUEST 1105 +#define IDS_QUERY_PENDING 1106 +#define IDS_SORTED_CTL 1107 +#define IDS_ARCHIVED_KEY_CERT_HASH 1108 +#define IDS_PRIVATE_KEY_USAGE_PERIOD 1109 +#define IDS_CLIENT_INFORMATION 1110 +#define IDS_SERVER_AUTHENTICATION 1111 +#define IDS_CLIENT_AUTHENTICATION 1112 +#define IDS_CODE_SIGNING 1113 +#define IDS_SECURE_EMAIL 1114 +#define IDS_TIME_STAMPING 1115 +#define IDS_MICROSOFT_TRUST_LIST_SIGNING 1116 +#define IDS_MICROSOFT_TIME_STAMPING 1117 +#define IDS_IPSEC_END_SYSTEM 1118 +#define IDS_IPSEC_TUNNEL 1119 +#define IDS_IPSEC_USER 1120 +#define IDS_EFS 1121 +#define IDS_WHQL_CRYPTO 1122 +#define IDS_NT5_CRYPTO 1123 +#define IDS_OEM_WHQL_CRYPTO 1124 +#define IDS_EMBEDDED_NT_CRYPTO 1125 +#define IDS_KEY_PACK_LICENSES 1126 +#define IDS_LICENSE_SERVER 1127 +#define IDS_SMART_CARD_LOGON 1128 +#define IDS_DIGITAL_RIGHTS 1129 +#define IDS_QUALIFIED_SUBORDINATION 1130 +#define IDS_KEY_RECOVERY 1131 +#define IDS_DOCUMENT_SIGNING 1132 +#define IDS_IPSEC_IKE_INTERMEDIATE 1133 +#define IDS_FILE_RECOVERY 1134 +#define IDS_ROOT_LIST_SIGNER 1135 +#define IDS_ANY_APPLICATION_POLICIES 1136 +#define IDS_DS_EMAIL_REPLICATION 1137 +#define IDS_ENROLLMENT_AGENT 1138 +#define IDS_LIFETIME_SIGNING 1139 +#define IDS_ANY_CERT_POLICY 1140 + +#endif /* ndef __WINE_CRYPTRES_H__ */ diff --git a/reactos/dll/win32/crypt32/encode.c b/reactos/dll/win32/crypt32/encode.c index 25f854e6335..d04f747fa2f 100644 --- a/reactos/dll/win32/crypt32/encode.c +++ b/reactos/dll/win32/crypt32/encode.c @@ -30,6 +30,10 @@ * MSDN, especially: * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp */ + +#include "config.h" +#include "wine/port.h" + #include #include #include @@ -66,6 +70,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(crypt); +struct GenericArray +{ + DWORD cItems; + BYTE *rgItems; +}; + typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *, BYTE *, DWORD *); typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *, @@ -80,10 +90,6 @@ typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *, * built-in functions, but the parameters are retained to simplify * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in * external DLLs that follow these signatures. - * FIXME: some built-in functions are suitable to be called directly by - * CryptEncodeObjectEx/CryptDecodeObjectEx (they implement exception handling - * and memory allocation if requested), others are only suitable to be called - * internally. Comment which are which. */ static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, @@ -91,6 +97,9 @@ static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); +static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); @@ -122,7 +131,7 @@ static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType, static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, +static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of @@ -1442,6 +1451,46 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const CERT_BASIC_CONSTRAINTS_INFO *info = + (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo; + struct AsnEncodeSequenceItem items[3] = { + { &info->SubjectType, CRYPT_AsnEncodeBits, 0 }, + { 0 } + }; + DWORD cItem = 1; + + if (info->fPathLenConstraint) + { + items[cItem].pvStructInfo = &info->dwPathLenConstraint; + items[cItem].encodeFunc = CRYPT_AsnEncodeInt; + cItem++; + } + if (info->cSubtreesConstraint) + { + items[cItem].pvStructInfo = &info->cSubtreesConstraint; + items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny; + cItem++; + } + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -2191,6 +2240,70 @@ static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const CERT_ENHKEY_USAGE *usage = + (const CERT_ENHKEY_USAGE *)pvStructInfo; + DWORD bytesNeeded = 0, lenBytes, size, i; + + ret = TRUE; + for (i = 0; ret && i < usage->cUsageIdentifier; i++) + { + ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, + usage->rgpszUsageIdentifier[i], + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size); + if (ret) + bytesNeeded += size; + } + CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes); + bytesNeeded += 1 + lenBytes; + if (ret) + { + if (!pbEncoded) + *pcbEncoded = bytesNeeded; + else + { + if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, + pbEncoded, pcbEncoded, bytesNeeded))) + { + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + *pbEncoded++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, + &lenBytes); + pbEncoded += lenBytes; + for (i = 0; ret && i < usage->cUsageIdentifier; i++) + { + size = bytesNeeded; + ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, + usage->rgpszUsageIdentifier[i], + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded, + &size); + if (ret) + { + pbEncoded += size; + bytesNeeded -= size; + } + } + } + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, void *pvEncoded, DWORD *pcbEncoded) @@ -2244,6 +2357,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_ALTERNATE_NAME: encodeFunc = CRYPT_AsnEncodeAltName; break; + case (WORD)X509_BASIC_CONSTRAINTS: + encodeFunc = CRYPT_AsnEncodeBasicConstraints; + break; case (WORD)X509_BASIC_CONSTRAINTS2: encodeFunc = CRYPT_AsnEncodeBasicConstraints2; break; @@ -2281,6 +2397,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_CRL_DIST_POINTS: encodeFunc = CRYPT_AsnEncodeCRLDistPoints; break; + case (WORD)X509_ENHANCED_KEY_USAGE: + encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage; + break; default: FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); } @@ -2295,6 +2414,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, encodeFunc = CRYPT_AsnEncodeBits; else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER)) encodeFunc = CRYPT_AsnEncodeOctets; + else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS)) + encodeFunc = CRYPT_AsnEncodeBasicConstraints; else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2)) encodeFunc = CRYPT_AsnEncodeBasicConstraints2; else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME)) @@ -2307,6 +2428,10 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, encodeFunc = CRYPT_AsnEncodeAltName; else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2)) encodeFunc = CRYPT_AsnEncodeAltName; + else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS)) + encodeFunc = CRYPT_AsnEncodeCRLDistPoints; + else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) + encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage; else TRACE("OID %s not found or unimplemented, looking for DLL\n", debugstr_a(lpszStructType)); @@ -2704,12 +2829,6 @@ struct AsnArrayItemSize DWORD size; }; -struct GenericArray -{ - DWORD cItems; - BYTE *rgItems; -}; - /* Decodes an array of like types into a struct GenericArray. * The layout and decoding of the array are described by a struct * AsnArrayDescriptor. @@ -3063,12 +3182,9 @@ static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType, { 0, offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO, Subject.pbData) }, - /* jil FIXME: shouldn't this have an internal version, which expects - * the pbData to be set? - */ { ASN_SEQUENCEOF, offsetof(CERT_INFO, SubjectPublicKeyInfo), - CRYPT_AsnDecodePubKeyInfo, sizeof(CERT_PUBLIC_KEY_INFO), FALSE, - TRUE, offsetof(CERT_INFO, + CRYPT_AsnDecodePubKeyInfoInternal, sizeof(CERT_PUBLIC_KEY_INFO), + FALSE, TRUE, offsetof(CERT_INFO, SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 }, { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, @@ -3554,8 +3670,11 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType, sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL, attr, pcbStructInfo, attr ? attr->pszObjId : NULL); if (attr) + { TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId, debugstr_a(attr->pszObjId)); + TRACE("attr->dwValueType is %ld\n", attr->dwValueType); + } TRACE("returning %d (%08lx)\n", ret, GetLastError()); } __EXCEPT_PAGE_FAULT @@ -3578,9 +3697,10 @@ static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType, struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, CRYPT_AsnDecodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE, offsetof(CERT_RDN_ATTR, pszObjId) }; + PCERT_RDN rdn = (PCERT_RDN)pvStructInfo; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL); } __EXCEPT_PAGE_FAULT { @@ -3682,6 +3802,29 @@ static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + struct AsnDecodeSequenceItem items[] = { + { ASN_SEQUENCEOF, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO, + Algorithm.pszObjId) }, + { ASN_BITSTRING, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, + offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) }, + }; + PCERT_PUBLIC_KEY_INFO info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, info ? + info->Algorithm.Parameters.pbData : NULL); + return ret; +} + static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) @@ -3690,19 +3833,30 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, __TRY { - struct AsnDecodeSequenceItem items[] = { - { ASN_SEQUENCEOF, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm), - CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), - FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO, - Algorithm.pszObjId) }, - { ASN_BITSTRING, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey), - CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, - offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) }, - }; + DWORD bytesNeeded; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + if ((ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + PCERT_PUBLIC_KEY_INFO info; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo; + info->Algorithm.Parameters.pbData = (BYTE *)pvStructInfo + + sizeof(CERT_PUBLIC_KEY_INFO); + ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, + &bytesNeeded); + } + } } __EXCEPT_PAGE_FAULT { @@ -3958,6 +4112,60 @@ static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeCopyBytes, sizeof(CERT_NAME_BLOB), TRUE, + offsetof(CERT_NAME_BLOB, pbData) }; + struct GenericArray *entries = (struct GenericArray *)pvStructInfo; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, + entries ? entries->rgItems : NULL); + TRACE("Returning %d (%08lx)\n", ret, GetLastError()); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_BITSTRING, offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType), + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, + offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType.pbData), 0 }, + { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS_INFO, + fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint, + sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 }, + { ASN_SEQUENCEOF, offsetof(CERT_BASIC_CONSTRAINTS_INFO, + cSubtreesConstraint), CRYPT_AsnDecodeSubtreeConstraints, + sizeof(struct GenericArray), TRUE, TRUE, + offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) @@ -5043,6 +5251,32 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnDecodeEnhancedKeyUsage(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), TRUE, 0 }; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) @@ -5106,6 +5340,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_ALTERNATE_NAME: decodeFunc = CRYPT_AsnDecodeAltName; break; + case (WORD)X509_BASIC_CONSTRAINTS: + decodeFunc = CRYPT_AsnDecodeBasicConstraints; + break; case (WORD)X509_BASIC_CONSTRAINTS2: decodeFunc = CRYPT_AsnDecodeBasicConstraints2; break; @@ -5143,6 +5380,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_CRL_DIST_POINTS: decodeFunc = CRYPT_AsnDecodeCRLDistPoints; break; + case (WORD)X509_ENHANCED_KEY_USAGE: + decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage; + break; default: FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); } @@ -5157,6 +5397,8 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, decodeFunc = CRYPT_AsnDecodeBits; else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER)) decodeFunc = CRYPT_AsnDecodeOctets; + else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS)) + decodeFunc = CRYPT_AsnDecodeBasicConstraints; else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2)) decodeFunc = CRYPT_AsnDecodeBasicConstraints2; else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME)) @@ -5169,6 +5411,10 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, decodeFunc = CRYPT_AsnDecodeAltName; else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2)) decodeFunc = CRYPT_AsnDecodeAltName; + else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS)) + decodeFunc = CRYPT_AsnDecodeCRLDistPoints; + else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) + decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage; else TRACE("OID %s not found or unimplemented, looking for DLL\n", debugstr_a(lpszStructType)); diff --git a/reactos/dll/win32/crypt32/main.c b/reactos/dll/win32/crypt32/main.c index df30206cb3c..5f31e6f3ce5 100644 --- a/reactos/dll/win32/crypt32/main.c +++ b/reactos/dll/win32/crypt32/main.c @@ -39,10 +39,11 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) switch (fdwReason) { case DLL_PROCESS_ATTACH: - CRYPT_InitFunctionSets(); + DisableThreadLibraryCalls(hInstance); + crypt_oid_init(hInstance); break; case DLL_PROCESS_DETACH: - CRYPT_FreeFunctionSets(); + crypt_oid_free(); if (hDefProv) CryptReleaseContext(hDefProv, 0); break; } @@ -217,96 +218,6 @@ BOOL WINAPI CryptSIPLoad return FALSE; } -struct OIDToAlgID -{ - LPCSTR oid; - DWORD algID; -}; - -static const struct OIDToAlgID oidToAlgID[] = { - { szOID_RSA_RSA, CALG_RSA_KEYX }, - { szOID_RSA_MD2RSA, CALG_MD2 }, - { szOID_RSA_MD4RSA, CALG_MD4 }, - { szOID_RSA_MD5RSA, CALG_MD5 }, - { szOID_RSA_SHA1RSA, CALG_SHA }, - { szOID_RSA_DH, CALG_DH_SF }, - { szOID_RSA_SMIMEalgESDH, CALG_DH_EPHEM }, - { szOID_RSA_SMIMEalgCMS3DESwrap, CALG_3DES }, - { szOID_RSA_SMIMEalgCMSRC2wrap, CALG_RC2 }, - { szOID_RSA_MD2, CALG_MD2 }, - { szOID_RSA_MD4, CALG_MD4 }, - { szOID_RSA_MD5, CALG_MD5 }, - { szOID_RSA_RC2CBC, CALG_RC2 }, - { szOID_RSA_RC4, CALG_RC4 }, - { szOID_RSA_DES_EDE3_CBC, CALG_3DES }, - { szOID_ANSI_X942_DH, CALG_DH_SF }, - { szOID_X957_DSA, CALG_DSS_SIGN }, - { szOID_X957_SHA1DSA, CALG_SHA }, - { szOID_OIWSEC_md4RSA, CALG_MD4 }, - { szOID_OIWSEC_md5RSA, CALG_MD5 }, - { szOID_OIWSEC_md4RSA2, CALG_MD4 }, - { szOID_OIWSEC_desCBC, CALG_DES }, - { szOID_OIWSEC_dsa, CALG_DSS_SIGN }, - { szOID_OIWSEC_shaDSA, CALG_SHA }, - { szOID_OIWSEC_shaRSA, CALG_SHA }, - { szOID_OIWSEC_sha, CALG_SHA }, - { szOID_OIWSEC_rsaXchg, CALG_RSA_KEYX }, - { szOID_OIWSEC_sha1, CALG_SHA }, - { szOID_OIWSEC_dsaSHA1, CALG_SHA }, - { szOID_OIWSEC_sha1RSASign, CALG_SHA }, - { szOID_OIWDIR_md2RSA, CALG_MD2 }, - { szOID_INFOSEC_mosaicUpdatedSig, CALG_SHA }, - { szOID_INFOSEC_mosaicKMandUpdSig, CALG_DSS_SIGN }, -}; - -LPCSTR WINAPI CertAlgIdToOID(DWORD dwAlgId) -{ - switch (dwAlgId) - { - case CALG_RSA_KEYX: - return szOID_RSA_RSA; - case CALG_DH_EPHEM: - return szOID_RSA_SMIMEalgESDH; - case CALG_MD2: - return szOID_RSA_MD2; - case CALG_MD4: - return szOID_RSA_MD4; - case CALG_MD5: - return szOID_RSA_MD5; - case CALG_RC2: - return szOID_RSA_RC2CBC; - case CALG_RC4: - return szOID_RSA_RC4; - case CALG_3DES: - return szOID_RSA_DES_EDE3_CBC; - case CALG_DH_SF: - return szOID_ANSI_X942_DH; - case CALG_DSS_SIGN: - return szOID_X957_DSA; - case CALG_DES: - return szOID_OIWSEC_desCBC; - case CALG_SHA: - return szOID_OIWSEC_sha1; - default: - return NULL; - } -} - -DWORD WINAPI CertOIDToAlgId(LPCSTR pszObjId) -{ - int i; - - if (pszObjId) - { - for (i = 0; i < sizeof(oidToAlgID) / sizeof(oidToAlgID[0]); i++) - { - if (!strcmp(pszObjId, oidToAlgID[i].oid)) - return oidToAlgID[i].algID; - } - } - return 0; -} - LPVOID WINAPI CryptMemAlloc(ULONG cbSize) { return HeapAlloc(GetProcessHeap(), 0, cbSize); @@ -351,3 +262,44 @@ BOOL WINAPI I_CryptFreeTls(DWORD dwTlsIndex, DWORD unknown) TRACE("(%ld, %ld)\n", dwTlsIndex, unknown); return TlsFree(dwTlsIndex); } + +BOOL WINAPI I_CryptGetOssGlobal(DWORD x) +{ + FIXME("%08lx\n", x); + return FALSE; +} + +BOOL WINAPI I_CryptInstallOssGlobal(DWORD x, DWORD y, DWORD z) +{ + FIXME("%08lx %08lx %08lx\n", x, y, z); + return FALSE; +} + +BOOL WINAPI I_CryptInstallAsn1Module(void *x, DWORD y, DWORD z) +{ + FIXME("%p %08lx %08lx\n", x, y, z); + return TRUE; +} + +BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void* pvObject, + DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags, + DWORD dwFlags, DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType, + DWORD* pdwFormatType, HCERTSTORE* phCertStore, HCRYPTMSG* phMsg, + const void** ppvContext) +{ + FIXME( "%08lx %p %08lx %08lx %08lx %p %p %p %p %p %p", dwObjectType, + pvObject, dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, + dwFlags, pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, + phCertStore, phMsg, ppvContext); + return FALSE; +} + +BOOL WINAPI CryptVerifyMessageSignature(/*PCRYPT_VERIFY_MESSAGE_PARA*/ void* pVerifyPara, + DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob, + BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert) +{ + FIXME("stub: %p, %ld, %p, %ld, %p, %p, %p\n", + pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob, + pbDecoded, pcbDecoded, ppSignerCert); + return FALSE; +} diff --git a/reactos/dll/win32/crypt32/oid.c b/reactos/dll/win32/crypt32/oid.c index e9733a1acce..1555bb240db 100644 --- a/reactos/dll/win32/crypt32/oid.c +++ b/reactos/dll/win32/crypt32/oid.c @@ -1,6 +1,6 @@ /* * Copyright 2002 Mike McCormack for CodeWeavers - * Copyright 2005 Juan Lang + * Copyright 2005-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 @@ -18,17 +18,38 @@ */ #include #include +#define NONAMELESSUNION #include "windef.h" #include "winbase.h" #include "wincrypt.h" #include "winreg.h" +#include "winuser.h" #include "wine/debug.h" #include "wine/list.h" #include "crypt32_private.h" +#include "cryptres.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); static const WCHAR DllW[] = { 'D','l','l',0 }; + +static void init_function_sets(void); +static void init_oid_info(HINSTANCE hinst); +static void free_function_sets(void); +static void free_oid_info(void); + +void crypt_oid_init(HINSTANCE hinst) +{ + init_function_sets(); + init_oid_info(hinst); +} + +void crypt_oid_free(void) +{ + free_function_sets(); + free_oid_info(); +} + CRITICAL_SECTION funcSetCS; struct list funcSets; @@ -47,13 +68,13 @@ struct OIDFunction struct list next; }; -void CRYPT_InitFunctionSets(void) +static void init_function_sets(void) { InitializeCriticalSection(&funcSetCS); list_init(&funcSets); } -void CRYPT_FreeFunctionSets(void) +static void free_function_sets(void) { struct OIDFunctionSet *setCursor, *setNext; @@ -64,7 +85,6 @@ void CRYPT_FreeFunctionSets(void) list_remove(&setCursor->next); CryptMemFree(setCursor->name); - CryptMemFree(setCursor); LIST_FOR_EACH_ENTRY_SAFE(functionCursor, funcNext, &setCursor->functions, struct OIDFunction, next) { @@ -72,6 +92,7 @@ void CRYPT_FreeFunctionSets(void) CryptMemFree(functionCursor); } DeleteCriticalSection(&setCursor->cs); + CryptMemFree(setCursor); } DeleteCriticalSection(&funcSetCS); } @@ -556,3 +577,555 @@ BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName, } return rc ? FALSE : TRUE; } + +CRITICAL_SECTION oidInfoCS; +struct list oidInfo; + +static const WCHAR tripledes[] = { '3','d','e','s',0 }; +static const WCHAR cms3deswrap[] = { 'C','M','S','3','D','E','S','w','r','a', + 'p',0 }; +static const WCHAR cmsrc2wrap[] = { 'C','M','S','R','C','2','w','r','a','p',0 }; +static const WCHAR des[] = { 'd','e','s',0 }; +static const WCHAR md2[] = { 'm','d','2',0 }; +static const WCHAR md4[] = { 'm','d','4',0 }; +static const WCHAR md5[] = { 'm','d','5',0 }; +static const WCHAR rc2[] = { 'r','c','2',0 }; +static const WCHAR rc4[] = { 'r','c','4',0 }; +static const WCHAR sha[] = { 's','h','a',0 }; +static const WCHAR sha1[] = { 's','h','a','1',0 }; +static const WCHAR RSA[] = { 'R','S','A',0 }; +static const WCHAR RSA_KEYX[] = { 'R','S','A','_','K','E','Y','X',0 }; +static const WCHAR RSA_SIGN[] = { 'R','S','A','_','S','I','G','N',0 }; +static const WCHAR DSA[] = { 'D','S','A',0 }; +static const WCHAR DSA_SIGN[] = { 'D','S','A','_','S','I','G','N',0 }; +static const WCHAR DH[] = { 'D','H',0 }; +static const WCHAR DSS[] = { 'D','S','S',0 }; +static const WCHAR mosaicKMandUpdSig[] = + { 'm','o','s','a','i','c','K','M','a','n','d','U','p','d','S','i','g',0 }; +static const WCHAR ESDH[] = { 'E','S','D','H',0 }; +static const WCHAR NO_SIGN[] = { 'N','O','S','I','G','N',0 }; +static const WCHAR dsaSHA1[] = { 'd','s','a','S','H','A','1',0 }; +static const WCHAR md2RSA[] = { 'm','d','2','R','S','A',0 }; +static const WCHAR md4RSA[] = { 'm','d','4','R','S','A',0 }; +static const WCHAR md5RSA[] = { 'm','d','5','R','S','A',0 }; +static const WCHAR shaDSA[] = { 's','h','a','D','S','A',0 }; +static const WCHAR sha1DSA[] = { 's','h','a','1','D','S','A',0 }; +static const WCHAR shaRSA[] = { 's','h','a','R','S','A',0 }; +static const WCHAR sha1RSA[] = { 's','h','a','1','R','S','A',0 }; +static const WCHAR mosaicUpdatedSig[] = + { 'm','o','s','a','i','c','U','p','d','a','t','e','d','S','i','g',0 }; +static const WCHAR CN[] = { 'C','N',0 }; +static const WCHAR L[] = { 'L',0 }; +static const WCHAR O[] = { 'O',0 }; +static const WCHAR OU[] = { 'O','U',0 }; +static const WCHAR E[] = { 'E',0 }; +static const WCHAR C[] = { 'C',0 }; +static const WCHAR S[] = { 'S',0 }; +static const WCHAR ST[] = { 'S','T',0 }; +static const WCHAR STREET[] = { 'S','T','R','E','E','T',0 }; +static const WCHAR T[] = { 'T',0 }; +static const WCHAR Title[] = { 'T','i','t','l','e',0 }; +static const WCHAR G[] = { 'G',0 }; +static const WCHAR GivenName[] = { 'G','i','v','e','n','N','a','m','e',0 }; +static const WCHAR I[] = { 'I',0 }; +static const WCHAR Initials[] = { 'I','n','i','t','i','a','l','s',0 }; +static const WCHAR SN[] = { 'S','N',0 }; +static const WCHAR DC[] = { 'D','C',0 }; +static const WCHAR Description[] = + { 'D','e','s','c','r','i','p','t','i','o','n',0 }; +static const WCHAR PostalCode[] = { 'P','o','s','t','a','l','C','o','d','e',0 }; +static const WCHAR POBox[] = { 'P','O','B','o','x',0 }; +static const WCHAR Phone[] = { 'P','h','o','n','e',0 }; +static const WCHAR X21Address[] = { 'X','2','1','A','d','d','r','e','s','s',0 }; +static const WCHAR dnQualifier[] = + { 'd','n','Q','u','a','l','i','f','i','e','r',0 }; +static const WCHAR Email[] = { 'E','m','a','i','l',0 }; +static const WCHAR GN[] = { 'G','N',0 }; + +static const DWORD noNullFlag = CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG; +static const DWORD mosaicFlags = CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG | + CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG; +static const CRYPT_DATA_BLOB noNullBlob = { sizeof(noNullFlag), + (LPBYTE)&noNullFlag }; +static const CRYPT_DATA_BLOB mosaicFlagsBlob = { sizeof(mosaicFlags), + (LPBYTE)&mosaicFlags }; + +static const DWORD rsaSign = CALG_RSA_SIGN; +static const DWORD dssSign[2] = { CALG_DSS_SIGN, + CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG }; +static const DWORD mosaicSign[2] = { CALG_DSS_SIGN, + CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG | + CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG }; +static const CRYPT_DATA_BLOB rsaSignBlob = { sizeof(rsaSign), + (LPBYTE)&rsaSign }; +static const CRYPT_DATA_BLOB dssSignBlob = { sizeof(dssSign), + (LPBYTE)dssSign }; +static const CRYPT_DATA_BLOB mosaicSignBlob = { sizeof(mosaicSign), + (LPBYTE)mosaicSign }; + +static const DWORD ia5String[] = { CERT_RDN_IA5_STRING, 0 }; +static const DWORD numericString[] = { CERT_RDN_NUMERIC_STRING, 0 }; +static const DWORD printableString[] = { CERT_RDN_PRINTABLE_STRING, 0 }; +static const DWORD domainCompTypes[] = { CERT_RDN_IA5_STRING, + CERT_RDN_UTF8_STRING, 0 }; +static const CRYPT_DATA_BLOB ia5StringBlob = { sizeof(ia5String), + (LPBYTE)ia5String }; +static const CRYPT_DATA_BLOB numericStringBlob = { sizeof(numericString), + (LPBYTE)numericString }; +static const CRYPT_DATA_BLOB printableStringBlob = { sizeof(printableString), + (LPBYTE)printableString }; +static const CRYPT_DATA_BLOB domainCompTypesBlob = { sizeof(domainCompTypes), + (LPBYTE)domainCompTypes }; + +struct OIDInfoConstructor { + DWORD dwGroupId; + LPCSTR pszOID; + UINT Algid; + LPCWSTR pwszName; + const CRYPT_DATA_BLOB *blob; +} oidInfoConstructors[] = { + { 1, szOID_OIWSEC_sha1, CALG_SHA1, sha1, NULL }, + { 1, szOID_OIWSEC_sha1, CALG_SHA1, sha, NULL }, + { 1, szOID_OIWSEC_sha, CALG_SHA, sha, NULL }, + { 1, szOID_RSA_MD5, CALG_MD5, md5, NULL }, + { 1, szOID_RSA_MD4, CALG_MD4, md4, NULL }, + { 1, szOID_RSA_MD2, CALG_MD2, md2, NULL }, + + { 2, szOID_OIWSEC_desCBC, CALG_DES, des, NULL }, + { 2, szOID_RSA_DES_EDE3_CBC, CALG_3DES, tripledes, NULL }, + { 2, szOID_RSA_RC2CBC, CALG_RC2, rc2, NULL }, + { 2, szOID_RSA_RC4, CALG_RC4, rc4, NULL }, + { 2, szOID_RSA_SMIMEalgCMS3DESwrap, CALG_3DES, cms3deswrap, NULL }, + { 2, szOID_RSA_SMIMEalgCMSRC2wrap, CALG_RC2, cmsrc2wrap, NULL }, + + { 3, szOID_RSA_RSA, CALG_RSA_KEYX, RSA, NULL }, + { 3, szOID_X957_DSA, CALG_DSS_SIGN, DSA, &noNullBlob }, + { 3, szOID_ANSI_X942_DH, CALG_DH_SF, DH, &noNullBlob }, + { 3, szOID_RSA_RSA, CALG_RSA_KEYX, RSA_KEYX, NULL }, + { 3, szOID_RSA_RSA, CALG_RSA_SIGN, RSA, NULL }, + { 3, szOID_RSA_RSA, CALG_RSA_SIGN, RSA_SIGN, NULL }, + { 3, szOID_OIWSEC_dsa, CALG_DSS_SIGN, DSA, &noNullBlob }, + { 3, szOID_OIWSEC_dsa, CALG_DSS_SIGN, DSS, &noNullBlob }, + { 3, szOID_OIWSEC_dsa, CALG_DSS_SIGN, DSA_SIGN, &noNullBlob }, + { 3, szOID_RSA_DH, CALG_DH_SF, DH, &noNullBlob }, + { 3, szOID_OIWSEC_rsaXchg, CALG_RSA_KEYX, RSA_KEYX, NULL }, + { 3, szOID_INFOSEC_mosaicKMandUpdSig, CALG_DSS_SIGN, mosaicKMandUpdSig, + &mosaicFlagsBlob }, + { 3, szOID_RSA_SMIMEalgESDH, CALG_DH_EPHEM, ESDH, &noNullBlob }, + { 3, szOID_PKIX_NO_SIGNATURE, CALG_NO_SIGN, NO_SIGN, NULL }, + + { 4, szOID_RSA_SHA1RSA, CALG_SHA1, sha1RSA, &rsaSignBlob }, + { 4, szOID_RSA_MD5RSA, CALG_MD5, md5RSA, &rsaSignBlob }, + { 4, szOID_X957_SHA1DSA, CALG_SHA1, sha1DSA, &dssSignBlob }, + { 4, szOID_OIWSEC_sha1RSASign, CALG_SHA1, sha1RSA, &rsaSignBlob }, + { 4, szOID_OIWSEC_sha1RSASign, CALG_SHA1, shaRSA, &rsaSignBlob }, + { 4, szOID_OIWSEC_shaRSA, CALG_SHA1, shaRSA, &rsaSignBlob }, + { 4, szOID_OIWSEC_md5RSA, CALG_MD5, md5RSA, &rsaSignBlob }, + { 4, szOID_RSA_MD2RSA, CALG_MD2, md2RSA, &rsaSignBlob }, + { 4, szOID_RSA_MD4RSA, CALG_MD4, md4RSA, &rsaSignBlob }, + { 4, szOID_OIWSEC_md4RSA, CALG_MD4, md4RSA, &rsaSignBlob }, + { 4, szOID_OIWSEC_md4RSA2, CALG_MD4, md4RSA, &rsaSignBlob }, + { 4, szOID_OIWDIR_md2RSA, CALG_MD2, md2RSA, &rsaSignBlob }, + { 4, szOID_OIWSEC_shaDSA, CALG_SHA1, sha1DSA, &dssSignBlob }, + { 4, szOID_OIWSEC_shaDSA, CALG_SHA1, shaDSA, &dssSignBlob }, + { 4, szOID_OIWSEC_dsaSHA1, CALG_SHA1, dsaSHA1, &dssSignBlob }, + { 4, szOID_INFOSEC_mosaicUpdatedSig, CALG_SHA1, mosaicUpdatedSig, + &mosaicSignBlob }, + + { 5, szOID_COMMON_NAME, 0, CN, NULL }, + { 5, szOID_LOCALITY_NAME, 0, L, NULL }, + { 5, szOID_ORGANIZATION_NAME, 0, O, NULL }, + { 5, szOID_ORGANIZATIONAL_UNIT_NAME, 0, OU, NULL }, + { 5, szOID_RSA_emailAddr, 0, E, &ia5StringBlob }, + { 5, szOID_RSA_emailAddr, 0, Email, &ia5StringBlob }, + { 5, szOID_COUNTRY_NAME, 0, C, &printableStringBlob }, + { 5, szOID_STATE_OR_PROVINCE_NAME, 0, S, NULL }, + { 5, szOID_STATE_OR_PROVINCE_NAME, 0, ST, NULL }, + { 5, szOID_STREET_ADDRESS, 0, STREET, NULL }, + { 5, szOID_TITLE, 0, T, NULL }, + { 5, szOID_TITLE, 0, Title, NULL }, + { 5, szOID_GIVEN_NAME, 0, G, NULL }, + { 5, szOID_GIVEN_NAME, 0, GN, NULL }, + { 5, szOID_GIVEN_NAME, 0, GivenName, NULL }, + { 5, szOID_INITIALS, 0, I, NULL }, + { 5, szOID_INITIALS, 0, Initials, NULL }, + { 5, szOID_SUR_NAME, 0, SN, NULL }, + { 5, szOID_DOMAIN_COMPONENT, 0, DC, &domainCompTypesBlob }, + { 5, szOID_DESCRIPTION, 0, Description, NULL }, + { 5, szOID_POSTAL_CODE, 0, PostalCode, NULL }, + { 5, szOID_POST_OFFICE_BOX, 0, POBox, NULL }, + { 5, szOID_TELEPHONE_NUMBER, 0, Phone, &printableStringBlob }, + { 5, szOID_X21_ADDRESS, 0, X21Address, &numericStringBlob }, + { 5, szOID_DN_QUALIFIER, 0, dnQualifier, NULL }, + + { 6, szOID_AUTHORITY_KEY_IDENTIFIER2, 0, (LPCWSTR)IDS_AUTHORITY_KEY_ID, NULL }, + { 6, szOID_AUTHORITY_KEY_IDENTIFIER, 0, (LPCWSTR)IDS_AUTHORITY_KEY_ID, NULL }, + { 6, szOID_KEY_ATTRIBUTES, 0, (LPCWSTR)IDS_KEY_ATTRIBUTES, NULL }, + { 6, szOID_KEY_USAGE_RESTRICTION, 0, (LPCWSTR)IDS_KEY_USAGE_RESTRICTION, NULL }, + { 6, szOID_SUBJECT_ALT_NAME2, 0, (LPCWSTR)IDS_SUBJECT_ALT_NAME, NULL }, + { 6, szOID_SUBJECT_ALT_NAME, 0, (LPCWSTR)IDS_SUBJECT_ALT_NAME, NULL }, + { 6, szOID_ISSUER_ALT_NAME2, 0, (LPCWSTR)IDS_ISSUER_ALT_NAME, NULL }, + { 6, szOID_ISSUER_ALT_NAME2, 0, (LPCWSTR)IDS_ISSUER_ALT_NAME, NULL }, + { 6, szOID_BASIC_CONSTRAINTS2, 0, (LPCWSTR)IDS_BASIC_CONSTRAINTS, NULL }, + { 6, szOID_BASIC_CONSTRAINTS, 0, (LPCWSTR)IDS_BASIC_CONSTRAINTS, NULL }, + { 6, szOID_KEY_USAGE, 0, (LPCWSTR)IDS_KEY_USAGE, NULL }, + { 6, szOID_CERT_POLICIES, 0, (LPCWSTR)IDS_CERT_POLICIES, NULL }, + { 6, szOID_SUBJECT_KEY_IDENTIFIER, 0, (LPCWSTR)IDS_SUBJECT_KEY_IDENTIFIER, NULL }, + { 6, szOID_CRL_REASON_CODE, 0, (LPCWSTR)IDS_CRL_REASON_CODE, NULL }, + { 6, szOID_CRL_DIST_POINTS, 0, (LPCWSTR)IDS_CRL_DIST_POINTS, NULL }, + { 6, szOID_ENHANCED_KEY_USAGE, 0, (LPCWSTR)IDS_ENHANCED_KEY_USAGE, NULL }, + { 6, szOID_AUTHORITY_INFO_ACCESS, 0, (LPCWSTR)IDS_AUTHORITY_INFO_ACCESS, NULL }, + { 6, szOID_CERT_EXTENSIONS, 0, (LPCWSTR)IDS_CERT_EXTENSIONS, NULL }, + { 6, szOID_RSA_certExtensions, 0, (LPCWSTR)IDS_CERT_EXTENSIONS, NULL }, + { 6, szOID_NEXT_UPDATE_LOCATION, 0, (LPCWSTR)IDS_NEXT_UPDATE_LOCATION, NULL }, + { 6, szOID_YESNO_TRUST_ATTR, 0, (LPCWSTR)IDS_YES_OR_NO_TRUST, NULL }, + { 6, szOID_RSA_emailAddr, 0, (LPCWSTR)IDS_EMAIL_ADDRESS, NULL }, + { 6, szOID_RSA_unstructName, 0, (LPCWSTR)IDS_UNSTRUCTURED_NAME, NULL }, + { 6, szOID_RSA_contentType, 0, (LPCWSTR)IDS_CONTENT_TYPE, NULL }, + { 6, szOID_RSA_messageDigest, 0, (LPCWSTR)IDS_MESSAGE_DIGEST, NULL }, + { 6, szOID_RSA_signingTime, 0, (LPCWSTR)IDS_SIGNING_TIME, NULL }, + { 6, szOID_RSA_counterSign, 0, (LPCWSTR)IDS_COUNTER_SIGN, NULL }, + { 6, szOID_RSA_challengePwd, 0, (LPCWSTR)IDS_CHALLENGE_PASSWORD, NULL }, + { 6, szOID_RSA_unstructAddr, 0, (LPCWSTR)IDS_UNSTRUCTURED_ADDRESS, NULL }, + { 6, szOID_RSA_SMIMECapabilities, 0, (LPCWSTR)IDS_SMIME_CAPABILITIES, NULL }, + { 6, szOID_RSA_preferSignedData, 0, (LPCWSTR)IDS_PREFER_SIGNED_DATA, NULL }, + { 6, szOID_PKIX_POLICY_QUALIFIER_CPS, 0, (LPCWSTR)IDS_CPS, NULL }, + { 6, szOID_PKIX_POLICY_QUALIFIER_USERNOTICE, 0, (LPCWSTR)IDS_USER_NOTICE, NULL }, + { 6, szOID_PKIX_OCSP, 0, (LPCWSTR)IDS_OCSP, NULL }, + { 6, szOID_PKIX_CA_ISSUERS, 0, (LPCWSTR)IDS_CA_ISSUER, NULL }, + { 6, szOID_ENROLL_CERTTYPE_EXTENSION, 0, (LPCWSTR)IDS_CERT_TEMPLATE_NAME, NULL }, + { 6, szOID_ENROLL_CERTTYPE_EXTENSION, 0, (LPCWSTR)IDS_CERT_TYPE, NULL }, + { 6, szOID_CERT_MANIFOLD, 0, (LPCWSTR)IDS_CERT_MANIFOLD, NULL }, + { 6, szOID_NETSCAPE_CERT_TYPE, 0, (LPCWSTR)IDS_NETSCAPE_CERT_TYPE, NULL }, + { 6, szOID_NETSCAPE_BASE_URL, 0, (LPCWSTR)IDS_NETSCAPE_BASE_URL, NULL }, + { 6, szOID_NETSCAPE_REVOCATION_URL, 0, (LPCWSTR)IDS_NETSCAPE_REVOCATION_URL, NULL }, + { 6, szOID_NETSCAPE_CA_REVOCATION_URL, 0, (LPCWSTR)IDS_NETSCAPE_CA_REVOCATION_URL, NULL }, + { 6, szOID_NETSCAPE_CERT_RENEWAL_URL, 0, (LPCWSTR)IDS_NETSCAPE_CERT_RENEWAL_URL, NULL }, + { 6, szOID_NETSCAPE_CA_POLICY_URL, 0, (LPCWSTR)IDS_NETSCAPE_CA_POLICY_URL, NULL }, + { 6, szOID_NETSCAPE_SSL_SERVER_NAME, 0, (LPCWSTR)IDS_NETSCAPE_SSL_SERVER_NAME, NULL }, + { 6, szOID_NETSCAPE_COMMENT, 0, (LPCWSTR)IDS_NETSCAPE_COMMENT, NULL }, + { 6, "1.3.6.1.4.1.311.2.1.10", 0, (LPCWSTR)IDS_SPC_SP_AGENCY_INFO, NULL }, + { 6, "1.3.6.1.4.1.311.2.1.27", 0, (LPCWSTR)IDS_SPC_FINANCIAL_CRITERIA, NULL }, + { 6, "1.3.6.1.4.1.311.2.1.26", 0, (LPCWSTR)IDS_SPC_MINIMAL_CRITERIA, NULL }, + { 6, szOID_COUNTRY_NAME, 0, (LPCWSTR)IDS_COUNTRY, NULL }, + { 6, szOID_ORGANIZATION_NAME, 0, (LPCWSTR)IDS_ORGANIZATION, NULL }, + { 6, szOID_ORGANIZATIONAL_UNIT_NAME, 0, (LPCWSTR)IDS_ORGANIZATIONAL_UNIT, NULL }, + { 6, szOID_COMMON_NAME, 0, (LPCWSTR)IDS_COMMON_NAME, NULL }, + { 6, szOID_LOCALITY_NAME, 0, (LPCWSTR)IDS_LOCALITY, NULL }, + { 6, szOID_STATE_OR_PROVINCE_NAME, 0, (LPCWSTR)IDS_STATE_OR_PROVINCE, NULL }, + { 6, szOID_TITLE, 0, (LPCWSTR)IDS_TITLE, NULL }, + { 6, szOID_GIVEN_NAME, 0, (LPCWSTR)IDS_GIVEN_NAME, NULL }, + { 6, szOID_INITIALS, 0, (LPCWSTR)IDS_INITIALS, NULL }, + { 6, szOID_SUR_NAME, 0, (LPCWSTR)IDS_SUR_NAME, NULL }, + { 6, szOID_DOMAIN_COMPONENT, 0, (LPCWSTR)IDS_DOMAIN_COMPONENT, NULL }, + { 6, szOID_STREET_ADDRESS, 0, (LPCWSTR)IDS_STREET_ADDRESS, NULL }, + { 6, szOID_DEVICE_SERIAL_NUMBER, 0, (LPCWSTR)IDS_SERIAL_NUMBER, NULL }, + { 6, szOID_CERTSRV_CA_VERSION, 0, (LPCWSTR)IDS_CA_VERSION, NULL }, + { 6, szOID_CERTSRV_CROSSCA_VERSION, 0, (LPCWSTR)IDS_CROSS_CA_VERSION, NULL }, + { 6, szOID_SERIALIZED, 0, (LPCWSTR)IDS_SERIALIZED_SIG_SERIAL_NUMBER, NULL }, + { 6, szOID_NT_PRINCIPAL_NAME, 0, (LPCWSTR)IDS_PRINCIPAL_NAME, NULL }, + { 6, szOID_PRODUCT_UPDATE, 0, (LPCWSTR)IDS_WINDOWS_PRODUCT_UPDATE, NULL }, + { 6, szOID_ENROLLMENT_NAME_VALUE_PAIR, 0, (LPCWSTR)IDS_ENROLLMENT_NAME_VALUE_PAIR, NULL }, + { 6, szOID_OS_VERSION, 0, (LPCWSTR)IDS_OS_VERSION, NULL }, + { 6, szOID_ENROLLMENT_CSP_PROVIDER, 0, (LPCWSTR)IDS_ENROLLMENT_CSP, NULL }, + { 6, szOID_CRL_NUMBER, 0, (LPCWSTR)IDS_CRL_NUMBER, NULL }, + { 6, szOID_DELTA_CRL_INDICATOR, 0, (LPCWSTR)IDS_DELTA_CRL_INDICATOR, NULL }, + { 6, szOID_ISSUING_DIST_POINT, 0, (LPCWSTR)IDS_ISSUING_DIST_POINT, NULL }, + { 6, szOID_FRESHEST_CRL, 0, (LPCWSTR)IDS_FRESHEST_CRL, NULL }, + { 6, szOID_NAME_CONSTRAINTS, 0, (LPCWSTR)IDS_NAME_CONSTRAINTS, NULL }, + { 6, szOID_POLICY_MAPPINGS, 0, (LPCWSTR)IDS_POLICY_MAPPINGS, NULL }, + { 6, szOID_LEGACY_POLICY_MAPPINGS, 0, (LPCWSTR)IDS_POLICY_MAPPINGS, NULL }, + { 6, szOID_POLICY_CONSTRAINTS, 0, (LPCWSTR)IDS_POLICY_CONSTRAINTS, NULL }, + { 6, szOID_CROSS_CERT_DIST_POINTS, 0, (LPCWSTR)IDS_CROSS_CERT_DIST_POINTS, NULL }, + { 6, szOID_APPLICATION_CERT_POLICIES, 0, (LPCWSTR)IDS_APPLICATION_POLICIES, NULL }, + { 6, szOID_APPLICATION_POLICY_MAPPINGS, 0, (LPCWSTR)IDS_APPLICATION_POLICY_MAPPINGS, NULL }, + { 6, szOID_APPLICATION_POLICY_CONSTRAINTS, 0, (LPCWSTR)IDS_APPLICATION_POLICY_CONSTRAINTS, NULL }, + { 6, szOID_CT_PKI_DATA, 0, (LPCWSTR)IDS_CMC_DATA, NULL }, + { 6, szOID_CT_PKI_RESPONSE, 0, (LPCWSTR)IDS_CMC_RESPONSE, NULL }, + { 6, szOID_CMC, 0, (LPCWSTR)IDS_UNSIGNED_CMC_REQUEST, NULL }, + { 6, szOID_CMC_STATUS_INFO, 0, (LPCWSTR)IDS_CMC_STATUS_INFO, NULL }, + { 6, szOID_CMC_ADD_EXTENSIONS, 0, (LPCWSTR)IDS_CMC_EXTENSIONS, NULL }, + { 6, szOID_CTL, 0, (LPCWSTR)IDS_CMC_ATTRIBUTES, NULL }, + { 6, szOID_RSA_data, 0, (LPCWSTR)IDS_PKCS_7_DATA, NULL }, + { 6, szOID_RSA_signedData, 0, (LPCWSTR)IDS_PKCS_7_SIGNED, NULL }, + { 6, szOID_RSA_envelopedData, 0, (LPCWSTR)IDS_PKCS_7_ENVELOPED, NULL }, + { 6, szOID_RSA_signEnvData, 0, (LPCWSTR)IDS_PKCS_7_SIGNED_ENVELOPED, NULL }, + { 6, szOID_RSA_digestedData, 0, (LPCWSTR)IDS_PKCS_7_DIGESTED, NULL }, + { 6, szOID_RSA_encryptedData, 0, (LPCWSTR)IDS_PKCS_7_ENCRYPTED, NULL }, + { 6, szOID_CERTSRV_PREVIOUS_CERT_HASH, 0, (LPCWSTR)IDS_PREVIOUS_CA_CERT_HASH, NULL }, + { 6, szOID_CRL_VIRTUAL_BASE, 0, (LPCWSTR)IDS_CRL_VIRTUAL_BASE, NULL }, + { 6, szOID_CRL_NEXT_PUBLISH, 0, (LPCWSTR)IDS_CRL_NEXT_PUBLISH, NULL }, + { 6, szOID_KP_CA_EXCHANGE, 0, (LPCWSTR)IDS_CA_EXCHANGE, NULL }, + { 6, szOID_KP_KEY_RECOVERY_AGENT, 0, (LPCWSTR)IDS_KEY_RECOVERY_AGENT, NULL }, + { 6, szOID_CERTIFICATE_TEMPLATE, 0, (LPCWSTR)IDS_CERTIFICATE_TEMPLATE, NULL }, + { 6, szOID_ENTERPRISE_OID_ROOT, 0, (LPCWSTR)IDS_ENTERPRISE_ROOT_OID, NULL }, + { 6, szOID_RDN_DUMMY_SIGNER, 0, (LPCWSTR)IDS_RDN_DUMMY_SIGNER, NULL }, + { 6, szOID_ARCHIVED_KEY_ATTR, 0, (LPCWSTR)IDS_ARCHIVED_KEY_ATTR, NULL }, + { 6, szOID_CRL_SELF_CDP, 0, (LPCWSTR)IDS_CRL_SELF_CDP, NULL }, + { 6, szOID_REQUIRE_CERT_CHAIN_POLICY, 0, (LPCWSTR)IDS_REQUIRE_CERT_CHAIN_POLICY, NULL }, + { 6, szOID_CMC_TRANSACTION_ID, 0, (LPCWSTR)IDS_TRANSACTION_ID, NULL }, + { 6, szOID_CMC_SENDER_NONCE, 0, (LPCWSTR)IDS_SENDER_NONCE, NULL }, + { 6, szOID_CMC_RECIPIENT_NONCE, 0, (LPCWSTR)IDS_RECIPIENT_NONCE, NULL }, + { 6, szOID_CMC_REG_INFO, 0, (LPCWSTR)IDS_REG_INFO, NULL }, + { 6, szOID_CMC_GET_CERT, 0, (LPCWSTR)IDS_GET_CERTIFICATE, NULL }, + { 6, szOID_CMC_GET_CRL, 0, (LPCWSTR)IDS_GET_CRL, NULL }, + { 6, szOID_CMC_REVOKE_REQUEST, 0, (LPCWSTR)IDS_REVOKE_REQUEST, NULL }, + { 6, szOID_CMC_QUERY_PENDING, 0, (LPCWSTR)IDS_QUERY_PENDING, NULL }, + { 6, szOID_SORTED_CTL, 0, (LPCWSTR)IDS_SORTED_CTL, NULL }, + { 6, szOID_ARCHIVED_KEY_CERT_HASH, 0, (LPCWSTR)IDS_ARCHIVED_KEY_CERT_HASH, NULL }, + { 6, szOID_PRIVATEKEY_USAGE_PERIOD, 0, (LPCWSTR)IDS_PRIVATE_KEY_USAGE_PERIOD, NULL }, + { 6, szOID_REQUEST_CLIENT_INFO, 0, (LPCWSTR)IDS_CLIENT_INFORMATION, NULL }, + + { 7, szOID_PKIX_KP_SERVER_AUTH, 0, (LPCWSTR)IDS_SERVER_AUTHENTICATION, NULL }, + { 7, szOID_PKIX_KP_CLIENT_AUTH, 0, (LPCWSTR)IDS_CLIENT_AUTHENTICATION, NULL }, + { 7, szOID_PKIX_KP_CODE_SIGNING, 0, (LPCWSTR)IDS_CODE_SIGNING, NULL }, + { 7, szOID_PKIX_KP_EMAIL_PROTECTION, 0, (LPCWSTR)IDS_SECURE_EMAIL, NULL }, + { 7, szOID_PKIX_KP_TIMESTAMP_SIGNING, 0, (LPCWSTR)IDS_TIME_STAMPING, NULL }, + { 7, szOID_KP_CTL_USAGE_SIGNING, 0, (LPCWSTR)IDS_MICROSOFT_TRUST_LIST_SIGNING, NULL }, + { 7, szOID_KP_TIME_STAMP_SIGNING, 0, (LPCWSTR)IDS_MICROSOFT_TIME_STAMPING, NULL }, + { 7, szOID_PKIX_KP_IPSEC_END_SYSTEM, 0, (LPCWSTR)IDS_IPSEC_END_SYSTEM, NULL }, + { 7, szOID_PKIX_KP_IPSEC_TUNNEL, 0, (LPCWSTR)IDS_IPSEC_TUNNEL, NULL }, + { 7, szOID_PKIX_KP_IPSEC_USER, 0, (LPCWSTR)IDS_IPSEC_USER, NULL }, + { 7, szOID_KP_EFS, 0, (LPCWSTR)IDS_EFS, NULL }, + { 7, szOID_WHQL_CRYPTO, 0, (LPCWSTR)IDS_WHQL_CRYPTO, NULL }, + { 7, szOID_NT5_CRYPTO, 0, (LPCWSTR)IDS_NT5_CRYPTO, NULL }, + { 7, szOID_OEM_WHQL_CRYPTO, 0, (LPCWSTR)IDS_OEM_WHQL_CRYPTO, NULL }, + { 7, szOID_EMBEDDED_NT_CRYPTO, 0, (LPCWSTR)IDS_EMBEDDED_NT_CRYPTO, NULL }, + { 7, szOID_LICENSES, 0, (LPCWSTR)IDS_KEY_PACK_LICENSES, NULL }, + { 7, szOID_LICENSE_SERVER, 0, (LPCWSTR)IDS_LICENSE_SERVER, NULL }, + { 7, szOID_KP_SMARTCARD_LOGON, 0, (LPCWSTR)IDS_SMART_CARD_LOGON, NULL }, + { 7, szOID_DRM, 0, (LPCWSTR)IDS_DIGITAL_RIGHTS, NULL }, + { 7, szOID_KP_QUALIFIED_SUBORDINATION, 0, (LPCWSTR)IDS_QUALIFIED_SUBORDINATION, NULL }, + { 7, szOID_KP_KEY_RECOVERY, 0, (LPCWSTR)IDS_KEY_RECOVERY, NULL }, + { 7, szOID_KP_DOCUMENT_SIGNING, 0, (LPCWSTR)IDS_DOCUMENT_SIGNING, NULL }, + { 7, szOID_IPSEC_KP_IKE_INTERMEDIATE, 0, (LPCWSTR)IDS_IPSEC_IKE_INTERMEDIATE, NULL }, + { 7, szOID_EFS_RECOVERY, 0, (LPCWSTR)IDS_FILE_RECOVERY, NULL }, + { 7, szOID_ROOT_LIST_SIGNER, 0, (LPCWSTR)IDS_ROOT_LIST_SIGNER, NULL }, + { 7, szOID_ANY_APPLICATION_POLICY, 0, (LPCWSTR)IDS_ANY_APPLICATION_POLICIES, NULL }, + { 7, szOID_DS_EMAIL_REPLICATION, 0, (LPCWSTR)IDS_DS_EMAIL_REPLICATION, NULL }, + { 7, szOID_ENROLLMENT_AGENT, 0, (LPCWSTR)IDS_ENROLLMENT_AGENT, NULL }, + { 7, szOID_KP_KEY_RECOVERY_AGENT, 0, (LPCWSTR)IDS_KEY_RECOVERY_AGENT, NULL }, + { 7, szOID_KP_CA_EXCHANGE, 0, (LPCWSTR)IDS_CA_EXCHANGE, NULL }, + { 7, szOID_KP_LIFETIME_SIGNING, 0, (LPCWSTR)IDS_LIFETIME_SIGNING, NULL }, + + { 8, szOID_ANY_CERT_POLICY, 0, (LPCWSTR)IDS_ANY_CERT_POLICY, NULL }, +}; + +struct OIDInfo { + CRYPT_OID_INFO info; + struct list entry; +}; + +static void init_oid_info(HINSTANCE hinst) +{ + DWORD i; + + InitializeCriticalSection(&oidInfoCS); + list_init(&oidInfo); + for (i = 0; i < sizeof(oidInfoConstructors) / + sizeof(oidInfoConstructors[0]); i++) + { + if (HIWORD(oidInfoConstructors[i].pwszName)) + { + struct OIDInfo *info; + + /* The name is a static string, so just use the same pointer */ + info = CryptMemAlloc(sizeof(struct OIDInfo)); + if (info) + { + memset(info, 0, sizeof(*info)); + info->info.cbSize = sizeof(CRYPT_OID_INFO); + info->info.pszOID = oidInfoConstructors[i].pszOID; + info->info.pwszName = oidInfoConstructors[i].pwszName; + info->info.dwGroupId = oidInfoConstructors[i].dwGroupId; + info->info.u.Algid = oidInfoConstructors[i].Algid; + if (oidInfoConstructors[i].blob) + { + info->info.ExtraInfo.cbData = + oidInfoConstructors[i].blob->cbData; + info->info.ExtraInfo.pbData = + oidInfoConstructors[i].blob->pbData; + } + list_add_tail(&oidInfo, &info->entry); + } + } + else + { + int len = LoadStringW(hinst, (UINT)oidInfoConstructors[i].pwszName, + NULL, 0); + + if (len) + { + struct OIDInfo *info = CryptMemAlloc(sizeof(struct OIDInfo) + + (len + 1) * sizeof(WCHAR)); + + if (info) + { + memset(info, 0, sizeof(*info)); + info->info.cbSize = sizeof(CRYPT_OID_INFO); + info->info.pszOID = oidInfoConstructors[i].pszOID; + info->info.pwszName = + (LPWSTR)((LPBYTE)info + sizeof(struct OIDInfo)); + info->info.dwGroupId = oidInfoConstructors[i].dwGroupId; + info->info.u.Algid = oidInfoConstructors[i].Algid; + LoadStringW(hinst, (UINT)oidInfoConstructors[i].pwszName, + (LPWSTR)info->info.pwszName, len + 1); + if (oidInfoConstructors[i].blob) + { + info->info.ExtraInfo.cbData = + oidInfoConstructors[i].blob->cbData; + info->info.ExtraInfo.pbData = + oidInfoConstructors[i].blob->pbData; + } + list_add_tail(&oidInfo, &info->entry); + } + } + } + } +} + +static void free_oid_info(void) +{ + struct OIDInfo *info, *next; + + LIST_FOR_EACH_ENTRY_SAFE(info, next, &oidInfo, struct OIDInfo, entry) + { + list_remove(&info->entry); + CryptMemFree(info); + } + DeleteCriticalSection(&oidInfoCS); +} + +BOOL WINAPI CryptEnumOIDInfo(DWORD dwGroupId, DWORD dwFlags, void *pvArg, + PFN_CRYPT_ENUM_OID_INFO pfnEnumOIDInfo) +{ + BOOL ret = TRUE; + struct OIDInfo *info; + + TRACE("(%ld, %08lx, %p, %p)\n", dwGroupId, dwFlags, pvArg, + pfnEnumOIDInfo); + + EnterCriticalSection(&oidInfoCS); + LIST_FOR_EACH_ENTRY(info, &oidInfo, struct OIDInfo, entry) + { + if (!dwGroupId || dwGroupId == info->info.dwGroupId) + { + ret = pfnEnumOIDInfo(&info->info, pvArg); + if (!ret) + break; + } + } + LeaveCriticalSection(&oidInfoCS); + return ret; +} + +PCCRYPT_OID_INFO WINAPI CryptFindOIDInfo(DWORD dwKeyType, void *pvKey, + DWORD dwGroupId) +{ + PCCRYPT_OID_INFO ret = NULL; + + TRACE("(%ld, %p, %ld)\n", dwKeyType, pvKey, dwGroupId); + + switch(dwKeyType) + { + case CRYPT_OID_INFO_ALGID_KEY: + { + struct OIDInfo *info; + + EnterCriticalSection(&oidInfoCS); + LIST_FOR_EACH_ENTRY(info, &oidInfo, struct OIDInfo, entry) + { + if (info->info.u.Algid == *(DWORD *)pvKey && + (!dwGroupId || info->info.dwGroupId == dwGroupId)) + { + ret = &info->info; + break; + } + } + LeaveCriticalSection(&oidInfoCS); + break; + } + case CRYPT_OID_INFO_NAME_KEY: + { + struct OIDInfo *info; + + EnterCriticalSection(&oidInfoCS); + LIST_FOR_EACH_ENTRY(info, &oidInfo, struct OIDInfo, entry) + { + if (!lstrcmpW(info->info.pwszName, (LPWSTR)pvKey) && + (!dwGroupId || info->info.dwGroupId == dwGroupId)) + { + ret = &info->info; + break; + } + } + LeaveCriticalSection(&oidInfoCS); + break; + } + case CRYPT_OID_INFO_OID_KEY: + { + struct OIDInfo *info; + LPSTR oid = (LPSTR)pvKey; + + EnterCriticalSection(&oidInfoCS); + LIST_FOR_EACH_ENTRY(info, &oidInfo, struct OIDInfo, entry) + { + if (!lstrcmpA(info->info.pszOID, oid) && + (!dwGroupId || info->info.dwGroupId == dwGroupId)) + { + ret = &info->info; + break; + } + } + LeaveCriticalSection(&oidInfoCS); + break; + } + case CRYPT_OID_INFO_SIGN_KEY: + { + struct OIDInfo *info; + + EnterCriticalSection(&oidInfoCS); + LIST_FOR_EACH_ENTRY(info, &oidInfo, struct OIDInfo, entry) + { + if (info->info.u.Algid == *(DWORD *)pvKey && + info->info.ExtraInfo.cbData >= sizeof(DWORD) && + *(DWORD *)info->info.ExtraInfo.pbData == + *(DWORD *)((LPBYTE)pvKey + sizeof(DWORD)) && + (!dwGroupId || info->info.dwGroupId == dwGroupId)) + { + ret = &info->info; + break; + } + } + LeaveCriticalSection(&oidInfoCS); + break; + } + } + return ret; +} + +LPCSTR WINAPI CertAlgIdToOID(DWORD dwAlgId) +{ + LPCSTR ret; + PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY, + &dwAlgId, 0); + + if (info) + ret = info->pszOID; + else + ret = NULL; + return ret; +} + +DWORD WINAPI CertOIDToAlgId(LPCSTR pszObjId) +{ + DWORD ret; + PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, + (void *)pszObjId, 0); + + if (info) + ret = info->u.Algid; + else + ret = 0; + return ret; +} diff --git a/reactos/dll/win32/crypt32/proplist.c b/reactos/dll/win32/crypt32/proplist.c new file mode 100644 index 00000000000..6671f0f2822 --- /dev/null +++ b/reactos/dll/win32/crypt32/proplist.c @@ -0,0 +1,215 @@ +/* + * 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 + */ +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +typedef struct _CONTEXT_PROPERTY_LIST +{ + CRITICAL_SECTION cs; + struct list properties; +} CONTEXT_PROPERTY_LIST; + +typedef struct _CONTEXT_PROPERTY +{ + DWORD propID; + DWORD cbData; + LPBYTE pbData; + struct list entry; +} CONTEXT_PROPERTY, *PCONTEXT_PROPERTY; + +PCONTEXT_PROPERTY_LIST ContextPropertyList_Create(void) +{ + PCONTEXT_PROPERTY_LIST list = CryptMemAlloc(sizeof(CONTEXT_PROPERTY_LIST)); + + if (list) + { + InitializeCriticalSection(&list->cs); + list_init(&list->properties); + } + return list; +} + +void ContextPropertyList_Free(PCONTEXT_PROPERTY_LIST list) +{ + PCONTEXT_PROPERTY prop, next; + + LIST_FOR_EACH_ENTRY_SAFE(prop, next, &list->properties, CONTEXT_PROPERTY, + entry) + { + list_remove(&prop->entry); + CryptMemFree(prop->pbData); + CryptMemFree(prop); + } + DeleteCriticalSection(&list->cs); + CryptMemFree(list); +} + +BOOL ContextPropertyList_FindProperty(PCONTEXT_PROPERTY_LIST list, DWORD id, + PCRYPT_DATA_BLOB blob) +{ + PCONTEXT_PROPERTY prop; + BOOL ret = FALSE; + + TRACE("(%p, %ld, %p)\n", list, id, blob); + + EnterCriticalSection(&list->cs); + LIST_FOR_EACH_ENTRY(prop, &list->properties, CONTEXT_PROPERTY, entry) + { + if (prop->propID == id) + { + blob->cbData = prop->cbData; + blob->pbData = prop->pbData; + ret = TRUE; + break; + } + } + LeaveCriticalSection(&list->cs); + return ret; +} + +BOOL ContextPropertyList_SetProperty(PCONTEXT_PROPERTY_LIST list, DWORD id, + const BYTE *pbData, size_t cbData) +{ + LPBYTE data; + BOOL ret = FALSE; + + if (cbData) + { + data = CryptMemAlloc(cbData); + if (data) + memcpy(data, pbData, cbData); + } + else + data = NULL; + if (!cbData || data) + { + PCONTEXT_PROPERTY prop; + BOOL found = FALSE; + + EnterCriticalSection(&list->cs); + LIST_FOR_EACH_ENTRY(prop, &list->properties, CONTEXT_PROPERTY, entry) + { + if (prop->propID == id) + { + found = TRUE; + break; + } + } + if (found) + { + CryptMemFree(prop->pbData); + prop->cbData = cbData; + prop->pbData = data; + ret = TRUE; + } + else + { + prop = CryptMemAlloc(sizeof(CONTEXT_PROPERTY)); + if (prop) + { + prop->propID = id; + prop->cbData = cbData; + list_init(&prop->entry); + prop->pbData = data; + list_add_tail(&list->properties, &prop->entry); + ret = TRUE; + } + else + CryptMemFree(data); + } + LeaveCriticalSection(&list->cs); + } + return ret; +} + +void ContextPropertyList_RemoveProperty(PCONTEXT_PROPERTY_LIST list, DWORD id) +{ + PCONTEXT_PROPERTY prop, next; + + EnterCriticalSection(&list->cs); + LIST_FOR_EACH_ENTRY_SAFE(prop, next, &list->properties, CONTEXT_PROPERTY, + entry) + { + if (prop->propID == id) + { + list_remove(&prop->entry); + CryptMemFree(prop->pbData); + CryptMemFree(prop); + } + } + LeaveCriticalSection(&list->cs); +} + +/* Since the properties are stored in a list, this is a tad inefficient + * (O(n^2)) since I have to find the previous position every time. + */ +DWORD ContextPropertyList_EnumPropIDs(PCONTEXT_PROPERTY_LIST list, DWORD id) +{ + DWORD ret; + + EnterCriticalSection(&list->cs); + if (id) + { + PCONTEXT_PROPERTY cursor = NULL; + + LIST_FOR_EACH_ENTRY(cursor, &list->properties, CONTEXT_PROPERTY, entry) + { + if (cursor->propID == id) + break; + } + if (cursor) + { + if (cursor->entry.next != &list->properties) + ret = LIST_ENTRY(cursor->entry.next, CONTEXT_PROPERTY, + entry)->propID; + else + ret = 0; + } + else + ret = 0; + } + else if (!list_empty(&list->properties)) + ret = LIST_ENTRY(list->properties.next, CONTEXT_PROPERTY, + entry)->propID; + else + ret = 0; + LeaveCriticalSection(&list->cs); + return ret; +} + +void ContextPropertyList_Copy(PCONTEXT_PROPERTY_LIST to, + PCONTEXT_PROPERTY_LIST from) +{ + PCONTEXT_PROPERTY prop; + + EnterCriticalSection(&from->cs); + LIST_FOR_EACH_ENTRY(prop, &from->properties, CONTEXT_PROPERTY, entry) + { + ContextPropertyList_SetProperty(to, prop->propID, prop->pbData, + prop->cbData); + } + LeaveCriticalSection(&from->cs); +} diff --git a/reactos/dll/win32/crypt32/serialize.c b/reactos/dll/win32/crypt32/serialize.c new file mode 100644 index 00000000000..228bf2de7d6 --- /dev/null +++ b/reactos/dll/win32/crypt32/serialize.c @@ -0,0 +1,515 @@ +/* + * 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 + */ +#include +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "wine/debug.h" +#include "excpt.h" +#include "wine/exception.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +/* 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, +}; + +/* 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; + +BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext, + DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) +{ + FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement, + pcbElement); + return FALSE; +} + +BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext, + DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) +{ + FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement, + pcbElement); + return FALSE; +} + +BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext, + DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) +{ + BOOL ret; + + TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement, + pcbElement); + + if (pCertContext) + { + DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + + pCertContext->cbCertEncoded; + DWORD prop = 0; + + ret = TRUE; + do { + prop = CertEnumCertificateContextProperties(pCertContext, prop); + if (prop) + { + DWORD propSize = 0; + + ret = CertGetCertificateContextProperty(pCertContext, + prop, NULL, &propSize); + if (ret) + bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize; + } + } while (ret && prop != 0); + + if (!pbElement) + { + *pcbElement = bytesNeeded; + ret = TRUE; + } + else if (*pcbElement < bytesNeeded) + { + *pcbElement = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + PWINE_CERT_PROP_HEADER hdr; + DWORD bufSize = 0; + LPBYTE buf = NULL; + + prop = 0; + do { + prop = CertEnumCertificateContextProperties(pCertContext, prop); + if (prop) + { + DWORD propSize = 0; + + ret = CertGetCertificateContextProperty(pCertContext, + prop, NULL, &propSize); + if (ret) + { + if (bufSize < propSize) + { + if (buf) + buf = CryptMemRealloc(buf, propSize); + else + buf = CryptMemAlloc(propSize); + bufSize = propSize; + } + if (buf) + { + ret = CertGetCertificateContextProperty( + pCertContext, prop, buf, &propSize); + if (ret) + { + hdr = (PWINE_CERT_PROP_HEADER)pbElement; + hdr->propID = prop; + hdr->unknown = 1; + hdr->cb = propSize; + pbElement += sizeof(WINE_CERT_PROP_HEADER); + if (propSize) + { + memcpy(pbElement, buf, propSize); + pbElement += propSize; + } + } + } + else + ret = FALSE; + } + } + } while (ret && prop != 0); + CryptMemFree(buf); + + hdr = (PWINE_CERT_PROP_HEADER)pbElement; + hdr->propID = CERT_CERT_PROP_ID; + hdr->unknown = 1; + hdr->cb = pCertContext->cbCertEncoded; + memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER), + pCertContext->pbCertEncoded, pCertContext->cbCertEncoded); + } + } + else + ret = FALSE; + return ret; +} + +/* Looks for the property with ID propID in the buffer buf. Returns a pointer + * to its header if a valid header is found, NULL if not. Valid means the + * length of thte property won't overrun buf, and the unknown field is 1. + */ +static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf, + DWORD size, DWORD propID) +{ + const WINE_CERT_PROP_HEADER *ret = NULL; + BOOL done = FALSE; + + while (size && !ret && !done) + { + if (size < sizeof(WINE_CERT_PROP_HEADER)) + { + SetLastError(CRYPT_E_FILE_ERROR); + done = TRUE; + } + else + { + const WINE_CERT_PROP_HEADER *hdr = + (const WINE_CERT_PROP_HEADER *)buf; + + size -= sizeof(WINE_CERT_PROP_HEADER); + buf += sizeof(WINE_CERT_PROP_HEADER); + if (size < hdr->cb) + { + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + done = TRUE; + } + else if (!hdr->propID) + { + /* assume a zero prop ID means the data are uninitialized, so + * stop looking. + */ + done = TRUE; + } + else if (hdr->unknown != 1) + { + SetLastError(ERROR_FILE_NOT_FOUND); + done = TRUE; + } + else if (hdr->propID == propID) + ret = hdr; + else + { + buf += hdr->cb; + size -= hdr->cb; + } + } + } + return ret; +} + +const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement, + DWORD dwContextTypeFlags, DWORD *pdwContentType) +{ + const void *context; + + TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags, + pdwContentType); + + if (!cbElement) + { + SetLastError(ERROR_END_OF_MEDIA); + return NULL; + } + + __TRY + { + const WINE_CONTEXT_INTERFACE *contextInterface = NULL; + const WINE_CERT_PROP_HEADER *hdr = NULL; + DWORD type = 0; + BOOL ret; + + ret = TRUE; + context = NULL; + if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG) + { + hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID); + if (hdr) + type = CERT_STORE_CERTIFICATE_CONTEXT; + else + { + hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID); + if (hdr) + type = CERT_STORE_CRL_CONTEXT; + else + { + hdr = CRYPT_findPropID(pbElement, cbElement, + CERT_CTL_PROP_ID); + if (hdr) + type = CERT_STORE_CTL_CONTEXT; + } + } + } + else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG) + { + hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID); + type = CERT_STORE_CERTIFICATE_CONTEXT; + } + else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG) + { + hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID); + type = CERT_STORE_CRL_CONTEXT; + } + else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG) + { + hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID); + type = CERT_STORE_CTL_CONTEXT; + } + + switch (type) + { + 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: + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + ret = FALSE; + } + if (!hdr) + ret = FALSE; + + if (ret) + context = contextInterface->create(X509_ASN_ENCODING, + (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb); + if (ret && context) + { + BOOL noMoreProps = FALSE; + + while (!noMoreProps && ret) + { + if (cbElement < sizeof(WINE_CERT_PROP_HEADER)) + ret = FALSE; + else + { + const WINE_CERT_PROP_HEADER *hdr = + (const WINE_CERT_PROP_HEADER *)pbElement; + + TRACE("prop is %ld\n", hdr->propID); + cbElement -= sizeof(WINE_CERT_PROP_HEADER); + pbElement += sizeof(WINE_CERT_PROP_HEADER); + if (cbElement < hdr->cb) + { + SetLastError(HRESULT_FROM_WIN32( + ERROR_INVALID_PARAMETER)); + ret = FALSE; + } + else if (!hdr->propID) + { + /* Like in CRYPT_findPropID, stop if the propID is zero + */ + noMoreProps = TRUE; + } + else if (hdr->unknown != 1) + { + SetLastError(ERROR_FILE_NOT_FOUND); + ret = FALSE; + } + else if (hdr->propID != CERT_CERT_PROP_ID && + hdr->propID != CERT_CRL_PROP_ID && hdr->propID != + CERT_CTL_PROP_ID) + { + /* Have to create a blob for most types, but not + * for all.. arghh. + */ + switch (hdr->propID) + { + case CERT_AUTO_ENROLL_PROP_ID: + case CERT_CTL_USAGE_PROP_ID: + case CERT_DESCRIPTION_PROP_ID: + case CERT_FRIENDLY_NAME_PROP_ID: + case CERT_HASH_PROP_ID: + case CERT_KEY_IDENTIFIER_PROP_ID: + case CERT_MD5_HASH_PROP_ID: + case CERT_NEXT_UPDATE_LOCATION_PROP_ID: + case CERT_PUBKEY_ALG_PARA_PROP_ID: + case CERT_PVK_FILE_PROP_ID: + case CERT_SIGNATURE_HASH_PROP_ID: + case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: + case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: + case CERT_ENROLLMENT_PROP_ID: + case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: + case CERT_RENEWAL_PROP_ID: + { + CRYPT_DATA_BLOB blob = { hdr->cb, + (LPBYTE)pbElement }; + + ret = contextInterface->setProp(context, + hdr->propID, 0, &blob); + break; + } + case CERT_DATE_STAMP_PROP_ID: + ret = contextInterface->setProp(context, + hdr->propID, 0, pbElement); + break; + default: + FIXME("prop ID %ld: stub\n", hdr->propID); + } + } + pbElement += hdr->cb; + cbElement -= hdr->cb; + if (!cbElement) + noMoreProps = TRUE; + } + } + if (ret) + { + if (pdwContentType) + *pdwContentType = type; + } + else + { + contextInterface->free(context); + context = NULL; + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + context = NULL; + } + __ENDTRY + return context; +} + +BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore, + const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags, + DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext) +{ + const void *context; + DWORD type; + BOOL ret; + + TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore, + pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags, + pdwContentType, ppvContext); + + /* Call the internal function, then delete the hashes. Tests show this + * function uses real hash values, not whatever's stored in the hash + * property. + */ + context = CRYPT_ReadSerializedElement(pbElement, cbElement, + dwContextTypeFlags, &type); + if (context) + { + const WINE_CONTEXT_INTERFACE *contextInterface = NULL; + + switch (type) + { + 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: + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + } + if (contextInterface) + { + contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL); + contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL); + contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0, + NULL); + if (pdwContentType) + *pdwContentType = type; + ret = contextInterface->addContextToStore(hCertStore, context, + dwAddDisposition, ppvContext); + contextInterface->free(context); + } + else + ret = FALSE; + } + else + ret = FALSE; + return ret; +} diff --git a/reactos/dll/win32/crypt32/store.c b/reactos/dll/win32/crypt32/store.c new file mode 100644 index 00000000000..3b521719667 --- /dev/null +++ b/reactos/dll/win32/crypt32/store.c @@ -0,0 +1,2666 @@ +/* + * 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 +#include +#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) + *ppStoreContext = + CertDuplicateCertificateContext((PCCERT_CONTEXT)entry); + ret = TRUE; + } + else + ret = FALSE; + } + else + ret = FALSE; + TRACE("returning %d\n", ret); + return ret; +} + +static PWINE_CERT_CONTEXT CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, + PWINE_CERT_CONTEXT pPrev) +{ + WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; + PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev; + PWINE_CERT_CONTEXT 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 = (PWINE_CERT_CONTEXT)CertDuplicateCertificateContext( + (PCCERT_CONTEXT)LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry)); + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + LeaveCriticalSection(&ms->cs); + + TRACE("returning %p\n", ret); + return ret; +} + +static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwFlags) +{ + WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore; + PWINE_CERT_LIST_ENTRY cert = (PWINE_CERT_LIST_ENTRY)pCertContext; + BOOL ret; + + /* The passed-in context is itself a list entry, so just remove it. */ + EnterCriticalSection(&store->cs); + list_remove(&cert->entry); + ret = CertFreeCertificateContext(pCertContext); + LeaveCriticalSection(&store->cs); + return ret; +} + +static void CRYPT_MemEmptyStore(PWINE_MEMSTORE store) +{ + PWINE_CERT_LIST_ENTRY cert, next; + + EnterCriticalSection(&store->cs); + 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); + } + LeaveCriticalSection(&store->cs); +} + +static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) +{ + WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore; + + TRACE("(%p, %08lx)\n", store, dwFlags); + if (dwFlags) + FIXME("Unimplemented flags: %08lx\n", dwFlags); + + CRYPT_MemEmptyStore(store); + 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.enumCert = CRYPT_MemEnumCert; + store->hdr.deleteCert = CRYPT_MemDeleteCert; + store->hdr.control = NULL; + InitializeCriticalSection(&store->cs); + list_init(&store->certs); + } + } + return (PWINECRYPT_CERTSTORE)store; +} + +static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, + PWINE_CERT_CONTEXT cert, DWORD dwAddDisposition, + PCCERT_CONTEXT *ppStoreContext) +{ + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + PWINE_STORE_LIST_ENTRY entry, next; + BOOL ret; + + TRACE("(%p, %p, %ld, %p)\n", store, cert, dwAddDisposition, ppStoreContext); + + 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, cert, dwAddDisposition, + ppStoreContext); + break; + } + } + LeaveCriticalSection(&cs->cs); + SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)); + return 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 child; + struct list *storeNext = list_next(&store->stores, &storeEntry->entry); + + TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev); + + if (pPrev) + { + /* Ref-counting funny business: "duplicate" (addref) the child, because + * the CertFreeCertificateContext(pPrev) below can cause the ref count + * to become negative. See comment below as well. + */ + child = ((PWINE_COLLECTION_CERT_CONTEXT)pPrev)->cert.linked; + CertDuplicateCertificateContext((PCCERT_CONTEXT)child); + child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store, + child); + CertFreeCertificateContext((PCCERT_CONTEXT)pPrev); + pPrev = NULL; + } + else + child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store, + NULL); + if (child) + { + ret = CryptMemAlloc(sizeof(WINE_COLLECTION_CERT_CONTEXT)); + if (ret) + { + CRYPT_InitCertRef((PWINE_CERT_CONTEXT_LINK)ret, child, store); + /* enumCert already addref'd once, and CRYPT_InitCertRef does again, + * so free child once to get the ref count right. (Not doing so + * will leak memory if the caller calls CertFreeCertificateContext + * rather than CertEnumCertificatesInStore.) + */ + CertFreeCertificateContext((PCCERT_CONTEXT)child); + ret->storeEntry = storeEntry; + } + else + CertFreeCertificateContext((PCCERT_CONTEXT)child); + } + else + { + 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 CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, + PWINE_CERT_CONTEXT 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->storeEntry, 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, NULL); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + LeaveCriticalSection(&cs->cs); + } + TRACE("returning %p\n", ret); + return (PWINE_CERT_CONTEXT)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->cert.linked); + return ret; +} + +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.enumCert = CRYPT_CollectionEnumCert; + store->hdr.deleteCert = CRYPT_CollectionDeleteCert; + InitializeCriticalSection(&store->cs); + list_init(&store->stores); + } + } + return (PWINECRYPT_CERTSTORE)store; +} + +static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) +{ + PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore; + + TRACE("(%p, %08lx)\n", store, dwFlags); + + if (store->provCloseStore) + store->provCloseStore(store->hStoreProv, dwFlags); + if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)) + CertCloseStore(store->memStore, dwFlags); + CryptMemFree(store); +} + +static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, + PWINE_CERT_CONTEXT cert, DWORD dwAddDisposition, + PCCERT_CONTEXT *ppStoreContext) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + BOOL ret; + + TRACE("(%p, %p, %ld, %p)\n", store, cert, dwAddDisposition, ppStoreContext); + + if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) + { + SetLastError(ERROR_ACCESS_DENIED); + ret = FALSE; + } + else + { + ret = TRUE; + if (ps->provWriteCert) + ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert, + CERT_STORE_PROV_WRITE_ADD_FLAG); + if (ret) + { + ret = ps->memStore->addCert(ps->memStore, cert, + dwAddDisposition, ppStoreContext); + /* dirty trick: replace the returned context's hCertStore with + * store. + */ + if (ppStoreContext) + (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store; + } + } + return ret; +} + +static PWINE_CERT_CONTEXT CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store, + PWINE_CERT_CONTEXT pPrev) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + PWINE_CERT_CONTEXT ret; + + ret = ps->memStore->enumCert(ps->memStore, pPrev); + if (ret) + { + /* same dirty trick: replace the returned context's hCertStore with + * store. + */ + ret->cert.hCertStore = store; + } + return ret; +} + +static BOOL WINAPI CRYPT_ProvDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT cert, DWORD dwFlags) +{ + PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore; + BOOL ret = TRUE; + + TRACE("(%p, %p, %08lx)\n", hCertStore, cert, dwFlags); + + if (store->provDeleteCert) + ret = store->provDeleteCert(store->hStoreProv, cert, dwFlags); + if (ret) + ret = store->memStore->deleteCert(store->memStore, cert, dwFlags); + return ret; +} + +static BOOL WINAPI CRYPT_ProvControl(HCERTSTORE hCertStore, DWORD dwFlags, + DWORD dwCtrlType, void const *pvCtrlPara) +{ + PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore; + BOOL ret = TRUE; + + TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType, + pvCtrlPara); + + if (store->provControl) + ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType, + pvCtrlPara); + return ret; +} + +static PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv, + DWORD dwFlags, PWINECRYPT_CERTSTORE memStore, PCERT_STORE_PROV_INFO pProvInfo) +{ + PWINE_PROVIDERSTORE ret = (PWINE_PROVIDERSTORE)CryptMemAlloc( + sizeof(WINE_PROVIDERSTORE)); + + if (ret) + { + CRYPT_InitStore(&ret->hdr, hCryptProv, dwFlags, + StoreTypeProvider); + ret->dwStoreProvFlags = pProvInfo->dwStoreProvFlags; + if (ret->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG) + { + CertCloseStore(memStore, 0); + ret->memStore = NULL; + } + else + ret->memStore = memStore; + ret->hStoreProv = pProvInfo->hStoreProv; + ret->hdr.closeStore = CRYPT_ProvCloseStore; + ret->hdr.addCert = CRYPT_ProvAddCert; + ret->hdr.enumCert = CRYPT_ProvEnumCert; + ret->hdr.deleteCert = CRYPT_ProvDeleteCert; + ret->hdr.control = CRYPT_ProvControl; + if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC) + ret->provCloseStore = + pProvInfo->rgpvStoreProvFunc[CERT_STORE_PROV_CLOSE_FUNC]; + else + ret->provCloseStore = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_WRITE_CERT_FUNC) + ret->provWriteCert = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_WRITE_CERT_FUNC]; + else + ret->provWriteCert = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_DELETE_CERT_FUNC) + ret->provDeleteCert = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_DELETE_CERT_FUNC]; + else + ret->provDeleteCert = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_CONTROL_FUNC) + ret->provControl = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_CONTROL_FUNC]; + else + ret->provControl = NULL; + } + return (PWINECRYPT_CERTSTORE)ret; +} + +static PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider, + DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara) +{ + static HCRYPTOIDFUNCSET set = NULL; + PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc; + HCRYPTOIDFUNCADDR hFunc; + PWINECRYPT_CERTSTORE ret = NULL; + + if (!set) + set = CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0); + CryptGetOIDFunctionAddress(set, dwEncodingType, lpszStoreProvider, 0, + (void **)&provOpenFunc, &hFunc); + if (provOpenFunc) + { + CERT_STORE_PROV_INFO provInfo = { 0 }; + + provInfo.cbSize = sizeof(provInfo); + if (dwFlags & CERT_STORE_DELETE_FLAG) + provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv, + dwFlags, pvPara, NULL, &provInfo); + else + { + PWINECRYPT_CERTSTORE memStore; + + memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL); + if (memStore) + { + if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv, + dwFlags, pvPara, memStore, &provInfo)) + ret = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore, + &provInfo); + else + CertCloseStore(memStore, 0); + } + } + CryptFreeOIDFunctionAddress(hFunc, 0); + } + else + SetLastError(ERROR_FILE_NOT_FOUND); + return ret; +} + +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_REGSTOREINFO 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->memStore, 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_REGSTOREINFO 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); + RegCloseKey(subKey); + } + if (!rc) + ret = TRUE; + else + { + SetLastError(rc); + ret = FALSE; + } + return ret; +} + +static BOOL CRYPT_SerializeContextsToReg(HKEY key, + const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore) +{ + const void *context = NULL; + BOOL ret; + + do { + context = contextInterface->enumContextsInStore(memStore, context); + if (context) + { + BYTE hash[20]; + DWORD hashSize = sizeof(hash); + + ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash, + &hashSize); + if (ret) + { + DWORD size = 0; + LPBYTE buf = NULL; + + ret = contextInterface->serialize(context, 0, NULL, &size); + if (size) + buf = CryptMemAlloc(size); + if (buf) + { + ret = contextInterface->serialize(context, 0, buf, &size); + if (ret) + ret = CRYPT_WriteSerializedToReg(key, hash, buf, size); + } + CryptMemFree(buf); + } + } + else + ret = TRUE; + } while (ret && context != NULL); + if (context) + contextInterface->free(context); + return ret; +} + +static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store) +{ + static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW }; + static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface, + &gCRLInterface, &gCTLInterface }; + struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL }; + BOOL ret = TRUE; + DWORD i; + + for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++) + { + HKEY key; + LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &key, NULL); + + if (!rc) + { + if (listToDelete[i]) + { + PWINE_HASH_TO_DELETE toDelete, next; + WCHAR asciiHash[20 * 2 + 1]; + + EnterCriticalSection(&store->cs); + LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i], + WINE_HASH_TO_DELETE, entry) + { + LONG rc; + + CRYPT_HashToStr(toDelete->hash, asciiHash); + TRACE("Removing %s\n", debugstr_w(asciiHash)); + rc = RegDeleteKeyW(key, asciiHash); + if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND) + { + SetLastError(rc); + ret = FALSE; + } + list_remove(&toDelete->entry); + CryptMemFree(toDelete); + } + LeaveCriticalSection(&store->cs); + } + ret = CRYPT_SerializeContextsToReg(key, interfaces[i], + store->memStore); + RegCloseKey(key); + } + else + { + SetLastError(rc); + ret = FALSE; + } + } + return ret; +} + +/* If force is true or the registry store is dirty, writes the contents of the + * store to the registry. + */ +static BOOL CRYPT_RegFlushStore(PWINE_REGSTOREINFO store, BOOL force) +{ + BOOL ret; + + TRACE("(%p, %d)\n", store, force); + + if (store->dirty || force) + ret = CRYPT_RegWriteToReg(store); + else + ret = TRUE; + return ret; +} + +static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %08lx)\n", store, dwFlags); + if (dwFlags) + FIXME("Unimplemented flags: %08lx\n", dwFlags); + + CRYPT_RegFlushStore(store, FALSE); + RegCloseKey(store->key); + DeleteCriticalSection(&store->cs); + CryptMemFree(store); +} + +static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT cert, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + BOOL ret; + + TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags); + + if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG) + { + store->dirty = TRUE; + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + BOOL ret; + + TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags); + + if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG) + { + SetLastError(ERROR_ACCESS_DENIED); + ret = FALSE; + } + else + { + PWINE_HASH_TO_DELETE toDelete = + CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE)); + + if (toDelete) + { + DWORD size = sizeof(toDelete->hash); + + ret = CertGetCertificateContextProperty(pCertContext, + CERT_HASH_PROP_ID, toDelete->hash, &size); + if (ret) + { + EnterCriticalSection(&store->cs); + list_add_tail(&store->certsToDelete, &toDelete->entry); + LeaveCriticalSection(&store->cs); + } + else + { + CryptMemFree(toDelete); + ret = FALSE; + } + } + else + ret = FALSE; + if (ret) + store->dirty = TRUE; + } + return ret; +} + +static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags, + DWORD dwCtrlType, void const *pvCtrlPara) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + BOOL ret; + + TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType, + pvCtrlPara); + + switch (dwCtrlType) + { + case CERT_STORE_CTRL_RESYNC: + CRYPT_RegFlushStore(store, FALSE); + CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore); + CRYPT_RegReadFromReg(store); + ret = TRUE; + break; + case CERT_STORE_CTRL_COMMIT: + ret = CRYPT_RegFlushStore(store, + dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG); + break; + default: + FIXME("%ld: stub\n", dwCtrlType); + ret = FALSE; + } + return ret; +} + +/* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */ +static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey) +{ + DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i; + WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; + HKEY hSubKey = 0; + + TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey)); + + dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); + if (!dwRet) + { + /* Find how many subkeys there are */ + dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount, + &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); + if (!dwRet) + { + dwMaxSubkeyLen++; + if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR)) + { + /* Name too big: alloc a buffer for it */ + lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR)); + } + + if (!lpszName) + dwRet = ERROR_NOT_ENOUGH_MEMORY; + else + { + /* Recursively delete all the subkeys */ + for (i = 0; i < dwKeyCount && !dwRet; i++) + { + dwSize = dwMaxSubkeyLen; + dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, + NULL, NULL, NULL); + if (!dwRet) + dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName); + } + + if (lpszName != szNameBuf) + { + /* Free buffer if allocated */ + CryptMemFree(lpszName); + } + } + } + + RegCloseKey(hSubKey); + if (!dwRet) + dwRet = RegDeleteKeyW(hKey, lpszSubKey); + } + return dwRet; +} + +static void *regProvFuncs[] = { + CRYPT_RegCloseStore, + NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */ + CRYPT_RegWriteCert, + CRYPT_RegDeleteCert, + NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */ + NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */ + NULL, /* CERT_STORE_PROV_WRITE_CRL_FUNC */ + NULL, /* CERT_STORE_PROV_DELETE_CRL_FUNC */ + NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */ + NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */ + CRYPT_RegControl, +}; + +static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + PWINECRYPT_CERTSTORE store = NULL; + + TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara); + + if (dwFlags & CERT_STORE_DELETE_FLAG) + { + DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW); + + if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) + rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW); + if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) + rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW); + if (rc == ERROR_NO_MORE_ITEMS) + rc = ERROR_SUCCESS; + SetLastError(rc); + } + else + { + HKEY key; + + if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara, + GetCurrentProcess(), (LPHANDLE)&key, + dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS, + TRUE, 0)) + { + PWINECRYPT_CERTSTORE memStore; + + memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL); + if (memStore) + { + PWINE_REGSTOREINFO regInfo = CryptMemAlloc( + sizeof(WINE_REGSTOREINFO)); + + if (regInfo) + { + CERT_STORE_PROV_INFO provInfo = { 0 }; + + regInfo->dwOpenFlags = dwFlags; + regInfo->cryptProv = hCryptProv; + regInfo->memStore = memStore; + regInfo->key = key; + InitializeCriticalSection(®Info->cs); + list_init(®Info->certsToDelete); + CRYPT_RegReadFromReg(regInfo); + regInfo->dirty = FALSE; + provInfo.cbSize = sizeof(provInfo); + provInfo.cStoreProvFunc = sizeof(regProvFuncs) / + sizeof(regProvFuncs[0]); + provInfo.rgpvStoreProvFunc = regProvFuncs; + provInfo.hStoreProv = regInfo; + store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore, + &provInfo); + } + } + } + } + TRACE("returning %p\n", store); + return store; +} + +/* FIXME: this isn't complete for the Root store, in which the top-level + * self-signed CA certs reside. Adding a cert to the Root store should present + * the user with a dialog indicating the consequences of doing so, and asking + * the user to confirm whether the cert should be added. + */ +static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + static const WCHAR fmt[] = { '%','s','\\','%','s',0 }; + LPCWSTR storeName = (LPCWSTR)pvPara; + LPWSTR storePath; + PWINECRYPT_CERTSTORE store = NULL; + HKEY root; + LPCWSTR base; + BOOL ret; + + TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, + debugstr_w((LPCWSTR)pvPara)); + + if (!pvPara) + { + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return NULL; + } + + ret = TRUE; + switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) + { + case CERT_SYSTEM_STORE_LOCAL_MACHINE: + root = HKEY_LOCAL_MACHINE; + base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; + break; + case CERT_SYSTEM_STORE_CURRENT_USER: + root = HKEY_CURRENT_USER; + base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; + break; + case CERT_SYSTEM_STORE_CURRENT_SERVICE: + /* hklm\Software\Microsoft\Cryptography\Services\servicename\ + * SystemCertificates + */ + FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n", + debugstr_w(storeName)); + return NULL; + case CERT_SYSTEM_STORE_SERVICES: + /* hklm\Software\Microsoft\Cryptography\Services\servicename\ + * SystemCertificates + */ + FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n", + debugstr_w(storeName)); + return NULL; + case CERT_SYSTEM_STORE_USERS: + /* hku\user sid\Software\Microsoft\SystemCertificates */ + FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n", + debugstr_w(storeName)); + return NULL; + case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY: + root = HKEY_CURRENT_USER; + base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; + break; + case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY: + root = HKEY_LOCAL_MACHINE; + base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; + break; + case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE: + /* hklm\Software\Microsoft\EnterpriseCertificates */ + FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n", + debugstr_w(storeName)); + return NULL; + default: + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return NULL; + } + + storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) * + sizeof(WCHAR)); + if (storePath) + { + LONG rc; + HKEY key; + REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : + KEY_ALL_ACCESS; + + wsprintfW(storePath, fmt, base, storeName); + if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG) + rc = RegOpenKeyExW(root, storePath, 0, sam, &key); + else + { + DWORD disp; + + rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL, + &key, &disp); + if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG && + disp == REG_OPENED_EXISTING_KEY) + { + RegCloseKey(key); + rc = ERROR_FILE_EXISTS; + } + } + if (!rc) + { + store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key); + RegCloseKey(key); + } + else + SetLastError(rc); + CryptMemFree(storePath); + } + return store; +} + +static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + int len; + PWINECRYPT_CERTSTORE ret = NULL; + + TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, + debugstr_a((LPCSTR)pvPara)); + + if (!pvPara) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return NULL; + } + len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0); + if (len) + { + LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); + + if (storeName) + { + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len); + ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName); + CryptMemFree(storeName); + } + } + return ret; +} + +static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + HCERTSTORE store = 0; + BOOL ret; + + TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, + debugstr_w((LPCWSTR)pvPara)); + + if (!pvPara) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return NULL; + } + /* This returns a different error than system registry stores if the + * location is invalid. + */ + switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) + { + case CERT_SYSTEM_STORE_LOCAL_MACHINE: + case CERT_SYSTEM_STORE_CURRENT_USER: + case CERT_SYSTEM_STORE_CURRENT_SERVICE: + case CERT_SYSTEM_STORE_SERVICES: + case CERT_SYSTEM_STORE_USERS: + case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY: + case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY: + case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE: + ret = TRUE; + break; + default: + SetLastError(ERROR_FILE_NOT_FOUND); + ret = FALSE; + } + if (ret) + { + HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, + 0, hCryptProv, dwFlags, pvPara); + + if (regStore) + { + store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddStoreToCollection(store, regStore, + dwFlags & CERT_STORE_READONLY_FLAG ? 0 : + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + CertCloseStore(regStore, 0); + /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM + * stores. + */ + if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) == + CERT_SYSTEM_STORE_CURRENT_USER) + { + dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER; + dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE; + regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, + hCryptProv, dwFlags, pvPara); + if (regStore) + { + CertAddStoreToCollection(store, regStore, + dwFlags & CERT_STORE_READONLY_FLAG ? 0 : + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + CertCloseStore(regStore, 0); + } + } + } + } + return (PWINECRYPT_CERTSTORE)store; +} + +static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + int len; + PWINECRYPT_CERTSTORE ret = NULL; + + TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, + debugstr_a((LPCSTR)pvPara)); + + if (!pvPara) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return NULL; + } + len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0); + if (len) + { + LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); + + if (storeName) + { + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len); + ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName); + CryptMemFree(storeName); + } + } + return ret; +} + +HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, + DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, + const void* pvPara) +{ + WINECRYPT_CERTSTORE *hcs; + StoreOpenFunc openFunc = NULL; + + TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider), + dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara); + + if (!HIWORD(lpszStoreProvider)) + { + switch (LOWORD(lpszStoreProvider)) + { + case (int)CERT_STORE_PROV_MEMORY: + openFunc = CRYPT_MemOpenStore; + break; + case (int)CERT_STORE_PROV_REG: + openFunc = CRYPT_RegOpenStore; + break; + case (int)CERT_STORE_PROV_COLLECTION: + openFunc = CRYPT_CollectionOpenStore; + break; + case (int)CERT_STORE_PROV_SYSTEM_A: + openFunc = CRYPT_SysOpenStoreA; + break; + case (int)CERT_STORE_PROV_SYSTEM_W: + openFunc = CRYPT_SysOpenStoreW; + break; + case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A: + openFunc = CRYPT_SysRegOpenStoreA; + break; + case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W: + openFunc = CRYPT_SysRegOpenStoreW; + break; + default: + if (LOWORD(lpszStoreProvider)) + FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider)); + } + } + else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY)) + openFunc = CRYPT_MemOpenStore; + else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM)) + openFunc = CRYPT_SysOpenStoreW; + else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION)) + openFunc = CRYPT_CollectionOpenStore; + else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY)) + openFunc = CRYPT_SysRegOpenStoreW; + else + { + FIXME("unimplemented type %s\n", lpszStoreProvider); + openFunc = NULL; + } + + if (!openFunc) + hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType, + hCryptProv, dwFlags, pvPara); + else + hcs = openFunc(hCryptProv, dwFlags, pvPara); + return (HCERTSTORE)hcs; +} + +HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv, + LPCSTR szSubSystemProtocol) +{ + if (!szSubSystemProtocol) + { + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return 0; + } + return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv, + CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol); +} + +HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv, + LPCWSTR szSubSystemProtocol) +{ + if (!szSubSystemProtocol) + { + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return 0; + } + return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv, + CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol); +} + +BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType, + DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags) +{ + FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore, + dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags); + return TRUE; +} + +PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType, + const BYTE* pbCrlEncoded, DWORD cbCrlEncoded) +{ + PCRL_CONTEXT pcrl; + BYTE* data; + + TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded); + + /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */ + pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) ); + if( !pcrl ) + return NULL; + + data = CryptMemAlloc( cbCrlEncoded ); + if( !data ) + { + CryptMemFree( pcrl ); + return NULL; + } + + pcrl->dwCertEncodingType = dwCertEncodingType; + pcrl->pbCrlEncoded = data; + pcrl->cbCrlEncoded = cbCrlEncoded; + pcrl->pCrlInfo = NULL; + pcrl->hCertStore = 0; + + return pcrl; +} + +/* Decodes the encoded certificate and creates the certificate context for it. + */ +static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext( + DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded) +{ + PWINE_CERT_CONTEXT_DATA cert = NULL; + BOOL ret; + PCERT_SIGNED_CONTENT_INFO signedCert = NULL; + PCERT_INFO certInfo = NULL; + DWORD size = 0; + + TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded, + cbCertEncoded); + + /* First try to decode it as a signed cert. */ + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded, + cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&signedCert, &size); + if (ret) + { + size = 0; + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, + signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&certInfo, &size); + LocalFree(signedCert); + } + /* Failing that, try it as an unsigned cert */ + if (!ret) + { + size = 0; + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, + pbCertEncoded, cbCertEncoded, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + (BYTE *)&certInfo, &size); + } + if (ret) + { + BYTE *data = NULL; + + cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_DATA)); + if (!cert) + goto end; + data = CryptMemAlloc(cbCertEncoded); + if (!data) + { + CryptMemFree(cert); + cert = NULL; + goto end; + } + memcpy(data, pbCertEncoded, cbCertEncoded); + cert->cert.dwCertEncodingType = dwCertEncodingType; + cert->cert.pbCertEncoded = data; + cert->cert.cbCertEncoded = cbCertEncoded; + cert->cert.pCertInfo = certInfo; + cert->cert.hCertStore = 0; + cert->ref = 1; + cert->type = ContextTypeData; + cert->properties = ContextPropertyList_Create(); + } + +end: + return (PWINE_CERT_CONTEXT)cert; +} + +PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType, + const BYTE *pbCertEncoded, DWORD cbCertEncoded) +{ + PWINE_CERT_CONTEXT cert; + + TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded, + cbCertEncoded); + + cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded, + cbCertEncoded); + return (PCCERT_CONTEXT)cert; +} + +/* If context is a link, follows it to its linked context (recursively, if + * necessary) and returns the data context associated with the link. + * Otherwise just returns context. + */ +static inline PWINE_CERT_CONTEXT_DATA CertContext_GetDataContext( + PWINE_CERT_CONTEXT context) +{ + PWINE_CERT_CONTEXT ptr = context; + + while (ptr && ptr->type == ContextTypeLink) + ptr = ((PWINE_CERT_CONTEXT_LINK)ptr)->linked; + return (ptr && ptr->type == ContextTypeData) ? + (PWINE_CERT_CONTEXT_DATA)ptr : NULL; +} + +DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext, + DWORD dwPropId) +{ + PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext( + (PWINE_CERT_CONTEXT)pCertContext); + DWORD ret; + + TRACE("(%p, %ld)\n", pCertContext, dwPropId); + + if (linked) + ret = ContextPropertyList_EnumPropIDs(linked->properties, dwPropId); + else + ret = 0; + return ret; +} + +static BOOL CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context, DWORD dwPropId, + ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData, + DWORD *pcbData) +{ + BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData, + pcbData); + if (ret) + { + CRYPT_DATA_BLOB blob = { *pcbData, pvData }; + + ret = CRYPT_SetCertificateContextProperty(context, dwPropId, + 0, &blob); + } + return ret; +} + +static BOOL WINAPI CRYPT_GetCertificateContextProperty( + PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData) +{ + PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext(context); + BOOL ret; + CRYPT_DATA_BLOB blob; + + TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData); + + if (linked) + ret = ContextPropertyList_FindProperty(linked->properties, dwPropId, + &blob); + else + ret = FALSE; + if (ret) + { + if (!pvData) + { + *pcbData = blob.cbData; + ret = TRUE; + } + else if (*pcbData < blob.cbData) + { + SetLastError(ERROR_MORE_DATA); + *pcbData = blob.cbData; + } + else + { + memcpy(pvData, blob.pbData, blob.cbData); + *pcbData = blob.cbData; + ret = TRUE; + } + } + else + { + /* Implicit properties */ + switch (dwPropId) + { + case CERT_SHA1_HASH_PROP_ID: + ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_SHA1, + context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData, + pcbData); + break; + case CERT_MD5_HASH_PROP_ID: + ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5, + context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData, + pcbData); + break; + case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: + ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5, + context->cert.pCertInfo->Subject.pbData, + context->cert.pCertInfo->Subject.cbData, + pvData, pcbData); + break; + case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: + ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5, + context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, + context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, + pvData, pcbData); + break; + case CERT_SIGNATURE_HASH_PROP_ID: + case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID: + FIXME("implicit property %ld\n", dwPropId); + SetLastError(CRYPT_E_NOT_FOUND); + break; + default: + SetLastError(CRYPT_E_NOT_FOUND); + } + } + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, + DWORD dwPropId, void *pvData, DWORD *pcbData) +{ + BOOL ret; + + TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData); + + /* Special cases for invalid/special prop IDs. + */ + switch (dwPropId) + { + case 0: + case CERT_CERT_PROP_ID: + case CERT_CRL_PROP_ID: + case CERT_CTL_PROP_ID: + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return FALSE; + case CERT_ACCESS_STATE_PROP_ID: + if (!pvData) + { + *pcbData = sizeof(DWORD); + return TRUE; + } + else if (*pcbData < sizeof(DWORD)) + { + SetLastError(ERROR_MORE_DATA); + *pcbData = sizeof(DWORD); + return FALSE; + } + else + { + DWORD state = 0; + + if (pCertContext->hCertStore) + { + PWINECRYPT_CERTSTORE store = + (PWINECRYPT_CERTSTORE)pCertContext->hCertStore; + + if (!(store->dwOpenFlags & CERT_STORE_READONLY_FLAG)) + state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG; + } + *(DWORD *)pvData = state; + return TRUE; + } + } + + ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCertContext, + dwPropId, pvData, pcbData); + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL WINAPI CRYPT_SetCertificateContextProperty( + PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData) +{ + PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext(context); + BOOL ret; + + TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData); + + if (!linked) + ret = FALSE; + else if (!pvData) + { + ContextPropertyList_RemoveProperty(linked->properties, dwPropId); + ret = TRUE; + } + else + { + switch (dwPropId) + { + case CERT_AUTO_ENROLL_PROP_ID: + case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */ + case CERT_DESCRIPTION_PROP_ID: + case CERT_FRIENDLY_NAME_PROP_ID: + case CERT_HASH_PROP_ID: + case CERT_KEY_IDENTIFIER_PROP_ID: + case CERT_MD5_HASH_PROP_ID: + case CERT_NEXT_UPDATE_LOCATION_PROP_ID: + case CERT_PUBKEY_ALG_PARA_PROP_ID: + case CERT_PVK_FILE_PROP_ID: + case CERT_SIGNATURE_HASH_PROP_ID: + case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: + case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: + case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: + case CERT_ENROLLMENT_PROP_ID: + case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: + case CERT_RENEWAL_PROP_ID: + { + PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData; + + ret = ContextPropertyList_SetProperty(linked->properties, dwPropId, + blob->pbData, blob->cbData); + break; + } + case CERT_DATE_STAMP_PROP_ID: + ret = ContextPropertyList_SetProperty(linked->properties, dwPropId, + pvData, sizeof(FILETIME)); + break; + default: + FIXME("%ld: stub\n", dwPropId); + ret = FALSE; + } + } + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext, + DWORD dwPropId, DWORD dwFlags, const void *pvData) +{ + BOOL ret; + + TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData); + + /* Handle special cases for "read-only"/invalid prop IDs. Windows just + * crashes on most of these, I'll be safer. + */ + switch (dwPropId) + { + case 0: + case CERT_ACCESS_STATE_PROP_ID: + case CERT_CERT_PROP_ID: + case CERT_CRL_PROP_ID: + case CERT_CTL_PROP_ID: + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return FALSE; + } + ret = CRYPT_SetCertificateContextProperty((PWINE_CERT_CONTEXT)pCertContext, + dwPropId, dwFlags, pvData); + TRACE("returning %d\n", ret); + return ret; +} + +PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext( + PCCERT_CONTEXT pCertContext) +{ + PWINE_CERT_CONTEXT context = (PWINE_CERT_CONTEXT)pCertContext; + + TRACE("(%p)\n", pCertContext); + InterlockedIncrement(&context->ref); + return pCertContext; +} + +BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition, + PCCERT_CONTEXT *ppStoreContext) +{ + PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore; + PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext( + (PWINE_CERT_CONTEXT)pCertContext); + PWINE_CERT_CONTEXT cert; + BOOL ret; + + TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext, + dwAddDisposition, ppStoreContext); + + /* FIXME: some tests needed to verify return codes */ + if (!store) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + cert = CRYPT_CreateCertificateContext(pCertContext->dwCertEncodingType, + pCertContext->pbCertEncoded, pCertContext->cbCertEncoded); + if (cert) + { + PWINE_CERT_CONTEXT_DATA certData = CertContext_GetDataContext(cert); + + ContextPropertyList_Copy(certData->properties, linked->properties); + ret = store->addCert(store, cert, dwAddDisposition, ppStoreContext); + CertFreeCertificateContext((PCCERT_CONTEXT)cert); + } + else + ret = FALSE; + return ret; +} + +BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded, + DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext) +{ + WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore; + BOOL ret; + + TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType, + pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext); + + if (!hcs) + ret = FALSE; + else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + ret = FALSE; + else + { + PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext( + dwCertEncodingType, pbCertEncoded, cbCertEncoded); + + if (cert) + { + ret = hcs->addCert(hcs, cert, dwAddDisposition, ppCertContext); + CertFreeCertificateContext((PCCERT_CONTEXT)cert); + } + else + ret = FALSE; + } + return ret; +} + +PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore, + PCCERT_CONTEXT pPrev) +{ + WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore; + PCCERT_CONTEXT ret; + + TRACE("(%p, %p)\n", hCertStore, pPrev); + if (!hCertStore) + ret = NULL; + else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + ret = NULL; + else + ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, (PWINE_CERT_CONTEXT)pPrev); + return ret; +} + +BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext) +{ + BOOL ret; + + TRACE("(%p)\n", pCertContext); + + if (!pCertContext) + ret = TRUE; + else if (!pCertContext->hCertStore) + { + ret = TRUE; + CertFreeCertificateContext(pCertContext); + } + else + { + PWINECRYPT_CERTSTORE hcs = + (PWINECRYPT_CERTSTORE)pCertContext->hCertStore; + + if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + ret = FALSE; + else + ret = hcs->deleteCert(hcs, pCertContext, 0); + CertFreeCertificateContext(pCertContext); + } + return ret; +} + +BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded, + DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext) +{ + FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore, + dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition, + ppCrlContext); + return FALSE; +} + +BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore, + PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition, + PCCRL_CONTEXT* ppStoreContext ) +{ + FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext, + dwAddDisposition, ppStoreContext); + return TRUE; +} + +BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext) +{ + FIXME("%p\n", pCrlContext ); + + return TRUE; +} + +BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext) +{ + FIXME("(%p): stub\n", pCrlContext); + return TRUE; +} + +PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore, + PCCRL_CONTEXT pPrev) +{ + FIXME("(%p, %p): stub\n", hCertStore, pPrev); + return NULL; +} + +PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType, + const BYTE* pbCtlEncoded, DWORD cbCtlEncoded) +{ + FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded, + cbCtlEncoded); + return NULL; +} + +BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore, + DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded, + DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext) +{ + FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore, + dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition, + ppCtlContext); + return FALSE; +} + +BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore, + PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition, + PCCTL_CONTEXT* ppStoreContext) +{ + FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext, + dwAddDisposition, ppStoreContext); + return TRUE; +} + +BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext) +{ + FIXME("(%p): stub\n", pCtlContext ); + return TRUE; +} + +BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext) +{ + FIXME("(%p): stub\n", pCtlContext); + return TRUE; +} + +PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore, + PCCTL_CONTEXT pPrev) +{ + FIXME("(%p, %p): stub\n", hCertStore, pPrev); + return NULL; +} + +HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore) +{ + WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore; + + TRACE("(%p)\n", hCertStore); + + if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC) + InterlockedIncrement(&hcs->ref); + return hCertStore; +} + +BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) +{ + WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore; + + TRACE("(%p, %08lx)\n", hCertStore, dwFlags); + + if( ! hCertStore ) + return TRUE; + + if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC ) + return FALSE; + + if (InterlockedDecrement(&hcs->ref) == 0) + { + TRACE("%p's ref count is 0, freeing\n", hcs); + hcs->dwMagic = 0; + if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) + CryptReleaseContext(hcs->cryptProv, 0); + hcs->closeStore(hcs, dwFlags); + } + else + TRACE("%p's ref count is %ld\n", hcs, hcs->ref); + return TRUE; +} + +BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags, + DWORD dwCtrlType, void const *pvCtrlPara) +{ + WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore; + BOOL ret; + + TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType, + pvCtrlPara); + + if (!hcs) + ret = FALSE; + else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + ret = FALSE; + else + { + if (hcs->control) + ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara); + else + ret = TRUE; + } + return ret; +} + +BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext, + DWORD dwPropId, void *pvData, DWORD *pcbData) +{ + FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData); + return FALSE; +} + +BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext, + DWORD dwPropId, DWORD dwFlags, const void *pvData) +{ + FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags, + pvData); + return FALSE; +} + +BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext, + DWORD dwPropId, void *pvData, DWORD *pcbData) +{ + FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData); + return FALSE; +} + +BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext, + DWORD dwPropId, DWORD dwFlags, const void *pvData) +{ + FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags, + pvData); + return FALSE; +} + +static void CertDataContext_Free(PWINE_CERT_CONTEXT_DATA context) +{ + CryptMemFree(context->cert.pbCertEncoded); + LocalFree(context->cert.pCertInfo); + ContextPropertyList_Free(context->properties); + CryptMemFree(context); +} + +static void CertLinkContext_Free(PWINE_CERT_CONTEXT_LINK context) +{ + CertFreeCertificateContext((PCCERT_CONTEXT)context->linked); + CryptMemFree(context); +} + +static void CertContext_Release(PWINE_CERT_CONTEXT context) +{ + if (InterlockedDecrement(&context->ref) == 0) + { + TRACE("freeing %p\n", context); + switch (context->type) + { + case ContextTypeData: + CertDataContext_Free((PWINE_CERT_CONTEXT_DATA)context); + break; + case ContextTypeLink: + CertLinkContext_Free((PWINE_CERT_CONTEXT_LINK)context); + break; + default: + assert(0); + } + } + else + TRACE("%p's ref count is %ld\n", context, context->ref); +} + +BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext) +{ + TRACE("(%p)\n", pCertContext); + + if (pCertContext) + CertContext_Release((PWINE_CERT_CONTEXT)pCertContext); + return TRUE; +} + +typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara); + +static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + return TRUE; +} + +static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + BOOL ret; + BYTE hash[16]; + DWORD size = sizeof(hash); + + ret = CertGetCertificateContextProperty(pCertContext, + CERT_MD5_HASH_PROP_ID, hash, &size); + if (ret) + { + const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara; + + if (size == pHash->cbData) + ret = !memcmp(pHash->pbData, hash, size); + else + ret = FALSE; + } + return ret; +} + +static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + BOOL ret; + BYTE hash[20]; + DWORD size = sizeof(hash); + + ret = CertGetCertificateContextProperty(pCertContext, + CERT_SHA1_HASH_PROP_ID, hash, &size); + if (ret) + { + const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara; + + if (size == pHash->cbData) + ret = !memcmp(pHash->pbData, hash, size); + else + ret = FALSE; + } + return ret; +} + +static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + const CERT_NAME_BLOB *blob = (const CERT_NAME_BLOB *)pvPara, *toCompare; + BOOL ret; + + if (dwType & CERT_INFO_SUBJECT_FLAG) + toCompare = &pCertContext->pCertInfo->Subject; + else + toCompare = &pCertContext->pCertInfo->Issuer; + if (toCompare->cbData == blob->cbData) + ret = !memcmp(toCompare->pbData, blob->pbData, blob->cbData); + else + ret = FALSE; + return ret; +} + +static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext, + DWORD dwType, DWORD dwFlags, const void *pvPara) +{ + const CERT_INFO *pCertInfo = (const CERT_INFO *)pvPara; + BOOL ret; + + if (pCertInfo->Issuer.cbData == pCertContext->pCertInfo->Subject.cbData) + ret = !memcmp(pCertInfo->Issuer.pbData, + pCertContext->pCertInfo->Subject.pbData, pCertInfo->Issuer.cbData); + else + ret = FALSE; + return ret; +} + +PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, + const void *pvPara, PCCERT_CONTEXT pPrevCertContext) +{ + PCCERT_CONTEXT ret; + CertCompareFunc compare; + + TRACE("(%p, %ld, %ld, %ld, %p, %p)\n", hCertStore, dwCertEncodingType, + dwFlags, dwType, pvPara, pPrevCertContext); + + switch (dwType >> CERT_COMPARE_SHIFT) + { + case CERT_COMPARE_ANY: + compare = compare_cert_any; + break; + case CERT_COMPARE_MD5_HASH: + compare = compare_cert_by_md5_hash; + break; + case CERT_COMPARE_SHA1_HASH: + compare = compare_cert_by_sha1_hash; + break; + case CERT_COMPARE_NAME: + compare = compare_cert_by_name; + break; + case CERT_COMPARE_SUBJECT_CERT: + compare = compare_cert_by_subject_cert; + break; + default: + FIXME("find type %08lx unimplemented\n", dwType); + compare = NULL; + } + + if (compare) + { + BOOL matches = FALSE; + + ret = pPrevCertContext; + do { + ret = CertEnumCertificatesInStore(hCertStore, ret); + if (ret) + matches = compare(ret, dwType, dwFlags, pvPara); + } while (ret != NULL && !matches); + if (!ret) + SetLastError(CRYPT_E_NOT_FOUND); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + return ret; +} + +BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore, + HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority) +{ + PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore; + WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore; + PWINE_STORE_LIST_ENTRY entry; + BOOL ret; + + TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore, + dwUpdateFlags, dwPriority); + + if (!collection || !sibling) + return TRUE; + if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return FALSE; + } + if (collection->hdr.type != StoreTypeCollection) + { + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return FALSE; + } + if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return FALSE; + } + + entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY)); + if (entry) + { + InterlockedIncrement(&sibling->ref); + TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref); + entry->store = sibling; + entry->dwUpdateFlags = dwUpdateFlags; + entry->dwPriority = dwPriority; + list_init(&entry->entry); + TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority); + EnterCriticalSection(&collection->cs); + if (dwPriority) + { + PWINE_STORE_LIST_ENTRY cursor; + BOOL added = FALSE; + + LIST_FOR_EACH_ENTRY(cursor, &collection->stores, + WINE_STORE_LIST_ENTRY, entry) + { + if (cursor->dwPriority < dwPriority) + { + list_add_before(&cursor->entry, &entry->entry); + added = TRUE; + break; + } + } + if (!added) + list_add_tail(&collection->stores, &entry->entry); + } + else + list_add_tail(&collection->stores, &entry->entry); + LeaveCriticalSection(&collection->cs); + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore, + HCERTSTORE hSiblingStore) +{ + PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore; + WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore; + PWINE_STORE_LIST_ENTRY store, next; + + TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore); + + if (!collection || !sibling) + return; + if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return; + } + if (collection->hdr.type != StoreTypeCollection) + return; + if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); + return; + } + EnterCriticalSection(&collection->cs); + LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores, + WINE_STORE_LIST_ENTRY, entry) + { + if (store->store == sibling) + { + list_remove(&store->entry); + CertCloseStore(store->store, 0); + CryptMemFree(store); + break; + } + } + LeaveCriticalSection(&collection->cs); +} diff --git a/reactos/dll/win32/crypt32/str.c b/reactos/dll/win32/crypt32/str.c new file mode 100644 index 00000000000..46acb9755c6 --- /dev/null +++ b/reactos/dll/win32/crypt32/str.c @@ -0,0 +1,441 @@ +/* + * Copyright 2006 Juan Lang for CodeWeavers + * + * 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 + */ +#include +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "wincrypt.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue, + LPSTR psz, DWORD csz) +{ + DWORD ret = 0; + + TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz); + + switch (dwValueType) + { + case CERT_RDN_ANY_TYPE: + break; + case CERT_RDN_PRINTABLE_STRING: + case CERT_RDN_IA5_STRING: + if (!psz || !csz) + ret = pValue->cbData; + else + { + DWORD chars = min(pValue->cbData, csz - 1); + + if (chars) + { + memcpy(psz, pValue->pbData, chars); + ret += chars; + csz -= chars; + } + } + break; + default: + FIXME("string type %ld unimplemented\n", dwValueType); + } + if (psz && csz) + { + *(psz + ret) = '\0'; + csz--; + ret++; + } + else + ret++; + return ret; +} + +DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue, + LPWSTR psz, DWORD csz) +{ + DWORD ret = 0; + + TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz); + + switch (dwValueType) + { + case CERT_RDN_ANY_TYPE: + break; + case CERT_RDN_PRINTABLE_STRING: + case CERT_RDN_IA5_STRING: + if (!psz || !csz) + ret = pValue->cbData; + else + { + DWORD chars = min(pValue->cbData, csz - 1); + + if (chars) + { + DWORD i; + + for (i = 0; i < chars; i++) + psz[i] = pValue->pbData[i]; + ret += chars; + csz -= chars; + } + } + break; + default: + FIXME("string type %ld unimplemented\n", dwValueType); + } + if (psz && csz) + { + *(psz + ret) = '\0'; + csz--; + ret++; + } + else + ret++; + return ret; +} + +DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, + DWORD dwStrType, LPSTR psz, DWORD csz) +{ + static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG | + CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG; + static const char commaSep[] = ", "; + static const char semiSep[] = "; "; + static const char crlfSep[] = "\r\n"; + static const char plusSep[] = " + "; + static const char spaceSep[] = " "; + DWORD ret = 0, bytes = 0; + BOOL bRet; + CERT_NAME_INFO *info; + + TRACE("(%ld, %p, %08lx, %p, %ld)\n", dwCertEncodingType, pName, dwStrType, + psz, csz); + if (dwStrType & unsupportedFlags) + FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags); + + bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData, + pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes); + if (bRet) + { + DWORD i, j, sepLen, rdnSepLen; + LPCSTR sep, rdnSep; + + if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG) + sep = semiSep; + else if (dwStrType & CERT_NAME_STR_CRLF_FLAG) + sep = crlfSep; + else + sep = commaSep; + sepLen = strlen(sep); + if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG) + rdnSep = spaceSep; + else + rdnSep = plusSep; + rdnSepLen = strlen(rdnSep); + for (i = 0; ret < csz && i < info->cRDN; i++) + { + for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++) + { + DWORD chars; + + if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR) + { + /* - 1 is needed to account for the NULL terminator. */ + chars = min( + lstrlenA(info->rgRDN[i].rgRDNAttr[j].pszObjId), + csz - ret - 1); + if (psz && chars) + memcpy(psz + ret, info->rgRDN[i].rgRDNAttr[j].pszObjId, + chars); + ret += chars; + csz -= chars; + if (csz > 1) + { + if (psz) + *(psz + ret) = '='; + ret++; + csz--; + } + } + /* FIXME: handle quoting */ + chars = CertRDNValueToStrA( + info->rgRDN[i].rgRDNAttr[j].dwValueType, + &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL, + csz - ret - 1); + if (chars) + ret += chars - 1; + if (j < info->rgRDN[i].cRDNAttr - 1) + { + if (psz && ret < csz - rdnSepLen - 1) + memcpy(psz + ret, rdnSep, rdnSepLen); + ret += rdnSepLen; + } + } + if (i < info->cRDN - 1) + { + if (psz && ret < csz - sepLen - 1) + memcpy(psz + ret, sep, sepLen); + ret += sepLen; + } + } + LocalFree(info); + } + if (psz && csz) + { + *(psz + ret) = '\0'; + csz--; + ret++; + } + else + ret++; + return ret; +} + +DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, + DWORD dwStrType, LPWSTR psz, DWORD csz) +{ + static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG | + CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG; + static const WCHAR commaSep[] = { ',',' ',0 }; + static const WCHAR semiSep[] = { ';',' ',0 }; + static const WCHAR crlfSep[] = { '\r','\n',0 }; + static const WCHAR plusSep[] = { ' ','+',' ',0 }; + static const WCHAR spaceSep[] = { ' ',0 }; + DWORD ret = 0, bytes = 0; + BOOL bRet; + CERT_NAME_INFO *info; + + TRACE("(%ld, %p, %08lx, %p, %ld)\n", dwCertEncodingType, pName, dwStrType, + psz, csz); + if (dwStrType & unsupportedFlags) + FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags); + + bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData, + pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes); + if (bRet) + { + DWORD i, j, sepLen, rdnSepLen; + LPCWSTR sep, rdnSep; + + if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG) + sep = semiSep; + else if (dwStrType & CERT_NAME_STR_CRLF_FLAG) + sep = crlfSep; + else + sep = commaSep; + sepLen = lstrlenW(sep); + if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG) + rdnSep = spaceSep; + else + rdnSep = plusSep; + rdnSepLen = lstrlenW(rdnSep); + for (i = 0; ret < csz && i < info->cRDN; i++) + { + for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++) + { + DWORD chars; + + if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR) + { + /* - 1 is needed to account for the NULL terminator. */ + chars = min( + lstrlenA(info->rgRDN[i].rgRDNAttr[j].pszObjId), + csz - ret - 1); + if (psz && chars) + { + DWORD k; + + for (k = 0; k < chars; k++) + *(psz + ret + k) = + info->rgRDN[i].rgRDNAttr[j].pszObjId[k]; + } + ret += chars; + csz -= chars; + if (csz > 1) + { + if (psz) + *(psz + ret) = '='; + ret++; + csz--; + } + } + /* FIXME: handle quoting */ + chars = CertRDNValueToStrW( + info->rgRDN[i].rgRDNAttr[j].dwValueType, + &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL, + csz - ret - 1); + if (chars) + ret += chars - 1; + if (j < info->rgRDN[i].cRDNAttr - 1) + { + if (psz && ret < csz - rdnSepLen - 1) + memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR)); + ret += rdnSepLen; + } + } + if (i < info->cRDN - 1) + { + if (psz && ret < csz - sepLen - 1) + memcpy(psz + ret, sep, sepLen * sizeof(WCHAR)); + ret += sepLen; + } + } + LocalFree(info); + } + if (psz && csz) + { + *(psz + ret) = '\0'; + csz--; + ret++; + } + else + ret++; + return ret; +} + +DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString) +{ + DWORD ret; + + TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", pCertContext, dwType, dwFlags, + pvTypePara, pszNameString, cchNameString); + + if (pszNameString) + { + LPWSTR wideName; + DWORD nameLen; + + nameLen = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara, + NULL, 0); + wideName = CryptMemAlloc(nameLen * sizeof(WCHAR)); + if (wideName) + { + CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara, + wideName, nameLen); + nameLen = WideCharToMultiByte(CP_ACP, 0, wideName, nameLen, + pszNameString, cchNameString, NULL, NULL); + if (nameLen <= cchNameString) + ret = nameLen; + else + { + pszNameString[cchNameString - 1] = '\0'; + ret = cchNameString; + } + CryptMemFree(wideName); + } + else + { + *pszNameString = '\0'; + ret = 1; + } + } + else + ret = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara, + NULL, 0); + return ret; +} + +DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString) +{ + DWORD ret; + PCERT_NAME_BLOB name; + LPCSTR altNameOID; + + TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", pCertContext, dwType, + dwFlags, pvTypePara, pszNameString, cchNameString); + + if (dwFlags & CERT_NAME_ISSUER_FLAG) + { + name = &pCertContext->pCertInfo->Issuer; + altNameOID = szOID_ISSUER_ALT_NAME; + } + else + { + name = &pCertContext->pCertInfo->Subject; + altNameOID = szOID_SUBJECT_ALT_NAME; + } + + switch (dwType) + { + case CERT_NAME_SIMPLE_DISPLAY_TYPE: + { + static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME, + szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME, + szOID_RSA_emailAddr }; + CERT_NAME_INFO *info = NULL; + PCERT_RDN_ATTR nameAttr = NULL; + DWORD bytes = 0, i; + + if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME, + name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, + &bytes)) + { + for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) / + sizeof(simpleAttributeOIDs[0]); i++) + nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info); + } + else + ret = 0; + if (!nameAttr) + { + PCERT_EXTENSION ext = CertFindExtension(altNameOID, + pCertContext->pCertInfo->cExtension, + pCertContext->pCertInfo->rgExtension); + + if (ext) + { + for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) / + sizeof(simpleAttributeOIDs[0]); i++) + nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info); + if (!nameAttr) + { + /* FIXME: gotta then look for a rfc822Name choice in ext. + * Failing that, look for the first attribute. + */ + FIXME("CERT_NAME_SIMPLE_DISPLAY_TYPE: stub\n"); + ret = 0; + } + } + } + ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value, + pszNameString, cchNameString); + if (info) + LocalFree(info); + break; + } + case CERT_NAME_FRIENDLY_DISPLAY_TYPE: + { + DWORD cch = cchNameString; + + if (CertGetCertificateContextProperty(pCertContext, + CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch)) + ret = cch; + else + ret = CertGetNameStringW(pCertContext, + CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString, + cchNameString); + break; + } + default: + FIXME("unimplemented for type %ld\n", dwType); + ret = 0; + } + return ret; +} diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index cad8c97abe3..15f597acae5 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -41,7 +41,7 @@ reactos/dll/win32/avifil32 # Synced to Wine-0_9_5 reactos/dll/win32/cabinet # Synced to Wine-0_9_10 reactos/dll/win32/comctl32 # Synced to Wine-20060328 reactos/dll/win32/comdlg32 # Synced to Wine-0_9_5 -reactos/dll/win32/crypt32 # Synced to Wine-0_9_5 +reactos/dll/win32/crypt32 # Synced to Wine-0_9_10 reactos/dll/win32/dbghelp # reactos/dll/win32/icmp # Synced to Wine-0_9_5 reactos/dll/win32/imm32 # Synced to Wine-0_9_10