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.
 
 
 
 
 
 

1206 lines
38 KiB

//+-------------------------------------------------------------------------
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: msrevoke.cpp
//
// Contents: CRL Distribution Points version of CertDllVerifyRevocation.
//
// Restrictions:
// - Only support CRYPT_ASN_ENCODING
// - Only processes certificates having the
// szOID_CRL_DIST_POINTS extension.
// - For szOID_CRL_DIST_POINTS extension: only URL FullName,
// no ReasonFlags or CRLIssuer.
// - URLs: http:, file:
// - 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: 10-Apr-97 philh created
// 01-Oct-97 kirtd major simplification, use
// CryptGetTimeValidObject
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
#define MSREVOKE_TIMEOUT 15000
//+-------------------------------------------------------------------------
// Default stores searched to find an issuer of the subject certificate
//--------------------------------------------------------------------------
static struct {
LPCWSTR pwszStore;
DWORD dwFlags;
} rgDefaultIssuerStores[] = {
L"CA", CERT_SYSTEM_STORE_CURRENT_USER,
L"ROOT", CERT_SYSTEM_STORE_CURRENT_USER,
L"SPC", CERT_SYSTEM_STORE_LOCAL_MACHINE
};
#define NUM_DEFAULT_ISSUER_STORES (sizeof(rgDefaultIssuerStores) / \
sizeof(rgDefaultIssuerStores[0]))
//+-------------------------------------------------------------------------
// Local functions called by MicrosoftCertDllVerifyRevocation
//--------------------------------------------------------------------------
PCCERT_CONTEXT GetIssuerCert(
IN DWORD cCert,
IN PCCERT_CONTEXT rgpCert[],
IN DWORD dwFlags,
IN PCERT_REVOCATION_PARA pRevPara
);
BOOL HasUnsupportedCrlCriticalExtension(
IN PCCRL_CONTEXT pCrl
);
// msrevoke specific flags that can be passed to GetTimeValidCrl
#define MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG 0x1
#define MSREVOKE_DELTA_CRL_FLAG 0x2
BOOL GetTimeValidCrl (
IN LPCSTR pszTimeValidOid,
IN LPVOID pvTimeValidPara,
IN PCCERT_CONTEXT pSubject,
IN PCCERT_CONTEXT pIssuer,
IN PCERT_REVOCATION_PARA pRevPara,
IN PCERT_EXTENSION pCDPExt,
IN DWORD dwRevFlags,
IN DWORD dwMsrevokeFlags,
IN FILETIME *pftEndUrlRetrieval,
OUT PCCRL_CONTEXT *ppCrl,
IN OUT BOOL *pfWireRetrieval
);
BOOL GetBaseCrl (
IN PCCERT_CONTEXT pSubject,
IN PCCERT_CONTEXT pIssuer,
IN PCERT_REVOCATION_PARA pRevPara,
IN PCERT_EXTENSION pCDPExt,
IN DWORD dwRevFlags,
IN FILETIME *pftEndUrlRetrieval,
OUT PCCRL_CONTEXT *ppBaseCrl,
OUT BOOL *pfBaseCrlTimeValid,
OUT BOOL *pfBaseWireRetrieval
);
BOOL GetDeltaCrl (
IN PCCERT_CONTEXT pSubject,
IN PCCERT_CONTEXT pIssuer,
IN PCERT_REVOCATION_PARA pRevPara,
IN DWORD dwRevFlags,
IN BOOL fBaseWireRetrieval,
IN FILETIME *pftEndUrlRetrieval,
IN OUT PCCRL_CONTEXT *ppBaseCrl,
IN OUT BOOL *pfCrlTimeValid,
OUT PCCRL_CONTEXT *ppDeltaCrl,
OUT DWORD *pdwFreshnessTime
);
DWORD GetCrlReason(
IN PCRL_ENTRY pCrlEntry
);
BOOL CrlIssuerIsCertIssuer (
IN PCCERT_CONTEXT pCert,
IN PCERT_EXTENSION pCrlDistPointExt
);
//+-------------------------------------------------------------------------
// External functions called by CertDllVerifyRevocation
//--------------------------------------------------------------------------
BOOL
WINAPI
NetscapeCertDllVerifyRevocation(
IN DWORD dwEncodingType,
IN DWORD dwRevType,
IN DWORD cContext,
IN PVOID rgpvContext[],
IN DWORD dwFlags,
IN PVOID pvReserved,
IN OUT PCERT_REVOCATION_STATUS pRevStatus
);
//+-------------------------------------------------------------------------
// MicrosoftCertDllVerifyRevocation using CRL Distribution Points extension.
//--------------------------------------------------------------------------
BOOL
WINAPI
MicrosoftCertDllVerifyRevocation(
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
)
{
BOOL fResult;
DWORD dwIndex = 0;
DWORD dwError = (DWORD) CRYPT_E_NO_REVOCATION_CHECK;
DWORD dwReason = 0;
PCCERT_CONTEXT pCert; // not allocated
PCCERT_CONTEXT pIssuer = NULL;
PCCRL_CONTEXT pBaseCrl = NULL;
PCCRL_CONTEXT pDeltaCrl = NULL;
PCRL_ENTRY pCrlEntry = NULL; // not allocated
BOOL fDeltaCrlEntry = FALSE;
BOOL fCrlTimeValid = FALSE;
BOOL fBaseWireRetrieval = FALSE;
PCERT_EXTENSION pCDPExt;
BOOL fSaveCheckFreshnessTime;
DWORD dwFreshnessTime;
CERT_REVOCATION_PARA RevPara;
FILETIME ftCurrent;
// Following is only used for CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG
FILETIME ftEndUrlRetrieval;
// Ensure we have a structure containing all the possible parameters
memset(&RevPara, 0, sizeof(RevPara));
if (pRevPara != NULL)
memcpy(&RevPara, pRevPara, min(pRevPara->cbSize, sizeof(RevPara)));
RevPara.cbSize = sizeof(RevPara);
if (0 == RevPara.dwUrlRetrievalTimeout)
RevPara.dwUrlRetrievalTimeout = MSREVOKE_TIMEOUT;
if (NULL == RevPara.pftCurrentTime) {
GetSystemTimeAsFileTime(&ftCurrent);
RevPara.pftCurrentTime = &ftCurrent;
}
pRevPara = &RevPara;
if (dwFlags & CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG) {
FILETIME ftStartUrlRetrieval;
GetSystemTimeAsFileTime(&ftStartUrlRetrieval);
I_CryptIncrementFileTimeByMilliseconds(
&ftStartUrlRetrieval, pRevPara->dwUrlRetrievalTimeout,
&ftEndUrlRetrieval);
}
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];
// Check if we have a CRL dist point
pCDPExt = CertFindExtension(
szOID_CRL_DIST_POINTS,
pCert->pCertInfo->cExtension,
pCert->pCertInfo->rgExtension
);
// On 04-05-01 changed back to W2K semantics. Continue to check
// if expired certificates are on the CRL.
// If we have a CDP and an expired certificate,
// then, the CA no longer maintains CRL information for the
// certificate. We must consider it as being revoked.
// if (NULL != pCDPExt &&
// 0 < CompareFileTime(RevPara.pftCurrentTime,
// &pCert->pCertInfo->NotAfter)) {
// dwReason = CRL_REASON_CESSATION_OF_OPERATION;
// goto ExpiredCertError;
// }
// Get the certificate's issuer
if (NULL == (pIssuer = GetIssuerCert(
cContext,
(PCCERT_CONTEXT *) rgpvContext,
dwFlags,
&RevPara
)))
goto NoIssuerError;
// Get the Base CRL for the subject certificate.
//
// Remember and disable the freshness retrieval option.
fSaveCheckFreshnessTime = RevPara.fCheckFreshnessTime;
RevPara.fCheckFreshnessTime = FALSE;
if (!GetBaseCrl(
pCert,
pIssuer,
&RevPara,
pCDPExt,
dwFlags,
&ftEndUrlRetrieval,
&pBaseCrl,
&fCrlTimeValid,
&fBaseWireRetrieval
))
goto GetBaseCrlError;
RevPara.fCheckFreshnessTime = fSaveCheckFreshnessTime;
// If either the base crl or subject cert has a freshest, delta CRL,
// get it
if (!GetDeltaCrl(
pCert,
pIssuer,
&RevPara,
dwFlags,
fBaseWireRetrieval,
&ftEndUrlRetrieval,
&pBaseCrl,
&fCrlTimeValid,
&pDeltaCrl,
&dwFreshnessTime
))
goto GetDeltaCrlError;
if (NULL == pDeltaCrl) {
dwFreshnessTime = I_CryptSubtractFileTimes(
RevPara.pftCurrentTime, &pBaseCrl->pCrlInfo->ThisUpdate);
if (RevPara.fCheckFreshnessTime) {
if (RevPara.dwFreshnessTime >= dwFreshnessTime)
fCrlTimeValid = TRUE;
else {
// Attempt to get a base CRL with better "freshness"
PCCRL_CONTEXT pNewCrl;
if (GetBaseCrl(
pCert,
pIssuer,
&RevPara,
pCDPExt,
dwFlags,
&ftEndUrlRetrieval,
&pNewCrl,
&fCrlTimeValid,
&fBaseWireRetrieval
)) {
CertFreeCRLContext(pBaseCrl);
pBaseCrl = pNewCrl;
dwFreshnessTime = I_CryptSubtractFileTimes(
RevPara.pftCurrentTime,
&pBaseCrl->pCrlInfo->ThisUpdate);
} else
fCrlTimeValid = FALSE;
}
}
} else {
if (!CertFindCertificateInCRL(
pCert,
pDeltaCrl,
0, // dwFlags
NULL, // pvReserved
&pCrlEntry
))
goto CertFindCertificateInDeltaCRLError;
}
if (pCrlEntry) {
// Delta CRL entry
dwReason = GetCrlReason(pCrlEntry);
if (CRL_REASON_REMOVE_FROM_CRL != dwReason)
fDeltaCrlEntry = TRUE;
else {
if (!CertFindCertificateInCRL(
pCert,
pBaseCrl,
0, // dwFlags
NULL, // pvReserved
&pCrlEntry
))
goto CertFindCertificateInBaseCRLError;
if (pCrlEntry) {
dwReason = GetCrlReason(pCrlEntry);
if (CRL_REASON_CERTIFICATE_HOLD == dwReason)
pCrlEntry = NULL;
}
if (NULL == pCrlEntry)
dwReason = 0;
}
} else {
if (!CertFindCertificateInCRL(
pCert,
pBaseCrl,
0, // dwFlags
NULL, // pvReserved
&pCrlEntry
))
goto CertFindCertificateInBaseCRLError;
if (pCrlEntry)
dwReason = GetCrlReason(pCrlEntry);
}
dwError = 0;
if ( ( pCrlEntry != NULL ) &&
( ( RevPara.pftTimeToUse == NULL ) ||
( CompareFileTime(
RevPara.pftTimeToUse,
&pCrlEntry->RevocationDate ) >= 0 ) ) )
{
dwError = (DWORD) CRYPT_E_REVOKED;
}
else if (!fCrlTimeValid)
{
dwError = (DWORD) CRYPT_E_REVOCATION_OFFLINE;
}
if (pRevStatus->cbSize >=
(offsetof(CERT_REVOCATION_STATUS, dwFreshnessTime) +
sizeof(pRevStatus->dwFreshnessTime))) {
pRevStatus->fHasFreshnessTime = TRUE;
pRevStatus->dwFreshnessTime = dwFreshnessTime;
}
if (RevPara.pCrlInfo) {
PCERT_REVOCATION_CRL_INFO pInfo = RevPara.pCrlInfo;
if (pInfo->cbSize >= sizeof(*pInfo)) {
if (pInfo->pBaseCrlContext)
CertFreeCRLContext(pInfo->pBaseCrlContext);
pInfo->pBaseCrlContext = CertDuplicateCRLContext(pBaseCrl);
if (pInfo->pDeltaCrlContext) {
CertFreeCRLContext(pInfo->pDeltaCrlContext);
pInfo->pDeltaCrlContext = NULL;
}
if (pDeltaCrl)
pInfo->pDeltaCrlContext = CertDuplicateCRLContext(pDeltaCrl);
pInfo->fDeltaCrlEntry = fDeltaCrlEntry;
pInfo->pCrlEntry = pCrlEntry;
}
}
CommonReturn:
if (0 == dwError) {
// Successfully checked that the certificate wasn't revoked
if (1 < cContext) {
dwIndex = 1;
dwError = (DWORD) CRYPT_E_NO_REVOCATION_CHECK;
fResult = FALSE;
} else
fResult = TRUE;
} else
fResult = FALSE;
if (pIssuer)
CertFreeCertificateContext(pIssuer);
if (pBaseCrl)
CertFreeCRLContext(pBaseCrl);
if (pDeltaCrl)
CertFreeCRLContext(pDeltaCrl);
pRevStatus->dwIndex = dwIndex;
pRevStatus->dwError = dwError;
pRevStatus->dwReason = dwReason;
SetLastError(dwError);
return fResult;
ErrorReturn:
dwError = GetLastError();
if (0 == dwError)
dwError = (DWORD) E_UNEXPECTED;
goto CommonReturn;
SET_ERROR(NoContextError, E_INVALIDARG)
SET_ERROR(NoRevocationCheckForEncodingTypeError, CRYPT_E_NO_REVOCATION_CHECK)
SET_ERROR(NoRevocationCheckForRevTypeError, CRYPT_E_NO_REVOCATION_CHECK)
// SET_ERROR(ExpiredCertError, CRYPT_E_REVOKED)
TRACE_ERROR(NoIssuerError)
TRACE_ERROR(GetBaseCrlError)
TRACE_ERROR(GetDeltaCrlError)
TRACE_ERROR(CertFindCertificateInDeltaCRLError)
TRACE_ERROR(CertFindCertificateInBaseCRLError)
}
//+---------------------------------------------------------------------------
//
// Function: HasUnsupportedCrlCriticalExtension
//
// Synopsis: checks if the CRL has an unsupported critical section
//
//----------------------------------------------------------------------------
LPCSTR rgpszSupportedCrlExtensionOID[] = {
szOID_DELTA_CRL_INDICATOR,
szOID_ISSUING_DIST_POINT,
szOID_FRESHEST_CRL,
szOID_CRL_NUMBER,
szOID_AUTHORITY_KEY_IDENTIFIER2,
NULL
};
BOOL IsSupportedCrlExtension(
PCERT_EXTENSION pExt
)
{
LPSTR pszExtOID = pExt->pszObjId;
LPCSTR *ppSupOID;
for (ppSupOID = rgpszSupportedCrlExtensionOID;
NULL != *ppSupOID; ppSupOID++) {
if (0 == strcmp(pszExtOID, *ppSupOID))
return TRUE;
}
return FALSE;
}
BOOL HasUnsupportedCrlCriticalExtension(
IN PCCRL_CONTEXT pCrl
)
{
PCRL_INFO pCrlInfo = pCrl->pCrlInfo;
DWORD cExt = pCrlInfo->cExtension;
PCERT_EXTENSION pExt = pCrlInfo->rgExtension;
for ( ; 0 < cExt; cExt--, pExt++) {
if (pExt->fCritical && !IsSupportedCrlExtension(pExt))
return TRUE;
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Function: GetTimeValidCrl
//
// Synopsis: get a time valid base or delta CRL
//
//----------------------------------------------------------------------------
BOOL GetTimeValidCrl (
IN LPCSTR pszTimeValidOid,
IN LPVOID pvTimeValidPara,
IN PCCERT_CONTEXT pSubject,
IN PCCERT_CONTEXT pIssuer,
IN PCERT_REVOCATION_PARA pRevPara,
IN PCERT_EXTENSION pCDPExt,
IN DWORD dwRevFlags,
IN DWORD dwMsrevokeFlags,
IN FILETIME *pftEndUrlRetrieval,
OUT PCCRL_CONTEXT *ppCrl,
IN OUT BOOL *pfWireRetrieval
)
{
BOOL fResult = FALSE;
DWORD dwFlags = 0;
FILETIME ftFreshness;
LPFILETIME pftValidFor;
if (pRevPara->fCheckFreshnessTime)
{
I_CryptDecrementFileTimeBySeconds(
pRevPara->pftCurrentTime,
pRevPara->dwFreshnessTime,
&ftFreshness);
pftValidFor = &ftFreshness;
dwFlags |= CRYPT_CHECK_FRESHNESS_TIME_VALIDITY;
}
else
{
pftValidFor = pRevPara->pftCurrentTime;
}
if ( dwMsrevokeFlags & MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG )
{
dwFlags |= CRYPT_DONT_CHECK_TIME_VALIDITY;
}
if ( pCDPExt != NULL )
{
fResult = CryptGetTimeValidObject(
pszTimeValidOid,
pvTimeValidPara,
pIssuer,
pftValidFor,
dwFlags | CRYPT_CACHE_ONLY_RETRIEVAL,
0, // dwTimeout
(LPVOID *)ppCrl,
NULL, // pCredentials
NULL // pvReserved
);
}
if ( fResult == FALSE )
{
DWORD dwSaveErr = 0;
HCERTSTORE hCrlStore = pRevPara->hCrlStore;
*ppCrl = NULL;
if ( hCrlStore != NULL )
{
PCCRL_CONTEXT pFindCrl = NULL;
DWORD dwFindFlags;
CRL_FIND_ISSUED_FOR_PARA FindPara;
dwSaveErr = GetLastError();
dwFindFlags = CRL_FIND_ISSUED_BY_AKI_FLAG |
CRL_FIND_ISSUED_BY_SIGNATURE_FLAG;
if (dwMsrevokeFlags & MSREVOKE_DELTA_CRL_FLAG)
dwFindFlags |= CRL_FIND_ISSUED_BY_DELTA_FLAG;
else
dwFindFlags |= CRL_FIND_ISSUED_BY_BASE_FLAG;
FindPara.pSubjectCert = pSubject;
FindPara.pIssuerCert = pIssuer;
while ((pFindCrl = CertFindCRLInStore(
hCrlStore,
pIssuer->dwCertEncodingType,
dwFindFlags,
CRL_FIND_ISSUED_FOR,
(const void *) &FindPara,
pFindCrl
)))
{
if (!CertIsValidCRLForCertificate(
pSubject,
pFindCrl,
0, // dwFlags
NULL // pvReserved
))
continue;
if ( !(dwMsrevokeFlags &
MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG ))
{
if (pRevPara->fCheckFreshnessTime)
{
if (CompareFileTime(pftValidFor,
&pFindCrl->pCrlInfo->ThisUpdate) > 0)
{
continue;
}
}
else
{
if ( CompareFileTime(
pftValidFor,
&pFindCrl->pCrlInfo->NextUpdate
) > 0 &&
!I_CryptIsZeroFileTime(
&pFindCrl->pCrlInfo->NextUpdate) )
{
continue;
}
}
}
if ( NULL == *ppCrl )
{
*ppCrl = CertDuplicateCRLContext(pFindCrl);
}
else
{
PCCRL_CONTEXT pPrevCrl = *ppCrl;
// See if this CRL is newer
if ( CompareFileTime(
&pFindCrl->pCrlInfo->ThisUpdate,
&pPrevCrl->pCrlInfo->ThisUpdate
) > 0 )
{
CertFreeCRLContext(pPrevCrl);
*ppCrl = CertDuplicateCRLContext(pFindCrl);
}
}
}
}
if ( *ppCrl != NULL )
{
return( TRUE );
}
else if ( pCDPExt == NULL )
{
SetLastError( (DWORD) CRYPT_E_NO_REVOCATION_CHECK );
return( FALSE );
}
if ( !( dwRevFlags & CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION ) )
{
if (dwRevFlags & CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG) {
pRevPara->dwUrlRetrievalTimeout =
I_CryptRemainingMilliseconds(pftEndUrlRetrieval);
if (0 == pRevPara->dwUrlRetrievalTimeout)
pRevPara->dwUrlRetrievalTimeout = 1;
dwFlags |= CRYPT_ACCUMULATIVE_TIMEOUT;
}
fResult = CryptGetTimeValidObject(
pszTimeValidOid,
pvTimeValidPara,
pIssuer,
pftValidFor,
dwFlags | CRYPT_WIRE_ONLY_RETRIEVAL,
pRevPara->dwUrlRetrievalTimeout,
(LPVOID *)ppCrl,
NULL, // pCredentials
NULL // pvReserved
);
*pfWireRetrieval = TRUE;
}
else if ( hCrlStore != NULL )
{
SetLastError( dwSaveErr );
}
assert( pCDPExt );
if (!fResult)
{
if ( CRYPT_E_NOT_FOUND == GetLastError() )
{
SetLastError( (DWORD) CRYPT_E_NO_REVOCATION_CHECK );
}
else
{
SetLastError( (DWORD) CRYPT_E_REVOCATION_OFFLINE );
}
}
}
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Function: GetBaseCrl
//
// Synopsis: get the base CRL associated with the subject certificate
//
//----------------------------------------------------------------------------
BOOL GetBaseCrl (
IN PCCERT_CONTEXT pSubject,
IN PCCERT_CONTEXT pIssuer,
IN PCERT_REVOCATION_PARA pRevPara,
IN PCERT_EXTENSION pCDPExt,
IN DWORD dwRevFlags,
IN FILETIME *pftEndUrlRetrieval,
OUT PCCRL_CONTEXT *ppBaseCrl,
OUT BOOL *pfBaseCrlTimeValid,
OUT BOOL *pfBaseWireRetrieval
)
{
BOOL fResult;
PCCRL_CONTEXT pBaseCrl = NULL;
*pfBaseWireRetrieval = FALSE;
if (GetTimeValidCrl(
TIME_VALID_OID_GET_CRL_FROM_CERT,
(LPVOID) pSubject,
pSubject,
pIssuer,
pRevPara,
pCDPExt,
dwRevFlags,
0, // dwMsrevokeFlags
pftEndUrlRetrieval,
&pBaseCrl,
pfBaseWireRetrieval
)) {
*pfBaseCrlTimeValid = TRUE;
} else {
*pfBaseCrlTimeValid = FALSE;
if (!GetTimeValidCrl(
TIME_VALID_OID_GET_CRL_FROM_CERT,
(LPVOID) pSubject,
pSubject,
pIssuer,
pRevPara,
pCDPExt,
dwRevFlags,
MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG,
pftEndUrlRetrieval,
&pBaseCrl,
pfBaseWireRetrieval
))
{
goto GetTimeInvalidCrlError;
}
}
if (HasUnsupportedCrlCriticalExtension(pBaseCrl))
goto HasUnsupportedCriticalExtensionError;
fResult = TRUE;
CommonReturn:
*ppBaseCrl = pBaseCrl;
return fResult;
ErrorReturn:
if (pBaseCrl) {
CertFreeCRLContext(pBaseCrl);
pBaseCrl = NULL;
}
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(GetTimeInvalidCrlError)
SET_ERROR(HasUnsupportedCriticalExtensionError, CRYPT_E_NO_REVOCATION_CHECK)
}
//+---------------------------------------------------------------------------
//
// Function: GetDeltaCrl
//
// Synopsis: get the delta CRL associated with the subject certificate and
// its base CRL
//
// For now, always return TRUE. If not able to find a delta CRL, set
// *pfCrlTimeValid to FALSE.
//
//----------------------------------------------------------------------------
BOOL GetDeltaCrl (
IN PCCERT_CONTEXT pSubject,
IN PCCERT_CONTEXT pIssuer,
IN PCERT_REVOCATION_PARA pRevPara,
IN DWORD dwRevFlags,
IN BOOL fBaseWireRetrieval,
IN FILETIME *pftEndUrlRetrieval,
IN OUT PCCRL_CONTEXT *ppBaseCrl,
IN OUT BOOL *pfCrlTimeValid,
OUT PCCRL_CONTEXT *ppDeltaCrl,
OUT DWORD *pdwFreshnessTime
)
{
PCERT_EXTENSION pFreshestExt;
PCCRL_CONTEXT pBaseCrl = *ppBaseCrl;
PCCRL_CONTEXT pDeltaCrl = NULL;
LPCSTR pszTimeValidOid;
LPVOID pvTimeValidPara;
CERT_CRL_CONTEXT_PAIR CertCrlPair;
BOOL fDeltaWireRetrieval;
PCERT_EXTENSION pBaseCrlNumberExt;
PCERT_EXTENSION pDeltaCrlIndicatorExt;
int iBaseCrlNumber = 0;
int iDeltaCrlIndicator = 0;
DWORD cbInt;
LPFILETIME pFreshnessThisUpdate;
assert(pBaseCrl);
// Check if the base CRL or the subject certificate has a freshest
// ext
if (pFreshestExt = CertFindExtension(
szOID_FRESHEST_CRL,
pBaseCrl->pCrlInfo->cExtension,
pBaseCrl->pCrlInfo->rgExtension
)) {
pszTimeValidOid = TIME_VALID_OID_GET_FRESHEST_CRL_FROM_CRL;
CertCrlPair.pCertContext = pSubject;
CertCrlPair.pCrlContext = pBaseCrl;
pvTimeValidPara = (LPVOID) &CertCrlPair;
} else if (pFreshestExt = CertFindExtension(
szOID_FRESHEST_CRL,
pSubject->pCertInfo->cExtension,
pSubject->pCertInfo->rgExtension
)) {
pszTimeValidOid = TIME_VALID_OID_GET_FRESHEST_CRL_FROM_CERT;
pvTimeValidPara = (LPVOID) pSubject;
} else {
goto NoDeltaCrlReturn;
}
if (GetTimeValidCrl(
pszTimeValidOid,
pvTimeValidPara,
pSubject,
pIssuer,
pRevPara,
pFreshestExt,
dwRevFlags,
MSREVOKE_DELTA_CRL_FLAG,
pftEndUrlRetrieval,
&pDeltaCrl,
&fDeltaWireRetrieval
)) {
*pfCrlTimeValid = TRUE;
} else {
*pfCrlTimeValid = FALSE;
if (!GetTimeValidCrl(
pszTimeValidOid,
pvTimeValidPara,
pSubject,
pIssuer,
pRevPara,
pFreshestExt,
dwRevFlags,
MSREVOKE_DELTA_CRL_FLAG |
MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG,
pftEndUrlRetrieval,
&pDeltaCrl,
&fDeltaWireRetrieval
))
{
goto GetTimeInvalidCrlError;
}
}
if (HasUnsupportedCrlCriticalExtension(pDeltaCrl))
goto HasUnsupportedCriticalExtensionError;
// Check that the base CRL number >= delta CRL indicator
if (NULL == (pBaseCrlNumberExt = CertFindExtension(
szOID_CRL_NUMBER,
pBaseCrl->pCrlInfo->cExtension,
pBaseCrl->pCrlInfo->rgExtension
)))
goto MissingBaseCrlNumberError;
if (NULL == (pDeltaCrlIndicatorExt = CertFindExtension(
szOID_DELTA_CRL_INDICATOR,
pDeltaCrl->pCrlInfo->cExtension,
pDeltaCrl->pCrlInfo->rgExtension
)))
goto MissingDeltaCrlIndicatorError;
cbInt = sizeof(iBaseCrlNumber);
if (!CryptDecodeObject(
pBaseCrl->dwCertEncodingType,
X509_INTEGER,
pBaseCrlNumberExt->Value.pbData,
pBaseCrlNumberExt->Value.cbData,
0, // dwFlags
&iBaseCrlNumber,
&cbInt
))
goto DecodeBaseCrlNumberError;
cbInt = sizeof(iDeltaCrlIndicator);
if (!CryptDecodeObject(
pDeltaCrl->dwCertEncodingType,
X509_INTEGER,
pDeltaCrlIndicatorExt->Value.pbData,
pDeltaCrlIndicatorExt->Value.cbData,
0, // dwFlags
&iDeltaCrlIndicator,
&cbInt
))
goto DecodeDeltaCrlIndicatorError;
pFreshnessThisUpdate = &pDeltaCrl->pCrlInfo->ThisUpdate;
if (iBaseCrlNumber < iDeltaCrlIndicator) {
BOOL fValidBaseCrl = FALSE;
if (!fBaseWireRetrieval &&
0 == (dwRevFlags & CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION)) {
// Attempt to get a more recent base CRL by hitting the wire
PCCRL_CONTEXT pWireBaseCrl = NULL;
CRL_IS_VALID_EXTRA_INFO CrlIsValidExtraInfo =
{ iDeltaCrlIndicator };
if (CryptGetTimeValidObject(
TIME_VALID_OID_GET_CRL_FROM_CERT,
(LPVOID)pSubject,
pIssuer,
NULL, // pftValidFor
CRYPT_WIRE_ONLY_RETRIEVAL | CRYPT_DONT_CHECK_TIME_VALIDITY,
pRevPara->dwUrlRetrievalTimeout,
(LPVOID *) &pWireBaseCrl,
NULL, // pCredentials
&CrlIsValidExtraInfo
)) {
// Already checked that the new Base CRL number is valid
CertFreeCRLContext(pBaseCrl);
*ppBaseCrl = pBaseCrl = pWireBaseCrl;
fValidBaseCrl = TRUE;
}
}
if (!fValidBaseCrl) {
*pfCrlTimeValid = FALSE;
pFreshnessThisUpdate = &pBaseCrl->pCrlInfo->ThisUpdate;
}
}
*pdwFreshnessTime = I_CryptSubtractFileTimes(
pRevPara->pftCurrentTime, pFreshnessThisUpdate);
if (pRevPara->fCheckFreshnessTime) {
if (pRevPara->dwFreshnessTime >= *pdwFreshnessTime)
*pfCrlTimeValid = TRUE;
else
*pfCrlTimeValid = FALSE;
}
NoDeltaCrlReturn:
CommonReturn:
*ppDeltaCrl = pDeltaCrl;
return TRUE;
ErrorReturn:
if (pDeltaCrl) {
CertFreeCRLContext(pDeltaCrl);
pDeltaCrl = NULL;
}
*pfCrlTimeValid = FALSE;
goto CommonReturn;
TRACE_ERROR(GetTimeInvalidCrlError)
SET_ERROR(HasUnsupportedCriticalExtensionError, CRYPT_E_NO_REVOCATION_CHECK)
SET_ERROR(MissingBaseCrlNumberError, CRYPT_E_NO_REVOCATION_CHECK)
SET_ERROR(MissingDeltaCrlIndicatorError, CRYPT_E_NO_REVOCATION_CHECK)
TRACE_ERROR(DecodeBaseCrlNumberError)
TRACE_ERROR(DecodeDeltaCrlIndicatorError)
}
//+-------------------------------------------------------------------------
// 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) {
if (CRYPT_E_SELF_SIGNED == GetLastError()) {
if (0 == (dwFlags & CERT_STORE_SIGNATURE_FLAG))
pIssuerCert = CertDuplicateCertificateContext(
pSubjectCert);
return pIssuerCert;
}
break;
} else if (0 == (dwFlags & CERT_STORE_SIGNATURE_FLAG))
return pIssuerCert;
}
}
return NULL;
}
static 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
//
// Note, pRevPara is our copy and guaranteed to contain all the fields.
//--------------------------------------------------------------------------
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) {
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 {
pIssuerCert = FindIssuerCertInStores(
pSubjectCert, pRevPara->cCertStore, pRevPara->rgCertStore);
if (NULL == pIssuerCert)
pIssuerCert = FindIssuerCertInDefaultStores(pSubjectCert);
}
if (NULL == pIssuerCert)
SetLastError((DWORD) CRYPT_E_REVOCATION_OFFLINE);
return pIssuerCert;
}
//+---------------------------------------------------------------------------
//
// Function: CrlIssuerIsCertIssuer
//
// Synopsis: is the issuer of the CRL the issuer of the cert
//
//----------------------------------------------------------------------------
BOOL CrlIssuerIsCertIssuer (
IN PCCERT_CONTEXT pCert,
IN PCERT_EXTENSION pCrlDistPointExt
)
{
BOOL fResult = FALSE;
DWORD cb = sizeof( PCRL_DIST_POINTS_INFO );
PCRL_DIST_POINTS_INFO pDistPointInfo;
if ( pCrlDistPointExt == NULL )
{
return( TRUE );
}
if ( CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
szOID_CRL_DIST_POINTS,
pCrlDistPointExt->Value.pbData,
pCrlDistPointExt->Value.cbData,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
(void *)&pDistPointInfo,
&cb
) == TRUE )
{
if ( pDistPointInfo->cDistPoint > 0 )
{
if ( pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.cAltEntry == 0 )
{
fResult = TRUE;
}
else if ( pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.rgAltEntry[ 0 ].dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME )
{
if ( pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.rgAltEntry[ 0 ].DirectoryName.cbData == 0 )
{
fResult = TRUE;
}
else if ( ( pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.rgAltEntry[ 0 ].DirectoryName.cbData ==
pCert->pCertInfo->Issuer.cbData ) &&
( memcmp(
pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.rgAltEntry[ 0 ].DirectoryName.pbData,
pCert->pCertInfo->Issuer.pbData,
pCert->pCertInfo->Issuer.cbData
) == 0 ) )
{
fResult = TRUE;
}
}
}
else
{
fResult = TRUE;
}
LocalFree( pDistPointInfo );
}
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Function: CertDllVerifyRevocation
//
// Synopsis: Dispatches to msrevoke
//
//----------------------------------------------------------------------------
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
)
{
return MicrosoftCertDllVerifyRevocation(
dwEncodingType,
dwRevType,
cContext,
rgpvContext,
dwFlags,
pRevPara,
pRevStatus
);
}