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.
 
 
 
 
 
 

1079 lines
32 KiB

// IISCertRequest.cpp : Implementation of CIISCertRequest
#include "stdafx.h"
#include "common.h"
#include "CertObj.h"
#include "IISCertRequest.h"
#include "base64.h"
#include "certca.h"
#include "certcli.h"
#include "certutil.h"
#include <strsafe.h>
#ifdef USE_CERT_REQUEST_OBJECT
const CLSID CLSID_CEnroll =
{0x43F8F289, 0x7A20, 0x11D0, {0x8F, 0x06, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1}};
const IID IID_IEnroll =
{0xacaa7838, 0x4585, 0x11d1, {0xab, 0x57, 0x00, 0xc0, 0x4f, 0xc2, 0x95, 0xe1}};
const IID IID_ICEnroll2 =
{0x704ca730, 0xc90b, 0x11d1, {0x9b, 0xec, 0x00, 0xc0, 0x4f, 0xc2, 0x95, 0xe1}};
const CLSID CLSID_CCertRequest =
{0x98aff3f0, 0x5524, 0x11d0, {0x88, 0x12, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
const IID IID_ICertRequest =
{0x014e4840, 0x5523, 0x11d0, {0x88, 0x12, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
// defines taken from the old KeyGen utility
#define MESSAGE_HEADER _T("-----BEGIN NEW CERTIFICATE REQUEST-----\r\n")
#define MESSAGE_TRAILER _T("-----END NEW CERTIFICATE REQUEST-----\r\n")
/////////////////////////////////////////////////////////////////////////////
// CIISCertRequest
CIISCertRequest::CIISCertRequest()
{
m_ServerName = _T("");
m_UserName = _T("");
m_UserPassword = _T("");
m_InstanceName = _T("");
m_Info_CommonName = _T("");
m_Info_FriendlyName = _T("");
m_Info_Country = _T("");
m_Info_State = _T("");
m_Info_Locality = _T("");
m_Info_Organization = _T("");
m_Info_OrganizationUnit = _T("");
m_Info_CAName = _T("");
m_Info_ExpirationDate = _T("");
m_Info_Usage = _T("");
m_Info_AltSubject = _T("");
// other
m_Info_ConfigCA = _T("");
m_Info_CertificateTemplate = wszCERTTYPE_WEBSERVER;
m_Info_DefaultProviderType = PROV_RSA_SCHANNEL;
m_Info_CustomProviderType = PROV_RSA_SCHANNEL;
m_Info_DefaultCSP = TRUE;
m_Info_CspName = _T("");
m_KeyLength = 512;
m_SGCcertificat = FALSE;
m_pEnroll = NULL;
return;
}
CIISCertRequest::~CIISCertRequest()
{
return;
}
IIISCertRequest * CIISCertRequest::GetObject(HRESULT * phr)
{
IIISCertRequest * pObj = NULL;
pObj = GetObject(phr,m_ServerName,m_UserName,m_UserPassword);
return pObj;
}
IIISCertRequest * CIISCertRequest::GetObject(HRESULT * phr,CString csServerName,CString csUserName,CString csUserPassword)
{
if (csServerName.IsEmpty())
{
// object is null, but it's the local machine, so just return back this pointer
m_pObj = this;
goto GetObject_Exit;
}
// There is a servername specified...
// check if it's the local machine that was specified!
if (IsServerLocal(csServerName))
{
m_pObj = this;
goto GetObject_Exit;
}
else
{
// there is a remote servername specified
// let's see if the machine has the com object that we want....
// we are using the user/name password that are in this object
// so were probably on the local machine
CComAuthInfo auth(csServerName,csUserName,csUserPassword);
// 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(IIISCertRequest), NULL, 0}
};
// this one seems to work with surrogates..
*phr = CoCreateInstanceEx(CLSID_IISCertRequest,NULL,CLSCTX_LOCAL_SERVER,pcsiName,1,res);
if (FAILED(*phr))
{
IISDebugOutput(_T("CIISCertRequest::GetObject:CoCreateInstanceEx failed:0x%x, csServerName=%s,csUserName=%s\n"),*phr,(LPCTSTR) csServerName,(LPCTSTR) csUserName);
goto GetObject_Exit;
}
// at this point we were able to instantiate the com object on the server (local or remote)
m_pObj = (IIISCertRequest *)res[0].pItf;
if (auth.UsesImpersonation())
{
*phr = auth.ApplyProxyBlanket(m_pObj);
// 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(m_pObj->QueryInterface(IID_IUnknown, (void **)&pUnk)))
{
goto GetObject_Exit;
}
if (FAILED(auth.ApplyProxyBlanket(pUnk)))
{
goto GetObject_Exit;
}
pUnk->Release();pUnk = NULL;
}
auth.FreeServerInfoStruct(pcsiName);
}
GetObject_Exit:
//ASSERT(m_pObj != NULL);
return m_pObj;
}
STDMETHODIMP CIISCertRequest::put_ServerName(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_ServerName = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_UserName(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_UserName = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_UserPassword(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_UserPassword = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_InstanceName(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_InstanceName = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_CommonName(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_CommonName;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_CommonName(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_CommonName = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_FriendlyName(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_FriendlyName;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_FriendlyName(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_FriendlyName = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_Country(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_Country;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_Country(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_Country = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_State(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_State;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_State(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_State = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_Locality(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_Locality;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_Locality(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_Locality = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_Organization(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_Organization;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_Organization(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_Organization = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_OrganizationUnit(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_OrganizationUnit;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_OrganizationUnit(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_OrganizationUnit = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_CAName(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_CAName;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_CAName(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_CAName = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_ExpirationDate(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_ExpirationDate;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_ExpirationDate(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_ExpirationDate = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_Usage(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_Usage;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_Usage(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_Usage = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_Info_AltSubject(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_Info_AltSubject;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_Info_AltSubject(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_Info_Usage = newVal;
return S_OK;
}
STDMETHODIMP CIISCertRequest::get_DispositionMessage(BSTR *pVal)
{
_bstr_t bstrTempName = (LPCTSTR) m_DispositionMessage;
*pVal = bstrTempName.copy();
return S_OK;
}
STDMETHODIMP CIISCertRequest::put_DispositionMessage(BSTR newVal)
{
// buffer overflow paranoia, make sure it's less than 255 characters long
if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
m_DispositionMessage = newVal;
return S_OK;
}
HRESULT CIISCertRequest::CreateDN(CString& str)
{
str.Empty();
str += _T("CN=") + m_Info_CommonName;
str += _T("\n,OU=") + m_Info_OrganizationUnit;
str += _T("\n,O=") + m_Info_Organization;
str += _T("\n,L=") + m_Info_Locality;
str += _T("\n,S=") + m_Info_State;
str += _T("\n,C=") + m_Info_Country;
return S_OK;
}
void CIISCertRequest::GetCertificateTemplate(CString& str)
{
str = _T("CertificateTemplate:");
str += m_Info_CertificateTemplate;
}
IEnroll * CIISCertRequest::GetEnrollObject()
{
if (m_pEnroll == NULL)
{
m_hResult = CoCreateInstance(CLSID_CEnroll,NULL,CLSCTX_INPROC_SERVER,IID_IEnroll,(void **)&m_pEnroll);
// now we need to change defaults for this
// object to LOCAL_MACHINE
if (m_pEnroll != NULL)
{
long dwFlags;
VERIFY(SUCCEEDED(m_pEnroll->get_MyStoreFlags(&dwFlags)));
dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
// following call will change Request store flags also
VERIFY(SUCCEEDED(m_pEnroll->put_MyStoreFlags(dwFlags)));
VERIFY(SUCCEEDED(m_pEnroll->get_GenKeyFlags(&dwFlags)));
dwFlags |= CRYPT_EXPORTABLE;
VERIFY(SUCCEEDED(m_pEnroll->put_GenKeyFlags(dwFlags)));
VERIFY(SUCCEEDED(m_pEnroll->put_KeySpec(AT_KEYEXCHANGE)));
VERIFY(SUCCEEDED(m_pEnroll->put_ProviderType(m_Info_DefaultProviderType)));
VERIFY(SUCCEEDED(m_pEnroll->put_DeleteRequestCert(TRUE)));
}
}
ASSERT(m_pEnroll != NULL);
return m_pEnroll;
}
PCCERT_CONTEXT CIISCertRequest::GetInstalledCert()
{
if (m_pInstalledCert == NULL)
{
m_pInstalledCert = ::GetInstalledCert(m_ServerName,m_InstanceName,GetEnrollObject(),&m_hResult);
}
return m_pInstalledCert;
}
PCCERT_CONTEXT CIISCertRequest::GetPendingRequest()
{
if (m_pPendingRequest == NULL)
{
ASSERT(!m_InstanceName.IsEmpty());
m_pPendingRequest = GetPendingDummyCert(m_InstanceName, GetEnrollObject(), &m_hResult);
}
return m_pPendingRequest;
}
STDMETHODIMP CIISCertRequest::SubmitRequest()
{
HRESULT hRes = E_INVALIDARG;
BOOL bTryToGetDispositionErrorString = FALSE;
ICertRequest * pCertRequest = NULL;
LONG ldisposition;
BSTR bstrRequest = NULL;
BSTR bstrOutCert = NULL;
CString strAttrib;
CString strDN;
// validate input to see that we have everything we need...
if (m_Info_ConfigCA.IsEmpty())
{
hRes = E_INVALIDARG;
goto SubmitRequest_Exit;
}
if (FAILED(hRes = CoCreateInstance(CLSID_CCertRequest, NULL, CLSCTX_INPROC_SERVER, IID_ICertRequest, (void **)&pCertRequest)))
{
goto SubmitRequest_Exit;
}
if (!pCertRequest)
{
hRes = E_FAIL;
goto SubmitRequest_Exit;
}
if (FAILED(hRes = CreateDN(strDN)))
{
goto SubmitRequest_Exit;
}
if (FAILED(hRes = CreateRequest_Base64((BSTR)(LPCTSTR)strDN, GetEnrollObject(),
m_Info_DefaultCSP ? NULL : (LPTSTR)(LPCTSTR)m_Info_CspName,
m_Info_DefaultCSP ? m_Info_DefaultProviderType : m_Info_CustomProviderType,
&bstrRequest)))
{
goto SubmitRequest_Exit;
}
bTryToGetDispositionErrorString = TRUE;
GetCertificateTemplate(strAttrib);
if (FAILED(hRes = pCertRequest->Submit(CR_IN_BASE64 | CR_IN_PKCS10, bstrRequest, (BSTR)(LPCTSTR)strAttrib, (LPTSTR)(LPCTSTR)m_Info_ConfigCA, &ldisposition)))
{
IISDebugOutput(_T("Submit bstrRequest returned HRESULT 0x%x; Disposition %x\n"), hRes, ldisposition);
goto SubmitRequest_Exit;
}
if (ldisposition != CR_DISP_ISSUED)
{
switch (ldisposition)
{
case CR_DISP_INCOMPLETE:
case CR_DISP_ERROR:
case CR_DISP_DENIED:
case CR_DISP_ISSUED_OUT_OF_BAND:
case CR_DISP_UNDER_SUBMISSION:
{
HRESULT hrLastStatus = 0;
if (SUCCEEDED(pCertRequest->GetLastStatus(&hrLastStatus)))
{
hRes = hrLastStatus;
}
}
break;
default:
{
if (SUCCEEDED(hRes))
{
hRes = E_FAIL;
}
break;
}
}
goto SubmitRequest_Exit;
}
if (FAILED(hRes = pCertRequest->GetCertificate(CR_OUT_BASE64 /*| CR_OUT_CHAIN */, &bstrOutCert)))
{
goto SubmitRequest_Exit;
}
CRYPT_DATA_BLOB blob;
blob.cbData = SysStringByteLen(bstrOutCert);
blob.pbData = (BYTE *)bstrOutCert;
if (FAILED(hRes = GetEnrollObject()->acceptPKCS7Blob(&blob)))
{
goto SubmitRequest_Exit;
}
PCCERT_CONTEXT pContext = GetCertContextFromPKCS7(blob.pbData, blob.cbData, NULL, &hRes);
ASSERT(pContext != NULL);
if (pContext != NULL)
{
BYTE HashBuffer[40]; // give it some extra size
DWORD dwHashSize = sizeof(HashBuffer);
if (CertGetCertificateContextProperty(pContext,CERT_SHA1_HASH_PROP_ID,(VOID *) HashBuffer,&dwHashSize))
{
CRYPT_HASH_BLOB hash_blob = {dwHashSize, HashBuffer};
InstallHashToMetabase(&hash_blob,m_ServerName,m_InstanceName,&hRes);
}
CertFreeCertificateContext(pContext);
}
// now put extra properties to the installed cert
if (NULL != (pContext = GetInstalledCert()))
{
if (!(AttachFriendlyName(pContext, m_Info_FriendlyName, &hRes)))
{
// forget the error if we can't attach the friendly name..
}
}
SubmitRequest_Exit:
if (FAILED(hRes))
{
// CreateRequest_Base64 failed.
// likely with "NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L)"
LPTSTR lpBuffer = NULL;
if (0 != FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL,hRes,MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR)&lpBuffer,0,NULL))
{
if (lpBuffer)
{
m_DispositionMessage = lpBuffer;
}
}
if (bTryToGetDispositionErrorString)
{
if (NULL == lpBuffer)
{
BSTR bstr = NULL;
if (SUCCEEDED(pCertRequest->GetDispositionMessage(&bstr)))
{
m_DispositionMessage = bstr;
if (bstr) {SysFreeString(bstr);}
}
}
}
if (lpBuffer) {LocalFree (lpBuffer);}
}
if (bstrOutCert)
{
SysFreeString(bstrOutCert);bstrOutCert=NULL;
}
if (bstrRequest)
{
SysFreeString(bstrRequest);bstrRequest=NULL;
}
if (pCertRequest)
{
pCertRequest->Release();pCertRequest=NULL;
}
IISDebugOutput(_T("SubmitRequest:end:hres=0x%x;\n"), hRes);
m_hResult = hRes;
return hRes;
}
// Instead of renewal we create new certificate based on parameters
// from the current one. After creation we install this certificate in place
// of current one and deleting the old one from store. Even if IIS has an
// opened SSL connection it should get a notification and update the certificate
// data.
//
STDMETHODIMP CIISCertRequest::SubmitRenewalRequest()
{
HRESULT hRes = E_FAIL;
if (LoadRenewalData())
{
if (SetSecuritySettings())
{
PCCERT_CONTEXT pCurrent = GetInstalledCert();
m_pInstalledCert = NULL;
hRes = SubmitRequest();
if (SUCCEEDED(hRes))
{
CertDeleteCertificateFromStore(pCurrent);
}
}
}
return hRes;
}
BOOL CIISCertRequest::SetSecuritySettings()
{
long dwGenKeyFlags;
if (SUCCEEDED(GetEnrollObject()->get_GenKeyFlags(&dwGenKeyFlags)))
{
dwGenKeyFlags &= 0x0000FFFF;
dwGenKeyFlags |= (m_KeyLength << 16);
if (m_SGCcertificat)
{
dwGenKeyFlags |= CRYPT_SGCKEY;
}
return (SUCCEEDED(GetEnrollObject()->put_GenKeyFlags(dwGenKeyFlags)));
}
return FALSE;
}
BOOL CIISCertRequest::GetCertDescription(PCCERT_CONTEXT pCert,CERT_DESCRIPTION& desc)
{
BOOL bRes = FALSE;
DWORD cb;
UINT i, j;
CERT_NAME_INFO * pNameInfo;
if (pCert == NULL)
goto ErrExit;
if ( !CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME,
pCert->pCertInfo->Subject.pbData,
pCert->pCertInfo->Subject.cbData,
0, NULL, &cb)
|| NULL == (pNameInfo = (CERT_NAME_INFO *)_alloca(cb))
|| !CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME,
pCert->pCertInfo->Subject.pbData,
pCert->pCertInfo->Subject.cbData,
0,
pNameInfo, &cb)
)
{
goto ErrExit;
}
for (i = 0; i < pNameInfo->cRDN; i++)
{
CERT_RDN rdn = pNameInfo->rgRDN[i];
for (j = 0; j < rdn.cRDNAttr; j++)
{
CERT_RDN_ATTR attr = rdn.rgRDNAttr[j];
if (strcmp(attr.pszObjId, szOID_COMMON_NAME) == 0)
{
FormatRdnAttr(desc.m_Info_CommonName, attr.dwValueType, attr.Value, FALSE);
}
else if (strcmp(attr.pszObjId, szOID_COUNTRY_NAME) == 0)
{
FormatRdnAttr(desc.m_Info_Country, attr.dwValueType, attr.Value, TRUE);
}
else if (strcmp(attr.pszObjId, szOID_LOCALITY_NAME) == 0)
{
FormatRdnAttr(desc.m_Info_Locality, attr.dwValueType, attr.Value, TRUE);
}
else if (strcmp(attr.pszObjId, szOID_STATE_OR_PROVINCE_NAME) == 0)
{
FormatRdnAttr(desc.m_Info_State, attr.dwValueType, attr.Value, TRUE);
}
else if (strcmp(attr.pszObjId, szOID_ORGANIZATION_NAME) == 0)
{
FormatRdnAttr(desc.m_Info_Organization, attr.dwValueType, attr.Value, TRUE);
}
else if (strcmp(attr.pszObjId, szOID_ORGANIZATIONAL_UNIT_NAME) == 0)
{
FormatRdnAttr(desc.m_Info_OrganizationUnit, attr.dwValueType, attr.Value, TRUE);
}
}
}
// issued to
if (!GetNameString(pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, desc.m_Info_CAName, &m_hResult))
{
goto ErrExit;
}
// expiration date
if (!FormatDateString(desc.m_Info_ExpirationDate, pCert->pCertInfo->NotAfter, FALSE, FALSE))
{
goto ErrExit;
}
// purpose
if (!FormatEnhancedKeyUsageString(desc.m_Info_Usage, pCert, FALSE, FALSE, &m_hResult))
{
// According to local experts, we should also use certs without this property set
ASSERT(FALSE);
//goto ErrExit;
}
// friendly name
if (!GetFriendlyName(pCert, desc.m_Info_FriendlyName, &m_hResult))
{
//desc.m_Info_FriendlyName.LoadString(IDS_FRIENDLYNAME_NONE);
desc.m_Info_FriendlyName = _T("<>");
}
// get the alternate subject name if subject is empty
// will use this as display only if subject name does not exist.
if (desc.m_Info_CommonName.IsEmpty())
{
TCHAR * pwszOut = NULL;
GetAlternateSubjectName(pCert,&pwszOut);
if (pwszOut)
{
desc.m_Info_AltSubject = pwszOut;
LocalFree(pwszOut);pwszOut = NULL;
}
}
bRes = TRUE;
ErrExit:
return bRes;
}
BOOL CIISCertRequest::LoadRenewalData()
{
// we need to obtain data from the installed cert
CERT_DESCRIPTION desc;
ASSERT(GetInstalledCert() != NULL);
BOOL res = FALSE;
DWORD cbData;
BYTE * pByte = NULL;
DWORD len = 0;
if (!GetCertDescription(GetInstalledCert(), desc))
{
res = FALSE;
goto ErrorExit;
}
m_Info_CommonName = desc.m_Info_CommonName;
m_Info_FriendlyName = desc.m_Info_FriendlyName;
m_Info_Country = desc.m_Info_Country;
m_Info_State = desc.m_Info_State;
m_Info_Locality = desc.m_Info_Locality;
m_Info_Organization = desc.m_Info_Organization;
m_Info_OrganizationUnit = desc.m_Info_OrganizationUnit;
len = CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &GetInstalledCert()->pCertInfo->SubjectPublicKeyInfo);
if (len == 0)
{
m_hResult = HRESULT_FROM_WIN32(GetLastError());
goto ErrorExit;
}
//
m_KeyLength = len;
// compare property value
if (CertGetCertificateContextProperty(GetInstalledCert(), CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbData)
&& (NULL != (pByte = (BYTE *)_alloca(cbData)))
&& CertGetCertificateContextProperty(GetInstalledCert(), CERT_KEY_PROV_INFO_PROP_ID, pByte, &cbData)
)
{
CRYPT_KEY_PROV_INFO * pProvInfo = (CRYPT_KEY_PROV_INFO *)pByte;
if (pProvInfo->dwProvType != m_Info_DefaultProviderType)
{
m_Info_DefaultCSP = FALSE;
m_Info_CustomProviderType = pProvInfo->dwProvType;
m_Info_CspName = pProvInfo->pwszProvName;
}
LPCSTR rgbpszUsageArray[2];
SecureZeroMemory( &rgbpszUsageArray, sizeof(rgbpszUsageArray) );
rgbpszUsageArray[0] = szOID_SERVER_GATED_CRYPTO;
rgbpszUsageArray[1] = szOID_SGC_NETSCAPE;
DWORD dwCount=sizeof(rgbpszUsageArray)/sizeof(rgbpszUsageArray[0]);
m_SGCcertificat = FALSE;
if (1 == ContainsKeyUsageProperty(GetInstalledCert(),rgbpszUsageArray,dwCount,&m_hResult))
{
m_SGCcertificat = TRUE;
}
res = TRUE;
}
else
{
m_hResult = HRESULT_FROM_WIN32(GetLastError());
goto ErrorExit;
}
ErrorExit:
return res;
}
BOOL CIISCertRequest::PrepareRequestString(CString& request_text, CCryptBlob& request_blob, BOOL bLoadFromRenewalData)
{
BOOL bReturn = FALSE;
CString strDN;
LPSTR pNewMessage = NULL;
TCHAR szUsage[] = _T(szOID_PKIX_KP_SERVER_AUTH);
if (TRUE == bLoadFromRenewalData)
{
if (FALSE == LoadRenewalData())
{
goto PrepareRequestString_Exit;
}
if (FALSE == SetSecuritySettings())
{
goto PrepareRequestString_Exit;
}
}
CreateDN(strDN);
ASSERT(!strDN.IsEmpty());
GetEnrollObject()->put_ProviderType(m_Info_DefaultCSP ? m_Info_DefaultProviderType : m_Info_CustomProviderType);
if (!m_Info_DefaultCSP)
{
GetEnrollObject()->put_ProviderNameWStr((LPTSTR)(LPCTSTR)m_Info_CspName);
// We are supporting only these two types of CSP, it is pretty safe to
// have just two options, because we are using the same two types when
// we are populating CSP selection list.
if (m_Info_CustomProviderType == PROV_DH_SCHANNEL)
{
GetEnrollObject()->put_KeySpec(AT_SIGNATURE);
}
else if (m_Info_CustomProviderType == PROV_RSA_SCHANNEL)
{
GetEnrollObject()->put_KeySpec(AT_KEYEXCHANGE);
}
}
if (FAILED(m_hResult = GetEnrollObject()->createPKCS10WStr((LPTSTR)(LPCTSTR)strDN,szUsage,request_blob)))
{
goto PrepareRequestString_Exit;
}
// BASE64 encode pkcs 10
DWORD cch = 0;
TCHAR * psz = NULL;
if (FAILED(Base64EncodeW(request_blob.GetData(), request_blob.GetSize(), NULL, &cch)))
{
goto PrepareRequestString_Exit;
}
psz = (TCHAR *) LocalAlloc(LPTR, (cch+1) * sizeof(TCHAR));
if (NULL == psz)
{
goto PrepareRequestString_Exit;
}
if (FAILED(Base64EncodeW(request_blob.GetData(), request_blob.GetSize(), psz, &cch)))
{
goto PrepareRequestString_Exit;
}
psz[cch] = '\0';
request_text = MESSAGE_HEADER;
request_text += psz;
request_text += MESSAGE_TRAILER;
bReturn = TRUE;
PrepareRequestString_Exit:
if (psz){LocalFree(psz);psz=NULL;}
return bReturn;
}
BOOL CIISCertRequest::WriteRequestString(CString& request)
{
ASSERT(!PathIsRelative(m_ReqFileName));
BOOL bRes = FALSE;
TCHAR szPath[_MAX_PATH];
if (m_ReqFileName.GetLength() > _MAX_PATH)
{
m_hResult = E_INVALIDARG;
return FALSE;
}
StringCbCopy(szPath,sizeof(szPath),m_ReqFileName);
PathRemoveFileSpec(szPath);
if (!PathIsDirectory(szPath))
{
if (!CreateDirectoryFromPath(szPath, NULL))
{
m_hResult = HRESULT_FROM_WIN32(GetLastError());
return FALSE;
}
}
HANDLE hFile = ::CreateFile(m_ReqFileName,GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD cb = request.GetLength();
char * ascii_buf = (char *) LocalAlloc(LPTR,cb);
if (ascii_buf)
{
wcstombs(ascii_buf, request, cb);
bRes = ::WriteFile(hFile, ascii_buf, cb, &cb, NULL);
::CloseHandle(hFile);
LocalFree(ascii_buf);ascii_buf=NULL;
}
else
{
m_hResult = HRESULT_FROM_WIN32(GetLastError());
}
}
else
{
m_hResult = HRESULT_FROM_WIN32(GetLastError());
}
return bRes;
}
STDMETHODIMP CIISCertRequest::SaveRequestToFile()
{
HRESULT hRes = E_FAIL;
CString request_text;
CCryptBlobIMalloc request_blob;
CCryptBlobLocal name_blob, request_store_blob, status_blob;
PCERT_REQUEST_INFO pReqInfo = NULL;
HCERTSTORE hStore = NULL;
PCCERT_CONTEXT pDummyCert = NULL;
// AARONL CHANGED
BOOL bLoadFromRenewalData = FALSE;
IISDebugOutput(_T("SaveRequestToFile:start\r\n"));
if (!PrepareRequestString(request_text,request_blob,bLoadFromRenewalData))
{
goto SaveRequestToFile_Exit;
}
if (!WriteRequestString(request_text))
{
goto SaveRequestToFile_Exit;
}
// prepare data we want to attach to dummy request
if (!EncodeString(m_InstanceName, name_blob, &hRes))
{
goto SaveRequestToFile_Exit;
}
if (!EncodeInteger(m_status_code, status_blob, &hRes))
{
goto SaveRequestToFile_Exit;
}
// get back request from encoded data
if (!GetRequestInfoFromPKCS10(request_blob, &pReqInfo, &hRes))
{
goto SaveRequestToFile_Exit;
}
// find dummy cert put to request store by createPKCS10 call
hStore = OpenRequestStore(GetEnrollObject(), &hRes);
if (NULL == hStore)
{
goto SaveRequestToFile_Exit;
}
pDummyCert = CertFindCertificateInStore(hStore,CRYPT_ASN_ENCODING,0,CERT_FIND_PUBLIC_KEY,(void *)&pReqInfo->SubjectPublicKeyInfo,NULL);
if (NULL == pDummyCert)
{
goto SaveRequestToFile_Cleanup;
}
if (!CertSetCertificateContextProperty(pDummyCert,CERTWIZ_INSTANCE_NAME_PROP_ID, 0, name_blob))
{
hRes = HRESULT_FROM_WIN32(GetLastError());
goto SaveRequestToFile_Cleanup;
}
if (!CertSetCertificateContextProperty(pDummyCert,CERTWIZ_REQUEST_FLAG_PROP_ID, 0, status_blob))
{
hRes = HRESULT_FROM_WIN32(GetLastError());
goto SaveRequestToFile_Cleanup;
}
// put friendly name to dummy cert -- we will reuse it later
if (!AttachFriendlyName(pDummyCert, m_Info_FriendlyName, &hRes))
{
hRes = HRESULT_FROM_WIN32(GetLastError());
goto SaveRequestToFile_Cleanup;
}
hRes = S_OK;
// put certificate text to the clipboard
if (OpenClipboard(GetFocus()))
{
size_t len = request_text.GetLength() + 1;
HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
LPSTR pMem = (LPSTR)GlobalLock(hMem);
if (pMem != NULL)
{
wcstombs(pMem, request_text, len);
GlobalUnlock(hMem);
SetClipboardData(CF_TEXT, hMem);
}
CloseClipboard();
}
SaveRequestToFile_Cleanup:
if (NULL != pDummyCert)
{
CertFreeCertificateContext(pDummyCert);pDummyCert = NULL;
}
if (NULL != hStore)
{
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);hStore = NULL;
}
SaveRequestToFile_Exit:
if (pReqInfo)
{
LocalFree(pReqInfo);pReqInfo = NULL;
}
m_hResult = hRes;
IISDebugOutput(_T("SaveRequestToFile:end ret=0x%x\r\n"),m_hResult);
return hRes;
}
STDMETHODIMP CIISCertRequest::Info_Dump()
{
m_ReqFileName = _T("c:\\reqtest1.txt");
IISDebugOutput(_T("m_ServerName:%s\r\n"),(LPCTSTR) m_ServerName);
IISDebugOutput(_T("m_UserName:%s\r\n"),(LPCTSTR) m_UserName);
//IISDebugOutput(_T("m_UserPassword:%s\r\n"),(LPCTSTR) m_UserPassword);
IISDebugOutput(_T("m_InstanceName:%s\r\n"),(LPCTSTR) m_InstanceName);
// Certificate Request Info
IISDebugOutput(_T("m_Info_CommonName=:%s\r\n"),(LPCTSTR) m_Info_CommonName);
IISDebugOutput(_T("m_Info_FriendlyName:%s\r\n"),(LPCTSTR) m_Info_FriendlyName);
IISDebugOutput(_T("m_Info_Country:%s\r\n"),(LPCTSTR) m_Info_Country);
IISDebugOutput(_T("m_Info_State:%s\r\n"),(LPCTSTR) m_Info_State);
IISDebugOutput(_T("m_Info_Locality:%s\r\n"),(LPCTSTR) m_Info_Locality);
IISDebugOutput(_T("m_Info_Organization:%s\r\n"),(LPCTSTR) m_Info_Organization);
IISDebugOutput(_T("m_Info_OrganizationUnit:%s\r\n"),(LPCTSTR) m_Info_OrganizationUnit);
IISDebugOutput(_T("m_Info_CAName:%s\r\n"),(LPCTSTR) m_Info_CAName);
IISDebugOutput(_T("m_Info_ExpirationDate:%s\r\n"),(LPCTSTR) m_Info_ExpirationDate);
IISDebugOutput(_T("m_Info_Usage:%s\r\n"),(LPCTSTR) m_Info_Usage);
IISDebugOutput(_T("m_Info_AltSubject:%s\r\n"),(LPCTSTR) m_Info_AltSubject);
// other
IISDebugOutput(_T("m_Info_ConfigCA:%s\r\n"),(LPCTSTR) m_Info_ConfigCA);
IISDebugOutput(_T("m_Info_CertificateTemplate:%s\r\n"),(LPCTSTR) m_Info_CertificateTemplate);
IISDebugOutput(_T("m_Info_DefaultProviderType:%d\r\n"),m_Info_DefaultProviderType);
IISDebugOutput(_T("m_Info_CustomProviderType:%d\r\n"),m_Info_CustomProviderType);
IISDebugOutput(_T("m_Info_DefaultCSP:%d\r\n"), m_Info_DefaultCSP);
IISDebugOutput(_T("m_Info_CspName:%s\r\n"),(LPCTSTR) m_Info_CspName);
IISDebugOutput(_T("m_pInstalledCert:%p\r\n"), m_pInstalledCert);
IISDebugOutput(_T("m_ReqFileName:%s\r\n"),(LPCTSTR) m_ReqFileName);
IISDebugOutput(_T("m_hResult:0x%x\r\n"), m_hResult);
IISDebugOutput(_T("m_DispositionMessage:%s\r\n"),(LPCTSTR) m_DispositionMessage);
return S_OK;
}
#endif