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

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)
}