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.

1206 lines
38 KiB

  1. //+-------------------------------------------------------------------------
  2. // Microsoft Windows
  3. //
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: msrevoke.cpp
  7. //
  8. // Contents: CRL Distribution Points version of CertDllVerifyRevocation.
  9. //
  10. // Restrictions:
  11. // - Only support CRYPT_ASN_ENCODING
  12. // - Only processes certificates having the
  13. // szOID_CRL_DIST_POINTS extension.
  14. // - For szOID_CRL_DIST_POINTS extension: only URL FullName,
  15. // no ReasonFlags or CRLIssuer.
  16. // - URLs: http:, file:
  17. // - CRL must be issued and signed by the issuer of the
  18. // certificate
  19. // - CRL must not have any critical extensions
  20. //
  21. // Functions: DllMain
  22. // DllRegisterServer
  23. // DllUnregisterServer
  24. // CertDllVerifyRevocation
  25. //
  26. // History: 10-Apr-97 philh created
  27. // 01-Oct-97 kirtd major simplification, use
  28. // CryptGetTimeValidObject
  29. //
  30. //--------------------------------------------------------------------------
  31. #include "global.hxx"
  32. #include <dbgdef.h>
  33. #define MSREVOKE_TIMEOUT 15000
  34. //+-------------------------------------------------------------------------
  35. // Default stores searched to find an issuer of the subject certificate
  36. //--------------------------------------------------------------------------
  37. static struct {
  38. LPCWSTR pwszStore;
  39. DWORD dwFlags;
  40. } rgDefaultIssuerStores[] = {
  41. L"CA", CERT_SYSTEM_STORE_CURRENT_USER,
  42. L"ROOT", CERT_SYSTEM_STORE_CURRENT_USER,
  43. L"SPC", CERT_SYSTEM_STORE_LOCAL_MACHINE
  44. };
  45. #define NUM_DEFAULT_ISSUER_STORES (sizeof(rgDefaultIssuerStores) / \
  46. sizeof(rgDefaultIssuerStores[0]))
  47. //+-------------------------------------------------------------------------
  48. // Local functions called by MicrosoftCertDllVerifyRevocation
  49. //--------------------------------------------------------------------------
  50. PCCERT_CONTEXT GetIssuerCert(
  51. IN DWORD cCert,
  52. IN PCCERT_CONTEXT rgpCert[],
  53. IN DWORD dwFlags,
  54. IN PCERT_REVOCATION_PARA pRevPara
  55. );
  56. BOOL HasUnsupportedCrlCriticalExtension(
  57. IN PCCRL_CONTEXT pCrl
  58. );
  59. // msrevoke specific flags that can be passed to GetTimeValidCrl
  60. #define MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG 0x1
  61. #define MSREVOKE_DELTA_CRL_FLAG 0x2
  62. BOOL GetTimeValidCrl (
  63. IN LPCSTR pszTimeValidOid,
  64. IN LPVOID pvTimeValidPara,
  65. IN PCCERT_CONTEXT pSubject,
  66. IN PCCERT_CONTEXT pIssuer,
  67. IN PCERT_REVOCATION_PARA pRevPara,
  68. IN PCERT_EXTENSION pCDPExt,
  69. IN DWORD dwRevFlags,
  70. IN DWORD dwMsrevokeFlags,
  71. IN FILETIME *pftEndUrlRetrieval,
  72. OUT PCCRL_CONTEXT *ppCrl,
  73. IN OUT BOOL *pfWireRetrieval
  74. );
  75. BOOL GetBaseCrl (
  76. IN PCCERT_CONTEXT pSubject,
  77. IN PCCERT_CONTEXT pIssuer,
  78. IN PCERT_REVOCATION_PARA pRevPara,
  79. IN PCERT_EXTENSION pCDPExt,
  80. IN DWORD dwRevFlags,
  81. IN FILETIME *pftEndUrlRetrieval,
  82. OUT PCCRL_CONTEXT *ppBaseCrl,
  83. OUT BOOL *pfBaseCrlTimeValid,
  84. OUT BOOL *pfBaseWireRetrieval
  85. );
  86. BOOL GetDeltaCrl (
  87. IN PCCERT_CONTEXT pSubject,
  88. IN PCCERT_CONTEXT pIssuer,
  89. IN PCERT_REVOCATION_PARA pRevPara,
  90. IN DWORD dwRevFlags,
  91. IN BOOL fBaseWireRetrieval,
  92. IN FILETIME *pftEndUrlRetrieval,
  93. IN OUT PCCRL_CONTEXT *ppBaseCrl,
  94. IN OUT BOOL *pfCrlTimeValid,
  95. OUT PCCRL_CONTEXT *ppDeltaCrl,
  96. OUT DWORD *pdwFreshnessTime
  97. );
  98. DWORD GetCrlReason(
  99. IN PCRL_ENTRY pCrlEntry
  100. );
  101. BOOL CrlIssuerIsCertIssuer (
  102. IN PCCERT_CONTEXT pCert,
  103. IN PCERT_EXTENSION pCrlDistPointExt
  104. );
  105. //+-------------------------------------------------------------------------
  106. // External functions called by CertDllVerifyRevocation
  107. //--------------------------------------------------------------------------
  108. BOOL
  109. WINAPI
  110. NetscapeCertDllVerifyRevocation(
  111. IN DWORD dwEncodingType,
  112. IN DWORD dwRevType,
  113. IN DWORD cContext,
  114. IN PVOID rgpvContext[],
  115. IN DWORD dwFlags,
  116. IN PVOID pvReserved,
  117. IN OUT PCERT_REVOCATION_STATUS pRevStatus
  118. );
  119. //+-------------------------------------------------------------------------
  120. // MicrosoftCertDllVerifyRevocation using CRL Distribution Points extension.
  121. //--------------------------------------------------------------------------
  122. BOOL
  123. WINAPI
  124. MicrosoftCertDllVerifyRevocation(
  125. IN DWORD dwEncodingType,
  126. IN DWORD dwRevType,
  127. IN DWORD cContext,
  128. IN PVOID rgpvContext[],
  129. IN DWORD dwFlags,
  130. IN PCERT_REVOCATION_PARA pRevPara,
  131. IN OUT PCERT_REVOCATION_STATUS pRevStatus
  132. )
  133. {
  134. BOOL fResult;
  135. DWORD dwIndex = 0;
  136. DWORD dwError = (DWORD) CRYPT_E_NO_REVOCATION_CHECK;
  137. DWORD dwReason = 0;
  138. PCCERT_CONTEXT pCert; // not allocated
  139. PCCERT_CONTEXT pIssuer = NULL;
  140. PCCRL_CONTEXT pBaseCrl = NULL;
  141. PCCRL_CONTEXT pDeltaCrl = NULL;
  142. PCRL_ENTRY pCrlEntry = NULL; // not allocated
  143. BOOL fDeltaCrlEntry = FALSE;
  144. BOOL fCrlTimeValid = FALSE;
  145. BOOL fBaseWireRetrieval = FALSE;
  146. PCERT_EXTENSION pCDPExt;
  147. BOOL fSaveCheckFreshnessTime;
  148. DWORD dwFreshnessTime;
  149. CERT_REVOCATION_PARA RevPara;
  150. FILETIME ftCurrent;
  151. // Following is only used for CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG
  152. FILETIME ftEndUrlRetrieval;
  153. // Ensure we have a structure containing all the possible parameters
  154. memset(&RevPara, 0, sizeof(RevPara));
  155. if (pRevPara != NULL)
  156. memcpy(&RevPara, pRevPara, min(pRevPara->cbSize, sizeof(RevPara)));
  157. RevPara.cbSize = sizeof(RevPara);
  158. if (0 == RevPara.dwUrlRetrievalTimeout)
  159. RevPara.dwUrlRetrievalTimeout = MSREVOKE_TIMEOUT;
  160. if (NULL == RevPara.pftCurrentTime) {
  161. GetSystemTimeAsFileTime(&ftCurrent);
  162. RevPara.pftCurrentTime = &ftCurrent;
  163. }
  164. pRevPara = &RevPara;
  165. if (dwFlags & CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG) {
  166. FILETIME ftStartUrlRetrieval;
  167. GetSystemTimeAsFileTime(&ftStartUrlRetrieval);
  168. I_CryptIncrementFileTimeByMilliseconds(
  169. &ftStartUrlRetrieval, pRevPara->dwUrlRetrievalTimeout,
  170. &ftEndUrlRetrieval);
  171. }
  172. if (cContext == 0)
  173. goto NoContextError;
  174. if (GET_CERT_ENCODING_TYPE(dwEncodingType) != CRYPT_ASN_ENCODING)
  175. goto NoRevocationCheckForEncodingTypeError;
  176. if (dwRevType != CERT_CONTEXT_REVOCATION_TYPE)
  177. goto NoRevocationCheckForRevTypeError;
  178. pCert = (PCCERT_CONTEXT) rgpvContext[0];
  179. // Check if we have a CRL dist point
  180. pCDPExt = CertFindExtension(
  181. szOID_CRL_DIST_POINTS,
  182. pCert->pCertInfo->cExtension,
  183. pCert->pCertInfo->rgExtension
  184. );
  185. // On 04-05-01 changed back to W2K semantics. Continue to check
  186. // if expired certificates are on the CRL.
  187. // If we have a CDP and an expired certificate,
  188. // then, the CA no longer maintains CRL information for the
  189. // certificate. We must consider it as being revoked.
  190. // if (NULL != pCDPExt &&
  191. // 0 < CompareFileTime(RevPara.pftCurrentTime,
  192. // &pCert->pCertInfo->NotAfter)) {
  193. // dwReason = CRL_REASON_CESSATION_OF_OPERATION;
  194. // goto ExpiredCertError;
  195. // }
  196. // Get the certificate's issuer
  197. if (NULL == (pIssuer = GetIssuerCert(
  198. cContext,
  199. (PCCERT_CONTEXT *) rgpvContext,
  200. dwFlags,
  201. &RevPara
  202. )))
  203. goto NoIssuerError;
  204. // Get the Base CRL for the subject certificate.
  205. //
  206. // Remember and disable the freshness retrieval option.
  207. fSaveCheckFreshnessTime = RevPara.fCheckFreshnessTime;
  208. RevPara.fCheckFreshnessTime = FALSE;
  209. if (!GetBaseCrl(
  210. pCert,
  211. pIssuer,
  212. &RevPara,
  213. pCDPExt,
  214. dwFlags,
  215. &ftEndUrlRetrieval,
  216. &pBaseCrl,
  217. &fCrlTimeValid,
  218. &fBaseWireRetrieval
  219. ))
  220. goto GetBaseCrlError;
  221. RevPara.fCheckFreshnessTime = fSaveCheckFreshnessTime;
  222. // If either the base crl or subject cert has a freshest, delta CRL,
  223. // get it
  224. if (!GetDeltaCrl(
  225. pCert,
  226. pIssuer,
  227. &RevPara,
  228. dwFlags,
  229. fBaseWireRetrieval,
  230. &ftEndUrlRetrieval,
  231. &pBaseCrl,
  232. &fCrlTimeValid,
  233. &pDeltaCrl,
  234. &dwFreshnessTime
  235. ))
  236. goto GetDeltaCrlError;
  237. if (NULL == pDeltaCrl) {
  238. dwFreshnessTime = I_CryptSubtractFileTimes(
  239. RevPara.pftCurrentTime, &pBaseCrl->pCrlInfo->ThisUpdate);
  240. if (RevPara.fCheckFreshnessTime) {
  241. if (RevPara.dwFreshnessTime >= dwFreshnessTime)
  242. fCrlTimeValid = TRUE;
  243. else {
  244. // Attempt to get a base CRL with better "freshness"
  245. PCCRL_CONTEXT pNewCrl;
  246. if (GetBaseCrl(
  247. pCert,
  248. pIssuer,
  249. &RevPara,
  250. pCDPExt,
  251. dwFlags,
  252. &ftEndUrlRetrieval,
  253. &pNewCrl,
  254. &fCrlTimeValid,
  255. &fBaseWireRetrieval
  256. )) {
  257. CertFreeCRLContext(pBaseCrl);
  258. pBaseCrl = pNewCrl;
  259. dwFreshnessTime = I_CryptSubtractFileTimes(
  260. RevPara.pftCurrentTime,
  261. &pBaseCrl->pCrlInfo->ThisUpdate);
  262. } else
  263. fCrlTimeValid = FALSE;
  264. }
  265. }
  266. } else {
  267. if (!CertFindCertificateInCRL(
  268. pCert,
  269. pDeltaCrl,
  270. 0, // dwFlags
  271. NULL, // pvReserved
  272. &pCrlEntry
  273. ))
  274. goto CertFindCertificateInDeltaCRLError;
  275. }
  276. if (pCrlEntry) {
  277. // Delta CRL entry
  278. dwReason = GetCrlReason(pCrlEntry);
  279. if (CRL_REASON_REMOVE_FROM_CRL != dwReason)
  280. fDeltaCrlEntry = TRUE;
  281. else {
  282. if (!CertFindCertificateInCRL(
  283. pCert,
  284. pBaseCrl,
  285. 0, // dwFlags
  286. NULL, // pvReserved
  287. &pCrlEntry
  288. ))
  289. goto CertFindCertificateInBaseCRLError;
  290. if (pCrlEntry) {
  291. dwReason = GetCrlReason(pCrlEntry);
  292. if (CRL_REASON_CERTIFICATE_HOLD == dwReason)
  293. pCrlEntry = NULL;
  294. }
  295. if (NULL == pCrlEntry)
  296. dwReason = 0;
  297. }
  298. } else {
  299. if (!CertFindCertificateInCRL(
  300. pCert,
  301. pBaseCrl,
  302. 0, // dwFlags
  303. NULL, // pvReserved
  304. &pCrlEntry
  305. ))
  306. goto CertFindCertificateInBaseCRLError;
  307. if (pCrlEntry)
  308. dwReason = GetCrlReason(pCrlEntry);
  309. }
  310. dwError = 0;
  311. if ( ( pCrlEntry != NULL ) &&
  312. ( ( RevPara.pftTimeToUse == NULL ) ||
  313. ( CompareFileTime(
  314. RevPara.pftTimeToUse,
  315. &pCrlEntry->RevocationDate ) >= 0 ) ) )
  316. {
  317. dwError = (DWORD) CRYPT_E_REVOKED;
  318. }
  319. else if (!fCrlTimeValid)
  320. {
  321. dwError = (DWORD) CRYPT_E_REVOCATION_OFFLINE;
  322. }
  323. if (pRevStatus->cbSize >=
  324. (offsetof(CERT_REVOCATION_STATUS, dwFreshnessTime) +
  325. sizeof(pRevStatus->dwFreshnessTime))) {
  326. pRevStatus->fHasFreshnessTime = TRUE;
  327. pRevStatus->dwFreshnessTime = dwFreshnessTime;
  328. }
  329. if (RevPara.pCrlInfo) {
  330. PCERT_REVOCATION_CRL_INFO pInfo = RevPara.pCrlInfo;
  331. if (pInfo->cbSize >= sizeof(*pInfo)) {
  332. if (pInfo->pBaseCrlContext)
  333. CertFreeCRLContext(pInfo->pBaseCrlContext);
  334. pInfo->pBaseCrlContext = CertDuplicateCRLContext(pBaseCrl);
  335. if (pInfo->pDeltaCrlContext) {
  336. CertFreeCRLContext(pInfo->pDeltaCrlContext);
  337. pInfo->pDeltaCrlContext = NULL;
  338. }
  339. if (pDeltaCrl)
  340. pInfo->pDeltaCrlContext = CertDuplicateCRLContext(pDeltaCrl);
  341. pInfo->fDeltaCrlEntry = fDeltaCrlEntry;
  342. pInfo->pCrlEntry = pCrlEntry;
  343. }
  344. }
  345. CommonReturn:
  346. if (0 == dwError) {
  347. // Successfully checked that the certificate wasn't revoked
  348. if (1 < cContext) {
  349. dwIndex = 1;
  350. dwError = (DWORD) CRYPT_E_NO_REVOCATION_CHECK;
  351. fResult = FALSE;
  352. } else
  353. fResult = TRUE;
  354. } else
  355. fResult = FALSE;
  356. if (pIssuer)
  357. CertFreeCertificateContext(pIssuer);
  358. if (pBaseCrl)
  359. CertFreeCRLContext(pBaseCrl);
  360. if (pDeltaCrl)
  361. CertFreeCRLContext(pDeltaCrl);
  362. pRevStatus->dwIndex = dwIndex;
  363. pRevStatus->dwError = dwError;
  364. pRevStatus->dwReason = dwReason;
  365. SetLastError(dwError);
  366. return fResult;
  367. ErrorReturn:
  368. dwError = GetLastError();
  369. if (0 == dwError)
  370. dwError = (DWORD) E_UNEXPECTED;
  371. goto CommonReturn;
  372. SET_ERROR(NoContextError, E_INVALIDARG)
  373. SET_ERROR(NoRevocationCheckForEncodingTypeError, CRYPT_E_NO_REVOCATION_CHECK)
  374. SET_ERROR(NoRevocationCheckForRevTypeError, CRYPT_E_NO_REVOCATION_CHECK)
  375. // SET_ERROR(ExpiredCertError, CRYPT_E_REVOKED)
  376. TRACE_ERROR(NoIssuerError)
  377. TRACE_ERROR(GetBaseCrlError)
  378. TRACE_ERROR(GetDeltaCrlError)
  379. TRACE_ERROR(CertFindCertificateInDeltaCRLError)
  380. TRACE_ERROR(CertFindCertificateInBaseCRLError)
  381. }
  382. //+---------------------------------------------------------------------------
  383. //
  384. // Function: HasUnsupportedCrlCriticalExtension
  385. //
  386. // Synopsis: checks if the CRL has an unsupported critical section
  387. //
  388. //----------------------------------------------------------------------------
  389. LPCSTR rgpszSupportedCrlExtensionOID[] = {
  390. szOID_DELTA_CRL_INDICATOR,
  391. szOID_ISSUING_DIST_POINT,
  392. szOID_FRESHEST_CRL,
  393. szOID_CRL_NUMBER,
  394. szOID_AUTHORITY_KEY_IDENTIFIER2,
  395. NULL
  396. };
  397. BOOL IsSupportedCrlExtension(
  398. PCERT_EXTENSION pExt
  399. )
  400. {
  401. LPSTR pszExtOID = pExt->pszObjId;
  402. LPCSTR *ppSupOID;
  403. for (ppSupOID = rgpszSupportedCrlExtensionOID;
  404. NULL != *ppSupOID; ppSupOID++) {
  405. if (0 == strcmp(pszExtOID, *ppSupOID))
  406. return TRUE;
  407. }
  408. return FALSE;
  409. }
  410. BOOL HasUnsupportedCrlCriticalExtension(
  411. IN PCCRL_CONTEXT pCrl
  412. )
  413. {
  414. PCRL_INFO pCrlInfo = pCrl->pCrlInfo;
  415. DWORD cExt = pCrlInfo->cExtension;
  416. PCERT_EXTENSION pExt = pCrlInfo->rgExtension;
  417. for ( ; 0 < cExt; cExt--, pExt++) {
  418. if (pExt->fCritical && !IsSupportedCrlExtension(pExt))
  419. return TRUE;
  420. }
  421. return FALSE;
  422. }
  423. //+---------------------------------------------------------------------------
  424. //
  425. // Function: GetTimeValidCrl
  426. //
  427. // Synopsis: get a time valid base or delta CRL
  428. //
  429. //----------------------------------------------------------------------------
  430. BOOL GetTimeValidCrl (
  431. IN LPCSTR pszTimeValidOid,
  432. IN LPVOID pvTimeValidPara,
  433. IN PCCERT_CONTEXT pSubject,
  434. IN PCCERT_CONTEXT pIssuer,
  435. IN PCERT_REVOCATION_PARA pRevPara,
  436. IN PCERT_EXTENSION pCDPExt,
  437. IN DWORD dwRevFlags,
  438. IN DWORD dwMsrevokeFlags,
  439. IN FILETIME *pftEndUrlRetrieval,
  440. OUT PCCRL_CONTEXT *ppCrl,
  441. IN OUT BOOL *pfWireRetrieval
  442. )
  443. {
  444. BOOL fResult = FALSE;
  445. DWORD dwFlags = 0;
  446. FILETIME ftFreshness;
  447. LPFILETIME pftValidFor;
  448. if (pRevPara->fCheckFreshnessTime)
  449. {
  450. I_CryptDecrementFileTimeBySeconds(
  451. pRevPara->pftCurrentTime,
  452. pRevPara->dwFreshnessTime,
  453. &ftFreshness);
  454. pftValidFor = &ftFreshness;
  455. dwFlags |= CRYPT_CHECK_FRESHNESS_TIME_VALIDITY;
  456. }
  457. else
  458. {
  459. pftValidFor = pRevPara->pftCurrentTime;
  460. }
  461. if ( dwMsrevokeFlags & MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG )
  462. {
  463. dwFlags |= CRYPT_DONT_CHECK_TIME_VALIDITY;
  464. }
  465. if ( pCDPExt != NULL )
  466. {
  467. fResult = CryptGetTimeValidObject(
  468. pszTimeValidOid,
  469. pvTimeValidPara,
  470. pIssuer,
  471. pftValidFor,
  472. dwFlags | CRYPT_CACHE_ONLY_RETRIEVAL,
  473. 0, // dwTimeout
  474. (LPVOID *)ppCrl,
  475. NULL, // pCredentials
  476. NULL // pvReserved
  477. );
  478. }
  479. if ( fResult == FALSE )
  480. {
  481. DWORD dwSaveErr = 0;
  482. HCERTSTORE hCrlStore = pRevPara->hCrlStore;
  483. *ppCrl = NULL;
  484. if ( hCrlStore != NULL )
  485. {
  486. PCCRL_CONTEXT pFindCrl = NULL;
  487. DWORD dwFindFlags;
  488. CRL_FIND_ISSUED_FOR_PARA FindPara;
  489. dwSaveErr = GetLastError();
  490. dwFindFlags = CRL_FIND_ISSUED_BY_AKI_FLAG |
  491. CRL_FIND_ISSUED_BY_SIGNATURE_FLAG;
  492. if (dwMsrevokeFlags & MSREVOKE_DELTA_CRL_FLAG)
  493. dwFindFlags |= CRL_FIND_ISSUED_BY_DELTA_FLAG;
  494. else
  495. dwFindFlags |= CRL_FIND_ISSUED_BY_BASE_FLAG;
  496. FindPara.pSubjectCert = pSubject;
  497. FindPara.pIssuerCert = pIssuer;
  498. while ((pFindCrl = CertFindCRLInStore(
  499. hCrlStore,
  500. pIssuer->dwCertEncodingType,
  501. dwFindFlags,
  502. CRL_FIND_ISSUED_FOR,
  503. (const void *) &FindPara,
  504. pFindCrl
  505. )))
  506. {
  507. if (!CertIsValidCRLForCertificate(
  508. pSubject,
  509. pFindCrl,
  510. 0, // dwFlags
  511. NULL // pvReserved
  512. ))
  513. continue;
  514. if ( !(dwMsrevokeFlags &
  515. MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG ))
  516. {
  517. if (pRevPara->fCheckFreshnessTime)
  518. {
  519. if (CompareFileTime(pftValidFor,
  520. &pFindCrl->pCrlInfo->ThisUpdate) > 0)
  521. {
  522. continue;
  523. }
  524. }
  525. else
  526. {
  527. if ( CompareFileTime(
  528. pftValidFor,
  529. &pFindCrl->pCrlInfo->NextUpdate
  530. ) > 0 &&
  531. !I_CryptIsZeroFileTime(
  532. &pFindCrl->pCrlInfo->NextUpdate) )
  533. {
  534. continue;
  535. }
  536. }
  537. }
  538. if ( NULL == *ppCrl )
  539. {
  540. *ppCrl = CertDuplicateCRLContext(pFindCrl);
  541. }
  542. else
  543. {
  544. PCCRL_CONTEXT pPrevCrl = *ppCrl;
  545. // See if this CRL is newer
  546. if ( CompareFileTime(
  547. &pFindCrl->pCrlInfo->ThisUpdate,
  548. &pPrevCrl->pCrlInfo->ThisUpdate
  549. ) > 0 )
  550. {
  551. CertFreeCRLContext(pPrevCrl);
  552. *ppCrl = CertDuplicateCRLContext(pFindCrl);
  553. }
  554. }
  555. }
  556. }
  557. if ( *ppCrl != NULL )
  558. {
  559. return( TRUE );
  560. }
  561. else if ( pCDPExt == NULL )
  562. {
  563. SetLastError( (DWORD) CRYPT_E_NO_REVOCATION_CHECK );
  564. return( FALSE );
  565. }
  566. if ( !( dwRevFlags & CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION ) )
  567. {
  568. if (dwRevFlags & CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG) {
  569. pRevPara->dwUrlRetrievalTimeout =
  570. I_CryptRemainingMilliseconds(pftEndUrlRetrieval);
  571. if (0 == pRevPara->dwUrlRetrievalTimeout)
  572. pRevPara->dwUrlRetrievalTimeout = 1;
  573. dwFlags |= CRYPT_ACCUMULATIVE_TIMEOUT;
  574. }
  575. fResult = CryptGetTimeValidObject(
  576. pszTimeValidOid,
  577. pvTimeValidPara,
  578. pIssuer,
  579. pftValidFor,
  580. dwFlags | CRYPT_WIRE_ONLY_RETRIEVAL,
  581. pRevPara->dwUrlRetrievalTimeout,
  582. (LPVOID *)ppCrl,
  583. NULL, // pCredentials
  584. NULL // pvReserved
  585. );
  586. *pfWireRetrieval = TRUE;
  587. }
  588. else if ( hCrlStore != NULL )
  589. {
  590. SetLastError( dwSaveErr );
  591. }
  592. assert( pCDPExt );
  593. if (!fResult)
  594. {
  595. if ( CRYPT_E_NOT_FOUND == GetLastError() )
  596. {
  597. SetLastError( (DWORD) CRYPT_E_NO_REVOCATION_CHECK );
  598. }
  599. else
  600. {
  601. SetLastError( (DWORD) CRYPT_E_REVOCATION_OFFLINE );
  602. }
  603. }
  604. }
  605. return( fResult );
  606. }
  607. //+---------------------------------------------------------------------------
  608. //
  609. // Function: GetBaseCrl
  610. //
  611. // Synopsis: get the base CRL associated with the subject certificate
  612. //
  613. //----------------------------------------------------------------------------
  614. BOOL GetBaseCrl (
  615. IN PCCERT_CONTEXT pSubject,
  616. IN PCCERT_CONTEXT pIssuer,
  617. IN PCERT_REVOCATION_PARA pRevPara,
  618. IN PCERT_EXTENSION pCDPExt,
  619. IN DWORD dwRevFlags,
  620. IN FILETIME *pftEndUrlRetrieval,
  621. OUT PCCRL_CONTEXT *ppBaseCrl,
  622. OUT BOOL *pfBaseCrlTimeValid,
  623. OUT BOOL *pfBaseWireRetrieval
  624. )
  625. {
  626. BOOL fResult;
  627. PCCRL_CONTEXT pBaseCrl = NULL;
  628. *pfBaseWireRetrieval = FALSE;
  629. if (GetTimeValidCrl(
  630. TIME_VALID_OID_GET_CRL_FROM_CERT,
  631. (LPVOID) pSubject,
  632. pSubject,
  633. pIssuer,
  634. pRevPara,
  635. pCDPExt,
  636. dwRevFlags,
  637. 0, // dwMsrevokeFlags
  638. pftEndUrlRetrieval,
  639. &pBaseCrl,
  640. pfBaseWireRetrieval
  641. )) {
  642. *pfBaseCrlTimeValid = TRUE;
  643. } else {
  644. *pfBaseCrlTimeValid = FALSE;
  645. if (!GetTimeValidCrl(
  646. TIME_VALID_OID_GET_CRL_FROM_CERT,
  647. (LPVOID) pSubject,
  648. pSubject,
  649. pIssuer,
  650. pRevPara,
  651. pCDPExt,
  652. dwRevFlags,
  653. MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG,
  654. pftEndUrlRetrieval,
  655. &pBaseCrl,
  656. pfBaseWireRetrieval
  657. ))
  658. {
  659. goto GetTimeInvalidCrlError;
  660. }
  661. }
  662. if (HasUnsupportedCrlCriticalExtension(pBaseCrl))
  663. goto HasUnsupportedCriticalExtensionError;
  664. fResult = TRUE;
  665. CommonReturn:
  666. *ppBaseCrl = pBaseCrl;
  667. return fResult;
  668. ErrorReturn:
  669. if (pBaseCrl) {
  670. CertFreeCRLContext(pBaseCrl);
  671. pBaseCrl = NULL;
  672. }
  673. fResult = FALSE;
  674. goto CommonReturn;
  675. TRACE_ERROR(GetTimeInvalidCrlError)
  676. SET_ERROR(HasUnsupportedCriticalExtensionError, CRYPT_E_NO_REVOCATION_CHECK)
  677. }
  678. //+---------------------------------------------------------------------------
  679. //
  680. // Function: GetDeltaCrl
  681. //
  682. // Synopsis: get the delta CRL associated with the subject certificate and
  683. // its base CRL
  684. //
  685. // For now, always return TRUE. If not able to find a delta CRL, set
  686. // *pfCrlTimeValid to FALSE.
  687. //
  688. //----------------------------------------------------------------------------
  689. BOOL GetDeltaCrl (
  690. IN PCCERT_CONTEXT pSubject,
  691. IN PCCERT_CONTEXT pIssuer,
  692. IN PCERT_REVOCATION_PARA pRevPara,
  693. IN DWORD dwRevFlags,
  694. IN BOOL fBaseWireRetrieval,
  695. IN FILETIME *pftEndUrlRetrieval,
  696. IN OUT PCCRL_CONTEXT *ppBaseCrl,
  697. IN OUT BOOL *pfCrlTimeValid,
  698. OUT PCCRL_CONTEXT *ppDeltaCrl,
  699. OUT DWORD *pdwFreshnessTime
  700. )
  701. {
  702. PCERT_EXTENSION pFreshestExt;
  703. PCCRL_CONTEXT pBaseCrl = *ppBaseCrl;
  704. PCCRL_CONTEXT pDeltaCrl = NULL;
  705. LPCSTR pszTimeValidOid;
  706. LPVOID pvTimeValidPara;
  707. CERT_CRL_CONTEXT_PAIR CertCrlPair;
  708. BOOL fDeltaWireRetrieval;
  709. PCERT_EXTENSION pBaseCrlNumberExt;
  710. PCERT_EXTENSION pDeltaCrlIndicatorExt;
  711. int iBaseCrlNumber = 0;
  712. int iDeltaCrlIndicator = 0;
  713. DWORD cbInt;
  714. LPFILETIME pFreshnessThisUpdate;
  715. assert(pBaseCrl);
  716. // Check if the base CRL or the subject certificate has a freshest
  717. // ext
  718. if (pFreshestExt = CertFindExtension(
  719. szOID_FRESHEST_CRL,
  720. pBaseCrl->pCrlInfo->cExtension,
  721. pBaseCrl->pCrlInfo->rgExtension
  722. )) {
  723. pszTimeValidOid = TIME_VALID_OID_GET_FRESHEST_CRL_FROM_CRL;
  724. CertCrlPair.pCertContext = pSubject;
  725. CertCrlPair.pCrlContext = pBaseCrl;
  726. pvTimeValidPara = (LPVOID) &CertCrlPair;
  727. } else if (pFreshestExt = CertFindExtension(
  728. szOID_FRESHEST_CRL,
  729. pSubject->pCertInfo->cExtension,
  730. pSubject->pCertInfo->rgExtension
  731. )) {
  732. pszTimeValidOid = TIME_VALID_OID_GET_FRESHEST_CRL_FROM_CERT;
  733. pvTimeValidPara = (LPVOID) pSubject;
  734. } else {
  735. goto NoDeltaCrlReturn;
  736. }
  737. if (GetTimeValidCrl(
  738. pszTimeValidOid,
  739. pvTimeValidPara,
  740. pSubject,
  741. pIssuer,
  742. pRevPara,
  743. pFreshestExt,
  744. dwRevFlags,
  745. MSREVOKE_DELTA_CRL_FLAG,
  746. pftEndUrlRetrieval,
  747. &pDeltaCrl,
  748. &fDeltaWireRetrieval
  749. )) {
  750. *pfCrlTimeValid = TRUE;
  751. } else {
  752. *pfCrlTimeValid = FALSE;
  753. if (!GetTimeValidCrl(
  754. pszTimeValidOid,
  755. pvTimeValidPara,
  756. pSubject,
  757. pIssuer,
  758. pRevPara,
  759. pFreshestExt,
  760. dwRevFlags,
  761. MSREVOKE_DELTA_CRL_FLAG |
  762. MSREVOKE_DONT_CHECK_TIME_VALIDITY_FLAG,
  763. pftEndUrlRetrieval,
  764. &pDeltaCrl,
  765. &fDeltaWireRetrieval
  766. ))
  767. {
  768. goto GetTimeInvalidCrlError;
  769. }
  770. }
  771. if (HasUnsupportedCrlCriticalExtension(pDeltaCrl))
  772. goto HasUnsupportedCriticalExtensionError;
  773. // Check that the base CRL number >= delta CRL indicator
  774. if (NULL == (pBaseCrlNumberExt = CertFindExtension(
  775. szOID_CRL_NUMBER,
  776. pBaseCrl->pCrlInfo->cExtension,
  777. pBaseCrl->pCrlInfo->rgExtension
  778. )))
  779. goto MissingBaseCrlNumberError;
  780. if (NULL == (pDeltaCrlIndicatorExt = CertFindExtension(
  781. szOID_DELTA_CRL_INDICATOR,
  782. pDeltaCrl->pCrlInfo->cExtension,
  783. pDeltaCrl->pCrlInfo->rgExtension
  784. )))
  785. goto MissingDeltaCrlIndicatorError;
  786. cbInt = sizeof(iBaseCrlNumber);
  787. if (!CryptDecodeObject(
  788. pBaseCrl->dwCertEncodingType,
  789. X509_INTEGER,
  790. pBaseCrlNumberExt->Value.pbData,
  791. pBaseCrlNumberExt->Value.cbData,
  792. 0, // dwFlags
  793. &iBaseCrlNumber,
  794. &cbInt
  795. ))
  796. goto DecodeBaseCrlNumberError;
  797. cbInt = sizeof(iDeltaCrlIndicator);
  798. if (!CryptDecodeObject(
  799. pDeltaCrl->dwCertEncodingType,
  800. X509_INTEGER,
  801. pDeltaCrlIndicatorExt->Value.pbData,
  802. pDeltaCrlIndicatorExt->Value.cbData,
  803. 0, // dwFlags
  804. &iDeltaCrlIndicator,
  805. &cbInt
  806. ))
  807. goto DecodeDeltaCrlIndicatorError;
  808. pFreshnessThisUpdate = &pDeltaCrl->pCrlInfo->ThisUpdate;
  809. if (iBaseCrlNumber < iDeltaCrlIndicator) {
  810. BOOL fValidBaseCrl = FALSE;
  811. if (!fBaseWireRetrieval &&
  812. 0 == (dwRevFlags & CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION)) {
  813. // Attempt to get a more recent base CRL by hitting the wire
  814. PCCRL_CONTEXT pWireBaseCrl = NULL;
  815. CRL_IS_VALID_EXTRA_INFO CrlIsValidExtraInfo =
  816. { iDeltaCrlIndicator };
  817. if (CryptGetTimeValidObject(
  818. TIME_VALID_OID_GET_CRL_FROM_CERT,
  819. (LPVOID)pSubject,
  820. pIssuer,
  821. NULL, // pftValidFor
  822. CRYPT_WIRE_ONLY_RETRIEVAL | CRYPT_DONT_CHECK_TIME_VALIDITY,
  823. pRevPara->dwUrlRetrievalTimeout,
  824. (LPVOID *) &pWireBaseCrl,
  825. NULL, // pCredentials
  826. &CrlIsValidExtraInfo
  827. )) {
  828. // Already checked that the new Base CRL number is valid
  829. CertFreeCRLContext(pBaseCrl);
  830. *ppBaseCrl = pBaseCrl = pWireBaseCrl;
  831. fValidBaseCrl = TRUE;
  832. }
  833. }
  834. if (!fValidBaseCrl) {
  835. *pfCrlTimeValid = FALSE;
  836. pFreshnessThisUpdate = &pBaseCrl->pCrlInfo->ThisUpdate;
  837. }
  838. }
  839. *pdwFreshnessTime = I_CryptSubtractFileTimes(
  840. pRevPara->pftCurrentTime, pFreshnessThisUpdate);
  841. if (pRevPara->fCheckFreshnessTime) {
  842. if (pRevPara->dwFreshnessTime >= *pdwFreshnessTime)
  843. *pfCrlTimeValid = TRUE;
  844. else
  845. *pfCrlTimeValid = FALSE;
  846. }
  847. NoDeltaCrlReturn:
  848. CommonReturn:
  849. *ppDeltaCrl = pDeltaCrl;
  850. return TRUE;
  851. ErrorReturn:
  852. if (pDeltaCrl) {
  853. CertFreeCRLContext(pDeltaCrl);
  854. pDeltaCrl = NULL;
  855. }
  856. *pfCrlTimeValid = FALSE;
  857. goto CommonReturn;
  858. TRACE_ERROR(GetTimeInvalidCrlError)
  859. SET_ERROR(HasUnsupportedCriticalExtensionError, CRYPT_E_NO_REVOCATION_CHECK)
  860. SET_ERROR(MissingBaseCrlNumberError, CRYPT_E_NO_REVOCATION_CHECK)
  861. SET_ERROR(MissingDeltaCrlIndicatorError, CRYPT_E_NO_REVOCATION_CHECK)
  862. TRACE_ERROR(DecodeBaseCrlNumberError)
  863. TRACE_ERROR(DecodeDeltaCrlIndicatorError)
  864. }
  865. //+-------------------------------------------------------------------------
  866. // If the CRL entry has a CRL Reason extension, the enumerated reason
  867. // code is returned. Otherwise, a reason code of 0 is returned.
  868. //--------------------------------------------------------------------------
  869. DWORD GetCrlReason(
  870. IN PCRL_ENTRY pCrlEntry
  871. )
  872. {
  873. DWORD dwReason = 0;
  874. PCERT_EXTENSION pExt;
  875. // Check if the certificate has a szOID_CRL_REASON_CODE extension
  876. if (pExt = CertFindExtension(
  877. szOID_CRL_REASON_CODE,
  878. pCrlEntry->cExtension,
  879. pCrlEntry->rgExtension
  880. )) {
  881. DWORD cbInfo = sizeof(dwReason);
  882. CryptDecodeObject(
  883. CRYPT_ASN_ENCODING,
  884. X509_CRL_REASON_CODE,
  885. pExt->Value.pbData,
  886. pExt->Value.cbData,
  887. 0, // dwFlags
  888. &dwReason,
  889. &cbInfo);
  890. }
  891. return dwReason;
  892. }
  893. //+=========================================================================
  894. // Get Issuer Certificate Functions
  895. //==========================================================================
  896. PCCERT_CONTEXT FindIssuerCertInStores(
  897. IN PCCERT_CONTEXT pSubjectCert,
  898. IN DWORD cStore,
  899. IN HCERTSTORE rgStore[]
  900. )
  901. {
  902. PCCERT_CONTEXT pIssuerCert = NULL;
  903. DWORD i;
  904. for (i = 0; i < cStore; i++) {
  905. while (TRUE) {
  906. DWORD dwFlags = CERT_STORE_SIGNATURE_FLAG;
  907. pIssuerCert = CertGetIssuerCertificateFromStore(
  908. rgStore[i],
  909. pSubjectCert,
  910. pIssuerCert,
  911. &dwFlags);
  912. if (NULL == pIssuerCert) {
  913. if (CRYPT_E_SELF_SIGNED == GetLastError()) {
  914. if (0 == (dwFlags & CERT_STORE_SIGNATURE_FLAG))
  915. pIssuerCert = CertDuplicateCertificateContext(
  916. pSubjectCert);
  917. return pIssuerCert;
  918. }
  919. break;
  920. } else if (0 == (dwFlags & CERT_STORE_SIGNATURE_FLAG))
  921. return pIssuerCert;
  922. }
  923. }
  924. return NULL;
  925. }
  926. static PCCERT_CONTEXT FindIssuerCertInDefaultStores(
  927. IN PCCERT_CONTEXT pSubjectCert
  928. )
  929. {
  930. PCCERT_CONTEXT pIssuerCert;
  931. HCERTSTORE hStore;
  932. DWORD i;
  933. for (i = 0; i < NUM_DEFAULT_ISSUER_STORES; i++) {
  934. if (hStore = CertOpenStore(
  935. CERT_STORE_PROV_SYSTEM_W,
  936. 0, // dwEncodingType
  937. 0, // hCryptProv
  938. rgDefaultIssuerStores[i].dwFlags | CERT_STORE_READONLY_FLAG,
  939. (const void *) rgDefaultIssuerStores[i].pwszStore
  940. )) {
  941. pIssuerCert = FindIssuerCertInStores(pSubjectCert, 1, &hStore);
  942. CertCloseStore(hStore, 0);
  943. if (pIssuerCert)
  944. return pIssuerCert;
  945. }
  946. }
  947. return NULL;
  948. }
  949. //+-------------------------------------------------------------------------
  950. // Get the issuer of the first certificate in the array
  951. //
  952. // Note, pRevPara is our copy and guaranteed to contain all the fields.
  953. //--------------------------------------------------------------------------
  954. PCCERT_CONTEXT GetIssuerCert(
  955. IN DWORD cCert,
  956. IN PCCERT_CONTEXT rgpCert[],
  957. IN DWORD dwFlags,
  958. IN PCERT_REVOCATION_PARA pRevPara
  959. )
  960. {
  961. PCCERT_CONTEXT pSubjectCert;
  962. PCCERT_CONTEXT pIssuerCert = NULL;
  963. assert(cCert >= 1);
  964. pSubjectCert = rgpCert[0];
  965. if (cCert == 1) {
  966. pIssuerCert = pRevPara->pIssuerCert;
  967. if (NULL == pIssuerCert && CertCompareCertificateName(
  968. pSubjectCert->dwCertEncodingType,
  969. &pSubjectCert->pCertInfo->Subject,
  970. &pSubjectCert->pCertInfo->Issuer))
  971. // Self issued
  972. pIssuerCert = pSubjectCert;
  973. } else if (dwFlags & CERT_VERIFY_REV_CHAIN_FLAG)
  974. pIssuerCert = rgpCert[1];
  975. if (pIssuerCert)
  976. pIssuerCert = CertDuplicateCertificateContext(pIssuerCert);
  977. else {
  978. pIssuerCert = FindIssuerCertInStores(
  979. pSubjectCert, pRevPara->cCertStore, pRevPara->rgCertStore);
  980. if (NULL == pIssuerCert)
  981. pIssuerCert = FindIssuerCertInDefaultStores(pSubjectCert);
  982. }
  983. if (NULL == pIssuerCert)
  984. SetLastError((DWORD) CRYPT_E_REVOCATION_OFFLINE);
  985. return pIssuerCert;
  986. }
  987. //+---------------------------------------------------------------------------
  988. //
  989. // Function: CrlIssuerIsCertIssuer
  990. //
  991. // Synopsis: is the issuer of the CRL the issuer of the cert
  992. //
  993. //----------------------------------------------------------------------------
  994. BOOL CrlIssuerIsCertIssuer (
  995. IN PCCERT_CONTEXT pCert,
  996. IN PCERT_EXTENSION pCrlDistPointExt
  997. )
  998. {
  999. BOOL fResult = FALSE;
  1000. DWORD cb = sizeof( PCRL_DIST_POINTS_INFO );
  1001. PCRL_DIST_POINTS_INFO pDistPointInfo;
  1002. if ( pCrlDistPointExt == NULL )
  1003. {
  1004. return( TRUE );
  1005. }
  1006. if ( CryptDecodeObjectEx(
  1007. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1008. szOID_CRL_DIST_POINTS,
  1009. pCrlDistPointExt->Value.pbData,
  1010. pCrlDistPointExt->Value.cbData,
  1011. CRYPT_DECODE_ALLOC_FLAG,
  1012. NULL,
  1013. (void *)&pDistPointInfo,
  1014. &cb
  1015. ) == TRUE )
  1016. {
  1017. if ( pDistPointInfo->cDistPoint > 0 )
  1018. {
  1019. if ( pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.cAltEntry == 0 )
  1020. {
  1021. fResult = TRUE;
  1022. }
  1023. else if ( pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.rgAltEntry[ 0 ].dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME )
  1024. {
  1025. if ( pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.rgAltEntry[ 0 ].DirectoryName.cbData == 0 )
  1026. {
  1027. fResult = TRUE;
  1028. }
  1029. else if ( ( pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.rgAltEntry[ 0 ].DirectoryName.cbData ==
  1030. pCert->pCertInfo->Issuer.cbData ) &&
  1031. ( memcmp(
  1032. pDistPointInfo->rgDistPoint[ 0 ].CRLIssuer.rgAltEntry[ 0 ].DirectoryName.pbData,
  1033. pCert->pCertInfo->Issuer.pbData,
  1034. pCert->pCertInfo->Issuer.cbData
  1035. ) == 0 ) )
  1036. {
  1037. fResult = TRUE;
  1038. }
  1039. }
  1040. }
  1041. else
  1042. {
  1043. fResult = TRUE;
  1044. }
  1045. LocalFree( pDistPointInfo );
  1046. }
  1047. return( fResult );
  1048. }
  1049. //+---------------------------------------------------------------------------
  1050. //
  1051. // Function: CertDllVerifyRevocation
  1052. //
  1053. // Synopsis: Dispatches to msrevoke
  1054. //
  1055. //----------------------------------------------------------------------------
  1056. BOOL WINAPI
  1057. CertDllVerifyRevocation(
  1058. IN DWORD dwEncodingType,
  1059. IN DWORD dwRevType,
  1060. IN DWORD cContext,
  1061. IN PVOID rgpvContext[],
  1062. IN DWORD dwFlags,
  1063. IN PCERT_REVOCATION_PARA pRevPara,
  1064. IN OUT PCERT_REVOCATION_STATUS pRevStatus
  1065. )
  1066. {
  1067. return MicrosoftCertDllVerifyRevocation(
  1068. dwEncodingType,
  1069. dwRevType,
  1070. cContext,
  1071. rgpvContext,
  1072. dwFlags,
  1073. pRevPara,
  1074. pRevStatus
  1075. );
  1076. }