From 6e23b4a25dd57a54dda8486aa1e88b4765404945 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Tue, 25 Jul 2006 16:29:50 -0700 Subject: [PATCH] crypt32: Implement file stores. --- dlls/crypt32/crypt32_private.h | 8 + dlls/crypt32/serialize.c | 336 ++++++++++++++++++++++++------- dlls/crypt32/store.c | 245 ++++++++++++++++++++-- dlls/crypt32/tests/store.c | 357 +++++++++++++++++++++++++++++++++ include/wincrypt.h | 9 + 5 files changed, 866 insertions(+), 89 deletions(-) diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h index db8719378c5..8aa544b2f06 100644 --- a/dlls/crypt32/crypt32_private.h +++ b/dlls/crypt32/crypt32_private.h @@ -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 diff --git a/dlls/crypt32/serialize.c b/dlls/crypt32/serialize.c index afcd13f1043..8d25eaa06e8 100644 --- a/dlls/crypt32/serialize.c +++ b/dlls/crypt32/serialize.c @@ -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) diff --git a/dlls/crypt32/store.c b/dlls/crypt32/store.c index f1cca0e7c1f..0aaa89d88ba 100644 --- a/dlls/crypt32/store.c +++ b/dlls/crypt32/store.c @@ -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)) diff --git a/dlls/crypt32/tests/store.c b/dlls/crypt32/tests/store.c index 1298b29e56d..d0186e25942 100644 --- a/dlls/crypt32/tests/store.c +++ b/dlls/crypt32/tests/store.c @@ -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(); diff --git a/include/wincrypt.h b/include/wincrypt.h index b34ebfb3ddc..6e8824937c6 100644 --- a/include/wincrypt.h +++ b/include/wincrypt.h @@ -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