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.

466 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. // Microsoft Windows
  3. //
  4. // Copyright (C) Microsoft Corporation, 2001 - 2001
  5. //
  6. // File: mscrlrev.cpp
  7. //
  8. // Contents: Check CRLs in CA store version of CertDllVerifyRevocation.
  9. //
  10. // Restrictions:
  11. // - Only support CRYPT_ASN_ENCODING
  12. // - CRL must already be in the CA system store
  13. // - CRL must be issued and signed by the issuer of the
  14. // certificate
  15. // - CRL must not have any critical extensions
  16. //
  17. // Functions: DllMain
  18. // DllRegisterServer
  19. // DllUnregisterServer
  20. // CertDllVerifyRevocation
  21. //
  22. // History: 15-Mar-01 philh created
  23. //--------------------------------------------------------------------------
  24. #include "global.hxx"
  25. #include <dbgdef.h>
  26. //+-------------------------------------------------------------------------
  27. // Default stores searched to find an issuer of the subject certificate
  28. //--------------------------------------------------------------------------
  29. struct {
  30. LPCWSTR pwszStore;
  31. DWORD dwFlags;
  32. } rgDefaultIssuerStores[] = {
  33. L"CA", CERT_SYSTEM_STORE_CURRENT_USER,
  34. L"ROOT", CERT_SYSTEM_STORE_CURRENT_USER
  35. };
  36. #define NUM_DEFAULT_ISSUER_STORES (sizeof(rgDefaultIssuerStores) / \
  37. sizeof(rgDefaultIssuerStores[0]))
  38. //+-------------------------------------------------------------------------
  39. // Dll initialization
  40. //--------------------------------------------------------------------------
  41. BOOL
  42. WINAPI
  43. DllMain(
  44. HMODULE hInst,
  45. ULONG ulReason,
  46. LPVOID lpReserved)
  47. {
  48. switch (ulReason) {
  49. case DLL_PROCESS_ATTACH:
  50. break;
  51. case DLL_PROCESS_DETACH:
  52. case DLL_THREAD_DETACH:
  53. default:
  54. break;
  55. }
  56. return TRUE;
  57. }
  58. HRESULT HError()
  59. {
  60. DWORD dw = GetLastError();
  61. HRESULT hr;
  62. if ( dw <= 0xFFFF )
  63. hr = HRESULT_FROM_WIN32 ( dw );
  64. else
  65. hr = dw;
  66. if ( ! FAILED ( hr ) )
  67. {
  68. // somebody failed a call without properly setting an error condition
  69. hr = E_UNEXPECTED;
  70. }
  71. return hr;
  72. }
  73. //+-------------------------------------------------------------------------
  74. // DllRegisterServer
  75. //--------------------------------------------------------------------------
  76. STDAPI DllRegisterServer(void)
  77. {
  78. if (!CryptRegisterDefaultOIDFunction(
  79. X509_ASN_ENCODING,
  80. CRYPT_OID_VERIFY_REVOCATION_FUNC,
  81. CRYPT_REGISTER_FIRST_INDEX,
  82. L"mscrlrev.dll"
  83. )) {
  84. if (ERROR_FILE_EXISTS != GetLastError())
  85. return HError();
  86. }
  87. return S_OK;
  88. }
  89. //+-------------------------------------------------------------------------
  90. // DllUnregisterServer
  91. //--------------------------------------------------------------------------
  92. STDAPI DllUnregisterServer(void)
  93. {
  94. if (!CryptUnregisterDefaultOIDFunction(
  95. X509_ASN_ENCODING,
  96. CRYPT_OID_VERIFY_REVOCATION_FUNC,
  97. L"mscrlrev.dll"
  98. )) {
  99. if (ERROR_FILE_NOT_FOUND != GetLastError())
  100. return HError();
  101. }
  102. return S_OK;
  103. }
  104. //+-------------------------------------------------------------------------
  105. // Local functions called by CertDllVerifyRevocation
  106. //--------------------------------------------------------------------------
  107. PCCERT_CONTEXT GetIssuerCert(
  108. IN DWORD cCert,
  109. IN PCCERT_CONTEXT rgpCert[],
  110. IN DWORD dwFlags,
  111. IN PCERT_REVOCATION_PARA pRevPara
  112. );
  113. BOOL GetSubjectCrl (
  114. IN PCCERT_CONTEXT pSubject,
  115. IN PCCERT_CONTEXT pIssuer,
  116. OUT PCCRL_CONTEXT* ppCrl
  117. );
  118. PCRL_ENTRY FindCertInCrl(
  119. IN PCCERT_CONTEXT pCert,
  120. IN PCCRL_CONTEXT pCrl,
  121. IN PCERT_REVOCATION_PARA pRevPara
  122. );
  123. DWORD GetCrlReason(
  124. IN PCRL_ENTRY pCrlEntry
  125. );
  126. //+-------------------------------------------------------------------------
  127. // CertDllVerifyRevocation using pre-loaded CRLs in the CA store
  128. //--------------------------------------------------------------------------
  129. BOOL
  130. WINAPI
  131. CertDllVerifyRevocation(
  132. IN DWORD dwEncodingType,
  133. IN DWORD dwRevType,
  134. IN DWORD cContext,
  135. IN PVOID rgpvContext[],
  136. IN DWORD dwFlags,
  137. IN PCERT_REVOCATION_PARA pRevPara,
  138. IN OUT PCERT_REVOCATION_STATUS pRevStatus
  139. )
  140. {
  141. DWORD dwError = (DWORD) CRYPT_E_NO_REVOCATION_CHECK;
  142. DWORD dwReason = 0;
  143. PCCERT_CONTEXT pCert; // not allocated
  144. PCCERT_CONTEXT pIssuer = NULL;
  145. PCCRL_CONTEXT pCrl = NULL;
  146. PCRL_ENTRY pCrlEntry;
  147. if (cContext == 0)
  148. goto NoContextError;
  149. if (GET_CERT_ENCODING_TYPE(dwEncodingType) != CRYPT_ASN_ENCODING)
  150. goto NoRevocationCheckForEncodingTypeError;
  151. if (dwRevType != CERT_CONTEXT_REVOCATION_TYPE)
  152. goto NoRevocationCheckForRevTypeError;
  153. pCert = (PCCERT_CONTEXT) rgpvContext[0];
  154. // Get the certificate's issuer
  155. if (NULL == (pIssuer = GetIssuerCert(
  156. cContext,
  157. (PCCERT_CONTEXT *) rgpvContext,
  158. dwFlags,
  159. pRevPara
  160. )))
  161. goto NoIssuerError;
  162. if (!GetSubjectCrl(
  163. pCert,
  164. pIssuer,
  165. &pCrl
  166. ))
  167. goto NoCrl;
  168. // Check if revoked
  169. pCrlEntry = FindCertInCrl(pCert, pCrl, pRevPara);
  170. if (pCrlEntry) {
  171. dwError = (DWORD) CRYPT_E_REVOKED;
  172. dwReason = GetCrlReason(pCrlEntry);
  173. goto Revoked;
  174. }
  175. CommonReturn:
  176. if (pIssuer)
  177. CertFreeCertificateContext(pIssuer);
  178. if (pCrl)
  179. CertFreeCRLContext(pCrl);
  180. pRevStatus->dwIndex = 0;
  181. pRevStatus->dwError = dwError;
  182. pRevStatus->dwReason = dwReason;
  183. SetLastError(dwError);
  184. return FALSE;
  185. ErrorReturn:
  186. goto CommonReturn;
  187. TRACE_ERROR(NoContextError)
  188. TRACE_ERROR(NoRevocationCheckForEncodingTypeError)
  189. TRACE_ERROR(NoRevocationCheckForRevTypeError)
  190. TRACE_ERROR(NoIssuerError)
  191. TRACE_ERROR(NoCrl)
  192. TRACE_ERROR(Revoked)
  193. }
  194. //+-------------------------------------------------------------------------
  195. // If the CRL entry has a CRL Reason extension, the enumerated reason
  196. // code is returned. Otherwise, a reason code of 0 is returned.
  197. //--------------------------------------------------------------------------
  198. DWORD GetCrlReason(
  199. IN PCRL_ENTRY pCrlEntry
  200. )
  201. {
  202. DWORD dwReason = 0;
  203. PCERT_EXTENSION pExt;
  204. // Check if the certificate has a szOID_CRL_REASON_CODE extension
  205. if (pExt = CertFindExtension(
  206. szOID_CRL_REASON_CODE,
  207. pCrlEntry->cExtension,
  208. pCrlEntry->rgExtension
  209. )) {
  210. DWORD cbInfo = sizeof(dwReason);
  211. CryptDecodeObject(
  212. CRYPT_ASN_ENCODING,
  213. X509_CRL_REASON_CODE,
  214. pExt->Value.pbData,
  215. pExt->Value.cbData,
  216. 0, // dwFlags
  217. &dwReason,
  218. &cbInfo);
  219. }
  220. return dwReason;
  221. }
  222. //+=========================================================================
  223. // Get Issuer Certificate Functions
  224. //==========================================================================
  225. PCCERT_CONTEXT FindIssuerCertInStores(
  226. IN PCCERT_CONTEXT pSubjectCert,
  227. IN DWORD cStore,
  228. IN HCERTSTORE rgStore[]
  229. )
  230. {
  231. PCCERT_CONTEXT pIssuerCert = NULL;
  232. DWORD i;
  233. for (i = 0; i < cStore; i++) {
  234. while (TRUE) {
  235. DWORD dwFlags = CERT_STORE_SIGNATURE_FLAG;
  236. pIssuerCert = CertGetIssuerCertificateFromStore(
  237. rgStore[i],
  238. pSubjectCert,
  239. pIssuerCert,
  240. &dwFlags);
  241. if (NULL == pIssuerCert)
  242. break;
  243. else if (0 == (dwFlags & CERT_STORE_SIGNATURE_FLAG))
  244. return pIssuerCert;
  245. }
  246. }
  247. return NULL;
  248. }
  249. PCCERT_CONTEXT FindIssuerCertInDefaultStores(
  250. IN PCCERT_CONTEXT pSubjectCert
  251. )
  252. {
  253. PCCERT_CONTEXT pIssuerCert;
  254. HCERTSTORE hStore;
  255. DWORD i;
  256. for (i = 0; i < NUM_DEFAULT_ISSUER_STORES; i++) {
  257. if (hStore = CertOpenStore(
  258. CERT_STORE_PROV_SYSTEM_W,
  259. 0, // dwEncodingType
  260. 0, // hCryptProv
  261. rgDefaultIssuerStores[i].dwFlags | CERT_STORE_READONLY_FLAG,
  262. (const void *) rgDefaultIssuerStores[i].pwszStore
  263. )) {
  264. pIssuerCert = FindIssuerCertInStores(pSubjectCert, 1, &hStore);
  265. CertCloseStore(hStore, 0);
  266. if (pIssuerCert)
  267. return pIssuerCert;
  268. }
  269. }
  270. return NULL;
  271. }
  272. //+-------------------------------------------------------------------------
  273. // Get the issuer of the first certificate in the array
  274. //--------------------------------------------------------------------------
  275. PCCERT_CONTEXT GetIssuerCert(
  276. IN DWORD cCert,
  277. IN PCCERT_CONTEXT rgpCert[],
  278. IN DWORD dwFlags,
  279. IN PCERT_REVOCATION_PARA pRevPara
  280. )
  281. {
  282. PCCERT_CONTEXT pSubjectCert;
  283. PCCERT_CONTEXT pIssuerCert = NULL;
  284. assert(cCert >= 1);
  285. pSubjectCert = rgpCert[0];
  286. if (cCert == 1) {
  287. if (pRevPara && pRevPara->cbSize >=
  288. (offsetof(CERT_REVOCATION_PARA, pIssuerCert) +
  289. sizeof(pRevPara->pIssuerCert)))
  290. pIssuerCert = pRevPara->pIssuerCert;
  291. if (NULL == pIssuerCert && CertCompareCertificateName(
  292. pSubjectCert->dwCertEncodingType,
  293. &pSubjectCert->pCertInfo->Subject,
  294. &pSubjectCert->pCertInfo->Issuer))
  295. // Self issued
  296. pIssuerCert = pSubjectCert;
  297. } else if (dwFlags && CERT_VERIFY_REV_CHAIN_FLAG)
  298. pIssuerCert = rgpCert[1];
  299. if (pIssuerCert)
  300. pIssuerCert = CertDuplicateCertificateContext(pIssuerCert);
  301. else {
  302. if (pRevPara && pRevPara->cbSize >=
  303. (offsetof(CERT_REVOCATION_PARA, rgCertStore) +
  304. sizeof(pRevPara->rgCertStore)))
  305. pIssuerCert = FindIssuerCertInStores(
  306. pSubjectCert, pRevPara->cCertStore, pRevPara->rgCertStore);
  307. if (NULL == pIssuerCert)
  308. pIssuerCert = FindIssuerCertInDefaultStores(pSubjectCert);
  309. }
  310. if (NULL == pIssuerCert)
  311. SetLastError(CRYPT_E_NO_REVOCATION_CHECK);
  312. return pIssuerCert;
  313. }
  314. //+-------------------------------------------------------------------------
  315. // Check that the CRL doesn't have any critical extensions
  316. //--------------------------------------------------------------------------
  317. BOOL IsExtensionValidCrl(
  318. IN PCCRL_CONTEXT pCrl
  319. )
  320. {
  321. DWORD cExt = pCrl->pCrlInfo->cExtension;
  322. PCERT_EXTENSION pExt = pCrl->pCrlInfo->rgExtension;
  323. for ( ; cExt > 0; cExt--, pExt++) {
  324. if (pExt->fCritical)
  325. return FALSE;
  326. }
  327. return TRUE;
  328. }
  329. //+---------------------------------------------------------------------------
  330. //
  331. // Function: GetSubjectCrl
  332. //
  333. // Synopsis: get the CRL associated with the subject certificate
  334. //
  335. //----------------------------------------------------------------------------
  336. BOOL GetSubjectCrl (
  337. IN PCCERT_CONTEXT pSubject,
  338. IN PCCERT_CONTEXT pIssuer,
  339. OUT PCCRL_CONTEXT* ppCrl
  340. )
  341. {
  342. BOOL fResult;
  343. HCERTSTORE hStore;
  344. PCCRL_CONTEXT pFindCrl = NULL;
  345. DWORD dwGetCrlFlags = CERT_STORE_SIGNATURE_FLAG;
  346. *ppCrl = NULL;
  347. hStore = CertOpenSystemStoreW( NULL, L"CA" );
  348. if ( hStore != NULL )
  349. {
  350. while ( ( pFindCrl = CertGetCRLFromStore(
  351. hStore,
  352. pIssuer,
  353. pFindCrl,
  354. &dwGetCrlFlags
  355. ) ) != NULL )
  356. {
  357. if ( dwGetCrlFlags != 0 || !IsExtensionValidCrl( pFindCrl ))
  358. {
  359. dwGetCrlFlags = CERT_STORE_SIGNATURE_FLAG;
  360. continue;
  361. }
  362. *ppCrl = pFindCrl;
  363. break;
  364. }
  365. CertCloseStore( hStore, 0 );
  366. if ( *ppCrl != NULL )
  367. {
  368. return( TRUE );
  369. }
  370. }
  371. return( FALSE );
  372. }
  373. //+-------------------------------------------------------------------------
  374. // Find a certificate identified by its serial number in the CRL.
  375. //--------------------------------------------------------------------------
  376. PCRL_ENTRY FindCertInCrl(
  377. IN PCCERT_CONTEXT pCert,
  378. IN PCCRL_CONTEXT pCrl,
  379. IN PCERT_REVOCATION_PARA pRevPara
  380. )
  381. {
  382. DWORD cEntry = pCrl->pCrlInfo->cCRLEntry;
  383. PCRL_ENTRY pEntry = pCrl->pCrlInfo->rgCRLEntry;
  384. DWORD cbSerialNumber = pCert->pCertInfo->SerialNumber.cbData;
  385. BYTE *pbSerialNumber = pCert->pCertInfo->SerialNumber.pbData;
  386. if (0 == cbSerialNumber)
  387. return NULL;
  388. for ( ; 0 < cEntry; cEntry--, pEntry++) {
  389. if (cbSerialNumber == pEntry->SerialNumber.cbData &&
  390. 0 == memcmp(pbSerialNumber, pEntry->SerialNumber.pbData,
  391. cbSerialNumber))
  392. {
  393. if (pRevPara && pRevPara->cbSize >=
  394. (offsetof(CERT_REVOCATION_PARA, pftTimeToUse) +
  395. sizeof(pRevPara->pftTimeToUse))
  396. &&
  397. NULL != pRevPara->pftTimeToUse
  398. &&
  399. 0 > CompareFileTime(pRevPara->pftTimeToUse,
  400. &pEntry->RevocationDate))
  401. // It was used before being revoked
  402. return NULL;
  403. else
  404. return pEntry;
  405. }
  406. }
  407. return NULL;
  408. }