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