wine/dlls/crypt32/object.c

2626 lines
91 KiB
C

/*
* crypt32 Crypt*Object functions
*
* Copyright 2007 Juan Lang
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "wincrypt.h"
#include "mssip.h"
#include "winuser.h"
#include "wintrust.h"
#include "crypt32_private.h"
#include "cryptres.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob)
{
BOOL ret = FALSE;
HANDLE file;
TRACE("%s\n", debugstr_w(fileName));
file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
if (file != INVALID_HANDLE_VALUE)
{
ret = TRUE;
blob->cbData = GetFileSize(file, NULL);
if (blob->cbData)
{
blob->pbData = CryptMemAlloc(blob->cbData);
if (blob->pbData)
{
DWORD read;
ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
}
}
CloseHandle(file);
}
TRACE("returning %d\n", ret);
return ret;
}
static BOOL CRYPT_QueryContextBlob(const CERT_BLOB *blob,
DWORD dwExpectedContentTypeFlags, HCERTSTORE store,
DWORD *contentType, const void **ppvContext)
{
BOOL ret = FALSE;
if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
{
ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
if (ret && contentType)
*contentType = CERT_QUERY_CONTENT_CERT;
}
if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
{
ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
if (ret && contentType)
*contentType = CERT_QUERY_CONTENT_CRL;
}
if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
{
ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
if (ret && contentType)
*contentType = CERT_QUERY_CONTENT_CTL;
}
return ret;
}
static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
HCERTSTORE *phCertStore, const void **ppvContext)
{
CERT_BLOB fileBlob;
const CERT_BLOB *blob;
HCERTSTORE store;
BOOL ret;
DWORD formatType = 0;
switch (dwObjectType)
{
case CERT_QUERY_OBJECT_FILE:
/* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
* just read the file directly
*/
ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
blob = &fileBlob;
break;
case CERT_QUERY_OBJECT_BLOB:
blob = pvObject;
ret = TRUE;
break;
default:
SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
ret = FALSE;
}
if (!ret)
return FALSE;
ret = FALSE;
store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
{
ret = CRYPT_QueryContextBlob(blob, dwExpectedContentTypeFlags, store,
pdwContentType, ppvContext);
if (ret)
formatType = CERT_QUERY_FORMAT_BINARY;
}
if (!ret &&
(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
{
CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
CRYPT_DATA_BLOB decoded;
while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
trimmed.cbData--;
ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
if (ret)
{
decoded.pbData = CryptMemAlloc(decoded.cbData);
if (decoded.pbData)
{
ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
&decoded.cbData, NULL, NULL);
if (ret)
{
ret = CRYPT_QueryContextBlob(&decoded,
dwExpectedContentTypeFlags, store, pdwContentType,
ppvContext);
if (ret)
formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
}
CryptMemFree(decoded.pbData);
}
else
ret = FALSE;
}
}
if (ret)
{
if (pdwMsgAndCertEncodingType)
*pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
if (pdwFormatType)
*pdwFormatType = formatType;
if (phCertStore)
*phCertStore = CertDuplicateStore(store);
}
CertCloseStore(store, 0);
if (blob == &fileBlob)
CryptMemFree(blob->pbData);
TRACE("returning %d\n", ret);
return ret;
}
static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
const void *pvObject, DWORD dwExpectedContentTypeFlags,
DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
HCERTSTORE *phCertStore, const void **ppvContext)
{
CERT_BLOB fileBlob;
const CERT_BLOB *blob;
const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
const void *context;
DWORD contextType;
BOOL ret;
switch (dwObjectType)
{
case CERT_QUERY_OBJECT_FILE:
/* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
* just read the file directly
*/
ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
blob = &fileBlob;
break;
case CERT_QUERY_OBJECT_BLOB:
blob = pvObject;
ret = TRUE;
break;
default:
SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
ret = FALSE;
}
if (!ret)
return FALSE;
ret = FALSE;
context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
if (context)
{
DWORD contentType, certStoreOffset;
ret = TRUE;
switch (contextType)
{
case CERT_STORE_CERTIFICATE_CONTEXT:
contextInterface = pCertInterface;
contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
if (!(dwExpectedContentTypeFlags &
CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
{
SetLastError(ERROR_INVALID_DATA);
ret = FALSE;
goto end;
}
break;
case CERT_STORE_CRL_CONTEXT:
contextInterface = pCRLInterface;
contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
if (!(dwExpectedContentTypeFlags &
CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
{
SetLastError(ERROR_INVALID_DATA);
ret = FALSE;
goto end;
}
break;
case CERT_STORE_CTL_CONTEXT:
contextInterface = pCTLInterface;
contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
if (!(dwExpectedContentTypeFlags &
CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
{
SetLastError(ERROR_INVALID_DATA);
ret = FALSE;
goto end;
}
break;
default:
SetLastError(ERROR_INVALID_DATA);
ret = FALSE;
goto end;
}
if (pdwMsgAndCertEncodingType)
*pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
if (pdwContentType)
*pdwContentType = contentType;
if (phCertStore)
*phCertStore = CertDuplicateStore(
*(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
if (ppvContext)
*ppvContext = contextInterface->duplicate(context);
}
end:
if (contextInterface && context)
contextInterface->free(context);
if (blob == &fileBlob)
CryptMemFree(blob->pbData);
TRACE("returning %d\n", ret);
return ret;
}
static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName,
DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
{
HANDLE file;
BOOL ret = FALSE;
TRACE("%s\n", debugstr_w(fileName));
file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
if (file != INVALID_HANDLE_VALUE)
{
HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
ret = CRYPT_ReadSerializedStoreFromFile(file, store);
if (ret)
{
if (pdwMsgAndCertEncodingType)
*pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
if (pdwContentType)
*pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
if (phCertStore)
*phCertStore = CertDuplicateStore(store);
}
CertCloseStore(store, 0);
CloseHandle(file);
}
TRACE("returning %d\n", ret);
return ret;
}
static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
{
HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, NULL);
BOOL ret;
TRACE("(%d, %p)\n", blob->cbData, blob->pbData);
ret = CRYPT_ReadSerializedStoreFromBlob(blob, store);
if (ret)
{
if (pdwMsgAndCertEncodingType)
*pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
if (pdwContentType)
*pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
if (phCertStore)
*phCertStore = CertDuplicateStore(store);
}
CertCloseStore(store, 0);
TRACE("returning %d\n", ret);
return ret;
}
static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
{
switch (dwObjectType)
{
case CERT_QUERY_OBJECT_FILE:
return CRYPT_QuerySerializedStoreFromFile(pvObject,
pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
case CERT_QUERY_OBJECT_BLOB:
return CRYPT_QuerySerializedStoreFromBlob(pvObject,
pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
default:
FIXME("unimplemented for type %d\n", dwObjectType);
SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
return FALSE;
}
}
static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob,
DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
{
DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
BOOL ret = FALSE;
HCRYPTMSG msg;
if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
{
ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
if (ret)
{
DWORD type, len = sizeof(type);
ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
if (ret)
{
if (type != CMSG_SIGNED)
{
SetLastError(ERROR_INVALID_DATA);
ret = FALSE;
}
}
}
if (!ret)
{
CryptMsgClose(msg);
msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL,
NULL);
if (msg)
{
ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
if (!ret)
{
CryptMsgClose(msg);
msg = NULL;
}
}
}
}
if (ret)
{
if (pdwMsgAndCertEncodingType)
*pdwMsgAndCertEncodingType = encodingType;
if (pdwContentType)
*pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
if (phMsg)
*phMsg = msg;
}
return ret;
}
static BOOL CRYPT_QueryUnsignedMessage(const CRYPT_DATA_BLOB *blob,
DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
{
DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
BOOL ret = FALSE;
HCRYPTMSG msg;
if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
{
ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
if (ret)
{
DWORD type, len = sizeof(type);
ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
if (ret)
{
if (type != CMSG_DATA)
{
SetLastError(ERROR_INVALID_DATA);
ret = FALSE;
}
}
}
if (!ret)
{
CryptMsgClose(msg);
msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0,
NULL, NULL);
if (msg)
{
ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
if (!ret)
{
CryptMsgClose(msg);
msg = NULL;
}
}
}
}
if (ret)
{
if (pdwMsgAndCertEncodingType)
*pdwMsgAndCertEncodingType = encodingType;
if (pdwContentType)
*pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
if (phMsg)
*phMsg = msg;
}
return ret;
}
/* Used to decode non-embedded messages */
static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
{
CERT_BLOB fileBlob;
const CERT_BLOB *blob;
BOOL ret;
HCRYPTMSG msg = NULL;
DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
DWORD formatType = 0;
TRACE("(%d, %p, %08x, %08x, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
phMsg);
switch (dwObjectType)
{
case CERT_QUERY_OBJECT_FILE:
/* This isn't an embedded PKCS7 message, so just read the file
* directly
*/
ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
blob = &fileBlob;
break;
case CERT_QUERY_OBJECT_BLOB:
blob = pvObject;
ret = TRUE;
break;
default:
SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
ret = FALSE;
}
if (!ret)
return FALSE;
ret = FALSE;
if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
{
/* Try it first as a signed message */
if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
ret = CRYPT_QuerySignedMessage(blob, pdwMsgAndCertEncodingType,
pdwContentType, &msg);
/* Failing that, try as an unsigned message */
if (!ret &&
(dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
ret = CRYPT_QueryUnsignedMessage(blob, pdwMsgAndCertEncodingType,
pdwContentType, &msg);
if (ret)
formatType = CERT_QUERY_FORMAT_BINARY;
}
if (!ret &&
(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
{
CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
CRYPT_DATA_BLOB decoded;
while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
trimmed.cbData--;
ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
if (ret)
{
decoded.pbData = CryptMemAlloc(decoded.cbData);
if (decoded.pbData)
{
ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
&decoded.cbData, NULL, NULL);
if (ret)
{
/* Try it first as a signed message */
if (dwExpectedContentTypeFlags &
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
ret = CRYPT_QuerySignedMessage(&decoded,
pdwMsgAndCertEncodingType, pdwContentType, &msg);
/* Failing that, try as an unsigned message */
if (!ret && (dwExpectedContentTypeFlags &
CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
ret = CRYPT_QueryUnsignedMessage(&decoded,
pdwMsgAndCertEncodingType, pdwContentType, &msg);
if (ret)
formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
}
CryptMemFree(decoded.pbData);
}
else
ret = FALSE;
}
if (!ret && !(blob->cbData % sizeof(WCHAR)))
{
CRYPT_DATA_BLOB decoded;
LPWSTR str = (LPWSTR)blob->pbData;
DWORD strLen = blob->cbData / sizeof(WCHAR);
/* Try again, assuming the input string is UTF-16 base64 */
while (strLen && !str[strLen - 1])
strLen--;
ret = CryptStringToBinaryW(str, strLen, CRYPT_STRING_BASE64_ANY,
NULL, &decoded.cbData, NULL, NULL);
if (ret)
{
decoded.pbData = CryptMemAlloc(decoded.cbData);
if (decoded.pbData)
{
ret = CryptStringToBinaryW(str, strLen,
CRYPT_STRING_BASE64_ANY, decoded.pbData, &decoded.cbData,
NULL, NULL);
if (ret)
{
/* Try it first as a signed message */
if (dwExpectedContentTypeFlags &
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
ret = CRYPT_QuerySignedMessage(&decoded,
pdwMsgAndCertEncodingType, pdwContentType, &msg);
/* Failing that, try as an unsigned message */
if (!ret && (dwExpectedContentTypeFlags &
CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
ret = CRYPT_QueryUnsignedMessage(&decoded,
pdwMsgAndCertEncodingType, pdwContentType, &msg);
if (ret)
formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
}
CryptMemFree(decoded.pbData);
}
else
ret = FALSE;
}
}
}
if (ret)
{
if (pdwFormatType)
*pdwFormatType = formatType;
if (phCertStore)
*phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
0, msg);
if (phMsg)
*phMsg = msg;
else
CryptMsgClose(msg);
}
if (blob == &fileBlob)
CryptMemFree(blob->pbData);
TRACE("returning %d\n", ret);
return ret;
}
static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
const void *pvObject, DWORD dwExpectedContentTypeFlags,
DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
{
HANDLE file;
GUID subject;
BOOL ret = FALSE;
TRACE("%s\n", debugstr_w(pvObject));
if (dwObjectType != CERT_QUERY_OBJECT_FILE)
{
WARN("don't know what to do for type %d embedded signed messages\n",
dwObjectType);
SetLastError(E_INVALIDARG);
return FALSE;
}
file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file != INVALID_HANDLE_VALUE)
{
ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject);
if (ret)
{
SIP_DISPATCH_INFO sip;
memset(&sip, 0, sizeof(sip));
sip.cbSize = sizeof(sip);
ret = CryptSIPLoad(&subject, 0, &sip);
if (ret)
{
SIP_SUBJECTINFO subjectInfo;
CERT_BLOB blob;
DWORD encodingType;
memset(&subjectInfo, 0, sizeof(subjectInfo));
subjectInfo.cbSize = sizeof(subjectInfo);
subjectInfo.pgSubjectType = &subject;
subjectInfo.hFile = file;
subjectInfo.pwsFileName = pvObject;
ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
NULL);
if (ret)
{
blob.pbData = CryptMemAlloc(blob.cbData);
if (blob.pbData)
{
ret = sip.pfGet(&subjectInfo, &encodingType, 0,
&blob.cbData, blob.pbData);
if (ret)
{
ret = CRYPT_QueryMessageObject(
CERT_QUERY_OBJECT_BLOB, &blob,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
CERT_QUERY_FORMAT_FLAG_BINARY,
pdwMsgAndCertEncodingType, NULL, NULL,
phCertStore, phMsg);
if (ret && pdwContentType)
*pdwContentType =
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED;
}
CryptMemFree(blob.pbData);
}
else
{
SetLastError(ERROR_OUTOFMEMORY);
ret = FALSE;
}
}
}
}
CloseHandle(file);
}
TRACE("returning %d\n", ret);
return ret;
}
BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
const void **ppvContext)
{
static const DWORD unimplementedTypes =
CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
BOOL ret = TRUE;
TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
dwObjectType, pvObject, dwExpectedContentTypeFlags,
dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
if (dwObjectType != CERT_QUERY_OBJECT_BLOB &&
dwObjectType != CERT_QUERY_OBJECT_FILE)
{
WARN("unsupported type %d\n", dwObjectType);
SetLastError(E_INVALIDARG);
return FALSE;
}
if (!pvObject)
{
WARN("missing required argument\n");
SetLastError(E_INVALIDARG);
return FALSE;
}
if (dwExpectedContentTypeFlags & unimplementedTypes)
WARN("unimplemented for types %08x\n",
dwExpectedContentTypeFlags & unimplementedTypes);
if (pdwFormatType)
*pdwFormatType = CERT_QUERY_FORMAT_BINARY;
if (phCertStore)
*phCertStore = NULL;
if (phMsg)
*phMsg = NULL;
if (ppvContext)
*ppvContext = NULL;
ret = FALSE;
if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
(dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
(dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
{
ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
ppvContext);
}
if (!ret &&
(dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
{
ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
}
if (!ret &&
((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
(dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
(dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
{
ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
phCertStore, ppvContext);
}
if (!ret &&
((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
(dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
{
ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
phCertStore, phMsg);
}
if (!ret &&
(dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
{
ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
phCertStore, phMsg);
}
if (!ret)
SetLastError(CRYPT_E_NO_MATCH);
TRACE("returning %d\n", ret);
return ret;
}
static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
BOOL ret;
DWORD bytesNeeded;
if (cbEncoded)
bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
else
bytesNeeded = sizeof(WCHAR);
if (!pbFormat)
{
*pcbFormat = bytesNeeded;
ret = TRUE;
}
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
static const WCHAR endFmt[] = { '%','0','2','x',0 };
DWORD i;
LPWSTR ptr = pbFormat;
*pcbFormat = bytesNeeded;
if (cbEncoded)
{
for (i = 0; i < cbEncoded; i++)
{
if (i < cbEncoded - 1)
ptr += sprintfW(ptr, fmt, pbEncoded[i]);
else
ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
}
}
else
*ptr = 0;
ret = TRUE;
}
return ret;
}
#define MAX_STRING_RESOURCE_LEN 128
static const WCHAR commaSpace[] = { ',',' ',0 };
struct BitToString
{
BYTE bit;
int id;
WCHAR str[MAX_STRING_RESOURCE_LEN];
};
static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
{
DWORD bytesNeeded = sizeof(WCHAR);
int i;
BOOL ret = TRUE, localFirst = *first;
for (i = 0; i < mapEntries; i++)
if (bits & map[i].bit)
{
if (!localFirst)
bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR);
localFirst = FALSE;
bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR);
}
if (!pbFormat)
{
*first = localFirst;
*pcbFormat = bytesNeeded;
}
else if (*pcbFormat < bytesNeeded)
{
*first = localFirst;
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
localFirst = *first;
*pcbFormat = bytesNeeded;
for (i = 0; i < mapEntries; i++)
if (bits & map[i].bit)
{
if (!localFirst)
{
strcpyW(str, commaSpace);
str += strlenW(commaSpace);
}
localFirst = FALSE;
strcpyW(str, map[i].str);
str += strlenW(map[i].str);
}
*first = localFirst;
}
return ret;
}
static struct BitToString keyUsageByte0Map[] = {
{ CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
{ CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
{ CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
{ CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
{ CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
{ CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
{ CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
{ CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
{ CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
};
static struct BitToString keyUsageByte1Map[] = {
{ CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
};
static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
DWORD size;
CRYPT_BIT_BLOB *bits;
BOOL ret;
if (!cbEncoded)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
{
WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
DWORD bytesNeeded = sizeof(WCHAR);
LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
if (!bits->cbData || bits->cbData > 2)
{
bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
*pcbFormat = bytesNeeded;
strcpyW(str, infoNotAvailable);
}
}
else
{
static BOOL stringsLoaded = FALSE;
int i;
DWORD bitStringLen;
BOOL first = TRUE;
if (!stringsLoaded)
{
for (i = 0;
i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]);
i++)
LoadStringW(hInstance, keyUsageByte0Map[i].id,
keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
for (i = 0;
i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]);
i++)
LoadStringW(hInstance, keyUsageByte1Map[i].id,
keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
stringsLoaded = TRUE;
}
CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
NULL, &bitStringLen, &first);
bytesNeeded += bitStringLen;
if (bits->cbData == 2)
{
CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
NULL, &bitStringLen, &first);
bytesNeeded += bitStringLen;
}
bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
bits->cbData, NULL, &size);
bytesNeeded += size;
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
bitStringLen = bytesNeeded;
first = TRUE;
CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
str, &bitStringLen, &first);
str += bitStringLen / sizeof(WCHAR) - 1;
if (bits->cbData == 2)
{
bitStringLen = bytesNeeded;
CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
str, &bitStringLen, &first);
str += bitStringLen / sizeof(WCHAR) - 1;
}
*str++ = ' ';
*str++ = '(';
CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
bits->cbData, str, &size);
str += size / sizeof(WCHAR) - 1;
*str++ = ')';
*str = 0;
}
}
LocalFree(bits);
}
return ret;
}
static const WCHAR crlf[] = { '\r','\n',0 };
static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
DWORD size;
CERT_BASIC_CONSTRAINTS2_INFO *info;
BOOL ret;
if (!cbEncoded)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
{
static const WCHAR pathFmt[] = { '%','d',0 };
static BOOL stringsLoaded = FALSE;
DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
LPCWSTR sep, subjectType;
DWORD sepLen;
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
sep = crlf;
sepLen = strlenW(crlf) * sizeof(WCHAR);
}
else
{
sep = commaSpace;
sepLen = strlenW(commaSpace) * sizeof(WCHAR);
}
if (!stringsLoaded)
{
LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
subjectTypeEndCert,
sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
stringsLoaded = TRUE;
}
bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
if (info->fCA)
subjectType = subjectTypeCA;
else
subjectType = subjectTypeEndCert;
bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
bytesNeeded += sepLen;
bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
if (info->fPathLenConstraint)
sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
else
LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
sizeof(pathLength) / sizeof(pathLength[0]));
bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
*pcbFormat = bytesNeeded;
strcpyW(str, subjectTypeHeader);
str += strlenW(subjectTypeHeader);
strcpyW(str, subjectType);
str += strlenW(subjectType);
strcpyW(str, sep);
str += sepLen / sizeof(WCHAR);
strcpyW(str, pathLengthHeader);
str += strlenW(pathLengthHeader);
strcpyW(str, pathLength);
str += strlenW(pathLength);
}
LocalFree(info);
}
return ret;
}
static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id,
LPWSTR str, DWORD *pcbStr)
{
WCHAR buf[MAX_STRING_RESOURCE_LEN];
DWORD bytesNeeded;
BOOL ret;
LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
blob->pbData, blob->cbData, NULL, &bytesNeeded);
bytesNeeded += strlenW(buf) * sizeof(WCHAR);
if (!str)
{
*pcbStr = bytesNeeded;
ret = TRUE;
}
else if (*pcbStr < bytesNeeded)
{
*pcbStr = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
*pcbStr = bytesNeeded;
strcpyW(str, buf);
str += strlenW(str);
bytesNeeded -= strlenW(str) * sizeof(WCHAR);
ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
blob->pbData, blob->cbData, str, &bytesNeeded);
}
return ret;
}
static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str,
DWORD *pcbStr)
{
return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
}
static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str,
DWORD *pcbStr)
{
return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
str, pcbStr);
}
static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
{
BOOL ret;
WCHAR buf[MAX_STRING_RESOURCE_LEN];
WCHAR mask[MAX_STRING_RESOURCE_LEN];
WCHAR ipAddrBuf[32];
WCHAR maskBuf[16];
DWORD bytesNeeded = sizeof(WCHAR);
DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
switch (entry->dwAltNameChoice)
{
case CERT_ALT_NAME_RFC822_NAME:
LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
sizeof(buf) / sizeof(buf[0]));
bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
ret = TRUE;
break;
case CERT_ALT_NAME_DNS_NAME:
LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
sizeof(buf) / sizeof(buf[0]));
bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
ret = TRUE;
break;
case CERT_ALT_NAME_DIRECTORY_NAME:
{
DWORD directoryNameLen;
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
strType |= CERT_NAME_STR_CRLF_FLAG;
directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf,
sizeof(buf) / sizeof(buf[0]));
bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR);
else
bytesNeeded += sizeof(WCHAR); /* '=' */
ret = TRUE;
break;
}
case CERT_ALT_NAME_URL:
LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
sizeof(buf) / sizeof(buf[0]));
bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
ret = TRUE;
break;
case CERT_ALT_NAME_IP_ADDRESS:
{
static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
'%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
};
static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
'.','%','d',0 };
LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
sizeof(buf) / sizeof(buf[0]));
if (entry->u.IPAddress.cbData == 8)
{
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
sizeof(mask) / sizeof(mask[0]));
bytesNeeded += strlenW(mask) * sizeof(WCHAR);
sprintfW(ipAddrBuf, ipAddrFmt,
entry->u.IPAddress.pbData[0],
entry->u.IPAddress.pbData[1],
entry->u.IPAddress.pbData[2],
entry->u.IPAddress.pbData[3]);
bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
/* indent again, for the mask line */
bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
sprintfW(maskBuf, ipAddrFmt,
entry->u.IPAddress.pbData[4],
entry->u.IPAddress.pbData[5],
entry->u.IPAddress.pbData[6],
entry->u.IPAddress.pbData[7]);
bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
}
else
{
sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
entry->u.IPAddress.pbData[0],
entry->u.IPAddress.pbData[1],
entry->u.IPAddress.pbData[2],
entry->u.IPAddress.pbData[3],
entry->u.IPAddress.pbData[4],
entry->u.IPAddress.pbData[5],
entry->u.IPAddress.pbData[6],
entry->u.IPAddress.pbData[7]);
bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
}
ret = TRUE;
}
else
{
FIXME("unknown IP address format (%d bytes)\n",
entry->u.IPAddress.cbData);
ret = FALSE;
}
break;
}
default:
FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
ret = FALSE;
}
if (ret)
{
bytesNeeded += strlenW(buf) * sizeof(WCHAR);
if (!str)
*pcbStr = bytesNeeded;
else if (*pcbStr < bytesNeeded)
{
*pcbStr = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
DWORD i;
*pcbStr = bytesNeeded;
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
for (i = 0; i < indentLevel; i++)
{
strcpyW(str, indent);
str += strlenW(indent);
}
}
strcpyW(str, buf);
str += strlenW(str);
switch (entry->dwAltNameChoice)
{
case CERT_ALT_NAME_RFC822_NAME:
case CERT_ALT_NAME_DNS_NAME:
case CERT_ALT_NAME_URL:
strcpyW(str, entry->u.pwszURL);
break;
case CERT_ALT_NAME_DIRECTORY_NAME:
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
strcpyW(str, colonCrlf);
str += strlenW(colonCrlf);
}
else
*str++ = '=';
cert_name_to_str_with_indent(X509_ASN_ENCODING,
indentLevel + 1, &entry->u.DirectoryName, strType, str,
bytesNeeded / sizeof(WCHAR));
break;
case CERT_ALT_NAME_IP_ADDRESS:
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
strcpyW(str, ipAddrBuf);
str += strlenW(ipAddrBuf);
strcpyW(str, crlf);
str += strlenW(crlf);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
for (i = 0; i < indentLevel; i++)
{
strcpyW(str, indent);
str += strlenW(indent);
}
}
strcpyW(str, mask);
str += strlenW(mask);
strcpyW(str, maskBuf);
}
else
strcpyW(str, ipAddrBuf);
break;
}
}
}
return ret;
}
static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
{
DWORD i, size, bytesNeeded = 0;
BOOL ret = TRUE;
LPCWSTR sep;
DWORD sepLen;
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
sep = crlf;
sepLen = strlenW(crlf) * sizeof(WCHAR);
}
else
{
sep = commaSpace;
sepLen = strlenW(commaSpace) * sizeof(WCHAR);
}
for (i = 0; ret && i < name->cAltEntry; i++)
{
ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
&name->rgAltEntry[i], NULL, &size);
if (ret)
{
bytesNeeded += size - sizeof(WCHAR);
if (i < name->cAltEntry - 1)
bytesNeeded += sepLen;
}
}
if (ret)
{
bytesNeeded += sizeof(WCHAR);
if (!str)
*pcbStr = bytesNeeded;
else if (*pcbStr < bytesNeeded)
{
*pcbStr = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
*pcbStr = bytesNeeded;
for (i = 0; ret && i < name->cAltEntry; i++)
{
ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
&name->rgAltEntry[i], str, &size);
if (ret)
{
str += size / sizeof(WCHAR) - 1;
if (i < name->cAltEntry - 1)
{
strcpyW(str, sep);
str += sepLen / sizeof(WCHAR);
}
}
}
}
}
return ret;
}
static const WCHAR colonSep[] = { ':',' ',0 };
static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
BOOL ret;
CERT_ALT_NAME_INFO *info;
DWORD size;
if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
{
ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
LocalFree(info);
}
return ret;
}
static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
{
WCHAR buf[MAX_STRING_RESOURCE_LEN];
DWORD bytesNeeded, sepLen;
LPCWSTR sep;
BOOL ret;
LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
&bytesNeeded);
bytesNeeded += strlenW(buf) * sizeof(WCHAR);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
sep = colonCrlf;
sepLen = strlenW(colonCrlf) * sizeof(WCHAR);
}
else
{
sep = colonSep;
sepLen = strlenW(colonSep) * sizeof(WCHAR);
}
bytesNeeded += sepLen;
if (ret)
{
if (!str)
*pcbStr = bytesNeeded;
else if (*pcbStr < bytesNeeded)
{
*pcbStr = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
*pcbStr = bytesNeeded;
strcpyW(str, buf);
bytesNeeded -= strlenW(str) * sizeof(WCHAR);
str += strlenW(str);
strcpyW(str, sep);
str += sepLen / sizeof(WCHAR);
ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
&bytesNeeded);
}
}
return ret;
}
static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
CERT_AUTHORITY_KEY_ID2_INFO *info;
DWORD size;
BOOL ret = FALSE;
if (!cbEncoded)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
{
DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
LPCWSTR sep;
DWORD sepLen;
BOOL needSeparator = FALSE;
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
sep = crlf;
sepLen = strlenW(crlf) * sizeof(WCHAR);
}
else
{
sep = commaSpace;
sepLen = strlenW(commaSpace) * sizeof(WCHAR);
}
if (info->KeyId.cbData)
{
needSeparator = TRUE;
ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
if (ret)
{
/* don't include NULL-terminator more than once */
bytesNeeded += size - sizeof(WCHAR);
}
}
if (info->AuthorityCertIssuer.cAltEntry)
{
if (needSeparator)
bytesNeeded += sepLen;
needSeparator = TRUE;
ret = CRYPT_FormatCertIssuer(dwFormatStrType,
&info->AuthorityCertIssuer, NULL, &size);
if (ret)
{
/* don't include NULL-terminator more than once */
bytesNeeded += size - sizeof(WCHAR);
}
}
if (info->AuthorityCertSerialNumber.cbData)
{
if (needSeparator)
bytesNeeded += sepLen;
ret = CRYPT_FormatCertSerialNumber(
&info->AuthorityCertSerialNumber, NULL, &size);
if (ret)
{
/* don't include NULL-terminator more than once */
bytesNeeded += size - sizeof(WCHAR);
}
}
if (ret)
{
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
*pcbFormat = bytesNeeded;
needSeparator = FALSE;
if (info->KeyId.cbData)
{
needSeparator = TRUE;
/* Overestimate size available, it's already been checked
* above.
*/
size = bytesNeeded;
ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
if (ret)
str += size / sizeof(WCHAR) - 1;
}
if (info->AuthorityCertIssuer.cAltEntry)
{
if (needSeparator)
{
strcpyW(str, sep);
str += sepLen / sizeof(WCHAR);
}
needSeparator = TRUE;
/* Overestimate size available, it's already been checked
* above.
*/
size = bytesNeeded;
ret = CRYPT_FormatCertIssuer(dwFormatStrType,
&info->AuthorityCertIssuer, str, &size);
if (ret)
str += size / sizeof(WCHAR) - 1;
}
if (info->AuthorityCertSerialNumber.cbData)
{
if (needSeparator)
{
strcpyW(str, sep);
str += sepLen / sizeof(WCHAR);
}
/* Overestimate size available, it's already been checked
* above.
*/
size = bytesNeeded;
ret = CRYPT_FormatCertSerialNumber(
&info->AuthorityCertSerialNumber, str, &size);
}
}
}
LocalFree(info);
}
return ret;
}
static WCHAR aia[MAX_STRING_RESOURCE_LEN];
static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
CERT_AUTHORITY_INFO_ACCESS *info;
DWORD size;
BOOL ret = FALSE;
if (!cbEncoded)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
NULL, &info, &size)))
{
DWORD bytesNeeded = sizeof(WCHAR);
if (!info->cAccDescr)
{
WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
*pcbFormat = bytesNeeded;
strcpyW(pbFormat, infoNotAvailable);
}
}
else
{
static const WCHAR numFmt[] = { '%','d',0 };
static const WCHAR equal[] = { '=',0 };
static BOOL stringsLoaded = FALSE;
DWORD i;
LPCWSTR headingSep, accessMethodSep, locationSep;
WCHAR accessDescrNum[11];
if (!stringsLoaded)
{
LoadStringW(hInstance, IDS_AIA, aia,
sizeof(aia) / sizeof(aia[0]));
LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
sizeof(accessMethod) / sizeof(accessMethod[0]));
LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
sizeof(ocsp) / sizeof(ocsp[0]));
LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
sizeof(caIssuers) / sizeof(caIssuers[0]));
LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
sizeof(unknown) / sizeof(unknown[0]));
LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
sizeof(accessLocation) / sizeof(accessLocation[0]));
stringsLoaded = TRUE;
}
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
headingSep = crlf;
accessMethodSep = crlf;
locationSep = colonCrlf;
}
else
{
headingSep = colonSep;
accessMethodSep = commaSpace;
locationSep = equal;
}
for (i = 0; ret && i < info->cAccDescr; i++)
{
/* Heading */
bytesNeeded += sizeof(WCHAR); /* left bracket */
sprintfW(accessDescrNum, numFmt, i + 1);
bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
bytesNeeded += sizeof(WCHAR); /* right bracket */
bytesNeeded += strlenW(aia) * sizeof(WCHAR);
bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
/* Access method */
bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
bytesNeeded += strlenW(indent) * sizeof(WCHAR);
if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
szOID_PKIX_OCSP))
bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
szOID_PKIX_CA_ISSUERS))
bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
else
bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
bytesNeeded += sizeof(WCHAR); /* space */
bytesNeeded += sizeof(WCHAR); /* left paren */
bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
* sizeof(WCHAR);
bytesNeeded += sizeof(WCHAR); /* right paren */
/* Delimiter between access method and location */
bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
bytesNeeded += strlenW(indent) * sizeof(WCHAR);
bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
&info->rgAccDescr[i].AccessLocation, NULL, &size);
if (ret)
bytesNeeded += size - sizeof(WCHAR);
/* Need extra delimiter between access method entries */
if (i < info->cAccDescr - 1)
bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
}
if (ret)
{
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
DWORD altNameEntrySize;
*pcbFormat = bytesNeeded;
for (i = 0; ret && i < info->cAccDescr; i++)
{
LPCSTR oidPtr;
*str++ = '[';
sprintfW(accessDescrNum, numFmt, i + 1);
strcpyW(str, accessDescrNum);
str += strlenW(accessDescrNum);
*str++ = ']';
strcpyW(str, aia);
str += strlenW(aia);
strcpyW(str, headingSep);
str += strlenW(headingSep);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
strcpyW(str, indent);
str += strlenW(indent);
}
strcpyW(str, accessMethod);
str += strlenW(accessMethod);
if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
szOID_PKIX_OCSP))
{
strcpyW(str, ocsp);
str += strlenW(ocsp);
}
else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
szOID_PKIX_CA_ISSUERS))
{
strcpyW(str, caIssuers);
str += strlenW(caIssuers);
}
else
{
strcpyW(str, unknown);
str += strlenW(unknown);
}
*str++ = ' ';
*str++ = '(';
for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
*oidPtr; oidPtr++, str++)
*str = *oidPtr;
*str++ = ')';
strcpyW(str, accessMethodSep);
str += strlenW(accessMethodSep);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
strcpyW(str, indent);
str += strlenW(indent);
}
strcpyW(str, accessLocation);
str += strlenW(accessLocation);
strcpyW(str, locationSep);
str += strlenW(locationSep);
/* This overestimates the size available, but that
* won't matter since we checked earlier whether enough
* space for the entire string was available.
*/
altNameEntrySize = bytesNeeded;
ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
&info->rgAccDescr[i].AccessLocation, str,
&altNameEntrySize);
if (ret)
str += altNameEntrySize / sizeof(WCHAR) - 1;
if (i < info->cAccDescr - 1)
{
strcpyW(str, accessMethodSep);
str += strlenW(accessMethodSep);
}
}
}
}
}
LocalFree(info);
}
return ret;
}
static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
struct reason_map_entry
{
BYTE reasonBit;
LPWSTR reason;
int id;
};
static struct reason_map_entry reason_map[] = {
{ CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
{ CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
{ CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
IDS_REASON_AFFILIATION_CHANGED },
{ CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
{ CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
IDS_REASON_CESSATION_OF_OPERATION },
{ CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
IDS_REASON_CERTIFICATE_HOLD },
};
static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
{
static const WCHAR sep[] = { ',',' ',0 };
static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
static BOOL stringsLoaded = FALSE;
int i, numReasons = 0;
BOOL ret = TRUE;
DWORD bytesNeeded = sizeof(WCHAR);
WCHAR bits[6];
if (!stringsLoaded)
{
for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
MAX_STRING_RESOURCE_LEN);
stringsLoaded = TRUE;
}
/* No need to check reasonFlags->cbData, we already know it's positive.
* Ignore any other bytes, as they're for undefined bits.
*/
for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
{
if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
{
bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
if (numReasons++)
bytesNeeded += strlenW(sep) * sizeof(WCHAR);
}
}
sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
bytesNeeded += strlenW(bits);
if (!str)
*pcbStr = bytesNeeded;
else if (*pcbStr < bytesNeeded)
{
*pcbStr = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
*pcbStr = bytesNeeded;
for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
{
if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
{
strcpyW(str, reason_map[i].reason);
str += strlenW(reason_map[i].reason);
if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
numReasons)
{
strcpyW(str, sep);
str += strlenW(sep);
}
}
}
strcpyW(str, bits);
}
return ret;
}
static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
static WCHAR reason[MAX_STRING_RESOURCE_LEN];
static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
CRL_DIST_POINTS_INFO *info;
DWORD size;
BOOL ret = FALSE;
if (!cbEncoded)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
{
static const WCHAR numFmt[] = { '%','d',0 };
static const WCHAR colon[] = { ':',0 };
static BOOL stringsLoaded = FALSE;
DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
BOOL haveAnEntry = FALSE;
LPCWSTR headingSep, nameSep;
WCHAR distPointNum[11];
DWORD i;
if (!stringsLoaded)
{
LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
sizeof(distPointName) / sizeof(distPointName[0]));
LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
sizeof(fullName) / sizeof(fullName[0]));
LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
sizeof(rdnName) / sizeof(rdnName[0]));
LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
sizeof(reason) / sizeof(reason[0]));
LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
sizeof(issuer) / sizeof(issuer[0]));
stringsLoaded = TRUE;
}
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
headingSep = crlf;
nameSep = colonCrlf;
}
else
{
headingSep = colonSep;
nameSep = colon;
}
for (i = 0; ret && i < info->cDistPoint; i++)
{
CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
if (distPoint->DistPointName.dwDistPointNameChoice !=
CRL_DIST_POINT_NO_NAME)
{
bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
if (distPoint->DistPointName.dwDistPointNameChoice ==
CRL_DIST_POINT_FULL_NAME)
bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
else
bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
/* The indent level (3) is higher than when used as the issuer,
* because the name is subordinate to the name type (full vs.
* RDN.)
*/
ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
&distPoint->DistPointName.u.FullName, NULL, &size);
if (ret)
bytesNeeded += size - sizeof(WCHAR);
haveAnEntry = TRUE;
}
else if (distPoint->ReasonFlags.cbData)
{
bytesNeeded += strlenW(reason) * sizeof(WCHAR);
ret = CRYPT_FormatReason(dwFormatStrType,
&distPoint->ReasonFlags, NULL, &size);
if (ret)
bytesNeeded += size - sizeof(WCHAR);
haveAnEntry = TRUE;
}
else if (distPoint->CRLIssuer.cAltEntry)
{
bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
&distPoint->CRLIssuer, NULL, &size);
if (ret)
bytesNeeded += size - sizeof(WCHAR);
haveAnEntry = TRUE;
}
if (haveAnEntry)
{
bytesNeeded += sizeof(WCHAR); /* left bracket */
sprintfW(distPointNum, numFmt, i + 1);
bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
bytesNeeded += sizeof(WCHAR); /* right bracket */
bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
bytesNeeded += strlenW(indent) * sizeof(WCHAR);
}
}
if (!haveAnEntry)
{
WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
*pcbFormat = bytesNeeded;
strcpyW(pbFormat, infoNotAvailable);
}
}
else
{
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
*pcbFormat = bytesNeeded;
for (i = 0; ret && i < info->cDistPoint; i++)
{
CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
*str++ = '[';
sprintfW(distPointNum, numFmt, i + 1);
strcpyW(str, distPointNum);
str += strlenW(distPointNum);
*str++ = ']';
strcpyW(str, crlDistPoint);
str += strlenW(crlDistPoint);
strcpyW(str, headingSep);
str += strlenW(headingSep);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
strcpyW(str, indent);
str += strlenW(indent);
}
if (distPoint->DistPointName.dwDistPointNameChoice !=
CRL_DIST_POINT_NO_NAME)
{
DWORD altNameSize = bytesNeeded;
strcpyW(str, distPointName);
str += strlenW(distPointName);
strcpyW(str, nameSep);
str += strlenW(nameSep);
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
strcpyW(str, indent);
str += strlenW(indent);
strcpyW(str, indent);
str += strlenW(indent);
}
if (distPoint->DistPointName.dwDistPointNameChoice ==
CRL_DIST_POINT_FULL_NAME)
{
strcpyW(str, fullName);
str += strlenW(fullName);
}
else
{
strcpyW(str, rdnName);
str += strlenW(rdnName);
}
strcpyW(str, nameSep);
str += strlenW(nameSep);
ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
&distPoint->DistPointName.u.FullName, str,
&altNameSize);
if (ret)
str += altNameSize / sizeof(WCHAR) - 1;
}
else if (distPoint->ReasonFlags.cbData)
{
DWORD reasonSize = bytesNeeded;
strcpyW(str, reason);
str += strlenW(reason);
ret = CRYPT_FormatReason(dwFormatStrType,
&distPoint->ReasonFlags, str, &reasonSize);
if (ret)
str += reasonSize / sizeof(WCHAR) - 1;
}
else if (distPoint->CRLIssuer.cAltEntry)
{
DWORD crlIssuerSize = bytesNeeded;
strcpyW(str, issuer);
str += strlenW(issuer);
strcpyW(str, nameSep);
str += strlenW(nameSep);
ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
&distPoint->CRLIssuer, str,
&crlIssuerSize);
if (ret)
str += crlIssuerSize / sizeof(WCHAR) - 1;
}
}
}
}
LocalFree(info);
}
return ret;
}
static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
CERT_ENHKEY_USAGE *usage;
DWORD size;
BOOL ret = FALSE;
if (!cbEncoded)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
{
WCHAR unknown[MAX_STRING_RESOURCE_LEN];
DWORD i;
DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
LPCWSTR sep;
DWORD sepLen;
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
sep = crlf;
sepLen = strlenW(crlf) * sizeof(WCHAR);
}
else
{
sep = commaSpace;
sepLen = strlenW(commaSpace) * sizeof(WCHAR);
}
LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
sizeof(unknown) / sizeof(unknown[0]));
for (i = 0; i < usage->cUsageIdentifier; i++)
{
PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
if (info)
bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
else
bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
bytesNeeded += sizeof(WCHAR); /* space */
bytesNeeded += sizeof(WCHAR); /* left paren */
bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
sizeof(WCHAR);
bytesNeeded += sizeof(WCHAR); /* right paren */
if (i < usage->cUsageIdentifier - 1)
bytesNeeded += sepLen;
}
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
*pcbFormat = bytesNeeded;
for (i = 0; i < usage->cUsageIdentifier; i++)
{
PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
usage->rgpszUsageIdentifier[i],
CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
LPCSTR oidPtr;
if (info)
{
strcpyW(str, info->pwszName);
str += strlenW(info->pwszName);
}
else
{
strcpyW(str, unknown);
str += strlenW(unknown);
}
*str++ = ' ';
*str++ = '(';
for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
*str++ = *oidPtr;
*str++ = ')';
*str = 0;
if (i < usage->cUsageIdentifier - 1)
{
strcpyW(str, sep);
str += sepLen / sizeof(WCHAR);
}
}
}
LocalFree(usage);
}
return ret;
}
static struct BitToString netscapeCertTypeMap[] = {
{ NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
{ NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
{ NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
{ NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
{ NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
{ NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
{ NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
};
static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
DWORD size;
CRYPT_BIT_BLOB *bits;
BOOL ret;
if (!cbEncoded)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
{
WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
DWORD bytesNeeded = sizeof(WCHAR);
LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
if (!bits->cbData || bits->cbData > 1)
{
bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
*pcbFormat = bytesNeeded;
strcpyW(str, infoNotAvailable);
}
}
else
{
static BOOL stringsLoaded = FALSE;
int i;
DWORD bitStringLen;
BOOL first = TRUE;
if (!stringsLoaded)
{
for (i = 0; i < sizeof(netscapeCertTypeMap) /
sizeof(netscapeCertTypeMap[0]); i++)
LoadStringW(hInstance, netscapeCertTypeMap[i].id,
netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
stringsLoaded = TRUE;
}
CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
NULL, &bitStringLen, &first);
bytesNeeded += bitStringLen;
bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
bits->cbData, NULL, &size);
bytesNeeded += size;
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
bitStringLen = bytesNeeded;
first = TRUE;
CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
str, &bitStringLen, &first);
str += bitStringLen / sizeof(WCHAR) - 1;
*str++ = ' ';
*str++ = '(';
CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
bits->cbData, str, &size);
str += size / sizeof(WCHAR) - 1;
*str++ = ')';
*str = 0;
}
}
LocalFree(bits);
}
return ret;
}
static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
static WCHAR available[MAX_STRING_RESOURCE_LEN];
static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
static WCHAR yes[MAX_STRING_RESOURCE_LEN];
static WCHAR no[MAX_STRING_RESOURCE_LEN];
static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
SPC_FINANCIAL_CRITERIA criteria;
DWORD size = sizeof(criteria);
BOOL ret = FALSE;
if (!cbEncoded)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
&size)))
{
static BOOL stringsLoaded = FALSE;
DWORD bytesNeeded = sizeof(WCHAR);
LPCWSTR sep;
DWORD sepLen;
if (!stringsLoaded)
{
LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
sizeof(financialCriteria) / sizeof(financialCriteria[0]));
LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
sizeof(available) / sizeof(available[0]));
LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
stringsLoaded = TRUE;
}
if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
{
sep = crlf;
sepLen = strlenW(crlf) * sizeof(WCHAR);
}
else
{
sep = commaSpace;
sepLen = strlenW(commaSpace) * sizeof(WCHAR);
}
bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
if (criteria.fFinancialInfoAvailable)
{
bytesNeeded += strlenW(available) * sizeof(WCHAR);
bytesNeeded += sepLen;
bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
if (criteria.fMeetsCriteria)
bytesNeeded += strlenW(yes) * sizeof(WCHAR);
else
bytesNeeded += strlenW(no) * sizeof(WCHAR);
}
else
bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
if (!pbFormat)
*pcbFormat = bytesNeeded;
else if (*pcbFormat < bytesNeeded)
{
*pcbFormat = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
*pcbFormat = bytesNeeded;
strcpyW(str, financialCriteria);
str += strlenW(financialCriteria);
if (criteria.fFinancialInfoAvailable)
{
strcpyW(str, available);
str += strlenW(available);
strcpyW(str, sep);
str += sepLen / sizeof(WCHAR);
strcpyW(str, meetsCriteria);
str += strlenW(meetsCriteria);
if (criteria.fMeetsCriteria)
strcpyW(str, yes);
else
strcpyW(str, no);
}
else
{
strcpyW(str, notAvailable);
str += strlenW(notAvailable);
}
}
}
return ret;
}
static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType,
DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
DWORD *pcbFormat)
{
CERT_NAME_VALUE *value;
DWORD size;
BOOL ret;
if (!cbEncoded)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size)))
{
if (!pbFormat)
*pcbFormat = value->Value.cbData;
else if (*pcbFormat < value->Value.cbData)
{
*pcbFormat = value->Value.cbData;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
LPWSTR str = pbFormat;
*pcbFormat = value->Value.cbData;
strcpyW(str, (LPWSTR)value->Value.pbData);
}
}
return ret;
}
typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
LPCSTR, const BYTE *, DWORD, void *, DWORD *);
static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
DWORD formatStrType, LPCSTR lpszStructType)
{
CryptFormatObjectFunc format = NULL;
if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
{
SetLastError(ERROR_FILE_NOT_FOUND);
return NULL;
}
if (!HIWORD(lpszStructType))
{
switch (LOWORD(lpszStructType))
{
case LOWORD(X509_KEY_USAGE):
format = CRYPT_FormatKeyUsage;
break;
case LOWORD(X509_ALTERNATE_NAME):
format = CRYPT_FormatAltName;
break;
case LOWORD(X509_BASIC_CONSTRAINTS2):
format = CRYPT_FormatBasicConstraints2;
break;
case LOWORD(X509_AUTHORITY_KEY_ID2):
format = CRYPT_FormatAuthorityKeyId2;
break;
case LOWORD(X509_AUTHORITY_INFO_ACCESS):
format = CRYPT_FormatAuthorityInfoAccess;
break;
case LOWORD(X509_CRL_DIST_POINTS):
format = CRYPT_FormatCRLDistPoints;
break;
case LOWORD(X509_ENHANCED_KEY_USAGE):
format = CRYPT_FormatEnhancedKeyUsage;
break;
case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
format = CRYPT_FormatSpcFinancialCriteria;
break;
}
}
else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
format = CRYPT_FormatAltName;
else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
format = CRYPT_FormatAltName;
else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
format = CRYPT_FormatKeyUsage;
else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
format = CRYPT_FormatAltName;
else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
format = CRYPT_FormatAltName;
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
format = CRYPT_FormatBasicConstraints2;
else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
format = CRYPT_FormatAuthorityInfoAccess;
else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
format = CRYPT_FormatAuthorityKeyId2;
else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
format = CRYPT_FormatCRLDistPoints;
else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
format = CRYPT_FormatEnhancedKeyUsage;
else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
format = CRYPT_FormatNetscapeCertType;
else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) ||
!strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) ||
!strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) ||
!strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) ||
!strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) ||
!strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) ||
!strcmp(lpszStructType, szOID_NETSCAPE_COMMENT))
format = CRYPT_FormatUnicodeString;
else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
format = CRYPT_FormatSpcFinancialCriteria;
return format;
}
BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
{
CryptFormatObjectFunc format = NULL;
HCRYPTOIDFUNCADDR hFunc = NULL;
BOOL ret = FALSE;
TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
pbEncoded, cbEncoded, pbFormat, pcbFormat);
if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
dwFormatStrType, lpszStructType)))
{
static HCRYPTOIDFUNCSET set = NULL;
if (!set)
set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
(void **)&format, &hFunc);
}
if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
format = CRYPT_FormatHexString;
if (format)
ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
pcbFormat);
if (hFunc)
CryptFreeOIDFunctionAddress(hFunc, 0);
return ret;
}