2006-04-16 19:15:04 +00:00
|
|
|
/*
|
2008-05-10 18:43:43 +00:00
|
|
|
* Copyright 2004-2007 Juan Lang
|
2006-04-16 19:15:04 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2006-07-06 10:19:03 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2006-04-16 19:15:04 +00:00
|
|
|
*/
|
2008-05-10 18:43:43 +00:00
|
|
|
|
2018-03-09 11:59:49 +00:00
|
|
|
#include "config.h"
|
|
|
|
#include "wine/port.h"
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "wincrypt.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
#include "wine/exception.h"
|
2006-04-16 19:15:04 +00:00
|
|
|
#include "crypt32_private.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
|
|
|
|
|
|
|
/* An extended certificate property in serialized form is prefixed by this
|
|
|
|
* header.
|
|
|
|
*/
|
|
|
|
typedef struct _WINE_CERT_PROP_HEADER
|
|
|
|
{
|
|
|
|
DWORD propID;
|
|
|
|
DWORD unknown; /* always 1 */
|
|
|
|
DWORD cb;
|
2014-04-22 15:10:43 +00:00
|
|
|
} WINE_CERT_PROP_HEADER;
|
2006-04-16 19:15:04 +00:00
|
|
|
|
2006-07-06 10:19:03 +00:00
|
|
|
static BOOL CRYPT_SerializeStoreElement(const void *context,
|
|
|
|
const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID,
|
2014-04-22 15:10:43 +00:00
|
|
|
const WINE_CONTEXT_INTERFACE *contextInterface, DWORD dwFlags, BOOL omitHashes,
|
2007-04-26 13:37:57 +00:00
|
|
|
BYTE *pbElement, DWORD *pcbElement)
|
2006-04-16 19:15:04 +00:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
|
2007-04-26 13:37:57 +00:00
|
|
|
TRACE("(%p, %p, %08x, %d, %p, %p)\n", context, contextInterface, dwFlags,
|
|
|
|
omitHashes, pbElement, pcbElement);
|
2006-04-16 19:15:04 +00:00
|
|
|
|
2006-07-06 10:19:03 +00:00
|
|
|
if (context)
|
2006-04-16 19:15:04 +00:00
|
|
|
{
|
2006-07-06 10:19:03 +00:00
|
|
|
DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext;
|
2006-04-16 19:15:04 +00:00
|
|
|
DWORD prop = 0;
|
|
|
|
|
|
|
|
ret = TRUE;
|
|
|
|
do {
|
2006-07-06 10:19:03 +00:00
|
|
|
prop = contextInterface->enumProps(context, prop);
|
2007-04-26 13:37:57 +00:00
|
|
|
if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
|
2006-04-16 19:15:04 +00:00
|
|
|
{
|
|
|
|
DWORD propSize = 0;
|
|
|
|
|
2006-07-06 10:19:03 +00:00
|
|
|
ret = contextInterface->getProp(context, prop, NULL, &propSize);
|
2006-04-16 19:15:04 +00:00
|
|
|
if (ret)
|
|
|
|
bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
|
|
|
|
}
|
|
|
|
} while (ret && prop != 0);
|
|
|
|
|
|
|
|
if (!pbElement)
|
|
|
|
{
|
|
|
|
*pcbElement = bytesNeeded;
|
|
|
|
ret = TRUE;
|
|
|
|
}
|
|
|
|
else if (*pcbElement < bytesNeeded)
|
|
|
|
{
|
|
|
|
*pcbElement = bytesNeeded;
|
|
|
|
SetLastError(ERROR_MORE_DATA);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-04-22 15:10:43 +00:00
|
|
|
WINE_CERT_PROP_HEADER *hdr;
|
2006-04-16 19:15:04 +00:00
|
|
|
DWORD bufSize = 0;
|
|
|
|
LPBYTE buf = NULL;
|
|
|
|
|
|
|
|
prop = 0;
|
|
|
|
do {
|
2006-07-06 10:19:03 +00:00
|
|
|
prop = contextInterface->enumProps(context, prop);
|
2007-04-26 13:37:57 +00:00
|
|
|
if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
|
2006-04-16 19:15:04 +00:00
|
|
|
{
|
|
|
|
DWORD propSize = 0;
|
|
|
|
|
2006-07-06 10:19:03 +00:00
|
|
|
ret = contextInterface->getProp(context, prop, NULL,
|
|
|
|
&propSize);
|
2006-04-16 19:15:04 +00:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
if (bufSize < propSize)
|
|
|
|
{
|
|
|
|
if (buf)
|
|
|
|
buf = CryptMemRealloc(buf, propSize);
|
|
|
|
else
|
|
|
|
buf = CryptMemAlloc(propSize);
|
|
|
|
bufSize = propSize;
|
|
|
|
}
|
|
|
|
if (buf)
|
|
|
|
{
|
2006-07-06 10:19:03 +00:00
|
|
|
ret = contextInterface->getProp(context, prop, buf,
|
|
|
|
&propSize);
|
2006-04-16 19:15:04 +00:00
|
|
|
if (ret)
|
|
|
|
{
|
2014-04-22 15:10:43 +00:00
|
|
|
hdr = (WINE_CERT_PROP_HEADER*)pbElement;
|
2006-04-16 19:15:04 +00:00
|
|
|
hdr->propID = prop;
|
|
|
|
hdr->unknown = 1;
|
|
|
|
hdr->cb = propSize;
|
|
|
|
pbElement += sizeof(WINE_CERT_PROP_HEADER);
|
|
|
|
if (propSize)
|
|
|
|
{
|
|
|
|
memcpy(pbElement, buf, propSize);
|
|
|
|
pbElement += propSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (ret && prop != 0);
|
|
|
|
CryptMemFree(buf);
|
|
|
|
|
2014-04-22 15:10:43 +00:00
|
|
|
hdr = (WINE_CERT_PROP_HEADER*)pbElement;
|
2006-07-06 10:19:03 +00:00
|
|
|
hdr->propID = contextPropID;
|
2006-04-16 19:15:04 +00:00
|
|
|
hdr->unknown = 1;
|
2006-07-06 10:19:03 +00:00
|
|
|
hdr->cb = cbEncodedContext;
|
2006-04-16 19:15:04 +00:00
|
|
|
memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
|
2006-07-06 10:19:03 +00:00
|
|
|
encodedContext, cbEncodedContext);
|
2006-04-16 19:15:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = FALSE;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-07-06 10:19:03 +00:00
|
|
|
BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
|
|
|
|
DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
|
|
|
|
{
|
|
|
|
return CRYPT_SerializeStoreElement(pCertContext,
|
|
|
|
pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
|
2007-04-26 13:37:57 +00:00
|
|
|
CERT_CERT_PROP_ID, pCertInterface, dwFlags, FALSE, pbElement, pcbElement);
|
2006-07-06 10:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
|
|
|
|
DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
|
|
|
|
{
|
|
|
|
return CRYPT_SerializeStoreElement(pCrlContext,
|
|
|
|
pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
|
2007-04-26 13:37:57 +00:00
|
|
|
CERT_CRL_PROP_ID, pCRLInterface, dwFlags, FALSE, pbElement, pcbElement);
|
2006-07-06 10:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
|
|
|
|
DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
|
|
|
|
{
|
|
|
|
return CRYPT_SerializeStoreElement(pCtlContext,
|
|
|
|
pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
|
2007-04-26 13:37:57 +00:00
|
|
|
CERT_CTL_PROP_ID, pCTLInterface, dwFlags, FALSE, pbElement, pcbElement);
|
2006-07-06 10:19:03 +00:00
|
|
|
}
|
|
|
|
|
2006-04-16 19:15:04 +00:00
|
|
|
/* Looks for the property with ID propID in the buffer buf. Returns a pointer
|
|
|
|
* to its header if a valid header is found, NULL if not. Valid means the
|
2012-01-23 15:45:15 +00:00
|
|
|
* length of the property won't overrun buf, and the unknown field is 1.
|
2006-04-16 19:15:04 +00:00
|
|
|
*/
|
|
|
|
static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
|
|
|
|
DWORD size, DWORD propID)
|
|
|
|
{
|
|
|
|
const WINE_CERT_PROP_HEADER *ret = NULL;
|
|
|
|
BOOL done = FALSE;
|
|
|
|
|
|
|
|
while (size && !ret && !done)
|
|
|
|
{
|
|
|
|
if (size < sizeof(WINE_CERT_PROP_HEADER))
|
|
|
|
{
|
|
|
|
SetLastError(CRYPT_E_FILE_ERROR);
|
|
|
|
done = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const WINE_CERT_PROP_HEADER *hdr =
|
|
|
|
(const WINE_CERT_PROP_HEADER *)buf;
|
|
|
|
|
|
|
|
size -= sizeof(WINE_CERT_PROP_HEADER);
|
|
|
|
buf += sizeof(WINE_CERT_PROP_HEADER);
|
|
|
|
if (size < hdr->cb)
|
|
|
|
{
|
2006-07-06 10:19:03 +00:00
|
|
|
SetLastError(E_INVALIDARG);
|
2006-04-16 19:15:04 +00:00
|
|
|
done = TRUE;
|
|
|
|
}
|
|
|
|
else if (!hdr->propID)
|
|
|
|
{
|
|
|
|
/* assume a zero prop ID means the data are uninitialized, so
|
|
|
|
* stop looking.
|
|
|
|
*/
|
|
|
|
done = TRUE;
|
|
|
|
}
|
|
|
|
else if (hdr->unknown != 1)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_FILE_NOT_FOUND);
|
|
|
|
done = TRUE;
|
|
|
|
}
|
|
|
|
else if (hdr->propID == propID)
|
|
|
|
ret = hdr;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
buf += hdr->cb;
|
|
|
|
size -= hdr->cb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-04-26 13:37:57 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-04-16 19:15:04 +00:00
|
|
|
const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
|
|
|
|
DWORD dwContextTypeFlags, DWORD *pdwContentType)
|
|
|
|
{
|
|
|
|
const void *context;
|
|
|
|
|
2007-04-26 13:37:57 +00:00
|
|
|
TRACE("(%p, %d, %08x, %p)\n", pbElement, cbElement, dwContextTypeFlags,
|
2006-04-16 19:15:04 +00:00
|
|
|
pdwContentType);
|
|
|
|
|
|
|
|
if (!cbElement)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_END_OF_MEDIA);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
__TRY
|
|
|
|
{
|
|
|
|
const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
|
|
|
|
const WINE_CERT_PROP_HEADER *hdr = NULL;
|
|
|
|
DWORD type = 0;
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
ret = TRUE;
|
|
|
|
context = NULL;
|
|
|
|
if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
|
|
|
|
{
|
|
|
|
hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
|
|
|
|
if (hdr)
|
|
|
|
type = CERT_STORE_CERTIFICATE_CONTEXT;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
|
|
|
|
if (hdr)
|
|
|
|
type = CERT_STORE_CRL_CONTEXT;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hdr = CRYPT_findPropID(pbElement, cbElement,
|
|
|
|
CERT_CTL_PROP_ID);
|
|
|
|
if (hdr)
|
|
|
|
type = CERT_STORE_CTL_CONTEXT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
|
|
|
|
{
|
|
|
|
hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
|
|
|
|
type = CERT_STORE_CERTIFICATE_CONTEXT;
|
|
|
|
}
|
|
|
|
else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
|
|
|
|
{
|
|
|
|
hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
|
|
|
|
type = CERT_STORE_CRL_CONTEXT;
|
|
|
|
}
|
|
|
|
else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
|
|
|
|
{
|
|
|
|
hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
|
|
|
|
type = CERT_STORE_CTL_CONTEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case CERT_STORE_CERTIFICATE_CONTEXT:
|
2006-07-06 10:19:03 +00:00
|
|
|
contextInterface = pCertInterface;
|
2006-04-16 19:15:04 +00:00
|
|
|
break;
|
|
|
|
case CERT_STORE_CRL_CONTEXT:
|
2006-07-06 10:19:03 +00:00
|
|
|
contextInterface = pCRLInterface;
|
2006-04-16 19:15:04 +00:00
|
|
|
break;
|
|
|
|
case CERT_STORE_CTL_CONTEXT:
|
2006-07-06 10:19:03 +00:00
|
|
|
contextInterface = pCTLInterface;
|
2006-04-16 19:15:04 +00:00
|
|
|
break;
|
|
|
|
default:
|
2006-07-06 10:19:03 +00:00
|
|
|
SetLastError(E_INVALIDARG);
|
2006-04-16 19:15:04 +00:00
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
if (!hdr)
|
|
|
|
ret = FALSE;
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
context = contextInterface->create(X509_ASN_ENCODING,
|
|
|
|
(BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
|
|
|
|
if (ret && context)
|
|
|
|
{
|
|
|
|
BOOL noMoreProps = FALSE;
|
|
|
|
|
|
|
|
while (!noMoreProps && ret)
|
|
|
|
{
|
|
|
|
if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
|
|
|
|
ret = FALSE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const WINE_CERT_PROP_HEADER *hdr =
|
|
|
|
(const WINE_CERT_PROP_HEADER *)pbElement;
|
|
|
|
|
2007-04-26 13:37:57 +00:00
|
|
|
TRACE("prop is %d\n", hdr->propID);
|
2006-04-16 19:15:04 +00:00
|
|
|
cbElement -= sizeof(WINE_CERT_PROP_HEADER);
|
|
|
|
pbElement += sizeof(WINE_CERT_PROP_HEADER);
|
2007-04-26 13:37:57 +00:00
|
|
|
if (!hdr->propID)
|
2006-04-16 19:15:04 +00:00
|
|
|
{
|
|
|
|
/* Like in CRYPT_findPropID, stop if the propID is zero
|
|
|
|
*/
|
|
|
|
noMoreProps = TRUE;
|
|
|
|
}
|
2007-04-26 13:37:57 +00:00
|
|
|
else
|
|
|
|
ret = CRYPT_ReadContextProp(contextInterface, context,
|
|
|
|
hdr, pbElement, cbElement);
|
2006-04-16 19:15:04 +00:00
|
|
|
pbElement += hdr->cb;
|
|
|
|
cbElement -= hdr->cb;
|
|
|
|
if (!cbElement)
|
|
|
|
noMoreProps = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
if (pdwContentType)
|
|
|
|
*pdwContentType = type;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-04-22 15:10:43 +00:00
|
|
|
Context_Release(context_from_ptr(context));
|
2006-04-16 19:15:04 +00:00
|
|
|
context = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
__EXCEPT_PAGE_FAULT
|
|
|
|
{
|
|
|
|
SetLastError(STATUS_ACCESS_VIOLATION);
|
|
|
|
context = NULL;
|
|
|
|
}
|
|
|
|
__ENDTRY
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
2007-04-26 13:37:57 +00:00
|
|
|
static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
|
|
|
|
|
2009-11-15 22:58:08 +00:00
|
|
|
typedef BOOL (*read_serialized_func)(void *handle, void *buffer,
|
|
|
|
DWORD bytesToRead, DWORD *bytesRead);
|
|
|
|
|
|
|
|
static BOOL CRYPT_ReadSerializedStore(void *handle,
|
|
|
|
read_serialized_func read_func, HCERTSTORE store)
|
2007-04-26 13:37:57 +00:00
|
|
|
{
|
|
|
|
BYTE fileHeaderBuf[sizeof(fileHeader)];
|
|
|
|
DWORD read;
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
/* Failure reading is non-critical, we'll leave the store empty */
|
2009-11-15 22:58:08 +00:00
|
|
|
ret = read_func(handle, fileHeaderBuf, sizeof(fileHeaderBuf), &read);
|
2007-04-26 13:37:57 +00:00
|
|
|
if (ret)
|
|
|
|
{
|
2008-05-10 18:43:43 +00:00
|
|
|
if (!read)
|
|
|
|
; /* an empty file is okay */
|
|
|
|
else if (read != sizeof(fileHeaderBuf))
|
|
|
|
ret = FALSE;
|
|
|
|
else if (!memcmp(fileHeaderBuf, fileHeader, read))
|
2007-04-26 13:37:57 +00:00
|
|
|
{
|
|
|
|
WINE_CERT_PROP_HEADER propHdr;
|
|
|
|
const void *context = NULL;
|
|
|
|
const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
|
|
|
|
LPBYTE buf = NULL;
|
|
|
|
DWORD bufSize = 0;
|
|
|
|
|
|
|
|
do {
|
2009-11-15 22:58:08 +00:00
|
|
|
ret = read_func(handle, &propHdr, sizeof(propHdr), &read);
|
2007-04-26 13:37:57 +00:00
|
|
|
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 */
|
2014-04-22 15:10:43 +00:00
|
|
|
Context_Release(context_from_ptr(context));
|
2007-04-26 13:37:57 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
Sync avifil, credui, crypt32, cryptdlg, cryptui, dnsapi, gdiplus, hhctrl, hnetcfg, iccvid, imaadp32, imm32, jscript, localspl, localui, mapi32, mciavi32, mcicda, mciqtz32, mciseq, mciwave, mshtml, msrle32, msvfw32, msvidc32, msxml3, oleacc, oleaut32 to Wine 1.2rc5 (Samuel Serapion, small changes by me)
Remove Esperanto and Walon languages from comctl32, comdlg32, mpr, msi, shlwapi, wininet
svn path=/trunk/; revision=47920
2010-07-01 11:09:47 +00:00
|
|
|
if (!propHdr.cb)
|
|
|
|
; /* Property is empty, nothing to do */
|
|
|
|
else if (buf)
|
2007-04-26 13:37:57 +00:00
|
|
|
{
|
2009-11-15 22:58:08 +00:00
|
|
|
ret = read_func(handle, buf, propHdr.cb, &read);
|
2007-04-26 13:37:57 +00:00
|
|
|
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
|
2009-11-15 22:58:08 +00:00
|
|
|
{
|
|
|
|
if (!contextInterface)
|
|
|
|
{
|
|
|
|
WARN("prop id %d before a context id\n",
|
|
|
|
propHdr.propID);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = CRYPT_ReadContextProp(
|
|
|
|
contextInterface, context, &propHdr, buf,
|
|
|
|
read);
|
|
|
|
}
|
2007-04-26 13:37:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
Sync avifil, credui, crypt32, cryptdlg, cryptui, dnsapi, gdiplus, hhctrl, hnetcfg, iccvid, imaadp32, imm32, jscript, localspl, localui, mapi32, mciavi32, mcicda, mciqtz32, mciseq, mciwave, mshtml, msrle32, msvfw32, msvidc32, msxml3, oleacc, oleaut32 to Wine 1.2rc5 (Samuel Serapion, small changes by me)
Remove Esperanto and Walon languages from comctl32, comdlg32, mpr, msi, shlwapi, wininet
svn path=/trunk/; revision=47920
2010-07-01 11:09:47 +00:00
|
|
|
} while (ret && read > 0 && propHdr.cb);
|
2007-04-26 13:37:57 +00:00
|
|
|
if (contextInterface && context)
|
|
|
|
{
|
|
|
|
/* Free the last context added */
|
2014-04-22 15:10:43 +00:00
|
|
|
Context_Release(context_from_ptr(context));
|
2007-04-26 13:37:57 +00:00
|
|
|
}
|
|
|
|
CryptMemFree(buf);
|
|
|
|
ret = TRUE;
|
|
|
|
}
|
2008-05-10 18:43:43 +00:00
|
|
|
else
|
|
|
|
ret = FALSE;
|
2007-04-26 13:37:57 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = TRUE;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-11-15 22:58:08 +00:00
|
|
|
static BOOL read_file_wrapper(void *handle, void *buffer, DWORD bytesToRead,
|
|
|
|
DWORD *bytesRead)
|
|
|
|
{
|
|
|
|
return ReadFile(handle, buffer, bytesToRead, bytesRead, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store)
|
|
|
|
{
|
|
|
|
return CRYPT_ReadSerializedStore(file, read_file_wrapper, store);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct BlobReader
|
|
|
|
{
|
|
|
|
const CRYPT_DATA_BLOB *blob;
|
|
|
|
DWORD current;
|
|
|
|
};
|
|
|
|
|
|
|
|
static BOOL read_blob_wrapper(void *handle, void *buffer, DWORD bytesToRead,
|
|
|
|
DWORD *bytesRead)
|
|
|
|
{
|
|
|
|
struct BlobReader *reader = handle;
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
if (reader->current < reader->blob->cbData)
|
|
|
|
{
|
|
|
|
*bytesRead = min(bytesToRead, reader->blob->cbData - reader->current);
|
|
|
|
memcpy(buffer, reader->blob->pbData + reader->current, *bytesRead);
|
Sync avifil, credui, crypt32, cryptdlg, cryptui, dnsapi, gdiplus, hhctrl, hnetcfg, iccvid, imaadp32, imm32, jscript, localspl, localui, mapi32, mciavi32, mcicda, mciqtz32, mciseq, mciwave, mshtml, msrle32, msvfw32, msvidc32, msxml3, oleacc, oleaut32 to Wine 1.2rc5 (Samuel Serapion, small changes by me)
Remove Esperanto and Walon languages from comctl32, comdlg32, mpr, msi, shlwapi, wininet
svn path=/trunk/; revision=47920
2010-07-01 11:09:47 +00:00
|
|
|
reader->current += *bytesRead;
|
|
|
|
ret = TRUE;
|
|
|
|
}
|
|
|
|
else if (reader->current == reader->blob->cbData)
|
|
|
|
{
|
|
|
|
*bytesRead = 0;
|
2009-11-15 22:58:08 +00:00
|
|
|
ret = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = FALSE;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
|
|
|
|
HCERTSTORE store)
|
|
|
|
{
|
|
|
|
struct BlobReader reader = { blob, 0 };
|
|
|
|
|
|
|
|
return CRYPT_ReadSerializedStore(&reader, read_blob_wrapper, store);
|
|
|
|
}
|
|
|
|
|
2007-04-26 13:37:57 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-05-10 18:43:43 +00:00
|
|
|
typedef BOOL (*SerializedOutputFunc)(void *handle, const void *buffer,
|
|
|
|
DWORD size);
|
|
|
|
|
|
|
|
static BOOL CRYPT_SerializeContextsToStream(SerializedOutputFunc output,
|
|
|
|
void *handle, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
|
2007-04-26 13:37:57 +00:00
|
|
|
{
|
|
|
|
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)
|
2008-05-10 18:43:43 +00:00
|
|
|
ret = output(handle, buf, size);
|
2007-04-26 13:37:57 +00:00
|
|
|
}
|
|
|
|
CryptMemFree(buf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = TRUE;
|
|
|
|
} while (ret && context != NULL);
|
|
|
|
if (context)
|
2014-04-22 15:10:43 +00:00
|
|
|
Context_Release(context_from_ptr(context));
|
2007-04-26 13:37:57 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-05-10 18:43:43 +00:00
|
|
|
static BOOL CRYPT_WriteSerializedStoreToStream(HCERTSTORE store,
|
|
|
|
SerializedOutputFunc output, void *handle)
|
2007-04-26 13:37:57 +00:00
|
|
|
{
|
|
|
|
static const BYTE fileTrailer[12] = { 0 };
|
|
|
|
WINE_CONTEXT_INTERFACE interface;
|
|
|
|
BOOL ret;
|
|
|
|
|
2008-05-10 18:43:43 +00:00
|
|
|
ret = output(handle, fileHeader, sizeof(fileHeader));
|
2007-04-26 13:37:57 +00:00
|
|
|
if (ret)
|
|
|
|
{
|
2013-04-03 22:43:22 +00:00
|
|
|
interface = *pCertInterface;
|
2007-04-26 13:37:57 +00:00
|
|
|
interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
|
2008-05-10 18:43:43 +00:00
|
|
|
ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
|
|
|
|
store);
|
2007-04-26 13:37:57 +00:00
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
{
|
2013-04-03 22:43:22 +00:00
|
|
|
interface = *pCRLInterface;
|
2007-04-26 13:37:57 +00:00
|
|
|
interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
|
2008-05-10 18:43:43 +00:00
|
|
|
ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
|
|
|
|
store);
|
2007-04-26 13:37:57 +00:00
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
{
|
2013-04-03 22:43:22 +00:00
|
|
|
interface = *pCTLInterface;
|
2007-04-26 13:37:57 +00:00
|
|
|
interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
|
2008-05-10 18:43:43 +00:00
|
|
|
ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
|
|
|
|
store);
|
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
ret = output(handle, fileTrailer, sizeof(fileTrailer));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL CRYPT_FileOutputFunc(void *handle, const void *buffer, DWORD size)
|
|
|
|
{
|
|
|
|
return WriteFile(handle, buffer, size, &size, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL CRYPT_WriteSerializedStoreToFile(HANDLE file, HCERTSTORE store)
|
|
|
|
{
|
|
|
|
SetFilePointer(file, 0, NULL, FILE_BEGIN);
|
|
|
|
return CRYPT_WriteSerializedStoreToStream(store, CRYPT_FileOutputFunc,
|
|
|
|
file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL CRYPT_SavePKCSToMem(HCERTSTORE store,
|
|
|
|
DWORD dwMsgAndCertEncodingType, void *handle)
|
|
|
|
{
|
2009-01-31 14:28:46 +00:00
|
|
|
CERT_BLOB *blob = handle;
|
2008-05-10 18:43:43 +00:00
|
|
|
CRYPT_SIGNED_INFO signedInfo = { 0 };
|
|
|
|
PCCERT_CONTEXT cert = NULL;
|
|
|
|
PCCRL_CONTEXT crl = NULL;
|
|
|
|
DWORD size;
|
|
|
|
BOOL ret = TRUE;
|
|
|
|
|
|
|
|
TRACE("(%d, %p)\n", blob->pbData ? blob->cbData : 0, blob->pbData);
|
|
|
|
|
|
|
|
do {
|
|
|
|
cert = CertEnumCertificatesInStore(store, cert);
|
|
|
|
if (cert)
|
|
|
|
signedInfo.cCertEncoded++;
|
|
|
|
} while (cert);
|
|
|
|
if (signedInfo.cCertEncoded)
|
|
|
|
{
|
|
|
|
signedInfo.rgCertEncoded = CryptMemAlloc(
|
|
|
|
signedInfo.cCertEncoded * sizeof(CERT_BLOB));
|
|
|
|
if (!signedInfo.rgCertEncoded)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DWORD i = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
cert = CertEnumCertificatesInStore(store, cert);
|
|
|
|
if (cert)
|
|
|
|
{
|
|
|
|
signedInfo.rgCertEncoded[i].cbData = cert->cbCertEncoded;
|
|
|
|
signedInfo.rgCertEncoded[i].pbData = cert->pbCertEncoded;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
} while (cert);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
crl = CertEnumCRLsInStore(store, crl);
|
|
|
|
if (crl)
|
|
|
|
signedInfo.cCrlEncoded++;
|
|
|
|
} while (crl);
|
|
|
|
if (signedInfo.cCrlEncoded)
|
|
|
|
{
|
|
|
|
signedInfo.rgCrlEncoded = CryptMemAlloc(
|
|
|
|
signedInfo.cCrlEncoded * sizeof(CERT_BLOB));
|
|
|
|
if (!signedInfo.rgCrlEncoded)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DWORD i = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
crl = CertEnumCRLsInStore(store, crl);
|
|
|
|
if (crl)
|
|
|
|
{
|
|
|
|
signedInfo.rgCrlEncoded[i].cbData = crl->cbCrlEncoded;
|
|
|
|
signedInfo.rgCrlEncoded[i].pbData = crl->pbCrlEncoded;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
} while (crl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
{
|
2008-09-14 11:32:55 +00:00
|
|
|
ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, NULL, &size);
|
2008-05-10 18:43:43 +00:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
if (!blob->pbData)
|
|
|
|
blob->cbData = size;
|
|
|
|
else if (blob->cbData < size)
|
|
|
|
{
|
|
|
|
blob->cbData = size;
|
|
|
|
SetLastError(ERROR_MORE_DATA);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
blob->cbData = size;
|
2008-09-14 11:32:55 +00:00
|
|
|
ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, blob->pbData,
|
2008-05-10 18:43:43 +00:00
|
|
|
&blob->cbData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CryptMemFree(signedInfo.rgCertEncoded);
|
|
|
|
CryptMemFree(signedInfo.rgCrlEncoded);
|
|
|
|
TRACE("returning %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL CRYPT_SavePKCSToFile(HCERTSTORE store,
|
|
|
|
DWORD dwMsgAndCertEncodingType, void *handle)
|
|
|
|
{
|
|
|
|
CERT_BLOB blob = { 0, NULL };
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
TRACE("(%p)\n", handle);
|
|
|
|
|
|
|
|
ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
blob.pbData = CryptMemAlloc(blob.cbData);
|
|
|
|
if (blob.pbData)
|
|
|
|
{
|
|
|
|
ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
|
|
|
|
if (ret)
|
|
|
|
ret = WriteFile(handle, blob.pbData, blob.cbData,
|
|
|
|
&blob.cbData, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TRACE("returning %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL CRYPT_SaveSerializedToFile(HCERTSTORE store,
|
|
|
|
DWORD dwMsgAndCertEncodingType, void *handle)
|
|
|
|
{
|
|
|
|
return CRYPT_WriteSerializedStoreToFile(handle, store);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct MemWrittenTracker
|
|
|
|
{
|
|
|
|
DWORD cbData;
|
|
|
|
BYTE *pbData;
|
|
|
|
DWORD written;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* handle is a pointer to a MemWrittenTracker. Assumes its pointer is valid. */
|
|
|
|
static BOOL CRYPT_MemOutputFunc(void *handle, const void *buffer, DWORD size)
|
|
|
|
{
|
2009-01-31 14:28:46 +00:00
|
|
|
struct MemWrittenTracker *tracker = handle;
|
2008-05-10 18:43:43 +00:00
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
if (tracker->written + size > tracker->cbData)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_MORE_DATA);
|
|
|
|
/* Update written so caller can notify its caller of the required size
|
|
|
|
*/
|
|
|
|
tracker->written += size;
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(tracker->pbData + tracker->written, buffer, size);
|
|
|
|
tracker->written += size;
|
|
|
|
ret = TRUE;
|
2007-04-26 13:37:57 +00:00
|
|
|
}
|
2008-05-10 18:43:43 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL CRYPT_CountSerializedBytes(void *handle, const void *buffer,
|
|
|
|
DWORD size)
|
|
|
|
{
|
|
|
|
*(DWORD *)handle += size;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL CRYPT_SaveSerializedToMem(HCERTSTORE store,
|
|
|
|
DWORD dwMsgAndCertEncodingType, void *handle)
|
|
|
|
{
|
2009-01-31 14:28:46 +00:00
|
|
|
CERT_BLOB *blob = handle;
|
2008-09-14 11:32:55 +00:00
|
|
|
DWORD size = 0;
|
2008-05-10 18:43:43 +00:00
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_CountSerializedBytes,
|
|
|
|
&size);
|
2007-04-26 13:37:57 +00:00
|
|
|
if (ret)
|
2008-05-10 18:43:43 +00:00
|
|
|
{
|
|
|
|
if (!blob->pbData)
|
|
|
|
blob->cbData = size;
|
|
|
|
else if (blob->cbData < size)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_MORE_DATA);
|
|
|
|
blob->cbData = size;
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
struct MemWrittenTracker tracker = { blob->cbData, blob->pbData,
|
|
|
|
0 };
|
|
|
|
|
|
|
|
ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_MemOutputFunc,
|
|
|
|
&tracker);
|
|
|
|
if (!ret && GetLastError() == ERROR_MORE_DATA)
|
|
|
|
blob->cbData = tracker.written;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TRACE("returning %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
|
|
|
|
DWORD dwSaveAs, DWORD dwSaveTo, void *pvSaveToPara, DWORD dwFlags)
|
|
|
|
{
|
|
|
|
BOOL (*saveFunc)(HCERTSTORE, DWORD, void *);
|
|
|
|
void *handle;
|
2009-01-31 14:28:46 +00:00
|
|
|
BOOL ret, closeFile = TRUE;
|
2008-05-10 18:43:43 +00:00
|
|
|
|
|
|
|
TRACE("(%p, %08x, %d, %d, %p, %08x)\n", hCertStore,
|
|
|
|
dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
|
|
|
|
|
|
|
|
switch (dwSaveAs)
|
|
|
|
{
|
|
|
|
case CERT_STORE_SAVE_AS_STORE:
|
2009-01-31 14:28:46 +00:00
|
|
|
if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
|
|
|
|
saveFunc = CRYPT_SaveSerializedToMem;
|
|
|
|
else
|
|
|
|
saveFunc = CRYPT_SaveSerializedToFile;
|
|
|
|
break;
|
2008-05-10 18:43:43 +00:00
|
|
|
case CERT_STORE_SAVE_AS_PKCS7:
|
2009-01-31 14:28:46 +00:00
|
|
|
if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
|
|
|
|
saveFunc = CRYPT_SavePKCSToMem;
|
|
|
|
else
|
|
|
|
saveFunc = CRYPT_SavePKCSToFile;
|
2008-05-10 18:43:43 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WARN("unimplemented for %d\n", dwSaveAs);
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
switch (dwSaveTo)
|
|
|
|
{
|
|
|
|
case CERT_STORE_SAVE_TO_FILE:
|
|
|
|
handle = pvSaveToPara;
|
2009-01-31 14:28:46 +00:00
|
|
|
closeFile = FALSE;
|
2008-05-10 18:43:43 +00:00
|
|
|
break;
|
|
|
|
case CERT_STORE_SAVE_TO_FILENAME_A:
|
2009-01-31 14:28:46 +00:00
|
|
|
handle = CreateFileA(pvSaveToPara, GENERIC_WRITE, 0, NULL,
|
2008-05-10 18:43:43 +00:00
|
|
|
CREATE_ALWAYS, 0, NULL);
|
|
|
|
break;
|
|
|
|
case CERT_STORE_SAVE_TO_FILENAME_W:
|
2009-01-31 14:28:46 +00:00
|
|
|
handle = CreateFileW(pvSaveToPara, GENERIC_WRITE, 0, NULL,
|
2008-05-10 18:43:43 +00:00
|
|
|
CREATE_ALWAYS, 0, NULL);
|
|
|
|
break;
|
|
|
|
case CERT_STORE_SAVE_TO_MEMORY:
|
|
|
|
handle = pvSaveToPara;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WARN("unimplemented for %d\n", dwSaveTo);
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
ret = saveFunc(hCertStore, dwMsgAndCertEncodingType, handle);
|
2009-01-31 14:28:46 +00:00
|
|
|
if (closeFile)
|
|
|
|
CloseHandle(handle);
|
2008-05-10 18:43:43 +00:00
|
|
|
TRACE("returning %d\n", ret);
|
2007-04-26 13:37:57 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-04-16 19:15:04 +00:00
|
|
|
BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
|
|
|
|
const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
|
|
|
|
DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
|
|
|
|
{
|
|
|
|
const void *context;
|
|
|
|
DWORD type;
|
|
|
|
BOOL ret;
|
|
|
|
|
2007-04-26 13:37:57 +00:00
|
|
|
TRACE("(%p, %p, %d, %08x, %08x, %08x, %p, %p)\n", hCertStore,
|
2006-04-16 19:15:04 +00:00
|
|
|
pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
|
|
|
|
pdwContentType, ppvContext);
|
|
|
|
|
|
|
|
/* Call the internal function, then delete the hashes. Tests show this
|
|
|
|
* function uses real hash values, not whatever's stored in the hash
|
|
|
|
* property.
|
|
|
|
*/
|
|
|
|
context = CRYPT_ReadSerializedElement(pbElement, cbElement,
|
|
|
|
dwContextTypeFlags, &type);
|
|
|
|
if (context)
|
|
|
|
{
|
|
|
|
const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case CERT_STORE_CERTIFICATE_CONTEXT:
|
2006-07-06 10:19:03 +00:00
|
|
|
contextInterface = pCertInterface;
|
2006-04-16 19:15:04 +00:00
|
|
|
break;
|
|
|
|
case CERT_STORE_CRL_CONTEXT:
|
2006-07-06 10:19:03 +00:00
|
|
|
contextInterface = pCRLInterface;
|
2006-04-16 19:15:04 +00:00
|
|
|
break;
|
|
|
|
case CERT_STORE_CTL_CONTEXT:
|
2006-07-06 10:19:03 +00:00
|
|
|
contextInterface = pCTLInterface;
|
2006-04-16 19:15:04 +00:00
|
|
|
break;
|
|
|
|
default:
|
2006-07-06 10:19:03 +00:00
|
|
|
SetLastError(E_INVALIDARG);
|
2006-04-16 19:15:04 +00:00
|
|
|
}
|
|
|
|
if (contextInterface)
|
|
|
|
{
|
|
|
|
contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
|
|
|
|
contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
|
|
|
|
contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
|
|
|
|
NULL);
|
|
|
|
if (pdwContentType)
|
|
|
|
*pdwContentType = type;
|
|
|
|
ret = contextInterface->addContextToStore(hCertStore, context,
|
|
|
|
dwAddDisposition, ppvContext);
|
2014-04-22 15:10:43 +00:00
|
|
|
Context_Release(context_from_ptr(context));
|
2006-04-16 19:15:04 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = FALSE;
|
|
|
|
return ret;
|
|
|
|
}
|