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.
 
 
 
 
 
 

466 lines
14 KiB

//+-------------------------------------------------------------------------
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 2001 - 2001
//
// File: mscrlrev.cpp
//
// Contents: Check CRLs in CA store version of CertDllVerifyRevocation.
//
// Restrictions:
// - Only support CRYPT_ASN_ENCODING
// - CRL must already be in the CA system store
// - CRL must be issued and signed by the issuer of the
// certificate
// - CRL must not have any critical extensions
//
// Functions: DllMain
// DllRegisterServer
// DllUnregisterServer
// CertDllVerifyRevocation
//
// History: 15-Mar-01 philh created
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
//+-------------------------------------------------------------------------
// Default stores searched to find an issuer of the subject certificate
//--------------------------------------------------------------------------
struct {
LPCWSTR pwszStore;
DWORD dwFlags;
} rgDefaultIssuerStores[] = {
L"CA", CERT_SYSTEM_STORE_CURRENT_USER,
L"ROOT", CERT_SYSTEM_STORE_CURRENT_USER
};
#define NUM_DEFAULT_ISSUER_STORES (sizeof(rgDefaultIssuerStores) / \
sizeof(rgDefaultIssuerStores[0]))
//+-------------------------------------------------------------------------
// Dll initialization
//--------------------------------------------------------------------------
BOOL
WINAPI
DllMain(
HMODULE hInst,
ULONG ulReason,
LPVOID lpReserved)
{
switch (ulReason) {
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_DETACH:
default:
break;
}
return TRUE;
}
HRESULT HError()
{
DWORD dw = GetLastError();
HRESULT hr;
if ( dw <= 0xFFFF )
hr = HRESULT_FROM_WIN32 ( dw );
else
hr = dw;
if ( ! FAILED ( hr ) )
{
// somebody failed a call without properly setting an error condition
hr = E_UNEXPECTED;
}
return hr;
}
//+-------------------------------------------------------------------------
// DllRegisterServer
//--------------------------------------------------------------------------
STDAPI DllRegisterServer(void)
{
if (!CryptRegisterDefaultOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_VERIFY_REVOCATION_FUNC,
CRYPT_REGISTER_FIRST_INDEX,
L"mscrlrev.dll"
)) {
if (ERROR_FILE_EXISTS != GetLastError())
return HError();
}
return S_OK;
}
//+-------------------------------------------------------------------------
// DllUnregisterServer
//--------------------------------------------------------------------------
STDAPI DllUnregisterServer(void)
{
if (!CryptUnregisterDefaultOIDFunction(
X509_ASN_ENCODING,
CRYPT_OID_VERIFY_REVOCATION_FUNC,
L"mscrlrev.dll"
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
return HError();
}
return S_OK;
}
//+-------------------------------------------------------------------------
// Local functions called by CertDllVerifyRevocation
//--------------------------------------------------------------------------
PCCERT_CONTEXT GetIssuerCert(
IN DWORD cCert,
IN PCCERT_CONTEXT rgpCert[],
IN DWORD dwFlags,
IN PCERT_REVOCATION_PARA pRevPara
);
BOOL GetSubjectCrl (
IN PCCERT_CONTEXT pSubject,
IN PCCERT_CONTEXT pIssuer,
OUT PCCRL_CONTEXT* ppCrl
);
PCRL_ENTRY FindCertInCrl(
IN PCCERT_CONTEXT pCert,
IN PCCRL_CONTEXT pCrl,
IN PCERT_REVOCATION_PARA pRevPara
);
DWORD GetCrlReason(
IN PCRL_ENTRY pCrlEntry
);
//+-------------------------------------------------------------------------
// CertDllVerifyRevocation using pre-loaded CRLs in the CA store
//--------------------------------------------------------------------------
BOOL
WINAPI
CertDllVerifyRevocation(
IN DWORD dwEncodingType,
IN DWORD dwRevType,
IN DWORD cContext,
IN PVOID rgpvContext[],
IN DWORD dwFlags,
IN PCERT_REVOCATION_PARA pRevPara,
IN OUT PCERT_REVOCATION_STATUS pRevStatus
)
{
DWORD dwError = (DWORD) CRYPT_E_NO_REVOCATION_CHECK;
DWORD dwReason = 0;
PCCERT_CONTEXT pCert; // not allocated
PCCERT_CONTEXT pIssuer = NULL;
PCCRL_CONTEXT pCrl = NULL;
PCRL_ENTRY pCrlEntry;
if (cContext == 0)
goto NoContextError;
if (GET_CERT_ENCODING_TYPE(dwEncodingType) != CRYPT_ASN_ENCODING)
goto NoRevocationCheckForEncodingTypeError;
if (dwRevType != CERT_CONTEXT_REVOCATION_TYPE)
goto NoRevocationCheckForRevTypeError;
pCert = (PCCERT_CONTEXT) rgpvContext[0];
// Get the certificate's issuer
if (NULL == (pIssuer = GetIssuerCert(
cContext,
(PCCERT_CONTEXT *) rgpvContext,
dwFlags,
pRevPara
)))
goto NoIssuerError;
if (!GetSubjectCrl(
pCert,
pIssuer,
&pCrl
))
goto NoCrl;
// Check if revoked
pCrlEntry = FindCertInCrl(pCert, pCrl, pRevPara);
if (pCrlEntry) {
dwError = (DWORD) CRYPT_E_REVOKED;
dwReason = GetCrlReason(pCrlEntry);
goto Revoked;
}
CommonReturn:
if (pIssuer)
CertFreeCertificateContext(pIssuer);
if (pCrl)
CertFreeCRLContext(pCrl);
pRevStatus->dwIndex = 0;
pRevStatus->dwError = dwError;
pRevStatus->dwReason = dwReason;
SetLastError(dwError);
return FALSE;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(NoContextError)
TRACE_ERROR(NoRevocationCheckForEncodingTypeError)
TRACE_ERROR(NoRevocationCheckForRevTypeError)
TRACE_ERROR(NoIssuerError)
TRACE_ERROR(NoCrl)
TRACE_ERROR(Revoked)
}
//+-------------------------------------------------------------------------
// If the CRL entry has a CRL Reason extension, the enumerated reason
// code is returned. Otherwise, a reason code of 0 is returned.
//--------------------------------------------------------------------------
DWORD GetCrlReason(
IN PCRL_ENTRY pCrlEntry
)
{
DWORD dwReason = 0;
PCERT_EXTENSION pExt;
// Check if the certificate has a szOID_CRL_REASON_CODE extension
if (pExt = CertFindExtension(
szOID_CRL_REASON_CODE,
pCrlEntry->cExtension,
pCrlEntry->rgExtension
)) {
DWORD cbInfo = sizeof(dwReason);
CryptDecodeObject(
CRYPT_ASN_ENCODING,
X509_CRL_REASON_CODE,
pExt->Value.pbData,
pExt->Value.cbData,
0, // dwFlags
&dwReason,
&cbInfo);
}
return dwReason;
}
//+=========================================================================
// Get Issuer Certificate Functions
//==========================================================================
PCCERT_CONTEXT FindIssuerCertInStores(
IN PCCERT_CONTEXT pSubjectCert,
IN DWORD cStore,
IN HCERTSTORE rgStore[]
)
{
PCCERT_CONTEXT pIssuerCert = NULL;
DWORD i;
for (i = 0; i < cStore; i++) {
while (TRUE) {
DWORD dwFlags = CERT_STORE_SIGNATURE_FLAG;
pIssuerCert = CertGetIssuerCertificateFromStore(
rgStore[i],
pSubjectCert,
pIssuerCert,
&dwFlags);
if (NULL == pIssuerCert)
break;
else if (0 == (dwFlags & CERT_STORE_SIGNATURE_FLAG))
return pIssuerCert;
}
}
return NULL;
}
PCCERT_CONTEXT FindIssuerCertInDefaultStores(
IN PCCERT_CONTEXT pSubjectCert
)
{
PCCERT_CONTEXT pIssuerCert;
HCERTSTORE hStore;
DWORD i;
for (i = 0; i < NUM_DEFAULT_ISSUER_STORES; i++) {
if (hStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
0, // dwEncodingType
0, // hCryptProv
rgDefaultIssuerStores[i].dwFlags | CERT_STORE_READONLY_FLAG,
(const void *) rgDefaultIssuerStores[i].pwszStore
)) {
pIssuerCert = FindIssuerCertInStores(pSubjectCert, 1, &hStore);
CertCloseStore(hStore, 0);
if (pIssuerCert)
return pIssuerCert;
}
}
return NULL;
}
//+-------------------------------------------------------------------------
// Get the issuer of the first certificate in the array
//--------------------------------------------------------------------------
PCCERT_CONTEXT GetIssuerCert(
IN DWORD cCert,
IN PCCERT_CONTEXT rgpCert[],
IN DWORD dwFlags,
IN PCERT_REVOCATION_PARA pRevPara
)
{
PCCERT_CONTEXT pSubjectCert;
PCCERT_CONTEXT pIssuerCert = NULL;
assert(cCert >= 1);
pSubjectCert = rgpCert[0];
if (cCert == 1) {
if (pRevPara && pRevPara->cbSize >=
(offsetof(CERT_REVOCATION_PARA, pIssuerCert) +
sizeof(pRevPara->pIssuerCert)))
pIssuerCert = pRevPara->pIssuerCert;
if (NULL == pIssuerCert && CertCompareCertificateName(
pSubjectCert->dwCertEncodingType,
&pSubjectCert->pCertInfo->Subject,
&pSubjectCert->pCertInfo->Issuer))
// Self issued
pIssuerCert = pSubjectCert;
} else if (dwFlags && CERT_VERIFY_REV_CHAIN_FLAG)
pIssuerCert = rgpCert[1];
if (pIssuerCert)
pIssuerCert = CertDuplicateCertificateContext(pIssuerCert);
else {
if (pRevPara && pRevPara->cbSize >=
(offsetof(CERT_REVOCATION_PARA, rgCertStore) +
sizeof(pRevPara->rgCertStore)))
pIssuerCert = FindIssuerCertInStores(
pSubjectCert, pRevPara->cCertStore, pRevPara->rgCertStore);
if (NULL == pIssuerCert)
pIssuerCert = FindIssuerCertInDefaultStores(pSubjectCert);
}
if (NULL == pIssuerCert)
SetLastError(CRYPT_E_NO_REVOCATION_CHECK);
return pIssuerCert;
}
//+-------------------------------------------------------------------------
// Check that the CRL doesn't have any critical extensions
//--------------------------------------------------------------------------
BOOL IsExtensionValidCrl(
IN PCCRL_CONTEXT pCrl
)
{
DWORD cExt = pCrl->pCrlInfo->cExtension;
PCERT_EXTENSION pExt = pCrl->pCrlInfo->rgExtension;
for ( ; cExt > 0; cExt--, pExt++) {
if (pExt->fCritical)
return FALSE;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: GetSubjectCrl
//
// Synopsis: get the CRL associated with the subject certificate
//
//----------------------------------------------------------------------------
BOOL GetSubjectCrl (
IN PCCERT_CONTEXT pSubject,
IN PCCERT_CONTEXT pIssuer,
OUT PCCRL_CONTEXT* ppCrl
)
{
BOOL fResult;
HCERTSTORE hStore;
PCCRL_CONTEXT pFindCrl = NULL;
DWORD dwGetCrlFlags = CERT_STORE_SIGNATURE_FLAG;
*ppCrl = NULL;
hStore = CertOpenSystemStoreW( NULL, L"CA" );
if ( hStore != NULL )
{
while ( ( pFindCrl = CertGetCRLFromStore(
hStore,
pIssuer,
pFindCrl,
&dwGetCrlFlags
) ) != NULL )
{
if ( dwGetCrlFlags != 0 || !IsExtensionValidCrl( pFindCrl ))
{
dwGetCrlFlags = CERT_STORE_SIGNATURE_FLAG;
continue;
}
*ppCrl = pFindCrl;
break;
}
CertCloseStore( hStore, 0 );
if ( *ppCrl != NULL )
{
return( TRUE );
}
}
return( FALSE );
}
//+-------------------------------------------------------------------------
// Find a certificate identified by its serial number in the CRL.
//--------------------------------------------------------------------------
PCRL_ENTRY FindCertInCrl(
IN PCCERT_CONTEXT pCert,
IN PCCRL_CONTEXT pCrl,
IN PCERT_REVOCATION_PARA pRevPara
)
{
DWORD cEntry = pCrl->pCrlInfo->cCRLEntry;
PCRL_ENTRY pEntry = pCrl->pCrlInfo->rgCRLEntry;
DWORD cbSerialNumber = pCert->pCertInfo->SerialNumber.cbData;
BYTE *pbSerialNumber = pCert->pCertInfo->SerialNumber.pbData;
if (0 == cbSerialNumber)
return NULL;
for ( ; 0 < cEntry; cEntry--, pEntry++) {
if (cbSerialNumber == pEntry->SerialNumber.cbData &&
0 == memcmp(pbSerialNumber, pEntry->SerialNumber.pbData,
cbSerialNumber))
{
if (pRevPara && pRevPara->cbSize >=
(offsetof(CERT_REVOCATION_PARA, pftTimeToUse) +
sizeof(pRevPara->pftTimeToUse))
&&
NULL != pRevPara->pftTimeToUse
&&
0 > CompareFileTime(pRevPara->pftTimeToUse,
&pEntry->RevocationDate))
// It was used before being revoked
return NULL;
else
return pEntry;
}
}
return NULL;
}