4544 lines
99 KiB
C++
4544 lines
99 KiB
C++
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: inf.cpp
|
|
//
|
|
// Contents: Cert Server INF file processing routines
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <certca.h>
|
|
|
|
#include "csdisp.h"
|
|
#include "initcert.h"
|
|
#include "clibres.h"
|
|
|
|
#define __dwFILE__ __dwFILE_CERTLIB_INF_CPP__
|
|
|
|
#define wszBSCAPOLICYFILE L"\\" wszCAPOLICYFILE
|
|
#define wszINFKEY_CONTINUE L"_continue_"
|
|
|
|
#define cwcVALUEMAX 1024
|
|
|
|
static WCHAR *s_pwszSection = NULL;
|
|
static WCHAR *s_pwszKey = NULL;
|
|
static WCHAR *s_pwszValue = NULL;
|
|
|
|
|
|
VOID
|
|
infClearString(
|
|
IN OUT WCHAR **ppwsz)
|
|
{
|
|
if (NULL != ppwsz && NULL != *ppwsz)
|
|
{
|
|
LocalFree(*ppwsz);
|
|
*ppwsz = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
infCopyString(
|
|
OPTIONAL IN WCHAR const *pwszIn,
|
|
OPTIONAL OUT WCHAR **ppwszOut)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL != pwszIn && L'\0' != *pwszIn)
|
|
{
|
|
if (NULL == *ppwszOut)
|
|
{
|
|
if (NULL != *ppwszOut)
|
|
{
|
|
LocalFree(*ppwszOut);
|
|
*ppwszOut = NULL;
|
|
}
|
|
hr = myDupString(pwszIn, ppwszOut);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(S_OK == hr);
|
|
}
|
|
|
|
|
|
#define INFSTRINGSELECT(pwsz) (NULL != (pwsz)? (pwsz) : L"")
|
|
|
|
#if DBG_CERTSRV
|
|
# define INFSETERROR(hr, pwszSection, pwszKey, pwszValue) \
|
|
{ \
|
|
_PrintError3(hr, "infSetError", ERROR_LINE_NOT_FOUND, S_FALSE); \
|
|
infSetError(hr, pwszSection, pwszKey, pwszValue, __LINE__); \
|
|
}
|
|
#else
|
|
# define INFSETERROR infSetError
|
|
#endif
|
|
|
|
|
|
VOID
|
|
infSetError(
|
|
IN HRESULT hr,
|
|
OPTIONAL IN WCHAR const *pwszSection,
|
|
OPTIONAL IN WCHAR const *pwszKey,
|
|
OPTIONAL IN WCHAR const *pwszValue
|
|
DBGPARM(IN DWORD dwLine))
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"inf.cpp(%u): infSetError Begin: [%ws] %ws = %ws\n",
|
|
dwLine,
|
|
INFSTRINGSELECT(pwszSection),
|
|
INFSTRINGSELECT(pwszKey),
|
|
INFSTRINGSELECT(pwszValue)));
|
|
infCopyString(pwszSection, &s_pwszSection);
|
|
infCopyString(pwszKey, &s_pwszKey);
|
|
infCopyString(pwszValue, &s_pwszValue);
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"inf.cpp(%u): infSetError End: [%ws] %ws = %ws\n",
|
|
dwLine,
|
|
INFSTRINGSELECT(s_pwszSection),
|
|
INFSTRINGSELECT(s_pwszKey),
|
|
INFSTRINGSELECT(s_pwszValue)));
|
|
}
|
|
|
|
|
|
WCHAR *
|
|
myInfGetError()
|
|
{
|
|
DWORD cwc = 1;
|
|
WCHAR *pwsz = NULL;
|
|
|
|
if (NULL != s_pwszSection)
|
|
{
|
|
cwc += wcslen(s_pwszSection) + 2;
|
|
}
|
|
if (NULL != s_pwszKey)
|
|
{
|
|
cwc += wcslen(s_pwszKey) + 1;
|
|
}
|
|
if (NULL != s_pwszValue)
|
|
{
|
|
cwc += wcslen(s_pwszValue) + 3;
|
|
}
|
|
if (1 == cwc)
|
|
{
|
|
goto error;
|
|
}
|
|
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
|
|
if (NULL == pwsz)
|
|
{
|
|
goto error;
|
|
}
|
|
*pwsz = L'\0';
|
|
if (NULL != s_pwszSection)
|
|
{
|
|
wcscat(pwsz, wszLBRACKET);
|
|
wcscat(pwsz, s_pwszSection);
|
|
wcscat(pwsz, wszRBRACKET);
|
|
}
|
|
if (NULL != s_pwszKey)
|
|
{
|
|
if (L'\0' != *pwsz)
|
|
{
|
|
wcscat(pwsz, L" ");
|
|
}
|
|
wcscat(pwsz, s_pwszKey);
|
|
}
|
|
if (NULL != s_pwszValue)
|
|
{
|
|
wcscat(pwsz, L" = ");
|
|
wcscat(pwsz, s_pwszValue);
|
|
}
|
|
error:
|
|
return(pwsz);
|
|
}
|
|
|
|
|
|
VOID
|
|
myInfClearError()
|
|
{
|
|
infClearString(&s_pwszSection);
|
|
infClearString(&s_pwszKey);
|
|
infClearString(&s_pwszValue);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infSetupFindFirstLine(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
OPTIONAL IN WCHAR const *pwszKey,
|
|
OUT INFCONTEXT *pInfContext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!SetupFindFirstLine(hInf, pwszSection, pwszKey, pInfContext))
|
|
{
|
|
hr = myHLastError();
|
|
if ((HRESULT) ERROR_LINE_NOT_FOUND == hr &&
|
|
SetupFindFirstLine(hInf, pwszSection, wszINFKEY_EMPTY, pInfContext))
|
|
{
|
|
hr = S_FALSE; // Section exists, but Key doesn't
|
|
}
|
|
_JumpErrorStr3(
|
|
hr,
|
|
error,
|
|
"SetupFindFirstLine",
|
|
pwszSection,
|
|
ERROR_LINE_NOT_FOUND,
|
|
S_FALSE);
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infBuildPolicyElement(
|
|
IN OUT INFCONTEXT *pInfContext,
|
|
OPTIONAL OUT CERT_POLICY_QUALIFIER_INFO *pcpqi)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
WCHAR wszKey[MAX_PATH];
|
|
BOOL fURL = FALSE;
|
|
BOOL fNotice = FALSE;
|
|
DWORD cwc;
|
|
WCHAR *pwszValue = NULL;
|
|
WCHAR *pwszURL = NULL;
|
|
BYTE *pbData = NULL;
|
|
DWORD cbData;
|
|
|
|
wszKey[0] = L'\0';
|
|
if (!SetupGetStringField(
|
|
pInfContext,
|
|
0,
|
|
wszKey,
|
|
ARRAYSIZE(wszKey),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
DBGPRINT((DBG_SS_CERTLIBI, "Element = %ws\n", wszKey));
|
|
|
|
if (0 == lstrcmpi(wszINFKEY_URL, wszKey))
|
|
{
|
|
fURL = TRUE;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(wszINFKEY_NOTICE, wszKey))
|
|
{
|
|
fNotice = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (0 != lstrcmpi(wszINFKEY_OID, wszKey))
|
|
{
|
|
_PrintErrorStr(E_INVALIDARG, "Skipping unknown key", wszKey);
|
|
}
|
|
hr = S_FALSE; // Skip this key
|
|
}
|
|
if (fURL || fNotice)
|
|
{
|
|
if (!SetupGetStringField(pInfContext, 1, NULL, 0, &cwc))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
pwszValue = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
|
|
if (NULL == pwszValue)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
if (!SetupGetStringField(pInfContext, 1, pwszValue, cwc, NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
DBGPRINT((DBG_SS_CERTLIBI, "SetupGetStringField = %ws\n", pwszValue));
|
|
|
|
if (fURL)
|
|
{
|
|
CERT_NAME_VALUE NameValue;
|
|
|
|
hr = myInternetCanonicalizeUrl(pwszValue, &pwszURL);
|
|
_JumpIfError(hr, error, "myInternetCanonicalizeUrl");
|
|
|
|
NameValue.dwValueType = CERT_RDN_IA5_STRING;
|
|
NameValue.Value.pbData = (BYTE *) pwszURL;
|
|
NameValue.Value.cbData = 0;
|
|
|
|
if (NULL != pcpqi)
|
|
{
|
|
CSILOG(S_OK, IDS_ILOG_CAPOLICY_ELEMENT, pwszURL, NULL, NULL);
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_NAME_VALUE,
|
|
&NameValue,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbData,
|
|
&cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CERT_POLICY_QUALIFIER_USER_NOTICE UserNotice;
|
|
|
|
ZeroMemory(&UserNotice, sizeof(UserNotice));
|
|
UserNotice.pszDisplayText = pwszValue;
|
|
|
|
if (NULL != pcpqi)
|
|
{
|
|
CSILOG(S_OK, IDS_ILOG_CAPOLICY_ELEMENT, pwszValue, NULL, NULL);
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_PKIX_POLICY_QUALIFIER_USERNOTICE,
|
|
&UserNotice,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbData,
|
|
&cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
}
|
|
if (NULL != pcpqi)
|
|
{
|
|
pcpqi->pszPolicyQualifierId = fURL?
|
|
szOID_PKIX_POLICY_QUALIFIER_CPS :
|
|
szOID_PKIX_POLICY_QUALIFIER_USERNOTICE;
|
|
pcpqi->Qualifier.pbData = pbData;
|
|
pcpqi->Qualifier.cbData = cbData;
|
|
pbData = NULL;
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
INFSETERROR(hr, NULL, wszKey, pwszValue);
|
|
}
|
|
if (NULL != pwszValue)
|
|
{
|
|
LocalFree(pwszValue);
|
|
}
|
|
if (NULL != pwszURL)
|
|
{
|
|
LocalFree(pwszURL);
|
|
}
|
|
if (NULL != pbData)
|
|
{
|
|
LocalFree(pbData);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infBuildPolicy(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
IN OUT CERT_POLICY_INFO *pcpi)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
DWORD i;
|
|
WCHAR wszValue[cwcVALUEMAX];
|
|
|
|
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
|
|
wszValue[0] = L'\0';
|
|
hr = infSetupFindFirstLine(hInf, pwszSection, wszINFKEY_OID, &InfContext);
|
|
if (S_OK != hr)
|
|
{
|
|
INFSETERROR(hr, NULL, wszINFKEY_OID, NULL);
|
|
_JumpErrorStr(hr, error, "infSetupFindFirstLine", pwszSection);
|
|
}
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
1,
|
|
wszValue,
|
|
ARRAYSIZE(wszValue),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
INFSETERROR(hr, NULL, wszINFKEY_OID, NULL);
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
|
|
if (!ConvertWszToSz(&pcpi->pszPolicyIdentifier, wszValue, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToSz");
|
|
}
|
|
DBGPRINT((DBG_SS_CERTLIBI, "OID = %hs\n", pcpi->pszPolicyIdentifier));
|
|
|
|
hr = infSetupFindFirstLine(hInf, pwszSection, NULL, &InfContext);
|
|
_JumpIfErrorStr(hr, error, "infSetupFindFirstLine", pwszSection);
|
|
|
|
for (i = 0; ; )
|
|
{
|
|
hr = infBuildPolicyElement(&InfContext, NULL);
|
|
if (S_FALSE != hr)
|
|
{
|
|
_JumpIfErrorStr(hr, error, "infBuildPolicyElement", pwszSection);
|
|
|
|
i++;
|
|
}
|
|
|
|
if (!SetupFindNextLine(&InfContext, &InfContext))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintErrorStr2(hr, "SetupFindNextLine", pwszSection, hr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
pcpi->cPolicyQualifier = i;
|
|
pcpi->rgPolicyQualifier = (CERT_POLICY_QUALIFIER_INFO *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
pcpi->cPolicyQualifier *
|
|
sizeof(pcpi->rgPolicyQualifier[0]));
|
|
if (NULL == pcpi->rgPolicyQualifier)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
hr = infSetupFindFirstLine(hInf, pwszSection, NULL, &InfContext);
|
|
_JumpIfErrorStr(hr, error, "infSetupFindFirstLine", pwszSection);
|
|
|
|
for (i = 0; ; )
|
|
{
|
|
// handle one URL or text message
|
|
|
|
hr = infBuildPolicyElement(&InfContext, &pcpi->rgPolicyQualifier[i]);
|
|
if (S_FALSE != hr)
|
|
{
|
|
_JumpIfErrorStr(hr, error, "infBuildPolicyElement", pwszSection);
|
|
|
|
i++;
|
|
}
|
|
if (!SetupFindNextLine(&InfContext, &InfContext))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintErrorStr2(hr, "SetupFindNextLine", pwszSection, hr);
|
|
break;
|
|
}
|
|
}
|
|
CSASSERT(i == pcpi->cPolicyQualifier);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
INFSETERROR(hr, pwszSection, NULL, L"???");
|
|
}
|
|
CSILOG(
|
|
hr,
|
|
IDS_ILOG_CAPOLICY_BUILD,
|
|
pwszSection,
|
|
S_OK == hr || L'\0' == wszValue[0]? NULL : wszValue,
|
|
NULL);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
infFreePolicy(
|
|
IN OUT CERT_POLICY_INFO *pcpi)
|
|
{
|
|
DWORD i;
|
|
CERT_POLICY_QUALIFIER_INFO *pcpqi;
|
|
|
|
if (NULL != pcpi->pszPolicyIdentifier)
|
|
{
|
|
LocalFree(pcpi->pszPolicyIdentifier);
|
|
}
|
|
if (NULL != pcpi->rgPolicyQualifier)
|
|
{
|
|
for (i = 0; i < pcpi->cPolicyQualifier; i++)
|
|
{
|
|
pcpqi = &pcpi->rgPolicyQualifier[i];
|
|
if (NULL != pcpqi->Qualifier.pbData)
|
|
{
|
|
LocalFree(pcpqi->Qualifier.pbData);
|
|
}
|
|
}
|
|
LocalFree(pcpi->rgPolicyQualifier);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myInfOpenFile(
|
|
OPTIONAL IN WCHAR const *pwszfnPolicy,
|
|
OUT HINF *phInf,
|
|
OUT DWORD *pErrorLine)
|
|
{
|
|
HRESULT hr;
|
|
HINF hInf;
|
|
WCHAR wszPath[MAX_PATH];
|
|
UINT ErrorLine;
|
|
DWORD Flags;
|
|
|
|
*phInf = INVALID_HANDLE_VALUE;
|
|
*pErrorLine = 0;
|
|
myInfClearError();
|
|
|
|
if (NULL == pwszfnPolicy)
|
|
{
|
|
if (0 == GetEnvironmentVariable(
|
|
L"SystemRoot",
|
|
wszPath,
|
|
ARRAYSIZE(wszPath) - ARRAYSIZE(wszBSCAPOLICYFILE)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpError(hr, error, "GetEnvironmentVariable");
|
|
}
|
|
wcscat(wszPath, wszBSCAPOLICYFILE);
|
|
pwszfnPolicy = wszPath;
|
|
}
|
|
else
|
|
{
|
|
if (NULL == wcschr(pwszfnPolicy, L'\\'))
|
|
{
|
|
if (ARRAYSIZE(wszPath) <= 2 + wcslen(pwszfnPolicy))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
|
|
_JumpErrorStr(hr, error, "filename too long", pwszfnPolicy);
|
|
}
|
|
wcscpy(wszPath, L".\\");
|
|
wcscat(wszPath, pwszfnPolicy);
|
|
pwszfnPolicy = wszPath;
|
|
}
|
|
}
|
|
|
|
Flags = INF_STYLE_WIN4;
|
|
while (TRUE)
|
|
{
|
|
ErrorLine = 0;
|
|
*phInf = SetupOpenInfFile(
|
|
pwszfnPolicy,
|
|
NULL,
|
|
Flags,
|
|
&ErrorLine);
|
|
*pErrorLine = ErrorLine;
|
|
if (INVALID_HANDLE_VALUE != *phInf)
|
|
{
|
|
break;
|
|
}
|
|
hr = myHLastError();
|
|
if ((HRESULT) ERROR_WRONG_INF_STYLE == hr && INF_STYLE_WIN4 == Flags)
|
|
{
|
|
Flags = INF_STYLE_OLDNT;
|
|
continue;
|
|
}
|
|
CSILOG(
|
|
hr,
|
|
IDS_ILOG_CAPOLICY_OPEN_FAILED,
|
|
pwszfnPolicy,
|
|
NULL,
|
|
0 == *pErrorLine? NULL : pErrorLine);
|
|
_JumpErrorStr(hr, error, "SetupOpenInfFile", pwszfnPolicy);
|
|
}
|
|
CSILOG(S_OK, IDS_ILOG_CAPOLICY_OPEN, pwszfnPolicy, NULL, NULL);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfOpenFile(%ws) hr=%x --> h=%x\n",
|
|
pwszfnPolicy,
|
|
hr,
|
|
*phInf));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
myInfCloseFile(
|
|
IN HINF hInf)
|
|
{
|
|
if (NULL != hInf && INVALID_HANDLE_VALUE != hInf)
|
|
{
|
|
WCHAR *pwszInfError = myInfGetError();
|
|
|
|
SetupCloseInfFile(hInf);
|
|
CSILOG(S_OK, IDS_ILOG_CAPOLICY_CLOSE, pwszInfError, NULL, NULL);
|
|
if (NULL != pwszInfError)
|
|
{
|
|
LocalFree(pwszInfError);
|
|
}
|
|
}
|
|
DBGPRINT((DBG_SS_CERTLIBI, "myInfCloseFile(%x)\n", hInf));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myInfParseBooleanValue(
|
|
IN WCHAR const *pwszValue,
|
|
OUT BOOL *pfValue)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
static WCHAR const * const s_apwszTrue[] = { L"True", L"Yes", L"On", L"1" };
|
|
static WCHAR const * const s_apwszFalse[] = { L"False", L"No", L"Off", L"0" };
|
|
|
|
*pfValue = FALSE;
|
|
for (i = 0; i < ARRAYSIZE(s_apwszTrue); i++)
|
|
{
|
|
if (0 == lstrcmpi(pwszValue, s_apwszTrue[i]))
|
|
{
|
|
*pfValue = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (i == ARRAYSIZE(s_apwszTrue))
|
|
{
|
|
for (i = 0; i < ARRAYSIZE(s_apwszFalse); i++)
|
|
{
|
|
if (0 == lstrcmpi(pwszValue, s_apwszFalse[i]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == ARRAYSIZE(s_apwszFalse))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpErrorStr(hr, error, "bad boolean value string", pwszValue);
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
INFSETERROR(hr, NULL, NULL, pwszValue);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myInfGetBooleanValue(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
IN WCHAR const *pwszKey,
|
|
IN BOOL fIgnoreMissingKey,
|
|
OUT BOOL *pfValue)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
DWORD i;
|
|
WCHAR wszValue[cwcVALUEMAX];
|
|
|
|
*pfValue = FALSE;
|
|
myInfClearError();
|
|
|
|
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
|
|
|
|
hr = infSetupFindFirstLine(hInf, pwszSection, pwszKey, &InfContext);
|
|
_PrintIfErrorStr3(
|
|
hr,
|
|
"infSetupFindFirstLine",
|
|
pwszSection,
|
|
ERROR_LINE_NOT_FOUND,
|
|
S_FALSE);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"infSetupFindFirstLine",
|
|
pwszKey,
|
|
ERROR_LINE_NOT_FOUND,
|
|
S_FALSE);
|
|
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
1,
|
|
wszValue,
|
|
ARRAYSIZE(wszValue),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr(hr, error, "SetupGetStringField", pwszKey);
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetBooleanValue --> '%ws'\n",
|
|
wszValue));
|
|
|
|
hr = myInfParseBooleanValue(wszValue, pfValue);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
error:
|
|
if (S_OK != hr &&
|
|
((HRESULT) ERROR_LINE_NOT_FOUND != hr || !fIgnoreMissingKey))
|
|
{
|
|
INFSETERROR(hr, pwszSection, pwszKey, NULL);
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetBooleanValue(%ws, %ws) hr=%x --> f=%d\n",
|
|
pwszSection,
|
|
pwszKey,
|
|
hr,
|
|
*pfValue));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infGetCriticalFlag(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
IN BOOL fDefault,
|
|
OUT BOOL *pfCritical)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = myInfGetBooleanValue(
|
|
hInf,
|
|
pwszSection,
|
|
wszINFKEY_CRITICAL,
|
|
TRUE,
|
|
pfCritical);
|
|
if (S_OK != hr)
|
|
{
|
|
*pfCritical = fDefault;
|
|
if ((HRESULT) ERROR_LINE_NOT_FOUND != hr && S_FALSE != hr)
|
|
{
|
|
_JumpErrorStr(hr, error, "myInfGetBooleanValue", pwszSection);
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infGetCriticalFlag(%ws) hr=%x --> f=%d\n",
|
|
pwszSection,
|
|
hr,
|
|
*pfCritical));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// infGetPolicyStatementExtensionSub -- build policy extension from INF file
|
|
//
|
|
// [pwszSection]
|
|
// Policies = LegalPolicy, LimitedUsePolicy, ExtraPolicy
|
|
//
|
|
// [LegalPolicy]
|
|
// OID = 1.3.6.1.4.1.311.21.43
|
|
// Notice = "Legal policy statement text."
|
|
//
|
|
// [LimitedUsePolicy]
|
|
// OID = 1.3.6.1.4.1.311.21.47
|
|
// URL = "http://http.site.com/some where/default.asp"
|
|
// URL = "ftp://ftp.site.com/some where else/default.asp"
|
|
// Notice = "Limited use policy statement text."
|
|
// URL = "ldap://ldap.site.com/some where else again/default.asp"
|
|
//
|
|
// [ExtraPolicy]
|
|
// OID = 1.3.6.1.4.1.311.21.53
|
|
// URL = http://extra.site.com/Extra Policy/default.asp
|
|
//
|
|
// Return S_OK if extension has been constructed from the INF file
|
|
// Return S_FALSE if empty section detected in INF file
|
|
// Return other error if no section detected in INF file
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
infGetPolicyStatementExtensionSub(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
IN char const *pszObjId,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
CERT_POLICIES_INFO PoliciesInfo;
|
|
INFCONTEXT InfContext;
|
|
DWORD i;
|
|
WCHAR wszValue[cwcVALUEMAX];
|
|
|
|
wszValue[0] = L'\0';
|
|
ZeroMemory(&PoliciesInfo, sizeof(PoliciesInfo));
|
|
ZeroMemory(pext, sizeof(*pext));
|
|
|
|
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
|
|
hr = infSetupFindFirstLine(
|
|
hInf,
|
|
pwszSection,
|
|
wszINFKEY_POLICIES,
|
|
&InfContext);
|
|
if (S_OK != hr)
|
|
{
|
|
CSILOG(
|
|
hr,
|
|
IDS_ILOG_CAPOLICY_NOKEY,
|
|
pwszSection,
|
|
wszINFKEY_POLICIES,
|
|
NULL);
|
|
_JumpErrorStr3(
|
|
hr,
|
|
error,
|
|
"infSetupFindFirstLine",
|
|
pwszSection,
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
}
|
|
|
|
// First, count the policies.
|
|
|
|
PoliciesInfo.cPolicyInfo = SetupGetFieldCount(&InfContext);
|
|
if (0 == PoliciesInfo.cPolicyInfo)
|
|
{
|
|
hr = S_FALSE;
|
|
_JumpError(hr, error, "SetupGetFieldCount");
|
|
}
|
|
|
|
// Next, allocate memory.
|
|
|
|
PoliciesInfo.rgPolicyInfo = (CERT_POLICY_INFO *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
PoliciesInfo.cPolicyInfo * sizeof(PoliciesInfo.rgPolicyInfo[0]));
|
|
if (NULL == PoliciesInfo.rgPolicyInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
// Finally! Fill in the policies data.
|
|
|
|
for (i = 0; i < PoliciesInfo.cPolicyInfo; i++)
|
|
{
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
i + 1,
|
|
wszValue,
|
|
ARRAYSIZE(wszValue),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr2(hr, error, "SetupGetStringField", wszINFKEY_POLICIES, hr);
|
|
}
|
|
DBGPRINT((DBG_SS_CERTLIBI, "%ws[%u] = %ws\n", wszINFKEY_POLICIES, i, wszValue));
|
|
|
|
hr = infBuildPolicy(hInf, wszValue, &PoliciesInfo.rgPolicyInfo[i]);
|
|
_JumpIfErrorStr(hr, error, "infBuildPolicy", wszValue);
|
|
}
|
|
|
|
hr = infGetCriticalFlag(hInf, pwszSection, FALSE, &pext->fCritical);
|
|
_JumpIfError(hr, error, "infGetCriticalFlag");
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_POLICIES,
|
|
&PoliciesInfo,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pext->Value.pbData,
|
|
&pext->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
INFSETERROR(hr, pwszSection, wszINFKEY_POLICIES, wszValue);
|
|
}
|
|
pext->pszObjId = const_cast<char *>(pszObjId); // on error, too!
|
|
|
|
if (NULL != PoliciesInfo.rgPolicyInfo)
|
|
{
|
|
for (i = 0; i < PoliciesInfo.cPolicyInfo; i++)
|
|
{
|
|
infFreePolicy(&PoliciesInfo.rgPolicyInfo[i]);
|
|
}
|
|
LocalFree(PoliciesInfo.rgPolicyInfo);
|
|
}
|
|
CSILOG(
|
|
hr,
|
|
IDS_ILOG_CAPOLICY_EXTENSION,
|
|
S_OK == hr || L'\0' == wszValue[0]? NULL : wszValue,
|
|
NULL,
|
|
NULL);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetPolicyStatementExtension -- build policy extension from INF file
|
|
//
|
|
// [PolicyStatementExtension]
|
|
// Policies = LegalPolicy, LimitedUsePolicy, ExtraPolicy
|
|
// ...
|
|
//
|
|
// OR
|
|
//
|
|
// [CAPolicy]
|
|
// Policies = LegalPolicy, LimitedUsePolicy, ExtraPolicy
|
|
// ...
|
|
//
|
|
// Return S_OK if extension has been constructed from the INF file
|
|
// Return S_FALSE if empty section detected in INF file
|
|
// Return other error if no section detected in INF file
|
|
//-------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetPolicyStatementExtension;
|
|
|
|
HRESULT
|
|
myInfGetPolicyStatementExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
myInfClearError();
|
|
hr = infGetPolicyStatementExtensionSub(
|
|
hInf,
|
|
wszINFSECTION_POLICYSTATEMENT,
|
|
szOID_CERT_POLICIES,
|
|
pext);
|
|
if (S_OK != hr)
|
|
{
|
|
HRESULT hr2;
|
|
|
|
hr2 = infGetPolicyStatementExtensionSub(
|
|
hInf,
|
|
wszINFSECTION_CAPOLICY,
|
|
szOID_CERT_POLICIES,
|
|
pext);
|
|
if (S_FALSE == hr2 && (HRESULT) ERROR_LINE_NOT_FOUND == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"infGetPolicyStatementExtensionSub",
|
|
wszINFSECTION_POLICYSTATEMENT,
|
|
ERROR_LINE_NOT_FOUND,
|
|
S_FALSE);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetPolicyStatementExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetApplicationPolicyStatementExtension -- build application policy
|
|
// extension from INF file
|
|
//
|
|
// [ApplicationPolicyStatementExtension]
|
|
// Policies = LegalPolicy, LimitedUsePolicy, ExtraPolicy
|
|
// ...
|
|
//
|
|
// Return S_OK if extension has been constructed from the INF file
|
|
// Return S_FALSE if empty section detected in INF file
|
|
// Return other error if no section detected in INF file
|
|
//-------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetApplicationPolicyStatementExtension;
|
|
|
|
HRESULT
|
|
myInfGetApplicationPolicyStatementExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
myInfClearError();
|
|
hr = infGetPolicyStatementExtensionSub(
|
|
hInf,
|
|
wszINFSECTION_APPLICATIONPOLICYSTATEMENT,
|
|
szOID_APPLICATION_CERT_POLICIES,
|
|
pext);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"infGetPolicyStatementExtensionSub",
|
|
wszINFSECTION_APPLICATIONPOLICYSTATEMENT,
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetApplicationPolicyStatementExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infGetCurrentKeyValue(
|
|
IN OUT INFCONTEXT *pInfContext,
|
|
IN DWORD Index,
|
|
OUT WCHAR **ppwszValue)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR wszValue[1024];
|
|
|
|
*ppwszValue = NULL;
|
|
wszValue[0] = L'\0';
|
|
if (!SetupGetStringField(
|
|
pInfContext,
|
|
Index,
|
|
wszValue,
|
|
ARRAYSIZE(wszValue),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
hr = myDupString(wszValue, ppwszValue);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
myinfGetCRLPublicationParams(
|
|
IN HINF hInf,
|
|
IN LPCWSTR szInfSection_CRLPeriod,
|
|
IN LPCWSTR szInfSection_CRLCount,
|
|
OUT LPWSTR* ppwszCRLPeriod,
|
|
OUT DWORD* pdwCRLCount)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Retrieve units count and string. If either fails, both are discarded.
|
|
|
|
*ppwszCRLPeriod = NULL;
|
|
hr = myInfGetNumericKeyValue(
|
|
hInf,
|
|
FALSE,
|
|
wszINFSECTION_CERTSERVER,
|
|
szInfSection_CRLCount,
|
|
pdwCRLCount);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"myInfGetNumericKeyValue",
|
|
szInfSection_CRLCount,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
hr = myInfGetKeyValue(
|
|
hInf,
|
|
FALSE,
|
|
wszINFSECTION_CERTSERVER,
|
|
szInfSection_CRLPeriod,
|
|
ppwszCRLPeriod);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"myInfGetKeyValue",
|
|
szInfSection_CRLPeriod,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
error:
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetKeyValue -- fetch a string value from INF file
|
|
//
|
|
// [pwszSection]
|
|
// pwszKey = string
|
|
//
|
|
// Returns: allocated string key value
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetKeyValue(
|
|
IN HINF hInf,
|
|
IN BOOL fLog,
|
|
IN WCHAR const *pwszSection,
|
|
IN WCHAR const *pwszKey,
|
|
OUT WCHAR **ppwszValue)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
WCHAR *pwszValue = NULL;
|
|
WCHAR *pwszT = NULL;
|
|
|
|
*ppwszValue = NULL;
|
|
myInfClearError();
|
|
|
|
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
|
|
hr = infSetupFindFirstLine(hInf, pwszSection, pwszKey, &InfContext);
|
|
if (S_OK != hr)
|
|
{
|
|
if (fLog)
|
|
{
|
|
CSILOG(hr, IDS_ILOG_CAPOLICY_NOKEY, pwszSection, pwszKey, NULL);
|
|
}
|
|
_JumpErrorStr2(
|
|
hr,
|
|
error,
|
|
"infSetupFindFirstLine",
|
|
pwszKey,
|
|
ERROR_LINE_NOT_FOUND);
|
|
}
|
|
|
|
hr = infGetCurrentKeyValue(&InfContext, 1, &pwszValue);
|
|
_JumpIfError(hr, error, "infGetCurrentKeyValue");
|
|
|
|
while (TRUE)
|
|
{
|
|
DWORD cwc;
|
|
WCHAR *pwsz;
|
|
|
|
if (!SetupFindNextLine(&InfContext, &InfContext))
|
|
{
|
|
break;
|
|
}
|
|
hr = infGetCurrentKeyValue(&InfContext, 0, &pwszT);
|
|
_JumpIfError(hr, error, "infGetCurrentKeyValue");
|
|
|
|
if (0 != lstrcmpi(wszINFKEY_CONTINUE, pwszT))
|
|
{
|
|
break;
|
|
}
|
|
LocalFree(pwszT);
|
|
pwszT = NULL;
|
|
|
|
hr = infGetCurrentKeyValue(&InfContext, 1, &pwszT);
|
|
_JumpIfError(hr, error, "infGetCurrentKeyValue");
|
|
|
|
cwc = wcslen(pwszValue) + wcslen(pwszT);
|
|
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
|
|
if (NULL == pwsz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
wcscpy(pwsz, pwszValue);
|
|
wcscat(pwsz, pwszT);
|
|
|
|
LocalFree(pwszValue);
|
|
pwszValue = pwsz;
|
|
|
|
LocalFree(pwszT);
|
|
pwszT = NULL;
|
|
}
|
|
*ppwszValue = pwszValue;
|
|
pwszValue = NULL;
|
|
hr = S_OK;
|
|
|
|
//wprintf(L"%ws = %ws\n", pwszKey, *ppwszValue);
|
|
|
|
error:
|
|
if (NULL != pwszValue)
|
|
{
|
|
LocalFree(pwszValue);
|
|
}
|
|
if (NULL != pwszT)
|
|
{
|
|
LocalFree(pwszT);
|
|
}
|
|
if (S_OK != hr && fLog)
|
|
{
|
|
INFSETERROR(hr, pwszSection, pwszKey, NULL);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetNumericKeyValue -- fetch a numeric value from INF file
|
|
//
|
|
// [pwszSection]
|
|
// pwszKey = 2048
|
|
//
|
|
// Returns: DWORD key value
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetNumericKeyValue(
|
|
IN HINF hInf,
|
|
IN BOOL fLog,
|
|
IN WCHAR const *pwszSection,
|
|
IN WCHAR const *pwszKey,
|
|
OUT DWORD *pdwValue)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
INT Value;
|
|
|
|
myInfClearError();
|
|
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
|
|
if (!SetupFindFirstLine(hInf, pwszSection, pwszKey, &InfContext))
|
|
{
|
|
hr = myHLastError();
|
|
if (fLog)
|
|
{
|
|
CSILOG(hr, IDS_ILOG_CAPOLICY_NOKEY, pwszSection, pwszKey, NULL);
|
|
}
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"SetupFindFirstLine",
|
|
pwszKey,
|
|
ERROR_LINE_NOT_FOUND);
|
|
_JumpErrorStr2(
|
|
hr,
|
|
error,
|
|
"SetupFindFirstLine",
|
|
pwszSection,
|
|
ERROR_LINE_NOT_FOUND);
|
|
}
|
|
|
|
if (!SetupGetIntField(&InfContext, 1, &Value))
|
|
{
|
|
hr = myHLastError();
|
|
if (fLog)
|
|
{
|
|
CSILOG(hr, IDS_ILOG_BAD_NUMERICFIELD, pwszSection, pwszKey, NULL);
|
|
}
|
|
_JumpErrorStr(hr, error, "SetupGetIntField", pwszKey);
|
|
}
|
|
*pdwValue = Value;
|
|
DBGPRINT((DBG_SS_CERTLIBI, "%ws = %u\n", pwszKey, *pdwValue));
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr && fLog)
|
|
{
|
|
INFSETERROR(hr, pwszSection, pwszKey, NULL);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetKeyLength -- fetch the renewal key length from CAPolicy.inf
|
|
//
|
|
// [certsrv_server]
|
|
// RenewalKeyLength = 2048
|
|
//
|
|
// Returns: DWORD key kength
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetKeyLength(
|
|
IN HINF hInf,
|
|
OUT DWORD *pdwKeyLength)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
myInfClearError();
|
|
hr = myInfGetNumericKeyValue(
|
|
hInf,
|
|
TRUE, // fLog
|
|
wszINFSECTION_CERTSERVER,
|
|
wszINFKEY_RENEWALKEYLENGTH,
|
|
pdwKeyLength);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"myInfGetNumericKeyValue",
|
|
wszINFKEY_RENEWALKEYLENGTH,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetKeyLength hr=%x --> len=%x\n",
|
|
hr,
|
|
*pdwKeyLength));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// infGetValidityPeriodSub -- fetch validity period & units from CAPolicy.inf
|
|
//
|
|
// [certsrv_server]
|
|
// xxxxValidityPeriod = 8 (count)
|
|
// xxxxValidityPeriodUnits = Years (string)
|
|
//
|
|
// Returns: validity period count and enum
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
infGetValidityPeriodSub(
|
|
IN HINF hInf,
|
|
IN BOOL fLog,
|
|
IN WCHAR const *pwszInfKeyNameCount,
|
|
IN WCHAR const *pwszInfKeyNameString,
|
|
OPTIONAL IN WCHAR const *pwszValidityPeriodCount,
|
|
OPTIONAL IN WCHAR const *pwszValidityPeriodString,
|
|
OUT DWORD *pdwValidityPeriodCount,
|
|
OUT ENUM_PERIOD *penumValidityPeriod)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
WCHAR *pwszStringValue = NULL;
|
|
BOOL fValidCount = TRUE;
|
|
UINT idsLog = IDS_ILOG_BAD_VALIDITY_STRING;
|
|
|
|
*pdwValidityPeriodCount = 0;
|
|
*penumValidityPeriod = ENUM_PERIOD_INVALID;
|
|
|
|
if (NULL == pwszValidityPeriodCount && NULL == pwszValidityPeriodString)
|
|
{
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
|
|
hr = myInfGetNumericKeyValue(
|
|
hInf,
|
|
fLog,
|
|
wszINFSECTION_CERTSERVER,
|
|
pwszInfKeyNameCount,
|
|
pdwValidityPeriodCount);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"myInfGetNumericKeyValue",
|
|
pwszInfKeyNameCount,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
hr = myInfGetKeyValue(
|
|
hInf,
|
|
fLog,
|
|
wszINFSECTION_CERTSERVER,
|
|
pwszInfKeyNameString,
|
|
&pwszStringValue);
|
|
if (S_OK != hr && fLog)
|
|
{
|
|
INFSETERROR(hr, wszINFSECTION_CERTSERVER, pwszInfKeyNameString, NULL);
|
|
}
|
|
_JumpIfErrorStr(hr, error, "myInfGetKeyValue", pwszInfKeyNameString);
|
|
|
|
pwszValidityPeriodString = pwszStringValue;
|
|
}
|
|
else
|
|
{
|
|
if (NULL != pwszValidityPeriodCount)
|
|
{
|
|
*pdwValidityPeriodCount = myWtoI(
|
|
pwszValidityPeriodCount,
|
|
&fValidCount);
|
|
}
|
|
idsLog = IDS_ILOG_BAD_VALIDITY_STRING_UNATTEND;
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"%ws = %u -- %ws = %ws\n",
|
|
pwszInfKeyNameCount,
|
|
*pdwValidityPeriodCount,
|
|
pwszInfKeyNameString,
|
|
pwszValidityPeriodString));
|
|
|
|
if (NULL != pwszValidityPeriodString)
|
|
{
|
|
if (0 == lstrcmpi(wszPERIODYEARS, pwszValidityPeriodString))
|
|
{
|
|
*penumValidityPeriod = ENUM_PERIOD_YEARS;
|
|
}
|
|
else if (0 == lstrcmpi(wszPERIODMONTHS, pwszValidityPeriodString))
|
|
{
|
|
*penumValidityPeriod = ENUM_PERIOD_MONTHS;
|
|
}
|
|
else if (0 == lstrcmpi(wszPERIODWEEKS, pwszValidityPeriodString))
|
|
{
|
|
*penumValidityPeriod = ENUM_PERIOD_WEEKS;
|
|
}
|
|
else if (0 == lstrcmpi(wszPERIODDAYS, pwszValidityPeriodString))
|
|
{
|
|
*penumValidityPeriod = ENUM_PERIOD_DAYS;
|
|
}
|
|
else if (fLog)
|
|
{
|
|
INFSETERROR(
|
|
hr,
|
|
wszINFSECTION_CERTSERVER,
|
|
pwszInfKeyNameString,
|
|
pwszValidityPeriodString);
|
|
}
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"%ws = %u (%ws)\n",
|
|
pwszInfKeyNameString,
|
|
*penumValidityPeriod,
|
|
pwszValidityPeriodString));
|
|
|
|
if (!fValidCount ||
|
|
(ENUM_PERIOD_YEARS == *penumValidityPeriod &&
|
|
fValidCount && 9999 < *pdwValidityPeriodCount))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
if (fLog)
|
|
{
|
|
WCHAR awcCount[20];
|
|
|
|
if (NULL == pwszValidityPeriodCount)
|
|
{
|
|
wsprintf(awcCount, L"%d", *pdwValidityPeriodCount);
|
|
}
|
|
INFSETERROR(
|
|
hr,
|
|
wszINFSECTION_CERTSERVER,
|
|
pwszInfKeyNameCount,
|
|
NULL != pwszValidityPeriodCount?
|
|
pwszValidityPeriodCount : awcCount);
|
|
CSILOG(
|
|
hr,
|
|
idsLog,
|
|
wszINFSECTION_CERTSERVER,
|
|
NULL == pwszValidityPeriodCount? pwszInfKeyNameCount : NULL,
|
|
pdwValidityPeriodCount);
|
|
}
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"bad ValidityPeriod count value",
|
|
pwszValidityPeriodCount);
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszStringValue)
|
|
{
|
|
LocalFree(pwszStringValue);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// infGetValidityPeriod -- fetch renewal period & units from CAPolicy.inf
|
|
//
|
|
// [certsrv_server]
|
|
// xxxxValidityPeriod = 8
|
|
// xxxxValidityPeriodUnits = Years
|
|
//
|
|
// Returns: validity period count and enum
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetValidityPeriod(
|
|
IN HINF hInf,
|
|
OPTIONAL IN WCHAR const *pwszValidityPeriodCount,
|
|
OPTIONAL IN WCHAR const *pwszValidityPeriodString,
|
|
OUT DWORD *pdwValidityPeriodCount,
|
|
OUT ENUM_PERIOD *penumValidityPeriod,
|
|
OPTIONAL OUT BOOL *pfSwap)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if ((NULL == hInf || INVALID_HANDLE_VALUE == hInf) &&
|
|
NULL == pwszValidityPeriodCount &&
|
|
NULL == pwszValidityPeriodString)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
myInfClearError();
|
|
|
|
if (NULL != pfSwap)
|
|
{
|
|
*pfSwap = FALSE;
|
|
}
|
|
|
|
// Try correct order:
|
|
// [certsrv_server]
|
|
// xxxxValidityPeriod = 8 (count)
|
|
// xxxxValidityPeriodUnits = Years (string)
|
|
|
|
hr = infGetValidityPeriodSub(
|
|
hInf,
|
|
TRUE,
|
|
wszINFKEY_RENEWALVALIDITYPERIODCOUNT,
|
|
wszINFKEY_RENEWALVALIDITYPERIODSTRING,
|
|
pwszValidityPeriodCount,
|
|
pwszValidityPeriodString,
|
|
pdwValidityPeriodCount,
|
|
penumValidityPeriod);
|
|
_PrintIfError2(hr, "infGetValidityPeriodSub", ERROR_LINE_NOT_FOUND);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
// Try backwards:
|
|
// [certsrv_server]
|
|
// xxxxValidityPeriodUnits = 8 (count)
|
|
// xxxxValidityPeriod = Years (string)
|
|
|
|
hr = infGetValidityPeriodSub(
|
|
hInf,
|
|
FALSE,
|
|
wszINFKEY_RENEWALVALIDITYPERIODSTRING,
|
|
wszINFKEY_RENEWALVALIDITYPERIODCOUNT,
|
|
pwszValidityPeriodString,
|
|
pwszValidityPeriodCount,
|
|
pdwValidityPeriodCount,
|
|
penumValidityPeriod);
|
|
_JumpIfError2(
|
|
hr,
|
|
error,
|
|
"infGetValidityPeriodSub",
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
if (NULL != pfSwap)
|
|
{
|
|
*pfSwap = TRUE;
|
|
}
|
|
}
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetValidityPeriod hr=%x --> c=%d, enum=%d\n",
|
|
hr,
|
|
*pdwValidityPeriodCount,
|
|
*penumValidityPeriod));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
infFindNextKey(
|
|
IN WCHAR const *pwszKey,
|
|
IN OUT INFCONTEXT *pInfContext)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cwc;
|
|
WCHAR wszKey[MAX_PATH];
|
|
|
|
while (TRUE)
|
|
{
|
|
if (!SetupFindNextLine(pInfContext, pInfContext))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintErrorStr2(hr, "SetupFindNextLine", pwszKey, hr);
|
|
if ((HRESULT) ERROR_LINE_NOT_FOUND == hr)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
_JumpError2(hr, error, "SetupFindNextLine", hr);
|
|
}
|
|
if (!SetupGetStringField(
|
|
pInfContext,
|
|
0,
|
|
wszKey,
|
|
ARRAYSIZE(wszKey),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
if (0 == lstrcmpi(pwszKey, wszKey))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetKeyList -- fetch a list of key values from CAPolicy.inf
|
|
//
|
|
// [pwszSection]
|
|
// pwszKey = Value1
|
|
// pwszKey = Value2
|
|
//
|
|
// Returns: double null terminated list of values
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetKeyList(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
IN WCHAR const *pwszKey,
|
|
OUT BOOL *pfCritical,
|
|
OUT WCHAR **ppwszz)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
DWORD iVal;
|
|
DWORD cwc;
|
|
WCHAR *pwsz;
|
|
WCHAR **apwszVal = NULL;
|
|
DWORD cVal;
|
|
WCHAR *pwszBuf = NULL;
|
|
DWORD cwcBuf = 0;
|
|
|
|
*ppwszz = NULL;
|
|
*pfCritical = FALSE;
|
|
myInfClearError();
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
hr = infSetupFindFirstLine(hInf, pwszSection, pwszKey, &InfContext);
|
|
if (S_OK != hr)
|
|
{
|
|
CSILOG(hr, IDS_ILOG_CAPOLICY_NOKEY, pwszSection, pwszKey, NULL);
|
|
_JumpErrorStr3(
|
|
hr,
|
|
error,
|
|
"infSetupFindFirstLine",
|
|
pwszSection,
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
}
|
|
|
|
cVal = 0;
|
|
while (TRUE)
|
|
{
|
|
if (!SetupGetStringField(&InfContext, 1, NULL, 0, &cwc))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr(hr, error, "SetupGetStringField", pwszKey);
|
|
}
|
|
cVal++;
|
|
if (cwcBuf < cwc)
|
|
{
|
|
cwcBuf = cwc;
|
|
}
|
|
hr = infFindNextKey(pwszKey, &InfContext);
|
|
if (S_FALSE == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfErrorStr(hr, error, "infFindNextKey", pwszKey);
|
|
}
|
|
|
|
pwszBuf = (WCHAR *) LocalAlloc(LMEM_FIXED, cwcBuf * sizeof(WCHAR));
|
|
if (NULL == pwszBuf)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
apwszVal = (WCHAR **) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cVal * sizeof(apwszVal[0]));
|
|
if (NULL == apwszVal)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
hr = infSetupFindFirstLine(hInf, pwszSection, pwszKey, &InfContext);
|
|
_JumpIfErrorStr(hr, error, "infSetupFindFirstLine", pwszSection);
|
|
|
|
cwc = 1;
|
|
iVal = 0;
|
|
while (TRUE)
|
|
{
|
|
if (!SetupGetStringField(&InfContext, 1, pwszBuf, cwcBuf, NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr(hr, error, "SetupGetStringField", pwszKey);
|
|
}
|
|
|
|
hr = myDupString(pwszBuf, &apwszVal[iVal]);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
DBGPRINT((DBG_SS_CERTLIBI, "%ws = %ws\n", pwszKey, apwszVal[iVal]));
|
|
|
|
cwc += wcslen(apwszVal[iVal]) + 1;
|
|
iVal++;
|
|
|
|
hr = infFindNextKey(pwszKey, &InfContext);
|
|
if (S_FALSE == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfErrorStr(hr, error, "infFindNextKey", pwszKey);
|
|
}
|
|
CSASSERT(iVal == cVal);
|
|
|
|
*ppwszz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
|
|
if (NULL == *ppwszz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
pwsz = *ppwszz;
|
|
for (iVal = 0; iVal < cVal; iVal++)
|
|
{
|
|
wcscpy(pwsz, apwszVal[iVal]);
|
|
pwsz += wcslen(pwsz) + 1;
|
|
}
|
|
*pwsz = L'\0';
|
|
CSASSERT(cwc == 1 + SAFE_SUBTRACT_POINTERS(pwsz, *ppwszz));
|
|
|
|
if (NULL != pfCritical)
|
|
{
|
|
hr = infGetCriticalFlag(hInf, pwszSection, FALSE, pfCritical);
|
|
_JumpIfError(hr, error, "infGetCriticalFlag");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
INFSETERROR(hr, pwszSection, pwszKey, NULL);
|
|
}
|
|
if (NULL != apwszVal)
|
|
{
|
|
for (iVal = 0; iVal < cVal; iVal++)
|
|
{
|
|
if (NULL != apwszVal[iVal])
|
|
{
|
|
LocalFree(apwszVal[iVal]);
|
|
}
|
|
}
|
|
LocalFree(apwszVal);
|
|
}
|
|
if (NULL != pwszBuf)
|
|
{
|
|
LocalFree(pwszBuf);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetCRLDistributionPoints -- fetch CDP URLs from CAPolicy.inf
|
|
//
|
|
// [CRLDistributionPoint]
|
|
// URL = http://CRLhttp.site.com/Public/MyCA.crl
|
|
// URL = ftp://CRLftp.site.com/Public/MyCA.crl
|
|
//
|
|
// Returns: double null terminated list of CDP URLs
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetCRLDistributionPoints(
|
|
IN HINF hInf,
|
|
OUT BOOL *pfCritical,
|
|
OUT WCHAR **ppwszz)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = myInfGetKeyList(
|
|
hInf,
|
|
wszINFSECTION_CDP,
|
|
wszINFKEY_URL,
|
|
pfCritical,
|
|
ppwszz);
|
|
_JumpIfErrorStr4(
|
|
hr,
|
|
error,
|
|
"myInfGetKeyList",
|
|
wszINFSECTION_CDP,
|
|
ERROR_LINE_NOT_FOUND,
|
|
S_FALSE,
|
|
E_HANDLE);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetCRLDistributionPoints hr=%x --> f=%d\n",
|
|
hr,
|
|
*pfCritical));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetAuthorityInformationAccess -- fetch AIA URLs from CAPolicy.inf
|
|
//
|
|
// [AuthorityInformationAccess]
|
|
// URL = http://CRThttp.site.com/Public/MyCA.crt
|
|
// URL = ftp://CRTftp.site.com/Public/MyCA.crt
|
|
//
|
|
// Returns: double null terminated list of AIA URLs
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetAuthorityInformationAccess(
|
|
IN HINF hInf,
|
|
OUT BOOL *pfCritical,
|
|
OUT WCHAR **ppwszz)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = myInfGetKeyList(
|
|
hInf,
|
|
wszINFSECTION_AIA,
|
|
wszINFKEY_URL,
|
|
pfCritical,
|
|
ppwszz);
|
|
_JumpIfErrorStr4(
|
|
hr,
|
|
error,
|
|
"myInfGetKeyList",
|
|
wszINFSECTION_AIA,
|
|
ERROR_LINE_NOT_FOUND,
|
|
S_FALSE,
|
|
E_HANDLE);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetAuthorityInformationAccess hr=%x --> f=%d\n",
|
|
hr,
|
|
*pfCritical));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetEnhancedKeyUsage -- fetch EKU OIDS from CAPolicy.inf
|
|
//
|
|
// [EnhancedKeyUsage]
|
|
// OID = 1.2.3.4.5
|
|
// OID = 1.2.3.4.6
|
|
//
|
|
// Returns: double null terminated list of EKU OIDs
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetEnhancedKeyUsage(
|
|
IN HINF hInf,
|
|
OUT BOOL *pfCritical,
|
|
OUT WCHAR **ppwszz)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = myInfGetKeyList(
|
|
hInf,
|
|
wszINFSECTION_EKU,
|
|
wszINFKEY_OID,
|
|
pfCritical,
|
|
ppwszz);
|
|
_JumpIfErrorStr4(
|
|
hr,
|
|
error,
|
|
"myInfGetKeyList",
|
|
wszINFSECTION_EKU,
|
|
ERROR_LINE_NOT_FOUND,
|
|
S_FALSE,
|
|
E_HANDLE);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetEnhancedKeyUsage hr=%x --> f=%d\n",
|
|
hr,
|
|
*pfCritical));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// infGetBasicConstraints2CAExtension -- fetch basic constraints extension
|
|
// from INF file, setting the SubjectType flag to CA
|
|
//
|
|
// If the INF handle is bad, or if the INF section does not exist, construct
|
|
// a default extension only if fDefault is set, otherwise fail.
|
|
//
|
|
// [BasicConstraintsExtension]
|
|
// ; Subject Type is not supported -- always set to CA
|
|
// ; maximum subordinate CA path length
|
|
// PathLength = 3
|
|
//
|
|
// Return S_OK if extension has been constructed from INF file.
|
|
//
|
|
// Returns: encoded basic constraints extension
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
infGetBasicConstraints2CAExtension(
|
|
IN BOOL fDefault,
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
CERT_BASIC_CONSTRAINTS2_INFO bc2i;
|
|
INFCONTEXT InfContext;
|
|
|
|
ZeroMemory(pext, sizeof(*pext));
|
|
ZeroMemory(&bc2i, sizeof(bc2i));
|
|
myInfClearError();
|
|
|
|
pext->fCritical = TRUE; // default value for both INF and default cases
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
if (!fDefault)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = infSetupFindFirstLine(
|
|
hInf,
|
|
wszINFSECTION_BASICCONSTRAINTS,
|
|
NULL,
|
|
&InfContext);
|
|
if (S_OK != hr)
|
|
{
|
|
if (!fDefault)
|
|
{
|
|
_JumpErrorStr3(
|
|
hr,
|
|
error,
|
|
"infSetupFindFirstLine",
|
|
wszINFSECTION_BASICCONSTRAINTS,
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = infGetCriticalFlag(
|
|
hInf,
|
|
wszINFSECTION_BASICCONSTRAINTS,
|
|
pext->fCritical, // fDefault
|
|
&pext->fCritical);
|
|
_JumpIfError(hr, error, "infGetCriticalFlag");
|
|
|
|
bc2i.fPathLenConstraint = TRUE;
|
|
hr = myInfGetNumericKeyValue(
|
|
hInf,
|
|
TRUE, // fLog
|
|
wszINFSECTION_BASICCONSTRAINTS,
|
|
wszINFKEY_PATHLENGTH,
|
|
&bc2i.dwPathLenConstraint);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"myInfGetNumericKeyValue",
|
|
wszINFKEY_PATHLENGTH,
|
|
ERROR_LINE_NOT_FOUND);
|
|
if ((HRESULT) ERROR_LINE_NOT_FOUND != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
bc2i.dwPathLenConstraint = 0;
|
|
bc2i.fPathLenConstraint = FALSE;
|
|
}
|
|
}
|
|
}
|
|
bc2i.fCA = TRUE;
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
&bc2i,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pext->Value.pbData,
|
|
&pext->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
INFSETERROR(hr, wszINFSECTION_BASICCONSTRAINTS, NULL, NULL);
|
|
}
|
|
pext->pszObjId = szOID_BASIC_CONSTRAINTS2; // on error, too!
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetBasicConstraints2CAExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
return(hr);
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// myInfGetBasicConstraints2CAExtension -- fetch basic constraints extension
|
|
// from INF file, setting the SubjectType flag to CA
|
|
//
|
|
// [BasicConstraintsExtension]
|
|
// ; Subject Type is not supported -- always set to CA
|
|
// ; maximum subordinate CA path length
|
|
// PathLength = 3
|
|
//
|
|
// Return S_OK if extension has been constructed from INF file.
|
|
//
|
|
// Returns: encoded basic constraints extension
|
|
//+--------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetBasicConstraints2CAExtension;
|
|
|
|
HRESULT
|
|
myInfGetBasicConstraints2CAExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = infGetBasicConstraints2CAExtension(FALSE, hInf, pext);
|
|
_JumpIfError3(
|
|
hr,
|
|
error,
|
|
"infGetBasicConstraints2CAExtension",
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
FNMYINFGETEXTENSION myInfGetBasicConstraints2CAExtensionOrDefault;
|
|
|
|
HRESULT
|
|
myInfGetBasicConstraints2CAExtensionOrDefault(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = infGetBasicConstraints2CAExtension(TRUE, hInf, pext);
|
|
_JumpIfError(hr, error, "infGetBasicConstraints2CAExtension");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// myInfGetEnhancedKeyUsageExtension -- fetch EKU extension from INF file
|
|
//
|
|
// [EnhancedKeyUsageExtension]
|
|
// OID = 1.2.3.4.5
|
|
// OID = 1.2.3.4.6
|
|
//
|
|
// Return S_OK if extension has been constructed from INF file.
|
|
// Return S_FALSE if empty section detected in INF file
|
|
// Return other error if no section detected in INF file
|
|
//
|
|
// Returns: encoded enhanced key usage extension
|
|
//+--------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetEnhancedKeyUsageExtension;
|
|
|
|
HRESULT
|
|
myInfGetEnhancedKeyUsageExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
DWORD cEKU = 0;
|
|
WCHAR *pwszzEKU = NULL;
|
|
WCHAR *pwszCurrentEKU;
|
|
CERT_ENHKEY_USAGE ceku;
|
|
|
|
ceku.rgpszUsageIdentifier = NULL;
|
|
ZeroMemory(pext, sizeof(*pext));
|
|
myInfClearError();
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
hr = myInfGetEnhancedKeyUsage(hInf, &pext->fCritical, &pwszzEKU);
|
|
_JumpIfError3(
|
|
hr,
|
|
error,
|
|
"myInfGetEnhancedKeyUsage",
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
pwszCurrentEKU = pwszzEKU;
|
|
if (NULL != pwszCurrentEKU)
|
|
{
|
|
while (L'\0' != *pwszCurrentEKU)
|
|
{
|
|
cEKU++;
|
|
pwszCurrentEKU += wcslen(pwszCurrentEKU) + 1;
|
|
}
|
|
}
|
|
if (0 == cEKU)
|
|
{
|
|
hr = S_FALSE;
|
|
goto error;
|
|
}
|
|
|
|
ceku.cUsageIdentifier = cEKU;
|
|
ceku.rgpszUsageIdentifier = (char **) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(ceku.rgpszUsageIdentifier[0]) * cEKU);
|
|
if (NULL == ceku.rgpszUsageIdentifier)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpIfError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
cEKU = 0;
|
|
pwszCurrentEKU = pwszzEKU;
|
|
while (L'\0' != *pwszCurrentEKU)
|
|
{
|
|
if (!ConvertWszToSz(&ceku.rgpszUsageIdentifier[cEKU], pwszCurrentEKU, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToSz");
|
|
}
|
|
cEKU++;
|
|
pwszCurrentEKU += wcslen(pwszCurrentEKU) + 1;
|
|
}
|
|
CSASSERT(ceku.cUsageIdentifier == cEKU);
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_ENHANCED_KEY_USAGE,
|
|
&ceku,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pext->Value.pbData,
|
|
&pext->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr && E_HANDLE != hr)
|
|
{
|
|
INFSETERROR(hr, wszINFSECTION_EKU, NULL, NULL);
|
|
}
|
|
pext->pszObjId = szOID_ENHANCED_KEY_USAGE; // on error, too!
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetEnhancedKeyUsageExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
if (NULL != ceku.rgpszUsageIdentifier)
|
|
{
|
|
for (i = 0; i < ceku.cUsageIdentifier; i++)
|
|
{
|
|
if (NULL != ceku.rgpszUsageIdentifier[i])
|
|
{
|
|
LocalFree(ceku.rgpszUsageIdentifier[i]);
|
|
}
|
|
}
|
|
LocalFree(ceku.rgpszUsageIdentifier);
|
|
}
|
|
if (NULL != pwszzEKU)
|
|
{
|
|
LocalFree(pwszzEKU);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infAddAttribute(
|
|
IN CRYPT_ATTR_BLOB const *pAttribute,
|
|
IN OUT DWORD *pcAttribute,
|
|
IN OUT CRYPT_ATTR_BLOB **ppaAttribute)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_ATTR_BLOB *pAttribT;
|
|
|
|
if (NULL == *ppaAttribute)
|
|
{
|
|
CSASSERT(0 == *pcAttribute);
|
|
pAttribT = (CRYPT_ATTR_BLOB *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
sizeof(**ppaAttribute));
|
|
}
|
|
else
|
|
{
|
|
CSASSERT(0 != *pcAttribute);
|
|
pAttribT = (CRYPT_ATTR_BLOB *) LocalReAlloc(
|
|
*ppaAttribute,
|
|
(*pcAttribute + 1) * sizeof(**ppaAttribute),
|
|
LMEM_MOVEABLE);
|
|
}
|
|
if (NULL == pAttribT)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(
|
|
hr,
|
|
error,
|
|
NULL == *ppaAttribute? "LocalAlloc" : "LocalReAlloc");
|
|
}
|
|
*ppaAttribute = pAttribT;
|
|
pAttribT[(*pcAttribute)++] = *pAttribute;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
myInfFreeRequestAttributes(
|
|
IN DWORD cAttribute,
|
|
IN OUT CRYPT_ATTR_BLOB *paAttribute)
|
|
{
|
|
if (NULL != paAttribute)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < cAttribute; i++)
|
|
{
|
|
if (NULL != paAttribute[i].pbData)
|
|
{
|
|
LocalFree(paAttribute[i].pbData);
|
|
}
|
|
}
|
|
LocalFree(paAttribute);
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetRequestAttributes -- fetch request attributes from INF file
|
|
//
|
|
// [RequestAttributes]
|
|
// AttributeName1 = AttributeValue1
|
|
// AttributeName2 = AttributeValue2
|
|
// ...
|
|
// AttributeNameN = AttributeValueN
|
|
//
|
|
// Returns: array of encoded attribute blobs
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetRequestAttributes(
|
|
IN HINF hInf,
|
|
OUT DWORD *pcAttribute,
|
|
OUT CRYPT_ATTR_BLOB **ppaAttribute,
|
|
OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
WCHAR wszName[MAX_PATH];
|
|
WCHAR wszValue[cwcVALUEMAX];
|
|
DWORD i;
|
|
DWORD cAttribute = 0;
|
|
CRYPT_ATTR_BLOB Attribute;
|
|
WCHAR *pwszTemplateName = NULL;
|
|
|
|
*ppwszTemplateName = NULL;
|
|
*pcAttribute = 0;
|
|
*ppaAttribute = NULL;
|
|
Attribute.pbData = NULL;
|
|
wszName[0] = L'\0';
|
|
wszValue[0] = L'\0';
|
|
myInfClearError();
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
hr = infSetupFindFirstLine(
|
|
hInf,
|
|
wszINFSECTION_REQUESTATTRIBUTES,
|
|
NULL, // Key
|
|
&InfContext);
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"infSetupFindFirstLine",
|
|
wszINFSECTION_REQUESTATTRIBUTES);
|
|
|
|
while (TRUE)
|
|
{
|
|
CRYPT_ENROLLMENT_NAME_VALUE_PAIR NamePair;
|
|
|
|
wszName[0] = L'\0';
|
|
wszValue[0] = L'\0';
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
0,
|
|
wszName,
|
|
ARRAYSIZE(wszName),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
1,
|
|
wszValue,
|
|
ARRAYSIZE(wszValue),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
|
|
//wprintf(L"%ws = %ws\n", wszName, wszValue);
|
|
|
|
NamePair.pwszName = wszName;
|
|
NamePair.pwszValue = wszValue;
|
|
|
|
if (0 == lstrcmpi(wszPROPCERTTEMPLATE, wszName))
|
|
{
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "Duplicate cert template");
|
|
}
|
|
hr = myDupString(wszValue, &pwszTemplateName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
// X509__ENROLLMENT_NAME_VALUE_PAIR
|
|
szOID_ENROLLMENT_NAME_VALUE_PAIR,
|
|
&NamePair,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&Attribute.pbData,
|
|
&Attribute.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
hr = infAddAttribute(&Attribute, &cAttribute, ppaAttribute);
|
|
_JumpIfError(hr, error, "infAddAttribute");
|
|
|
|
Attribute.pbData = NULL;
|
|
|
|
if (!SetupFindNextLine(&InfContext, &InfContext))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError2(hr, "SetupFindNextLine(end)", hr);
|
|
break;
|
|
}
|
|
}
|
|
*pcAttribute = cAttribute;
|
|
cAttribute = 0;
|
|
*ppwszTemplateName = pwszTemplateName;
|
|
pwszTemplateName = NULL;
|
|
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
INFSETERROR(hr, wszINFSECTION_REQUESTATTRIBUTES, wszName, wszValue);
|
|
}
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
LocalFree(pwszTemplateName);
|
|
}
|
|
if (NULL != Attribute.pbData)
|
|
{
|
|
LocalFree(Attribute.pbData);
|
|
}
|
|
if (0 != cAttribute)
|
|
{
|
|
myInfFreeRequestAttributes(cAttribute, *ppaAttribute);
|
|
*ppaAttribute = NULL;
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetRequestAttributes hr=%x --> c=%d\n",
|
|
hr,
|
|
*pcAttribute));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
typedef struct _SUBTREEINFO
|
|
{
|
|
BOOL fEmptyDefault;
|
|
DWORD dwInfMinMaxIndexBase;
|
|
DWORD dwAltNameChoice;
|
|
WCHAR const *pwszKey;
|
|
} SUBTREEINFO;
|
|
|
|
SUBTREEINFO g_aSubTreeInfo[] = {
|
|
{ TRUE, 2, CERT_ALT_NAME_OTHER_NAME, wszINFKEY_UPN },
|
|
{ TRUE, 2, CERT_ALT_NAME_RFC822_NAME, wszINFKEY_EMAIL },
|
|
{ TRUE, 2, CERT_ALT_NAME_DNS_NAME, wszINFKEY_DNS },
|
|
{ TRUE, 2, CERT_ALT_NAME_DIRECTORY_NAME, wszINFKEY_DIRECTORYNAME },
|
|
{ TRUE, 2, CERT_ALT_NAME_URL, wszINFKEY_URL },
|
|
{ TRUE, 3, CERT_ALT_NAME_IP_ADDRESS, wszINFKEY_IPADDRESS },
|
|
{ FALSE, 2, CERT_ALT_NAME_REGISTERED_ID, wszINFKEY_REGISTEREDID },
|
|
};
|
|
#define CSUBTREEINFO ARRAYSIZE(g_aSubTreeInfo)
|
|
|
|
#define STII_UPNOTHERNAME 0 // CERT_ALT_NAME_OTHER_NAME pOtherName
|
|
#define STII_RFC822NAME 1 // CERT_ALT_NAME_RFC822_NAME pwszRfc822Name
|
|
#define STII_DNSNAME 2 // CERT_ALT_NAME_DNS_NAME pwszDNSName
|
|
#define STII_DIRECTORYNAME 3 // CERT_ALT_NAME_DIRECTORY_NAME DirectoryName
|
|
#define STII_URL 4 // CERT_ALT_NAME_URL pwszURL
|
|
#define STII_IPADDRESS 5 // CERT_ALT_NAME_IP_ADDRESS IPAddress
|
|
#define STII_REGISTEREDID 6 // CERT_ALT_NAME_REGISTERED_ID pszRegisteredID
|
|
|
|
|
|
VOID
|
|
infFreeGeneralSubTreeElement(
|
|
IN OUT CERT_GENERAL_SUBTREE *pSubTree)
|
|
{
|
|
CERT_ALT_NAME_ENTRY *pName = &pSubTree->Base;
|
|
VOID **ppv = NULL;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infFreeGeneralSubTreeElement: p=%x, choice=%x\n",
|
|
pSubTree,
|
|
pName->dwAltNameChoice));
|
|
switch (pName->dwAltNameChoice)
|
|
{
|
|
case CERT_ALT_NAME_OTHER_NAME:
|
|
ppv = (VOID **) &pName->pOtherName;
|
|
if (NULL != pName->pOtherName &&
|
|
NULL != pName->pOtherName->Value.pbData)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infFreeGeneralSubTreeElement: p=%x, Free(other.pbData=%x\n)",
|
|
pSubTree,
|
|
pName->pOtherName->Value.pbData));
|
|
LocalFree(pName->pOtherName->Value.pbData);
|
|
}
|
|
break;
|
|
|
|
case CERT_ALT_NAME_RFC822_NAME:
|
|
ppv = (VOID **) &pName->pwszRfc822Name;
|
|
break;
|
|
|
|
case CERT_ALT_NAME_DNS_NAME:
|
|
ppv = (VOID **) &pName->pwszDNSName;
|
|
break;
|
|
|
|
case CERT_ALT_NAME_DIRECTORY_NAME:
|
|
ppv = (VOID **) &pName->DirectoryName.pbData;
|
|
break;
|
|
|
|
case CERT_ALT_NAME_URL:
|
|
ppv = (VOID **) &pName->pwszURL;
|
|
break;
|
|
|
|
case CERT_ALT_NAME_IP_ADDRESS:
|
|
ppv = (VOID **) &pName->IPAddress.pbData;
|
|
break;
|
|
|
|
case CERT_ALT_NAME_REGISTERED_ID:
|
|
ppv = (VOID **) &pName->pszRegisteredID;
|
|
break;
|
|
}
|
|
if (NULL != ppv && NULL != *ppv)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infFreeGeneralSubTreeElement: p=%x, Free(pv=%x)\n",
|
|
pSubTree,
|
|
*ppv));
|
|
LocalFree(*ppv);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
infFreeGeneralSubTree(
|
|
IN DWORD cSubTree,
|
|
IN OUT CERT_GENERAL_SUBTREE *pSubTree)
|
|
{
|
|
if (NULL != pSubTree)
|
|
{
|
|
DWORD i;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infFreeGeneralSubTree: p=%x, c=%x\n",
|
|
pSubTree,
|
|
cSubTree));
|
|
for (i = 0; i < cSubTree; i++)
|
|
{
|
|
infFreeGeneralSubTreeElement(&pSubTree[i]);
|
|
}
|
|
LocalFree(pSubTree);
|
|
}
|
|
}
|
|
|
|
|
|
// Destructively parse an old-style 4 byte IP Address.
|
|
|
|
#define CB_IPV4ADDRESS 4
|
|
|
|
HRESULT
|
|
infParseIPV4Address(
|
|
IN WCHAR *pwszValue,
|
|
OUT BYTE *pb,
|
|
IN OUT DWORD *pcb)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cb;
|
|
|
|
DBGPRINT((DBG_SS_CERTLIBI, "infParseIPV4Address(%ws)\n", pwszValue));
|
|
if (CB_IPV4ADDRESS > *pcb)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
_JumpError(hr, error, "buffer too small");
|
|
}
|
|
for (cb = 0; cb < CB_IPV4ADDRESS; cb++)
|
|
{
|
|
WCHAR *pwszNext;
|
|
BOOL fValid;
|
|
DWORD dw;
|
|
|
|
pwszNext = &pwszValue[wcscspn(pwszValue, L".")];
|
|
if (L'.' == *pwszNext)
|
|
{
|
|
*pwszNext++ = L'\0';
|
|
}
|
|
dw = myWtoI(pwszValue, &fValid);
|
|
if (!fValid || 255 < dw)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpErrorStr(hr, error, "bad IP Address digit string", pwszValue);
|
|
}
|
|
pb[cb] = (BYTE) dw;
|
|
pwszValue = pwszNext;
|
|
}
|
|
if (L'\0' != *pwszValue)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "extra data");
|
|
}
|
|
*pcb = cb;
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infParseIPV4Address: %u.%u.%u.%u\n",
|
|
pb[0],
|
|
pb[1],
|
|
pb[2],
|
|
pb[3]));
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// Destructively parse a new-style 16 byte IP Address.
|
|
|
|
#define CB_IPV6ADDRESS 16
|
|
#define MAKE16(b0, b1) (((b0) << 8) | (b1))
|
|
|
|
|
|
HRESULT
|
|
infParseIPV6AddressSub(
|
|
IN WCHAR *pwszValue,
|
|
OUT BYTE *pb,
|
|
IN OUT DWORD *pcb)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cbMax = *pcb;
|
|
DWORD cb;
|
|
WCHAR *pwsz;
|
|
|
|
DBGPRINT((DBG_SS_CERTLIBI, "infParseIPV6AddressSub(%ws)\n", pwszValue));
|
|
ZeroMemory(pb, cbMax);
|
|
|
|
for (cb = 0; cb < cbMax; cb += 2)
|
|
{
|
|
WCHAR *pwszNext;
|
|
BOOL fValid;
|
|
DWORD dw;
|
|
WCHAR awc[7];
|
|
|
|
pwszNext = &pwszValue[wcscspn(pwszValue, L":")];
|
|
if (L':' == *pwszNext)
|
|
{
|
|
*pwszNext++ = L'\0';
|
|
}
|
|
if (L'\0' == *pwszValue)
|
|
{
|
|
break;
|
|
}
|
|
if (4 < wcslen(pwszValue))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpErrorStr(hr, error, "too many IP Address digits", pwszValue);
|
|
}
|
|
wcscpy(awc, L"0x");
|
|
wcscat(awc, pwszValue);
|
|
CSASSERT(wcslen(awc) < ARRAYSIZE(awc));
|
|
|
|
dw = myWtoI(awc, &fValid);
|
|
if (!fValid || 64 * 1024 <= dw)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpErrorStr(hr, error, "bad IP Address digit string", pwszValue);
|
|
}
|
|
pb[cb] = (BYTE) (dw >> 8);
|
|
pb[cb + 1] = (BYTE) dw;
|
|
pwszValue = pwszNext;
|
|
}
|
|
if (L'\0' != *pwszValue)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpErrorStr(hr, error, "extra data", pwszValue);
|
|
}
|
|
*pcb = cb;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// Destructively parse a new-style 16 byte IP Address.
|
|
|
|
HRESULT
|
|
infParseIPV6Address(
|
|
IN WCHAR *pwszValue,
|
|
OUT BYTE *pb,
|
|
IN OUT DWORD *pcb)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cbMax;
|
|
WCHAR *pwsz;
|
|
WCHAR *pwszLeft;
|
|
WCHAR *pwszRight;
|
|
BYTE abRight[CB_IPV6ADDRESS];
|
|
DWORD cbLeft;
|
|
DWORD cbRight;
|
|
DWORD i;
|
|
BOOL fV4Compat;
|
|
|
|
DBGPRINT((DBG_SS_CERTLIBI, "infParseIPV6Address(%ws)\n", pwszValue));
|
|
if (CB_IPV6ADDRESS > *pcb)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
_JumpError(hr, error, "buffer too small");
|
|
}
|
|
ZeroMemory(pb, CB_IPV6ADDRESS);
|
|
cbMax = CB_IPV6ADDRESS;
|
|
|
|
// If there's a period after the last colon, an IP V4 Address is attached.
|
|
// Parse it as an IP V4 Address, and reduce the expected size of the IP V6
|
|
// Address to be parsed from eight to six 16-bit address chunks.
|
|
|
|
pwsz = wcsrchr(pwszValue, L':');
|
|
if (NULL != pwsz)
|
|
{
|
|
if (NULL != wcschr(pwsz, L'.'))
|
|
{
|
|
DWORD cb = CB_IPV4ADDRESS;
|
|
|
|
hr = infParseIPV4Address(
|
|
&pwsz[1],
|
|
&pb[CB_IPV6ADDRESS - CB_IPV4ADDRESS],
|
|
&cb);
|
|
_JumpIfError(hr, error, "infParseIPV4Address");
|
|
|
|
CSASSERT(CB_IPV4ADDRESS == cb);
|
|
|
|
pwsz[1] = L'\0'; // get rid of the trailing IP V4 Address
|
|
|
|
// drop the trailing colon -- if it's not part of a double colon.
|
|
|
|
if (pwsz > pwszValue && L':' != *--pwsz)
|
|
{
|
|
pwsz[1] = L'\0';
|
|
}
|
|
cbMax -= CB_IPV4ADDRESS;
|
|
}
|
|
}
|
|
cbLeft = 0;
|
|
cbRight = 0;
|
|
pwszLeft = pwszValue;
|
|
pwszRight = wcsstr(pwszValue, L"::");
|
|
if (NULL != pwszRight)
|
|
{
|
|
*pwszRight = L'\0';
|
|
pwszRight += 2;
|
|
if (L'\0' != *pwszRight)
|
|
{
|
|
cbRight = cbMax;
|
|
hr = infParseIPV6AddressSub(pwszRight, abRight, &cbRight);
|
|
_JumpIfError(hr, error, "infParseIPV6AddressSub");
|
|
}
|
|
}
|
|
|
|
if (L'\0' != *pwszLeft)
|
|
{
|
|
cbLeft = cbMax;
|
|
hr = infParseIPV6AddressSub(pwszLeft, pb, &cbLeft);
|
|
_JumpIfError(hr, error, "infParseIPV6AddressSub");
|
|
}
|
|
if (NULL == pwszRight && cbLeft != cbMax)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "too few IP Address chunks");
|
|
}
|
|
if (cbLeft + cbRight + (NULL != pwszRight? 1 : 0) > cbMax)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "too many IP Address chunks");
|
|
}
|
|
if (0 != cbRight)
|
|
{
|
|
CopyMemory(&pb[cbMax - cbRight], abRight, cbRight);
|
|
}
|
|
*pcb = CB_IPV6ADDRESS;
|
|
|
|
fV4Compat = TRUE;
|
|
for (i = 0; i < CB_IPV6ADDRESS - CB_IPV4ADDRESS - 2; i++)
|
|
{
|
|
if (0 != pb[i])
|
|
{
|
|
fV4Compat = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (fV4Compat)
|
|
{
|
|
CSASSERT(i == CB_IPV6ADDRESS - CB_IPV4ADDRESS - 2);
|
|
fV4Compat = (0 == pb[i] && 0 == pb[i + 1]) ||
|
|
(0xff == pb[i] && 0xff == pb[i + 1]);
|
|
}
|
|
if (fV4Compat)
|
|
{
|
|
CSASSERT(i == CB_IPV6ADDRESS - CB_IPV4ADDRESS - 2);
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIB,
|
|
"infParseIPV6Address: ::%hs%u.%u.%u.%u\n",
|
|
0 == pb[i]? "" : "ffff:",
|
|
pb[12],
|
|
pb[13],
|
|
pb[14],
|
|
pb[15]));
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIB,
|
|
"infParseIPV6Address: %x:%x:%x:%x:%x:%x:%x:%x\n",
|
|
MAKE16(pb[0], pb[1]),
|
|
MAKE16(pb[2], pb[3]),
|
|
MAKE16(pb[4], pb[5]),
|
|
MAKE16(pb[6], pb[7]),
|
|
MAKE16(pb[8], pb[9]),
|
|
MAKE16(pb[10], pb[11]),
|
|
MAKE16(pb[12], pb[13]),
|
|
MAKE16(pb[14], pb[15])));
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infParseIPAddress(
|
|
IN WCHAR const *pwszValue,
|
|
OUT BYTE *pbData,
|
|
OUT DWORD *pcbData)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cb = *pcbData;
|
|
WCHAR *pwszDup = NULL;
|
|
WCHAR *pwsz;
|
|
|
|
// if pwszValue is an empty string, return zero length.
|
|
|
|
*pcbData = 0;
|
|
if (L'\0' != *pwszValue)
|
|
{
|
|
hr = myDupString(pwszValue, &pwszDup);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
if (NULL == wcschr(pwszDup, L':'))
|
|
{
|
|
hr = infParseIPV4Address(pwszDup, pbData, &cb);
|
|
_JumpIfError(hr, error, "infParseIPV4Address");
|
|
}
|
|
else
|
|
{
|
|
hr = infParseIPV6Address(pwszDup, pbData, &cb);
|
|
_JumpIfError(hr, error, "infParseIPV6Address");
|
|
}
|
|
*pcbData = cb;
|
|
DBGDUMPHEX((
|
|
DBG_SS_CERTLIBI,
|
|
DH_NOADDRESS | DH_NOTABPREFIX | 8,
|
|
pbData,
|
|
*pcbData));
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
INFSETERROR(hr, NULL, NULL, pwszValue);
|
|
}
|
|
if (NULL != pwszDup)
|
|
{
|
|
LocalFree(pwszDup);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
infParseIPAddressAndMask(
|
|
IN WCHAR const *pwszIPAddress,
|
|
IN WCHAR const *pwszIPAddressMask,
|
|
OUT BYTE **ppbData,
|
|
OUT DWORD *pcbData)
|
|
{
|
|
HRESULT hr;
|
|
BYTE ab[2 * CB_IPV6ADDRESS];
|
|
DWORD cb;
|
|
DWORD cbAddress;
|
|
DWORD cbMask;
|
|
WCHAR *pwsz;
|
|
|
|
*ppbData = NULL;
|
|
*pcbData = 0;
|
|
|
|
// if pwszValue is an empty string, encode zero length blob.
|
|
|
|
cb = 0;
|
|
if (L'\0' != *pwszIPAddress && L'\0' != *pwszIPAddressMask)
|
|
{
|
|
cbAddress = sizeof(ab) / 2;
|
|
|
|
hr = infParseIPAddress(pwszIPAddress, ab, &cbAddress);
|
|
_JumpIfError(hr, error, "infParseIPAddress");
|
|
|
|
if (L'\0' != *pwszIPAddressMask)
|
|
{
|
|
cbMask = sizeof(ab) / 2;
|
|
hr = infParseIPAddress(pwszIPAddressMask, &ab[cbAddress], &cbMask);
|
|
_JumpIfError(hr, error, "infParseIPMask");
|
|
}
|
|
if (cbAddress != cbMask)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "address and mask lengths differ");
|
|
}
|
|
cb = cbAddress + cbMask;
|
|
}
|
|
else if (L'\0' != *pwszIPAddress || L'\0' != *pwszIPAddressMask)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "address or mask missing");
|
|
}
|
|
|
|
*ppbData = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == *ppbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
*pcbData = cb;
|
|
CopyMemory(*ppbData, ab, cb);
|
|
DBGDUMPHEX((
|
|
DBG_SS_CERTLIBI,
|
|
DH_NOADDRESS | DH_NOTABPREFIX | 8,
|
|
*ppbData,
|
|
*pcbData));
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// [NameConstraintsPermitted]/[NameConstraintsExcluded]
|
|
// ; the numeric second and third arguments are optional
|
|
// ; when present, the second argument is the minimum depth
|
|
// ; when present, the third argument is the maximum depth
|
|
// ; The IETF recommends against specifying dwMinimum & dwMaximum
|
|
// DNS = foo@domain.com
|
|
// DNS = domain1.domain.com, 3, 6
|
|
|
|
HRESULT
|
|
infBuildSubTreeElement(
|
|
IN OUT INFCONTEXT *pInfContext,
|
|
OPTIONAL IN WCHAR const *pwszEmptyEntry, // NULL means read INF file
|
|
IN DWORD iSubTreeInfo,
|
|
OPTIONAL OUT CERT_GENERAL_SUBTREE *pSubTree)
|
|
{
|
|
HRESULT hr;
|
|
SUBTREEINFO const *pSubTreeInfo = &g_aSubTreeInfo[iSubTreeInfo];
|
|
CERT_GENERAL_SUBTREE SubTree;
|
|
WCHAR *pwszValueRead = NULL;
|
|
WCHAR *pwszValueRead2 = NULL;
|
|
WCHAR const *pwszValue = NULL;
|
|
WCHAR const *pwszValue2;
|
|
|
|
ZeroMemory(&SubTree, sizeof(SubTree));
|
|
if (NULL != pSubTree)
|
|
{
|
|
ZeroMemory(pSubTree, sizeof(*pSubTree));
|
|
}
|
|
|
|
// If pwszEmptyEntry is NULL, read the value from the INF file.
|
|
// Otherwise, encode the specified (empty string) value.
|
|
|
|
if (NULL == pwszEmptyEntry)
|
|
{
|
|
INT Value;
|
|
|
|
hr = infGetCurrentKeyValue(pInfContext, 1, &pwszValueRead);
|
|
_JumpIfError(hr, error, "infGetCurrentKeyValue");
|
|
|
|
pwszValue = pwszValueRead;
|
|
|
|
if (!SetupGetIntField(
|
|
pInfContext,
|
|
pSubTreeInfo->dwInfMinMaxIndexBase,
|
|
&Value))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError2(hr, "SetupGetIntField:2", hr);
|
|
|
|
Value = 0;
|
|
}
|
|
SubTree.dwMinimum = Value;
|
|
SubTree.fMaximum = TRUE;
|
|
|
|
if (!SetupGetIntField(
|
|
pInfContext,
|
|
pSubTreeInfo->dwInfMinMaxIndexBase + 1,
|
|
&Value))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError2(hr, "SetupGetIntField:3", hr);
|
|
|
|
Value = 0;
|
|
SubTree.fMaximum = FALSE;
|
|
}
|
|
SubTree.dwMaximum = Value;
|
|
}
|
|
else
|
|
{
|
|
pwszValue = pwszEmptyEntry;
|
|
}
|
|
|
|
SubTree.Base.dwAltNameChoice = pSubTreeInfo->dwAltNameChoice;
|
|
if (NULL != pSubTree)
|
|
{
|
|
WCHAR **ppwsz = NULL;
|
|
|
|
CSASSERT(CSUBTREEINFO > iSubTreeInfo);
|
|
switch (iSubTreeInfo)
|
|
{
|
|
case STII_UPNOTHERNAME:
|
|
{
|
|
CERT_NAME_VALUE nameUpn;
|
|
|
|
SubTree.Base.pOtherName = (CERT_OTHER_NAME *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(*SubTree.Base.pOtherName));
|
|
if (NULL == SubTree.Base.pOtherName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
SubTree.Base.pOtherName->pszObjId = szOID_NT_PRINCIPAL_NAME;
|
|
|
|
nameUpn.dwValueType = CERT_RDN_UTF8_STRING;
|
|
nameUpn.Value.pbData = (BYTE *) pwszValue;
|
|
nameUpn.Value.cbData = 0;
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
&nameUpn,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&SubTree.Base.pOtherName->Value.pbData,
|
|
&SubTree.Base.pOtherName->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infFreeGeneralSubTreeElement: p=%x, otherUPN=%x,%x\n",
|
|
pSubTree,
|
|
SubTree.Base.pOtherName,
|
|
SubTree.Base.pOtherName->Value.pbData));
|
|
break;
|
|
}
|
|
|
|
case STII_RFC822NAME:
|
|
ppwsz = &SubTree.Base.pwszRfc822Name;
|
|
break;
|
|
|
|
case STII_DNSNAME:
|
|
ppwsz = &SubTree.Base.pwszDNSName;
|
|
break;
|
|
|
|
case STII_DIRECTORYNAME:
|
|
hr = myCertStrToName(
|
|
X509_ASN_ENCODING,
|
|
pwszValue, // pszX500
|
|
CERT_NAME_STR_REVERSE_FLAG,
|
|
NULL, // pvReserved
|
|
&SubTree.Base.DirectoryName.pbData,
|
|
&SubTree.Base.DirectoryName.cbData,
|
|
NULL); // ppszError
|
|
_JumpIfError(hr, error, "myCertStrToName");
|
|
|
|
break;
|
|
|
|
case STII_URL:
|
|
ppwsz = &SubTree.Base.pwszURL;
|
|
break;
|
|
|
|
case STII_IPADDRESS:
|
|
|
|
// convert INF string value to binary IP Address
|
|
|
|
if (NULL == pwszEmptyEntry)
|
|
{
|
|
hr = infGetCurrentKeyValue(pInfContext, 2, &pwszValueRead2);
|
|
_JumpIfError(hr, error, "infGetCurrentKeyValue");
|
|
|
|
pwszValue2 = pwszValueRead2;
|
|
}
|
|
else
|
|
{
|
|
pwszValue2 = pwszEmptyEntry;
|
|
}
|
|
|
|
hr = infParseIPAddressAndMask(
|
|
pwszValue,
|
|
pwszValue2,
|
|
&SubTree.Base.IPAddress.pbData,
|
|
&SubTree.Base.IPAddress.cbData);
|
|
_JumpIfError(hr, error, "infParseIPAddressAndMask");
|
|
|
|
break;
|
|
|
|
case STII_REGISTEREDID:
|
|
if (!myConvertWszToSz(
|
|
&SubTree.Base.pszRegisteredID,
|
|
pwszValue,
|
|
-1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToSz");
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infFreeGeneralSubTreeElement: p=%x, psz=%x\n",
|
|
pSubTree,
|
|
SubTree.Base.pszRegisteredID));
|
|
break;
|
|
|
|
}
|
|
if (NULL != ppwsz)
|
|
{
|
|
hr = myDupString(pwszValue, ppwsz);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infFreeGeneralSubTreeElement: p=%x, pwsz=%x\n",
|
|
pSubTree,
|
|
*ppwsz));
|
|
}
|
|
*pSubTree = SubTree;
|
|
ZeroMemory(&SubTree, sizeof(SubTree));
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
INFSETERROR(hr, NULL, NULL, pwszValue);
|
|
}
|
|
infFreeGeneralSubTreeElement(&SubTree);
|
|
if (NULL != pwszValueRead)
|
|
{
|
|
LocalFree(pwszValueRead);
|
|
}
|
|
if (NULL != pwszValueRead2)
|
|
{
|
|
LocalFree(pwszValueRead2);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infGetGeneralSubTreeByType(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
OPTIONAL IN WCHAR const *pwszEmptyEntry,
|
|
IN DWORD iSubTreeInfo,
|
|
IN OUT DWORD *pcName,
|
|
OPTIONAL OUT CERT_GENERAL_SUBTREE *pSubTree)
|
|
{
|
|
HRESULT hr;
|
|
SUBTREEINFO const *pSubTreeInfo = &g_aSubTreeInfo[iSubTreeInfo];
|
|
INFCONTEXT InfContext;
|
|
DWORD iName;
|
|
DWORD cName = MAXDWORD;
|
|
BOOL fIgnore = FALSE;
|
|
|
|
if (NULL == pSubTree)
|
|
{
|
|
*pcName = 0;
|
|
}
|
|
else
|
|
{
|
|
cName = *pcName;
|
|
}
|
|
|
|
// If pwszEmptyEntry is NULL, read the value from the INF file.
|
|
// Otherwise, encode the specified (empty string) value.
|
|
|
|
if (!SetupFindFirstLine(
|
|
hInf,
|
|
pwszSection,
|
|
pSubTreeInfo->pwszKey,
|
|
&InfContext))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"SetupFindFirstLine",
|
|
pwszSection,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
// INF file entry does not exist. Create an empty name constraints
|
|
// entry only if asked to do so (if pwszEmptyEntry is non-NULL).
|
|
|
|
if (NULL == pwszEmptyEntry)
|
|
{
|
|
fIgnore = (HRESULT) ERROR_LINE_NOT_FOUND == hr;
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// INF file entry exists; don't create an empty name constraints entry.
|
|
|
|
pwszEmptyEntry = NULL;
|
|
}
|
|
|
|
for (iName = 0; ; )
|
|
{
|
|
CSASSERT(NULL == pSubTree || iName < cName);
|
|
hr = infBuildSubTreeElement(
|
|
&InfContext,
|
|
pwszEmptyEntry,
|
|
iSubTreeInfo,
|
|
pSubTree);
|
|
_JumpIfErrorStr(hr, error, "infBuildSubTreeElement", pSubTreeInfo->pwszKey);
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infBuildSubTreeElement: &p[%u]=%x, type=%ws\n",
|
|
iName,
|
|
pSubTree,
|
|
pSubTreeInfo->pwszKey));
|
|
iName++;
|
|
if (NULL != pSubTree)
|
|
{
|
|
pSubTree++;
|
|
}
|
|
|
|
if (NULL == pwszEmptyEntry)
|
|
{
|
|
hr = infFindNextKey(pSubTreeInfo->pwszKey, &InfContext);
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
if (S_FALSE == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfErrorStr(hr, error, "infFindNextKey", pSubTreeInfo->pwszKey);
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infGetGeneralSubTreeByType: i=%x, c=%x\n",
|
|
iName,
|
|
cName));
|
|
CSASSERT(NULL == pSubTree || iName <= cName);
|
|
*pcName = iName;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr && !fIgnore)
|
|
{
|
|
INFSETERROR(hr, pwszSection, pSubTreeInfo->pwszKey, NULL);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infGetGeneralSubTree(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
IN WCHAR const *pwszKey, // key value is sub-section name
|
|
OPTIONAL IN WCHAR const *pwszEmptyEntry,
|
|
OUT DWORD *pcSubTree,
|
|
OUT CERT_GENERAL_SUBTREE **ppSubTree)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszSubTreeSection = NULL;
|
|
DWORD cSubTree = 0;
|
|
CERT_GENERAL_SUBTREE *rgSubTree = NULL;
|
|
CERT_GENERAL_SUBTREE *pSubTree;
|
|
DWORD iSubTreeInfo;
|
|
DWORD count;
|
|
DWORD cRemain;
|
|
SUBTREEINFO const *pSubTreeInfo;
|
|
|
|
*pcSubTree = 0;
|
|
*ppSubTree = NULL;
|
|
|
|
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
|
|
hr = myInfGetKeyValue(
|
|
hInf,
|
|
TRUE, // fLog
|
|
pwszSection,
|
|
pwszKey,
|
|
&pwszSubTreeSection);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"myInfGetKeyValue",
|
|
pwszKey,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
for (iSubTreeInfo = 0; iSubTreeInfo < CSUBTREEINFO; iSubTreeInfo++)
|
|
{
|
|
pSubTreeInfo = &g_aSubTreeInfo[iSubTreeInfo];
|
|
|
|
hr = infGetGeneralSubTreeByType(
|
|
hInf,
|
|
pwszSubTreeSection,
|
|
pSubTreeInfo->fEmptyDefault? pwszEmptyEntry : NULL,
|
|
iSubTreeInfo,
|
|
&count,
|
|
NULL);
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infGetGeneralSubTreeByType(%ws, %ws, NULL) -> hr=%x, c=%x\n",
|
|
pwszSubTreeSection,
|
|
pSubTreeInfo->pwszKey,
|
|
hr,
|
|
count));
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"infGetGeneralSubTreeByType",
|
|
pSubTreeInfo->pwszKey,
|
|
ERROR_LINE_NOT_FOUND);
|
|
if ((HRESULT) ERROR_LINE_NOT_FOUND != hr)
|
|
{
|
|
_JumpErrorStr(
|
|
hr,
|
|
error,
|
|
"infGetGeneralSubTreeByType",
|
|
pSubTreeInfo->pwszKey);
|
|
}
|
|
count = 0;
|
|
}
|
|
cSubTree += count;
|
|
}
|
|
rgSubTree = (CERT_GENERAL_SUBTREE *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cSubTree * sizeof(rgSubTree[0]));
|
|
if (NULL == rgSubTree)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infGetGeneralSubTree: rg=%x, total=%x\n",
|
|
rgSubTree,
|
|
cSubTree));
|
|
|
|
pSubTree = rgSubTree;
|
|
cRemain = cSubTree;
|
|
for (iSubTreeInfo = 0; iSubTreeInfo < CSUBTREEINFO; iSubTreeInfo++)
|
|
{
|
|
pSubTreeInfo = &g_aSubTreeInfo[iSubTreeInfo];
|
|
count = cRemain;
|
|
hr = infGetGeneralSubTreeByType(
|
|
hInf,
|
|
pwszSubTreeSection,
|
|
pSubTreeInfo->fEmptyDefault? pwszEmptyEntry : NULL,
|
|
iSubTreeInfo,
|
|
&count,
|
|
pSubTree);
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"infGetGeneralSubTreeByType(%ws, %ws, &p[%x]=%x) -> hr=%x, c=%x\n",
|
|
pwszSubTreeSection,
|
|
pSubTreeInfo->pwszKey,
|
|
SAFE_SUBTRACT_POINTERS(pSubTree, rgSubTree),
|
|
pSubTree,
|
|
hr,
|
|
count));
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"infGetGeneralSubTreeByType",
|
|
pSubTreeInfo->pwszKey,
|
|
ERROR_LINE_NOT_FOUND);
|
|
if ((HRESULT) ERROR_LINE_NOT_FOUND != hr)
|
|
{
|
|
_JumpErrorStr(
|
|
hr,
|
|
error,
|
|
"infGetGeneralSubTreeByType",
|
|
pSubTreeInfo->pwszKey);
|
|
}
|
|
if (0 < cRemain)
|
|
{
|
|
ZeroMemory(pSubTree, sizeof(*pSubTree));
|
|
}
|
|
count = 0;
|
|
}
|
|
cRemain -= count;
|
|
pSubTree += count;
|
|
}
|
|
CSASSERT(0 == cRemain);
|
|
*pcSubTree = cSubTree;
|
|
*ppSubTree = rgSubTree;
|
|
rgSubTree = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
INFSETERROR(hr, pwszSection, pwszKey, pwszSubTreeSection);
|
|
}
|
|
if (NULL != pwszSubTreeSection)
|
|
{
|
|
LocalFree(pwszSubTreeSection);
|
|
}
|
|
if (NULL != rgSubTree)
|
|
{
|
|
infFreeGeneralSubTree(cSubTree, rgSubTree);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetNameConstraintsExtension -- fetch name constraints extension from INF file
|
|
//
|
|
// [NameConstraintsExtension]
|
|
// Include = NameConstraintsPermitted
|
|
// Exclude = NameConstraintsExcluded
|
|
//
|
|
// [NameConstraintsPermitted]
|
|
// ; the numeric second and third arguments are optional
|
|
// ; when present, the second argument is the minimum depth
|
|
// ; when present, the third argument is the maximum depth
|
|
// ; The IETF recommends against specifying dwMinimum & dwMaximum
|
|
// DNS = foo@domain.com
|
|
// DNS = domain1.domain.com, 3, 6
|
|
//
|
|
// [NameConstraintsExcluded]
|
|
// DNS = domain.com
|
|
// DNS = domain2.com
|
|
//
|
|
// Returns: encoded name constraints extension
|
|
//-------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetNameConstraintsExtension;
|
|
|
|
HRESULT
|
|
myInfGetNameConstraintsExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR const *pwszKey = NULL;
|
|
CERT_NAME_CONSTRAINTS_INFO NameConstraints;
|
|
|
|
ZeroMemory(&NameConstraints, sizeof(NameConstraints));
|
|
ZeroMemory(pext, sizeof(*pext));
|
|
myInfClearError();
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
pwszKey = wszINFKEY_INCLUDE;
|
|
hr = infGetGeneralSubTree(
|
|
hInf,
|
|
wszINFSECTION_NAMECONSTRAINTS,
|
|
pwszKey,
|
|
L"",
|
|
&NameConstraints.cPermittedSubtree,
|
|
&NameConstraints.rgPermittedSubtree);
|
|
_PrintIfErrorStr2(
|
|
hr,
|
|
"infGetGeneralSubTree",
|
|
pwszKey,
|
|
ERROR_LINE_NOT_FOUND);
|
|
if (S_OK != hr && (HRESULT) ERROR_LINE_NOT_FOUND != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
pwszKey = wszINFKEY_EXCLUDE;
|
|
hr = infGetGeneralSubTree(
|
|
hInf,
|
|
wszINFSECTION_NAMECONSTRAINTS,
|
|
pwszKey,
|
|
NULL,
|
|
&NameConstraints.cExcludedSubtree,
|
|
&NameConstraints.rgExcludedSubtree);
|
|
_PrintIfErrorStr2(
|
|
hr,
|
|
"infGetGeneralSubTree",
|
|
pwszKey,
|
|
ERROR_LINE_NOT_FOUND);
|
|
if (S_OK != hr && (HRESULT) ERROR_LINE_NOT_FOUND != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
pwszKey = NULL;
|
|
|
|
if (NULL == NameConstraints.rgPermittedSubtree &&
|
|
NULL == NameConstraints.rgExcludedSubtree)
|
|
{
|
|
hr = S_FALSE;
|
|
_JumpError2(hr, error, "no data", hr);
|
|
}
|
|
hr = infGetCriticalFlag(
|
|
hInf,
|
|
wszINFSECTION_NAMECONSTRAINTS,
|
|
FALSE,
|
|
&pext->fCritical);
|
|
_JumpIfError(hr, error, "infGetCriticalFlag");
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_NAME_CONSTRAINTS,
|
|
&NameConstraints,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pext->Value.pbData,
|
|
&pext->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
INFSETERROR(hr, wszINFSECTION_NAMECONSTRAINTS, pwszKey, NULL);
|
|
}
|
|
pext->pszObjId = szOID_NAME_CONSTRAINTS; // on error, too!
|
|
|
|
if (NULL != NameConstraints.rgPermittedSubtree)
|
|
{
|
|
infFreeGeneralSubTree(
|
|
NameConstraints.cPermittedSubtree,
|
|
NameConstraints.rgPermittedSubtree);
|
|
}
|
|
if (NULL != NameConstraints.rgExcludedSubtree)
|
|
{
|
|
infFreeGeneralSubTree(
|
|
NameConstraints.cExcludedSubtree,
|
|
NameConstraints.rgExcludedSubtree);
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetNameConstraintsExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
infFreePolicyMappings(
|
|
IN DWORD cPolicyMapping,
|
|
IN OUT CERT_POLICY_MAPPING *pPolicyMapping)
|
|
{
|
|
if (NULL != pPolicyMapping)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < cPolicyMapping; i++)
|
|
{
|
|
CERT_POLICY_MAPPING *pMap = &pPolicyMapping[i];
|
|
|
|
if (NULL != pMap->pszIssuerDomainPolicy)
|
|
{
|
|
LocalFree(pMap->pszIssuerDomainPolicy);
|
|
}
|
|
if (NULL != pMap->pszSubjectDomainPolicy)
|
|
{
|
|
LocalFree(pMap->pszSubjectDomainPolicy);
|
|
}
|
|
}
|
|
LocalFree(pPolicyMapping);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infGetPolicyMappingsSub(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
IN OUT DWORD *pcPolicyMapping,
|
|
OPTIONAL OUT CERT_POLICY_MAPPING *pPolicyMapping)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
WCHAR wszIssuer[cwcVALUEMAX];
|
|
WCHAR wszSubject[cwcVALUEMAX];
|
|
DWORD i;
|
|
DWORD cPolicyMappingIn;
|
|
DWORD cPolicyMapping = 0;
|
|
|
|
cPolicyMappingIn = MAXDWORD;
|
|
if (NULL != pPolicyMapping)
|
|
{
|
|
cPolicyMappingIn = *pcPolicyMapping;
|
|
}
|
|
*pcPolicyMapping = 0;
|
|
wszIssuer[0] = L'\0';
|
|
wszSubject[0] = L'\0';
|
|
|
|
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
|
|
|
|
cPolicyMapping = 0;
|
|
hr = infSetupFindFirstLine(hInf, pwszSection, NULL, &InfContext);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"infSetupFindFirstLine",
|
|
pwszSection,
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
while (TRUE)
|
|
{
|
|
wszIssuer[0] = L'\0';
|
|
wszSubject[0] = L'\0';
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
0,
|
|
wszIssuer,
|
|
ARRAYSIZE(wszIssuer),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
if (iswdigit(wszIssuer[0]))
|
|
{
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
1,
|
|
wszSubject,
|
|
ARRAYSIZE(wszSubject),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
if (!iswdigit(wszSubject[0]))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpErrorStr(hr, error, "bad OID", wszSubject);
|
|
}
|
|
if (NULL != pPolicyMapping)
|
|
{
|
|
CERT_POLICY_MAPPING *pMap;
|
|
|
|
if (cPolicyMappingIn <= cPolicyMapping)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
|
|
_JumpError(hr, error, "*pcPolicyMapping");
|
|
}
|
|
|
|
pMap = &pPolicyMapping[cPolicyMapping];
|
|
if (!ConvertWszToSz(&pMap->pszIssuerDomainPolicy, wszIssuer, -1) ||
|
|
!ConvertWszToSz(&pMap->pszSubjectDomainPolicy, wszSubject, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToSz");
|
|
}
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"Map[%u]: %ws = %ws\n",
|
|
cPolicyMapping,
|
|
wszIssuer,
|
|
wszSubject));
|
|
|
|
cPolicyMapping++;
|
|
}
|
|
if (!SetupFindNextLine(&InfContext, &InfContext))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError2(hr, "SetupFindNextLine", hr);
|
|
break;
|
|
}
|
|
}
|
|
*pcPolicyMapping = cPolicyMapping;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
INFSETERROR(hr, pwszSection, wszIssuer, wszSubject);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infGetPolicyMappings(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
OUT DWORD *pcPolicyMapping,
|
|
OUT CERT_POLICY_MAPPING **ppPolicyMapping)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
WCHAR wszIssuer[cwcVALUEMAX];
|
|
WCHAR wszSubject[cwcVALUEMAX];
|
|
DWORD i;
|
|
DWORD cPolicyMapping = 0;
|
|
CERT_POLICY_MAPPING *pPolicyMapping = NULL;
|
|
|
|
*pcPolicyMapping = 0;
|
|
*ppPolicyMapping = NULL;
|
|
|
|
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
|
|
|
|
cPolicyMapping = 0;
|
|
hr = infGetPolicyMappingsSub(
|
|
hInf,
|
|
pwszSection,
|
|
&cPolicyMapping,
|
|
NULL);
|
|
_JumpIfError3(
|
|
hr,
|
|
error,
|
|
"infGetPolicyMappingsSub",
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
*pcPolicyMapping = cPolicyMapping;
|
|
pPolicyMapping = (CERT_POLICY_MAPPING *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cPolicyMapping * sizeof(*pPolicyMapping));
|
|
if (NULL == pPolicyMapping)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
hr = infGetPolicyMappingsSub(
|
|
hInf,
|
|
pwszSection,
|
|
&cPolicyMapping,
|
|
pPolicyMapping);
|
|
_JumpIfError(hr, error, "infGetPolicyMappingsSub");
|
|
|
|
CSASSERT(*pcPolicyMapping == cPolicyMapping);
|
|
*ppPolicyMapping = pPolicyMapping;
|
|
pPolicyMapping = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pPolicyMapping)
|
|
{
|
|
infFreePolicyMappings(*pcPolicyMapping, pPolicyMapping);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// infGetPolicyMappingSub -- fetch policy mapping extension from INF file
|
|
//
|
|
// [pwszSection]
|
|
// ; list of user defined policy mappings
|
|
// ; The first OID is for the Issuer Domain Policy, the second is for the
|
|
// ; Subject Domain Policy. Each entry maps one Issuer Domain policy OID
|
|
// ; to a Subject Domain policy OID
|
|
//
|
|
// 1.3.6.1.4.1.311.21.53 = 1.2.3.4.87
|
|
// 1.3.6.1.4.1.311.21.53 = 1.2.3.4.89
|
|
//
|
|
// Returns: encoded policy mapping extension
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
infGetPolicyMappingExtensionSub(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
IN char const *pszObjId,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
CERT_POLICY_MAPPINGS_INFO PolicyMappings;
|
|
|
|
ZeroMemory(&PolicyMappings, sizeof(PolicyMappings));
|
|
ZeroMemory(pext, sizeof(*pext));
|
|
myInfClearError();
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
hr = infGetPolicyMappings(
|
|
hInf,
|
|
pwszSection,
|
|
&PolicyMappings.cPolicyMapping,
|
|
&PolicyMappings.rgPolicyMapping);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"infGetPolicyMappings",
|
|
pwszSection,
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
hr = infGetCriticalFlag(
|
|
hInf,
|
|
pwszSection,
|
|
FALSE,
|
|
&pext->fCritical);
|
|
_JumpIfError(hr, error, "infGetCriticalFlag");
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_POLICY_MAPPINGS,
|
|
&PolicyMappings,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pext->Value.pbData,
|
|
&pext->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
INFSETERROR(hr, pwszSection, NULL, NULL);
|
|
}
|
|
pext->pszObjId = const_cast<char *>(pszObjId); // on error, too!
|
|
|
|
if (NULL != PolicyMappings.rgPolicyMapping)
|
|
{
|
|
infFreePolicyMappings(
|
|
PolicyMappings.cPolicyMapping,
|
|
PolicyMappings.rgPolicyMapping);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetPolicyMapping -- fetch policy mapping extension from INF file
|
|
//
|
|
// [PolicyMappingExtension]
|
|
// ; list of user defined policy mappings
|
|
// ; The first OID is for the Issuer Domain Policy, the second is for the
|
|
// ; Subject Domain Policy. Each entry maps one Issuer Domain policy OID
|
|
// ; to a Subject Domain policy OID
|
|
//
|
|
// 1.3.6.1.4.1.311.21.53 = 1.2.3.4.87
|
|
// 1.3.6.1.4.1.311.21.53 = 1.2.3.4.89
|
|
//
|
|
// Returns: encoded policy mapping extension
|
|
//-------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetPolicyMappingExtension;
|
|
|
|
HRESULT
|
|
myInfGetPolicyMappingExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = infGetPolicyMappingExtensionSub(
|
|
hInf,
|
|
wszINFSECTION_POLICYMAPPINGS,
|
|
szOID_POLICY_MAPPINGS,
|
|
pext);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"infGetPolicyMappingExtensionSub",
|
|
wszINFSECTION_POLICYMAPPINGS,
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetPolicyMappingExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetApplicationPolicyMapping -- fetch application policy mapping
|
|
// extension from INF file
|
|
//
|
|
// [ApplicationPolicyMappingExtension]
|
|
// ; list of user defined policy mappings
|
|
// ; The first OID is for the Issuer Domain Policy, the second is for the
|
|
// ; Subject Domain Policy. Each entry maps one Issuer Domain policy OID
|
|
// ; to a Subject Domain policy OID
|
|
//
|
|
// 1.3.6.1.4.1.311.21.53 = 1.2.3.4.87
|
|
// 1.3.6.1.4.1.311.21.53 = 1.2.3.4.89
|
|
//
|
|
// Returns: encoded policy mapping extension
|
|
//-------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetApplicationPolicyMappingExtension;
|
|
|
|
HRESULT
|
|
myInfGetApplicationPolicyMappingExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = infGetPolicyMappingExtensionSub(
|
|
hInf,
|
|
wszINFSECTION_APPLICATIONPOLICYMAPPINGS,
|
|
szOID_APPLICATION_POLICY_MAPPINGS,
|
|
pext);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"infGetPolicyMappingExtensionSub",
|
|
wszINFSECTION_APPLICATIONPOLICYMAPPINGS,
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetApplicationPolicyMappingExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// infGetPolicyConstraintsExtensionSub -- get policy constraints ext from INF
|
|
//
|
|
// [pwszSection]
|
|
// ; consists of two optional DWORDs
|
|
// ; They refer to the depth of the CA hierarchy that requires and inhibits
|
|
// ; Policy Mapping
|
|
// RequireExplicitPolicy = 3
|
|
// InhibitPolicyMapping = 5
|
|
//
|
|
// Returns: encoded policy constraints extension
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
infGetPolicyConstraintsExtensionSub(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
IN char const *pszObjId,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
CERT_POLICY_CONSTRAINTS_INFO PolicyConstraints;
|
|
WCHAR const *pwszKey = NULL;
|
|
|
|
ZeroMemory(&PolicyConstraints, sizeof(PolicyConstraints));
|
|
ZeroMemory(pext, sizeof(*pext));
|
|
myInfClearError();
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
|
|
PolicyConstraints.fRequireExplicitPolicy = TRUE;
|
|
pwszKey = wszINFKEY_REQUIREEXPLICITPOLICY;
|
|
hr = myInfGetNumericKeyValue(
|
|
hInf,
|
|
TRUE, // fLog
|
|
pwszSection,
|
|
pwszKey,
|
|
&PolicyConstraints.dwRequireExplicitPolicySkipCerts);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"myInfGetNumericKeyValue",
|
|
wszINFKEY_REQUIREEXPLICITPOLICY,
|
|
ERROR_LINE_NOT_FOUND);
|
|
PolicyConstraints.dwRequireExplicitPolicySkipCerts = 0;
|
|
PolicyConstraints.fRequireExplicitPolicy = FALSE;
|
|
}
|
|
|
|
PolicyConstraints.fInhibitPolicyMapping = TRUE;
|
|
pwszKey = wszINFKEY_INHIBITPOLICYMAPPING;
|
|
hr = myInfGetNumericKeyValue(
|
|
hInf,
|
|
TRUE, // fLog
|
|
pwszSection,
|
|
pwszKey,
|
|
&PolicyConstraints.dwInhibitPolicyMappingSkipCerts);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"myInfGetNumericKeyValue",
|
|
wszINFKEY_INHIBITPOLICYMAPPING,
|
|
ERROR_LINE_NOT_FOUND);
|
|
PolicyConstraints.dwInhibitPolicyMappingSkipCerts = 0;
|
|
PolicyConstraints.fInhibitPolicyMapping = FALSE;
|
|
}
|
|
pwszKey = NULL;
|
|
if (!PolicyConstraints.fRequireExplicitPolicy &&
|
|
!PolicyConstraints.fInhibitPolicyMapping)
|
|
{
|
|
hr = S_FALSE;
|
|
_JumpError2(hr, error, "no policy constraints", hr);
|
|
}
|
|
|
|
hr = infGetCriticalFlag(
|
|
hInf,
|
|
pwszSection,
|
|
FALSE,
|
|
&pext->fCritical);
|
|
_JumpIfError(hr, error, "infGetCriticalFlag");
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_POLICY_CONSTRAINTS,
|
|
&PolicyConstraints,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pext->Value.pbData,
|
|
&pext->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
INFSETERROR(hr, pwszSection, pwszKey, NULL);
|
|
}
|
|
pext->pszObjId = const_cast<char *>(pszObjId); // on error, too!
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetPolicyConstraintsExtension -- get policy constraints ext from INF
|
|
//
|
|
// [PolicyConstraintsExtension]
|
|
// ; consists of two optional DWORDs
|
|
// ; They refer to the depth of the CA hierarchy that requires and inhibits
|
|
// ; Policy Mapping
|
|
// RequireExplicitPolicy = 3
|
|
// InhibitPolicyMapping = 5
|
|
//
|
|
// Returns: encoded policy constraints extension
|
|
//-------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetPolicyConstraintsExtension;
|
|
|
|
HRESULT
|
|
myInfGetPolicyConstraintsExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = infGetPolicyConstraintsExtensionSub(
|
|
hInf,
|
|
wszINFSECTION_POLICYCONSTRAINTS,
|
|
szOID_POLICY_CONSTRAINTS,
|
|
pext);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"infGetPolicyConstraintsExtensionSub",
|
|
wszINFSECTION_POLICYCONSTRAINTS,
|
|
S_FALSE);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetPolicyConstraintsExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetApplicationPolicyConstraintsExtension -- get application policy
|
|
// constraints extension from INF
|
|
//
|
|
// [ApplicationPolicyConstraintsExtension]
|
|
// ; consists of two optional DWORDs
|
|
// ; They refer to the depth of the CA hierarchy that requires and inhibits
|
|
// ; Policy Mapping
|
|
// RequireExplicitPolicy = 3
|
|
// InhibitPolicyMapping = 5
|
|
//
|
|
// Returns: encoded policy constraints extension
|
|
//-------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetApplicationPolicyConstraintsExtension;
|
|
|
|
HRESULT
|
|
myInfGetApplicationPolicyConstraintsExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = infGetPolicyConstraintsExtensionSub(
|
|
hInf,
|
|
wszINFSECTION_APPLICATIONPOLICYCONSTRAINTS,
|
|
szOID_APPLICATION_POLICY_CONSTRAINTS,
|
|
pext);
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"infGetPolicyConstraintsExtensionSub",
|
|
wszINFSECTION_APPLICATIONPOLICYCONSTRAINTS,
|
|
S_FALSE);
|
|
|
|
error:
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetApplicationPolicyConstraintsExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetCrossCertDistributionPointsExtension -- fetch Cross CertDist Point
|
|
// URLs from CAPolicy.inf
|
|
//
|
|
// [CrossCertificateDistributionPointsExtension]
|
|
// SyncDeltaTime = 24
|
|
// URL = http://CRLhttp.site.com/Public/MyCA.crt
|
|
// URL = ftp://CRLftp.site.com/Public/MyCA.crt
|
|
//
|
|
// Returns: encoded cross cert dist points extension
|
|
//-------------------------------------------------------------------------
|
|
|
|
FNMYINFGETEXTENSION myInfGetCrossCertDistributionPointsExtension;
|
|
|
|
HRESULT
|
|
myInfGetCrossCertDistributionPointsExtension(
|
|
IN HINF hInf,
|
|
OUT CERT_EXTENSION *pext)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
CROSS_CERT_DIST_POINTS_INFO ccdpi;
|
|
CERT_ALT_NAME_INFO AltNameInfo;
|
|
CERT_ALT_NAME_ENTRY *rgAltEntry = NULL;
|
|
WCHAR const *pwsz;
|
|
WCHAR *pwszzURL = NULL;
|
|
BYTE *pbData = NULL;
|
|
DWORD cbData;
|
|
DWORD i;
|
|
WCHAR const *pwszKey = NULL;
|
|
|
|
ZeroMemory(&ccdpi, sizeof(ccdpi));
|
|
ZeroMemory(&AltNameInfo, sizeof(AltNameInfo));
|
|
ZeroMemory(pext, sizeof(*pext));
|
|
myInfClearError();
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
|
|
hr = infSetupFindFirstLine(hInf, wszINFSECTION_CCDP, NULL, &InfContext);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"infSetupFindFirstLine",
|
|
wszINFSECTION_CCDP,
|
|
S_FALSE,
|
|
ERROR_LINE_NOT_FOUND);
|
|
|
|
pwszKey = wszINFKEY_CCDPSYNCDELTATIME;
|
|
hr = myInfGetNumericKeyValue(
|
|
hInf,
|
|
TRUE, // fLog
|
|
wszINFSECTION_CCDP,
|
|
pwszKey,
|
|
&ccdpi.dwSyncDeltaTime);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"myInfGetNumericKeyValue",
|
|
pwszKey,
|
|
ERROR_LINE_NOT_FOUND);
|
|
ccdpi.dwSyncDeltaTime = 0;
|
|
}
|
|
pwszKey = wszINFKEY_URL;
|
|
hr = myInfGetKeyList(
|
|
hInf,
|
|
wszINFSECTION_CCDP,
|
|
pwszKey,
|
|
&pext->fCritical,
|
|
&pwszzURL);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"myInfGetKeyList",
|
|
pwszKey,
|
|
ERROR_LINE_NOT_FOUND,
|
|
S_FALSE);
|
|
pwszKey = NULL;
|
|
|
|
if (NULL != pwszzURL)
|
|
{
|
|
for (pwsz = pwszzURL; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
|
|
{
|
|
AltNameInfo.cAltEntry++;
|
|
}
|
|
}
|
|
|
|
if (0 != AltNameInfo.cAltEntry)
|
|
{
|
|
ccdpi.cDistPoint = 1;
|
|
ccdpi.rgDistPoint = &AltNameInfo;
|
|
|
|
AltNameInfo.rgAltEntry = (CERT_ALT_NAME_ENTRY *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
AltNameInfo.cAltEntry * sizeof(AltNameInfo.rgAltEntry[0]));
|
|
if (NULL == AltNameInfo.rgAltEntry)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
i = 0;
|
|
for (pwsz = pwszzURL; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
|
|
{
|
|
AltNameInfo.rgAltEntry[i].pwszURL = const_cast<WCHAR *>(pwsz);
|
|
AltNameInfo.rgAltEntry[i].dwAltNameChoice = CERT_ALT_NAME_URL;
|
|
i++;
|
|
}
|
|
CSASSERT(i == AltNameInfo.cAltEntry);
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CROSS_CERT_DIST_POINTS,
|
|
&ccdpi,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pext->Value.pbData,
|
|
&pext->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
INFSETERROR(hr, wszINFSECTION_CCDP, pwszKey, NULL);
|
|
}
|
|
pext->pszObjId = szOID_CROSS_CERT_DIST_POINTS; // on error, too!
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetCrossCertDistributionPointsExtension hr=%x --> f=%d, cb=%x\n",
|
|
hr,
|
|
pext->fCritical,
|
|
pext->Value.cbData));
|
|
|
|
if (NULL != AltNameInfo.rgAltEntry)
|
|
{
|
|
LocalFree(AltNameInfo.rgAltEntry);
|
|
}
|
|
if (NULL != pwszzURL)
|
|
{
|
|
LocalFree(pwszzURL);
|
|
}
|
|
if (NULL != rgAltEntry)
|
|
{
|
|
LocalFree(rgAltEntry);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
infAddKey(
|
|
IN WCHAR const *pwszName,
|
|
IN OUT DWORD *pcValues,
|
|
IN OUT INFVALUES **prgInfValues,
|
|
OUT INFVALUES **ppInfValues)
|
|
{
|
|
HRESULT hr;
|
|
INFVALUES *rgInfValues;
|
|
WCHAR *pwszKeyT = NULL;
|
|
|
|
hr = myDupString(pwszName, &pwszKeyT);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
if (NULL == *prgInfValues)
|
|
{
|
|
CSASSERT(0 == *pcValues);
|
|
rgInfValues = (INFVALUES *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(**prgInfValues));
|
|
}
|
|
else
|
|
{
|
|
CSASSERT(0 != *pcValues);
|
|
rgInfValues = (INFVALUES *) LocalReAlloc(
|
|
*prgInfValues,
|
|
(*pcValues + 1) * sizeof(**prgInfValues),
|
|
LMEM_MOVEABLE | LMEM_ZEROINIT);
|
|
}
|
|
if (NULL == rgInfValues)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(
|
|
hr,
|
|
error,
|
|
NULL == *prgInfValues? "LocalAlloc" : "LocalReAlloc");
|
|
}
|
|
*prgInfValues = rgInfValues;
|
|
*ppInfValues = &rgInfValues[*pcValues];
|
|
(*pcValues)++;
|
|
(*ppInfValues)->pwszKey = pwszKeyT;
|
|
pwszKeyT = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszKeyT)
|
|
{
|
|
LocalFree(pwszKeyT);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
infAddValue(
|
|
IN WCHAR const *pwszValue,
|
|
IN OUT INFVALUES *pInfValues)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszValueT = NULL;
|
|
WCHAR **rgpwszValues = NULL;
|
|
|
|
hr = myDupString(pwszValue, &pwszValueT);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
if (NULL == pInfValues->rgpwszValues)
|
|
{
|
|
CSASSERT(0 == pInfValues->cValues);
|
|
rgpwszValues = (WCHAR **) LocalAlloc(
|
|
LMEM_FIXED,
|
|
sizeof(*pInfValues->rgpwszValues));
|
|
}
|
|
else
|
|
{
|
|
CSASSERT(0 != pInfValues->cValues);
|
|
rgpwszValues = (WCHAR **) LocalReAlloc(
|
|
pInfValues->rgpwszValues,
|
|
(pInfValues->cValues + 1) * sizeof(*pInfValues->rgpwszValues),
|
|
LMEM_MOVEABLE);
|
|
}
|
|
if (NULL == rgpwszValues)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(
|
|
hr,
|
|
error,
|
|
NULL == pInfValues->rgpwszValues? "LocalAlloc" : "LocalReAlloc");
|
|
}
|
|
pInfValues->rgpwszValues = rgpwszValues;
|
|
pInfValues->rgpwszValues[pInfValues->cValues] = pwszValueT;
|
|
pInfValues->cValues++;
|
|
pwszValueT = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszValueT)
|
|
{
|
|
LocalFree(pwszValueT);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
myInfFreeSectionValues(
|
|
IN DWORD cInfValues,
|
|
IN OUT INFVALUES *rgInfValues)
|
|
{
|
|
DWORD i;
|
|
DWORD ival;
|
|
INFVALUES *pInfValues;
|
|
|
|
if (NULL != rgInfValues)
|
|
{
|
|
for (i = 0; i < cInfValues; i++)
|
|
{
|
|
pInfValues = &rgInfValues[i];
|
|
|
|
if (NULL != pInfValues->pwszKey)
|
|
{
|
|
LocalFree(pInfValues->pwszKey);
|
|
}
|
|
if (NULL != pInfValues->rgpwszValues)
|
|
{
|
|
for (ival = 0; ival < pInfValues->cValues; ival++)
|
|
{
|
|
if (NULL != pInfValues->rgpwszValues[ival])
|
|
{
|
|
LocalFree(pInfValues->rgpwszValues[ival]);
|
|
}
|
|
}
|
|
LocalFree(pInfValues->rgpwszValues);
|
|
}
|
|
}
|
|
LocalFree(rgInfValues);
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
// myInfGetSectionValues -- fetch all section values from INF file
|
|
//
|
|
// [pwszSection]
|
|
// KeyName1 = KeyValue1a, KeyValue1b, ...
|
|
// KeyName2 = KeyValue2a, KeyValue2b, ...
|
|
// ...
|
|
// KeyNameN = KeyValueNa, KeyValueNb, ...
|
|
//
|
|
// Returns: array of key names and values
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
myInfGetSectionValues(
|
|
IN HINF hInf,
|
|
IN WCHAR const *pwszSection,
|
|
OUT DWORD *pcInfValues,
|
|
OUT INFVALUES **prgInfValues)
|
|
{
|
|
HRESULT hr;
|
|
INFCONTEXT InfContext;
|
|
WCHAR wszName[MAX_PATH];
|
|
WCHAR wszValue[cwcVALUEMAX];
|
|
DWORD i;
|
|
DWORD cInfValues = 0;
|
|
INFVALUES *rgInfValues = NULL;
|
|
INFVALUES *pInfValues;
|
|
|
|
*pcInfValues = 0;
|
|
*prgInfValues = NULL;
|
|
wszName[0] = L'\0';
|
|
wszValue[0] = L'\0';
|
|
myInfClearError();
|
|
|
|
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError2(hr, error, "hInf", hr);
|
|
}
|
|
hr = infSetupFindFirstLine(hInf, pwszSection, NULL, &InfContext);
|
|
_JumpIfErrorStr(hr, error, "infSetupFindFirstLine", pwszSection);
|
|
|
|
while (TRUE)
|
|
{
|
|
wszName[0] = L'\0';
|
|
wszValue[0] = L'\0';
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
0,
|
|
wszName,
|
|
ARRAYSIZE(wszName),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
|
|
//wprintf(L"%ws[0]:\n", wszName);
|
|
|
|
hr = infAddKey(wszName, &cInfValues, &rgInfValues, &pInfValues);
|
|
_JumpIfError(hr, error, "infAddKey");
|
|
|
|
for (i = 1; ; i++)
|
|
{
|
|
wszValue[0] = L'\0';
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
i,
|
|
wszValue,
|
|
ARRAYSIZE(wszValue),
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
if (1 == i)
|
|
{
|
|
_JumpError(hr, error, "SetupGetStringField");
|
|
}
|
|
break;
|
|
}
|
|
//wprintf(L"%ws[%u] = %ws\n", wszName, i, wszValue);
|
|
|
|
hr = infAddValue(wszValue, pInfValues);
|
|
_JumpIfError(hr, error, "infAddValue");
|
|
}
|
|
|
|
if (!SetupFindNextLine(&InfContext, &InfContext))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError2(hr, "SetupFindNextLine(end)", hr);
|
|
break;
|
|
}
|
|
}
|
|
*pcInfValues = cInfValues;
|
|
*prgInfValues = rgInfValues;
|
|
rgInfValues = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
INFSETERROR(hr, pwszSection, wszName, wszValue);
|
|
}
|
|
if (NULL != rgInfValues)
|
|
{
|
|
myInfFreeSectionValues(cInfValues, rgInfValues);
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"myInfGetSectionValues hr=%x --> c=%d\n",
|
|
hr,
|
|
*pcInfValues));
|
|
return(hr);
|
|
}
|