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