|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 2000
//
// File: xcert.cpp
//
// Contents: CCertChainEngine's Cross Certificate Methods
//
// History: 22-Dec-99 philh Created
//
//----------------------------------------------------------------------------
#include <global.hxx>
#include <dbgdef.h>
//+=========================================================================
// Cross Certificate Distribution Point Support Functions
//==========================================================================
//+-------------------------------------------------------------------------
// Get and allocate the cross certificate distribution points Url array
// and info for the specified certificate.
//--------------------------------------------------------------------------
BOOL WINAPI XCertGetDistPointsUrl( IN PCCERT_CONTEXT pCert, OUT PCRYPT_URL_ARRAY *ppUrlArray, OUT PCRYPT_URL_INFO *ppUrlInfo ) { BOOL fResult; PCRYPT_URL_ARRAY pUrlArray = NULL; DWORD cbUrlArray = 0; PCRYPT_URL_INFO pUrlInfo = NULL; DWORD cbUrlInfo = 0;
if (!ChainGetObjectUrl( URL_OID_CROSS_CERT_DIST_POINT, (LPVOID) pCert, CRYPT_GET_URL_FROM_PROPERTY | CRYPT_GET_URL_FROM_EXTENSION, NULL, // pUrlArray
&cbUrlArray, NULL, // pUrlInfo
&cbUrlInfo, NULL // pvReserved
)) goto GetObjectUrlError;
pUrlArray = (PCRYPT_URL_ARRAY) new BYTE [cbUrlArray]; if (NULL == pUrlArray) goto OutOfMemory;
pUrlInfo = (PCRYPT_URL_INFO) new BYTE [cbUrlInfo]; if (NULL == pUrlInfo) goto OutOfMemory;
if (!ChainGetObjectUrl( URL_OID_CROSS_CERT_DIST_POINT, (LPVOID) pCert, CRYPT_GET_URL_FROM_PROPERTY | CRYPT_GET_URL_FROM_EXTENSION, pUrlArray, &cbUrlArray, pUrlInfo, &cbUrlInfo, NULL // pvReserved
)) goto GetObjectUrlError;
if (0 == pUrlArray->cUrl || 0 == pUrlInfo->cGroup) goto NoDistPointUrls;
fResult = TRUE; CommonReturn: *ppUrlArray = pUrlArray; *ppUrlInfo = pUrlInfo; return fResult;
ErrorReturn: if (pUrlArray) { delete (LPBYTE) pUrlArray; pUrlArray = NULL; } if (pUrlInfo) { delete (LPBYTE) pUrlInfo; pUrlInfo = NULL; } fResult = FALSE; goto CommonReturn;
TRACE_ERROR(GetObjectUrlError) SET_ERROR(OutOfMemory, E_OUTOFMEMORY) SET_ERROR(NoDistPointUrls, CRYPT_E_NOT_FOUND) }
//+-------------------------------------------------------------------------
// Checks and returns TRUE if all the Urls are contained in the
// distribution point.
//--------------------------------------------------------------------------
BOOL WINAPI XCertIsUrlInDistPoint( IN DWORD cUrl, IN LPWSTR *ppwszUrl, IN PXCERT_DP_ENTRY pEntry ) { for ( ; 0 < cUrl; cUrl--, ppwszUrl++) { DWORD cDPUrl = pEntry->cUrl; LPWSTR *ppwszDPUrl = pEntry->rgpwszUrl;
for ( ; 0 < cDPUrl; cDPUrl--, ppwszDPUrl++) { if (0 == wcscmp(*ppwszUrl, *ppwszDPUrl)) break; }
if (0 == cDPUrl) return FALSE; }
return TRUE; }
//+-------------------------------------------------------------------------
// Finds a distribution point link containing all the Urls.
//--------------------------------------------------------------------------
PXCERT_DP_LINK WINAPI XCertFindUrlInDistPointLinks( IN DWORD cUrl, IN LPWSTR *rgpwszUrl, IN PXCERT_DP_LINK pLink ) { for ( ; pLink; pLink = pLink->pNext) { if (XCertIsUrlInDistPoint(cUrl, rgpwszUrl, pLink->pCrossCertDPEntry)) return pLink; }
return NULL; }
//+-------------------------------------------------------------------------
// Finds a distribution point entry containing all the Urls.
//--------------------------------------------------------------------------
PXCERT_DP_ENTRY WINAPI XCertFindUrlInDistPointEntries( IN DWORD cUrl, IN LPWSTR *rgpwszUrl, PXCERT_DP_ENTRY pEntry ) { for ( ; pEntry; pEntry = pEntry->pNext) { if (XCertIsUrlInDistPoint(cUrl, rgpwszUrl, pEntry)) return pEntry; }
return NULL; }
//+-------------------------------------------------------------------------
// Inserts the cross certificate distribution entry into the engine's
// list. The list is ordered according to ascending NextSyncTimes.
//--------------------------------------------------------------------------
void CCertChainEngine::InsertCrossCertDistPointEntry( IN OUT PXCERT_DP_ENTRY pEntry ) { if (NULL == m_pCrossCertDPEntry) { // First entry to be added to engine's list
pEntry->pNext = NULL; pEntry->pPrev = NULL; m_pCrossCertDPEntry = pEntry; } else { PXCERT_DP_ENTRY pListEntry = m_pCrossCertDPEntry; BOOL fLast = FALSE;
// Loop while Entry's NextSyncTime > list's NextSyncTime
while (0 < CompareFileTime(&pEntry->NextSyncTime, &pListEntry->NextSyncTime)) { if (NULL == pListEntry->pNext) { fLast = TRUE; break; } else pListEntry = pListEntry->pNext; }
if (fLast) { assert(NULL == pListEntry->pNext); pEntry->pNext = NULL; pEntry->pPrev = pListEntry; pListEntry->pNext = pEntry; } else { pEntry->pNext = pListEntry; pEntry->pPrev = pListEntry->pPrev; if (pListEntry->pPrev) { assert(pListEntry->pPrev->pNext == pListEntry); pListEntry->pPrev->pNext = pEntry; } else { assert(m_pCrossCertDPEntry == pListEntry); m_pCrossCertDPEntry = pEntry; } pListEntry->pPrev = pEntry; } } }
//+-------------------------------------------------------------------------
// Removes the cross certificate distribution point from the engine's list.
//--------------------------------------------------------------------------
void CCertChainEngine::RemoveCrossCertDistPointEntry( IN OUT PXCERT_DP_ENTRY pEntry ) { if (pEntry->pNext) pEntry->pNext->pPrev = pEntry->pPrev; if (pEntry->pPrev) pEntry->pPrev->pNext = pEntry->pNext; else m_pCrossCertDPEntry = pEntry->pNext; }
//+-------------------------------------------------------------------------
// For an online certificate distribution point updates the NextSyncTime
// and repositions accordingly in the engine's list.
//
// NextSyncTime = LastSyncTime + dwSyncDeltaTime.
//--------------------------------------------------------------------------
void CCertChainEngine::RepositionOnlineCrossCertDistPointEntry( IN OUT PXCERT_DP_ENTRY pEntry, IN LPFILETIME pLastSyncTime ) { assert(!I_CryptIsZeroFileTime(pLastSyncTime)); pEntry->LastSyncTime = *pLastSyncTime; pEntry->dwOfflineCnt = 0;
I_CryptIncrementFileTimeBySeconds( pLastSyncTime, pEntry->dwSyncDeltaTime, &pEntry->NextSyncTime );
RemoveCrossCertDistPointEntry(pEntry); InsertCrossCertDistPointEntry(pEntry); }
//+-------------------------------------------------------------------------
// For an offline certificate distribution point, increments the offline
// count, updates the NextSyncTime to be some delta from the current time
// and repositions accordingly in the engine's list.
//
// NextSyncTime = CurrentTime +
// rgChainOfflineUrlDeltaSeconds[dwOfflineCnt - 1]
//--------------------------------------------------------------------------
void CCertChainEngine::RepositionOfflineCrossCertDistPointEntry( IN OUT PXCERT_DP_ENTRY pEntry, IN LPFILETIME pCurrentTime ) { pEntry->dwOfflineCnt++;
I_CryptIncrementFileTimeBySeconds( pCurrentTime, ChainGetOfflineUrlDeltaSeconds(pEntry->dwOfflineCnt), &pEntry->NextSyncTime );
RemoveCrossCertDistPointEntry(pEntry); InsertCrossCertDistPointEntry(pEntry); }
//+-------------------------------------------------------------------------
// For a smaller SyncDeltaTime in a certificate distribution point,
// updates the NextSyncTime and repositions accordingly in the engine's list.
//
// Note, if the distribution point is offline, the NextSyncTime isn't
// updated.
//
// NextSyncTime = LastSyncTime + dwSyncDeltaTime.
//--------------------------------------------------------------------------
void CCertChainEngine::RepositionNewSyncDeltaTimeCrossCertDistPointEntry( IN OUT PXCERT_DP_ENTRY pEntry, IN DWORD dwSyncDeltaTime ) { if (dwSyncDeltaTime >= pEntry->dwSyncDeltaTime) return;
pEntry->dwSyncDeltaTime = dwSyncDeltaTime;
if (I_CryptIsZeroFileTime(&pEntry->LastSyncTime) || 0 != pEntry->dwOfflineCnt) return;
RepositionOnlineCrossCertDistPointEntry(pEntry, &pEntry->LastSyncTime); }
//+-------------------------------------------------------------------------
// Creates the cross certificate distribution point and insert's in the
// engine's list.
//
// The returned entry has a refCnt of 1.
//--------------------------------------------------------------------------
PXCERT_DP_ENTRY CCertChainEngine::CreateCrossCertDistPointEntry( IN DWORD dwSyncDeltaTime, IN DWORD cUrl, IN LPWSTR *rgpwszUrl ) { PXCERT_DP_ENTRY pEntry; DWORD cbEntry; LPWSTR *ppwszEntryUrl; LPWSTR pwszEntryUrl; DWORD i;
cbEntry = sizeof(XCERT_DP_ENTRY) + cUrl * sizeof(LPWSTR); for (i = 0; i < cUrl; i++) cbEntry += (wcslen(rgpwszUrl[i]) + 1) * sizeof(WCHAR);
pEntry = (PXCERT_DP_ENTRY) new BYTE [cbEntry]; if (NULL == pEntry) { SetLastError((DWORD) E_OUTOFMEMORY); return NULL; }
memset(pEntry, 0, sizeof(XCERT_DP_ENTRY)); pEntry->lRefCnt = 1; pEntry->dwSyncDeltaTime = dwSyncDeltaTime;
pEntry->cUrl = cUrl; pEntry->rgpwszUrl = ppwszEntryUrl = (LPWSTR *) &pEntry[1]; pwszEntryUrl = (LPWSTR) &ppwszEntryUrl[cUrl];
for (i = 0; i < cUrl; i++) { ppwszEntryUrl[i] = pwszEntryUrl; wcscpy(pwszEntryUrl, rgpwszUrl[i]); pwszEntryUrl += wcslen(rgpwszUrl[i]) + 1; }
InsertCrossCertDistPointEntry(pEntry);
return pEntry; }
//+-------------------------------------------------------------------------
// Increments the cross certificate distribution point's reference count.
//--------------------------------------------------------------------------
void CCertChainEngine::AddRefCrossCertDistPointEntry( IN OUT PXCERT_DP_ENTRY pEntry ) { pEntry->lRefCnt++; }
//+-------------------------------------------------------------------------
// Decrements the cross certificate distribution point's reference count.
//
// When decremented to 0, removed from the engine's list and freed.
//
// Returns TRUE if decremented to 0 and freed.
//--------------------------------------------------------------------------
BOOL CCertChainEngine::ReleaseCrossCertDistPointEntry( IN OUT PXCERT_DP_ENTRY pEntry ) { if (0 != --pEntry->lRefCnt) return FALSE;
RemoveCrossCertDistPointEntry(pEntry); FreeCrossCertDistPoints(&pEntry->pChildCrossCertDPLink);
if (pEntry->hUrlStore) { CertRemoveStoreFromCollection( m_hCrossCertStore, pEntry->hUrlStore ); CertCloseStore(pEntry->hUrlStore, 0); }
delete (LPBYTE) pEntry;
return TRUE; }
//+-------------------------------------------------------------------------
// Finds and gets the Cross Certificate Distribution Points for the
// specified certificate store.
//
// *ppLinkHead is updated to contain the store's distribution point links.
//--------------------------------------------------------------------------
BOOL CCertChainEngine::GetCrossCertDistPointsForStore( IN HCERTSTORE hStore, IN OUT PXCERT_DP_LINK *ppLinkHead ) { BOOL fResult; PXCERT_DP_LINK pOldLinkHead = *ppLinkHead; PXCERT_DP_LINK pNewLinkHead = NULL; PCCERT_CONTEXT pCert = NULL; PCRYPT_URL_ARRAY pUrlArray = NULL; PCRYPT_URL_INFO pUrlInfo = NULL;
while (pCert = CertFindCertificateInStore( hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, // dwFindFlags
CERT_FIND_CROSS_CERT_DIST_POINTS, NULL, // pvFindPara,
pCert )) {
DWORD dwSyncDeltaTime; DWORD cDP; DWORD *pcUrl; LPWSTR *ppwszUrl;
if (!XCertGetDistPointsUrl( pCert, &pUrlArray, &pUrlInfo )) continue;
dwSyncDeltaTime = pUrlInfo->dwSyncDeltaTime; if (0 == dwSyncDeltaTime) dwSyncDeltaTime = XCERT_DEFAULT_SYNC_DELTA_TIME; else if (XCERT_MIN_SYNC_DELTA_TIME > dwSyncDeltaTime) dwSyncDeltaTime = XCERT_MIN_SYNC_DELTA_TIME;
cDP = pUrlInfo->cGroup; pcUrl = pUrlInfo->rgcGroupEntry; ppwszUrl = pUrlArray->rgwszUrl;
for ( ; 0 < cDP; cDP--, ppwszUrl += *pcUrl++) { PXCERT_DP_LINK pLink; PXCERT_DP_ENTRY pEntry; DWORD cUrl = *pcUrl;
if (0 == cUrl) continue;
// Do we already have an entry in the new list
if (XCertFindUrlInDistPointLinks(cUrl, ppwszUrl, pNewLinkHead)) continue;
// If the entry existed in the old list, move to the new list
if (pLink = XCertFindUrlInDistPointLinks( cUrl, ppwszUrl, pOldLinkHead)) { if (pLink->pNext) pLink->pNext->pPrev = pLink->pPrev; if (pLink->pPrev) pLink->pPrev->pNext = pLink->pNext; else pOldLinkHead = pLink->pNext;
RepositionNewSyncDeltaTimeCrossCertDistPointEntry( pLink->pCrossCertDPEntry, dwSyncDeltaTime); } else { // Check if the entry already exists for the engine
if (pEntry = XCertFindUrlInDistPointEntries( cUrl, ppwszUrl, m_pCrossCertDPEntry)) { AddRefCrossCertDistPointEntry(pEntry); RepositionNewSyncDeltaTimeCrossCertDistPointEntry( pEntry, dwSyncDeltaTime); } else { // Create entry and insert at beginning of
// entries list.
if (NULL == (pEntry = CreateCrossCertDistPointEntry( dwSyncDeltaTime, cUrl, ppwszUrl ))) goto CreateDistPointEntryError; }
pLink = new XCERT_DP_LINK; if (NULL == pLink) { ReleaseCrossCertDistPointEntry(pEntry); goto CreateDistPointLinkError; }
pLink->pCrossCertDPEntry = pEntry;
}
if (pNewLinkHead) { assert(NULL == pNewLinkHead->pPrev); pNewLinkHead->pPrev = pLink; } pLink->pNext = pNewLinkHead; pLink->pPrev = NULL; pNewLinkHead = pLink; }
delete (LPBYTE) pUrlArray; pUrlArray = NULL; delete (LPBYTE) pUrlInfo; pUrlInfo = NULL; }
assert(NULL == pUrlArray); assert(NULL == pUrlInfo); assert(NULL == pCert);
*ppLinkHead = pNewLinkHead; fResult = TRUE; CommonReturn: if (pOldLinkHead) { DWORD dwErr = GetLastError();
FreeCrossCertDistPoints(&pOldLinkHead);
SetLastError(dwErr); }
return fResult;
ErrorReturn: *ppLinkHead = NULL; if (pUrlArray) delete (LPBYTE) pUrlArray; if (pUrlInfo) delete (LPBYTE) pUrlInfo; if (pCert) CertFreeCertificateContext(pCert);
if (pNewLinkHead) { FreeCrossCertDistPoints(&pNewLinkHead); assert(NULL == pNewLinkHead); } fResult = FALSE; goto CommonReturn;
TRACE_ERROR(CreateDistPointEntryError) TRACE_ERROR(CreateDistPointLinkError) }
//+-------------------------------------------------------------------------
// Removes an orphan'ed entry not in any list of links.
//--------------------------------------------------------------------------
void CCertChainEngine::RemoveCrossCertDistPointOrphanEntry( IN PXCERT_DP_ENTRY pOrphanEntry ) { PXCERT_DP_ENTRY pEntry;
for (pEntry = m_pCrossCertDPEntry; pEntry; pEntry = pEntry->pNext) { PXCERT_DP_LINK pLink = pEntry->pChildCrossCertDPLink;
while (pLink) { if (pLink->pCrossCertDPEntry == pOrphanEntry) { if (pLink->pNext) pLink->pNext->pPrev = pLink->pPrev; if (pLink->pPrev) pLink->pPrev->pNext = pLink->pNext; else pEntry->pChildCrossCertDPLink = pLink->pNext;
delete pLink;
if (ReleaseCrossCertDistPointEntry(pOrphanEntry)) return; else break; }
pLink = pLink->pNext; } } }
//+-------------------------------------------------------------------------
// Returns TRUE if the entry is in this or any child link list
//--------------------------------------------------------------------------
BOOL WINAPI XCertIsDistPointInLinkList( IN PXCERT_DP_ENTRY pOrphanEntry, IN PXCERT_DP_LINK pLink ) { for (; pLink; pLink = pLink->pNext) { PXCERT_DP_ENTRY pEntry = pLink->pCrossCertDPEntry; if (pOrphanEntry == pEntry) return TRUE;
// Note, inhibit recursion by checking an entry's list of links
// only once.
if (!pEntry->fChecked) { pEntry->fChecked = TRUE;
if (XCertIsDistPointInLinkList(pOrphanEntry, pEntry->pChildCrossCertDPLink)) return TRUE; } }
return FALSE; }
//+-------------------------------------------------------------------------
// Frees the cross certificate distribution point links.
//--------------------------------------------------------------------------
void CCertChainEngine::FreeCrossCertDistPoints( IN OUT PXCERT_DP_LINK *ppLinkHead ) { PXCERT_DP_LINK pLink = *ppLinkHead; *ppLinkHead = NULL;
while (pLink) { PXCERT_DP_LINK pDelete; PXCERT_DP_ENTRY pEntry;
pEntry = pLink->pCrossCertDPEntry; if (ReleaseCrossCertDistPointEntry(pEntry)) ; else { // Clear the fChecked flag for all entries
PXCERT_DP_ENTRY pCheckEntry; for (pCheckEntry = m_pCrossCertDPEntry; pCheckEntry; pCheckEntry = pCheckEntry->pNext) pCheckEntry->fChecked = FALSE;
if (!XCertIsDistPointInLinkList(pEntry, m_pCrossCertDPLink)) // An orphaned entry. Not in anyone else's list
RemoveCrossCertDistPointOrphanEntry(pEntry); } pDelete = pLink; pLink = pLink->pNext; delete pDelete; } }
//+-------------------------------------------------------------------------
// Retrieve the cross certificates
//
// Leaves the engine's critical section to do the URL
// fetching. If the engine was touched by another thread,
// it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
//
// If the URL store is changed, increments engine's touch count and flushes
// issuer and end cert object caches.
//
// Assumption: Chain engine is locked once in the calling thread.
//--------------------------------------------------------------------------
BOOL CCertChainEngine::RetrieveCrossCertUrl( IN PCCHAINCALLCONTEXT pCallContext, IN OUT PXCERT_DP_ENTRY pEntry, IN DWORD dwRetrievalFlags, IN OUT BOOL *pfTimeValid ) { BOOL fResult; FILETIME CurrentTime; HCERTSTORE hNewUrlStore = NULL; FILETIME NewLastSyncTime; CRYPT_RETRIEVE_AUX_INFO RetrieveAuxInfo; DWORD i;
memset(&RetrieveAuxInfo, 0, sizeof(RetrieveAuxInfo)); RetrieveAuxInfo.cbSize = sizeof(RetrieveAuxInfo); RetrieveAuxInfo.pLastSyncTime = &NewLastSyncTime;
pCallContext->CurrentTime(&CurrentTime);
// Loop through Urls and try to retrieve a time valid cross cert URL
for (i = 0; i < pEntry->cUrl; i++) { NewLastSyncTime = CurrentTime; LPWSTR pwszUrl = NULL; DWORD cbUrl;
// Do URL fetching outside of the engine's critical section
// Need to make a copy of the Url string. pEntry
// can be modified by another thread outside of the critical section.
cbUrl = (wcslen(pEntry->rgpwszUrl[i]) + 1) * sizeof(WCHAR); pwszUrl = (LPWSTR) PkiNonzeroAlloc(cbUrl); if (NULL == pwszUrl) goto OutOfMemory; memcpy(pwszUrl, pEntry->rgpwszUrl[i], cbUrl);
pCallContext->ChainEngine()->UnlockEngine(); fResult = ChainRetrieveObjectByUrlW( pwszUrl, CONTEXT_OID_CAPI2_ANY, dwRetrievalFlags | CRYPT_RETRIEVE_MULTIPLE_OBJECTS | CRYPT_STICKY_CACHE_RETRIEVAL, pCallContext->ChainPara()->dwUrlRetrievalTimeout, (LPVOID *) &hNewUrlStore, NULL, // hAsyncRetrieve
NULL, // pCredentials
NULL, // pvVerify
&RetrieveAuxInfo ); pCallContext->ChainEngine()->LockEngine();
PkiFree(pwszUrl);
if (pCallContext->IsTouchedEngine()) goto TouchedDuringUrlRetrieval;
if (fResult) { assert(hNewUrlStore);
if (0 > CompareFileTime(&pEntry->LastSyncTime, &NewLastSyncTime)) { BOOL fStoreChanged = FALSE;
// Move us to the head of the Url list
DWORD j; LPWSTR pwszUrl = pEntry->rgpwszUrl[i];
for (j = i; 0 < j; j--) pEntry->rgpwszUrl[j] = pEntry->rgpwszUrl[j - 1]; pEntry->rgpwszUrl[0] = pwszUrl;
if (NULL == pEntry->hUrlStore) { if (!CertAddStoreToCollection( m_hCrossCertStore, hNewUrlStore, 0, 0 )) goto AddStoreToCollectionError; pEntry->hUrlStore = hNewUrlStore; hNewUrlStore = NULL; fStoreChanged = TRUE; } else { DWORD dwOutFlags = 0; if (!I_CertSyncStoreEx( pEntry->hUrlStore, hNewUrlStore, ICERT_SYNC_STORE_INHIBIT_SYNC_PROPERTY_IN_FLAG, &dwOutFlags, NULL // pvReserved
)) goto SyncStoreError; if (dwOutFlags & ICERT_SYNC_STORE_CHANGED_OUT_FLAG) fStoreChanged = TRUE; }
if (fStoreChanged) { m_pCertObjectCache->FlushObjects( pCallContext ); pCallContext->TouchEngine();
if (!GetCrossCertDistPointsForStore( pEntry->hUrlStore, &pEntry->pChildCrossCertDPLink )) goto UpdateDistPointError; }
RepositionOnlineCrossCertDistPointEntry(pEntry, &NewLastSyncTime);
if (0 < CompareFileTime(&pEntry->NextSyncTime, &CurrentTime)) { *pfTimeValid = TRUE; break; } }
if (hNewUrlStore) { CertCloseStore(hNewUrlStore, 0); hNewUrlStore = NULL; } } }
fResult = TRUE; CommonReturn: if (hNewUrlStore) CertCloseStore(hNewUrlStore, 0); return fResult;
ErrorReturn: fResult = FALSE; goto CommonReturn;
TRACE_ERROR(AddStoreToCollectionError) TRACE_ERROR(SyncStoreError) TRACE_ERROR(UpdateDistPointError) TRACE_ERROR(OutOfMemory) SET_ERROR(TouchedDuringUrlRetrieval, ERROR_CAN_NOT_COMPLETE) }
//+-------------------------------------------------------------------------
// Update cross certificate distribution points whose NextSyncTime has
// expired.
//
// Leaves the engine's critical section to do the URL
// fetching. If the engine was touched by another thread,
// it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
//
// If the URL store is changed, increments engine's touch count and flushes
// issuer and end cert object caches.
//
// Assumption: Chain engine is locked once in the calling thread.
//--------------------------------------------------------------------------
BOOL CCertChainEngine::UpdateCrossCerts( IN PCCHAINCALLCONTEXT pCallContext ) { BOOL fResult; PXCERT_DP_ENTRY pEntry; FILETIME CurrentTime;
pEntry = m_pCrossCertDPEntry; if (NULL == pEntry) goto SuccessReturn; m_dwCrossCertDPResyncIndex++;
pCallContext->CurrentTime(&CurrentTime); while (pEntry && 0 >= CompareFileTime(&pEntry->NextSyncTime, &CurrentTime)) { PXCERT_DP_ENTRY pNextEntry = pEntry->pNext;
if (pEntry->dwResyncIndex < m_dwCrossCertDPResyncIndex) { BOOL fTimeValid = FALSE;
if (0 == pEntry->dwResyncIndex || pCallContext->IsOnline()) { RetrieveCrossCertUrl( pCallContext, pEntry, CRYPT_CACHE_ONLY_RETRIEVAL, &fTimeValid ); if (pCallContext->IsTouchedEngine()) goto TouchedDuringUrlRetrieval;
if (!fTimeValid && pCallContext->IsOnline()) { RetrieveCrossCertUrl( pCallContext, pEntry, CRYPT_WIRE_ONLY_RETRIEVAL, &fTimeValid ); if (pCallContext->IsTouchedEngine()) goto TouchedDuringUrlRetrieval;
if (!fTimeValid) RepositionOfflineCrossCertDistPointEntry(pEntry, &CurrentTime); }
// Start over at the beginning. May have added some entries.
pNextEntry = m_pCrossCertDPEntry; }
pEntry->dwResyncIndex = m_dwCrossCertDPResyncIndex;
} // else
// Skip entries we have already processed.
pEntry = pNextEntry; }
SuccessReturn: fResult = TRUE; CommonReturn: return fResult;
ErrorReturn: fResult = FALSE; goto CommonReturn;
SET_ERROR(TouchedDuringUrlRetrieval, ERROR_CAN_NOT_COMPLETE) }
|