Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3339 lines
83 KiB

//+--------------------------------------------------------------------------
//
// 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 <ntdsapi.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"
#define __dwFILE__ __dwFILE_POLICY_DEFAULT_TEMPLATE_CPP__
// 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)
// All of the "known" Key Usage bits currently defined:
#define dwKNOWN_KEY_USAGE_BITS \
(CERT_DIGITAL_SIGNATURE_KEY_USAGE | \
CERT_NON_REPUDIATION_KEY_USAGE | \
CERT_KEY_ENCIPHERMENT_KEY_USAGE | \
CERT_DATA_ENCIPHERMENT_KEY_USAGE | \
CERT_KEY_AGREEMENT_KEY_USAGE | \
CERT_KEY_CERT_SIGN_KEY_USAGE | \
CERT_OFFLINE_CRL_SIGN_KEY_USAGE | \
CERT_CRL_SIGN_KEY_USAGE | \
CERT_ENCIPHER_ONLY_KEY_USAGE | \
(CERT_DECIPHER_ONLY_KEY_USAGE << 8))
// Mask to turn off all the "known" Key Usage bits that aren't expclitly valid:
#define dwKUMASK(dwValid) ((DWORD) ((dwValid) | ~dwKNOWN_KEY_USAGE_BITS))
typedef struct _KEYUSAGEMASK {
WCHAR const * const *apwszAlg;
DWORD dwMask1; // 1: CA mask (2: if any of these bits are set)
DWORD dwMask2; // 1: EE mask (2: clear these bits)
} KEYUSAGEMASK;
WCHAR const * const s_apwszRSA[] = // RSA public key
{
TEXT(szOID_RSA_RSA),
TEXT(szOID_OIWSEC_rsaXchg),
NULL
};
WCHAR const * const s_apwszDSA[] = // DSA public key
{
TEXT(szOID_X957_DSA),
TEXT(szOID_OIWSEC_dsa),
TEXT(szOID_INFOSEC_mosaicKMandUpdSig),
NULL
};
WCHAR const * const s_apwszDH[] = // DH public key
{
TEXT(szOID_ANSI_X942_DH),
TEXT(szOID_RSA_DH),
NULL
};
KEYUSAGEMASK g_aKeyUsageMask1[] =
{
{
s_apwszRSA,
// Valid CA cert Key Usage bits -> mask = 0xffff7ff6
dwKUMASK(
CERT_DIGITAL_SIGNATURE_KEY_USAGE |
CERT_NON_REPUDIATION_KEY_USAGE |
CERT_KEY_ENCIPHERMENT_KEY_USAGE |
CERT_DATA_ENCIPHERMENT_KEY_USAGE |
CERT_KEY_CERT_SIGN_KEY_USAGE |
CERT_CRL_SIGN_KEY_USAGE), // same as CERT_OFFLINE_CRL_SIGN_KEY_USAGE
// Valid EE cert Key Usage bits -> mask = 0xffff7ff0
dwKUMASK(
CERT_DIGITAL_SIGNATURE_KEY_USAGE |
CERT_NON_REPUDIATION_KEY_USAGE |
CERT_KEY_ENCIPHERMENT_KEY_USAGE |
CERT_DATA_ENCIPHERMENT_KEY_USAGE),
},
{
s_apwszDSA,
// Valid CA cert Key Usage bits -> mask = 0xffff7fc6
dwKUMASK(
CERT_DIGITAL_SIGNATURE_KEY_USAGE |
CERT_NON_REPUDIATION_KEY_USAGE |
CERT_KEY_CERT_SIGN_KEY_USAGE |
CERT_CRL_SIGN_KEY_USAGE), // same as CERT_OFFLINE_CRL_SIGN_KEY_USAGE
// Valid EE cert Key Usage bits -> mask = 0xffff7fc0
dwKUMASK(
CERT_DIGITAL_SIGNATURE_KEY_USAGE |
CERT_NON_REPUDIATION_KEY_USAGE),
},
{
s_apwszDH,
// Valid CA cert Key Usage bits -> mask = 0xffff7f09
dwKUMASK(
CERT_KEY_AGREEMENT_KEY_USAGE |
CERT_ENCIPHER_ONLY_KEY_USAGE),
// Valid EE cert Key Usage bits -> mask = 0xffff7f09
dwKUMASK(
CERT_KEY_AGREEMENT_KEY_USAGE |
CERT_ENCIPHER_ONLY_KEY_USAGE),
},
};
KEYUSAGEMASK g_aKeyUsageMask2[] =
{
{
s_apwszRSA,
// CERT_KEY_ENCIPHERMENT_KEY_USAGE(SHOULD not be set w/Cert,CRL sign)
// CERT_DATA_ENCIPHERMENT_KEY_USAGE (SHOULD not be set w/Cert,CRL sign)
CERT_KEY_CERT_SIGN_KEY_USAGE |
CERT_CRL_SIGN_KEY_USAGE, // same as CERT_OFFLINE_CRL_SIGN_KEY_USAGE
CERT_KEY_ENCIPHERMENT_KEY_USAGE |
CERT_DATA_ENCIPHERMENT_KEY_USAGE,
},
};
CRITICAL_SECTION g_DSCacheCriticalSection;
BOOL g_fDSCacheCriticalSection = FALSE;
HRESULT
TPInitialize(
IN ICertServerPolicy *) // pServer
{
return(S_OK);
}
VOID
TPCleanup()
{
}
HRESULT
tpCAGetCertTypeProperty(
IN HCERTTYPE hCertType,
IN WCHAR const *pwszPropName,
WCHAR ***papwszValues)
{
HRESULT hr;
*papwszValues = NULL;
hr = CAGetCertTypeProperty(hCertType, pwszPropName, papwszValues);
_PrintIfErrorStr2(
hr,
"Policy:CAGetCertTypeProperty",
pwszPropName,
HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
if (S_OK != hr)
{
*papwszValues = NULL;
if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr)
{
goto error;
}
hr = S_OK;
}
error:
return(hr);
}
HRESULT
tpCAGetCertTypeStringProperty(
IN HCERTTYPE hCertType,
IN WCHAR const *pwszPropName,
OUT WCHAR **ppwszValue)
{
HRESULT hr;
WCHAR **apwszValues = NULL;
*ppwszValue = NULL;
hr = CAGetCertTypeProperty(hCertType, pwszPropName, &apwszValues);
if (S_OK != hr)
{
apwszValues = NULL;
_JumpErrorStr(hr, error, "CAGetCertTypeProperty", pwszPropName);
}
if (NULL == apwszValues || NULL == apwszValues[0])
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
_JumpErrorStr(hr, error, "CAGetCertTypeProperty", pwszPropName);
}
hr = myDupString(apwszValues[0], ppwszValue);
_JumpIfError(hr, error, "myDupString");
error:
if (NULL != apwszValues)
{
CAFreeCertTypeProperty(hCertType, apwszValues);
}
return(hr);
}
HRESULT
tpCAGetCertTypeObjectIdList(
IN HCERTTYPE hCertType,
IN WCHAR const *pwszPropName,
OUT OBJECTIDLIST *prgPolicies)
{
HRESULT hr;
WCHAR **apwsz;
prgPolicies->cObjId = 0;
prgPolicies->rgpwszObjId = NULL;
hr = tpCAGetCertTypeProperty(
hCertType,
pwszPropName,
&prgPolicies->rgpwszObjId);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:tpCAGetCertTypeProperty",
pwszPropName);
apwsz = prgPolicies->rgpwszObjId;
if (NULL != apwsz)
{
while (NULL != *apwsz++)
{
prgPolicies->cObjId++;
}
}
hr = S_OK;
error:
return(hr);
}
CTemplatePolicy::CTemplatePolicy()
{
m_hCertType = NULL;
ZeroMemory(&m_tp, sizeof(m_tp));
m_pwszTemplateName = NULL;
m_pwszTemplateObjId = NULL;
m_pExtensions = NULL;
ZeroMemory(&m_CriticalExtensions, sizeof(m_CriticalExtensions));
ZeroMemory(&m_PoliciesIssuance, sizeof(m_PoliciesIssuance));
ZeroMemory(&m_PoliciesApplication, sizeof(m_PoliciesApplication));
m_pPolicy = NULL;
}
CTemplatePolicy::~CTemplatePolicy()
{
_Cleanup();
}
VOID
CTemplatePolicy::_Cleanup()
{
ZeroMemory(&m_tp, sizeof(m_tp));
if (NULL != m_hCertType)
{
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;
}
if (NULL != m_pExtensions)
{
LocalFree(m_pExtensions);
m_pExtensions = NULL;
}
if (NULL != m_CriticalExtensions.rgpwszObjId)
{
LocalFree(m_CriticalExtensions.rgpwszObjId);
}
ZeroMemory(&m_CriticalExtensions, sizeof(m_CriticalExtensions));
if (NULL != m_PoliciesIssuance.rgpwszObjId)
{
LocalFree(m_PoliciesIssuance.rgpwszObjId);
}
ZeroMemory(&m_PoliciesIssuance, sizeof(m_PoliciesIssuance));
if (NULL != m_PoliciesApplication.rgpwszObjId)
{
LocalFree(m_PoliciesApplication.rgpwszObjId);
}
ZeroMemory(&m_PoliciesApplication, sizeof(m_PoliciesApplication));
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;
WCHAR *pwszNameAndVersion = NULL;
#define wszFORMATVERSION L"(v%u.%u): V%u"
WCHAR wszVersion[ARRAYSIZE(wszFORMATVERSION) + 3 * cwcDWORDSPRINTF];
WCHAR const *pwszTemplate;
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;
}
wsprintf(
wszVersion,
wszFORMATVERSION,
m_tp.dwTemplateMajorVersion,
m_tp.dwTemplateMinorVersion,
m_tp.dwSchemaVersion);
CSASSERT(wcslen(wszVersion) < ARRAYSIZE(wszVersion));
pwszTemplate = m_pwszTemplateName;
if (NULL == pwszTemplate)
{
pwszTemplate = L"???";
}
pwszNameAndVersion = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwszTemplate) + wcslen(wszVersion) + 1) *
sizeof(WCHAR));
if (NULL == pwszNameAndVersion)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:LocalAlloc");
}
wcscpy(pwszNameAndVersion, pwszTemplate);
wcscat(pwszNameAndVersion, wszVersion);
apwsz[0] = pwszNameAndVersion;
apwsz[1] = pwszError;
hr = LogPolicyEvent(
g_hInstance,
S_OK,
MsgId,
pServer,
pwszLogProp,
apwsz);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:LogPolicyEvent");
error:
if (NULL != pwszNameAndVersion)
{
LocalFree(pwszNameAndVersion);
}
if (NULL != pwszError)
{
LocalFree(const_cast<WCHAR *>(pwszError));
}
return(hr);
}
HRESULT
CTemplatePolicy::_CloneExtensions(
IN CERT_EXTENSIONS const *pExtensionsIn,
OUT CERT_EXTENSIONS **ppExtensionsOut)
{
HRESULT hr;
DWORD cb;
CERT_EXTENSION *pExt;
CERT_EXTENSION *pExtEnd;
CERT_EXTENSION *pExtOut;
BYTE *pbOut;
*ppExtensionsOut = NULL;
cb = sizeof(CERT_EXTENSIONS) +
pExtensionsIn->cExtension * sizeof(pExtensionsIn->rgExtension[0]);
pExtEnd = &pExtensionsIn->rgExtension[pExtensionsIn->cExtension];
for (pExt = pExtensionsIn->rgExtension; pExt < pExtEnd; pExt++)
{
cb += DWORDROUND(strlen(pExt->pszObjId) + 1);
cb += DWORDROUND(pExt->Value.cbData);
}
*ppExtensionsOut = (CERT_EXTENSIONS *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == *ppExtensionsOut)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:LocalAlloc");
}
(*ppExtensionsOut)->cExtension = pExtensionsIn->cExtension;
pExtOut = (CERT_EXTENSION *) &(*ppExtensionsOut)[1];
(*ppExtensionsOut)->rgExtension = pExtOut;
pbOut = (BYTE *) &pExtOut[pExtensionsIn->cExtension];
for (pExt = pExtensionsIn->rgExtension; pExt < pExtEnd; pExt++, pExtOut++)
{
pExtOut->pszObjId = (char *) pbOut;
strcpy(pExtOut->pszObjId, pExt->pszObjId);
pbOut += DWORDROUND(strlen(pExt->pszObjId) + 1);
pExtOut->fCritical = pExt->fCritical;
pExtOut->Value.cbData = pExt->Value.cbData;
pExtOut->Value.pbData = pbOut;
CopyMemory(
pExtOut->Value.pbData,
pExt->Value.pbData,
pExt->Value.cbData);
pbOut += DWORDROUND(pExt->Value.cbData);
}
CSASSERT(Add2Ptr(*ppExtensionsOut, cb) == pbOut);
hr = S_OK;
error:
return(hr);
}
HRESULT
CTemplatePolicy::_CloneObjectIdList(
IN OBJECTIDLIST const *pObjectIdListIn,
OUT OBJECTIDLIST *pObjectIdListOut)
{
HRESULT hr;
ZeroMemory(pObjectIdListOut, sizeof(*pObjectIdListOut));
pObjectIdListOut->cObjId = pObjectIdListIn->cObjId;
if (0 != pObjectIdListIn->cObjId)
{
DWORD cb = (pObjectIdListIn->cObjId + 1) * sizeof(pObjectIdListIn->rgpwszObjId);
WCHAR const * const *ppwsz;
WCHAR const * const *ppwszEnd;
WCHAR **ppwszOut;
BYTE *pbOut;
ppwszEnd = &pObjectIdListIn->rgpwszObjId[pObjectIdListIn->cObjId];
for (ppwsz = pObjectIdListIn->rgpwszObjId; ppwsz < ppwszEnd; ppwsz++)
{
cb += DWORDROUND((wcslen(*ppwsz) + 1) * sizeof(WCHAR));
}
pObjectIdListOut->rgpwszObjId = (WCHAR **) LocalAlloc(LMEM_FIXED, cb);
if (NULL == pObjectIdListOut->rgpwszObjId)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:LocalAlloc");
}
ppwszOut = pObjectIdListOut->rgpwszObjId;
pbOut = (BYTE *) &ppwszOut[pObjectIdListOut->cObjId + 1];
for (
ppwsz = pObjectIdListIn->rgpwszObjId;
ppwsz < ppwszEnd;
ppwsz++, ppwszOut++)
{
*ppwszOut = (WCHAR *) pbOut;
wcscpy(*ppwszOut, *ppwsz);
pbOut += DWORDROUND((wcslen(*ppwszOut) + 1) * sizeof(WCHAR));
}
}
hr = S_OK;
error:
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;
OBJECTIDLIST CriticalExtensions;
OBJECTIDLIST PoliciesIssuance;
OBJECTIDLIST PoliciesApplication;
ZeroMemory(&CriticalExtensions, sizeof(CriticalExtensions));
ZeroMemory(&PoliciesIssuance, sizeof(PoliciesIssuance));
ZeroMemory(&PoliciesApplication, sizeof(PoliciesApplication));
_Cleanup();
CSASSERT(0 == m_tp.dwTemplateMajorVersion);
CSASSERT(0 == m_tp.dwTemplateMinorVersion);
CSASSERT(0 == m_tp.dwSchemaVersion);
CSASSERT(0 == m_tp.dwMinKeyLength);
hr = tpCAGetCertTypeStringProperty(
hCertType,
CERTTYPE_PROP_DN,
&m_pwszTemplateName);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:tpCAGetCertTypeStringProperty",
CERTTYPE_PROP_DN);
hr = CAGetCertTypePropertyEx(
hCertType,
CERTTYPE_PROP_REVISION,
&m_tp.dwTemplateMajorVersion);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:CAGetCertTypePropertyEx",
CERTTYPE_PROP_REVISION);
hr = CAGetCertTypePropertyEx(
hCertType,
CERTTYPE_PROP_SCHEMA_VERSION,
&m_tp.dwSchemaVersion);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:CAGetCertTypePropertyEx",
CERTTYPE_PROP_SCHEMA_VERSION);
if (CERTTYPE_SCHEMA_VERSION_2 <= m_tp.dwSchemaVersion)
{
hr = tpCAGetCertTypeStringProperty(
hCertType,
CERTTYPE_PROP_OID,
&m_pwszTemplateObjId);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:tpCAGetCertTypeStringProperty",
CERTTYPE_PROP_OID);
hr = CAGetCertTypePropertyEx(
hCertType,
CERTTYPE_PROP_MINOR_REVISION,
&m_tp.dwTemplateMinorVersion);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:CAGetCertTypePropertyEx",
CERTTYPE_PROP_MINOR_REVISION);
hr = CAGetCertTypePropertyEx(
hCertType,
CERTTYPE_PROP_MIN_KEY_SIZE,
&m_tp.dwMinKeyLength);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:Initialize:CAGetCertTypePropertyEx",
CERTTYPE_PROP_MIN_KEY_SIZE);
}
if (!FIsAdvancedServer() && CERTTYPE_SCHEMA_VERSION_2 <= m_tp.dwSchemaVersion)
{
// V2 templates require Advanced Server
hr = HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
_JumpError(hr, error, "CTemplatePolicy:Initialize:m_tp.dwSchemaVersion");
}
m_pPolicy = pPolicy;
hr = CAGetCertTypeFlagsEx(
hCertType,
CERTTYPE_ENROLLMENT_FLAG,
&m_tp.dwEnrollmentFlags);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeFlagsEx");
hr = CAGetCertTypeFlagsEx(
hCertType,
CERTTYPE_SUBJECT_NAME_FLAG,
&m_tp.dwSubjectNameFlags);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeFlagsEx");
hr = CAGetCertTypeFlagsEx(
hCertType,
CERTTYPE_PRIVATE_KEY_FLAG,
&m_tp.dwPrivateKeyFlags);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeFlagsEx");
hr = CAGetCertTypeFlagsEx(
hCertType,
CERTTYPE_GENERAL_FLAG,
&m_tp.dwGeneralFlags);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeFlagsEx");
hr = CAGetCertTypePropertyEx(
hCertType,
CERTTYPE_PROP_RA_SIGNATURE,
&m_tp.dwcSignatureRequired);
_PrintIfErrorStr2(
hr,
"CTemplatePolicy:Initialize: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;
}
m_tp.dwcSignatureRequired = 0;
}
hr = CAGetCertTypeExpiration(
hCertType,
&m_tp.llftExpirationPeriod.ft,
&m_tp.llftOverlapPeriod.ft);
_JumpIfError(hr, error, "Policy:CAGetCertTypeExpiration");
hr = CAGetCertTypeExtensions(hCertType, &pExtensions);
_JumpIfError(hr, error, "CTemplatePolicy:Initialize:CAGetCertTypeExtensions");
hr = _CloneExtensions(pExtensions, &m_pExtensions);
_JumpIfError(hr, error, "CTemplatePolicy:_CloneExtensions");
hr = tpCAGetCertTypeObjectIdList(
hCertType,
CERTTYPE_PROP_CRITICAL_EXTENSIONS,
&CriticalExtensions);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:tpCAGetCertTypePolicies",
CERTTYPE_PROP_CRITICAL_EXTENSIONS);
hr = _CloneObjectIdList(&CriticalExtensions, &m_CriticalExtensions);
_JumpIfError(hr, error, "CTemplatePolicy:_CloneObjectIdList");
hr = tpCAGetCertTypeObjectIdList(
hCertType,
CERTTYPE_PROP_RA_POLICY,
&PoliciesIssuance);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:tpCAGetCertTypePolicies",
CERTTYPE_PROP_RA_POLICY);
hr = _CloneObjectIdList(&PoliciesIssuance, &m_PoliciesIssuance);
_JumpIfError(hr, error, "CTemplatePolicy:_CloneObjectIdList");
hr = tpCAGetCertTypeObjectIdList(
hCertType,
CERTTYPE_PROP_RA_APPLICATION_POLICY,
&PoliciesApplication);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:tpCAGetCertTypePolicies",
CERTTYPE_PROP_RA_APPLICATION_POLICY);
hr = _CloneObjectIdList(&PoliciesApplication, &m_PoliciesApplication);
_JumpIfError(hr, error, "CTemplatePolicy:_CloneObjectIdList");
m_hCertType = hCertType; // Transfer ownership only on success
error:
if (NULL != pExtensions)
{
CAFreeCertTypeExtensions(hCertType, pExtensions);
}
if (NULL != CriticalExtensions.rgpwszObjId)
{
CAFreeCertTypeProperty(hCertType, CriticalExtensions.rgpwszObjId);
}
if (NULL != PoliciesIssuance.rgpwszObjId)
{
CAFreeCertTypeProperty(hCertType, PoliciesIssuance.rgpwszObjId);
}
if (NULL != PoliciesApplication.rgpwszObjId)
{
CAFreeCertTypeProperty(hCertType, PoliciesApplication.rgpwszObjId);
}
DBGPRINT((
DBG_SS_CERTPOL,
"Policy:Template:Initialize(%ws, v%u.%u): V%u hr=%x\n",
NULL != m_pwszTemplateName? m_pwszTemplateName : L"",
m_tp.dwTemplateMajorVersion,
m_tp.dwTemplateMinorVersion,
m_tp.dwSchemaVersion,
hr));
_LogLoadResult(pPolicy, pServer, hr);
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::Clone
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::Clone(
OUT CTemplatePolicy **ppTemplate)
{
HRESULT hr;
CTemplatePolicy *pTemplateClone = NULL;
*ppTemplate = NULL;
pTemplateClone = new CTemplatePolicy;
if (NULL == pTemplateClone)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:Clone:new");
}
//pTemplateClone->m_hCertType = m_hCertType;
pTemplateClone->m_tp = m_tp;
if (NULL != m_pwszTemplateName)
{
hr = myDupString(
m_pwszTemplateName,
&pTemplateClone->m_pwszTemplateName);
_JumpIfError(hr, error, "myDupString");
}
if (NULL != m_pwszTemplateObjId)
{
hr = myDupString(
m_pwszTemplateObjId,
&pTemplateClone->m_pwszTemplateObjId);
_JumpIfError(hr, error, "myDupString");
}
hr = _CloneExtensions(m_pExtensions, &pTemplateClone->m_pExtensions);
_JumpIfError(hr, error, "CTemplatePolicy:_CloneExtensions");
hr = _CloneObjectIdList(
&m_CriticalExtensions,
&pTemplateClone->m_CriticalExtensions);
_JumpIfError(hr, error, "CTemplatePolicy:_CloneObjectIdList");
hr = _CloneObjectIdList(
&m_PoliciesIssuance,
&pTemplateClone->m_PoliciesIssuance);
_JumpIfError(hr, error, "CTemplatePolicy:_CloneObjectIdList");
hr = _CloneObjectIdList(
&m_PoliciesApplication,
&pTemplateClone->m_PoliciesApplication);
_JumpIfError(hr, error, "CTemplatePolicy:_CloneObjectIdList");
pTemplateClone->m_pPolicy = m_pPolicy;
*ppTemplate = pTemplateClone;
pTemplateClone = NULL;
hr = S_OK;
error:
if (NULL != pTemplateClone)
{
delete pTemplateClone;
}
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::AccessCheck
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::AccessCheck(
IN HANDLE hToken)
{
HRESULT hr;
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");
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::Apply
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::Apply(
IN ICertServerPolicy *pServer,
IN CRequestInstance *pRequest,
OUT BOOL *pfReenroll)
{
HRESULT hr;
DWORD dwRequestTemplateMinimumMajorVersion;
DWORD dwRequestTemplateMinimumMinorVersion;
BOOL fEnrollOnBehalfOf = FALSE;
*pfReenroll = FALSE;
pRequest->GetTemplateVersion(
&dwRequestTemplateMinimumMajorVersion,
&dwRequestTemplateMinimumMinorVersion);
CONSOLEPRINT5((
DBG_SS_CERTPOL,
"Request cert type: %ws(v%u.%u/v%u.%u)\n",
pRequest->GetTemplateName(),
dwRequestTemplateMinimumMajorVersion,
dwRequestTemplateMinimumMinorVersion,
m_tp.dwTemplateMajorVersion,
m_tp.dwTemplateMinorVersion));
hr = _AddBasicConstraintsExtension(pRequest, pServer);
_JumpIfError(hr, error, "Policy:_AddBasicConstraintsExtension");
hr = _AddKeyUsageExtension(pServer, pRequest);
_JumpIfError(hr, error, "Policy:_AddKeyUsageExtension");
hr = _AddTemplateExtensionArray(pServer);
_JumpIfError(hr, error, "Policy:_AddTemplateExtensionArray");
if (0 == (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT & m_tp.dwSubjectNameFlags))
{
hr = pRequest->_LoadPrincipalObject(
pServer,
this,
0 != ((CT_FLAG_SUBJECT_REQUIRE_COMMON_NAME |
CT_FLAG_SUBJECT_REQUIRE_DNS_AS_CN |
CT_FLAG_SUBJECT_ALT_REQUIRE_DNS) &
m_tp.dwSubjectNameFlags));
_JumpIfError(hr, error, "_LoadPrincipalObject");
hr = _AddSubjectName(pServer, pRequest);
_JumpIfError(hr, error, "Policy:_AddSubjectName");
}
hr = _AddAltSubjectName(pServer, pRequest);
_JumpIfError(hr, error, "Policy:_AddAltSubjectName");
pRequest->_ReleasePrincipalObject();
hr = _ApplyExpirationTime(pServer, pRequest);
_JumpIfError(hr, error, "Policy:_ApplyExpirationTime");
hr = _EnforceKeySizePolicy(pServer);
_JumpIfError(hr, error, "Policy:_EnforceKeySizePolicy");
hr = _EnforceKeyArchivalPolicy(pServer);
_JumpIfError(hr, error, "Policy:_EnforceKeyArchivalPolicy");
hr = _EnforceSymmetricAlgorithms(pServer);
_JumpIfError(hr, error, "Policy:_EnforceSymmetricAlgorithms");
hr = _EnforceMinimumTemplateVersion(pRequest);
_JumpIfError(hr, error, "Policy:_EnforceMinimumTemplateVersion");
hr = _EnforceEnrollOnBehalfOfAllowed(pServer, &fEnrollOnBehalfOf);
_JumpIfError(hr, error, "Policy:_EnforceEnrollOnBehalfOfAllowed");
hr = S_FALSE;
if (CT_FLAG_PREVIOUS_APPROVAL_VALIDATE_REENROLLMENT & m_tp.dwEnrollmentFlags)
{
hr = _EnforceReenrollment(pServer, pRequest);
_PrintIfError(hr, "Policy:_EnforceReenrollment");
if (S_OK == hr)
{
*pfReenroll = TRUE;
}
}
if (S_OK != hr)
{
hr = _EnforceSignaturePolicy(pServer, pRequest, fEnrollOnBehalfOf);
_JumpIfError(hr, error, "Policy:_EnforceSignaturePolicy");
}
CSASSERT(S_OK == hr);
error:
pRequest->_ReleasePrincipalObject();
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);
}
KEYUSAGEMASK const *
FindKeyUsage(
IN WCHAR const *pwszAlg,
IN KEYUSAGEMASK const *pKeyUsageMask,
IN DWORD cKeyUsageMask)
{
KEYUSAGEMASK const *pKeyUsageMaskRet = NULL;
KEYUSAGEMASK const *pKeyUsageMaskEnd;
for (
pKeyUsageMaskEnd = &pKeyUsageMask[cKeyUsageMask];
pKeyUsageMask < pKeyUsageMaskEnd;
pKeyUsageMask++)
{
DWORD i;
for (i = 0; NULL != pKeyUsageMask->apwszAlg[i]; i++)
{
if (0 == wcscmp(pwszAlg, pKeyUsageMask->apwszAlg[i]))
{
pKeyUsageMaskRet = pKeyUsageMask;
break;
}
}
if (NULL != pKeyUsageMaskRet)
{
break;
}
}
return(pKeyUsageMaskRet);
}
//+--------------------------------------------------------------------------
// CTemplatePolicy::_AddKeyUsageExtension
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_AddKeyUsageExtension(
IN ICertServerPolicy *pServer,
IN CRequestInstance *pRequest)
{
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 dwKU;
KEYUSAGEMASK const *pKeyUsageMask;
VariantInit(&varExtension);
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");
}
hr = polGetCertificateStringProperty(
pServer,
wszPROPCERTIFICATEPUBLICKEYALGORITHM,
&strAlg);
_JumpIfError(hr, error, "Policy:polGetCertificateStringProperty");
// Mask out any illegal bits
dwKU = 0;
CopyMemory(&dwKU, pKeyUsage->pbData, min(sizeof(dwKU), pKeyUsage->cbData));
pKeyUsageMask = FindKeyUsage(
strAlg,
g_aKeyUsageMask1,
ARRAYSIZE(g_aKeyUsageMask1));
if (NULL != pKeyUsageMask)
{
dwKU &= pRequest->IsCARequest()?
pKeyUsageMask->dwMask1 : pKeyUsageMask->dwMask2;
}
pKeyUsageMask = FindKeyUsage(
strAlg,
g_aKeyUsageMask2,
ARRAYSIZE(g_aKeyUsageMask2));
if (NULL != pKeyUsageMask && (dwKU & pKeyUsageMask->dwMask1))
{
dwKU &= ~pKeyUsageMask->dwMask2;
}
CopyMemory(pKeyUsage->pbData, &dwKU, min(sizeof(dwKU), pKeyUsage->cbData));
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 = polSetCertificateExtension(
pServer,
TEXT(szOID_KEY_USAGE),
PROPTYPE_BINARY,
pExt->fCritical? EXTENSION_CRITICAL_FLAG : 0,
&varExtension);
_JumpIfError(hr, error, "Policy:polSetCertificateExtension");
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:polSetCertificateExtension", 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;
BSTR strPropEMail = NULL;
VARIANT varValue;
BSTR strSubjectDot = NULL;
BSTR strSubjectCommonName = NULL;
varValue.vt = VT_NULL;
strSubjectDot = SysAllocString(wszPROPSUBJECTDOT);
strSubjectCommonName = SysAllocString(wszPROPSUBJECTCOMMONNAME);
if (NULL == strSubjectDot || NULL == strSubjectCommonName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocString");
}
// Clear out any existing subject name info
hr = pServer->SetCertificateProperty(
strSubjectDot,
PROPTYPE_STRING,
&varValue);
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
if (CT_FLAG_SUBJECT_REQUIRE_DIRECTORY_PATH & m_tp.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_tp.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(
strSubjectCommonName,
PROPTYPE_STRING,
&varValue);
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
}
if (CT_FLAG_SUBJECT_REQUIRE_EMAIL & m_tp.dwSubjectNameFlags)
{
hr = pRequest->_GetValueString(DS_ATTR_EMAIL_ADDR, &strEMail);
if (S_OK != hr)
{
if (CERTTYPE_SCHEMA_VERSION_2 <= m_tp.dwSchemaVersion &&
0 == (EDITF_EMAILOPTIONAL & m_pPolicy->GetEditFlags()))
{
hr = CERTSRV_E_SUBJECT_EMAIL_REQUIRED;
_JumpError(hr, error, "Policy:_AddSubjectName:EMail");
}
pRequest->BuildErrorInfo(
hr,
MSG_NO_EMAIL_NAME,
&pRequest->m_strUserDN);
}
else
{
varValue.vt = VT_BSTR;
varValue.bstrVal = const_cast<BSTR>(strEMail);
strPropEMail = SysAllocString(wszPROPSUBJECTEMAIL);
if (NULL == strPropEMail)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocStringLen");
}
hr = pServer->SetCertificateProperty(
strPropEMail,
PROPTYPE_STRING,
&varValue);
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
}
}
hr = S_OK;
error:
if (NULL != strPropEMail)
{
SysFreeString(strPropEMail);
}
if (NULL != strCN)
{
SysFreeString(const_cast<BSTR>(strCN));
}
if (NULL != strEMail)
{
SysFreeString(const_cast<BSTR>(strEMail));
}
if (NULL != strSubjectDot)
{
SysFreeString(strSubjectDot);
}
if (NULL != strSubjectCommonName)
{
SysFreeString(strSubjectCommonName);
}
return(hr);
}
HRESULT
tpDsUnquoteRdnValue(
IN DWORD cwcVal,
IN WCHAR const *pwcVal,
OUT WCHAR **ppwszVal)
{
HRESULT hr;
DWORD cwc;
*ppwszVal = NULL;
cwc = 0;
while (TRUE)
{
hr = DsUnquoteRdnValue(cwcVal, pwcVal, &cwc, *ppwszVal);
if (S_OK != hr)
{
hr = myHError(hr);
if (NULL == *ppwszVal)
{
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) == hr)
{
hr = S_OK;
}
}
else
{
LocalFree(*ppwszVal);
*ppwszVal = NULL;
}
_JumpIfError(hr, error, "Policy:DsUnquoteRdnValue");
}
if (NULL != *ppwszVal)
{
(*ppwszVal)[cwc] = L'\0';
break;
}
*ppwszVal = (WCHAR *) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * (cwc + 1));
if (NULL == *ppwszVal)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:LocalAlloc");
}
}
hr = S_OK;
error:
return(hr);
}
HRESULT
tpSetRequestRDN(
IN ICertServerPolicy *pServer,
IN WCHAR const *pwcKey,
IN DWORD cwcKey,
IN WCHAR const *pwcVal,
IN DWORD cwcVal)
{
HRESULT hr;
WCHAR *pwszVal = NULL;
BSTR strRDNName = NULL;
BSTR strValueOld = NULL;
BSTR strValue = NULL;
VARIANT varNew;
hr = tpDsUnquoteRdnValue(cwcVal, pwcVal, &pwszVal);
_JumpIfError(hr, error, "Policy:tpDsUnquoteRdnValue");
strRDNName = SysAllocStringLen(
NULL,
WSZARRAYSIZE(wszPROPSUBJECTDOT) + cwcKey);
if (NULL == strRDNName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocStringLen");
}
wcscpy(strRDNName, wszPROPSUBJECTDOT);
CopyMemory(
&strRDNName[WSZARRAYSIZE(wszPROPSUBJECTDOT)],
pwcKey,
sizeof(WCHAR) * cwcKey);
strRDNName[WSZARRAYSIZE(wszPROPSUBJECTDOT) + cwcKey] = L'\0';
CSASSERT(SysStringByteLen(strRDNName) == wcslen(strRDNName) * sizeof(WCHAR));
hr = polGetCertificateStringProperty(pServer, strRDNName, &strValueOld);
if (S_OK == hr)
{
strValue = SysAllocStringLen(
NULL,
wcslen(pwszVal) +
WSZARRAYSIZE(wszNAMESEPARATORDEFAULT) +
wcslen(strValueOld));
if (NULL == strValue)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocStringLen");
}
wcscpy(strValue, pwszVal);
wcscat(strValue, wszNAMESEPARATORDEFAULT);
wcscat(strValue, strValueOld);
}
else
{
strValue = SysAllocString(pwszVal);
if (NULL == strValue)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocStringLen");
}
}
CSASSERT(SysStringByteLen(strValue) == wcslen(strValue) * sizeof(WCHAR));
varNew.vt = VT_BSTR;
varNew.bstrVal = strValue;
hr = pServer->SetCertificateProperty(strRDNName, PROPTYPE_STRING, &varNew);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = CERTSRV_E_BAD_REQUESTSUBJECT;
}
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
error:
if (NULL != pwszVal)
{
LocalFree(pwszVal);
}
if (NULL != strRDNName)
{
SysFreeString(strRDNName);
}
if (NULL != strValueOld)
{
SysFreeString(strValueOld);
}
if (NULL != strValue)
{
SysFreeString(strValue);
}
return(hr);
}
DWORD
s_myDsGetRdnW(
IN OUT WCHAR const **ppwcDN,
IN OUT DWORD *pcwcDN,
OUT WCHAR const **ppwcKey,
OUT DWORD *pcwcKey,
OUT WCHAR const **ppwcVal,
OUT DWORD *pcwcVal)
{
HRESULT hr;
WCHAR const *pwc = *ppwcDN;
DWORD cwc = *pcwcDN;
if (0 < cwc && L',' == *pwc)
{
pwc++;
cwc--;
}
hr = ERROR_DS_NAME_UNPARSEABLE;
*ppwcKey = pwc;
while (TRUE)
{
if (0 == cwc)
{
_JumpError(hr, error, "no key");
}
if (L'=' == *pwc)
{
break;
}
pwc++;
cwc--;
}
*pcwcKey = SAFE_SUBTRACT_POINTERS(pwc, *ppwcKey);
pwc++;
cwc--;
*ppwcVal = pwc;
if (0 == cwc)
{
_JumpError(hr, error, "no value");
}
while (TRUE)
{
if (0 == cwc || L',' == *pwc)
{
break;
}
pwc++;
cwc--;
}
*pcwcVal = SAFE_SUBTRACT_POINTERS(pwc, *ppwcVal);
*ppwcDN = pwc;
*pcwcDN = cwc;
hr = S_OK;
error:
return(hr);
}
typedef DWORD (WINAPI FNDSGETRDNW)(
IN OUT LPCWCH *ppDN,
IN OUT DWORD *pcDN,
OUT LPCWCH *ppKey,
OUT DWORD *pcKey,
OUT LPCWCH *ppVal,
OUT DWORD *pcVal);
DWORD
myDsGetRdn(
IN OUT WCHAR const **ppwcDN,
IN OUT DWORD *pcwcDN,
OUT WCHAR const **ppwcKey,
OUT DWORD *pcwcKey,
OUT WCHAR const **ppwcVal,
OUT DWORD *pcwcVal)
{
HRESULT hr;
HMODULE hModule;
static FNDSGETRDNW *s_pfn = NULL;
if (NULL == s_pfn)
{
hModule = GetModuleHandle(TEXT("ntdsapi.dll"));
if (NULL == hModule)
{
hr = GetLastError();
goto error;
}
// load system function
s_pfn = (FNDSGETRDNW *) GetProcAddress(hModule, "DsGetRdnW");
if (NULL == s_pfn)
{
hr = GetLastError();
_PrintError(hr, "ntdsapi.dll!DsGetRdnW");
s_pfn = s_myDsGetRdnW;
}
}
hr = (*s_pfn)(ppwcDN, pcwcDN, ppwcKey, pcwcKey, ppwcVal, pcwcVal);
_JumpIfError(hr, error, "Policy:DsGetRdnW");
error:
return(hr);
}
HRESULT
CTemplatePolicy::_AddDSDistinguishedName(
IN ICertServerPolicy *pServer,
CRequestInstance *pRequest)
{
HRESULT hr;
WCHAR const *pwcDN;
DWORD cwcDN;
DWORD cRDN;
cRDN = 0;
pwcDN = pRequest->m_strUserDN;
if (NULL != pwcDN)
{
WCHAR const *pwcKey;
WCHAR const *pwcVal;
DWORD cwcKey;
DWORD cwcVal;
cwcDN = wcslen(pwcDN);
while (0 != cwcDN)
{
hr = myDsGetRdn(&pwcDN, &cwcDN, &pwcKey, &cwcKey, &pwcVal, &cwcVal);
if (S_OK != hr)
{
hr = myHError(hr);
_JumpError(hr, error, "Policy:myDsGetRdn");
}
if (0 != cwcKey && 0 != cwcVal)
{
hr = tpSetRequestRDN(
pServer,
pwcKey,
cwcKey,
pwcVal,
cwcVal);
_JumpIfError(hr, error, "Policy:tpSetRequestRDN");
cRDN++;
}
}
}
if (0 == cRDN)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "Policy:m_strUserDN");
}
hr = S_OK;
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CCertPolicyEnterprise::_AddAltSubjectName
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_AddAltSubjectName(
IN ICertServerPolicy *pServer,
IN OUT 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 = NULL;
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_tp.dwSubjectNameFlags)
{
LONG ExtFlags;
hr = polGetCertificateExtension(
pServer,
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:polGetCertificateExtension");
hr = pServer->GetCertificateExtensionFlags(&ExtFlags);
_JumpIfError(hr, error, "Policy:GetCertificateExtensionFlags");
if (EXTENSION_DISABLE_FLAG & ExtFlags)
{
ExtFlags &= ~EXTENSION_DISABLE_FLAG;
hr = polSetCertificateExtension(
pServer,
TEXT(szOID_SUBJECT_ALT_NAME2),
PROPTYPE_BINARY,
ExtFlags,
&varExtension);
_JumpIfError(hr, error, "Policy:polSetCertificateExtension");
}
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_tp.dwSubjectNameFlags)
{
// Add the UPN
if (NULL == pRequest->m_pwszUPN)
{
hr = CERTSRV_E_SUBJECT_UPN_REQUIRED;
_JumpError(hr, error, "Policy:_AddAltSubjectName:UPN");
}
AltName.cAltEntry++;
}
if (CT_FLAG_SUBJECT_ALT_REQUIRE_EMAIL & m_tp.dwSubjectNameFlags)
{
hr = pRequest->_GetValues(DS_ATTR_EMAIL_ADDR, &apwszMailNames);
if (S_OK != hr || NULL == apwszMailNames || NULL == apwszMailNames[0])
{
_PrintIfError(hr, "_GetValues(email)");
if (CERTTYPE_SCHEMA_VERSION_2 <= m_tp.dwSchemaVersion &&
0 == (EDITF_EMAILOPTIONAL & m_pPolicy->GetEditFlags()))
{
hr = CERTSRV_E_SUBJECT_EMAIL_REQUIRED;
_JumpError(hr, error, "Policy:_AddAltSubjectName:EMail");
}
pRequest->BuildErrorInfo(
hr,
MSG_NO_EMAIL_NAME,
&pRequest->m_strUserDN);
}
else
{
ppwszCurName = apwszMailNames;
while (NULL != *ppwszCurName)
{
AltName.cAltEntry++;
ppwszCurName++;
}
}
}
if (CT_FLAG_SUBJECT_ALT_REQUIRE_DIRECTORY_GUID & m_tp.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:GUID");
}
AltName.cAltEntry++;
}
if (CT_FLAG_SUBJECT_ALT_REQUIRE_DNS & m_tp.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:DNS");
}
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_tp.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_tp.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_tp.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_tp.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 = polSetCertificateExtension(
pServer,
TEXT(szOID_SUBJECT_ALT_NAME2),
PROPTYPE_BINARY,
0,
&varExtension);
_JumpIfError(hr, error, "Policy:polSetCertificateExtension");
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,
IN OUT CRequestInstance *pRequest)
{
HRESULT hr = S_OK;
VARIANT varValue;
BSTR strNameNotBefore = NULL;
BSTR strNameNotAfter = NULL;
SYSTEMTIME SystemTime;
LLFILETIME llftNotAfter;
LLFILETIME llftNotAfterCalc;
LLFILETIME llftNotBefore;
LLFILETIME llftNotAfterOverlap;
WCHAR const *pwszTemplate;
VariantInit(&varValue);
pwszTemplate = m_pwszTemplateName;
if (NULL == pwszTemplate)
{
pwszTemplate = m_pwszTemplateObjId;
}
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, &llftNotBefore.ft))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:SystemTimeToFileTime");
}
strNameNotAfter = SysAllocString(wszPROPCERTIFICATENOTAFTERDATE);
if (NULL == strNameNotAfter)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Policy:SysAllocString");
}
VariantClear(&varValue);
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, &llftNotAfter.ft))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:SystemTimeToFileTime");
}
if (0 > m_tp.llftExpirationPeriod.ll)
{
llftNotAfterCalc.ll = llftNotBefore.ll - m_tp.llftExpirationPeriod.ll;
}
else
{
llftNotAfterCalc.ll = m_tp.llftExpirationPeriod.ll;
}
if (llftNotAfterCalc.ll > llftNotAfter.ll)
{
// truncated!
llftNotAfterCalc.ll = llftNotAfter.ll;
pRequest->BuildErrorInfo(
S_OK,
MSG_TEMPLATE_VALIDITY_TOO_LONG,
&pwszTemplate);
}
if (!FileTimeToSystemTime(&llftNotAfterCalc.ft, &SystemTime))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:FileTimeToSystemTime");
}
if (!SystemTimeToVariantTime(&SystemTime, &varValue.date))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:SystemTimeToVariantTime");
}
hr = pServer->SetCertificateProperty(
strNameNotAfter,
PROPTYPE_DATE,
&varValue);
if (S_OK != hr)
{
DBGPRINTTIMEORPERIOD(" Old NotBefore", &llftNotBefore.ft);
DBGPRINTTIMEORPERIOD(" Old NotAfter", &llftNotAfter.ft);
DBGPRINTTIMEORPERIOD("Template Period", &m_tp.llftExpirationPeriod.ft);
DBGPRINTTIMEORPERIOD(" New NotAfter", &llftNotAfterCalc.ft);
}
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
// Verify new cert will be valid for at least as long as the overlap period
if (0 > m_tp.llftOverlapPeriod.ll)
{
llftNotAfterOverlap.ll = llftNotBefore.ll - m_tp.llftOverlapPeriod.ll;
}
else
{
llftNotAfterOverlap.ll = m_tp.llftOverlapPeriod.ll;
}
if (llftNotAfterOverlap.ll > llftNotAfter.ll)
{
LONG RequestFlags;
hr = polGetRequestLongProperty(
pServer,
wszPROPREQUESTFLAGS,
&RequestFlags);
_JumpIfErrorStr(
hr,
error,
"Policy:polGetRequestLongProperty",
wszPROPREQUESTFLAGS);
if (CR_FLG_RENEWAL & RequestFlags)
{
// too little life left, log and fail!
pRequest->BuildErrorInfo(
S_OK,
MSG_TEMPLATE_OVERLAP_TOO_LONG,
&pwszTemplate);
hr = CERTSRV_E_CERT_TYPE_OVERLAP;
_JumpError(hr, error, "Overlap too long");
}
}
CSASSERT(S_OK == hr);
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_tp.dwMinKeyLength)
{
LONG KeyLength;
hr = polGetCertificateLongProperty(
pServer,
wszPROPCERTIFICATEPUBLICKEYLENGTH,
&KeyLength);
_JumpIfErrorStr(
hr,
error,
"Policy:polGetCertificateLongProperty",
wszPROPCERTIFICATEPUBLICKEYLENGTH);
if (m_tp.dwMinKeyLength > (DWORD) KeyLength)
{
DBGPRINT((
DBG_SS_ERROR,
"Key Length %u, expected minimum %u\n",
KeyLength,
m_tp.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;
LONG fKeyArchived;
hr = polGetCertificateLongProperty(
pServer,
wszPROPKEYARCHIVED,
&fKeyArchived);
_JumpIfErrorStr(
hr,
error,
"Policy:polGetCertificateLongProperty",
wszPROPKEYARCHIVED);
if (CT_FLAG_REQUIRE_PRIVATE_KEY_ARCHIVAL & m_tp.dwPrivateKeyFlags)
{
if (!fKeyArchived)
{
hr = CERTSRV_E_ARCHIVED_KEY_REQUIRED;
_JumpError(hr, error, "missing archived key");
}
}
else
{
if (fKeyArchived)
{
hr = CERTSRV_E_ARCHIVED_KEY_UNEXPECTED;
_JumpError(hr, error, "unexpected archived key");
}
}
hr = S_OK;
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CCertPolicyEnterprise::_EnforceSymmetricAlgorithms
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT
CTemplatePolicy::_EnforceSymmetricAlgorithms(
IN ICertServerPolicy *pServer)
{
HRESULT hr;
VARIANT varExtension;
BOOL fSetNeeded = FALSE;
LONG ExtFlags = 0;
BSTR strCSPProvider = NULL;
VariantInit(&varExtension);
if (CT_FLAG_INCLUDE_SYMMETRIC_ALGORITHMS & m_tp.dwEnrollmentFlags)
{
hr = polGetCertificateExtension(
pServer,
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 = polSetCertificateExtension(
pServer,
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);
}
#ifdef CERTSRV_EOBO_DCR_APPROVED
// Fail the request if:
// the request is for a V2 template
// AND
// RequesterName is not the same as the CallerName (enroll-on-behalf-of)
// AND
// CT_FLAG_ALLOW_ENROLL_ON_BEHALF_OF is not set in the template flags
// OR
// RequesterName *is* the same as the CallerName (not enroll-on-behalf-of)
// AND
// CT_FLAG_ALLOW_ENROLL_ON_BEHALF_OF *is* set in the template flags
#else
// 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)
#endif
HRESULT
CTemplatePolicy::_EnforceEnrollOnBehalfOfAllowed(
IN ICertServerPolicy *pServer,
OUT BOOL *pfEnrollOnBehalfOf)
{
HRESULT hr;
BSTR strRequester = NULL;
BSTR strCaller = NULL;
*pfEnrollOnBehalfOf = FALSE;
hr = polGetRequestStringProperty(
pServer,
wszPROPREQUESTERNAME,
&strRequester);
_JumpIfErrorStr(
hr,
error,
"Policy:polGetRequestStringProperty",
wszPROPREQUESTERNAME);
hr = polGetRequestStringProperty(
pServer,
wszPROPCALLERNAME,
&strCaller);
_JumpIfErrorStr(
hr,
error,
"Policy:polGetRequestStringProperty",
wszPROPCALLERNAME);
*pfEnrollOnBehalfOf = 0 != mylstrcmpiL(strRequester, strCaller);
if (CERTTYPE_SCHEMA_VERSION_2 <= m_tp.dwSchemaVersion
#ifdef CERTSRV_EOBO_DCR_APPROVED
#else
&& 0 == m_tp.dwcSignatureRequired
#endif
)
{
#ifdef CERTSRV_EOBO_DCR_APPROVED
if (!*pfEnrollOnBehalfOf ^
(0 != (CT_FLAG_ALLOW_ENROLL_ON_BEHALF_OF & m_tp.dwEnrollmentFlags)))
#else
if (*pfEnrollOnBehalfOf)
#endif
{
hr = CERTSRV_E_BAD_RENEWAL_SUBJECT;
_JumpError(hr, error, "EnrollOnBehalfOf allowed/disallowed");
}
}
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_tp.dwTemplateMajorVersion < dwRequestTemplateMinimumMajorVersion ||
(m_tp.dwTemplateMajorVersion == dwRequestTemplateMinimumMajorVersion &&
m_tp.dwTemplateMinorVersion < dwRequestTemplateMinimumMinorVersion))
{
DBGPRINT((
DBG_SS_ERROR,
"Requested template version %u.%u, Loaded version %u.%u\n",
dwRequestTemplateMinimumMajorVersion,
dwRequestTemplateMinimumMinorVersion,
m_tp.dwTemplateMajorVersion,
m_tp.dwTemplateMinorVersion));
hr = CERTSRV_E_BAD_TEMPLATE_VERSION;
_JumpError(hr, error, "Policy:_EnforceMinimumTemplateVersion");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
tpSplitPolicies(
IN BSTR strPolicies,
OUT DWORD *pcPolicies,
OUT OBJECTIDLIST **pprgPolicies)
{
HRESULT hr;
WCHAR const *pwszT;
WCHAR *pwszOut;
DWORD cPolicies;
OBJECTIDLIST *prgPolicies;
DWORD cObjId;
WCHAR **rgpwszObjId;
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 = (OBJECTIDLIST *) 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;
rgpwszObjId = (WCHAR **) &prgPolicies[cPolicies];
pwszOut = (WCHAR *) &rgpwszObjId[cObjId];
wcscpy(pwszOut, strPolicies);
fNew = TRUE;
while (L'\0' != *pwszOut)
{
if (fNew)
{
prgPolicies->cObjId = 0;
prgPolicies->rgpwszObjId = rgpwszObjId;
}
prgPolicies->cObjId++;
*rgpwszObjId = pwszOut;
rgpwszObjId++; // 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::_LoadSignaturePolicies(
IN ICertServerPolicy *pServer,
IN WCHAR const *pwszPropNameRequest,
OUT DWORD *pcSignaturePolicies,
OUT OBJECTIDLIST **pprgSignaturePolicies) // from the signing cert(s)
{
HRESULT hr;
BSTR strSignaturePolicies = NULL;
*pcSignaturePolicies = 0;
*pprgSignaturePolicies = NULL;
hr = polGetRequestStringProperty(
pServer,
pwszPropNameRequest,
&strSignaturePolicies);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = CERTSRV_E_SIGNATURE_POLICY_REQUIRED;
}
_JumpIfErrorStr(
hr,
error,
"Policy:polGetRequestStringProperty",
pwszPropNameRequest);
hr = tpSplitPolicies(
strSignaturePolicies,
pcSignaturePolicies,
pprgSignaturePolicies);
_JumpIfError(hr, error, "Policy:tpSplitPolicies");
error:
if (NULL != strSignaturePolicies)
{
SysFreeString(strSignaturePolicies);
}
return(hr);
}
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 *pTemplateExt = 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
wszPROPREQUESTRAWOLDCERTIFICATE,
PROPTYPE_BINARY,
&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 **) &pTemplateExt,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "Policy:myDecodeObject");
}
if (!myConvertSzToWsz(&pwszObjId, pTemplateExt->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 != mylstrcmpiL(
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 != pTemplateExt)
{
LocalFree(pTemplateExt);
}
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,
IN CRequestInstance *pRequest,
IN BOOL fEnrollOnBehalfOf)
{
HRESULT hr;
DWORD cSignatureAccepted;
DWORD cSignatureRejected;
DWORD *prgdwRefCount = NULL;
DWORD i;
WCHAR const *awszStrings[3];
WCHAR wszCountAccepted[50];
WCHAR wszCountRequired[50];
WCHAR *pwszMissing = NULL;
OBJECTIDLIST *pPoliciesApplication;
DWORD cSignatureIssuance;
OBJECTIDLIST *prgSignatureIssuance = NULL;
DWORD cSignatureApplication;
OBJECTIDLIST *prgSignatureApplication = NULL;
static WCHAR *s_pwszObjIdEA = TEXT(szOID_ENROLLMENT_AGENT);
static OBJECTIDLIST s_PoliciesApplicationEA = { 1, &s_pwszObjIdEA };
pPoliciesApplication = &m_PoliciesApplication;
if (0 == m_tp.dwcSignatureRequired)
{
if (!fEnrollOnBehalfOf ||
CERTTYPE_SCHEMA_VERSION_2 <= m_tp.dwSchemaVersion)
{
hr = S_OK;
goto error;
}
// V1 template with fEnrollOnBehalfOf request.
// Enforce szOID_ENROLLMENT_AGENT
pPoliciesApplication = &s_PoliciesApplicationEA;
}
hr = _LoadSignaturePolicies(
pServer,
wszPROPSIGNERPOLICIES,
&cSignatureIssuance, // from the signing cert(s)
&prgSignatureIssuance);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:_LoadSignaturePolicies",
CERTTYPE_PROP_RA_POLICY);
hr = _LoadSignaturePolicies(
pServer,
wszPROPSIGNERAPPLICATIONPOLICIES,
&cSignatureApplication, // from the signing cert(s)
&prgSignatureApplication);
_JumpIfErrorStr(
hr,
error,
"CTemplatePolicy:_LoadSignaturePolicies",
CERTTYPE_PROP_RA_APPLICATION_POLICY);
if (0 == m_PoliciesIssuance.cObjId && 0 == pPoliciesApplication->cObjId)
{
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 != m_PoliciesIssuance.cObjId)
{
prgdwRefCount = (DWORD *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
m_PoliciesIssuance.cObjId * 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 **rgpwszObjId;
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.
rgpwszObjId = prgSignatureApplication[i].rgpwszObjId;
cObjId = prgSignatureApplication[i].cObjId;
for (j = 0; j < pPoliciesApplication->cObjId; j++)
{
idx = polFindObjIdInList(
pPoliciesApplication->rgpwszObjId[j],
cObjId,
rgpwszObjId);
if (MAXDWORD == idx)
{
fReject = TRUE;
_PrintErrorStr(
S_OK,
"Policy:missing Application Policy",
pPoliciesApplication->rgpwszObjId[j]);
}
}
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.
rgpwszObjId = prgSignatureIssuance[i].rgpwszObjId;
cObjId = prgSignatureIssuance[i].cObjId;
for (j = 0; j < cObjId; j++)
{
// "*" means the signing cert is good for *all* policies.
if (0 == wcscmp(L"*", rgpwszObjId[j]))
{
for (idx = 0; idx < m_PoliciesIssuance.cObjId; idx++)
{
prgdwRefCount[idx]++;
cFound++;
}
}
else
{
idx = polFindObjIdInList(
rgpwszObjId[j],
m_PoliciesIssuance.cObjId,
m_PoliciesIssuance.rgpwszObjId);
if (MAXDWORD != idx)
{
prgdwRefCount[idx]++;
cFound++;
}
}
}
// If no Issuance Policy OIDs are required, all signatures are OK.
if (0 != m_PoliciesIssuance.cObjId && 0 == cFound)
{
fReject = TRUE;
}
}
if (fReject)
{
cSignatureRejected++;
}
else
{
cSignatureAccepted++;
}
DBGPRINT((
DBG_SS_CERTPOL,
"Sig[%u]: %ws\n",
i,
fReject? L"Rejected" : L"Accepted"));
}
awszStrings[0] = m_pwszTemplateName;
if (NULL == awszStrings[0])
{
awszStrings[0] = m_pwszTemplateObjId;
}
hr = S_OK;
if (cSignatureAccepted < m_tp.dwcSignatureRequired)
{
hr = CERTSRV_E_SIGNATURE_COUNT;
if (0 != cSignatureRejected)
{
hr = CERTSRV_E_SIGNATURE_REJECTED;
}
_PrintError(hr, "Policy:not enough signatures");
// The %1 Certificate Template requires %2 signatures,
// but only %3 were accepted.
wsprintf(wszCountRequired, L"%u", m_tp.dwcSignatureRequired);
awszStrings[1] = wszCountRequired;
wsprintf(wszCountAccepted, L"%u", cSignatureAccepted);
awszStrings[2] = wszCountAccepted;
pRequest->BuildErrorInfo(hr, MSG_SIGNATURE_COUNT, awszStrings);
}
DBGPRINT((
S_OK != hr? DBG_SS_CERTPOLI : DBG_SS_CERTPOL,
"Signatures: %u needed, %u accepted\n",
m_tp.dwcSignatureRequired,
cSignatureAccepted));
for (i = 0; i < m_PoliciesIssuance.cObjId; i++)
{
if (0 == prgdwRefCount[i])
{
hr = CERTSRV_E_ISSUANCE_POLICY_REQUIRED;
_PrintErrorStr(
hr,
"Policy:missing Issuance Policy",
m_PoliciesIssuance.rgpwszObjId[i]);
myAppendString(
m_PoliciesIssuance.rgpwszObjId[i],
L", ",
&pwszMissing);
}
}
if (NULL != pwszMissing)
{
// The %1 Certificate Template requires the following issuance
// policies that signing certificates did not include: %2.
awszStrings[1] = pwszMissing;
pRequest->BuildErrorInfo(
hr,
MSG_SIGNATURE_ISSUANCE_POLICY,
awszStrings);
}
_JumpIfError(hr, error, "Policy:missing Policy/Signature");
error:
if (NULL != pwszMissing)
{
LocalFree(pwszMissing);
}
if (NULL != prgSignatureIssuance)
{
LocalFree(prgSignatureIssuance);
}
if (NULL != prgSignatureApplication)
{
LocalFree(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_tp.dwEnrollmentFlags;
break;
case CERTTYPE_SUBJECT_NAME_FLAG:
*pdwFlags = m_tp.dwSubjectNameFlags;
break;
case CERTTYPE_PRIVATE_KEY_FLAG:
*pdwFlags = m_tp.dwPrivateKeyFlags;
break;
case CERTTYPE_GENERAL_FLAG:
*pdwFlags = m_tp.dwGeneralFlags;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "Policy:bad dwOption");
}
hr = S_OK;
error:
return(hr);
}
HRESULT
CTemplatePolicy::GetCriticalExtensions(
OUT DWORD *pcCriticalExtensions,
OUT WCHAR const * const **papwszCriticalExtensions)
{
HRESULT hr;
*pcCriticalExtensions = m_CriticalExtensions.cObjId;
*papwszCriticalExtensions = m_CriticalExtensions.rgpwszObjId;
hr = S_OK;
return(hr);
}
HRESULT
CTemplatePolicy::GetV1TemplateClass(
OUT WCHAR const **ppwszV1TemplateClass)
{
WCHAR const *pwsz = NULL;
*ppwszV1TemplateClass = NULL;
if (CERTTYPE_SCHEMA_VERSION_2 > m_tp.dwSchemaVersion)
{
pwsz = m_pwszTemplateName;
}
else if (CT_FLAG_IS_CROSS_CA & m_tp.dwGeneralFlags)
{
pwsz = wszCERTTYPE_CROSS_CA;
}
*ppwszV1TemplateClass = pwsz;
return(S_OK);
}
// 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 == mylstrcmpiL(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 == mylstrcmpiL(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);
}