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.
 
 
 
 
 
 

3981 lines
88 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows NT
//
// Copyright (C) Microsoft Corporation, 1995 - 1998
//
// File: cepca.cpp
//
// Contents: Cisco enrollment protocal implementation.
// This file has the control's (ra) specific code.
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
//--------------------------------------------------------------------------
//
// FreeRAInformation
//
//--------------------------------------------------------------------------
BOOL FreeRAInformation(CEP_RA_INFO *pRAInfo)
{
if(pRAInfo)
{
if(pRAInfo->fFree)
{
if(pRAInfo->hRAProv)
CryptReleaseContext(pRAInfo->hRAProv, 0);
}
if(pRAInfo->fSignFree)
{
if(pRAInfo->hSignProv)
CryptReleaseContext(pRAInfo->hSignProv, 0);
}
if(pRAInfo->pRACert)
CertFreeCertificateContext(pRAInfo->pRACert);
if(pRAInfo->pRASign)
CertFreeCertificateContext(pRAInfo->pRASign);
memset(pRAInfo, 0, sizeof(CEP_RA_INFO));
}
return TRUE;
}
/*
//--------------------------------------------------------------------------
//
// GetRAInfo
//
//--------------------------------------------------------------------------
BOOL GetRAInfo(CEP_RA_INFO *pRAInfo)
{
BOOL fResult = FALSE;
HCERTSTORE hCEPStore=NULL;
DWORD dwSize=0;
DWORD dwIndex=0;
HANDLE hThread=NULL; //no need to close
HANDLE hToken=NULL;
HCERTSTORE hSignStore=NULL;
CERT_ENHKEY_USAGE *pKeyUsage = NULL;
memset(pRAInfo, 0, sizeof(CEP_RA_INFO));
// so we can get access to the local machine's private key
hThread=GetCurrentThread();
if(NULL != hThread)
{
if(OpenThreadToken(hThread,
TOKEN_IMPERSONATE | TOKEN_QUERY,
FALSE,
&hToken))
{
if(hToken)
{
//no need to check for return here. If this failed, just go on
RevertToSelf();
}
}
}
//sign RA
if(!(hSignStore=CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
ENCODE_TYPE,
NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
L"CEPSIGN")))
goto TraceErr;
if(!(pRAInfo->pRASign=CertEnumCertificatesInStore(
hSignStore,
NULL)))
goto TraceErr;
//the RA cert should have private key and enrollment agent usage
dwSize=0;
if(!CertGetCertificateContextProperty(
pRAInfo->pRASign,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&dwSize) || (0==dwSize))
goto InvalidArgErr;
if(!CryptAcquireCertificatePrivateKey(pRAInfo->pRASign,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_CACHE_FLAG,
NULL,
&(pRAInfo->hSignProv),
&(pRAInfo->dwSignKeySpec),
&(pRAInfo->fSignFree)))
goto TraceErr;
//exchange RA
if(!(hCEPStore=CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
ENCODE_TYPE,
NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
CEP_STORE_NAME)))
goto TraceErr;
if(!(pRAInfo->pRACert=CertEnumCertificatesInStore(
hCEPStore,
NULL)))
goto TraceErr;
//the RA cert should have private key and enrollment agent usage
dwSize=0;
if(!CertGetCertificateContextProperty(
pRAInfo->pRACert,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&dwSize) || (0==dwSize))
goto InvalidArgErr;
if(!CryptAcquireCertificatePrivateKey(pRAInfo->pRACert,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_CACHE_FLAG,
NULL,
&(pRAInfo->hRAProv),
&(pRAInfo->dwKeySpec),
&(pRAInfo->fFree)))
goto TraceErr;
if(!CertGetEnhancedKeyUsage(pRAInfo->pRACert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
NULL,
&dwSize))
goto InvalidArgErr;
if(NULL==(pKeyUsage=(CERT_ENHKEY_USAGE *)malloc(dwSize)))
goto MemoryErr;
if (!CertGetEnhancedKeyUsage(pRAInfo->pRACert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
pKeyUsage,
&dwSize))
goto InvalidArgErr;
for(dwIndex=0; dwIndex < pKeyUsage->cUsageIdentifier; dwIndex++)
{
if(0 == strcmp(pKeyUsage->rgpszUsageIdentifier[dwIndex], szOID_ENROLLMENT_AGENT))
{
fResult=TRUE;
break;
}
}
if(!fResult)
goto ErrorReturn;
CommonReturn:
if(hCEPStore)
CertCloseStore(hCEPStore, 0);
if(hSignStore)
CertCloseStore(hSignStore, 0);
if(pKeyUsage)
free(pKeyUsage);
//if hToken is valid, we reverted to ourselves.
if(hToken)
{
SetThreadToken(&hThread, hToken);
CloseHandle(hToken);
}
return fResult;
ErrorReturn:
FreeRAInformation(pRAInfo);
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
TRACE_ERROR(TraceErr);
} */
//--------------------------------------------------------------------------
//
// SigningCert
//
//--------------------------------------------------------------------------
BOOL WINAPI SigningCert(PCCERT_CONTEXT pCertContext)
{
BOOL fSign=FALSE;
PCERT_EXTENSION pExt=NULL;
DWORD cbSize=0;
CRYPT_BIT_BLOB *pKeyUsage=NULL;
if(!pCertContext)
goto CLEANUP;
if(!(pExt=CertFindExtension(
szOID_KEY_USAGE,
pCertContext->pCertInfo->cExtension,
pCertContext->pCertInfo->rgExtension)))
goto CLEANUP;
if(!CryptDecodeObject(ENCODE_TYPE,
X509_KEY_USAGE,
pExt->Value.pbData,
pExt->Value.cbData,
0,
NULL,
&cbSize))
goto CLEANUP;
pKeyUsage=(CRYPT_BIT_BLOB *)malloc(cbSize);
if(NULL==pKeyUsage)
goto CLEANUP;
if(!CryptDecodeObject(ENCODE_TYPE,
X509_KEY_USAGE,
pExt->Value.pbData,
pExt->Value.cbData,
0,
pKeyUsage,
&cbSize))
goto CLEANUP;
if(CERT_DIGITAL_SIGNATURE_KEY_USAGE & (pKeyUsage->pbData[0]))
fSign=TRUE;
CLEANUP:
if(pKeyUsage)
free(pKeyUsage);
return fSign;
}
//--------------------------------------------------------------------------
//
// GetConfigInfo
//
//--------------------------------------------------------------------------
BOOL WINAPI GetConfigInfo(DWORD *pdwRefreshDays, BOOL *pfPassword)
{
DWORD cbData=0;
DWORD dwData=0;
DWORD dwType=0;
BOOL fResult=FALSE;
long dwErr=0;
HKEY hKeyRefresh=NULL;
HKEY hKeyPassword=NULL;
if(!pdwRefreshDays || !pfPassword)
goto InvalidArgErr;
//default the refresh days
*pdwRefreshDays=CEP_REFRESH_DAY;
*pfPassword=FALSE;
if(ERROR_SUCCESS == RegOpenKeyExU(
HKEY_LOCAL_MACHINE,
MSCEP_REFRESH_LOCATION,
0,
KEY_READ,
&hKeyRefresh))
{
cbData=sizeof(dwData);
if(ERROR_SUCCESS == RegQueryValueExU(
hKeyRefresh,
MSCEP_KEY_REFRESH,
NULL,
&dwType,
(BYTE *)&dwData,
&cbData))
{
if ((dwType == REG_DWORD) ||
(dwType == REG_BINARY))
{
*pdwRefreshDays=dwData;
}
}
}
dwType=0;
dwData=0;
cbData=sizeof(dwData);
//we have to have the knowledge of the password policy
if(ERROR_SUCCESS != (dwErr = RegOpenKeyExU(
HKEY_LOCAL_MACHINE,
MSCEP_PASSWORD_LOCATION,
0,
KEY_READ,
&hKeyPassword)))
goto RegErr;
if(ERROR_SUCCESS != (dwErr = RegQueryValueExU(
hKeyPassword,
MSCEP_KEY_PASSWORD,
NULL,
&dwType,
(BYTE *)&dwData,
&cbData)))
goto RegErr;
if ((dwType != REG_DWORD) &&
(dwType != REG_BINARY))
goto RegErr;
if(0 == dwData)
*pfPassword=FALSE;
else
*pfPassword=TRUE;
fResult=TRUE;
CommonReturn:
if(hKeyRefresh)
RegCloseKey(hKeyRefresh);
if(hKeyPassword)
RegCloseKey(hKeyPassword);
return fResult;
ErrorReturn:
if(pdwRefreshDays)
*pdwRefreshDays=0;
if(pfPassword)
*pfPassword=FALSE;
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR_VAR(RegErr, dwErr);
}
//--------------------------------------------------------------------------
//
// GetRAInfo
//
// We need to have two RA cert: One for signature cert (also the enrollment
// agent) and one for the key encipherment.
//--------------------------------------------------------------------------
BOOL GetRAInfo(CEP_RA_INFO *pRAInfo)
{
BOOL fResult = FALSE;
BOOL fFound = FALSE;
DWORD dwSize=0;
DWORD dwIndex=0;
HANDLE hThread=NULL; //no need to close
PCCERT_CONTEXT pPreCert=NULL;
HCERTSTORE hCEPStore=NULL;
CERT_ENHKEY_USAGE *pKeyUsage = NULL;
PCCERT_CONTEXT pCurCert=NULL;
HANDLE hToken=NULL;
memset(pRAInfo, 0, sizeof(CEP_RA_INFO));
if(!GetConfigInfo(&(pRAInfo->dwRefreshDays), &(pRAInfo->fPassword)))
goto TraceErr;
// so we can get access to the local machine's private key
hThread=GetCurrentThread();
if(NULL != hThread)
{
if(OpenThreadToken(hThread,
TOKEN_IMPERSONATE | TOKEN_QUERY,
FALSE,
&hToken))
{
if(hToken)
{
//no need to check for return here. If this failed, just go on
RevertToSelf();
}
}
}
if(!(hCEPStore=CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
ENCODE_TYPE,
NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
CEP_STORE_NAME)))
goto TraceErr;
while(pCurCert=CertEnumCertificatesInStore(hCEPStore,
pPreCert))
{
//has to have a private key
dwSize=0;
if(!CertGetCertificateContextProperty(
pCurCert,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&dwSize) || (0==dwSize))
goto InvalidArgErr;
//decide based on the key usage
if(SigningCert(pCurCert))
{
//one signing RA Only
if(pRAInfo->pRASign)
goto InvalidArgErr;
if(!(pRAInfo->pRASign=CertDuplicateCertificateContext(pCurCert)))
goto TraceErr;
if(!CryptAcquireCertificatePrivateKey(pRAInfo->pRASign,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_CACHE_FLAG,
NULL,
&(pRAInfo->hSignProv),
&(pRAInfo->dwSignKeySpec),
&(pRAInfo->fSignFree)))
goto TraceErr;
//has to have the enrollment agent eku
dwSize=0;
if(!CertGetEnhancedKeyUsage(pCurCert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
NULL,
&dwSize))
goto InvalidArgErr;
if(NULL==(pKeyUsage=(CERT_ENHKEY_USAGE *)malloc(dwSize)))
goto MemoryErr;
if (!CertGetEnhancedKeyUsage(pCurCert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
pKeyUsage,
&dwSize))
goto InvalidArgErr;
fFound=FALSE;
for(dwIndex=0; dwIndex < pKeyUsage->cUsageIdentifier; dwIndex++)
{
if(0 == strcmp(pKeyUsage->rgpszUsageIdentifier[dwIndex], szOID_ENROLLMENT_AGENT))
{
fFound=TRUE;
break;
}
}
if(!fFound)
goto InvalidArgErr;
}
else
{
//one encryption RA only
if(pRAInfo->pRACert)
goto InvalidArgErr;
if(!(pRAInfo->pRACert=CertDuplicateCertificateContext(pCurCert)))
goto TraceErr;
if(!CryptAcquireCertificatePrivateKey(pRAInfo->pRACert,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_CACHE_FLAG,
NULL,
&(pRAInfo->hRAProv),
&(pRAInfo->dwKeySpec),
&(pRAInfo->fFree)))
goto TraceErr;
}
if(pKeyUsage)
{
free(pKeyUsage);
pKeyUsage=NULL;
}
pPreCert=pCurCert;
}
//we have to have both RA certs
if((NULL == pRAInfo->pRACert) ||
(NULL == pRAInfo->pRASign))
goto InvalidArgErr;
fResult=TRUE;
CommonReturn:
if(hCEPStore)
CertCloseStore(hCEPStore, 0);
if(pKeyUsage)
free(pKeyUsage);
//if hToken is valid, we reverted to ourselves.
if(hToken)
{
SetThreadToken(&hThread, hToken);
CloseHandle(hToken);
}
if(pCurCert)
CertFreeCertificateContext(pCurCert);
return fResult;
ErrorReturn:
FreeRAInformation(pRAInfo);
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
TRACE_ERROR(TraceErr);
}
//--------------------------------------------------------------------------
//
// OperationGetPKI
//
//--------------------------------------------------------------------------
BOOL OperationGetPKI( CEP_RA_INFO *pRAInfo,
CEP_CA_INFO *pCAInfo,
LPSTR szMsg,
BYTE **ppbData,
DWORD *pcbData)
{
BOOL fResult = FALSE;
CEP_MESSAGE_INFO MsgInfo;
DWORD cbContent=0;
DWORD cbEnvelop=1;
BYTE bFoo=0;
BYTE *pbContent=NULL;
BYTE *pbEnvelop=&bFoo;
memset(&MsgInfo, 0, sizeof(CEP_MESSAGE_INFO));
if(!GetReturnInfoAndContent(pRAInfo, pCAInfo, szMsg, &pbContent, &cbContent, &MsgInfo))
goto TraceErr;
//envelop the data
if(MESSAGE_STATUS_SUCCESS == MsgInfo.dwStatus)
{
if(!EnvelopData(MsgInfo.pSigningCert, pbContent, cbContent,
&pbEnvelop, &cbEnvelop))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_TO_ENCRYPT, 1, g_pwszComputerName);
goto TraceErr;
}
}
//sign the data with authenticated attributes
//when the dwStatus is not SUCCESS, the pbEnvelop is NULL and cbEnvelop is 0.
if(!SignData(&MsgInfo, pRAInfo, pbEnvelop, cbEnvelop, ppbData, pcbData))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_TO_SIGN, 1, g_pwszComputerName);
goto TraceErr;
}
fResult = TRUE;
CommonReturn:
if(pbContent)
free(pbContent);
if(&bFoo != pbEnvelop)
free(pbEnvelop);
FreeMessageInfo(&MsgInfo);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
}
//--------------------------------------------------------------------------
//
// SignData
//
// the messageType is always response and the senderNonce should be generated
// in case the pending and failure, pbEnvelop will be NULL.
//
// In the initial GetContentFromPKCS7, we retrive MessageType, TransactionID,
// RecipientNonce, signing Cert serial number.
//
// In the process, we get the dwStatus and dwErrorInfo when applicable.
////--------------------------------------------------------------------------
BOOL SignData(CEP_MESSAGE_INFO *pMsgInfo,
CEP_RA_INFO *pRAInfo,
BYTE *pbEnvelop,
DWORD cbEnvelop,
BYTE **ppbData,
DWORD *pcbData)
{
BOOL fResult = FALSE;
CMSG_SIGNER_ENCODE_INFO SignerInfo;
CMSG_SIGNED_ENCODE_INFO SignEncodedInfo;
CERT_BLOB CertBlob;
BOOL fProvFree=FALSE;
PCCRYPT_OID_INFO pOIDInfo=NULL;
ALG_ID AlgValue=CALG_MD5;
DWORD cAttr=0;
CRYPT_ATTR_BLOB rgAttrBlob[CEP_RESPONSE_AUTH_ATTR_COUNT];
DWORD dwIndex=0;
HCRYPTMSG hMsg=NULL;
CRYPT_ATTRIBUTE rgAttr[CEP_RESPONSE_AUTH_ATTR_COUNT];
if(!pMsgInfo || !pRAInfo || !ppbData || !pcbData)
goto InvalidArgErr;
*ppbData=NULL;
*pcbData=0;
pMsgInfo->dwMessageType=MESSAGE_TYPE_CERT_RESPONSE;
if(!GenerateSenderNonce(&(pMsgInfo->SenderNonce)))
goto TraceErr;
memset(&SignerInfo, 0, sizeof(SignerInfo));
memset(&SignEncodedInfo, 0, sizeof(SignEncodedInfo));
SignEncodedInfo.cbSize=sizeof(SignEncodedInfo);
SignEncodedInfo.cSigners=1;
SignEncodedInfo.rgSigners=&SignerInfo,
/* SignEncodedInfo.cCertEncoded=1;
SignEncodedInfo.rgCertEncoded=&CertBlob; */
SignEncodedInfo.cCertEncoded=0;
SignEncodedInfo.rgCertEncoded=NULL;
SignEncodedInfo.cCrlEncoded=0;
SignEncodedInfo.rgCrlEncoded=NULL;
CertBlob.cbData=pRAInfo->pRASign->cbCertEncoded;
CertBlob.pbData=pRAInfo->pRASign->pbCertEncoded;
SignerInfo.cbSize=sizeof(SignerInfo);
SignerInfo.pCertInfo=pRAInfo->pRASign->pCertInfo;
//specify AlgID
if(pOIDInfo=CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY,
&AlgValue,
CRYPT_HASH_ALG_OID_GROUP_ID))
SignerInfo.HashAlgorithm.pszObjId=(LPSTR)(pOIDInfo->pszOID);
else
SignerInfo.HashAlgorithm.pszObjId=szOID_RSA_MD5;
//get the private key
SignerInfo.hCryptProv=pRAInfo->hSignProv;
SignerInfo.dwKeySpec=pRAInfo->dwSignKeySpec;
//get the autheticated attributes
//together we should have 6 attributes: TransactionID, MessageType, PkiStatus,
//ErrorInfo, senderNonce, and recipientNonce
memset(rgAttr, 0, CEP_RESPONSE_AUTH_ATTR_COUNT * sizeof(CRYPT_ATTRIBUTE));
memset(rgAttrBlob, 0, CEP_RESPONSE_AUTH_ATTR_COUNT * sizeof(CRYPT_ATTR_BLOB));
for(dwIndex=0; dwIndex<CEP_RESPONSE_AUTH_ATTR_COUNT; dwIndex++)
{
rgAttr[dwIndex].cValue=1;
rgAttr[dwIndex].rgValue=&(rgAttrBlob[dwIndex]);
}
cAttr=0;
//TransactionID
rgAttr[cAttr].pszObjId=szOIDVerisign_TransactionID;
//transactionID internally are stored as a string
pMsgInfo->TransactionID.cbData=strlen((LPSTR)(pMsgInfo->TransactionID.pbData));
if(!CEPAllocAndEncodeName(CERT_RDN_PRINTABLE_STRING,
pMsgInfo->TransactionID.pbData,
pMsgInfo->TransactionID.cbData,
&(rgAttr[cAttr].rgValue[0].pbData),
&(rgAttr[cAttr].rgValue[0].cbData)))
goto TraceErr;
cAttr++;
//MessageType
rgAttr[cAttr].pszObjId=szOIDVerisign_MessageType;
if(!CEPAllocAndEncodeDword(CERT_RDN_PRINTABLE_STRING,
pMsgInfo->dwMessageType,
&(rgAttr[cAttr].rgValue[0].pbData),
&(rgAttr[cAttr].rgValue[0].cbData)))
goto TraceErr;
cAttr++;
//Status
rgAttr[cAttr].pszObjId=szOIDVerisign_PkiStatus;
if(!CEPAllocAndEncodeDword(CERT_RDN_PRINTABLE_STRING,
pMsgInfo->dwStatus,
&(rgAttr[cAttr].rgValue[0].pbData),
&(rgAttr[cAttr].rgValue[0].cbData)))
goto TraceErr;
cAttr++;
//ErrorInfo only if the error case
if(MESSAGE_STATUS_FAILURE == pMsgInfo->dwStatus)
{
rgAttr[cAttr].pszObjId=szOIDVerisign_FailInfo;
if(!CEPAllocAndEncodeDword(CERT_RDN_PRINTABLE_STRING,
pMsgInfo->dwErrorInfo,
&(rgAttr[cAttr].rgValue[0].pbData),
&(rgAttr[cAttr].rgValue[0].cbData)))
goto TraceErr;
cAttr++;
}
//senderNonce
rgAttr[cAttr].pszObjId=szOIDVerisign_SenderNonce;
if(!CEPAllocAndEncodeName(CERT_RDN_OCTET_STRING,
pMsgInfo->SenderNonce.pbData,
pMsgInfo->SenderNonce.cbData,
&(rgAttr[cAttr].rgValue[0].pbData),
&(rgAttr[cAttr].rgValue[0].cbData)))
goto TraceErr;
cAttr++;
//recipientNonce
rgAttr[cAttr].pszObjId=szOIDVerisign_RecipientNonce;
if(!CEPAllocAndEncodeName(CERT_RDN_OCTET_STRING,
pMsgInfo->RecipientNonce.pbData,
pMsgInfo->RecipientNonce.cbData,
&(rgAttr[cAttr].rgValue[0].pbData),
&(rgAttr[cAttr].rgValue[0].cbData)))
goto TraceErr;
cAttr++;
SignerInfo.cAuthAttr=cAttr;
SignerInfo.rgAuthAttr=rgAttr;
//message encoding
if(NULL==(hMsg=CryptMsgOpenToEncode(ENCODE_TYPE,
0,
CMSG_SIGNED,
&SignEncodedInfo,
NULL, //we are encoding as CMSG_DATA(7.1)
NULL)))
goto TraceErr;
if(!CryptMsgUpdate(hMsg,
pbEnvelop,
cbEnvelop,
TRUE))
goto TraceErr;
if(!CryptMsgGetParam(hMsg,
CMSG_CONTENT_PARAM,
0,
NULL,
pcbData))
goto TraceErr;
*ppbData=(BYTE *)malloc(*pcbData);
if(NULL==(*ppbData))
goto MemoryErr;
if(!CryptMsgGetParam(hMsg,
CMSG_CONTENT_PARAM,
0,
*ppbData,
pcbData))
goto TraceErr;
fResult = TRUE;
CommonReturn:
for(dwIndex=0; dwIndex < cAttr; dwIndex ++)
{
if(rgAttrBlob[dwIndex].pbData)
free(rgAttrBlob[dwIndex].pbData);
}
if(hMsg)
CryptMsgClose(hMsg);
return fResult;
ErrorReturn:
if(ppbData)
{
if(*ppbData)
{
free(*ppbData);
*ppbData=NULL;
}
}
if(pcbData)
*pcbData=0;
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// CEPAllocAndEncodeDword
//
// PreCondition: ppbEncoded and pcbEncoded should not be NULL.
// The dwData is no more than 11
//--------------------------------------------------------------------------
BOOL CEPAllocAndEncodeDword(DWORD dwValueType,
DWORD dwData,
BYTE **ppbEncoded,
DWORD *pcbEncoded)
{
BOOL fResult = FALSE;
CHAR szString[12];
BYTE *pbData=NULL;
DWORD cbData=0;
_ltoa(dwData, szString, 10);
pbData=(BYTE *)szString;
cbData=strlen(szString);
return CEPAllocAndEncodeName(dwValueType, pbData, cbData, ppbEncoded, pcbEncoded);
}
//--------------------------------------------------------------------------
//
// CEPAllocAndEncodeName
//
// PreCondition: ppbEncoded and pcbEncoded should not be NULL.
//--------------------------------------------------------------------------
BOOL CEPAllocAndEncodeName(DWORD dwValueType,
BYTE *pbData,
DWORD cbData,
BYTE **ppbEncoded,
DWORD *pcbEncoded)
{
CERT_NAME_VALUE CertName;
*ppbEncoded=NULL;
*pcbEncoded=0;
CertName.dwValueType=dwValueType;
CertName.Value.pbData=pbData;
CertName.Value.cbData=cbData;
return CEPAllocAndEncode(X509_ANY_STRING,
&CertName,
ppbEncoded,
pcbEncoded);
}
//--------------------------------------------------------------------------
//
// GenerateSenderNonce
//
// We use GUID to generate a random 16 byte number
//
//--------------------------------------------------------------------------
BOOL GenerateSenderNonce(CRYPT_INTEGER_BLOB *pBlob)
{
BOOL fResult = FALSE;
GUID guid;
BYTE *pData=NULL;
UuidCreate(&guid);
pBlob->cbData=sizeof(guid.Data1) + sizeof(guid.Data2) +
sizeof(guid.Data3) + sizeof(guid.Data4);
pBlob->pbData=(BYTE *)malloc(pBlob->cbData);
if(NULL==(pBlob->pbData))
goto MemoryErr;
pData=pBlob->pbData;
memcpy(pData, &(guid.Data1), sizeof(guid.Data1));
pData += sizeof(guid.Data1);
memcpy(pData, &(guid.Data2), sizeof(guid.Data2));
pData += sizeof(guid.Data2);
memcpy(pData, &(guid.Data3), sizeof(guid.Data3));
pData += sizeof(guid.Data3);
memcpy(pData, &(guid.Data4), sizeof(guid.Data4));
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// EnvelopData
//
// In the initial GetContentFromPKCS7, we retrieve pSigningCert for
// GetCertInitial, CertReq, and GetCert request.
//
// In the process,we retrieve pSigningCert for GetCRL request.
//--------------------------------------------------------------------------
BOOL EnvelopData(PCCERT_CONTEXT pSigningCert,
BYTE *pbContent,
DWORD cbContent,
BYTE **ppbEnvelop,
DWORD *pcbEnvelop)
{
BOOL fResult = FALSE;
CMSG_ENVELOPED_ENCODE_INFO EnvInfo;
HCRYPTMSG hMsg=NULL;
if(!pSigningCert || !pbContent || !ppbEnvelop || !pcbEnvelop)
goto InvalidArgErr;
*ppbEnvelop=NULL;
*pcbEnvelop=0;
memset(&EnvInfo, 0, sizeof(CMSG_ENVELOPED_ENCODE_INFO));
EnvInfo.cbSize=sizeof(CMSG_ENVELOPED_ENCODE_INFO);
EnvInfo.hCryptProv=NULL;
EnvInfo.ContentEncryptionAlgorithm.pszObjId=szOID_OIWSEC_desCBC;
EnvInfo.pvEncryptionAuxInfo=NULL;
EnvInfo.cRecipients=1;
EnvInfo.rgpRecipients=(PCERT_INFO *)(&(pSigningCert->pCertInfo));
if(NULL==(hMsg=CryptMsgOpenToEncode(ENCODE_TYPE,
0,
CMSG_ENVELOPED,
&EnvInfo,
NULL, //we are encoding as CMSG_DATA(7.1)
NULL)))
goto TraceErr;
if(!CryptMsgUpdate(hMsg,
pbContent,
cbContent,
TRUE))
goto TraceErr;
if(!CryptMsgGetParam(hMsg,
CMSG_CONTENT_PARAM,
0,
NULL,
pcbEnvelop))
goto TraceErr;
*ppbEnvelop=(BYTE *)malloc(*pcbEnvelop);
if(NULL==(*ppbEnvelop))
goto MemoryErr;
if(!CryptMsgGetParam(hMsg,
CMSG_CONTENT_PARAM,
0,
*ppbEnvelop,
pcbEnvelop))
goto TraceErr;
fResult = TRUE;
CommonReturn:
if(hMsg)
CryptMsgClose(hMsg);
return fResult;
ErrorReturn:
if(ppbEnvelop)
{
if(*ppbEnvelop)
{
free(*ppbEnvelop);
*ppbEnvelop=NULL;
}
}
if(pcbEnvelop)
*pcbEnvelop=0;
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// DecodeCertW
//
//--------------------------------------------------------------------------
HRESULT
DecodeCertW(
IN void const *pchIn,
IN DWORD cchIn,
IN DWORD Flags,
OUT BYTE **ppbOut,
OUT DWORD *pcbOut)
{
HRESULT hr;
BYTE *pbOut = NULL;
DWORD cbOut;
BOOL fRet;
//init
*ppbOut = NULL;
*pcbOut = 0;
while (TRUE)
{
fRet = CryptStringToBinaryW((LPCWSTR)pchIn, cchIn, Flags, pbOut, &cbOut, NULL, NULL);
if (!fRet)
{
hr = GetLastError();
goto error;
}
if (NULL != pbOut)
{
break; //done
}
pbOut = (BYTE*)LocalAlloc(LMEM_FIXED, cbOut);
if (NULL == pbOut)
{
hr = E_OUTOFMEMORY;
goto error;
}
}
*ppbOut = pbOut;
pbOut = NULL;
*pcbOut = cbOut;
hr = S_OK;
error:
if (NULL != pbOut)
{
LocalFree(pbOut);
}
return hr;
}
//--------------------------------------------------------------------------
//
// GetReturnInfoAndContent
//
//--------------------------------------------------------------------------
BOOL GetReturnInfoAndContent(CEP_RA_INFO *pRAInfo,
CEP_CA_INFO *pCAInfo,
LPSTR szMsg,
BYTE **ppbData,
DWORD *pcbData,
CEP_MESSAGE_INFO *pMsgInfo)
{
BOOL fResult = FALSE;
DWORD cbBase64Decoded=0;
DWORD cbReqEnv=0;
DWORD cbReqDecrypt=0;
DWORD cbSize=0;
HRESULT hr=E_FAIL;
BYTE *pbBase64Decoded=NULL;
BYTE *pbReqEnv=NULL;
BYTE *pbReqDecrypt=NULL;
WCHAR wszBuffer[INTERNET_MAX_PATH_LENGTH * 2 +1];
LPWSTR pwszMsg=NULL;
LPWSTR pwszBuffer=NULL;
//convert sz to wsz
pwszMsg=MkWStr(szMsg);
if(NULL==pwszMsg)
goto MemoryErr;
//we need to get rid of the escape characters
if(S_OK != (hr=CoInternetParseUrl(pwszMsg,
PARSE_UNESCAPE,
0,
wszBuffer,
INTERNET_MAX_PATH_LENGTH*2,
&cbSize,
0)))
{
//S_FALSE means that the buffer is too small
if(S_FALSE != hr)
{
LogSCEPEvent(0, TRUE, hr, EVENT_MSCEP_FAIL_TO_CONVERT, 1, g_pwszComputerName);
goto TraceErr;
}
if(0==cbSize)
{
LogSCEPEvent(0, TRUE, hr, EVENT_MSCEP_FAIL_TO_CONVERT, 1, g_pwszComputerName);
goto TraceErr;
}
//allocate the buffer
pwszBuffer=(LPWSTR)malloc(cbSize * sizeof(WCHAR));
if(NULL==pwszBuffer)
goto MemoryErr;
*pwszBuffer=L'\0';
if(S_OK != (hr = CoInternetParseUrl(pwszMsg,
PARSE_UNESCAPE,
0,
pwszBuffer,
cbSize,
&cbSize,
0)))
{
LogSCEPEvent(0, TRUE, hr, EVENT_MSCEP_FAIL_TO_CONVERT, 1, g_pwszComputerName);
goto TraceErr;
}
}
if(S_OK != (hr = DecodeCertW(
pwszBuffer ? pwszBuffer : wszBuffer,
pwszBuffer ? wcslen(pwszBuffer) : wcslen(wszBuffer),
CRYPT_STRING_BASE64_ANY, //DECF_BASE64_ANY,
&pbBase64Decoded,
&cbBase64Decoded)))
{
LogSCEPEvent(0, TRUE, hr, EVENT_MSCEP_FAIL_TO_DECODE, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
//get the message type, transaction ID, recepientNonce, serial number in the
//signer_info of the most outer PKCS#7 and inner content
if(!GetContentFromPKCS7(pbBase64Decoded,
cbBase64Decoded,
&pbReqEnv,
&cbReqEnv,
pMsgInfo))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_TO_RETRIEVE_INFO, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
//decrypt the inner content
if(!DecryptMsg(pRAInfo, pbReqEnv, cbReqEnv, &pbReqDecrypt, &cbReqDecrypt))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_TO_DECRYPT_INNER, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
//get the return inner content based on the message type
switch(pMsgInfo->dwMessageType)
{
case MESSAGE_TYPE_CERT_REQUEST:
//we use the signing RA cert as the enrollment agent
if(!ProcessCertRequest( pRAInfo->dwRefreshDays,
pRAInfo->fPassword,
pRAInfo->pRACert,
pRAInfo->pRASign,
pCAInfo,
pbReqDecrypt,
cbReqDecrypt,
ppbData,
pcbData,
pMsgInfo))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_CERT_REQ, 1, g_pwszComputerName);
goto TraceErr;
}
break;
case MESSAGE_TYPE_GET_CERT_INITIAL:
if(!ProcessCertInitial(pRAInfo->dwRefreshDays, pCAInfo, pbReqDecrypt,
cbReqDecrypt, ppbData, pcbData,
pMsgInfo))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_GET_CERT_INITIAL, 1, g_pwszComputerName);
goto TraceErr;
}
break;
case MESSAGE_TYPE_GET_CERT:
if(!ProcessGetCert(pCAInfo, pbReqDecrypt,
cbReqDecrypt, ppbData, pcbData,
pMsgInfo))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_GET_CERT, 1, g_pwszComputerName);
goto TraceErr;
}
break;
case MESSAGE_TYPE_GET_CRL:
if(!ProcessGetCRL(pCAInfo, pbReqDecrypt,
cbReqDecrypt, ppbData, pcbData,
pMsgInfo))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_GET_CRL, 1, g_pwszComputerName);
goto TraceErr;
}
break;
default:
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_BAD_MESSAGE_TYPE, 1, g_pwszComputerName);
goto InvalidArgErr;
break;
}
fResult = TRUE;
CommonReturn:
if(pwszBuffer)
free(pwszBuffer);
if(pwszMsg)
FreeWStr(pwszMsg);
//memory from certcli.dll. Has to be freed by LocalFree()
if(pbBase64Decoded)
LocalFree(pbBase64Decoded);
if(pbReqEnv)
free(pbReqEnv);
if(pbReqDecrypt)
free(pbReqDecrypt);
return fResult;
FailureStatusReturn:
//we set the error status for the return message
//and consider this http transation a success
pMsgInfo->dwStatus=MESSAGE_STATUS_FAILURE;
pMsgInfo->dwErrorInfo=MESSAGE_FAILURE_BAD_MESSAGE_CHECK;
*ppbData=NULL;
*pcbData=0;
fResult=TRUE;
goto CommonReturn;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// RetrieveContextFromSerialNumber
//
//
//--------------------------------------------------------------------------
BOOL WINAPI RetrieveContextFromSerialNumber(CEP_CA_INFO *pCAInfo,
CERT_BLOB *pSerialNumber,
PCCERT_CONTEXT *ppCertContext)
{
BOOL fResult = FALSE;
DWORD cb=0;
long dwDisposition=0;
HRESULT hr=E_FAIL;
DWORD cbCert=0;
BYTE *pbCert=NULL;
LPWSTR pwsz=NULL;
BSTR bstrCert=NULL;
LPWSTR pwszNewConfig=NULL;
BSTR bstrNewConfig=NULL;
if(S_OK != (hr=MultiByteIntegerToWszBuf(
FALSE,
pSerialNumber->cbData,
pSerialNumber->pbData,
&cb,
NULL)))
goto SetHrErr;
pwsz=(LPWSTR)malloc(cb);
if(NULL==pwsz)
goto MemoryErr;
if(S_OK != (hr=MultiByteIntegerToWszBuf(
FALSE,
pSerialNumber->cbData,
pSerialNumber->pbData,
&cb,
pwsz)))
goto SetHrErr;
//contatenate the serialNumber with the config string
pwszNewConfig=(LPWSTR)malloc(sizeof(WCHAR) *
(wcslen(pCAInfo->bstrCAConfig)+wcslen(pwsz)+wcslen(L"\\")+1));
if(NULL==pwszNewConfig)
goto MemoryErr;
//the config string to retrieve the cert based on the
//serialNumber is configString\SerialNumber
//
wcscpy(pwszNewConfig, pCAInfo->bstrCAConfig);
wcscat(pwszNewConfig, L"\\");
wcscat(pwszNewConfig, pwsz);
bstrNewConfig=SysAllocString(pwszNewConfig);
if(NULL==bstrNewConfig)
goto MemoryErr;
if(S_OK != (hr=pCAInfo->pICertRequest->RetrievePending(0,
bstrNewConfig,
&dwDisposition)))
goto SetHrErr;
if(S_OK != (hr= pCAInfo->pICertRequest->GetCertificate(CR_OUT_BINARY,
&bstrCert)))
goto SetHrErr;
cbCert = (DWORD)SysStringByteLen(bstrCert);
pbCert = (BYTE *)bstrCert;
if(!(*ppCertContext=CertCreateCertificateContext(ENCODE_TYPE,
pbCert,
cbCert)))
goto TraceErr;
fResult = TRUE;
CommonReturn:
if(pwsz)
free(pwsz);
if(bstrCert)
SysFreeString(bstrCert);
if(pwszNewConfig)
free(pwszNewConfig);
if(bstrNewConfig)
SysFreeString(bstrNewConfig);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
SET_ERROR_VAR(SetHrErr, hr);
TRACE_ERROR(TraceErr);
}
//--------------------------------------------------------------------------
//
// ProcessGetCRL
//
//
//--------------------------------------------------------------------------
BOOL WINAPI ProcessGetCRL(CEP_CA_INFO *pCAInfo,
BYTE *pbRequest,
DWORD cbRequest,
BYTE **ppbData,
DWORD *pcbData,
CEP_MESSAGE_INFO *pMsgInfo)
{
BOOL fResult = FALSE;
DWORD dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
DWORD cbUrlArray=0;
DWORD dwIndex=0;
PCCERT_CONTEXT pCertContext=NULL;
PCCRL_CONTEXT pCRLContext=NULL;
PCRYPT_URL_ARRAY pUrlArray = NULL;
if(!pCAInfo || !ppbData || !pcbData || !pMsgInfo)
goto InvalidArgErr;
*ppbData=NULL;
*pcbData=0;
//retrieve the cert context from the serialNumber
//protected by the critical Section since it uses ICertRequest interface
if(!RetrieveContextFromSerialNumber(pCAInfo, &(pMsgInfo->SerialNumber), &pCertContext))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_TO_GET_CERT_FROM_NUMBER, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
if(!CryptGetObjectUrl(
URL_OID_CERTIFICATE_CRL_DIST_POINT,
(LPVOID)pCertContext,
CRYPT_GET_URL_FROM_EXTENSION,
NULL,
&cbUrlArray,
NULL,
NULL,
NULL))
goto FailureStatusReturn;
pUrlArray=(PCRYPT_URL_ARRAY)malloc(cbUrlArray);
if(NULL == pUrlArray)
goto FailureStatusReturn;
if(!CryptGetObjectUrl(
URL_OID_CERTIFICATE_CRL_DIST_POINT,
(LPVOID)pCertContext,
CRYPT_GET_URL_FROM_EXTENSION,
pUrlArray,
&cbUrlArray,
NULL,
NULL,
NULL))
goto FailureStatusReturn;
for(dwIndex=0; dwIndex < pUrlArray->cUrl; dwIndex++)
{
if(CryptRetrieveObjectByUrlW (
pUrlArray->rgwszUrl[dwIndex],
CONTEXT_OID_CRL,
CRYPT_WIRE_ONLY_RETRIEVAL, //we should try to hit the wire
0,
(LPVOID *)&pCRLContext,
NULL,
NULL,
NULL,
NULL))
break;
}
if(NULL==pCRLContext)
goto FailureStatusReturn;
//package the CRL in an empty PKCS7
if(!PackageBlobToPKCS7(CEP_CONTEXT_CRL, pCRLContext->pbCrlEncoded,
pCRLContext->cbCrlEncoded, ppbData, pcbData))
goto FailureStatusReturn;
//this is the signing cert to which our response should be encrypted
if(NULL==(pMsgInfo->pSigningCert=CertDuplicateCertificateContext(pCertContext)))
goto FailureStatusReturn;
fResult = TRUE;
CommonReturn:
if(pCertContext)
CertFreeCertificateContext(pCertContext);
if(pCRLContext)
CertFreeCRLContext(pCRLContext);
if(pUrlArray)
free(pUrlArray);
return fResult;
FailureStatusReturn:
//we set the error status for the return message
//and consider this http transation a success
pMsgInfo->dwStatus=MESSAGE_STATUS_FAILURE;
pMsgInfo->dwErrorInfo=dwErrorInfo;
if(ppbData)
{
if(*ppbData)
free(*ppbData);
*ppbData=NULL;
}
if(pcbData)
*pcbData=0;
fResult=TRUE;
goto CommonReturn;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
}
//--------------------------------------------------------------------------
//
// ProcessGetCert
//
//
//--------------------------------------------------------------------------
BOOL WINAPI ProcessGetCert(CEP_CA_INFO *pCAInfo,
BYTE *pbRequest,
DWORD cbRequest,
BYTE **ppbData,
DWORD *pcbData,
CEP_MESSAGE_INFO *pMsgInfo)
{
BOOL fResult = FALSE;
DWORD dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
CRYPT_INTEGER_BLOB SerialNumber;
PCCERT_CONTEXT pCertContext=NULL;
if(!pCAInfo || !pbRequest || !ppbData || !pcbData || !pMsgInfo)
goto InvalidArgErr;
*ppbData=NULL;
*pcbData=0;
memset(&SerialNumber, 0, sizeof(CRYPT_INTEGER_BLOB));
//get the serialnumber from the request
if(!GetSerialNumberFromBlob(pbRequest,
cbRequest,
&SerialNumber))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_NUMBER_FROM_MESSAGE, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
//retrieve the cert context from the serialNumber
//protected by the critical Section since it uses ICertRequest interface
if(!RetrieveContextFromSerialNumber(pCAInfo, (CERT_BLOB*)&SerialNumber, &pCertContext))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_TO_GET_CERT_FROM_NUMBER, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
//package it in an empty PKCS7
if(!PackageBlobToPKCS7(CEP_CONTEXT_CERT, pCertContext->pbCertEncoded,
pCertContext->cbCertEncoded, ppbData, pcbData))
goto FailureStatusReturn;
//this is the signing cert to which our response should be encrypted
/* if(NULL==(pMsgInfo->pSigningCert=CertDuplicateCertificateContext(pCertContext)))
goto FailureStatusReturn; */
fResult = TRUE;
CommonReturn:
if(SerialNumber.pbData)
free(SerialNumber.pbData);
if(pCertContext)
CertFreeCertificateContext(pCertContext);
return fResult;
FailureStatusReturn:
//we set the error status for the return message
//and consider this http transation a success
pMsgInfo->dwStatus=MESSAGE_STATUS_FAILURE;
pMsgInfo->dwErrorInfo=dwErrorInfo;
if(ppbData)
{
if(*ppbData)
free(*ppbData);
*ppbData=NULL;
}
if(pcbData)
*pcbData=0;
fResult=TRUE;
goto CommonReturn;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
}
//--------------------------------------------------------------------------
//
// ProcessCertInitial
//
//
//--------------------------------------------------------------------------
BOOL ProcessCertInitial( DWORD dwRefreshDays,
CEP_CA_INFO *pCAInfo,
BYTE *pbRequest,
DWORD cbRequest,
BYTE **ppbData,
DWORD *pcbData,
CEP_MESSAGE_INFO *pMsgInfo)
{
BOOL fResult = FALSE;
DWORD dwRequestID=0;
DWORD cbCert=0;
BYTE *pbCert=NULL;
DWORD dwErrorInfo=MESSAGE_FAILURE_BAD_CERT_ID;
long dwDisposition=0;
HRESULT hr=S_OK;
BSTR bstrCert=NULL;
if(!pCAInfo || !pbRequest || !ppbData || !pcbData || !pMsgInfo)
goto InvalidArgErr;
*ppbData=NULL;
*pcbData=0;
//map the trasactionID to the request ID
if(!CEPHashGetRequestID(dwRefreshDays, &(pMsgInfo->TransactionID), &dwRequestID))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_TO_GET_ID, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
if(S_OK != (hr = pCAInfo->pICertRequest->RetrievePending(dwRequestID,
pCAInfo->bstrCAConfig,
&dwDisposition)))
{
LogSCEPEvent(0, TRUE, hr, EVENT_MSCEP_FAIL_QUERY_CA, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
switch(dwDisposition)
{
case CR_DISP_ISSUED:
if(S_OK != (hr = pCAInfo->pICertRequest->GetCertificate(CR_OUT_BINARY,
&bstrCert)))
{
LogSCEPEvent(0, TRUE, hr, EVENT_MSCEP_FAIL_QUERY_CERT, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
cbCert = (DWORD)SysStringByteLen(bstrCert);
pbCert = (BYTE *)bstrCert;
//package it in an empty PKCS7
if(!PackageBlobToPKCS7(CEP_CONTEXT_CERT, pbCert, cbCert, ppbData, pcbData))
goto FailureStatusReturn;
pMsgInfo->dwStatus=MESSAGE_STATUS_SUCCESS;
//mark the finished for RequesetID/TransactionID pair
CEPHashMarkTransactionFinished(dwRequestID, &(pMsgInfo->TransactionID));
break;
case CR_DISP_UNDER_SUBMISSION:
pMsgInfo->dwStatus=MESSAGE_STATUS_PENDING;
break;
case CR_DISP_INCOMPLETE:
case CR_DISP_ERROR:
case CR_DISP_DENIED:
case CR_DISP_ISSUED_OUT_OF_BAND: //we consider it a failure in this case
case CR_DISP_REVOKED:
default:
//mark the finished for RequesetID/TransactionID pair
CEPHashMarkTransactionFinished(dwRequestID, &(pMsgInfo->TransactionID));
dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
goto FailureStatusReturn;
break;
}
fResult = TRUE;
CommonReturn:
if(bstrCert)
SysFreeString(bstrCert);
return fResult;
FailureStatusReturn:
//we set the error status for the return message
//and consider this http transation a success
pMsgInfo->dwStatus=MESSAGE_STATUS_FAILURE;
pMsgInfo->dwErrorInfo=dwErrorInfo;
*ppbData=NULL;
*pcbData=0;
fResult=TRUE;
goto CommonReturn;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
}
//--------------------------------------------------------------------------
//
// PackageBlobToPKCS7
//
// Precondition: ppbData and pcbData is guaranteed not to be NULL
//--------------------------------------------------------------------------
BOOL PackageBlobToPKCS7(DWORD dwCEP_Context,
BYTE *pbEncoded,
DWORD cbEncoded,
BYTE **ppbData,
DWORD *pcbData)
{
BOOL fResult=FALSE;
CERT_BLOB CertBlob;
HCERTSTORE hCertStore=NULL;
if((!pbEncoded) || (0==cbEncoded))
goto InvalidArgErr;
*ppbData=NULL;
*pcbData=0;
if(NULL == (hCertStore = CertOpenStore(
CERT_STORE_PROV_MEMORY,
ENCODE_TYPE,
NULL,
0,
NULL)))
goto TraceErr;
switch(dwCEP_Context)
{
case CEP_CONTEXT_CERT:
if(!CertAddEncodedCertificateToStore(hCertStore,
ENCODE_TYPE,
pbEncoded,
cbEncoded,
CERT_STORE_ADD_ALWAYS,
NULL))
goto TraceErr;
break;
case CEP_CONTEXT_CRL:
if(!CertAddEncodedCRLToStore(hCertStore,
ENCODE_TYPE,
pbEncoded,
cbEncoded,
CERT_STORE_ADD_ALWAYS,
NULL))
goto TraceErr;
break;
default:
goto InvalidArgErr;
break;
}
CertBlob.cbData=0;
CertBlob.pbData=NULL;
if(!CertSaveStore(hCertStore,
ENCODE_TYPE,
CERT_STORE_SAVE_AS_PKCS7,
CERT_STORE_SAVE_TO_MEMORY,
&CertBlob,
0))
goto TraceErr;
CertBlob.pbData = (BYTE *)malloc(CertBlob.cbData);
if(NULL == CertBlob.pbData)
goto MemoryErr;
if(!CertSaveStore(hCertStore,
ENCODE_TYPE,
CERT_STORE_SAVE_AS_PKCS7,
CERT_STORE_SAVE_TO_MEMORY,
&CertBlob,
0))
goto TraceErr;
//copy the memory
*ppbData=CertBlob.pbData;
*pcbData=CertBlob.cbData;
CertBlob.pbData=NULL;
fResult = TRUE;
CommonReturn:
if(CertBlob.pbData)
free(CertBlob.pbData);
if(hCertStore)
CertCloseStore(hCertStore, 0);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// CEPRetrievePasswordFromRequest
//
//--------------------------------------------------------------------------
BOOL WINAPI CEPRetrievePasswordFromRequest(BYTE *pbRequest,
DWORD cbRequest,
LPWSTR *ppwszPassword,
DWORD *pdwUsage)
{
BOOL fResult=FALSE;
DWORD cbData=0;
DWORD dwIndex=0;
DWORD cbNameValue=0;
DWORD dwExt=0;
DWORD cbExtensions=0;
DWORD cbSize=0;
CERT_REQUEST_INFO *pCertRequestInfo=NULL;
CERT_NAME_VALUE *pbNameValue=NULL;
CERT_EXTENSIONS *pExtensions=NULL;
CRYPT_BIT_BLOB *pKeyUsage=NULL;
*ppwszPassword=NULL;
*pdwUsage=0;
if(!CEPAllocAndDecode(X509_CERT_REQUEST_TO_BE_SIGNED,
pbRequest,
cbRequest,
(void **)&pCertRequestInfo,
&cbData))
goto TraceErr;
//get the key usage
for(dwIndex=0; dwIndex < pCertRequestInfo->cAttribute; dwIndex++)
{
if((0 == strcmp(szOID_RSA_certExtensions, pCertRequestInfo->rgAttribute[dwIndex].pszObjId)) ||
(0 == strcmp(szOID_CERT_EXTENSIONS, pCertRequestInfo->rgAttribute[dwIndex].pszObjId))
)
{
if(CEPAllocAndDecode(X509_EXTENSIONS,
pCertRequestInfo->rgAttribute[dwIndex].rgValue[0].pbData,
pCertRequestInfo->rgAttribute[dwIndex].rgValue[0].cbData,
(void **)&pExtensions,
&cbExtensions))
{
for(dwExt=0; dwExt < pExtensions->cExtension; dwExt++)
{
if(0==strcmp(szOID_KEY_USAGE, pExtensions->rgExtension[dwExt].pszObjId))
{
if(CEPAllocAndDecode(X509_KEY_USAGE,
pExtensions->rgExtension[dwExt].Value.pbData,
pExtensions->rgExtension[dwExt].Value.cbData,
(void **)&pKeyUsage,
&cbSize))
{
if(pKeyUsage->pbData)
{
if(CERT_DIGITAL_SIGNATURE_KEY_USAGE & (pKeyUsage->pbData[0]))
(*pdwUsage) = (*pdwUsage) | CEP_REQUEST_SIGNATURE;
if(CERT_KEY_ENCIPHERMENT_KEY_USAGE & (pKeyUsage->pbData[0]))
(*pdwUsage) = (*pdwUsage) | CEP_REQUEST_EXCHANGE;
}
}
if(pKeyUsage)
free(pKeyUsage);
pKeyUsage=NULL;
cbSize=0;
}
}
}
if(pExtensions)
free(pExtensions);
pExtensions=NULL;
cbExtensions=0;
}
}
//get the password
for(dwIndex=0; dwIndex < pCertRequestInfo->cAttribute; dwIndex++)
{
if(0 == strcmp(szOID_RSA_challengePwd,
pCertRequestInfo->rgAttribute[dwIndex].pszObjId))
break;
}
//the password is not required to be present in this function
if(dwIndex != pCertRequestInfo->cAttribute)
{
if(!CEPAllocAndDecode(X509_UNICODE_ANY_STRING,
pCertRequestInfo->rgAttribute[dwIndex].rgValue[0].pbData,
pCertRequestInfo->rgAttribute[dwIndex].rgValue[0].cbData,
(void **)&pbNameValue,
&cbNameValue))
goto TraceErr;
if(CERT_RDN_PRINTABLE_STRING != (pbNameValue->dwValueType))
goto InvalidArgErr;
cbData=wcslen((LPWSTR)(pbNameValue->Value.pbData));
*ppwszPassword=(LPWSTR)malloc(sizeof(WCHAR) * (cbData + 1));
if(NULL==(*ppwszPassword))
goto MemoryErr;
wcscpy(*ppwszPassword,(LPWSTR)(pbNameValue->Value.pbData));
}
fResult=TRUE;
CommonReturn:
if(pExtensions)
free(pExtensions);
if(pKeyUsage)
free(pKeyUsage);
if(pbNameValue)
free(pbNameValue);
if(pCertRequestInfo)
free(pCertRequestInfo);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// AltNameExist
//
// Return TRUE is szOID_SUBJECT_ALT_NAME2 is present in the PKCS10
// FALSE otherwise
//--------------------------------------------------------------------------
BOOL WINAPI AltNameExist(BYTE *pbRequest, DWORD cbRequest)
{
BOOL fResult = FALSE;
DWORD cbData=0;
DWORD cbExtensions=0;
DWORD dwIndex=0;
DWORD dwExt=0;
CERT_REQUEST_INFO *pCertRequestInfo=NULL;
CERT_EXTENSIONS *pExtensions=NULL;
if(!CEPAllocAndDecode(X509_CERT_REQUEST_TO_BE_SIGNED,
pbRequest,
cbRequest,
(void **)&pCertRequestInfo,
&cbData))
goto ErrorReturn;
for(dwIndex=0; dwIndex < pCertRequestInfo->cAttribute; dwIndex++)
{
if((0 == strcmp(szOID_RSA_certExtensions, pCertRequestInfo->rgAttribute[dwIndex].pszObjId)) ||
(0 == strcmp(szOID_CERT_EXTENSIONS, pCertRequestInfo->rgAttribute[dwIndex].pszObjId))
)
{
if(CEPAllocAndDecode(X509_EXTENSIONS,
pCertRequestInfo->rgAttribute[dwIndex].rgValue[0].pbData,
pCertRequestInfo->rgAttribute[dwIndex].rgValue[0].cbData,
(void **)&pExtensions,
&cbExtensions))
{
for(dwExt=0; dwExt < pExtensions->cExtension; dwExt++)
{
if(0==strcmp(szOID_SUBJECT_ALT_NAME2, pExtensions->rgExtension[dwExt].pszObjId))
{
fResult=TRUE;
goto CommonReturn;
}
}
}
if(pExtensions)
free(pExtensions);
pExtensions=NULL;
cbExtensions=0;
}
}
CommonReturn:
if(pExtensions)
free(pExtensions);
if(pCertRequestInfo)
free(pCertRequestInfo);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
}
//--------------------------------------------------------------------------
//
// CEPAllocAndEncode
//
//--------------------------------------------------------------------------
BOOL WINAPI CEPAllocAndEncode(LPCSTR lpszStructType,
void *pStructInfo,
BYTE **ppbEncoded,
DWORD *pcbEncoded)
{
BOOL fResult=FALSE;
*pcbEncoded=0;
if(!CryptEncodeObject(ENCODE_TYPE,
lpszStructType,
pStructInfo,
NULL,
pcbEncoded))
goto TraceErr;
*ppbEncoded=(BYTE *)malloc(*pcbEncoded);
if(NULL==(*ppbEncoded))
goto MemoryErr;
if(!CryptEncodeObject(ENCODE_TYPE,
lpszStructType,
pStructInfo,
*ppbEncoded,
pcbEncoded))
goto TraceErr;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
if(*ppbEncoded)
{
free(*ppbEncoded);
*ppbEncoded=NULL;
}
*pcbEncoded=0;
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// ConvertIPStringToBinary
//
// Conver the IP address in the format of "xxx.xx.xx.xx" to an arry of
// bytes. One byte per xxx
//--------------------------------------------------------------------------
BOOL ConvertIPStringToBinary(LPWSTR pwszIP,
CRYPT_DATA_BLOB *pIPAddress)
{
BOOL fResult = FALSE;
LPWSTR pwszTok=NULL;
DWORD cTok=0;
DWORD dwIndex=0;
if(!pwszIP || !pIPAddress)
goto InvalidArgErr;
pIPAddress->pbData=NULL;
pIPAddress->cbData=0;
pwszTok=wcstok(pwszIP, L".");
while(NULL != pwszTok)
{
cTok++;
pwszTok=wcstok(NULL, L".");
}
pIPAddress->pbData=(BYTE *)malloc(cTok);
if(NULL==pIPAddress->pbData)
goto MemoryErr;
pIPAddress->cbData=cTok;
pwszTok=pwszIP;
for(dwIndex=0; dwIndex < cTok; dwIndex++)
{
pIPAddress->pbData[dwIndex]=(BYTE)_wtol(pwszTok);
pwszTok=pwszTok+wcslen(pwszTok)+1;
}
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// GetAltNameElement
//
// We create the subject alternative extension based on the PKCS10.
// unstructedName(DNS name) and unstructedAddress (IP address) are included.
// At lease one element should be present.
//--------------------------------------------------------------------------
BOOL WINAPI GetAltNameElement(BYTE *pb10,
DWORD cb10,
LPWSTR *ppwszDNS,
CRYPT_DATA_BLOB *pIPAddress)
{
BOOL fResult = FALSE;
DWORD cbRequestInfo=0;
DWORD cbNameInfo=0;
DWORD dwRDN=0;
DWORD dwAttr=0;
PCERT_RDN_ATTR pAttr=NULL;
DWORD cb=0;
CERT_REQUEST_INFO *pRequestInfo=NULL;
CERT_NAME_INFO *pNameInfo=NULL;
if(!pb10 || !ppwszDNS || !pIPAddress)
goto InvalidArgErr;
*ppwszDNS=NULL;
pIPAddress->cbData=0;
pIPAddress->pbData=NULL;
if(!CEPAllocAndDecode(X509_CERT_REQUEST_TO_BE_SIGNED,
pb10,
cb10,
(void **)&pRequestInfo,
&cbRequestInfo))
goto TraceErr;
if(!CEPAllocAndDecode(X509_UNICODE_NAME,
pRequestInfo->Subject.pbData,
pRequestInfo->Subject.cbData,
(void **)&pNameInfo,
&cbNameInfo))
goto TraceErr;
for(dwRDN=0; dwRDN<pNameInfo->cRDN; dwRDN++)
{
for(dwAttr=0; dwAttr<pNameInfo->rgRDN[dwRDN].cRDNAttr; dwAttr++)
{
pAttr=&(pNameInfo->rgRDN[dwRDN].rgRDNAttr[dwAttr]);
//we are happy if we have found both the IPAddress and the fqdn
if((*ppwszDNS) && (pIPAddress->pbData))
break;
if((NULL==*ppwszDNS) && (0 == strcmp(szOID_RSA_unstructName,pAttr->pszObjId)))
{
cb=sizeof(WCHAR) * (1+wcslen((LPWSTR)(pAttr->Value.pbData)));
*ppwszDNS=(LPWSTR)malloc(cb);
if(NULL == *ppwszDNS)
goto MemoryErr;
wcscpy(*ppwszDNS, (LPWSTR)(pAttr->Value.pbData));
}
else
{
if((NULL==pIPAddress->pbData) && (0 == strcmp(szOID_RSA_unstructAddr,pAttr->pszObjId)))
{
if(!ConvertIPStringToBinary((LPWSTR)(pAttr->Value.pbData),
pIPAddress))
goto TraceErr;
}
}
}
}
//we need to have some element
if((NULL == *ppwszDNS) && (NULL==pIPAddress->pbData))
goto InvalidArgErr;
fResult = TRUE;
CommonReturn:
if(pNameInfo)
free(pNameInfo);
if(pRequestInfo)
free(pRequestInfo);
return fResult;
ErrorReturn:
if(ppwszDNS)
{
if(*ppwszDNS)
{
free(*ppwszDNS);
*ppwszDNS=NULL;
}
}
if(pIPAddress)
{
if(pIPAddress->pbData)
{
free(pIPAddress->pbData);
pIPAddress->pbData=NULL;
}
pIPAddress->cbData=0;
}
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// CreateAltNameExtenions
//
//--------------------------------------------------------------------------
BOOL WINAPI CreateAltNameExtenions(LPWSTR pwszDNS,
CRYPT_DATA_BLOB *pIPAddress,
BYTE **ppbExt,
DWORD *pcbExt)
{
BOOL fResult = FALSE;
CERT_ALT_NAME_INFO AltNameInfo;
CERT_ALT_NAME_ENTRY rgAltNameEntry[2];
DWORD cAltNameEntry=0;
//DNS name
if(pwszDNS)
{
rgAltNameEntry[cAltNameEntry].dwAltNameChoice=CERT_ALT_NAME_DNS_NAME;
rgAltNameEntry[cAltNameEntry].pwszDNSName=pwszDNS;
cAltNameEntry++;
}
//IP address
if(pIPAddress->pbData)
{
rgAltNameEntry[cAltNameEntry].dwAltNameChoice=CERT_ALT_NAME_IP_ADDRESS;
rgAltNameEntry[cAltNameEntry].IPAddress.cbData=pIPAddress->cbData;
rgAltNameEntry[cAltNameEntry].IPAddress.pbData=pIPAddress->pbData;
cAltNameEntry++;
}
memset(&AltNameInfo, 0, sizeof(CERT_ALT_NAME_INFO));
AltNameInfo.cAltEntry=cAltNameEntry;
AltNameInfo.rgAltEntry=rgAltNameEntry;
if(!CEPAllocAndEncode(szOID_SUBJECT_ALT_NAME2,
&AltNameInfo,
ppbExt,
pcbExt))
goto TraceErr;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
}
//--------------------------------------------------------------------------
//
// AddAltNameInRequest
//
//--------------------------------------------------------------------------
BOOL WINAPI AddAltNameInRequest(PCCERT_CONTEXT pRACert,
BYTE *pb10,
DWORD cb10,
LPWSTR pwszDNS,
CRYPT_DATA_BLOB *pIPAddress,
BYTE **ppb7,
DWORD *pcb7)
{
BOOL fResult = FALSE;
DWORD cbExt=0;
CERT_EXTENSIONS Exts;
CERT_EXTENSION Ext;
DWORD cbAllExt=0;
CRYPT_SIGN_MESSAGE_PARA signPara;
CRYPT_ATTRIBUTE AuthAttr;
PCCRYPT_OID_INFO pOIDInfo=NULL;
ALG_ID AlgValue=CALG_SHA1;
CRYPT_ATTR_BLOB AttrBlob;
BYTE *pbExt=NULL;
BYTE *pbAllExt=NULL;
if(!pRACert || !pb10 || !ppb7 || !pcb7)
goto InvalidArgErr;
*ppb7=NULL;
*pcb7=0;
if(!CreateAltNameExtenions(pwszDNS, pIPAddress, &pbExt, &cbExt))
goto TraceErr;
Exts.cExtension=1;
Exts.rgExtension=&Ext;
Ext.pszObjId=szOID_SUBJECT_ALT_NAME2;
Ext.fCritical=TRUE;
Ext.Value.pbData=pbExt;
Ext.Value.cbData=cbExt;
if(!CEPAllocAndEncode(X509_EXTENSIONS,
&Exts,
&pbAllExt,
&cbAllExt))
goto TraceErr;
AuthAttr.pszObjId=szOID_CERT_EXTENSIONS;
AuthAttr.cValue=1;
AuthAttr.rgValue=&AttrBlob;
AttrBlob.pbData=pbAllExt;
AttrBlob.cbData=cbAllExt;
memset(&signPara, 0, sizeof(signPara));
signPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
signPara.dwMsgEncodingType = ENCODE_TYPE;
signPara.pSigningCert = pRACert;
signPara.cMsgCert = 1;
signPara.rgpMsgCert = &pRACert;
signPara.cAuthAttr = 1;
signPara.rgAuthAttr = &AuthAttr;
if(pOIDInfo=CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY,
&AlgValue,
CRYPT_HASH_ALG_OID_GROUP_ID))
signPara.HashAlgorithm.pszObjId=(LPSTR)(pOIDInfo->pszOID);
else
signPara.HashAlgorithm.pszObjId=szOID_OIWSEC_sha1;
if(!CryptSignMessage(
&signPara,
FALSE,
1,
(const BYTE **) &pb10,
&cb10,
NULL,
pcb7))
goto TraceErr;
*ppb7=(BYTE *)malloc(*pcb7);
if(NULL==(*ppb7))
goto MemoryErr;
if(!CryptSignMessage(
&signPara,
FALSE,
1,
(const BYTE **) &pb10,
&cb10,
*ppb7,
pcb7))
goto TraceErr;
fResult = TRUE;
CommonReturn:
if(pbAllExt)
free(pbAllExt);
if(pbExt)
free(pbExt);
return fResult;
ErrorReturn:
if(ppb7)
{
if(*ppb7)
{
free(*ppb7);
*ppb7=NULL;
}
}
if(pcb7)
*pcb7=0;
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
TRACE_ERROR(TraceErr);
}
//--------------------------------------------------------------------------
//
// MakePKCS7Request
//
//--------------------------------------------------------------------------
BOOL WINAPI MakePKCS7Request(PCCERT_CONTEXT pRACert,
BYTE *pb10,
DWORD cb10,
BYTE **ppb7,
DWORD *pcb7)
{
BOOL fResult = FALSE;
CRYPT_SIGN_MESSAGE_PARA signPara;
PCCRYPT_OID_INFO pOIDInfo=NULL;
ALG_ID AlgValue=CALG_SHA1;
if(!pRACert || !pb10 || !ppb7 || !pcb7)
goto InvalidArgErr;
*ppb7=NULL;
*pcb7=0;
memset(&signPara, 0, sizeof(signPara));
signPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
signPara.dwMsgEncodingType = ENCODE_TYPE;
signPara.pSigningCert = pRACert;
signPara.cMsgCert = 1;
signPara.rgpMsgCert = &pRACert;
signPara.cAuthAttr = 0;
signPara.rgAuthAttr = NULL;
if(pOIDInfo=CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY,
&AlgValue,
CRYPT_HASH_ALG_OID_GROUP_ID))
signPara.HashAlgorithm.pszObjId=(LPSTR)(pOIDInfo->pszOID);
else
signPara.HashAlgorithm.pszObjId=szOID_OIWSEC_sha1;
if(!CryptSignMessage(
&signPara,
FALSE,
1,
(const BYTE **) &pb10,
&cb10,
NULL,
pcb7))
goto TraceErr;
*ppb7=(BYTE *)malloc(*pcb7);
if(NULL==(*ppb7))
goto MemoryErr;
if(!CryptSignMessage(
&signPara,
FALSE,
1,
(const BYTE **) &pb10,
&cb10,
*ppb7,
pcb7))
goto TraceErr;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
if(ppb7)
{
if(*ppb7)
{
free(*ppb7);
*ppb7=NULL;
}
}
if(pcb7)
*pcb7=0;
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
TRACE_ERROR(TraceErr);
}
/*//--------------------------------------------------------------------------
//
// GetLogonInfoFromValue
//
// The pwszString can be of format "name;password" or "domain\name;password"
//
//--------------------------------------------------------------------------
BOOL GetLogonInfoFromValue(PCCERT_CONTEXT pRAEncrypt,
LPWSTR pwszString,
LPWSTR *ppwszDomain,
LPWSTR *ppwszUser,
LPWSTR *ppwszPassword)
{
BOOL fResult=FALSE;
LPWSTR pwsz=NULL;
BOOL fDomain=FALSE;
BOOL fPassword=FALSE;
LPWSTR pwszPlainText=NULL;
*ppwszDomain=NULL;
*ppwszUser=NULL;
*ppwszPassword=NULL;
if(NULL==pwszString)
goto InvalidArgErr;
if(0 == wcslen(pwszString))
goto InvalidArgErr;
for(pwsz=pwszString; *pwsz!=L'\0'; pwsz++)
{
if(*pwsz==L'\\')
{
if(fDomain)
goto InvalidArgErr;
fDomain=TRUE;
*pwsz='\0';
}
else
{
if(*pwsz==L';')
{
if(fPassword)
goto InvalidArgErr;
fPassword=TRUE;
*pwsz='\0';
}
}
}
//have to have userName and password.
//One and only one ";" should be found
if(!fPassword)
goto InvalidArgErr;
//one or no "\" should be found
if(fDomain)
{
*ppwszDomain=pwszString;
*ppwszUser=*ppwszDomain + wcslen(*ppwszDomain) + 1;
}
else
{
*ppwszDomain=NULL;
*ppwszUser=pwszString;
}
*ppwszPassword = *ppwszUser + wcslen(*ppwszUser) + 1;
if(fDomain)
{
if(L'\0'==(**ppwszDomain))
goto InvalidArgErr;
}
if((L'\0'==(**ppwszUser)) || (L'\0'==(**ppwszPassword)))
goto InvalidArgErr;
//convert the encrypted password to the plain text form
if(!CEPDecryptPassword(pRAEncrypt,
*ppwszPassword,
&pwszPlainText))
goto TraceErr;
*ppwszPassword=pwszPlainText;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
*ppwszDomain=NULL;
*ppwszUser=NULL;
*ppwszPassword=NULL;
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
} */
/*//--------------------------------------------------------------------------
//
// CEPGetTokenFromPKCS10
//
// If fPassword is TRUE, an impersonation has to occur.
//--------------------------------------------------------------------------
BOOL CEPGetTokenFromPKCS10(BOOL fPassword,
PCCERT_CONTEXT pRAEncrypt,
BYTE *pbRequest,
DWORD cbRequest,
HANDLE *phToken)
{
BOOL fResult=FALSE;
DWORD cbRequestInfo=0;
DWORD dwIndex=0;
CRYPT_ATTRIBUTE *pAttr=NULL;
DWORD cbData=0;
LPWSTR pwszDomain=NULL;
LPWSTR pwszUserName=NULL;
LPWSTR pwszPassword=NULL;
CERT_REQUEST_INFO *pRequestInfo=NULL;
CERT_NAME_VALUE *pCertNameValue=NULL;
*phToken=NULL;
if((!pbRequest) || (0==cbRequest))
goto InvalidArgErr;
if(!CEPAllocAndDecode(X509_CERT_REQUEST_TO_BE_SIGNED,
pbRequest,
cbRequest,
(void **)&pRequestInfo,
&cbRequestInfo))
goto TraceErr;
for(dwIndex=0; dwIndex < pRequestInfo->cAttribute; dwIndex++)
{
if(0 == strcmp(szOID_RSA_challengePwd, (pRequestInfo->rgAttribute[dwIndex]).pszObjId))
{
pAttr= &(pRequestInfo->rgAttribute[dwIndex]);
break;
}
}
if(NULL==pAttr)
{
if(fPassword)
goto InvalidArgErr;
else
{
*phToken=NULL;
fResult=TRUE;
goto CommonReturn;
}
}
if(CEPAllocAndDecode(X509_UNICODE_ANY_STRING,
pAttr->rgValue[0].pbData,
pAttr->rgValue[0].cbData,
(void **)&pCertNameValue,
&cbData))
{
if(GetLogonInfoFromValue(pRAEncrypt,
(LPWSTR)(pCertNameValue->Value.pbData),
&pwszDomain,
&pwszUserName,
&pwszPassword))
{
if(!LogonUserW(pwszUserName,
pwszDomain,
pwszPassword,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
phToken))
*phToken=NULL;
}
}
if(NULL == *phToken)
{
if(fPassword)
goto InvalidArgErr;
}
fResult = TRUE;
CommonReturn:
if(pRequestInfo)
free(pRequestInfo);
if(pCertNameValue)
free(pCertNameValue);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
} */
//--------------------------------------------------------------------------
//
// CEPCopyRequestAndRequestID
//
//--------------------------------------------------------------------------
BOOL WINAPI CEPCopyRequestAndRequestID(BYTE *pbRequest,
DWORD cbRequest,
DWORD dwRequestID)
{
BOOL fResult=FALSE;
BYTE pbHash[CEP_MD5_HASH_SIZE];
DWORD cbData=0;
cbData=CEP_MD5_HASH_SIZE;
if(!CryptHashCertificate(
NULL,
CALG_MD5,
0,
pbRequest,
cbRequest,
pbHash,
&cbData))
goto TraceErr;
if(!CEPRequestAddHashAndRequestID(pbHash, dwRequestID))
goto TraceErr;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
}
//--------------------------------------------------------------------------
//
// CEPGetCertFromPKCS10
//
//--------------------------------------------------------------------------
BOOL WINAPI CEPGetCertFromPKCS10(CEP_CA_INFO *pCAInfo,
BYTE *pbRequest,
DWORD cbRequest,
BYTE **ppbData,
DWORD *pcbData,
CEP_MESSAGE_INFO *pMsgInfo)
{
BOOL fResult = FALSE;
DWORD dwRequestID=0;
DWORD cbCert=0;
BYTE *pbCert=NULL;
DWORD dwErrorInfo=MESSAGE_FAILURE_BAD_CERT_ID;
long dwDisposition=0;
BYTE pbHash[CEP_MD5_HASH_SIZE];
DWORD cbData=0;
BSTR bstrCert=NULL;
if(!pCAInfo || !pbRequest || !ppbData || !pcbData || !pMsgInfo)
goto InvalidArgErr;
*ppbData=NULL;
*pcbData=0;
cbData=CEP_MD5_HASH_SIZE;
if(!CryptHashCertificate(
NULL,
CALG_MD5,
0,
pbRequest,
cbRequest,
pbHash,
&cbData))
goto TraceErr;
if(!CEPRequestRetrieveRequestIDFromHash(pbHash, &dwRequestID))
goto InvalidArgErr;
if(S_OK != pCAInfo->pICertRequest->RetrievePending(dwRequestID,
pCAInfo->bstrCAConfig,
&dwDisposition))
goto InvalidArgErr;
switch(dwDisposition)
{
case CR_DISP_ISSUED:
if(S_OK != pCAInfo->pICertRequest->GetCertificate(CR_OUT_BINARY,
&bstrCert))
goto FailureStatusReturn;
cbCert = (DWORD)SysStringByteLen(bstrCert);
pbCert = (BYTE *)bstrCert;
//package it in an empty PKCS7
if(!PackageBlobToPKCS7(CEP_CONTEXT_CERT, pbCert, cbCert, ppbData, pcbData))
goto FailureStatusReturn;
pMsgInfo->dwStatus=MESSAGE_STATUS_SUCCESS;
break;
case CR_DISP_UNDER_SUBMISSION:
pMsgInfo->dwStatus=MESSAGE_STATUS_PENDING;
break;
case CR_DISP_INCOMPLETE:
case CR_DISP_ERROR:
case CR_DISP_DENIED:
case CR_DISP_ISSUED_OUT_OF_BAND: //we consider it a failure in this case
case CR_DISP_REVOKED:
default:
dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
goto FailureStatusReturn;
break;
}
fResult = TRUE;
CommonReturn:
if(bstrCert)
SysFreeString(bstrCert);
return fResult;
FailureStatusReturn:
//we set the error status for the return message
//and consider this http transation a success
pMsgInfo->dwStatus=MESSAGE_STATUS_FAILURE;
pMsgInfo->dwErrorInfo=dwErrorInfo;
*ppbData=NULL;
*pcbData=0;
fResult=TRUE;
goto CommonReturn;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
}
//--------------------------------------------------------------------------
//
// ProcessCertRequest
//
//--------------------------------------------------------------------------
BOOL ProcessCertRequest( DWORD dwRefreshDays,
BOOL fPassword,
PCCERT_CONTEXT pRAEncrypt,
PCCERT_CONTEXT pRACert,
CEP_CA_INFO *pCAInfo,
BYTE *pbRequest,
DWORD cbRequest,
BYTE **ppbData,
DWORD *pcbData,
CEP_MESSAGE_INFO *pMsgInfo)
{
BOOL fResult = FALSE;
HRESULT hr=E_FAIL;
DWORD dwFlags=0;
long dwDisposition=0;
DWORD dwErrorInfo=MESSAGE_FAILURE_BAD_MESSAGE_CHECK;
DWORD cbNewRequest=0;
DWORD cbCert=0;
BYTE *pbCert=NULL;
DWORD dwRequestID=0;
DWORD dwUsage=0;
LPWSTR pwszTemplate=L"IPSECIntermediateOffline";
LPWSTR pwszAttr=NULL;
BSTR bstrRequest=NULL;
BYTE *pbNewRequest=NULL;
BSTR bstrCert=NULL;
BSTR bstrAttr=NULL;
LPWSTR pwszDNS=NULL;
CRYPT_DATA_BLOB IPAddress={0, NULL};
LPWSTR pwszPassword=NULL;
if(!pCAInfo || !pbRequest || !ppbData || !pcbData || !pMsgInfo)
goto InvalidArgErr;
*ppbData=NULL;
*pcbData=0;
//check to see if the PKCS10 is in our cached request table
//if so, we return messages based on the cached requestID
if(CEPGetCertFromPKCS10(pCAInfo, pbRequest, cbRequest, ppbData, pcbData, pMsgInfo))
{
fResult=TRUE;
}
else
{
//retrieve password and key usage from the request. The presence of password
//or key usage is not required
if(!CEPRetrievePasswordFromRequest(pbRequest, cbRequest, &pwszPassword, &dwUsage))
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_KEY_USAGE, 1, g_pwszComputerName);
dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
goto FailureStatusReturn;
}
if(0 == dwUsage)
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_KEY_USAGE, 1, g_pwszComputerName);
dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
goto FailureStatusReturn;
}
//if the password is required, we need to make sure the password
//supplied is valid.
if(fPassword)
{
if(NULL == pwszPassword)
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_PASSWORD, 1, g_pwszComputerName);
dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
goto FailureStatusReturn;
}
if(!CEPVerifyPasswordAndDeleteFromTable(pwszPassword, dwUsage))
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_INVALID_PASSWORD, 1, g_pwszComputerName);
dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
goto FailureStatusReturn;
}
}
//if the altname extention is not in the PKCS10, we need to add it
//otherwise, just use the PKCS10
dwFlags = CR_IN_PKCS10;
pbNewRequest=pbRequest;
cbNewRequest=cbRequest;
if(!AltNameExist(pbRequest, cbRequest))
{
if(GetAltNameElement(pbRequest, cbRequest, &pwszDNS, &IPAddress))
{
if(!AddAltNameInRequest(pRACert, pbRequest, cbRequest, pwszDNS, &IPAddress, &pbNewRequest, &cbNewRequest))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAIL_ADD_ALT, 1, g_pwszComputerName);
goto TraceErr;
}
dwFlags = CR_IN_PKCS7;
}
}
//we always want to make a PKCS7 request so that we can work with enterprise CA
if(CR_IN_PKCS10 == dwFlags)
{
if(!MakePKCS7Request(pRACert, pbRequest, cbRequest, &pbNewRequest, &cbNewRequest))
goto TraceErr;
dwFlags = CR_IN_PKCS7;
}
if(!(bstrRequest=SysAllocStringByteLen((LPCSTR)pbNewRequest, cbNewRequest)))
goto MemoryErr;
//we are requesting a IPSEC offline cert template for Standalone CA
//or general purpose enterprise CA
if((FALSE == pCAInfo->fEnterpriseCA) ||
((dwUsage & CEP_REQUEST_SIGNATURE) && (dwUsage & CEP_REQUEST_EXCHANGE))
)
{
if(!(bstrAttr=SysAllocString(L"CertificateTemplate:IPSECIntermediateOffline\r\n")))
goto MemoryErr;
}
else
{
if(dwUsage & CEP_REQUEST_SIGNATURE)
{
if(pCAInfo->pwszTemplateSig)
pwszTemplate=pCAInfo->pwszTemplateSig;
}
else
{
//the encryption usage must be set
if( 0 == (dwUsage & CEP_REQUEST_EXCHANGE))
{
LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_KEY_USAGE, 1, g_pwszComputerName);
dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
goto FailureStatusReturn;
}
if(pCAInfo->pwszTemplateEnt)
pwszTemplate=pCAInfo->pwszTemplateEnt;
}
pwszAttr=(LPWSTR)malloc((wcslen(CEP_TEMPLATE_ATTR) + wcslen(pwszTemplate) + 5) * sizeof(WCHAR));
if(NULL == pwszAttr)
goto MemoryErr;
wcscpy(pwszAttr, CEP_TEMPLATE_ATTR);
wcscat(pwszAttr, pwszTemplate);
wcscat(pwszAttr, L"\r\n");
if(!(bstrAttr=SysAllocString(pwszAttr)))
goto MemoryErr;
}
if(S_OK != (hr=pCAInfo->pICertRequest->Submit(
CR_IN_BINARY | dwFlags,
bstrRequest,
bstrAttr,
pCAInfo->bstrCAConfig,
&dwDisposition)))
{
LogSCEPEvent(0, TRUE, hr, EVENT_MSCEP_FAIL_SUBMIT, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
switch(dwDisposition)
{
case CR_DISP_ISSUED:
if(S_OK != (hr = pCAInfo->pICertRequest->GetCertificate(CR_OUT_BINARY,
&bstrCert)))
{
LogSCEPEvent(0, TRUE, hr, EVENT_MSCEP_FAIL_QUERY_CERT, 1, g_pwszComputerName);
goto FailureStatusReturn;
}
cbCert = (DWORD)SysStringByteLen(bstrCert);
pbCert = (BYTE *)bstrCert;
//package it in an empty PKCS7
if(!PackageBlobToPKCS7(CEP_CONTEXT_CERT, pbCert, cbCert, ppbData, pcbData))
goto FailureStatusReturn;
pMsgInfo->dwStatus=MESSAGE_STATUS_SUCCESS;
//copy the PKCS10 to the cached request table
if(S_OK == (hr=pCAInfo->pICertRequest->GetRequestId((long*)(&dwRequestID))))
{
CEPCopyRequestAndRequestID(pbRequest, cbRequest, dwRequestID);
}
break;
case CR_DISP_UNDER_SUBMISSION:
//copy the transactionID/requestID pair
if(S_OK == (hr=pCAInfo->pICertRequest->GetRequestId((long*)(&dwRequestID))))
{
if(!CEPHashAddRequestAndTransaction(dwRefreshDays,
dwRequestID,
&(pMsgInfo->TransactionID)))
{
LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_ADD_ID, 1, g_pwszComputerName);
goto DatabaseErr;
}
//also copy the PKCS10 to the cached request table for retrial cases
CEPCopyRequestAndRequestID(pbRequest, cbRequest, dwRequestID);
}
else
{
LogSCEPEvent(0, TRUE, hr, EVENT_MSCEP_GET_REQUEST_ID, 1, g_pwszComputerName);
}
pMsgInfo->dwStatus=MESSAGE_STATUS_PENDING;
break;
case CR_DISP_INCOMPLETE:
case CR_DISP_ERROR:
case CR_DISP_DENIED:
case CR_DISP_ISSUED_OUT_OF_BAND: //we consider it a failure in this case
case CR_DISP_REVOKED:
default:
dwErrorInfo=MESSAGE_FAILURE_BAD_REQUEST;
goto FailureStatusReturn;
break;
}
}
fResult = TRUE;
CommonReturn:
if(pwszAttr)
free(pwszAttr);
if(pwszPassword)
free(pwszPassword);
if(bstrCert)
SysFreeString(bstrCert);
if(bstrRequest)
SysFreeString(bstrRequest);
if(bstrAttr)
SysFreeString(bstrAttr);
if(pwszDNS)
free(pwszDNS);
if(IPAddress.pbData)
free(IPAddress.pbData);
if(dwFlags == CR_IN_PKCS7)
{
if(pbNewRequest)
free(pbNewRequest);
}
return fResult;
FailureStatusReturn:
//we set the error status for the return message
//and consider this http transation a success
pMsgInfo->dwStatus=MESSAGE_STATUS_FAILURE;
pMsgInfo->dwErrorInfo=dwErrorInfo;
*ppbData=NULL;
*pcbData=0;
fResult=TRUE;
goto CommonReturn;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
TRACE_ERROR(TraceErr);
TRACE_ERROR(DatabaseErr);
}
//--------------------------------------------------------------------------
//
// DecryptMsg
//
//--------------------------------------------------------------------------
BOOL WINAPI DecryptMsg(CEP_RA_INFO *pRAInfo,
BYTE *pbReqEnv,
DWORD cbReqEnv,
BYTE **ppbReqDecrypt,
DWORD *pcbReqDecrypt)
{
BOOL fResult = FALSE;
CMSG_CTRL_DECRYPT_PARA DecryptPara;
BOOL fProvFree=FALSE;
HCRYPTMSG hMsg=NULL;
if(!pRAInfo || !pbReqEnv || !ppbReqDecrypt || !pcbReqDecrypt)
goto InvalidArgErr;
*ppbReqDecrypt=NULL;
*pcbReqDecrypt=0;
if(NULL == (hMsg=CryptMsgOpenToDecode(
ENCODE_TYPE,
0,
0,
NULL,
NULL,
NULL)))
goto TraceErr;
if(!CryptMsgUpdate(hMsg,
pbReqEnv,
cbReqEnv,
TRUE))
goto TraceErr;
//decrypt
memset(&DecryptPara, 0, sizeof(CMSG_CTRL_DECRYPT_PARA));
DecryptPara.cbSize=sizeof(CMSG_CTRL_DECRYPT_PARA);
DecryptPara.dwRecipientIndex=0;
DecryptPara.hCryptProv=pRAInfo->hRAProv;
DecryptPara.dwKeySpec=pRAInfo->dwKeySpec;
if(!CryptMsgControl(hMsg,
0,
CMSG_CTRL_DECRYPT,
&DecryptPara))
goto TraceErr;
//get the content
if(!CryptMsgGetParam(hMsg,
CMSG_CONTENT_PARAM,
0,
NULL,
pcbReqDecrypt))
goto TraceErr;
*ppbReqDecrypt=(BYTE *)malloc(*pcbReqDecrypt);
if(NULL==(*ppbReqDecrypt))
goto MemoryErr;
if(!CryptMsgGetParam(hMsg,
CMSG_CONTENT_PARAM,
0,
*ppbReqDecrypt,
pcbReqDecrypt))
goto TraceErr;
fResult = TRUE;
CommonReturn:
if(hMsg)
CryptMsgClose(hMsg);
return fResult;
ErrorReturn:
if(ppbReqDecrypt)
{
if(*ppbReqDecrypt)
{
free(*ppbReqDecrypt);
*ppbReqDecrypt=NULL;
}
}
if(pcbReqDecrypt)
*pcbReqDecrypt=0;
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// GetContentFromPKCS7
//
//--------------------------------------------------------------------------
BOOL WINAPI GetContentFromPKCS7(BYTE *pbMessage,
DWORD cbMessage,
BYTE **ppbContent,
DWORD *pcbContent,
CEP_MESSAGE_INFO *pMsgInfo)
{
BOOL fResult = FALSE;
DWORD cbAuth=0;
DWORD dwIndex=0;
CRYPT_ATTRIBUTE *pOneAuth=NULL;
DWORD cb=0;
DWORD cbCertInfo=0;
PCCERT_CONTEXT pCertPre=NULL;
HCRYPTMSG hMsg=NULL;
CRYPT_ATTRIBUTES *pbAuth=NULL;
void *pb=NULL;
CERT_INFO *pbCertInfo=NULL;
HCERTSTORE hCertStore=NULL;
PCCERT_CONTEXT pCertCur=NULL;
if(!pMsgInfo || !ppbContent || !pcbContent)
goto InvalidArgErr;
*ppbContent=NULL;
*pcbContent=0;
memset(pMsgInfo, 0, sizeof(CEP_MESSAGE_INFO));
if(NULL == (hMsg=CryptMsgOpenToDecode(
ENCODE_TYPE,
0,
0,
NULL,
NULL,
NULL)))
goto TraceErr;
if(!CryptMsgUpdate(hMsg,
pbMessage,
cbMessage,
TRUE))
goto TraceErr;
//get the content
if(!CryptMsgGetParam(hMsg,
CMSG_CONTENT_PARAM,
0,
NULL,
pcbContent))
goto TraceErr;
*ppbContent=(BYTE *)malloc(*pcbContent);
if(NULL==(*ppbContent))
goto MemoryErr;
if(!CryptMsgGetParam(hMsg,
CMSG_CONTENT_PARAM,
0,
*ppbContent,
pcbContent))
goto TraceErr;
//get message type
if(!CryptMsgGetParam(hMsg,
CMSG_SIGNER_AUTH_ATTR_PARAM,
0,
NULL,
&cbAuth))
goto TraceErr;
pbAuth=(CRYPT_ATTRIBUTES *)malloc(cbAuth);
if(NULL==pbAuth)
goto MemoryErr;
if(!CryptMsgGetParam(hMsg,
CMSG_SIGNER_AUTH_ATTR_PARAM,
0,
pbAuth,
&cbAuth))
goto TraceErr;
for(dwIndex=0; dwIndex < pbAuth->cAttr; dwIndex++)
{
pOneAuth=&(pbAuth->rgAttr[dwIndex]);
if((!(pOneAuth->pszObjId)) || (!(pOneAuth->rgValue)))
continue;
if((0==(pOneAuth->rgValue[0].cbData)) || (!(pOneAuth->rgValue[0].pbData)))
continue;
if(0 == strcmp(pOneAuth->pszObjId, szOIDVerisign_MessageType))
{
if(!CEPAllocAndDecode(X509_ANY_STRING,
pOneAuth->rgValue[0].pbData,
pOneAuth->rgValue[0].cbData,
(void **)&pb,
&cb))
goto TraceErr;
if(CERT_RDN_PRINTABLE_STRING != ((CERT_NAME_VALUE *)pb)->dwValueType)
goto InvalidArgErr;
pMsgInfo->dwMessageType = atol((LPSTR)(((CERT_NAME_VALUE *)pb)->Value.pbData));
}
else
{
if(0 == strcmp(pOneAuth->pszObjId, szOIDVerisign_SenderNonce))
{
if(!CEPAllocAndDecode(X509_OCTET_STRING,
pOneAuth->rgValue[0].pbData,
pOneAuth->rgValue[0].cbData,
(void **)&pb,
&cb))
goto TraceErr;
//the SenderNonce in the request is the recipienNonce in the response
if(!AllocAndCopyBlob(&(pMsgInfo->RecipientNonce),
(CERT_BLOB *)pb))
goto TraceErr;
}
else
{
if(0 == strcmp(pOneAuth->pszObjId, szOIDVerisign_TransactionID))
{
if(!CEPAllocAndDecode(X509_ANY_STRING,
pOneAuth->rgValue[0].pbData,
pOneAuth->rgValue[0].cbData,
(void **)&pb,
&cb))
goto TraceErr;
if(CERT_RDN_PRINTABLE_STRING != ((CERT_NAME_VALUE *)pb)->dwValueType)
goto InvalidArgErr;
if(!AllocAndCopyString(&(pMsgInfo->TransactionID),
(LPSTR)(((CERT_NAME_VALUE *)pb)->Value.pbData)))
goto TraceErr;
}
}
}
if(pb)
free(pb);
pb=NULL;
cb=0;
}
//we have to have TrasanctionID and messageType
if((0 == pMsgInfo->dwMessageType)||(NULL == (pMsgInfo->TransactionID.pbData)))
goto InvalidArgErr;
//we get the serial number of the signing certificate
cbCertInfo=0;
if(!CryptMsgGetParam(hMsg,
CMSG_SIGNER_CERT_INFO_PARAM,
0,
NULL,
&cbCertInfo))
goto TraceErr;
pbCertInfo=(CERT_INFO *)malloc(cbCertInfo);
if(NULL==pbCertInfo)
goto MemoryErr;
if(!CryptMsgGetParam(hMsg,
CMSG_SIGNER_CERT_INFO_PARAM,
0,
pbCertInfo,
&cbCertInfo))
goto TraceErr;
if(!AllocAndCopyBlob(&(pMsgInfo->SerialNumber), (CERT_BLOB *)(&(pbCertInfo->SerialNumber))))
goto TraceErr;
//we get the rounter's CA issued certificate for GetCertInitial message
if((MESSAGE_TYPE_GET_CERT_INITIAL == pMsgInfo->dwMessageType) ||
(MESSAGE_TYPE_CERT_REQUEST == pMsgInfo->dwMessageType) ||
(MESSAGE_TYPE_GET_CERT == pMsgInfo->dwMessageType)
)
{
if(NULL == (hCertStore=CertOpenStore(CERT_STORE_PROV_MSG,
ENCODE_TYPE,
NULL,
0,
hMsg)))
goto TraceErr;
pCertPre=NULL;
while(pCertCur=CertEnumCertificatesInStore(hCertStore, pCertPre))
{
if(SameCert(pCertCur->pCertInfo, pbCertInfo))
{
if(NULL==(pMsgInfo->pSigningCert=CertDuplicateCertificateContext(pCertCur)))
goto TraceErr;
break;
}
pCertPre=pCertCur;
}
if(NULL == (pMsgInfo->pSigningCert))
goto InvalidArgErr;
}
fResult = TRUE;
CommonReturn:
if(pCertCur)
CertFreeCertificateContext(pCertCur);
if(hCertStore)
CertCloseStore(hCertStore, 0);
if(pbCertInfo)
free(pbCertInfo);
if(pb)
free(pb);
if(pbAuth)
free(pbAuth);
if(hMsg)
CryptMsgClose(hMsg);
return fResult;
ErrorReturn:
if(ppbContent)
{
if(*ppbContent)
{
free(*ppbContent);
*ppbContent=NULL;
}
}
if(pcbContent)
*pcbContent=0;
FreeMessageInfo(pMsgInfo);
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// SameCert
//
//--------------------------------------------------------------------------
BOOL WINAPI SameCert(CERT_INFO *pCertInfoOne, CERT_INFO *pCertInfoTwo)
{
if(!pCertInfoOne || !pCertInfoTwo)
return FALSE;
if(!SameBlob(&(pCertInfoOne->SerialNumber), &(pCertInfoTwo->SerialNumber)))
return FALSE;
if(!SameBlob((CRYPT_INTEGER_BLOB *)(&(pCertInfoOne->Issuer)),
(CRYPT_INTEGER_BLOB *)(&(pCertInfoTwo->Issuer))))
return FALSE;
return TRUE;
}
//--------------------------------------------------------------------------
//
// SameBlob
//
//--------------------------------------------------------------------------
BOOL WINAPI SameBlob(CRYPT_INTEGER_BLOB *pBlobOne, CRYPT_INTEGER_BLOB *pBlobTwo)
{
if(!pBlobOne || !pBlobTwo)
return FALSE;
if(pBlobOne->cbData != pBlobTwo->cbData)
return FALSE;
if(0!=(memcmp(pBlobOne->pbData, pBlobTwo->pbData,pBlobTwo->cbData)))
return FALSE;
return TRUE;
}
//--------------------------------------------------------------------------
//
// CEPAllocAndDecode
//
//--------------------------------------------------------------------------
BOOL WINAPI CEPAllocAndDecode( LPCSTR lpszStructType,
BYTE *pbEncoded,
DWORD cbEncoded,
void **ppb,
DWORD *pcb)
{
BOOL fResult = FALSE;
*pcb=0;
*ppb=NULL;
if(!CryptDecodeObject(ENCODE_TYPE,
lpszStructType,
pbEncoded,
cbEncoded,
0,
NULL,
pcb))
goto DecodeErr;
*ppb=malloc(*pcb);
if(NULL==(*ppb))
goto MemoryErr;
if(!CryptDecodeObject(ENCODE_TYPE,
lpszStructType,
pbEncoded,
cbEncoded,
0,
*ppb,
pcb))
goto DecodeErr;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
if(ppb)
{
if(*ppb)
{
free(*ppb);
*ppb=NULL;
}
}
if(pcb)
*pcb=0;
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(DecodeErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------------
//
// FreeMessageInfo
//
//--------------------------------------------------------------------------
void WINAPI FreeMessageInfo(CEP_MESSAGE_INFO *pMsgInfo)
{
if(pMsgInfo)
{
if(pMsgInfo->TransactionID.pbData)
free(pMsgInfo->TransactionID.pbData);
if(pMsgInfo->SenderNonce.pbData)
free(pMsgInfo->SenderNonce.pbData);
if(pMsgInfo->RecipientNonce.pbData)
free(pMsgInfo->RecipientNonce.pbData);
if(pMsgInfo->SerialNumber.pbData)
free(pMsgInfo->SerialNumber.pbData);
if(pMsgInfo->pSigningCert)
CertFreeCertificateContext(pMsgInfo->pSigningCert);
memset(pMsgInfo, 0, sizeof(CEP_MESSAGE_INFO));
}
}
//--------------------------------------------------------------------------
//
// AllocAndCopyBlob
//
//--------------------------------------------------------------------------
BOOL WINAPI AllocAndCopyBlob(CERT_BLOB *pDestBlob,
CERT_BLOB *pSrcBlob)
{
memset(pDestBlob, 0, sizeof(CERT_BLOB));
if(NULL==pSrcBlob->pbData)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
pDestBlob->pbData = (BYTE *)malloc(pSrcBlob->cbData);
if(NULL==(pDestBlob->pbData))
{
SetLastError(E_OUTOFMEMORY);
return FALSE;
}
pDestBlob->cbData=pSrcBlob->cbData;
memcpy(pDestBlob->pbData, pSrcBlob->pbData, pDestBlob->cbData);
return TRUE;
}
//--------------------------------------------------------------------------
//
// AllocAndCopyString
//
//--------------------------------------------------------------------------
BOOL WINAPI AllocAndCopyString(CERT_BLOB *pDestBlob,
LPSTR psz)
{
if(!psz)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
pDestBlob->cbData=0;
pDestBlob->pbData=NULL;
pDestBlob->pbData=(BYTE*)malloc(strlen(psz) + 1);
if(NULL == pDestBlob->pbData)
{
SetLastError(E_OUTOFMEMORY);
return FALSE;
}
pDestBlob->cbData=strlen(psz);
strcpy((LPSTR)pDestBlob->pbData, psz);
return TRUE;
}
//--------------------------------------------------------------------------
//
// GetTagValue
//
//--------------------------------------------------------------------------
LPSTR GetTagValue(LPSTR szString, LPSTR szTag)
{
LPSTR pszValue=NULL;
DWORD cbString=0;
DWORD cbTag=0;
cbString = strlen(szString);
cbTag = strlen(szTag);
for(pszValue=szString; cbString > cbTag; pszValue++, cbString--)
{
if((*pszValue) == (*szTag))
{
if(0==_strnicmp(pszValue, szTag, cbTag))
{
//skip the tag
pszValue += cbTag * sizeof(CHAR);
return pszValue;
}
}
}
return NULL;
}