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.
3484 lines
96 KiB
3484 lines
96 KiB
//
|
|
// CertUtil.cpp
|
|
//
|
|
#include "StdAfx.h"
|
|
#include "CertUtil.h"
|
|
#include "base64.h"
|
|
#include <malloc.h>
|
|
#include "Certificat.h"
|
|
#include <wincrypt.h>
|
|
#include "Resource.h"
|
|
#include "Shlwapi.h"
|
|
#include "CertCA.h"
|
|
#include "cryptui.h"
|
|
#include <schannel.h>
|
|
#include <strsafe.h>
|
|
|
|
// for certobj object
|
|
#include "certobj.h"
|
|
|
|
|
|
#define ISNUM(cChar) ((cChar >= _T('0')) && (cChar <= _T('9'))) ? (TRUE) : (FALSE)
|
|
|
|
const CLSID CLSID_CCertConfig =
|
|
{0x372fce38, 0x4324, 0x11d0, {0x88, 0x10, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
|
|
|
|
const GUID IID_ICertConfig =
|
|
{0x372fce34, 0x4324, 0x11d0, {0x88, 0x10, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
|
|
|
|
#define CRYPTUI_MAX_STRING_SIZE 768
|
|
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
|
|
|
|
BOOL
|
|
GetOnlineCAList(CStringList& list, const CString& certType, HRESULT * phRes)
|
|
{
|
|
BOOL bRes = TRUE;
|
|
HRESULT hr = S_OK;
|
|
DWORD errBefore = GetLastError();
|
|
DWORD dwCACount = 0;
|
|
|
|
HCAINFO hCurCAInfo = NULL;
|
|
HCAINFO hPreCAInfo = NULL;
|
|
|
|
if (certType.IsEmpty())
|
|
return FALSE;
|
|
|
|
*phRes = CAFindByCertType(certType, NULL, 0, &hCurCAInfo);
|
|
if (FAILED(*phRes) || NULL == hCurCAInfo)
|
|
{
|
|
if (S_OK == hr)
|
|
hr=E_FAIL;
|
|
return FALSE;
|
|
}
|
|
|
|
//get the CA count
|
|
if (0 == (dwCACount = CACountCAs(hCurCAInfo)))
|
|
{
|
|
*phRes = E_FAIL;
|
|
return FALSE;
|
|
}
|
|
WCHAR ** ppwstrName, ** ppwstrMachine;
|
|
while (hCurCAInfo)
|
|
{
|
|
//get the CA information
|
|
if ( SUCCEEDED(CAGetCAProperty(hCurCAInfo, CA_PROP_DISPLAY_NAME, &ppwstrName))
|
|
&& SUCCEEDED(CAGetCAProperty(hCurCAInfo, CA_PROP_DNSNAME, &ppwstrMachine))
|
|
)
|
|
{
|
|
CString config;
|
|
config = *ppwstrMachine;
|
|
config += L"\\";
|
|
config += *ppwstrName;
|
|
list.AddTail(config);
|
|
CAFreeCAProperty(hCurCAInfo, ppwstrName);
|
|
CAFreeCAProperty(hCurCAInfo, ppwstrMachine);
|
|
}
|
|
else
|
|
{
|
|
bRes = FALSE;
|
|
break;
|
|
}
|
|
|
|
hPreCAInfo = hCurCAInfo;
|
|
if (FAILED(*phRes = CAEnumNextCA(hPreCAInfo, &hCurCAInfo)))
|
|
{
|
|
bRes = FALSE;
|
|
break;
|
|
}
|
|
CACloseCA(hPreCAInfo);
|
|
hPreCAInfo = NULL;
|
|
}
|
|
|
|
if (hPreCAInfo)
|
|
CACloseCA(hPreCAInfo);
|
|
if (hCurCAInfo)
|
|
CACloseCA(hCurCAInfo);
|
|
|
|
SetLastError(errBefore);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
PCCERT_CONTEXT
|
|
GetRequestContext(CCryptBlob& pkcs7, HRESULT * phRes)
|
|
{
|
|
ASSERT(phRes != NULL);
|
|
BOOL bRes = FALSE;
|
|
HCERTSTORE hStoreMsg = NULL;
|
|
PCCERT_CONTEXT pCertContextMsg = NULL;
|
|
|
|
if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
|
|
(PCERT_BLOB)pkcs7,
|
|
(CERT_QUERY_CONTENT_FLAG_CERT |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
|
|
CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED) ,
|
|
CERT_QUERY_FORMAT_FLAG_ALL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&hStoreMsg,
|
|
NULL,
|
|
NULL)
|
|
|| NULL == (pCertContextMsg = CertFindCertificateInStore(
|
|
hStoreMsg,
|
|
X509_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_ANY,
|
|
NULL,
|
|
NULL))
|
|
)
|
|
{
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
return pCertContextMsg;
|
|
}
|
|
|
|
|
|
BOOL GetRequestInfoFromPKCS10(CCryptBlob& pkcs10,
|
|
PCERT_REQUEST_INFO * pReqInfo,
|
|
HRESULT * phRes)
|
|
{
|
|
ASSERT(pReqInfo != NULL);
|
|
ASSERT(phRes != NULL);
|
|
BOOL bRes = FALSE;
|
|
DWORD req_info_size;
|
|
if (!(bRes = CryptDecodeObjectEx(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
pkcs10.GetData(),
|
|
pkcs10.GetSize(),
|
|
CRYPT_DECODE_ALLOC_FLAG,
|
|
NULL,
|
|
pReqInfo,
|
|
&req_info_size)))
|
|
{
|
|
TRACE(_T("Error from CryptDecodeObjectEx: %xd\n"), GetLastError());
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
#if 0
|
|
// This function extracts data from pkcs7 format
|
|
BOOL GetRequestInfoFromRenewalRequest(CCryptBlob& renewal_req,
|
|
PCCERT_CONTEXT * pSignerCert,
|
|
HCERTSTORE hStore,
|
|
PCERT_REQUEST_INFO * pReqInfo,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes;
|
|
CRYPT_DECRYPT_MESSAGE_PARA decr_para;
|
|
CRYPT_VERIFY_MESSAGE_PARA ver_para;
|
|
|
|
decr_para.cbSize = sizeof(decr_para);
|
|
decr_para.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
|
|
decr_para.cCertStore = 1;
|
|
decr_para.rghCertStore = &hStore;
|
|
|
|
ver_para.cbSize = sizeof(ver_para);
|
|
ver_para.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
|
|
ver_para.hCryptProv = 0;
|
|
ver_para.pfnGetSignerCertificate = NULL;
|
|
ver_para.pvGetArg = NULL;
|
|
|
|
DWORD dwMsgType;
|
|
DWORD dwInnerContentType;
|
|
DWORD cbDecoded;
|
|
|
|
if (bRes = CryptDecodeMessage(
|
|
CMSG_SIGNED_FLAG,
|
|
&decr_para,
|
|
&ver_para,
|
|
0,
|
|
renewal_req.GetData(),
|
|
renewal_req.GetSize(),
|
|
0,
|
|
&dwMsgType,
|
|
&dwInnerContentType,
|
|
NULL,
|
|
&cbDecoded,
|
|
NULL,
|
|
pSignerCert))
|
|
{
|
|
CCryptBlobLocal decoded_req;
|
|
decoded_req.Resize(cbDecoded);
|
|
if (bRes = CryptDecodeMessage(
|
|
CMSG_SIGNED_FLAG,
|
|
&decr_para,
|
|
&ver_para,
|
|
0,
|
|
renewal_req.GetData(),
|
|
renewal_req.GetSize(),
|
|
0,
|
|
&dwMsgType,
|
|
&dwInnerContentType,
|
|
decoded_req.GetData(),
|
|
&cbDecoded,
|
|
NULL,
|
|
pSignerCert))
|
|
{
|
|
bRes = GetRequestInfoFromPKCS10(decoded_req,
|
|
pReqInfo, phRes);
|
|
}
|
|
}
|
|
if (!bRes)
|
|
{
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
return bRes;
|
|
}
|
|
#endif
|
|
|
|
HCERTSTORE
|
|
OpenRequestStore(IEnroll * pEnroll, HRESULT * phResult)
|
|
{
|
|
ASSERT(NULL != phResult);
|
|
HCERTSTORE hStore = NULL;
|
|
WCHAR * bstrStoreName, * bstrStoreType;
|
|
long dwStoreFlags;
|
|
VERIFY(SUCCEEDED(pEnroll->get_RequestStoreNameWStr(&bstrStoreName)));
|
|
VERIFY(SUCCEEDED(pEnroll->get_RequestStoreTypeWStr(&bstrStoreType)));
|
|
VERIFY(SUCCEEDED(pEnroll->get_RequestStoreFlags(&dwStoreFlags)));
|
|
size_t store_type_len = _tcslen(bstrStoreType);
|
|
|
|
char * szStoreProvider = (char *) LocalAlloc(LPTR,store_type_len + 1);
|
|
|
|
ASSERT(szStoreProvider != NULL);
|
|
size_t n = wcstombs(szStoreProvider, bstrStoreType, store_type_len);
|
|
szStoreProvider[n] = '\0';
|
|
hStore = CertOpenStore(
|
|
szStoreProvider,
|
|
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
|
|
NULL,
|
|
dwStoreFlags,
|
|
bstrStoreName
|
|
);
|
|
CoTaskMemFree(bstrStoreName);
|
|
CoTaskMemFree(bstrStoreType);
|
|
if (hStore == NULL)
|
|
{
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
if (szStoreProvider)
|
|
{
|
|
LocalFree(szStoreProvider);szStoreProvider=NULL;
|
|
}
|
|
return hStore;
|
|
}
|
|
|
|
HCERTSTORE
|
|
OpenMyStore(IEnroll * pEnroll, HRESULT * phResult)
|
|
{
|
|
ASSERT(NULL != phResult);
|
|
HCERTSTORE hStore = NULL;
|
|
BSTR bstrStoreName, bstrStoreType;
|
|
long dwStoreFlags;
|
|
VERIFY(SUCCEEDED(pEnroll->get_MyStoreNameWStr(&bstrStoreName)));
|
|
VERIFY(SUCCEEDED(pEnroll->get_MyStoreTypeWStr(&bstrStoreType)));
|
|
VERIFY(SUCCEEDED(pEnroll->get_MyStoreFlags(&dwStoreFlags)));
|
|
size_t store_type_len = _tcslen(bstrStoreType);
|
|
|
|
char * szStoreProvider = (char *) LocalAlloc(LPTR,store_type_len + 1);
|
|
ASSERT(szStoreProvider != NULL);
|
|
size_t n = wcstombs(szStoreProvider, bstrStoreType, store_type_len);
|
|
ASSERT(n != -1);
|
|
// this converter doesn't set zero byte!!!
|
|
szStoreProvider[n] = '\0';
|
|
hStore = CertOpenStore(
|
|
szStoreProvider,
|
|
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
|
|
NULL,
|
|
dwStoreFlags,
|
|
bstrStoreName
|
|
);
|
|
CoTaskMemFree(bstrStoreName);
|
|
CoTaskMemFree(bstrStoreType);
|
|
if (hStore == NULL)
|
|
{
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
if (szStoreProvider)
|
|
{
|
|
LocalFree(szStoreProvider);szStoreProvider=NULL;
|
|
}
|
|
return hStore;
|
|
}
|
|
|
|
BOOL
|
|
GetStringProperty(PCCERT_CONTEXT pCertContext,
|
|
DWORD propId,
|
|
CString& str,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
DWORD cb = 0;
|
|
BYTE * prop = NULL;
|
|
DWORD cbData = 0;
|
|
void * pData = NULL;
|
|
|
|
// compare property value
|
|
if (!CertGetCertificateContextProperty(pCertContext, propId, NULL, &cb))
|
|
{
|
|
goto GetStringProperty_Exit;
|
|
}
|
|
|
|
prop = (BYTE *) LocalAlloc(LPTR,cb);
|
|
if (NULL == prop)
|
|
{
|
|
goto GetStringProperty_Exit;
|
|
}
|
|
|
|
if (!CertGetCertificateContextProperty(pCertContext, propId, prop, &cb))
|
|
{
|
|
goto GetStringProperty_Exit;
|
|
}
|
|
|
|
// decode this instance name property
|
|
if (!CryptDecodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,prop, cb, 0, NULL, &cbData))
|
|
{
|
|
goto GetStringProperty_Exit;
|
|
}
|
|
pData = LocalAlloc(LPTR,cbData);
|
|
if (NULL == pData)
|
|
{
|
|
goto GetStringProperty_Exit;
|
|
}
|
|
|
|
if (!CryptDecodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,prop, cb, 0, pData, &cbData))
|
|
{
|
|
goto GetStringProperty_Exit;
|
|
}
|
|
else
|
|
{
|
|
CERT_NAME_VALUE * pName = (CERT_NAME_VALUE *)pData;
|
|
DWORD cch = pName->Value.cbData/sizeof(TCHAR);
|
|
void * p = str.GetBuffer(cch);
|
|
memcpy(p, pName->Value.pbData, pName->Value.cbData);
|
|
str.ReleaseBuffer(cch);
|
|
bRes = TRUE;
|
|
}
|
|
|
|
GetStringProperty_Exit:
|
|
if (!bRes)
|
|
{
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
if (prop)
|
|
{
|
|
LocalFree(prop);prop=NULL;
|
|
}
|
|
if (pData)
|
|
{
|
|
LocalFree(pData);pData=NULL;
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
BOOL
|
|
GetBlobProperty(PCCERT_CONTEXT pCertContext,
|
|
DWORD propId,
|
|
CCryptBlob& blob,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
DWORD cb;
|
|
// compare property value
|
|
if ( CertGetCertificateContextProperty(pCertContext, propId, NULL, &cb)
|
|
&& blob.Resize(cb)
|
|
&& CertGetCertificateContextProperty(pCertContext, propId, blob.GetData(), &cb)
|
|
)
|
|
{
|
|
bRes = TRUE;
|
|
}
|
|
if (!bRes)
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
return bRes;
|
|
}
|
|
|
|
PCCERT_CONTEXT
|
|
GetPendingDummyCert(const CString& inst_name,
|
|
IEnroll * pEnroll,
|
|
HRESULT * phRes)
|
|
{
|
|
PCCERT_CONTEXT pRes = NULL;
|
|
HCERTSTORE hStore = OpenRequestStore(pEnroll, phRes);
|
|
if (hStore != NULL)
|
|
{
|
|
DWORD dwPropId = CERTWIZ_INSTANCE_NAME_PROP_ID;
|
|
PCCERT_CONTEXT pDummyCert = NULL;
|
|
while (NULL != (pDummyCert = CertFindCertificateInStore(hStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
0, CERT_FIND_PROPERTY,
|
|
(LPVOID)&dwPropId, pDummyCert)))
|
|
{
|
|
CString str;
|
|
if (GetStringProperty(pDummyCert, dwPropId, str, phRes))
|
|
{
|
|
if (str.CompareNoCase(inst_name) == 0)
|
|
{
|
|
pRes = pDummyCert;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
return pRes;
|
|
}
|
|
|
|
PCCERT_CONTEXT
|
|
GetReqCertByKey(IEnroll * pEnroll, CERT_PUBLIC_KEY_INFO * pKeyInfo, HRESULT * phResult)
|
|
{
|
|
PCCERT_CONTEXT pRes = NULL;
|
|
HCERTSTORE hStore = OpenRequestStore(pEnroll, phResult);
|
|
if (hStore != NULL)
|
|
{
|
|
if (NULL != (pRes = CertFindCertificateInStore(hStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
0, CERT_FIND_PUBLIC_KEY, (LPVOID)pKeyInfo, NULL)))
|
|
{
|
|
*phResult = S_OK;
|
|
}
|
|
VERIFY(CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG));
|
|
}
|
|
return pRes;
|
|
}
|
|
|
|
#define CERT_QUERY_CONTENT_FLAGS\
|
|
CERT_QUERY_CONTENT_FLAG_CERT\
|
|
|CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED\
|
|
|CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE\
|
|
|CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED
|
|
|
|
PCCERT_CONTEXT
|
|
GetCertContextFromPKCS7File(const CString& resp_file_name,
|
|
CERT_PUBLIC_KEY_INFO * pKeyInfo,
|
|
HRESULT * phResult)
|
|
{
|
|
ASSERT(phResult != NULL);
|
|
PCCERT_CONTEXT pRes = NULL;
|
|
HANDLE hFile;
|
|
|
|
if (INVALID_HANDLE_VALUE != (hFile = CreateFile(resp_file_name,
|
|
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, NULL)))
|
|
{
|
|
// find the length of the buffer
|
|
DWORD cbData = GetFileSize(hFile, NULL);
|
|
BYTE * pbData = NULL;
|
|
// alloc temp buffer
|
|
if ((pbData = (BYTE *) LocalAlloc(LPTR,cbData)) != NULL)
|
|
{
|
|
DWORD cb = 0;
|
|
if (ReadFile(hFile, pbData, cbData, &cb, NULL))
|
|
{
|
|
ASSERT(cb == cbData);
|
|
pRes = GetCertContextFromPKCS7(pbData, cb, pKeyInfo, phResult);
|
|
}
|
|
else
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
CloseHandle(hFile);
|
|
|
|
if (pbData)
|
|
{
|
|
LocalFree(pbData);pbData=NULL;
|
|
}
|
|
}
|
|
else
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
return pRes;
|
|
}
|
|
|
|
PCCERT_CONTEXT
|
|
GetCertContextFromPKCS7(const BYTE * pbData,
|
|
DWORD cbData,
|
|
CERT_PUBLIC_KEY_INFO * pKeyInfo,
|
|
HRESULT * phResult)
|
|
{
|
|
ASSERT(phResult != NULL);
|
|
PCCERT_CONTEXT pRes = NULL;
|
|
CRYPT_DATA_BLOB blob;
|
|
memset(&blob, 0, sizeof(CRYPT_DATA_BLOB));
|
|
blob.cbData = cbData;
|
|
blob.pbData = (BYTE *)pbData;
|
|
|
|
HCERTSTORE hStoreMsg = NULL;
|
|
|
|
if(CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
|
|
&blob,
|
|
(CERT_QUERY_CONTENT_FLAG_CERT |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
|
|
CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED) ,
|
|
CERT_QUERY_FORMAT_FLAG_ALL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&hStoreMsg,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
if (pKeyInfo != NULL)
|
|
pRes = CertFindCertificateInStore(hStoreMsg,
|
|
X509_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_PUBLIC_KEY,
|
|
pKeyInfo,
|
|
NULL);
|
|
else
|
|
pRes = CertFindCertificateInStore(hStoreMsg,
|
|
X509_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_ANY,
|
|
NULL,
|
|
NULL);
|
|
if (pRes == NULL)
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
CertCloseStore(hStoreMsg, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
else
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
return pRes;
|
|
}
|
|
|
|
BOOL
|
|
FormatDateString(CString& str, FILETIME ft, BOOL fIncludeTime, BOOL fLongFormat)
|
|
{
|
|
int cch;
|
|
int cch2;
|
|
LPWSTR psz;
|
|
SYSTEMTIME st;
|
|
FILETIME localTime;
|
|
|
|
if (!FileTimeToLocalFileTime(&ft, &localTime))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!FileTimeToSystemTime(&localTime, &st))
|
|
{
|
|
//
|
|
// if the conversion to local time failed, then just use the original time
|
|
//
|
|
if (!FileTimeToSystemTime(&ft, &st))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
cch = (GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &st, NULL, NULL, 0) +
|
|
GetDateFormat(LOCALE_SYSTEM_DEFAULT, fLongFormat ? DATE_LONGDATE : 0, &st, NULL, NULL, 0) + 5);
|
|
|
|
if (NULL == (psz = str.GetBuffer((cch+5) * sizeof(WCHAR))))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
cch2 = GetDateFormat(LOCALE_SYSTEM_DEFAULT, fLongFormat ? DATE_LONGDATE : 0, &st, NULL, psz, cch);
|
|
|
|
if (fIncludeTime)
|
|
{
|
|
psz[cch2-1] = ' ';
|
|
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_NOSECONDS, &st, NULL, &psz[cch2], cch-cch2);
|
|
}
|
|
str.ReleaseBuffer();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL MyGetOIDInfo(LPWSTR string, DWORD stringSize, LPSTR pszObjId)
|
|
{
|
|
PCCRYPT_OID_INFO pOIDInfo;
|
|
|
|
if (NULL != (pOIDInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pszObjId, 0)))
|
|
{
|
|
if ((DWORD)wcslen(pOIDInfo->pwszName)+1 <= stringSize)
|
|
{
|
|
if (FAILED(StringCbCopy(string,stringSize * sizeof(WCHAR),pOIDInfo->pwszName)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (MultiByteToWideChar(CP_ACP, 0, pszObjId, -1, string, stringSize) != 0);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GetKeyUsageProperty(PCCERT_CONTEXT pCertContext,
|
|
CERT_ENHKEY_USAGE ** pKeyUsage,
|
|
BOOL fPropertiesOnly,
|
|
HRESULT * phRes)
|
|
{
|
|
DWORD cb = 0;
|
|
BOOL bRes = FALSE;
|
|
if (!CertGetEnhancedKeyUsage(pCertContext,
|
|
fPropertiesOnly ? CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG : 0,
|
|
NULL,
|
|
&cb))
|
|
{
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrExit;
|
|
}
|
|
if (NULL == (*pKeyUsage = (CERT_ENHKEY_USAGE *)malloc(cb)))
|
|
{
|
|
*phRes = E_OUTOFMEMORY;
|
|
goto ErrExit;
|
|
}
|
|
if (!CertGetEnhancedKeyUsage (pCertContext,
|
|
fPropertiesOnly ? CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG : 0,
|
|
*pKeyUsage,
|
|
&cb))
|
|
{
|
|
free(*pKeyUsage);
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrExit;
|
|
}
|
|
*phRes = S_OK;
|
|
bRes = TRUE;
|
|
ErrExit:
|
|
return bRes;
|
|
}
|
|
|
|
BOOL
|
|
GetFriendlyName(PCCERT_CONTEXT pCertContext,
|
|
CString& name,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
DWORD cb;
|
|
BYTE * pName = NULL;
|
|
|
|
if ( CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, NULL, &cb)
|
|
&& NULL != (pName = (BYTE *)name.GetBuffer((cb + 1)/sizeof(TCHAR)))
|
|
&& CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, pName, &cb)
|
|
)
|
|
{
|
|
pName[cb] = 0;
|
|
bRes = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
if (pName != NULL && name.IsEmpty())
|
|
{
|
|
name.ReleaseBuffer();
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
BOOL
|
|
GetNameString(PCCERT_CONTEXT pCertContext,
|
|
DWORD type,
|
|
DWORD flag,
|
|
CString& name,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
LPTSTR pName;
|
|
DWORD cchName = CertGetNameString(pCertContext, type, flag, NULL, NULL, 0);
|
|
if (cchName > 1 && (NULL != (pName = name.GetBuffer(cchName))))
|
|
{
|
|
bRes = (1 != CertGetNameString(pCertContext, type, flag, NULL, pName, cchName));
|
|
name.ReleaseBuffer();
|
|
}
|
|
else
|
|
{
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
// Return:
|
|
// 0 = The CertContext does not have a EnhancedKeyUsage (EKU) field
|
|
// 1 = The CertContext has EnhancedKeyUsage (EKU) and contains the uses we want.
|
|
// This is also returned when The UsageIdentifier that depics "all uses" is true
|
|
// 2 = The CertContext has EnhancedKeyUsage (EKU) but does NOT contain the uses we want.
|
|
// This is also returned when The UsageIdentifier that depics "no uses" is true
|
|
INT
|
|
ContainsKeyUsageProperty(PCCERT_CONTEXT pCertContext,
|
|
CArray<LPCSTR, LPCSTR>& uses,
|
|
HRESULT * phRes
|
|
)
|
|
{
|
|
// Default it with "No EnhancedKeyUsage (EKU) Exist"
|
|
INT iReturn = 0;
|
|
CERT_ENHKEY_USAGE * pKeyUsage = NULL;
|
|
if ( uses.GetSize() > 0
|
|
&& GetKeyUsageProperty(pCertContext, &pKeyUsage, FALSE, phRes)
|
|
)
|
|
{
|
|
if (pKeyUsage->cUsageIdentifier == 0)
|
|
{
|
|
/*
|
|
But in MSDN article about SR
|
|
(see: ms-help://MS.MSDNQTR.2002APR.1033/security/security/certgetenhancedkeyusage.htm)
|
|
|
|
In Windows Me and Windows 2000 and later, if the cUsageIdentifier member is zero (0),
|
|
the certificate might be valid for ALL uses or the certificate might have no valid uses.
|
|
The return from a call to GetLastError can be used to determine whether the certificate
|
|
is good for all uses or for none. If GetLastError returns CRYPT_E_NOT_FOUND, the certificate
|
|
is good for all uses. If it returns zero (0), the certificate has no valid uses.
|
|
*/
|
|
|
|
// Default it with "has EnhancedKeyUsage (EKU), but doesn't have what we want"
|
|
iReturn = 2;
|
|
if (GetLastError() == CRYPT_E_NOT_FOUND)
|
|
{
|
|
// All uses!
|
|
iReturn = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Default it with "has EnhancedKeyUsage (EKU), but doesn't have what we want"
|
|
iReturn = 2;
|
|
|
|
for (DWORD i = 0; i < pKeyUsage->cUsageIdentifier; i++)
|
|
{
|
|
// Our friends from CAPI made this property ASCII even for
|
|
// UNICODE program
|
|
for (int n = 0; n < uses.GetSize(); n++)
|
|
{
|
|
if (strstr(pKeyUsage->rgpszUsageIdentifier[i], uses[n]) != NULL)
|
|
{
|
|
iReturn = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
free(pKeyUsage);
|
|
}
|
|
return iReturn;
|
|
}
|
|
|
|
BOOL
|
|
FormatEnhancedKeyUsageString(CString& str,
|
|
PCCERT_CONTEXT pCertContext,
|
|
BOOL fPropertiesOnly,
|
|
BOOL fMultiline,
|
|
HRESULT * phRes)
|
|
{
|
|
CERT_ENHKEY_USAGE * pKeyUsage = NULL;
|
|
WCHAR szText[CRYPTUI_MAX_STRING_SIZE];
|
|
BOOL bRes = FALSE;
|
|
|
|
if (GetKeyUsageProperty(pCertContext, &pKeyUsage, fPropertiesOnly, phRes))
|
|
{
|
|
// loop for each usage and add it to the display string
|
|
for (DWORD i = 0; i < pKeyUsage->cUsageIdentifier; i++)
|
|
{
|
|
if (!(bRes = MyGetOIDInfo(szText, ARRAYSIZE(szText), pKeyUsage->rgpszUsageIdentifier[i])))
|
|
break;
|
|
// add delimeter if not first iteration
|
|
if (i != 0)
|
|
{
|
|
str += fMultiline ? L"\n" : L", ";
|
|
}
|
|
// add the enhanced key usage string
|
|
str += szText;
|
|
}
|
|
free (pKeyUsage);
|
|
}
|
|
else
|
|
{
|
|
str.LoadString(IDS_ANY);
|
|
bRes = TRUE;
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
BOOL
|
|
GetServerComment(const CString& machine_name,
|
|
const CString& server_name,
|
|
CString& comment,
|
|
HRESULT * phResult)
|
|
{
|
|
ASSERT(!machine_name.IsEmpty());
|
|
ASSERT(!server_name.IsEmpty());
|
|
*phResult = S_OK;
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth,
|
|
server_name,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE
|
|
);
|
|
if (key.Succeeded())
|
|
{
|
|
return SUCCEEDED(*phResult = key.QueryValue(MD_SERVER_COMMENT, comment));
|
|
}
|
|
else
|
|
{
|
|
*phResult = key.QueryResult();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
GetInstalledCert
|
|
|
|
Function reads cert hash attribute from metabase
|
|
using machine_name and server name as server instance
|
|
description, then looks in MY store for a certificate
|
|
with hash equal found in metabase.
|
|
Return is cert context pointer or NULL, if cert wasn't
|
|
found or certificate store wasn't opened.
|
|
On return HRESULT * is filled by error code.
|
|
*/
|
|
PCCERT_CONTEXT
|
|
GetInstalledCert(const CString& machine_name,
|
|
const CString& server_name,
|
|
IEnroll * pEnroll,
|
|
HRESULT * phResult)
|
|
{
|
|
ASSERT(pEnroll != NULL);
|
|
ASSERT(phResult != NULL);
|
|
ASSERT(!machine_name.IsEmpty());
|
|
ASSERT(!server_name.IsEmpty());
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
*phResult = S_OK;
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth, server_name,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE
|
|
);
|
|
if (key.Succeeded())
|
|
{
|
|
CString store_name;
|
|
CBlob hash;
|
|
if ( SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name))
|
|
&& SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_HASH, hash))
|
|
)
|
|
{
|
|
// Open MY store. We assume that store type and flags
|
|
// cannot be changed between installation and unistallation
|
|
// of the sertificate.
|
|
HCERTSTORE hStore = OpenMyStore(pEnroll, phResult);
|
|
ASSERT(hStore != NULL);
|
|
if (hStore != NULL)
|
|
{
|
|
// Now we need to find cert by hash
|
|
CRYPT_HASH_BLOB crypt_hash;
|
|
ZeroMemory(&crypt_hash, sizeof(CRYPT_HASH_BLOB));
|
|
|
|
crypt_hash.cbData = hash.GetSize();
|
|
crypt_hash.pbData = hash.GetData();
|
|
pCert = CertFindCertificateInStore(hStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
0, CERT_FIND_HASH, (LPVOID)&crypt_hash, NULL);
|
|
if (pCert == NULL)
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
VERIFY(CertCloseStore(hStore, 0));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*phResult = key.QueryResult();
|
|
}
|
|
return pCert;
|
|
}
|
|
|
|
|
|
/*
|
|
GetInstalledCert
|
|
|
|
Function reads cert hash attribute from metabase
|
|
using machine_name and server name as server instance
|
|
description, then looks in MY store for a certificate
|
|
with hash equal found in metabase.
|
|
Return is cert context pointer or NULL, if cert wasn't
|
|
found or certificate store wasn't opened.
|
|
On return HRESULT * is filled by error code.
|
|
*/
|
|
CRYPT_HASH_BLOB *
|
|
GetInstalledCertHash(const CString& machine_name,
|
|
const CString& server_name,
|
|
IEnroll * pEnroll,
|
|
HRESULT * phResult)
|
|
{
|
|
ASSERT(pEnroll != NULL);
|
|
ASSERT(phResult != NULL);
|
|
ASSERT(!machine_name.IsEmpty());
|
|
ASSERT(!server_name.IsEmpty());
|
|
CRYPT_HASH_BLOB * pHashBlob = NULL;
|
|
*phResult = S_OK;
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth, server_name,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE
|
|
);
|
|
if (key.Succeeded())
|
|
{
|
|
CString store_name;
|
|
CBlob hash;
|
|
if ( SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name))
|
|
&& SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_HASH, hash))
|
|
)
|
|
{
|
|
pHashBlob = new CRYPT_HASH_BLOB;
|
|
if (pHashBlob)
|
|
{
|
|
pHashBlob->cbData = hash.GetSize();
|
|
pHashBlob->pbData = (BYTE *) ::CoTaskMemAlloc(pHashBlob->cbData);
|
|
if (pHashBlob->pbData)
|
|
{
|
|
memcpy(pHashBlob->pbData,hash.GetData(),pHashBlob->cbData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*phResult = key.QueryResult();
|
|
}
|
|
return pHashBlob;
|
|
}
|
|
|
|
|
|
/*
|
|
InstallHashToMetabase
|
|
|
|
Function writes hash array to metabase. After that IIS
|
|
could use certificate with that hash from MY store.
|
|
Function expects server_name in format lm\w3svc\<number>,
|
|
i.e. from root node down to virtual server
|
|
|
|
*/
|
|
BOOL
|
|
InstallHashToMetabase(CRYPT_HASH_BLOB * pHash,
|
|
const CString& machine_name,
|
|
const CString& server_name,
|
|
HRESULT * phResult)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth, server_name,
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE
|
|
);
|
|
if (key.Succeeded())
|
|
{
|
|
CBlob blob;
|
|
blob.SetValue(pHash->cbData, pHash->pbData, TRUE);
|
|
bRes = SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_HASH, blob))
|
|
&& SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_STORE_NAME, CString(L"MY")));
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("Failed to open metabase key. Error 0x%x\n"), key.QueryResult());
|
|
*phResult = key.QueryResult();
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
/*
|
|
InstallCertByHash
|
|
|
|
Function looks in MY store for certificate which has hash
|
|
equal to pHash parameter. If cert is found, it is installed
|
|
to metabase.
|
|
This function is used after xenroll accept() method, which
|
|
puts certificate to store
|
|
|
|
*/
|
|
BOOL
|
|
InstallCertByHash(CRYPT_HASH_BLOB * pHash,
|
|
const CString& machine_name,
|
|
const CString& server_name,
|
|
IEnroll * pEnroll,
|
|
HRESULT * phResult)
|
|
|
|
{
|
|
BOOL bRes = FALSE;
|
|
// we are looking to MY store only
|
|
HCERTSTORE hStore = OpenMyStore(pEnroll, phResult);
|
|
if (hStore != NULL)
|
|
{
|
|
PCCERT_CONTEXT pCert = CertFindCertificateInStore(hStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
0, CERT_FIND_HASH, (LPVOID)pHash, NULL);
|
|
// now install cert info to IIS MetaBase
|
|
if (pCert != NULL)
|
|
{
|
|
bRes = InstallHashToMetabase(pHash,
|
|
machine_name, server_name, phResult);
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("FAILED: certificate installation, error 0x%x\n"), GetLastError());
|
|
// We definitely need to store the hash of the cert, so error out
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
VERIFY(CertCloseStore(hStore, 0));
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
HRESULT
|
|
CreateRequest_Base64(const BSTR bstr_dn,
|
|
IEnroll * pEnroll,
|
|
BSTR csp_name,
|
|
DWORD csp_type,
|
|
BSTR * pOut)
|
|
{
|
|
ASSERT(pOut != NULL);
|
|
ASSERT(bstr_dn != NULL);
|
|
HRESULT hRes = S_OK;
|
|
CString strUsage(szOID_PKIX_KP_SERVER_AUTH);
|
|
CRYPT_DATA_BLOB request = {0, NULL};
|
|
pEnroll->put_ProviderType(csp_type);
|
|
pEnroll->put_ProviderNameWStr(csp_name);
|
|
if (csp_type == PROV_DH_SCHANNEL)
|
|
{
|
|
pEnroll->put_KeySpec(AT_SIGNATURE);
|
|
}
|
|
else if (csp_type == PROV_RSA_SCHANNEL)
|
|
{
|
|
pEnroll->put_KeySpec(AT_KEYEXCHANGE);
|
|
}
|
|
|
|
if (SUCCEEDED(hRes = pEnroll->createPKCS10WStr(
|
|
bstr_dn,
|
|
(LPTSTR)(LPCTSTR)strUsage,
|
|
&request)))
|
|
{
|
|
WCHAR * wszRequestB64 = NULL;
|
|
DWORD cch = 0;
|
|
DWORD err = ERROR_SUCCESS;
|
|
// BASE64 encode pkcs 10
|
|
if ((err = Base64EncodeW(request.pbData, request.cbData, NULL, &cch)) == ERROR_SUCCESS)
|
|
{
|
|
wszRequestB64 = (WCHAR *) LocalAlloc(LPTR,cch * sizeof(WCHAR));
|
|
if (NULL != wszRequestB64)
|
|
{
|
|
if ((err = Base64EncodeW(request.pbData, request.cbData, wszRequestB64, &cch)) == ERROR_SUCCESS)
|
|
{
|
|
if ((*pOut = SysAllocStringLen(wszRequestB64, cch)) == NULL )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = HRESULT_FROM_WIN32(err);
|
|
}
|
|
|
|
if (request.pbData != NULL)
|
|
{
|
|
CoTaskMemFree(request.pbData);
|
|
}
|
|
|
|
if (wszRequestB64)
|
|
{
|
|
LocalFree(wszRequestB64);wszRequestB64=NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
BOOL
|
|
AttachFriendlyName(PCCERT_CONTEXT pContext,
|
|
const CString& name,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes = TRUE;
|
|
CRYPT_DATA_BLOB blob_name;
|
|
|
|
// Check if friendlyname is empty
|
|
// if it is then don't try to set the friendly name
|
|
if (!name.IsEmpty())
|
|
{
|
|
blob_name.pbData = (LPBYTE)(LPCTSTR)name;
|
|
blob_name.cbData = (name.GetLength() + 1) * sizeof(WCHAR);
|
|
if (!(bRes = CertSetCertificateContextProperty(pContext,
|
|
CERT_FRIENDLY_NAME_PROP_ID, 0, &blob_name)))
|
|
{
|
|
ASSERT(phRes != NULL);
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
return bRes;
|
|
}
|
|
|
|
BOOL GetHashProperty(PCCERT_CONTEXT pCertContext,
|
|
CCryptBlob& blob,
|
|
HRESULT * phRes)
|
|
{
|
|
DWORD cb;
|
|
if (CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, NULL, &cb))
|
|
{
|
|
if (blob.Resize(cb))
|
|
{
|
|
if (CertGetCertificateContextProperty(pCertContext,
|
|
CERT_SHA1_HASH_PROP_ID, blob.GetData(), &cb))
|
|
return TRUE;
|
|
}
|
|
}
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
EncodeString(CString& str,
|
|
CCryptBlob& blob,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
DWORD cb;
|
|
CERT_NAME_VALUE name_value;
|
|
name_value.dwValueType = CERT_RDN_BMP_STRING;
|
|
name_value.Value.cbData = 0;
|
|
name_value.Value.pbData = (LPBYTE)(LPCTSTR)str;
|
|
if ( CryptEncodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
|
|
&name_value, NULL, &cb)
|
|
&& blob.Resize(cb)
|
|
&& CryptEncodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
|
|
&name_value, blob.GetData(), &cb)
|
|
)
|
|
{
|
|
bRes = TRUE;
|
|
}
|
|
else
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
return bRes;
|
|
}
|
|
|
|
#define CERTWIZ_RENEWAL_DATA ((LPCSTR)1000)
|
|
|
|
BOOL
|
|
EncodeBlob(CCryptBlob& in,
|
|
CCryptBlob& out,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
DWORD cb;
|
|
if ( CryptEncodeObject(CRYPT_ASN_ENCODING, CERTWIZ_RENEWAL_DATA, in, NULL, &cb)
|
|
&& out.Resize(cb)
|
|
&& CryptEncodeObject(CRYPT_ASN_ENCODING, CERTWIZ_RENEWAL_DATA, in, out.GetData(), &cb)
|
|
)
|
|
{
|
|
bRes = TRUE;
|
|
}
|
|
else
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
return bRes;
|
|
}
|
|
|
|
BOOL
|
|
DecodeBlob(CCryptBlob& in,
|
|
CCryptBlob& out,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
DWORD cb;
|
|
if ( CryptDecodeObject(CRYPT_ASN_ENCODING, CERTWIZ_RENEWAL_DATA,
|
|
in.GetData(),
|
|
in.GetSize(),
|
|
0,
|
|
NULL, &cb)
|
|
&& out.Resize(cb)
|
|
&& CryptDecodeObject(CRYPT_ASN_ENCODING, CERTWIZ_RENEWAL_DATA,
|
|
in.GetData(),
|
|
in.GetSize(),
|
|
0,
|
|
out.GetData(),
|
|
&cb)
|
|
)
|
|
{
|
|
bRes = TRUE;
|
|
}
|
|
else
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
return bRes;
|
|
}
|
|
|
|
BOOL
|
|
EncodeInteger(int number,
|
|
CCryptBlob& blob,
|
|
HRESULT * phRes)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
DWORD cb;
|
|
if ( CryptEncodeObject(CRYPT_ASN_ENCODING, X509_INTEGER,
|
|
&number, NULL, &cb)
|
|
&& blob.Resize(cb)
|
|
&& CryptEncodeObject(CRYPT_ASN_ENCODING, X509_INTEGER,
|
|
&number, blob.GetData(), &cb)
|
|
)
|
|
{
|
|
bRes = TRUE;
|
|
}
|
|
else
|
|
*phRes = HRESULT_FROM_WIN32(GetLastError());
|
|
return bRes;
|
|
}
|
|
|
|
const WCHAR RgwchHex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
|
|
|
static BOOL
|
|
FormatMemBufToString(CString& str, LPBYTE pbData, DWORD cbData)
|
|
{
|
|
DWORD i = 0;
|
|
LPBYTE pb;
|
|
DWORD numCharsInserted = 0;
|
|
LPTSTR pString;
|
|
|
|
//
|
|
// calculate the size needed
|
|
//
|
|
pb = pbData;
|
|
while (pb <= &(pbData[cbData-1]))
|
|
{
|
|
if (numCharsInserted == 4)
|
|
{
|
|
i += sizeof(WCHAR);
|
|
numCharsInserted = 0;
|
|
}
|
|
else
|
|
{
|
|
i += 2 * sizeof(WCHAR);
|
|
pb++;
|
|
numCharsInserted += 2;
|
|
}
|
|
}
|
|
|
|
if (NULL == (pString = str.GetBuffer(i)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// copy to the buffer
|
|
//
|
|
i = 0;
|
|
numCharsInserted = 0;
|
|
pb = pbData;
|
|
while (pb <= &(pbData[cbData-1]))
|
|
{
|
|
if (numCharsInserted == 4)
|
|
{
|
|
pString[i++] = L' ';
|
|
numCharsInserted = 0;
|
|
}
|
|
else
|
|
{
|
|
pString[i++] = RgwchHex[(*pb & 0xf0) >> 4];
|
|
pString[i++] = RgwchHex[*pb & 0x0f];
|
|
pb++;
|
|
numCharsInserted += 2;
|
|
}
|
|
}
|
|
pString[i] = 0;
|
|
str.ReleaseBuffer();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void FormatRdnAttr(CString& str, DWORD dwValueType, CRYPT_DATA_BLOB& blob, BOOL fAppend)
|
|
{
|
|
if ( CERT_RDN_ENCODED_BLOB == dwValueType
|
|
|| CERT_RDN_OCTET_STRING == dwValueType
|
|
)
|
|
{
|
|
// translate the buffer to a text string
|
|
FormatMemBufToString(str, blob.pbData, blob.cbData);
|
|
}
|
|
else
|
|
{
|
|
// buffer is already a string so just copy/append to it
|
|
if (fAppend)
|
|
{
|
|
str += (LPTSTR)blob.pbData;
|
|
}
|
|
else
|
|
{
|
|
// don't concatenate these entries...
|
|
str = (LPTSTR)blob.pbData;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CreateDirectoryFromPath(LPCTSTR szPath, LPSECURITY_ATTRIBUTES lpSA)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates the directory specified in szPath and any other "higher"
|
|
directories in the specified path that don't exist.
|
|
|
|
Arguments:
|
|
|
|
IN LPCTSTR szPath
|
|
directory path to create (assumed to be a DOS path, not a UNC)
|
|
|
|
IN LPSECURITY_ATTRIBUTES lpSA
|
|
pointer to security attributes argument used by CreateDirectory
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if directory(ies) created
|
|
FALSE if error (GetLastError to find out why)
|
|
|
|
--*/
|
|
{
|
|
LPTSTR pLeftHalf, pNext;
|
|
CString RightHalf;
|
|
// 1. We are supporting only absolute paths. Caller should decide which
|
|
// root to use and build the path
|
|
if (PathIsRelative(szPath))
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
pLeftHalf = (LPTSTR)szPath;
|
|
pNext = PathSkipRoot(pLeftHalf);
|
|
|
|
do {
|
|
// copy the chunk between pLeftHalf and pNext to the
|
|
// local buffer
|
|
while (pLeftHalf < pNext)
|
|
RightHalf += *pLeftHalf++;
|
|
// check if new path exists
|
|
int index = RightHalf.GetLength() - 1;
|
|
BOOL bBackslash = FALSE, bContinue = FALSE;
|
|
if (bBackslash = (RightHalf[index] == L'\\'))
|
|
{
|
|
RightHalf.SetAt(index, 0);
|
|
}
|
|
bContinue = PathIsUNCServerShare(RightHalf);
|
|
if (bBackslash)
|
|
RightHalf.SetAt(index, L'\\');
|
|
if (bContinue || PathIsDirectory(RightHalf))
|
|
continue;
|
|
else if (PathFileExists(RightHalf))
|
|
{
|
|
// we cannot create this directory
|
|
// because file with this name already exists
|
|
SetLastError(ERROR_ALREADY_EXISTS);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// no file no directory, create
|
|
if (!CreateDirectory(RightHalf, lpSA))
|
|
return FALSE;
|
|
}
|
|
}
|
|
while (NULL != (pNext = PathFindNextComponent(pLeftHalf)));
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CompactPathToWidth(CWnd * pControl, CString& strPath)
|
|
{
|
|
BOOL bRes;
|
|
CRect rc;
|
|
CFont * pFont = pControl->GetFont(), * pFontTmp;
|
|
CDC * pdc = pControl->GetDC(), dc;
|
|
LPTSTR pPath = strPath.GetBuffer(MAX_PATH);
|
|
|
|
dc.CreateCompatibleDC(pdc);
|
|
pFontTmp = dc.SelectObject(pFont);
|
|
pControl->GetClientRect(&rc);
|
|
|
|
bRes = PathCompactPath(dc.GetSafeHdc(), pPath, rc.Width());
|
|
|
|
dc.SelectObject(pFontTmp);
|
|
pControl->ReleaseDC(pdc);
|
|
strPath.ReleaseBuffer();
|
|
|
|
return bRes;
|
|
}
|
|
|
|
BOOL
|
|
GetKeySizeLimits(IEnroll * pEnroll,
|
|
DWORD * min, DWORD * max, DWORD * def,
|
|
BOOL bGSC,
|
|
HRESULT * phRes)
|
|
{
|
|
HCRYPTPROV hProv = NULL;
|
|
long dwProviderType;
|
|
DWORD dwFlags, cbData;
|
|
BSTR bstrProviderName;
|
|
PROV_ENUMALGS_EX paramData;
|
|
BOOL bRes = FALSE;
|
|
|
|
VERIFY(SUCCEEDED(pEnroll->get_ProviderNameWStr(&bstrProviderName)));
|
|
VERIFY(SUCCEEDED(pEnroll->get_ProviderType(&dwProviderType)));
|
|
|
|
if (!CryptAcquireContext(
|
|
&hProv,
|
|
NULL,
|
|
bstrProviderName,
|
|
dwProviderType,
|
|
CRYPT_VERIFYCONTEXT))
|
|
{
|
|
*phRes = GetLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
for (int i = 0; ; i++)
|
|
{
|
|
dwFlags = 0 == i ? CRYPT_FIRST : 0;
|
|
cbData = sizeof(paramData);
|
|
if (!CryptGetProvParam(hProv, PP_ENUMALGS_EX, (BYTE*)¶mData, &cbData, dwFlags))
|
|
{
|
|
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == GetLastError())
|
|
{
|
|
// out of for loop
|
|
*phRes = S_OK;
|
|
bRes = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*phRes = GetLastError();
|
|
}
|
|
break;
|
|
}
|
|
if (ALG_CLASS_KEY_EXCHANGE == GET_ALG_CLASS(paramData.aiAlgid))
|
|
{
|
|
*min = paramData.dwMinLen;
|
|
*max = paramData.dwMaxLen;
|
|
*def = paramData.dwDefaultLen;
|
|
bRes = TRUE;
|
|
*phRes = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
if (NULL != hProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
HRESULT ShutdownSSL(CString& machine_name, CString& server_name)
|
|
{
|
|
CString str = server_name;
|
|
str += _T("/root");
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth, str,METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
|
|
|
|
DWORD dwSslAccess;
|
|
if ( key.Succeeded()
|
|
&& SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess))
|
|
&& dwSslAccess > 0
|
|
)
|
|
{
|
|
// bug356587 should remove SslAccessPerm property and not set to 0 when Cert Removed
|
|
key.SetValue(MD_SSL_ACCESS_PERM, 0);
|
|
key.DeleteValue(MD_SSL_ACCESS_PERM);
|
|
//bug:612595 leave binding if removing cert.
|
|
//key.DeleteValue(MD_SECURE_BINDINGS);
|
|
}
|
|
|
|
// Now we need to remove SSL setting from any virtual directory below
|
|
CError err;
|
|
CStringListEx strlDataPaths;
|
|
DWORD dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType;
|
|
|
|
VERIFY(CMetaKey::GetMDFieldDef(MD_SSL_ACCESS_PERM, dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType));
|
|
|
|
err = key.GetDataPaths(strlDataPaths,dwMDIdentifier,dwMDDataType);
|
|
|
|
if (err.Succeeded() && !strlDataPaths.IsEmpty())
|
|
{
|
|
POSITION pos = strlDataPaths.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CString& str2 = strlDataPaths.GetNext(pos);
|
|
if (SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess, NULL, str2)) && dwSslAccess > 0)
|
|
{
|
|
key.SetValue(MD_SSL_ACCESS_PERM, 0, NULL, str2);
|
|
key.DeleteValue(MD_SSL_ACCESS_PERM, str2);
|
|
//bug:612595 leave binding if removing cert.
|
|
//key.DeleteValue(MD_SECURE_BINDINGS, str2);
|
|
}
|
|
}
|
|
}
|
|
return key.QueryResult();
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetServerComment(const CString& machine_name,
|
|
const CString& user_name,
|
|
const CString& user_password,
|
|
CString& MetabaseNode,
|
|
CString& comment,
|
|
HRESULT * phResult
|
|
)
|
|
{
|
|
ASSERT(!machine_name.IsEmpty());
|
|
*phResult = S_OK;
|
|
|
|
if (user_name.IsEmpty())
|
|
{
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth,MetabaseNode,METADATA_PERMISSION_READ);
|
|
if (key.Succeeded())
|
|
{
|
|
return SUCCEEDED(*phResult = key.QueryValue(MD_SERVER_COMMENT, comment));
|
|
}
|
|
else
|
|
{
|
|
*phResult = key.QueryResult();
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
CComAuthInfo auth(machine_name,user_name,user_password);
|
|
CMetaKey key(&auth,MetabaseNode,METADATA_PERMISSION_READ);
|
|
if (key.Succeeded())
|
|
{
|
|
return SUCCEEDED(*phResult = key.QueryValue(MD_SERVER_COMMENT, comment));
|
|
}
|
|
else
|
|
{
|
|
*phResult = key.QueryResult();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOL IsSiteTypeMetabaseNode(CString & MetabasePath)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
INT iPos1 = 0;
|
|
CString PathCopy = MetabasePath;
|
|
CString PathCopy2;
|
|
TCHAR MyChar;
|
|
|
|
// check if ends with a slash...
|
|
// if it does, then cut it off
|
|
if (PathCopy.Right(1) == _T('/'))
|
|
{
|
|
iPos1 = PathCopy.ReverseFind(_T('/'));
|
|
if (iPos1 != -1)
|
|
{
|
|
PathCopy.SetAt(iPos1,_T('0'));
|
|
}
|
|
}
|
|
|
|
iPos1 = PathCopy.ReverseFind((TCHAR) _T('/'));
|
|
if (iPos1 == -1)
|
|
{
|
|
goto IsSiteTypeMetabaseNode_Exit;
|
|
}
|
|
PathCopy2 = PathCopy.Right(PathCopy.GetLength() - iPos1);
|
|
PathCopy2.TrimRight();
|
|
for (INT i = 0; i < PathCopy2.GetLength(); i++)
|
|
{
|
|
MyChar = PathCopy2.GetAt(i);
|
|
if (MyChar != _T(' ') && MyChar != _T('/'))
|
|
{
|
|
if (FALSE == ISNUM(MyChar))
|
|
{
|
|
goto IsSiteTypeMetabaseNode_Exit;
|
|
}
|
|
}
|
|
}
|
|
bReturn = TRUE;
|
|
|
|
IsSiteTypeMetabaseNode_Exit:
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL IsMachineLocal(CString& machine_name,CString& user_name,CString& user_password)
|
|
{
|
|
CComAuthInfo auth(machine_name,user_name,user_password);
|
|
return auth.IsLocal();
|
|
}
|
|
|
|
HRESULT EnumSites(CString& machine_name,CString& user_name,CString& user_password,CString strCurrentMetabaseSite, CString strSiteToExclude,CStringListEx * MyStringList)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CString str = ReturnGoodMetabaseServerPath(strCurrentMetabaseSite);
|
|
CString strChildPath = _T("");
|
|
CString strServerComment;
|
|
BOOL IsLocalMachine = FALSE;
|
|
CComAuthInfo auth(machine_name,user_name,user_password);
|
|
CMetaKey key(&auth,str,METADATA_PERMISSION_READ);
|
|
|
|
// if it's local then make sure not to diplay the current site
|
|
IsLocalMachine = auth.IsLocal();
|
|
|
|
hr = key.QueryResult();
|
|
if (key.Succeeded())
|
|
{
|
|
// Do a Get data paths on this key.
|
|
CError err;
|
|
CStringListEx strlDataPaths;
|
|
CBlob hash;
|
|
DWORD dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType;
|
|
|
|
VERIFY(CMetaKey::GetMDFieldDef(MD_SERVER_BINDINGS, dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType));
|
|
err = key.GetDataPaths(strlDataPaths,dwMDIdentifier,dwMDDataType);
|
|
if (err.Succeeded() && !strlDataPaths.IsEmpty())
|
|
{
|
|
POSITION pos = strlDataPaths.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CString& strJustTheEnd = strlDataPaths.GetNext(pos);
|
|
|
|
strChildPath = str + strJustTheEnd;
|
|
if (TRUE == IsSiteTypeMetabaseNode(strChildPath))
|
|
{
|
|
if (TRUE == IsLocalMachine)
|
|
{
|
|
// Check if this the site that we want to exclude
|
|
if (strChildPath.Left(1) == _T("/"))
|
|
{
|
|
if (strSiteToExclude.Left(1) != _T("/"))
|
|
{strSiteToExclude = _T("/") + strSiteToExclude;}
|
|
}
|
|
|
|
if (strChildPath.Right(1) == _T("/"))
|
|
{
|
|
if (strSiteToExclude.Right(1) != _T("/"))
|
|
{strSiteToExclude = strSiteToExclude + _T("/");}
|
|
}
|
|
if (0 != _tcsicmp(strChildPath,strSiteToExclude))
|
|
{
|
|
MyStringList->AddTail(strChildPath);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MyStringList->AddTail(strChildPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
hr = key.QueryResult();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT EnumSitesWithCertInstalled(CString& machine_name,CString& user_name,CString& user_password,CString strCurrentMetabaseSite,CString strSiteToExclude,CStringListEx * MyStringList)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CString str = ReturnGoodMetabaseServerPath(strCurrentMetabaseSite);
|
|
CString strChildPath = _T("");
|
|
CString strServerComment;
|
|
BOOL IsLocalMachine = FALSE;
|
|
CComAuthInfo auth(machine_name,user_name,user_password);
|
|
CMetaKey key(&auth,str,METADATA_PERMISSION_READ);
|
|
|
|
// if it's local then make sure not to diplay the current site
|
|
IsLocalMachine = auth.IsLocal();
|
|
|
|
hr = key.QueryResult();
|
|
if (key.Succeeded())
|
|
{
|
|
// Do a Get data paths on this key.
|
|
CError err;
|
|
CStringListEx strlDataPaths;
|
|
CBlob hash;
|
|
DWORD dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType;
|
|
|
|
//MD_SSL_CERT_STORE_NAME
|
|
//MD_SSL_CERT_HASH, hash
|
|
VERIFY(CMetaKey::GetMDFieldDef(MD_SSL_CERT_HASH, dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType));
|
|
err = key.GetDataPaths(strlDataPaths,dwMDIdentifier,dwMDDataType);
|
|
if (err.Succeeded() && !strlDataPaths.IsEmpty())
|
|
{
|
|
POSITION pos = strlDataPaths.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CString& strJustTheEnd = strlDataPaths.GetNext(pos);
|
|
|
|
strChildPath = str + strJustTheEnd;
|
|
|
|
if (TRUE == IsSiteTypeMetabaseNode(strChildPath))
|
|
{
|
|
// check if this is a local machine.
|
|
if (TRUE == IsLocalMachine)
|
|
{
|
|
if (strChildPath.Left(1) == _T("/"))
|
|
{
|
|
if (strSiteToExclude.Left(1) != _T("/"))
|
|
{strSiteToExclude = _T("/") + strSiteToExclude;}
|
|
}
|
|
|
|
if (strChildPath.Right(1) == _T("/"))
|
|
{
|
|
if (strSiteToExclude.Right(1) != _T("/"))
|
|
{strSiteToExclude = strSiteToExclude + _T("/");}
|
|
}
|
|
// Check if this the site that we want to exclude
|
|
if (0 != _tcsicmp(strChildPath,strSiteToExclude))
|
|
{
|
|
MyStringList->AddTail(strChildPath);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MyStringList->AddTail(strChildPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
hr = key.QueryResult();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL IsWebSiteExistRemote(CString& machine_name,CString& user_name,CString& user_password,CString& site_instance_path,BOOL * bReturnIfCertificateExists)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComAuthInfo auth(machine_name,user_name,user_password);
|
|
CMetaKey key(&auth,site_instance_path,METADATA_PERMISSION_READ);
|
|
*bReturnIfCertificateExists = FALSE;
|
|
|
|
hr = key.QueryResult();
|
|
if (key.Succeeded())
|
|
{
|
|
// see if there is a certificate on it!
|
|
CString store_name;
|
|
CBlob hash;
|
|
if ( SUCCEEDED(hr = key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name))
|
|
&& SUCCEEDED(hr = key.QueryValue(MD_SSL_CERT_HASH, hash))
|
|
)
|
|
{
|
|
*bReturnIfCertificateExists = TRUE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (hr == ERROR_ACCESS_DENIED)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT IsWebServerExistRemote(CString& machine_name,CString& user_name,CString& user_password,CString strCurrentMetabaseSite)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CString str = ReturnGoodMetabaseServerPath(strCurrentMetabaseSite);
|
|
CComAuthInfo auth(machine_name,user_name,user_password);
|
|
CMetaKey key(&auth,str,METADATA_PERMISSION_READ);
|
|
|
|
hr = key.QueryResult();
|
|
if (key.Succeeded())
|
|
{
|
|
// i guess so.
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT IsCertObjExistRemote(CString& machine_name,CString& user_name,CString& user_password)
|
|
{
|
|
BOOL bPleaseDoCoUninit = FALSE;
|
|
HRESULT hResult = E_FAIL;
|
|
IIISCertObj *pTheObject = NULL;
|
|
|
|
hResult = CoInitialize(NULL);
|
|
if(FAILED(hResult))
|
|
{
|
|
return hResult;
|
|
}
|
|
bPleaseDoCoUninit = TRUE;
|
|
|
|
CComAuthInfo auth(machine_name,user_name,user_password);
|
|
// RPC_C_AUTHN_LEVEL_DEFAULT 0
|
|
// RPC_C_AUTHN_LEVEL_NONE 1
|
|
// RPC_C_AUTHN_LEVEL_CONNECT 2
|
|
// RPC_C_AUTHN_LEVEL_CALL 3
|
|
// RPC_C_AUTHN_LEVEL_PKT 4
|
|
// RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
|
|
// RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6
|
|
COSERVERINFO * pcsiName = auth.CreateServerInfoStruct(RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
|
|
MULTI_QI res[1] =
|
|
{
|
|
{&__uuidof(IIISCertObj), NULL, 0}
|
|
};
|
|
|
|
// this one seems to work with surrogates..
|
|
hResult = CoCreateInstanceEx(CLSID_IISCertObj,NULL,CLSCTX_LOCAL_SERVER,pcsiName,1,res);
|
|
pTheObject = (IIISCertObj *) res[0].pItf;
|
|
if (FAILED(hResult))
|
|
{
|
|
// The object probably doesn't exist on remote system
|
|
}
|
|
else
|
|
{
|
|
// at this point we were able to instantiate the com object on the server (local or remote)
|
|
if (auth.UsesImpersonation())
|
|
{
|
|
HRESULT hr = auth.ApplyProxyBlanket(pTheObject,RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
|
|
|
|
// There is a remote IUnknown Interface that lurks behind IUnknown.
|
|
// If that is not set, then the Release call can return access denied.
|
|
IUnknown * pUnk = NULL;
|
|
if(FAILED(pTheObject->QueryInterface(IID_IUnknown, (void **)&pUnk)))
|
|
{
|
|
goto IsCertObjExistRemote_Exit;
|
|
}
|
|
if (FAILED(auth.ApplyProxyBlanket(pUnk,RPC_C_AUTHN_LEVEL_PKT_PRIVACY)))
|
|
{
|
|
goto IsCertObjExistRemote_Exit;
|
|
}
|
|
pUnk->Release();pUnk = NULL;
|
|
}
|
|
auth.FreeServerInfoStruct(pcsiName);
|
|
}
|
|
|
|
IsCertObjExistRemote_Exit:
|
|
if (pTheObject)
|
|
{
|
|
pTheObject->Release();
|
|
pTheObject = NULL;
|
|
}
|
|
if (bPleaseDoCoUninit)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
return hResult;
|
|
}
|
|
|
|
|
|
HRESULT IsCertUsedBySSLBelowMe(CString& machine_name, CString& server_name, CStringList& listFillMe)
|
|
{
|
|
CString str = server_name;
|
|
str += _T("/root");
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth, str,METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
|
|
|
|
DWORD dwSslAccess;
|
|
if ( key.Succeeded()
|
|
&& SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess))
|
|
&& dwSslAccess > 0
|
|
)
|
|
{
|
|
// it's used on my node...
|
|
// return back something to say it's used...
|
|
listFillMe.AddTail(str);
|
|
}
|
|
|
|
// Now check if it's being used below me...
|
|
CError err;
|
|
CStringListEx strlDataPaths;
|
|
DWORD dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType;
|
|
|
|
VERIFY(CMetaKey::GetMDFieldDef(MD_SSL_ACCESS_PERM, dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType));
|
|
|
|
err = key.GetDataPaths(strlDataPaths,dwMDIdentifier,dwMDDataType);
|
|
|
|
if (err.Succeeded() && !strlDataPaths.IsEmpty())
|
|
{
|
|
POSITION pos = strlDataPaths.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CString& str2 = strlDataPaths.GetNext(pos);
|
|
if (SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess, NULL, str2)) && dwSslAccess > 0)
|
|
{
|
|
// yes, it's being used here...
|
|
// return back something to say it's used...
|
|
listFillMe.AddTail(str2);
|
|
}
|
|
}
|
|
}
|
|
return key.QueryResult();
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
HereIsVtArrayGimmieBinary(
|
|
VARIANT * lpVarSrcObject,
|
|
DWORD * cbBinaryBufferSize,
|
|
char **pbBinaryBuffer,
|
|
BOOL bReturnBinaryAsVT_VARIANT
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG dwSLBound = 0;
|
|
LONG dwSUBound = 0;
|
|
CHAR HUGEP *pArray = NULL;
|
|
|
|
if (NULL == cbBinaryBufferSize || NULL == pbBinaryBuffer)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto HereIsVtArrayGimmieBinary_Exit;
|
|
}
|
|
|
|
if (bReturnBinaryAsVT_VARIANT)
|
|
{
|
|
hr = VariantChangeType(lpVarSrcObject,lpVarSrcObject,0,VT_ARRAY | VT_VARIANT);
|
|
}
|
|
else
|
|
{
|
|
hr = VariantChangeType(lpVarSrcObject,lpVarSrcObject,0,VT_ARRAY | VT_UI1);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (hr != E_OUTOFMEMORY)
|
|
{
|
|
hr = OLE_E_CANTCONVERT;
|
|
}
|
|
goto HereIsVtArrayGimmieBinary_Exit;
|
|
}
|
|
|
|
if (bReturnBinaryAsVT_VARIANT)
|
|
{
|
|
if( lpVarSrcObject->vt != (VT_ARRAY | VT_VARIANT))
|
|
{
|
|
hr = OLE_E_CANTCONVERT;
|
|
goto HereIsVtArrayGimmieBinary_Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( lpVarSrcObject->vt != (VT_ARRAY | VT_UI1))
|
|
{
|
|
hr = OLE_E_CANTCONVERT;
|
|
goto HereIsVtArrayGimmieBinary_Exit;
|
|
}
|
|
}
|
|
|
|
hr = SafeArrayGetLBound(V_ARRAY(lpVarSrcObject),1,(long FAR *) &dwSLBound );
|
|
if (FAILED(hr))
|
|
{goto HereIsVtArrayGimmieBinary_Exit;}
|
|
|
|
hr = SafeArrayGetUBound(V_ARRAY(lpVarSrcObject),1,(long FAR *) &dwSUBound );
|
|
if (FAILED(hr))
|
|
{goto HereIsVtArrayGimmieBinary_Exit;}
|
|
|
|
//*pbBinaryBuffer = (LPBYTE) AllocADsMem(dwSUBound - dwSLBound + 1);
|
|
*pbBinaryBuffer = (char *) ::CoTaskMemAlloc(dwSUBound - dwSLBound + 1);
|
|
if (*pbBinaryBuffer == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto HereIsVtArrayGimmieBinary_Exit;
|
|
}
|
|
|
|
*cbBinaryBufferSize = dwSUBound - dwSLBound + 1;
|
|
|
|
hr = SafeArrayAccessData( V_ARRAY(lpVarSrcObject),(void HUGEP * FAR *) &pArray );
|
|
if (FAILED(hr))
|
|
{goto HereIsVtArrayGimmieBinary_Exit;}
|
|
|
|
memcpy(*pbBinaryBuffer,pArray,dwSUBound-dwSLBound+1);
|
|
SafeArrayUnaccessData( V_ARRAY(lpVarSrcObject) );
|
|
|
|
HereIsVtArrayGimmieBinary_Exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
CERT_CONTEXT * GetInstalledCertFromHash(HRESULT * phResult,DWORD cbHashBlob, char * pHashBlob)
|
|
{
|
|
ATLASSERT(phResult != NULL);
|
|
CERT_CONTEXT * pCert = NULL;
|
|
*phResult = S_OK;
|
|
CString store_name = _T("MY");
|
|
|
|
HCERTSTORE hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,NULL,CERT_SYSTEM_STORE_LOCAL_MACHINE,store_name);
|
|
ASSERT(hStore != NULL);
|
|
if (hStore != NULL)
|
|
{
|
|
// Now we need to find cert by hash
|
|
CRYPT_HASH_BLOB crypt_hash;
|
|
ZeroMemory(&crypt_hash, sizeof(CRYPT_HASH_BLOB));
|
|
|
|
crypt_hash.cbData = cbHashBlob;
|
|
crypt_hash.pbData = (BYTE *) pHashBlob;
|
|
pCert = (CERT_CONTEXT *)CertFindCertificateInStore(hStore,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,0,CERT_FIND_HASH,(LPVOID)&crypt_hash,NULL);
|
|
if (pCert == NULL)
|
|
{
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
VERIFY(CertCloseStore(hStore, 0));
|
|
}
|
|
else
|
|
{
|
|
*phResult = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
return pCert;
|
|
}
|
|
|
|
|
|
BOOL ViewCertificateDialog(CRYPT_HASH_BLOB* pcrypt_hash, HWND hWnd)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
HCERTSTORE hStore = NULL;
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
CString store_name = _T("MY");
|
|
|
|
|
|
hStore = CertOpenStore(
|
|
CERT_STORE_PROV_SYSTEM,
|
|
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
|
|
NULL,
|
|
CERT_SYSTEM_STORE_LOCAL_MACHINE,
|
|
store_name
|
|
);
|
|
if (hStore != NULL)
|
|
{
|
|
// Now we need to find cert by hash
|
|
//CRYPT_HASH_BLOB crypt_hash;
|
|
//crypt_hash.cbData = hash.GetSize();
|
|
//crypt_hash.pbData = hash.GetData();
|
|
pCert = CertFindCertificateInStore(hStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
0, CERT_FIND_HASH, (LPVOID)pcrypt_hash, NULL);
|
|
}
|
|
|
|
if (pCert)
|
|
{
|
|
BOOL fPropertiesChanged;
|
|
CRYPTUI_VIEWCERTIFICATE_STRUCT vcs;
|
|
HCERTSTORE hCertStore = ::CertDuplicateStore(hStore);
|
|
::ZeroMemory (&vcs, sizeof (vcs));
|
|
vcs.dwSize = sizeof (vcs);
|
|
vcs.hwndParent = hWnd;
|
|
vcs.dwFlags = 0;
|
|
vcs.cStores = 1;
|
|
vcs.rghStores = &hCertStore;
|
|
vcs.pCertContext = pCert;
|
|
::CryptUIDlgViewCertificate(&vcs, &fPropertiesChanged);
|
|
::CertCloseStore (hCertStore, 0);
|
|
bReturn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// it failed
|
|
}
|
|
if (pCert != NULL)
|
|
::CertFreeCertificateContext(pCert);
|
|
if (hStore != NULL)
|
|
::CertCloseStore(hStore, 0);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
/*
|
|
|
|
-----Original Message-----
|
|
From: Helle Vu (SPECTOR)
|
|
Sent: Friday, April 27, 2001 6:02 PM
|
|
To: Aaron Lee; Trevor Freeman
|
|
Cc: Sergei Antonov
|
|
Subject: RE: bug 31010
|
|
|
|
Perfect timing, I was just about to send you an update on this:
|
|
|
|
I talked to Trevor about this, and he suggested the best thing to do for IIS would be the following (Trevor, please double-check I got this right):
|
|
If there is an EKU, and it has serverauth, display it in the list to pick web server certs from
|
|
If no EKU, look at basic constraints:
|
|
* If we do not have basic constraints, do display it in the list to pick web server certs from
|
|
* If we do have basic constraints with Subject Type =CA, don't display it in the list to pick web server certs from (this will filter out CA certs)
|
|
* If we do have basic constraints with SubectType !=CA, do display it in the list to pick web server certs from
|
|
*/
|
|
|
|
/*
|
|
===== Opened by kshenoy on 11/13/2000 02:26PM =====
|
|
Add Existing certificate option in "Web Server Certificate Request wizard" should not list CA certificates in the filter
|
|
but only End entity certificates with "Server Authentication" EKU
|
|
|
|
Since CA certificates by default have all the EKUs the filter will list CA certificates apart from
|
|
end entity certificates with "Server Auth" EKU.
|
|
|
|
In order to check if a given certificate is a CA or end entity you can look at the Basic Constraints
|
|
extension of the certificate if present. This will be present in CA certificates and set to SubjectType=CA.
|
|
If present in end entity certificates it will be set to "ServerAuth"
|
|
*/
|
|
|
|
int CheckCertConstraints(PCCERT_CONTEXT pCC)
|
|
{
|
|
PCERT_EXTENSION pCExt;
|
|
LPCSTR pszObjId;
|
|
DWORD i;
|
|
CERT_BASIC_CONSTRAINTS_INFO *pConstraints=NULL;
|
|
CERT_BASIC_CONSTRAINTS2_INFO *p2Constraints=NULL;
|
|
DWORD ConstraintSize=0;
|
|
int ReturnValue = FAILURE;
|
|
BOOL Using2=FALSE;
|
|
void* ConstraintBlob=NULL;
|
|
|
|
pszObjId = szOID_BASIC_CONSTRAINTS;
|
|
|
|
pCExt = CertFindExtension(pszObjId,pCC->pCertInfo->cExtension,pCC->pCertInfo->rgExtension);
|
|
if (pCExt == NULL)
|
|
{
|
|
pszObjId = szOID_BASIC_CONSTRAINTS2;
|
|
pCExt = CertFindExtension(pszObjId,pCC->pCertInfo->cExtension,pCC->pCertInfo->rgExtension);
|
|
Using2=TRUE;
|
|
}
|
|
|
|
if (pCExt == NULL)
|
|
{
|
|
ReturnValue = DID_NOT_FIND_CONSTRAINT;
|
|
goto CheckCertConstraints_Exit;
|
|
}
|
|
|
|
// Decode extension
|
|
if (!CryptDecodeObject(X509_ASN_ENCODING,pCExt->pszObjId,pCExt->Value.pbData,pCExt->Value.cbData,0,NULL,&ConstraintSize))
|
|
{
|
|
goto CheckCertConstraints_Exit;
|
|
}
|
|
|
|
ConstraintBlob = malloc(ConstraintSize);
|
|
if (ConstraintBlob == NULL)
|
|
{
|
|
goto CheckCertConstraints_Exit;
|
|
}
|
|
|
|
if (!CryptDecodeObject(X509_ASN_ENCODING,pCExt->pszObjId,pCExt->Value.pbData,pCExt->Value.cbData,0,(void*)ConstraintBlob,&ConstraintSize))
|
|
{
|
|
goto CheckCertConstraints_Exit;
|
|
|
|
}
|
|
|
|
if (Using2)
|
|
{
|
|
p2Constraints=(CERT_BASIC_CONSTRAINTS2_INFO*)ConstraintBlob;
|
|
if (!p2Constraints->fCA)
|
|
{
|
|
// there is a constraint, and it's not a CA
|
|
ReturnValue = FOUND_CONSTRAINT;
|
|
}
|
|
else
|
|
{
|
|
// This is a CA. CA cannot be used as a 'server auth'
|
|
ReturnValue = FOUND_CONSTRAINT_BUT_THIS_IS_A_CA_OR_ITS_NOT_AN_END_ENTITY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pConstraints=(CERT_BASIC_CONSTRAINTS_INFO*)ConstraintBlob;
|
|
if (((pConstraints->SubjectType.cbData * 8) - pConstraints->SubjectType.cUnusedBits) >= 2)
|
|
{
|
|
if ((*pConstraints->SubjectType.pbData) & CERT_END_ENTITY_SUBJECT_FLAG)
|
|
{
|
|
// there is a valid constraint
|
|
ReturnValue = FOUND_CONSTRAINT;
|
|
}
|
|
else
|
|
{
|
|
// this is not an 'end entity' so hey -- we can't use it.
|
|
ReturnValue = FOUND_CONSTRAINT_BUT_THIS_IS_A_CA_OR_ITS_NOT_AN_END_ENTITY;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
CheckCertConstraints_Exit:
|
|
if (ConstraintBlob){free(ConstraintBlob);}
|
|
return (ReturnValue);
|
|
|
|
}
|
|
|
|
|
|
BOOL IsCertExportable(PCCERT_CONTEXT pCertContext)
|
|
{
|
|
HCRYPTPROV hCryptProv = NULL;
|
|
DWORD dwKeySpec = 0;
|
|
BOOL fCallerFreeProv = FALSE;
|
|
BOOL fReturn = FALSE;
|
|
HCRYPTKEY hKey = NULL;
|
|
DWORD dwPermissions = 0;
|
|
DWORD dwSize = 0;
|
|
|
|
if (!pCertContext)
|
|
{
|
|
fReturn = FALSE;
|
|
goto IsCertExportable_Exit;
|
|
}
|
|
|
|
//
|
|
// first get the private key context
|
|
//
|
|
if (!CryptAcquireCertificatePrivateKey(
|
|
pCertContext,
|
|
CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
|
|
NULL,
|
|
&hCryptProv,
|
|
&dwKeySpec,
|
|
&fCallerFreeProv))
|
|
{
|
|
fReturn = FALSE;
|
|
goto IsCertExportable_Exit;
|
|
}
|
|
|
|
//
|
|
// get the handle to the key
|
|
//
|
|
if (!CryptGetUserKey(hCryptProv, dwKeySpec, &hKey))
|
|
{
|
|
fReturn = FALSE;
|
|
goto IsCertExportable_Exit;
|
|
}
|
|
|
|
//
|
|
// finally, get the permissions on the key and check if it is exportable
|
|
//
|
|
dwSize = sizeof(dwPermissions);
|
|
if (!CryptGetKeyParam(hKey, KP_PERMISSIONS, (PBYTE)&dwPermissions, &dwSize, 0))
|
|
{
|
|
fReturn = FALSE;
|
|
goto IsCertExportable_Exit;
|
|
}
|
|
|
|
fReturn = (dwPermissions & CRYPT_EXPORT) ? TRUE : FALSE;
|
|
|
|
IsCertExportable_Exit:
|
|
if (hKey != NULL){CryptDestroyKey(hKey);}
|
|
if (fCallerFreeProv){CryptReleaseContext(hCryptProv, 0);}
|
|
return fReturn;
|
|
}
|
|
|
|
BOOL IsCertExportableOnRemoteMachine(CString ServerName,CString UserName,CString UserPassword,CString InstanceName)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
BOOL bPleaseDoCoUninit = FALSE;
|
|
HRESULT hResult = E_FAIL;
|
|
IIISCertObj *pTheObject = NULL;
|
|
VARIANT_BOOL varBool = VARIANT_FALSE;
|
|
|
|
BSTR bstrServerName = SysAllocString(ServerName);
|
|
BSTR bstrUserName = SysAllocString(UserName);
|
|
BSTR bstrUserPassword = SysAllocString(UserPassword);
|
|
BSTR bstrInstanceName = SysAllocString(InstanceName);
|
|
|
|
hResult = CoInitialize(NULL);
|
|
if(FAILED(hResult))
|
|
{
|
|
return bRes;
|
|
}
|
|
bPleaseDoCoUninit = TRUE;
|
|
|
|
// this one seems to work with surrogates..
|
|
hResult = CoCreateInstance(CLSID_IISCertObj,NULL,CLSCTX_SERVER,IID_IIISCertObj,(void **)&pTheObject);
|
|
if (FAILED(hResult))
|
|
{
|
|
goto InstallCopyMoveFromRemote_Exit;
|
|
}
|
|
|
|
// at this point we were able to instantiate the com object on the server (local or remote)
|
|
pTheObject->put_ServerName(bstrServerName);
|
|
pTheObject->put_UserName(bstrUserName);
|
|
pTheObject->put_UserPassword(bstrUserPassword);
|
|
pTheObject->put_InstanceName(bstrInstanceName);
|
|
|
|
hResult = pTheObject->IsInstalled(&varBool);
|
|
|
|
hResult = pTheObject->IsExportable(&varBool);
|
|
if (FAILED(hResult))
|
|
{
|
|
goto InstallCopyMoveFromRemote_Exit;
|
|
}
|
|
|
|
if (varBool == VARIANT_FALSE)
|
|
{
|
|
bRes = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bRes = TRUE;
|
|
}
|
|
|
|
InstallCopyMoveFromRemote_Exit:
|
|
if (pTheObject)
|
|
{
|
|
pTheObject->Release();
|
|
pTheObject = NULL;
|
|
}
|
|
if (bPleaseDoCoUninit)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
|
|
if (bstrServerName) {SysFreeString(bstrServerName);}
|
|
if (bstrUserName) {SysFreeString(bstrUserName);}
|
|
if (bstrUserPassword) {SysFreeString(bstrUserPassword);}
|
|
if (bstrInstanceName) {SysFreeString(bstrInstanceName);}
|
|
return bRes;
|
|
}
|
|
|
|
BOOL DumpCertDesc(char * pBlobInfo)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
|
|
IISDebugOutput(_T("blob=%s\n"),pBlobInfo);
|
|
|
|
bRes = TRUE;
|
|
return bRes;
|
|
}
|
|
|
|
|
|
BOOL GetCertDescInfo(CString ServerName,CString UserName,CString UserPassword,CString InstanceName,CERT_DESCRIPTION* desc)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
HRESULT hResult = E_FAIL;
|
|
IIISCertObj *pTheObject = NULL;
|
|
DWORD cbBinaryBufferSize = 0;
|
|
char * pbBinaryBuffer = NULL;
|
|
BOOL bPleaseDoCoUninit = FALSE;
|
|
BSTR bstrServerName = SysAllocString(ServerName);
|
|
BSTR bstrUserName = SysAllocString(UserName);
|
|
BSTR bstrUserPassword = SysAllocString(UserPassword);
|
|
BSTR bstrInstanceName = SysAllocString(InstanceName);
|
|
VARIANT VtArray;
|
|
CString csTemp;
|
|
|
|
|
|
hResult = CoInitialize(NULL);
|
|
if(FAILED(hResult))
|
|
{
|
|
return bReturn;
|
|
}
|
|
bPleaseDoCoUninit = TRUE;
|
|
|
|
// this one seems to work with surrogates..
|
|
hResult = CoCreateInstance(CLSID_IISCertObj,NULL,CLSCTX_SERVER,IID_IIISCertObj,(void **)&pTheObject);
|
|
if (FAILED(hResult))
|
|
{
|
|
goto GetCertDescInfo_Exit;
|
|
}
|
|
|
|
pTheObject->put_ServerName(bstrServerName);
|
|
pTheObject->put_UserName(bstrUserName);
|
|
pTheObject->put_UserPassword(bstrUserPassword);
|
|
pTheObject->put_InstanceName(bstrInstanceName);
|
|
|
|
hResult = pTheObject->GetCertInfo(&VtArray);
|
|
if (FAILED(hResult))
|
|
{
|
|
goto GetCertDescInfo_Exit;
|
|
}
|
|
|
|
// we have a VtArray now.
|
|
// change it back to a binary blob
|
|
hResult = HereIsVtArrayGimmieBinary(&VtArray,&cbBinaryBufferSize,&pbBinaryBuffer,FALSE);
|
|
if (FAILED(hResult))
|
|
{
|
|
goto GetCertDescInfo_Exit;
|
|
}
|
|
|
|
// Dump it out!
|
|
//DumpCertDesc(pbBinaryBuffer);
|
|
|
|
// Loop thru the buffer
|
|
// and fill up the data structure that was passed in...
|
|
// should be delimited by carriage returns...
|
|
TCHAR *token = NULL;
|
|
INT iColon = 0;
|
|
token = _tcstok((TCHAR*) pbBinaryBuffer, _T("\n"));
|
|
while (token)
|
|
{
|
|
csTemp = token;
|
|
iColon = csTemp.Find( _T('=') );
|
|
if (iColon != 0)
|
|
{
|
|
char AsciiString[255];
|
|
CString csTemp2;
|
|
|
|
csTemp2 = csTemp.Left(iColon);
|
|
WideCharToMultiByte( CP_ACP, 0, (LPCTSTR) csTemp2, -1, AsciiString, 255, NULL, NULL );
|
|
|
|
if (strcmp(AsciiString,szOID_COMMON_NAME) == 0)
|
|
{
|
|
desc->m_CommonName = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,szOID_COUNTRY_NAME) == 0)
|
|
{
|
|
desc->m_Country = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,szOID_LOCALITY_NAME) == 0)
|
|
{
|
|
desc->m_Locality = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,szOID_STATE_OR_PROVINCE_NAME) == 0)
|
|
{
|
|
desc->m_State = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,szOID_ORGANIZATION_NAME) == 0)
|
|
{
|
|
desc->m_Organization = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,szOID_ORGANIZATIONAL_UNIT_NAME) == 0)
|
|
{
|
|
desc->m_OrganizationUnit = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,"4") == 0)
|
|
{
|
|
desc->m_CAName = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,"6") == 0)
|
|
{
|
|
desc->m_ExpirationDate = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,szOID_ENHANCED_KEY_USAGE) == 0)
|
|
{
|
|
desc->m_Usage = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,szOID_SUBJECT_ALT_NAME2) == 0)
|
|
{
|
|
desc->m_AltSubject = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
if (strcmp(AsciiString,szOID_SUBJECT_ALT_NAME) == 0)
|
|
{
|
|
desc->m_AltSubject = csTemp.Right(csTemp.GetLength() - iColon - 1);
|
|
}
|
|
}
|
|
|
|
token = _tcstok(NULL, _T("\n"));
|
|
}
|
|
|
|
/*
|
|
IISDebugOutput(_T("desc.m_CommonName=%s\n"),(LPCTSTR) desc->m_CommonName);
|
|
IISDebugOutput(_T("desc.m_Country=%s\n"),(LPCTSTR) desc->m_Country);
|
|
IISDebugOutput(_T("desc.m_Locality=%s\n"),(LPCTSTR) desc->m_Locality);
|
|
IISDebugOutput(_T("desc.m_State=%s\n"),(LPCTSTR) desc->m_State);
|
|
IISDebugOutput(_T("desc.m_Organization=%s\n"),(LPCTSTR) desc->m_Organization);
|
|
IISDebugOutput(_T("desc.m_OrganizationUnit=%s\n"),(LPCTSTR) desc->m_OrganizationUnit);
|
|
IISDebugOutput(_T("desc.m_CAName=%s\n"),(LPCTSTR) desc->m_CAName);
|
|
IISDebugOutput(_T("desc.m_ExpirationDate=%s\n"),(LPCTSTR) desc->m_ExpirationDate);
|
|
IISDebugOutput(_T("desc.m_Usage=%s\n"),(LPCTSTR) desc->m_Usage);
|
|
*/
|
|
|
|
bReturn = TRUE;
|
|
|
|
GetCertDescInfo_Exit:
|
|
if (pTheObject)
|
|
{
|
|
pTheObject->Release();
|
|
pTheObject = NULL;
|
|
}
|
|
if (pbBinaryBuffer)
|
|
{
|
|
CoTaskMemFree(pbBinaryBuffer);
|
|
}
|
|
if (bPleaseDoCoUninit)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL IsWhistlerWorkstation(void)
|
|
{
|
|
BOOL WorkstationSKU = FALSE;
|
|
OSVERSIONINFOEX osvi;
|
|
//
|
|
// Determine if we are installing Personal/Professional SKU
|
|
//
|
|
ZeroMemory( &osvi, sizeof( OSVERSIONINFOEX ) );
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
GetVersionEx((OSVERSIONINFO *) &osvi);
|
|
if (osvi.wProductType == VER_NT_WORKSTATION)
|
|
{
|
|
WorkstationSKU = TRUE;
|
|
}
|
|
return WorkstationSKU;
|
|
}
|
|
|
|
|
|
void MsgboxPopup(HRESULT hResult)
|
|
{
|
|
DWORD dwFMResult;
|
|
LPTSTR szBuffer = NULL;
|
|
|
|
dwFMResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, hResult, 0,(LPTSTR) &szBuffer,0, NULL);
|
|
if (dwFMResult)
|
|
{
|
|
AfxMessageBox(szBuffer, MB_OK);
|
|
}
|
|
|
|
if (dwFMResult)
|
|
{
|
|
LocalFree(szBuffer);szBuffer=NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
CString ReturnGoodMetabaseServerPath(CString csInstanceName)
|
|
{
|
|
CString csTemp = _T("");
|
|
CString csInstanceName2 = _T("");
|
|
CString key_path = _T("");
|
|
int iPlace = 0;
|
|
//IISDebugOutput(_T("START=%s\n"),(LPCTSTR) csInstanceName);
|
|
|
|
// csInstanceName will come in looking like
|
|
// w3svc/1
|
|
// or /lm/w3svc/1
|
|
// or LM/W3SVC/1
|
|
//
|
|
// we want to it to go out as /lm/w3svc
|
|
key_path = csInstanceName;
|
|
|
|
if (!key_path.IsEmpty())
|
|
{
|
|
// Get the service name.
|
|
// which is right after the LM.
|
|
iPlace = csInstanceName.Find(SZ_MBN_MACHINE SZ_MBN_SEP_STR);
|
|
if (iPlace != -1)
|
|
{
|
|
iPlace = iPlace + _tcslen(SZ_MBN_MACHINE) + _tcslen(SZ_MBN_SEP_STR);
|
|
csTemp = csInstanceName.Right(csInstanceName.GetLength() - iPlace);
|
|
// we should now have
|
|
// "W3SVC/1"
|
|
// find the next "/"
|
|
iPlace = csTemp.Find(SZ_MBN_SEP_STR);
|
|
if (iPlace != -1)
|
|
{
|
|
csTemp = csTemp.Left(iPlace);
|
|
key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;
|
|
key_path += csTemp;
|
|
}
|
|
else
|
|
{
|
|
key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;
|
|
key_path += csTemp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// could not find a LM/
|
|
// so it must be like w3svc/1 or /w3svc/1
|
|
if (csInstanceName == SZ_MBN_SEP_STR SZ_MBN_MACHINE )
|
|
{
|
|
key_path += csInstanceName;
|
|
}
|
|
else
|
|
{
|
|
if (csInstanceName.Left(1) == SZ_MBN_SEP_STR)
|
|
{
|
|
csInstanceName2 = SZ_MBN_SEP_STR SZ_MBN_MACHINE;
|
|
}
|
|
else
|
|
{
|
|
csInstanceName2 = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;
|
|
}
|
|
csInstanceName2 += csInstanceName;
|
|
|
|
key_path = csInstanceName2;
|
|
iPlace = csInstanceName2.Find(SZ_MBN_MACHINE SZ_MBN_SEP_STR);
|
|
if (iPlace != -1)
|
|
{
|
|
iPlace = iPlace + _tcslen(SZ_MBN_MACHINE) + _tcslen(SZ_MBN_SEP_STR);
|
|
csTemp = csInstanceName2.Right(csInstanceName2.GetLength() - iPlace);
|
|
// we should now have
|
|
// "W3SVC/1"
|
|
// find the next "/"
|
|
iPlace = csTemp.Find(SZ_MBN_SEP_STR);
|
|
if (iPlace != -1)
|
|
{
|
|
csTemp = csTemp.Left(iPlace);
|
|
key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;
|
|
key_path += csTemp;
|
|
}
|
|
else
|
|
{
|
|
key_path = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;
|
|
key_path += csTemp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//IISDebugOutput(_T(" END=%s\n"),(LPCTSTR) key_path);
|
|
return key_path;
|
|
}
|
|
|
|
|
|
static const LPCSTR rgpszSubjectAltOID[] =
|
|
{
|
|
szOID_SUBJECT_ALT_NAME2,
|
|
szOID_SUBJECT_ALT_NAME
|
|
};
|
|
#define NUM_SUBJECT_ALT_OID (sizeof(rgpszSubjectAltOID) / sizeof(rgpszSubjectAltOID[0]))
|
|
|
|
void *AllocAndDecodeObject(
|
|
IN DWORD dwCertEncodingType,
|
|
IN LPCSTR lpszStructType,
|
|
IN const BYTE *pbEncoded,
|
|
IN DWORD cbEncoded,
|
|
IN DWORD dwFlags,
|
|
OUT OPTIONAL DWORD *pcbStructInfo = NULL
|
|
)
|
|
{
|
|
DWORD cbStructInfo;
|
|
void *pvStructInfo;
|
|
|
|
if (!CryptDecodeObjectEx(
|
|
dwCertEncodingType,
|
|
lpszStructType,
|
|
pbEncoded,
|
|
cbEncoded,
|
|
dwFlags | CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
|
|
NULL,
|
|
(void *) &pvStructInfo,
|
|
&cbStructInfo
|
|
))
|
|
goto ErrorReturn;
|
|
|
|
CommonReturn:
|
|
if (pcbStructInfo)
|
|
{
|
|
*pcbStructInfo = cbStructInfo;
|
|
}
|
|
return pvStructInfo;
|
|
|
|
ErrorReturn:
|
|
pvStructInfo = NULL;
|
|
cbStructInfo = 0;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Returns pointer to allocated CERT_ALT_NAME_INFO by decoding either the
|
|
// Subject or Issuer Alternative Extension. CERT_NAME_ISSUER_FLAG is
|
|
// set to select the Issuer.
|
|
//
|
|
// Returns NULL if extension not found or cAltEntry == 0
|
|
//--------------------------------------------------------------------------
|
|
PCERT_ALT_NAME_INFO AllocAndGetAltSubjectInfo(IN PCCERT_CONTEXT pCertContext)
|
|
{
|
|
DWORD cAltOID;
|
|
const LPCSTR *ppszAltOID;
|
|
|
|
PCERT_EXTENSION pExt;
|
|
PCERT_ALT_NAME_INFO pInfo;
|
|
|
|
cAltOID = NUM_SUBJECT_ALT_OID;
|
|
ppszAltOID = rgpszSubjectAltOID;
|
|
|
|
// Try to find an alternative name extension
|
|
pExt = NULL;
|
|
for ( ; cAltOID > 0; cAltOID--, ppszAltOID++)
|
|
{
|
|
if (pExt = CertFindExtension(*ppszAltOID,pCertContext->pCertInfo->cExtension,pCertContext->pCertInfo->rgExtension))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (NULL == pExt)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (NULL == (pInfo = (PCERT_ALT_NAME_INFO) AllocAndDecodeObject(pCertContext->dwCertEncodingType,X509_ALTERNATE_NAME,pExt->Value.pbData,pExt->Value.cbData,0)))
|
|
{
|
|
return NULL;
|
|
}
|
|
if (0 == pInfo->cAltEntry)
|
|
{
|
|
LocalFree(pInfo);
|
|
pInfo = NULL;
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return pInfo;
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Attempt to find the specified choice in the decoded alternative name
|
|
// extension.
|
|
//--------------------------------------------------------------------------
|
|
BOOL GetAltNameUnicodeStringChoiceW(
|
|
IN DWORD dwAltNameChoice,
|
|
IN PCERT_ALT_NAME_INFO pAltNameInfo,
|
|
OUT TCHAR **pcwszOut
|
|
)
|
|
{
|
|
DWORD cEntry;
|
|
PCERT_ALT_NAME_ENTRY pEntry;
|
|
|
|
if (NULL == pAltNameInfo)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
cEntry = pAltNameInfo->cAltEntry;
|
|
pEntry = pAltNameInfo->rgAltEntry;
|
|
for ( ; cEntry > 0; cEntry--, pEntry++)
|
|
{
|
|
if (dwAltNameChoice == pEntry->dwAltNameChoice)
|
|
{
|
|
// pwszRfc822Name union choice is the same as
|
|
// pwszDNSName and pwszURL.
|
|
|
|
// This is it, copy it out to a new allocation
|
|
if (pEntry->pwszRfc822Name)
|
|
{
|
|
*pcwszOut = NULL;
|
|
if(*pcwszOut = (TCHAR *) LocalAlloc(LPTR, sizeof(TCHAR)*(lstrlen(pEntry->pwszRfc822Name)+1)))
|
|
{
|
|
if (FAILED(StringCbCopy(*pcwszOut,sizeof(TCHAR)*(lstrlen(pEntry->pwszRfc822Name)+1),pEntry->pwszRfc822Name)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL GetAlternateSubjectName(PCCERT_CONTEXT pCertContext,TCHAR ** cwszOut)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PCERT_ALT_NAME_INFO pAltNameInfo = NULL;
|
|
*cwszOut = NULL;
|
|
|
|
pAltNameInfo = AllocAndGetAltSubjectInfo(pCertContext);
|
|
if (pAltNameInfo)
|
|
{
|
|
if (!GetAltNameUnicodeStringChoiceW(CERT_ALT_NAME_RFC822_NAME,pAltNameInfo,cwszOut))
|
|
{
|
|
if (!GetAltNameUnicodeStringChoiceW(CERT_ALT_NAME_DNS_NAME,pAltNameInfo,cwszOut))
|
|
{
|
|
cwszOut = NULL;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pAltNameInfo){LocalFree(pAltNameInfo);pAltNameInfo=NULL;}
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL IsSiteUsingThisCertHash(const CString& machine_name, const CString& server_name,CRYPT_HASH_BLOB * hash_blob,HRESULT *phResult)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
*phResult = E_FAIL;
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth,server_name,METADATA_PERMISSION_READ);
|
|
|
|
if (key.Succeeded())
|
|
{
|
|
CString store_name;
|
|
CBlob hash;
|
|
if ( SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name))
|
|
&& SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_HASH, hash))
|
|
)
|
|
{
|
|
// Now we need to find cert by hash
|
|
CRYPT_HASH_BLOB crypt_hash;
|
|
ZeroMemory(&crypt_hash, sizeof(CRYPT_HASH_BLOB));
|
|
|
|
crypt_hash.cbData = hash.GetSize();
|
|
crypt_hash.pbData = hash.GetData();
|
|
//IISDebugOutput(_T("\r\nOurHash[%p,%d]\r\nSiteHash[%p,%d]\r\n"),hash_blob->pbData,hash_blob->cbData,crypt_hash.pbData,crypt_hash.cbData);
|
|
|
|
if (hash_blob->cbData == crypt_hash.cbData)
|
|
{
|
|
// Compare with the cert hash we are looking for.
|
|
if (0 == memcmp(hash_blob->pbData, crypt_hash.pbData, hash_blob->cbData))
|
|
{
|
|
bReturn = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*phResult = key.QueryResult();
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
HRESULT EnumSitesWithThisCertHashInstalled(CRYPT_HASH_BLOB * hash_blob,CString& machine_name,CString& user_name,CString& user_password,CString strCurrentMetabaseSite,CStringListEx * MyStringList)
|
|
{
|
|
HRESULT hr;
|
|
CStringListEx strlDataPaths;
|
|
|
|
hr = EnumSitesWithCertInstalled(machine_name,user_name,user_password,strCurrentMetabaseSite,_T(""),&strlDataPaths);
|
|
if (!strlDataPaths.IsEmpty())
|
|
{
|
|
POSITION pos;
|
|
CString SiteInstance;
|
|
|
|
// loop thru the list and display all the stuff on a dialog box...
|
|
pos = strlDataPaths.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
SiteInstance = strlDataPaths.GetAt(pos);
|
|
|
|
// See if this site is using our certificate.
|
|
if (TRUE == IsSiteUsingThisCertHash(machine_name,SiteInstance,hash_blob,&hr))
|
|
{
|
|
MyStringList->AddTail(SiteInstance);
|
|
}
|
|
|
|
strlDataPaths.GetNext(pos);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetHashFromCertFile(LPCTSTR PFXFileName,LPCTSTR PFXPassword,DWORD *cbHashBufferSize,BYTE **pbHashBuffer)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BYTE * pbData = NULL;
|
|
DWORD actual = 0, cbData = 0;
|
|
BOOL bAllowExport = TRUE;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
PCCERT_CONTEXT pCertPre = NULL;
|
|
CRYPT_DATA_BLOB blob;
|
|
CRYPT_HASH_BLOB hash;
|
|
ZeroMemory(&blob, sizeof(CRYPT_DATA_BLOB));
|
|
ZeroMemory(&hash, sizeof(CRYPT_HASH_BLOB));
|
|
|
|
HANDLE hFile = CreateFile(PFXFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
hFile = NULL;
|
|
goto GetHashFromCertFile_Exit;
|
|
}
|
|
|
|
if (-1 == (cbData = ::GetFileSize(hFile, NULL)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetHashFromCertFile_Exit;
|
|
}
|
|
|
|
if (NULL == (pbData = (BYTE *)::CoTaskMemAlloc(cbData)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto GetHashFromCertFile_Exit;
|
|
}
|
|
if (FALSE == ReadFile(hFile, pbData, cbData, &actual, NULL))
|
|
{
|
|
goto GetHashFromCertFile_Exit;
|
|
}
|
|
|
|
ZeroMemory(&blob, sizeof(CRYPT_DATA_BLOB));
|
|
blob.pbData = pbData;
|
|
blob.cbData = cbData;
|
|
|
|
HCERTSTORE hStore = PFXImportCertStore(&blob, PFXPassword, (bAllowExport ? CRYPT_MACHINE_KEYSET|CRYPT_EXPORTABLE : CRYPT_MACHINE_KEYSET));
|
|
if (hStore == NULL)
|
|
{
|
|
goto GetHashFromCertFile_Exit;
|
|
}
|
|
|
|
while (SUCCEEDED(hr) && NULL != (pCertContext = CertEnumCertificatesInStore(hStore, pCertPre)))
|
|
{
|
|
//check if the certificate has the property on it
|
|
//make sure the private key matches the certificate
|
|
//search for both machine key and user keys
|
|
DWORD dwData = 0;
|
|
if (CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwData) && CryptFindCertificateKeyProvInfo(pCertContext, 0, NULL))
|
|
{
|
|
if (CertGetCertificateContextProperty(pCertContext,CERT_SHA1_HASH_PROP_ID, NULL, &hash.cbData))
|
|
{
|
|
hash.pbData = NULL;
|
|
hash.pbData = (BYTE *) LocalAlloc(LPTR,hash.cbData);
|
|
if (NULL != hash.pbData)
|
|
{
|
|
if (CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, hash.pbData, &hash.cbData))
|
|
{
|
|
// check if we need to return back the hash
|
|
if (NULL != pbHashBuffer)
|
|
{
|
|
*pbHashBuffer = (BYTE *) ::CoTaskMemAlloc(hash.cbData);
|
|
if (NULL == *pbHashBuffer)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
*pbHashBuffer = NULL;
|
|
*cbHashBufferSize = 0;
|
|
}
|
|
else
|
|
{
|
|
*cbHashBufferSize = hash.cbData;
|
|
memcpy(*pbHashBuffer,hash.pbData,hash.cbData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
pCertPre = pCertContext;
|
|
}
|
|
CertCloseStore(hStore, 0);
|
|
|
|
GetHashFromCertFile_Exit:
|
|
if (hash.pbData != NULL)
|
|
{
|
|
ZeroMemory(hash.pbData, hash.cbData);
|
|
LocalFree(hash.pbData);hash.pbData=NULL;
|
|
}
|
|
if (pCertContext != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCertContext);
|
|
}
|
|
if (pbData != NULL)
|
|
{
|
|
ZeroMemory(pbData, cbData);
|
|
::CoTaskMemFree(pbData);
|
|
}
|
|
if (hFile != NULL)
|
|
{
|
|
CloseHandle(hFile);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DisplayUsageBySitesOfCert(LPCTSTR PFXFileName,LPCTSTR PFXPassword,CString &machine_name,CString &user_name,CString &user_password,CString ¤t_site)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CRYPT_HASH_BLOB hash;
|
|
ZeroMemory(&hash, sizeof(CRYPT_HASH_BLOB));
|
|
|
|
// Try to get the certificate hash.
|
|
hr = GetHashFromCertFile(PFXFileName,PFXPassword,&(hash.cbData),&(hash.pbData));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Enum thru all our sites to see if this is being used right now...
|
|
CStringListEx MyStringList;
|
|
if (SUCCEEDED(EnumSitesWithThisCertHashInstalled(&hash,machine_name,user_name,user_password,current_site,&MyStringList)))
|
|
{
|
|
if (!MyStringList.IsEmpty())
|
|
{
|
|
POSITION pos;
|
|
CString SiteInstance;
|
|
|
|
// loop thru the list and display all the stuff on a dialog box...
|
|
pos = MyStringList.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
SiteInstance = MyStringList.GetAt(pos);
|
|
|
|
IISDebugOutput(_T("CertUsedBy:%s\r\n"),SiteInstance);
|
|
|
|
MyStringList.GetNext(pos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hash.pbData != NULL)
|
|
{
|
|
ZeroMemory(hash.pbData, hash.cbData);
|
|
::CoTaskMemFree(hash.pbData);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
BOOL IsWebServerType(CString strMetabaseNode)
|
|
{
|
|
CString spath, sname;
|
|
CMetabasePath::GetServicePath(strMetabaseNode, spath);
|
|
CMetabasePath::GetLastNodeName(spath, sname);
|
|
if (sname.CompareNoCase(SZ_MBN_WEB) == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
BuildBinding(
|
|
OUT CString & strBinding,
|
|
IN CIPAddress & iaIpAddress,
|
|
IN UINT & nTCPPort,
|
|
IN CString & strDomainName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build up a binding string from its component parts
|
|
|
|
Arguments:
|
|
|
|
CString & strBinding : Output binding string
|
|
CIPAddress & iaIpAddress : ip address (could be 0.0.0.0)
|
|
UINT & nTCPPort : TCP Port
|
|
CString & strDomainName : Domain name (host header)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
if (!iaIpAddress.IsZeroValue())
|
|
{
|
|
strBinding.Format(
|
|
_T("%s:%d:%s"),
|
|
(LPCTSTR)iaIpAddress,
|
|
nTCPPort,
|
|
(LPCTSTR)strDomainName
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Leave the ip address field blank
|
|
//
|
|
strBinding.Format(_T(":%d:%s"), nTCPPort, (LPCTSTR)strDomainName);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CrackBinding(
|
|
IN CString strBinding,
|
|
OUT CIPAddress & iaIpAddress,
|
|
OUT UINT & nTCPPort,
|
|
OUT CString & strDomainName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper function to crack a binding string
|
|
|
|
Arguments:
|
|
|
|
CString strBinding : Binding string to be parsed
|
|
CIPAddress & iaIpAddress : IP Address output
|
|
UINT & nTCPPort : TCP Port
|
|
CString & strDomainName : Domain (host) header name
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Zero initialize
|
|
//
|
|
iaIpAddress.SetZeroValue();
|
|
nTCPPort = 0;
|
|
strDomainName.Empty();
|
|
int iColonPos = strBinding.Find(_TCHAR(':'));
|
|
|
|
if(iColonPos != -1)
|
|
{
|
|
//
|
|
// Get the IP address
|
|
//
|
|
iaIpAddress = strBinding.Left(iColonPos);
|
|
|
|
//
|
|
// Look for the second colon
|
|
//
|
|
strBinding = strBinding.Mid(iColonPos + 1);
|
|
iColonPos = strBinding.Find(_TCHAR(':'));
|
|
}
|
|
|
|
if(iColonPos != -1)
|
|
{
|
|
//
|
|
// Get the port number
|
|
//
|
|
nTCPPort = ::_ttol(strBinding.Left(iColonPos));
|
|
|
|
//
|
|
// Look for the NULL termination
|
|
//
|
|
strBinding = strBinding.Mid(iColonPos + 1);
|
|
iColonPos = strBinding.Find(_TCHAR('\0'));
|
|
}
|
|
|
|
if(iColonPos != -1)
|
|
{
|
|
strDomainName = strBinding.Left(iColonPos);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WriteSSLPortToSite( const CString& machine_name,
|
|
const CString& server_name,
|
|
const CString& strSSLPort,
|
|
HRESULT * phResult)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth,server_name,METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
|
|
if (key.Succeeded())
|
|
{
|
|
CString strBinding(strSSLPort);
|
|
CString strDomainName = _T("");
|
|
CIPAddress iaIpAddress((DWORD)0);
|
|
CIPAddress iaIpAddress2((DWORD)0);
|
|
UINT nSSLPort = StrToInt(strSSLPort);
|
|
UINT nTCPPort = 0;
|
|
CString strDomainName2;
|
|
BOOL bFoundExisting = FALSE;
|
|
|
|
// Bug:761056
|
|
// if we have an existing securebindings for ssl, then use it.
|
|
CStringListEx strSecureBindings;
|
|
if SUCCEEDED(key.QueryValue(MD_SECURE_BINDINGS, strSecureBindings))
|
|
{
|
|
if (!strSecureBindings.IsEmpty())
|
|
{
|
|
CString &strBinding2 = strSecureBindings.GetHead();
|
|
nTCPPort = 0;
|
|
iaIpAddress2.SetZeroValue();
|
|
CrackBinding(strBinding2, iaIpAddress2, nTCPPort, strDomainName2);
|
|
|
|
// check if ipaddress is specified.
|
|
if (!iaIpAddress2.IsZeroValue())
|
|
{
|
|
// use the IP address that is already there...
|
|
iaIpAddress = iaIpAddress2;
|
|
bFoundExisting = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bFoundExisting)
|
|
{
|
|
// Bug:761056
|
|
// lookup to see if the IP address is specified in the Server Bindings metabase value.
|
|
// If it is then add that info to the SSL site.
|
|
CStringListEx strServerBindings;
|
|
if SUCCEEDED(key.QueryValue(MD_SERVER_BINDINGS, strServerBindings))
|
|
{
|
|
if (!strServerBindings.IsEmpty())
|
|
{
|
|
CString &strBinding2 = strServerBindings.GetHead();
|
|
nTCPPort = 0;
|
|
iaIpAddress2.SetZeroValue();
|
|
CrackBinding(strBinding2, iaIpAddress2, nTCPPort, strDomainName2);
|
|
|
|
// check if ipaddress is specified.
|
|
if (!iaIpAddress2.IsZeroValue())
|
|
{
|
|
// use the IP address that the serverbinding is using.
|
|
iaIpAddress = iaIpAddress2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BuildBinding(strBinding,iaIpAddress,nSSLPort,strDomainName);
|
|
|
|
CStringListEx strlBindings;
|
|
strlBindings.AddTail(strBinding);
|
|
bRes = SUCCEEDED(*phResult = key.SetValue(MD_SECURE_BINDINGS, strlBindings));
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("Failed to open metabase key. Error 0x%x\n"), key.QueryResult());
|
|
*phResult = key.QueryResult();
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetSSLPortFromSite(const CString& machine_name,
|
|
const CString& server_name,
|
|
CString& strSSLPort,
|
|
HRESULT * phResult)
|
|
{
|
|
ASSERT(!machine_name.IsEmpty());
|
|
ASSERT(!server_name.IsEmpty());
|
|
*phResult = S_OK;
|
|
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth,server_name,METADATA_PERMISSION_READ);
|
|
if (key.Succeeded())
|
|
{
|
|
CStringListEx strlBindings;
|
|
*phResult = key.QueryValue(MD_SECURE_BINDINGS, strlBindings);
|
|
if SUCCEEDED(*phResult)
|
|
{
|
|
if (!strlBindings.IsEmpty())
|
|
{
|
|
UINT nTCPPort = 0;
|
|
CString strDomainName;
|
|
CString &strBinding = strlBindings.GetHead();
|
|
CIPAddress iaIpAddress((DWORD)0);
|
|
CrackBinding(strBinding, iaIpAddress, nTCPPort, strDomainName);
|
|
if (nTCPPort > 0)
|
|
{
|
|
TCHAR Buf[10];
|
|
_itot(nTCPPort, Buf, 10);
|
|
strSSLPort = Buf;
|
|
}
|
|
}
|
|
}
|
|
return SUCCEEDED(*phResult);
|
|
}
|
|
else
|
|
{
|
|
*phResult = key.QueryResult();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsSSLPortBeingUsedOnNonSSLPort(const CString& machine_name,
|
|
const CString& server_name,
|
|
const CString& strSSLPort,
|
|
HRESULT * phResult)
|
|
{
|
|
ASSERT(!machine_name.IsEmpty());
|
|
ASSERT(!server_name.IsEmpty());
|
|
CString strPort;
|
|
BOOL bRet = FALSE;
|
|
*phResult = S_OK;
|
|
|
|
CComAuthInfo auth(machine_name);
|
|
CMetaKey key(&auth,server_name,METADATA_PERMISSION_READ);
|
|
if (key.Succeeded())
|
|
{
|
|
CStringListEx strlBindings;
|
|
*phResult = key.QueryValue(MD_SERVER_BINDINGS, strlBindings);
|
|
if SUCCEEDED(*phResult)
|
|
{
|
|
if (!strlBindings.IsEmpty())
|
|
{
|
|
UINT nTCPPort = 0;
|
|
CString strDomainName;
|
|
CString &strBinding = strlBindings.GetHead();
|
|
CIPAddress iaIpAddress((DWORD)0);
|
|
CrackBinding(strBinding, iaIpAddress, nTCPPort, strDomainName);
|
|
if (nTCPPort > 0)
|
|
{
|
|
TCHAR Buf[10];
|
|
_itot(nTCPPort, Buf, 10);
|
|
strPort = Buf;
|
|
}
|
|
if (strPort.IsEmpty() && strSSLPort.IsEmpty())
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (0 == strSSLPort.CompareNoCase(strPort))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*phResult = key.QueryResult();
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
#define CB_SHA_DIGEST_LEN 20
|
|
|
|
BOOL
|
|
CheckForCertificateRenewal(
|
|
DWORD dwProtocol,
|
|
PCCERT_CONTEXT pCertContext,
|
|
PCCERT_CONTEXT *ppNewCertificate)
|
|
{
|
|
BYTE rgbThumbprint[CB_SHA_DIGEST_LEN];
|
|
DWORD cbThumbprint = sizeof(rgbThumbprint);
|
|
CRYPT_HASH_BLOB HashBlob;
|
|
PCCERT_CONTEXT pNewCert;
|
|
BOOL fMachineCert;
|
|
PCRYPT_KEY_PROV_INFO pProvInfo = NULL;
|
|
DWORD cbSize;
|
|
HCERTSTORE hMyCertStore = 0;
|
|
BOOL fRenewed = FALSE;
|
|
|
|
HCERTSTORE g_hMyCertStore;
|
|
|
|
if(dwProtocol & SP_PROT_SERVERS)
|
|
{
|
|
fMachineCert = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fMachineCert = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Loop through the linked list of renewed certificates, looking
|
|
// for the last one.
|
|
//
|
|
|
|
while(TRUE)
|
|
{
|
|
//
|
|
// Check for renewal property.
|
|
//
|
|
|
|
if(!CertGetCertificateContextProperty(pCertContext,
|
|
CERT_RENEWAL_PROP_ID,
|
|
rgbThumbprint,
|
|
&cbThumbprint))
|
|
{
|
|
// Certificate has not been renewed.
|
|
break;
|
|
}
|
|
//DebugLog((DEB_TRACE, "Certificate has renewal property\n"));
|
|
|
|
|
|
//
|
|
// Determine whether to look in the local machine MY store
|
|
// or the current user MY store.
|
|
//
|
|
|
|
if(!hMyCertStore)
|
|
{
|
|
if(CertGetCertificateContextProperty(pCertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
NULL,
|
|
&cbSize))
|
|
{
|
|
|
|
pProvInfo = (PCRYPT_KEY_PROV_INFO) LocalAlloc(LPTR,cbSize);
|
|
if(pProvInfo == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(CertGetCertificateContextProperty(pCertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
pProvInfo,
|
|
&cbSize))
|
|
{
|
|
if(pProvInfo->dwFlags & CRYPT_MACHINE_KEYSET)
|
|
{
|
|
fMachineCert = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fMachineCert = FALSE;
|
|
}
|
|
}
|
|
|
|
if (pProvInfo)
|
|
{
|
|
LocalFree(pProvInfo);pProvInfo=NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Open up the appropriate MY store, and attempt to find
|
|
// the new certificate.
|
|
//
|
|
|
|
if(!hMyCertStore)
|
|
{
|
|
if(fMachineCert)
|
|
{
|
|
g_hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,X509_ASN_ENCODING,0,CERT_SYSTEM_STORE_LOCAL_MACHINE,L"MY");
|
|
if(g_hMyCertStore)
|
|
{
|
|
hMyCertStore = g_hMyCertStore;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hMyCertStore = CertOpenSystemStore(0, _T("MY"));
|
|
}
|
|
|
|
if(!hMyCertStore)
|
|
{
|
|
//DebugLog((DEB_ERROR, "Error 0x%x opening %s MY certificate store!\n", GetLastError(),(fMachineCert ? "local machine" : "current user") ));
|
|
break;
|
|
}
|
|
}
|
|
|
|
HashBlob.cbData = cbThumbprint;
|
|
HashBlob.pbData = rgbThumbprint;
|
|
|
|
pNewCert = CertFindCertificateInStore(hMyCertStore,
|
|
X509_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_HASH,
|
|
&HashBlob,
|
|
NULL);
|
|
if(pNewCert == NULL)
|
|
{
|
|
// Certificate has been renewed, but the new certificate
|
|
// cannot be found.
|
|
//DebugLog((DEB_ERROR, "New certificate cannot be found: 0x%x\n", GetLastError()));
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Return the new certificate, but first loop back and see if it's been
|
|
// renewed itself.
|
|
//
|
|
|
|
pCertContext = pNewCert;
|
|
*ppNewCertificate = pNewCert;
|
|
|
|
|
|
//DebugLog((DEB_TRACE, "Certificate has been renewed\n"));
|
|
fRenewed = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Cleanup.
|
|
//
|
|
|
|
if(hMyCertStore && hMyCertStore != g_hMyCertStore)
|
|
{
|
|
CertCloseStore(hMyCertStore, 0);
|
|
}
|
|
|
|
return fRenewed;
|
|
}
|