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.

1938 lines
63 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: policy.cpp
  8. //
  9. // Contents: Certificate Chain Policy APIs
  10. //
  11. // Functions: CertChainPolicyDllMain
  12. // CertVerifyCertificateChainPolicy
  13. // CertDllVerifyBaseCertificateChainPolicy
  14. // CertDllVerifyBasicConstraintsCertificateChainPolicy
  15. // CertDllVerifyAuthenticodeCertificateChainPolicy
  16. // CertDllVerifyAuthenticodeTimeStampCertificateChainPolicy
  17. // CertDllVerifySSLCertificateChainPolicy
  18. // CertDllVerifyNTAuthCertificateChainPolicy
  19. // CertDllVerifyMicrosoftRootCertificateChainPolicy
  20. //
  21. // History: 16-Feb-98 philh created
  22. //--------------------------------------------------------------------------
  23. #include "global.hxx"
  24. #include <dbgdef.h>
  25. #include "wintrust.h"
  26. #include "softpub.h"
  27. #include "wininet.h"
  28. #ifndef SECURITY_FLAG_IGNORE_REVOCATION
  29. # define SECURITY_FLAG_IGNORE_REVOCATION 0x00000080
  30. # define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100
  31. #endif
  32. #ifndef SECURITY_FLAG_IGNORE_WRONG_USAGE
  33. # define SECURITY_FLAG_IGNORE_WRONG_USAGE 0x00000200
  34. #endif
  35. #define INVALID_NAME_ERROR_STATUS ( \
  36. CERT_TRUST_INVALID_NAME_CONSTRAINTS | \
  37. CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT | \
  38. CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | \
  39. CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT | \
  40. CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT \
  41. )
  42. #define INVALID_POLICY_ERROR_STATUS ( \
  43. CERT_TRUST_INVALID_POLICY_CONSTRAINTS | \
  44. CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY \
  45. )
  46. BOOL fWildcardsEnabledInSslServerCerts = TRUE;
  47. //+-------------------------------------------------------------------------
  48. // Global cert policy critical section.
  49. //--------------------------------------------------------------------------
  50. static CRITICAL_SECTION CertPolicyCriticalSection;
  51. //+-------------------------------------------------------------------------
  52. // Cached certificate store used for NTAuth certificate chain policy.
  53. //--------------------------------------------------------------------------
  54. static HCERTSTORE hNTAuthCertStore = NULL;
  55. //
  56. // support for MS test roots!!!!
  57. //
  58. static BYTE rgbTestRoot[] =
  59. {
  60. #include "mstest1.h"
  61. };
  62. static BYTE rgbTestRootCorrected[] =
  63. {
  64. #include "mstest2.h"
  65. };
  66. static BYTE rgbTestRootBeta1[] =
  67. {
  68. #include "mstestb1.h"
  69. };
  70. static CERT_PUBLIC_KEY_INFO rgTestRootPublicKeyInfo[] =
  71. {
  72. {szOID_RSA_RSA, 0, NULL, sizeof(rgbTestRoot), rgbTestRoot, 0},
  73. {szOID_RSA_RSA, 0, NULL,
  74. sizeof(rgbTestRootCorrected), rgbTestRootCorrected, 0},
  75. {szOID_RSA_RSA, 0, NULL, sizeof(rgbTestRootBeta1), rgbTestRootBeta1, 0}
  76. };
  77. #define NTESTROOTS (sizeof(rgTestRootPublicKeyInfo)/ \
  78. sizeof(rgTestRootPublicKeyInfo[0]))
  79. HCRYPTOIDFUNCSET hChainPolicyFuncSet;
  80. typedef BOOL (WINAPI *PFN_CHAIN_POLICY_FUNC) (
  81. IN LPCSTR pszPolicyOID,
  82. IN PCCERT_CHAIN_CONTEXT pChainContext,
  83. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  84. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  85. );
  86. BOOL
  87. WINAPI
  88. CertDllVerifyBaseCertificateChainPolicy(
  89. IN LPCSTR pszPolicyOID,
  90. IN PCCERT_CHAIN_CONTEXT pChainContext,
  91. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  92. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  93. );
  94. BOOL
  95. WINAPI
  96. CertDllVerifyAuthenticodeCertificateChainPolicy(
  97. IN LPCSTR pszPolicyOID,
  98. IN PCCERT_CHAIN_CONTEXT pChainContext,
  99. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  100. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  101. );
  102. BOOL
  103. WINAPI
  104. CertDllVerifyAuthenticodeTimeStampCertificateChainPolicy(
  105. IN LPCSTR pszPolicyOID,
  106. IN PCCERT_CHAIN_CONTEXT pChainContext,
  107. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  108. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  109. );
  110. BOOL
  111. WINAPI
  112. CertDllVerifySSLCertificateChainPolicy(
  113. IN LPCSTR pszPolicyOID,
  114. IN PCCERT_CHAIN_CONTEXT pChainContext,
  115. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  116. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  117. );
  118. BOOL
  119. WINAPI
  120. CertDllVerifyBasicConstraintsCertificateChainPolicy(
  121. IN LPCSTR pszPolicyOID,
  122. IN PCCERT_CHAIN_CONTEXT pChainContext,
  123. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  124. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  125. );
  126. BOOL
  127. WINAPI
  128. CertDllVerifyNTAuthCertificateChainPolicy(
  129. IN LPCSTR pszPolicyOID,
  130. IN PCCERT_CHAIN_CONTEXT pChainContext,
  131. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  132. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  133. );
  134. BOOL
  135. WINAPI
  136. CertDllVerifyMicrosoftRootCertificateChainPolicy(
  137. IN LPCSTR pszPolicyOID,
  138. IN PCCERT_CHAIN_CONTEXT pChainContext,
  139. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  140. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  141. );
  142. static const CRYPT_OID_FUNC_ENTRY ChainPolicyFuncTable[] = {
  143. CERT_CHAIN_POLICY_BASE, CertDllVerifyBaseCertificateChainPolicy,
  144. CERT_CHAIN_POLICY_AUTHENTICODE,
  145. CertDllVerifyAuthenticodeCertificateChainPolicy,
  146. CERT_CHAIN_POLICY_AUTHENTICODE_TS,
  147. CertDllVerifyAuthenticodeTimeStampCertificateChainPolicy,
  148. CERT_CHAIN_POLICY_SSL,
  149. CertDllVerifySSLCertificateChainPolicy,
  150. CERT_CHAIN_POLICY_BASIC_CONSTRAINTS,
  151. CertDllVerifyBasicConstraintsCertificateChainPolicy,
  152. CERT_CHAIN_POLICY_NT_AUTH,
  153. CertDllVerifyNTAuthCertificateChainPolicy,
  154. CERT_CHAIN_POLICY_MICROSOFT_ROOT,
  155. CertDllVerifyMicrosoftRootCertificateChainPolicy,
  156. };
  157. #define CHAIN_POLICY_FUNC_COUNT (sizeof(ChainPolicyFuncTable) / \
  158. sizeof(ChainPolicyFuncTable[0]))
  159. BOOL
  160. WINAPI
  161. CertChainPolicyDllMain(
  162. HMODULE hInst,
  163. ULONG ulReason,
  164. LPVOID lpReserved)
  165. {
  166. BOOL fRet;
  167. switch (ulReason) {
  168. case DLL_PROCESS_ATTACH:
  169. if (NULL == (hChainPolicyFuncSet = CryptInitOIDFunctionSet(
  170. CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC,
  171. 0)))
  172. goto CryptInitOIDFunctionSetError;
  173. if (!CryptInstallOIDFunctionAddress(
  174. NULL, // hModule
  175. 0, // dwEncodingType
  176. CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC,
  177. CHAIN_POLICY_FUNC_COUNT,
  178. ChainPolicyFuncTable,
  179. 0)) // dwFlags
  180. goto CryptInstallOIDFunctionAddressError;
  181. if (!Pki_InitializeCriticalSection(&CertPolicyCriticalSection))
  182. goto InitCritSectionError;
  183. break;
  184. case DLL_PROCESS_DETACH:
  185. DeleteCriticalSection(&CertPolicyCriticalSection);
  186. if (hNTAuthCertStore)
  187. CertCloseStore(hNTAuthCertStore, 0);
  188. break;
  189. case DLL_THREAD_DETACH:
  190. default:
  191. break;
  192. }
  193. fRet = TRUE;
  194. CommonReturn:
  195. return fRet;
  196. ErrorReturn:
  197. fRet = FALSE;
  198. goto CommonReturn;
  199. TRACE_ERROR(InitCritSectionError)
  200. TRACE_ERROR(CryptInitOIDFunctionSetError)
  201. TRACE_ERROR(CryptInstallOIDFunctionAddressError)
  202. }
  203. //+-------------------------------------------------------------------------
  204. // Lock and unlock global cert policy functions
  205. //--------------------------------------------------------------------------
  206. static inline void CertPolicyLock()
  207. {
  208. EnterCriticalSection(&CertPolicyCriticalSection);
  209. }
  210. static inline void CertPolicyUnlock()
  211. {
  212. LeaveCriticalSection(&CertPolicyCriticalSection);
  213. }
  214. //+-------------------------------------------------------------------------
  215. // Verify that the certificate chain satisfies the specified policy
  216. // requirements. If we were able to verify the chain policy, TRUE is returned
  217. // and the dwError field of the pPolicyStatus is updated. A dwError of 0
  218. // (ERROR_SUCCESS, S_OK) indicates the chain satisfies the specified policy.
  219. //
  220. // If dwError applies to the entire chain context, both lChainIndex and
  221. // lElementIndex are set to -1. If dwError applies to a simple chain,
  222. // lElementIndex is set to -1 and lChainIndex is set to the index of the
  223. // first offending chain having the error. If dwError applies to a
  224. // certificate element, lChainIndex and lElementIndex are updated to
  225. // index the first offending certificate having the error, where, the
  226. // the certificate element is at:
  227. // pChainContext->rgpChain[lChainIndex]->rgpElement[lElementIndex].
  228. //
  229. // The dwFlags in pPolicyPara can be set to change the default policy checking
  230. // behaviour. In addition, policy specific parameters can be passed in
  231. // the pvExtraPolicyPara field of pPolicyPara.
  232. //
  233. // In addition to returning dwError, in pPolicyStatus, policy OID specific
  234. // extra status may be returned via pvExtraPolicyStatus.
  235. //--------------------------------------------------------------------------
  236. BOOL
  237. WINAPI
  238. CertVerifyCertificateChainPolicy(
  239. IN LPCSTR pszPolicyOID,
  240. IN PCCERT_CHAIN_CONTEXT pChainContext,
  241. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  242. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  243. )
  244. {
  245. BOOL fResult;
  246. void *pvFuncAddr;
  247. HCRYPTOIDFUNCADDR hFuncAddr = NULL;
  248. assert(pPolicyStatus && offsetof(CERT_CHAIN_POLICY_STATUS, lElementIndex) <
  249. pPolicyStatus->cbSize);
  250. pPolicyStatus->dwError = 0;
  251. pPolicyStatus->lChainIndex = -1;
  252. pPolicyStatus->lElementIndex = -1;
  253. if (!CryptGetOIDFunctionAddress(
  254. hChainPolicyFuncSet,
  255. 0, // dwEncodingType,
  256. pszPolicyOID,
  257. 0, // dwFlags
  258. &pvFuncAddr,
  259. &hFuncAddr))
  260. goto GetOIDFuncAddrError;
  261. fResult = ((PFN_CHAIN_POLICY_FUNC) pvFuncAddr)(
  262. pszPolicyOID,
  263. pChainContext,
  264. pPolicyPara,
  265. pPolicyStatus
  266. );
  267. CryptFreeOIDFunctionAddress(hFuncAddr, 0);
  268. CommonReturn:
  269. return fResult;
  270. ErrorReturn:
  271. fResult = FALSE;
  272. goto CommonReturn;
  273. TRACE_ERROR(GetOIDFuncAddrError)
  274. }
  275. static inline PCERT_CHAIN_ELEMENT GetRootChainElement(
  276. IN PCCERT_CHAIN_CONTEXT pChainContext
  277. )
  278. {
  279. DWORD dwRootChainIndex = pChainContext->cChain - 1;
  280. DWORD dwRootElementIndex =
  281. pChainContext->rgpChain[dwRootChainIndex]->cElement - 1;
  282. return pChainContext->rgpChain[dwRootChainIndex]->
  283. rgpElement[dwRootElementIndex];
  284. }
  285. void GetElementIndexOfFirstError(
  286. IN PCCERT_CHAIN_CONTEXT pChainContext,
  287. IN DWORD dwErrorStatusMask,
  288. OUT LONG *plChainIndex,
  289. OUT LONG *plElementIndex
  290. )
  291. {
  292. DWORD i;
  293. for (i = 0; i < pChainContext->cChain; i++) {
  294. DWORD j;
  295. PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[i];
  296. for (j = 0; j < pChain->cElement; j++) {
  297. PCERT_CHAIN_ELEMENT pEle = pChain->rgpElement[j];
  298. if (pEle->TrustStatus.dwErrorStatus & dwErrorStatusMask) {
  299. *plChainIndex = (LONG) i;
  300. *plElementIndex = (LONG) j;
  301. return;
  302. }
  303. }
  304. }
  305. *plChainIndex = -1;
  306. *plElementIndex = -1;
  307. }
  308. void GetChainIndexOfFirstError(
  309. IN PCCERT_CHAIN_CONTEXT pChainContext,
  310. IN DWORD dwErrorStatusMask,
  311. OUT LONG *plChainIndex
  312. )
  313. {
  314. DWORD i;
  315. for (i = 0; i < pChainContext->cChain; i++) {
  316. PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[i];
  317. if (pChain->TrustStatus.dwErrorStatus & dwErrorStatusMask) {
  318. *plChainIndex = (LONG) i;
  319. return;
  320. }
  321. }
  322. *plChainIndex = -1;
  323. }
  324. //+=========================================================================
  325. // CertDllVerifyBaseCertificateChainPolicy Functions
  326. //==========================================================================
  327. BOOL
  328. WINAPI
  329. CertDllVerifyBaseCertificateChainPolicy(
  330. IN LPCSTR pszPolicyOID,
  331. IN PCCERT_CHAIN_CONTEXT pChainContext,
  332. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  333. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  334. )
  335. {
  336. DWORD dwError;
  337. DWORD dwFlags;
  338. DWORD dwContextError;
  339. LONG lChainIndex = -1;
  340. LONG lElementIndex = -1;
  341. DWORD dwErrorStatusMask;
  342. dwContextError = pChainContext->TrustStatus.dwErrorStatus;
  343. if (0 == dwContextError) {
  344. // Valid chain
  345. dwError = 0;
  346. goto CommonReturn;
  347. }
  348. if (pPolicyPara && offsetof(CERT_CHAIN_POLICY_PARA, dwFlags) <
  349. pPolicyPara->cbSize)
  350. dwFlags = pPolicyPara->dwFlags;
  351. else
  352. dwFlags = 0;
  353. if (dwContextError &
  354. (CERT_TRUST_IS_NOT_SIGNATURE_VALID |
  355. CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID)) {
  356. dwError = (DWORD) TRUST_E_CERT_SIGNATURE;
  357. dwErrorStatusMask =
  358. CERT_TRUST_IS_NOT_SIGNATURE_VALID |
  359. CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID;
  360. if (dwErrorStatusMask & CERT_TRUST_IS_NOT_SIGNATURE_VALID)
  361. goto GetElementIndexReturn;
  362. else
  363. goto GetChainIndexReturn;
  364. }
  365. if (dwContextError & CERT_TRUST_IS_UNTRUSTED_ROOT) {
  366. dwErrorStatusMask = CERT_TRUST_IS_UNTRUSTED_ROOT;
  367. if (dwFlags & CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG) {
  368. ;
  369. } else if (0 == (dwFlags & CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG)) {
  370. dwError = (DWORD) CERT_E_UNTRUSTEDROOT;
  371. goto GetElementIndexReturn;
  372. } else {
  373. // Check if one of the "test" roots
  374. DWORD i;
  375. BOOL fTestRoot;
  376. PCERT_CHAIN_ELEMENT pRootElement;
  377. PCCERT_CONTEXT pRootCert;
  378. pRootElement = GetRootChainElement(pChainContext);
  379. assert(pRootElement->TrustStatus.dwInfoStatus &
  380. CERT_TRUST_IS_SELF_SIGNED);
  381. pRootCert = pRootElement->pCertContext;
  382. fTestRoot = FALSE;
  383. for (i = 0; i < NTESTROOTS; i++) {
  384. if (CertComparePublicKeyInfo(
  385. pRootCert->dwCertEncodingType,
  386. &pRootCert->pCertInfo->SubjectPublicKeyInfo,
  387. &rgTestRootPublicKeyInfo[i])) {
  388. fTestRoot = TRUE;
  389. break;
  390. }
  391. }
  392. if (fTestRoot) {
  393. if (0 == (dwFlags & CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG)) {
  394. dwError = (DWORD) CERT_E_UNTRUSTEDTESTROOT;
  395. goto GetElementIndexReturn;
  396. }
  397. } else {
  398. dwError = (DWORD) CERT_E_UNTRUSTEDROOT;
  399. goto GetElementIndexReturn;
  400. }
  401. }
  402. }
  403. if (dwContextError & CERT_TRUST_IS_PARTIAL_CHAIN) {
  404. if (0 == (dwFlags & CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG)) {
  405. dwError = (DWORD) CERT_E_CHAINING;
  406. dwErrorStatusMask = CERT_TRUST_IS_PARTIAL_CHAIN;
  407. goto GetChainIndexReturn;
  408. }
  409. }
  410. if (dwContextError & CERT_TRUST_IS_REVOKED) {
  411. dwError = (DWORD) CRYPT_E_REVOKED;
  412. dwErrorStatusMask = CERT_TRUST_IS_REVOKED;
  413. goto GetElementIndexReturn;
  414. }
  415. if (dwContextError & (CERT_TRUST_IS_NOT_VALID_FOR_USAGE |
  416. CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE)) {
  417. if (0 == (dwFlags & CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG)) {
  418. dwError = (DWORD) CERT_E_WRONG_USAGE;
  419. dwErrorStatusMask = CERT_TRUST_IS_NOT_VALID_FOR_USAGE |
  420. CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
  421. if (dwContextError & CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
  422. goto GetElementIndexReturn;
  423. else
  424. goto GetChainIndexReturn;
  425. }
  426. }
  427. if (dwContextError & CERT_TRUST_IS_NOT_TIME_VALID) {
  428. if (0 == (dwFlags & CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG)) {
  429. dwError = (DWORD) CERT_E_EXPIRED;
  430. dwErrorStatusMask = CERT_TRUST_IS_NOT_TIME_VALID;
  431. goto GetElementIndexReturn;
  432. }
  433. }
  434. if (dwContextError & CERT_TRUST_CTL_IS_NOT_TIME_VALID) {
  435. if (0 == (dwFlags & CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG)) {
  436. dwErrorStatusMask = CERT_TRUST_CTL_IS_NOT_TIME_VALID;
  437. dwError = (DWORD) CERT_E_EXPIRED;
  438. goto GetChainIndexReturn;
  439. }
  440. }
  441. if (dwContextError & INVALID_NAME_ERROR_STATUS) {
  442. if (0 == (dwFlags & CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG)) {
  443. dwError = (DWORD) CERT_E_INVALID_NAME;
  444. dwErrorStatusMask = INVALID_NAME_ERROR_STATUS;
  445. goto GetElementIndexReturn;
  446. }
  447. }
  448. if (dwContextError & INVALID_POLICY_ERROR_STATUS) {
  449. if (0 == (dwFlags & CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG)) {
  450. dwError = (DWORD) CERT_E_INVALID_POLICY;
  451. dwErrorStatusMask = INVALID_POLICY_ERROR_STATUS;
  452. goto GetElementIndexReturn;
  453. }
  454. }
  455. if (dwContextError & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
  456. if (0 == (dwFlags &
  457. CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG)) {
  458. dwError = (DWORD) TRUST_E_BASIC_CONSTRAINTS;
  459. dwErrorStatusMask = CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
  460. goto GetElementIndexReturn;
  461. }
  462. }
  463. if (dwContextError & CERT_TRUST_IS_NOT_TIME_NESTED) {
  464. if (0 == (dwFlags & CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG)) {
  465. dwErrorStatusMask = CERT_TRUST_IS_NOT_TIME_NESTED;
  466. dwError = (DWORD) CERT_E_VALIDITYPERIODNESTING;
  467. goto GetElementIndexReturn;
  468. }
  469. }
  470. dwError = 0;
  471. // Note, OFFLINE takes precedence over NO_CHECK
  472. if (dwContextError & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) {
  473. if ((dwFlags & CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS) !=
  474. CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS) {
  475. DWORD i;
  476. for (i = 0; i < pChainContext->cChain; i++) {
  477. DWORD j;
  478. PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[i];
  479. for (j = 0; j < pChain->cElement; j++) {
  480. PCERT_CHAIN_ELEMENT pEle = pChain->rgpElement[j];
  481. DWORD dwEleError = pEle->TrustStatus.dwErrorStatus;
  482. DWORD dwEleInfo = pEle->TrustStatus.dwInfoStatus;
  483. DWORD dwRevokeError;
  484. BOOL fEnableRevokeError;
  485. if (0 == (dwEleError &
  486. CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
  487. continue;
  488. assert(pEle->pRevocationInfo);
  489. dwRevokeError = pEle->pRevocationInfo->dwRevocationResult;
  490. if (CRYPT_E_NO_REVOCATION_CHECK != dwRevokeError)
  491. dwRevokeError = (DWORD) CRYPT_E_REVOCATION_OFFLINE;
  492. fEnableRevokeError = FALSE;
  493. if (dwEleInfo & CERT_TRUST_IS_SELF_SIGNED) {
  494. // Chain Root
  495. if (0 == (dwFlags &
  496. CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG)) {
  497. fEnableRevokeError = TRUE;
  498. }
  499. } else if (0 == i && 0 == j) {
  500. // End certificate
  501. if (0 == (dwFlags &
  502. CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG)) {
  503. fEnableRevokeError = TRUE;
  504. }
  505. } else if (0 == j) {
  506. // CTL signer certificate
  507. if (0 ==
  508. (dwFlags & CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG)) {
  509. fEnableRevokeError = TRUE;
  510. }
  511. } else {
  512. // CA certificate
  513. if (0 ==
  514. (dwFlags & CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG)) {
  515. fEnableRevokeError = TRUE;
  516. }
  517. }
  518. if (fEnableRevokeError) {
  519. if (0 == dwError ||
  520. CRYPT_E_REVOCATION_OFFLINE == dwRevokeError) {
  521. dwError = dwRevokeError;
  522. lChainIndex = (LONG) i;
  523. lElementIndex = (LONG) j;
  524. if (CRYPT_E_REVOCATION_OFFLINE == dwError)
  525. goto CommonReturn;
  526. }
  527. }
  528. }
  529. }
  530. }
  531. }
  532. CommonReturn:
  533. assert(pPolicyStatus && offsetof(CERT_CHAIN_POLICY_STATUS, lElementIndex) <
  534. pPolicyStatus->cbSize);
  535. pPolicyStatus->dwError = dwError;
  536. pPolicyStatus->lChainIndex = lChainIndex;
  537. pPolicyStatus->lElementIndex = lElementIndex;
  538. return TRUE;
  539. GetElementIndexReturn:
  540. GetElementIndexOfFirstError(pChainContext, dwErrorStatusMask,
  541. &lChainIndex, &lElementIndex);
  542. goto CommonReturn;
  543. GetChainIndexReturn:
  544. GetChainIndexOfFirstError(pChainContext, dwErrorStatusMask,
  545. &lChainIndex);
  546. goto CommonReturn;
  547. }
  548. //+=========================================================================
  549. // CertDllVerifyBasicConstraintsCertificateChainPolicy Functions
  550. //==========================================================================
  551. // If dwFlags is 0, allow either CA or END_ENTITY for dwEleIndex == 0
  552. BOOL CheckChainElementBasicConstraints(
  553. IN PCERT_CHAIN_ELEMENT pEle,
  554. IN DWORD dwEleIndex,
  555. IN DWORD dwFlags
  556. )
  557. {
  558. BOOL fResult;
  559. PCERT_INFO pCertInfo = pEle->pCertContext->pCertInfo;
  560. PCERT_EXTENSION pExt;
  561. PCERT_BASIC_CONSTRAINTS_INFO pInfo = NULL;
  562. PCERT_BASIC_CONSTRAINTS2_INFO pInfo2 = NULL;
  563. DWORD cbInfo;
  564. BOOL fCA;
  565. BOOL fEndEntity;
  566. if (pEle->TrustStatus.dwErrorStatus &
  567. CERT_TRUST_INVALID_BASIC_CONSTRAINTS)
  568. goto ChainBasicContraintsError;
  569. if (0 == dwFlags || 0 != dwEleIndex || 0 == pCertInfo->cExtension)
  570. goto SuccessReturn;
  571. // else
  572. // Only need to do additional checking to see if the end cert is
  573. // a CA or END_ENTITY.
  574. if (pExt = CertFindExtension(
  575. szOID_BASIC_CONSTRAINTS2,
  576. pCertInfo->cExtension,
  577. pCertInfo->rgExtension
  578. )) {
  579. if (!CryptDecodeObjectEx(
  580. pEle->pCertContext->dwCertEncodingType,
  581. X509_BASIC_CONSTRAINTS2,
  582. pExt->Value.pbData,
  583. pExt->Value.cbData,
  584. CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG |
  585. CRYPT_DECODE_SHARE_OID_STRING_FLAG,
  586. &PkiDecodePara,
  587. (void *) &pInfo2,
  588. &cbInfo
  589. )) {
  590. if (pExt->fCritical)
  591. goto DecodeError;
  592. else
  593. goto SuccessReturn;
  594. }
  595. fCA = pInfo2->fCA;
  596. fEndEntity = !fCA;
  597. } else if (pExt = CertFindExtension(
  598. szOID_BASIC_CONSTRAINTS,
  599. pCertInfo->cExtension,
  600. pCertInfo->rgExtension
  601. )) {
  602. if (!CryptDecodeObjectEx(
  603. pEle->pCertContext->dwCertEncodingType,
  604. X509_BASIC_CONSTRAINTS,
  605. pExt->Value.pbData,
  606. pExt->Value.cbData,
  607. CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG |
  608. CRYPT_DECODE_SHARE_OID_STRING_FLAG,
  609. &PkiDecodePara,
  610. (void *) &pInfo,
  611. &cbInfo
  612. )) {
  613. if (pExt->fCritical)
  614. goto DecodeError;
  615. else
  616. goto SuccessReturn;
  617. }
  618. if (pExt->fCritical && pInfo->cSubtreesConstraint)
  619. goto SubtreesError;
  620. if (pInfo->SubjectType.cbData > 0) {
  621. BYTE bRole = pInfo->SubjectType.pbData[0];
  622. fCA = (0 != (bRole & CERT_CA_SUBJECT_FLAG));
  623. fEndEntity = (0 != (bRole & CERT_END_ENTITY_SUBJECT_FLAG));
  624. } else {
  625. fCA = FALSE;
  626. fEndEntity = FALSE;
  627. }
  628. } else
  629. goto SuccessReturn;
  630. if (dwFlags & BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG) {
  631. if (!fEndEntity)
  632. goto NotAnEndEntity;
  633. }
  634. if (dwFlags & BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_CA_FLAG) {
  635. if (!fCA)
  636. goto NotACA;
  637. }
  638. SuccessReturn:
  639. fResult = TRUE;
  640. CommonReturn:
  641. PkiFree(pInfo);
  642. PkiFree(pInfo2);
  643. return fResult;
  644. ErrorReturn:
  645. fResult = FALSE;
  646. goto CommonReturn;
  647. TRACE_ERROR(ChainBasicContraintsError)
  648. TRACE_ERROR(NotACA)
  649. TRACE_ERROR(NotAnEndEntity)
  650. TRACE_ERROR(SubtreesError)
  651. TRACE_ERROR(DecodeError)
  652. }
  653. BOOL
  654. WINAPI
  655. CertDllVerifyBasicConstraintsCertificateChainPolicy(
  656. IN LPCSTR pszPolicyOID,
  657. IN PCCERT_CHAIN_CONTEXT pChainContext,
  658. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  659. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  660. )
  661. {
  662. DWORD dwFlags;
  663. if (pPolicyPara && offsetof(CERT_CHAIN_POLICY_PARA, dwFlags) <
  664. pPolicyPara->cbSize) {
  665. dwFlags = pPolicyPara->dwFlags;
  666. dwFlags &= (BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_CA_FLAG |
  667. BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG);
  668. if (dwFlags == (BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_CA_FLAG |
  669. BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG))
  670. dwFlags = 0; // 0 => allow CA or END_ENTITY
  671. } else
  672. dwFlags = 0;
  673. DWORD i;
  674. for (i = 0; i < pChainContext->cChain; i++) {
  675. DWORD j;
  676. PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[i];
  677. for (j = 0; j < pChain->cElement; j++) {
  678. if (!CheckChainElementBasicConstraints(pChain->rgpElement[j], j,
  679. dwFlags)) {
  680. assert(pPolicyStatus && offsetof(CERT_CHAIN_POLICY_STATUS,
  681. lElementIndex) < pPolicyStatus->cbSize);
  682. pPolicyStatus->dwError = (DWORD) TRUST_E_BASIC_CONSTRAINTS;
  683. pPolicyStatus->lChainIndex = (LONG) i;
  684. pPolicyStatus->lElementIndex = (LONG) j;
  685. return TRUE;
  686. }
  687. }
  688. // Allow CTL to be signed by either a CA or END_ENTITY
  689. dwFlags = 0;
  690. }
  691. assert(pPolicyStatus && offsetof(CERT_CHAIN_POLICY_STATUS, lElementIndex) <
  692. pPolicyStatus->cbSize);
  693. pPolicyStatus->dwError = 0;
  694. pPolicyStatus->lChainIndex = -1;
  695. pPolicyStatus->lElementIndex = -1;
  696. return TRUE;
  697. }
  698. //+=========================================================================
  699. // CertDllVerifyAuthenticodeCertificateChainPolicy Functions
  700. //
  701. // On July 1, 2000 philh removed all of the individual/commercial
  702. // stuff. It hasn't been used for years!.
  703. //==========================================================================
  704. // Returns TRUE if the signer cert has the Code Signing EKU or if the signer
  705. // cert has the legacy Key Usage extension with either the individual or
  706. // commercial usage.
  707. //
  708. // For backwards compatibility, allow a signer cert without any EKU's
  709. BOOL CheckAuthenticodeChainPurpose(
  710. IN PCCERT_CHAIN_CONTEXT pChainContext
  711. )
  712. {
  713. BOOL fResult;
  714. PCERT_CHAIN_ELEMENT pEle;
  715. PCCERT_CONTEXT pCert;
  716. PCERT_INFO pCertInfo;
  717. PCERT_EXTENSION pExt;
  718. PCERT_KEY_USAGE_RESTRICTION_INFO pInfo = NULL;
  719. DWORD cbInfo;
  720. pEle = pChainContext->rgpChain[0]->rgpElement[0];
  721. if (NULL == pEle->pApplicationUsage) {
  722. // No usages. Good for any usage.
  723. // Do we want to allow this?? Yes, for backward compatibility
  724. goto SuccessReturn;
  725. } else {
  726. DWORD cUsage;
  727. LPSTR *ppszUsage;
  728. cUsage = pEle->pApplicationUsage->cUsageIdentifier;
  729. ppszUsage = pEle->pApplicationUsage->rgpszUsageIdentifier;
  730. for ( ; cUsage > 0; cUsage--, ppszUsage++) {
  731. if (0 == strcmp(*ppszUsage, szOID_PKIX_KP_CODE_SIGNING))
  732. goto SuccessReturn;
  733. }
  734. }
  735. pCert = pEle->pCertContext;
  736. pCertInfo = pCert->pCertInfo;
  737. if (0 == pCertInfo->cExtension)
  738. goto NoSignerCertExtensions;
  739. if (NULL == (pExt = CertFindExtension(
  740. szOID_KEY_USAGE_RESTRICTION,
  741. pCertInfo->cExtension,
  742. pCertInfo->rgExtension
  743. )))
  744. goto NoSignerKeyUsageExtension;
  745. if (!CryptDecodeObjectEx(
  746. pCert->dwCertEncodingType,
  747. X509_KEY_USAGE_RESTRICTION,
  748. pExt->Value.pbData,
  749. pExt->Value.cbData,
  750. CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG |
  751. CRYPT_DECODE_SHARE_OID_STRING_FLAG,
  752. &PkiDecodePara,
  753. (void *) &pInfo,
  754. &cbInfo
  755. ))
  756. goto DecodeError;
  757. if (pInfo->cCertPolicyId) {
  758. DWORD cPolicyId;
  759. PCERT_POLICY_ID pPolicyId;
  760. cPolicyId = pInfo->cCertPolicyId;
  761. pPolicyId = pInfo->rgCertPolicyId;
  762. for ( ; cPolicyId > 0; cPolicyId--, pPolicyId++) {
  763. DWORD cElementId = pPolicyId->cCertPolicyElementId;
  764. LPSTR *ppszElementId = pPolicyId->rgpszCertPolicyElementId;
  765. for ( ; cElementId > 0; cElementId--, ppszElementId++)
  766. {
  767. if (0 == strcmp(*ppszElementId,
  768. SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID))
  769. goto SuccessReturn;
  770. else if (0 == strcmp(*ppszElementId,
  771. SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID))
  772. goto SuccessReturn;
  773. }
  774. }
  775. }
  776. goto NoSignerLegacyPurpose;
  777. SuccessReturn:
  778. fResult = TRUE;
  779. CommonReturn:
  780. PkiFree(pInfo);
  781. return fResult;
  782. ErrorReturn:
  783. fResult = FALSE;
  784. goto CommonReturn;
  785. TRACE_ERROR(NoSignerCertExtensions)
  786. TRACE_ERROR(NoSignerKeyUsageExtension)
  787. TRACE_ERROR(DecodeError);
  788. TRACE_ERROR(NoSignerLegacyPurpose)
  789. }
  790. void MapAuthenticodeRegPolicySettingsToBaseChainPolicyFlags(
  791. IN DWORD dwRegPolicySettings,
  792. IN OUT DWORD *pdwFlags
  793. )
  794. {
  795. DWORD dwFlags;
  796. if (0 == dwRegPolicySettings)
  797. return;
  798. dwFlags = *pdwFlags;
  799. if (dwRegPolicySettings & WTPF_TRUSTTEST)
  800. dwFlags |= CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG;
  801. if (dwRegPolicySettings & WTPF_TESTCANBEVALID)
  802. dwFlags |= CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG;
  803. if (dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
  804. dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS;
  805. if (dwRegPolicySettings & WTPF_IGNOREREVOKATION)
  806. dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
  807. else if (dwRegPolicySettings & (WTPF_OFFLINEOK_COM | WTPF_OFFLINEOK_IND))
  808. dwFlags |= CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG;
  809. *pdwFlags = dwFlags;
  810. }
  811. void GetAuthenticodePara(
  812. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  813. OUT DWORD *pdwRegPolicySettings,
  814. OUT PCMSG_SIGNER_INFO *ppSignerInfo
  815. )
  816. {
  817. *ppSignerInfo = NULL;
  818. *pdwRegPolicySettings = 0;
  819. if (pPolicyPara && offsetof(CERT_CHAIN_POLICY_PARA, pvExtraPolicyPara) <
  820. pPolicyPara->cbSize && pPolicyPara->pvExtraPolicyPara) {
  821. PAUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA pAuthPara =
  822. (PAUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA)
  823. pPolicyPara->pvExtraPolicyPara;
  824. if (offsetof(AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA,
  825. dwRegPolicySettings) < pAuthPara->cbSize)
  826. *pdwRegPolicySettings = pAuthPara->dwRegPolicySettings;
  827. if (offsetof(AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA,
  828. pSignerInfo) < pAuthPara->cbSize)
  829. *ppSignerInfo = pAuthPara->pSignerInfo;
  830. }
  831. }
  832. // Map the CRYPT_E_ revocation errors to the corresponding CERT_E_
  833. // revocation errors
  834. static DWORD MapToAuthenticodeError(
  835. IN DWORD dwError
  836. )
  837. {
  838. switch (dwError) {
  839. case CRYPT_E_REVOKED:
  840. return (DWORD) CERT_E_REVOKED;
  841. break;
  842. case CRYPT_E_NO_REVOCATION_DLL:
  843. case CRYPT_E_NO_REVOCATION_CHECK:
  844. case CRYPT_E_REVOCATION_OFFLINE:
  845. case CRYPT_E_NOT_IN_REVOCATION_DATABASE:
  846. return (DWORD) CERT_E_REVOCATION_FAILURE;
  847. break;
  848. }
  849. return dwError;
  850. }
  851. BOOL
  852. WINAPI
  853. CertDllVerifyAuthenticodeCertificateChainPolicy(
  854. IN LPCSTR pszPolicyOID,
  855. IN PCCERT_CHAIN_CONTEXT pChainContext,
  856. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  857. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  858. )
  859. {
  860. DWORD dwError;
  861. DWORD dwFlags;
  862. DWORD dwRegPolicySettings;
  863. PCMSG_SIGNER_INFO pSignerInfo;
  864. LONG lChainIndex = -1;
  865. LONG lElementIndex = -1;
  866. CERT_CHAIN_POLICY_PARA BasePolicyPara;
  867. memset(&BasePolicyPara, 0, sizeof(BasePolicyPara));
  868. BasePolicyPara.cbSize = sizeof(BasePolicyPara);
  869. CERT_CHAIN_POLICY_STATUS BasePolicyStatus;
  870. memset(&BasePolicyStatus, 0, sizeof(BasePolicyStatus));
  871. BasePolicyStatus.cbSize = sizeof(BasePolicyStatus);
  872. if (pPolicyPara && offsetof(CERT_CHAIN_POLICY_PARA, dwFlags) <
  873. pPolicyPara->cbSize)
  874. dwFlags = pPolicyPara->dwFlags;
  875. else
  876. dwFlags = 0;
  877. GetAuthenticodePara(pPolicyPara, &dwRegPolicySettings, &pSignerInfo);
  878. MapAuthenticodeRegPolicySettingsToBaseChainPolicyFlags(
  879. dwRegPolicySettings, &dwFlags);
  880. // Do the basic chain policy verification. Authenticode overrides
  881. // the defaults for the following:
  882. dwFlags |=
  883. CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG |
  884. CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
  885. CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
  886. CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG |
  887. CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
  888. BasePolicyPara.dwFlags = dwFlags;
  889. if (!CertVerifyCertificateChainPolicy(
  890. CERT_CHAIN_POLICY_BASE,
  891. pChainContext,
  892. &BasePolicyPara,
  893. &BasePolicyStatus
  894. ))
  895. return FALSE;
  896. if (dwError = BasePolicyStatus.dwError) {
  897. dwError = MapToAuthenticodeError(dwError);
  898. lChainIndex = BasePolicyStatus.lChainIndex;
  899. lElementIndex = BasePolicyStatus.lElementIndex;
  900. if (CERT_E_REVOCATION_FAILURE != dwError)
  901. goto CommonReturn;
  902. // else
  903. // for REVOCATION_FAILURE let
  904. // PURPOSE and BASIC_CONSTRAINTS errors take precedence
  905. }
  906. if (pSignerInfo) {
  907. // Check that either the chain has the code signing EKU or
  908. // the signer cert has the legacy Key Usage extension containing
  909. // the commerical or individual policy.
  910. if (!CheckAuthenticodeChainPurpose(pChainContext)) {
  911. dwError = (DWORD) CERT_E_PURPOSE;
  912. lChainIndex = 0;
  913. lElementIndex = 0;
  914. goto CommonReturn;
  915. }
  916. }
  917. if (pSignerInfo)
  918. BasePolicyPara.dwFlags =
  919. BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG;
  920. else
  921. BasePolicyPara.dwFlags = 0;
  922. if (!CertVerifyCertificateChainPolicy(
  923. CERT_CHAIN_POLICY_BASIC_CONSTRAINTS,
  924. pChainContext,
  925. &BasePolicyPara,
  926. &BasePolicyStatus
  927. ))
  928. return FALSE;
  929. if (BasePolicyStatus.dwError) {
  930. dwError = BasePolicyStatus.dwError;
  931. lChainIndex = BasePolicyStatus.lChainIndex;
  932. lElementIndex = BasePolicyStatus.lElementIndex;
  933. goto CommonReturn;
  934. }
  935. CommonReturn:
  936. assert(pPolicyStatus && offsetof(CERT_CHAIN_POLICY_STATUS, lElementIndex) <
  937. pPolicyStatus->cbSize);
  938. pPolicyStatus->dwError = dwError;
  939. pPolicyStatus->lChainIndex = lChainIndex;
  940. pPolicyStatus->lElementIndex = lElementIndex;
  941. if (offsetof(CERT_CHAIN_POLICY_STATUS, pvExtraPolicyStatus) <
  942. pPolicyStatus->cbSize &&
  943. pPolicyStatus->pvExtraPolicyStatus) {
  944. // Since the signer statement's Commercial/Individual flag is no
  945. // longer used, default to individual
  946. PAUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_STATUS pAuthStatus =
  947. (PAUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_STATUS)
  948. pPolicyStatus->pvExtraPolicyStatus;
  949. if (offsetof(AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_STATUS,
  950. fCommercial) < pAuthStatus->cbSize)
  951. pAuthStatus->fCommercial = FALSE;
  952. }
  953. return TRUE;
  954. }
  955. //+=========================================================================
  956. // CertDllVerifyAuthenticodeTimeStampCertificateChainPolicy Functions
  957. //==========================================================================
  958. void MapAuthenticodeTimeStampRegPolicySettingsToBaseChainPolicyFlags(
  959. IN DWORD dwRegPolicySettings,
  960. IN OUT DWORD *pdwFlags
  961. )
  962. {
  963. DWORD dwFlags;
  964. if (0 == dwRegPolicySettings)
  965. return;
  966. dwFlags = *pdwFlags;
  967. if (dwRegPolicySettings & WTPF_TRUSTTEST)
  968. dwFlags |= CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG;
  969. if (dwRegPolicySettings & WTPF_TESTCANBEVALID)
  970. dwFlags |= CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG;
  971. if (dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
  972. dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS;
  973. if (dwRegPolicySettings & WTPF_IGNOREREVOCATIONONTS)
  974. dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
  975. else if (dwRegPolicySettings & (WTPF_OFFLINEOK_COM | WTPF_OFFLINEOK_IND))
  976. dwFlags |= CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG;
  977. *pdwFlags = dwFlags;
  978. }
  979. void GetAuthenticodeTimeStampPara(
  980. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  981. OUT DWORD *pdwRegPolicySettings
  982. )
  983. {
  984. *pdwRegPolicySettings = 0;
  985. if (pPolicyPara && offsetof(CERT_CHAIN_POLICY_PARA, pvExtraPolicyPara) <
  986. pPolicyPara->cbSize && pPolicyPara->pvExtraPolicyPara) {
  987. PAUTHENTICODE_TS_EXTRA_CERT_CHAIN_POLICY_PARA pAuthPara =
  988. (PAUTHENTICODE_TS_EXTRA_CERT_CHAIN_POLICY_PARA)
  989. pPolicyPara->pvExtraPolicyPara;
  990. if (offsetof(AUTHENTICODE_TS_EXTRA_CERT_CHAIN_POLICY_PARA,
  991. dwRegPolicySettings) < pAuthPara->cbSize)
  992. *pdwRegPolicySettings = pAuthPara->dwRegPolicySettings;
  993. }
  994. }
  995. BOOL
  996. WINAPI
  997. CertDllVerifyAuthenticodeTimeStampCertificateChainPolicy(
  998. IN LPCSTR pszPolicyOID,
  999. IN PCCERT_CHAIN_CONTEXT pChainContext,
  1000. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  1001. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  1002. )
  1003. {
  1004. DWORD dwError;
  1005. DWORD dwFlags;
  1006. DWORD dwRegPolicySettings;
  1007. LONG lChainIndex = -1;
  1008. LONG lElementIndex = -1;
  1009. CERT_CHAIN_POLICY_PARA BasePolicyPara;
  1010. memset(&BasePolicyPara, 0, sizeof(BasePolicyPara));
  1011. BasePolicyPara.cbSize = sizeof(BasePolicyPara);
  1012. CERT_CHAIN_POLICY_STATUS BasePolicyStatus;
  1013. memset(&BasePolicyStatus, 0, sizeof(BasePolicyStatus));
  1014. BasePolicyStatus.cbSize = sizeof(BasePolicyStatus);
  1015. if (pPolicyPara && offsetof(CERT_CHAIN_POLICY_PARA, dwFlags) <
  1016. pPolicyPara->cbSize)
  1017. dwFlags = pPolicyPara->dwFlags;
  1018. else
  1019. dwFlags = 0;
  1020. GetAuthenticodeTimeStampPara(
  1021. pPolicyPara, &dwRegPolicySettings);
  1022. MapAuthenticodeTimeStampRegPolicySettingsToBaseChainPolicyFlags(
  1023. dwRegPolicySettings, &dwFlags);
  1024. // Do the basic chain policy verification. Authenticode overrides
  1025. // the defaults for the following:
  1026. dwFlags |=
  1027. CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG |
  1028. CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
  1029. CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
  1030. CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG |
  1031. CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
  1032. BasePolicyPara.dwFlags = dwFlags;
  1033. if (!CertVerifyCertificateChainPolicy(
  1034. CERT_CHAIN_POLICY_BASE,
  1035. pChainContext,
  1036. &BasePolicyPara,
  1037. &BasePolicyStatus
  1038. ))
  1039. return FALSE;
  1040. if (dwError = BasePolicyStatus.dwError) {
  1041. dwError = MapToAuthenticodeError(dwError);
  1042. lChainIndex = BasePolicyStatus.lChainIndex;
  1043. lElementIndex = BasePolicyStatus.lElementIndex;
  1044. goto CommonReturn;
  1045. }
  1046. CommonReturn:
  1047. assert(pPolicyStatus && offsetof(CERT_CHAIN_POLICY_STATUS, lElementIndex) <
  1048. pPolicyStatus->cbSize);
  1049. pPolicyStatus->dwError = dwError;
  1050. pPolicyStatus->lChainIndex = lChainIndex;
  1051. pPolicyStatus->lElementIndex = lElementIndex;
  1052. return TRUE;
  1053. }
  1054. //+=========================================================================
  1055. // CertDllVerifySSLCertificateChainPolicy Functions
  1056. //==========================================================================
  1057. // www.foobar.com == www.foobar.com
  1058. // Www.Foobar.com == www.fooBar.cOm
  1059. // www.foobar.com == *.foobar.com
  1060. // www.foobar.com == w*.foobar.com
  1061. // www.foobar.com == ww*.foobar.com
  1062. // www.foobar.com != *ww.foobar.com
  1063. // abcdef.foobar.com != ab*ef.foobar.com
  1064. // abcdef.foobar.com != abc*ef.foobar.com
  1065. // abcdef.foobar.com != abc*def.foobar.com
  1066. // www.foobar.com != www.f*bar.com
  1067. // www.foobar.com != www.*bar.com
  1068. // www.foobar.com != www.foo*.com
  1069. // www.foobar.com != www.*.com
  1070. // foobar.com != *.com
  1071. // www.foobar.abc.com != *.abc.com
  1072. // foobar.com != *.*
  1073. // foobar != *
  1074. // abc.def.foobar.com != a*.d*.foobar.com
  1075. // abc.foobar.com.au != *.*.com.au
  1076. // abc.foobar.com.au != www.*.com.au
  1077. BOOL CompareSSLDNStoCommonName(LPCWSTR pDNS, LPCWSTR pCN)
  1078. {
  1079. BOOL fUseWildCardRules = FALSE;
  1080. if (NULL == pDNS || L'\0' == *pDNS ||
  1081. NULL == pCN || L'\0' == *pCN)
  1082. return FALSE;
  1083. if(fWildcardsEnabledInSslServerCerts)
  1084. {
  1085. if(wcschr(pCN, L'*') != NULL)
  1086. {
  1087. fUseWildCardRules = TRUE;
  1088. }
  1089. }
  1090. if(fUseWildCardRules)
  1091. {
  1092. DWORD nCountPeriods = 1;
  1093. BOOL fExactMatch = TRUE;
  1094. BOOL fComp;
  1095. LPCWSTR pWild;
  1096. pWild = wcschr(pCN, L'*');
  1097. if(pWild)
  1098. {
  1099. // Fail if CN contains more than one '*'.
  1100. if(wcschr(pWild + 1, L'*'))
  1101. {
  1102. return FALSE;
  1103. }
  1104. // Fail if the wildcard isn't in the first name component.
  1105. if(pWild > wcschr(pCN, L'.'))
  1106. {
  1107. return FALSE;
  1108. }
  1109. }
  1110. while(TRUE)
  1111. {
  1112. fComp = (CSTR_EQUAL == CompareStringU(
  1113. LOCALE_USER_DEFAULT,
  1114. NORM_IGNORECASE,
  1115. pDNS,
  1116. 1, // cchCount1
  1117. pCN,
  1118. 1)); // cchCount2
  1119. if ((!fComp && *pCN != L'*') || !(*pDNS) || !(*pCN))
  1120. {
  1121. break;
  1122. }
  1123. if (!fComp)
  1124. {
  1125. fExactMatch = FALSE;
  1126. }
  1127. if (*pCN == L'*')
  1128. {
  1129. nCountPeriods = 0;
  1130. if (*pDNS == L'.')
  1131. {
  1132. pCN++;
  1133. }
  1134. else
  1135. {
  1136. pDNS++;
  1137. }
  1138. }
  1139. else
  1140. {
  1141. if (*pDNS == L'.')
  1142. {
  1143. nCountPeriods++;
  1144. }
  1145. pDNS++;
  1146. pCN++;
  1147. }
  1148. }
  1149. return((*pDNS == 0) && (*pCN == 0) && ((nCountPeriods >= 2) || fExactMatch));
  1150. }
  1151. else
  1152. {
  1153. if (CSTR_EQUAL == CompareStringU(
  1154. LOCALE_USER_DEFAULT,
  1155. NORM_IGNORECASE,
  1156. pDNS,
  1157. -1, // cchCount1
  1158. pCN,
  1159. -1 // cchCount2
  1160. ))
  1161. return TRUE;
  1162. else
  1163. return FALSE;
  1164. }
  1165. }
  1166. BOOL IsSSLServerNameInNameInfo(
  1167. IN DWORD dwCertEncodingType,
  1168. IN PCERT_NAME_BLOB pNameInfoBlob,
  1169. IN LPCWSTR pwszServerName
  1170. )
  1171. {
  1172. BOOL fResult;
  1173. PCERT_NAME_INFO pInfo = NULL;
  1174. DWORD cbInfo;
  1175. DWORD cRDN;
  1176. PCERT_RDN pRDN;
  1177. if (!CryptDecodeObjectEx(
  1178. dwCertEncodingType,
  1179. X509_UNICODE_NAME,
  1180. pNameInfoBlob->pbData,
  1181. pNameInfoBlob->cbData,
  1182. CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG |
  1183. CRYPT_DECODE_SHARE_OID_STRING_FLAG,
  1184. &PkiDecodePara,
  1185. (void *) &pInfo,
  1186. &cbInfo
  1187. ))
  1188. goto DecodeError;
  1189. cRDN = pInfo->cRDN;
  1190. pRDN = pInfo->rgRDN;
  1191. for ( ; cRDN > 0; cRDN--, pRDN++) {
  1192. DWORD cAttr = pRDN->cRDNAttr;
  1193. PCERT_RDN_ATTR pAttr = pRDN->rgRDNAttr;
  1194. for ( ; cAttr > 0; cAttr--, pAttr++) {
  1195. if (!IS_CERT_RDN_CHAR_STRING(pAttr->dwValueType))
  1196. continue;
  1197. if (0 == strcmp(pAttr->pszObjId, szOID_COMMON_NAME)) {
  1198. if (CompareSSLDNStoCommonName(pwszServerName,
  1199. (LPCWSTR) pAttr->Value.pbData))
  1200. goto SuccessReturn;
  1201. }
  1202. }
  1203. }
  1204. goto ErrorReturn;
  1205. SuccessReturn:
  1206. fResult = TRUE;
  1207. CommonReturn:
  1208. PkiFree(pInfo);
  1209. return fResult;
  1210. ErrorReturn:
  1211. fResult = FALSE;
  1212. goto CommonReturn;
  1213. TRACE_ERROR(DecodeError)
  1214. }
  1215. //
  1216. // Returns:
  1217. // 1 - found a matching DNS_NAME choice
  1218. // 0 - AltName has DNS_NAME choices, no match
  1219. // -1 - AltName doesn't have DNS_NAME choices
  1220. //
  1221. int IsSSLServerNameInAltName(
  1222. IN DWORD dwCertEncodingType,
  1223. IN PCRYPT_DER_BLOB pAltNameBlob,
  1224. IN LPCWSTR pwszServerName
  1225. )
  1226. {
  1227. int iResult = -1; // default to no DNS_NAME choices
  1228. PCERT_ALT_NAME_INFO pInfo = NULL;
  1229. DWORD cbInfo;
  1230. DWORD cEntry;
  1231. PCERT_ALT_NAME_ENTRY pEntry;
  1232. if (!CryptDecodeObjectEx(
  1233. dwCertEncodingType,
  1234. X509_ALTERNATE_NAME,
  1235. pAltNameBlob->pbData,
  1236. pAltNameBlob->cbData,
  1237. CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG |
  1238. CRYPT_DECODE_SHARE_OID_STRING_FLAG,
  1239. &PkiDecodePara,
  1240. (void *) &pInfo,
  1241. &cbInfo
  1242. ))
  1243. goto DecodeError;
  1244. cEntry = pInfo->cAltEntry;
  1245. pEntry = pInfo->rgAltEntry;
  1246. for ( ; cEntry > 0; cEntry--, pEntry++) {
  1247. if (CERT_ALT_NAME_DNS_NAME == pEntry->dwAltNameChoice) {
  1248. if (CompareSSLDNStoCommonName(pwszServerName,
  1249. pEntry->pwszDNSName))
  1250. goto SuccessReturn;
  1251. else
  1252. iResult = 0;
  1253. }
  1254. }
  1255. goto ErrorReturn;
  1256. SuccessReturn:
  1257. iResult = 1;
  1258. CommonReturn:
  1259. PkiFree(pInfo);
  1260. return iResult;
  1261. ErrorReturn:
  1262. goto CommonReturn;
  1263. TRACE_ERROR(DecodeError)
  1264. }
  1265. BOOL IsSSLServerName(
  1266. IN PCCERT_CONTEXT pCertContext,
  1267. IN LPCWSTR pwszServerName
  1268. )
  1269. {
  1270. PCERT_INFO pCertInfo = pCertContext->pCertInfo;
  1271. DWORD dwCertEncodingType = pCertContext->dwCertEncodingType;
  1272. PCERT_EXTENSION pExt;
  1273. pExt = CertFindExtension(
  1274. szOID_SUBJECT_ALT_NAME2,
  1275. pCertInfo->cExtension,
  1276. pCertInfo->rgExtension
  1277. );
  1278. if (NULL == pExt) {
  1279. pExt = CertFindExtension(
  1280. szOID_SUBJECT_ALT_NAME,
  1281. pCertInfo->cExtension,
  1282. pCertInfo->rgExtension
  1283. );
  1284. }
  1285. if (pExt) {
  1286. int iResult;
  1287. iResult = IsSSLServerNameInAltName(dwCertEncodingType,
  1288. &pExt->Value, pwszServerName);
  1289. if (0 < iResult)
  1290. return TRUE;
  1291. else if (0 == iResult)
  1292. return FALSE;
  1293. // else
  1294. // AltName didn't have any DNS_NAME choices
  1295. }
  1296. return IsSSLServerNameInNameInfo(dwCertEncodingType,
  1297. &pCertInfo->Subject, pwszServerName);
  1298. }
  1299. BOOL
  1300. WINAPI
  1301. CertDllVerifySSLCertificateChainPolicy(
  1302. IN LPCSTR pszPolicyOID,
  1303. IN PCCERT_CHAIN_CONTEXT pChainContext,
  1304. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  1305. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  1306. )
  1307. {
  1308. DWORD dwError;
  1309. DWORD dwFlags;
  1310. DWORD fdwChecks;
  1311. LONG lChainIndex = -1;
  1312. LONG lElementIndex = -1;
  1313. SSL_EXTRA_CERT_CHAIN_POLICY_PARA NullSSLExtraPara;
  1314. PSSL_EXTRA_CERT_CHAIN_POLICY_PARA pSSLExtraPara; // not allocated
  1315. CERT_CHAIN_POLICY_PARA BasePolicyPara;
  1316. memset(&BasePolicyPara, 0, sizeof(BasePolicyPara));
  1317. BasePolicyPara.cbSize = sizeof(BasePolicyPara);
  1318. CERT_CHAIN_POLICY_STATUS BasePolicyStatus;
  1319. memset(&BasePolicyStatus, 0, sizeof(BasePolicyStatus));
  1320. BasePolicyStatus.cbSize = sizeof(BasePolicyStatus);
  1321. if (pPolicyPara && offsetof(CERT_CHAIN_POLICY_PARA, dwFlags) <
  1322. pPolicyPara->cbSize)
  1323. dwFlags = pPolicyPara->dwFlags;
  1324. else
  1325. dwFlags = 0;
  1326. if (pPolicyPara && offsetof(CERT_CHAIN_POLICY_PARA, pvExtraPolicyPara) <
  1327. pPolicyPara->cbSize && pPolicyPara->pvExtraPolicyPara) {
  1328. pSSLExtraPara =
  1329. (PSSL_EXTRA_CERT_CHAIN_POLICY_PARA) pPolicyPara->pvExtraPolicyPara;
  1330. if (offsetof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA, pwszServerName) >=
  1331. pSSLExtraPara->cbSize) {
  1332. SetLastError((DWORD) ERROR_INVALID_PARAMETER);
  1333. return FALSE;
  1334. }
  1335. } else {
  1336. pSSLExtraPara = &NullSSLExtraPara;
  1337. memset(&NullSSLExtraPara, 0, sizeof(NullSSLExtraPara));
  1338. NullSSLExtraPara.cbSize = sizeof(NullSSLExtraPara);
  1339. NullSSLExtraPara.dwAuthType = AUTHTYPE_SERVER;
  1340. }
  1341. fdwChecks = pSSLExtraPara->fdwChecks;
  1342. if (fdwChecks) {
  1343. if (fdwChecks & SECURITY_FLAG_IGNORE_UNKNOWN_CA)
  1344. // 11-Nov-98 per Sanjay Shenoy removed
  1345. // CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG;
  1346. dwFlags |= CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG;
  1347. if (fdwChecks & SECURITY_FLAG_IGNORE_WRONG_USAGE)
  1348. dwFlags |= CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG;
  1349. if (fdwChecks & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)
  1350. dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS;
  1351. if (fdwChecks & SECURITY_FLAG_IGNORE_CERT_CN_INVALID)
  1352. dwFlags |= CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG;
  1353. }
  1354. // Do the basic chain policy verification. SSL overrides
  1355. // the defaults for the following:
  1356. dwFlags |=
  1357. CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
  1358. CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
  1359. CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG |
  1360. CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
  1361. BasePolicyPara.dwFlags = dwFlags;
  1362. if (!CertVerifyCertificateChainPolicy(
  1363. CERT_CHAIN_POLICY_BASE,
  1364. pChainContext,
  1365. &BasePolicyPara,
  1366. &BasePolicyStatus
  1367. ))
  1368. return FALSE;
  1369. if (dwError = BasePolicyStatus.dwError) {
  1370. // Map to errors understood by wininet
  1371. switch (dwError) {
  1372. case CERT_E_CHAINING:
  1373. dwError = (DWORD) CERT_E_UNTRUSTEDROOT;
  1374. break;
  1375. case CERT_E_INVALID_NAME:
  1376. dwError = (DWORD) CERT_E_CN_NO_MATCH;
  1377. break;
  1378. case CERT_E_INVALID_POLICY:
  1379. dwError = (DWORD) CERT_E_PURPOSE;
  1380. break;
  1381. case TRUST_E_BASIC_CONSTRAINTS:
  1382. dwError = (DWORD) CERT_E_ROLE;
  1383. break;
  1384. default:
  1385. break;
  1386. }
  1387. lChainIndex = BasePolicyStatus.lChainIndex;
  1388. lElementIndex = BasePolicyStatus.lElementIndex;
  1389. if (CRYPT_E_NO_REVOCATION_CHECK != dwError &&
  1390. CRYPT_E_REVOCATION_OFFLINE != dwError)
  1391. goto CommonReturn;
  1392. // else
  1393. // for NO_REVOCATION or REVOCATION_OFFLINE let
  1394. // ServerName errors take precedence
  1395. }
  1396. // Note, this policy can also be used for LDAP ServerName strings. These
  1397. // strings can have the following syntax:
  1398. // svc-class/host/service-name[@domain]
  1399. //
  1400. // Will parse the ServerName as follows:
  1401. // take everything after the last forward slash and before the "@"
  1402. // (if any).
  1403. if (pSSLExtraPara->pwszServerName) {
  1404. DWORD cbServerName;
  1405. LPWSTR pwszAllocServerName = NULL;
  1406. LPWSTR pwszServerName = NULL;
  1407. LPWSTR pwsz;
  1408. WCHAR wc;
  1409. cbServerName = (wcslen(pSSLExtraPara->pwszServerName) + 1) *
  1410. sizeof(WCHAR);
  1411. pwszAllocServerName = (LPWSTR) PkiNonzeroAlloc(cbServerName);
  1412. if (NULL == pwszAllocServerName) {
  1413. dwError = (DWORD) E_OUTOFMEMORY;
  1414. goto EndCertError;
  1415. }
  1416. pwszServerName = pwszAllocServerName;
  1417. memcpy(pwszServerName, pSSLExtraPara->pwszServerName, cbServerName);
  1418. for (pwsz = pwszServerName; wc = *pwsz; pwsz++) {
  1419. if (L'/' == wc)
  1420. pwszServerName = pwsz + 1;
  1421. else if (L'@' == wc) {
  1422. *pwsz = L'\0';
  1423. break;
  1424. }
  1425. }
  1426. if (0 == (fdwChecks & SECURITY_FLAG_IGNORE_CERT_CN_INVALID)) {
  1427. if (!IsSSLServerName(
  1428. pChainContext->rgpChain[0]->rgpElement[0]->pCertContext,
  1429. pwszServerName
  1430. )) {
  1431. PkiFree(pwszAllocServerName);
  1432. dwError = (DWORD) CERT_E_CN_NO_MATCH;
  1433. goto EndCertError;
  1434. }
  1435. }
  1436. PkiFree(pwszAllocServerName);
  1437. }
  1438. CommonReturn:
  1439. assert(pPolicyStatus && offsetof(CERT_CHAIN_POLICY_STATUS, lElementIndex) <
  1440. pPolicyStatus->cbSize);
  1441. pPolicyStatus->dwError = dwError;
  1442. pPolicyStatus->lChainIndex = lChainIndex;
  1443. pPolicyStatus->lElementIndex = lElementIndex;
  1444. return TRUE;
  1445. EndCertError:
  1446. lChainIndex = 0;
  1447. lElementIndex = 0;
  1448. goto CommonReturn;
  1449. }
  1450. //+=========================================================================
  1451. // CertDllVerifyNTAuthCertificateChainPolicy Functions
  1452. //==========================================================================
  1453. // Open and cache the store containing CAs trusted for NT Authentication.
  1454. // Also, enable auto resync for the cached store.
  1455. HCERTSTORE OpenNTAuthStore()
  1456. {
  1457. HCERTSTORE hStore;
  1458. hStore = hNTAuthCertStore;
  1459. if (NULL == hStore) {
  1460. // Serialize opening of the cached store
  1461. CertPolicyLock();
  1462. hStore = hNTAuthCertStore;
  1463. if (NULL == hStore) {
  1464. hStore = CertOpenStore(
  1465. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  1466. 0, // dwEncodingType
  1467. 0, // hCryptProv
  1468. CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE |
  1469. CERT_STORE_MAXIMUM_ALLOWED_FLAG,
  1470. L"NTAuth"
  1471. );
  1472. if (hStore) {
  1473. CertControlStore(
  1474. hStore,
  1475. 0, // dwFlags
  1476. CERT_STORE_CTRL_AUTO_RESYNC,
  1477. NULL // pvCtrlPara
  1478. );
  1479. hNTAuthCertStore = hStore;
  1480. }
  1481. }
  1482. CertPolicyUnlock();
  1483. }
  1484. return hStore;
  1485. }
  1486. BOOL
  1487. WINAPI
  1488. CertDllVerifyNTAuthCertificateChainPolicy(
  1489. IN LPCSTR pszPolicyOID,
  1490. IN PCCERT_CHAIN_CONTEXT pChainContext,
  1491. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  1492. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  1493. )
  1494. {
  1495. BOOL fResult;
  1496. DWORD dwError;
  1497. LONG lChainIndex = 0;
  1498. LONG lElementIndex = 0;
  1499. PCERT_SIMPLE_CHAIN pChain;
  1500. assert(pPolicyStatus && offsetof(CERT_CHAIN_POLICY_STATUS, lElementIndex) <
  1501. pPolicyStatus->cbSize);
  1502. if (!CertDllVerifyBaseCertificateChainPolicy(
  1503. pszPolicyOID,
  1504. pChainContext,
  1505. pPolicyPara,
  1506. pPolicyStatus
  1507. ))
  1508. return FALSE;
  1509. if (dwError = pPolicyStatus->dwError) {
  1510. if (CRYPT_E_NO_REVOCATION_CHECK != dwError &&
  1511. CRYPT_E_REVOCATION_OFFLINE != dwError)
  1512. return TRUE;
  1513. // else
  1514. // for NO_REVOCATION or REVOCATION_OFFLINE let
  1515. // following errors take precedence
  1516. // Remember revocation indices
  1517. lChainIndex = pPolicyStatus->lChainIndex;
  1518. lElementIndex = pPolicyStatus->lElementIndex;
  1519. }
  1520. fResult = CertDllVerifyBasicConstraintsCertificateChainPolicy(
  1521. pszPolicyOID,
  1522. pChainContext,
  1523. pPolicyPara,
  1524. pPolicyStatus
  1525. );
  1526. if (!fResult || 0 != pPolicyStatus->dwError)
  1527. return fResult;
  1528. // Check if we have a CA certificate that issued the end entity
  1529. // certificate. Its Element[1] in the first simple chain.
  1530. pChain = pChainContext->rgpChain[0];
  1531. if (2 > pChain->cElement)
  1532. goto MissingCACert;
  1533. if (IPR_IsNTAuthRequiredDisabled() &&
  1534. (pChain->TrustStatus.dwInfoStatus &
  1535. CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS)) {
  1536. // If its not required that the issuing CA be in the NTAuth store
  1537. // and there are valid name constraints for all name spaces including
  1538. // UPN, then, we can skip the test for being in the NTAuth store.
  1539. ;
  1540. } else {
  1541. PCCERT_CONTEXT pFindCert; // freed if found
  1542. HCERTSTORE hStore; // cached, don't close
  1543. BYTE rgbCertHash[SHA1_HASH_LEN];
  1544. CRYPT_HASH_BLOB CertHash;
  1545. // Open the store where the CA certificate must exist to be trusted.
  1546. // Note, this store is cached with auto resync enabled.
  1547. if (NULL == (hStore = OpenNTAuthStore()))
  1548. goto OpenNTAuthStoreError;
  1549. // Try to find the CA certificate in the store
  1550. CertHash.cbData = sizeof(rgbCertHash);
  1551. CertHash.pbData = rgbCertHash;
  1552. if (!CertGetCertificateContextProperty(
  1553. pChain->rgpElement[1]->pCertContext,
  1554. CERT_SHA1_HASH_PROP_ID,
  1555. CertHash.pbData,
  1556. &CertHash.cbData
  1557. ))
  1558. goto GetHashPropertyError;
  1559. if (NULL == (pFindCert = CertFindCertificateInStore(
  1560. hStore,
  1561. 0, // dwCertEncodingType
  1562. 0, // dwFindFlags
  1563. CERT_FIND_SHA1_HASH,
  1564. &CertHash,
  1565. NULL // pPrevCertContext
  1566. )))
  1567. goto UntrustedNTAuthCert;
  1568. CertFreeCertificateContext(pFindCert);
  1569. }
  1570. if (dwError) {
  1571. // For NO_REVOCATION or REVOCATION_OFFLINE update indices
  1572. pPolicyStatus->lChainIndex = lChainIndex;
  1573. pPolicyStatus->lElementIndex = lElementIndex;
  1574. }
  1575. CommonReturn:
  1576. pPolicyStatus->dwError = dwError;
  1577. return TRUE;
  1578. ErrorReturn:
  1579. pPolicyStatus->lChainIndex = 0;
  1580. pPolicyStatus->lElementIndex = 1;
  1581. MissingCACert:
  1582. dwError = (DWORD) CERT_E_UNTRUSTEDCA;
  1583. goto CommonReturn;
  1584. TRACE_ERROR(OpenNTAuthStoreError)
  1585. TRACE_ERROR(GetHashPropertyError)
  1586. TRACE_ERROR(UntrustedNTAuthCert)
  1587. }
  1588. //+-------------------------------------------------------------------------
  1589. // SHA1 Key Identifier of the Microsoft roots
  1590. //--------------------------------------------------------------------------
  1591. const BYTE MicrosoftRootList[][SHA1_HASH_LEN] = {
  1592. // The following is the sha1 key identifier for the Microsoft root
  1593. {
  1594. 0x4A, 0x5C, 0x75, 0x22, 0xAA, 0x46, 0xBF, 0xA4, 0x08, 0x9D,
  1595. 0x39, 0x97, 0x4E, 0xBD, 0xB4, 0xA3, 0x60, 0xF7, 0xA0, 0x1D
  1596. },
  1597. // The following is the sha1 key identifier for the Microsoft root
  1598. // generated in 2001 with a key length of 4096 bits
  1599. {
  1600. 0x0E, 0xAC, 0x82, 0x60, 0x40, 0x56, 0x27, 0x97, 0xE5, 0x25,
  1601. 0x13, 0xFC, 0x2A, 0xE1, 0x0A, 0x53, 0x95, 0x59, 0xE4, 0xA4
  1602. },
  1603. };
  1604. #define MICROSOFT_ROOT_LIST_CNT (sizeof(MicrosoftRootList) / \
  1605. sizeof(MicrosoftRootList[0]))
  1606. //+-------------------------------------------------------------------------
  1607. // SHA1 Key Identifier of the Microsoft test roots
  1608. //--------------------------------------------------------------------------
  1609. const BYTE MicrosoftTestRootList[][SHA1_HASH_LEN] = {
  1610. // The following is the sha1 key for the Microsoft Test Root:
  1611. // CN=Microsoft Test Root Authority
  1612. // OU=Microsoft Corporation
  1613. // OU=Copyright (c) 1999 Microsoft Corp.
  1614. //
  1615. // NotBefore:: Sat Jan 09 23:00:00 1999
  1616. // NotAfter:: Wed Dec 30 23:00:00 2020
  1617. {
  1618. 0x22, 0xCD, 0x37, 0xF1, 0xB1, 0x47, 0x50, 0xAE, 0x53, 0x7C,
  1619. 0x8C, 0x6A, 0x03, 0x67, 0x47, 0xE2, 0xB7, 0x1E, 0x17, 0xB7
  1620. },
  1621. };
  1622. #define MICROSOFT_TEST_ROOT_LIST_CNT (sizeof(MicrosoftTestRootList) / \
  1623. sizeof(MicrosoftTestRootList[0]))
  1624. BOOL
  1625. WINAPI
  1626. CertDllVerifyMicrosoftRootCertificateChainPolicy(
  1627. IN LPCSTR pszPolicyOID,
  1628. IN PCCERT_CHAIN_CONTEXT pChainContext,
  1629. IN PCERT_CHAIN_POLICY_PARA pPolicyPara,
  1630. IN OUT PCERT_CHAIN_POLICY_STATUS pPolicyStatus
  1631. )
  1632. {
  1633. DWORD dwError;
  1634. LONG lElementIndex;
  1635. PCERT_SIMPLE_CHAIN pChain;
  1636. DWORD cChainElement;
  1637. PCCERT_CONTEXT pCert; // not refCount'ed
  1638. BYTE rgbKeyId[SHA1_HASH_LEN];
  1639. DWORD cbKeyId;
  1640. DWORD i;
  1641. DWORD dwFlags;
  1642. assert(pPolicyStatus && offsetof(CERT_CHAIN_POLICY_STATUS, lElementIndex) <
  1643. pPolicyStatus->cbSize);
  1644. pChain = pChainContext->rgpChain[0];
  1645. cChainElement = pChain->cElement;
  1646. // Check that the top level certificate contains the public
  1647. // key for the Microsoft root.
  1648. pCert = pChain->rgpElement[cChainElement - 1]->pCertContext;
  1649. cbKeyId = SHA1_HASH_LEN;
  1650. if (!CryptHashPublicKeyInfo(
  1651. NULL, // hCryptProv
  1652. CALG_SHA1,
  1653. 0, // dwFlags
  1654. X509_ASN_ENCODING,
  1655. &pCert->pCertInfo->SubjectPublicKeyInfo,
  1656. rgbKeyId,
  1657. &cbKeyId) || SHA1_HASH_LEN != cbKeyId)
  1658. goto HashPublicKeyInfoError;
  1659. for (i = 0; i < MICROSOFT_ROOT_LIST_CNT; i++) {
  1660. if (0 == memcmp(MicrosoftRootList[i], rgbKeyId, SHA1_HASH_LEN))
  1661. goto SuccessReturn;
  1662. }
  1663. if (pPolicyPara && offsetof(CERT_CHAIN_POLICY_PARA, dwFlags) <
  1664. pPolicyPara->cbSize)
  1665. dwFlags = pPolicyPara->dwFlags;
  1666. else
  1667. dwFlags = 0;
  1668. if (dwFlags & MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG) {
  1669. for (i = 0; i < MICROSOFT_TEST_ROOT_LIST_CNT; i++) {
  1670. if (0 == memcmp(MicrosoftTestRootList[i], rgbKeyId, SHA1_HASH_LEN))
  1671. goto SuccessReturn;
  1672. }
  1673. }
  1674. goto InvalidMicrosoftRoot;
  1675. SuccessReturn:
  1676. dwError = 0;
  1677. lElementIndex = 0;
  1678. CommonReturn:
  1679. pPolicyStatus->dwError = dwError;
  1680. pPolicyStatus->lChainIndex = 0;
  1681. pPolicyStatus->lElementIndex = lElementIndex;
  1682. return TRUE;
  1683. ErrorReturn:
  1684. dwError = (DWORD) CERT_E_UNTRUSTEDROOT;
  1685. lElementIndex = cChainElement - 1;
  1686. goto CommonReturn;
  1687. TRACE_ERROR(HashPublicKeyInfoError)
  1688. TRACE_ERROR(InvalidMicrosoftRoot)
  1689. }