From 0070d8226fc1a075b1056abf7596335a654719ca Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Thu, 16 Aug 2007 10:54:03 -0700 Subject: [PATCH] crypt32: Move registry stores to a separate file. --- dlls/crypt32/Makefile.in | 1 + dlls/crypt32/crypt32_private.h | 3 + dlls/crypt32/regstore.c | 543 +++++++++++++++++++++++++++++++++ dlls/crypt32/store.c | 516 +------------------------------ 4 files changed, 548 insertions(+), 515 deletions(-) create mode 100644 dlls/crypt32/regstore.c diff --git a/dlls/crypt32/Makefile.in b/dlls/crypt32/Makefile.in index c2fd5a9d26d..f7b62f818a0 100644 --- a/dlls/crypt32/Makefile.in +++ b/dlls/crypt32/Makefile.in @@ -22,6 +22,7 @@ C_SRCS = \ proplist.c \ protectdata.c \ provstore.c \ + regstore.c \ serialize.c \ sip.c \ store.c \ diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h index 0d9d4fa6704..57846c7b8a4 100644 --- a/dlls/crypt32/crypt32_private.h +++ b/dlls/crypt32/crypt32_private.h @@ -234,6 +234,7 @@ typedef struct WINE_CRYPTCERTSTORE void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv, DWORD dwFlags, CertStoreType type); void CRYPT_FreeStore(PWINECRYPT_CERTSTORE store); +void CRYPT_EmptyStore(HCERTSTORE store); PWINECRYPT_CERTSTORE CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara); @@ -243,6 +244,8 @@ PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv, PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider, DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara); +PWINECRYPT_CERTSTORE CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, + const void *pvPara); /* Helper function for store reading functions and * CertAddSerializedElementToStore. Returns a context of the appropriate type diff --git a/dlls/crypt32/regstore.c b/dlls/crypt32/regstore.c new file mode 100644 index 00000000000..b2a35ebfdfe --- /dev/null +++ b/dlls/crypt32/regstore.c @@ -0,0 +1,543 @@ +/* + * Copyright 2004-2007 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include +#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" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +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; + HCERTSTORE memStore; + HKEY key; + BOOL dirty; + CRITICAL_SECTION cs; + struct list certsToDelete; + struct list crlsToDelete; +} WINE_REGSTOREINFO, *PWINE_REGSTOREINFO; + +static void CRYPT_HashToStr(const BYTE *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(const WINE_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 = pCertInterface; + break; + case CERT_STORE_CRL_CONTEXT: + contextInterface = pCRLInterface; + break; + case CERT_STORE_CTL_CONTEXT: + contextInterface = pCTLInterface; + 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(const WINE_REGSTOREINFO *store) +{ + static const WCHAR * const 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, const BYTE *hash, const BYTE *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 * const subKeys[] = { CertsW, CRLsW, CTLsW }; + const WINE_CONTEXT_INTERFACE * const interfaces[] = { pCertInterface, + pCRLInterface, pCTLInterface }; + struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete, + 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, %08x)\n", store, dwFlags); + if (dwFlags) + FIXME("Unimplemented flags: %08x\n", dwFlags); + + CRYPT_RegFlushStore(store, FALSE); + RegCloseKey(store->key); + store->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&store->cs); + CryptMemFree(store); +} + +static BOOL WINAPI CRYPT_RegWriteContext(PWINE_REGSTOREINFO store, + const void *context, DWORD dwFlags) +{ + BOOL ret; + + if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG) + { + store->dirty = TRUE; + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +static BOOL CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store, + struct list *deleteList, const void *context, + PCWINE_CONTEXT_INTERFACE contextInterface) +{ + BOOL ret; + + 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 = contextInterface->getProp(context, CERT_HASH_PROP_ID, + toDelete->hash, &size); + if (ret) + { + EnterCriticalSection(&store->cs); + list_add_tail(deleteList, &toDelete->entry); + LeaveCriticalSection(&store->cs); + } + else + { + CryptMemFree(toDelete); + ret = FALSE; + } + } + else + ret = FALSE; + if (ret) + store->dirty = TRUE; + } + return ret; +} + +static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT cert, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags); + + return CRYPT_RegWriteContext(store, cert, dwFlags); +} + +static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %08x)\n", store, pCertContext, dwFlags); + + return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext, + pCertInterface); +} + +static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT crl, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags); + + return CRYPT_RegWriteContext(store, crl, dwFlags); +} + +static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT pCrlContext, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %08x)\n", store, pCrlContext, dwFlags); + + return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext, + pCRLInterface); +} + +static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags, + DWORD dwCtrlType, void const *pvCtrlPara) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + BOOL ret; + + TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, + pvCtrlPara); + + switch (dwCtrlType) + { + case CERT_STORE_CTRL_RESYNC: + CRYPT_RegFlushStore(store, FALSE); + CRYPT_EmptyStore(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("%d: stub\n", dwCtrlType); + ret = FALSE; + } + return ret; +} + +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 */ + CRYPT_RegWriteCRL, + CRYPT_RegDeleteCRL, + 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, +}; + +PWINECRYPT_CERTSTORE CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, + const void *pvPara) +{ + PWINECRYPT_CERTSTORE store = NULL; + + TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); + + if (dwFlags & CERT_STORE_DELETE_FLAG) + { + DWORD rc = RegDeleteTreeW((HKEY)pvPara, CertsW); + + if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) + rc = RegDeleteTreeW((HKEY)pvPara, CRLsW); + if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) + rc = RegDeleteTreeW((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 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, hCryptProv, + CERT_STORE_CREATE_NEW_FLAG, 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); + regInfo->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_REGSTOREINFO->cs"); + list_init(®Info->certsToDelete); + list_init(®Info->crlsToDelete); + 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; +} diff --git a/dlls/crypt32/store.c b/dlls/crypt32/store.c index 06475069674..c2ba2da4073 100644 --- a/dlls/crypt32/store.c +++ b/dlls/crypt32/store.c @@ -93,24 +93,6 @@ typedef struct _WINE_MEMSTORE struct ContextList *crls; } 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; - HCERTSTORE memStore; - HKEY key; - BOOL dirty; - CRITICAL_SECTION cs; - struct list certsToDelete; - struct list crlsToDelete; -} WINE_REGSTOREINFO, *PWINE_REGSTOREINFO; - typedef struct _WINE_FILESTOREINFO { DWORD dwOpenFlags; @@ -233,7 +215,7 @@ static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext) return TRUE; } -static void CRYPT_EmptyStore(HCERTSTORE store) +void CRYPT_EmptyStore(HCERTSTORE store) { PCCERT_CONTEXT cert; PCCRL_CONTEXT crl; @@ -299,502 +281,6 @@ static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, return (PWINECRYPT_CERTSTORE)store; } -static void CRYPT_HashToStr(const BYTE *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(const WINE_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 = pCertInterface; - break; - case CERT_STORE_CRL_CONTEXT: - contextInterface = pCRLInterface; - break; - case CERT_STORE_CTL_CONTEXT: - contextInterface = pCTLInterface; - 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(const WINE_REGSTOREINFO *store) -{ - static const WCHAR * const 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, const BYTE *hash, const BYTE *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 * const subKeys[] = { CertsW, CRLsW, CTLsW }; - const WINE_CONTEXT_INTERFACE * const interfaces[] = { pCertInterface, - pCRLInterface, pCTLInterface }; - struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete, - 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, %08x)\n", store, dwFlags); - if (dwFlags) - FIXME("Unimplemented flags: %08x\n", dwFlags); - - CRYPT_RegFlushStore(store, FALSE); - RegCloseKey(store->key); - store->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&store->cs); - CryptMemFree(store); -} - -static BOOL WINAPI CRYPT_RegWriteContext(PWINE_REGSTOREINFO store, - const void *context, DWORD dwFlags) -{ - BOOL ret; - - if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG) - { - store->dirty = TRUE; - ret = TRUE; - } - else - ret = FALSE; - return ret; -} - -static BOOL CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store, - struct list *deleteList, const void *context, - PCWINE_CONTEXT_INTERFACE contextInterface) -{ - BOOL ret; - - 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 = contextInterface->getProp(context, CERT_HASH_PROP_ID, - toDelete->hash, &size); - if (ret) - { - EnterCriticalSection(&store->cs); - list_add_tail(deleteList, &toDelete->entry); - LeaveCriticalSection(&store->cs); - } - else - { - CryptMemFree(toDelete); - ret = FALSE; - } - } - else - ret = FALSE; - if (ret) - store->dirty = TRUE; - } - return ret; -} - -static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT cert, DWORD dwFlags) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - - TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags); - - return CRYPT_RegWriteContext(store, cert, dwFlags); -} - -static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT pCertContext, DWORD dwFlags) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - - TRACE("(%p, %p, %08x)\n", store, pCertContext, dwFlags); - - return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext, - pCertInterface); -} - -static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore, - PCCRL_CONTEXT crl, DWORD dwFlags) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - - TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags); - - return CRYPT_RegWriteContext(store, crl, dwFlags); -} - -static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore, - PCCRL_CONTEXT pCrlContext, DWORD dwFlags) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - - TRACE("(%p, %p, %08x)\n", store, pCrlContext, dwFlags); - - return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext, - pCRLInterface); -} - -static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags, - DWORD dwCtrlType, void const *pvCtrlPara) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - BOOL ret; - - TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, - pvCtrlPara); - - switch (dwCtrlType) - { - case CERT_STORE_CTRL_RESYNC: - CRYPT_RegFlushStore(store, FALSE); - CRYPT_EmptyStore(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("%d: stub\n", dwCtrlType); - ret = FALSE; - } - return ret; -} - -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 */ - CRYPT_RegWriteCRL, - CRYPT_RegDeleteCRL, - 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, %08x, %p)\n", hCryptProv, dwFlags, pvPara); - - if (dwFlags & CERT_STORE_DELETE_FLAG) - { - DWORD rc = RegDeleteTreeW((HKEY)pvPara, CertsW); - - if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) - rc = RegDeleteTreeW((HKEY)pvPara, CRLsW); - if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) - rc = RegDeleteTreeW((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 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, hCryptProv, - CERT_STORE_CREATE_NEW_FLAG, 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); - regInfo->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_REGSTOREINFO->cs"); - list_init(®Info->certsToDelete); - list_init(®Info->crlsToDelete); - 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