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.
5128 lines
122 KiB
5128 lines
122 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 2000
|
|
//
|
|
// File: policy.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 "policy.h"
|
|
#include "cainfop.h"
|
|
|
|
|
|
#define __dwFILE__ __dwFILE_POLICY_DEFAULT_POLICY_CPP__
|
|
|
|
|
|
// begin_sdksample
|
|
|
|
#ifndef DBG_CERTSRV
|
|
#error -- DBG_CERTSRV not defined!
|
|
#endif
|
|
|
|
// worker
|
|
HRESULT
|
|
polGetServerCallbackInterface(
|
|
OUT ICertServerPolicy **ppServer,
|
|
IN LONG Context)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == ppServer)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "Policy:polGetServerCallbackInterface");
|
|
}
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_CCertServerPolicy,
|
|
NULL, // pUnkOuter
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ICertServerPolicy,
|
|
(VOID **) ppServer);
|
|
_JumpIfError(hr, error, "Policy:CoCreateInstance");
|
|
|
|
if (NULL == *ppServer)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
_JumpError(hr, error, "Policy:CoCreateInstance");
|
|
}
|
|
|
|
// only set context if nonzero
|
|
if (0 != Context)
|
|
{
|
|
hr = (*ppServer)->SetContext(Context);
|
|
_JumpIfError(hr, error, "Policy:SetContext");
|
|
}
|
|
|
|
error:
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polGetProperty(
|
|
IN ICertServerPolicy *pServer,
|
|
IN BOOL fRequest,
|
|
IN WCHAR const *pwszPropertyName,
|
|
IN DWORD PropType,
|
|
OUT VARIANT *pvarOut)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strName = NULL;
|
|
|
|
VariantInit(pvarOut);
|
|
strName = SysAllocString(pwszPropertyName);
|
|
if (NULL == strName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
if (fRequest)
|
|
{
|
|
hr = pServer->GetRequestProperty(strName, PropType, pvarOut);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"Policy:GetRequestProperty",
|
|
pwszPropertyName,
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
}
|
|
else
|
|
{
|
|
hr = pServer->GetCertificateProperty(strName, PropType, pvarOut);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"Policy:GetCertificateProperty",
|
|
pwszPropertyName,
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
}
|
|
|
|
error:
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polGetStringProperty(
|
|
IN ICertServerPolicy *pServer,
|
|
IN BOOL fRequest,
|
|
IN WCHAR const *pwszPropertyName,
|
|
OUT BSTR *pstrOut)
|
|
{
|
|
HRESULT hr;
|
|
VARIANT var;
|
|
|
|
VariantInit(&var);
|
|
if (NULL != *pstrOut)
|
|
{
|
|
SysFreeString(*pstrOut);
|
|
*pstrOut = NULL;
|
|
}
|
|
hr = polGetProperty(
|
|
pServer,
|
|
fRequest,
|
|
pwszPropertyName,
|
|
PROPTYPE_STRING,
|
|
&var);
|
|
_JumpIfError2(
|
|
hr,
|
|
error,
|
|
"Policy:polGetProperty",
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
if (VT_BSTR != var.vt || NULL == var.bstrVal || L'\0' == var.bstrVal)
|
|
{
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
_JumpError(hr, error, "Policy:polGetProperty");
|
|
}
|
|
*pstrOut = var.bstrVal;
|
|
var.vt = VT_EMPTY;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
VariantClear(&var);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polGetLongProperty(
|
|
IN ICertServerPolicy *pServer,
|
|
IN BOOL fRequest,
|
|
IN WCHAR const *pwszPropertyName,
|
|
OUT LONG *plOut)
|
|
{
|
|
HRESULT hr;
|
|
VARIANT var;
|
|
|
|
VariantInit(&var);
|
|
hr = polGetProperty(
|
|
pServer,
|
|
fRequest,
|
|
pwszPropertyName,
|
|
PROPTYPE_LONG,
|
|
&var);
|
|
_JumpIfError2(hr, error, "Policy:polGetProperty", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
if (VT_I4 != var.vt)
|
|
{
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
_JumpError(hr, error, "Policy:polGetProperty");
|
|
}
|
|
*plOut = var.lVal;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
VariantClear(&var);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polGetRequestStringProperty(
|
|
IN ICertServerPolicy *pServer,
|
|
IN WCHAR const *pwszPropertyName,
|
|
OUT BSTR *pstrOut)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = polGetStringProperty(pServer, TRUE, pwszPropertyName, pstrOut);
|
|
_JumpIfError2(hr, error, "polGetStringProperty", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polGetCertificateStringProperty(
|
|
IN ICertServerPolicy *pServer,
|
|
IN WCHAR const *pwszPropertyName,
|
|
OUT BSTR *pstrOut)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = polGetStringProperty(pServer, FALSE, pwszPropertyName, pstrOut);
|
|
_JumpIfError2(hr, error, "polGetStringProperty", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polGetRequestLongProperty(
|
|
IN ICertServerPolicy *pServer,
|
|
IN WCHAR const *pwszPropertyName,
|
|
OUT LONG *plOut)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = polGetLongProperty(pServer, TRUE, pwszPropertyName, plOut);
|
|
_JumpIfError2(hr, error, "polGetLongProperty", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polGetCertificateLongProperty(
|
|
IN ICertServerPolicy *pServer,
|
|
IN WCHAR const *pwszPropertyName,
|
|
OUT LONG *plOut)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = polGetLongProperty(pServer, FALSE, pwszPropertyName, plOut);
|
|
_JumpIfError2(hr, error, "polGetLongProperty", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polGetRequestAttribute(
|
|
IN ICertServerPolicy *pServer,
|
|
IN WCHAR const *pwszAttributeName,
|
|
OUT BSTR *pstrOut)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strName = NULL;
|
|
|
|
strName = SysAllocString(pwszAttributeName);
|
|
if (NULL == strName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
hr = pServer->GetRequestAttribute(strName, pstrOut);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"Policy:GetRequestAttribute",
|
|
pwszAttributeName,
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
error:
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polGetCertificateExtension(
|
|
IN ICertServerPolicy *pServer,
|
|
IN WCHAR const *pwszExtensionName,
|
|
IN DWORD dwPropType,
|
|
IN OUT VARIANT *pvarOut)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strName = NULL;
|
|
|
|
strName = SysAllocString(pwszExtensionName);
|
|
if (NULL == strName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
hr = pServer->GetCertificateExtension(strName, dwPropType, pvarOut);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"Policy:GetCertificateExtension",
|
|
pwszExtensionName,
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
error:
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polSetCertificateExtension(
|
|
IN ICertServerPolicy *pServer,
|
|
IN WCHAR const *pwszExtensionName,
|
|
IN DWORD dwPropType,
|
|
IN DWORD dwExtFlags,
|
|
IN VARIANT const *pvarIn)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strName = NULL;
|
|
|
|
strName = SysAllocString(pwszExtensionName);
|
|
if (NULL == strName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
hr = pServer->SetCertificateExtension(
|
|
strName,
|
|
dwPropType,
|
|
dwExtFlags,
|
|
pvarIn);
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"Policy:SetCertificateExtension",
|
|
pwszExtensionName);
|
|
|
|
error:
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::~CCertPolicyEnterprise -- destructor
|
|
//
|
|
// free memory associated with this instance
|
|
//+--------------------------------------------------------------------------
|
|
|
|
CCertPolicyEnterprise::~CCertPolicyEnterprise()
|
|
{
|
|
_Cleanup();
|
|
|
|
// end_sdksample
|
|
if (m_fTemplateCriticalSection)
|
|
{
|
|
DeleteCriticalSection(&m_TemplateCriticalSection);
|
|
}
|
|
// begin_sdksample
|
|
}
|
|
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_FreeStringArray(
|
|
IN OUT DWORD *pcString,
|
|
IN OUT LPWSTR **papwsz)
|
|
{
|
|
LPWSTR *apwsz = *papwsz;
|
|
DWORD i;
|
|
|
|
if (NULL != apwsz)
|
|
{
|
|
for (i = *pcString; i-- > 0; )
|
|
{
|
|
if (NULL != apwsz[i])
|
|
{
|
|
DBGPRINT((DBG_SS_CERTPOLI, "_FreeStringArray[%u]: '%ws'\n", i, apwsz[i]));
|
|
LocalFree(apwsz[i]);
|
|
}
|
|
}
|
|
LocalFree(apwsz);
|
|
*papwsz = NULL;
|
|
}
|
|
*pcString = 0;
|
|
}
|
|
|
|
|
|
// end_sdksample
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_UnloadDSConfig -- release LDAP related resources
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_UnloadDSConfig()
|
|
{
|
|
HRESULT hr;
|
|
|
|
_ReleaseTemplates();
|
|
if (NULL != m_hCertTypeQuery)
|
|
{
|
|
hr = CACertTypeUnregisterQuery(m_hCertTypeQuery);
|
|
_PrintIfError(hr, "Policy:CACertTypeUnregisterQuery");
|
|
m_hCertTypeQuery = NULL;
|
|
}
|
|
myLdapClose(m_pld, m_strDomainDN, m_strConfigDN);
|
|
m_pld = NULL;
|
|
m_strDomainDN = NULL;
|
|
m_strConfigDN = NULL;
|
|
m_fConfigLoaded = FALSE;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_LoadDSConfig -- acquire LDAP related resources
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_LoadDSConfig(
|
|
IN ICertServerPolicy *pServer,
|
|
IN BOOL fRediscover)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwLogId = 0;
|
|
ULONG ldaperr;
|
|
WCHAR *pwszHostName = NULL;
|
|
|
|
_UnloadDSConfig();
|
|
if (m_fUseDS)
|
|
{
|
|
hr = myDoesDSExist(TRUE);
|
|
if (hr == HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN))
|
|
{
|
|
dwLogId = MSG_NO_DOMAIN;
|
|
_JumpError(hr, error, "Policy:myDoesDSExist");
|
|
}
|
|
|
|
// Renewal domain and config containers (%5, %6)
|
|
// We're going to be signing LDAP traffic and setting a template watch
|
|
// point, so require a related DS bug fix: RLBF_REQUIRE_LDAP_INTEG.
|
|
|
|
hr = myLdapOpen(
|
|
NULL, // pwszDomainName
|
|
RLBF_REQUIRE_SECURE_LDAP |
|
|
RLBF_REQUIRE_LDAP_INTEG |
|
|
(fRediscover? RLBF_ATTEMPT_REDISCOVER : 0),
|
|
&m_pld,
|
|
&m_strDomainDN,
|
|
&m_strConfigDN);
|
|
if (S_OK != hr)
|
|
{
|
|
dwLogId = MSG_NO_DOMAIN;
|
|
_JumpError(hr, error, "myLdapOpen");
|
|
}
|
|
|
|
if (IsEnterpriseCA(m_CAType))
|
|
{
|
|
// turn off auto-reconnect for the template container watch
|
|
|
|
ldaperr = ldap_set_option(
|
|
m_pld,
|
|
LDAP_OPT_AUTO_RECONNECT,
|
|
(void *) LDAP_OPT_OFF);
|
|
if (LDAP_SUCCESS != ldaperr)
|
|
{
|
|
hr = myHLdapError(m_pld, ldaperr, NULL);
|
|
_JumpError(hr, error, "ldap_set_option:LDAP_OPT_AUTO_RECONNECT");
|
|
}
|
|
|
|
hr = CACertTypeRegisterQuery(0, m_pld, &m_hCertTypeQuery);
|
|
_JumpIfError(hr, error, "Policy:CACertTypeRegisterQuery");
|
|
|
|
hr = _UpdateTemplates(pServer, TRUE);
|
|
_JumpIfError(hr, error, "Policy:_UpdateTemplates");
|
|
}
|
|
hr = myLdapGetDSHostName(m_pld, &pwszHostName);
|
|
_JumpIfError(hr, error, "myLdapGetDSHostName");
|
|
|
|
CSASSERT(NULL != pwszHostName);
|
|
if (fRediscover || NULL != m_pwszHostName)
|
|
{
|
|
LPCWSTR apwsz[2];
|
|
|
|
apwsz[0] = NULL != m_pwszHostName? m_pwszHostName : L"???";
|
|
apwsz[1] = pwszHostName;
|
|
hr = LogPolicyEvent(
|
|
g_hInstance,
|
|
S_OK,
|
|
MSG_DS_RECONNECTED,
|
|
pServer,
|
|
wszPROPEVENTLOGWARNING,
|
|
apwsz);
|
|
_PrintIfError(hr, "Policy:LogPolicyEvent");
|
|
|
|
if (NULL != m_pwszHostName)
|
|
{
|
|
LocalFree(m_pwszHostName);
|
|
m_pwszHostName = NULL;
|
|
}
|
|
}
|
|
hr = myDupString(pwszHostName, &m_pwszHostName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
hr = _SetSystemStringProp(pServer, wszPROPDCNAME, m_pwszHostName);
|
|
_PrintIfErrorStr(hr, "_SetSystemStringProp(wszPROPDCNAME)", m_pwszHostName);
|
|
}
|
|
else
|
|
{
|
|
m_strDomainDN = SysAllocString(L"");
|
|
m_strConfigDN = SysAllocString(L"");
|
|
if (NULL == m_strDomainDN || NULL == m_strConfigDN)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:LocalAlloc");
|
|
}
|
|
}
|
|
m_fConfigLoaded = TRUE;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
if (0 == dwLogId && NULL == m_pCreateErrorInfo)
|
|
{
|
|
dwLogId = MSG_DOMAIN_INIT;
|
|
}
|
|
if (0 != dwLogId)
|
|
{
|
|
_BuildErrorInfo(hr, dwLogId);
|
|
}
|
|
_UnloadDSConfig();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
// begin_sdksample
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_Cleanup -- free memory associated with this instance
|
|
//
|
|
// free memory associated with this instance
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_Cleanup()
|
|
{
|
|
DWORD i;
|
|
|
|
if (m_strDescription)
|
|
{
|
|
SysFreeString(m_strDescription);
|
|
m_strDescription = NULL;
|
|
}
|
|
|
|
// RevocationExtension variables:
|
|
|
|
if (NULL != m_wszASPRevocationURL)
|
|
{
|
|
LocalFree(m_wszASPRevocationURL);
|
|
m_wszASPRevocationURL = NULL;
|
|
}
|
|
|
|
// end_sdksample
|
|
// SubjectAltNameExtension variables:
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (NULL != m_astrSubjectAltNameProp[i])
|
|
{
|
|
SysFreeString(m_astrSubjectAltNameProp[i]);
|
|
m_astrSubjectAltNameProp[i] = NULL;
|
|
}
|
|
if (NULL != m_astrSubjectAltNameObjectId[i])
|
|
{
|
|
SysFreeString(m_astrSubjectAltNameObjectId[i]);
|
|
m_astrSubjectAltNameObjectId[i] = NULL;
|
|
}
|
|
}
|
|
// begin_sdksample
|
|
|
|
_FreeStringArray(&m_cEnableRequestExtensions, &m_apwszEnableRequestExtensions);
|
|
_FreeStringArray(&m_cEnableEnrolleeRequestExtensions, &m_apwszEnableEnrolleeRequestExtensions);
|
|
_FreeStringArray(&m_cDisableExtensions, &m_apwszDisableExtensions);
|
|
|
|
if (NULL != m_strCAName)
|
|
{
|
|
SysFreeString(m_strCAName);
|
|
m_strCAName = NULL;
|
|
}
|
|
if (NULL != m_strCASanitizedName)
|
|
{
|
|
SysFreeString(m_strCASanitizedName);
|
|
m_strCASanitizedName = NULL;
|
|
}
|
|
if (NULL != m_strCASanitizedDSName)
|
|
{
|
|
SysFreeString(m_strCASanitizedDSName);
|
|
m_strCASanitizedDSName = NULL;
|
|
}
|
|
if (NULL != m_strRegStorageLoc)
|
|
{
|
|
SysFreeString(m_strRegStorageLoc);
|
|
m_strRegStorageLoc = NULL;
|
|
}
|
|
if (NULL != m_pCert)
|
|
{
|
|
CertFreeCertificateContext(m_pCert);
|
|
m_pCert = NULL;
|
|
}
|
|
if (m_strMachineDNSName)
|
|
{
|
|
SysFreeString(m_strMachineDNSName);
|
|
m_strMachineDNSName=NULL;
|
|
}
|
|
|
|
// end_sdksample
|
|
|
|
if (NULL != m_pbSMIME)
|
|
{
|
|
LocalFree(m_pbSMIME);
|
|
m_pbSMIME = NULL;
|
|
}
|
|
if (NULL != m_pwszHostName)
|
|
{
|
|
LocalFree(m_pwszHostName);
|
|
m_pwszHostName = NULL;
|
|
}
|
|
_UnloadDSConfig();
|
|
if (NULL != m_pCreateErrorInfo)
|
|
{
|
|
m_pCreateErrorInfo->Release();
|
|
m_pCreateErrorInfo = NULL;
|
|
}
|
|
// begin_sdksample
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_ReadRegistryString(
|
|
IN HKEY hkey,
|
|
IN BOOL fURL,
|
|
IN WCHAR const *pwszRegName,
|
|
IN WCHAR const *pwszSuffix,
|
|
OUT LPWSTR *ppwszOut)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszRegValue = NULL;
|
|
DWORD cbValue;
|
|
DWORD dwType;
|
|
|
|
*ppwszOut = NULL;
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
pwszRegName,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
NULL,
|
|
&cbValue);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"Policy:RegQueryValueEx",
|
|
pwszRegName,
|
|
ERROR_FILE_NOT_FOUND);
|
|
|
|
if (REG_SZ != dwType && REG_MULTI_SZ != dwType)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpErrorStr(hr, error, "Policy:RegQueryValueEx TYPE", pwszRegName);
|
|
}
|
|
if (NULL != pwszSuffix)
|
|
{
|
|
cbValue += wcslen(pwszSuffix) * sizeof(WCHAR);
|
|
}
|
|
pwszRegValue = (WCHAR *) LocalAlloc(LMEM_FIXED, cbValue + sizeof(WCHAR));
|
|
if (NULL == pwszRegValue)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpErrorStr(hr, error, "Policy:LocalAlloc", pwszRegName);
|
|
}
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
pwszRegName,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) pwszRegValue,
|
|
&cbValue);
|
|
_JumpIfErrorStr(hr, error, "Policy:RegQueryValueEx", pwszRegName);
|
|
|
|
// Handle malformed registry values cleanly:
|
|
|
|
pwszRegValue[cbValue / sizeof(WCHAR)] = L'\0';
|
|
if (NULL != pwszSuffix)
|
|
{
|
|
wcscat(pwszRegValue, pwszSuffix);
|
|
}
|
|
|
|
hr = myFormatCertsrvStringArray(
|
|
fURL, // fURL
|
|
m_strMachineDNSName, // pwszServerName_p1_2
|
|
m_strCASanitizedName, // pwszSanitizedName_p3_7
|
|
m_iCert, // iCert_p4
|
|
MAXDWORD, // iCertTarget_p4
|
|
m_strDomainDN, // pwszDomainDN_p5
|
|
m_strConfigDN, // pwszConfigDN_p6
|
|
m_iCRL, // iCRL_p8
|
|
FALSE, // fDeltaCRL_p9
|
|
TRUE, // fDSAttrib_p10_11
|
|
1, // cStrings
|
|
(LPCWSTR *) &pwszRegValue, // apwszStringsIn
|
|
ppwszOut); // apwszStringsOut
|
|
_JumpIfError(hr, error, "Policy:myFormatCertsrvStringArray");
|
|
|
|
error:
|
|
if (NULL != pwszRegValue)
|
|
{
|
|
LocalFree(pwszRegValue);
|
|
}
|
|
return(myHError(hr)); // Reg routines return Win32 error codes
|
|
}
|
|
|
|
|
|
#if DBG_CERTSRV
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_DumpStringArray(
|
|
IN char const *pszType,
|
|
IN DWORD count,
|
|
IN LPWSTR const *apwsz)
|
|
{
|
|
DWORD i;
|
|
WCHAR const *pwszName;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
pwszName = L"";
|
|
if (iswdigit(apwsz[i][0]))
|
|
{
|
|
pwszName = myGetOIDName(apwsz[i]); // Static: do not free!
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOLI,
|
|
"%hs[%u]: %ws%hs%ws\n",
|
|
pszType,
|
|
i,
|
|
apwsz[i],
|
|
L'\0' != *pwszName? " -- " : "",
|
|
pwszName));
|
|
}
|
|
}
|
|
#endif // DBG_CERTSRV
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_SetSystemStringProp(
|
|
IN ICertServerPolicy *pServer,
|
|
IN WCHAR const *pwszName,
|
|
OPTIONAL IN WCHAR const *pwszValue)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strName = NULL;
|
|
VARIANT varValue;
|
|
|
|
varValue.vt = VT_NULL;
|
|
varValue.bstrVal = NULL;
|
|
|
|
if (!myConvertWszToBstr(&strName, pwszName, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
|
|
if (NULL != pwszValue)
|
|
{
|
|
if (!myConvertWszToBstr(&varValue.bstrVal, pwszValue, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
varValue.vt = VT_BSTR;
|
|
}
|
|
|
|
hr = pServer->SetCertificateProperty(strName, PROPTYPE_STRING, &varValue);
|
|
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
|
|
|
|
error:
|
|
VariantClear(&varValue);
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_AddStringArray(
|
|
IN WCHAR const *pwszzValue,
|
|
IN BOOL fURL,
|
|
IN OUT DWORD *pcStrings,
|
|
IN OUT LPWSTR **papwszRegValues)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cString = 0;
|
|
WCHAR const *pwsz;
|
|
LPCWSTR *awszFormatStrings = NULL;
|
|
LPWSTR *awszOutputStrings = NULL;
|
|
|
|
// Count the number of strings we're adding
|
|
for (pwsz = pwszzValue; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
|
|
{
|
|
cString++;
|
|
}
|
|
if (0 == cString) // no strings
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
awszFormatStrings = (LPCWSTR *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cString * sizeof(LPWSTR));
|
|
if (NULL == awszFormatStrings)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:LocalAlloc");
|
|
}
|
|
|
|
cString = 0;
|
|
for (pwsz = pwszzValue; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
|
|
{
|
|
// Skip strings that start with a an unescaped minus sign.
|
|
// Strings with an escaped minus sign (2 minus signs) are not skipped.
|
|
|
|
if (L'-' == *pwsz)
|
|
{
|
|
pwsz++;
|
|
if (L'-' != *pwsz)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
awszFormatStrings[cString++] = pwsz;
|
|
}
|
|
|
|
// if no strings to add, don't modify
|
|
if (cString > 0)
|
|
{
|
|
awszOutputStrings = (LPWSTR *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
(cString + *pcStrings) * sizeof(LPWSTR));
|
|
if (NULL == awszOutputStrings)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:LocalAlloc");
|
|
}
|
|
|
|
if (0 != *pcStrings)
|
|
{
|
|
CSASSERT(NULL != *papwszRegValues);
|
|
CopyMemory(
|
|
awszOutputStrings,
|
|
*papwszRegValues,
|
|
*pcStrings * sizeof(LPWSTR));
|
|
}
|
|
|
|
hr = myFormatCertsrvStringArray(
|
|
fURL, // fURL
|
|
m_strMachineDNSName, // pwszServerName_p1_2
|
|
m_strCASanitizedName, // pwszSanitizedName_p3_7
|
|
m_iCert, // iCert_p4
|
|
MAXDWORD, // iCertTarget_p4
|
|
m_strDomainDN, // pwszDomainDN_p5
|
|
m_strConfigDN, // pwszConfigDN_p6
|
|
m_iCRL, // iCRL_p8
|
|
FALSE, // fDeltaCRL_p9
|
|
TRUE, // fDSAttrib_p10_11
|
|
cString, // cStrings
|
|
awszFormatStrings, // apwszStringsIn
|
|
awszOutputStrings + (*pcStrings)); // apwszStringsOut
|
|
_JumpIfError(hr, error, "Policy:myFormatCertsrvStringArray");
|
|
|
|
*pcStrings = (*pcStrings) + cString;
|
|
if (*papwszRegValues)
|
|
{
|
|
LocalFree(*papwszRegValues);
|
|
}
|
|
*papwszRegValues = awszOutputStrings;
|
|
awszOutputStrings = NULL;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != awszOutputStrings)
|
|
{
|
|
LocalFree(awszOutputStrings);
|
|
}
|
|
if (NULL != awszFormatStrings)
|
|
{
|
|
LocalFree(awszFormatStrings);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_ReadRegistryStringArray(
|
|
IN HKEY hkey,
|
|
IN BOOL fURL,
|
|
IN DWORD dwFlags,
|
|
IN DWORD cRegNames,
|
|
IN DWORD *aFlags,
|
|
IN WCHAR const * const *apwszRegNames,
|
|
IN OUT DWORD *pcStrings,
|
|
IN OUT LPWSTR **papwszRegValues)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
WCHAR *pwszzValue = NULL;
|
|
DWORD cbValue;
|
|
DWORD dwType;
|
|
|
|
for (i = 0; i < cRegNames; i++)
|
|
{
|
|
if (0 == (dwFlags & aFlags[i]))
|
|
{
|
|
continue;
|
|
}
|
|
if (NULL != pwszzValue)
|
|
{
|
|
LocalFree(pwszzValue);
|
|
pwszzValue = NULL;
|
|
}
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
apwszRegNames[i],
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
NULL,
|
|
&cbValue);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"Policy:RegQueryValueEx",
|
|
apwszRegNames[i],
|
|
ERROR_FILE_NOT_FOUND);
|
|
continue;
|
|
}
|
|
if (REG_SZ != dwType && REG_MULTI_SZ != dwType)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_PrintErrorStr(hr, "Policy:RegQueryValueEx TYPE", apwszRegNames[i]);
|
|
continue;
|
|
}
|
|
|
|
// Handle malformed registry values cleanly by adding two WCHAR L'\0's
|
|
// allocate space for 3 WCHARs to allow for unaligned (odd) cbValue;
|
|
|
|
pwszzValue = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
cbValue + 3 * sizeof(WCHAR));
|
|
if (NULL == pwszzValue)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpErrorStr(hr, error, "Policy:LocalAlloc", apwszRegNames[i]);
|
|
}
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
apwszRegNames[i],
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) pwszzValue,
|
|
&cbValue);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr(hr, "Policy:RegQueryValueEx", apwszRegNames[i]);
|
|
continue;
|
|
}
|
|
|
|
// Handle malformed registry values cleanly:
|
|
|
|
pwszzValue[cbValue / sizeof(WCHAR)] = L'\0';
|
|
pwszzValue[cbValue / sizeof(WCHAR) + 1] = L'\0';
|
|
|
|
hr = _AddStringArray(
|
|
pwszzValue,
|
|
fURL,
|
|
pcStrings,
|
|
papwszRegValues);
|
|
_JumpIfErrorStr(hr, error, "_AddStringArray", apwszRegNames[i]);
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszzValue)
|
|
{
|
|
LocalFree(pwszzValue);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_InitRevocationExtension
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_InitRevocationExtension(
|
|
IN HKEY hkey)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwType;
|
|
DWORD cb;
|
|
|
|
cb = sizeof(m_dwRevocationFlags);
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
wszREGREVOCATIONTYPE,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &m_dwRevocationFlags,
|
|
&cb);
|
|
if (S_OK != hr ||
|
|
REG_DWORD != dwType ||
|
|
sizeof(m_dwRevocationFlags) != cb)
|
|
{
|
|
m_dwRevocationFlags = 0;
|
|
goto error;
|
|
}
|
|
DBGPRINT((DBG_SS_CERTPOL, "Revocation Flags = %x\n", m_dwRevocationFlags));
|
|
|
|
// clean up from previous call
|
|
|
|
if (NULL != m_wszASPRevocationURL)
|
|
{
|
|
LocalFree(m_wszASPRevocationURL);
|
|
m_wszASPRevocationURL = NULL;
|
|
}
|
|
|
|
if (REVEXT_ASPENABLE & m_dwRevocationFlags)
|
|
{
|
|
hr = _ReadRegistryString(
|
|
hkey,
|
|
TRUE, // fURL
|
|
wszREGREVOCATIONURL, // pwszRegName
|
|
L"?", // pwszSuffix
|
|
&m_wszASPRevocationURL); // pstrRegValue
|
|
_JumpIfErrorStr(hr, error, "_ReadRegistryString", wszREGREVOCATIONURL);
|
|
_DumpStringArray("ASP", 1, &m_wszASPRevocationURL);
|
|
}
|
|
|
|
error:
|
|
;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_InitRequestExtensionList
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_InitRequestExtensionList(
|
|
IN HKEY hkey)
|
|
{
|
|
HRESULT hr;
|
|
DWORD adwFlags[] = {
|
|
EDITF_REQUESTEXTENSIONLIST,
|
|
};
|
|
WCHAR *apwszRegNames[] = {
|
|
wszREGENABLEREQUESTEXTENSIONLIST,
|
|
};
|
|
WCHAR *apwszRegNamesEnrollee[] = {
|
|
wszREGENABLEENROLLEEREQUESTEXTENSIONLIST,
|
|
};
|
|
|
|
CSASSERT(ARRAYSIZE(adwFlags) == ARRAYSIZE(apwszRegNames));
|
|
CSASSERT(ARRAYSIZE(adwFlags) == ARRAYSIZE(apwszRegNamesEnrollee));
|
|
|
|
// clean up from previous call
|
|
|
|
if (NULL != m_apwszEnableRequestExtensions)
|
|
{
|
|
_FreeStringArray(
|
|
&m_cEnableRequestExtensions,
|
|
&m_apwszEnableRequestExtensions);
|
|
}
|
|
if (NULL != m_apwszEnableEnrolleeRequestExtensions)
|
|
{
|
|
_FreeStringArray(
|
|
&m_cEnableEnrolleeRequestExtensions,
|
|
&m_apwszEnableEnrolleeRequestExtensions);
|
|
}
|
|
|
|
hr = _ReadRegistryStringArray(
|
|
hkey,
|
|
FALSE, // fURL
|
|
m_dwEditFlags,
|
|
ARRAYSIZE(adwFlags),
|
|
adwFlags,
|
|
apwszRegNames,
|
|
&m_cEnableRequestExtensions,
|
|
&m_apwszEnableRequestExtensions);
|
|
_JumpIfError(hr, error, "_ReadRegistryStringArray");
|
|
|
|
_DumpStringArray(
|
|
"Request",
|
|
m_cEnableRequestExtensions,
|
|
m_apwszEnableRequestExtensions);
|
|
|
|
hr = _ReadRegistryStringArray(
|
|
hkey,
|
|
FALSE, // fURL
|
|
m_dwEditFlags,
|
|
ARRAYSIZE(adwFlags),
|
|
adwFlags,
|
|
apwszRegNamesEnrollee,
|
|
&m_cEnableEnrolleeRequestExtensions,
|
|
&m_apwszEnableEnrolleeRequestExtensions);
|
|
_JumpIfError(hr, error, "_ReadRegistryStringArray");
|
|
|
|
_DumpStringArray(
|
|
"EnrolleeRequest",
|
|
m_cEnableEnrolleeRequestExtensions,
|
|
m_apwszEnableEnrolleeRequestExtensions);
|
|
|
|
error:
|
|
;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_InitDisableExtensionList
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_InitDisableExtensionList(
|
|
IN HKEY hkey)
|
|
{
|
|
HRESULT hr;
|
|
DWORD adwFlags[] = {
|
|
EDITF_DISABLEEXTENSIONLIST,
|
|
};
|
|
WCHAR *apwszRegNames[] = {
|
|
wszREGDISABLEEXTENSIONLIST,
|
|
};
|
|
|
|
CSASSERT(ARRAYSIZE(adwFlags) == ARRAYSIZE(apwszRegNames));
|
|
|
|
// clean up from previous call
|
|
|
|
if (NULL != m_apwszDisableExtensions)
|
|
{
|
|
_FreeStringArray(&m_cDisableExtensions, &m_apwszDisableExtensions);
|
|
}
|
|
|
|
|
|
hr = _ReadRegistryStringArray(
|
|
hkey,
|
|
FALSE, // fURL
|
|
m_dwEditFlags,
|
|
ARRAYSIZE(adwFlags),
|
|
adwFlags,
|
|
apwszRegNames,
|
|
&m_cDisableExtensions,
|
|
&m_apwszDisableExtensions);
|
|
_JumpIfError(hr, error, "_ReadRegistryStringArray");
|
|
|
|
_DumpStringArray(
|
|
"Disable",
|
|
m_cDisableExtensions,
|
|
m_apwszDisableExtensions);
|
|
|
|
error:
|
|
;
|
|
}
|
|
|
|
|
|
// end_sdksample
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_InitDefaultSMIMEExtension
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_InitDefaultSMIMEExtension(
|
|
IN HKEY hkey)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_SMIME_CAPABILITIES SMIME = { 0, NULL };
|
|
CRYPT_SMIME_CAPABILITY *pSMIME;
|
|
DWORD cSMIME;
|
|
DWORD i;
|
|
LPWSTR *apwszSMIME = NULL;
|
|
DWORD adwFlags[] = {
|
|
EDITF_ENABLEDEFAULTSMIME,
|
|
};
|
|
WCHAR *apwszRegNames[] = {
|
|
wszREGDEFAULTSMIME,
|
|
};
|
|
|
|
CSASSERT(ARRAYSIZE(adwFlags) == ARRAYSIZE(apwszRegNames));
|
|
|
|
// clean up from previous call
|
|
|
|
if (NULL != m_pbSMIME)
|
|
{
|
|
LocalFree(m_pbSMIME);
|
|
m_pbSMIME = NULL;
|
|
}
|
|
|
|
cSMIME = 0;
|
|
hr = _ReadRegistryStringArray(
|
|
hkey,
|
|
FALSE, // fURL
|
|
m_dwEditFlags,
|
|
ARRAYSIZE(adwFlags),
|
|
adwFlags,
|
|
apwszRegNames,
|
|
&cSMIME,
|
|
&apwszSMIME);
|
|
_JumpIfError(hr, error, "_ReadRegistryStringArray");
|
|
|
|
_DumpStringArray("SMIME", cSMIME, apwszSMIME);
|
|
|
|
if (0 != cSMIME)
|
|
{
|
|
SMIME.rgCapability = (CRYPT_SMIME_CAPABILITY *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cSMIME * sizeof(SMIME.rgCapability[0]));
|
|
if (NULL == SMIME.rgCapability)
|
|
{
|
|
_JumpError(E_OUTOFMEMORY, error, "Policy:LocalAlloc");
|
|
}
|
|
SMIME.cCapability = cSMIME;
|
|
|
|
for (i = 0; i < cSMIME; i++)
|
|
{
|
|
WCHAR *pwszKeyLength = wcschr(apwszSMIME[i], L',');
|
|
|
|
pSMIME = &SMIME.rgCapability[i];
|
|
if (NULL != pwszKeyLength)
|
|
{
|
|
DWORD dwKeyLength;
|
|
|
|
*pwszKeyLength++ = L'\0';
|
|
dwKeyLength = _wtoi(pwszKeyLength);
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_INTEGER,
|
|
&dwKeyLength,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pSMIME->Parameters.pbData,
|
|
&pSMIME->Parameters.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
}
|
|
if (!myConvertWszToSz(&pSMIME->pszObjId, apwszSMIME[i], -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToSz");
|
|
}
|
|
}
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
PKCS_SMIME_CAPABILITIES,
|
|
&SMIME,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&m_pbSMIME,
|
|
&m_cbSMIME))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (NULL != apwszSMIME)
|
|
{
|
|
_FreeStringArray(&cSMIME, &apwszSMIME);
|
|
}
|
|
if (NULL != SMIME.rgCapability)
|
|
{
|
|
for (i = 0; i < SMIME.cCapability; i++)
|
|
{
|
|
pSMIME = &SMIME.rgCapability[i];
|
|
|
|
if (NULL != pSMIME->Parameters.pbData)
|
|
{
|
|
LocalFree(pSMIME->Parameters.pbData);
|
|
}
|
|
if (NULL != pSMIME->pszObjId)
|
|
{
|
|
LocalFree(pSMIME->pszObjId);
|
|
}
|
|
}
|
|
LocalFree(SMIME.rgCapability);
|
|
}
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_InitSubjectAltNameExtension
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_InitSubjectAltNameExtension(
|
|
IN HKEY hkey,
|
|
IN WCHAR const *pwszRegName,
|
|
IN WCHAR const *pwszObjectId,
|
|
IN DWORD iAltName)
|
|
{
|
|
DWORD err;
|
|
DWORD dwType;
|
|
DWORD cbbuf;
|
|
WCHAR awcbuf[MAX_PATH];
|
|
|
|
// ObjectId may be needed as a BSTR even if registry isn't set
|
|
|
|
if (!myConvertWszToBstr(
|
|
&m_astrSubjectAltNameObjectId[iAltName],
|
|
pwszObjectId,
|
|
-1))
|
|
{
|
|
_JumpError(E_OUTOFMEMORY, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
|
|
cbbuf = sizeof(awcbuf) - sizeof(WCHAR);
|
|
err = RegQueryValueEx(
|
|
hkey,
|
|
pwszRegName,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) awcbuf,
|
|
&cbbuf);
|
|
if (ERROR_SUCCESS != err ||
|
|
REG_SZ != dwType ||
|
|
sizeof(awcbuf) - sizeof(WCHAR) <= cbbuf)
|
|
{
|
|
goto error;
|
|
}
|
|
awcbuf[ARRAYSIZE(awcbuf) - 1] = L'\0'; // Just in case
|
|
if (0 == LSTRCMPIS(awcbuf, wszATTREMAIL1) ||
|
|
0 == LSTRCMPIS(awcbuf, wszATTREMAIL2))
|
|
{
|
|
if (!myConvertWszToBstr(
|
|
&m_astrSubjectAltNameProp[iAltName],
|
|
wszPROPSUBJECTEMAIL,
|
|
-1))
|
|
{
|
|
_JumpError(E_OUTOFMEMORY, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOLI,
|
|
"Policy: %ws(RDN=%ws): %ws\n",
|
|
pwszRegName,
|
|
awcbuf,
|
|
m_astrSubjectAltNameProp[iAltName]));
|
|
|
|
error:
|
|
;
|
|
}
|
|
|
|
// begin_sdksample
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::Initialize
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CCertPolicyEnterprise::Initialize(
|
|
/* [in] */ BSTR const strConfig)
|
|
{
|
|
HRESULT hr;
|
|
HKEY hkey = NULL;
|
|
DWORD dwType;
|
|
DWORD dwSize;
|
|
ICertServerPolicy *pServer = NULL;
|
|
BOOL fCritSecEntered = FALSE; // no_sdksample
|
|
BOOL fUpgraded;
|
|
BSTR bstrDescription = NULL;
|
|
ICreateErrorInfo *pCreateErrorInfo = NULL; // no_sdksample
|
|
|
|
CERT_RDN_ATTR rdnAttr = { szOID_COMMON_NAME, CERT_RDN_ANY_TYPE, };
|
|
|
|
rdnAttr.Value.pbData = NULL;
|
|
|
|
DBGPRINT((DBG_SS_CERTPOL, "Policy:Initialize:\n"));
|
|
|
|
// end_sdksample
|
|
|
|
hr = S_OK;
|
|
if (!m_fTemplateCriticalSection)
|
|
{
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&m_TemplateCriticalSection);
|
|
m_fTemplateCriticalSection = TRUE;
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
_JumpIfError(hr, error, "InitializeCriticalSection");
|
|
}
|
|
EnterCriticalSection(&m_TemplateCriticalSection);
|
|
fCritSecEntered = TRUE;
|
|
if (NULL != m_pCreateErrorInfo)
|
|
{
|
|
m_pCreateErrorInfo->Release();
|
|
m_pCreateErrorInfo = NULL;
|
|
}
|
|
// begin_sdksample
|
|
|
|
__try
|
|
{
|
|
_Cleanup();
|
|
|
|
m_strCAName = SysAllocString(strConfig);
|
|
if (NULL == m_strCAName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_LeaveError(hr, "CCertPolicyEnterprise::SysAllocString");
|
|
}
|
|
|
|
// force loading the description from resources
|
|
|
|
hr = GetDescription(&bstrDescription);
|
|
_LeaveIfError(hr, "CCertPolicyEnterprise::GetDescription");
|
|
|
|
// get server callbacks
|
|
|
|
hr = polGetServerCallbackInterface(&pServer, 0);
|
|
_LeaveIfError(hr, "Policy:polGetServerCallbackInterface");
|
|
|
|
hr = ReqInitialize(pServer);
|
|
_JumpIfError(hr, error, "ReqInitialize");
|
|
|
|
hr = TPInitialize(pServer); // no_sdksample
|
|
_JumpIfError(hr, error, "TPInitialize"); // no_sdksample
|
|
|
|
// get storage location
|
|
hr = polGetCertificateStringProperty(
|
|
pServer,
|
|
wszPROPMODULEREGLOC,
|
|
&m_strRegStorageLoc);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateStringProperty",
|
|
wszPROPMODULEREGLOC);
|
|
|
|
|
|
// get CA type
|
|
|
|
hr = polGetCertificateLongProperty(
|
|
pServer,
|
|
wszPROPCATYPE,
|
|
(LONG *) &m_CAType);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateLongProperty",
|
|
wszPROPCATYPE);
|
|
|
|
// end_sdksample
|
|
|
|
hr = polGetCertificateLongProperty(
|
|
pServer,
|
|
wszPROPUSEDS,
|
|
(LONG *) &m_fUseDS);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateLongProperty",
|
|
wszREGCAUSEDS);
|
|
|
|
hr = polGetCertificateLongProperty(
|
|
pServer,
|
|
wszPROPLOGLEVEL,
|
|
(LONG *) &m_dwLogLevel);
|
|
if (S_OK != hr)
|
|
{
|
|
m_dwLogLevel = CERTLOG_WARNING;
|
|
_PrintErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateLongProperty",
|
|
wszPROPLOGLEVEL);
|
|
}
|
|
|
|
// begin_sdksample
|
|
|
|
// get sanitized name
|
|
|
|
hr = polGetCertificateStringProperty(
|
|
pServer,
|
|
wszPROPSANITIZEDCANAME,
|
|
&m_strCASanitizedName);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateStringProperty",
|
|
wszPROPSANITIZEDCANAME);
|
|
|
|
// get sanitized name
|
|
|
|
hr = polGetCertificateStringProperty(
|
|
pServer,
|
|
wszPROPSANITIZEDSHORTNAME,
|
|
&m_strCASanitizedDSName);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateStringProperty",
|
|
wszPROPSANITIZEDSHORTNAME);
|
|
|
|
hr = polGetCertificateLongProperty(
|
|
pServer,
|
|
wszPROPSERVERUPGRADED,
|
|
(LONG *) &fUpgraded);
|
|
if (S_OK != hr)
|
|
{
|
|
fUpgraded = FALSE;
|
|
_PrintErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateLongProperty",
|
|
wszPROPSERVERUPGRADED);
|
|
}
|
|
|
|
hr = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
m_strRegStorageLoc,
|
|
0, // dwReserved
|
|
fUpgraded?
|
|
KEY_ALL_ACCESS :
|
|
(KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_QUERY_VALUE),
|
|
&hkey);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:Initialize:RegOpenKeyEx",
|
|
m_strRegStorageLoc);
|
|
|
|
// Ignore error codes.
|
|
|
|
dwSize = sizeof(m_dwDispositionFlags);
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
wszREGREQUESTDISPOSITION,
|
|
0,
|
|
&dwType,
|
|
(BYTE *) &m_dwDispositionFlags,
|
|
&dwSize);
|
|
if (S_OK != hr || REG_DWORD != dwType)
|
|
{
|
|
m_dwDispositionFlags = REQDISP_PENDINGFIRST | REQDISP_ISSUE;
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"Disposition Flags = %x\n",
|
|
m_dwDispositionFlags));
|
|
|
|
dwSize = sizeof(m_dwEditFlags);
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
wszREGEDITFLAGS,
|
|
0,
|
|
&dwType,
|
|
(BYTE *) &m_dwEditFlags,
|
|
&dwSize);
|
|
if (S_OK != hr || REG_DWORD != dwType)
|
|
{
|
|
m_dwEditFlags =
|
|
IsEnterpriseCA(m_CAType)? // no_sdksample
|
|
EDITF_DEFAULT_ENTERPRISE : // no_sdksample
|
|
EDITF_DEFAULT_STANDALONE;
|
|
}
|
|
if (fUpgraded)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"Initialize: setting EDITF_SERVERUPGRADED\n"));
|
|
|
|
m_dwEditFlags |= EDITF_SERVERUPGRADED;
|
|
dwSize = sizeof(m_dwEditFlags);
|
|
hr = RegSetValueEx(
|
|
hkey,
|
|
wszREGEDITFLAGS,
|
|
0,
|
|
REG_DWORD,
|
|
(BYTE *) &m_dwEditFlags,
|
|
dwSize);
|
|
_PrintIfError(hr, "Policy:RegSetValueEx");
|
|
}
|
|
DBGPRINT((DBG_SS_CERTPOL, "Edit Flags = %x\n", m_dwEditFlags));
|
|
|
|
dwSize = sizeof(m_CAPathLength);
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
wszREGCAPATHLENGTH,
|
|
0,
|
|
&dwType,
|
|
(BYTE *) &m_CAPathLength,
|
|
&dwSize);
|
|
if (S_OK != hr || REG_DWORD != dwType)
|
|
{
|
|
m_CAPathLength = CAPATHLENGTH_INFINITE;
|
|
}
|
|
DBGPRINT((DBG_SS_CERTPOL, "CAPathLength = %x\n", m_CAPathLength));
|
|
|
|
|
|
// Initialize the insertion string array.
|
|
// Machine DNS name (%1)
|
|
|
|
hr = polGetCertificateStringProperty(
|
|
pServer,
|
|
wszPROPMACHINEDNSNAME,
|
|
&m_strMachineDNSName);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateStringProperty",
|
|
wszPROPMACHINEDNSNAME);
|
|
|
|
hr = polGetCertificateLongProperty(
|
|
pServer,
|
|
wszPROPCERTCOUNT,
|
|
(LONG *) &m_iCert);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateLongProperty",
|
|
wszPROPCERTCOUNT);
|
|
|
|
if (0 == m_iCert) // no CA certs?
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateLongProperty",
|
|
wszPROPCERTCOUNT);
|
|
}
|
|
m_iCert--;
|
|
|
|
hr = polGetCertificateLongProperty(
|
|
pServer,
|
|
wszPROPCRLINDEX,
|
|
(LONG *) &m_iCRL);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateLongProperty",
|
|
wszPROPCRLINDEX);
|
|
|
|
_InitRevocationExtension(hkey);
|
|
_InitRequestExtensionList(hkey);
|
|
_InitDisableExtensionList(hkey);
|
|
|
|
// end_sdksample
|
|
|
|
_InitSubjectAltNameExtension(
|
|
hkey,
|
|
wszREGSUBJECTALTNAME,
|
|
TEXT(szOID_SUBJECT_ALT_NAME),
|
|
0);
|
|
_InitSubjectAltNameExtension(
|
|
hkey,
|
|
wszREGSUBJECTALTNAME2,
|
|
TEXT(szOID_SUBJECT_ALT_NAME2),
|
|
1);
|
|
|
|
hr = polGetCertificateLongProperty(
|
|
pServer,
|
|
wszPROPTEMPLATECHANGESEQUENCENUMBER,
|
|
(LONG *) &m_dwCATemplListSequenceNum);
|
|
_LeaveIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateLongProperty",
|
|
wszPROPTEMPLATECHANGESEQUENCENUMBER);
|
|
|
|
_InitDefaultSMIMEExtension(hkey);
|
|
|
|
hr = _LoadDSConfig(pServer, FALSE);
|
|
_PrintIfError(hr, "Policy:_LoadDSConfig");
|
|
|
|
// if we fail the bind, don't sweat it, as we'll try again later,
|
|
// at each request, and when GPO download happens.
|
|
|
|
pCreateErrorInfo = m_pCreateErrorInfo;
|
|
m_pCreateErrorInfo = NULL;
|
|
|
|
// begin_sdksample
|
|
hr = S_OK;
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
_PrintError(hr, "Exception");
|
|
}
|
|
|
|
error:
|
|
if (NULL != bstrDescription)
|
|
{
|
|
SysFreeString(bstrDescription);
|
|
}
|
|
if (NULL != hkey)
|
|
{
|
|
RegCloseKey(hkey);
|
|
}
|
|
if (NULL != pServer)
|
|
{
|
|
pServer->Release();
|
|
}
|
|
// end_sdksample
|
|
if (fCritSecEntered)
|
|
{
|
|
LeaveCriticalSection(&m_TemplateCriticalSection);
|
|
}
|
|
if (NULL != pCreateErrorInfo)
|
|
{
|
|
HRESULT hr2 = SetModuleErrorInfo(pCreateErrorInfo);
|
|
pCreateErrorInfo->Release();
|
|
_PrintIfError(hr2, "Policy:SetModuleErrorInfo");
|
|
}
|
|
// begin_sdksample
|
|
return(myHError(hr)); // Reg routines return Win32 error codes
|
|
}
|
|
|
|
|
|
DWORD
|
|
polFindObjIdInList(
|
|
IN WCHAR const *pwsz,
|
|
IN DWORD count,
|
|
IN WCHAR const * const *ppwsz)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (NULL == pwsz || NULL == ppwsz[i])
|
|
{
|
|
i = count;
|
|
break;
|
|
}
|
|
if (0 == wcscmp(pwsz, ppwsz[i]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return(i < count? i : MAXDWORD);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_EnumerateExtensions(
|
|
IN ICertServerPolicy *pServer,
|
|
IN LONG bNewRequest,
|
|
IN BOOL fFirstPass,
|
|
IN BOOL fEnableEnrolleeExtensions,
|
|
IN DWORD cCriticalExtensions,
|
|
OPTIONAL IN WCHAR const * const *apwszCriticalExtensions)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
BSTR strName = NULL;
|
|
LONG ExtFlags;
|
|
VARIANT varValue;
|
|
BOOL fClose = FALSE;
|
|
BOOL fEnable;
|
|
BOOL fDisable;
|
|
BOOL fCritical;
|
|
|
|
VariantInit(&varValue);
|
|
|
|
hr = pServer->EnumerateExtensionsSetup(0);
|
|
_JumpIfError(hr, error, "Policy:EnumerateExtensionsSetup");
|
|
|
|
fClose = TRUE;
|
|
while (TRUE)
|
|
{
|
|
hr = pServer->EnumerateExtensions(&strName);
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
_JumpIfError(hr, error, "Policy:EnumerateExtensions");
|
|
|
|
hr = pServer->GetCertificateExtension(
|
|
strName,
|
|
PROPTYPE_BINARY,
|
|
&varValue);
|
|
_JumpIfError(hr, error, "Policy:GetCertificateExtension");
|
|
|
|
hr = pServer->GetCertificateExtensionFlags(&ExtFlags);
|
|
_JumpIfError(hr, error, "Policy:GetCertificateExtensionFlags");
|
|
|
|
fEnable = FALSE;
|
|
fDisable = FALSE;
|
|
fCritical = FALSE;
|
|
|
|
if (fFirstPass)
|
|
{
|
|
if (bNewRequest && (EXTENSION_DISABLE_FLAG & ExtFlags))
|
|
{
|
|
switch (EXTENSION_ORIGIN_MASK & ExtFlags)
|
|
{
|
|
case EXTENSION_ORIGIN_REQUEST:
|
|
case EXTENSION_ORIGIN_RENEWALCERT:
|
|
case EXTENSION_ORIGIN_PKCS7:
|
|
case EXTENSION_ORIGIN_CMC:
|
|
if ((EDITF_ENABLEREQUESTEXTENSIONS & m_dwEditFlags) ||
|
|
MAXDWORD != polFindObjIdInList(
|
|
strName,
|
|
m_cEnableRequestExtensions,
|
|
m_apwszEnableRequestExtensions) ||
|
|
(fEnableEnrolleeExtensions &&
|
|
MAXDWORD != polFindObjIdInList(
|
|
strName,
|
|
m_cEnableEnrolleeRequestExtensions,
|
|
m_apwszEnableEnrolleeRequestExtensions)))
|
|
{
|
|
ExtFlags &= ~EXTENSION_DISABLE_FLAG;
|
|
fEnable = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (0 == (EXTENSION_DISABLE_FLAG & ExtFlags) &&
|
|
MAXDWORD != polFindObjIdInList(
|
|
strName,
|
|
m_cDisableExtensions,
|
|
m_apwszDisableExtensions))
|
|
{
|
|
ExtFlags |= EXTENSION_DISABLE_FLAG;
|
|
fDisable = TRUE;
|
|
}
|
|
if (0 == (EXTENSION_CRITICAL_FLAG & ExtFlags) &&
|
|
MAXDWORD != polFindObjIdInList(
|
|
strName,
|
|
cCriticalExtensions,
|
|
apwszCriticalExtensions))
|
|
{
|
|
ExtFlags |= EXTENSION_CRITICAL_FLAG;
|
|
fCritical = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fDisable || fEnable)
|
|
{
|
|
hr = pServer->SetCertificateExtension(
|
|
strName,
|
|
PROPTYPE_BINARY,
|
|
ExtFlags,
|
|
&varValue);
|
|
_JumpIfError(hr, error, "Policy:SetCertificateExtension");
|
|
}
|
|
|
|
if (fFirstPass || fDisable || fEnable)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"Policy:EnumerateExtensions(%ws, Flags=%x, %x bytes)%hs%hs\n",
|
|
strName,
|
|
ExtFlags,
|
|
SysStringByteLen(varValue.bstrVal),
|
|
fDisable? " DISABLING" : (fEnable? " ENABLING" : ""),
|
|
fCritical? " +CRITICAL" : ""));
|
|
}
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
strName = NULL;
|
|
}
|
|
VariantClear(&varValue);
|
|
}
|
|
|
|
error:
|
|
if (fClose)
|
|
{
|
|
hr2 = pServer->EnumerateExtensionsClose();
|
|
if (S_OK != hr2)
|
|
{
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
_PrintError(hr2, "Policy:EnumerateExtensionsClose");
|
|
}
|
|
}
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
VariantClear(&varValue);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
EnumerateAttributes(
|
|
IN ICertServerPolicy *pServer)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
BSTR strName = NULL;
|
|
BOOL fClose = FALSE;
|
|
BSTR strValue = NULL;
|
|
|
|
hr = pServer->EnumerateAttributesSetup(0);
|
|
_JumpIfError(hr, error, "Policy:EnumerateAttributesSetup");
|
|
|
|
fClose = TRUE;
|
|
while (TRUE)
|
|
{
|
|
hr = pServer->EnumerateAttributes(&strName);
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
_JumpIfError(hr, error, "Policy:EnumerateAttributes");
|
|
|
|
hr = pServer->GetRequestAttribute(strName, &strValue);
|
|
_JumpIfError(hr, error, "Policy:GetRequestAttribute");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"Policy:EnumerateAttributes(%ws = %ws)\n",
|
|
strName,
|
|
strValue));
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
strName = NULL;
|
|
}
|
|
if (NULL != strValue)
|
|
{
|
|
SysFreeString(strValue);
|
|
strValue = NULL;
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (fClose)
|
|
{
|
|
hr2 = pServer->EnumerateAttributesClose();
|
|
if (S_OK != hr2)
|
|
{
|
|
_PrintError(hr2, "Policy:EnumerateAttributesClose");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
}
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
if (NULL != strValue)
|
|
{
|
|
SysFreeString(strValue);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetRequestId(
|
|
IN ICertServerPolicy *pServer,
|
|
OUT LONG *plRequestId)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = polGetRequestLongProperty(pServer, wszPROPREQUESTREQUESTID, plRequestId);
|
|
_JumpIfError(hr, error, "Policy:polGetRequestLongProperty");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"Policy:GetRequestId(%ws = %u)\n",
|
|
wszPROPREQUESTREQUESTID,
|
|
*plRequestId));
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_AddRevocationExtension
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_AddRevocationExtension(
|
|
IN ICertServerPolicy *pServer)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR strASPExtension = NULL;
|
|
VARIANT varExtension;
|
|
|
|
if (NULL != m_wszASPRevocationURL)
|
|
{
|
|
strASPExtension = SysAllocString(m_wszASPRevocationURL);
|
|
if (NULL == strASPExtension)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
|
|
varExtension.vt = VT_BSTR;
|
|
varExtension.bstrVal = strASPExtension;
|
|
hr = polSetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_NETSCAPE_REVOCATION_URL),
|
|
PROPTYPE_STRING,
|
|
0,
|
|
&varExtension);
|
|
_JumpIfErrorStr(hr, error, "Policy:polSetCertificateExtension", L"ASP");
|
|
}
|
|
|
|
error:
|
|
if (NULL != strASPExtension)
|
|
{
|
|
SysFreeString(strASPExtension);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
#define HIGHBIT(bitno) (1 << (7 - (bitno))) // bit counted from high end
|
|
|
|
#define SSLBIT_CLIENT ((BYTE) HIGHBIT(0)) // certified for client auth
|
|
#define SSLBIT_SERVER ((BYTE) HIGHBIT(1)) // certified for server auth
|
|
#define SSLBIT_SMIME ((BYTE) HIGHBIT(2)) // certified for S/MIME
|
|
#define SSLBIT_SIGN ((BYTE) HIGHBIT(3)) // certified for signing
|
|
|
|
#define SSLBIT_RESERVED ((BYTE) HIGHBIT(4)) // reserved for future use
|
|
|
|
#define SSLBIT_CASSL ((BYTE) HIGHBIT(5)) // CA for SSL auth certs
|
|
#define SSLBIT_CASMIME ((BYTE) HIGHBIT(6)) // CA for S/MIME certs
|
|
#define SSLBIT_CASIGN ((BYTE) HIGHBIT(7)) // CA for signing certs
|
|
|
|
#define NSCERTTYPE_CLIENT ((BYTE) SSLBIT_CLIENT)
|
|
#define NSCERTTYPE_SERVER ((BYTE) (SSLBIT_SERVER | SSLBIT_CLIENT))
|
|
#define NSCERTTYPE_SMIME ((BYTE) SSLBIT_SMIME)
|
|
#define NSCERTTYPE_CA ((BYTE) (SSLBIT_CASSL | SSLBIT_CASMIME | SSLBIT_CASIGN))
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_AddOldCertTypeExtension
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_AddOldCertTypeExtension(
|
|
IN ICertServerPolicy *pServer,
|
|
IN BOOL fCA)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ICertEncodeBitString *pBitString = NULL;
|
|
BSTR strExtension = NULL;
|
|
VARIANT varExtension;
|
|
BSTR strBitString = NULL;
|
|
BSTR strCertType = NULL;
|
|
CERT_BASIC_CONSTRAINTS2_INFO Constraints;
|
|
VARIANT varConstraints;
|
|
DWORD cb;
|
|
|
|
VariantInit(&varConstraints);
|
|
|
|
if (EDITF_ADDOLDCERTTYPE & m_dwEditFlags)
|
|
{
|
|
BYTE CertType;
|
|
|
|
if (!fCA)
|
|
{
|
|
hr = polGetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_BASIC_CONSTRAINTS2),
|
|
PROPTYPE_BINARY,
|
|
&varConstraints);
|
|
if (S_OK == hr)
|
|
{
|
|
cb = sizeof(Constraints);
|
|
if (!CryptDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
(BYTE const *) varConstraints.bstrVal,
|
|
SysStringByteLen(varConstraints.bstrVal),
|
|
0,
|
|
&Constraints,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:CryptDecodeObject");
|
|
}
|
|
fCA = Constraints.fCA;
|
|
}
|
|
}
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_CCertEncodeBitString,
|
|
NULL, // pUnkOuter
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ICertEncodeBitString,
|
|
(VOID **) &pBitString);
|
|
_JumpIfError(hr, error, "Policy:CoCreateInstance");
|
|
|
|
CertType = NSCERTTYPE_CLIENT; // Default to client auth. cert
|
|
if (fCA)
|
|
{
|
|
CertType = NSCERTTYPE_CA;
|
|
}
|
|
else
|
|
{
|
|
hr = polGetRequestAttribute(pServer, wszPROPCERTTYPE, &strCertType);
|
|
if (S_OK == hr)
|
|
{
|
|
if (0 == LSTRCMPIS(strCertType, L"server"))
|
|
{
|
|
CertType = NSCERTTYPE_SERVER;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!myConvertWszToBstr(
|
|
&strBitString,
|
|
(WCHAR const *) &CertType,
|
|
sizeof(CertType)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
|
|
hr = pBitString->Encode(
|
|
sizeof(CertType) * 8,
|
|
strBitString,
|
|
&strExtension);
|
|
_JumpIfError(hr, error, "Policy:BitString:Encode");
|
|
|
|
varExtension.vt = VT_BSTR;
|
|
varExtension.bstrVal = strExtension;
|
|
hr = polSetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_NETSCAPE_CERT_TYPE),
|
|
PROPTYPE_BINARY,
|
|
0,
|
|
&varExtension);
|
|
_JumpIfError(hr, error, "Policy:polSetCertificateExtension");
|
|
}
|
|
|
|
error:
|
|
VariantClear(&varConstraints);
|
|
if (NULL != strExtension)
|
|
{
|
|
SysFreeString(strExtension);
|
|
}
|
|
if (NULL != strBitString)
|
|
{
|
|
SysFreeString(strBitString);
|
|
}
|
|
if (NULL != strCertType)
|
|
{
|
|
SysFreeString(strCertType);
|
|
}
|
|
if (NULL != pBitString)
|
|
{
|
|
pBitString->Release();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_AddAuthorityKeyId
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_AddAuthorityKeyId(
|
|
IN ICertServerPolicy *pServer)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BYTE *pbEncoded = NULL;
|
|
DWORD cbEncoded;
|
|
BSTR strExtension = NULL;
|
|
VARIANT varExtension;
|
|
VARIANT varExtensionT;
|
|
PCERT_AUTHORITY_KEY_ID2_INFO pInfo = NULL;
|
|
DWORD cbInfo = 0;
|
|
LONG ExtFlags = 0;
|
|
|
|
VariantInit(&varExtension);
|
|
|
|
// Optimization
|
|
|
|
if ((EDITF_ENABLEAKIKEYID |
|
|
EDITF_ENABLEAKIISSUERNAME |
|
|
EDITF_ENABLEAKIISSUERSERIAL) ==
|
|
((EDITF_ENABLEAKIKEYID |
|
|
EDITF_ENABLEAKIISSUERNAME |
|
|
EDITF_ENABLEAKIISSUERSERIAL |
|
|
EDITF_ENABLEAKICRITICAL) & m_dwEditFlags))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
hr = polGetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_AUTHORITY_KEY_IDENTIFIER2),
|
|
PROPTYPE_BINARY,
|
|
&varExtension);
|
|
_JumpIfError(hr, error, "Policy:polGetCertificateExtension");
|
|
|
|
hr = pServer->GetCertificateExtensionFlags(&ExtFlags);
|
|
_JumpIfError(hr, error, "Policy:GetCertificateExtensionFlags");
|
|
|
|
if (VT_BSTR != varExtension.vt)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Policy:GetCertificateExtension");
|
|
}
|
|
|
|
cbInfo = 0;
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_AUTHORITY_KEY_ID2,
|
|
(BYTE *) varExtension.bstrVal,
|
|
SysStringByteLen(varExtension.bstrVal),
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pInfo,
|
|
&cbInfo))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "Policy:myDecodeObject");
|
|
}
|
|
|
|
// Make Any Modifications Here
|
|
|
|
if (0 == (EDITF_ENABLEAKIKEYID & m_dwEditFlags))
|
|
{
|
|
pInfo->KeyId.cbData = 0;
|
|
pInfo->KeyId.pbData = NULL;
|
|
}
|
|
if (0 == (EDITF_ENABLEAKIISSUERNAME & m_dwEditFlags))
|
|
{
|
|
pInfo->AuthorityCertIssuer.cAltEntry = 0;
|
|
pInfo->AuthorityCertIssuer.rgAltEntry = NULL;
|
|
}
|
|
if (0 == (EDITF_ENABLEAKIISSUERSERIAL & m_dwEditFlags))
|
|
{
|
|
pInfo->AuthorityCertSerialNumber.cbData = 0;
|
|
pInfo->AuthorityCertSerialNumber.pbData = NULL;
|
|
}
|
|
if (EDITF_ENABLEAKICRITICAL & m_dwEditFlags)
|
|
{
|
|
ExtFlags |= EXTENSION_CRITICAL_FLAG;
|
|
}
|
|
if (0 ==
|
|
((EDITF_ENABLEAKIKEYID |
|
|
EDITF_ENABLEAKIISSUERNAME |
|
|
EDITF_ENABLEAKIISSUERSERIAL) & m_dwEditFlags))
|
|
{
|
|
ExtFlags |= EXTENSION_DISABLE_FLAG;
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_AUTHORITY_KEY_ID2,
|
|
pInfo,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbEncoded,
|
|
&cbEncoded))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
if (!myConvertWszToBstr(
|
|
&strExtension,
|
|
(WCHAR const *) pbEncoded,
|
|
cbEncoded))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
|
|
varExtensionT.vt = VT_BSTR;
|
|
varExtensionT.bstrVal = strExtension;
|
|
hr = polSetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_AUTHORITY_KEY_IDENTIFIER2),
|
|
PROPTYPE_BINARY,
|
|
ExtFlags,
|
|
&varExtensionT);
|
|
_JumpIfError(hr, error, "Policy:polSetCertificateExtension(AuthorityKeyId2)");
|
|
|
|
error:
|
|
VariantClear(&varExtension);
|
|
if (NULL != pInfo)
|
|
{
|
|
LocalFree(pInfo);
|
|
}
|
|
if (NULL != pbEncoded)
|
|
{
|
|
LocalFree(pbEncoded);
|
|
}
|
|
if (NULL != strExtension)
|
|
{
|
|
SysFreeString(strExtension);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicy::_AddDefaultKeyUsageExtension
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_AddDefaultKeyUsageExtension(
|
|
IN ICertServerPolicy *pServer,
|
|
IN BOOL fCA)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strName = NULL;
|
|
ICertEncodeBitString *pBitString = NULL;
|
|
BSTR strExtension = NULL;
|
|
VARIANT varExtension;
|
|
BSTR strBitString = NULL;
|
|
CERT_BASIC_CONSTRAINTS2_INFO Constraints;
|
|
VARIANT varConstraints;
|
|
VARIANT varKeyUsage;
|
|
CRYPT_BIT_BLOB *pKeyUsage = NULL;
|
|
DWORD cb;
|
|
BYTE abKeyUsage[1];
|
|
BYTE *pbKeyUsage;
|
|
DWORD cbKeyUsage;
|
|
|
|
VariantInit(&varConstraints);
|
|
VariantInit(&varKeyUsage);
|
|
|
|
if (EDITF_ADDOLDKEYUSAGE & m_dwEditFlags)
|
|
{
|
|
BOOL fModified = FALSE;
|
|
|
|
if (!fCA)
|
|
{
|
|
hr = polGetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_BASIC_CONSTRAINTS2),
|
|
PROPTYPE_BINARY,
|
|
&varConstraints);
|
|
if (S_OK == hr)
|
|
{
|
|
cb = sizeof(Constraints);
|
|
if (!CryptDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
(BYTE const *) varConstraints.bstrVal,
|
|
SysStringByteLen(varConstraints.bstrVal),
|
|
0,
|
|
&Constraints,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:CryptDecodeObject");
|
|
}
|
|
fCA = Constraints.fCA;
|
|
}
|
|
}
|
|
|
|
ZeroMemory(abKeyUsage, sizeof(abKeyUsage));
|
|
pbKeyUsage = abKeyUsage;
|
|
cbKeyUsage = sizeof(abKeyUsage);
|
|
|
|
hr = polGetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_KEY_USAGE),
|
|
PROPTYPE_BINARY,
|
|
&varKeyUsage);
|
|
if (S_OK == hr)
|
|
{
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_KEY_USAGE,
|
|
(BYTE const *) varKeyUsage.bstrVal,
|
|
SysStringByteLen(varKeyUsage.bstrVal),
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pKeyUsage,
|
|
&cb))
|
|
{
|
|
hr = GetLastError();
|
|
_PrintError(hr, "Policy:myDecodeObject");
|
|
}
|
|
else if (0 != cb && NULL != pKeyUsage && 0 != pKeyUsage->cbData)
|
|
{
|
|
pbKeyUsage = pKeyUsage->pbData;
|
|
cbKeyUsage = pKeyUsage->cbData;
|
|
}
|
|
}
|
|
|
|
if ((CERT_KEY_ENCIPHERMENT_KEY_USAGE & pbKeyUsage[0]) &&
|
|
(CERT_KEY_AGREEMENT_KEY_USAGE & pbKeyUsage[0]))
|
|
{
|
|
pbKeyUsage[0] &= ~CERT_KEY_AGREEMENT_KEY_USAGE;
|
|
pbKeyUsage[0] |= CERT_DIGITAL_SIGNATURE_KEY_USAGE;
|
|
fModified = TRUE;
|
|
}
|
|
if (fCA)
|
|
{
|
|
pbKeyUsage[0] |= myCASIGN_KEY_USAGE;
|
|
fModified = TRUE;
|
|
}
|
|
if (fModified)
|
|
{
|
|
hr = CoCreateInstance(
|
|
CLSID_CCertEncodeBitString,
|
|
NULL, // pUnkOuter
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ICertEncodeBitString,
|
|
(VOID **) &pBitString);
|
|
_JumpIfError(hr, error, "Policy:CoCreateInstance");
|
|
|
|
if (!myConvertWszToBstr(
|
|
&strBitString,
|
|
(WCHAR const *) pbKeyUsage,
|
|
cbKeyUsage))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
|
|
hr = pBitString->Encode(cbKeyUsage * 8, strBitString, &strExtension);
|
|
_JumpIfError(hr, error, "Policy:Encode");
|
|
|
|
if (!myConvertWszToBstr(&strName, TEXT(szOID_KEY_USAGE), -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
varExtension.vt = VT_BSTR;
|
|
varExtension.bstrVal = strExtension;
|
|
hr = pServer->SetCertificateExtension(
|
|
strName,
|
|
PROPTYPE_BINARY,
|
|
0,
|
|
&varExtension);
|
|
_JumpIfError(hr, error, "Policy:SetCertificateExtension");
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
VariantClear(&varConstraints);
|
|
VariantClear(&varKeyUsage);
|
|
if (NULL != pKeyUsage)
|
|
{
|
|
LocalFree(pKeyUsage);
|
|
}
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
if (NULL != strExtension)
|
|
{
|
|
SysFreeString(strExtension);
|
|
}
|
|
if (NULL != strBitString)
|
|
{
|
|
SysFreeString(strBitString);
|
|
}
|
|
if (NULL != pBitString)
|
|
{
|
|
pBitString->Release();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_AddEnhancedKeyUsageExtension(
|
|
IN ICertServerPolicy *pServer)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strUsage = NULL;
|
|
char *pszUsage = NULL;
|
|
char *psz;
|
|
char *pszNext;
|
|
CERT_ENHKEY_USAGE ceu;
|
|
CERT_POLICIES_INFO cpi;
|
|
BYTE *pbKeyUsage = NULL;
|
|
DWORD cbKeyUsage;
|
|
BYTE *pbPolicies = NULL;
|
|
DWORD cbPolicies;
|
|
CERT_POLICY_INFO *pcpi = NULL;
|
|
DWORD i;
|
|
VARIANT varExtension;
|
|
|
|
ZeroMemory(&ceu, sizeof(ceu));
|
|
ZeroMemory(&cpi, sizeof(cpi));
|
|
VariantInit(&varExtension);
|
|
|
|
if (0 == (EDITF_ATTRIBUTEEKU & m_dwEditFlags))
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
hr = polGetRequestAttribute(pServer, wszPROPCERTUSAGE, &strUsage);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
if (!myConvertWszToSz(&pszUsage, strUsage, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToSz");
|
|
}
|
|
for (psz = pszUsage; '\0' != *psz; psz = pszNext)
|
|
{
|
|
pszNext = &psz[strcspn(psz, ",")];
|
|
if ('\0' != *pszNext)
|
|
{
|
|
pszNext++;
|
|
}
|
|
ceu.cUsageIdentifier++;
|
|
}
|
|
if (0 == ceu.cUsageIdentifier)
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
|
|
ceu.rgpszUsageIdentifier = (char **) LocalAlloc(
|
|
LMEM_FIXED,
|
|
ceu.cUsageIdentifier * sizeof(ceu.rgpszUsageIdentifier[0]));
|
|
if (NULL == ceu.rgpszUsageIdentifier)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myLocalAlloc");
|
|
}
|
|
|
|
// Destructively parse comma separated ObjIds into individual strings
|
|
|
|
i = 0;
|
|
for (psz = pszUsage; '\0' != *psz; psz = pszNext)
|
|
{
|
|
char *pszEnd;
|
|
|
|
CSASSERT(i < ceu.cUsageIdentifier);
|
|
pszNext = &psz[strcspn(psz, ",")];
|
|
pszEnd = pszNext;
|
|
if ('\0' != *pszNext)
|
|
{
|
|
*pszNext++ = '\0';
|
|
}
|
|
while (' ' == *psz)
|
|
{
|
|
psz++;
|
|
}
|
|
while (pszEnd > psz && ' ' == *--pszEnd)
|
|
{
|
|
*pszEnd = '\0';
|
|
}
|
|
if ('\0' != *psz)
|
|
{
|
|
hr = myVerifyObjIdA(psz);
|
|
_JumpIfError(hr, error, "Policy:myVerifyObjIdA");
|
|
|
|
ceu.rgpszUsageIdentifier[i++] = psz;
|
|
}
|
|
}
|
|
ceu.cUsageIdentifier = i;
|
|
if (0 == ceu.cUsageIdentifier)
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_ENHANCED_KEY_USAGE,
|
|
&ceu,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbKeyUsage,
|
|
&cbKeyUsage))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
|
|
varExtension.bstrVal = NULL;
|
|
if (!myConvertWszToBstr(
|
|
&varExtension.bstrVal,
|
|
(WCHAR const *) pbKeyUsage,
|
|
cbKeyUsage))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
varExtension.vt = VT_BSTR;
|
|
hr = polSetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_ENHANCED_KEY_USAGE),
|
|
PROPTYPE_BINARY,
|
|
0,
|
|
&varExtension);
|
|
_JumpIfError(hr, error, "Policy:polSetCertificateExtension");
|
|
|
|
cpi.cPolicyInfo = ceu.cUsageIdentifier;
|
|
cpi.rgPolicyInfo = (CERT_POLICY_INFO *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cpi.cPolicyInfo * sizeof(cpi.rgPolicyInfo[0]));
|
|
if (NULL == cpi.rgPolicyInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:LocalAlloc");
|
|
}
|
|
for (i = 0; i < cpi.cPolicyInfo; i++)
|
|
{
|
|
cpi.rgPolicyInfo[i].pszPolicyIdentifier = ceu.rgpszUsageIdentifier[i];
|
|
}
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_POLICIES,
|
|
&cpi,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbPolicies,
|
|
&cbPolicies))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
|
|
if (!myConvertWszToBstr(
|
|
&varExtension.bstrVal,
|
|
(WCHAR const *) pbPolicies,
|
|
cbPolicies))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
hr = polSetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_APPLICATION_CERT_POLICIES),
|
|
PROPTYPE_BINARY,
|
|
0,
|
|
&varExtension);
|
|
_JumpIfError(hr, error, "Policy:polSetCertificateExtension");
|
|
|
|
error:
|
|
if (NULL != pcpi)
|
|
{
|
|
LocalFree(pcpi);
|
|
}
|
|
VariantClear(&varExtension);
|
|
if (NULL != ceu.rgpszUsageIdentifier)
|
|
{
|
|
LocalFree(ceu.rgpszUsageIdentifier);
|
|
}
|
|
if (NULL != pbPolicies)
|
|
{
|
|
LocalFree(pbPolicies);
|
|
}
|
|
if (NULL != pbKeyUsage)
|
|
{
|
|
LocalFree(pbKeyUsage);
|
|
}
|
|
if (NULL != pszUsage)
|
|
{
|
|
LocalFree(pszUsage);
|
|
}
|
|
if (NULL != strUsage)
|
|
{
|
|
SysFreeString(strUsage);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicy::_AddDefaultBasicConstraintsExtension
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_AddDefaultBasicConstraintsExtension(
|
|
IN ICertServerPolicy *pServer,
|
|
IN BOOL fCA)
|
|
{
|
|
HRESULT hr;
|
|
VARIANT varExtension;
|
|
LONG ExtFlags;
|
|
CERT_EXTENSION Ext;
|
|
CERT_EXTENSION *pExtension = NULL;
|
|
BSTR strCertType = NULL;
|
|
|
|
VariantInit(&varExtension);
|
|
|
|
if (EDITF_BASICCONSTRAINTSCA & m_dwEditFlags)
|
|
{
|
|
hr = polGetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_BASIC_CONSTRAINTS2),
|
|
PROPTYPE_BINARY,
|
|
&varExtension);
|
|
if (S_OK == hr)
|
|
{
|
|
CERT_BASIC_CONSTRAINTS2_INFO Constraints;
|
|
DWORD cb;
|
|
|
|
hr = pServer->GetCertificateExtensionFlags(&ExtFlags);
|
|
if (S_OK == hr)
|
|
{
|
|
Ext.pszObjId = szOID_BASIC_CONSTRAINTS2;
|
|
Ext.fCritical = FALSE;
|
|
if (EXTENSION_CRITICAL_FLAG & ExtFlags)
|
|
{
|
|
Ext.fCritical = TRUE;
|
|
}
|
|
Ext.Value.pbData = (BYTE *) varExtension.bstrVal;
|
|
Ext.Value.cbData = SysStringByteLen(varExtension.bstrVal);
|
|
pExtension = &Ext;
|
|
|
|
cb = sizeof(Constraints);
|
|
if (!fCA && CryptDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
Ext.Value.pbData,
|
|
Ext.Value.cbData,
|
|
0,
|
|
&Constraints,
|
|
&cb))
|
|
{
|
|
fCA = Constraints.fCA;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (EDITF_ATTRIBUTECA & m_dwEditFlags)
|
|
{
|
|
if (!fCA)
|
|
{
|
|
hr = polGetRequestAttribute(pServer, wszPROPCERTTYPE, &strCertType);
|
|
if (S_OK == hr)
|
|
{
|
|
if (0 == LSTRCMPIS(strCertType, L"ca"))
|
|
{
|
|
fCA = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (!fCA)
|
|
{
|
|
hr = polGetRequestAttribute(pServer, wszPROPCERTTEMPLATE, &strCertType);
|
|
if (S_OK == hr)
|
|
{
|
|
if (0 == LSTRCMPIS(strCertType, wszCERTTYPE_SUBORDINATE_CA) ||
|
|
0 == LSTRCMPIS(strCertType, wszCERTTYPE_CROSS_CA))
|
|
{
|
|
fCA = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// For standalone, the extension is only enabled if it's a CA
|
|
|
|
hr = AddBasicConstraintsCommon(pServer, pExtension, fCA, fCA);
|
|
_JumpIfError(hr, error, "Policy:AddBasicConstraintsCommon");
|
|
|
|
error:
|
|
VariantClear(&varExtension);
|
|
if (NULL != strCertType)
|
|
{
|
|
SysFreeString(strCertType);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::AddBasicConstraintsCommon(
|
|
IN ICertServerPolicy *pServer,
|
|
IN CERT_EXTENSION const *pExtension,
|
|
IN BOOL fCA,
|
|
IN BOOL fEnableExtension)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strExtension = NULL;
|
|
VARIANT varExtension;
|
|
CERT_CONTEXT const *pIssuerCert;
|
|
CERT_EXTENSION *pIssuerExtension;
|
|
LONG ExtFlags = 0;
|
|
BYTE *pbConstraints = NULL;
|
|
CERT_BASIC_CONSTRAINTS2_INFO Constraints;
|
|
CERT_BASIC_CONSTRAINTS2_INFO IssuerConstraints;
|
|
ZeroMemory(&IssuerConstraints, sizeof(IssuerConstraints));
|
|
|
|
DWORD cb;
|
|
|
|
pIssuerCert = _GetIssuer(pServer);
|
|
if (NULL == pIssuerCert)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "_GetIssuer");
|
|
}
|
|
|
|
if (NULL != pExtension)
|
|
{
|
|
cb = sizeof(Constraints);
|
|
if (!CryptDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
pExtension->Value.pbData,
|
|
pExtension->Value.cbData,
|
|
0,
|
|
&Constraints,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:CryptDecodeObject");
|
|
}
|
|
|
|
// Cert templates use CAPATHLENGTH_INFINITE to indicate
|
|
// fPathLenConstraint should be FALSE.
|
|
|
|
if (CAPATHLENGTH_INFINITE == Constraints.dwPathLenConstraint)
|
|
{
|
|
|
|
// NOTE: This is ok as certcli already sets fPathLenConstraint to FALSE
|
|
// for templates in this case.
|
|
Constraints.fPathLenConstraint = FALSE;
|
|
|
|
// NOTE: This is ok as autoenrollment ignores dwPathLenConstraint
|
|
// if fPathLenConstraint is FALSE;
|
|
Constraints.dwPathLenConstraint = 0;
|
|
}
|
|
if (pExtension->fCritical)
|
|
{
|
|
ExtFlags = EXTENSION_CRITICAL_FLAG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Constraints.fCA = fCA;
|
|
Constraints.fPathLenConstraint = FALSE;
|
|
Constraints.dwPathLenConstraint = 0;
|
|
}
|
|
if (EDITF_BASICCONSTRAINTSCRITICAL & m_dwEditFlags)
|
|
{
|
|
ExtFlags = EXTENSION_CRITICAL_FLAG;
|
|
}
|
|
|
|
// Check basic constraints against the issuer's cert.
|
|
|
|
pIssuerExtension = CertFindExtension(
|
|
szOID_BASIC_CONSTRAINTS2,
|
|
pIssuerCert->pCertInfo->cExtension,
|
|
pIssuerCert->pCertInfo->rgExtension);
|
|
if (NULL != pIssuerExtension)
|
|
{
|
|
cb = sizeof(IssuerConstraints);
|
|
if (!CryptDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
pIssuerExtension->Value.pbData,
|
|
pIssuerExtension->Value.cbData,
|
|
0,
|
|
&IssuerConstraints,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:CryptDecodeObject");
|
|
}
|
|
if (!IssuerConstraints.fCA)
|
|
{
|
|
hr = CERTSRV_E_INVALID_CA_CERTIFICATE;
|
|
_JumpError(hr, error, "Policy:CA cert not a CA cert");
|
|
}
|
|
}
|
|
|
|
if (Constraints.fCA)
|
|
{
|
|
if (IssuerConstraints.fPathLenConstraint)
|
|
{
|
|
if (0 == IssuerConstraints.dwPathLenConstraint)
|
|
{
|
|
hr = CERTSRV_E_INVALID_CA_CERTIFICATE;
|
|
_JumpError(hr, error, "Policy:CA cert is a leaf CA cert");
|
|
}
|
|
if (!Constraints.fPathLenConstraint ||
|
|
Constraints.dwPathLenConstraint >
|
|
IssuerConstraints.dwPathLenConstraint - 1)
|
|
{
|
|
Constraints.fPathLenConstraint = TRUE;
|
|
Constraints.dwPathLenConstraint =
|
|
IssuerConstraints.dwPathLenConstraint - 1;
|
|
}
|
|
}
|
|
if (CAPATHLENGTH_INFINITE != m_CAPathLength)
|
|
{
|
|
if (0 == m_CAPathLength)
|
|
{
|
|
hr = CERTSRV_E_INVALID_CA_CERTIFICATE;
|
|
_JumpError(hr, error, "Policy:Registry says not to issue CA certs");
|
|
}
|
|
if (!Constraints.fPathLenConstraint ||
|
|
Constraints.dwPathLenConstraint > m_CAPathLength - 1)
|
|
{
|
|
Constraints.fPathLenConstraint = TRUE;
|
|
Constraints.dwPathLenConstraint = m_CAPathLength - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fEnableExtension)
|
|
{
|
|
ExtFlags |= EXTENSION_DISABLE_FLAG;
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
&Constraints,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbConstraints,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
|
|
if (!myConvertWszToBstr(
|
|
&strExtension,
|
|
(WCHAR const *) pbConstraints,
|
|
cb))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
|
|
varExtension.vt = VT_BSTR;
|
|
varExtension.bstrVal = strExtension;
|
|
hr = polSetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_BASIC_CONSTRAINTS2),
|
|
PROPTYPE_BINARY,
|
|
ExtFlags,
|
|
&varExtension);
|
|
_JumpIfError(hr, error, "Policy:polSetCertificateExtension");
|
|
|
|
error:
|
|
if (NULL != pbConstraints)
|
|
{
|
|
LocalFree(pbConstraints);
|
|
}
|
|
if (NULL != strExtension)
|
|
{
|
|
SysFreeString(strExtension);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicy::_SetValidityPeriod
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_SetValidityPeriod(
|
|
IN ICertServerPolicy *pServer)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strPeriodString = NULL;
|
|
BSTR strPeriodCount = NULL;
|
|
BSTR strNameNotBefore = NULL;
|
|
BSTR strNameNotAfter = NULL;
|
|
VARIANT varValue;
|
|
LONG lDelta;
|
|
ENUM_PERIOD enumValidityPeriod;
|
|
BOOL fValidDigitString;
|
|
|
|
VariantInit(&varValue);
|
|
|
|
if (!(EDITF_ATTRIBUTEENDDATE & m_dwEditFlags))
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
|
|
hr = polGetRequestAttribute(
|
|
pServer,
|
|
wszPROPVALIDITYPERIODSTRING,
|
|
&strPeriodString);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"Policy:polGetRequestAttribute",
|
|
wszPROPVALIDITYPERIODSTRING,
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
goto error;
|
|
}
|
|
|
|
hr = polGetRequestAttribute(
|
|
pServer,
|
|
wszPROPVALIDITYPERIODCOUNT,
|
|
&strPeriodCount);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"Policy:polGetRequestAttribute",
|
|
wszPROPVALIDITYPERIODCOUNT,
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
goto error;
|
|
}
|
|
|
|
// Swap Count and String BSTRs if backwards -- Windows 2000 had it wrong.
|
|
|
|
lDelta = myWtoI(strPeriodCount, &fValidDigitString);
|
|
if (!fValidDigitString)
|
|
{
|
|
BSTR str = strPeriodCount;
|
|
|
|
strPeriodCount = strPeriodString;
|
|
strPeriodString = str;
|
|
|
|
lDelta = myWtoI(strPeriodCount, &fValidDigitString);
|
|
if (!fValidDigitString)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "Policy:myWtoI");
|
|
}
|
|
}
|
|
|
|
hr = myTranslatePeriodUnits(strPeriodString, lDelta, &enumValidityPeriod, &lDelta);
|
|
_JumpIfError(hr, error, "Policy:myTranslatePeriodUnits");
|
|
|
|
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");
|
|
|
|
hr = myMakeExprDate(&varValue.date, lDelta, enumValidityPeriod);
|
|
_JumpIfError(hr, error, "Policy:myMakeExprDate");
|
|
|
|
strNameNotAfter = SysAllocString(wszPROPCERTIFICATENOTAFTERDATE);
|
|
if (NULL == strNameNotAfter)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
hr = pServer->SetCertificateProperty(
|
|
strNameNotAfter,
|
|
PROPTYPE_DATE,
|
|
&varValue);
|
|
_JumpIfError(hr, error, "Policy:SetCertificateProperty");
|
|
|
|
hr = S_OK;
|
|
|
|
error:
|
|
VariantClear(&varValue);
|
|
if (NULL != strPeriodString)
|
|
{
|
|
SysFreeString(strPeriodString);
|
|
}
|
|
if (NULL != strPeriodCount)
|
|
{
|
|
SysFreeString(strPeriodCount);
|
|
}
|
|
if (NULL != strNameNotBefore)
|
|
{
|
|
SysFreeString(strNameNotBefore);
|
|
}
|
|
if (NULL != strNameNotAfter)
|
|
{
|
|
SysFreeString(strNameNotAfter);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
// end_sdksample
|
|
|
|
|
|
HRESULT
|
|
polBuildErrorInfo(
|
|
IN HRESULT hrLog,
|
|
IN DWORD dwLogId,
|
|
IN WCHAR const *pwszDescription,
|
|
OPTIONAL IN WCHAR const * const *ppwszInsert,
|
|
IN OUT ICreateErrorInfo **ppCreateErrorInfo)
|
|
{
|
|
HRESULT hr;
|
|
ICreateErrorInfo *pCreateErrorInfo = NULL;
|
|
|
|
CSASSERT(NULL != pwszDescription);
|
|
hr = ::LogModuleStatus(
|
|
g_hInstance,
|
|
hrLog,
|
|
dwLogId,
|
|
TRUE,
|
|
pwszDescription,
|
|
ppwszInsert,
|
|
&pCreateErrorInfo);
|
|
_JumpIfError(hr, error, "LogModuleStatus");
|
|
|
|
if (NULL != *ppCreateErrorInfo)
|
|
{
|
|
(*ppCreateErrorInfo)->Release();
|
|
}
|
|
*ppCreateErrorInfo = pCreateErrorInfo;
|
|
pCreateErrorInfo = NULL;
|
|
|
|
error:
|
|
if (NULL != pCreateErrorInfo)
|
|
{
|
|
pCreateErrorInfo->Release();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// make a binary BSTR from Base64 string (or Encode UTF8 string)
|
|
|
|
HRESULT
|
|
polReencodeBinary(
|
|
IN OUT BSTR *pstr)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbOut = NULL;
|
|
DWORD cbOut;
|
|
BSTR strOut;
|
|
|
|
hr = myEncodeOtherNameBinary(*pstr, &pbOut, &cbOut);
|
|
_JumpIfError(hr, error, "Policy:myEncodeOtherNameBinary");
|
|
|
|
strOut = NULL;
|
|
if (!myConvertWszToBstr(&strOut, (WCHAR const *) pbOut, cbOut))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "myConvertWszToBstr");
|
|
}
|
|
SysFreeString(*pstr);
|
|
*pstr = strOut;
|
|
|
|
error:
|
|
if (NULL != pbOut)
|
|
{
|
|
LocalFree(pbOut);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// make a binary BSTR (Encode a UTF8 string)
|
|
|
|
HRESULT
|
|
polReencodeUTF8(
|
|
IN OUT BSTR *pstr)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbOut = NULL;
|
|
DWORD cbOut;
|
|
BSTR strOut;
|
|
|
|
hr = myEncodeUTF8(*pstr, &pbOut, &cbOut);
|
|
_JumpIfError(hr, error, "Policy:myEncodeUTF8");
|
|
|
|
strOut = NULL;
|
|
if (!myConvertWszToBstr(&strOut, (WCHAR const *) pbOut, cbOut))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "myConvertWszToBstr");
|
|
}
|
|
SysFreeString(*pstr);
|
|
*pstr = strOut;
|
|
|
|
error:
|
|
if (NULL != pbOut)
|
|
{
|
|
LocalFree(pbOut);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polReencodeIPAddress(
|
|
IN OUT BSTR *pstr)
|
|
{
|
|
HRESULT hr;
|
|
BYTE abOut[CB_IPV6ADDRESS];
|
|
DWORD cbOut;
|
|
BSTR strOut;
|
|
|
|
cbOut = sizeof(abOut);
|
|
hr = myParseIPAddress(*pstr, abOut, &cbOut);
|
|
_JumpIfError(hr, error, "Policy:myParseIPAddress");
|
|
|
|
CSASSERT(CB_IPV4ADDRESS == cbOut || CB_IPV6ADDRESS == cbOut);
|
|
|
|
strOut = NULL;
|
|
if (!myConvertWszToBstr(&strOut, (WCHAR const *) abOut, cbOut))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "myConvertWszToBstr");
|
|
}
|
|
SysFreeString(*pstr);
|
|
*pstr = strOut;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// polReencodeGUID -- translate a stringized GUID to a binary GUID encoded with
|
|
// an OCTET string wrapper.
|
|
//
|
|
// Input string: "{f7c3ac41-b8ce-4fb4-aa58-3d1dc0e36b39}" (braces are optional)
|
|
//---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
polReencodeGUID(
|
|
IN OUT BSTR *pstr)
|
|
{
|
|
HRESULT hr;
|
|
GUID guid;
|
|
CRYPT_DATA_BLOB blob;
|
|
BYTE *pbOut = NULL;
|
|
DWORD cbOut;
|
|
BSTR strOut;
|
|
WCHAR *pwszAlloc = NULL;
|
|
WCHAR *pwsz;
|
|
|
|
pwsz = *pstr;
|
|
if (wcLBRACE != *pwsz)
|
|
{
|
|
DWORD cwc = wcslen(pwsz) + 2;
|
|
|
|
pwszAlloc = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
|
|
if (NULL == pwszAlloc)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:LocalAlloc");
|
|
}
|
|
*pwszAlloc = wcLBRACE;
|
|
wcscpy(&pwszAlloc[1], pwsz);
|
|
wcscat(pwszAlloc, wszRBRACE);
|
|
pwsz = pwszAlloc;
|
|
}
|
|
|
|
hr = CLSIDFromString(pwsz, &guid);
|
|
_JumpIfErrorStr(hr, error, "CLSIDFromString", pwsz);
|
|
|
|
blob.pbData = (BYTE *) &guid;
|
|
blob.cbData = sizeof(guid);
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_OCTET_STRING,
|
|
&blob,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbOut,
|
|
&cbOut))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
strOut = NULL;
|
|
if (!myConvertWszToBstr(&strOut, (WCHAR const *) pbOut, cbOut))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "myConvertWszToBstr");
|
|
}
|
|
SysFreeString(*pstr);
|
|
*pstr = strOut;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszAlloc)
|
|
{
|
|
LocalFree(pwszAlloc);
|
|
}
|
|
if (NULL != pbOut)
|
|
{
|
|
LocalFree(pbOut);
|
|
}
|
|
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 |
|
|
CERT_NAME_STR_REVERSE_FLAG |
|
|
CERT_NAME_STR_NO_PLUS_FLAG |
|
|
CERT_NAME_STR_COMMA_FLAG,
|
|
NULL, // pvReserved
|
|
NULL, // pbEncoded
|
|
&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 |
|
|
CERT_NAME_STR_REVERSE_FLAG |
|
|
CERT_NAME_STR_NO_PLUS_FLAG |
|
|
CERT_NAME_STR_COMMA_FLAG,
|
|
NULL, // pvReserved
|
|
pName->pbData,
|
|
&pName->cbData,
|
|
&pwszError))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:CertStrToName");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polReencodeDN(
|
|
IN OUT BSTR *pstr)
|
|
{
|
|
HRESULT hr;
|
|
CERT_NAME_BLOB Name = { 0, NULL };
|
|
BSTR strOut;
|
|
|
|
hr = myCertStrToName(*pstr, &Name);
|
|
_JumpIfError(hr, error, "Policy:myCertStrToName");
|
|
|
|
strOut = NULL;
|
|
if (!myConvertWszToBstr(&strOut, (WCHAR const *) Name.pbData, Name.cbData))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "myConvertWszToBstr");
|
|
}
|
|
SysFreeString(*pstr);
|
|
*pstr = strOut;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != Name.pbData)
|
|
{
|
|
LocalFree(Name.pbData);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
polSetAltNameEntry(
|
|
IN ICertEncodeAltName *pAltName,
|
|
IN DWORD iName,
|
|
IN WCHAR const *pwszName,
|
|
IN WCHAR const *pwszValue)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strT = NULL;
|
|
BSTR strT2 = NULL;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"Policy:polSetAltNameEntry[%u]: %ws = %ws\n",
|
|
iName,
|
|
pwszName,
|
|
pwszValue));
|
|
if (!myConvertWszToBstr(&strT, pwszValue, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
if (iswdigit(pwszName[0])) // Other name...
|
|
{
|
|
hr = myVerifyObjId(pwszName);
|
|
_JumpIfError(hr, error, "Policy:myVerifyObjId");
|
|
|
|
if (!myConvertWszToBstr(&strT2, pwszName, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
hr = pAltName->SetNameEntry(
|
|
EAN_NAMEOBJECTID | iName,
|
|
CERT_ALT_NAME_OTHER_NAME,
|
|
strT2);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
|
|
// Binary BSTR (from Base64 or possible Encoded UTF8 string):
|
|
|
|
hr = polReencodeBinary(&strT);
|
|
_JumpIfError(hr, error, "Policy:polReencodeBinary");
|
|
|
|
hr = pAltName->SetNameEntry(
|
|
iName,
|
|
CERT_ALT_NAME_OTHER_NAME,
|
|
strT);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszName, wszPROPUPN))
|
|
{
|
|
strT2 = SysAllocString(TEXT(szOID_NT_PRINCIPAL_NAME));
|
|
if (NULL == strT2)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
hr = pAltName->SetNameEntry(
|
|
EAN_NAMEOBJECTID | iName,
|
|
CERT_ALT_NAME_OTHER_NAME,
|
|
strT2);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
|
|
// Binary BSTR (Encoded UTF8 string):
|
|
|
|
hr = polReencodeUTF8(&strT);
|
|
_JumpIfError(hr, error, "Policy:polReencodeUTF8");
|
|
|
|
hr = pAltName->SetNameEntry(
|
|
iName,
|
|
CERT_ALT_NAME_OTHER_NAME,
|
|
strT);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszName, wszPROPGUID))
|
|
{
|
|
strT2 = SysAllocString(TEXT(szOID_NTDS_REPLICATION));
|
|
if (NULL == strT2)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
hr = pAltName->SetNameEntry(
|
|
EAN_NAMEOBJECTID | iName,
|
|
CERT_ALT_NAME_OTHER_NAME,
|
|
strT2);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
|
|
// Binary BSTR (Encoded UTF8 string):
|
|
|
|
hr = polReencodeGUID(&strT);
|
|
_JumpIfError(hr, error, "Policy:polReencodeUTF8");
|
|
|
|
hr = pAltName->SetNameEntry(
|
|
iName,
|
|
CERT_ALT_NAME_OTHER_NAME,
|
|
strT);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszName, wszPROPEMAIL))
|
|
{
|
|
hr = pAltName->SetNameEntry(
|
|
iName,
|
|
CERT_ALT_NAME_RFC822_NAME,
|
|
strT);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszName, wszPROPDNS))
|
|
{
|
|
hr = pAltName->SetNameEntry(
|
|
iName,
|
|
CERT_ALT_NAME_DNS_NAME,
|
|
strT);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszName, wszPROPDN))
|
|
{
|
|
// Binary BSTR (from DN string):
|
|
|
|
hr = polReencodeDN(&strT);
|
|
_JumpIfError(hr, error, "Policy:polReencodeDN");
|
|
|
|
hr = pAltName->SetNameEntry(
|
|
iName,
|
|
CERT_ALT_NAME_DIRECTORY_NAME,
|
|
strT);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszName, wszPROPURL))
|
|
{
|
|
hr = pAltName->SetNameEntry(
|
|
iName,
|
|
CERT_ALT_NAME_URL,
|
|
strT);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszName, wszPROPIPADDRESS))
|
|
{
|
|
// Binary BSTR (from IP Address string):
|
|
|
|
hr = polReencodeIPAddress(&strT);
|
|
_JumpIfError(hr, error, "Policy:polReencodeIPAddress");
|
|
|
|
hr = pAltName->SetNameEntry(
|
|
iName,
|
|
CERT_ALT_NAME_IP_ADDRESS,
|
|
strT);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
}
|
|
else if (0 == LSTRCMPIS(pwszName, wszPROPOID))
|
|
{
|
|
hr = pAltName->SetNameEntry(
|
|
iName,
|
|
CERT_ALT_NAME_REGISTERED_ID,
|
|
strT);
|
|
_JumpIfError(hr, error, "Policy:AltName:SetNameEntry");
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Policy:pwszName");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != strT)
|
|
{
|
|
SysFreeString(strT);
|
|
}
|
|
if (NULL != strT2)
|
|
{
|
|
SysFreeString(strT2);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_AddSubjectAltNameExtension
|
|
//
|
|
// SubjectAltName request attribute syntax example:
|
|
//
|
|
// SAN:1.2.3.4={asn}Base64String & ...
|
|
// or
|
|
// SAN:1.2.3.4={octet}Base64String & ...
|
|
// or
|
|
// SAN:1.2.3.4={utf8}UTF8String & ...
|
|
//
|
|
// Or:
|
|
//
|
|
// SAN:
|
|
// 1.2.3.4={asn}Base64String& (this is the OtherName mechanism)
|
|
// [email protected]&
|
|
// dns=foo.bar.com&
|
|
// dn="CN=xxx,OU=xxx,DC=xxx"&
|
|
// url="http://foo.com/default.htlm"&
|
|
// ipaddress=172.134.10.134&
|
|
// oid=1.2.3.4&
|
|
// [email protected]&
|
|
// guid=f7c3ac41-b8ce-4fb4-aa58-3d1dc0e36b39
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_AddSubjectAltNameExtension(
|
|
IN ICertServerPolicy *pServer,
|
|
IN DWORD iAltName)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strValue = NULL;
|
|
WCHAR *pwszDup = NULL;
|
|
ICertEncodeAltName *pAltName = NULL;
|
|
BSTR strExtension = NULL;
|
|
VARIANT varValue;
|
|
|
|
VariantInit(&varValue);
|
|
|
|
if (1 == iAltName && (EDITF_ATTRIBUTESUBJECTALTNAME2 & m_dwEditFlags))
|
|
{
|
|
hr = polGetRequestAttribute(pServer, wszPROPSUBJECTALTNAME2, &strValue);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"Policy:polGetRequestAttribute",
|
|
wszPROPSUBJECTALTNAME2,
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL == strValue && NULL != m_astrSubjectAltNameProp[iAltName])
|
|
{
|
|
hr = pServer->GetRequestProperty(
|
|
m_astrSubjectAltNameProp[iAltName],
|
|
PROPTYPE_STRING,
|
|
&varValue);
|
|
if (S_OK != hr)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"Policy:GetRequestProperty(%ws):%hs %x\n",
|
|
m_astrSubjectAltNameProp[iAltName],
|
|
CERTSRV_E_PROPERTY_EMPTY == hr? " MISSING ATTRIBUTE" : "",
|
|
hr));
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
_JumpErrorStr(
|
|
hr,
|
|
error,
|
|
"Policy:GetRequestProperty",
|
|
m_astrSubjectAltNameProp[iAltName]);
|
|
}
|
|
}
|
|
else if (VT_BSTR != varValue.vt)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Policy:varValue.vt");
|
|
}
|
|
if (VT_BSTR == varValue.vt && // could be empty
|
|
NULL != varValue.bstrVal &&
|
|
L'\0' != varValue.bstrVal[0])
|
|
{
|
|
DWORD cwc;
|
|
|
|
cwc = WSZARRAYSIZE(wszPROPEMAIL) + 3 + wcslen(varValue.bstrVal);
|
|
strValue = SysAllocStringLen(NULL, cwc);
|
|
if (NULL == strValue)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocStringLen");
|
|
}
|
|
wcscpy(strValue, wszPROPEMAIL);
|
|
wcscat(strValue, L"=\"");
|
|
wcscat(strValue, varValue.bstrVal);
|
|
wcscat(strValue, L"\"");
|
|
CSASSERT(SysStringByteLen(strValue) == wcslen(strValue) * sizeof(WCHAR));
|
|
}
|
|
}
|
|
if (NULL != strValue)
|
|
{
|
|
WCHAR *pwszT;
|
|
DWORD cName;
|
|
DWORD iName;
|
|
VARIANT varExtension;
|
|
|
|
hr = myDupString(strValue, &pwszDup);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
pwszT = pwszDup; // Destructively parse value
|
|
cName = 0;
|
|
while (TRUE)
|
|
{
|
|
WCHAR const *pwszName;
|
|
WCHAR const *pwszValue;
|
|
|
|
hr = myParseNextAttribute(&pwszT, TRUE, &pwszName, &pwszValue);
|
|
if (S_FALSE == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfError(hr, error, "myParseNextAttribute");
|
|
|
|
cName++;
|
|
}
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_CCertEncodeAltName,
|
|
NULL, // pUnkOuter
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ICertEncodeAltName,
|
|
(VOID **) &pAltName);
|
|
_JumpIfError(hr, error, "Policy:CoCreateInstance");
|
|
|
|
hr = pAltName->Reset(cName);
|
|
_JumpIfError(hr, error, "Policy:AltName:Reset");
|
|
|
|
pwszT = strValue; // Destructively parse value
|
|
for (iName = 0; ; iName++)
|
|
{
|
|
WCHAR const *pwszName;
|
|
WCHAR const *pwszValue;
|
|
|
|
hr = myParseNextAttribute(&pwszT, TRUE, &pwszName, &pwszValue);
|
|
if (S_FALSE == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfError(hr, error, "myParseNextAttribute");
|
|
|
|
hr = polSetAltNameEntry(pAltName, iName, pwszName, pwszValue);
|
|
_JumpIfError(hr, error, "polSetAltNameEntry");
|
|
}
|
|
CSASSERT(iName == cName);
|
|
|
|
hr = pAltName->Encode(&strExtension);
|
|
_JumpIfError(hr, error, "Policy:AltName:Encode");
|
|
|
|
myRegisterMemAlloc(strExtension, -1, CSM_SYSALLOC);
|
|
|
|
varExtension.vt = VT_BSTR;
|
|
varExtension.bstrVal = strExtension;
|
|
hr = pServer->SetCertificateExtension(
|
|
m_astrSubjectAltNameObjectId[iAltName],
|
|
PROPTYPE_BINARY,
|
|
0,
|
|
&varExtension);
|
|
_JumpIfError(hr, error, "Policy:SetCertificateExtension");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != strValue)
|
|
{
|
|
SysFreeString(strValue);
|
|
}
|
|
if (NULL != pwszDup)
|
|
{
|
|
LocalFree(pwszDup);
|
|
}
|
|
if (NULL != strExtension)
|
|
{
|
|
SysFreeString(strExtension);
|
|
}
|
|
if (NULL != pAltName)
|
|
{
|
|
pAltName->Release();
|
|
}
|
|
VariantClear(&varValue);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_PatchExchangeSubjectAltName
|
|
//
|
|
// If the request is for one of the Exchange templates, and if it contains an
|
|
// RFC822 entry and a Directory Name entry consisting solely of a single common
|
|
// name, strip out the common name entry. The common name entry was used for
|
|
// display purposes by Outlook, but it interferes with name constraints
|
|
// enforcement.
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_PatchExchangeSubjectAltName(
|
|
IN ICertServerPolicy *pServer,
|
|
OPTIONAL IN BSTRC strTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strName = NULL;
|
|
LONG ExtFlags;
|
|
VARIANT varExtension;
|
|
VARIANT varExtension2;
|
|
CERT_ALT_NAME_INFO *pAltName = NULL;
|
|
CERT_ALT_NAME_ENTRY *pRFC822Name;
|
|
CERT_ALT_NAME_ENTRY *pDirectoryName;
|
|
CERT_RDN const *prdn;
|
|
CERT_ALT_NAME_INFO AltName;
|
|
DWORD cbEncoded;
|
|
BYTE *pbEncoded = NULL;
|
|
CERT_NAME_INFO *pNameInfo = NULL;
|
|
DWORD cbNameInfo;
|
|
|
|
VariantInit(&varExtension);
|
|
VariantInit(&varExtension2);
|
|
|
|
if (NULL == strTemplateName ||
|
|
(0 != LSTRCMPIS(strTemplateName, wszCERTTYPE_EXCHANGE_USER) &&
|
|
0 != LSTRCMPIS(strTemplateName, wszCERTTYPE_EXCHANGE_USER_SIGNATURE)))
|
|
{
|
|
goto skip; // not an Exchange request.
|
|
|
|
}
|
|
|
|
strName = SysAllocString(TEXT(szOID_SUBJECT_ALT_NAME2));
|
|
if (NULL == strName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
|
|
hr = pServer->GetCertificateExtension(
|
|
strName,
|
|
PROPTYPE_BINARY,
|
|
&varExtension);
|
|
_PrintIfError2(hr, "Policy:GetCertificateExtension", hr);
|
|
if (S_OK != hr || VT_BSTR != varExtension.vt)
|
|
{
|
|
goto skip; // skip if the extension doesn't exist.
|
|
}
|
|
|
|
hr = pServer->GetCertificateExtensionFlags(&ExtFlags);
|
|
_JumpIfError(hr, error, "Policy:GetCertificateExtensionFlags");
|
|
|
|
if (EXTENSION_DISABLE_FLAG & ExtFlags)
|
|
{
|
|
goto skip; // skip if the extension is disabled.
|
|
}
|
|
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_ALTERNATE_NAME,
|
|
(BYTE *) varExtension.bstrVal,
|
|
SysStringByteLen(varExtension.bstrVal),
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pAltName,
|
|
&cbEncoded))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myDecodeObject");
|
|
}
|
|
if (2 != pAltName->cAltEntry)
|
|
{
|
|
goto skip; // skip if the extension isn't as expected
|
|
}
|
|
|
|
pRFC822Name = &pAltName->rgAltEntry[0];
|
|
pDirectoryName = &pAltName->rgAltEntry[1];
|
|
if (CERT_ALT_NAME_RFC822_NAME == pRFC822Name->dwAltNameChoice &&
|
|
CERT_ALT_NAME_DIRECTORY_NAME == pDirectoryName->dwAltNameChoice)
|
|
{
|
|
}
|
|
else
|
|
if (CERT_ALT_NAME_DIRECTORY_NAME == pRFC822Name->dwAltNameChoice &&
|
|
CERT_ALT_NAME_RFC822_NAME == pDirectoryName->dwAltNameChoice)
|
|
{
|
|
pDirectoryName = &pAltName->rgAltEntry[0];
|
|
pRFC822Name = &pAltName->rgAltEntry[1];
|
|
}
|
|
else
|
|
{
|
|
goto skip; // skip if the extension doesn't contain one of each
|
|
}
|
|
if (!myDecodeName(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_NAME,
|
|
pDirectoryName->DirectoryName.pbData,
|
|
pDirectoryName->DirectoryName.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pNameInfo,
|
|
&cbNameInfo))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeName");
|
|
}
|
|
if (1 != pNameInfo->cRDN)
|
|
{
|
|
goto skip; // skip if the entry doesn't contain one common name
|
|
}
|
|
prdn = &pNameInfo->rgRDN[0];
|
|
if (1 != prdn->cRDNAttr ||
|
|
0 != strcmp(prdn->rgRDNAttr[0].pszObjId, szOID_COMMON_NAME))
|
|
{
|
|
goto skip; // skip if the entry doesn't contain one common name
|
|
}
|
|
|
|
// rewrite the extension with only the RFC822 entry.
|
|
|
|
AltName.cAltEntry = 1;
|
|
AltName.rgAltEntry = pRFC822Name;
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_ALTERNATE_NAME,
|
|
&AltName,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbEncoded,
|
|
&cbEncoded))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
|
|
varExtension2.bstrVal = NULL;
|
|
if (!myConvertWszToBstr(
|
|
&varExtension2.bstrVal,
|
|
(WCHAR const *) pbEncoded,
|
|
cbEncoded))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
varExtension2.vt = VT_BSTR;
|
|
|
|
hr = pServer->SetCertificateExtension(
|
|
strName,
|
|
PROPTYPE_BINARY,
|
|
0,
|
|
&varExtension2);
|
|
_JumpIfError(hr, error, "Policy:SetCertificateExtension");
|
|
|
|
skip:
|
|
hr = S_OK;
|
|
|
|
error:
|
|
VariantClear(&varExtension);
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
if (NULL != pAltName)
|
|
{
|
|
LocalFree(pAltName);
|
|
}
|
|
if (NULL != pNameInfo)
|
|
{
|
|
LocalFree(pNameInfo);
|
|
}
|
|
if (NULL != pbEncoded)
|
|
{
|
|
LocalFree(pbEncoded);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
// begin_sdksample
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_AddV1TemplateNameExtension
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::AddV1TemplateNameExtension(
|
|
IN ICertServerPolicy *pServer,
|
|
OPTIONAL IN WCHAR const *pwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strName = NULL;
|
|
LONG ExtFlags = 0;
|
|
VARIANT varExtension;
|
|
CERT_NAME_VALUE *pName = NULL;
|
|
CERT_NAME_VALUE NameValue;
|
|
DWORD cbEncoded;
|
|
BYTE *pbEncoded = NULL;
|
|
BOOL fUpdate = TRUE;
|
|
|
|
VariantInit(&varExtension);
|
|
|
|
strName = SysAllocString(TEXT(szOID_ENROLL_CERTTYPE_EXTENSION));
|
|
if (NULL == strName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
|
|
hr = pServer->GetCertificateExtension(
|
|
strName,
|
|
PROPTYPE_BINARY,
|
|
&varExtension);
|
|
_PrintIfError2(hr, "Policy:GetCertificateExtension", hr);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
if (NULL == pwszTemplateName)
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_JumpIfError(hr, error, "Policy:GetCertificateExtension");
|
|
|
|
hr = pServer->GetCertificateExtensionFlags(&ExtFlags);
|
|
_JumpIfError(hr, error, "Policy:GetCertificateExtensionFlags");
|
|
|
|
if (VT_BSTR == varExtension.vt &&
|
|
0 == (EXTENSION_DISABLE_FLAG & ExtFlags) &&
|
|
NULL != pwszTemplateName)
|
|
{
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
(BYTE *) varExtension.bstrVal,
|
|
SysStringByteLen(varExtension.bstrVal),
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pName,
|
|
&cbEncoded))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myDecodeObject");
|
|
}
|
|
|
|
// case sensitive compare -- be sure to match case of template
|
|
|
|
if (0 == lstrcmp(
|
|
(WCHAR const *) pName->Value.pbData,
|
|
pwszTemplateName))
|
|
{
|
|
fUpdate = FALSE;
|
|
}
|
|
}
|
|
}
|
|
if (fUpdate)
|
|
{
|
|
if (NULL == pwszTemplateName)
|
|
{
|
|
ExtFlags |= EXTENSION_DISABLE_FLAG;
|
|
}
|
|
else
|
|
{
|
|
VariantClear(&varExtension);
|
|
varExtension.bstrVal = NULL;
|
|
|
|
NameValue.dwValueType = CERT_RDN_UNICODE_STRING;
|
|
NameValue.Value.pbData = (BYTE *) pwszTemplateName;
|
|
NameValue.Value.cbData = 0;
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
&NameValue,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbEncoded,
|
|
&cbEncoded))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
if (!myConvertWszToBstr(
|
|
&varExtension.bstrVal,
|
|
(WCHAR const *) pbEncoded,
|
|
cbEncoded))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
varExtension.vt = VT_BSTR;
|
|
ExtFlags &= ~EXTENSION_DISABLE_FLAG;
|
|
}
|
|
hr = pServer->SetCertificateExtension(
|
|
strName,
|
|
PROPTYPE_BINARY,
|
|
ExtFlags,
|
|
&varExtension);
|
|
_JumpIfError(hr, error, "Policy:SetCertificateExtension");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
VariantClear(&varExtension);
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
if (NULL != pName)
|
|
{
|
|
LocalFree(pName);
|
|
}
|
|
if (NULL != pbEncoded)
|
|
{
|
|
LocalFree(pbEncoded);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
// end_sdksample
|
|
|
|
HRESULT CCertPolicyEnterprise::_DuplicateAppPoliciesToEKU(
|
|
IN ICertServerPolicy *pServer)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbEKU = NULL;
|
|
DWORD cbEKU;
|
|
VARIANT varAppPolicies;
|
|
VARIANT varEKU;
|
|
|
|
VariantInit(&varAppPolicies);
|
|
VariantInit(&varEKU);
|
|
|
|
hr = polGetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_APPLICATION_CERT_POLICIES),
|
|
PROPTYPE_BINARY,
|
|
&varAppPolicies);
|
|
|
|
// if app policies extension is found
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
_JumpIfError(hr, error, "PropGetExtension(szOID_APPLICATION_CERT_POLICIES)");
|
|
|
|
hr = polGetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_ENHANCED_KEY_USAGE),
|
|
PROPTYPE_BINARY,
|
|
&varEKU);
|
|
|
|
// and EKU extension not found
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
// copy all app policies OIDs into EKU format
|
|
hr = myConvertAppPoliciesToEKU(
|
|
(BYTE *) varAppPolicies.bstrVal,
|
|
SysStringByteLen(varAppPolicies.bstrVal),
|
|
&pbEKU,
|
|
&cbEKU);
|
|
_JumpIfError(hr, error, "ConvertAppPoliciesToEKU");
|
|
|
|
// If app policies extension was empty, myConvertAppPoliciesToEKU returns NULL.
|
|
// Write EKU only if there was at least one app policy.
|
|
if(pbEKU)
|
|
{
|
|
varEKU.bstrVal = NULL;
|
|
if (!myConvertWszToBstr(
|
|
&varEKU.bstrVal,
|
|
(WCHAR const *) pbEKU,
|
|
cbEKU))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertWszToBstr");
|
|
}
|
|
|
|
varEKU.vt = VT_BSTR;
|
|
|
|
// set EKU extension with all app policies OIDs
|
|
hr = polSetCertificateExtension(
|
|
pServer,
|
|
TEXT(szOID_ENHANCED_KEY_USAGE),
|
|
PROPTYPE_BINARY,
|
|
0,
|
|
&varEKU);
|
|
_JumpIfError(hr, error, "Policy:polSetCertificateExtension");
|
|
}
|
|
}
|
|
_JumpIfError(hr, error, "polGetCertificateExtension(szOID_ENHANCED_KEY_USAGE)");
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
error:
|
|
VariantClear(&varAppPolicies);
|
|
VariantClear(&varEKU);
|
|
if (NULL != pbEKU)
|
|
{
|
|
LocalFree(pbEKU);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::FindTemplate(
|
|
OPTIONAL IN WCHAR const *pwszTemplateName,
|
|
OPTIONAL IN WCHAR const *pwszTemplateObjId,
|
|
OUT CTemplatePolicy **ppTemplate)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
|
|
hr = CERTSRV_E_UNSUPPORTED_CERT_TYPE;
|
|
*ppTemplate = NULL;
|
|
for (i = 0; i < m_cTemplatePolicies; i++)
|
|
{
|
|
if (NULL == m_apTemplatePolicies[i])
|
|
{
|
|
continue;
|
|
}
|
|
if (m_apTemplatePolicies[i]->IsRequestedTemplate(
|
|
pwszTemplateName,
|
|
pwszTemplateObjId))
|
|
{
|
|
*ppTemplate = m_apTemplatePolicies[i];
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
_JumpIfErrorStr(hr, error, "FindTemplate", pwszTemplateName);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_AddTemplateToCA(
|
|
IN HCAINFO hCAInfo,
|
|
IN WCHAR const *pwszTemplateName,
|
|
OUT BOOL *pfAdded)
|
|
{
|
|
HRESULT hr;
|
|
HCERTTYPE hCertType = NULL;
|
|
CTemplatePolicy *pTemplate;
|
|
|
|
*pfAdded = FALSE;
|
|
hr = FindTemplate(pwszTemplateName, NULL, &pTemplate);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = CAFindCertTypeByName(
|
|
pwszTemplateName,
|
|
m_pld,
|
|
CT_FIND_LOCAL_SYSTEM |
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES |
|
|
CT_FLAG_SCOPE_IS_LDAP_HANDLE |
|
|
CT_FLAG_NO_CACHE_LOOKUP,
|
|
&hCertType);
|
|
_JumpIfErrorStr(hr, error, "CAFindCertTypeByName", pwszTemplateName);
|
|
|
|
hr = CAAddCACertificateType(hCAInfo, hCertType);
|
|
_JumpIfErrorStr(hr, error, "CAAddCACertificateType", pwszTemplateName);
|
|
|
|
*pfAdded = TRUE;
|
|
}
|
|
CSASSERT(S_OK == hr);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"_AddTemplateToCA(%ws) --> %x\n",
|
|
pwszTemplateName,
|
|
hr));
|
|
|
|
if (NULL != hCertType)
|
|
{
|
|
CACloseCertType(hCertType);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
CCertPolicyEnterprise::_ReleaseTemplates()
|
|
{
|
|
DWORD i;
|
|
|
|
if (NULL != m_apTemplatePolicies)
|
|
{
|
|
for (i = 0; i < m_cTemplatePolicies; i++)
|
|
{
|
|
if (NULL != m_apTemplatePolicies[i])
|
|
{
|
|
delete m_apTemplatePolicies[i];
|
|
}
|
|
}
|
|
LocalFree(m_apTemplatePolicies);
|
|
m_apTemplatePolicies = NULL;
|
|
}
|
|
m_cTemplatePolicies = 0;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_LogLoadTemplateError(
|
|
IN ICertServerPolicy *pServer,
|
|
IN HRESULT hr,
|
|
LPCWSTR pcwszTemplate)
|
|
{
|
|
LPCWSTR apwsz[2];
|
|
LPCWSTR pwszError;
|
|
|
|
_PrintErrorStr(hr, "LogLoadTemplateError", pcwszTemplate);
|
|
|
|
pwszError = myGetErrorMessageText(hr, TRUE);
|
|
apwsz[0] = pcwszTemplate;
|
|
apwsz[1] = pwszError;
|
|
|
|
HRESULT hr2 = LogPolicyEvent(
|
|
g_hInstance,
|
|
S_OK,
|
|
MSG_LOAD_TEMPLATE,
|
|
pServer,
|
|
wszPROPEVENTLOGWARNING,
|
|
apwsz);
|
|
_PrintIfError(hr2, "LogPolicyEvent");
|
|
|
|
LOCAL_FREE(const_cast<LPWSTR>(pwszError));
|
|
return(hr2);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_LoadTemplates(
|
|
IN ICertServerPolicy *pServer,
|
|
OPTIONAL OUT HCAINFO *phCAInfo)
|
|
{
|
|
HRESULT hr;
|
|
HCERTTYPE hCertType = NULL;
|
|
DWORD dwLogId = 0;
|
|
WCHAR **ppwszTemplates = NULL;
|
|
int iTempl, iTemplPol;
|
|
HCAINFO hCAInfo = NULL;
|
|
|
|
_ReleaseTemplates();
|
|
|
|
hr = CAFindByName(
|
|
m_strCASanitizedDSName,
|
|
(WCHAR const *) m_pld,
|
|
CA_FIND_INCLUDE_UNTRUSTED | CA_FLAG_SCOPE_IS_LDAP_HANDLE,
|
|
&hCAInfo);
|
|
if (S_OK != hr)
|
|
{
|
|
dwLogId = MSG_NO_CA_OBJECT;
|
|
_JumpError(hr, error, "Policy:CAFindByName");
|
|
}
|
|
|
|
hr = CAGetCAProperty(hCAInfo, CA_PROP_CERT_TYPES, &ppwszTemplates);
|
|
if (S_OK != hr ||
|
|
!ppwszTemplates ||
|
|
!ppwszTemplates[0] ||
|
|
!wcscmp(ppwszTemplates[0], L" "))
|
|
{
|
|
dwLogId = MSG_NO_CERT_TYPES;
|
|
_JumpError(hr, error, "CAGetCAProperty");
|
|
}
|
|
|
|
// count # of templates in the CA's list
|
|
for (m_cTemplatePolicies = 0;
|
|
ppwszTemplates[m_cTemplatePolicies];
|
|
m_cTemplatePolicies++)
|
|
NULL;
|
|
|
|
m_apTemplatePolicies = (CTemplatePolicy **) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(CTemplatePolicy *) * m_cTemplatePolicies);
|
|
_JumpIfAllocFailed(m_apTemplatePolicies, error);
|
|
|
|
for (iTempl = 0, iTemplPol = 0; NULL != ppwszTemplates[iTempl]; iTempl++)
|
|
{
|
|
hr = CAFindCertTypeByName(
|
|
ppwszTemplates[iTempl],
|
|
m_pld,
|
|
CT_FIND_LOCAL_SYSTEM |
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES |
|
|
CT_FLAG_SCOPE_IS_LDAP_HANDLE |
|
|
(iTempl? 0 : CT_FLAG_NO_CACHE_LOOKUP),
|
|
&hCertType);
|
|
if (S_OK != hr)
|
|
{
|
|
// failed to retrieve the template with this name, log an error and
|
|
// move to the next template name
|
|
|
|
_LogLoadTemplateError(pServer, hr, ppwszTemplates[iTempl]);
|
|
continue;
|
|
}
|
|
|
|
m_apTemplatePolicies[iTemplPol] = new CTemplatePolicy;
|
|
_JumpIfAllocFailed(m_apTemplatePolicies[iTemplPol], error);
|
|
|
|
hr = m_apTemplatePolicies[iTemplPol]->Initialize(hCertType, pServer, this);
|
|
if (S_OK != hr)
|
|
{
|
|
_LogLoadTemplateError(pServer, hr, ppwszTemplates[iTempl]);
|
|
|
|
delete m_apTemplatePolicies[iTemplPol];
|
|
m_apTemplatePolicies[iTemplPol] = NULL;
|
|
CACloseCertType(hCertType);
|
|
|
|
continue;
|
|
}
|
|
iTemplPol++;
|
|
}
|
|
|
|
m_cTemplatePolicies = iTemplPol; // # of templates we retrieved successfully
|
|
if (NULL != phCAInfo)
|
|
{
|
|
CAFreeCAProperty(hCAInfo, ppwszTemplates);
|
|
ppwszTemplates = NULL;
|
|
|
|
*phCAInfo = hCAInfo;
|
|
hCAInfo = NULL;
|
|
}
|
|
|
|
error:
|
|
if (0 != dwLogId)
|
|
{
|
|
_BuildErrorInfo(hr, dwLogId);
|
|
}
|
|
if (NULL != ppwszTemplates)
|
|
{
|
|
CAFreeCAProperty(hCAInfo, ppwszTemplates);
|
|
}
|
|
if (NULL != hCAInfo)
|
|
{
|
|
CACloseCA(hCAInfo);
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
LOCAL_FREE(m_apTemplatePolicies);
|
|
m_apTemplatePolicies = NULL;
|
|
m_cTemplatePolicies = 0;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_UpgradeTemplatesInDS(
|
|
IN const HCAINFO hCAInfo,
|
|
IN BOOL fForceLoad,
|
|
OUT BOOL *pfTemplateAdded)
|
|
{
|
|
HRESULT hr;
|
|
HKEY hkey = NULL;
|
|
DWORD cb;
|
|
BOOL fTemplateAdded = FALSE;
|
|
|
|
*pfTemplateAdded = FALSE;
|
|
if (fForceLoad && (EDITF_SERVERUPGRADED & m_dwEditFlags))
|
|
{
|
|
BOOL fUpgradeComplete = TRUE;
|
|
|
|
if (FIsAdvancedServer())
|
|
{
|
|
CTemplatePolicy *pTemplate;
|
|
|
|
hr = FindTemplate(wszCERTTYPE_DC, NULL, &pTemplate);
|
|
if (S_OK == hr)
|
|
{
|
|
BOOL fAdded;
|
|
|
|
hr = _AddTemplateToCA(
|
|
hCAInfo,
|
|
wszCERTTYPE_DC_AUTH,
|
|
&fAdded);
|
|
if (S_OK == hr && fAdded)
|
|
{
|
|
fTemplateAdded = TRUE;
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
fUpgradeComplete = FALSE;
|
|
}
|
|
hr = _AddTemplateToCA(
|
|
hCAInfo,
|
|
wszCERTTYPE_DS_EMAIL_REPLICATION,
|
|
&fAdded);
|
|
if (S_OK == hr && fAdded)
|
|
{
|
|
fTemplateAdded = TRUE;
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
fUpgradeComplete = FALSE;
|
|
}
|
|
if (fTemplateAdded)
|
|
{
|
|
hr = CAUpdateCA(hCAInfo);
|
|
_JumpIfError(hr, error, "CAUpdateCA");
|
|
}
|
|
}
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"_UpdateTemplates: %ws EDITF_SERVERUPGRADED\n",
|
|
fUpgradeComplete? L"clearing" : L"keeping"));
|
|
|
|
if (fUpgradeComplete)
|
|
{
|
|
m_dwEditFlags &= ~EDITF_SERVERUPGRADED;
|
|
|
|
hr = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
m_strRegStorageLoc,
|
|
0, // dwReserved
|
|
KEY_ALL_ACCESS,
|
|
&hkey);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintIfError(hr, "Policy:RegOpenKeyEx");
|
|
}
|
|
else
|
|
{
|
|
cb = sizeof(m_dwEditFlags);
|
|
hr = RegSetValueEx(
|
|
hkey,
|
|
wszREGEDITFLAGS,
|
|
0,
|
|
REG_DWORD,
|
|
(BYTE *) &m_dwEditFlags,
|
|
cb);
|
|
_PrintIfError(hr, "Policy:RegSetValueEx");
|
|
}
|
|
}
|
|
}
|
|
*pfTemplateAdded = fTemplateAdded;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hkey)
|
|
{
|
|
RegCloseKey(hkey);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_UpdateTemplates(
|
|
IN ICertServerPolicy *pServer,
|
|
IN BOOL fForceLoad)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fUpdateTemplates;
|
|
DWORD dwChangeSequence;
|
|
HCAINFO hCAInfo = NULL;
|
|
DWORD dwCATemplListSequenceNum;
|
|
|
|
if (NULL == m_hCertTypeQuery)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID);
|
|
_JumpError(hr, error, "NULL m_hCertTypeQuery");
|
|
}
|
|
|
|
hr = CACertTypeQuery(m_hCertTypeQuery, &dwChangeSequence);
|
|
_JumpIfError(hr, error, "CACertTypeQuery");
|
|
|
|
hr = polGetCertificateLongProperty(
|
|
pServer,
|
|
wszPROPTEMPLATECHANGESEQUENCENUMBER,
|
|
(LONG *) &dwCATemplListSequenceNum);
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"polGetCertificateLongProperty",
|
|
wszPROPTEMPLATECHANGESEQUENCENUMBER);
|
|
|
|
fUpdateTemplates = fForceLoad ||
|
|
!m_fConfigLoaded ||
|
|
dwChangeSequence != m_TemplateSequence ||
|
|
dwCATemplListSequenceNum != m_dwCATemplListSequenceNum;
|
|
DBGPRINT((
|
|
DBG_SS_CERTPOL,
|
|
"_UpdateTemplates(fForce=%u) Sequence=%u->%u, %u->%u: fUpdate=%u\n",
|
|
fForceLoad,
|
|
m_TemplateSequence,
|
|
dwChangeSequence,
|
|
m_dwCATemplListSequenceNum,
|
|
dwCATemplListSequenceNum,
|
|
fUpdateTemplates));
|
|
|
|
while (fUpdateTemplates)
|
|
{
|
|
BOOL fTemplateAdded;
|
|
|
|
hr = _LoadTemplates(pServer, &hCAInfo);
|
|
_JumpIfError(hr, error, "_LoadTemplates");
|
|
|
|
m_TemplateSequence = dwChangeSequence;
|
|
m_dwCATemplListSequenceNum = dwCATemplListSequenceNum;
|
|
|
|
hr = _UpgradeTemplatesInDS(hCAInfo, fForceLoad, &fTemplateAdded);
|
|
_PrintIfError(hr, "UpgradeTemplatesInDS");
|
|
|
|
if (!fTemplateAdded)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hCAInfo)
|
|
{
|
|
CACloseCA(hCAInfo);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicyEnterprise::_BuildErrorInfo(
|
|
IN HRESULT hrLog,
|
|
IN DWORD dwLogId)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = polBuildErrorInfo(
|
|
hrLog,
|
|
dwLogId,
|
|
m_strDescription,
|
|
NULL,
|
|
&m_pCreateErrorInfo);
|
|
_JumpIfError(hr, error, "polBuildErrorInfo");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::VerifyRequest
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4509) // nonstandard extension used: uses SEH and has destructor
|
|
// begin_sdksample
|
|
|
|
STDMETHODIMP
|
|
CCertPolicyEnterprise::VerifyRequest(
|
|
/* [in] */ BSTR const, // strConfig
|
|
/* [in] */ LONG Context,
|
|
/* [in] */ LONG bNewRequest,
|
|
/* [in] */ LONG, // Flags
|
|
/* [out, retval] */ LONG __RPC_FAR *pDisposition)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ICertServerPolicy *pServer = NULL;
|
|
LONG lRequestId;
|
|
CRequestInstance Request;
|
|
BSTR strDisposition = NULL;
|
|
BOOL fCritSecEntered = FALSE; // no_sdksample
|
|
DWORD dwEnrollmentFlags = 0; // no_sdksample
|
|
BOOL fEnableEnrolleeExtensions;
|
|
BOOL fReenroll = FALSE;
|
|
DWORD cCriticalExtensions = 0;
|
|
WCHAR const * const *apwszCriticalExtensions = NULL;
|
|
|
|
lRequestId = 0;
|
|
|
|
// end_sdksample
|
|
if (!m_fTemplateCriticalSection)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
|
|
_JumpError(hr, error, "InitializeCriticalSection");
|
|
}
|
|
// begin_sdksample
|
|
|
|
__try
|
|
{
|
|
if (NULL == pDisposition)
|
|
{
|
|
hr = E_POINTER;
|
|
_LeaveError(hr, "Policy:pDisposition");
|
|
}
|
|
*pDisposition = VR_INSTANT_BAD;
|
|
|
|
hr = polGetServerCallbackInterface(&pServer, Context);
|
|
_LeaveIfError(hr, "Policy:polGetServerCallbackInterface");
|
|
|
|
hr = GetRequestId(pServer, &lRequestId);
|
|
_JumpIfError(hr, deny, "Policy:GetRequestId");
|
|
|
|
// only need to check user access for original submitter:
|
|
// resubmit can only be called by admins
|
|
|
|
if (bNewRequest && (0 == (m_dwEditFlags & EDITF_IGNOREREQUESTERGROUP)))
|
|
{
|
|
BOOL fRequesterAccess = FALSE;
|
|
|
|
// Is this user allowed to request certs?
|
|
hr = polGetCertificateLongProperty(
|
|
pServer,
|
|
wszPROPREQUESTERCAACCESS,
|
|
(LONG *) &fRequesterAccess);
|
|
_PrintIfErrorStr(
|
|
hr,
|
|
"Policy:polGetCertificateLongProperty",
|
|
wszPROPREQUESTERCAACCESS);
|
|
if (hr != S_OK || !fRequesterAccess)
|
|
{
|
|
hr = CERTSRV_E_ENROLL_DENIED;
|
|
_JumpError(hr, deny, "Policy:fRequesterAccess");
|
|
}
|
|
}
|
|
|
|
// end_sdksample
|
|
|
|
EnterCriticalSection(&m_TemplateCriticalSection);
|
|
fCritSecEntered = TRUE;
|
|
|
|
if (NULL != m_pCreateErrorInfo)
|
|
{
|
|
m_pCreateErrorInfo->Release();
|
|
m_pCreateErrorInfo = NULL;
|
|
}
|
|
hr = S_OK;
|
|
if (IsEnterpriseCA(m_CAType))
|
|
{
|
|
hr = _UpdateTemplates(pServer, FALSE);
|
|
_PrintIfError(hr, "Policy:_UpdateTemplates(will rebind)");
|
|
}
|
|
if (!m_fConfigLoaded || S_OK != hr)
|
|
{
|
|
// Uninitialized or possible LDAP handle gone bad -- rebind
|
|
// _LoadDSConfig calls _UpdateTemplates
|
|
|
|
hr = _LoadDSConfig(pServer, TRUE);
|
|
Request.SaveErrorInfo(m_pCreateErrorInfo);
|
|
m_pCreateErrorInfo = NULL;
|
|
_LeaveIfError(hr, "Policy:_LoadDSConfig");
|
|
}
|
|
|
|
// begin_sdksample
|
|
|
|
hr = Request.Initialize(
|
|
this,
|
|
IsEnterpriseCA(m_CAType), // no_sdksample
|
|
bNewRequest, // no_sdksample
|
|
pServer,
|
|
&fEnableEnrolleeExtensions);
|
|
_LeaveIfError(hr, "Policy:VerifyRequest:Request.Initialize");
|
|
|
|
LeaveCriticalSection(&m_TemplateCriticalSection); // no_sdksample
|
|
fCritSecEntered = FALSE; // no_sdksample
|
|
|
|
hr = _EnumerateExtensions(
|
|
pServer,
|
|
bNewRequest,
|
|
TRUE,
|
|
fEnableEnrolleeExtensions,
|
|
0,
|
|
NULL);
|
|
_LeaveIfError(hr, "_EnumerateExtensions");
|
|
|
|
if (IsStandaloneCA(m_CAType)) // no_sdksample
|
|
{
|
|
hr = _AddDefaultBasicConstraintsExtension(
|
|
pServer,
|
|
Request.IsCARequest());
|
|
_LeaveIfError(hr, "_AddDefaultBasicConstraintsExtension");
|
|
|
|
hr = _AddDefaultKeyUsageExtension(pServer, Request.IsCARequest());
|
|
_LeaveIfError(hr, "_AddDefaultKeyUsageExtension");
|
|
|
|
hr = _AddEnhancedKeyUsageExtension(pServer);
|
|
_LeaveIfError(hr, "_AddEnhancedKeyUsageExtension");
|
|
}
|
|
|
|
hr = _SetValidityPeriod(pServer);
|
|
_LeaveIfError(hr, "_SetValidityPeriod");
|
|
|
|
hr = EnumerateAttributes(pServer);
|
|
_LeaveIfError(hr, "Policy:EnumerateAttributes");
|
|
|
|
hr = _AddRevocationExtension(pServer);
|
|
_LeaveIfError(hr, "_AddRevocationExtension");
|
|
|
|
hr = _AddOldCertTypeExtension(pServer, Request.IsCARequest());
|
|
_LeaveIfError(hr, "_AddOldCertTypeExtension");
|
|
|
|
hr = _AddAuthorityKeyId(pServer);
|
|
_LeaveIfError(hr, "_AddAuthorityKeyId");
|
|
|
|
// end_sdksample
|
|
|
|
hr = _PatchExchangeSubjectAltName(pServer, Request.GetTemplateName());
|
|
_LeaveIfError(hr, "_PatchExchangeSubjectAltName");
|
|
|
|
cCriticalExtensions = 0;
|
|
if (IsEnterpriseCA(m_CAType))
|
|
{
|
|
hr = Request.ApplyTemplate(
|
|
pServer,
|
|
&fReenroll,
|
|
&dwEnrollmentFlags,
|
|
&cCriticalExtensions,
|
|
&apwszCriticalExtensions);
|
|
_JumpIfError(hr, deny, "_ApplyTemplate"); // pass hr as Disposition
|
|
}
|
|
|
|
hr = _AddSubjectAltNameExtension(pServer, 0);
|
|
_LeaveIfError(hr, "_AddSubjectAltNameExtension");
|
|
|
|
hr = _AddSubjectAltNameExtension(pServer, 1);
|
|
_LeaveIfError(hr, "_AddSubjectAltNameExtension");
|
|
|
|
// bug# 630833: if application policies are present but no EKU, copy
|
|
// all app policies to EKU extension
|
|
hr = _DuplicateAppPoliciesToEKU(pServer);
|
|
_LeaveIfError(hr, "_DuplicateAppPoliciesToEKU");
|
|
|
|
// begin_sdksample
|
|
|
|
// pass hr as Disposition
|
|
|
|
if ((EDITF_DISABLEEXTENSIONLIST & m_dwEditFlags) ||
|
|
NULL != apwszCriticalExtensions)
|
|
{
|
|
hr = _EnumerateExtensions(
|
|
pServer,
|
|
bNewRequest,
|
|
FALSE,
|
|
FALSE,
|
|
cCriticalExtensions,
|
|
apwszCriticalExtensions);
|
|
_LeaveIfError(hr, "_EnumerateExtensions");
|
|
}
|
|
|
|
if (bNewRequest &&
|
|
(
|
|
((CT_FLAG_PEND_ALL_REQUESTS & dwEnrollmentFlags) && !fReenroll) || // no_sdksample
|
|
(REQDISP_PENDINGFIRST & m_dwDispositionFlags)))
|
|
{
|
|
*pDisposition = VR_PENDING;
|
|
}
|
|
else switch (REQDISP_MASK & m_dwDispositionFlags)
|
|
{
|
|
default:
|
|
case REQDISP_PENDING:
|
|
*pDisposition = VR_PENDING;
|
|
break;
|
|
|
|
case REQDISP_ISSUE:
|
|
*pDisposition = VR_INSTANT_OK;
|
|
break;
|
|
|
|
case REQDISP_DENY:
|
|
*pDisposition = VR_INSTANT_BAD;
|
|
break;
|
|
|
|
case REQDISP_USEREQUESTATTRIBUTE:
|
|
*pDisposition = VR_INSTANT_OK;
|
|
hr = polGetRequestAttribute(
|
|
pServer,
|
|
wszPROPDISPOSITION,
|
|
&strDisposition);
|
|
if (S_OK == hr)
|
|
{
|
|
if (0 == LSTRCMPIS(strDisposition, wszPROPDISPOSITIONDENY))
|
|
{
|
|
*pDisposition = VR_INSTANT_BAD;
|
|
}
|
|
if (0 == LSTRCMPIS(strDisposition, wszPROPDISPOSITIONPENDING))
|
|
{
|
|
*pDisposition = VR_PENDING;
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
deny:
|
|
if (FAILED(hr))
|
|
{
|
|
*pDisposition = hr; // pass failed HRESULT back as Disposition
|
|
}
|
|
else if (hr != S_OK)
|
|
{
|
|
*pDisposition = VR_INSTANT_BAD;
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
_PrintError(hr, "Exception");
|
|
}
|
|
|
|
error: // no_sdksample
|
|
{
|
|
HRESULT hr2 = hr;
|
|
#define wszFORMATREQUESTID L"RequestId=%u"
|
|
WCHAR wszRequestId[ARRAYSIZE(wszFORMATREQUESTID) + cwcDWORDSPRINTF];
|
|
|
|
if (S_OK == hr2 && NULL != pDisposition && FAILED(*pDisposition))
|
|
{
|
|
hr2 = *pDisposition;
|
|
}
|
|
if (S_OK != hr2)
|
|
{
|
|
wsprintf(wszRequestId, wszFORMATREQUESTID, lRequestId);
|
|
_PrintErrorStr(hr2, "VerifyRequest", wszRequestId);
|
|
}
|
|
}
|
|
if (NULL != strDisposition)
|
|
{
|
|
SysFreeString(strDisposition);
|
|
}
|
|
if (NULL != pServer)
|
|
{
|
|
pServer->Release();
|
|
}
|
|
// end_sdksample
|
|
if (fCritSecEntered)
|
|
{
|
|
LeaveCriticalSection(&m_TemplateCriticalSection);
|
|
}
|
|
Request.SetErrorInfo();
|
|
// begin_sdksample
|
|
//_PrintIfError(hr, "Policy:VerifyRequest(hr)");
|
|
//_PrintError(*pDisposition, "Policy:VerifyRequest(*pDisposition)");
|
|
return(hr);
|
|
}
|
|
#pragma warning(pop) // no_sdksample
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::GetDescription
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CCertPolicyEnterprise::GetDescription(
|
|
/* [out, retval] */ BSTR __RPC_FAR *pstrDescription)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR sz[MAX_PATH];
|
|
|
|
if(!m_strDescription)
|
|
{
|
|
#ifdef IDS_MODULE_NAME // no_sdksample
|
|
if (!LoadString(g_hInstance, IDS_MODULE_NAME, sz, ARRAYSIZE(sz))) // no_sdksample
|
|
{ // no_sdksample
|
|
sz[0] = L'\0'; // no_sdksample
|
|
} // no_sdksample
|
|
#else // no_sdksample
|
|
CSASSERT(wcslen(wsz_SAMPLE_DESCRIPTION) < ARRAYSIZE(sz));
|
|
wcsncpy(sz, wsz_SAMPLE_DESCRIPTION, ARRAYSIZE(sz));
|
|
sz[ARRAYSIZE(sz) - 1] = L'\0';
|
|
#endif // no_sdksample
|
|
|
|
m_strDescription = SysAllocString(sz);
|
|
if (NULL == m_strDescription)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
if (NULL != *pstrDescription)
|
|
{
|
|
SysFreeString(*pstrDescription);
|
|
}
|
|
|
|
*pstrDescription = SysAllocString(m_strDescription);
|
|
if (NULL == *pstrDescription)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::ShutDown
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CCertPolicyEnterprise::ShutDown(VOID)
|
|
{
|
|
// called once, as Server unloading policy dll
|
|
_Cleanup();
|
|
ReqCleanup(); // no_sdksample
|
|
TPCleanup(); // no_sdksample
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::GetManageModule
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CCertPolicyEnterprise::GetManageModule(
|
|
/* [out, retval] */ ICertManageModule **ppManageModule)
|
|
{
|
|
HRESULT hr;
|
|
|
|
*ppManageModule = NULL;
|
|
hr = CoCreateInstance(
|
|
CLSID_CCertManagePolicyModule,
|
|
NULL, // pUnkOuter
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ICertManageModule,
|
|
(VOID **) ppManageModule);
|
|
_JumpIfError(hr, error, "CoCreateInstance");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicyEnterprise::_GetIssuer
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
PCCERT_CONTEXT
|
|
CCertPolicyEnterprise::_GetIssuer(
|
|
IN ICertServerPolicy *pServer)
|
|
{
|
|
HRESULT hr;
|
|
VARIANT varValue;
|
|
BSTR strName = NULL;
|
|
|
|
VariantInit(&varValue);
|
|
if (NULL != m_pCert)
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
strName = SysAllocString(wszPROPRAWCACERTIFICATE);
|
|
if (NULL == strName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:SysAllocString");
|
|
}
|
|
hr = pServer->GetCertificateProperty(strName, PROPTYPE_BINARY, &varValue);
|
|
_JumpIfError(hr, error, "Policy:GetCertificateProperty");
|
|
|
|
m_pCert = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
(BYTE *) varValue.bstrVal,
|
|
SysStringByteLen(varValue.bstrVal));
|
|
if (NULL == m_pCert)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:CertCreateCertificateContext");
|
|
}
|
|
|
|
error:
|
|
VariantClear(&varValue);
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
return(m_pCert);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CCertPolicyEnterprise::InterfaceSupportsErrorInfo(
|
|
IN REFIID riid)
|
|
{
|
|
static const IID *arr[] =
|
|
{
|
|
&IID_ICertPolicy,
|
|
};
|
|
|
|
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
|
|
{
|
|
if (IsEqualGUID(*arr[i], riid))
|
|
{
|
|
return(S_OK);
|
|
}
|
|
}
|
|
return(S_FALSE);
|
|
}
|
|
|
|
// end_sdksample
|