Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

901 lines
27 KiB

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