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.

376 lines
12 KiB

  1. //+-------------------------------------------------------------------------
  2. // Microsoft Windows
  3. //
  4. // Copyright (C) Microsoft Corporation, 1999 - 1999
  5. //
  6. // File: rootlist.cpp
  7. //
  8. // Contents: Signed List of Trusted Roots Helper Functions
  9. //
  10. //
  11. // Functions: IRL_VerifyAuthRootAutoUpdateCtl
  12. //
  13. // History: 01-Aug-99 philh created
  14. //--------------------------------------------------------------------------
  15. #include "global.hxx"
  16. #include <dbgdef.h>
  17. #ifdef STATIC
  18. #undef STATIC
  19. #endif
  20. #define STATIC
  21. //+-------------------------------------------------------------------------
  22. // If the certificate has an EKU extension, returns an allocated and
  23. // decoded EKU. Otherwise, returns NULL.
  24. //
  25. // PkiFree() must be called to free the returned EKU.
  26. //--------------------------------------------------------------------------
  27. STATIC
  28. PCERT_ENHKEY_USAGE
  29. WINAPI
  30. GetAndAllocCertEKUExt(
  31. IN PCCERT_CONTEXT pCert
  32. )
  33. {
  34. PCERT_ENHKEY_USAGE pUsage = NULL;
  35. DWORD cbUsage;
  36. cbUsage = 0;
  37. if (!CertGetEnhancedKeyUsage(
  38. pCert,
  39. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  40. NULL, // pUsage
  41. &cbUsage) || 0 == cbUsage)
  42. goto GetEnhancedKeyUsageError;
  43. if (NULL == (pUsage = (PCERT_ENHKEY_USAGE) PkiNonzeroAlloc(cbUsage)))
  44. goto OutOfMemory;
  45. if (!CertGetEnhancedKeyUsage(
  46. pCert,
  47. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  48. pUsage,
  49. &cbUsage))
  50. goto GetEnhancedKeyUsageError;
  51. CommonReturn:
  52. return pUsage;
  53. ErrorReturn:
  54. if (pUsage) {
  55. PkiFree(pUsage);
  56. pUsage = NULL;
  57. }
  58. goto CommonReturn;
  59. SET_ERROR(GetEnhancedKeyUsageError, CERT_E_WRONG_USAGE)
  60. TRACE_ERROR(OutOfMemory)
  61. }
  62. //+-------------------------------------------------------------------------
  63. // The signature of the CTL is verified. The signer of the CTL is verified
  64. // up to a trusted root containing the predefined Microsoft public key.
  65. //
  66. // The signer and intermediate certificates must have the
  67. // szOID_ROOT_LIST_SIGNER enhanced key usage extension.
  68. //--------------------------------------------------------------------------
  69. STATIC
  70. BOOL
  71. WINAPI
  72. VerifyAuthRootAutoUpdateCtlSigner(
  73. IN HCRYPTMSG hCryptMsg
  74. )
  75. {
  76. BOOL fResult;
  77. DWORD dwLastError = 0;
  78. HCERTSTORE hMsgStore = NULL;
  79. PCCERT_CONTEXT pSignerCert = NULL;
  80. LPSTR pszUsageOID;
  81. CERT_CHAIN_PARA ChainPara;
  82. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  83. PCERT_SIMPLE_CHAIN pChain;
  84. DWORD cChainElement;
  85. CERT_CHAIN_POLICY_PARA BasePolicyPara;
  86. CERT_CHAIN_POLICY_STATUS BasePolicyStatus;
  87. CERT_CHAIN_POLICY_PARA MicrosoftRootPolicyPara;
  88. CERT_CHAIN_POLICY_STATUS MicrosoftRootPolicyStatus;
  89. PCERT_ENHKEY_USAGE pUsage = NULL;
  90. DWORD i;
  91. if (NULL == (hMsgStore = CertOpenStore(
  92. CERT_STORE_PROV_MSG,
  93. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  94. 0, // hCryptProv
  95. 0, // dwFlags
  96. hCryptMsg // pvPara
  97. )))
  98. goto OpenMsgStoreError;
  99. if (!CryptMsgGetAndVerifySigner(
  100. hCryptMsg,
  101. 0, // cSignerStore
  102. NULL, // rghSignerStore
  103. 0, // dwFlags
  104. &pSignerCert,
  105. NULL // pdwSignerIndex
  106. ))
  107. goto CryptMsgGetAndVerifySignerError;
  108. pszUsageOID = szOID_ROOT_LIST_SIGNER;
  109. memset(&ChainPara, 0, sizeof(ChainPara));
  110. ChainPara.cbSize = sizeof(ChainPara);
  111. ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  112. ChainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
  113. ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = &pszUsageOID;
  114. if (!CertGetCertificateChain(
  115. NULL, // hChainEngine
  116. pSignerCert,
  117. NULL, // pTime
  118. hMsgStore,
  119. &ChainPara,
  120. CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE,
  121. NULL, // pvReserved
  122. &pChainContext
  123. ))
  124. goto GetChainError;
  125. // Do the basic chain policy verification
  126. memset(&BasePolicyPara, 0, sizeof(BasePolicyPara));
  127. BasePolicyPara.cbSize = sizeof(BasePolicyPara);
  128. // We explicitly check for the Microsoft Root below. It doesn't need
  129. // to be in the root store.
  130. BasePolicyPara.dwFlags =
  131. CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG |
  132. CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
  133. memset(&BasePolicyStatus, 0, sizeof(BasePolicyStatus));
  134. BasePolicyStatus.cbSize = sizeof(BasePolicyStatus);
  135. if (!CertVerifyCertificateChainPolicy(
  136. CERT_CHAIN_POLICY_BASE,
  137. pChainContext,
  138. &BasePolicyPara,
  139. &BasePolicyStatus
  140. ))
  141. goto VerifyChainBasePolicyError;
  142. if (0 != BasePolicyStatus.dwError)
  143. goto ChainBasePolicyError;
  144. // Check that we have more than just the signer cert.
  145. pChain = pChainContext->rgpChain[0];
  146. cChainElement = pChain->cElement;
  147. if (2 > cChainElement)
  148. goto MissingSignerChainCertsError;
  149. // Check that the top level certificate contains the public
  150. // key for the Microsoft root.
  151. memset(&MicrosoftRootPolicyPara, 0, sizeof(MicrosoftRootPolicyPara));
  152. MicrosoftRootPolicyPara.cbSize = sizeof(MicrosoftRootPolicyPara);
  153. memset(&MicrosoftRootPolicyStatus, 0, sizeof(MicrosoftRootPolicyStatus));
  154. MicrosoftRootPolicyStatus.cbSize = sizeof(MicrosoftRootPolicyStatus);
  155. if (!CertVerifyCertificateChainPolicy(
  156. CERT_CHAIN_POLICY_MICROSOFT_ROOT,
  157. pChainContext,
  158. &MicrosoftRootPolicyPara,
  159. &MicrosoftRootPolicyStatus
  160. ))
  161. goto VerifyChainMicrosoftRootPolicyError;
  162. if (0 != MicrosoftRootPolicyStatus.dwError)
  163. goto ChainMicrosoftRootPolicyError;
  164. // Check that the signer and intermediate certs have the RootListSigner
  165. // Usage extension
  166. for (i = 0; i < cChainElement - 1; i++) {
  167. PCCERT_CONTEXT pCert; // not refCount'ed
  168. DWORD j;
  169. pCert = pChain->rgpElement[i]->pCertContext;
  170. pUsage = GetAndAllocCertEKUExt(pCert);
  171. if (NULL == pUsage)
  172. goto GetAndAllocCertEKUExtError;
  173. for (j = 0; j < pUsage->cUsageIdentifier; j++) {
  174. if (0 == strcmp(szOID_ROOT_LIST_SIGNER,
  175. pUsage->rgpszUsageIdentifier[j]))
  176. break;
  177. }
  178. if (j == pUsage->cUsageIdentifier)
  179. goto MissingRootListSignerUsageError;
  180. PkiFree(pUsage);
  181. pUsage = NULL;
  182. }
  183. fResult = TRUE;
  184. CommonReturn:
  185. if (pChainContext)
  186. CertFreeCertificateChain(pChainContext);
  187. if (pUsage)
  188. PkiFree(pUsage);
  189. if (pSignerCert)
  190. CertFreeCertificateContext(pSignerCert);
  191. if (hMsgStore)
  192. CertCloseStore(hMsgStore, 0);
  193. SetLastError(dwLastError);
  194. return fResult;
  195. ErrorReturn:
  196. dwLastError = GetLastError();
  197. fResult = FALSE;
  198. goto CommonReturn;
  199. TRACE_ERROR(OpenMsgStoreError)
  200. TRACE_ERROR(CryptMsgGetAndVerifySignerError)
  201. TRACE_ERROR(GetChainError)
  202. TRACE_ERROR(VerifyChainBasePolicyError)
  203. SET_ERROR_VAR(ChainBasePolicyError, BasePolicyStatus.dwError)
  204. TRACE_ERROR(VerifyChainMicrosoftRootPolicyError)
  205. SET_ERROR_VAR(ChainMicrosoftRootPolicyError, MicrosoftRootPolicyStatus.dwError)
  206. SET_ERROR(MissingSignerChainCertsError, CERT_E_CHAINING)
  207. TRACE_ERROR(GetAndAllocCertEKUExtError)
  208. SET_ERROR(MissingRootListSignerUsageError, CERT_E_WRONG_USAGE)
  209. }
  210. //+-------------------------------------------------------------------------
  211. // Returns TRUE if all the CTL fields are valid. Checks for the following:
  212. // - The SubjectUsage is szOID_ROOT_LIST_SIGNER
  213. // - If NextUpdate isn't NULL, that the CTL is still time valid
  214. // - Only allow roots identified by their sha1 hash
  215. //--------------------------------------------------------------------------
  216. STATIC
  217. BOOL
  218. WINAPI
  219. VerifyAuthRootAutoUpdateCtlFields(
  220. IN PCTL_INFO pCtlInfo
  221. )
  222. {
  223. BOOL fResult;
  224. // Must have the szOID_ROOT_LIST_SIGNER usage
  225. if (1 != pCtlInfo->SubjectUsage.cUsageIdentifier ||
  226. 0 != strcmp(szOID_ROOT_LIST_SIGNER,
  227. pCtlInfo->SubjectUsage.rgpszUsageIdentifier[0]))
  228. goto InvalidSubjectUsageError;
  229. // If NextUpdate is present, verify that the CTL hasn't expired.
  230. if (pCtlInfo->NextUpdate.dwLowDateTime ||
  231. pCtlInfo->NextUpdate.dwHighDateTime) {
  232. SYSTEMTIME SystemTime;
  233. FILETIME FileTime;
  234. GetSystemTime(&SystemTime);
  235. SystemTimeToFileTime(&SystemTime, &FileTime);
  236. if (CompareFileTime(&FileTime, &pCtlInfo->NextUpdate) > 0)
  237. goto ExpiredCtlError;
  238. }
  239. // Only allow roots identified by their sha1 hash
  240. if (0 != strcmp(szOID_OIWSEC_sha1,
  241. pCtlInfo->SubjectAlgorithm.pszObjId))
  242. goto InvalidSubjectAlgorithm;
  243. fResult = TRUE;
  244. CommonReturn:
  245. return fResult;
  246. ErrorReturn:
  247. fResult = FALSE;
  248. goto CommonReturn;
  249. SET_ERROR(InvalidSubjectUsageError, ERROR_INVALID_DATA)
  250. SET_ERROR(ExpiredCtlError, CERT_E_EXPIRED)
  251. SET_ERROR(InvalidSubjectAlgorithm, ERROR_INVALID_DATA)
  252. }
  253. //+-------------------------------------------------------------------------
  254. // Returns TRUE if the CTL doesn't have any critical extensions.
  255. //--------------------------------------------------------------------------
  256. STATIC
  257. BOOL
  258. WINAPI
  259. VerifyAuthRootAutoUpdateCtlExtensions(
  260. IN PCTL_INFO pCtlInfo
  261. )
  262. {
  263. BOOL fResult;
  264. PCERT_EXTENSION pExt;
  265. DWORD cExt;
  266. // Verify the extensions
  267. for (cExt = pCtlInfo->cExtension,
  268. pExt = pCtlInfo->rgExtension; 0 < cExt; cExt--, pExt++)
  269. {
  270. if (pExt->fCritical) {
  271. goto CriticalExtensionError;
  272. }
  273. }
  274. fResult = TRUE;
  275. CommonReturn:
  276. return fResult;
  277. ErrorReturn:
  278. fResult = FALSE;
  279. goto CommonReturn;
  280. SET_ERROR(CriticalExtensionError, ERROR_INVALID_DATA)
  281. }
  282. //+-------------------------------------------------------------------------
  283. // Verifies that the CTL contains a valid list of AuthRoots used for
  284. // Auto Update.
  285. //
  286. // The signature of the CTL is verified. The signer of the CTL is verified
  287. // up to a trusted root containing the predefined Microsoft public key.
  288. // The signer and intermediate certificates must have the
  289. // szOID_ROOT_LIST_SIGNER enhanced key usage extension.
  290. //
  291. // The CTL fields are validated as follows:
  292. // - The SubjectUsage is szOID_ROOT_LIST_SIGNER
  293. // - If NextUpdate isn't NULL, that the CTL is still time valid
  294. // - Only allow roots identified by their sha1 hash
  295. //
  296. // If the CTL contains any critical extensions, then, the
  297. // CTL verification fails.
  298. //--------------------------------------------------------------------------
  299. BOOL
  300. WINAPI
  301. IRL_VerifyAuthRootAutoUpdateCtl(
  302. IN PCCTL_CONTEXT pCtl
  303. )
  304. {
  305. BOOL fResult;
  306. PCTL_INFO pCtlInfo; // not allocated
  307. if (!VerifyAuthRootAutoUpdateCtlSigner(pCtl->hCryptMsg))
  308. goto VerifyCtlSignerError;
  309. pCtlInfo = pCtl->pCtlInfo;
  310. if (!VerifyAuthRootAutoUpdateCtlFields(pCtlInfo))
  311. goto VerifyCtlFieldsError;
  312. if (!VerifyAuthRootAutoUpdateCtlExtensions(pCtlInfo))
  313. goto VerifyCtlExtensionsError;
  314. fResult = TRUE;
  315. CommonReturn:
  316. return fResult;
  317. ErrorReturn:
  318. fResult = FALSE;
  319. goto CommonReturn;
  320. TRACE_ERROR(VerifyCtlSignerError)
  321. TRACE_ERROR(VerifyCtlFieldsError)
  322. TRACE_ERROR(VerifyCtlExtensionsError)
  323. }