mirror of https://github.com/tongzx/nt5src
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.
1527 lines
42 KiB
1527 lines
42 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows NT Security
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: ssctl.cpp
|
|
//
|
|
// Contents: Self Signed Certificate Trust List Subsystem used by the
|
|
// Certificate Chaining Infrastructure for building complex
|
|
// chains
|
|
//
|
|
// History: 11-Feb-98 kirtd Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include <global.hxx>
|
|
#include <dbgdef.h>
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Attempt to get and allocate the CTL NextUpdate location Url array.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
SSCtlGetNextUpdateUrl(
|
|
IN PCCTL_CONTEXT pCtl,
|
|
OUT PCRYPT_URL_ARRAY *ppUrlArray
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
PCRYPT_URL_ARRAY pUrlArray = NULL;
|
|
DWORD cbUrlArray = 0;
|
|
LPVOID apv[2];
|
|
|
|
apv[0] = (LPVOID) pCtl;
|
|
apv[1] = (LPVOID)(UINT_PTR)(0); // Signer Index
|
|
|
|
if (!ChainGetObjectUrl(
|
|
URL_OID_CTL_NEXT_UPDATE,
|
|
apv,
|
|
0, // dwFlags
|
|
NULL, // pUrlArray
|
|
&cbUrlArray,
|
|
NULL, // pUrlInfo
|
|
NULL, // cbUrlInfo,
|
|
NULL // pvReserved
|
|
))
|
|
goto GetObjectUrlError;
|
|
|
|
pUrlArray = (PCRYPT_URL_ARRAY) new BYTE [cbUrlArray];
|
|
if (NULL == pUrlArray)
|
|
goto OutOfMemory;
|
|
|
|
if (!ChainGetObjectUrl(
|
|
URL_OID_CTL_NEXT_UPDATE,
|
|
apv,
|
|
0, // dwFlags
|
|
pUrlArray,
|
|
&cbUrlArray,
|
|
NULL, // pUrlInfo
|
|
NULL, // cbUrlInfo,
|
|
NULL // pvReserved
|
|
))
|
|
goto GetObjectUrlError;
|
|
|
|
if (0 == pUrlArray->cUrl)
|
|
goto NoNextUpdateUrls;
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
*ppUrlArray = pUrlArray;
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
if (pUrlArray) {
|
|
delete (LPBYTE) pUrlArray;
|
|
pUrlArray = NULL;
|
|
}
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(GetObjectUrlError)
|
|
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
|
|
SET_ERROR(NoNextUpdateUrls, CRYPT_E_NOT_FOUND)
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObject::CSSCtlObject, public
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CSSCtlObject::CSSCtlObject (
|
|
IN PCCERTCHAINENGINE pChainEngine,
|
|
IN PCCTL_CONTEXT pCtlContext,
|
|
IN BOOL fAdditionalStore,
|
|
OUT BOOL& rfResult
|
|
)
|
|
{
|
|
DWORD cbData;
|
|
CRYPT_DATA_BLOB DataBlob;
|
|
|
|
rfResult = TRUE;
|
|
|
|
m_cRefs = 1;
|
|
m_pCtlContext = CertDuplicateCTLContext( pCtlContext );
|
|
m_fHasSignatureBeenVerified = FALSE;
|
|
m_fSignatureValid = FALSE;
|
|
m_hMessageStore = NULL;
|
|
m_hHashEntry = NULL;
|
|
m_pChainEngine = pChainEngine;
|
|
|
|
m_pNextUpdateUrlArray = NULL;
|
|
m_dwOfflineCnt = 0;
|
|
I_CryptZeroFileTime(&m_OfflineUpdateTime);
|
|
|
|
memset( &m_SignerInfo, 0, sizeof( m_SignerInfo ) );
|
|
|
|
cbData = CHAINHASHLEN;
|
|
rfResult = CertGetCTLContextProperty(
|
|
pCtlContext,
|
|
CERT_MD5_HASH_PROP_ID,
|
|
m_rgbCtlHash,
|
|
&cbData
|
|
);
|
|
|
|
if ( rfResult && CHAINHASHLEN != cbData)
|
|
{
|
|
rfResult = FALSE;
|
|
SetLastError( (DWORD) E_UNEXPECTED);
|
|
}
|
|
|
|
if (!fAdditionalStore)
|
|
{
|
|
if ( rfResult == TRUE )
|
|
{
|
|
DataBlob.cbData = CHAINHASHLEN;
|
|
DataBlob.pbData = m_rgbCtlHash;
|
|
|
|
rfResult = I_CryptCreateLruEntry(
|
|
pChainEngine->SSCtlObjectCache()->HashIndex(),
|
|
&DataBlob,
|
|
this,
|
|
&m_hHashEntry
|
|
);
|
|
}
|
|
|
|
if ( rfResult == TRUE )
|
|
{
|
|
m_hMessageStore = CertOpenStore(
|
|
CERT_STORE_PROV_MSG,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
NULL,
|
|
0,
|
|
pCtlContext->hCryptMsg
|
|
);
|
|
|
|
if ( m_hMessageStore == NULL )
|
|
{
|
|
rfResult = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( rfResult == TRUE )
|
|
{
|
|
rfResult = SSCtlGetSignerInfo( pCtlContext, &m_SignerInfo );
|
|
}
|
|
|
|
if (!fAdditionalStore)
|
|
{
|
|
if ( rfResult == TRUE )
|
|
{
|
|
if (!I_CryptIsZeroFileTime(&m_pCtlContext->pCtlInfo->NextUpdate))
|
|
{
|
|
// Ignore any errors
|
|
SSCtlGetNextUpdateUrl(m_pCtlContext, &m_pNextUpdateUrlArray);
|
|
}
|
|
}
|
|
}
|
|
|
|
assert( m_pChainEngine != NULL );
|
|
assert( m_pCtlContext != NULL );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObject::~CSSCtlObject, public
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CSSCtlObject::~CSSCtlObject ()
|
|
{
|
|
SSCtlFreeSignerInfo( &m_SignerInfo );
|
|
|
|
if ( m_hMessageStore != NULL )
|
|
{
|
|
CertCloseStore( m_hMessageStore, 0 );
|
|
}
|
|
|
|
if ( m_pNextUpdateUrlArray != NULL )
|
|
{
|
|
delete (LPBYTE) m_pNextUpdateUrlArray;
|
|
}
|
|
|
|
if ( m_hHashEntry != NULL )
|
|
{
|
|
I_CryptReleaseLruEntry( m_hHashEntry );
|
|
}
|
|
|
|
CertFreeCTLContext( m_pCtlContext );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObject::GetSigner, public
|
|
//
|
|
// Synopsis: get the certificate object of the signer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
CSSCtlObject::GetSigner (
|
|
IN PCCHAINPATHOBJECT pSubject,
|
|
IN PCCHAINCALLCONTEXT pCallContext,
|
|
IN HCERTSTORE hAdditionalStore,
|
|
OUT PCCHAINPATHOBJECT* ppSigner,
|
|
OUT BOOL* pfCtlSignatureValid
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
PCCHAINPATHOBJECT pSigner = NULL;
|
|
BOOL fNewSigner = TRUE;
|
|
|
|
fResult = SSCtlGetSignerChainPathObject(
|
|
pSubject,
|
|
pCallContext,
|
|
&m_SignerInfo,
|
|
hAdditionalStore,
|
|
&pSigner,
|
|
&fNewSigner
|
|
);
|
|
|
|
if (fResult)
|
|
{
|
|
if ( !m_fHasSignatureBeenVerified || fNewSigner )
|
|
{
|
|
CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA CtrlPara;
|
|
|
|
memset(&CtrlPara, 0, sizeof(CtrlPara));
|
|
CtrlPara.cbSize = sizeof(CtrlPara);
|
|
// CtrlPara.hCryptProv =
|
|
|
|
// This needs to be updated when chain building
|
|
// supports CTLs with more than one signer.
|
|
CtrlPara.dwSignerIndex = 0;
|
|
CtrlPara.dwSignerType = CMSG_VERIFY_SIGNER_CERT;
|
|
CtrlPara.pvSigner = (void *) pSigner->CertObject()->CertContext();
|
|
|
|
|
|
m_fSignatureValid = CryptMsgControl(
|
|
m_pCtlContext->hCryptMsg,
|
|
0,
|
|
CMSG_CTRL_VERIFY_SIGNATURE_EX,
|
|
&CtrlPara
|
|
);
|
|
|
|
m_fHasSignatureBeenVerified = TRUE;
|
|
|
|
CertPerfIncrementChainVerifyCtlSignatureCount();
|
|
}
|
|
else
|
|
{
|
|
CertPerfIncrementChainBeenVerifiedCtlSignatureCount();
|
|
}
|
|
|
|
*ppSigner = pSigner;
|
|
}
|
|
*pfCtlSignatureValid = m_fSignatureValid;
|
|
|
|
|
|
return fResult;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObject::GetTrustListInfo, public
|
|
//
|
|
// Synopsis: get the trust list information relative to a particular cert
|
|
// object
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
CSSCtlObject::GetTrustListInfo (
|
|
IN PCCERT_CONTEXT pCertContext,
|
|
OUT PCERT_TRUST_LIST_INFO* ppTrustListInfo
|
|
)
|
|
{
|
|
PCTL_ENTRY pCtlEntry;
|
|
PCERT_TRUST_LIST_INFO pTrustListInfo;
|
|
|
|
pCtlEntry = CertFindSubjectInCTL(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
CTL_CERT_SUBJECT_TYPE,
|
|
(LPVOID)pCertContext,
|
|
m_pCtlContext,
|
|
0
|
|
);
|
|
|
|
if ( pCtlEntry == NULL )
|
|
{
|
|
SetLastError( (DWORD) CRYPT_E_NOT_FOUND );
|
|
return( FALSE );
|
|
}
|
|
|
|
pTrustListInfo = new CERT_TRUST_LIST_INFO;
|
|
if ( pTrustListInfo == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
pTrustListInfo->cbSize = sizeof( CERT_TRUST_LIST_INFO );
|
|
pTrustListInfo->pCtlEntry = pCtlEntry;
|
|
pTrustListInfo->pCtlContext = CertDuplicateCTLContext( m_pCtlContext );
|
|
|
|
*ppTrustListInfo = pTrustListInfo;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObject::CalculateStatus, public
|
|
//
|
|
// Synopsis: calculate the status
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
CSSCtlObject::CalculateStatus (
|
|
IN LPFILETIME pTime,
|
|
IN PCERT_USAGE_MATCH pRequestedUsage,
|
|
IN OUT PCERT_TRUST_STATUS pStatus
|
|
)
|
|
{
|
|
assert( m_fHasSignatureBeenVerified == TRUE );
|
|
|
|
SSCtlGetCtlTrustStatus(
|
|
m_pCtlContext,
|
|
m_fSignatureValid,
|
|
pTime,
|
|
pRequestedUsage,
|
|
pStatus
|
|
);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObject::HasNextUpdateUrl, public
|
|
//
|
|
// Synopsis: returns TRUE if the Ctl has a NextUpdate time and location Url
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL CSSCtlObject::HasNextUpdateUrl (
|
|
OUT LPFILETIME pUpdateTime
|
|
)
|
|
{
|
|
if ( m_pNextUpdateUrlArray != NULL )
|
|
{
|
|
assert(!I_CryptIsZeroFileTime(&m_pCtlContext->pCtlInfo->NextUpdate));
|
|
if (0 != m_dwOfflineCnt) {
|
|
assert(!I_CryptIsZeroFileTime(&m_OfflineUpdateTime));
|
|
*pUpdateTime = m_OfflineUpdateTime;
|
|
} else
|
|
*pUpdateTime = m_pCtlContext->pCtlInfo->NextUpdate;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObject::SetOffline, public
|
|
//
|
|
// Synopsis: called when offline
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void CSSCtlObject::SetOffline (
|
|
IN LPFILETIME pCurrentTime,
|
|
OUT LPFILETIME pUpdateTime
|
|
)
|
|
{
|
|
m_dwOfflineCnt++;
|
|
|
|
I_CryptIncrementFileTimeBySeconds(
|
|
pCurrentTime,
|
|
ChainGetOfflineUrlDeltaSeconds(m_dwOfflineCnt),
|
|
&m_OfflineUpdateTime
|
|
);
|
|
|
|
*pUpdateTime = m_OfflineUpdateTime;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObjectCache::CSSCtlObjectCache, public
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CSSCtlObjectCache::CSSCtlObjectCache (
|
|
OUT BOOL& rfResult
|
|
)
|
|
{
|
|
LRU_CACHE_CONFIG Config;
|
|
|
|
memset( &Config, 0, sizeof( Config ) );
|
|
|
|
Config.dwFlags = LRU_CACHE_NO_SERIALIZE | LRU_CACHE_NO_COPY_IDENTIFIER;
|
|
Config.pfnHash = CertObjectCacheHashMd5Identifier;
|
|
Config.cBuckets = DEFAULT_CERT_OBJECT_CACHE_BUCKETS;
|
|
Config.pfnOnRemoval = SSCtlOnRemovalFromCache;
|
|
|
|
m_hHashIndex = NULL;
|
|
|
|
rfResult = I_CryptCreateLruCache( &Config, &m_hHashIndex );
|
|
|
|
I_CryptZeroFileTime(&m_UpdateTime);
|
|
m_fFirstUpdate = FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObjectCache::~CSSCtlObjectCache, public
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CSSCtlObjectCache::~CSSCtlObjectCache ()
|
|
{
|
|
I_CryptFreeLruCache( m_hHashIndex, 0, NULL );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObjectCache::PopulateCache, public
|
|
//
|
|
// Synopsis: populate the cache
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
CSSCtlObjectCache::PopulateCache (
|
|
IN PCCERTCHAINENGINE pChainEngine
|
|
)
|
|
{
|
|
assert( pChainEngine->SSCtlObjectCache() == this );
|
|
|
|
return( SSCtlPopulateCacheFromCertStore( pChainEngine, NULL ) );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObjectCache::AddObject, public
|
|
//
|
|
// Synopsis: add an object to the cache
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
CSSCtlObjectCache::AddObject (
|
|
IN PCSSCTLOBJECT pSSCtlObject,
|
|
IN BOOL fCheckForDuplicate
|
|
)
|
|
{
|
|
FILETIME UpdateTime;
|
|
|
|
if ( fCheckForDuplicate == TRUE )
|
|
{
|
|
PCSSCTLOBJECT pDuplicate;
|
|
|
|
pDuplicate = FindObjectByHash( pSSCtlObject->CtlHash() );
|
|
if ( pDuplicate != NULL )
|
|
{
|
|
pDuplicate->Release();
|
|
SetLastError( (DWORD) CRYPT_E_EXISTS );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
pSSCtlObject->AddRef();
|
|
|
|
if (pSSCtlObject->HasNextUpdateUrl(&UpdateTime))
|
|
{
|
|
// Set earliest update time
|
|
if (I_CryptIsZeroFileTime(&m_UpdateTime) ||
|
|
0 > CompareFileTime(&UpdateTime, &m_UpdateTime))
|
|
{
|
|
m_UpdateTime = UpdateTime;
|
|
}
|
|
|
|
m_fFirstUpdate = TRUE;
|
|
|
|
}
|
|
|
|
I_CryptInsertLruEntry( pSSCtlObject->HashIndexEntry(), NULL );
|
|
|
|
if (pSSCtlObject->MessageStore() )
|
|
{
|
|
CertAddStoreToCollection(
|
|
pSSCtlObject->ChainEngine()->OtherStore(),
|
|
pSSCtlObject->MessageStore(),
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
|
|
CertPerfIncrementChainCtlCacheCount();
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObjectCache::RemoveObject, public
|
|
//
|
|
// Synopsis: remove object from cache
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
CSSCtlObjectCache::RemoveObject (
|
|
IN PCSSCTLOBJECT pSSCtlObject
|
|
)
|
|
{
|
|
I_CryptRemoveLruEntry( pSSCtlObject->HashIndexEntry(), 0, NULL );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObjectCache::FindObjectByHash, public
|
|
//
|
|
// Synopsis: find object with given hash
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
PCSSCTLOBJECT
|
|
CSSCtlObjectCache::FindObjectByHash (
|
|
IN BYTE rgbHash [ CHAINHASHLEN ]
|
|
)
|
|
{
|
|
HLRUENTRY hFound;
|
|
PCSSCTLOBJECT pFound = NULL;
|
|
CRYPT_HASH_BLOB HashBlob;
|
|
|
|
HashBlob.cbData = CHAINHASHLEN;
|
|
HashBlob.pbData = rgbHash;
|
|
|
|
hFound = I_CryptFindLruEntry( m_hHashIndex, &HashBlob );
|
|
if ( hFound != NULL )
|
|
{
|
|
pFound = (PCSSCTLOBJECT)I_CryptGetLruEntryData( hFound );
|
|
pFound->AddRef();
|
|
|
|
I_CryptReleaseLruEntry( hFound );
|
|
}
|
|
|
|
return( pFound );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObjectCache::EnumObjects, public
|
|
//
|
|
// Synopsis: enumerate objects
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
CSSCtlObjectCache::EnumObjects (
|
|
IN PFN_ENUM_SSCTLOBJECTS pfnEnum,
|
|
IN LPVOID pvParameter
|
|
)
|
|
{
|
|
SSCTL_ENUM_OBJECTS_DATA EnumData;
|
|
|
|
EnumData.pfnEnumObjects = pfnEnum;
|
|
EnumData.pvEnumParameter = pvParameter;
|
|
|
|
I_CryptWalkAllLruCacheEntries(
|
|
m_hHashIndex,
|
|
SSCtlEnumObjectsWalkFn,
|
|
&EnumData
|
|
);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObjectCache::Resync, public
|
|
//
|
|
// Synopsis: resync the cache
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
CSSCtlObjectCache::Resync (IN PCCERTCHAINENGINE pChainEngine)
|
|
{
|
|
I_CryptFlushLruCache( m_hHashIndex, 0, NULL );
|
|
|
|
I_CryptZeroFileTime(&m_UpdateTime);
|
|
m_fFirstUpdate = FALSE;
|
|
|
|
return( PopulateCache( pChainEngine ) );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CSSCtlObjectCache::UpdateCache, public
|
|
//
|
|
// Synopsis: update the cache
|
|
//
|
|
// 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 CTL is updated, increments the engine's touch count
|
|
// and flushes issuer and end cert object caches.
|
|
//
|
|
// Assumption: Chain engine is locked once in the calling thread.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
CSSCtlObjectCache::UpdateCache (
|
|
IN PCCERTCHAINENGINE pChainEngine,
|
|
IN PCCHAINCALLCONTEXT pCallContext
|
|
)
|
|
{
|
|
FILETIME CurrentTime;
|
|
SSCTL_UPDATE_CTL_OBJ_PARA Para;
|
|
|
|
assert( pChainEngine->SSCtlObjectCache() == this );
|
|
|
|
// Check if we have any CTLs needing to be updated
|
|
if (I_CryptIsZeroFileTime(&m_UpdateTime))
|
|
return TRUE;
|
|
pCallContext->CurrentTime(&CurrentTime);
|
|
if (0 < CompareFileTime(&m_UpdateTime, &CurrentTime))
|
|
return TRUE;
|
|
|
|
if (!m_fFirstUpdate && !pCallContext->IsOnline())
|
|
return TRUE;
|
|
|
|
memset(&Para, 0, sizeof(Para));
|
|
Para.pChainEngine = pChainEngine;
|
|
Para.pCallContext = pCallContext;
|
|
|
|
EnumObjects(SSCtlUpdateCtlObjectEnumFn, &Para);
|
|
if (pCallContext->IsTouchedEngine()) {
|
|
PSSCTL_UPDATE_CTL_OBJ_ENTRY pEntry;
|
|
|
|
pEntry = Para.pEntry;
|
|
while (pEntry) {
|
|
PSSCTL_UPDATE_CTL_OBJ_ENTRY pDeleteEntry;
|
|
|
|
pEntry->pSSCtlObjectAdd->Release();
|
|
|
|
pDeleteEntry = pEntry;
|
|
pEntry = pEntry->pNext;
|
|
delete pDeleteEntry;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
m_UpdateTime = Para.UpdateTime;
|
|
m_fFirstUpdate = FALSE;
|
|
|
|
if (Para.pEntry) {
|
|
HCERTSTORE hTrustStore;
|
|
PSSCTL_UPDATE_CTL_OBJ_ENTRY pEntry;
|
|
|
|
hTrustStore = pChainEngine->OpenTrustStore();
|
|
|
|
pChainEngine->CertObjectCache()->FlushObjects( pCallContext );
|
|
pCallContext->TouchEngine();
|
|
|
|
pEntry = Para.pEntry;
|
|
while (pEntry) {
|
|
PSSCTL_UPDATE_CTL_OBJ_ENTRY pDeleteEntry;
|
|
|
|
RemoveObject(pEntry->pSSCtlObjectRemove);
|
|
if (AddObject(pEntry->pSSCtlObjectAdd, TRUE)) {
|
|
if (hTrustStore) {
|
|
// Persist the newer CTL to the trust store
|
|
CertAddCTLContextToStore(
|
|
hTrustStore,
|
|
pEntry->pSSCtlObjectAdd->CtlContext(),
|
|
CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
|
|
pEntry->pSSCtlObjectAdd->Release();
|
|
|
|
pDeleteEntry = pEntry;
|
|
pEntry = pEntry->pNext;
|
|
delete pDeleteEntry;
|
|
}
|
|
|
|
if (hTrustStore)
|
|
CertCloseStore(hTrustStore, 0);
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlOnRemovalFromCache
|
|
//
|
|
// Synopsis: SS CTL removal notification used when the cache is destroyed
|
|
// or an object is explicitly removed. Note that this cache
|
|
// does not LRU remove objects
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID WINAPI
|
|
SSCtlOnRemovalFromCache (
|
|
IN LPVOID pv,
|
|
IN OPTIONAL LPVOID pvRemovalContext
|
|
)
|
|
{
|
|
PCSSCTLOBJECT pSSCtlObject = (PCSSCTLOBJECT) pv;
|
|
CertPerfDecrementChainCtlCacheCount();
|
|
|
|
assert( pvRemovalContext == NULL );
|
|
|
|
if (pSSCtlObject->MessageStore() )
|
|
{
|
|
CertRemoveStoreFromCollection(
|
|
pSSCtlObject->ChainEngine()->OtherStore(),
|
|
pSSCtlObject->MessageStore()
|
|
);
|
|
}
|
|
|
|
pSSCtlObject->Release();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlGetSignerInfo
|
|
//
|
|
// Synopsis: get the signer info
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SSCtlGetSignerInfo (
|
|
IN PCCTL_CONTEXT pCtlContext,
|
|
OUT PSSCTL_SIGNER_INFO pSignerInfo
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_INFO pMessageSignerCertInfo = NULL;
|
|
DWORD cbData = 0;
|
|
|
|
fResult = CryptMsgGetParam(
|
|
pCtlContext->hCryptMsg,
|
|
CMSG_SIGNER_CERT_INFO_PARAM,
|
|
0,
|
|
NULL,
|
|
&cbData
|
|
);
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
pMessageSignerCertInfo = (PCERT_INFO)new BYTE [ cbData ];
|
|
if ( pMessageSignerCertInfo != NULL )
|
|
{
|
|
fResult = CryptMsgGetParam(
|
|
pCtlContext->hCryptMsg,
|
|
CMSG_SIGNER_CERT_INFO_PARAM,
|
|
0,
|
|
pMessageSignerCertInfo,
|
|
&cbData
|
|
);
|
|
}
|
|
else
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
fResult = FALSE;
|
|
}
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
pSignerInfo->pMessageSignerCertInfo = pMessageSignerCertInfo;
|
|
pSignerInfo->fSignerHashAvailable = FALSE;
|
|
}
|
|
else
|
|
{
|
|
delete pMessageSignerCertInfo;
|
|
}
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlFreeSignerInfo
|
|
//
|
|
// Synopsis: free the data in the signer info
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID WINAPI
|
|
SSCtlFreeSignerInfo (
|
|
IN PSSCTL_SIGNER_INFO pSignerInfo
|
|
)
|
|
{
|
|
delete (LPBYTE)pSignerInfo->pMessageSignerCertInfo;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlGetSignerChainPathObject
|
|
//
|
|
// Synopsis: get the signer chain path object
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SSCtlGetSignerChainPathObject (
|
|
IN PCCHAINPATHOBJECT pSubject,
|
|
IN PCCHAINCALLCONTEXT pCallContext,
|
|
IN PSSCTL_SIGNER_INFO pSignerInfo,
|
|
IN HCERTSTORE hAdditionalStore,
|
|
OUT PCCHAINPATHOBJECT* ppSigner,
|
|
OUT BOOL *pfNewSigner
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
PCCERTCHAINENGINE pChainEngine = pSubject->CertObject()->ChainEngine();
|
|
PCCERTOBJECTCACHE pCertObjectCache = pChainEngine->CertObjectCache();
|
|
PCCERTOBJECT pCertObject = NULL;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
PCCHAINPATHOBJECT pSigner = NULL;
|
|
BOOL fAdditionalStoreUsed = FALSE;
|
|
BYTE rgbCertHash[ CHAINHASHLEN ];
|
|
|
|
|
|
*pfNewSigner = FALSE;
|
|
|
|
if ( pSignerInfo->fSignerHashAvailable == TRUE )
|
|
{
|
|
pCertObject = pCertObjectCache->FindIssuerObjectByHash(
|
|
pSignerInfo->rgbSignerCertHash );
|
|
}
|
|
|
|
if ( pCertObject == NULL )
|
|
{
|
|
if ( pSignerInfo->fSignerHashAvailable == TRUE )
|
|
{
|
|
pCertContext = SSCtlFindCertificateInStoreByHash(
|
|
pChainEngine->OtherStore(),
|
|
pSignerInfo->rgbSignerCertHash
|
|
);
|
|
|
|
if ( ( pCertContext == NULL ) && ( hAdditionalStore != NULL ) )
|
|
{
|
|
fAdditionalStoreUsed = TRUE;
|
|
|
|
pCertContext = SSCtlFindCertificateInStoreByHash(
|
|
hAdditionalStore,
|
|
pSignerInfo->rgbSignerCertHash
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( pCertContext == NULL )
|
|
{
|
|
*pfNewSigner = TRUE;
|
|
fAdditionalStoreUsed = FALSE;
|
|
|
|
pCertContext = CertGetSubjectCertificateFromStore(
|
|
pChainEngine->OtherStore(),
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
pSignerInfo->pMessageSignerCertInfo
|
|
);
|
|
}
|
|
|
|
if ( ( pCertContext == NULL ) && ( hAdditionalStore != NULL ) )
|
|
{
|
|
fAdditionalStoreUsed = TRUE;
|
|
|
|
pCertContext = CertGetSubjectCertificateFromStore(
|
|
hAdditionalStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
pSignerInfo->pMessageSignerCertInfo
|
|
);
|
|
}
|
|
|
|
if ( pCertContext != NULL )
|
|
{
|
|
DWORD cbData = CHAINHASHLEN;
|
|
fResult = CertGetCertificateContextProperty(
|
|
pCertContext,
|
|
CERT_MD5_HASH_PROP_ID,
|
|
rgbCertHash,
|
|
&cbData
|
|
);
|
|
|
|
if ( fResult && CHAINHASHLEN != cbData)
|
|
{
|
|
fResult = FALSE;
|
|
SetLastError( (DWORD) E_UNEXPECTED);
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = ChainCreateCertObject (
|
|
fAdditionalStoreUsed ?
|
|
CERT_EXTERNAL_ISSUER_OBJECT_TYPE :
|
|
CERT_CACHED_ISSUER_OBJECT_TYPE,
|
|
pCallContext,
|
|
pCertContext,
|
|
rgbCertHash,
|
|
&pCertObject
|
|
);
|
|
}
|
|
|
|
CertFreeCertificateContext( pCertContext );
|
|
}
|
|
else
|
|
{
|
|
fResult = FALSE;
|
|
SetLastError((DWORD) CRYPT_E_NOT_FOUND);
|
|
}
|
|
}
|
|
|
|
if ( fResult )
|
|
{
|
|
assert(pCertObject);
|
|
fResult = ChainCreatePathObject(
|
|
pCallContext,
|
|
pCertObject,
|
|
hAdditionalStore,
|
|
&pSigner
|
|
);
|
|
}
|
|
|
|
if ( fResult )
|
|
{
|
|
assert(pSigner);
|
|
|
|
if ( !pSignerInfo->fSignerHashAvailable || *pfNewSigner )
|
|
{
|
|
memcpy(
|
|
pSignerInfo->rgbSignerCertHash,
|
|
rgbCertHash,
|
|
CHAINHASHLEN
|
|
);
|
|
|
|
pSignerInfo->fSignerHashAvailable = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if ( pCertObject != NULL )
|
|
{
|
|
pCertObject->Release();
|
|
}
|
|
|
|
*ppSigner = pSigner;
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlFindCertificateInStoreByHash
|
|
//
|
|
// Synopsis: find certificate in store by hash
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
PCCERT_CONTEXT WINAPI
|
|
SSCtlFindCertificateInStoreByHash (
|
|
IN HCERTSTORE hStore,
|
|
IN BYTE rgbHash [ CHAINHASHLEN]
|
|
)
|
|
{
|
|
CRYPT_HASH_BLOB HashBlob;
|
|
|
|
HashBlob.cbData = CHAINHASHLEN;
|
|
HashBlob.pbData = rgbHash;
|
|
|
|
return( CertFindCertificateInStore(
|
|
hStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_MD5_HASH,
|
|
&HashBlob,
|
|
NULL
|
|
) );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlGetCtlTrustStatus
|
|
//
|
|
// Synopsis: get the trust status for the CTL
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID WINAPI
|
|
SSCtlGetCtlTrustStatus (
|
|
IN PCCTL_CONTEXT pCtlContext,
|
|
IN BOOL fSignatureValid,
|
|
IN LPFILETIME pTime,
|
|
IN PCERT_USAGE_MATCH pRequestedUsage,
|
|
IN OUT PCERT_TRUST_STATUS pStatus
|
|
)
|
|
{
|
|
FILETIME NoTime;
|
|
CERT_TRUST_STATUS UsageStatus;
|
|
|
|
memset( &NoTime, 0, sizeof( NoTime ) );
|
|
|
|
if ( fSignatureValid == FALSE )
|
|
{
|
|
pStatus->dwErrorStatus |= CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID;
|
|
}
|
|
|
|
if ( ( CompareFileTime(
|
|
pTime,
|
|
&pCtlContext->pCtlInfo->ThisUpdate
|
|
) < 0 ) ||
|
|
( ( ( CompareFileTime(
|
|
&NoTime,
|
|
&pCtlContext->pCtlInfo->NextUpdate
|
|
) != 0 ) &&
|
|
( CompareFileTime(
|
|
pTime,
|
|
&pCtlContext->pCtlInfo->NextUpdate
|
|
) > 0 ) ) ) )
|
|
{
|
|
pStatus->dwErrorStatus |= CERT_TRUST_CTL_IS_NOT_TIME_VALID;
|
|
}
|
|
|
|
memset( &UsageStatus, 0, sizeof( UsageStatus ) );
|
|
ChainGetUsageStatus(
|
|
(PCERT_ENHKEY_USAGE)&pRequestedUsage->Usage,
|
|
(PCERT_ENHKEY_USAGE)&pCtlContext->pCtlInfo->SubjectUsage,
|
|
pRequestedUsage->dwType,
|
|
&UsageStatus
|
|
);
|
|
|
|
if ( UsageStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE )
|
|
{
|
|
pStatus->dwErrorStatus |= CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlPopulateCacheFromCertStore
|
|
//
|
|
// Synopsis: populate the SS CTL object cache from certificate store CTLs
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SSCtlPopulateCacheFromCertStore (
|
|
IN PCCERTCHAINENGINE pChainEngine,
|
|
IN OPTIONAL HCERTSTORE hStore
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
BOOL fAdditionalStore = TRUE;
|
|
PCCTL_CONTEXT pCtlContext = NULL;
|
|
BYTE rgbCtlHash[ CHAINHASHLEN ];
|
|
PCSSCTLOBJECT pSSCtlObject;
|
|
PCSSCTLOBJECTCACHE pSSCtlObjectCache;
|
|
|
|
pSSCtlObjectCache = pChainEngine->SSCtlObjectCache();
|
|
|
|
if ( hStore == NULL )
|
|
{
|
|
hStore = pChainEngine->TrustStore();
|
|
fAdditionalStore = FALSE;
|
|
}
|
|
|
|
while ( ( pCtlContext = CertEnumCTLsInStore(
|
|
hStore,
|
|
pCtlContext
|
|
) ) != NULL )
|
|
{
|
|
DWORD cbData = CHAINHASHLEN;
|
|
fResult = CertGetCTLContextProperty(
|
|
pCtlContext,
|
|
CERT_MD5_HASH_PROP_ID,
|
|
rgbCtlHash,
|
|
&cbData
|
|
);
|
|
if ( fResult && CHAINHASHLEN != cbData)
|
|
{
|
|
fResult = FALSE;
|
|
SetLastError( (DWORD) E_UNEXPECTED);
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
pSSCtlObject = pSSCtlObjectCache->FindObjectByHash( rgbCtlHash );
|
|
if ( pSSCtlObject == NULL )
|
|
{
|
|
fResult = SSCtlCreateCtlObject(
|
|
pChainEngine,
|
|
pCtlContext,
|
|
FALSE, // fAdditionalStore
|
|
&pSSCtlObject
|
|
);
|
|
}
|
|
else
|
|
{
|
|
pSSCtlObject->Release();
|
|
fResult = FALSE;
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = pSSCtlObjectCache->AddObject( pSSCtlObject, FALSE );
|
|
|
|
// NOTE: Since fDuplicate == FALSE this should never fail
|
|
assert( fResult == TRUE );
|
|
|
|
pSSCtlObject->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlCreateCtlObject
|
|
//
|
|
// Synopsis: create an SS CTL Object
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SSCtlCreateCtlObject (
|
|
IN PCCERTCHAINENGINE pChainEngine,
|
|
IN PCCTL_CONTEXT pCtlContext,
|
|
IN BOOL fAdditionalStore,
|
|
OUT PCSSCTLOBJECT* ppSSCtlObject
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
PCSSCTLOBJECT pSSCtlObject;
|
|
|
|
pSSCtlObject = new CSSCtlObject(
|
|
pChainEngine, pCtlContext, fAdditionalStore, fResult );
|
|
if ( pSSCtlObject == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
fResult = FALSE;
|
|
}
|
|
else if ( fResult == TRUE )
|
|
{
|
|
*ppSSCtlObject = pSSCtlObject;
|
|
}
|
|
else
|
|
{
|
|
delete pSSCtlObject;
|
|
}
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlEnumObjectsWalkFn
|
|
//
|
|
// Synopsis: object enumerator walk function
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SSCtlEnumObjectsWalkFn (
|
|
IN LPVOID pvParameter,
|
|
IN HLRUENTRY hEntry
|
|
)
|
|
{
|
|
PSSCTL_ENUM_OBJECTS_DATA pEnumData = (PSSCTL_ENUM_OBJECTS_DATA)pvParameter;
|
|
|
|
return( ( *pEnumData->pfnEnumObjects )(
|
|
pEnumData->pvEnumParameter,
|
|
(PCSSCTLOBJECT)I_CryptGetLruEntryData( hEntry )
|
|
) );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlCreateObjectCache
|
|
//
|
|
// Synopsis: create the SS CTL object cache
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SSCtlCreateObjectCache (
|
|
OUT PCSSCTLOBJECTCACHE* ppSSCtlObjectCache
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
PCSSCTLOBJECTCACHE pSSCtlObjectCache;
|
|
|
|
pSSCtlObjectCache = new CSSCtlObjectCache( fResult );
|
|
|
|
if ( pSSCtlObjectCache == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
fResult = FALSE;
|
|
}
|
|
else if ( fResult == TRUE )
|
|
{
|
|
*ppSSCtlObjectCache = pSSCtlObjectCache;
|
|
}
|
|
else
|
|
{
|
|
delete pSSCtlObjectCache;
|
|
}
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlFreeObjectCache
|
|
//
|
|
// Synopsis: free the object cache
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID WINAPI
|
|
SSCtlFreeObjectCache (
|
|
IN PCSSCTLOBJECTCACHE pSSCtlObjectCache
|
|
)
|
|
{
|
|
delete pSSCtlObjectCache;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlFreeTrustListInfo
|
|
//
|
|
// Synopsis: free the trust list info
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID WINAPI
|
|
SSCtlFreeTrustListInfo (
|
|
IN PCERT_TRUST_LIST_INFO pTrustListInfo
|
|
)
|
|
{
|
|
CertFreeCTLContext( pTrustListInfo->pCtlContext );
|
|
|
|
delete pTrustListInfo;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SSCtlAllocAndCopyTrustListInfo
|
|
//
|
|
// Synopsis: allocate and copy the trust list info
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI
|
|
SSCtlAllocAndCopyTrustListInfo (
|
|
IN PCERT_TRUST_LIST_INFO pTrustListInfo,
|
|
OUT PCERT_TRUST_LIST_INFO* ppTrustListInfo
|
|
)
|
|
{
|
|
PCERT_TRUST_LIST_INFO pCopyTrustListInfo;
|
|
|
|
pCopyTrustListInfo = new CERT_TRUST_LIST_INFO;
|
|
if ( pCopyTrustListInfo == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
pCopyTrustListInfo->cbSize = sizeof( CERT_TRUST_LIST_INFO );
|
|
|
|
pCopyTrustListInfo->pCtlContext = CertDuplicateCTLContext(
|
|
pTrustListInfo->pCtlContext
|
|
);
|
|
|
|
pCopyTrustListInfo->pCtlEntry = pTrustListInfo->pCtlEntry;
|
|
|
|
*ppTrustListInfo = pCopyTrustListInfo;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Retrieve a newer and time valid CTL at one of the NextUpdate Urls
|
|
//
|
|
// 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.
|
|
//
|
|
// Assumption: Chain engine is locked once in the calling thread.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
SSCtlRetrieveCtlUrl(
|
|
IN PCCERTCHAINENGINE pChainEngine,
|
|
IN PCCHAINCALLCONTEXT pCallContext,
|
|
IN OUT PCRYPT_URL_ARRAY pNextUpdateUrlArray,
|
|
IN DWORD dwRetrievalFlags,
|
|
IN OUT PCCTL_CONTEXT *ppCtl,
|
|
IN OUT BOOL *pfNewerCtl,
|
|
IN OUT BOOL *pfTimeValid
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
DWORD i;
|
|
|
|
// Loop through Urls and try to retrieve a newer and time valid CTL
|
|
for (i = 0; i < pNextUpdateUrlArray->cUrl; i++) {
|
|
PCCTL_CONTEXT pNewCtl = NULL;
|
|
LPWSTR pwszUrl = NULL;
|
|
DWORD cbUrl;
|
|
|
|
|
|
// Do URL fetching outside of the engine's critical section
|
|
|
|
// Need to make a copy of the Url string. pNextUpdateUrlArray
|
|
// can be modified by another thread outside of the critical section.
|
|
cbUrl = (wcslen(pNextUpdateUrlArray->rgwszUrl[i]) + 1) * sizeof(WCHAR);
|
|
pwszUrl = (LPWSTR) PkiNonzeroAlloc(cbUrl);
|
|
if (NULL == pwszUrl)
|
|
goto OutOfMemory;
|
|
memcpy(pwszUrl, pNextUpdateUrlArray->rgwszUrl[i], cbUrl);
|
|
|
|
pCallContext->ChainEngine()->UnlockEngine();
|
|
fResult = ChainRetrieveObjectByUrlW(
|
|
pwszUrl,
|
|
CONTEXT_OID_CTL,
|
|
dwRetrievalFlags |
|
|
CRYPT_LDAP_SCOPE_BASE_ONLY_RETRIEVAL |
|
|
CRYPT_STICKY_CACHE_RETRIEVAL,
|
|
pCallContext->ChainPara()->dwUrlRetrievalTimeout,
|
|
(LPVOID *) &pNewCtl,
|
|
NULL, // hAsyncRetrieve
|
|
NULL, // pCredentials
|
|
NULL, // pvVerify
|
|
NULL // pAuxInfo
|
|
);
|
|
pCallContext->ChainEngine()->LockEngine();
|
|
|
|
PkiFree(pwszUrl);
|
|
|
|
if (pCallContext->IsTouchedEngine()) {
|
|
if (pNewCtl)
|
|
CertFreeCTLContext(pNewCtl);
|
|
goto TouchedDuringUrlRetrieval;
|
|
}
|
|
|
|
if (fResult) {
|
|
PCCTL_CONTEXT pOldCtl;
|
|
|
|
assert(pNewCtl);
|
|
|
|
pOldCtl = *ppCtl;
|
|
if (0 < CompareFileTime(&pNewCtl->pCtlInfo->ThisUpdate,
|
|
&pOldCtl->pCtlInfo->ThisUpdate)) {
|
|
FILETIME CurrentTime;
|
|
|
|
// Move us to the head of the Url list
|
|
DWORD j;
|
|
LPWSTR pwszUrl = pNextUpdateUrlArray->rgwszUrl[i];
|
|
|
|
for (j = i; 0 < j; j--) {
|
|
pNextUpdateUrlArray->rgwszUrl[j] =
|
|
pNextUpdateUrlArray->rgwszUrl[j - 1];
|
|
}
|
|
pNextUpdateUrlArray->rgwszUrl[0] = pwszUrl;
|
|
|
|
*pfNewerCtl = TRUE;
|
|
CertFreeCTLContext(pOldCtl);
|
|
*ppCtl = pNewCtl;
|
|
|
|
pCallContext->CurrentTime(&CurrentTime);
|
|
if (I_CryptIsZeroFileTime(&pNewCtl->pCtlInfo->NextUpdate) ||
|
|
0 < CompareFileTime(&pNewCtl->pCtlInfo->NextUpdate,
|
|
&CurrentTime)) {
|
|
*pfTimeValid = TRUE;
|
|
break;
|
|
}
|
|
} else
|
|
CertFreeCTLContext(pNewCtl);
|
|
}
|
|
}
|
|
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR(TouchedDuringUrlRetrieval, ERROR_CAN_NOT_COMPLETE)
|
|
TRACE_ERROR(OutOfMemory)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Update Ctl Object Enum Function
|
|
//
|
|
// 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.
|
|
//
|
|
// Assumption: Chain engine is locked once in the calling thread.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
SSCtlUpdateCtlObjectEnumFn(
|
|
IN LPVOID pvPara,
|
|
IN PCSSCTLOBJECT pSSCtlObject
|
|
)
|
|
{
|
|
BOOL fTouchResult = TRUE;
|
|
|
|
PSSCTL_UPDATE_CTL_OBJ_PARA pPara = (PSSCTL_UPDATE_CTL_OBJ_PARA) pvPara;
|
|
FILETIME CurrentTime;
|
|
FILETIME UpdateTime;
|
|
PCCTL_CONTEXT pRetrieveCtl = NULL;
|
|
BOOL fTimeValid = FALSE;
|
|
BOOL fNewerCtl = FALSE;
|
|
PCRYPT_URL_ARRAY pNextUpdateUrlArray;
|
|
|
|
if (!pSSCtlObject->HasNextUpdateUrl(&UpdateTime))
|
|
return TRUE;
|
|
|
|
pPara->pCallContext->CurrentTime(&CurrentTime);
|
|
|
|
if (0 < CompareFileTime(&UpdateTime, &CurrentTime))
|
|
goto CommonReturn;
|
|
|
|
pRetrieveCtl = CertDuplicateCTLContext(pSSCtlObject->CtlContext());
|
|
pNextUpdateUrlArray = pSSCtlObject->NextUpdateUrlArray();
|
|
|
|
SSCtlRetrieveCtlUrl(
|
|
pPara->pChainEngine,
|
|
pPara->pCallContext,
|
|
pNextUpdateUrlArray,
|
|
CRYPT_CACHE_ONLY_RETRIEVAL,
|
|
&pRetrieveCtl,
|
|
&fNewerCtl,
|
|
&fTimeValid
|
|
);
|
|
if (pPara->pCallContext->IsTouchedEngine()) {
|
|
fTouchResult = FALSE;
|
|
goto TouchedDuringUrlRetrieval;
|
|
}
|
|
|
|
if (!fTimeValid && pPara->pCallContext->IsOnline()) {
|
|
SSCtlRetrieveCtlUrl(
|
|
pPara->pChainEngine,
|
|
pPara->pCallContext,
|
|
pNextUpdateUrlArray,
|
|
CRYPT_WIRE_ONLY_RETRIEVAL,
|
|
&pRetrieveCtl,
|
|
&fNewerCtl,
|
|
&fTimeValid
|
|
);
|
|
if (pPara->pCallContext->IsTouchedEngine()) {
|
|
fTouchResult = FALSE;
|
|
goto TouchedDuringUrlRetrieval;
|
|
}
|
|
|
|
if (!fNewerCtl)
|
|
pSSCtlObject->SetOffline(&CurrentTime, &UpdateTime);
|
|
}
|
|
|
|
if (fNewerCtl) {
|
|
PSSCTL_UPDATE_CTL_OBJ_ENTRY pEntry;
|
|
|
|
pSSCtlObject->SetOnline();
|
|
|
|
pEntry = new SSCTL_UPDATE_CTL_OBJ_ENTRY;
|
|
if (NULL == pEntry)
|
|
goto OutOfMemory;
|
|
|
|
if (!SSCtlCreateCtlObject(
|
|
pPara->pChainEngine,
|
|
pRetrieveCtl,
|
|
FALSE, // fAdditionalStore
|
|
&pEntry->pSSCtlObjectAdd
|
|
)) {
|
|
delete pEntry;
|
|
goto CreateCtlObjectError;
|
|
}
|
|
|
|
pEntry->pSSCtlObjectRemove = pSSCtlObject;
|
|
pEntry->pNext = pPara->pEntry;
|
|
pPara->pEntry = pEntry;
|
|
|
|
}
|
|
|
|
CommonReturn:
|
|
if (!fNewerCtl) {
|
|
if (I_CryptIsZeroFileTime(&pPara->UpdateTime) ||
|
|
0 > CompareFileTime(&UpdateTime, &pPara->UpdateTime))
|
|
pPara->UpdateTime = UpdateTime;
|
|
}
|
|
|
|
if (pRetrieveCtl)
|
|
CertFreeCTLContext(pRetrieveCtl);
|
|
|
|
return fTouchResult;
|
|
|
|
ErrorReturn:
|
|
fNewerCtl = FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
|
|
TRACE_ERROR(CreateCtlObjectError)
|
|
SET_ERROR(TouchedDuringUrlRetrieval, ERROR_CAN_NOT_COMPLETE)
|
|
}
|