Leaked source code of windows server 2003
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.

918 lines
29 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT Security
  4. // Copyright (C) Microsoft Corporation, 1997 - 2000
  5. //
  6. // File: xcert.cpp
  7. //
  8. // Contents: CCertChainEngine's Cross Certificate Methods
  9. //
  10. // History: 22-Dec-99 philh Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <global.hxx>
  14. #include <dbgdef.h>
  15. //+=========================================================================
  16. // Cross Certificate Distribution Point Support Functions
  17. //==========================================================================
  18. //+-------------------------------------------------------------------------
  19. // Get and allocate the cross certificate distribution points Url array
  20. // and info for the specified certificate.
  21. //--------------------------------------------------------------------------
  22. BOOL
  23. WINAPI
  24. XCertGetDistPointsUrl(
  25. IN PCCERT_CONTEXT pCert,
  26. OUT PCRYPT_URL_ARRAY *ppUrlArray,
  27. OUT PCRYPT_URL_INFO *ppUrlInfo
  28. )
  29. {
  30. BOOL fResult;
  31. PCRYPT_URL_ARRAY pUrlArray = NULL;
  32. DWORD cbUrlArray = 0;
  33. PCRYPT_URL_INFO pUrlInfo = NULL;
  34. DWORD cbUrlInfo = 0;
  35. if (!ChainGetObjectUrl(
  36. URL_OID_CROSS_CERT_DIST_POINT,
  37. (LPVOID) pCert,
  38. CRYPT_GET_URL_FROM_PROPERTY | CRYPT_GET_URL_FROM_EXTENSION,
  39. NULL, // pUrlArray
  40. &cbUrlArray,
  41. NULL, // pUrlInfo
  42. &cbUrlInfo,
  43. NULL // pvReserved
  44. ))
  45. goto GetObjectUrlError;
  46. pUrlArray = (PCRYPT_URL_ARRAY) new BYTE [cbUrlArray];
  47. if (NULL == pUrlArray)
  48. goto OutOfMemory;
  49. pUrlInfo = (PCRYPT_URL_INFO) new BYTE [cbUrlInfo];
  50. if (NULL == pUrlInfo)
  51. goto OutOfMemory;
  52. if (!ChainGetObjectUrl(
  53. URL_OID_CROSS_CERT_DIST_POINT,
  54. (LPVOID) pCert,
  55. CRYPT_GET_URL_FROM_PROPERTY | CRYPT_GET_URL_FROM_EXTENSION,
  56. pUrlArray,
  57. &cbUrlArray,
  58. pUrlInfo,
  59. &cbUrlInfo,
  60. NULL // pvReserved
  61. ))
  62. goto GetObjectUrlError;
  63. if (0 == pUrlArray->cUrl || 0 == pUrlInfo->cGroup)
  64. goto NoDistPointUrls;
  65. fResult = TRUE;
  66. CommonReturn:
  67. *ppUrlArray = pUrlArray;
  68. *ppUrlInfo = pUrlInfo;
  69. return fResult;
  70. ErrorReturn:
  71. if (pUrlArray) {
  72. delete (LPBYTE) pUrlArray;
  73. pUrlArray = NULL;
  74. }
  75. if (pUrlInfo) {
  76. delete (LPBYTE) pUrlInfo;
  77. pUrlInfo = NULL;
  78. }
  79. fResult = FALSE;
  80. goto CommonReturn;
  81. TRACE_ERROR(GetObjectUrlError)
  82. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  83. SET_ERROR(NoDistPointUrls, CRYPT_E_NOT_FOUND)
  84. }
  85. //+-------------------------------------------------------------------------
  86. // Checks and returns TRUE if all the Urls are contained in the
  87. // distribution point.
  88. //--------------------------------------------------------------------------
  89. BOOL
  90. WINAPI
  91. XCertIsUrlInDistPoint(
  92. IN DWORD cUrl,
  93. IN LPWSTR *ppwszUrl,
  94. IN PXCERT_DP_ENTRY pEntry
  95. )
  96. {
  97. for ( ; 0 < cUrl; cUrl--, ppwszUrl++) {
  98. DWORD cDPUrl = pEntry->cUrl;
  99. LPWSTR *ppwszDPUrl = pEntry->rgpwszUrl;
  100. for ( ; 0 < cDPUrl; cDPUrl--, ppwszDPUrl++) {
  101. if (0 == wcscmp(*ppwszUrl, *ppwszDPUrl))
  102. break;
  103. }
  104. if (0 == cDPUrl)
  105. return FALSE;
  106. }
  107. return TRUE;
  108. }
  109. //+-------------------------------------------------------------------------
  110. // Finds a distribution point link containing all the Urls.
  111. //--------------------------------------------------------------------------
  112. PXCERT_DP_LINK
  113. WINAPI
  114. XCertFindUrlInDistPointLinks(
  115. IN DWORD cUrl,
  116. IN LPWSTR *rgpwszUrl,
  117. IN PXCERT_DP_LINK pLink
  118. )
  119. {
  120. for ( ; pLink; pLink = pLink->pNext) {
  121. if (XCertIsUrlInDistPoint(cUrl, rgpwszUrl, pLink->pCrossCertDPEntry))
  122. return pLink;
  123. }
  124. return NULL;
  125. }
  126. //+-------------------------------------------------------------------------
  127. // Finds a distribution point entry containing all the Urls.
  128. //--------------------------------------------------------------------------
  129. PXCERT_DP_ENTRY
  130. WINAPI
  131. XCertFindUrlInDistPointEntries(
  132. IN DWORD cUrl,
  133. IN LPWSTR *rgpwszUrl,
  134. PXCERT_DP_ENTRY pEntry
  135. )
  136. {
  137. for ( ; pEntry; pEntry = pEntry->pNext) {
  138. if (XCertIsUrlInDistPoint(cUrl, rgpwszUrl, pEntry))
  139. return pEntry;
  140. }
  141. return NULL;
  142. }
  143. //+-------------------------------------------------------------------------
  144. // Inserts the cross certificate distribution entry into the engine's
  145. // list. The list is ordered according to ascending NextSyncTimes.
  146. //--------------------------------------------------------------------------
  147. void
  148. CCertChainEngine::InsertCrossCertDistPointEntry(
  149. IN OUT PXCERT_DP_ENTRY pEntry
  150. )
  151. {
  152. if (NULL == m_pCrossCertDPEntry) {
  153. // First entry to be added to engine's list
  154. pEntry->pNext = NULL;
  155. pEntry->pPrev = NULL;
  156. m_pCrossCertDPEntry = pEntry;
  157. } else {
  158. PXCERT_DP_ENTRY pListEntry = m_pCrossCertDPEntry;
  159. BOOL fLast = FALSE;
  160. // Loop while Entry's NextSyncTime > list's NextSyncTime
  161. while (0 < CompareFileTime(&pEntry->NextSyncTime,
  162. &pListEntry->NextSyncTime)) {
  163. if (NULL == pListEntry->pNext) {
  164. fLast = TRUE;
  165. break;
  166. } else
  167. pListEntry = pListEntry->pNext;
  168. }
  169. if (fLast) {
  170. assert(NULL == pListEntry->pNext);
  171. pEntry->pNext = NULL;
  172. pEntry->pPrev = pListEntry;
  173. pListEntry->pNext = pEntry;
  174. } else {
  175. pEntry->pNext = pListEntry;
  176. pEntry->pPrev = pListEntry->pPrev;
  177. if (pListEntry->pPrev) {
  178. assert(pListEntry->pPrev->pNext == pListEntry);
  179. pListEntry->pPrev->pNext = pEntry;
  180. } else {
  181. assert(m_pCrossCertDPEntry == pListEntry);
  182. m_pCrossCertDPEntry = pEntry;
  183. }
  184. pListEntry->pPrev = pEntry;
  185. }
  186. }
  187. }
  188. //+-------------------------------------------------------------------------
  189. // Removes the cross certificate distribution point from the engine's list.
  190. //--------------------------------------------------------------------------
  191. void
  192. CCertChainEngine::RemoveCrossCertDistPointEntry(
  193. IN OUT PXCERT_DP_ENTRY pEntry
  194. )
  195. {
  196. if (pEntry->pNext)
  197. pEntry->pNext->pPrev = pEntry->pPrev;
  198. if (pEntry->pPrev)
  199. pEntry->pPrev->pNext = pEntry->pNext;
  200. else
  201. m_pCrossCertDPEntry = pEntry->pNext;
  202. }
  203. //+-------------------------------------------------------------------------
  204. // For an online certificate distribution point updates the NextSyncTime
  205. // and repositions accordingly in the engine's list.
  206. //
  207. // NextSyncTime = LastSyncTime + dwSyncDeltaTime.
  208. //--------------------------------------------------------------------------
  209. void
  210. CCertChainEngine::RepositionOnlineCrossCertDistPointEntry(
  211. IN OUT PXCERT_DP_ENTRY pEntry,
  212. IN LPFILETIME pLastSyncTime
  213. )
  214. {
  215. assert(!I_CryptIsZeroFileTime(pLastSyncTime));
  216. pEntry->LastSyncTime = *pLastSyncTime;
  217. pEntry->dwOfflineCnt = 0;
  218. I_CryptIncrementFileTimeBySeconds(
  219. pLastSyncTime,
  220. pEntry->dwSyncDeltaTime,
  221. &pEntry->NextSyncTime
  222. );
  223. RemoveCrossCertDistPointEntry(pEntry);
  224. InsertCrossCertDistPointEntry(pEntry);
  225. }
  226. //+-------------------------------------------------------------------------
  227. // For an offline certificate distribution point, increments the offline
  228. // count, updates the NextSyncTime to be some delta from the current time
  229. // and repositions accordingly in the engine's list.
  230. //
  231. // NextSyncTime = CurrentTime +
  232. // rgChainOfflineUrlDeltaSeconds[dwOfflineCnt - 1]
  233. //--------------------------------------------------------------------------
  234. void
  235. CCertChainEngine::RepositionOfflineCrossCertDistPointEntry(
  236. IN OUT PXCERT_DP_ENTRY pEntry,
  237. IN LPFILETIME pCurrentTime
  238. )
  239. {
  240. pEntry->dwOfflineCnt++;
  241. I_CryptIncrementFileTimeBySeconds(
  242. pCurrentTime,
  243. ChainGetOfflineUrlDeltaSeconds(pEntry->dwOfflineCnt),
  244. &pEntry->NextSyncTime
  245. );
  246. RemoveCrossCertDistPointEntry(pEntry);
  247. InsertCrossCertDistPointEntry(pEntry);
  248. }
  249. //+-------------------------------------------------------------------------
  250. // For a smaller SyncDeltaTime in a certificate distribution point,
  251. // updates the NextSyncTime and repositions accordingly in the engine's list.
  252. //
  253. // Note, if the distribution point is offline, the NextSyncTime isn't
  254. // updated.
  255. //
  256. // NextSyncTime = LastSyncTime + dwSyncDeltaTime.
  257. //--------------------------------------------------------------------------
  258. void
  259. CCertChainEngine::RepositionNewSyncDeltaTimeCrossCertDistPointEntry(
  260. IN OUT PXCERT_DP_ENTRY pEntry,
  261. IN DWORD dwSyncDeltaTime
  262. )
  263. {
  264. if (dwSyncDeltaTime >= pEntry->dwSyncDeltaTime)
  265. return;
  266. pEntry->dwSyncDeltaTime = dwSyncDeltaTime;
  267. if (I_CryptIsZeroFileTime(&pEntry->LastSyncTime) ||
  268. 0 != pEntry->dwOfflineCnt)
  269. return;
  270. RepositionOnlineCrossCertDistPointEntry(pEntry, &pEntry->LastSyncTime);
  271. }
  272. //+-------------------------------------------------------------------------
  273. // Creates the cross certificate distribution point and insert's in the
  274. // engine's list.
  275. //
  276. // The returned entry has a refCnt of 1.
  277. //--------------------------------------------------------------------------
  278. PXCERT_DP_ENTRY
  279. CCertChainEngine::CreateCrossCertDistPointEntry(
  280. IN DWORD dwSyncDeltaTime,
  281. IN DWORD cUrl,
  282. IN LPWSTR *rgpwszUrl
  283. )
  284. {
  285. PXCERT_DP_ENTRY pEntry;
  286. DWORD cbEntry;
  287. LPWSTR *ppwszEntryUrl;
  288. LPWSTR pwszEntryUrl;
  289. DWORD i;
  290. cbEntry = sizeof(XCERT_DP_ENTRY) + cUrl * sizeof(LPWSTR);
  291. for (i = 0; i < cUrl; i++)
  292. cbEntry += (wcslen(rgpwszUrl[i]) + 1) * sizeof(WCHAR);
  293. pEntry = (PXCERT_DP_ENTRY) new BYTE [cbEntry];
  294. if (NULL == pEntry) {
  295. SetLastError((DWORD) E_OUTOFMEMORY);
  296. return NULL;
  297. }
  298. memset(pEntry, 0, sizeof(XCERT_DP_ENTRY));
  299. pEntry->lRefCnt = 1;
  300. pEntry->dwSyncDeltaTime = dwSyncDeltaTime;
  301. pEntry->cUrl = cUrl;
  302. pEntry->rgpwszUrl = ppwszEntryUrl = (LPWSTR *) &pEntry[1];
  303. pwszEntryUrl = (LPWSTR) &ppwszEntryUrl[cUrl];
  304. for (i = 0; i < cUrl; i++) {
  305. ppwszEntryUrl[i] = pwszEntryUrl;
  306. wcscpy(pwszEntryUrl, rgpwszUrl[i]);
  307. pwszEntryUrl += wcslen(rgpwszUrl[i]) + 1;
  308. }
  309. InsertCrossCertDistPointEntry(pEntry);
  310. return pEntry;
  311. }
  312. //+-------------------------------------------------------------------------
  313. // Increments the cross certificate distribution point's reference count.
  314. //--------------------------------------------------------------------------
  315. void
  316. CCertChainEngine::AddRefCrossCertDistPointEntry(
  317. IN OUT PXCERT_DP_ENTRY pEntry
  318. )
  319. {
  320. pEntry->lRefCnt++;
  321. }
  322. //+-------------------------------------------------------------------------
  323. // Decrements the cross certificate distribution point's reference count.
  324. //
  325. // When decremented to 0, removed from the engine's list and freed.
  326. //
  327. // Returns TRUE if decremented to 0 and freed.
  328. //--------------------------------------------------------------------------
  329. BOOL
  330. CCertChainEngine::ReleaseCrossCertDistPointEntry(
  331. IN OUT PXCERT_DP_ENTRY pEntry
  332. )
  333. {
  334. if (0 != --pEntry->lRefCnt)
  335. return FALSE;
  336. RemoveCrossCertDistPointEntry(pEntry);
  337. FreeCrossCertDistPoints(&pEntry->pChildCrossCertDPLink);
  338. if (pEntry->hUrlStore) {
  339. CertRemoveStoreFromCollection(
  340. m_hCrossCertStore,
  341. pEntry->hUrlStore
  342. );
  343. CertCloseStore(pEntry->hUrlStore, 0);
  344. }
  345. delete (LPBYTE) pEntry;
  346. return TRUE;
  347. }
  348. //+-------------------------------------------------------------------------
  349. // Finds and gets the Cross Certificate Distribution Points for the
  350. // specified certificate store.
  351. //
  352. // *ppLinkHead is updated to contain the store's distribution point links.
  353. //--------------------------------------------------------------------------
  354. BOOL
  355. CCertChainEngine::GetCrossCertDistPointsForStore(
  356. IN HCERTSTORE hStore,
  357. IN BOOL fOnlyLMSystemStore,
  358. IN OUT PXCERT_DP_LINK *ppLinkHead
  359. )
  360. {
  361. BOOL fResult;
  362. PXCERT_DP_LINK pOldLinkHead = *ppLinkHead;
  363. PXCERT_DP_LINK pNewLinkHead = NULL;
  364. PCCERT_CONTEXT pCert = NULL;
  365. PCRYPT_URL_ARRAY pUrlArray = NULL;
  366. PCRYPT_URL_INFO pUrlInfo = NULL;
  367. while (pCert = CertFindCertificateInStore(
  368. hStore,
  369. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  370. 0, // dwFindFlags
  371. CERT_FIND_CROSS_CERT_DIST_POINTS,
  372. NULL, // pvFindPara,
  373. pCert
  374. )) {
  375. DWORD dwSyncDeltaTime;
  376. DWORD cDP;
  377. DWORD *pcUrl;
  378. LPWSTR *ppwszUrl;
  379. if (fOnlyLMSystemStore) {
  380. DWORD dwAccessStateFlags = 0;
  381. DWORD cbData = sizeof(dwAccessStateFlags);
  382. if (!CertGetCertificateContextProperty(
  383. pCert,
  384. CERT_ACCESS_STATE_PROP_ID,
  385. &dwAccessStateFlags,
  386. &cbData
  387. ) ||
  388. (0 == (dwAccessStateFlags &
  389. CERT_ACCESS_STATE_LM_SYSTEM_STORE_FLAG)))
  390. continue;
  391. }
  392. if (!XCertGetDistPointsUrl(
  393. pCert,
  394. &pUrlArray,
  395. &pUrlInfo
  396. ))
  397. continue;
  398. dwSyncDeltaTime = pUrlInfo->dwSyncDeltaTime;
  399. if (0 == dwSyncDeltaTime)
  400. dwSyncDeltaTime = XCERT_DEFAULT_SYNC_DELTA_TIME;
  401. else if (XCERT_MIN_SYNC_DELTA_TIME > dwSyncDeltaTime)
  402. dwSyncDeltaTime = XCERT_MIN_SYNC_DELTA_TIME;
  403. cDP = pUrlInfo->cGroup;
  404. pcUrl = pUrlInfo->rgcGroupEntry;
  405. ppwszUrl = pUrlArray->rgwszUrl;
  406. for ( ; 0 < cDP; cDP--, ppwszUrl += *pcUrl++) {
  407. PXCERT_DP_LINK pLink;
  408. PXCERT_DP_ENTRY pEntry;
  409. DWORD cUrl = *pcUrl;
  410. if (0 == cUrl)
  411. continue;
  412. // Do we already have an entry in the new list
  413. if (XCertFindUrlInDistPointLinks(cUrl, ppwszUrl, pNewLinkHead))
  414. continue;
  415. // If the entry existed in the old list, move to the new list
  416. if (pLink = XCertFindUrlInDistPointLinks(
  417. cUrl, ppwszUrl, pOldLinkHead)) {
  418. if (pLink->pNext)
  419. pLink->pNext->pPrev = pLink->pPrev;
  420. if (pLink->pPrev)
  421. pLink->pPrev->pNext = pLink->pNext;
  422. else
  423. pOldLinkHead = pLink->pNext;
  424. RepositionNewSyncDeltaTimeCrossCertDistPointEntry(
  425. pLink->pCrossCertDPEntry, dwSyncDeltaTime);
  426. } else {
  427. // Check if the entry already exists for the engine
  428. if (pEntry = XCertFindUrlInDistPointEntries(
  429. cUrl, ppwszUrl, m_pCrossCertDPEntry)) {
  430. AddRefCrossCertDistPointEntry(pEntry);
  431. RepositionNewSyncDeltaTimeCrossCertDistPointEntry(
  432. pEntry, dwSyncDeltaTime);
  433. } else {
  434. // Create entry and insert at beginning of
  435. // entries list.
  436. if (NULL == (pEntry = CreateCrossCertDistPointEntry(
  437. dwSyncDeltaTime,
  438. cUrl,
  439. ppwszUrl
  440. )))
  441. goto CreateDistPointEntryError;
  442. }
  443. pLink = new XCERT_DP_LINK;
  444. if (NULL == pLink) {
  445. ReleaseCrossCertDistPointEntry(pEntry);
  446. goto CreateDistPointLinkError;
  447. }
  448. pLink->pCrossCertDPEntry = pEntry;
  449. }
  450. if (pNewLinkHead) {
  451. assert(NULL == pNewLinkHead->pPrev);
  452. pNewLinkHead->pPrev = pLink;
  453. }
  454. pLink->pNext = pNewLinkHead;
  455. pLink->pPrev = NULL;
  456. pNewLinkHead = pLink;
  457. }
  458. delete (LPBYTE) pUrlArray;
  459. pUrlArray = NULL;
  460. delete (LPBYTE) pUrlInfo;
  461. pUrlInfo = NULL;
  462. }
  463. assert(NULL == pUrlArray);
  464. assert(NULL == pUrlInfo);
  465. assert(NULL == pCert);
  466. *ppLinkHead = pNewLinkHead;
  467. fResult = TRUE;
  468. CommonReturn:
  469. if (pOldLinkHead) {
  470. DWORD dwErr = GetLastError();
  471. FreeCrossCertDistPoints(&pOldLinkHead);
  472. SetLastError(dwErr);
  473. }
  474. return fResult;
  475. ErrorReturn:
  476. *ppLinkHead = NULL;
  477. if (pUrlArray)
  478. delete (LPBYTE) pUrlArray;
  479. if (pUrlInfo)
  480. delete (LPBYTE) pUrlInfo;
  481. if (pCert)
  482. CertFreeCertificateContext(pCert);
  483. if (pNewLinkHead) {
  484. FreeCrossCertDistPoints(&pNewLinkHead);
  485. assert(NULL == pNewLinkHead);
  486. }
  487. fResult = FALSE;
  488. goto CommonReturn;
  489. TRACE_ERROR(CreateDistPointEntryError)
  490. TRACE_ERROR(CreateDistPointLinkError)
  491. }
  492. //+-------------------------------------------------------------------------
  493. // Removes an orphan'ed entry not in any list of links.
  494. //--------------------------------------------------------------------------
  495. void
  496. CCertChainEngine::RemoveCrossCertDistPointOrphanEntry(
  497. IN PXCERT_DP_ENTRY pOrphanEntry
  498. )
  499. {
  500. PXCERT_DP_ENTRY pEntry;
  501. for (pEntry = m_pCrossCertDPEntry; pEntry; pEntry = pEntry->pNext) {
  502. PXCERT_DP_LINK pLink = pEntry->pChildCrossCertDPLink;
  503. while (pLink) {
  504. if (pLink->pCrossCertDPEntry == pOrphanEntry) {
  505. if (pLink->pNext)
  506. pLink->pNext->pPrev = pLink->pPrev;
  507. if (pLink->pPrev)
  508. pLink->pPrev->pNext = pLink->pNext;
  509. else
  510. pEntry->pChildCrossCertDPLink = pLink->pNext;
  511. delete pLink;
  512. if (ReleaseCrossCertDistPointEntry(pOrphanEntry))
  513. return;
  514. else
  515. break;
  516. }
  517. pLink = pLink->pNext;
  518. }
  519. }
  520. }
  521. //+-------------------------------------------------------------------------
  522. // Returns TRUE if the entry is in this or any child link list
  523. //--------------------------------------------------------------------------
  524. BOOL
  525. WINAPI
  526. XCertIsDistPointInLinkList(
  527. IN PXCERT_DP_ENTRY pOrphanEntry,
  528. IN PXCERT_DP_LINK pLink
  529. )
  530. {
  531. for (; pLink; pLink = pLink->pNext) {
  532. PXCERT_DP_ENTRY pEntry = pLink->pCrossCertDPEntry;
  533. if (pOrphanEntry == pEntry)
  534. return TRUE;
  535. // Note, inhibit recursion by checking an entry's list of links
  536. // only once.
  537. if (!pEntry->fChecked) {
  538. pEntry->fChecked = TRUE;
  539. if (XCertIsDistPointInLinkList(pOrphanEntry,
  540. pEntry->pChildCrossCertDPLink))
  541. return TRUE;
  542. }
  543. }
  544. return FALSE;
  545. }
  546. //+-------------------------------------------------------------------------
  547. // Frees the cross certificate distribution point links.
  548. //--------------------------------------------------------------------------
  549. void
  550. CCertChainEngine::FreeCrossCertDistPoints(
  551. IN OUT PXCERT_DP_LINK *ppLinkHead
  552. )
  553. {
  554. PXCERT_DP_LINK pLink = *ppLinkHead;
  555. *ppLinkHead = NULL;
  556. while (pLink) {
  557. PXCERT_DP_LINK pDelete;
  558. PXCERT_DP_ENTRY pEntry;
  559. pEntry = pLink->pCrossCertDPEntry;
  560. if (ReleaseCrossCertDistPointEntry(pEntry))
  561. ;
  562. else {
  563. // Clear the fChecked flag for all entries
  564. PXCERT_DP_ENTRY pCheckEntry;
  565. for (pCheckEntry = m_pCrossCertDPEntry; pCheckEntry;
  566. pCheckEntry = pCheckEntry->pNext)
  567. pCheckEntry->fChecked = FALSE;
  568. if (!XCertIsDistPointInLinkList(pEntry, m_pCrossCertDPLink))
  569. // An orphaned entry. Not in anyone else's list
  570. RemoveCrossCertDistPointOrphanEntry(pEntry);
  571. }
  572. pDelete = pLink;
  573. pLink = pLink->pNext;
  574. delete pDelete;
  575. }
  576. }
  577. //+-------------------------------------------------------------------------
  578. // Retrieve the cross certificates
  579. //
  580. // Leaves the engine's critical section to do the URL
  581. // fetching. If the engine was touched by another thread,
  582. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  583. //
  584. // If the URL store is changed, increments engine's touch count and flushes
  585. // issuer and end cert object caches.
  586. //
  587. // Assumption: Chain engine is locked once in the calling thread.
  588. //--------------------------------------------------------------------------
  589. BOOL
  590. CCertChainEngine::RetrieveCrossCertUrl(
  591. IN PCCHAINCALLCONTEXT pCallContext,
  592. IN OUT PXCERT_DP_ENTRY pEntry,
  593. IN DWORD dwRetrievalFlags,
  594. IN OUT BOOL *pfTimeValid
  595. )
  596. {
  597. BOOL fResult;
  598. FILETIME CurrentTime;
  599. HCERTSTORE hNewUrlStore = NULL;
  600. FILETIME NewLastSyncTime;
  601. CRYPT_RETRIEVE_AUX_INFO RetrieveAuxInfo;
  602. DWORD i;
  603. memset(&RetrieveAuxInfo, 0, sizeof(RetrieveAuxInfo));
  604. RetrieveAuxInfo.cbSize = sizeof(RetrieveAuxInfo);
  605. RetrieveAuxInfo.pLastSyncTime = &NewLastSyncTime;
  606. pCallContext->CurrentTime(&CurrentTime);
  607. // Loop through Urls and try to retrieve a time valid cross cert URL
  608. for (i = 0; i < pEntry->cUrl; i++) {
  609. NewLastSyncTime = CurrentTime;
  610. LPWSTR pwszUrl = NULL;
  611. DWORD cbUrl;
  612. // Do URL fetching outside of the engine's critical section
  613. // Need to make a copy of the Url string. pEntry
  614. // can be modified by another thread outside of the critical section.
  615. cbUrl = (wcslen(pEntry->rgpwszUrl[i]) + 1) * sizeof(WCHAR);
  616. pwszUrl = (LPWSTR) PkiNonzeroAlloc(cbUrl);
  617. if (NULL == pwszUrl)
  618. goto OutOfMemory;
  619. memcpy(pwszUrl, pEntry->rgpwszUrl[i], cbUrl);
  620. pCallContext->ChainEngine()->UnlockEngine();
  621. fResult = ChainRetrieveObjectByUrlW(
  622. pwszUrl,
  623. CONTEXT_OID_CAPI2_ANY,
  624. dwRetrievalFlags |
  625. CRYPT_RETRIEVE_MULTIPLE_OBJECTS |
  626. CRYPT_STICKY_CACHE_RETRIEVAL,
  627. pCallContext->ChainPara()->dwUrlRetrievalTimeout,
  628. (LPVOID *) &hNewUrlStore,
  629. NULL, // hAsyncRetrieve
  630. NULL, // pCredentials
  631. NULL, // pvVerify
  632. &RetrieveAuxInfo
  633. );
  634. pCallContext->ChainEngine()->LockEngine();
  635. PkiFree(pwszUrl);
  636. if (pCallContext->IsTouchedEngine())
  637. goto TouchedDuringUrlRetrieval;
  638. if (fResult) {
  639. assert(hNewUrlStore);
  640. if (0 > CompareFileTime(&pEntry->LastSyncTime, &NewLastSyncTime)) {
  641. BOOL fStoreChanged = FALSE;
  642. // Move us to the head of the Url list
  643. DWORD j;
  644. LPWSTR pwszUrl = pEntry->rgpwszUrl[i];
  645. for (j = i; 0 < j; j--)
  646. pEntry->rgpwszUrl[j] = pEntry->rgpwszUrl[j - 1];
  647. pEntry->rgpwszUrl[0] = pwszUrl;
  648. if (NULL == pEntry->hUrlStore) {
  649. if (!CertAddStoreToCollection(
  650. m_hCrossCertStore,
  651. hNewUrlStore,
  652. 0,
  653. 0
  654. ))
  655. goto AddStoreToCollectionError;
  656. pEntry->hUrlStore = hNewUrlStore;
  657. hNewUrlStore = NULL;
  658. fStoreChanged = TRUE;
  659. } else {
  660. DWORD dwOutFlags = 0;
  661. if (!I_CertSyncStoreEx(
  662. pEntry->hUrlStore,
  663. hNewUrlStore,
  664. ICERT_SYNC_STORE_INHIBIT_SYNC_PROPERTY_IN_FLAG,
  665. &dwOutFlags,
  666. NULL // pvReserved
  667. ))
  668. goto SyncStoreError;
  669. if (dwOutFlags & ICERT_SYNC_STORE_CHANGED_OUT_FLAG)
  670. fStoreChanged = TRUE;
  671. }
  672. if (fStoreChanged) {
  673. m_pCertObjectCache->FlushObjects( pCallContext );
  674. pCallContext->TouchEngine();
  675. if (!GetCrossCertDistPointsForStore(
  676. pEntry->hUrlStore,
  677. FALSE, // fOnlyLMSystemStore
  678. &pEntry->pChildCrossCertDPLink
  679. ))
  680. goto UpdateDistPointError;
  681. }
  682. RepositionOnlineCrossCertDistPointEntry(pEntry,
  683. &NewLastSyncTime);
  684. if (0 < CompareFileTime(&pEntry->NextSyncTime, &CurrentTime)) {
  685. *pfTimeValid = TRUE;
  686. break;
  687. }
  688. }
  689. if (hNewUrlStore) {
  690. CertCloseStore(hNewUrlStore, 0);
  691. hNewUrlStore = NULL;
  692. }
  693. }
  694. }
  695. fResult = TRUE;
  696. CommonReturn:
  697. if (hNewUrlStore)
  698. CertCloseStore(hNewUrlStore, 0);
  699. return fResult;
  700. ErrorReturn:
  701. fResult = FALSE;
  702. goto CommonReturn;
  703. TRACE_ERROR(AddStoreToCollectionError)
  704. TRACE_ERROR(SyncStoreError)
  705. TRACE_ERROR(UpdateDistPointError)
  706. TRACE_ERROR(OutOfMemory)
  707. SET_ERROR(TouchedDuringUrlRetrieval, ERROR_CAN_NOT_COMPLETE)
  708. }
  709. //+-------------------------------------------------------------------------
  710. // Update cross certificate distribution points whose NextSyncTime has
  711. // expired.
  712. //
  713. // Leaves the engine's critical section to do the URL
  714. // fetching. If the engine was touched by another thread,
  715. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  716. //
  717. // If the URL store is changed, increments engine's touch count and flushes
  718. // issuer and end cert object caches.
  719. //
  720. // Assumption: Chain engine is locked once in the calling thread.
  721. //--------------------------------------------------------------------------
  722. BOOL
  723. CCertChainEngine::UpdateCrossCerts(
  724. IN PCCHAINCALLCONTEXT pCallContext
  725. )
  726. {
  727. BOOL fResult;
  728. PXCERT_DP_ENTRY pEntry;
  729. FILETIME CurrentTime;
  730. pEntry = m_pCrossCertDPEntry;
  731. if (NULL == pEntry)
  732. goto SuccessReturn;
  733. m_dwCrossCertDPResyncIndex++;
  734. pCallContext->CurrentTime(&CurrentTime);
  735. while (pEntry &&
  736. 0 >= CompareFileTime(&pEntry->NextSyncTime, &CurrentTime)) {
  737. PXCERT_DP_ENTRY pNextEntry = pEntry->pNext;
  738. if (pEntry->dwResyncIndex < m_dwCrossCertDPResyncIndex) {
  739. BOOL fTimeValid = FALSE;
  740. if (0 == pEntry->dwResyncIndex || pCallContext->IsOnline()) {
  741. RetrieveCrossCertUrl(
  742. pCallContext,
  743. pEntry,
  744. CRYPT_CACHE_ONLY_RETRIEVAL,
  745. &fTimeValid
  746. );
  747. if (pCallContext->IsTouchedEngine())
  748. goto TouchedDuringUrlRetrieval;
  749. if (!fTimeValid && pCallContext->IsOnline()) {
  750. RetrieveCrossCertUrl(
  751. pCallContext,
  752. pEntry,
  753. CRYPT_WIRE_ONLY_RETRIEVAL,
  754. &fTimeValid
  755. );
  756. if (pCallContext->IsTouchedEngine())
  757. goto TouchedDuringUrlRetrieval;
  758. if (!fTimeValid)
  759. RepositionOfflineCrossCertDistPointEntry(pEntry,
  760. &CurrentTime);
  761. }
  762. // Start over at the beginning. May have added some entries.
  763. pNextEntry = m_pCrossCertDPEntry;
  764. }
  765. pEntry->dwResyncIndex = m_dwCrossCertDPResyncIndex;
  766. }
  767. // else
  768. // Skip entries we have already processed.
  769. pEntry = pNextEntry;
  770. }
  771. SuccessReturn:
  772. fResult = TRUE;
  773. CommonReturn:
  774. return fResult;
  775. ErrorReturn:
  776. fResult = FALSE;
  777. goto CommonReturn;
  778. SET_ERROR(TouchedDuringUrlRetrieval, ERROR_CAN_NOT_COMPLETE)
  779. }