//+--------------------------------------------------------------------------- // // 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 #include //+========================================================================= // 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) }