2025-04-27 07:49:33 -04:00

2496 lines
62 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2000
//
// File: template.cpp
//
// Contents: Cert Server Policy Module implementation
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
#include <ntdsapi.h>
#include <lm.h>
#include <winldap.h>
#include <security.h>
#include "cspelog.h"
#include "pollog.h"
#include "csprop.h"
#include "csldap.h"
#include "csdisp.h"
#include "csber.h"
#include "policy.h"
#include "cainfop.h"
// Versions of NT earlier than this build have an auto-enrollment loop problem
// with not having the basic constraints extension, so we must put one in certs
// for these builds. This build marks when certcli started return no BC
// extension for templates that were not CA's.
#define VERSION_AUTOENROLLMENT_BC_AWARE 2036
// Versions of NT earlier than this build have an auto-enrollment loop problem
// with having the UPN anywhere but the CN. Certs for these builds must have
// the UPN in the common name.
#define VERSION_AUTOENROLLMENT_UPN_AWARE 2090
#define VERSION_WIN2K_XENROLL_CLIENT (2195 + 1)
KUMASK g_aKUMasks[] =
{
{ ~CERT_KEY_AGREEMENT_KEY_USAGE, TEXT(szOID_RSA_RSA) },
{ ~CERT_KEY_ENCIPHERMENT_KEY_USAGE, TEXT(szOID_OIWSEC_dsa) },
{ ~CERT_KEY_ENCIPHERMENT_KEY_USAGE, TEXT(szOID_X957_DSA) },
{ ~CERT_KEY_ENCIPHERMENT_KEY_USAGE, TEXT(szOID_ANSI_X942_DH) },
{ ~CERT_KEY_ENCIPHERMENT_KEY_USAGE, TEXT(szOID_RSA_DH) },
{ ~CERT_KEY_AGREEMENT_KEY_USAGE, TEXT(szOID_OIWSEC_rsaXchg) },
{ ~CERT_KEY_ENCIPHERMENT_KEY_USAGE, TEXT(szOID_INFOSEC_mosaicKMandUpdSig) }
};
CTemplatePolicy::CTemplatePolicy()
{
m_hCertType = NULL;
m_pExtensions = NULL;
m_pwszTemplateName = NULL;
m_pwszTemplateObjId = NULL;
m_dwEnrollmentFlags = 0;
m_dwSubjectNameFlags = 0;
m_dwPrivateKeyFlags = 0;
m_dwGeneralFlags = 0;
m_pPolicy = NULL;
}
CTemplatePolicy::~CTemplatePolicy()
{
_Cleanup();
}
VOID
CTemplatePolicy::_Cleanup()
{
if (NULL != m_hCertType)
{
if (NULL != m_pExtensions)
{
CAFreeCertTypeExtensions(m_hCertType, m_pExtensions);
m_pExtensions = NULL;
}
CACloseCertType(m_hCertType);
m_hCertType = NULL;
}
if (NULL != m_pwszTemplateName)
{
LocalFree(m_pwszTemplateName);
m_pwszTemplateName = NULL;
}
if (NULL != m_pwszTemplateObjId)
{
LocalFree(m_pwszTemplateObjId);
m_pwszTemplateObjId = NULL;
}
m_pPolicy = NULL;
}
HRESULT
CTemplatePolicy::_LogLoadResult(
IN CCertPolicyEnterprise *pPolicy,
IN ICertServerPolicy *pServer,
IN HRESULT hrLoad)
{
HRESULT hr;
WCHAR const *pwszError = NULL;
WCHAR const *apwsz[2];
DWORD level;
DWORD MsgId;
WCHAR const *pwszLogProp;
if (S_OK != hrLoad)
{
pwszError = myGetErrorMessageText(hrLoad, TRUE);
level = CERTLOG_WARNING;
MsgId = MSG_LOAD_TEMPLATE;
pwszLogProp = wszPROPEVENTLOGWARNING;
}
else
{
level = CERTLOG_VERBOSE;
MsgId = MSG_LOAD_TEMPLATE_SUCCEEDED;
pwszLogProp = wszPROPEVENTLOGVERBOSE;
}
if (level > pPolicy->GetLogLevel())
{
hr = S_OK;
goto error;
}
apwsz[0] = m_pwszTemplateName;
apwsz[1] = pwszError;
hr = LogPolicyEvent(
g_hInstance,
MsgId,
pServer,
pwszLogProp,
apwsz);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:LogPolicyEvent");
error:
if (NULL != pwszError)
{
LocalFree(const_cast<WCHAR *>(pwszError));
}
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::Initialize
// Populate the CTemplatePolicy object from the registry
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::Initialize(
IN HCERTTYPE hCertType,
IN ICertServerPolicy *pServer,
IN CCertPolicyEnterprise *pPolicy)
{
HRESULT hr;
CERT_EXTENSIONS *pExtensions = NULL;
_Cleanup();
hr = polCAGetCertTypeStringProperty(
hCertType,
CERTTYPE_PROP_DN,
&m_pwszTemplateName);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:polCAGetCertTypeStringProperty",
CERTTYPE_PROP_DN);
hr = CAGetCertTypePropertyEx(
hCertType,
CERTTYPE_PROP_SCHEMA_VERSION,
&m_dwSchemaVersion);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:CAGetCertTypePropertyEx",
CERTTYPE_PROP_SCHEMA_VERSION);
if (!FIsAdvancedServer() && CERTTYPE_SCHEMA_VERSION_2 <= m_dwSchemaVersion)
{
// V2 templates require Advanced Server
hr = HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
_JumpError(hr, error, "CTemplatePolicy:Initialize:m_dwSchemaVersion");
}
m_pPolicy = pPolicy;
hr = CAGetCertTypeFlagsEx(
hCertType,
CERTTYPE_ENROLLMENT_FLAG,
&m_dwEnrollmentFlags);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeFlagsEx");
hr = CAGetCertTypeFlagsEx(
hCertType,
CERTTYPE_SUBJECT_NAME_FLAG,
&m_dwSubjectNameFlags);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeFlagsEx");
hr = CAGetCertTypeFlagsEx(
hCertType,
CERTTYPE_PRIVATE_KEY_FLAG,
&m_dwPrivateKeyFlags);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeFlagsEx");
hr = CAGetCertTypeFlagsEx(
hCertType,
CERTTYPE_GENERAL_FLAG,
&m_dwGeneralFlags);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeFlagsEx");
hr = CAGetCertTypeExtensions(hCertType, &pExtensions);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeExtensions");
m_dwTemplateMinorVersion = 0;
m_dwMinKeyLength = 0;
if (CERTTYPE_SCHEMA_VERSION_2 <= m_dwSchemaVersion)
{
hr = polCAGetCertTypeStringProperty(
hCertType,
CERTTYPE_PROP_OID,
&m_pwszTemplateObjId);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:polCAGetCertTypeStringProperty",
CERTTYPE_PROP_OID);
hr = CAGetCertTypePropertyEx(
hCertType,
CERTTYPE_PROP_MINOR_REVISION,
&m_dwTemplateMinorVersion);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:CAGetCertTypePropertyEx",
CERTTYPE_PROP_MINOR_REVISION);
hr = CAGetCertTypePropertyEx(
hCertType,
CERTTYPE_PROP_MIN_KEY_SIZE,
&m_dwMinKeyLength);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:CAGetCertTypePropertyEx",
CERTTYPE_PROP_MIN_KEY_SIZE);
}
hr = CAGetCertTypePropertyEx(
hCertType,
CERTTYPE_PROP_REVISION,
&m_dwTemplateMajorVersion);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:CAGetCertTypePropertyEx",
CERTTYPE_PROP_REVISION);
m_hCertType = hCertType; // Transfer ownership only on success
m_pExtensions = pExtensions;
pExtensions = NULL;
hr = S_OK;
error:
if (NULL != pExtensions)
{
CAFreeCertTypeExtensions(hCertType, pExtensions);
}
DBGPRINT((
DBG_SS_CERTPOL,
"Policy:Template:Initialize(%ws, v%u.%u): V%u hr=%x\n",
NULL != m_pwszTemplateName? m_pwszTemplateName : L"",
m_dwTemplateMajorVersion,
m_dwTemplateMinorVersion,
m_dwSchemaVersion,
hr));
_LogLoadResult(pPolicy, pServer, hr);
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::Apply
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::Apply(
IN ICertServerPolicy *pServer,
IN CRequestInstance *pRequest)
{
HRESULT hr;
HANDLE hToken;
if(pRequest->IsNewRequest())
{
// on resubmitted requests we don't have the requester's token
hToken = pRequest->_GetToken();
CSASSERT(NULL != hToken);
hr = CACertTypeAccessCheck(m_hCertType, hToken);
if (E_ACCESSDENIED == hr)
{
// map E_ACCESSDENIED to a more meaningful error
hr = CERTSRV_E_TEMPLATE_DENIED;
}
_JumpIfError(hr, error, "Policy:CACertTypeAccessCheck");
}
hr = _AddBasicConstraintsExtension(pRequest, pServer);
_JumpIfError(hr, error, "Policy:_AddBasicConstraintsExtension");
hr = _AddKeyUsageExtension(pServer);
_JumpIfError(hr, error, "Policy:_AddKeyUsageExtension");
hr = _AddTemplateExtensionArray(pServer);
_JumpIfError(hr, error, "Policy:_AddTemplateExtensionArray");
if (0 == (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT & m_dwSubjectNameFlags))
{
hr = pRequest->_LoadPrincipalObject(pServer, this);
_JumpIfError(hr, error, "_LoadPrincipalObject");
hr = _AddSubjectName(pServer, pRequest);
_JumpIfError(hr, error, "Policy:_AddSubjectName");
}
hr = _AddAltSubjectName(pServer, pRequest);
_JumpIfError(hr, error, "Policy:_AddAltSubjectName");
hr = _ApplyExpirationTime(pServer);
_JumpIfError(hr, error, "Policy:_ApplyExpirationTime");
hr = _EnforceKeySizePolicy(pServer);
_JumpIfError(hr, error, "Policy:_EnforceKeySizePolicy");
hr = _EnforceKeyArchivalPolicy(pServer);
_JumpIfError(hr, error, "Policy:_EnforceKeyArchivalPolicy");
hr = _EnforceSymmetricAlgorithms(pServer, pRequest);
_JumpIfError(hr, error, "Policy:_EnforceSymmetricAlgorithms");
hr = _EnforceMinimumTemplateVersion(pRequest);
_JumpIfError(hr, error, "Policy:_EnforceMinimumTemplateVersion");
hr = _EnforceEnrollOnBehalfOfAllowed(pServer, pRequest);
_JumpIfError(hr, error, "Policy:_EnforceEnrollOnBehalfOfAllowed");
hr = S_FALSE;
if (CT_FLAG_PREVIOUS_APPROVAL_VALIDATE_REENROLLMENT & m_dwEnrollmentFlags)
{
hr = _EnforceReenrollment(pServer, pRequest);
_PrintIfError(hr, "Policy:_EnforceReenrollment");
}
if (S_OK != hr)
{
hr = _EnforceSignaturePolicy(pServer);
_JumpIfError(hr, error, "Policy:_EnforceSignaturePolicy");
}
CSASSERT(S_OK == hr);
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::_AddBasicConstraintsExtension
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_AddBasicConstraintsExtension(
IN CRequestInstance *pRequest,
IN ICertServerPolicy *pServer)
{
HRESULT hr;
CERT_EXTENSION const *pExt;
CERT_EXTENSION BasicConstraintsExtension;
BasicConstraintsExtension.Value.pbData = NULL;
pExt = CertFindExtension(
szOID_BASIC_CONSTRAINTS2,
m_pExtensions->cExtension,
m_pExtensions->rgExtension);
if (NULL == pExt)
{
if (pRequest->_IsNTClientOlder(
5,
0,
VERSION_AUTOENROLLMENT_BC_AWARE,
VER_PLATFORM_WIN32_NT))
{
CERT_BASIC_CONSTRAINTS2_INFO OldBasicConstraints =
{ FALSE, FALSE, 0};
// Older autoenrollment clients don't know how to deal with
// having no basic constraints extension, so they might loop.
// For an old client, we must fabricate a basic constraints.
if (!myEncodeObject(
X509_ASN_ENCODING,
szOID_BASIC_CONSTRAINTS2,
&OldBasicConstraints,
0,
CERTLIB_USE_LOCALALLOC,
&BasicConstraintsExtension.Value.pbData,
&BasicConstraintsExtension.Value.cbData))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myEncodeObject");
}
BasicConstraintsExtension.fCritical = TRUE;
BasicConstraintsExtension.pszObjId = szOID_BASIC_CONSTRAINTS2;
pExt = &BasicConstraintsExtension;
}
}
hr = m_pPolicy->AddBasicConstraintsCommon(
pServer,
pExt,
FALSE, // fCA only enabled for standalone
NULL != pExt);
_JumpIfError(hr, error, "Policy:AddBasicConstraintsCommon");
error:
if (NULL != BasicConstraintsExtension.Value.pbData)
{
LocalFree(BasicConstraintsExtension.Value.pbData);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::_AddKeyUsageExtension
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_AddKeyUsageExtension(
IN ICertServerPolicy *pServer)
{
HRESULT hr = S_OK;
BSTR strExtension = NULL;
VARIANT varExtension;
BSTR strAlg = NULL;
CERT_EXTENSION const *pExt;
CRYPT_BIT_BLOB *pKeyUsage = NULL;
BYTE *pbKeyUsage = NULL;
DWORD cbKeyUsage;
DWORD dwMask = 0xffffffff;
DWORD i;
VariantInit(&varExtension);
hr = polGetCertificateStringProperty(
pServer,
wszPROPCERTIFICATEPUBLICKEYALGORITHM,
&strAlg);
_JumpIfError(hr, error, "Policy:polGetCertificateStringProperty");
for (i = 0; i < ARRAYSIZE(g_aKUMasks); i++)
{
if (0 == wcscmp(strAlg, g_aKUMasks[i].wszAlg))
{
dwMask = g_aKUMasks[i].dwMask;
break;
}
}
pExt = CertFindExtension(
szOID_KEY_USAGE,
m_pExtensions->cExtension,
m_pExtensions->rgExtension);
if (NULL == pExt)
{
hr = S_OK;
goto error;
}
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_KEY_USAGE,
pExt->Value.pbData,
pExt->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pKeyUsage,
&cbKeyUsage))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myDecodeObject");
}
// Mask out any unneeded bits
for (i = 0; i < pKeyUsage->cbData; i++)
{
pKeyUsage->pbData[i] &= ((BYTE *) &dwMask)[i];
}
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_KEY_USAGE,
pKeyUsage,
0,
CERTLIB_USE_LOCALALLOC,
&pbKeyUsage,
&cbKeyUsage))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myEncodeObject");
}
if (!myConvertWszToBstr(
&strExtension,
(WCHAR const *) pbKeyUsage,
cbKeyUsage))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:myConvertWszToBstr");
}
varExtension.vt = VT_BSTR;
varExtension.bstrVal = strExtension;
strExtension = NULL;
hr = pServer->SetCertificateExtension(
TEXT(szOID_KEY_USAGE),
PROPTYPE_BINARY,
pExt->fCritical? EXTENSION_CRITICAL_FLAG : 0,
&varExtension);
_JumpIfError(hr, error, "Policy:SetCertificateExtension");
error:
VariantClear(&varExtension);
if (NULL != strAlg)
{
SysFreeString(strAlg);
}
if (NULL != strExtension)
{
SysFreeString(strExtension);
}
if (NULL != pbKeyUsage)
{
LocalFree(pbKeyUsage);
}
if (NULL != pKeyUsage)
{
LocalFree(pKeyUsage);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::_AddTemplateExtensionArray
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_AddTemplateExtensionArray(
IN ICertServerPolicy *pServer)
{
HRESULT hr;
DWORD i;
for (i = 0; i < m_pExtensions->cExtension; i++)
{
CERT_EXTENSION const *pExt = &m_pExtensions->rgExtension[i];
// Skip extensions that have special handling code.
if (0 == strcmp(szOID_BASIC_CONSTRAINTS2, pExt->pszObjId) ||
0 == strcmp(szOID_KEY_USAGE, pExt->pszObjId))
{
continue;
}
hr = _AddTemplateExtension(pServer, pExt);
_JumpIfError(hr, error, "Policy:_AddTemplateExtension");
}
hr = S_OK;
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::_AddTemplateExtension
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_AddTemplateExtension(
IN ICertServerPolicy *pServer,
IN CERT_EXTENSION const *pExt)
{
HRESULT hr = S_OK;
BSTR strExtension = NULL;
BSTR strObjId = NULL;
VARIANT varExtension;
if (!myConvertSzToBstr(&strObjId, pExt->pszObjId, -1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:myConvertSzToBstr");
}
if (!myConvertWszToBstr(
&strExtension,
(WCHAR const *) pExt->Value.pbData,
pExt->Value.cbData))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:myConvertWszToBstr");
}
varExtension.vt = VT_BSTR;
varExtension.bstrVal = strExtension;
hr = pServer->SetCertificateExtension(
strObjId,
PROPTYPE_BINARY,
pExt->fCritical? EXTENSION_CRITICAL_FLAG : 0,
&varExtension);
_JumpIfErrorStr(hr, error, "Policy:SetCertificateExtension", strObjId);
error:
if (NULL != strObjId)
{
SysFreeString(strObjId);
}
if (NULL != strExtension)
{
SysFreeString(strExtension);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::_AddSubjectName
//
// Build the subject name and add it to the cert, if required
//
// The subject name consists of:
// machine: the CN is set to the UPN (machineDNSName)
// old user: the CN is set to the UPN (Kerberos name)
// user: the CN is set to the DS_ATTR_COMMON_NAME
//
// both: E= indicates an e-mail name
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_AddSubjectName(
IN ICertServerPolicy *pServer,
CRequestInstance *pRequest)
{
HRESULT hr;
BSTRC strCN = NULL;
BSTRC strEMail = NULL;
VARIANT varValue;
// Clear out any existing subject name info
varValue.vt = VT_NULL;
hr = pServer->SetCertificateProperty(
wszPROPSUBJECTDOT, // BUGBUG:BSTR
PROPTYPE_STRING,
&varValue);
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
if (CT_FLAG_SUBJECT_REQUIRE_DIRECTORY_PATH & m_dwSubjectNameFlags)
{
hr = _AddDSDistinguishedName(pServer, pRequest);
_JumpIfError(hr, error, "Policy:_AddDSDistinguishedName");
}
else
if ((CT_FLAG_SUBJECT_REQUIRE_COMMON_NAME |
CT_FLAG_SUBJECT_REQUIRE_DNS_AS_CN) & m_dwSubjectNameFlags)
{
if (!pRequest->_IsUser() ||
(pRequest->_IsXenrollRequest() &&
pRequest->_IsNTClientOlder(
5,
0,
VERSION_AUTOENROLLMENT_UPN_AWARE,
VER_PLATFORM_WIN32_NT)))
{
// The UPN will be either a user UPN or the machine DNS name
if (NULL == pRequest->m_pwszUPN)
{
hr = E_POINTER; // We should never get this
_JumpError(hr, error, "Policy:NULL UPN");
}
strCN = SysAllocString(pRequest->m_pwszUPN);
if (NULL == strCN)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocString");
}
}
else
{
// We are talking to an advanced client which can deal with a UPN
// in a SubjectAltName extension. Put the DS CN in the cert.
hr = pRequest->_GetValueString(DS_ATTR_COMMON_NAME, &strCN);
_JumpIfErrorStr(
hr,
error,
"Policy:_GetValueString",
DS_ATTR_COMMON_NAME);
}
CSASSERT(NULL != strCN);
varValue.vt = VT_BSTR;
varValue.bstrVal = const_cast<BSTR>(strCN);
hr = pServer->SetCertificateProperty(
wszPROPSUBJECTCOMMONNAME, // BUGBUG:BSTR
PROPTYPE_STRING,
&varValue);
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
}
if (CT_FLAG_SUBJECT_REQUIRE_EMAIL & m_dwSubjectNameFlags)
{
hr = pRequest->_GetValueString(DS_ATTR_EMAIL_ADDR, &strEMail);
if (S_OK == hr)
{
varValue.vt = VT_BSTR;
varValue.bstrVal = const_cast<BSTR>(strEMail);
hr = pServer->SetCertificateProperty(
wszPROPSUBJECTEMAIL, // BUGBUG:BSTR
PROPTYPE_STRING,
&varValue);
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
}
else
{
LPCWSTR wszStrings[1];
wszStrings[0] = pRequest->m_strUserDN;
::LogModuleStatus(
g_hInstance,
MSG_NO_EMAIL_NAME,
TRUE,
pRequest->GetPolicy()->GetPolicyDescription(),
wszStrings);
}
}
hr = S_OK;
error:
if (NULL != strCN)
{
SysFreeString(const_cast<BSTR>(strCN));
}
if (NULL != strEMail)
{
SysFreeString(const_cast<BSTR>(strEMail));
}
return(hr);
}
HRESULT
myCertStrToName(
IN WCHAR const *pwszName,
OUT CERT_NAME_BLOB *pName)
{
HRESULT hr;
WCHAR const *pwszError;
pName->cbData = 0;
pName->pbData = NULL;
if (!CertStrToName(
X509_ASN_ENCODING,
pwszName,
CERT_X500_NAME_STR,
NULL,
NULL, // pName
&pName->cbData,
&pwszError))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:CertStrToName");
}
pName->pbData = (BYTE *) LocalAlloc(LMEM_FIXED, pName->cbData);
if (NULL == pName->pbData)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:LocalAlloc");
}
if (!CertStrToName(
X509_ASN_ENCODING,
pwszName,
CERT_X500_NAME_STR,
NULL,
pName->pbData,
&pName->cbData,
&pwszError))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:CertStrToName");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
CTemplatePolicy::_AddDSDistinguishedName(
IN ICertServerPolicy *pServer,
CRequestInstance *pRequest)
{
HRESULT hr;
CERT_NAME_BLOB Name = { 0, NULL };
CERT_NAME_INFO *pNameInfo = NULL;
WCHAR *pwszObjId = NULL;
BSTR strRDN = NULL;
BSTR strRDNName = NULL;
BSTR strRDNValue = NULL;
DWORD cb;
CERT_RDN *prdn;
CERT_RDN *prdnEnd;
if (NULL == pRequest->m_strUserDN)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "Policy:m_strUserDN");
}
hr = myCertStrToName(pRequest->m_strUserDN, &Name);
_JumpIfError(hr, error, "Policy:myCertStrToName");
if (!myDecodeName(
X509_ASN_ENCODING,
X509_UNICODE_NAME,
Name.pbData,
Name.cbData,
CERTLIB_USE_LOCALALLOC,
&pNameInfo,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeName");
}
for (
prdn = pNameInfo->rgRDN, prdnEnd = &prdn[pNameInfo->cRDN];
prdn < prdnEnd;
prdn++)
{
CERT_RDN_ATTR *prdna;
CERT_RDN_ATTR *prdnaEnd;
for (
prdna = prdn->rgRDNAttr, prdnaEnd = &prdna[prdn->cRDNAttr];
prdna < prdnaEnd;
prdna++)
{
VARIANT varNew;
if (NULL == prdna->Value.pbData ||
sizeof(WCHAR) > prdna->Value.cbData ||
L'\0' == *(WCHAR *) prdna->Value.pbData)
{
continue;
}
if (NULL != strRDNValue)
{
SysFreeString(strRDNValue);
strRDNValue = NULL;
}
if (NULL != strRDNName)
{
SysFreeString(strRDNName);
strRDNName = NULL;
}
if (NULL != pwszObjId)
{
LocalFree(pwszObjId);
pwszObjId = NULL;
}
if (!myConvertSzToWsz(&pwszObjId, prdna->pszObjId, MAXDWORD))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:myConvertSzToWsz");
}
strRDNName = SysAllocStringLen(
NULL,
WSZARRAYSIZE(wszPROPSUBJECTDOT) + wcslen(pwszObjId));
if (NULL == strRDNName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocStringLen");
}
wcscpy(strRDNName, wszPROPSUBJECTDOT);
wcscat(strRDNName, pwszObjId);
CSASSERT(SysStringByteLen(strRDNName) == wcslen(strRDNName) * sizeof(WCHAR));
hr = polGetCertificateStringProperty(pServer, strRDNName, &strRDN);
if (S_OK == hr)
{
strRDNValue = SysAllocStringLen(
NULL,
wcslen((WCHAR *) prdna->Value.pbData) +
WSZARRAYSIZE(wszNAMESEPARATORDEFAULT) +
wcslen(strRDN));
if (NULL == strRDNValue)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocStringLen");
}
wcscpy(strRDNValue, (WCHAR *) prdna->Value.pbData);
wcscat(strRDNValue, wszNAMESEPARATORDEFAULT);
wcscat(strRDNValue, strRDN);
}
if (NULL == strRDNValue)
{
strRDNValue = SysAllocString((WCHAR *) prdna->Value.pbData);
if (NULL == strRDNValue)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocStringLen");
}
}
varNew.vt = VT_BSTR;
varNew.bstrVal = strRDNValue;
hr = pServer->SetCertificateProperty(
strRDNName,
PROPTYPE_STRING,
&varNew);
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
}
}
error:
if (NULL != strRDN)
{
SysFreeString(strRDN);
}
if (NULL != strRDNValue)
{
SysFreeString(strRDNValue);
}
if (NULL != strRDNName)
{
SysFreeString(strRDNName);
}
if (NULL != pwszObjId)
{
LocalFree(pwszObjId);
}
if (NULL != Name.pbData)
{
LocalFree(Name.pbData);
}
if (NULL != pNameInfo)
{
LocalFree(pNameInfo);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CCertPolicyEnterprise::_AddAltSubjectName
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_AddAltSubjectName(
IN ICertServerPolicy *pServer,
CRequestInstance *pRequest)
{
HRESULT hr = S_OK;
DWORD cbExtension;
VARIANT varExtension;
DWORD iNameEntry;
WCHAR **ppwszCurName;
CERT_OTHER_NAME objectGuidOtherName;
CERT_OTHER_NAME upnOtherName;
WCHAR **apwszMailNames = NULL;
WCHAR **apwszMachineNames = NULL;
BYTE *pbExtension= NULL;
BSTR strobjectGuid = NULL;
CERT_ALT_NAME_INFO AltName;
AltName.cAltEntry = 0;
AltName.rgAltEntry = 0;
objectGuidOtherName.Value.pbData = NULL;
objectGuidOtherName.Value.cbData = 0;
upnOtherName.Value.pbData = NULL;
upnOtherName.Value.cbData = 0;
VariantInit(&varExtension);
// If this cert template doesn't set the alt-subject-name, then enable
// whatever alt subject name that was in the request.
if (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME & m_dwSubjectNameFlags)
{
LONG ExtFlags;
hr = pServer->GetCertificateExtension(
TEXT(szOID_SUBJECT_ALT_NAME2),
PROPTYPE_BINARY,
&varExtension);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED;
}
_JumpIfError(hr, error, "Policy:GetCertificateExtension");
hr = pServer->GetCertificateExtensionFlags(&ExtFlags);
_JumpIfError(hr, error, "Policy:GetCertificateExtensionFlags");
if (EXTENSION_DISABLE_FLAG & ExtFlags)
{
ExtFlags &= ~EXTENSION_DISABLE_FLAG;
hr = pServer->SetCertificateExtension(
TEXT(szOID_SUBJECT_ALT_NAME2),
PROPTYPE_BINARY,
ExtFlags,
&varExtension);
_JumpIfError(hr, error, "Policy:SetCertificateExtension");
}
CSASSERT(S_OK == hr);
goto error;
}
// We do alt name entries for
// UPN/SPN
// rfc822 (mail name)
// DNSname
// DS location
if ((CT_FLAG_SUBJECT_ALT_REQUIRE_UPN | CT_FLAG_SUBJECT_ALT_REQUIRE_SPN) &
m_dwSubjectNameFlags)
{
// Add the UPN
if (NULL == pRequest->m_pwszUPN)
{
hr = CERTSRV_E_SUBJECT_UPN_REQUIRED;
_JumpError(hr, error, "Policy:_AddAltSubjectName");
}
AltName.cAltEntry++;
}
if (CT_FLAG_SUBJECT_ALT_REQUIRE_EMAIL & m_dwSubjectNameFlags)
{
hr = pRequest->_GetValues(DS_ATTR_EMAIL_ADDR, &apwszMailNames);
if (S_OK != hr || NULL == apwszMailNames || NULL == apwszMailNames[0])
{
LPCWSTR wszStrings[1];
_PrintIfError(hr, "_GetValues(email)");
wszStrings[0] = pRequest->m_strUserDN;
::LogModuleStatus(
g_hInstance,
MSG_NO_EMAIL_NAME,
TRUE,
pRequest->GetPolicy()->GetPolicyDescription(),
wszStrings);
}
else
{
ppwszCurName = apwszMailNames;
while (NULL != *ppwszCurName)
{
AltName.cAltEntry++;
ppwszCurName++;
}
}
}
if (CT_FLAG_SUBJECT_ALT_REQUIRE_DIRECTORY_GUID & m_dwSubjectNameFlags)
{
hr = pRequest->_GetObjectGUID(&strobjectGuid);
if (S_OK != hr || NULL == strobjectGuid)
{
_PrintIfError(hr, "_GetObjectGUID");
hr = CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED;
_JumpError(hr, error, "Policy:_AddAltSubjectName");
}
AltName.cAltEntry++;
}
if (CT_FLAG_SUBJECT_ALT_REQUIRE_DNS & m_dwSubjectNameFlags)
{
hr = pRequest->_GetValues(DS_ATTR_DNS_NAME, &apwszMachineNames);
if (S_OK != hr || NULL == apwszMachineNames || NULL == apwszMachineNames[0])
{
_PrintIfError(hr, "_GetValues(dns)");
hr = CERTSRV_E_SUBJECT_DNS_REQUIRED;
_JumpError(hr, error, "Policy:_AddAltSubjectName");
}
ppwszCurName = apwszMachineNames;
while (NULL != *ppwszCurName)
{
AltName.cAltEntry++;
ppwszCurName++;
}
}
if (AltName.cAltEntry == 0)
{
hr = S_OK;
goto error;
}
AltName.rgAltEntry = (CERT_ALT_NAME_ENTRY *) LocalAlloc(
LMEM_FIXED,
sizeof(CERT_ALT_NAME_ENTRY) * AltName.cAltEntry);
if (NULL == AltName.rgAltEntry)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:LocalAlloc");
}
iNameEntry = 0;
if ((CT_FLAG_SUBJECT_ALT_REQUIRE_UPN | CT_FLAG_SUBJECT_ALT_REQUIRE_SPN) &
m_dwSubjectNameFlags)
{
// Add the UPN
CERT_NAME_VALUE nameUpn;
nameUpn.dwValueType = CERT_RDN_UTF8_STRING;
nameUpn.Value.pbData = (BYTE *) pRequest->m_pwszUPN;
nameUpn.Value.cbData = wcslen(pRequest->m_pwszUPN) * sizeof(WCHAR);
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_UNICODE_ANY_STRING,
&nameUpn,
0,
CERTLIB_USE_LOCALALLOC,
&upnOtherName.Value.pbData,
&upnOtherName.Value.cbData))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myEncodeObject");
}
upnOtherName.pszObjId = szOID_NT_PRINCIPAL_NAME;
AltName.rgAltEntry[iNameEntry].dwAltNameChoice= CERT_ALT_NAME_OTHER_NAME;
AltName.rgAltEntry[iNameEntry++].pOtherName = &upnOtherName;
}
// Now do strobjectGuid
if (CT_FLAG_SUBJECT_ALT_REQUIRE_DIRECTORY_GUID & m_dwSubjectNameFlags)
{
CRYPT_DATA_BLOB blobGuid;
CSASSERT(NULL != strobjectGuid);
blobGuid.pbData = (BYTE *) strobjectGuid;
blobGuid.cbData = SysStringByteLen(strobjectGuid);
objectGuidOtherName.pszObjId = szOID_NTDS_REPLICATION;
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_OCTET_STRING,
&blobGuid,
0,
CERTLIB_USE_LOCALALLOC,
&objectGuidOtherName.Value.pbData,
&objectGuidOtherName.Value.cbData))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myEncodeObject");
}
AltName.rgAltEntry[iNameEntry].dwAltNameChoice= CERT_ALT_NAME_OTHER_NAME;
AltName.rgAltEntry[iNameEntry++].pOtherName = &objectGuidOtherName;
}
// Now do rfc822
if (CT_FLAG_SUBJECT_ALT_REQUIRE_EMAIL & m_dwSubjectNameFlags)
{
ppwszCurName = apwszMailNames;
if (NULL != ppwszCurName)
{
while (NULL != *ppwszCurName)
{
AltName.rgAltEntry[iNameEntry].dwAltNameChoice= CERT_ALT_NAME_RFC822_NAME;
AltName.rgAltEntry[iNameEntry++].pwszRfc822Name = *ppwszCurName;
ppwszCurName++;
}
}
}
// Now do DNS
if (CT_FLAG_SUBJECT_ALT_REQUIRE_DNS & m_dwSubjectNameFlags)
{
ppwszCurName = apwszMachineNames;
if (NULL != ppwszCurName)
{
while (NULL != *ppwszCurName)
{
AltName.rgAltEntry[iNameEntry].dwAltNameChoice= CERT_ALT_NAME_DNS_NAME;
AltName.rgAltEntry[iNameEntry++].pwszRfc822Name = *ppwszCurName;
ppwszCurName++;
}
}
}
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_ALTERNATE_NAME,
&AltName,
0,
CERTLIB_USE_LOCALALLOC,
&pbExtension,
&cbExtension))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myEncodeObject");
}
varExtension.vt = VT_BSTR;
varExtension.bstrVal = SysAllocStringByteLen(
(char const *) pbExtension,
cbExtension);
if (NULL == varExtension.bstrVal)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocStringByteLen");
}
hr = pServer->SetCertificateExtension(
TEXT(szOID_SUBJECT_ALT_NAME2),
PROPTYPE_BINARY,
0,
&varExtension);
_JumpIfError(hr, error, "Policy:SetCertificateExtension");
error:
if (NULL != pbExtension)
{
LocalFree(pbExtension);
}
if (NULL != strobjectGuid)
{
SysFreeString(strobjectGuid);
}
if (NULL != AltName.rgAltEntry)
{
// clean each entry in array
for (DWORD i = 0; i < AltName.cAltEntry; i++)
{
switch (AltName.rgAltEntry[i].dwAltNameChoice)
{
case CERT_ALT_NAME_DIRECTORY_NAME:
{
if (NULL != AltName.rgAltEntry[i].DirectoryName.pbData)
{
LocalFree(AltName.rgAltEntry[i].DirectoryName.pbData);
AltName.rgAltEntry[i].DirectoryName.pbData = NULL;
}
break;
}
case CERT_ALT_NAME_OTHER_NAME:
// points to objectGuidOtherName or bstrUpn, which are
// freed separately
break;
case CERT_ALT_NAME_RFC822_NAME:
// points to apwszMailNames, freed later
break;
case CERT_ALT_NAME_DNS_NAME:
// points to apwszMachineNames, freed later
break;
}
}
// free array
LocalFree(AltName.rgAltEntry);
}
if (NULL != objectGuidOtherName.Value.pbData)
{
LocalFree(objectGuidOtherName.Value.pbData);
}
if (NULL != upnOtherName.Value.pbData)
{
LocalFree(upnOtherName.Value.pbData);
}
if (NULL != pRequest)
{
if (NULL != apwszMailNames)
{
pRequest->_FreeValues(apwszMailNames);
}
if (NULL != apwszMachineNames)
{
pRequest->_FreeValues(apwszMachineNames);
}
}
VariantClear(&varExtension);
return(hr);
}
#ifdef DBG_CERTSRV_DEBUG_PRINT
# define DBGPRINTTIMEORPERIOD(pszDesc, pft) \
policyDbgPrintTimeOrPeriod((pszDesc), (pft))
VOID
policyDbgPrintTimeOrPeriod(
IN char const *pszDesc,
IN FILETIME const *pft)
{
HRESULT hr;
WCHAR *pwszTime = NULL;
WCHAR awc[1];
if (0 <= (LONG) pft->dwHighDateTime)
{
hr = myGMTFileTimeToWszLocalTime(pft, TRUE, &pwszTime);
_PrintIfError(hr, "myGMTFileTimeToWszLocalTime");
}
else
{
hr = myFileTimePeriodToWszTimePeriod(pft, TRUE, &pwszTime);
_PrintIfError(hr, "myFileTimePeriodToWszTimePeriod");
}
if (S_OK != hr)
{
awc[0] = L'\0';
pwszTime = awc;
}
DBGPRINT((DBG_SS_CERTPOL, "%hs: %ws\n", pszDesc, pwszTime));
//error:
if (NULL != pwszTime && awc != pwszTime)
{
LocalFree(pwszTime);
}
}
#else // DBG_CERTSRV_DEBUG_PRINT
# define DBGPRINTTIMEORPERIOD(pszDesc, pft)
#endif // DBG_CERTSRV_DEBUG_PRINT
//+--------------------------------------------------------------------------
// CCertPolicyEnterprise::_ApplyExpirationTime
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_ApplyExpirationTime(
IN ICertServerPolicy *pServer)
{
HRESULT hr = S_OK;
VARIANT varValue;
BSTR strNameNotBefore = NULL;
BSTR strNameNotAfter = NULL;
SYSTEMTIME SystemTime;
LARGE_INTEGER ftExpirationPeriod;
LARGE_INTEGER ftNotAfter;
LARGE_INTEGER ftNotAfterCalc;
LARGE_INTEGER ftNotBefore;
VariantInit(&varValue);
strNameNotBefore = SysAllocString(wszPROPCERTIFICATENOTBEFOREDATE);
if (NULL == strNameNotBefore)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocString");
}
hr = pServer->GetCertificateProperty(
strNameNotBefore,
PROPTYPE_DATE,
&varValue);
_JumpIfError(hr, error, "Policy:GetCertificateProperty");
if (VT_DATE != varValue.vt)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Policy:varValue.vt");
}
if (!VariantTimeToSystemTime(varValue.date, &SystemTime))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:VariantTimeToSystemTime");
}
if (!SystemTimeToFileTime(&SystemTime, (LPFILETIME)&ftNotBefore))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:SystemTimeToFileTime");
}
strNameNotAfter = SysAllocString(wszPROPCERTIFICATENOTAFTERDATE);
if (NULL == strNameNotAfter)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocString");
}
hr = pServer->GetCertificateProperty(
strNameNotAfter,
PROPTYPE_DATE,
&varValue);
_JumpIfError(hr, error, "Policy:GetCertificateProperty");
if (VT_DATE != varValue.vt)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Policy:varValue.vt");
}
if (!VariantTimeToSystemTime(varValue.date, &SystemTime))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:VariantTimeToSystemTime");
}
if (!SystemTimeToFileTime(&SystemTime, (LPFILETIME)&ftNotAfter))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:SystemTimeToFileTime");
}
hr = CAGetCertTypeExpiration(m_hCertType, (LPFILETIME)&ftExpirationPeriod, NULL);
_JumpIfError(hr, error, "Policy:CAGetCertTypeExpiration");
if (0 > ftExpirationPeriod.QuadPart)
{
ftNotAfterCalc.QuadPart = ftNotBefore.QuadPart - ftExpirationPeriod.QuadPart;
}
else
{
ftNotAfterCalc = ftExpirationPeriod;
}
if (ftNotAfterCalc.QuadPart > ftNotAfter.QuadPart)
{
ftNotAfterCalc = ftNotAfter;
}
if (!FileTimeToSystemTime((FILETIME *) &ftNotAfterCalc, &SystemTime))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:FileTimeToSystemTime");
}
if (!SystemTimeToVariantTime(&SystemTime, &varValue.date))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:SystemTimeToVariantTime");
}
hr = pServer->SetCertificateProperty(
wszPROPCERTIFICATENOTAFTERDATE, // BUGBUG:BSTR
PROPTYPE_DATE,
&varValue);
if (S_OK != hr)
{
DBGPRINTTIMEORPERIOD(" Old NotBefore", (FILETIME const *) &ftNotBefore);
DBGPRINTTIMEORPERIOD(" Old NotAfter", (FILETIME const *) &ftNotAfter);
DBGPRINTTIMEORPERIOD("Template Period", (FILETIME const *) &ftExpirationPeriod);
DBGPRINTTIMEORPERIOD(" New NotAfter", (FILETIME const *) &ftNotAfterCalc);
}
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
error:
VariantClear(&varValue);
if (NULL != strNameNotBefore)
{
SysFreeString(strNameNotBefore);
}
if (NULL != strNameNotAfter)
{
SysFreeString(strNameNotAfter);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CCertPolicyEnterprise::_EnforceKeySizePolicy
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_EnforceKeySizePolicy(
IN ICertServerPolicy *pServer)
{
HRESULT hr;
if (0 != m_dwMinKeyLength)
{
LONG KeyLength;
hr = polGetCertificateLongProperty(
pServer,
wszPROPCERTIFICATEPUBLICKEYLENGTH,
&KeyLength);
_JumpIfErrorStr(
hr,
error,
"Policy:polGetCertificateLongProperty",
wszPROPCERTIFICATEPUBLICKEYLENGTH);
if (m_dwMinKeyLength > (DWORD) KeyLength)
{
DBGPRINT((
DBG_SS_ERROR,
"Key Length %u, expected minimum %u\n",
KeyLength,
m_dwMinKeyLength));
hr = CERTSRV_E_KEY_LENGTH;
_JumpError(hr, error, "Key too small");
}
}
hr = S_OK;
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CCertPolicyEnterprise::_EnforceKeyArchivalPolicy
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_EnforceKeyArchivalPolicy(
IN ICertServerPolicy *pServer)
{
HRESULT hr;
BSTR str = NULL;
hr = polGetRequestStringProperty(
pServer,
wszPROPREQUESTKEYRECOVERYHASHES,
&str);
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_JumpIfErrorStr(
hr,
error,
"Policy:polGetRequestStringProperty",
wszPROPREQUESTKEYRECOVERYHASHES);
}
if (CT_FLAG_REQUIRE_PRIVATE_KEY_ARCHIVAL & m_dwPrivateKeyFlags)
{
if (S_OK != hr)
{
hr = CERTSRV_E_ARCHIVED_KEY_REQUIRED;
_JumpError(hr, error, "missing archived key");
}
}
else
{
if (S_OK == hr)
{
hr = CERTSRV_E_ARCHIVED_KEY_UNEXPECTED;
_JumpError(hr, error, "unexpected archived key");
}
}
hr = S_OK;
error:
if (NULL != str)
{
SysFreeString(str);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CCertPolicyEnterprise::_EnforceSymmetricAlgorithms
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_EnforceSymmetricAlgorithms(
IN ICertServerPolicy *pServer,
IN CRequestInstance *pRequest)
{
HRESULT hr;
VARIANT varExtension;
BOOL fSetNeeded = FALSE;
BOOL fAddExtension = FALSE;
LONG ExtFlags = 0;
BSTR strCSPProvider = NULL;
VariantInit(&varExtension);
if (CT_FLAG_INCLUDE_SYMMETRIC_ALGORITHMS & m_dwEnrollmentFlags)
{
hr = pServer->GetCertificateExtension(
TEXT(szOID_RSA_SMIMECapabilities),
PROPTYPE_BINARY,
&varExtension);
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_JumpIfError(hr, error, "Policy:GetCertificateExtension");
hr = pServer->GetCertificateExtensionFlags(&ExtFlags);
_JumpIfError(hr, error, "Policy:GetCertificateExtensionFlags");
if (EXTENSION_DISABLE_FLAG & ExtFlags)
{
ExtFlags &= ~EXTENSION_DISABLE_FLAG;
fSetNeeded = TRUE;
}
}
else
{
BYTE const *pbSMIME;
DWORD cbSMIME;
pbSMIME = m_pPolicy->GetSMIME(&cbSMIME);
if (0 == (EDITF_ENABLEDEFAULTSMIME & m_pPolicy->GetEditFlags()) ||
NULL == pbSMIME)
{
hr = CERTSRV_E_SMIME_REQUIRED;
_JumpError(hr, error, "Policy:GetCertificateExtension");
}
varExtension.bstrVal = NULL;
if (!myConvertWszToBstr(
&varExtension.bstrVal,
(WCHAR const *) pbSMIME,
cbSMIME))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:myConvertWszToBstr");
}
varExtension.vt = VT_BSTR;
fSetNeeded = TRUE;
}
}
if (fSetNeeded)
{
hr = pServer->SetCertificateExtension(
TEXT(szOID_RSA_SMIMECapabilities),
PROPTYPE_BINARY,
ExtFlags,
&varExtension);
_JumpIfError(hr, error, "Policy:SetCertificateExtension");
}
hr = S_OK;
error:
if (NULL != strCSPProvider)
{
SysFreeString(strCSPProvider);
}
VariantClear(&varExtension);
return(hr);
}
// Fail the request if all of the following are true:
// 1: the request is for a V2 template
// 2: no signatures are required by the template
// 3: the RequesterName is not the same as the CallerName (enroll-on-behalf-of)
HRESULT
CTemplatePolicy::_EnforceEnrollOnBehalfOfAllowed(
IN ICertServerPolicy *pServer,
IN CRequestInstance *pRequest)
{
HRESULT hr;
BSTR strRequester = NULL;
BSTR strCaller = NULL;
DWORD cSignatureRequired;
if (CERTTYPE_SCHEMA_VERSION_2 > m_dwSchemaVersion)
{
hr = S_OK;
goto error; // skip V1 template
}
hr = CAGetCertTypePropertyEx(
m_hCertType,
CERTTYPE_PROP_RA_SIGNATURE,
&cSignatureRequired);
_PrintIfErrorStr2(
hr,
"_EnforceEnrollOnBehalfOfAllowed:CAGetCertTypePropertyEx",
CERTTYPE_PROP_RA_SIGNATURE,
HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
if (S_OK == hr && 0 != cSignatureRequired)
{
hr = S_OK;
goto error; // skip when no signatures required
}
hr = polGetRequestStringProperty(
pServer,
wszPROPREQUESTERNAME,
&strRequester);
_JumpIfErrorStr(
hr,
error,
"Policy:polGetRequestStringProperty",
wszPROPREQUESTERNAME);
hr = polGetRequestStringProperty(
pServer,
wszPROPCALLERNAME,
&strCaller);
_JumpIfErrorStr(
hr,
error,
"Policy:polGetRequestStringProperty",
wszPROPCALLERNAME);
if (0 != lstrcmpi(strRequester, strCaller))
{
hr = CERTSRV_E_BAD_RENEWAL_SUBJECT;
_JumpError(hr, error, "UPN doesn't match renewal UPN");
}
hr = S_OK; // caller matches requester
error:
if (NULL != strRequester)
{
SysFreeString(strRequester);
}
if (NULL != strCaller)
{
SysFreeString(strCaller);
}
return(hr);
}
HRESULT
CTemplatePolicy::_EnforceMinimumTemplateVersion(
IN CRequestInstance *pRequest)
{
HRESULT hr;
DWORD dwRequestTemplateMinimumMajorVersion;
DWORD dwRequestTemplateMinimumMinorVersion;
pRequest->GetTemplateVersion(
&dwRequestTemplateMinimumMajorVersion,
&dwRequestTemplateMinimumMinorVersion);
if (m_dwTemplateMajorVersion < dwRequestTemplateMinimumMajorVersion ||
(m_dwTemplateMajorVersion == dwRequestTemplateMinimumMajorVersion &&
m_dwTemplateMinorVersion < dwRequestTemplateMinimumMinorVersion))
{
DBGPRINT((
DBG_SS_ERROR,
"Requested template version %u.%u, Loaded version %u.%u\n",
dwRequestTemplateMinimumMajorVersion,
dwRequestTemplateMinimumMinorVersion,
m_dwTemplateMajorVersion,
m_dwTemplateMinorVersion));
hr = CERTSRV_E_BAD_TEMPLATE_VERSION;
_JumpError(hr, error, "Policy:_EnforceMinimumTemplateVersion");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
polSplitPolicies(
IN BSTR strPolicies,
OUT DWORD *pcPolicies,
OUT POLICIES **pprgPolicies)
{
HRESULT hr;
WCHAR const *pwszT;
WCHAR *pwszOut;
WCHAR *pwsz;
DWORD cPolicies;
POLICIES *prgPolicies;
DWORD cObjId;
WCHAR **prgObjId;
BOOL fNew;
*pprgPolicies = NULL;
pwszT = strPolicies;
cPolicies = 1; // plus one per newline separator
cObjId = 0;
while (L'\0' != *pwszT)
{
int ichar = wcscspn(pwszT, L",\n");
if (ichar == 0) // neither of these, look for end-of-string
ichar = wcslen(pwszT);
pwszT += ichar;
switch (*pwszT)
{
case L'\n':
cPolicies++; // plus one per newline separator
pwszT++; // step over the newline
break;
case L',':
cObjId++; // plus one per comma separator
pwszT++; // step over the comma
break;
case L'\0':
default:
CSASSERT(L'\0' == *pwszT);
break;
}
}
cObjId += cPolicies; // plus one per signature
prgPolicies = (POLICIES *) LocalAlloc(
LMEM_FIXED,
cPolicies * sizeof(prgPolicies[0]) +
cObjId * sizeof(WCHAR *) +
(wcslen(strPolicies) + 1) * sizeof(WCHAR));
if (NULL == prgPolicies)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocString");
}
*pprgPolicies = prgPolicies;
*pcPolicies = cPolicies;
prgObjId = (WCHAR **) &prgPolicies[cPolicies];
pwszOut = (WCHAR *) &prgObjId[cObjId];
wcscpy(pwszOut, strPolicies);
fNew = TRUE;
while (L'\0' != *pwszOut)
{
if (fNew)
{
prgPolicies->cObjId = 0;
prgPolicies->prgObjId = prgObjId;
}
prgPolicies->cObjId++;
*prgObjId = pwszOut;
prgObjId++; // next array entry
fNew = FALSE;
int ichar = wcscspn(pwszOut , L",\n");
if (ichar == 0) // neither of these, look for end-of-string
ichar = wcslen(pwszOut);
pwszOut += ichar;
switch (*pwszOut)
{
case L'\n':
prgPolicies++;
fNew = TRUE;
// FALLTHROUGH
case L',':
*pwszOut++ = L'\0';
break;
case L'\0':
default:
CSASSERT(L'\0' == *pwszOut);
break;
}
}
hr = S_OK;
error:
return(hr);
}
HRESULT
CTemplatePolicy::_LoadPolicies(
IN ICertServerPolicy *pServer,
IN WCHAR const *pwszPropNameCertType,
IN WCHAR const *pwszPropNameRequest,
OUT DWORD *pcTemplatePolicies,
OUT WCHAR ***papwszTemplatePolicies, // from the cert template
OUT DWORD *pcSignaturePolicies,
OUT POLICIES **pprgSignaturePolicies) // from the signing cert(s)
{
HRESULT hr;
BSTR strSignaturePolicies = NULL;
DWORD cTemplatePolicies;
WCHAR **apwsz;
*pcTemplatePolicies = 0;
*papwszTemplatePolicies = NULL;
*pcSignaturePolicies = 0;
*pprgSignaturePolicies = NULL;
hr = polCAGetCertTypeProperty(
m_hCertType,
pwszPropNameCertType,
papwszTemplatePolicies);
_PrintIfErrorStr(
hr,
"CTemplatePolicy:_LoadPolicies:polCAGetCertTypeProperty",
pwszPropNameCertType);
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:_LoadPolicies:polCAGetCertTypeProperty",
pwszPropNameCertType);
}
cTemplatePolicies = 0;
apwsz = *papwszTemplatePolicies;
if (NULL != apwsz)
{
while (NULL != *apwsz++)
{
cTemplatePolicies++;
}
}
*pcTemplatePolicies = cTemplatePolicies;
hr = polGetRequestStringProperty(
pServer,
pwszPropNameRequest,
&strSignaturePolicies);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = CERTSRV_E_SIGNATURE_POLICY_REQUIRED;
}
_JumpIfErrorStr(
hr,
error,
"Policy:polGetRequestStringProperty",
pwszPropNameRequest);
hr = polSplitPolicies(
strSignaturePolicies,
pcSignaturePolicies,
pprgSignaturePolicies);
_JumpIfError(hr, error, "Policy:polSplitPolicies");
error:
if (NULL != strSignaturePolicies)
{
SysFreeString(strSignaturePolicies);
}
return(hr);
}
VOID
CTemplatePolicy::_FreePolicies(
IN WCHAR **apwszTemplatePolicies,
IN POLICIES *prgPolicies)
{
if (NULL != apwszTemplatePolicies)
{
CAFreeCertTypeProperty(m_hCertType, apwszTemplatePolicies);
}
if (NULL != prgPolicies)
{
LocalFree(prgPolicies);
}
}
HRESULT
CTemplatePolicy::_EnforceReenrollment(
IN ICertServerPolicy *pServer,
IN CRequestInstance *pRequest)
{
HRESULT hr;
VARIANT var;
CERT_CONTEXT const *pOldCert = NULL;
CERT_EXTENSION const *pExt;
CERT_TEMPLATE_EXT *pTemplate = NULL;
WCHAR *pwszObjId = NULL;
CERT_ALT_NAME_INFO *pAltName = NULL;
CERT_NAME_VALUE *pName = NULL;
DWORD cb;
DWORD i;
VariantInit(&var);
if (NULL == m_pwszTemplateObjId)
{
hr = CERTSRV_E_UNSUPPORTED_CERT_TYPE;
_JumpError(hr, error, "Policy:No template ObjId");
}
hr = polGetProperty(
pServer,
TRUE, // fRequest
PROPTYPE_BINARY,
wszPROPREQUESTRAWOLDCERTIFICATE,
&var);
_JumpIfError(hr, error, "Policy:polGetProperty");
if (VT_BSTR != var.vt || NULL == var.bstrVal)
{
hr = CERTSRV_E_PROPERTY_EMPTY;
_JumpError(hr, error, "Policy:polGetProperty");
}
var.bstrVal;
pOldCert = CertCreateCertificateContext(
X509_ASN_ENCODING,
(BYTE *) var.bstrVal,
SysStringByteLen(var.bstrVal));
if (NULL == pOldCert)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "CertCreateCertificateContext");
}
pExt = CertFindExtension(
szOID_CERTIFICATE_TEMPLATE,
pOldCert->pCertInfo->cExtension,
pOldCert->pCertInfo->rgExtension);
if (NULL == pExt)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
_JumpError(hr, error, "CertFindExtension(Template)");
}
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_CERTIFICATE_TEMPLATE,
pExt->Value.pbData,
pExt->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pTemplate,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myDecodeObject");
}
if (!myConvertSzToWsz(&pwszObjId, pTemplate->pszObjId, MAXDWORD))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:myConvertSzToWsz");
}
if (0 != lstrcmp(pwszObjId, m_pwszTemplateObjId))
{
hr = CERTSRV_E_UNSUPPORTED_CERT_TYPE;
_JumpError(hr, error, "Policy:different cert type");
}
if (NULL == pRequest->m_pwszUPN)
{
hr = E_POINTER; // We should never get this
_JumpError(hr, error, "Policy:NULL UPN");
}
pExt = CertFindExtension(
szOID_SUBJECT_ALT_NAME2,
pOldCert->pCertInfo->cExtension,
pOldCert->pCertInfo->rgExtension);
if (NULL == pExt)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
_JumpError(hr, error, "CertFindExtension(SubjectAltName)");
}
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_ALTERNATE_NAME,
pExt->Value.pbData,
pExt->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pAltName,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myDecodeObject");
}
for (i = 0; i < pAltName->cAltEntry; i++)
{
CERT_ALT_NAME_ENTRY *pAltEntry = &pAltName->rgAltEntry[i];
if (CERT_ALT_NAME_OTHER_NAME != pAltEntry->dwAltNameChoice)
{
continue;
}
if (0 != strcmp(
pAltEntry->pOtherName->pszObjId,
szOID_NT_PRINCIPAL_NAME))
{
continue;
}
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_UNICODE_ANY_STRING,
pAltEntry->pOtherName->Value.pbData,
pAltEntry->pOtherName->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pName,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myDecodeObject");
}
if (CERT_RDN_UTF8_STRING != pName->dwValueType ||
0 != lstrcmpi(
pRequest->m_pwszUPN,
(WCHAR const *) pName->Value.pbData))
{
hr = CERTSRV_E_BAD_REQUESTSUBJECT;
_JumpError(hr, error, "UPN doesn't match renewal UPN");
}
}
if (NULL == pName)
{
hr = CERTSRV_E_BAD_REQUESTSUBJECT;
_JumpError(hr, error, "missing renewal UPN");
}
hr = S_OK;
error:
if (NULL != pName)
{
LocalFree(pName);
}
if (NULL != pAltName)
{
LocalFree(pAltName);
}
if (NULL != pwszObjId)
{
LocalFree(pwszObjId);
}
if (NULL != pTemplate)
{
LocalFree(pTemplate);
}
if (NULL != pOldCert)
{
CertFreeCertificateContext(pOldCert);
}
VariantClear(&var);
return(hr);
}
//+--------------------------------------------------------------------------
// CCertPolicyEnterprise::_EnforceSignaturePolicy
//
// Fetch required lists of Issuance and Application ObjIds from the template.
// Fetch signing certificates' lists of Issuance and Application ObjIds from
// the cert server.
//
// Reject signatures that don't include all of the required Application ObjIds.
// Reject signatures that don't include at least one of the required Issuance
// ObjIds.
//
// The count of accepted signatures must be equal to or greater than the
// template-specified required signature count.
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_EnforceSignaturePolicy(
IN ICertServerPolicy *pServer)
{
HRESULT hr;
DWORD cSignatureRequired;
DWORD cSignatureAccepted;
DWORD cSignatureRejected;
DWORD *prgdwRefCount = NULL;
WCHAR **apwsz;
DWORD i;
DWORD cTemplateIssuance;
WCHAR **apwszTemplateIssuance = NULL;
DWORD cSignatureIssuance;
POLICIES *prgSignatureIssuance = NULL;
DWORD cTemplateApplication;
WCHAR **apwszTemplateApplication = NULL;
DWORD cSignatureApplication;
POLICIES *prgSignatureApplication = NULL;
hr = CAGetCertTypePropertyEx(
m_hCertType,
CERTTYPE_PROP_RA_SIGNATURE,
&cSignatureRequired);
_PrintIfErrorStr2(
hr,
"CTemplatePolicy:_EnforceSignaturePolicy:CAGetCertTypePropertyEx",
CERTTYPE_PROP_RA_SIGNATURE,
HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
if (S_OK != hr)
{
if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr)
{
goto error;
}
cSignatureRequired = 0;
}
if (0 == cSignatureRequired)
{
hr = S_OK;
goto error;
}
hr = _LoadPolicies(
pServer,
CERTTYPE_PROP_RA_POLICY,
wszPROPSIGNERPOLICIES,
&cTemplateIssuance, // from the cert template
&apwszTemplateIssuance,
&cSignatureIssuance, // from the signing cert(s)
&prgSignatureIssuance);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:_LoadPolicies",
CERTTYPE_PROP_RA_POLICY);
hr = _LoadPolicies(
pServer,
CERTTYPE_PROP_RA_APPLICATION_POLICY,
wszPROPSIGNERAPPLICATIONPOLICIES,
&cTemplateApplication, // from the cert template
&apwszTemplateApplication,
&cSignatureApplication, // from the signing cert(s)
&prgSignatureApplication);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:_LoadPolicies",
CERTTYPE_PROP_RA_APPLICATION_POLICY);
if (0 == cTemplateIssuance && 0 == cTemplateApplication)
{
hr = CERTSRV_E_TEMPLATE_POLICY_REQUIRED;
_JumpIfError(hr, error, "no template policies");
}
if (cSignatureIssuance != cSignatureApplication)
{
hr = NTE_BAD_SIGNATURE; // must be an internal server problem
_JumpError(hr, error, "Policy:bad request policies counts");
}
if (0 != cTemplateIssuance)
{
prgdwRefCount = (DWORD *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
cTemplateIssuance * sizeof(DWORD));
if (NULL == prgdwRefCount)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:LocalAlloc");
}
}
// Loop through each signature's Application and Issuance Policy OIDs
cSignatureAccepted = 0;
cSignatureRejected = 0;
for (i = 0; i < cSignatureIssuance; i++)
{
BOOL fReject = FALSE;
WCHAR **prgObjId;
DWORD cObjId;
DWORD j;
DWORD idx;
// This signature must include ALL required Application Policy OIDs
// If no Application Policy OIDs are required, all signatures are OK.
prgObjId = prgSignatureApplication[i].prgObjId;
cObjId = prgSignatureApplication[i].cObjId;
for (j = 0; j < cTemplateApplication; j++)
{
idx = polFindObjIdInList(
apwszTemplateApplication[j],
cObjId,
prgObjId);
if (MAXDWORD == idx)
{
fReject = TRUE;
_PrintErrorStr(
hr,
"Policy:missing Application Policy",
apwszTemplateApplication[i]);
}
}
if (!fReject)
{
DWORD cFound = 0;
// For each Issuance Policy OID in this signature that also exists
// in the required Issuance Policy OIDs, increment the ref count to
// show the OID was referenced by an accepted signature.
// Reject the signature if it doesn't reference any required OID.
prgObjId = prgSignatureIssuance[i].prgObjId;
cObjId = prgSignatureIssuance[i].cObjId;
for (j = 0; j < cObjId; j++)
{
idx = polFindObjIdInList(
prgObjId[j],
cTemplateIssuance,
apwszTemplateIssuance);
if (MAXDWORD != idx)
{
prgdwRefCount[idx]++;
cFound++;
}
}
// If no Issuance Policy OIDs are required, all signatures are OK.
if (0 != cTemplateIssuance && 0 == cFound)
{
fReject = TRUE;
}
}
if (fReject)
{
cSignatureRejected++;
}
else
{
cSignatureAccepted++;
}
DBGPRINT((
DBG_SS_CERTPOL,
"Sig[%u]: %ws\n",
i,
fReject? L"Rejected" : L"Accepted"));
}
hr = S_OK;
if (cSignatureAccepted < cSignatureRequired)
{
hr = CERTSRV_E_SIGNATURE_COUNT;
if (0 != cSignatureRejected)
{
hr = CERTSRV_E_SIGNATURE_REJECTED;
}
_PrintError(hr, "Policy:not enough signatures");
}
DBGPRINT((
S_OK != hr? DBG_SS_CERTPOLI : DBG_SS_CERTPOL,
"Signatures: %u needed, %u accepted\n",
cSignatureRequired,
cSignatureAccepted));
for (i = 0; i < cTemplateIssuance; i++)
{
if (0 == prgdwRefCount[i])
{
hr = CERTSRV_E_ISSUANCE_POLICY_REQUIRED;
_PrintErrorStr(
hr,
"Policy:missing Issuance Policy",
apwszTemplateIssuance[i]);
}
}
_JumpIfError(hr, error, "Policy:missing Policy/Signature");
error:
_FreePolicies(apwszTemplateIssuance, prgSignatureIssuance);
_FreePolicies(apwszTemplateApplication, prgSignatureApplication);
if (NULL != prgdwRefCount)
{
LocalFree(prgdwRefCount);
}
return(hr);
}
HRESULT
CTemplatePolicy::GetFlags(
IN DWORD dwOption,
OUT DWORD *pdwFlags)
{
HRESULT hr;
switch (dwOption)
{
case CERTTYPE_ENROLLMENT_FLAG:
*pdwFlags = m_dwEnrollmentFlags;
break;
case CERTTYPE_SUBJECT_NAME_FLAG:
*pdwFlags = m_dwSubjectNameFlags;
break;
case CERTTYPE_PRIVATE_KEY_FLAG:
*pdwFlags = m_dwPrivateKeyFlags;
break;
case CERTTYPE_GENERAL_FLAG:
*pdwFlags = m_dwGeneralFlags;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "Policy:bad dwOption");
}
hr = S_OK;
error:
return(hr);
}
// IsRequestedTemplate - determine if the request specifies this template
BOOL
CTemplatePolicy::IsRequestedTemplate(
OPTIONAL IN WCHAR const *pwszTemplateName,
OPTIONAL IN WCHAR const *pwszTemplateObjId)
{
HRESULT hr = CERTSRV_E_UNSUPPORTED_CERT_TYPE;
if (NULL != pwszTemplateName)
{
if ((NULL != m_pwszTemplateName &&
0 == lstrcmpi(m_pwszTemplateName, pwszTemplateName)) ||
(NULL != m_pwszTemplateObjId &&
0 == lstrcmp(m_pwszTemplateObjId, pwszTemplateName)))
{
hr = S_OK;
}
}
if (S_OK != hr && NULL != pwszTemplateObjId)
{
if ((NULL != m_pwszTemplateName &&
0 == lstrcmpi(m_pwszTemplateName, pwszTemplateObjId)) ||
(NULL != m_pwszTemplateObjId &&
0 == lstrcmp(m_pwszTemplateObjId, pwszTemplateObjId)))
{
hr = S_OK;
}
}
_JumpIfErrorStr2(
hr,
error,
"Policy:wrong CertType",
m_pwszTemplateName,
hr);
error:
return(S_OK == hr);
}