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.
 
 
 
 
 
 

376 lines
12 KiB

//+-------------------------------------------------------------------------
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1999 - 1999
//
// File: rootlist.cpp
//
// Contents: Signed List of Trusted Roots Helper Functions
//
//
// Functions: IRL_VerifyAuthRootAutoUpdateCtl
//
// History: 01-Aug-99 philh created
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
#ifdef STATIC
#undef STATIC
#endif
#define STATIC
//+-------------------------------------------------------------------------
// If the certificate has an EKU extension, returns an allocated and
// decoded EKU. Otherwise, returns NULL.
//
// PkiFree() must be called to free the returned EKU.
//--------------------------------------------------------------------------
STATIC
PCERT_ENHKEY_USAGE
WINAPI
GetAndAllocCertEKUExt(
IN PCCERT_CONTEXT pCert
)
{
PCERT_ENHKEY_USAGE pUsage = NULL;
DWORD cbUsage;
cbUsage = 0;
if (!CertGetEnhancedKeyUsage(
pCert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
NULL, // pUsage
&cbUsage) || 0 == cbUsage)
goto GetEnhancedKeyUsageError;
if (NULL == (pUsage = (PCERT_ENHKEY_USAGE) PkiNonzeroAlloc(cbUsage)))
goto OutOfMemory;
if (!CertGetEnhancedKeyUsage(
pCert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
pUsage,
&cbUsage))
goto GetEnhancedKeyUsageError;
CommonReturn:
return pUsage;
ErrorReturn:
if (pUsage) {
PkiFree(pUsage);
pUsage = NULL;
}
goto CommonReturn;
SET_ERROR(GetEnhancedKeyUsageError, CERT_E_WRONG_USAGE)
TRACE_ERROR(OutOfMemory)
}
//+-------------------------------------------------------------------------
// The signature of the CTL is verified. The signer of the CTL is verified
// up to a trusted root containing the predefined Microsoft public key.
//
// The signer and intermediate certificates must have the
// szOID_ROOT_LIST_SIGNER enhanced key usage extension.
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
VerifyAuthRootAutoUpdateCtlSigner(
IN HCRYPTMSG hCryptMsg
)
{
BOOL fResult;
DWORD dwLastError = 0;
HCERTSTORE hMsgStore = NULL;
PCCERT_CONTEXT pSignerCert = NULL;
LPSTR pszUsageOID;
CERT_CHAIN_PARA ChainPara;
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
PCERT_SIMPLE_CHAIN pChain;
DWORD cChainElement;
CERT_CHAIN_POLICY_PARA BasePolicyPara;
CERT_CHAIN_POLICY_STATUS BasePolicyStatus;
CERT_CHAIN_POLICY_PARA MicrosoftRootPolicyPara;
CERT_CHAIN_POLICY_STATUS MicrosoftRootPolicyStatus;
PCERT_ENHKEY_USAGE pUsage = NULL;
DWORD i;
if (NULL == (hMsgStore = CertOpenStore(
CERT_STORE_PROV_MSG,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0, // hCryptProv
0, // dwFlags
hCryptMsg // pvPara
)))
goto OpenMsgStoreError;
if (!CryptMsgGetAndVerifySigner(
hCryptMsg,
0, // cSignerStore
NULL, // rghSignerStore
0, // dwFlags
&pSignerCert,
NULL // pdwSignerIndex
))
goto CryptMsgGetAndVerifySignerError;
pszUsageOID = szOID_ROOT_LIST_SIGNER;
memset(&ChainPara, 0, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
ChainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = &pszUsageOID;
if (!CertGetCertificateChain(
NULL, // hChainEngine
pSignerCert,
NULL, // pTime
hMsgStore,
&ChainPara,
CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE,
NULL, // pvReserved
&pChainContext
))
goto GetChainError;
// Do the basic chain policy verification
memset(&BasePolicyPara, 0, sizeof(BasePolicyPara));
BasePolicyPara.cbSize = sizeof(BasePolicyPara);
// We explicitly check for the Microsoft Root below. It doesn't need
// to be in the root store.
BasePolicyPara.dwFlags =
CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG |
CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
memset(&BasePolicyStatus, 0, sizeof(BasePolicyStatus));
BasePolicyStatus.cbSize = sizeof(BasePolicyStatus);
if (!CertVerifyCertificateChainPolicy(
CERT_CHAIN_POLICY_BASE,
pChainContext,
&BasePolicyPara,
&BasePolicyStatus
))
goto VerifyChainBasePolicyError;
if (0 != BasePolicyStatus.dwError)
goto ChainBasePolicyError;
// Check that we have more than just the signer cert.
pChain = pChainContext->rgpChain[0];
cChainElement = pChain->cElement;
if (2 > cChainElement)
goto MissingSignerChainCertsError;
// Check that the top level certificate contains the public
// key for the Microsoft root.
memset(&MicrosoftRootPolicyPara, 0, sizeof(MicrosoftRootPolicyPara));
MicrosoftRootPolicyPara.cbSize = sizeof(MicrosoftRootPolicyPara);
memset(&MicrosoftRootPolicyStatus, 0, sizeof(MicrosoftRootPolicyStatus));
MicrosoftRootPolicyStatus.cbSize = sizeof(MicrosoftRootPolicyStatus);
if (!CertVerifyCertificateChainPolicy(
CERT_CHAIN_POLICY_MICROSOFT_ROOT,
pChainContext,
&MicrosoftRootPolicyPara,
&MicrosoftRootPolicyStatus
))
goto VerifyChainMicrosoftRootPolicyError;
if (0 != MicrosoftRootPolicyStatus.dwError)
goto ChainMicrosoftRootPolicyError;
// Check that the signer and intermediate certs have the RootListSigner
// Usage extension
for (i = 0; i < cChainElement - 1; i++) {
PCCERT_CONTEXT pCert; // not refCount'ed
DWORD j;
pCert = pChain->rgpElement[i]->pCertContext;
pUsage = GetAndAllocCertEKUExt(pCert);
if (NULL == pUsage)
goto GetAndAllocCertEKUExtError;
for (j = 0; j < pUsage->cUsageIdentifier; j++) {
if (0 == strcmp(szOID_ROOT_LIST_SIGNER,
pUsage->rgpszUsageIdentifier[j]))
break;
}
if (j == pUsage->cUsageIdentifier)
goto MissingRootListSignerUsageError;
PkiFree(pUsage);
pUsage = NULL;
}
fResult = TRUE;
CommonReturn:
if (pChainContext)
CertFreeCertificateChain(pChainContext);
if (pUsage)
PkiFree(pUsage);
if (pSignerCert)
CertFreeCertificateContext(pSignerCert);
if (hMsgStore)
CertCloseStore(hMsgStore, 0);
SetLastError(dwLastError);
return fResult;
ErrorReturn:
dwLastError = GetLastError();
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenMsgStoreError)
TRACE_ERROR(CryptMsgGetAndVerifySignerError)
TRACE_ERROR(GetChainError)
TRACE_ERROR(VerifyChainBasePolicyError)
SET_ERROR_VAR(ChainBasePolicyError, BasePolicyStatus.dwError)
TRACE_ERROR(VerifyChainMicrosoftRootPolicyError)
SET_ERROR_VAR(ChainMicrosoftRootPolicyError, MicrosoftRootPolicyStatus.dwError)
SET_ERROR(MissingSignerChainCertsError, CERT_E_CHAINING)
TRACE_ERROR(GetAndAllocCertEKUExtError)
SET_ERROR(MissingRootListSignerUsageError, CERT_E_WRONG_USAGE)
}
//+-------------------------------------------------------------------------
// Returns TRUE if all the CTL fields are valid. Checks for the following:
// - The SubjectUsage is szOID_ROOT_LIST_SIGNER
// - If NextUpdate isn't NULL, that the CTL is still time valid
// - Only allow roots identified by their sha1 hash
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
VerifyAuthRootAutoUpdateCtlFields(
IN PCTL_INFO pCtlInfo
)
{
BOOL fResult;
// Must have the szOID_ROOT_LIST_SIGNER usage
if (1 != pCtlInfo->SubjectUsage.cUsageIdentifier ||
0 != strcmp(szOID_ROOT_LIST_SIGNER,
pCtlInfo->SubjectUsage.rgpszUsageIdentifier[0]))
goto InvalidSubjectUsageError;
// If NextUpdate is present, verify that the CTL hasn't expired.
if (pCtlInfo->NextUpdate.dwLowDateTime ||
pCtlInfo->NextUpdate.dwHighDateTime) {
SYSTEMTIME SystemTime;
FILETIME FileTime;
GetSystemTime(&SystemTime);
SystemTimeToFileTime(&SystemTime, &FileTime);
if (CompareFileTime(&FileTime, &pCtlInfo->NextUpdate) > 0)
goto ExpiredCtlError;
}
// Only allow roots identified by their sha1 hash
if (0 != strcmp(szOID_OIWSEC_sha1,
pCtlInfo->SubjectAlgorithm.pszObjId))
goto InvalidSubjectAlgorithm;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidSubjectUsageError, ERROR_INVALID_DATA)
SET_ERROR(ExpiredCtlError, CERT_E_EXPIRED)
SET_ERROR(InvalidSubjectAlgorithm, ERROR_INVALID_DATA)
}
//+-------------------------------------------------------------------------
// Returns TRUE if the CTL doesn't have any critical extensions.
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
VerifyAuthRootAutoUpdateCtlExtensions(
IN PCTL_INFO pCtlInfo
)
{
BOOL fResult;
PCERT_EXTENSION pExt;
DWORD cExt;
// Verify the extensions
for (cExt = pCtlInfo->cExtension,
pExt = pCtlInfo->rgExtension; 0 < cExt; cExt--, pExt++)
{
if (pExt->fCritical) {
goto CriticalExtensionError;
}
}
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(CriticalExtensionError, ERROR_INVALID_DATA)
}
//+-------------------------------------------------------------------------
// Verifies that the CTL contains a valid list of AuthRoots used for
// Auto Update.
//
// The signature of the CTL is verified. The signer of the CTL is verified
// up to a trusted root containing the predefined Microsoft public key.
// The signer and intermediate certificates must have the
// szOID_ROOT_LIST_SIGNER enhanced key usage extension.
//
// The CTL fields are validated as follows:
// - The SubjectUsage is szOID_ROOT_LIST_SIGNER
// - If NextUpdate isn't NULL, that the CTL is still time valid
// - Only allow roots identified by their sha1 hash
//
// If the CTL contains any critical extensions, then, the
// CTL verification fails.
//--------------------------------------------------------------------------
BOOL
WINAPI
IRL_VerifyAuthRootAutoUpdateCtl(
IN PCCTL_CONTEXT pCtl
)
{
BOOL fResult;
PCTL_INFO pCtlInfo; // not allocated
if (!VerifyAuthRootAutoUpdateCtlSigner(pCtl->hCryptMsg))
goto VerifyCtlSignerError;
pCtlInfo = pCtl->pCtlInfo;
if (!VerifyAuthRootAutoUpdateCtlFields(pCtlInfo))
goto VerifyCtlFieldsError;
if (!VerifyAuthRootAutoUpdateCtlExtensions(pCtlInfo))
goto VerifyCtlExtensionsError;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(VerifyCtlSignerError)
TRACE_ERROR(VerifyCtlFieldsError)
TRACE_ERROR(VerifyCtlExtensionsError)
}