crypt32: Implement file stores.
diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h
index db87193..8aa544b 100644
--- a/dlls/crypt32/crypt32_private.h
+++ b/dlls/crypt32/crypt32_private.h
@@ -104,6 +104,14 @@
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
diff --git a/dlls/crypt32/serialize.c b/dlls/crypt32/serialize.c
index afcd13f..8d25eaa 100644
--- a/dlls/crypt32/serialize.c
+++ b/dlls/crypt32/serialize.c
@@ -38,13 +38,13 @@
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 @@
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 @@
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 @@
{
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 @@
{
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 @@
{
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 @@
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 @@
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 @@
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)
diff --git a/dlls/crypt32/store.c b/dlls/crypt32/store.c
index f1cca0e..0aaa89d 100644
--- a/dlls/crypt32/store.c
+++ b/dlls/crypt32/store.c
@@ -163,6 +163,15 @@
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 @@
(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 @@
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 @@
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 @@
}
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))
diff --git a/dlls/crypt32/tests/store.c b/dlls/crypt32/tests/store.c
index 1298b29..d0186e2 100644
--- a/dlls/crypt32/tests/store.c
+++ b/dlls/crypt32/tests/store.c
@@ -1003,6 +1003,361 @@
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 @@
testRegStore();
testSystemRegStore();
testSystemStore();
+ testFileStore();
+ testFileNameStore();
testCertOpenSystemStore();
diff --git a/include/wincrypt.h b/include/wincrypt.h
index b34ebfb..6e88249 100644
--- a/include/wincrypt.h
+++ b/include/wincrypt.h
@@ -1617,6 +1617,15 @@
#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