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.

1527 lines
42 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT Security
  4. // Copyright (C) Microsoft Corporation, 1997 - 1999
  5. //
  6. // File: ssctl.cpp
  7. //
  8. // Contents: Self Signed Certificate Trust List Subsystem used by the
  9. // Certificate Chaining Infrastructure for building complex
  10. // chains
  11. //
  12. // History: 11-Feb-98 kirtd Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <global.hxx>
  16. #include <dbgdef.h>
  17. //+-------------------------------------------------------------------------
  18. // Attempt to get and allocate the CTL NextUpdate location Url array.
  19. //--------------------------------------------------------------------------
  20. BOOL
  21. WINAPI
  22. SSCtlGetNextUpdateUrl(
  23. IN PCCTL_CONTEXT pCtl,
  24. OUT PCRYPT_URL_ARRAY *ppUrlArray
  25. )
  26. {
  27. BOOL fResult;
  28. PCRYPT_URL_ARRAY pUrlArray = NULL;
  29. DWORD cbUrlArray = 0;
  30. LPVOID apv[2];
  31. apv[0] = (LPVOID) pCtl;
  32. apv[1] = (LPVOID)(UINT_PTR)(0); // Signer Index
  33. if (!ChainGetObjectUrl(
  34. URL_OID_CTL_NEXT_UPDATE,
  35. apv,
  36. 0, // dwFlags
  37. NULL, // pUrlArray
  38. &cbUrlArray,
  39. NULL, // pUrlInfo
  40. NULL, // cbUrlInfo,
  41. NULL // pvReserved
  42. ))
  43. goto GetObjectUrlError;
  44. pUrlArray = (PCRYPT_URL_ARRAY) new BYTE [cbUrlArray];
  45. if (NULL == pUrlArray)
  46. goto OutOfMemory;
  47. if (!ChainGetObjectUrl(
  48. URL_OID_CTL_NEXT_UPDATE,
  49. apv,
  50. 0, // dwFlags
  51. pUrlArray,
  52. &cbUrlArray,
  53. NULL, // pUrlInfo
  54. NULL, // cbUrlInfo,
  55. NULL // pvReserved
  56. ))
  57. goto GetObjectUrlError;
  58. if (0 == pUrlArray->cUrl)
  59. goto NoNextUpdateUrls;
  60. fResult = TRUE;
  61. CommonReturn:
  62. *ppUrlArray = pUrlArray;
  63. return fResult;
  64. ErrorReturn:
  65. if (pUrlArray) {
  66. delete (LPBYTE) pUrlArray;
  67. pUrlArray = NULL;
  68. }
  69. fResult = FALSE;
  70. goto CommonReturn;
  71. TRACE_ERROR(GetObjectUrlError)
  72. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  73. SET_ERROR(NoNextUpdateUrls, CRYPT_E_NOT_FOUND)
  74. }
  75. //+---------------------------------------------------------------------------
  76. //
  77. // Member: CSSCtlObject::CSSCtlObject, public
  78. //
  79. // Synopsis: Constructor
  80. //
  81. //----------------------------------------------------------------------------
  82. CSSCtlObject::CSSCtlObject (
  83. IN PCCERTCHAINENGINE pChainEngine,
  84. IN PCCTL_CONTEXT pCtlContext,
  85. IN BOOL fAdditionalStore,
  86. OUT BOOL& rfResult
  87. )
  88. {
  89. DWORD cbData;
  90. CRYPT_DATA_BLOB DataBlob;
  91. rfResult = TRUE;
  92. m_cRefs = 1;
  93. m_pCtlContext = CertDuplicateCTLContext( pCtlContext );
  94. m_fHasSignatureBeenVerified = FALSE;
  95. m_fSignatureValid = FALSE;
  96. m_hMessageStore = NULL;
  97. m_hHashEntry = NULL;
  98. m_pChainEngine = pChainEngine;
  99. m_pNextUpdateUrlArray = NULL;
  100. m_dwOfflineCnt = 0;
  101. I_CryptZeroFileTime(&m_OfflineUpdateTime);
  102. memset( &m_SignerInfo, 0, sizeof( m_SignerInfo ) );
  103. cbData = CHAINHASHLEN;
  104. rfResult = CertGetCTLContextProperty(
  105. pCtlContext,
  106. CERT_MD5_HASH_PROP_ID,
  107. m_rgbCtlHash,
  108. &cbData
  109. );
  110. if ( rfResult && CHAINHASHLEN != cbData)
  111. {
  112. rfResult = FALSE;
  113. SetLastError( (DWORD) E_UNEXPECTED);
  114. }
  115. if (!fAdditionalStore)
  116. {
  117. if ( rfResult == TRUE )
  118. {
  119. DataBlob.cbData = CHAINHASHLEN;
  120. DataBlob.pbData = m_rgbCtlHash;
  121. rfResult = I_CryptCreateLruEntry(
  122. pChainEngine->SSCtlObjectCache()->HashIndex(),
  123. &DataBlob,
  124. this,
  125. &m_hHashEntry
  126. );
  127. }
  128. if ( rfResult == TRUE )
  129. {
  130. m_hMessageStore = CertOpenStore(
  131. CERT_STORE_PROV_MSG,
  132. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  133. NULL,
  134. 0,
  135. pCtlContext->hCryptMsg
  136. );
  137. if ( m_hMessageStore == NULL )
  138. {
  139. rfResult = FALSE;
  140. }
  141. }
  142. }
  143. if ( rfResult == TRUE )
  144. {
  145. rfResult = SSCtlGetSignerInfo( pCtlContext, &m_SignerInfo );
  146. }
  147. if (!fAdditionalStore)
  148. {
  149. if ( rfResult == TRUE )
  150. {
  151. if (!I_CryptIsZeroFileTime(&m_pCtlContext->pCtlInfo->NextUpdate))
  152. {
  153. // Ignore any errors
  154. SSCtlGetNextUpdateUrl(m_pCtlContext, &m_pNextUpdateUrlArray);
  155. }
  156. }
  157. }
  158. assert( m_pChainEngine != NULL );
  159. assert( m_pCtlContext != NULL );
  160. }
  161. //+---------------------------------------------------------------------------
  162. //
  163. // Member: CSSCtlObject::~CSSCtlObject, public
  164. //
  165. // Synopsis: Destructor
  166. //
  167. //----------------------------------------------------------------------------
  168. CSSCtlObject::~CSSCtlObject ()
  169. {
  170. SSCtlFreeSignerInfo( &m_SignerInfo );
  171. if ( m_hMessageStore != NULL )
  172. {
  173. CertCloseStore( m_hMessageStore, 0 );
  174. }
  175. if ( m_pNextUpdateUrlArray != NULL )
  176. {
  177. delete (LPBYTE) m_pNextUpdateUrlArray;
  178. }
  179. if ( m_hHashEntry != NULL )
  180. {
  181. I_CryptReleaseLruEntry( m_hHashEntry );
  182. }
  183. CertFreeCTLContext( m_pCtlContext );
  184. }
  185. //+---------------------------------------------------------------------------
  186. //
  187. // Member: CSSCtlObject::GetSigner, public
  188. //
  189. // Synopsis: get the certificate object of the signer
  190. //
  191. //----------------------------------------------------------------------------
  192. BOOL
  193. CSSCtlObject::GetSigner (
  194. IN PCCHAINPATHOBJECT pSubject,
  195. IN PCCHAINCALLCONTEXT pCallContext,
  196. IN HCERTSTORE hAdditionalStore,
  197. OUT PCCHAINPATHOBJECT* ppSigner,
  198. OUT BOOL* pfCtlSignatureValid
  199. )
  200. {
  201. BOOL fResult;
  202. PCCHAINPATHOBJECT pSigner = NULL;
  203. BOOL fNewSigner = TRUE;
  204. fResult = SSCtlGetSignerChainPathObject(
  205. pSubject,
  206. pCallContext,
  207. &m_SignerInfo,
  208. hAdditionalStore,
  209. &pSigner,
  210. &fNewSigner
  211. );
  212. if (fResult)
  213. {
  214. if ( !m_fHasSignatureBeenVerified || fNewSigner )
  215. {
  216. CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA CtrlPara;
  217. memset(&CtrlPara, 0, sizeof(CtrlPara));
  218. CtrlPara.cbSize = sizeof(CtrlPara);
  219. // CtrlPara.hCryptProv =
  220. // This needs to be updated when chain building
  221. // supports CTLs with more than one signer.
  222. CtrlPara.dwSignerIndex = 0;
  223. CtrlPara.dwSignerType = CMSG_VERIFY_SIGNER_CERT;
  224. CtrlPara.pvSigner = (void *) pSigner->CertObject()->CertContext();
  225. m_fSignatureValid = CryptMsgControl(
  226. m_pCtlContext->hCryptMsg,
  227. 0,
  228. CMSG_CTRL_VERIFY_SIGNATURE_EX,
  229. &CtrlPara
  230. );
  231. m_fHasSignatureBeenVerified = TRUE;
  232. CertPerfIncrementChainVerifyCtlSignatureCount();
  233. }
  234. else
  235. {
  236. CertPerfIncrementChainBeenVerifiedCtlSignatureCount();
  237. }
  238. *ppSigner = pSigner;
  239. }
  240. *pfCtlSignatureValid = m_fSignatureValid;
  241. return fResult;
  242. }
  243. //+---------------------------------------------------------------------------
  244. //
  245. // Member: CSSCtlObject::GetTrustListInfo, public
  246. //
  247. // Synopsis: get the trust list information relative to a particular cert
  248. // object
  249. //
  250. //----------------------------------------------------------------------------
  251. BOOL
  252. CSSCtlObject::GetTrustListInfo (
  253. IN PCCERT_CONTEXT pCertContext,
  254. OUT PCERT_TRUST_LIST_INFO* ppTrustListInfo
  255. )
  256. {
  257. PCTL_ENTRY pCtlEntry;
  258. PCERT_TRUST_LIST_INFO pTrustListInfo;
  259. pCtlEntry = CertFindSubjectInCTL(
  260. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  261. CTL_CERT_SUBJECT_TYPE,
  262. (LPVOID)pCertContext,
  263. m_pCtlContext,
  264. 0
  265. );
  266. if ( pCtlEntry == NULL )
  267. {
  268. SetLastError( (DWORD) CRYPT_E_NOT_FOUND );
  269. return( FALSE );
  270. }
  271. pTrustListInfo = new CERT_TRUST_LIST_INFO;
  272. if ( pTrustListInfo == NULL )
  273. {
  274. SetLastError( (DWORD) E_OUTOFMEMORY );
  275. return( FALSE );
  276. }
  277. pTrustListInfo->cbSize = sizeof( CERT_TRUST_LIST_INFO );
  278. pTrustListInfo->pCtlEntry = pCtlEntry;
  279. pTrustListInfo->pCtlContext = CertDuplicateCTLContext( m_pCtlContext );
  280. *ppTrustListInfo = pTrustListInfo;
  281. return( TRUE );
  282. }
  283. //+---------------------------------------------------------------------------
  284. //
  285. // Member: CSSCtlObject::CalculateStatus, public
  286. //
  287. // Synopsis: calculate the status
  288. //
  289. //----------------------------------------------------------------------------
  290. VOID
  291. CSSCtlObject::CalculateStatus (
  292. IN LPFILETIME pTime,
  293. IN PCERT_USAGE_MATCH pRequestedUsage,
  294. IN OUT PCERT_TRUST_STATUS pStatus
  295. )
  296. {
  297. assert( m_fHasSignatureBeenVerified == TRUE );
  298. SSCtlGetCtlTrustStatus(
  299. m_pCtlContext,
  300. m_fSignatureValid,
  301. pTime,
  302. pRequestedUsage,
  303. pStatus
  304. );
  305. }
  306. //+---------------------------------------------------------------------------
  307. //
  308. // Member: CSSCtlObject::HasNextUpdateUrl, public
  309. //
  310. // Synopsis: returns TRUE if the Ctl has a NextUpdate time and location Url
  311. //
  312. //----------------------------------------------------------------------------
  313. BOOL CSSCtlObject::HasNextUpdateUrl (
  314. OUT LPFILETIME pUpdateTime
  315. )
  316. {
  317. if ( m_pNextUpdateUrlArray != NULL )
  318. {
  319. assert(!I_CryptIsZeroFileTime(&m_pCtlContext->pCtlInfo->NextUpdate));
  320. if (0 != m_dwOfflineCnt) {
  321. assert(!I_CryptIsZeroFileTime(&m_OfflineUpdateTime));
  322. *pUpdateTime = m_OfflineUpdateTime;
  323. } else
  324. *pUpdateTime = m_pCtlContext->pCtlInfo->NextUpdate;
  325. return TRUE;
  326. }
  327. else
  328. {
  329. return FALSE;
  330. }
  331. }
  332. //+---------------------------------------------------------------------------
  333. //
  334. // Member: CSSCtlObject::SetOffline, public
  335. //
  336. // Synopsis: called when offline
  337. //
  338. //----------------------------------------------------------------------------
  339. void CSSCtlObject::SetOffline (
  340. IN LPFILETIME pCurrentTime,
  341. OUT LPFILETIME pUpdateTime
  342. )
  343. {
  344. m_dwOfflineCnt++;
  345. I_CryptIncrementFileTimeBySeconds(
  346. pCurrentTime,
  347. ChainGetOfflineUrlDeltaSeconds(m_dwOfflineCnt),
  348. &m_OfflineUpdateTime
  349. );
  350. *pUpdateTime = m_OfflineUpdateTime;
  351. }
  352. //+---------------------------------------------------------------------------
  353. //
  354. // Member: CSSCtlObjectCache::CSSCtlObjectCache, public
  355. //
  356. // Synopsis: Constructor
  357. //
  358. //----------------------------------------------------------------------------
  359. CSSCtlObjectCache::CSSCtlObjectCache (
  360. OUT BOOL& rfResult
  361. )
  362. {
  363. LRU_CACHE_CONFIG Config;
  364. memset( &Config, 0, sizeof( Config ) );
  365. Config.dwFlags = LRU_CACHE_NO_SERIALIZE | LRU_CACHE_NO_COPY_IDENTIFIER;
  366. Config.pfnHash = CertObjectCacheHashMd5Identifier;
  367. Config.cBuckets = DEFAULT_CERT_OBJECT_CACHE_BUCKETS;
  368. Config.pfnOnRemoval = SSCtlOnRemovalFromCache;
  369. m_hHashIndex = NULL;
  370. rfResult = I_CryptCreateLruCache( &Config, &m_hHashIndex );
  371. I_CryptZeroFileTime(&m_UpdateTime);
  372. m_fFirstUpdate = FALSE;
  373. }
  374. //+---------------------------------------------------------------------------
  375. //
  376. // Member: CSSCtlObjectCache::~CSSCtlObjectCache, public
  377. //
  378. // Synopsis: Destructor
  379. //
  380. //----------------------------------------------------------------------------
  381. CSSCtlObjectCache::~CSSCtlObjectCache ()
  382. {
  383. I_CryptFreeLruCache( m_hHashIndex, 0, NULL );
  384. }
  385. //+---------------------------------------------------------------------------
  386. //
  387. // Member: CSSCtlObjectCache::PopulateCache, public
  388. //
  389. // Synopsis: populate the cache
  390. //
  391. //----------------------------------------------------------------------------
  392. BOOL
  393. CSSCtlObjectCache::PopulateCache (
  394. IN PCCERTCHAINENGINE pChainEngine
  395. )
  396. {
  397. assert( pChainEngine->SSCtlObjectCache() == this );
  398. return( SSCtlPopulateCacheFromCertStore( pChainEngine, NULL ) );
  399. }
  400. //+---------------------------------------------------------------------------
  401. //
  402. // Member: CSSCtlObjectCache::AddObject, public
  403. //
  404. // Synopsis: add an object to the cache
  405. //
  406. //----------------------------------------------------------------------------
  407. BOOL
  408. CSSCtlObjectCache::AddObject (
  409. IN PCSSCTLOBJECT pSSCtlObject,
  410. IN BOOL fCheckForDuplicate
  411. )
  412. {
  413. FILETIME UpdateTime;
  414. if ( fCheckForDuplicate == TRUE )
  415. {
  416. PCSSCTLOBJECT pDuplicate;
  417. pDuplicate = FindObjectByHash( pSSCtlObject->CtlHash() );
  418. if ( pDuplicate != NULL )
  419. {
  420. pDuplicate->Release();
  421. SetLastError( (DWORD) CRYPT_E_EXISTS );
  422. return( FALSE );
  423. }
  424. }
  425. pSSCtlObject->AddRef();
  426. if (pSSCtlObject->HasNextUpdateUrl(&UpdateTime))
  427. {
  428. // Set earliest update time
  429. if (I_CryptIsZeroFileTime(&m_UpdateTime) ||
  430. 0 > CompareFileTime(&UpdateTime, &m_UpdateTime))
  431. {
  432. m_UpdateTime = UpdateTime;
  433. }
  434. m_fFirstUpdate = TRUE;
  435. }
  436. I_CryptInsertLruEntry( pSSCtlObject->HashIndexEntry(), NULL );
  437. if (pSSCtlObject->MessageStore() )
  438. {
  439. CertAddStoreToCollection(
  440. pSSCtlObject->ChainEngine()->OtherStore(),
  441. pSSCtlObject->MessageStore(),
  442. 0,
  443. 0
  444. );
  445. }
  446. CertPerfIncrementChainCtlCacheCount();
  447. return( TRUE );
  448. }
  449. //+---------------------------------------------------------------------------
  450. //
  451. // Member: CSSCtlObjectCache::RemoveObject, public
  452. //
  453. // Synopsis: remove object from cache
  454. //
  455. //----------------------------------------------------------------------------
  456. VOID
  457. CSSCtlObjectCache::RemoveObject (
  458. IN PCSSCTLOBJECT pSSCtlObject
  459. )
  460. {
  461. I_CryptRemoveLruEntry( pSSCtlObject->HashIndexEntry(), 0, NULL );
  462. }
  463. //+---------------------------------------------------------------------------
  464. //
  465. // Member: CSSCtlObjectCache::FindObjectByHash, public
  466. //
  467. // Synopsis: find object with given hash
  468. //
  469. //----------------------------------------------------------------------------
  470. PCSSCTLOBJECT
  471. CSSCtlObjectCache::FindObjectByHash (
  472. IN BYTE rgbHash [ CHAINHASHLEN ]
  473. )
  474. {
  475. HLRUENTRY hFound;
  476. PCSSCTLOBJECT pFound = NULL;
  477. CRYPT_HASH_BLOB HashBlob;
  478. HashBlob.cbData = CHAINHASHLEN;
  479. HashBlob.pbData = rgbHash;
  480. hFound = I_CryptFindLruEntry( m_hHashIndex, &HashBlob );
  481. if ( hFound != NULL )
  482. {
  483. pFound = (PCSSCTLOBJECT)I_CryptGetLruEntryData( hFound );
  484. pFound->AddRef();
  485. I_CryptReleaseLruEntry( hFound );
  486. }
  487. return( pFound );
  488. }
  489. //+---------------------------------------------------------------------------
  490. //
  491. // Member: CSSCtlObjectCache::EnumObjects, public
  492. //
  493. // Synopsis: enumerate objects
  494. //
  495. //----------------------------------------------------------------------------
  496. VOID
  497. CSSCtlObjectCache::EnumObjects (
  498. IN PFN_ENUM_SSCTLOBJECTS pfnEnum,
  499. IN LPVOID pvParameter
  500. )
  501. {
  502. SSCTL_ENUM_OBJECTS_DATA EnumData;
  503. EnumData.pfnEnumObjects = pfnEnum;
  504. EnumData.pvEnumParameter = pvParameter;
  505. I_CryptWalkAllLruCacheEntries(
  506. m_hHashIndex,
  507. SSCtlEnumObjectsWalkFn,
  508. &EnumData
  509. );
  510. }
  511. //+---------------------------------------------------------------------------
  512. //
  513. // Member: CSSCtlObjectCache::Resync, public
  514. //
  515. // Synopsis: resync the cache
  516. //
  517. //----------------------------------------------------------------------------
  518. BOOL
  519. CSSCtlObjectCache::Resync (IN PCCERTCHAINENGINE pChainEngine)
  520. {
  521. I_CryptFlushLruCache( m_hHashIndex, 0, NULL );
  522. I_CryptZeroFileTime(&m_UpdateTime);
  523. m_fFirstUpdate = FALSE;
  524. return( PopulateCache( pChainEngine ) );
  525. }
  526. //+---------------------------------------------------------------------------
  527. //
  528. // Member: CSSCtlObjectCache::UpdateCache, public
  529. //
  530. // Synopsis: update the cache
  531. //
  532. // Leaves the engine's critical section to do the URL
  533. // fetching. If the engine was touched by another thread,
  534. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  535. //
  536. // If the CTL is updated, increments the engine's touch count
  537. // and flushes issuer and end cert object caches.
  538. //
  539. // Assumption: Chain engine is locked once in the calling thread.
  540. //
  541. //----------------------------------------------------------------------------
  542. BOOL
  543. CSSCtlObjectCache::UpdateCache (
  544. IN PCCERTCHAINENGINE pChainEngine,
  545. IN PCCHAINCALLCONTEXT pCallContext
  546. )
  547. {
  548. FILETIME CurrentTime;
  549. SSCTL_UPDATE_CTL_OBJ_PARA Para;
  550. assert( pChainEngine->SSCtlObjectCache() == this );
  551. // Check if we have any CTLs needing to be updated
  552. if (I_CryptIsZeroFileTime(&m_UpdateTime))
  553. return TRUE;
  554. pCallContext->CurrentTime(&CurrentTime);
  555. if (0 < CompareFileTime(&m_UpdateTime, &CurrentTime))
  556. return TRUE;
  557. if (!m_fFirstUpdate && !pCallContext->IsOnline())
  558. return TRUE;
  559. memset(&Para, 0, sizeof(Para));
  560. Para.pChainEngine = pChainEngine;
  561. Para.pCallContext = pCallContext;
  562. EnumObjects(SSCtlUpdateCtlObjectEnumFn, &Para);
  563. if (pCallContext->IsTouchedEngine()) {
  564. PSSCTL_UPDATE_CTL_OBJ_ENTRY pEntry;
  565. pEntry = Para.pEntry;
  566. while (pEntry) {
  567. PSSCTL_UPDATE_CTL_OBJ_ENTRY pDeleteEntry;
  568. pEntry->pSSCtlObjectAdd->Release();
  569. pDeleteEntry = pEntry;
  570. pEntry = pEntry->pNext;
  571. delete pDeleteEntry;
  572. }
  573. return FALSE;
  574. }
  575. m_UpdateTime = Para.UpdateTime;
  576. m_fFirstUpdate = FALSE;
  577. if (Para.pEntry) {
  578. HCERTSTORE hTrustStore;
  579. PSSCTL_UPDATE_CTL_OBJ_ENTRY pEntry;
  580. hTrustStore = pChainEngine->OpenTrustStore();
  581. pChainEngine->CertObjectCache()->FlushObjects( pCallContext );
  582. pCallContext->TouchEngine();
  583. pEntry = Para.pEntry;
  584. while (pEntry) {
  585. PSSCTL_UPDATE_CTL_OBJ_ENTRY pDeleteEntry;
  586. RemoveObject(pEntry->pSSCtlObjectRemove);
  587. if (AddObject(pEntry->pSSCtlObjectAdd, TRUE)) {
  588. if (hTrustStore) {
  589. // Persist the newer CTL to the trust store
  590. CertAddCTLContextToStore(
  591. hTrustStore,
  592. pEntry->pSSCtlObjectAdd->CtlContext(),
  593. CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES,
  594. NULL
  595. );
  596. }
  597. }
  598. pEntry->pSSCtlObjectAdd->Release();
  599. pDeleteEntry = pEntry;
  600. pEntry = pEntry->pNext;
  601. delete pDeleteEntry;
  602. }
  603. if (hTrustStore)
  604. CertCloseStore(hTrustStore, 0);
  605. }
  606. return TRUE;
  607. }
  608. //+---------------------------------------------------------------------------
  609. //
  610. // Function: SSCtlOnRemovalFromCache
  611. //
  612. // Synopsis: SS CTL removal notification used when the cache is destroyed
  613. // or an object is explicitly removed. Note that this cache
  614. // does not LRU remove objects
  615. //
  616. //----------------------------------------------------------------------------
  617. VOID WINAPI
  618. SSCtlOnRemovalFromCache (
  619. IN LPVOID pv,
  620. IN OPTIONAL LPVOID pvRemovalContext
  621. )
  622. {
  623. PCSSCTLOBJECT pSSCtlObject = (PCSSCTLOBJECT) pv;
  624. CertPerfDecrementChainCtlCacheCount();
  625. assert( pvRemovalContext == NULL );
  626. if (pSSCtlObject->MessageStore() )
  627. {
  628. CertRemoveStoreFromCollection(
  629. pSSCtlObject->ChainEngine()->OtherStore(),
  630. pSSCtlObject->MessageStore()
  631. );
  632. }
  633. pSSCtlObject->Release();
  634. }
  635. //+---------------------------------------------------------------------------
  636. //
  637. // Function: SSCtlGetSignerInfo
  638. //
  639. // Synopsis: get the signer info
  640. //
  641. //----------------------------------------------------------------------------
  642. BOOL WINAPI
  643. SSCtlGetSignerInfo (
  644. IN PCCTL_CONTEXT pCtlContext,
  645. OUT PSSCTL_SIGNER_INFO pSignerInfo
  646. )
  647. {
  648. BOOL fResult;
  649. PCERT_INFO pMessageSignerCertInfo = NULL;
  650. DWORD cbData = 0;
  651. fResult = CryptMsgGetParam(
  652. pCtlContext->hCryptMsg,
  653. CMSG_SIGNER_CERT_INFO_PARAM,
  654. 0,
  655. NULL,
  656. &cbData
  657. );
  658. if ( fResult == TRUE )
  659. {
  660. pMessageSignerCertInfo = (PCERT_INFO)new BYTE [ cbData ];
  661. if ( pMessageSignerCertInfo != NULL )
  662. {
  663. fResult = CryptMsgGetParam(
  664. pCtlContext->hCryptMsg,
  665. CMSG_SIGNER_CERT_INFO_PARAM,
  666. 0,
  667. pMessageSignerCertInfo,
  668. &cbData
  669. );
  670. }
  671. else
  672. {
  673. SetLastError( (DWORD) E_OUTOFMEMORY );
  674. fResult = FALSE;
  675. }
  676. }
  677. if ( fResult == TRUE )
  678. {
  679. pSignerInfo->pMessageSignerCertInfo = pMessageSignerCertInfo;
  680. pSignerInfo->fSignerHashAvailable = FALSE;
  681. }
  682. else
  683. {
  684. delete pMessageSignerCertInfo;
  685. }
  686. return( fResult );
  687. }
  688. //+---------------------------------------------------------------------------
  689. //
  690. // Function: SSCtlFreeSignerInfo
  691. //
  692. // Synopsis: free the data in the signer info
  693. //
  694. //----------------------------------------------------------------------------
  695. VOID WINAPI
  696. SSCtlFreeSignerInfo (
  697. IN PSSCTL_SIGNER_INFO pSignerInfo
  698. )
  699. {
  700. delete (LPBYTE)pSignerInfo->pMessageSignerCertInfo;
  701. }
  702. //+---------------------------------------------------------------------------
  703. //
  704. // Function: SSCtlGetSignerChainPathObject
  705. //
  706. // Synopsis: get the signer chain path object
  707. //
  708. //----------------------------------------------------------------------------
  709. BOOL WINAPI
  710. SSCtlGetSignerChainPathObject (
  711. IN PCCHAINPATHOBJECT pSubject,
  712. IN PCCHAINCALLCONTEXT pCallContext,
  713. IN PSSCTL_SIGNER_INFO pSignerInfo,
  714. IN HCERTSTORE hAdditionalStore,
  715. OUT PCCHAINPATHOBJECT* ppSigner,
  716. OUT BOOL *pfNewSigner
  717. )
  718. {
  719. BOOL fResult = TRUE;
  720. PCCERTCHAINENGINE pChainEngine = pSubject->CertObject()->ChainEngine();
  721. PCCERTOBJECTCACHE pCertObjectCache = pChainEngine->CertObjectCache();
  722. PCCERTOBJECT pCertObject = NULL;
  723. PCCERT_CONTEXT pCertContext = NULL;
  724. PCCHAINPATHOBJECT pSigner = NULL;
  725. BOOL fAdditionalStoreUsed = FALSE;
  726. BYTE rgbCertHash[ CHAINHASHLEN ];
  727. *pfNewSigner = FALSE;
  728. if ( pSignerInfo->fSignerHashAvailable == TRUE )
  729. {
  730. pCertObject = pCertObjectCache->FindIssuerObjectByHash(
  731. pSignerInfo->rgbSignerCertHash );
  732. }
  733. if ( pCertObject == NULL )
  734. {
  735. if ( pSignerInfo->fSignerHashAvailable == TRUE )
  736. {
  737. pCertContext = SSCtlFindCertificateInStoreByHash(
  738. pChainEngine->OtherStore(),
  739. pSignerInfo->rgbSignerCertHash
  740. );
  741. if ( ( pCertContext == NULL ) && ( hAdditionalStore != NULL ) )
  742. {
  743. fAdditionalStoreUsed = TRUE;
  744. pCertContext = SSCtlFindCertificateInStoreByHash(
  745. hAdditionalStore,
  746. pSignerInfo->rgbSignerCertHash
  747. );
  748. }
  749. }
  750. if ( pCertContext == NULL )
  751. {
  752. *pfNewSigner = TRUE;
  753. fAdditionalStoreUsed = FALSE;
  754. pCertContext = CertGetSubjectCertificateFromStore(
  755. pChainEngine->OtherStore(),
  756. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  757. pSignerInfo->pMessageSignerCertInfo
  758. );
  759. }
  760. if ( ( pCertContext == NULL ) && ( hAdditionalStore != NULL ) )
  761. {
  762. fAdditionalStoreUsed = TRUE;
  763. pCertContext = CertGetSubjectCertificateFromStore(
  764. hAdditionalStore,
  765. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  766. pSignerInfo->pMessageSignerCertInfo
  767. );
  768. }
  769. if ( pCertContext != NULL )
  770. {
  771. DWORD cbData = CHAINHASHLEN;
  772. fResult = CertGetCertificateContextProperty(
  773. pCertContext,
  774. CERT_MD5_HASH_PROP_ID,
  775. rgbCertHash,
  776. &cbData
  777. );
  778. if ( fResult && CHAINHASHLEN != cbData)
  779. {
  780. fResult = FALSE;
  781. SetLastError( (DWORD) E_UNEXPECTED);
  782. }
  783. if ( fResult == TRUE )
  784. {
  785. fResult = ChainCreateCertObject (
  786. fAdditionalStoreUsed ?
  787. CERT_EXTERNAL_ISSUER_OBJECT_TYPE :
  788. CERT_CACHED_ISSUER_OBJECT_TYPE,
  789. pCallContext,
  790. pCertContext,
  791. rgbCertHash,
  792. &pCertObject
  793. );
  794. }
  795. CertFreeCertificateContext( pCertContext );
  796. }
  797. else
  798. {
  799. fResult = FALSE;
  800. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  801. }
  802. }
  803. if ( fResult )
  804. {
  805. assert(pCertObject);
  806. fResult = ChainCreatePathObject(
  807. pCallContext,
  808. pCertObject,
  809. hAdditionalStore,
  810. &pSigner
  811. );
  812. }
  813. if ( fResult )
  814. {
  815. assert(pSigner);
  816. if ( !pSignerInfo->fSignerHashAvailable || *pfNewSigner )
  817. {
  818. memcpy(
  819. pSignerInfo->rgbSignerCertHash,
  820. rgbCertHash,
  821. CHAINHASHLEN
  822. );
  823. pSignerInfo->fSignerHashAvailable = TRUE;
  824. }
  825. }
  826. if ( pCertObject != NULL )
  827. {
  828. pCertObject->Release();
  829. }
  830. *ppSigner = pSigner;
  831. return( fResult );
  832. }
  833. //+---------------------------------------------------------------------------
  834. //
  835. // Function: SSCtlFindCertificateInStoreByHash
  836. //
  837. // Synopsis: find certificate in store by hash
  838. //
  839. //----------------------------------------------------------------------------
  840. PCCERT_CONTEXT WINAPI
  841. SSCtlFindCertificateInStoreByHash (
  842. IN HCERTSTORE hStore,
  843. IN BYTE rgbHash [ CHAINHASHLEN]
  844. )
  845. {
  846. CRYPT_HASH_BLOB HashBlob;
  847. HashBlob.cbData = CHAINHASHLEN;
  848. HashBlob.pbData = rgbHash;
  849. return( CertFindCertificateInStore(
  850. hStore,
  851. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  852. 0,
  853. CERT_FIND_MD5_HASH,
  854. &HashBlob,
  855. NULL
  856. ) );
  857. }
  858. //+---------------------------------------------------------------------------
  859. //
  860. // Function: SSCtlGetCtlTrustStatus
  861. //
  862. // Synopsis: get the trust status for the CTL
  863. //
  864. //----------------------------------------------------------------------------
  865. VOID WINAPI
  866. SSCtlGetCtlTrustStatus (
  867. IN PCCTL_CONTEXT pCtlContext,
  868. IN BOOL fSignatureValid,
  869. IN LPFILETIME pTime,
  870. IN PCERT_USAGE_MATCH pRequestedUsage,
  871. IN OUT PCERT_TRUST_STATUS pStatus
  872. )
  873. {
  874. FILETIME NoTime;
  875. CERT_TRUST_STATUS UsageStatus;
  876. memset( &NoTime, 0, sizeof( NoTime ) );
  877. if ( fSignatureValid == FALSE )
  878. {
  879. pStatus->dwErrorStatus |= CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID;
  880. }
  881. if ( ( CompareFileTime(
  882. pTime,
  883. &pCtlContext->pCtlInfo->ThisUpdate
  884. ) < 0 ) ||
  885. ( ( ( CompareFileTime(
  886. &NoTime,
  887. &pCtlContext->pCtlInfo->NextUpdate
  888. ) != 0 ) &&
  889. ( CompareFileTime(
  890. pTime,
  891. &pCtlContext->pCtlInfo->NextUpdate
  892. ) > 0 ) ) ) )
  893. {
  894. pStatus->dwErrorStatus |= CERT_TRUST_CTL_IS_NOT_TIME_VALID;
  895. }
  896. memset( &UsageStatus, 0, sizeof( UsageStatus ) );
  897. ChainGetUsageStatus(
  898. (PCERT_ENHKEY_USAGE)&pRequestedUsage->Usage,
  899. (PCERT_ENHKEY_USAGE)&pCtlContext->pCtlInfo->SubjectUsage,
  900. pRequestedUsage->dwType,
  901. &UsageStatus
  902. );
  903. if ( UsageStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE )
  904. {
  905. pStatus->dwErrorStatus |= CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
  906. }
  907. }
  908. //+---------------------------------------------------------------------------
  909. //
  910. // Function: SSCtlPopulateCacheFromCertStore
  911. //
  912. // Synopsis: populate the SS CTL object cache from certificate store CTLs
  913. //
  914. //----------------------------------------------------------------------------
  915. BOOL WINAPI
  916. SSCtlPopulateCacheFromCertStore (
  917. IN PCCERTCHAINENGINE pChainEngine,
  918. IN OPTIONAL HCERTSTORE hStore
  919. )
  920. {
  921. BOOL fResult;
  922. BOOL fAdditionalStore = TRUE;
  923. PCCTL_CONTEXT pCtlContext = NULL;
  924. BYTE rgbCtlHash[ CHAINHASHLEN ];
  925. PCSSCTLOBJECT pSSCtlObject;
  926. PCSSCTLOBJECTCACHE pSSCtlObjectCache;
  927. pSSCtlObjectCache = pChainEngine->SSCtlObjectCache();
  928. if ( hStore == NULL )
  929. {
  930. hStore = pChainEngine->TrustStore();
  931. fAdditionalStore = FALSE;
  932. }
  933. while ( ( pCtlContext = CertEnumCTLsInStore(
  934. hStore,
  935. pCtlContext
  936. ) ) != NULL )
  937. {
  938. DWORD cbData = CHAINHASHLEN;
  939. fResult = CertGetCTLContextProperty(
  940. pCtlContext,
  941. CERT_MD5_HASH_PROP_ID,
  942. rgbCtlHash,
  943. &cbData
  944. );
  945. if ( fResult && CHAINHASHLEN != cbData)
  946. {
  947. fResult = FALSE;
  948. SetLastError( (DWORD) E_UNEXPECTED);
  949. }
  950. if ( fResult == TRUE )
  951. {
  952. pSSCtlObject = pSSCtlObjectCache->FindObjectByHash( rgbCtlHash );
  953. if ( pSSCtlObject == NULL )
  954. {
  955. fResult = SSCtlCreateCtlObject(
  956. pChainEngine,
  957. pCtlContext,
  958. FALSE, // fAdditionalStore
  959. &pSSCtlObject
  960. );
  961. }
  962. else
  963. {
  964. pSSCtlObject->Release();
  965. fResult = FALSE;
  966. }
  967. if ( fResult == TRUE )
  968. {
  969. fResult = pSSCtlObjectCache->AddObject( pSSCtlObject, FALSE );
  970. // NOTE: Since fDuplicate == FALSE this should never fail
  971. assert( fResult == TRUE );
  972. pSSCtlObject->Release();
  973. }
  974. }
  975. }
  976. return( TRUE );
  977. }
  978. //+---------------------------------------------------------------------------
  979. //
  980. // Function: SSCtlCreateCtlObject
  981. //
  982. // Synopsis: create an SS CTL Object
  983. //
  984. //----------------------------------------------------------------------------
  985. BOOL WINAPI
  986. SSCtlCreateCtlObject (
  987. IN PCCERTCHAINENGINE pChainEngine,
  988. IN PCCTL_CONTEXT pCtlContext,
  989. IN BOOL fAdditionalStore,
  990. OUT PCSSCTLOBJECT* ppSSCtlObject
  991. )
  992. {
  993. BOOL fResult = TRUE;
  994. PCSSCTLOBJECT pSSCtlObject;
  995. pSSCtlObject = new CSSCtlObject(
  996. pChainEngine, pCtlContext, fAdditionalStore, fResult );
  997. if ( pSSCtlObject == NULL )
  998. {
  999. SetLastError( (DWORD) E_OUTOFMEMORY );
  1000. fResult = FALSE;
  1001. }
  1002. else if ( fResult == TRUE )
  1003. {
  1004. *ppSSCtlObject = pSSCtlObject;
  1005. }
  1006. else
  1007. {
  1008. delete pSSCtlObject;
  1009. }
  1010. return( fResult );
  1011. }
  1012. //+---------------------------------------------------------------------------
  1013. //
  1014. // Function: SSCtlEnumObjectsWalkFn
  1015. //
  1016. // Synopsis: object enumerator walk function
  1017. //
  1018. //----------------------------------------------------------------------------
  1019. BOOL WINAPI
  1020. SSCtlEnumObjectsWalkFn (
  1021. IN LPVOID pvParameter,
  1022. IN HLRUENTRY hEntry
  1023. )
  1024. {
  1025. PSSCTL_ENUM_OBJECTS_DATA pEnumData = (PSSCTL_ENUM_OBJECTS_DATA)pvParameter;
  1026. return( ( *pEnumData->pfnEnumObjects )(
  1027. pEnumData->pvEnumParameter,
  1028. (PCSSCTLOBJECT)I_CryptGetLruEntryData( hEntry )
  1029. ) );
  1030. }
  1031. //+---------------------------------------------------------------------------
  1032. //
  1033. // Function: SSCtlCreateObjectCache
  1034. //
  1035. // Synopsis: create the SS CTL object cache
  1036. //
  1037. //----------------------------------------------------------------------------
  1038. BOOL WINAPI
  1039. SSCtlCreateObjectCache (
  1040. OUT PCSSCTLOBJECTCACHE* ppSSCtlObjectCache
  1041. )
  1042. {
  1043. BOOL fResult = TRUE;
  1044. PCSSCTLOBJECTCACHE pSSCtlObjectCache;
  1045. pSSCtlObjectCache = new CSSCtlObjectCache( fResult );
  1046. if ( pSSCtlObjectCache == NULL )
  1047. {
  1048. SetLastError( (DWORD) E_OUTOFMEMORY );
  1049. fResult = FALSE;
  1050. }
  1051. else if ( fResult == TRUE )
  1052. {
  1053. *ppSSCtlObjectCache = pSSCtlObjectCache;
  1054. }
  1055. else
  1056. {
  1057. delete pSSCtlObjectCache;
  1058. }
  1059. return( fResult );
  1060. }
  1061. //+---------------------------------------------------------------------------
  1062. //
  1063. // Function: SSCtlFreeObjectCache
  1064. //
  1065. // Synopsis: free the object cache
  1066. //
  1067. //----------------------------------------------------------------------------
  1068. VOID WINAPI
  1069. SSCtlFreeObjectCache (
  1070. IN PCSSCTLOBJECTCACHE pSSCtlObjectCache
  1071. )
  1072. {
  1073. delete pSSCtlObjectCache;
  1074. }
  1075. //+---------------------------------------------------------------------------
  1076. //
  1077. // Function: SSCtlFreeTrustListInfo
  1078. //
  1079. // Synopsis: free the trust list info
  1080. //
  1081. //----------------------------------------------------------------------------
  1082. VOID WINAPI
  1083. SSCtlFreeTrustListInfo (
  1084. IN PCERT_TRUST_LIST_INFO pTrustListInfo
  1085. )
  1086. {
  1087. CertFreeCTLContext( pTrustListInfo->pCtlContext );
  1088. delete pTrustListInfo;
  1089. }
  1090. //+---------------------------------------------------------------------------
  1091. //
  1092. // Function: SSCtlAllocAndCopyTrustListInfo
  1093. //
  1094. // Synopsis: allocate and copy the trust list info
  1095. //
  1096. //----------------------------------------------------------------------------
  1097. BOOL WINAPI
  1098. SSCtlAllocAndCopyTrustListInfo (
  1099. IN PCERT_TRUST_LIST_INFO pTrustListInfo,
  1100. OUT PCERT_TRUST_LIST_INFO* ppTrustListInfo
  1101. )
  1102. {
  1103. PCERT_TRUST_LIST_INFO pCopyTrustListInfo;
  1104. pCopyTrustListInfo = new CERT_TRUST_LIST_INFO;
  1105. if ( pCopyTrustListInfo == NULL )
  1106. {
  1107. SetLastError( (DWORD) E_OUTOFMEMORY );
  1108. return( FALSE );
  1109. }
  1110. pCopyTrustListInfo->cbSize = sizeof( CERT_TRUST_LIST_INFO );
  1111. pCopyTrustListInfo->pCtlContext = CertDuplicateCTLContext(
  1112. pTrustListInfo->pCtlContext
  1113. );
  1114. pCopyTrustListInfo->pCtlEntry = pTrustListInfo->pCtlEntry;
  1115. *ppTrustListInfo = pCopyTrustListInfo;
  1116. return( TRUE );
  1117. }
  1118. //+-------------------------------------------------------------------------
  1119. // Retrieve a newer and time valid CTL at one of the NextUpdate Urls
  1120. //
  1121. // Leaves the engine's critical section to do the URL
  1122. // fetching. If the engine was touched by another thread,
  1123. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  1124. //
  1125. // Assumption: Chain engine is locked once in the calling thread.
  1126. //--------------------------------------------------------------------------
  1127. BOOL
  1128. WINAPI
  1129. SSCtlRetrieveCtlUrl(
  1130. IN PCCERTCHAINENGINE pChainEngine,
  1131. IN PCCHAINCALLCONTEXT pCallContext,
  1132. IN OUT PCRYPT_URL_ARRAY pNextUpdateUrlArray,
  1133. IN DWORD dwRetrievalFlags,
  1134. IN OUT PCCTL_CONTEXT *ppCtl,
  1135. IN OUT BOOL *pfNewerCtl,
  1136. IN OUT BOOL *pfTimeValid
  1137. )
  1138. {
  1139. BOOL fResult;
  1140. DWORD i;
  1141. // Loop through Urls and try to retrieve a newer and time valid CTL
  1142. for (i = 0; i < pNextUpdateUrlArray->cUrl; i++) {
  1143. PCCTL_CONTEXT pNewCtl = NULL;
  1144. LPWSTR pwszUrl = NULL;
  1145. DWORD cbUrl;
  1146. // Do URL fetching outside of the engine's critical section
  1147. // Need to make a copy of the Url string. pNextUpdateUrlArray
  1148. // can be modified by another thread outside of the critical section.
  1149. cbUrl = (wcslen(pNextUpdateUrlArray->rgwszUrl[i]) + 1) * sizeof(WCHAR);
  1150. pwszUrl = (LPWSTR) PkiNonzeroAlloc(cbUrl);
  1151. if (NULL == pwszUrl)
  1152. goto OutOfMemory;
  1153. memcpy(pwszUrl, pNextUpdateUrlArray->rgwszUrl[i], cbUrl);
  1154. pCallContext->ChainEngine()->UnlockEngine();
  1155. fResult = ChainRetrieveObjectByUrlW(
  1156. pwszUrl,
  1157. CONTEXT_OID_CTL,
  1158. dwRetrievalFlags |
  1159. CRYPT_LDAP_SCOPE_BASE_ONLY_RETRIEVAL |
  1160. CRYPT_STICKY_CACHE_RETRIEVAL,
  1161. pCallContext->ChainPara()->dwUrlRetrievalTimeout,
  1162. (LPVOID *) &pNewCtl,
  1163. NULL, // hAsyncRetrieve
  1164. NULL, // pCredentials
  1165. NULL, // pvVerify
  1166. NULL // pAuxInfo
  1167. );
  1168. pCallContext->ChainEngine()->LockEngine();
  1169. PkiFree(pwszUrl);
  1170. if (pCallContext->IsTouchedEngine()) {
  1171. if (pNewCtl)
  1172. CertFreeCTLContext(pNewCtl);
  1173. goto TouchedDuringUrlRetrieval;
  1174. }
  1175. if (fResult) {
  1176. PCCTL_CONTEXT pOldCtl;
  1177. assert(pNewCtl);
  1178. pOldCtl = *ppCtl;
  1179. if (0 < CompareFileTime(&pNewCtl->pCtlInfo->ThisUpdate,
  1180. &pOldCtl->pCtlInfo->ThisUpdate)) {
  1181. FILETIME CurrentTime;
  1182. // Move us to the head of the Url list
  1183. DWORD j;
  1184. LPWSTR pwszUrl = pNextUpdateUrlArray->rgwszUrl[i];
  1185. for (j = i; 0 < j; j--) {
  1186. pNextUpdateUrlArray->rgwszUrl[j] =
  1187. pNextUpdateUrlArray->rgwszUrl[j - 1];
  1188. }
  1189. pNextUpdateUrlArray->rgwszUrl[0] = pwszUrl;
  1190. *pfNewerCtl = TRUE;
  1191. CertFreeCTLContext(pOldCtl);
  1192. *ppCtl = pNewCtl;
  1193. pCallContext->CurrentTime(&CurrentTime);
  1194. if (I_CryptIsZeroFileTime(&pNewCtl->pCtlInfo->NextUpdate) ||
  1195. 0 < CompareFileTime(&pNewCtl->pCtlInfo->NextUpdate,
  1196. &CurrentTime)) {
  1197. *pfTimeValid = TRUE;
  1198. break;
  1199. }
  1200. } else
  1201. CertFreeCTLContext(pNewCtl);
  1202. }
  1203. }
  1204. fResult = TRUE;
  1205. CommonReturn:
  1206. return fResult;
  1207. ErrorReturn:
  1208. fResult = FALSE;
  1209. goto CommonReturn;
  1210. SET_ERROR(TouchedDuringUrlRetrieval, ERROR_CAN_NOT_COMPLETE)
  1211. TRACE_ERROR(OutOfMemory)
  1212. }
  1213. //+-------------------------------------------------------------------------
  1214. // Update Ctl Object Enum Function
  1215. //
  1216. // Leaves the engine's critical section to do the URL
  1217. // fetching. If the engine was touched by another thread,
  1218. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  1219. //
  1220. // Assumption: Chain engine is locked once in the calling thread.
  1221. //--------------------------------------------------------------------------
  1222. BOOL
  1223. WINAPI
  1224. SSCtlUpdateCtlObjectEnumFn(
  1225. IN LPVOID pvPara,
  1226. IN PCSSCTLOBJECT pSSCtlObject
  1227. )
  1228. {
  1229. BOOL fTouchResult = TRUE;
  1230. PSSCTL_UPDATE_CTL_OBJ_PARA pPara = (PSSCTL_UPDATE_CTL_OBJ_PARA) pvPara;
  1231. FILETIME CurrentTime;
  1232. FILETIME UpdateTime;
  1233. PCCTL_CONTEXT pRetrieveCtl = NULL;
  1234. BOOL fTimeValid = FALSE;
  1235. BOOL fNewerCtl = FALSE;
  1236. PCRYPT_URL_ARRAY pNextUpdateUrlArray;
  1237. if (!pSSCtlObject->HasNextUpdateUrl(&UpdateTime))
  1238. return TRUE;
  1239. pPara->pCallContext->CurrentTime(&CurrentTime);
  1240. if (0 < CompareFileTime(&UpdateTime, &CurrentTime))
  1241. goto CommonReturn;
  1242. pRetrieveCtl = CertDuplicateCTLContext(pSSCtlObject->CtlContext());
  1243. pNextUpdateUrlArray = pSSCtlObject->NextUpdateUrlArray();
  1244. SSCtlRetrieveCtlUrl(
  1245. pPara->pChainEngine,
  1246. pPara->pCallContext,
  1247. pNextUpdateUrlArray,
  1248. CRYPT_CACHE_ONLY_RETRIEVAL,
  1249. &pRetrieveCtl,
  1250. &fNewerCtl,
  1251. &fTimeValid
  1252. );
  1253. if (pPara->pCallContext->IsTouchedEngine()) {
  1254. fTouchResult = FALSE;
  1255. goto TouchedDuringUrlRetrieval;
  1256. }
  1257. if (!fTimeValid && pPara->pCallContext->IsOnline()) {
  1258. SSCtlRetrieveCtlUrl(
  1259. pPara->pChainEngine,
  1260. pPara->pCallContext,
  1261. pNextUpdateUrlArray,
  1262. CRYPT_WIRE_ONLY_RETRIEVAL,
  1263. &pRetrieveCtl,
  1264. &fNewerCtl,
  1265. &fTimeValid
  1266. );
  1267. if (pPara->pCallContext->IsTouchedEngine()) {
  1268. fTouchResult = FALSE;
  1269. goto TouchedDuringUrlRetrieval;
  1270. }
  1271. if (!fNewerCtl)
  1272. pSSCtlObject->SetOffline(&CurrentTime, &UpdateTime);
  1273. }
  1274. if (fNewerCtl) {
  1275. PSSCTL_UPDATE_CTL_OBJ_ENTRY pEntry;
  1276. pSSCtlObject->SetOnline();
  1277. pEntry = new SSCTL_UPDATE_CTL_OBJ_ENTRY;
  1278. if (NULL == pEntry)
  1279. goto OutOfMemory;
  1280. if (!SSCtlCreateCtlObject(
  1281. pPara->pChainEngine,
  1282. pRetrieveCtl,
  1283. FALSE, // fAdditionalStore
  1284. &pEntry->pSSCtlObjectAdd
  1285. )) {
  1286. delete pEntry;
  1287. goto CreateCtlObjectError;
  1288. }
  1289. pEntry->pSSCtlObjectRemove = pSSCtlObject;
  1290. pEntry->pNext = pPara->pEntry;
  1291. pPara->pEntry = pEntry;
  1292. }
  1293. CommonReturn:
  1294. if (!fNewerCtl) {
  1295. if (I_CryptIsZeroFileTime(&pPara->UpdateTime) ||
  1296. 0 > CompareFileTime(&UpdateTime, &pPara->UpdateTime))
  1297. pPara->UpdateTime = UpdateTime;
  1298. }
  1299. if (pRetrieveCtl)
  1300. CertFreeCTLContext(pRetrieveCtl);
  1301. return fTouchResult;
  1302. ErrorReturn:
  1303. fNewerCtl = FALSE;
  1304. goto CommonReturn;
  1305. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  1306. TRACE_ERROR(CreateCtlObjectError)
  1307. SET_ERROR(TouchedDuringUrlRetrieval, ERROR_CAN_NOT_COMPLETE)
  1308. }