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.
354 lines
12 KiB
354 lines
12 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: ctlfunc.cpp
|
|
//
|
|
// Contents: Certificate Verify CTL Usage Dispatch Functions
|
|
//
|
|
// Functions: I_CertCTLUsageFuncDllMain
|
|
// CertVerifyCTLUsage
|
|
//
|
|
// History: 29-Apr-97 philh created
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "global.hxx"
|
|
#include <dbgdef.h>
|
|
|
|
static HCRYPTOIDFUNCSET hUsageFuncSet;
|
|
|
|
typedef BOOL (WINAPI *PFN_CERT_DLL_VERIFY_CTL_USAGE)(
|
|
IN DWORD dwEncodingType,
|
|
IN DWORD dwSubjectType,
|
|
IN void *pvSubject,
|
|
IN PCTL_USAGE pSubjectUsage,
|
|
IN DWORD dwFlags,
|
|
IN OPTIONAL PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
|
|
IN OUT PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus
|
|
);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Dll initialization
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
I_CertCTLUsageFuncDllMain(
|
|
HMODULE hModule,
|
|
ULONG ulReason,
|
|
LPVOID lpReserved)
|
|
{
|
|
BOOL fRet;
|
|
|
|
switch (ulReason) {
|
|
case DLL_PROCESS_ATTACH:
|
|
if (NULL == (hUsageFuncSet = CryptInitOIDFunctionSet(
|
|
CRYPT_OID_VERIFY_CTL_USAGE_FUNC,
|
|
0))) // dwFlags
|
|
goto CryptInitOIDFunctionSetError;
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
case DLL_THREAD_DETACH:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
TRACE_ERROR(CryptInitOIDFunctionSetError)
|
|
}
|
|
|
|
static void ZeroUsageStatus(
|
|
IN OUT PCTL_VERIFY_USAGE_STATUS pUsageStatus)
|
|
{
|
|
pUsageStatus->dwError = 0;
|
|
pUsageStatus->dwFlags = 0;
|
|
if (pUsageStatus->ppCtl)
|
|
*pUsageStatus->ppCtl = NULL;
|
|
pUsageStatus->dwCtlEntryIndex = 0;
|
|
if (pUsageStatus->ppSigner)
|
|
*pUsageStatus->ppSigner = NULL;
|
|
pUsageStatus->dwSignerIndex = 0;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Remember the "most interesting" error
|
|
//--------------------------------------------------------------------------
|
|
static void UpdateUsageError(
|
|
IN DWORD dwNewError,
|
|
IN OUT DWORD *pdwError
|
|
)
|
|
{
|
|
if (0 != dwNewError) {
|
|
DWORD dwError = *pdwError;
|
|
if ((DWORD) CRYPT_E_NOT_IN_CTL == dwNewError ||
|
|
(DWORD) CRYPT_E_NO_VERIFY_USAGE_DLL == dwError
|
|
||
|
|
((DWORD) CRYPT_E_NOT_IN_CTL != dwError &&
|
|
(DWORD) CRYPT_E_NO_TRUSTED_SIGNER != dwError &&
|
|
(DWORD) CRYPT_E_NO_VERIFY_USAGE_CHECK != dwNewError))
|
|
*pdwError = dwNewError;
|
|
}
|
|
}
|
|
|
|
static BOOL VerifyDefaultUsage(
|
|
IN DWORD dwEncodingType,
|
|
IN DWORD dwSubjectType,
|
|
IN void *pvSubject,
|
|
IN PCTL_USAGE pSubjectUsage,
|
|
IN DWORD dwFlags,
|
|
IN OPTIONAL PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
|
|
IN OUT PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
DWORD dwError = (DWORD) CRYPT_E_NO_VERIFY_USAGE_DLL;
|
|
LPWSTR pwszDllList; // _alloca'ed
|
|
DWORD cchDllList;
|
|
DWORD cchDll;
|
|
void *pvFuncAddr;
|
|
HCRYPTOIDFUNCADDR hFuncAddr;
|
|
|
|
// Iterate through the installed default functions.
|
|
// Setting pwszDll to NULL searches the installed list. Setting
|
|
// hFuncAddr to NULL starts the search at the beginning.
|
|
hFuncAddr = NULL;
|
|
while (CryptGetDefaultOIDFunctionAddress(
|
|
hUsageFuncSet,
|
|
dwEncodingType,
|
|
NULL, // pwszDll
|
|
0, // dwFlags
|
|
&pvFuncAddr,
|
|
&hFuncAddr)) {
|
|
ZeroUsageStatus(pVerifyUsageStatus);
|
|
fResult = ((PFN_CERT_DLL_VERIFY_CTL_USAGE) pvFuncAddr)(
|
|
dwEncodingType,
|
|
dwSubjectType,
|
|
pvSubject,
|
|
pSubjectUsage,
|
|
dwFlags,
|
|
pVerifyUsagePara,
|
|
pVerifyUsageStatus);
|
|
if (fResult) {
|
|
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
|
|
goto CommonReturn;
|
|
} else
|
|
// Unable to verify usage for this installed
|
|
// function. However, remember any "interesting"
|
|
// errors.
|
|
UpdateUsageError(pVerifyUsageStatus->dwError, &dwError);
|
|
}
|
|
|
|
if (!CryptGetDefaultOIDDllList(
|
|
hUsageFuncSet,
|
|
dwEncodingType,
|
|
NULL, // pszDllList
|
|
&cchDllList)) goto GetDllListError;
|
|
__try {
|
|
pwszDllList = (LPWSTR) _alloca(cchDllList * sizeof(WCHAR));
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
goto OutOfMemory;
|
|
}
|
|
if (!CryptGetDefaultOIDDllList(
|
|
hUsageFuncSet,
|
|
dwEncodingType,
|
|
pwszDllList,
|
|
&cchDllList)) goto GetDllListError;
|
|
|
|
for (; 0 != (cchDll = wcslen(pwszDllList)); pwszDllList += cchDll + 1) {
|
|
if (CryptGetDefaultOIDFunctionAddress(
|
|
hUsageFuncSet,
|
|
dwEncodingType,
|
|
pwszDllList,
|
|
0, // dwFlags
|
|
&pvFuncAddr,
|
|
&hFuncAddr)) {
|
|
ZeroUsageStatus(pVerifyUsageStatus);
|
|
fResult = ((PFN_CERT_DLL_VERIFY_CTL_USAGE) pvFuncAddr)(
|
|
dwEncodingType,
|
|
dwSubjectType,
|
|
pvSubject,
|
|
pSubjectUsage,
|
|
dwFlags,
|
|
pVerifyUsagePara,
|
|
pVerifyUsageStatus);
|
|
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
|
|
if (fResult)
|
|
goto CommonReturn;
|
|
else
|
|
// Unable to verify usage for this registered
|
|
// function. However, remember any "interesting"
|
|
// errors.
|
|
UpdateUsageError(pVerifyUsageStatus->dwError, &dwError);
|
|
}
|
|
}
|
|
|
|
goto ErrorReturn;
|
|
|
|
CommonReturn:
|
|
return fResult;
|
|
ErrorReturn:
|
|
pVerifyUsageStatus->dwError = dwError;
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
TRACE_ERROR(GetDllListError)
|
|
TRACE_ERROR(OutOfMemory)
|
|
}
|
|
|
|
static BOOL VerifyOIDUsage(
|
|
IN DWORD dwEncodingType,
|
|
IN DWORD dwSubjectType,
|
|
IN void *pvSubject,
|
|
IN PCTL_USAGE pSubjectUsage,
|
|
IN DWORD dwFlags,
|
|
IN OPTIONAL PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
|
|
IN OUT PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
HCRYPTOIDFUNCADDR hFuncAddr;
|
|
PVOID pvFuncAddr;
|
|
|
|
if (pSubjectUsage && pSubjectUsage->cUsageIdentifier > 0 &&
|
|
CryptGetOIDFunctionAddress(
|
|
hUsageFuncSet,
|
|
dwEncodingType,
|
|
pSubjectUsage->rgpszUsageIdentifier[0],
|
|
0, // dwFlags
|
|
&pvFuncAddr,
|
|
&hFuncAddr)) {
|
|
ZeroUsageStatus(pVerifyUsageStatus);
|
|
fResult = ((PFN_CERT_DLL_VERIFY_CTL_USAGE) pvFuncAddr)(
|
|
dwEncodingType,
|
|
dwSubjectType,
|
|
pvSubject,
|
|
pSubjectUsage,
|
|
dwFlags,
|
|
pVerifyUsagePara,
|
|
pVerifyUsageStatus);
|
|
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
|
|
} else {
|
|
pVerifyUsageStatus->dwError = (DWORD) CRYPT_E_NO_VERIFY_USAGE_DLL;
|
|
fResult = FALSE;
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Verify that a subject is trusted for the specified usage by finding a
|
|
// signed and time valid CTL with the usage identifiers and containing the
|
|
// the subject. A subject can be identified by either its certificate context
|
|
// or any identifier such as its SHA1 hash.
|
|
//
|
|
// See CertFindSubjectInCTL for definition of dwSubjectType and pvSubject
|
|
// parameters.
|
|
//
|
|
// Via pVerifyUsagePara, the caller can specify the stores to be searched
|
|
// to find the CTL. The caller can also specify the stores containing
|
|
// acceptable CTL signers. By setting the ListIdentifier, the caller
|
|
// can also restrict to a particular signer CTL list.
|
|
//
|
|
// Via pVerifyUsageStatus, the CTL containing the subject, the subject's
|
|
// index into the CTL's array of entries, and the signer of the CTL
|
|
// are returned. If the caller is interested, ppCtl and ppSigner can be set
|
|
// to NULL. Returned contexts must be freed via the store's free context APIs.
|
|
//
|
|
// If the CERT_VERIFY_INHIBIT_CTL_UPDATE_FLAG isn't set, then, a time
|
|
// invalid CTL in one of the CtlStores may be replaced. When replaced, the
|
|
// CERT_VERIFY_UPDATED_CTL_FLAG is set in pVerifyUsageStatus->dwFlags.
|
|
//
|
|
// If the CERT_VERIFY_TRUSTED_SIGNERS_FLAG is set, then, only the
|
|
// SignerStores specified in pVerifyUsageStatus are searched to find
|
|
// the signer. Otherwise, the SignerStores provide additional sources
|
|
// to find the signer's certificate.
|
|
//
|
|
// If CERT_VERIFY_NO_TIME_CHECK_FLAG is set, then, the CTLs aren't checked
|
|
// for time validity.
|
|
//
|
|
// If CERT_VERIFY_ALLOW_MORE_USAGE_FLAG is set, then, the CTL may contain
|
|
// additional usage identifiers than specified by pSubjectUsage. Otherwise,
|
|
// the found CTL will contain the same usage identifers and no more.
|
|
//
|
|
// CertVerifyCTLUsage will be implemented as a dispatcher to OID installable
|
|
// functions. First, it will try to find an OID function matching the first
|
|
// usage object identifier in the pUsage sequence. Next, it will dispatch
|
|
// to the default CertDllVerifyCTLUsage functions.
|
|
//
|
|
// If the subject is trusted for the specified usage, then, TRUE is
|
|
// returned. Otherwise, FALSE is returned with dwError set to one of the
|
|
// following:
|
|
// CRYPT_E_NO_VERIFY_USAGE_DLL
|
|
// CRYPT_E_NO_VERIFY_USAGE_CHECK
|
|
// CRYPT_E_VERIFY_USAGE_OFFLINE
|
|
// CRYPT_E_NOT_IN_CTL
|
|
// CRYPT_E_NO_TRUSTED_SIGNER
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
CertVerifyCTLUsage(
|
|
IN DWORD dwEncodingType,
|
|
IN DWORD dwSubjectType,
|
|
IN void *pvSubject,
|
|
IN PCTL_USAGE pSubjectUsage,
|
|
IN DWORD dwFlags,
|
|
IN OPTIONAL PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
|
|
IN OUT PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
|
|
assert(NULL == pVerifyUsagePara || pVerifyUsagePara->cbSize >=
|
|
sizeof(CTL_VERIFY_USAGE_PARA));
|
|
assert(pVerifyUsageStatus && pVerifyUsageStatus->cbSize >=
|
|
sizeof(CTL_VERIFY_USAGE_STATUS));
|
|
if (pVerifyUsagePara && pVerifyUsagePara->cbSize <
|
|
sizeof(CTL_VERIFY_USAGE_PARA))
|
|
goto InvalidArg;
|
|
if (NULL == pVerifyUsageStatus || pVerifyUsageStatus->cbSize <
|
|
sizeof(CTL_VERIFY_USAGE_STATUS))
|
|
goto InvalidArg;
|
|
|
|
|
|
fResult = VerifyOIDUsage(
|
|
dwEncodingType,
|
|
dwSubjectType,
|
|
pvSubject,
|
|
pSubjectUsage,
|
|
dwFlags,
|
|
pVerifyUsagePara,
|
|
pVerifyUsageStatus);
|
|
if (!fResult) {
|
|
DWORD dwError = pVerifyUsageStatus->dwError;
|
|
|
|
fResult = VerifyDefaultUsage(
|
|
dwEncodingType,
|
|
dwSubjectType,
|
|
pvSubject,
|
|
pSubjectUsage,
|
|
dwFlags,
|
|
pVerifyUsagePara,
|
|
pVerifyUsageStatus);
|
|
if (!fResult) {
|
|
UpdateUsageError(pVerifyUsageStatus->dwError, &dwError);
|
|
ZeroUsageStatus(pVerifyUsageStatus);
|
|
pVerifyUsageStatus->dwError = dwError;
|
|
SetLastError(dwError);
|
|
}
|
|
}
|
|
|
|
CommonReturn:
|
|
return fResult;
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR(InvalidArg, E_INVALIDARG)
|
|
}
|