crypt32: Implement file stores.
This commit is contained in:
parent
a5142837c6
commit
6e23b4a25d
|
@ -104,6 +104,14 @@ extern PCWINE_CONTEXT_INTERFACE pCTLInterface;
|
||||||
const void *CRYPT_ReadSerializedElement(const BYTE *pbElement,
|
const void *CRYPT_ReadSerializedElement(const BYTE *pbElement,
|
||||||
DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
|
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
|
/* 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
|
* 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
|
* provider parameters, in a contiguous buffer, but where info's pointers are
|
||||||
|
|
|
@ -38,13 +38,13 @@ typedef struct _WINE_CERT_PROP_HEADER
|
||||||
|
|
||||||
static BOOL CRYPT_SerializeStoreElement(const void *context,
|
static BOOL CRYPT_SerializeStoreElement(const void *context,
|
||||||
const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID,
|
const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID,
|
||||||
PCWINE_CONTEXT_INTERFACE contextInterface, DWORD dwFlags, BYTE *pbElement,
|
PCWINE_CONTEXT_INTERFACE contextInterface, DWORD dwFlags, BOOL omitHashes,
|
||||||
DWORD *pcbElement)
|
BYTE *pbElement, DWORD *pcbElement)
|
||||||
{
|
{
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
|
|
||||||
TRACE("(%p, %p, %08lx, %p, %p)\n", context, contextInterface, dwFlags,
|
TRACE("(%p, %p, %08lx, %d, %p, %p)\n", context, contextInterface, dwFlags,
|
||||||
pbElement, pcbElement);
|
omitHashes, pbElement, pcbElement);
|
||||||
|
|
||||||
if (context)
|
if (context)
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,7 @@ static BOOL CRYPT_SerializeStoreElement(const void *context,
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
do {
|
do {
|
||||||
prop = contextInterface->enumProps(context, prop);
|
prop = contextInterface->enumProps(context, prop);
|
||||||
if (prop)
|
if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
|
||||||
{
|
{
|
||||||
DWORD propSize = 0;
|
DWORD propSize = 0;
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ static BOOL CRYPT_SerializeStoreElement(const void *context,
|
||||||
prop = 0;
|
prop = 0;
|
||||||
do {
|
do {
|
||||||
prop = contextInterface->enumProps(context, prop);
|
prop = contextInterface->enumProps(context, prop);
|
||||||
if (prop)
|
if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
|
||||||
{
|
{
|
||||||
DWORD propSize = 0;
|
DWORD propSize = 0;
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
|
||||||
{
|
{
|
||||||
return CRYPT_SerializeStoreElement(pCertContext,
|
return CRYPT_SerializeStoreElement(pCertContext,
|
||||||
pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
|
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,
|
BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
|
||||||
|
@ -151,7 +151,7 @@ BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
|
||||||
{
|
{
|
||||||
return CRYPT_SerializeStoreElement(pCrlContext,
|
return CRYPT_SerializeStoreElement(pCrlContext,
|
||||||
pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
|
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,
|
BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
|
||||||
|
@ -159,7 +159,7 @@ BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
|
||||||
{
|
{
|
||||||
return CRYPT_SerializeStoreElement(pCtlContext,
|
return CRYPT_SerializeStoreElement(pCtlContext,
|
||||||
pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
|
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
|
/* 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;
|
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,
|
const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
|
||||||
DWORD dwContextTypeFlags, DWORD *pdwContentType)
|
DWORD dwContextTypeFlags, DWORD *pdwContentType)
|
||||||
{
|
{
|
||||||
|
@ -310,73 +384,15 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
|
||||||
TRACE("prop is %ld\n", hdr->propID);
|
TRACE("prop is %ld\n", hdr->propID);
|
||||||
cbElement -= sizeof(WINE_CERT_PROP_HEADER);
|
cbElement -= sizeof(WINE_CERT_PROP_HEADER);
|
||||||
pbElement += sizeof(WINE_CERT_PROP_HEADER);
|
pbElement += sizeof(WINE_CERT_PROP_HEADER);
|
||||||
if (cbElement < hdr->cb)
|
if (!hdr->propID)
|
||||||
{
|
|
||||||
SetLastError(E_INVALIDARG);
|
|
||||||
ret = FALSE;
|
|
||||||
}
|
|
||||||
else if (!hdr->propID)
|
|
||||||
{
|
{
|
||||||
/* Like in CRYPT_findPropID, stop if the propID is zero
|
/* Like in CRYPT_findPropID, stop if the propID is zero
|
||||||
*/
|
*/
|
||||||
noMoreProps = TRUE;
|
noMoreProps = TRUE;
|
||||||
}
|
}
|
||||||
else if (hdr->unknown != 1)
|
else
|
||||||
{
|
ret = CRYPT_ReadContextProp(contextInterface, context,
|
||||||
SetLastError(ERROR_FILE_NOT_FOUND);
|
hdr, pbElement, cbElement);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pbElement += hdr->cb;
|
pbElement += hdr->cb;
|
||||||
cbElement -= hdr->cb;
|
cbElement -= hdr->cb;
|
||||||
if (!cbElement)
|
if (!cbElement)
|
||||||
|
@ -404,6 +420,184 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
|
||||||
return context;
|
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,
|
BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
|
||||||
const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
|
const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
|
||||||
DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
|
DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
|
||||||
|
|
|
@ -163,6 +163,15 @@ typedef struct _WINE_REGSTOREINFO
|
||||||
struct list crlsToDelete;
|
struct list crlsToDelete;
|
||||||
} WINE_REGSTOREINFO, *PWINE_REGSTOREINFO;
|
} 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
|
typedef struct _WINE_STORE_LIST_ENTRY
|
||||||
{
|
{
|
||||||
PWINECRYPT_CERTSTORE store;
|
PWINECRYPT_CERTSTORE store;
|
||||||
|
@ -695,21 +704,13 @@ static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, void *cert,
|
||||||
(const void **)ppStoreContext);
|
(const void **)ppStoreContext);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
|
ret = TRUE;
|
||||||
{
|
if (ps->provWriteCert)
|
||||||
SetLastError(ERROR_ACCESS_DENIED);
|
ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert,
|
||||||
ret = FALSE;
|
CERT_STORE_PROV_WRITE_ADD_FLAG);
|
||||||
}
|
if (ret)
|
||||||
else
|
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
|
/* dirty trick: replace the returned context's hCertStore with
|
||||||
* store.
|
* store.
|
||||||
|
@ -1723,12 +1724,215 @@ static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
|
||||||
return ret;
|
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,
|
static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
|
||||||
DWORD dwFlags, const void *pvPara)
|
DWORD dwFlags, const void *pvPara)
|
||||||
{
|
{
|
||||||
FIXME("(%ld, %08lx, %s): stub\n", hCryptProv, dwFlags,
|
HCERTSTORE store = 0;
|
||||||
debugstr_w((LPCWSTR)pvPara));
|
LPCWSTR fileName = (LPCWSTR)pvPara;
|
||||||
return NULL;
|
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,
|
static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
|
||||||
|
@ -1788,6 +1992,9 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
|
||||||
case (int)CERT_STORE_PROV_MEMORY:
|
case (int)CERT_STORE_PROV_MEMORY:
|
||||||
openFunc = CRYPT_MemOpenStore;
|
openFunc = CRYPT_MemOpenStore;
|
||||||
break;
|
break;
|
||||||
|
case (int)CERT_STORE_PROV_FILE:
|
||||||
|
openFunc = CRYPT_FileOpenStore;
|
||||||
|
break;
|
||||||
case (int)CERT_STORE_PROV_REG:
|
case (int)CERT_STORE_PROV_REG:
|
||||||
openFunc = CRYPT_RegOpenStore;
|
openFunc = CRYPT_RegOpenStore;
|
||||||
break;
|
break;
|
||||||
|
@ -1822,6 +2029,8 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
|
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
|
||||||
openFunc = CRYPT_MemOpenStore;
|
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))
|
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
|
||||||
openFunc = CRYPT_SysOpenStoreW;
|
openFunc = CRYPT_SysOpenStoreW;
|
||||||
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
|
else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
|
||||||
|
|
|
@ -1003,6 +1003,361 @@ static void testSystemStore(void)
|
||||||
RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW);
|
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)
|
static void testCertOpenSystemStore(void)
|
||||||
{
|
{
|
||||||
HCERTSTORE store;
|
HCERTSTORE store;
|
||||||
|
@ -1185,6 +1540,8 @@ START_TEST(store)
|
||||||
testRegStore();
|
testRegStore();
|
||||||
testSystemRegStore();
|
testSystemRegStore();
|
||||||
testSystemStore();
|
testSystemStore();
|
||||||
|
testFileStore();
|
||||||
|
testFileNameStore();
|
||||||
|
|
||||||
testCertOpenSystemStore();
|
testCertOpenSystemStore();
|
||||||
|
|
||||||
|
|
|
@ -1617,6 +1617,15 @@ static const WCHAR CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH[] =
|
||||||
#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
|
#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
|
||||||
#define CERT_STORE_READONLY_FLAG 0x00008000
|
#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 */
|
/* dwAddDisposition */
|
||||||
#define CERT_STORE_ADD_NEW 1
|
#define CERT_STORE_ADD_NEW 1
|
||||||
#define CERT_STORE_ADD_USE_EXISTING 2
|
#define CERT_STORE_ADD_USE_EXISTING 2
|
||||||
|
|
Loading…
Reference in New Issue