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.
3145 lines
74 KiB
3145 lines
74 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: policy.cpp
|
|
//
|
|
// Contents: Cert Server Policy Module implementation
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
#include <assert.h>
|
|
#include "celib.h"
|
|
#include "policy.h"
|
|
#include "module.h"
|
|
|
|
BOOL fDebug = DBG_CERTSRV;
|
|
|
|
#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);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::~CCertPolicySample -- destructor
|
|
//
|
|
// free memory associated with this instance
|
|
//+--------------------------------------------------------------------------
|
|
|
|
CCertPolicySample::~CCertPolicySample()
|
|
{
|
|
_Cleanup();
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
CCertPolicySample::_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((fDebug, "_FreeStringArray[%u]: '%ws'\n", i, apwsz[i]));
|
|
LocalFree(apwsz[i]);
|
|
}
|
|
}
|
|
LocalFree(apwsz);
|
|
*papwsz = NULL;
|
|
}
|
|
*pcString = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::_Cleanup -- free memory associated with this instance
|
|
//
|
|
// free memory associated with this instance
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicySample::_Cleanup()
|
|
{
|
|
DWORD i;
|
|
|
|
if (m_strDescription)
|
|
{
|
|
SysFreeString(m_strDescription);
|
|
m_strDescription = NULL;
|
|
}
|
|
|
|
// RevocationExtension variables:
|
|
|
|
if (NULL != m_wszASPRevocationURL)
|
|
{
|
|
LocalFree(m_wszASPRevocationURL);
|
|
m_wszASPRevocationURL = NULL;
|
|
}
|
|
|
|
|
|
_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;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertPolicySample::_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 = ceFormatCertsrvStringArray(
|
|
fURL, // fURL
|
|
m_strMachineDNSName, // pwszServerName_p1_2
|
|
m_strCASanitizedName, // pwszSanitizedName_p3_7
|
|
m_iCert, // iCert_p4
|
|
MAXDWORD, // iCertTarget_p4
|
|
L"", // pwszDomainDN_p5
|
|
L"", // pwszConfigDN_p6
|
|
m_iCRL, // iCRL_p8
|
|
FALSE, // fDeltaCRL_p9
|
|
TRUE, // fDSAttrib_p10_11
|
|
1, // cStrings
|
|
(LPCWSTR *) &pwszRegValue, // apwszStringsIn
|
|
ppwszOut); // apwszStringsOut
|
|
_JumpIfError(hr, error, "Policy:ceFormatCertsrvStringArray");
|
|
|
|
error:
|
|
if (NULL != pwszRegValue)
|
|
{
|
|
LocalFree(pwszRegValue);
|
|
}
|
|
return(ceHError(hr)); // Reg routines return Win32 error codes
|
|
}
|
|
|
|
|
|
#if DBG_CERTSRV
|
|
|
|
VOID
|
|
CCertPolicySample::_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 = ceGetOIDName(apwsz[i]); // Static: do not free!
|
|
}
|
|
DBGPRINT((
|
|
fDebug,
|
|
"%hs[%u]: %ws%hs%ws\n",
|
|
pszType,
|
|
i,
|
|
apwsz[i],
|
|
L'\0' != *pwszName? " -- " : "",
|
|
pwszName));
|
|
}
|
|
}
|
|
#endif // DBG_CERTSRV
|
|
|
|
|
|
HRESULT
|
|
CCertPolicySample::_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 (!ceConvertWszToBstr(&strName, pwszName, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
|
|
if (NULL != pwszValue)
|
|
{
|
|
if (!ceConvertWszToBstr(&varValue.bstrVal, pwszValue, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
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
|
|
CCertPolicySample::_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)
|
|
{
|
|
assert(NULL != *papwszRegValues);
|
|
CopyMemory(
|
|
awszOutputStrings,
|
|
*papwszRegValues,
|
|
*pcStrings * sizeof(LPWSTR));
|
|
}
|
|
|
|
hr = ceFormatCertsrvStringArray(
|
|
fURL, // fURL
|
|
m_strMachineDNSName, // pwszServerName_p1_2
|
|
m_strCASanitizedName, // pwszSanitizedName_p3_7
|
|
m_iCert, // iCert_p4
|
|
MAXDWORD, // iCertTarget_p4
|
|
L"", // pwszDomainDN_p5
|
|
L"", // pwszConfigDN_p6
|
|
m_iCRL, // iCRL_p8
|
|
FALSE, // fDeltaCRL_p9
|
|
TRUE, // fDSAttrib_p10_11
|
|
cString, // cStrings
|
|
awszFormatStrings, // apwszStringsIn
|
|
awszOutputStrings + (*pcStrings)); // apwszStringsOut
|
|
_JumpIfError(hr, error, "Policy:ceFormatCertsrvStringArray");
|
|
|
|
*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
|
|
CCertPolicySample::_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);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::_InitRevocationExtension
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicySample::_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((fDebug, "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:
|
|
;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::_InitRequestExtensionList
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicySample::_InitRequestExtensionList(
|
|
IN HKEY hkey)
|
|
{
|
|
HRESULT hr;
|
|
DWORD adwFlags[] = {
|
|
EDITF_REQUESTEXTENSIONLIST,
|
|
};
|
|
WCHAR *apwszRegNames[] = {
|
|
wszREGENABLEREQUESTEXTENSIONLIST,
|
|
};
|
|
WCHAR *apwszRegNamesEnrollee[] = {
|
|
wszREGENABLEENROLLEEREQUESTEXTENSIONLIST,
|
|
};
|
|
|
|
assert(ARRAYSIZE(adwFlags) == ARRAYSIZE(apwszRegNames));
|
|
assert(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:
|
|
;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::_InitDisableExtensionList
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CCertPolicySample::_InitDisableExtensionList(
|
|
IN HKEY hkey)
|
|
{
|
|
HRESULT hr;
|
|
DWORD adwFlags[] = {
|
|
EDITF_DISABLEEXTENSIONLIST,
|
|
};
|
|
WCHAR *apwszRegNames[] = {
|
|
wszREGDISABLEEXTENSIONLIST,
|
|
};
|
|
|
|
assert(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:
|
|
;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::Initialize
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CCertPolicySample::Initialize(
|
|
/* [in] */ BSTR const strConfig)
|
|
{
|
|
HRESULT hr;
|
|
HKEY hkey = NULL;
|
|
DWORD dwType;
|
|
DWORD dwSize;
|
|
ICertServerPolicy *pServer = NULL;
|
|
BOOL fUpgraded;
|
|
BSTR bstrDescription = NULL;
|
|
|
|
CERT_RDN_ATTR rdnAttr = { szOID_COMMON_NAME, CERT_RDN_ANY_TYPE, };
|
|
|
|
rdnAttr.Value.pbData = NULL;
|
|
|
|
DBGPRINT((fDebug, "Policy:Initialize:\n"));
|
|
|
|
|
|
__try
|
|
{
|
|
_Cleanup();
|
|
|
|
m_strCAName = SysAllocString(strConfig);
|
|
if (NULL == m_strCAName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_LeaveError(hr, "CCertPolicySample::SysAllocString");
|
|
}
|
|
|
|
// force loading the description from resources
|
|
|
|
hr = GetDescription(&bstrDescription);
|
|
_LeaveIfError(hr, "CCertPolicySample::GetDescription");
|
|
|
|
// get server callbacks
|
|
|
|
hr = polGetServerCallbackInterface(&pServer, 0);
|
|
_LeaveIfError(hr, "Policy:polGetServerCallbackInterface");
|
|
|
|
hr = ReqInitialize(pServer);
|
|
_JumpIfError(hr, error, "ReqInitialize");
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
// 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((
|
|
fDebug,
|
|
"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 =
|
|
EDITF_DEFAULT_STANDALONE;
|
|
}
|
|
if (fUpgraded)
|
|
{
|
|
DBGPRINT((
|
|
fDebug,
|
|
"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((fDebug, "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((fDebug, "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);
|
|
|
|
hr = S_OK;
|
|
}
|
|
__except(hr = ceHError(GetExceptionCode()), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
_PrintError(hr, "Exception");
|
|
}
|
|
|
|
error:
|
|
if (NULL != bstrDescription)
|
|
{
|
|
SysFreeString(bstrDescription);
|
|
}
|
|
if (NULL != hkey)
|
|
{
|
|
RegCloseKey(hkey);
|
|
}
|
|
if (NULL != pServer)
|
|
{
|
|
pServer->Release();
|
|
}
|
|
return(ceHError(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
|
|
CCertPolicySample::_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((
|
|
fDebug,
|
|
"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((
|
|
fDebug,
|
|
"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((
|
|
fDebug,
|
|
"Policy:GetRequestId(%ws = %u)\n",
|
|
wszPROPREQUESTREQUESTID,
|
|
*plRequestId));
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::_AddRevocationExtension
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicySample::_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))
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::_AddOldCertTypeExtension
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicySample::_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 = ceHLastError();
|
|
_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 == celstrcmpiL(strCertType, L"server"))
|
|
{
|
|
CertType = NSCERTTYPE_SERVER;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ceConvertWszToBstr(
|
|
&strBitString,
|
|
(WCHAR const *) &CertType,
|
|
sizeof(CertType)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::_AddAuthorityKeyId
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicySample::_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 (!ceDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_AUTHORITY_KEY_ID2,
|
|
(BYTE *) varExtension.bstrVal,
|
|
SysStringByteLen(varExtension.bstrVal),
|
|
FALSE,
|
|
(VOID **) &pInfo,
|
|
&cbInfo))
|
|
{
|
|
hr = ceHLastError();
|
|
_JumpIfError(hr, error, "Policy:ceDecodeObject");
|
|
}
|
|
|
|
// 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 (!ceEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_AUTHORITY_KEY_ID2,
|
|
pInfo,
|
|
0,
|
|
FALSE,
|
|
&pbEncoded,
|
|
&cbEncoded))
|
|
{
|
|
hr = ceHLastError();
|
|
_JumpError(hr, error, "Policy:ceEncodeObject");
|
|
}
|
|
if (!ceConvertWszToBstr(
|
|
&strExtension,
|
|
(WCHAR const *) pbEncoded,
|
|
cbEncoded))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
|
|
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
|
|
CCertPolicySample::_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 = ceHLastError();
|
|
_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 (!ceDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_KEY_USAGE,
|
|
(BYTE const *) varKeyUsage.bstrVal,
|
|
SysStringByteLen(varKeyUsage.bstrVal),
|
|
FALSE,
|
|
(VOID **) &pKeyUsage,
|
|
&cb))
|
|
{
|
|
hr = GetLastError();
|
|
_PrintError(hr, "Policy:ceDecodeObject");
|
|
}
|
|
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] |= ceCASIGN_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 (!ceConvertWszToBstr(
|
|
&strBitString,
|
|
(WCHAR const *) pbKeyUsage,
|
|
cbKeyUsage))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
|
|
hr = pBitString->Encode(cbKeyUsage * 8, strBitString, &strExtension);
|
|
_JumpIfError(hr, error, "Policy:Encode");
|
|
|
|
if (!ceConvertWszToBstr(&strName, TEXT(szOID_KEY_USAGE), -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
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
|
|
CCertPolicySample::_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 (!ceConvertWszToSz(&pszUsage, strUsage, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToSz");
|
|
}
|
|
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;
|
|
|
|
assert(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 = ceVerifyObjIdA(psz);
|
|
_JumpIfError(hr, error, "Policy:ceVerifyObjIdA");
|
|
|
|
ceu.rgpszUsageIdentifier[i++] = psz;
|
|
}
|
|
}
|
|
ceu.cUsageIdentifier = i;
|
|
if (0 == ceu.cUsageIdentifier)
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
|
|
if (!ceEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_ENHANCED_KEY_USAGE,
|
|
&ceu,
|
|
0,
|
|
FALSE,
|
|
&pbKeyUsage,
|
|
&cbKeyUsage))
|
|
{
|
|
hr = ceHLastError();
|
|
_JumpError(hr, error, "Policy:ceEncodeObject");
|
|
}
|
|
|
|
varExtension.bstrVal = NULL;
|
|
if (!ceConvertWszToBstr(
|
|
&varExtension.bstrVal,
|
|
(WCHAR const *) pbKeyUsage,
|
|
cbKeyUsage))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
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 (!ceEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_POLICIES,
|
|
&cpi,
|
|
0,
|
|
FALSE,
|
|
&pbPolicies,
|
|
&cbPolicies))
|
|
{
|
|
hr = ceHLastError();
|
|
_JumpError(hr, error, "Policy:ceEncodeObject");
|
|
}
|
|
|
|
if (!ceConvertWszToBstr(
|
|
&varExtension.bstrVal,
|
|
(WCHAR const *) pbPolicies,
|
|
cbPolicies))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
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
|
|
CCertPolicySample::_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 == celstrcmpiL(strCertType, L"ca"))
|
|
{
|
|
fCA = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (!fCA)
|
|
{
|
|
hr = polGetRequestAttribute(pServer, wszPROPCERTTEMPLATE, &strCertType);
|
|
if (S_OK == hr)
|
|
{
|
|
if (0 == celstrcmpiL(strCertType, wszCERTTYPE_SUBORDINATE_CA) ||
|
|
0 == celstrcmpiL(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
|
|
CCertPolicySample::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 = ceHLastError();
|
|
_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 = ceHLastError();
|
|
_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 (!ceEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
&Constraints,
|
|
0,
|
|
FALSE,
|
|
&pbConstraints,
|
|
&cb))
|
|
{
|
|
hr = ceHLastError();
|
|
_JumpError(hr, error, "Policy:ceEncodeObject");
|
|
}
|
|
|
|
if (!ceConvertWszToBstr(
|
|
&strExtension,
|
|
(WCHAR const *) pbConstraints,
|
|
cb))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
|
|
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
|
|
CCertPolicySample::_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 = ceWtoI(strPeriodCount, &fValidDigitString);
|
|
if (!fValidDigitString)
|
|
{
|
|
BSTR str = strPeriodCount;
|
|
|
|
strPeriodCount = strPeriodString;
|
|
strPeriodString = str;
|
|
|
|
lDelta = ceWtoI(strPeriodCount, &fValidDigitString);
|
|
if (!fValidDigitString)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "Policy:ceWtoI");
|
|
}
|
|
}
|
|
|
|
hr = ceTranslatePeriodUnits(strPeriodString, lDelta, &enumValidityPeriod, &lDelta);
|
|
_JumpIfError(hr, error, "Policy:ceTranslatePeriodUnits");
|
|
|
|
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 = ceMakeExprDate(&varValue.date, lDelta, enumValidityPeriod);
|
|
_JumpIfError(hr, error, "Policy:ceMakeExprDate");
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::_AddV1TemplateNameExtension
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertPolicySample::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 (!ceDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
(BYTE *) varExtension.bstrVal,
|
|
SysStringByteLen(varExtension.bstrVal),
|
|
FALSE,
|
|
(VOID **) &pName,
|
|
&cbEncoded))
|
|
{
|
|
hr = ceHLastError();
|
|
_JumpError(hr, error, "Policy:ceDecodeObject");
|
|
}
|
|
|
|
// 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 (!ceEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
&NameValue,
|
|
0,
|
|
FALSE,
|
|
&pbEncoded,
|
|
&cbEncoded))
|
|
{
|
|
hr = ceHLastError();
|
|
_JumpError(hr, error, "Policy:ceEncodeObject");
|
|
}
|
|
if (!ceConvertWszToBstr(
|
|
&varExtension.bstrVal,
|
|
(WCHAR const *) pbEncoded,
|
|
cbEncoded))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:ceConvertWszToBstr");
|
|
}
|
|
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);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CCertPolicySample::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 fEnableEnrolleeExtensions;
|
|
BOOL fReenroll = FALSE;
|
|
DWORD cCriticalExtensions = 0;
|
|
WCHAR const * const *apwszCriticalExtensions = NULL;
|
|
|
|
lRequestId = 0;
|
|
|
|
|
|
__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");
|
|
}
|
|
}
|
|
|
|
|
|
hr = Request.Initialize(
|
|
this,
|
|
pServer,
|
|
&fEnableEnrolleeExtensions);
|
|
_LeaveIfError(hr, "Policy:VerifyRequest:Request.Initialize");
|
|
|
|
|
|
hr = _EnumerateExtensions(
|
|
pServer,
|
|
bNewRequest,
|
|
TRUE,
|
|
fEnableEnrolleeExtensions,
|
|
0,
|
|
NULL);
|
|
_LeaveIfError(hr, "_EnumerateExtensions");
|
|
|
|
{
|
|
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");
|
|
|
|
|
|
// pass hr as Disposition
|
|
|
|
if ((EDITF_DISABLEEXTENSIONLIST & m_dwEditFlags) ||
|
|
NULL != apwszCriticalExtensions)
|
|
{
|
|
hr = _EnumerateExtensions(
|
|
pServer,
|
|
bNewRequest,
|
|
FALSE,
|
|
FALSE,
|
|
cCriticalExtensions,
|
|
apwszCriticalExtensions);
|
|
_LeaveIfError(hr, "_EnumerateExtensions");
|
|
}
|
|
|
|
if (bNewRequest &&
|
|
(
|
|
(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 == celstrcmpiL(strDisposition, wszPROPDISPOSITIONDENY))
|
|
{
|
|
*pDisposition = VR_INSTANT_BAD;
|
|
}
|
|
if (0 == celstrcmpiL(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 = ceHError(GetExceptionCode()), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
_PrintError(hr, "Exception");
|
|
}
|
|
|
|
{
|
|
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();
|
|
}
|
|
//_PrintIfError(hr, "Policy:VerifyRequest(hr)");
|
|
//_PrintError(*pDisposition, "Policy:VerifyRequest(*pDisposition)");
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::GetDescription
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CCertPolicySample::GetDescription(
|
|
/* [out, retval] */ BSTR __RPC_FAR *pstrDescription)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR sz[MAX_PATH];
|
|
|
|
if(!m_strDescription)
|
|
{
|
|
assert(wcslen(wsz_SAMPLE_DESCRIPTION) < ARRAYSIZE(sz));
|
|
wcsncpy(sz, wsz_SAMPLE_DESCRIPTION, ARRAYSIZE(sz));
|
|
sz[ARRAYSIZE(sz) - 1] = L'\0';
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::ShutDown
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CCertPolicySample::ShutDown(VOID)
|
|
{
|
|
// called once, as Server unloading policy dll
|
|
_Cleanup();
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::GetManageModule
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CCertPolicySample::GetManageModule(
|
|
/* [out, retval] */ ICertManageModule **ppManageModule)
|
|
{
|
|
HRESULT hr;
|
|
|
|
*ppManageModule = NULL;
|
|
hr = CoCreateInstance(
|
|
CLSID_CCertManagePolicyModuleSample,
|
|
NULL, // pUnkOuter
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ICertManageModule,
|
|
(VOID **) ppManageModule);
|
|
_JumpIfError(hr, error, "CoCreateInstance");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertPolicySample::_GetIssuer
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
PCCERT_CONTEXT
|
|
CCertPolicySample::_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 = ceHLastError();
|
|
_JumpError(hr, error, "Policy:CertCreateCertificateContext");
|
|
}
|
|
|
|
error:
|
|
VariantClear(&varValue);
|
|
if (NULL != strName)
|
|
{
|
|
SysFreeString(strName);
|
|
}
|
|
return(m_pCert);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CCertPolicySample::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);
|
|
}
|
|
|