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
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;
|
|
}
|
|
|
|
|
|
|