crypt32: Implement file stores.

oldstable
Juan Lang 2006-07-25 16:29:50 -07:00 committed by Alexandre Julliard
parent a5142837c6
commit 6e23b4a25d
5 changed files with 866 additions and 89 deletions

View File

@ -104,6 +104,14 @@ extern PCWINE_CONTEXT_INTERFACE pCTLInterface;
const void *CRYPT_ReadSerializedElement(const BYTE *pbElement,
DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
/* Writes contexts from the memory store to the file. */
BOOL CRYPT_WriteSerializedFile(HANDLE file, HCERTSTORE store);
/* Reads contexts serialized in the file into the memory store. Returns FALSE
* if the file is not of the expected format.
*/
BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store);
/* Fixes up the the pointers in info, where info is assumed to be a
* CRYPT_KEY_PROV_INFO, followed by its container name, provider name, and any
* provider parameters, in a contiguous buffer, but where info's pointers are

View File

@ -38,13 +38,13 @@ typedef struct _WINE_CERT_PROP_HEADER
static BOOL CRYPT_SerializeStoreElement(const void *context,
const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID,
PCWINE_CONTEXT_INTERFACE contextInterface, DWORD dwFlags, BYTE *pbElement,
DWORD *pcbElement)
PCWINE_CONTEXT_INTERFACE contextInterface, DWORD dwFlags, BOOL omitHashes,
BYTE *pbElement, DWORD *pcbElement)
{
BOOL ret;
TRACE("(%p, %p, %08lx, %p, %p)\n", context, contextInterface, dwFlags,
pbElement, pcbElement);
TRACE("(%p, %p, %08lx, %d, %p, %p)\n", context, contextInterface, dwFlags,
omitHashes, pbElement, pcbElement);
if (context)
{
@ -54,7 +54,7 @@ static BOOL CRYPT_SerializeStoreElement(const void *context,
ret = TRUE;
do {
prop = contextInterface->enumProps(context, prop);
if (prop)
if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
{
DWORD propSize = 0;
@ -84,7 +84,7 @@ static BOOL CRYPT_SerializeStoreElement(const void *context,
prop = 0;
do {
prop = contextInterface->enumProps(context, prop);
if (prop)
if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
{
DWORD propSize = 0;
@ -143,7 +143,7 @@ BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
{
return CRYPT_SerializeStoreElement(pCertContext,
pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
CERT_CERT_PROP_ID, pCertInterface, dwFlags, pbElement, pcbElement);
CERT_CERT_PROP_ID, pCertInterface, dwFlags, FALSE, pbElement, pcbElement);
}
BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
@ -151,7 +151,7 @@ BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
{
return CRYPT_SerializeStoreElement(pCrlContext,
pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
CERT_CRL_PROP_ID, pCRLInterface, dwFlags, pbElement, pcbElement);
CERT_CRL_PROP_ID, pCRLInterface, dwFlags, FALSE, pbElement, pcbElement);
}
BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
@ -159,7 +159,7 @@ BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
{
return CRYPT_SerializeStoreElement(pCtlContext,
pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
CERT_CTL_PROP_ID, pCRLInterface, dwFlags, pbElement, pcbElement);
CERT_CTL_PROP_ID, pCTLInterface, dwFlags, FALSE, pbElement, pcbElement);
}
/* Looks for the property with ID propID in the buffer buf. Returns a pointer
@ -215,6 +215,80 @@ static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
return ret;
}
static BOOL CRYPT_ReadContextProp(
const WINE_CONTEXT_INTERFACE *contextInterface, const void *context,
const WINE_CERT_PROP_HEADER *hdr, const BYTE *pbElement, DWORD cbElement)
{
BOOL ret;
if (cbElement < hdr->cb)
{
SetLastError(E_INVALIDARG);
ret = FALSE;
}
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;
case CERT_KEY_PROV_INFO_PROP_ID:
{
PCRYPT_KEY_PROV_INFO info =
(PCRYPT_KEY_PROV_INFO)pbElement;
CRYPT_FixKeyProvInfoPointers(info);
ret = contextInterface->setProp(context,
hdr->propID, 0, pbElement);
break;
}
default:
ret = FALSE;
}
}
else
{
/* ignore the context itself */
ret = TRUE;
}
return ret;
}
const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
DWORD dwContextTypeFlags, DWORD *pdwContentType)
{
@ -310,73 +384,15 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
TRACE("prop is %ld\n", hdr->propID);
cbElement -= sizeof(WINE_CERT_PROP_HEADER);
pbElement += sizeof(WINE_CERT_PROP_HEADER);
if (cbElement < hdr->cb)
{
SetLastError(E_INVALIDARG);
ret = FALSE;
}
else if (!hdr->propID)
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;
case CERT_KEY_PROV_INFO_PROP_ID:
{
PCRYPT_KEY_PROV_INFO info =
(PCRYPT_KEY_PROV_INFO)pbElement;
CRYPT_FixKeyProvInfoPointers(info);
ret = contextInterface->setProp(context,
hdr->propID, 0, pbElement);
break;
}
default:
FIXME("prop ID %ld: stub\n", hdr->propID);
}
}
else
ret = CRYPT_ReadContextProp(contextInterface, context,
hdr, pbElement, cbElement);
pbElement += hdr->cb;
cbElement -= hdr->cb;
if (!cbElement)
@ -404,6 +420,184 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
return context;
}
static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store)
{
BYTE fileHeaderBuf[sizeof(fileHeader)];
DWORD read;
BOOL ret;
/* Failure reading is non-critical, we'll leave the store empty */
ret = ReadFile(file, fileHeaderBuf, sizeof(fileHeaderBuf), &read, NULL);
if (ret)
{
if (!memcmp(fileHeaderBuf, fileHeader, read))
{
WINE_CERT_PROP_HEADER propHdr;
const void *context = NULL;
const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
LPBYTE buf = NULL;
DWORD bufSize = 0;
do {
ret = ReadFile(file, &propHdr, sizeof(propHdr), &read, NULL);
if (ret && read == sizeof(propHdr))
{
if (contextInterface && context &&
(propHdr.propID == CERT_CERT_PROP_ID ||
propHdr.propID == CERT_CRL_PROP_ID ||
propHdr.propID == CERT_CTL_PROP_ID))
{
/* We have a new context, so free the existing one */
contextInterface->free(context);
}
if (propHdr.cb > bufSize)
{
/* Not reusing realloc, because the old data aren't
* needed any longer.
*/
CryptMemFree(buf);
buf = CryptMemAlloc(propHdr.cb);
bufSize = propHdr.cb;
}
if (buf)
{
ret = ReadFile(file, buf, propHdr.cb, &read, NULL);
if (ret && read == propHdr.cb)
{
if (propHdr.propID == CERT_CERT_PROP_ID)
{
contextInterface = pCertInterface;
ret = contextInterface->addEncodedToStore(store,
X509_ASN_ENCODING, buf, read,
CERT_STORE_ADD_NEW, &context);
}
else if (propHdr.propID == CERT_CRL_PROP_ID)
{
contextInterface = pCRLInterface;
ret = contextInterface->addEncodedToStore(store,
X509_ASN_ENCODING, buf, read,
CERT_STORE_ADD_NEW, &context);
}
else if (propHdr.propID == CERT_CTL_PROP_ID)
{
contextInterface = pCTLInterface;
ret = contextInterface->addEncodedToStore(store,
X509_ASN_ENCODING, buf, read,
CERT_STORE_ADD_NEW, &context);
}
else
ret = CRYPT_ReadContextProp(contextInterface,
context, &propHdr, buf, read);
}
}
else
ret = FALSE;
}
} while (ret && read > 0);
if (contextInterface && context)
{
/* Free the last context added */
contextInterface->free(context);
}
CryptMemFree(buf);
ret = TRUE;
}
}
else
ret = TRUE;
return ret;
}
static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
{
return CRYPT_SerializeStoreElement(pCertContext,
pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement);
}
static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext,
DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
{
return CRYPT_SerializeStoreElement(pCrlContext,
pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement);
}
static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext,
DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
{
return CRYPT_SerializeStoreElement(pCtlContext,
pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement);
}
static BOOL CRYPT_SerializeContextsToFile(HANDLE file,
const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
{
const void *context = NULL;
BOOL ret;
do {
context = contextInterface->enumContextsInStore(store, context);
if (context)
{
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 = WriteFile(file, buf, size, &size, NULL);
}
CryptMemFree(buf);
}
else
ret = TRUE;
} while (ret && context != NULL);
if (context)
contextInterface->free(context);
return ret;
}
BOOL CRYPT_WriteSerializedFile(HANDLE file, HCERTSTORE store)
{
static const BYTE fileTrailer[12] = { 0 };
WINE_CONTEXT_INTERFACE interface;
BOOL ret;
DWORD size;
SetFilePointer(file, 0, NULL, FILE_BEGIN);
ret = WriteFile(file, fileHeader, sizeof(fileHeader), &size, NULL);
if (ret)
{
memcpy(&interface, pCertInterface, sizeof(interface));
interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
ret = CRYPT_SerializeContextsToFile(file, &interface, store);
}
if (ret)
{
memcpy(&interface, pCRLInterface, sizeof(interface));
interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
ret = CRYPT_SerializeContextsToFile(file, &interface, store);
}
if (ret)
{
memcpy(&interface, pCTLInterface, sizeof(interface));
interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
ret = CRYPT_SerializeContextsToFile(file, &interface, store);
}
if (ret)
ret = WriteFile(file, fileTrailer, sizeof(fileTrailer), &size, NULL);
return ret;
}
BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)

View File

@ -163,6 +163,15 @@ typedef struct _WINE_REGSTOREINFO
struct list crlsToDelete;
} WINE_REGSTOREINFO, *PWINE_REGSTOREINFO;
typedef struct _WINE_FILESTOREINFO
{
DWORD dwOpenFlags;
HCRYPTPROV cryptProv;
PWINECRYPT_CERTSTORE memStore;
HANDLE file;
BOOL dirty;
} WINE_FILESTOREINFO, *PWINE_FILESTOREINFO;
typedef struct _WINE_STORE_LIST_ENTRY
{
PWINECRYPT_CERTSTORE store;
@ -695,21 +704,13 @@ static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, void *cert,
(const void **)ppStoreContext);
else
{
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->certs.addContext(ps->memStore, cert, NULL,
(const void **)ppStoreContext);
}
ret = TRUE;
if (ps->provWriteCert)
ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert,
CERT_STORE_PROV_WRITE_ADD_FLAG);
if (ret)
ret = ps->memStore->certs.addContext(ps->memStore, cert, NULL,
(const void **)ppStoreContext);
}
/* dirty trick: replace the returned context's hCertStore with
* store.
@ -1723,12 +1724,215 @@ static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
return ret;
}
static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
{
PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
TRACE("(%p, %08lx)\n", store, dwFlags);
if (store->dirty)
CRYPT_WriteSerializedFile(store->file, store->memStore);
CertCloseStore(store->memStore, dwFlags);
CloseHandle(store->file);
CryptMemFree(store);
}
static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore,
PCCERT_CONTEXT cert, DWORD dwFlags)
{
PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags);
store->dirty = TRUE;
return TRUE;
}
static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore,
PCCERT_CONTEXT pCertContext, DWORD dwFlags)
{
PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
store->dirty = TRUE;
return TRUE;
}
static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore,
PCCRL_CONTEXT crl, DWORD dwFlags)
{
PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
TRACE("(%p, %p, %ld)\n", hCertStore, crl, dwFlags);
store->dirty = TRUE;
return TRUE;
}
static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore,
PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
{
PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
TRACE("(%p, %p, %08lx)\n", hCertStore, pCrlContext, dwFlags);
store->dirty = TRUE;
return TRUE;
}
static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags,
DWORD dwCtrlType, void const *pvCtrlPara)
{
PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
BOOL ret;
TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
pvCtrlPara);
switch (dwCtrlType)
{
case CERT_STORE_CTRL_RESYNC:
CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore);
CRYPT_ReadSerializedFile(store->file, store);
ret = TRUE;
break;
case CERT_STORE_CTRL_COMMIT:
if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
ret = FALSE;
}
else if (store->dirty)
ret = CRYPT_WriteSerializedFile(store->file, store->memStore);
else
ret = TRUE;
break;
default:
FIXME("%ld: stub\n", dwCtrlType);
ret = FALSE;
}
return ret;
}
static void *fileProvFuncs[] = {
CRYPT_FileCloseStore,
NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
CRYPT_FileWriteCert,
CRYPT_FileDeleteCert,
NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
CRYPT_FileWriteCRL,
CRYPT_FileDeleteCRL,
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_FileControl,
};
static PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv,
DWORD dwFlags, const void *pvPara)
{
PWINECRYPT_CERTSTORE store = NULL;
HANDLE file = (HANDLE)pvPara;
TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
if (!pvPara)
{
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
if (dwFlags & CERT_STORE_DELETE_FLAG)
{
SetLastError(E_INVALIDARG);
return NULL;
}
if ((dwFlags & CERT_STORE_READONLY_FLAG) &&
(dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
{
SetLastError(E_INVALIDARG);
return NULL;
}
if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ?
GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0))
{
PWINECRYPT_CERTSTORE memStore;
memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
if (memStore)
{
if (CRYPT_ReadSerializedFile(file, memStore))
{
PWINE_FILESTOREINFO info = CryptMemAlloc(
sizeof(WINE_FILESTOREINFO));
if (info)
{
CERT_STORE_PROV_INFO provInfo = { 0 };
info->dwOpenFlags = dwFlags;
info->cryptProv = hCryptProv;
info->memStore = memStore;
info->file = file;
info->dirty = FALSE;
provInfo.cbSize = sizeof(provInfo);
provInfo.cStoreProvFunc = sizeof(fileProvFuncs) /
sizeof(fileProvFuncs[0]);
provInfo.rgpvStoreProvFunc = fileProvFuncs;
provInfo.hStoreProv = info;
store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
&provInfo);
}
}
}
}
TRACE("returning %p\n", store);
return store;
}
static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
DWORD dwFlags, const void *pvPara)
{
FIXME("(%ld, %08lx, %s): stub\n", hCryptProv, dwFlags,
debugstr_w((LPCWSTR)pvPara));
return NULL;
HCERTSTORE store = 0;
LPCWSTR fileName = (LPCWSTR)pvPara;
DWORD access, create;
HANDLE file;
TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName));
if (!fileName)
{
SetLastError(ERROR_PATH_NOT_FOUND);
return NULL;
}
if (!(dwFlags & (CERT_FILE_STORE_COMMIT_ENABLE_FLAG |
CERT_STORE_READONLY_FLAG)))
{
SetLastError(ERROR_FILE_NOT_FOUND);
return NULL;
}
access = GENERIC_READ;
if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
access |= GENERIC_WRITE;
if (dwFlags & CERT_STORE_CREATE_NEW_FLAG)
create = CREATE_NEW;
else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
create = OPEN_EXISTING;
else
create = OPEN_ALWAYS;
file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create,
FILE_ATTRIBUTE_NORMAL, NULL);
if (file != INVALID_HANDLE_VALUE)
{
/* FIXME: need to check whether it's a serialized store; if not, fall
* back to a PKCS#7 signed message, then to a single serialized cert.
*/
store = CertOpenStore(CERT_STORE_PROV_FILE, 0, hCryptProv, dwFlags,
file);
CloseHandle(file);
}
return (PWINECRYPT_CERTSTORE)store;
}
static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
@ -1788,6 +1992,9 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
case (int)CERT_STORE_PROV_MEMORY:
openFunc = CRYPT_MemOpenStore;
break;
case (int)CERT_STORE_PROV_FILE:
openFunc = CRYPT_FileOpenStore;
break;
case (int)CERT_STORE_PROV_REG:
openFunc = CRYPT_RegOpenStore;
break;
@ -1822,6 +2029,8 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
}
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
openFunc = CRYPT_MemOpenStore;
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_FILENAME_W))
openFunc = CRYPT_FileOpenStore;
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
openFunc = CRYPT_SysOpenStoreW;
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))

View File

@ -1003,6 +1003,361 @@ static void testSystemStore(void)
RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
}
static const BYTE serializedStoreWithCert[] = {
0x00,0x00,0x00,0x00,0x43,0x45,0x52,0x54,0x20,0x00,0x00,0x00,0x01,0x00,0x00,
0x00,0x7c,0x00,0x00,0x00,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,
0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,
0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,
0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,
0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,
0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,
0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00 };
static const BYTE serializedStoreWithCertAndCRL[] = {
0x00,0x00,0x00,0x00,0x43,0x45,0x52,0x54,0x20,0x00,0x00,0x00,0x01,0x00,0x00,
0x00,0x7c,0x00,0x00,0x00,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,
0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,
0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,
0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,
0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,
0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,
0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0x21,0x00,0x00,0x00,0x01,0x00,
0x00,0x00,0x47,0x00,0x00,0x00,0x30,0x45,0x30,0x2c,0x30,0x02,0x06,0x00,0x30,
0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00,0x03,0x11,
0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
static void compareFile(LPCWSTR filename, const BYTE *pb, DWORD cb)
{
HANDLE h;
BYTE buf[200];
BOOL ret;
DWORD cbRead = 0, totalRead = 0;
h = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
return;
do {
ret = ReadFile(h, buf, sizeof(buf), &cbRead, NULL);
if (ret && cbRead)
{
ok(totalRead + cbRead <= cb, "Expected total count %ld, see %ld\n",
cb, totalRead + cbRead);
ok(!memcmp(pb + totalRead, buf, cbRead),
"Unexpected data in file\n");
totalRead += cbRead;
}
} while (ret && cbRead);
CloseHandle(h);
}
static void testFileStore(void)
{
static const WCHAR szPrefix[] = { 'c','e','r',0 };
static const WCHAR szDot[] = { '.',0 };
WCHAR filename[MAX_PATH];
HCERTSTORE store;
BOOL ret;
PCCERT_CONTEXT cert;
HANDLE file;
store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, 0, NULL);
ok(!store && GetLastError() == ERROR_INVALID_HANDLE,
"Expected ERROR_INVALID_HANDLE, got %08lx\n", GetLastError());
if (!GetTempFileNameW(szDot, szPrefix, 0, filename))
return;
DeleteFileW(filename);
file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE)
return;
store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, CERT_STORE_DELETE_FLAG,
file);
ok(!store && GetLastError() == E_INVALIDARG,
"Expected E_INVALIDARG, got %08lx\n", GetLastError());
store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0,
CERT_FILE_STORE_COMMIT_ENABLE_FLAG | CERT_STORE_READONLY_FLAG, file);
ok(!store && GetLastError() == E_INVALIDARG,
"Expected E_INVALIDARG, got %08lx\n", GetLastError());
/* A "read-only" file store.. */
store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0,
CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, file);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
if (store)
{
DWORD size;
ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
/* apparently allows adding certificates.. */
ok(ret, "CertAddEncodedCertificateToStore failed: %d\n", ret);
/* but not commits.. */
ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
ok(!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
"Expected ERROR_CALL_NOT_IMPLEMENTED, got %08lx\n", GetLastError());
/* It still has certs in memory.. */
cert = CertEnumCertificatesInStore(store, NULL);
ok(cert != NULL, "CertEnumCertificatesInStore failed: %08lx\n",
GetLastError());
CertFreeCertificateContext(cert);
/* but the file size is still 0. */
size = GetFileSize(file, NULL);
ok(size == 0, "Expected size 0, got %ld\n", size);
CertCloseStore(store, 0);
}
/* The create new flag is allowed.. */
store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, file);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
if (store)
{
/* but without the commit enable flag, commits don't happen. */
ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCertificateToStore failed: %d\n", ret);
ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
ok(!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
"Expected ERROR_CALL_NOT_IMPLEMENTED, got %08lx\n", GetLastError());
CertCloseStore(store, 0);
}
/* as is the open existing flag. */
store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0,
CERT_STORE_OPEN_EXISTING_FLAG, file);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
if (store)
{
/* but without the commit enable flag, commits don't happen. */
ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCertificateToStore failed: %d\n", ret);
ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
ok(!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
"Expected ERROR_CALL_NOT_IMPLEMENTED, got %08lx\n", GetLastError());
CertCloseStore(store, 0);
}
store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0,
CERT_FILE_STORE_COMMIT_ENABLE_FLAG, file);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
if (store)
{
CloseHandle(file);
ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
GetLastError());
/* with commits enabled, commit is allowed */
ret = CertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL);
ok(ret, "CertControlStore failed: %d\n", ret);
compareFile(filename, serializedStoreWithCert,
sizeof(serializedStoreWithCert));
CertCloseStore(store, 0);
}
file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE)
return;
store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0,
CERT_FILE_STORE_COMMIT_ENABLE_FLAG, file);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
if (store)
{
CloseHandle(file);
ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, signedCRL,
sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCRLToStore failed: %08lx\n", GetLastError());
CertCloseStore(store, 0);
compareFile(filename, serializedStoreWithCertAndCRL,
sizeof(serializedStoreWithCertAndCRL));
}
DeleteFileW(filename);
}
static void checkFileStoreFailure(LPCWSTR filename, DWORD dwEncodingType,
DWORD dwFlags, DWORD expectedError)
{
HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_FILENAME_W,
dwEncodingType, 0, dwFlags, filename);
ok(!store && GetLastError() == expectedError,
"Expected %08lx, got %08lx\n", expectedError, GetLastError());
}
static BOOL initFileFromData(LPCWSTR filename, const BYTE *pb, DWORD cb)
{
HANDLE file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
BOOL ret;
if (file != INVALID_HANDLE_VALUE)
{
DWORD written;
ret = WriteFile(file, pb, cb, &written, NULL);
CloseHandle(file);
}
else
ret = FALSE;
return ret;
}
static void testFileNameStore(void)
{
static const WCHAR szPrefix[] = { 'c','e','r',0 };
static const WCHAR szDot[] = { '.',0 };
WCHAR filename[MAX_PATH];
HCERTSTORE store;
BOOL ret;
checkFileStoreFailure(NULL, 0, 0, ERROR_PATH_NOT_FOUND);
if (!GetTempFileNameW(szDot, szPrefix, 0, filename))
return;
DeleteFileW(filename);
/* The two flags are mutually exclusive */
checkFileStoreFailure(filename, 0,
CERT_FILE_STORE_COMMIT_ENABLE_FLAG | CERT_STORE_READONLY_FLAG,
E_INVALIDARG);
/* Without an encoding type, these all fail */
checkFileStoreFailure(filename, 0, 0, ERROR_FILE_NOT_FOUND);
checkFileStoreFailure(filename, 0, CERT_STORE_OPEN_EXISTING_FLAG,
ERROR_FILE_NOT_FOUND);
checkFileStoreFailure(filename, 0, CERT_STORE_CREATE_NEW_FLAG,
ERROR_FILE_NOT_FOUND);
/* Without a message encoding type, these still fail */
checkFileStoreFailure(filename, X509_ASN_ENCODING, 0, ERROR_FILE_NOT_FOUND);
checkFileStoreFailure(filename, X509_ASN_ENCODING,
CERT_STORE_OPEN_EXISTING_FLAG, ERROR_FILE_NOT_FOUND);
checkFileStoreFailure(filename, X509_ASN_ENCODING,
CERT_STORE_CREATE_NEW_FLAG, ERROR_FILE_NOT_FOUND);
/* Without a cert encoding type, they still fail */
checkFileStoreFailure(filename, PKCS_7_ASN_ENCODING, 0,
ERROR_FILE_NOT_FOUND);
checkFileStoreFailure(filename, PKCS_7_ASN_ENCODING,
CERT_STORE_OPEN_EXISTING_FLAG, ERROR_FILE_NOT_FOUND);
checkFileStoreFailure(filename, PKCS_7_ASN_ENCODING,
CERT_STORE_CREATE_NEW_FLAG, ERROR_FILE_NOT_FOUND);
/* With both a message and cert encoding type, but without commit enabled,
* they still fail
*/
checkFileStoreFailure(filename, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
ERROR_FILE_NOT_FOUND);
checkFileStoreFailure(filename, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CERT_STORE_OPEN_EXISTING_FLAG, ERROR_FILE_NOT_FOUND);
checkFileStoreFailure(filename, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CERT_STORE_CREATE_NEW_FLAG, ERROR_FILE_NOT_FOUND);
/* In all of the following tests, the encoding type seems to be ignored */
if (initFileFromData(filename, bigCert, sizeof(bigCert)))
{
PCCERT_CONTEXT cert;
PCCRL_CONTEXT crl;
store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0,
CERT_STORE_READONLY_FLAG, filename);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
cert = CertEnumCertificatesInStore(store, NULL);
todo_wine ok(cert != NULL, "CertEnumCertificatesInStore failed: %08lx\n",
GetLastError());
cert = CertEnumCertificatesInStore(store, cert);
ok(!cert, "Expected only one cert\n");
crl = CertEnumCRLsInStore(store, NULL);
ok(!crl, "Expected no CRLs\n");
CertCloseStore(store, 0);
DeleteFileW(filename);
}
if (initFileFromData(filename, serializedStoreWithCert,
sizeof(serializedStoreWithCert)))
{
PCCERT_CONTEXT cert;
PCCRL_CONTEXT crl;
store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0,
CERT_STORE_READONLY_FLAG, filename);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
cert = CertEnumCertificatesInStore(store, NULL);
ok(cert != NULL, "CertEnumCertificatesInStore failed: %08lx\n",
GetLastError());
cert = CertEnumCertificatesInStore(store, cert);
ok(!cert, "Expected only one cert\n");
crl = CertEnumCRLsInStore(store, NULL);
ok(!crl, "Expected no CRLs\n");
CertCloseStore(store, 0);
DeleteFileW(filename);
}
if (initFileFromData(filename, serializedStoreWithCertAndCRL,
sizeof(serializedStoreWithCertAndCRL)))
{
PCCERT_CONTEXT cert;
PCCRL_CONTEXT crl;
store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0,
CERT_STORE_READONLY_FLAG, filename);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
cert = CertEnumCertificatesInStore(store, NULL);
ok(cert != NULL, "CertEnumCertificatesInStore failed: %08lx\n",
GetLastError());
cert = CertEnumCertificatesInStore(store, cert);
ok(!cert, "Expected only one cert\n");
crl = CertEnumCRLsInStore(store, NULL);
ok(crl != NULL, "CertEnumCRLsInStore failed: %08lx\n", GetLastError());
crl = CertEnumCRLsInStore(store, crl);
ok(!crl, "Expected only one CRL\n");
CertCloseStore(store, 0);
/* Don't delete it this time, the next test uses it */
}
/* Now that the file exists, we can open it read-only */
store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0,
CERT_STORE_READONLY_FLAG, filename);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
CertCloseStore(store, 0);
DeleteFileW(filename);
store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0,
CERT_FILE_STORE_COMMIT_ENABLE_FLAG | CERT_STORE_CREATE_NEW_FLAG, filename);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
if (store)
{
ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
GetLastError());
CertCloseStore(store, 0);
compareFile(filename, serializedStoreWithCert,
sizeof(serializedStoreWithCert));
}
store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0,
CERT_FILE_STORE_COMMIT_ENABLE_FLAG, filename);
ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
if (store)
{
ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING,
signedCRL, sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL);
ok(ret, "CertAddEncodedCRLToStore failed: %08lx\n", GetLastError());
CertCloseStore(store, 0);
compareFile(filename, serializedStoreWithCertAndCRL,
sizeof(serializedStoreWithCertAndCRL));
}
}
static void testCertOpenSystemStore(void)
{
HCERTSTORE store;
@ -1185,6 +1540,8 @@ START_TEST(store)
testRegStore();
testSystemRegStore();
testSystemStore();
testFileStore();
testFileNameStore();
testCertOpenSystemStore();

View File

@ -1617,6 +1617,15 @@ static const WCHAR CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH[] =
#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
#define CERT_STORE_READONLY_FLAG 0x00008000
#define CERT_REGISTRY_STORE_REMOTE_FLAG 0x00010000
#define CERT_REGISTRY_STORE_SERIALIZED_FLAG 0x00020000
#define CERT_REGISTRY_STORE_ROAMING_FLAG 0x00040000
#define CERT_REGISTRY_STORE_MY_IE_DIRTY_FLAG 0x00080000
#define CERT_REGISTRY_STORE_LM_GPT_FLAG 0x01000000
#define CERT_REGISTRY_STORE_CLIENT_GPT_FLAG 0x80000000
#define CERT_FILE_STORE_COMMIT_ENABLE_FLAG 0x00010000
/* dwAddDisposition */
#define CERT_STORE_ADD_NEW 1
#define CERT_STORE_ADD_USE_EXISTING 2