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.

747 lines
24 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: I_CertVerifySignedListOfTrustedRoots
  12. //
  13. // History: 01-Aug-99 philh created
  14. //--------------------------------------------------------------------------
  15. #include <windows.h>
  16. #include <assert.h>
  17. #include "wincrypt.h"
  18. #include "wintrust.h"
  19. #include "softpub.h"
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <memory.h>
  24. #include <time.h>
  25. #include "dbgdef.h"
  26. #include "rootlist.h"
  27. #ifdef STATIC
  28. #undef STATIC
  29. #endif
  30. #define STATIC
  31. #define SHA1_HASH_LEN 20
  32. //+-------------------------------------------------------------------------
  33. // SHA1 Key Identifier of the signer's root
  34. //--------------------------------------------------------------------------
  35. STATIC BYTE rgbSignerRootKeyId[SHA1_HASH_LEN] = {
  36. #if 1
  37. // The following is the sha1 key identifier for the Microsoft root
  38. 0x4A, 0x5C, 0x75, 0x22, 0xAA, 0x46, 0xBF, 0xA4, 0x08, 0x9D,
  39. 0x39, 0x97, 0x4E, 0xBD, 0xB4, 0xA3, 0x60, 0xF7, 0xA0, 0x1D
  40. #else
  41. // The following is the sha1 key identifier for the test root
  42. 0x9A, 0xA6, 0x58, 0x7F, 0x94, 0xDD, 0x91, 0xD9, 0x1E, 0x63,
  43. 0xDF, 0xD3, 0xF0, 0xCE, 0x5F, 0xAE, 0x18, 0x93, 0xAA, 0xB7
  44. #endif
  45. };
  46. //+-------------------------------------------------------------------------
  47. // If the certificate has an EKU extension, returns an allocated and
  48. // decoded EKU. Otherwise, returns NULL.
  49. //
  50. // LocalFree() must be called to free the returned EKU.
  51. //--------------------------------------------------------------------------
  52. STATIC
  53. PCERT_ENHKEY_USAGE
  54. WINAPI
  55. GetAndAllocCertEKUExt(
  56. IN PCCERT_CONTEXT pCert
  57. )
  58. {
  59. PCERT_ENHKEY_USAGE pUsage = NULL;
  60. DWORD cbUsage;
  61. cbUsage = 0;
  62. if (!CertGetEnhancedKeyUsage(
  63. pCert,
  64. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  65. NULL, // pUsage
  66. &cbUsage) || 0 == cbUsage)
  67. goto GetEnhancedKeyUsageError;
  68. if (NULL == (pUsage = (PCERT_ENHKEY_USAGE) LocalAlloc(LPTR, cbUsage)))
  69. goto OutOfMemory;
  70. if (!CertGetEnhancedKeyUsage(
  71. pCert,
  72. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  73. pUsage,
  74. &cbUsage))
  75. goto GetEnhancedKeyUsageError;
  76. CommonReturn:
  77. return pUsage;
  78. ErrorReturn:
  79. if (pUsage) {
  80. LocalFree(pUsage);
  81. pUsage = NULL;
  82. }
  83. goto CommonReturn;
  84. SET_ERROR(GetEnhancedKeyUsageError, CERT_E_WRONG_USAGE)
  85. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  86. }
  87. //+-------------------------------------------------------------------------
  88. // The signature of the CTL is verified. The signer of the CTL is verified
  89. // up to a trusted root containing the predefined Microsoft public key.
  90. // The signer and intermediate certificates must have the
  91. // szOID_ROOT_LIST_SIGNER enhanced key usage extension.
  92. //
  93. // For success, *ppSignerCert is updated with certificate context of the
  94. // signer.
  95. //--------------------------------------------------------------------------
  96. STATIC
  97. BOOL
  98. WINAPI
  99. GetAndVerifyTrustedRootsSigner(
  100. IN HCRYPTMSG hCryptMsg,
  101. IN HCERTSTORE hMsgStore,
  102. OUT PCCERT_CONTEXT *ppSignerCert
  103. )
  104. {
  105. BOOL fResult;
  106. LONG lStatus;
  107. PCCERT_CONTEXT pSignerCert = NULL;
  108. GUID wvtCertActionID = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
  109. WINTRUST_CERT_INFO wvtCertInfo;
  110. WINTRUST_DATA wvtData;
  111. BOOL fCloseWVT = FALSE;
  112. DWORD dwLastError = 0;
  113. CRYPT_PROVIDER_DATA *pProvData; // not allocated
  114. CRYPT_PROVIDER_SGNR *pProvSigner; // not allocated
  115. CRYPT_PROVIDER_CERT *pProvCert; // not allocated
  116. DWORD idxCert;
  117. PCCERT_CONTEXT pCert; // not refCount'ed
  118. PCERT_ENHKEY_USAGE pUsage = NULL;
  119. BYTE rgbKeyId[SHA1_HASH_LEN];
  120. DWORD cbKeyId;
  121. if (!CryptMsgGetAndVerifySigner(
  122. hCryptMsg,
  123. 0, // cSignerStore
  124. NULL, // rghSignerStore
  125. 0, // dwFlags
  126. &pSignerCert,
  127. NULL // pdwSignerIndex
  128. ))
  129. goto CryptMsgGetAndVerifySignerError;
  130. memset(&wvtCertInfo, 0, sizeof(wvtCertInfo));
  131. wvtCertInfo.cbStruct = sizeof(wvtCertInfo);
  132. wvtCertInfo.psCertContext = (PCERT_CONTEXT) pSignerCert;
  133. wvtCertInfo.chStores = 1;
  134. wvtCertInfo.pahStores = &hMsgStore;
  135. wvtCertInfo.dwFlags = 0;
  136. wvtCertInfo.pcwszDisplayName = L"";
  137. memset(&wvtData, 0, sizeof(wvtData));
  138. wvtData.cbStruct = sizeof(wvtData);
  139. wvtData.pPolicyCallbackData = (void *) szOID_ROOT_LIST_SIGNER;
  140. wvtData.dwUIChoice = WTD_UI_NONE;
  141. wvtData.fdwRevocationChecks = WTD_REVOKE_NONE;
  142. wvtData.dwUnionChoice = WTD_CHOICE_CERT;
  143. wvtData.pCert = &wvtCertInfo;
  144. wvtData.dwStateAction = WTD_STATEACTION_VERIFY;
  145. wvtData.hWVTStateData = NULL;
  146. wvtData.dwProvFlags = 0;
  147. lStatus = WinVerifyTrust(
  148. NULL, // hwnd
  149. &wvtCertActionID,
  150. &wvtData
  151. );
  152. #if (0) // DSIE
  153. if (ERROR_SUCCESS != lStatus)
  154. goto WinVerifyTrustError;
  155. else
  156. fCloseWVT = TRUE;
  157. #else
  158. if (ERROR_SUCCESS != lStatus && CERT_E_REVOCATION_FAILURE != lStatus)
  159. goto WinVerifyTrustError;
  160. else
  161. fCloseWVT = TRUE;
  162. #endif
  163. if (NULL == (pProvData = WTHelperProvDataFromStateData(
  164. wvtData.hWVTStateData)))
  165. goto NoProvDataError;
  166. if (0 == pProvData->csSigners)
  167. goto NoProvSignerError;
  168. if (NULL == (pProvSigner = WTHelperGetProvSignerFromChain(
  169. pProvData,
  170. 0, // idxSigner
  171. FALSE, // fCounterSigner
  172. 0 // idxCounterSigner
  173. )))
  174. goto NoProvSignerError;
  175. if (2 > pProvSigner->csCertChain)
  176. goto MissingSignerCertsError;
  177. // Check that the top level certificate contains the public
  178. // key for the Microsoft root.
  179. pProvCert = WTHelperGetProvCertFromChain(pProvSigner,
  180. pProvSigner->csCertChain - 1);
  181. if (NULL == pProvCert)
  182. goto UnexpectedError;
  183. pCert = pProvCert->pCert;
  184. cbKeyId = SHA1_HASH_LEN;
  185. if (!CryptHashPublicKeyInfo(
  186. NULL, // hCryptProv
  187. CALG_SHA1,
  188. 0, // dwFlags
  189. X509_ASN_ENCODING,
  190. &pCert->pCertInfo->SubjectPublicKeyInfo,
  191. rgbKeyId,
  192. &cbKeyId
  193. ))
  194. goto HashPublicKeyInfoError;
  195. if (SHA1_HASH_LEN != cbKeyId ||
  196. 0 != memcmp(rgbSignerRootKeyId, rgbKeyId, SHA1_HASH_LEN))
  197. goto InvalidSignerRootError;
  198. // Check that the signer and intermediate certs have the RootListSigner
  199. // Usage extension
  200. for (idxCert = 0; idxCert < pProvSigner->csCertChain - 1; idxCert++) {
  201. DWORD i;
  202. pProvCert = WTHelperGetProvCertFromChain(pProvSigner, idxCert);
  203. if (NULL == pProvCert)
  204. goto UnexpectedError;
  205. pCert = pProvCert->pCert;
  206. pUsage = GetAndAllocCertEKUExt(pCert);
  207. if (NULL == pUsage)
  208. goto GetAndAllocCertEKUExtError;
  209. for (i = 0; i < pUsage->cUsageIdentifier; i++) {
  210. if (0 == strcmp(szOID_ROOT_LIST_SIGNER,
  211. pUsage->rgpszUsageIdentifier[i]))
  212. break;
  213. }
  214. if (i == pUsage->cUsageIdentifier)
  215. goto MissingTrustListSignerUsageError;
  216. LocalFree(pUsage);
  217. pUsage = NULL;
  218. }
  219. fResult = TRUE;
  220. CommonReturn:
  221. if (fCloseWVT) {
  222. wvtData.dwStateAction = WTD_STATEACTION_CLOSE;
  223. lStatus = WinVerifyTrust(
  224. NULL, // hwnd
  225. &wvtCertActionID,
  226. &wvtData
  227. );
  228. }
  229. if (pUsage)
  230. LocalFree(pUsage);
  231. SetLastError(dwLastError);
  232. *ppSignerCert = pSignerCert;
  233. return fResult;
  234. ErrorReturn:
  235. dwLastError = GetLastError();
  236. if (pSignerCert) {
  237. CertFreeCertificateContext(pSignerCert);
  238. pSignerCert = NULL;
  239. }
  240. fResult = FALSE;
  241. goto CommonReturn;
  242. TRACE_ERROR(CryptMsgGetAndVerifySignerError)
  243. SET_ERROR_VAR(WinVerifyTrustError, lStatus)
  244. SET_ERROR(NoProvDataError, E_UNEXPECTED)
  245. SET_ERROR(NoProvSignerError, TRUST_E_NO_SIGNER_CERT)
  246. SET_ERROR(MissingSignerCertsError, CERT_E_CHAINING)
  247. SET_ERROR(UnexpectedError, E_UNEXPECTED)
  248. TRACE_ERROR(HashPublicKeyInfoError)
  249. SET_ERROR(InvalidSignerRootError, CERT_E_UNTRUSTEDROOT)
  250. TRACE_ERROR(GetAndAllocCertEKUExtError)
  251. SET_ERROR(MissingTrustListSignerUsageError, CERT_E_WRONG_USAGE)
  252. }
  253. //+-------------------------------------------------------------------------
  254. // Returns TRUE if all the CTL fields are valid. Checks for the following:
  255. // - There is at least one SubjectUsage (really the roots enhanced key usage)
  256. // - If NextUpdate isn't NULL, that the CTL is still time valid
  257. // - Only allow roots identified by their sha1 hash
  258. //--------------------------------------------------------------------------
  259. STATIC
  260. BOOL
  261. WINAPI
  262. VerifyTrustedRootsCtlFields(
  263. IN PCTL_INFO pCtlInfo
  264. )
  265. {
  266. BOOL fResult;
  267. // Must have a least one usage
  268. if (0 == pCtlInfo->SubjectUsage.cUsageIdentifier)
  269. goto NoSubjectUsageError;
  270. // If NextUpdate is present, verify that the CTL hasn't expired.
  271. if (pCtlInfo->NextUpdate.dwLowDateTime ||
  272. pCtlInfo->NextUpdate.dwHighDateTime) {
  273. SYSTEMTIME SystemTime;
  274. FILETIME FileTime;
  275. GetSystemTime(&SystemTime);
  276. SystemTimeToFileTime(&SystemTime, &FileTime);
  277. if (CompareFileTime(&FileTime, &pCtlInfo->NextUpdate) > 0)
  278. goto ExpiredCtlError;
  279. }
  280. // Only allow roots identified by their sha1 hash
  281. if (0 != strcmp(szOID_OIWSEC_sha1,
  282. pCtlInfo->SubjectAlgorithm.pszObjId))
  283. goto InvalidSubjectAlgorithm;
  284. fResult = TRUE;
  285. CommonReturn:
  286. return fResult;
  287. ErrorReturn:
  288. fResult = FALSE;
  289. goto CommonReturn;
  290. SET_ERROR(NoSubjectUsageError, ERROR_INVALID_DATA)
  291. SET_ERROR(ExpiredCtlError, CERT_E_EXPIRED)
  292. SET_ERROR(InvalidSubjectAlgorithm, ERROR_INVALID_DATA)
  293. }
  294. //+-------------------------------------------------------------------------
  295. // Returns TRUE if all the known extensions are valid and there aren't any
  296. // unknown critical extensions.
  297. //
  298. // We know about the following extensions:
  299. // - szOID_ENHANCED_KEY_USAGE - if present, must contain
  300. // szOID_ROOT_LIST_SIGNER usage
  301. // - szOID_REMOVE_CERTIFICATE - integer value, 0 => FALSE (add)
  302. // 1 => TRUE (remove), all other values are invalid
  303. // - szOID_CERT_POLICIES - ignored
  304. //
  305. // If szOID_REMOVE_CERTIFICATE is present, then, *pfRemoveRoots is updated.
  306. // Otherwise, *pfRemoveRoots defaults to FALSE.
  307. //--------------------------------------------------------------------------
  308. STATIC
  309. BOOL
  310. WINAPI
  311. VerifyTrustedRootsCtlExtensions(
  312. IN PCTL_INFO pCtlInfo,
  313. OUT BOOL *pfRemoveRoots
  314. )
  315. {
  316. BOOL fResult;
  317. PCERT_EXTENSION pExt;
  318. DWORD cExt;
  319. PCERT_ENHKEY_USAGE pUsage = NULL;
  320. DWORD cbRemoveRoots;
  321. *pfRemoveRoots = FALSE;
  322. // Verify the extensions
  323. for (cExt = pCtlInfo->cExtension,
  324. pExt = pCtlInfo->rgExtension; 0 < cExt; cExt--, pExt++) {
  325. if (0 == strcmp(szOID_ENHANCED_KEY_USAGE, pExt->pszObjId)) {
  326. DWORD cbUsage;
  327. DWORD i;
  328. // Check for szOID_ROOT_LIST_SIGNER usage
  329. if (!CryptDecodeObject(
  330. X509_ASN_ENCODING,
  331. X509_ENHANCED_KEY_USAGE,
  332. pExt->Value.pbData,
  333. pExt->Value.cbData,
  334. 0, // dwFlags
  335. NULL, // pvStructInfo
  336. &cbUsage
  337. ))
  338. goto DecodeEnhancedKeyUsageExtError;
  339. if (NULL == (pUsage = (PCERT_ENHKEY_USAGE) LocalAlloc(
  340. LPTR, cbUsage)))
  341. goto OutOfMemory;
  342. if (!CryptDecodeObject(
  343. X509_ASN_ENCODING,
  344. X509_ENHANCED_KEY_USAGE,
  345. pExt->Value.pbData,
  346. pExt->Value.cbData,
  347. 0, // dwFlags
  348. pUsage,
  349. &cbUsage
  350. ))
  351. goto DecodeEnhancedKeyUsageExtError;
  352. for (i = 0; i < pUsage->cUsageIdentifier; i++) {
  353. if (0 == strcmp(szOID_ROOT_LIST_SIGNER,
  354. pUsage->rgpszUsageIdentifier[i]))
  355. break;
  356. }
  357. if (i == pUsage->cUsageIdentifier)
  358. goto MissingTrustListSignerUsageInExtError;
  359. LocalFree(pUsage);
  360. pUsage = NULL;
  361. } else if (0 == strcmp(szOID_REMOVE_CERTIFICATE, pExt->pszObjId)) {
  362. int iVal;
  363. DWORD cbVal;
  364. cbVal = sizeof(iVal);
  365. iVal = 0;
  366. if (!CryptDecodeObject(
  367. X509_ASN_ENCODING,
  368. X509_INTEGER,
  369. pExt->Value.pbData,
  370. pExt->Value.cbData,
  371. 0, // dwFlags
  372. &iVal,
  373. &cbVal
  374. ))
  375. goto DecodeRemoveCertificateExtError;
  376. switch(iVal) {
  377. case 0:
  378. *pfRemoveRoots = FALSE;
  379. break;
  380. case 1:
  381. *pfRemoveRoots = TRUE;
  382. break;
  383. default:
  384. goto InvalidRemoveCertificateExtValueError;
  385. }
  386. } else if (0 == strcmp(szOID_CERT_POLICIES, pExt->pszObjId)) {
  387. ;
  388. } else if (pExt->fCritical) {
  389. goto UnknownCriticalExtensionError;
  390. }
  391. }
  392. fResult = TRUE;
  393. CommonReturn:
  394. if (pUsage)
  395. LocalFree(pUsage);
  396. return fResult;
  397. ErrorReturn:
  398. fResult = FALSE;
  399. goto CommonReturn;
  400. TRACE_ERROR(DecodeEnhancedKeyUsageExtError)
  401. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  402. SET_ERROR(MissingTrustListSignerUsageInExtError, ERROR_INVALID_DATA)
  403. TRACE_ERROR(DecodeRemoveCertificateExtError)
  404. SET_ERROR(InvalidRemoveCertificateExtValueError, ERROR_INVALID_DATA)
  405. SET_ERROR(UnknownCriticalExtensionError, ERROR_INVALID_DATA)
  406. }
  407. //+-------------------------------------------------------------------------
  408. // Returns TRUE, if a sha1 entry exists in the CTL for the certificate
  409. //--------------------------------------------------------------------------
  410. STATIC
  411. BOOL
  412. WINAPI
  413. IsTrustedRoot(
  414. IN PCTL_INFO pCtlInfo,
  415. IN PCCERT_CONTEXT pCert
  416. )
  417. {
  418. BOOL fResult = FALSE;
  419. BYTE rgbSha1Hash[SHA1_HASH_LEN];
  420. DWORD cbSha1Hash;
  421. DWORD cEntry;
  422. PCTL_ENTRY pEntry; // not allocated
  423. cbSha1Hash = SHA1_HASH_LEN;
  424. if (!CertGetCertificateContextProperty(
  425. pCert,
  426. CERT_SHA1_HASH_PROP_ID,
  427. rgbSha1Hash,
  428. &cbSha1Hash
  429. ))
  430. goto GetSha1HashError;
  431. for (cEntry = pCtlInfo->cCTLEntry,
  432. pEntry = pCtlInfo->rgCTLEntry; 0 < cEntry; cEntry--, pEntry++) {
  433. if (SHA1_HASH_LEN == pEntry->SubjectIdentifier.cbData &&
  434. 0 == memcmp(rgbSha1Hash, pEntry->SubjectIdentifier.pbData,
  435. SHA1_HASH_LEN)) {
  436. fResult = TRUE;
  437. break;
  438. }
  439. }
  440. CommonReturn:
  441. return fResult;
  442. ErrorReturn:
  443. goto CommonReturn;
  444. TRACE_ERROR(GetSha1HashError)
  445. }
  446. //+-------------------------------------------------------------------------
  447. // Checks if the certificate has an EKU extension and if all of the
  448. // cert's usages are within the specified list of usages.
  449. //
  450. // Returns TRUE if the above two conditions are satisfied.
  451. //--------------------------------------------------------------------------
  452. STATIC
  453. BOOL
  454. WINAPI
  455. IsValidCertEKUExtSubset(
  456. IN PCCERT_CONTEXT pCert,
  457. PCERT_ENHKEY_USAGE pValidUsage
  458. )
  459. {
  460. PCERT_ENHKEY_USAGE pCertUsage = NULL;
  461. BOOL fResult = FALSE;
  462. DWORD i, j;
  463. pCertUsage = GetAndAllocCertEKUExt(pCert);
  464. if (NULL == pCertUsage || 0 == pCertUsage->cUsageIdentifier)
  465. goto CommonReturn;
  466. for (i = 0; i < pCertUsage->cUsageIdentifier; i++) {
  467. for (j = 0; j < pValidUsage->cUsageIdentifier; j++) {
  468. if (0 == strcmp(pCertUsage->rgpszUsageIdentifier[i],
  469. pValidUsage->rgpszUsageIdentifier[j]))
  470. break;
  471. }
  472. if (j == pValidUsage->cUsageIdentifier)
  473. // No Match
  474. goto CommonReturn;
  475. }
  476. fResult = TRUE;
  477. CommonReturn:
  478. if (pCertUsage)
  479. LocalFree(pCertUsage);
  480. return fResult;
  481. }
  482. //+-------------------------------------------------------------------------
  483. // Removes all certificates from the store not having a sha1 hash
  484. // entry in the CTL.
  485. //
  486. // For added certificates, sets the CERT_ENHKEY_USAGE_PROP_ID
  487. //--------------------------------------------------------------------------
  488. STATIC
  489. BOOL
  490. WINAPI
  491. FilterAndUpdateTrustedRootsInStore(
  492. IN PCTL_INFO pCtlInfo,
  493. IN BOOL fRemoveRoots,
  494. IN OUT HCERTSTORE hMsgStore
  495. )
  496. {
  497. BOOL fResult;
  498. PCCERT_CONTEXT pCert = NULL;
  499. CRYPT_DATA_BLOB EncodedUsage = {0, NULL}; // pbData is allocated
  500. if (!fRemoveRoots) {
  501. // Re-encode the decoded SubjectUsage field. It will be added as
  502. // a CERT_ENHKEY_USAGE_PROP_ID to each of the certs in the list
  503. if (!CryptEncodeObject(
  504. X509_ASN_ENCODING,
  505. X509_ENHANCED_KEY_USAGE,
  506. &pCtlInfo->SubjectUsage,
  507. NULL, // pbEncoded
  508. &EncodedUsage.cbData
  509. ))
  510. goto EncodeUsageError;
  511. if (NULL == (EncodedUsage.pbData = (BYTE *) LocalAlloc(
  512. LPTR, EncodedUsage.cbData)))
  513. goto OutOfMemory;
  514. if (!CryptEncodeObject(
  515. X509_ASN_ENCODING,
  516. X509_ENHANCED_KEY_USAGE,
  517. &pCtlInfo->SubjectUsage,
  518. EncodedUsage.pbData,
  519. &EncodedUsage.cbData
  520. ))
  521. goto EncodeUsageError;
  522. }
  523. // Iterate through the certificates in the message store.
  524. // Remove certificates not in the signed CTL entry list
  525. pCert = NULL;
  526. while (pCert = CertEnumCertificatesInStore(hMsgStore, pCert)) {
  527. if (IsTrustedRoot(pCtlInfo, pCert)) {
  528. // Add the enhanced key usage property if the certificate
  529. // doesn't already have an EKU extension that's a subset
  530. // of the SubjectUsage
  531. if (!fRemoveRoots && !IsValidCertEKUExtSubset(
  532. pCert, &pCtlInfo->SubjectUsage)) {
  533. if (!CertSetCertificateContextProperty(
  534. pCert,
  535. CERT_ENHKEY_USAGE_PROP_ID,
  536. 0, // dwFlags
  537. &EncodedUsage
  538. ))
  539. goto SetEnhancedKeyUsagePropertyError;
  540. }
  541. } else {
  542. PCCERT_CONTEXT pCertDup;
  543. pCertDup = CertDuplicateCertificateContext(pCert);
  544. CertDeleteCertificateFromStore(pCertDup);
  545. }
  546. }
  547. fResult = TRUE;
  548. CommonReturn:
  549. if (EncodedUsage.pbData)
  550. LocalFree(EncodedUsage.pbData);
  551. if (pCert)
  552. CertFreeCertificateContext(pCert);
  553. return fResult;
  554. ErrorReturn:
  555. fResult = FALSE;
  556. goto CommonReturn;
  557. TRACE_ERROR(EncodeUsageError)
  558. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  559. TRACE_ERROR(SetEnhancedKeyUsagePropertyError)
  560. }
  561. //+-------------------------------------------------------------------------
  562. // Verify that the encoded CTL contains a signed list of roots. For success,
  563. // return certificate store containing the trusted roots to add or
  564. // remove. Also for success, return certificate context of the signer.
  565. //
  566. // The signature of the CTL is verified. The signer of the CTL is verified
  567. // up to a trusted root containing the predefined Microsoft public key.
  568. // The signer and intermediate certificates must have the
  569. // szOID_ROOT_LIST_SIGNER enhanced key usage extension.
  570. //
  571. // The CTL fields are validated as follows:
  572. // - There is at least one SubjectUsage (really the roots enhanced key usage)
  573. // - If NextUpdate isn't NULL, that the CTL is still time valid
  574. // - Only allow roots identified by their sha1 hash
  575. //
  576. // The following CTL extensions are processed:
  577. // - szOID_ENHANCED_KEY_USAGE - if present, must contain
  578. // szOID_ROOT_LIST_SIGNER usage
  579. // - szOID_REMOVE_CERTIFICATE - integer value, 0 => FALSE (add)
  580. // 1 => TRUE (remove), all other values are invalid
  581. // - szOID_CERT_POLICIES - ignored
  582. //
  583. // If the CTL contains any other critical extensions, then, the
  584. // CTL verification fails.
  585. //
  586. // For a successfully verified CTL:
  587. // - TRUE is returned
  588. // - *pfRemoveRoots is set to FALSE to add roots and is set to TRUE to
  589. // remove roots.
  590. // - *phRootListStore is a certificate store containing only the roots to
  591. // add or remove. *phRootListStore must be closed by calling
  592. // CertCloseStore(). For added roots, the CTL's SubjectUsage field is
  593. // set as CERT_ENHKEY_USAGE_PROP_ID on all of the certificates in the
  594. // store.
  595. // - *ppSignerCert is a pointer to the certificate context of the signer.
  596. // *ppSignerCert must be freed by calling CertFreeCertificateContext().
  597. //
  598. // Otherwise, FALSE is returned with *phRootListStore and *ppSignerCert
  599. // set to NULL.
  600. //--------------------------------------------------------------------------
  601. BOOL
  602. WINAPI
  603. I_CertVerifySignedListOfTrustedRoots(
  604. IN const BYTE *pbCtlEncoded,
  605. IN DWORD cbCtlEncoded,
  606. OUT BOOL *pfRemoveRoots, // FALSE: add, TRUE: remove
  607. OUT HCERTSTORE *phRootListStore,
  608. OUT PCCERT_CONTEXT *ppSignerCert
  609. )
  610. {
  611. BOOL fResult;
  612. PCCTL_CONTEXT pCtl = NULL;
  613. HCERTSTORE hMsgStore = NULL;
  614. PCCERT_CONTEXT pSignerCert = NULL;
  615. BOOL fRemoveRoots = FALSE;
  616. PCTL_INFO pCtlInfo; // not allocated
  617. if (NULL == (pCtl = CertCreateCTLContext(
  618. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  619. pbCtlEncoded,
  620. cbCtlEncoded)))
  621. goto CreateCtlContextError;
  622. if (NULL == (hMsgStore = CertOpenStore(
  623. CERT_STORE_PROV_MSG,
  624. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  625. 0, // hCryptProv
  626. 0, // dwFlags
  627. pCtl->hCryptMsg // pvPara
  628. )))
  629. goto OpenMsgStoreError;
  630. if (!GetAndVerifyTrustedRootsSigner(
  631. pCtl->hCryptMsg, hMsgStore, &pSignerCert))
  632. goto GetAndVerifyTrustedRootsSignerError;
  633. pCtlInfo = pCtl->pCtlInfo;
  634. if (!VerifyTrustedRootsCtlFields(pCtlInfo))
  635. goto VerifyCtlFieldsError;
  636. if (!VerifyTrustedRootsCtlExtensions(pCtlInfo, &fRemoveRoots))
  637. goto VerifyCtlExtensionsError;
  638. if (!FilterAndUpdateTrustedRootsInStore(pCtlInfo, fRemoveRoots, hMsgStore))
  639. goto FilterAndUpdateTrustedRootsError;
  640. fResult = TRUE;
  641. CommonReturn:
  642. if (pCtl)
  643. CertFreeCTLContext(pCtl);
  644. *pfRemoveRoots = fRemoveRoots;
  645. *phRootListStore = hMsgStore;
  646. *ppSignerCert = pSignerCert;
  647. return fResult;
  648. ErrorReturn:
  649. if (pSignerCert) {
  650. CertFreeCertificateContext(pSignerCert);
  651. pSignerCert = NULL;
  652. }
  653. if (hMsgStore) {
  654. CertCloseStore(hMsgStore, 0);
  655. hMsgStore = NULL;
  656. }
  657. fResult = FALSE;
  658. goto CommonReturn;
  659. TRACE_ERROR(CreateCtlContextError)
  660. TRACE_ERROR(OpenMsgStoreError)
  661. TRACE_ERROR(GetAndVerifyTrustedRootsSignerError)
  662. TRACE_ERROR(VerifyCtlFieldsError)
  663. TRACE_ERROR(VerifyCtlExtensionsError)
  664. TRACE_ERROR(FilterAndUpdateTrustedRootsError)
  665. }