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

5634 lines
127 KiB

//+--------------------------------------------------------------------------
//
// 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"
#include "csber.h"
#define __dwFILE__ __dwFILE_CERTLIB_INF_CPP__
#define wszBSCAPOLICYFILE L"\\" wszCAPOLICYFILE
#define wszINFKEY_CONTINUE L"_continue_"
#define wszINFKEY_VERSION L"Version"
#define wszINFSECTION_EXTENSIONS L"Extensions"
#define cwcINFLINEMAX 1024
#define wcBOM (WCHAR) 0xfffe
#define wcBOMBIGENDIAN (WCHAR) 0xfeff
static WCHAR *s_pwszSection = NULL;
static WCHAR *s_pwszKey = NULL;
static WCHAR *s_pwszValue = NULL;
static HRESULT s_hr = S_OK;
static WCHAR g_wcBOM = L'\0';
static BOOL g_fIgnoreReferencedSections = FALSE;
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 && NULL == *ppwszOut)
{
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)));
s_hr = hr;
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 + 2;
}
if (NULL != s_pwszValue)
{
cwc += wcslen(s_pwszValue) + 1;
}
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 && L'\0' != s_pwszKey[0])
{
wcscat(pwsz, L" ");
wcscat(pwsz, s_pwszKey);
wcscat(pwsz, L" =");
}
if (NULL != s_pwszValue && L'\0' != s_pwszValue[0])
{
wcscat(pwsz, L" ");
wcscat(pwsz, s_pwszValue);
}
error:
return(pwsz);
}
VOID
myInfClearError()
{
s_hr = S_OK;
infClearString(&s_pwszSection);
infClearString(&s_pwszKey);
infClearString(&s_pwszValue);
}
typedef struct _SECTIONINFO {
DWORD dwRefCount;
WCHAR *pwszSection;
struct _SECTIONINFO *pNext;
} SECTIONINFO;
SECTIONINFO *g_pSectionInfo = NULL;
HRESULT
infSaveSectionName(
IN WCHAR const *pwszSection)
{
HRESULT hr;
SECTIONINFO *psi = NULL;
if (0 != LSTRCMPIS(pwszSection, wszINFKEY_VERSION))
{
psi = (SECTIONINFO *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
sizeof(*psi));
if (NULL == psi)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
hr = myDupString(pwszSection, &psi->pwszSection);
_JumpIfError(hr, error, "myDupString");
psi->pNext = g_pSectionInfo;
g_pSectionInfo = psi;
psi = NULL;
}
hr = S_OK;
error:
if (NULL != psi)
{
LocalFree(psi);
}
return(hr);
}
VOID
infFreeSectionNames()
{
SECTIONINFO *psi;
psi = g_pSectionInfo;
g_pSectionInfo = NULL;
while (NULL != psi)
{
SECTIONINFO *psiNext;
if (NULL != psi->pwszSection)
{
LocalFree(psi->pwszSection);
}
psiNext = psi->pNext;
LocalFree(psi);
psi = psiNext;
}
}
HRESULT
myInfGetUnreferencedSectionNames(
OUT WCHAR **ppwszzSectionNames)
{
HRESULT hr;
DWORD cwc;
SECTIONINFO *psi;
*ppwszzSectionNames = NULL;
cwc = 0;
for (psi = g_pSectionInfo; NULL != psi; psi = psi->pNext)
{
if (0 == psi->dwRefCount)
{
cwc += wcslen(psi->pwszSection) + 3;
}
}
if (0 != cwc)
{
WCHAR *pwszz;
WCHAR *pwsz;
pwszz = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
if (NULL == pwszz)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pwsz = pwszz;
for (psi = g_pSectionInfo; NULL != psi; psi = psi->pNext)
{
if (0 == psi->dwRefCount)
{
*pwsz++ = wcLBRACKET;
wcscpy(pwsz, psi->pwszSection);
pwsz += wcslen(pwsz);
*pwsz++ = wcRBRACKET;
*pwsz++ = L'\0';
}
}
*pwsz = L'\0';
CSASSERT(cwc == SAFE_SUBTRACT_POINTERS(pwsz, pwszz));
*ppwszzSectionNames = pwszz;
}
hr = S_OK;
error:
return(hr);
}
HRESULT
infReferenceSectionName(
IN WCHAR const *pwszSection)
{
HRESULT hr;
SECTIONINFO *psi;
if (!g_fIgnoreReferencedSections)
{
for (psi = g_pSectionInfo; NULL != psi; psi = psi->pNext)
{
if (0 == mylstrcmpiL(pwszSection, psi->pwszSection))
{
psi->dwRefCount++;
break;
}
}
if (NULL == psi)
{
hr = SPAPI_E_LINE_NOT_FOUND; // don't ignore this error
_JumpError(hr, error, "unexpected section");
}
}
hr = S_OK;
error:
return(hr);
}
HRESULT
inffopen(
IN WCHAR const *pwszfn,
OUT FILE **ppf)
{
HRESULT hr;
FILE *pf = NULL;
*ppf = NULL;
g_fIgnoreReferencedSections = FALSE;
g_wcBOM = L'\0';
pf = _wfopen(pwszfn, L"r"); // Assume Ansi INF file
if (NULL == pf)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "_wfopen");
}
g_wcBOM = (WCHAR) fgetc(pf) << 8;
g_wcBOM |= fgetc(pf);
if (!feof(pf))
{
if (wcBOM == g_wcBOM) // Oops, Unicode INF file
{
fclose(pf);
pf = _wfopen(pwszfn, L"rb");
if (NULL == pf)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "fopen");
}
}
else if (wcBOMBIGENDIAN == g_wcBOM)
{
g_fIgnoreReferencedSections = TRUE;
fclose(pf);
pf = NULL;
}
else
{
if (fseek(pf, 0L, SEEK_SET))
{
hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
_JumpError(hr, error, "fseek");
}
}
}
*ppf = pf;
hr = S_OK;
error:
return(hr);
}
WCHAR *
inffgetws(
OUT WCHAR *pwcLine,
IN DWORD cwcLine,
IN FILE *pfInf)
{
HRESULT hr;
WCHAR *pwc = NULL;
WCHAR *pwsz = NULL;
char achLine[cwcINFLINEMAX];
char *pch;
if (wcBOM == g_wcBOM)
{
pwc = fgetws(pwcLine, cwcLine, pfInf);
}
else
{
pch = fgets(achLine, ARRAYSIZE(achLine), pfInf);
if (NULL == pch)
{
goto error;
}
if (!myConvertSzToWsz(&pwsz, achLine, -1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "myConvertSzToWsz");
}
wcsncpy(pwcLine, pwsz, cwcLine);
pwcLine[cwcLine - 1] = L'\0';
pwc = pwcLine;
}
error:
if (NULL != pwsz)
{
LocalFree(pwsz);
}
return(pwc);
}
#define ISBLANK(ch) (L' ' == (ch) || L'\t' == (ch))
HRESULT
infCollectSectionNames(
IN WCHAR const *pwszfnInf)
{
HRESULT hr;
FILE *pfInf = NULL;
WCHAR awcLine[cwcINFLINEMAX];
WCHAR *pwszEnd;
hr = inffopen(pwszfnInf, &pfInf);
_JumpIfError(hr, error, "inffopen");
if (!g_fIgnoreReferencedSections)
{
while (NULL != inffgetws(awcLine, ARRAYSIZE(awcLine), pfInf))
{
WCHAR *pwsz;
awcLine[wcscspn(awcLine, L";=\r\n")] = L'\0';
pwsz = wcschr(awcLine, wcLBRACKET);
if (NULL == pwsz)
{
continue;
}
pwsz++;
pwszEnd = wcschr(awcLine, wcRBRACKET);
if (NULL == pwszEnd)
{
continue;
}
*pwszEnd = L'\0';
while (ISBLANK(*pwsz))
{
pwsz++;
}
while (--pwszEnd >= pwsz && ISBLANK(*pwszEnd))
{
*pwszEnd = L'\0';
}
hr = infSaveSectionName(pwsz);
_JumpIfError(hr, error, "infSaveSectionName");
}
}
hr = S_OK;
error:
if (NULL != pfInf)
{
fclose(pfInf);
}
return(hr);
}
HRESULT
infGetCurrentKeyValueAndAlloc(
IN OUT INFCONTEXT *pInfContext,
IN DWORD Index,
OUT WCHAR **ppwszValue)
{
HRESULT hr;
WCHAR *pwszValue = NULL;
DWORD cwc;
if (!SetupGetStringField(pInfContext, Index, NULL, 0, &cwc))
{
hr = myHLastError();
_JumpError2(hr, error, "SetupGetStringField", E_INVALIDARG);
}
pwszValue = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
if (NULL == pwszValue)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if (!SetupGetStringField(pInfContext, Index, pwszValue, cwc, NULL))
{
hr = myHLastError();
_JumpError(hr, error, "SetupGetStringField");
}
*ppwszValue = pwszValue;
pwszValue = NULL;
hr = S_OK;
error:
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
return(hr);
}
HRESULT
infGetCurrentKeyValue(
IN OUT INFCONTEXT *pInfContext,
OPTIONAL IN WCHAR const *pwszSection, // for error logging only
OPTIONAL IN WCHAR const *pwszKey, // for error logging only
IN DWORD Index,
IN BOOL fLastValue,
OUT WCHAR **ppwszValue)
{
HRESULT hr;
WCHAR *pwszValue = NULL;
WCHAR *pwszValueExtra = NULL;
WCHAR *pwszValueError = NULL;
DWORD cwc;
WCHAR *pwszT = NULL;
INFCONTEXT InfContext;
*ppwszValue = NULL;
hr = infGetCurrentKeyValueAndAlloc(pInfContext, Index, &pwszValue);
_JumpIfError2(hr, error, "infGetCurrentKeyValueAndAlloc", E_INVALIDARG);
if (1 == Index)
{
InfContext = *pInfContext;
for (;;)
{
WCHAR *pwsz;
if (!SetupFindNextLine(&InfContext, &InfContext))
{
break;
}
hr = infGetCurrentKeyValueAndAlloc(&InfContext, 0, &pwszT);
_JumpIfError2(hr, error, "infGetCurrentKeyValueAndAlloc", E_INVALIDARG);
if (0 != LSTRCMPIS(pwszT, wszINFKEY_CONTINUE))
{
break;
}
LocalFree(pwszT);
pwszT = NULL;
hr = infGetCurrentKeyValueAndAlloc(&InfContext, 1, &pwszT);
_JumpIfError2(hr, error, "infGetCurrentKeyValueAndAlloc", E_INVALIDARG);
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;
}
}
if (fLastValue)
{
DWORD cValue;
cValue = SetupGetFieldCount(pInfContext);
if (Index != cValue)
{
DWORD i;
for (i = Index + 5; i > Index; i--)
{
hr = infGetCurrentKeyValue(
pInfContext,
pwszSection,
pwszKey,
i,
FALSE, // fLastValue
&pwszValueExtra);
if (S_OK == hr)
{
DWORD j;
cwc = wcslen(pwszValue) + i - 1 + wcslen(pwszValueExtra);
pwszValueError = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(cwc + 1) * sizeof(WCHAR));
if (NULL == pwszValueError)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pwszValueError[0] = L'\0';
for (j = 1; j < Index; j++)
{
wcscat(pwszValueError, L",");
}
wcscat(pwszValueError, pwszValue);
for (j = Index; j < i; j++)
{
wcscat(pwszValueError, L",");
}
wcscat(pwszValueError, pwszValueExtra);
CSASSERT(wcslen(pwszValueError) == cwc);
hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
INFSETERROR(hr, pwszSection, pwszKey, pwszValueError);
_PrintErrorStr(hr, "extra values", pwszKey);
_JumpErrorStr(hr, error, "extra values", pwszValueError);
}
}
}
}
*ppwszValue = pwszValue;
pwszValue = NULL;
hr = S_OK;
error:
if (NULL != pwszT)
{
LocalFree(pwszT);
}
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
if (NULL != pwszValueExtra)
{
LocalFree(pwszValueExtra);
}
if (NULL != pwszValueError)
{
LocalFree(pwszValueError);
}
return(hr);
}
HRESULT
infFindNextKey(
IN WCHAR const *pwszKey,
IN OUT INFCONTEXT *pInfContext)
{
HRESULT hr;
WCHAR *pwszKeyT = NULL;
for (;;)
{
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 (NULL != pwszKeyT)
{
LocalFree(pwszKeyT);
pwszKeyT = NULL;
}
hr = infGetCurrentKeyValue(
pInfContext,
NULL, // pwszSection
NULL, // pwszKey
0,
FALSE, // fLastValue
&pwszKeyT);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
if (0 == mylstrcmpiL(pwszKey, pwszKeyT))
{
break;
}
}
hr = S_OK;
error:
if (NULL != pwszKeyT)
{
LocalFree(pwszKeyT);
}
return(hr);
}
HRESULT
infSetupFindFirstLine(
IN HINF hInf,
IN WCHAR const *pwszSection,
OPTIONAL IN WCHAR const *pwszKey,
IN BOOL fUniqueKey,
IN DWORD cValueMax,
OPTIONAL WCHAR const * const *ppwszValidKeys,
IN BOOL fUniqueValidKeys,
OUT INFCONTEXT *pInfContext)
{
HRESULT hr;
WCHAR *pwszValue = NULL;
WCHAR *pwszKeyT = NULL;
WCHAR *pwszValueT = NULL;
if (!SetupFindFirstLine(hInf, pwszSection, pwszKey, pInfContext))
{
// if the [Section] or Key = does not exist, see if the section is
// completely empty. It exists and is empty if SetupGetLineCount
// returns 0, or if the Empty key is found in the section.
hr = myHLastError();
if ((HRESULT) ERROR_LINE_NOT_FOUND == hr &&
(0 == SetupGetLineCount(hInf, pwszSection) ||
SetupFindFirstLine(
hInf,
pwszSection,
wszINFKEY_EMPTY,
pInfContext)))
{
hr = infReferenceSectionName(pwszSection);
_JumpIfErrorStr(hr, error, "infReferenceSectionName", pwszKey);
hr = S_FALSE; // Section exists, but is empty
}
_JumpErrorStr3(
hr,
error,
"SetupFindFirstLine",
pwszSection,
ERROR_LINE_NOT_FOUND,
S_FALSE);
}
hr = infReferenceSectionName(pwszSection);
_JumpIfErrorStr(hr, error, "infReferenceSectionName", pwszKey);
if (NULL != pwszKey)
{
if (fUniqueKey)
{
INFCONTEXT InfContext = *pInfContext;
hr = infFindNextKey(pwszKey, &InfContext);
if (S_OK == hr)
{
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
pwszKey,
1,
FALSE, // fLastValue
&pwszValue);
_PrintIfError(hr, "infGetCurrentKeyValue");
hr = HRESULT_FROM_WIN32(RPC_S_ENTRY_ALREADY_EXISTS);
INFSETERROR(hr, pwszSection, pwszKey, pwszValue);
_JumpErrorStr(hr, error, "duplicate key", pwszKey);
}
}
if (0 != cValueMax)
{
hr = infGetCurrentKeyValue(
pInfContext,
pwszSection,
pwszKey,
cValueMax,
TRUE, // fLastValue
&pwszValue);
_JumpIfErrorStr(hr, error, "infGetCurrentKeyValue", pwszKey);
}
}
if (NULL != ppwszValidKeys)
{
INFCONTEXT InfContext;
WCHAR const * const *ppwszKey;
if (!SetupFindFirstLine(hInf, pwszSection, NULL, &InfContext))
{
hr = myHLastError();
_JumpErrorStr(hr, error, "SetupFindFirstLine", pwszSection)
}
for (;;)
{
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
NULL, // pwszKey
0,
FALSE, // fLastValue
&pwszKeyT);
_JumpIfErrorStr(hr, error, "infGetCurrentKeyValue", pwszSection);
for (ppwszKey = ppwszValidKeys; NULL != *ppwszKey; ppwszKey++)
{
if (0 == mylstrcmpiL(*ppwszKey, pwszKeyT))
{
break;
}
}
if (NULL == *ppwszKey)
{
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
pwszKeyT,
1,
FALSE, // fLastValue
&pwszValueT);
_PrintIfError(hr, "infGetCurrentKeyValue");
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
INFSETERROR(hr, pwszSection, pwszKeyT, pwszValueT);
_JumpErrorStr(hr, error, "invalid key", pwszKeyT);
}
if (fUniqueValidKeys)
{
INFCONTEXT InfContextT = InfContext;
hr = infFindNextKey(pwszKeyT, &InfContextT);
if (S_OK == hr)
{
hr = infGetCurrentKeyValue(
&InfContextT,
pwszSection,
pwszKeyT,
1,
FALSE, // fLastValue
&pwszValueT);
_PrintIfError(hr, "infGetCurrentKeyValue");
hr = HRESULT_FROM_WIN32(RPC_S_ENTRY_ALREADY_EXISTS);
INFSETERROR(hr, pwszSection, pwszKeyT, pwszValueT);
_JumpErrorStr(hr, error, "duplicate key", pwszKeyT);
}
}
LocalFree(pwszKeyT);
pwszKeyT = NULL;
if (!SetupFindNextLine(&InfContext, &InfContext))
{
hr = myHLastError();
_PrintErrorStr2(hr, "SetupFindNextLine", pwszSection, hr);
break;
}
}
}
hr = S_OK;
error:
if (NULL != pwszKeyT)
{
LocalFree(pwszKeyT);
}
if (NULL != pwszValueT)
{
LocalFree(pwszValueT);
}
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
return(hr);
}
HRESULT
infBuildPolicyElement(
IN OUT INFCONTEXT *pInfContext,
OPTIONAL OUT CERT_POLICY_QUALIFIER_INFO *pcpqi)
{
HRESULT hr;
WCHAR *pwszKey = NULL;
BOOL fURL = FALSE;
BOOL fNotice = FALSE;
WCHAR *pwszValue = NULL;
WCHAR *pwszURL = NULL;
BYTE *pbData = NULL;
DWORD cbData;
hr = infGetCurrentKeyValue(
pInfContext,
NULL, // pwszSection
NULL, // pwszKey
0,
FALSE, // fLastValue
&pwszKey);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
DBGPRINT((DBG_SS_CERTLIBI, "Element = %ws\n", pwszKey));
if (0 == LSTRCMPIS(pwszKey, wszINFKEY_URL))
{
fURL = TRUE;
}
else
if (0 == LSTRCMPIS(pwszKey, wszINFKEY_NOTICE))
{
fNotice = TRUE;
}
else
{
if (0 != LSTRCMPIS(pwszKey, wszINFKEY_OID) &&
0 != LSTRCMPIS(pwszKey, wszINFKEY_CONTINUE))
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "unknown key", pwszKey);
}
hr = S_FALSE; // Skip this key
_JumpError2(hr, error, "skip OID key", hr);
}
hr = infGetCurrentKeyValue(
pInfContext,
NULL, // pwszSection
pwszKey,
1,
TRUE, // fLastValue
&pwszValue);
_JumpIfErrorStr(hr, error, "infGetCurrentKeyValue", pwszKey);
DBGPRINT((DBG_SS_CERTLIBI, "%ws = %ws\n", pwszKey, 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, pwszKey, pwszValue);
}
if (NULL != pwszKey)
{
LocalFree(pwszKey);
}
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 *pwszValue = NULL;
static WCHAR const * const s_apwszKeys[] =
{
wszINFKEY_OID,
wszINFKEY_URL,
wszINFKEY_NOTICE,
wszINFKEY_CONTINUE,
NULL
};
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
hr = infSetupFindFirstLine(
hInf,
pwszSection,
wszINFKEY_OID,
TRUE, // fUniqueKey
1, // cValueMax
s_apwszKeys,
FALSE, // fUniqueValidKeys
&InfContext);
if (S_OK != hr)
{
if ((HRESULT) ERROR_LINE_NOT_FOUND == hr)
{
hr = SPAPI_E_LINE_NOT_FOUND; // don't ignore this error
}
INFSETERROR(hr, NULL, wszINFKEY_OID, NULL);
_JumpErrorStr(hr, error, "infSetupFindFirstLine", pwszSection);
}
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
wszINFKEY_OID,
1,
TRUE, // fLastValue
&pwszValue);
_JumpIfErrorStr(hr, error, "infGetCurrentKeyValue", wszINFKEY_OID);
hr = myVerifyObjId(pwszValue);
_JumpIfErrorStr(hr, error, "myVerifyObjId", pwszValue);
if (!ConvertWszToSz(&pcpi->pszPolicyIdentifier, pwszValue, -1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ConvertWszToSz");
}
DBGPRINT((DBG_SS_CERTLIBI, "OID = %hs\n", pcpi->pszPolicyIdentifier));
hr = infSetupFindFirstLine(
hInf,
pwszSection,
NULL, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&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, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&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, pwszValue, NULL);
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
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;
WCHAR wszPath[MAX_PATH];
UINT ErrorLine;
DWORD Flags;
*phInf = INVALID_HANDLE_VALUE;
*pErrorLine = 0;
myInfClearError();
if (NULL == pwszfnPolicy)
{
DWORD cwc;
cwc = GetEnvironmentVariable(
L"SystemRoot",
wszPath,
ARRAYSIZE(wszPath) - ARRAYSIZE(wszBSCAPOLICYFILE));
if (0 == cwc ||
ARRAYSIZE(wszPath) - ARRAYSIZE(wszBSCAPOLICYFILE) <= cwc)
{
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;
}
}
hr = infCollectSectionNames(pwszfnPolicy);
_JumpIfErrorStr(hr, error, "infCollectSectionNames", pwszfnPolicy);
Flags = INF_STYLE_WIN4;
for (;;)
{
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);
}
}
myInfClearError();
infFreeSectionNames();
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 == mylstrcmpiL(pwszValue, s_apwszTrue[i]))
{
*pfValue = TRUE;
break;
}
}
if (i == ARRAYSIZE(s_apwszTrue))
{
for (i = 0; i < ARRAYSIZE(s_apwszFalse); i++)
{
if (0 == mylstrcmpiL(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;
WCHAR *pwszValue = NULL;
*pfValue = FALSE;
myInfClearError();
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
hr = infSetupFindFirstLine(
hInf,
pwszSection,
pwszKey, // pwszKey
TRUE, // fUniqueKey
1, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&InfContext);
_PrintIfErrorStr3(
hr,
"infSetupFindFirstLine",
pwszSection,
ERROR_LINE_NOT_FOUND,
S_FALSE);
_JumpIfErrorStr3(
hr,
error,
"infSetupFindFirstLine",
pwszKey,
ERROR_LINE_NOT_FOUND,
S_FALSE);
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
pwszKey,
1,
TRUE, // fLastValue
&pwszValue);
_JumpIfErrorStr(hr, error, "infGetCurrentKeyValue", pwszKey);
DBGPRINT((
DBG_SS_CERTLIBI,
"myInfGetBooleanValue --> '%ws'\n",
pwszValue));
hr = myInfParseBooleanValue(pwszValue, pfValue);
_JumpIfError(hr, error, "myInfParseBooleanValue");
error:
if (S_OK != hr &&
((HRESULT) ERROR_LINE_NOT_FOUND != hr || !fIgnoreMissingKey))
{
INFSETERROR(hr, pwszSection, pwszKey, pwszValue);
CSILOG(hr, IDS_ILOG_BAD_BOOLEAN, pwszSection, pwszKey, NULL);
}
DBGPRINT((
DBG_SS_CERTLIBI,
"myInfGetBooleanValue(%ws, %ws) hr=%x --> f=%d\n",
pwszSection,
pwszKey,
hr,
*pfValue));
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
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 *pwszValue = NULL;
static WCHAR const * const s_apwszKeys[] =
{ wszINFKEY_POLICIES, wszINFKEY_CRITICAL, NULL };
ZeroMemory(&PoliciesInfo, sizeof(PoliciesInfo));
ZeroMemory(pext, sizeof(*pext));
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
hr = infSetupFindFirstLine(
hInf,
pwszSection,
wszINFKEY_POLICIES,
TRUE, // fUniqueKey
0, // cValueMax
s_apwszKeys,
TRUE, // fUniqueValidKeys
&InfContext);
if (S_OK != hr)
{
CSILOG(
hr,
IDS_ILOG_CAPOLICY_NOKEY,
pwszSection,
wszINFKEY_POLICIES,
NULL);
_JumpErrorStr3(
hr,
error,
"infSetupFindFirstLine",
pwszSection,
S_FALSE,
(HRESULT) 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 (NULL != pwszValue)
{
LocalFree(pwszValue);
pwszValue = NULL;
}
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
wszINFKEY_POLICIES,
i + 1,
FALSE, // fLastValue
&pwszValue);
_JumpIfErrorStr(hr, error, "infGetCurrentKeyValue", wszINFKEY_POLICIES);
DBGPRINT((DBG_SS_CERTLIBI, "%ws[%u] = %ws\n", wszINFKEY_POLICIES, i, pwszValue));
hr = infBuildPolicy(hInf, pwszValue, &PoliciesInfo.rgPolicyInfo[i]);
_JumpIfErrorStr(hr, error, "infBuildPolicy", pwszValue);
}
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, pwszValue);
}
CSILOG(hr, IDS_ILOG_CAPOLICY_EXTENSION, pwszValue, NULL, NULL);
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);
}
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
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_OK == hr2 ||
(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,
(HRESULT) 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
myInfGetCRLPublicationParams(
IN HINF hInf,
IN WCHAR const *pwszKeyCRLPeriodString,
IN WCHAR const *pwszKeyCRLPeriodCount,
OUT WCHAR **ppwszCRLPeriodString,
OUT DWORD *pdwCRLPeriodCount)
{
HRESULT hr;
WCHAR const *pwszKey;
// Retrieve units count and string. If either fails, both are discarded.
*ppwszCRLPeriodString = NULL;
pwszKey = pwszKeyCRLPeriodCount;
hr = myInfGetNumericKeyValue(
hInf,
TRUE, // fLog
wszINFSECTION_CERTSERVER,
pwszKey,
1,
TRUE, // fLastValue
pdwCRLPeriodCount);
_JumpIfErrorStr2(
hr,
error,
"myInfGetNumericKeyValue",
pwszKeyCRLPeriodCount,
ERROR_LINE_NOT_FOUND);
pwszKey = pwszKeyCRLPeriodString;
hr = myInfGetKeyValue(
hInf,
TRUE, // fLog
wszINFSECTION_CERTSERVER,
pwszKey,
1,
TRUE, // fLastValue
ppwszCRLPeriodString);
_JumpIfErrorStr2(
hr,
error,
"myInfGetKeyValue",
pwszKeyCRLPeriodString,
ERROR_LINE_NOT_FOUND);
error:
if (S_OK != hr)
{
INFSETERROR(hr, wszINFSECTION_CERTSERVER, pwszKey, NULL);
}
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,
IN DWORD Index,
IN BOOL fLastValue,
OUT WCHAR **ppwszValue)
{
HRESULT hr;
INFCONTEXT InfContext;
WCHAR *pwszValue = NULL;
*ppwszValue = NULL;
myInfClearError();
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
hr = infSetupFindFirstLine(
hInf,
pwszSection,
pwszKey,
TRUE, // fUniqueKey
fLastValue? Index : 0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&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,
pwszSection,
pwszKey,
Index,
fLastValue,
&pwszValue);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
*ppwszValue = pwszValue;
pwszValue = NULL;
hr = S_OK;
//wprintf(L"%ws = %ws\n", pwszKey, *ppwszValue);
error:
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
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,
IN DWORD Index,
IN BOOL fLastValue,
OUT DWORD *pdwValue)
{
HRESULT hr;
INFCONTEXT InfContext;
WCHAR *pwszValue = NULL;
INT Value;
myInfClearError();
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
hr = infSetupFindFirstLine(
hInf,
pwszSection,
pwszKey,
TRUE, // fUniqueKey
fLastValue? Index : 0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&InfContext);
if (S_OK != hr)
{
if (fLog)
{
CSILOG(hr, IDS_ILOG_CAPOLICY_NOKEY, pwszSection, pwszKey, NULL);
}
_PrintErrorStr2(
hr,
"infSetupFindFirstLine",
pwszKey,
ERROR_LINE_NOT_FOUND);
_JumpErrorStr2(
hr,
error,
"infSetupFindFirstLine",
pwszSection,
ERROR_LINE_NOT_FOUND);
}
if (fLastValue)
{
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
pwszKey,
Index,
fLastValue,
&pwszValue);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
}
if (!SetupGetIntField(&InfContext, Index, &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 (NULL != pwszValue)
{
LocalFree(pwszValue);
}
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,
1,
TRUE, // fLastValue
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 = Years (string)
// xxxxValidityPeriodUnits = 8 (count)
//
// 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;
WCHAR *pwszStringValue = NULL;
BOOL fValidCount = TRUE;
UINT idsLog = IDS_ILOG_BAD_VALIDITY_STRING;
*pdwValidityPeriodCount = 0;
*penumValidityPeriod = ENUM_PERIOD_INVALID;
hr = S_OK;
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,
1,
TRUE, // fLastValue
pdwValidityPeriodCount);
_JumpIfErrorStr2(
hr,
error,
"myInfGetNumericKeyValue",
pwszInfKeyNameCount,
ERROR_LINE_NOT_FOUND);
hr = myInfGetKeyValue(
hInf,
fLog,
wszINFSECTION_CERTSERVER,
pwszInfKeyNameString,
1,
TRUE, // fLastValue
&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 == LSTRCMPIS(pwszValidityPeriodString, wszPERIODYEARS))
{
*penumValidityPeriod = ENUM_PERIOD_YEARS;
}
else if (0 == LSTRCMPIS(pwszValidityPeriodString, wszPERIODMONTHS))
{
*penumValidityPeriod = ENUM_PERIOD_MONTHS;
}
else if (0 == LSTRCMPIS(pwszValidityPeriodString, wszPERIODWEEKS))
{
*penumValidityPeriod = ENUM_PERIOD_WEEKS;
}
else if (0 == LSTRCMPIS(pwszValidityPeriodString, wszPERIODDAYS))
{
*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[cwcDWORDSPRINTF];
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);
}
//+------------------------------------------------------------------------
// myInfGetValidityPeriod -- fetch renewal period & units from CAPolicy.inf
//
// [certsrv_server]
// xxxxValidityPeriod = Years (string)
// xxxxValidityPeriodUnits = 8 (count)
//
// 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 = Years (string)
// xxxxValidityPeriodUnits = 8 (count)
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 = Years (string)
// xxxxValidityPeriod = 8 (count)
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);
}
//+------------------------------------------------------------------------
// 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,
OPTIONAL IN WCHAR const *pwszKey,
OPTIONAL WCHAR const * const *ppwszValidKeys,
OPTIONAL OUT BOOL *pfCritical,
OPTIONAL OUT WCHAR **ppwszz)
{
HRESULT hr;
INFCONTEXT InfContext;
DWORD iVal;
DWORD cwc;
WCHAR *pwsz;
WCHAR **apwszVal = NULL;
DWORD cVal;
if (NULL != pfCritical)
{
*pfCritical = FALSE;
}
if (NULL != ppwszz)
{
*ppwszz = NULL;
}
myInfClearError();
cVal = 0;
if (NULL == pwszKey)
{
if (NULL == ppwszValidKeys || NULL != pfCritical || NULL != ppwszz)
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "NULL/non-NULL parms", pwszSection);
}
}
else if (NULL == ppwszz)
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "ppwszz parms", pwszKey);
}
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
{
hr = E_HANDLE;
_JumpError2(hr, error, "hInf", hr);
}
hr = infSetupFindFirstLine(
hInf,
pwszSection,
pwszKey,
FALSE, // fUniqueKey
NULL == pwszKey? 0 : 1, // cValueMax
ppwszValidKeys,
FALSE, // fUniqueValidKeys
&InfContext);
if (S_OK != hr)
{
CSILOG(hr, IDS_ILOG_CAPOLICY_NOKEY, pwszSection, pwszKey, NULL);
_JumpErrorStr3(
hr,
error,
"infSetupFindFirstLine",
pwszSection,
S_FALSE,
(HRESULT) ERROR_LINE_NOT_FOUND);
}
if (NULL != pwszKey)
{
for (;;)
{
cVal++;
hr = infFindNextKey(pwszKey, &InfContext);
if (S_FALSE == hr)
{
break;
}
_JumpIfErrorStr(hr, error, "infFindNextKey", pwszKey);
}
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,
FALSE, // fUniqueKey
1, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&InfContext);
_JumpIfErrorStr(hr, error, "infSetupFindFirstLine", pwszSection);
cwc = 1;
iVal = 0;
for (;;)
{
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
pwszKey,
1,
TRUE, // fLastValue
&apwszVal[iVal]);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
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);
}
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;
static WCHAR const * const s_apwszKeys[] =
{ wszINFKEY_URL, wszINFKEY_CRITICAL, NULL };
hr = myInfGetKeyList(
hInf,
wszINFSECTION_CDP,
wszINFKEY_URL,
s_apwszKeys,
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;
static WCHAR const * const s_apwszKeys[] =
{ wszINFKEY_URL, wszINFKEY_CRITICAL, NULL };
hr = myInfGetKeyList(
hInf,
wszINFSECTION_AIA,
wszINFKEY_URL,
s_apwszKeys,
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;
WCHAR *pwszz = NULL;
WCHAR const *pwsz;
static WCHAR const * const s_apwszKeys[] =
{ wszINFKEY_OID, wszINFKEY_CRITICAL, NULL };
*ppwszz = NULL;
hr = myInfGetKeyList(
hInf,
wszINFSECTION_EKU,
wszINFKEY_OID,
s_apwszKeys,
pfCritical,
&pwszz);
_JumpIfErrorStr4(
hr,
error,
"myInfGetKeyList",
wszINFSECTION_EKU,
ERROR_LINE_NOT_FOUND,
S_FALSE,
E_HANDLE);
for (pwsz = pwszz; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
{
hr = myVerifyObjId(pwsz);
if (S_OK != hr)
{
INFSETERROR(hr, wszINFSECTION_EKU, wszINFKEY_OID, pwsz);
_JumpErrorStr(hr, error, "myVerifyObjId", pwsz);
}
}
*ppwszz = pwszz;
pwszz = NULL;
error:
DBGPRINT((
DBG_SS_CERTLIBI,
"myInfGetEnhancedKeyUsage hr=%x --> f=%d\n",
hr,
*pfCritical));
if (NULL != pwszz)
{
LocalFree(pwszz);
}
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;
static WCHAR const * const s_apwszKeys[] =
{ wszINFKEY_PATHLENGTH, wszINFKEY_CRITICAL, NULL };
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, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
s_apwszKeys,
TRUE, // fUniqueValidKeys
&InfContext);
if (S_OK != hr)
{
if (!fDefault)
{
_JumpErrorStr3(
hr,
error,
"infSetupFindFirstLine",
wszINFSECTION_BASICCONSTRAINTS,
S_FALSE,
(HRESULT) 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,
1,
TRUE, // fLastValue
&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,
(HRESULT) 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;
ceku.cUsageIdentifier = 0;
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,
(HRESULT) 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 *pwszName = NULL;
WCHAR *pwszValue = NULL;
DWORD cAttribute = 0;
CRYPT_ATTR_BLOB Attribute;
WCHAR *pwszTemplateName = NULL;
*ppwszTemplateName = NULL;
*pcAttribute = 0;
*ppaAttribute = NULL;
Attribute.pbData = NULL;
myInfClearError();
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
{
hr = E_HANDLE;
_JumpError2(hr, error, "hInf", hr);
}
hr = infSetupFindFirstLine(
hInf,
wszINFSECTION_REQUESTATTRIBUTES,
NULL, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&InfContext);
_JumpIfErrorStr2(
hr,
error,
"infSetupFindFirstLine",
wszINFSECTION_REQUESTATTRIBUTES,
ERROR_LINE_NOT_FOUND);
for (;;)
{
CRYPT_ENROLLMENT_NAME_VALUE_PAIR NamePair;
if (NULL != pwszName)
{
LocalFree(pwszName);
pwszName = NULL;
}
if (NULL != pwszValue)
{
LocalFree(pwszValue);
pwszValue = NULL;
}
hr = infGetCurrentKeyValue(
&InfContext,
wszINFSECTION_REQUESTATTRIBUTES,
NULL, // pwszKey
0,
FALSE, // fLastValue
&pwszName);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
hr = infGetCurrentKeyValue(
&InfContext,
wszINFSECTION_REQUESTATTRIBUTES,
pwszName,
1,
TRUE, // fLastValue
&pwszValue);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
//wprintf(L"%ws = %ws\n", pwszName, pwszValue);
NamePair.pwszName = pwszName;
NamePair.pwszValue = pwszValue;
if (0 == LSTRCMPIS(pwszName, wszPROPCERTTEMPLATE))
{
if (NULL != pwszTemplateName)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Duplicate cert template");
}
pwszTemplateName = pwszValue;
pwszValue = NULL;
}
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, pwszName, pwszValue);
}
if (NULL != pwszName)
{
LocalFree(pwszName);
}
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
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 },
{ FALSE, 3, CERT_ALT_NAME_OTHER_NAME, wszINFKEY_OTHERNAME },
};
#define CSUBTREEINFO ARRAYSIZE(g_aSubTreeInfo)
#define STII_OTHERNAMEUPN 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
#define STII_OTHERNAMEOID 7 // CERT_ALT_NAME_OTHER_NAME pOtherName
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)
{
if (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);
}
if (NULL != pName->pOtherName->pszObjId)
{
DBGPRINT((
DBG_SS_CERTLIBI,
"infFreeGeneralSubTreeElement: p=%x, Free(other.pszObjId=%x)\n",
pSubTree,
pName->pOtherName->pszObjId));
LocalFree(pName->pOtherName->pszObjId);
}
}
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);
}
}
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=0;
WCHAR const *pwszValue = pwszIPAddress;
*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 = myParseIPAddress(pwszIPAddress, ab, &cbAddress);
_JumpIfError(hr, error, "myParseIPAddress");
if (L'\0' != *pwszIPAddressMask)
{
cbMask = sizeof(ab) / 2;
pwszValue = pwszIPAddressMask;
hr = myParseIPAddress(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:
if (S_OK != hr)
{
INFSETERROR(hr, NULL, NULL, pwszValue);
}
return(hr);
}
HRESULT
infVerifySubtreeElement(
IN CERT_GENERAL_SUBTREE const *pSubTree)
{
HRESULT hr;
BYTE *pb = NULL;
DWORD cb;
CERT_NAME_CONSTRAINTS_INFO *pnci = NULL;
CERT_NAME_CONSTRAINTS_INFO nci;
ZeroMemory(&nci, sizeof(nci));
nci.cPermittedSubtree = 1;
nci.rgPermittedSubtree = const_cast<CERT_GENERAL_SUBTREE *>(pSubTree);
if (!myEncodeObject(
X509_ASN_ENCODING,
X509_NAME_CONSTRAINTS,
&nci,
0,
CERTLIB_USE_LOCALALLOC,
&pb,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myEncodeObject");
}
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_NAME_CONSTRAINTS,
pb,
cb,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pnci,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeObject");
}
hr = S_OK;
error:
if (NULL != pb)
{
LocalFree(pb);
}
if (NULL != pnci)
{
LocalFree(pnci);
}
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 = [email protected]
// 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,
NULL, // pwszSection
NULL, // pwszKey
1,
2 == pSubTreeInfo->dwInfMinMaxIndexBase, // fLastValue
&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_OTHERNAMEUPN:
case STII_OTHERNAMEOID:
{
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");
}
if (STII_OTHERNAMEUPN == iSubTreeInfo)
{
hr = myDupStringA(
szOID_NT_PRINCIPAL_NAME,
&SubTree.Base.pOtherName->pszObjId);
_JumpIfError(hr, error, "myDupStringA");
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");
}
}
else
{
hr = myVerifyObjId(pwszValue);
_JumpIfErrorStr(hr, error, "myVerifyObjId", pwszValue);
if (!myConvertWszToSz(
&SubTree.Base.pOtherName->pszObjId,
pwszValue,
-1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ConvertWszToSz");
}
if (NULL == pwszEmptyEntry)
{
hr = infGetCurrentKeyValue(
pInfContext,
NULL, // pwszSection
NULL, // pwszKey
2,
TRUE, // fLastValue
&pwszValueRead2);
_PrintIfError2(hr, "infGetCurrentKeyValue", hr);
pwszValue2 = pwszValueRead2;
}
else
{
pwszValue2 = pwszEmptyEntry;
}
if (NULL == pwszValue2 || L'\0' == *pwszValue2)
{
pwszValue2 = wszPROPOCTETTAG;
}
hr = myEncodeOtherNameBinary(
pwszValue2,
&SubTree.Base.pOtherName->Value.pbData,
&SubTree.Base.pOtherName->Value.cbData);
_JumpIfError(hr, error, "myEncodeOtherNameBinary");
}
DBGPRINT((
DBG_SS_CERTLIBI,
"infBuildSubTreeElement: p=%x, OtherName=%x,%x,%x\n",
pSubTree,
SubTree.Base.pOtherName,
SubTree.Base.pOtherName->pszObjId,
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");
DBGPRINT((
DBG_SS_CERTLIBI,
"infBuildSubTreeElement: p=%x, DirName=%x\n",
pSubTree,
SubTree.Base.DirectoryName.pbData));
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,
NULL, // pwszSection
NULL, // pwszKey
2,
TRUE, // fLastValue
&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");
DBGPRINT((
DBG_SS_CERTLIBI,
"infBuildSubTreeElement: p=%x, IPAddress=%x\n",
pSubTree,
SubTree.Base.IPAddress.pbData));
break;
case STII_REGISTEREDID:
if (!myConvertWszToSz(
&SubTree.Base.pszRegisteredID,
pwszValue,
-1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ConvertWszToSz");
}
DBGPRINT((
DBG_SS_CERTLIBI,
"infBuildSubTreeElement: 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,
"infBuildSubTreeElement: p=%x, pwsz=%x\n",
pSubTree,
*ppwsz));
}
hr = infVerifySubtreeElement(&SubTree);
_JumpIfErrorStr(hr, error, "infVerifySubTreeElement", pSubTreeInfo->pwszKey);
*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;
INFCONTEXT InfContext;
static WCHAR const * const s_apwszKeys[] =
{
wszINFKEY_UPN,
wszINFKEY_EMAIL,
wszINFKEY_DNS,
wszINFKEY_DIRECTORYNAME,
wszINFKEY_URL,
wszINFKEY_IPADDRESS,
wszINFKEY_REGISTEREDID,
wszINFKEY_OTHERNAME,
NULL
};
*pcSubTree = 0;
*ppSubTree = NULL;
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
hr = myInfGetKeyValue(
hInf,
TRUE, // fLog
pwszSection,
pwszKey,
1,
TRUE, // fLastValue
&pwszSubTreeSection);
_JumpIfErrorStr2(
hr,
error,
"myInfGetKeyValue",
pwszKey,
ERROR_LINE_NOT_FOUND);
hr = infSetupFindFirstLine(
hInf,
pwszSubTreeSection,
NULL, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
s_apwszKeys,
FALSE, // fUniqueValidKeys
&InfContext);
// if S_FALSE is returned if the section is empty. In this case,
// allow execution to continue, to fill in the empty permitted names.
if (S_OK != hr &&
S_FALSE != hr)
{
if ((HRESULT) ERROR_LINE_NOT_FOUND == hr)
{
hr = SPAPI_E_LINE_NOT_FOUND; // don't ignore this error
}
INFSETERROR(hr, pwszSubTreeSection, L"", L"");
_JumpErrorStr(hr, error, "infSetupFindFirstLine", pwszSubTreeSection);
}
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;
}
if (0 == cSubTree)
{
hr = SPAPI_E_LINE_NOT_FOUND; // don't ignore this error
INFSETERROR(hr, pwszSubTreeSection, L"", L"");
_JumpErrorStr(hr, error, "infSetupFindFirstLine", pwszSubTreeSection);
}
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 = [email protected]
// 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;
INFCONTEXT InfContext;
static WCHAR const * const s_apwszKeys[] =
{ wszINFKEY_EXCLUDE, wszINFKEY_INCLUDE, wszINFKEY_CRITICAL, NULL };
ZeroMemory(&NameConstraints, sizeof(NameConstraints));
ZeroMemory(pext, sizeof(*pext));
myInfClearError();
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
{
hr = E_HANDLE;
_JumpError2(hr, error, "hInf", hr);
}
hr = infSetupFindFirstLine(
hInf,
wszINFSECTION_NAMECONSTRAINTS,
NULL, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
s_apwszKeys,
TRUE, // fUniqueValidKeys
&InfContext);
_JumpIfErrorStr2(
hr,
error,
"infSetupFindFirstLine",
wszINFSECTION_NAMECONSTRAINTS,
ERROR_LINE_NOT_FOUND);
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 *pwszIssuer = NULL;
WCHAR *pwszSubject = NULL;
DWORD cPolicyMappingIn;
DWORD cPolicyMapping = 0;
cPolicyMappingIn = MAXDWORD;
if (NULL != pPolicyMapping)
{
cPolicyMappingIn = *pcPolicyMapping;
}
*pcPolicyMapping = 0;
CSASSERT(NULL != hInf && INVALID_HANDLE_VALUE != hInf);
cPolicyMapping = 0;
hr = infSetupFindFirstLine(
hInf,
pwszSection,
NULL, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&InfContext);
_JumpIfErrorStr3(
hr,
error,
"infSetupFindFirstLine",
pwszSection,
S_FALSE,
(HRESULT) ERROR_LINE_NOT_FOUND);
for (;;)
{
if (NULL != pwszIssuer)
{
LocalFree(pwszIssuer);
pwszIssuer = NULL;
}
if (NULL != pwszSubject)
{
LocalFree(pwszSubject);
pwszSubject = NULL;
}
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
NULL, // pwszKey
0,
FALSE, // fLastValue
&pwszIssuer);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
if (!iswdigit(pwszIssuer[0]))
{
if (0 != LSTRCMPIS(pwszIssuer, wszINFKEY_CRITICAL))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpErrorStr(hr, error, "bad key", pwszIssuer);
}
}
else
{
hr = myVerifyObjId(pwszIssuer);
_JumpIfErrorStr(hr, error, "myVerifyObjId", pwszIssuer);
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
pwszIssuer,
1,
TRUE, // fLastValue
&pwszSubject);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
hr = myVerifyObjId(pwszSubject);
_JumpIfErrorStr(hr, error, "myVerifyObjId", pwszSubject);
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, pwszIssuer, -1) ||
!ConvertWszToSz(&pMap->pszSubjectDomainPolicy, pwszSubject, -1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "ConvertWszToSz");
}
}
DBGPRINT((
DBG_SS_CERTLIBI,
"Map[%u]: %ws = %ws\n",
cPolicyMapping,
pwszIssuer,
pwszSubject));
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, pwszIssuer, pwszSubject);
}
if (NULL != pwszIssuer)
{
LocalFree(pwszIssuer);
}
if (NULL != pwszSubject)
{
LocalFree(pwszSubject);
}
return(hr);
}
HRESULT
infGetPolicyMappings(
IN HINF hInf,
IN WCHAR const *pwszSection,
OUT DWORD *pcPolicyMapping,
OUT CERT_POLICY_MAPPING **ppPolicyMapping)
{
HRESULT hr;
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,
(HRESULT) 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,
(HRESULT) 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,
(HRESULT) 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,
(HRESULT) 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;
INFCONTEXT InfContext;
static WCHAR const * const s_apwszKeys[] =
{
wszINFKEY_REQUIREEXPLICITPOLICY,
wszINFKEY_INHIBITPOLICYMAPPING,
wszINFKEY_CRITICAL,
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);
}
hr = infSetupFindFirstLine(
hInf,
pwszSection,
NULL, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
s_apwszKeys,
TRUE, // fUniqueValidKeys
&InfContext);
_JumpIfErrorStr2(
hr,
error,
"infSetupFindFirstLine",
pwszSection,
ERROR_LINE_NOT_FOUND);
PolicyConstraints.fRequireExplicitPolicy = TRUE;
pwszKey = wszINFKEY_REQUIREEXPLICITPOLICY;
hr = myInfGetNumericKeyValue(
hInf,
TRUE, // fLog
pwszSection,
pwszKey,
1,
TRUE, // fLastValue
&PolicyConstraints.dwRequireExplicitPolicySkipCerts);
if (S_OK != hr)
{
if ((HRESULT) ERROR_LINE_NOT_FOUND != hr)
{
_JumpError(hr, error, "myInfGetNumericKeyValue");
}
_PrintErrorStr2(
hr,
"myInfGetNumericKeyValue",
wszINFKEY_REQUIREEXPLICITPOLICY,
hr);
PolicyConstraints.dwRequireExplicitPolicySkipCerts = 0;
PolicyConstraints.fRequireExplicitPolicy = FALSE;
}
PolicyConstraints.fInhibitPolicyMapping = TRUE;
pwszKey = wszINFKEY_INHIBITPOLICYMAPPING;
hr = myInfGetNumericKeyValue(
hInf,
TRUE, // fLog
pwszSection,
pwszKey,
1,
TRUE, // fLastValue
&PolicyConstraints.dwInhibitPolicyMappingSkipCerts);
if (S_OK != hr)
{
if ((HRESULT) ERROR_LINE_NOT_FOUND != hr)
{
_JumpError(hr, error, "myInfGetNumericKeyValue");
}
_PrintErrorStr2(
hr,
"myInfGetNumericKeyValue",
wszINFKEY_INHIBITPOLICYMAPPING,
hr);
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);
_JumpIfErrorStr3(
hr,
error,
"infGetPolicyConstraintsExtensionSub",
wszINFSECTION_POLICYCONSTRAINTS,
S_FALSE,
(HRESULT) ERROR_LINE_NOT_FOUND);
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);
_JumpIfErrorStr3(
hr,
error,
"infGetPolicyConstraintsExtensionSub",
wszINFSECTION_APPLICATIONPOLICYCONSTRAINTS,
S_FALSE,
(HRESULT) ERROR_LINE_NOT_FOUND);
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;
DWORD i;
WCHAR const *pwszKey = NULL;
static WCHAR const * const s_apwszKeys[] =
{ wszINFKEY_CCDPSYNCDELTATIME, wszINFKEY_URL, wszINFKEY_CRITICAL, 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, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
s_apwszKeys,
FALSE, // fUniqueValidKeys
&InfContext);
_JumpIfErrorStr3(
hr,
error,
"infSetupFindFirstLine",
wszINFSECTION_CCDP,
S_FALSE,
(HRESULT) ERROR_LINE_NOT_FOUND);
pwszKey = wszINFKEY_CCDPSYNCDELTATIME;
hr = myInfGetNumericKeyValue(
hInf,
TRUE, // fLog
wszINFSECTION_CCDP,
pwszKey,
1,
TRUE, // fLastValue
&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,
NULL, // apwszKeys
&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 *pwszName = NULL;
WCHAR *pwszValue = NULL;
DWORD i;
DWORD cInfValues = 0;
INFVALUES *rgInfValues = NULL;
INFVALUES *pInfValues;
*pcInfValues = 0;
*prgInfValues = NULL;
myInfClearError();
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
{
hr = E_HANDLE;
_JumpError2(hr, error, "hInf", hr);
}
hr = infSetupFindFirstLine(
hInf,
pwszSection,
NULL, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&InfContext);
_JumpIfErrorStr(hr, error, "infSetupFindFirstLine", pwszSection);
for (;;)
{
DWORD cValue;
if (NULL != pwszName)
{
LocalFree(pwszName);
pwszName = NULL;
}
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
NULL, // pwszKey
0,
FALSE, // fLastValue
&pwszName);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
//wprintf(L"%ws[0]:\n", pwszName);
hr = infAddKey(pwszName, &cInfValues, &rgInfValues, &pInfValues);
_JumpIfError(hr, error, "infAddKey");
cValue = SetupGetFieldCount(&InfContext);
if (0 == cValue)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
INFSETERROR(hr, pwszSection, pwszName, L"");
_JumpErrorStr(hr, error, "SetupGetFieldCount", pwszName);
}
for (i = 0; i < cValue; i++)
{
if (NULL != pwszValue)
{
LocalFree(pwszValue);
pwszValue = NULL;
}
hr = infGetCurrentKeyValue(
&InfContext,
pwszSection,
pwszName,
i + 1,
FALSE, // fLastValue
&pwszValue);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
//wprintf(L"%ws[%u] = %ws\n", pwszName, i, pwszValue);
hr = infAddValue(pwszValue, 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, pwszName, pwszValue);
}
if (NULL != rgInfValues)
{
myInfFreeSectionValues(cInfValues, rgInfValues);
}
if (NULL != pwszName)
{
LocalFree(pwszName);
}
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
DBGPRINT((
DBG_SS_CERTLIBI,
"myInfGetSectionValues hr=%x --> c=%d\n",
hr,
*pcInfValues));
return(hr);
}
HRESULT
myInfGetEnableKeyCounting(
IN HINF hInf,
OUT BOOL *pfValue)
{
HRESULT hr;
*pfValue = FALSE;
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
{
hr = E_HANDLE;
_JumpError2(hr, error, "hInf", hr);
}
myInfClearError();
hr = myInfGetBooleanValue(
hInf,
wszINFSECTION_CERTSERVER,
wszINFKEY_ENABLEKEYCOUNTING,
TRUE,
pfValue);
_JumpIfError2(hr, error, "myDupString", ERROR_LINE_NOT_FOUND);
error:
return(hr);
}
VOID
myInfFreeExtensions(
IN DWORD cExt,
IN CERT_EXTENSION *rgExt)
{
if (NULL != rgExt)
{
DWORD i;
for (i = 0; i < cExt; i++)
{
if (NULL != rgExt[i].pszObjId)
{
LocalFree(rgExt[i].pszObjId);
}
if (NULL != rgExt[i].Value.pbData)
{
LocalFree(rgExt[i].Value.pbData);
}
}
LocalFree(rgExt);
}
}
HRESULT
infBuildExtension(
IN OUT INFCONTEXT *pInfContext,
OPTIONAL OUT CERT_EXTENSION *pExt)
{
HRESULT hr;
WCHAR *pwszKey = NULL;
char *pszObjId = NULL;
WCHAR *pwszValue = NULL;
BYTE *pbData = NULL;
DWORD cbData;
hr = infGetCurrentKeyValue(
pInfContext,
NULL, // pwszSection
NULL, // pwszKey
0,
FALSE, // fLastValue
&pwszKey);
_JumpIfError(hr, error, "infGetCurrentKeyValue");
DBGPRINT((DBG_SS_CERTLIBI, "Element = %ws\n", pwszKey));
if (0 == LSTRCMPIS(pwszKey, wszINFKEY_CRITICAL) ||
0 == LSTRCMPIS(pwszKey, wszINFKEY_CONTINUE))
{
hr = S_FALSE; // Skip this key
_JumpError2(hr, error, "skip Critical/_continue_ key", hr);
}
if (!myConvertWszToSz(&pszObjId, pwszKey, -1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "myConvertWszToSz");
}
hr = myVerifyObjIdA(pszObjId);
_JumpIfErrorStr(hr, error, "myVerifyObjIdA", pwszKey);
DBGPRINT((DBG_SS_CERTLIBI, "OID = %hs\n", pszObjId));
hr = infGetCurrentKeyValue(
pInfContext,
NULL, // pwszSection
pwszKey,
1,
TRUE, // fLastValue
&pwszValue);
_JumpIfErrorStr(hr, error, "infGetCurrentKeyValue", pwszKey);
DBGPRINT((DBG_SS_CERTLIBI, "%ws = %ws\n", pwszKey, pwszValue));
cbData = 0;
if (L'\0' != *pwszValue) // allow empty values
{
hr = myCryptStringToBinary(
pwszValue,
wcslen(pwszValue),
CRYPT_STRING_BASE64,
&pbData,
&cbData,
NULL,
NULL);
_JumpIfErrorStr(hr, error, "myCryptStringToBinary", pwszKey);
}
if (NULL != pExt)
{
pExt->pszObjId = pszObjId;
pExt->Value.pbData = pbData;
pExt->Value.cbData = cbData;
pszObjId = NULL;
pbData = NULL;
}
hr = S_OK;
error:
if (S_OK != hr && S_FALSE != hr)
{
INFSETERROR(hr, NULL, pwszKey, pwszValue);
}
if (NULL != pwszKey)
{
LocalFree(pwszKey);
}
if (NULL != pszObjId)
{
LocalFree(pszObjId);
}
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
if (NULL != pbData)
{
LocalFree(pbData);
}
return(hr);
}
HRESULT
myInfGetExtensions(
IN HINF hInf,
OUT DWORD *pcExt,
OUT CERT_EXTENSION **ppExt)
{
HRESULT hr;
DWORD i;
DWORD cExt;
CERT_EXTENSION *rgExt = NULL;
DWORD cCritical;
INFCONTEXT InfContext;
WCHAR *pwszValue = NULL;
char *pszObjId = NULL;
WCHAR *pwszObjIdKey = NULL;
WCHAR const *pwszSection = wszINFSECTION_EXTENSIONS;
WCHAR const *pwszKey = wszINFKEY_CRITICAL;
DWORD j;
*pcExt = 0;
*ppExt = NULL;
cExt = 0;
if (NULL == hInf || INVALID_HANDLE_VALUE == hInf)
{
hr = E_HANDLE;
_JumpError2(hr, error, "hInf", hr);
}
myInfClearError();
hr = infSetupFindFirstLine(
hInf,
pwszSection,
NULL, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&InfContext);
_JumpIfErrorStr2(
hr,
error,
"infSetupFindFirstLine",
pwszSection,
ERROR_LINE_NOT_FOUND);
for (i = 0; ; )
{
hr = infBuildExtension(&InfContext, NULL);
if (S_FALSE != hr)
{
_JumpIfErrorStr(hr, error, "infBuildExtension", pwszSection);
i++;
}
if (!SetupFindNextLine(&InfContext, &InfContext))
{
hr = myHLastError();
_PrintErrorStr2(hr, "SetupFindNextLine", pwszSection, hr);
break;
}
}
cExt = i;
rgExt = (CERT_EXTENSION *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
cExt * sizeof(rgExt[0]));
if (NULL == rgExt)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
hr = infSetupFindFirstLine(
hInf,
pwszSection,
NULL, // pwszKey
FALSE, // fUniqueKey
0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&InfContext);
_JumpIfErrorStr(hr, error, "infSetupFindFirstLine", pwszSection);
for (i = 0; ; )
{
// handle one URL or text message
hr = infBuildExtension(&InfContext, &rgExt[i]);
if (S_FALSE != hr)
{
_JumpIfErrorStr(hr, error, "infBuildExtension", pwszSection);
for (j = 0; j < i; j++)
{
if (0 == strcmp(rgExt[j].pszObjId, rgExt[i].pszObjId))
{
if (!myConvertSzToWsz(&pwszObjIdKey, rgExt[i].pszObjId, -1))
{
_PrintError(E_OUTOFMEMORY, "myConvertSzToWsz");
}
hr = HRESULT_FROM_WIN32(RPC_S_ENTRY_ALREADY_EXISTS);
INFSETERROR(hr, pwszSection, pwszObjIdKey, NULL);
_JumpErrorStr(hr, error, "infBuildExtension", pwszObjIdKey);
}
}
i++;
}
if (!SetupFindNextLine(&InfContext, &InfContext))
{
hr = myHLastError();
_PrintErrorStr2(hr, "SetupFindNextLine", pwszSection, hr);
break;
}
}
CSASSERT(i == cExt);
hr = infSetupFindFirstLine(
hInf,
pwszSection,
pwszKey,
TRUE, // fUniqueKey
0, // cValueMax
NULL, // apwszKeys
FALSE, // fUniqueValidKeys
&InfContext);
_PrintIfErrorStr2(
hr,
"infSetupFindFirstLine",
pwszKey,
ERROR_LINE_NOT_FOUND);
if (S_OK != hr)
{
if ((HRESULT) ERROR_LINE_NOT_FOUND != hr)
{
INFSETERROR(hr, pwszSection, pwszKey, NULL);
_JumpErrorStr(hr, error, "infSetupFindFirstLine", pwszKey);
}
}
else
{
cCritical = SetupGetFieldCount(&InfContext);
for (i = 1; i <= cCritical; i++)
{
if (NULL != pwszValue)
{
LocalFree(pwszValue);
pwszValue = NULL;
}
if (NULL != pszObjId)
{
LocalFree(pszObjId);
pszObjId = NULL;
}
hr = infGetCurrentKeyValue(
&InfContext,
NULL, // pwszSection
pwszKey,
i,
FALSE, // fLastValue
&pwszValue);
_JumpIfErrorStr(hr, error, "infGetCurrentKeyValue", pwszKey);
if (!myConvertWszToSz(&pszObjId, pwszValue, -1))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "myConvertWszToSz");
}
for (j = 0; j < cExt; j++)
{
if (NULL != rgExt[j].Value.pbData &&
0 != rgExt[j].Value.cbData &&
0 == strcmp(rgExt[j].pszObjId, pszObjId))
{
if (rgExt[j].fCritical)
{
hr = HRESULT_FROM_WIN32(RPC_S_ENTRY_ALREADY_EXISTS);
INFSETERROR(hr, pwszSection, pwszKey, pwszValue);
_JumpErrorStr(hr, error, "duplicate OID", pwszValue);
}
rgExt[j].fCritical = TRUE;
break;
}
}
if (j == cExt)
{
hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
INFSETERROR(hr, pwszSection, pwszKey, pwszValue);
_JumpErrorStr(hr, error, "extraneous OID", pwszValue);
}
}
}
*pcExt = cExt;
*ppExt = rgExt;
rgExt = NULL;
hr = S_OK;
error:
if (S_OK != hr && (HRESULT) ERROR_LINE_NOT_FOUND != hr)
{
INFSETERROR(hr, pwszSection, NULL, NULL);
}
if (NULL != pwszValue)
{
LocalFree(pwszValue);
}
if (NULL != pszObjId)
{
LocalFree(pszObjId);
}
if (NULL != pwszObjIdKey)
{
LocalFree(pwszObjIdKey);
}
myInfFreeExtensions(cExt, rgExt);
return(hr);
}