Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1505 lines
33 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: xcertlib.cpp
//
// Contents: most functions are moved and modofied from certsrv library
//
// History: 03-2000 xtan created
//--------------------------------------------------------------------------
#include <windows.h>
#include <assert.h>
#include <dbgdef.h>
#include <wininet.h>
#include "xelib.h"
// Crypt callback versions: must have certain signatures
LPVOID myCryptAlloc_LocalAlloc(size_t cbSize) { return myAlloc(cbSize, CERTLIB_USE_LOCALALLOC); }
VOID myCryptAlloc_LocalFree(VOID* pv) { myFree(pv, CERTLIB_USE_LOCALALLOC); }
LPVOID myCryptAlloc_CoTaskMemAlloc(size_t cbSize) { return myAlloc(cbSize, CERTLIB_USE_COTASKMEMALLOC); }
VOID myCryptAlloc_CoTaskMemFree(VOID* pv) { myFree(pv, CERTLIB_USE_COTASKMEMALLOC); }
// give callers an easy way to choose what to call: pick allocator based on allocation type
PFN_CRYPT_ALLOC PickAlloc(CERTLIB_ALLOCATOR allocType)
{
if (allocType == CERTLIB_USE_LOCALALLOC)
return myCryptAlloc_LocalAlloc;
else if (allocType == CERTLIB_USE_COTASKMEMALLOC)
return myCryptAlloc_CoTaskMemAlloc;
CSASSERT(!"Bad allocType");
return NULL;
}
PFN_CRYPT_FREE PickFree(CERTLIB_ALLOCATOR allocType)
{
if (allocType == CERTLIB_USE_LOCALALLOC)
return myCryptAlloc_LocalFree;
else if (allocType == CERTLIB_USE_COTASKMEMALLOC)
return myCryptAlloc_CoTaskMemFree;
CSASSERT(!"Bad allocType");
return NULL;
}
VOID *
myAlloc(IN size_t cbBytes, IN CERTLIB_ALLOCATOR allocType)
{
void *pv;
switch (allocType)
{
case CERTLIB_USE_LOCALALLOC:
pv = LocalAlloc(LMEM_FIXED, cbBytes);
break;
case CERTLIB_USE_COTASKMEMALLOC:
pv = CoTaskMemAlloc(cbBytes);
break;
default:
CSASSERT(FALSE);
pv = NULL;
break;
}
if (NULL == pv)
{
_PrintError(E_OUTOFMEMORY, "myAlloc");
SetLastError((DWORD) E_OUTOFMEMORY);
}
return(pv);
}
VOID
myFree(IN void *pv, IN CERTLIB_ALLOCATOR allocType)
{
switch(allocType)
{
case CERTLIB_USE_LOCALALLOC:
LocalFree(pv);
break;
case CERTLIB_USE_COTASKMEMALLOC:
CoTaskMemFree(pv);
break;
default:
CSASSERT(FALSE);
break;
}
}
HRESULT
myHError(HRESULT hr)
{
CSASSERT(S_FALSE != hr);
if (S_OK != hr && S_FALSE != hr && !FAILED(hr))
{
hr = HRESULT_FROM_WIN32(hr);
if (0 == HRESULT_CODE(hr))
{
// A call failed without properly setting an error condition!
hr = E_UNEXPECTED;
}
CSASSERT(FAILED(hr));
}
return(hr);
}
HRESULT
myHLastError(VOID)
{
return(myHError(GetLastError()));
}
#ifdef _XENROLL_SRC_
typedef BOOL
(WINAPI * PFNCryptEncodeObjectEx)
(IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const void *pvStructInfo,
IN DWORD dwFlags,
IN OPTIONAL PCRYPT_ENCODE_PARA pEncodePara,
OUT void *pvEncoded,
IN OUT DWORD *pcbEncoded);
typedef BOOL
(WINAPI * PFNCryptDecodeObjectEx)
(IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
IN OPTIONAL PCRYPT_DECODE_PARA pDecodePara,
OUT OPTIONAL void *pvStructInfo,
IN OUT DWORD *pcbStructInfo);
#endif //_XENROLL_SRC_
BOOL
myEncodeObject(
DWORD dwEncodingType,
IN LPCSTR lpszStructType,
IN VOID const *pvStructInfo,
IN DWORD dwFlags,
IN CERTLIB_ALLOCATOR allocType,
OUT BYTE **ppbEncoded,
OUT DWORD *pcbEncoded)
{
BOOL b = FALSE;
CSASSERT(NULL != ppbEncoded);
CRYPT_ENCODE_PARA sAllocator;
sAllocator.cbSize = sizeof(sAllocator);
sAllocator.pfnAlloc = PickAlloc(allocType);
sAllocator.pfnFree = PickFree(allocType);
#ifdef _XENROLL_SRC_
PFNCryptEncodeObjectEx pfnCryptEncodeObjectEx = NULL;
HMODULE hModule = GetModuleHandle("crypt32.dll");
if (NULL != hModule)
{
pfnCryptEncodeObjectEx = (PFNCryptEncodeObjectEx)
GetProcAddress(hModule, "CryptEncodeObjectEx");
if (NULL != pfnCryptEncodeObjectEx)
{
b = pfnCryptEncodeObjectEx(
dwEncodingType,
lpszStructType,
const_cast<VOID *>(pvStructInfo),
dwFlags|CRYPT_ENCODE_ALLOC_FLAG,
&sAllocator,
ppbEncoded,
pcbEncoded);
}
}
#else
b = CryptEncodeObjectEx(
dwEncodingType,
lpszStructType,
const_cast<VOID *>(pvStructInfo),
dwFlags|CRYPT_ENCODE_ALLOC_FLAG,
&sAllocator,
ppbEncoded,
pcbEncoded);
if (b && 0 == *pcbEncoded)
{
SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
b = FALSE;
}
#endif //_XENROLL_SRC_
return(b);
}
BOOL
myDecodeObject(
IN DWORD dwEncodingType,
IN LPCSTR lpszStructType,
IN BYTE const *pbEncoded,
IN DWORD cbEncoded,
IN CERTLIB_ALLOCATOR allocType,
OUT VOID **ppvStructInfo,
OUT DWORD *pcbStructInfo)
{
BOOL b = FALSE;
CRYPT_DECODE_PARA sAllocator;
sAllocator.cbSize = sizeof(sAllocator);
sAllocator.pfnAlloc = PickAlloc(allocType);
sAllocator.pfnFree = PickFree(allocType);
#ifdef _XENROLL_SRC_
PFNCryptDecodeObjectEx pfnCryptDecodeObjectEx = NULL;
HMODULE hModule = GetModuleHandle("crypt32.dll");
if (NULL != hModule)
{
pfnCryptDecodeObjectEx = (PFNCryptDecodeObjectEx)
GetProcAddress(hModule, "CryptDecodeObjectEx");
if (NULL != pfnCryptDecodeObjectEx)
{
b = pfnCryptDecodeObjectEx(
dwEncodingType,
lpszStructType,
pbEncoded,
cbEncoded,
CRYPT_DECODE_ALLOC_FLAG, // dwFlags
&sAllocator,
ppvStructInfo,
pcbStructInfo);
}
}
#else
b = CryptDecodeObjectEx(
dwEncodingType,
lpszStructType,
pbEncoded,
cbEncoded,
CRYPT_DECODE_ALLOC_FLAG, // dwFlags
&sAllocator,
ppvStructInfo,
pcbStructInfo);
if (b && 0 == *pcbStructInfo)
{
SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
b = FALSE;
}
#endif //_XENROLL_SRC_
return(b);
}
HRESULT
myDecodePKCS7(
IN BYTE const *pbIn,
IN DWORD cbIn,
OPTIONAL OUT BYTE **ppbContents,
OPTIONAL OUT DWORD *pcbContents,
OPTIONAL OUT DWORD *pdwMsgType,
OPTIONAL OUT char **ppszInnerContentObjId,
OPTIONAL OUT DWORD *pcSigner,
OPTIONAL OUT DWORD *pcRecipient,
OPTIONAL OUT HCERTSTORE *phStore,
OPTIONAL OUT HCRYPTMSG *phMsg)
{
HRESULT hr;
BYTE *pbContents = NULL;
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
DWORD cbContents;
char *pszInnerContentObjId = NULL;
DWORD cb;
if (NULL != ppszInnerContentObjId)
{
*ppszInnerContentObjId = NULL;
}
if (NULL != pcSigner)
{
*pcSigner = 0;
}
if (NULL != pcRecipient)
{
*pcRecipient = 0;
}
if (NULL != ppbContents)
{
*ppbContents = NULL;
}
if (NULL != phStore)
{
*phStore = NULL;
}
if (NULL != phMsg)
{
*phMsg = NULL;
}
if (NULL != phStore)
{
CRYPT_DATA_BLOB blobPKCS7;
blobPKCS7.pbData = (BYTE *) pbIn;
blobPKCS7.cbData = cbIn;
hStore = CertOpenStore(
CERT_STORE_PROV_PKCS7,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
NULL, // hCryptProv
0, // dwFlags
&blobPKCS7);
if (NULL == hStore)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
// _JumpError2(hr, error, "CertOpenStore", CRYPT_E_ASN1_BADTAG);
}
}
hMsg = CryptMsgOpenToDecode(
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
0, // dwFlags
0, // dwMsgType
NULL, // hCryptProv
NULL, // pRecipientInfo
NULL); // pStreamInfo
if (NULL == hMsg)
{
hr = myHLastError();
_JumpError(hr, error, "CryptMsgOpenToDecode");
}
if (!CryptMsgUpdate(hMsg, pbIn, cbIn, TRUE))
{
hr = myHLastError();
_JumpError(hr, error, "CryptMsgUpdate");
}
hr = myCryptMsgGetParam(
hMsg,
CMSG_INNER_CONTENT_TYPE_PARAM,
0, // dwIndex
CERTLIB_USE_LOCALALLOC,
(VOID **) &pszInnerContentObjId,
&cb);
_PrintIfError(hr, "myCryptMsgGetParam(inner content type)");
#if 0
DBGPRINT((
DBG_SS_CERTLIBI,
"pszInnerContentObjId = %hs\n",
pszInnerContentObjId));
#endif //0
cbContents = 0;
hr = myCryptMsgGetParam(
hMsg,
CMSG_CONTENT_PARAM,
0, // dwIndex
CERTLIB_USE_LOCALALLOC,
(VOID **) &pbContents,
&cbContents);
_JumpIfError(hr, error, "myCryptMsgGetParam(content)");
if (NULL != pdwMsgType)
{
cb = sizeof(*pdwMsgType);
if (!CryptMsgGetParam(
hMsg,
CMSG_TYPE_PARAM,
0,
pdwMsgType,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "CryptMsgGetParam(type)");
}
}
if (NULL != pcSigner)
{
cb = sizeof(*pcSigner);
if (!CryptMsgGetParam(
hMsg,
CMSG_SIGNER_COUNT_PARAM,
0,
pcSigner,
&cb))
{
hr = myHLastError();
*pcSigner = 0;
if (CRYPT_E_INVALID_MSG_TYPE != hr)
{
_JumpError(hr, error, "CryptMsgGetParam(signer count)");
}
}
}
if (NULL != pcRecipient)
{
cb = sizeof(*pcRecipient);
if (!CryptMsgGetParam(
hMsg,
CMSG_RECIPIENT_COUNT_PARAM,
0,
pcRecipient,
&cb))
{
hr = myHLastError();
*pcRecipient = 0;
if (CRYPT_E_INVALID_MSG_TYPE != hr)
{
_JumpError(hr, error, "CryptMsgGetParam(recipient count)");
}
}
}
if (NULL != phMsg)
{
*phMsg = hMsg;
hMsg = NULL;
}
if (NULL != phStore)
{
*phStore = hStore;
hStore = NULL;
}
if (NULL != ppszInnerContentObjId)
{
*ppszInnerContentObjId = pszInnerContentObjId;
pszInnerContentObjId = NULL;
}
if (NULL != pcbContents)
{
*pcbContents = cbContents;
}
if (NULL != ppbContents && 0 != cbContents)
{
*ppbContents = pbContents;
pbContents = NULL;
}
hr = S_OK;
error:
if (NULL != hMsg)
{
CryptMsgClose(hMsg);
}
if (NULL != hStore)
{
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
if (NULL != pbContents)
{
LocalFree(pbContents);
}
if (NULL != pszInnerContentObjId)
{
LocalFree(pszInnerContentObjId);
}
return(hr);
}
HRESULT
myDupString(
IN WCHAR const *pwszIn,
IN WCHAR **ppwszOut)
{
DWORD cb;
HRESULT hr;
cb = (wcslen(pwszIn) + 1) * sizeof(WCHAR);
*ppwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == *ppwszOut)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(*ppwszOut, pwszIn, cb);
hr = S_OK;
error:
return(hr);
}
HRESULT
myAddNameSuffix(
IN WCHAR const *pwszValue,
IN WCHAR const *pwszSuffix,
IN DWORD cwcNameMax,
OUT WCHAR **ppwszOut)
{
HRESULT hr;
DWORD cwcValue = wcslen(pwszValue);
DWORD cwcSuffix = wcslen(pwszSuffix);
WCHAR *pwszOut;
*ppwszOut = NULL;
pwszOut = (WCHAR *) LocalAlloc(
LMEM_FIXED,
sizeof(WCHAR) * (1 + cwcValue + cwcSuffix));
if (NULL == pwszOut)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CSASSERT(cwcNameMax > cwcSuffix);
if (cwcValue > cwcNameMax - cwcSuffix)
{
cwcValue = cwcNameMax - cwcSuffix;
}
wcscpy(pwszOut, pwszValue);
wcscpy(&pwszOut[cwcValue], pwszSuffix);
*ppwszOut = pwszOut;
hr = S_OK;
error:
return(hr);
}
#define OCTECTSPACES
VOID
MultiByteStringSize(
IN BOOL fOctetString,
IN BYTE const *pbIn,
IN OUT DWORD *pcbIn,
OUT DWORD *pcbString)
{
DWORD cbIn = *pcbIn;
DWORD cbString;
if (!fOctetString)
{
while (1 < cbIn && 0 == pbIn[cbIn - 1])
{
cbIn--;
}
}
// Two ascii-hex characters per byte, plus the null terminator:
cbString = ((2 * cbIn) + 1) * sizeof(WCHAR);
#ifdef OCTECTSPACES
// Allow for separating spaces after each byte except the last:
if (fOctetString && 1 < cbIn)
{
cbString += (cbIn - 1) * sizeof(WCHAR);
}
#endif // OCTECTSPACES
*pcbIn = cbIn;
*pcbString = cbString;
}
__inline WCHAR
NibbleToAscii(
IN BYTE b)
{
return(L"0123456789abcdef"[b & 0x0f]);
}
// MultiByteIntegerToWszBuf - convert a little-endian integer blob to
// a big endian null-terminated ascii-hex encoded WCHAR string of even length.
HRESULT
MultiByteIntegerToWszBuf(
IN BOOL fOctetString,
IN DWORD cbIn,
IN BYTE const *pbIn,
IN OUT DWORD *pcbOut,
OPTIONAL OUT WCHAR *pwszOut)
{
HRESULT hr = S_OK;
DWORD cbOut;
BYTE const *pbEnd = &pbIn[cbIn];
MultiByteStringSize(fOctetString, pbIn, &cbIn, &cbOut);
if (NULL != pwszOut)
{
BYTE const *pb;
if (cbOut > *pcbOut)
{
hr = TYPE_E_BUFFERTOOSMALL;
_JumpError(hr, error, "MultiByteIntegerToWsz: buffer overflow");
}
if (fOctetString)
{
for (pb = pbIn; pb < pbEnd; pb++)
{
*pwszOut++ = NibbleToAscii(*pb >> 4);
*pwszOut++ = NibbleToAscii(*pb);
#ifdef OCTECTSPACES
if (pb + 1 < pbEnd)
{
*pwszOut++ = L' ';
}
#endif // OCTECTSPACES
}
}
else
{
for (pb = pbEnd; pb-- > pbIn; )
{
*pwszOut++ = NibbleToAscii(*pb >> 4);
*pwszOut++ = NibbleToAscii(*pb);
}
}
*pwszOut = L'\0';
CSASSERT(
(SAFE_SUBTRACT_POINTERS(pwszOut, pwsz) + 1) * sizeof(WCHAR) ==
cbOut);
}
*pcbOut = cbOut;
error:
return(hr);
}
// MultiByteIntegerToBstr - convert a little-endian integer blob to
// a big endian null-terminated ascii-hex encoded BSTR of even length.
// If fOctetString is TRUE, preserve endian order, as in a hex dump
HRESULT
MultiByteIntegerToBstr(
IN BOOL fOctetString,
IN DWORD cbIn,
IN BYTE const *pbIn,
OUT BSTR *pstrOut)
{
HRESULT hr = S_OK;
BSTR str = NULL;
DWORD cbOut;
MultiByteStringSize(fOctetString, pbIn, &cbIn, &cbOut);
str = SysAllocStringByteLen(NULL, cbOut - sizeof(WCHAR));
if (NULL == str)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "SysAllocStringLen");
}
hr = MultiByteIntegerToWszBuf(fOctetString, cbIn, pbIn, &cbOut, str);
_JumpIfError(hr, error, "MultiByteIntegerToWszBuf");
CSASSERT((wcslen(str) + 1) * sizeof(WCHAR) == cbOut);
CSASSERT(SysStringByteLen(str) + sizeof(WCHAR) == cbOut);
if (NULL != *pstrOut)
{
SysFreeString(*pstrOut);
}
*pstrOut = str;
str = NULL;
error:
if (NULL != str)
{
SysFreeString(str);
}
return(hr);
}
BOOL
myCryptExportPublicKeyInfo(
IN HCRYPTPROV hCryptProv,
IN DWORD dwKeySpec, // AT_SIGNATURE | AT_KEYEXCHANGE
IN CERTLIB_ALLOCATOR allocType,
OUT CERT_PUBLIC_KEY_INFO **ppPubKey,
OUT DWORD *pcbPubKey)
{
BOOL b;
*ppPubKey = NULL;
*pcbPubKey = 0;
for (;;)
{
b = CryptExportPublicKeyInfo(
hCryptProv,
dwKeySpec,
X509_ASN_ENCODING,
*ppPubKey,
pcbPubKey);
if (b && 0 == *pcbPubKey)
{
SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
b = FALSE;
}
if (!b)
{
if (NULL != *ppPubKey)
{
myFree(*ppPubKey, allocType);
*ppPubKey = NULL;
}
break;
}
if (NULL != *ppPubKey)
{
break;
}
*ppPubKey = (CERT_PUBLIC_KEY_INFO *) myAlloc(*pcbPubKey, allocType);
if (NULL == *ppPubKey)
{
b = FALSE;
break;
}
}
return(b);
}
VOID
myMakeExprDateTime(
IN OUT FILETIME *pft,
IN LONG lDelta,
IN enum ENUM_PERIOD enumPeriod)
{
LONGLONG llDelta;
BOOL fSysTimeDelta;
llDelta = lDelta;
fSysTimeDelta = FALSE;
switch (enumPeriod)
{
case ENUM_PERIOD_WEEKS: llDelta *= CVT_WEEKS; break;
case ENUM_PERIOD_DAYS: llDelta *= CVT_DAYS; break;
case ENUM_PERIOD_HOURS: llDelta *= CVT_HOURS; break;
case ENUM_PERIOD_MINUTES: llDelta *= CVT_MINUTES; break;
case ENUM_PERIOD_SECONDS: break;
//case ENUM_PERIOD_MONTHS:
//case ENUM_PERIOD_YEARS:
default:
// Avoid side effect of round trip SYSTEMTIME conversion
// (avoid truncating microseconds) if lDelta is zero.
if (0 != lDelta)
{
fSysTimeDelta = TRUE;
}
break;
}
if (fSysTimeDelta)
{
SYSTEMTIME SystemTime;
FileTimeToSystemTime(pft, &SystemTime);
switch (enumPeriod)
{
case ENUM_PERIOD_MONTHS:
if (0 > lDelta)
{
DWORD dwDelta = (DWORD) -lDelta;
SystemTime.wYear -= (WORD) (dwDelta / 12) + 1;
SystemTime.wMonth += 12 - (WORD) (dwDelta % 12);
}
else
{
SystemTime.wMonth = (WORD) (SystemTime.wMonth + lDelta);
}
if (12 < SystemTime.wMonth)
{
SystemTime.wYear += (SystemTime.wMonth - 1) / 12;
SystemTime.wMonth = ((SystemTime.wMonth - 1) % 12) + 1;
}
break;
case ENUM_PERIOD_YEARS:
SystemTime.wYear = (WORD) (SystemTime.wYear + lDelta);
break;
default:
SystemTime.wYear += 1;
break;
}
DoConvert:
if (!SystemTimeToFileTime(&SystemTime, pft))
{
if (GetLastError() != ERROR_INVALID_PARAMETER)
{
CSASSERT(!"Unable to do time conversion");
return;
}
// In some cases we'll convert to an invalid month-end
// only one month changes length from year to year
if (SystemTime.wMonth == 2)
{
// > 29? try leap year
if (SystemTime.wDay > 29)
{
SystemTime.wDay = 29;
goto DoConvert;
}
// == 29? try non-leap year
else if (SystemTime.wDay == 29)
{
SystemTime.wDay = 28;
goto DoConvert;
}
}
// sept (9), apr(4), jun(6), nov(11) all have 30 days
else if ((SystemTime.wMonth == 9) ||
(SystemTime.wMonth == 4) ||
(SystemTime.wMonth == 6) ||
(SystemTime.wMonth == 11))
{
if (SystemTime.wDay > 30)
{
SystemTime.wDay = 30;
goto DoConvert;
}
}
// should never get here
CSASSERT(!"Month/year processing: inaccessible code");
return;
}
}
else
{
*(LONGLONG UNALIGNED *) pft += llDelta * CVT_BASE;
}
}
BOOL
myCryptSignCertificate(
IN HCRYPTPROV hCryptProv,
IN DWORD dwKeySpec,
IN DWORD dwEncodingType,
IN BYTE const *pbEncodedToBeSigned,
IN DWORD cbEncodedToBeSigned,
IN CRYPT_ALGORITHM_IDENTIFIER const *pSignatureAlgorithm,
IN CERTLIB_ALLOCATOR allocType,
OUT BYTE **ppbSignature,
OUT DWORD *pcbSignature)
{
BOOL b;
*ppbSignature = NULL;
*pcbSignature = 0;
for (;;)
{
b = CryptSignCertificate(
hCryptProv,
dwKeySpec,
dwEncodingType,
pbEncodedToBeSigned,
cbEncodedToBeSigned,
const_cast<CRYPT_ALGORITHM_IDENTIFIER *>(pSignatureAlgorithm),
NULL, // pvHashAuxInfo
*ppbSignature,
pcbSignature);
if (b && 0 == *pcbSignature)
{
SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
b = FALSE;
}
if (!b)
{
if (NULL != *ppbSignature)
{
myFree(*ppbSignature, allocType);
*ppbSignature = NULL;
}
break;
}
if (NULL != *ppbSignature)
{
break;
}
*ppbSignature = (BYTE *) myAlloc(*pcbSignature, allocType);
if (NULL == *ppbSignature)
{
b = FALSE;
break;
}
}
return(b);
}
HRESULT
myEncodeSignedContent(
IN HCRYPTPROV hProv,
IN DWORD dwCertEncodingType,
IN char const *pszObjIdSignatureAlgorithm,
IN BYTE *pbToBeSigned,
IN DWORD cbToBeSigned,
IN CERTLIB_ALLOCATOR allocType,
OUT BYTE **ppbSigned,
OUT DWORD *pcbSigned)
{
HRESULT hr;
CERT_SIGNED_CONTENT_INFO csci;
ZeroMemory(&csci, sizeof(csci));
csci.SignatureAlgorithm.pszObjId = (char *) pszObjIdSignatureAlgorithm;
csci.ToBeSigned.cbData = cbToBeSigned;
csci.ToBeSigned.pbData = pbToBeSigned;
*ppbSigned = NULL;
if (!myCryptSignCertificate(
hProv,
AT_SIGNATURE,
dwCertEncodingType,
csci.ToBeSigned.pbData,
csci.ToBeSigned.cbData,
&csci.SignatureAlgorithm,
CERTLIB_USE_LOCALALLOC,
&csci.Signature.pbData,
&csci.Signature.cbData))
{
hr = myHLastError();
_JumpError(hr, error, "myCryptSignCertificate");
}
// if (!myEncodeCert(
if (!myEncodeObject(
dwCertEncodingType,
X509_CERT,
&csci,
0,
allocType,
ppbSigned,
pcbSigned))
{
hr = myHLastError();
// _JumpError(hr, error, "myEncodeCert");
_JumpError(hr, error, "myEncodeObject");
}
hr = S_OK;
error:
if (NULL != csci.Signature.pbData)
{
LocalFree(csci.Signature.pbData);
}
return(hr);
}
HRESULT
myGetPublicKeyHash(
OPTIONAL IN CERT_INFO const *pCertInfo,
IN CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo,
OUT BYTE **ppbData,
OUT DWORD *pcbData)
{
HRESULT hr;
CRYPT_DATA_BLOB *pBlob = NULL;
DWORD cb;
BYTE const *pb;
BYTE abHash[CBMAX_CRYPT_HASH_LEN];
*ppbData = NULL;
if (NULL == pPublicKeyInfo)
{
hr = E_POINTER;
_JumpError(hr, error, "parm NULL");
}
pb = NULL;
cb = 0;
if (NULL != pCertInfo)
{
CERT_EXTENSION const *pExt;
CERT_EXTENSION const *pExtEnd;
pExtEnd = &pCertInfo->rgExtension[pCertInfo->cExtension];
for (pExt = pCertInfo->rgExtension; pExt < pExtEnd; pExt++)
{
if (0 == strcmp(szOID_SUBJECT_KEY_IDENTIFIER, pExt->pszObjId))
{
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_OCTET_STRING,
pExt->Value.pbData,
pExt->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pBlob,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeObject");
}
pb = pBlob->pbData;
cb = pBlob->cbData;
break;
}
}
}
if (NULL == pb)
{
cb = sizeof(abHash);
if (!CryptHashPublicKeyInfo(
NULL, // hCryptProv
CALG_SHA1,
0, // dwFlags,
X509_ASN_ENCODING,
const_cast<CERT_PUBLIC_KEY_INFO *>(pPublicKeyInfo),
abHash,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "CryptHashPublicKeyInfo");
}
pb = abHash;
}
*ppbData = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == *ppbData)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
*pcbData = cb;
CopyMemory(*ppbData, pb, cb);
hr = S_OK;
error:
if (NULL != pBlob)
{
LocalFree(pBlob);
}
return(hr);
}
HRESULT
myCreateSubjectKeyIdentifierExtension(
IN CERT_PUBLIC_KEY_INFO const *pPubKey,
OUT BYTE **ppbEncoded,
OUT DWORD *pcbEncoded)
{
HRESULT hr;
CRYPT_DATA_BLOB KeyIdentifier;
KeyIdentifier.pbData = NULL;
hr = myGetPublicKeyHash(
NULL, // pCertInfo
pPubKey,
&KeyIdentifier.pbData,
&KeyIdentifier.cbData);
_JumpIfError(hr, error, "myGetPublicKeyHash");
// Issuer's KeyId:
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_OCTET_STRING,
&KeyIdentifier,
0,
CERTLIB_USE_LOCALALLOC,
ppbEncoded,
pcbEncoded))
{
hr = myHLastError();
_JumpError(hr, error, "myEncodeObject");
}
hr = S_OK;
error:
if (NULL != KeyIdentifier.pbData)
{
LocalFree(KeyIdentifier.pbData);
}
return(hr);
}
HRESULT
myCalculateKeyArchivalHash(
IN const BYTE *pbEncryptedKey,
IN DWORD cbEncryptedKey,
OUT BYTE **ppbHash,
OUT DWORD *pcbHash)
{
HRESULT hr;
HCRYPTPROV hProv = NULL;
HCRYPTHASH hHash = NULL;
BYTE* pbHash = NULL;
DWORD cbHash = 0;
DWORD dwSize;
if (NULL == pbEncryptedKey ||
NULL == ppbHash ||
NULL == pcbHash)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
_JumpError(hr, error, "Invalid parameters");
}
//init
*ppbHash = NULL;
*pcbHash = 0;
if (!CryptAcquireContext(
&hProv,
NULL, // pszContainer
NULL, // pszProvider
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
hr = myHLastError();
_JumpError(hr, error, "CryptAcquireContext");
}
//create a hash object
if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
{
hr = myHLastError();
_JumpError(hr, error, "CryptCreateHash");
}
//hash the data
if (!CryptHashData(
hHash,
pbEncryptedKey,
cbEncryptedKey,
0))
{
hr = myHLastError();
_JumpError(hr, error, "CryptHashData");
}
//get the hash size
dwSize = sizeof(cbHash);
if (!CryptGetHashParam(
hHash,
HP_HASHSIZE,
(BYTE*)&cbHash,
&dwSize,
0))
{
hr = myHLastError();
_JumpError(hr, error, "CryptGetHashParam");
}
//allocate for hash buffer
pbHash = (BYTE*)LocalAlloc(LMEM_FIXED, cbHash);
if (NULL == pbHash)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
dwSize = cbHash;
//get the hash
if (!CryptGetHashParam(
hHash,
HP_HASHVAL,
(BYTE*)pbHash,
&dwSize,
0))
{
hr = myHLastError();
_JumpError(hr, error, "CryptGetHashParam");
}
//should be the same
CSASSERT(dwSize == cbHash);
//return
*ppbHash = pbHash;
*pcbHash = cbHash;
pbHash = NULL;
hr = S_OK;
error:
if (NULL != hHash)
{
CryptDestroyHash(hHash);
}
if (NULL != hProv)
{
CryptReleaseContext(hProv, 0);
}
if (NULL != pbHash)
{
LocalFree(pbHash);
}
return hr;
}
//--------------------------------------------------------------------
// Escapes any characters unsuitable for a URL. Returns a new string.
HRESULT
myInternetCanonicalizeUrl(
IN WCHAR const *pwszIn,
OUT WCHAR **ppwszOut)
{
HRESULT hr;
WCHAR *pwsz = NULL;
CSASSERT(NULL != pwszIn);
if (0 == _wcsnicmp(L"file:", pwszIn, 5))
{
hr = myDupString(pwszIn, &pwsz);
_JumpIfError(hr, error, "myDupString");
}
else
{
// Calculate required buffer size by passing a very small buffer
// The call will fail, and tell us how big the buffer should be.
WCHAR wszPlaceHolder[1];
DWORD cwc = ARRAYSIZE(wszPlaceHolder);
BOOL bResult;
bResult = InternetCanonicalizeUrlW(
pwszIn, // lpszUrl
wszPlaceHolder, // lpszBuffer
&cwc, // lpdwBufferLength
0); // dwFlags
CSASSERT(!bResult); // This will always fail
hr = myHLastError();
if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
{
// unexpected error
_JumpError(hr, error, "InternetCanonicalizeUrl");
}
// NOTE: InternetCanonicalizeUrl counts characters, not bytes as doc'd
// cwc includes trailing L'0'
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
if (NULL == pwsz)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
// canonicalize
if (!InternetCanonicalizeUrlW(
pwszIn, // lpszUrl
pwsz, // lpszBuffer
&cwc, // lpdwBufferLength
0)) // dwFlags
{
hr = myHLastError();
_JumpError(hr, error, "InternetCanonicalizeUrl");
}
}
*ppwszOut = pwsz;
pwsz = NULL;
hr = S_OK;
error:
if (NULL != pwsz)
{
LocalFree(pwsz);
}
return(hr);
}
// Inverse of InternetCanonicalizeUrl -- Convert "%20" sequences to " ", etc.
HRESULT
myInternetUncanonicalizeURL(
IN WCHAR const *pwszURLIn,
OUT WCHAR **ppwszURLOut)
{
HRESULT hr;
URL_COMPONENTSW urlcomp;
WCHAR wszScheme[10]; // L"ldap"
WCHAR wszHost[MAX_PATH];
WCHAR wszURL[MAX_PATH];
WCHAR wszExtra[MAX_PATH];
WCHAR *pwszURL = NULL;
DWORD cURL;
DWORD cwcURLAlloc;
*ppwszURLOut = NULL;
ZeroMemory(&urlcomp, sizeof(urlcomp));
urlcomp.dwStructSize = sizeof(urlcomp);
urlcomp.lpszScheme = wszScheme;
urlcomp.dwSchemeLength = ARRAYSIZE(wszScheme);
urlcomp.lpszHostName = wszHost;
urlcomp.dwHostNameLength = ARRAYSIZE(wszHost);
urlcomp.lpszUrlPath = wszURL;
urlcomp.dwUrlPathLength = ARRAYSIZE(wszURL);
urlcomp.lpszExtraInfo = wszExtra;
urlcomp.dwExtraInfoLength = ARRAYSIZE(wszExtra);
// Decode escape sequemces
if (!InternetCrackUrlW(pwszURLIn, 0, ICU_ESCAPE, &urlcomp))
{
hr = myHLastError();
_JumpError(hr, error, "InternetCrackUrl");
}
cURL = 0;
for (;;)
{
// InternetCreateUrl is spec'd strangely:
//
// When called with a NULL input pointer or an insufficient buffer
// size, the returned count is the number of bytes required, including
// the trailing L'\0'.
//
// When called with a non-NULL input pointer of adequate size, the
// returned count is the count of chars, excluding the trailing L'\0'.
//
// This is just so wierd!
if (!InternetCreateUrlW(&urlcomp, 0, pwszURL, &cURL))
{
hr = myHLastError();
if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr ||
NULL != pwszURL)
{
_JumpError(hr, error, "InternetCreatUrl");
}
}
if (NULL != pwszURL)
{
CSASSERT(wcslen(pwszURL) == cURL);
CSASSERT(cwcURLAlloc == cURL + 1);
break;
}
pwszURL = (WCHAR *) LocalAlloc(LMEM_FIXED, cURL);
if (NULL == pwszURL)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
cURL /= sizeof(WCHAR);
cwcURLAlloc = cURL;
}
*ppwszURLOut = pwszURL;
pwszURL = NULL;
hr = S_OK;
error:
if (NULL != pwszURL)
{
LocalFree(pwszURL);
}
return(hr);
}
BOOL
ConvertWszToMultiByte(
OUT CHAR **ppsz,
IN UINT CodePage,
IN WCHAR const *pwc,
IN LONG cwc)
{
HRESULT hr;
LONG cch = 0;
*ppsz = NULL;
for (;;)
{
cch = WideCharToMultiByte(
CodePage,
0, // dwFlags
pwc,
cwc, // cchWideChar, -1 => null terminated
*ppsz,
cch,
NULL,
NULL);
if (0 >= cch &&
(0 != cch || (0 != cwc && (MAXLONG != cwc || L'\0' != *pwc))))
{
hr = myHLastError();
_PrintError(hr, "WideCharToMultiByte");
if (NULL != *ppsz)
{
LocalFree(*ppsz);
*ppsz = NULL;
}
break;
}
if (NULL != *ppsz)
{
(*ppsz)[cch] = '\0';
hr = S_OK;
break;
}
*ppsz = (CHAR *) LocalAlloc(LMEM_FIXED, cch + 1);
if (NULL == *ppsz)
{
hr = E_OUTOFMEMORY;
break;
}
}
if (S_OK != hr)
{
SetLastError(hr);
}
return(S_OK == hr);
}
BOOL
myConvertWszToUTF8(
OUT CHAR **ppsz,
IN WCHAR const *pwc,
IN LONG cwc)
{
return(ConvertWszToMultiByte(ppsz, CP_UTF8, pwc, cwc));
}
BOOL
myConvertWszToSz(
OUT CHAR **ppsz,
IN WCHAR const *pwc,
IN LONG cwc)
{
return(ConvertWszToMultiByte(ppsz, GetACP(), pwc, cwc));
}
BOOL
myConvertMultiByteToWsz(
OUT WCHAR **ppwsz,
IN UINT CodePage,
IN CHAR const *pch,
IN LONG cch)
{
HRESULT hr;
LONG cwc = 0;
*ppwsz = NULL;
for (;;)
{
cwc = MultiByteToWideChar(CodePage, 0, pch, cch, *ppwsz, cwc);
if (0 >= cwc)
{
hr = myHLastError();
_PrintError(hr, "MultiByteToWideChar");
if (NULL != *ppwsz)
{
LocalFree(*ppwsz);
*ppwsz = NULL;
}
break;
}
if (NULL != *ppwsz)
{
(*ppwsz)[cwc] = L'\0';
hr = S_OK;
break;
}
*ppwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
if (NULL == *ppwsz)
{
hr = E_OUTOFMEMORY;
break;
}
}
if (S_OK != hr)
{
SetLastError(hr);
}
return(S_OK == hr);
}
BOOL
myConvertUTF8ToWsz(
OUT WCHAR **ppwsz,
IN CHAR const *pch,
IN LONG cch)
{
return(myConvertMultiByteToWsz(ppwsz, CP_UTF8, pch, cch));
}
BOOL
myConvertSzToWsz(
OUT WCHAR **ppwsz,
IN CHAR const *pch,
IN LONG cch)
{
return(myConvertMultiByteToWsz(ppwsz, GetACP(), pch, cch));
}