Source code of Windows XP (NT5)
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.

882 lines
26 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // No portion of this source code may be reproduced
  6. // without express written permission of Microsoft Corporation.
  7. //
  8. // This source code is proprietary and confidential.
  9. //
  10. // SYSTEM: Industry Update
  11. //
  12. // CLASS: N/A
  13. // MODULE: TRUST.LIB
  14. // FILE: Trust.CPP
  15. //
  16. /////////////////////////////////////////////////////////////////////
  17. //
  18. // DESC: this file implements the functions used to make cabs
  19. // signed by certain providers trusted.
  20. //
  21. //
  22. // AUTHOR: Charles Ma, converted from WU CDMLIB
  23. // DATE: 10/4/2000
  24. //
  25. /////////////////////////////////////////////////////////////////////
  26. //
  27. // Revision History:
  28. //
  29. // Date Author Description
  30. // ~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  31. //
  32. //
  33. /////////////////////////////////////////////////////////////////////
  34. #include "stdafx.h"
  35. #include <wintrust.h>
  36. #include <softpub.h>
  37. #include "trust.h"
  38. #include "TrustPriv.h"
  39. #include "wusafefn.h"
  40. #if !defined(DISABLE_IU_LOGGING)
  41. #include <MemUtil.h>
  42. #include <logging.h>
  43. #endif
  44. #if defined(DEBUG) || defined(DBG)
  45. #ifdef DISABLE_IU_POLICY // in debug mode, we enable pop up check
  46. #undef DISABLE_IU_POLICY
  47. #endif
  48. #else
  49. #define DISABLE_IU_POLICY // in release mode, we never allow cert pop up!
  50. #endif
  51. #if defined(__WUIUTEST) || !defined(DISABLE_IU_POLICY)
  52. const TCHAR REGKEY_IUCTL[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\IUControl");
  53. #endif
  54. /////////////////////////////////////////////////////////////////////////////
  55. //
  56. // typedefs for APIs used in the CheckTrust() function
  57. //
  58. // Since some of these APIs are new and only available on IE5 we have to
  59. // try to dynamicaly use them when available and do without the extra checks
  60. // when we are on an OS that has not been upgraded to the new crypto code.
  61. //
  62. /////////////////////////////////////////////////////////////////////////////
  63. #define WINTRUST _T("wintrust.dll")
  64. #define CRYPT32 _T("crypt32.dll")
  65. #if !defined(USES_IU_CONVERSION) && defined(USES_CONVERSION)
  66. #define USES_IU_CONVERSION USES_CONVERSION
  67. #endif
  68. //
  69. // declare a global crypt32.dll library handler, so we don't
  70. // need to load the library every time these functions are called.
  71. // NOTE: we do not release the library though. When the process of
  72. // calling this feature exits, the library is released.
  73. // same as wintrust.dll
  74. //
  75. static HINSTANCE shWinTrustDllInst = NULL;
  76. static HINSTANCE shCrypt32DllInst = NULL;
  77. //
  78. // define prototype for function WinVerifyTrust()
  79. // and declare a global variable to point to this function
  80. //
  81. typedef HRESULT
  82. (WINAPI * PFNWinVerifyTrust)(
  83. HWND hwnd, GUID *ActionID, LPVOID ActionData);
  84. PFNWinVerifyTrust pfnWinVerifyTrust = NULL;
  85. //
  86. // define prototype for function WTHelperProvDataFromStateData()
  87. // and declare a global variable to point to this function
  88. //
  89. typedef CRYPT_PROVIDER_DATA *
  90. (WINAPI * PFNWTHelperProvDataFromStateData)(
  91. HANDLE hStateData);
  92. PFNWTHelperProvDataFromStateData pfnWTHelperProvDataFromStateData = NULL;
  93. //
  94. // define prototype for function WTHelperGetProvSignerFromChain()
  95. // and declare a global variable to point to this function
  96. //
  97. typedef CRYPT_PROVIDER_SGNR *
  98. (WINAPI * PFNWTHelperGetProvSignerFromChain)(
  99. CRYPT_PROVIDER_DATA *pProvData,
  100. DWORD idxSigner,
  101. BOOL fCounterSigner,
  102. DWORD idxCounterSigner);
  103. PFNWTHelperGetProvSignerFromChain pfnWTHelperGetProvSignerFromChain = NULL;
  104. //
  105. // define prototype for function PFNWTHelperGetProvCertFromChain()
  106. // and declare a global variable to point to this function
  107. //
  108. typedef CRYPT_PROVIDER_CERT *
  109. (WINAPI * PFNWTHelperGetProvCertFromChain)(
  110. CRYPT_PROVIDER_SGNR *pSgnr,
  111. DWORD idxCert);
  112. PFNWTHelperGetProvCertFromChain pfnWTHelperGetProvCertFromChain = NULL;
  113. //
  114. // define prototype for function CryptHashPublicKeyInfo()
  115. // and declare a global variable to point to this function
  116. //
  117. typedef BOOL
  118. (WINAPI * PFNCryptHashPublicKeyInfo)(
  119. HCRYPTPROV hCryptProv,
  120. ALG_ID Algid,
  121. DWORD dwFlags,
  122. DWORD dwCertEncodingType,
  123. PCERT_PUBLIC_KEY_INFO pInfo,
  124. BYTE *pbComputedHash,
  125. DWORD *pcbComputedHash);
  126. PFNCryptHashPublicKeyInfo pfnCryptHashPublicKeyInfo = NULL;
  127. //
  128. // define prototype for function CertGetCertificateContextProperty()
  129. // and declare a global variable to point to this function
  130. //
  131. typedef BOOL
  132. (WINAPI * PFNCertGetCertificateContextProperty)(
  133. PCCERT_CONTEXT pCertContext,
  134. DWORD dwPropId,
  135. void *pvData,
  136. DWORD *pcbData);
  137. PFNCertGetCertificateContextProperty pfnCertGetCertificateContextProperty = NULL;
  138. /////////////////////////////////////////////////////////////////////////////
  139. //
  140. // pre-defined cert data to check against
  141. //
  142. /////////////////////////////////////////////////////////////////////////////
  143. //
  144. // The following is the sha1 key identifier for the Microsoft root
  145. //
  146. static const BYTE rgbSignerRootKeyIds[40] = {
  147. 0x4A, 0x5C, 0x75, 0x22, 0xAA, 0x46, 0xBF, 0xA4, 0x08, 0x9D, // the original MS root
  148. 0x39, 0x97, 0x4E, 0xBD, 0xB4, 0xA3, 0x60, 0xF7, 0xA0, 0x1D,
  149. 0x0E, 0xAC, 0x82, 0x60, 0x40, 0x56, 0x27, 0x97, 0xE5, 0x25, // the new "son of MS root"
  150. 0x13, 0xFC, 0x2A, 0xE1, 0x0A, 0x53, 0x95, 0x59, 0xE4, 0xA4
  151. };
  152. //
  153. // define the size of each hash values in the known id buffer
  154. // for special certs.
  155. //
  156. const size_t ExpectedKnownCertHashSize = 20;
  157. //
  158. // this is the size of buffer to receive the cert hash value
  159. // it must be not less than the largest number in the
  160. // above-defined array
  161. //
  162. const size_t ShaBufSize = 20;
  163. //
  164. // id buffer to store SH1 hashing values of known Microsoft
  165. // certs (signature) that we should recognize.
  166. // Warning: the size of this buffer should match the sum
  167. // of size_t values defined above.
  168. //
  169. static const BYTE rgbSpecialCertId[200] = {
  170. 0xB1,0x59,0xA5,0x2E,0x3D,0xD8,0xCE,0xCD,0x3A,0x9A,0x4A,0x7A,0x73,0x92,0xAA,0x8D,0xA7,0xE7,0xD6,0x7F, // MS cert
  171. 0xB1,0xC7,0x75,0xE0,0x4A,0x9D,0xFD,0x23,0xB6,0x18,0x97,0x11,0x5E,0xF6,0xEA,0x6B,0x99,0xEC,0x76,0x1D, // MSN cert
  172. 0x11,0xC7,0x10,0xF3,0xCB,0x6C,0x43,0xE1,0x66,0xEC,0x64,0x1C,0x7C,0x01,0x17,0xC4,0xB4,0x10,0x35,0x30, // MSNBC cert
  173. 0x95,0x25,0x58,0xD4,0x07,0xDE,0x4A,0xFD,0xAE,0xBA,0x13,0x72,0x83,0xC2,0xB3,0x37,0x04,0x90,0xC9,0x8A, // MSN Europe
  174. 0x72,0x54,0x14,0x91,0x1D,0x6E,0x10,0x84,0x8E,0x0F,0xFA,0xA0,0xB0,0xA1,0x65,0xBF,0x44,0x8F,0x9F,0x6D, // MS Europe
  175. 0x20,0x5E,0x48,0x43,0xAB,0xAD,0x54,0x77,0x71,0xBD,0x8D,0x1A,0x3C,0xE0,0xE5,0x9D,0xF5,0xBD,0x25,0xF9, // Old MS cert: 97~98
  176. 0xD6,0xCD,0x01,0x90,0xB3,0x1B,0x31,0x85,0x81,0x12,0x23,0x14,0xB5,0x17,0xA0,0xAA,0xCE,0xF2,0x7B,0xD5, // Old MS cert: 98~99
  177. 0x8A,0xA1,0x37,0xF5,0x03,0x9F,0xE0,0x28,0xC9,0x26,0xAA,0x55,0x90,0x14,0x19,0x68,0xFA,0xFF,0xE8,0x1A, // Old MS cert: 99~00
  178. 0xF3,0x25,0xF8,0x67,0x07,0x29,0xE5,0x27,0xF3,0x77,0x52,0x34,0xE0,0x51,0x57,0x69,0x0F,0x40,0xC6,0x1C, // Old MS Europe cert: 99~00
  179. 0x6A,0x71,0xFE,0x54,0x8A,0x51,0x08,0x70,0xF9,0x8A,0x56,0xCA,0x11,0x55,0xF6,0x76,0x45,0x92,0x02,0x5A // Old MS Europe cert: 98~99
  180. };
  181. /////////////////////////////////////////////////////////////////////////////
  182. //
  183. // Private Function ULONG CompareMem(PVOID pBlock1, PVOID pBlock2, ULONG Length)
  184. //
  185. // This function acts in the same way as RtlCompareMemory()
  186. //
  187. //
  188. // Input: two pointers to two memory blocks, and a byte size to compare
  189. // Return: the number of bytes that compared as equal.
  190. // If all bytes compare as equal, the input Length is returned.
  191. // If any pointer is NULL, 0 is returned.
  192. //
  193. /////////////////////////////////////////////////////////////////////////////
  194. ULONG CompareMem(const BYTE* pBlock1, const BYTE* pBlock2, ULONG Length)
  195. {
  196. ULONG uLen = 0L;
  197. if (pBlock1 != NULL && pBlock2 != NULL)
  198. {
  199. for (; uLen < Length; uLen++, pBlock1++, pBlock2++)
  200. {
  201. if (*pBlock1 != *pBlock2) return uLen;
  202. }
  203. }
  204. return uLen;
  205. }
  206. /////////////////////////////////////////////////////////////////////////////
  207. //
  208. // Private Function VerifyMSRoot()
  209. //
  210. // This function takes the passed-in certificate as a root cert,
  211. // and verifies its public key hash value is the same as
  212. // known "Microsoft Root Authority" cert value.
  213. //
  214. //
  215. // Input: hCrypt32DllInst - handle point to loaded crypt32.dll library
  216. // pRootCert - the certificate context of the root cert
  217. //
  218. // Return: HRESULT - result of execution, S_OK if matched.
  219. // the result code, in case of error, are code retuned by
  220. // crypt32.dll, with these the exception of E_INVALIDARG if
  221. // the passed-in parameters are NULL.
  222. //
  223. /////////////////////////////////////////////////////////////////////////////
  224. HRESULT VerifyMSRoot(
  225. HINSTANCE hCrypt32DllInst, // handle point to loaded crypt32.dll librar
  226. PCCERT_CONTEXT pRootCert
  227. )
  228. {
  229. HRESULT hr = S_OK;
  230. BYTE rgbKeyId[ExpectedKnownCertHashSize];
  231. DWORD cbKeyId = sizeof(rgbKeyId);
  232. LOG_Block("VerifyMSRoot()");
  233. //
  234. // valid parameter values
  235. //
  236. if (NULL == hCrypt32DllInst || NULL == pRootCert)
  237. {
  238. hr = E_INVALIDARG;
  239. goto ErrHandler;
  240. }
  241. //
  242. // get the function we need from the passed in library handle
  243. // If not available, return error
  244. //
  245. if (NULL == (pfnCryptHashPublicKeyInfo = (PFNCryptHashPublicKeyInfo)
  246. GetProcAddress(hCrypt32DllInst, "CryptHashPublicKeyInfo")))
  247. {
  248. hr = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
  249. goto ErrHandler;
  250. }
  251. //
  252. // get the public key hash value of this cert
  253. //
  254. ZeroMemory(rgbKeyId, sizeof(rgbKeyId));
  255. if (!pfnCryptHashPublicKeyInfo(
  256. 0, // use default crypto svc provider
  257. CALG_SHA1, // use SHA algorithm
  258. 0, // dwFlags
  259. X509_ASN_ENCODING,
  260. &pRootCert->pCertInfo->SubjectPublicKeyInfo,
  261. rgbKeyId,
  262. &cbKeyId
  263. ))
  264. {
  265. hr = HRESULT_FROM_WIN32(GetLastError());
  266. goto ErrHandler;
  267. }
  268. //
  269. // compare the hash value of public key of this root cert with the known MS root cert value
  270. //
  271. if (ExpectedKnownCertHashSize != cbKeyId ||
  272. (cbKeyId != CompareMem(rgbSignerRootKeyIds, rgbKeyId, cbKeyId) &&
  273. cbKeyId != CompareMem(rgbSignerRootKeyIds + ExpectedKnownCertHashSize, rgbKeyId, cbKeyId)
  274. )
  275. )
  276. {
  277. hr = S_FALSE;
  278. }
  279. ErrHandler:
  280. if (FAILED(hr))
  281. {
  282. LOG_ErrorMsg(hr);
  283. }
  284. else
  285. {
  286. LOG_Trust(_T("Exit VerifyMSRoot() with %s"), (S_OK == hr) ? _T("S_OK") : _T("S_FALSE"));
  287. }
  288. return hr;
  289. }
  290. /////////////////////////////////////////////////////////////////////////////
  291. //
  292. // Private Function VerifySpecialMSCerts()
  293. //
  294. // This function takes the passed-in certificate as a leaf cert,
  295. // and verifies its hash value matches the hash value of one of
  296. // known Microsoft special certs that does not have MS root.
  297. //
  298. // The known certs are, in comparing order:
  299. // Microsoft Corporation
  300. // Microsoft Corporation MSN
  301. // MSNBC Interactive News LLC
  302. // Microsoft Corporation MSN (Europe)
  303. // Microsoft Corporation (Europe)
  304. //
  305. //
  306. // Input: hCrypt32DllInst - handle point to loaded crypt32.dll library
  307. // pRootCert - the certificate context of the root cert
  308. // pbSha1HashVal - if not NULL, compare to this one, instead of
  309. // hard-coded hash values. this is the case
  310. // of working on 3rd party package
  311. //
  312. // Return: HRESULT - result of execution, S_OK if matched.
  313. // if not matched, CERT_E_UNTRUSTEDROOT, or
  314. // E_INVALIDARG if arguments not right, or
  315. // crypt32.dll error returned by API calls
  316. //
  317. /////////////////////////////////////////////////////////////////////////////
  318. HRESULT VerifyKnownCerts(
  319. HINSTANCE hCrypt32DllInst, // handle point to loaded crypt32.dll librar
  320. PCCERT_CONTEXT pLeafCert,
  321. pCERT_HASH_ARRAY pKnownCertsData
  322. )
  323. {
  324. HRESULT hr = S_FALSE;
  325. BYTE btShaBuffer[ShaBufSize];
  326. DWORD dwSize = sizeof(btShaBuffer);
  327. BYTE const * pId;
  328. LOG_Block("VerifyKnownCerts()");
  329. //
  330. // valid parameter values
  331. //
  332. if (NULL == hCrypt32DllInst || NULL == pLeafCert)
  333. {
  334. hr = E_INVALIDARG;
  335. goto ErrHandler;
  336. }
  337. //
  338. // get the function we need from the passed in library handle
  339. // If not available, return error
  340. //
  341. if (NULL == (pfnCertGetCertificateContextProperty = (PFNCertGetCertificateContextProperty)
  342. GetProcAddress(hCrypt32DllInst, "CertGetCertificateContextProperty")))
  343. {
  344. hr = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
  345. goto ErrHandler;
  346. }
  347. //
  348. // find out the id hash of leaf cert
  349. //
  350. ZeroMemory(btShaBuffer, dwSize);
  351. if (!pfnCertGetCertificateContextProperty(
  352. pLeafCert, // pCertContext
  353. CERT_SHA1_HASH_PROP_ID, // dwPropId
  354. btShaBuffer,
  355. &dwSize
  356. ))
  357. {
  358. hr = GetLastError();
  359. goto ErrHandler;
  360. }
  361. if (NULL == pKnownCertsData)
  362. {
  363. int i;
  364. //
  365. // iterrate through all known id hash values to see if this file is signed
  366. // with any of these special certs.
  367. //
  368. hr = S_FALSE;
  369. for (i = 0,pId = rgbSpecialCertId;
  370. i < sizeof(rgbSpecialCertId)/ExpectedKnownCertHashSize;
  371. i++, pId += ExpectedKnownCertHashSize)
  372. {
  373. if (ExpectedKnownCertHashSize == dwSize &&
  374. dwSize == CompareMem(btShaBuffer, pId, dwSize))
  375. {
  376. //
  377. // found a matching known cert!
  378. //
  379. hr = S_OK;
  380. LOG_Trust(_T("Found hash matching on #%d of %d MS certs!"), i, sizeof(rgbSpecialCertId)/ExpectedKnownCertHashSize);
  381. break;
  382. }
  383. }
  384. }
  385. else
  386. {
  387. //
  388. // check if the retrieved hashing value matches the one passed in.
  389. //
  390. UINT i;
  391. LOG_Trust(_T("Comparing retrieved hash value with passed-in key"));
  392. hr = S_FALSE;
  393. for (i = 0, pId = pKnownCertsData->pCerts; i < pKnownCertsData->uiCount;
  394. i++, pId += HASH_VAL_SIZE)
  395. {
  396. if (dwSize == HASH_VAL_SIZE &&
  397. HASH_VAL_SIZE == CompareMem(btShaBuffer, pId, HASH_VAL_SIZE))
  398. {
  399. hr = S_OK;
  400. LOG_Trust(_T("Found hash matching #%d of %d passed-in certs!"),
  401. i, pKnownCertsData->uiCount);
  402. break;
  403. }
  404. }
  405. }
  406. ErrHandler:
  407. if (FAILED(hr))
  408. {
  409. LOG_ErrorMsg(hr);
  410. }
  411. else
  412. {
  413. LOG_Trust(_T("Exit VerifyKnownCerts() with %s"), (S_OK == hr) ? _T("S_OK") : _T("S_FALSE"));
  414. }
  415. return hr;
  416. }
  417. /////////////////////////////////////////////////////////////////////////////
  418. //
  419. // Private Function CheckWinTrust()
  420. //
  421. // This function will return the HRESULT for the trust state on the
  422. // specified file. The file can be pointing to any URL or local file.
  423. // The verification will be done by the wintrust.dll.
  424. //
  425. // dwUIChoice is WTD_UI_NONE, WTD_UI_ALL, etc. (defined in wintrust.h).
  426. // dwCheckRevocation is WTD_REVOKE_NONE (default) or WTD_REVOKE_WHOLE_CHAIN.
  427. //
  428. // Input: Fully qualified filename, UIChoice, dwCheckRevocation
  429. // Return: HRESULT - result of execution
  430. //
  431. /////////////////////////////////////////////////////////////////////////////
  432. HRESULT CheckWinTrust(LPCTSTR pszFileName, pCERT_HASH_ARRAY pCertsData, DWORD dwUIChoice, DWORD dwCheckRevocation)
  433. {
  434. LOG_Block("CheckWinTrust()");
  435. #if !defined(UNICODE) && !defined(_UNICODE)
  436. USES_IU_CONVERSION;
  437. #endif
  438. // Now verify the file
  439. WINTRUST_DATA winData;
  440. WINTRUST_FILE_INFO winFile;
  441. GUID gAction = WINTRUST_ACTION_GENERIC_VERIFY_V2;
  442. CRYPT_PROVIDER_DATA const *pProvData = NULL;
  443. CRYPT_PROVIDER_SGNR *pProvSigner = NULL;
  444. CRYPT_PROVIDER_CERT *pProvCert = NULL;
  445. HRESULT hr = S_OK;
  446. #ifdef __WUIUTEST
  447. {
  448. LOG_Trust(_T("CheckWinTrust _IUTEST Handling Begins"));
  449. //
  450. // handling test case:
  451. // if a reg key value is set to 1, then we will see if we need to pop up ALL certs
  452. //
  453. // NOTE:
  454. //
  455. // for the certs that user has checked "Always trust this provider..." previously,
  456. // WinCheckTrust() API will still NOT show any UI even if we signal Show-ALL flag
  457. //
  458. HKEY hkey;
  459. DWORD dwWinTrustUI = 0;
  460. DWORD dwSize = sizeof(dwWinTrustUI);
  461. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, 0, KEY_READ, &hkey))
  462. {
  463. RegQueryValueEx(hkey, _T("WinTrustUI"), 0, 0, (LPBYTE)&dwWinTrustUI, &dwSize);
  464. RegCloseKey(hkey);
  465. LOG_Trust(_T("Found regval %s\\WinTrustUI=%x"), REGKEY_IUCTL, dwWinTrustUI);
  466. }
  467. if (0x1 == dwWinTrustUI && WTD_UI_NONE != dwUIChoice)
  468. {
  469. //
  470. // if there is a WinTrustUI reg key exist, and value is 1
  471. // and caller does not request silence, then we
  472. // pop up all certs
  473. //
  474. LOG_Trust(_T("Change UI choice to WTD_UI_ALL"));
  475. dwUIChoice = WTD_UI_ALL;
  476. }
  477. if (0x2 == dwWinTrustUI)
  478. {
  479. //
  480. // if reg vlaue is 2, we pop up any cert no matter caller
  481. // says showing UI or not
  482. //
  483. LOG_Trust(_T("Changed UI choice from %d to WTD_UI_NOGOOD"));
  484. dwUIChoice = WTD_UI_ALL;
  485. }
  486. if (0x3 == dwWinTrustUI)
  487. {
  488. //
  489. // if reg value is 3, we pop up bad (include test) cert no matter
  490. // caller allow showing UI or not
  491. //
  492. LOG_Trust(_T("Changed UI choice from %d to WTD_UI_NOGOOD"));
  493. dwUIChoice = WTD_UI_NOGOOD;
  494. }
  495. }
  496. #endif
  497. //
  498. // dynamically load the wintrust.dll
  499. //
  500. if (NULL == shWinTrustDllInst)
  501. {
  502. if (NULL == (shWinTrustDllInst = LoadLibraryFromSystemDir(WINTRUST)))
  503. {
  504. LOG_Error(_T("Failed to load libary %s, exit function."), WINTRUST);
  505. hr = HRESULT_FROM_WIN32(GetLastError());
  506. goto Done;
  507. }
  508. }
  509. //
  510. // dynamically load the crypt32.dll, which will be used by the two
  511. // helper functions to verify the cert is MS cert
  512. //
  513. if (NULL == shCrypt32DllInst)
  514. {
  515. if (NULL == (shCrypt32DllInst = LoadLibraryFromSystemDir(CRYPT32)))
  516. {
  517. LOG_Error(_T("Failed to load libary %s, exit function."), CRYPT32);
  518. hr = HRESULT_FROM_WIN32(GetLastError());
  519. goto Done;
  520. }
  521. }
  522. //
  523. // find the functions we need
  524. //
  525. if (NULL == (pfnWinVerifyTrust = (PFNWinVerifyTrust)
  526. GetProcAddress(shWinTrustDllInst, "WinVerifyTrust")) ||
  527. NULL == (pfnWTHelperProvDataFromStateData = (PFNWTHelperProvDataFromStateData)
  528. GetProcAddress(shWinTrustDllInst, "WTHelperProvDataFromStateData")) ||
  529. NULL == (pfnWTHelperGetProvSignerFromChain = (PFNWTHelperGetProvSignerFromChain)
  530. GetProcAddress(shWinTrustDllInst, "WTHelperGetProvSignerFromChain")) ||
  531. NULL == (pfnWTHelperGetProvCertFromChain = (PFNWTHelperGetProvCertFromChain)
  532. GetProcAddress(shWinTrustDllInst, "WTHelperGetProvCertFromChain")))
  533. {
  534. //
  535. // at least one function was not found in the loaded cryp32.dll libary.
  536. // we can not continue, jsut quit.
  537. // NOTE: this shouldn't happen since we have tried to get
  538. // the least common denomination of different version of this dll
  539. // on both IE4 and IE5
  540. //
  541. LOG_Error(_T("CheckWinTrust() did not find functions needed from %s"), CRYPT32);
  542. hr = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
  543. goto Done;
  544. }
  545. //
  546. // initialize the data structure used to verify trust
  547. //
  548. winFile.cbStruct = sizeof(WINTRUST_FILE_INFO);
  549. winFile.hFile = INVALID_HANDLE_VALUE;
  550. winFile.pcwszFilePath = T2COLE(pszFileName);
  551. winFile.pgKnownSubject = NULL;
  552. winData.cbStruct = sizeof(WINTRUST_DATA);
  553. winData.pPolicyCallbackData = NULL;
  554. winData.pSIPClientData = NULL;
  555. winData.dwUIChoice = (WTD_UI_ALL == dwUIChoice) ? dwUIChoice : WTD_UI_NONE;
  556. winData.fdwRevocationChecks = WTD_REVOKE_NONE;
  557. winData.dwUnionChoice = WTD_CHOICE_FILE;
  558. winData.dwStateAction = WTD_STATEACTION_VERIFY;
  559. winData.hWVTStateData = 0;
  560. winData.dwProvFlags = WTD_REVOCATION_CHECK_NONE;
  561. winData.pFile = &winFile;
  562. if (dwCheckRevocation == WTD_REVOKE_WHOLECHAIN)
  563. {
  564. winData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
  565. winData.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN;
  566. }
  567. //
  568. // verify the signature
  569. //
  570. hr = pfnWinVerifyTrust( (HWND)0, &gAction, &winData);
  571. //
  572. // Ignore errors when retrieving Cert Revocation List (CRL). This
  573. // just means the list itself couldn't be retrieved, not that the
  574. // current cert was invalid or revoked. (KenSh, 2002/01/17)
  575. //
  576. if (hr == CERT_E_REVOCATION_FAILURE)
  577. {
  578. hr = S_OK;
  579. }
  580. if (FAILED(hr))
  581. {
  582. //
  583. // The object isn't even trusted so just get out here
  584. //
  585. LOG_Error(_T("When processing %s found error 0x%0x."), pszFileName, hr);
  586. goto Return;
  587. }
  588. //
  589. // the real usage should never pass in WTD_UI_ALL. If this is the case,
  590. // then we are calling this recursively in order to force the show
  591. // a good but non-MS cert only, so no need to check MS cert again.
  592. //
  593. // or, in test mode, we always do this part
  594. //
  595. if (WTD_UI_ALL != dwUIChoice)
  596. {
  597. //
  598. // if come to here, it means all above verified okay.
  599. //
  600. // the rset of code is used to verify the signed cert is
  601. // a known cert.
  602. //
  603. hr = S_FALSE;
  604. pProvData = pfnWTHelperProvDataFromStateData(winData.hWVTStateData);
  605. pProvSigner = pfnWTHelperGetProvSignerFromChain(
  606. (PCRYPT_PROVIDER_DATA) pProvData,
  607. 0, // first signer
  608. FALSE, // not a counter signer
  609. 0);
  610. //
  611. // check root cert then check leaf (signing) cert if that fails
  612. //
  613. // 0 is signing cert, csCertChain-1 is root cert
  614. //
  615. if (NULL == pCertsData)
  616. {
  617. //
  618. // if caller does not specify a hash value, then it means we want
  619. // to verify if this cert is known MS cert. We will first
  620. // try to find out if it is signed with a cert that has MS as root.
  621. //
  622. pProvCert = pfnWTHelperGetProvCertFromChain(pProvSigner, pProvSigner->csCertChain - 1);
  623. hr = VerifyMSRoot(shCrypt32DllInst, pProvCert->pCert);
  624. }
  625. if (S_OK != hr)
  626. {
  627. pProvCert = pfnWTHelperGetProvCertFromChain(pProvSigner, 0);
  628. hr = VerifyKnownCerts(shCrypt32DllInst, pProvCert->pCert, pCertsData);
  629. }
  630. }
  631. Return:
  632. //
  633. // free the wintrust state that was used to get the cert in the chain
  634. //
  635. winData.dwStateAction = WTD_STATEACTION_CLOSE;
  636. pfnWinVerifyTrust( (HWND)0, &gAction, &winData);
  637. //
  638. // recursively call this function if not in test mode so we can show
  639. // UI for this non-MS but good cert.
  640. // Only the two functions checking MS cert will return S_FALSE
  641. //
  642. if (S_OK != hr)
  643. {
  644. if (WTD_UI_NOGOOD == dwUIChoice)
  645. {
  646. //
  647. // we need to show UI, so we will have to call this thing again
  648. // in case this is not a MS cert. From UI, if user clicks YES
  649. // then the return value will be S_OK;
  650. //
  651. hr = CheckWinTrust(pszFileName, NULL, WTD_UI_ALL, dwCheckRevocation);
  652. LOG_Error(_T("CheckWinTrust() found file not signed by a known MS cert. If user has not checked \"Always trust this\", UI should be shown, and user selected %s"),
  653. SUCCEEDED(hr) ? _T("YES") : _T("NO"));
  654. }
  655. else
  656. {
  657. LOG_Error(_T("CheckWinTrust() found file not signed by a known cert!"));
  658. #if defined(UNICODE) || defined(_UNICODE)
  659. LogError(hr, "Digital Signatures on file %ls are not trusted", pszFileName);
  660. #else
  661. LogError(hr, "Digital Signatures on file %s are not trusted", pszFileName);
  662. #endif
  663. hr = TRUST_E_SUBJECT_NOT_TRUSTED;
  664. }
  665. }
  666. if (WTD_UI_ALL != dwUIChoice)
  667. {
  668. if (FAILED(hr))
  669. {
  670. LOG_ErrorMsg(hr);
  671. #if defined(UNICODE) || defined(_UNICODE)
  672. LogError(hr, "Digital Signatures on file %ls are not trusted", pszFileName);
  673. #else
  674. LogError(hr, "Digital Signatures on file %s are not trusted", pszFileName);
  675. #endif
  676. }
  677. else
  678. {
  679. LOG_Trust(_T("CheckWinTrust(%s) returns S_OK"), pszFileName);
  680. }
  681. }
  682. Done:
  683. if (NULL != shWinTrustDllInst)
  684. {
  685. FreeLibrary(shWinTrustDllInst);
  686. shWinTrustDllInst = NULL;
  687. }
  688. if (NULL != shCrypt32DllInst)
  689. {
  690. FreeLibrary(shCrypt32DllInst);
  691. shCrypt32DllInst = NULL;
  692. }
  693. return (hr);
  694. }
  695. /////////////////////////////////////////////////////////////////////////////
  696. //
  697. // Public Function VerifyFileTrust()
  698. //
  699. // This is a wrapper function for CheckWinTrust that both Whistler
  700. // and WU classic code should use.
  701. //
  702. // Input: szFileName - the file with complete path
  703. // pbSha1HashVal - hash value of a known good cert
  704. // fShowBadUI - whether pop up UI in cases
  705. // (1) inproperly signed signature,
  706. // (2) properly signed but not signed by a known cert
  707. //
  708. // Return: HRESULT - S_OK the file is signed with a valid known cert
  709. // or error code.
  710. //
  711. // Note: If _WUV3TEST flag is set (for test build), then fShowBadUI is
  712. // ignored:
  713. // if reg key SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\wuv3test\WinTrustUI
  714. // is set to 1, then no UI is shown, and this function always return S_OK;
  715. // otherwise, UI always show no matter what cert, and return value is same
  716. // as the live build.
  717. //
  718. /////////////////////////////////////////////////////////////////////////////
  719. HRESULT VerifyFileTrust(
  720. IN LPCTSTR szFileName,
  721. IN pCERT_HASH_ARRAY pCertsData,
  722. BOOL fShowBadUI,
  723. BOOL fCheckRevocation /*=FALSE*/
  724. )
  725. {
  726. DWORD dwUIChoice = fShowBadUI ? WTD_UI_NOGOOD : WTD_UI_NONE;
  727. DWORD dwCheckRevocation = fCheckRevocation ? WTD_REVOKE_WHOLECHAIN : WTD_REVOKE_NONE;
  728. return CheckWinTrust(szFileName, pCertsData, dwUIChoice, dwCheckRevocation);
  729. }
  730. /////////////////////////////////////////////////////////////////////////////
  731. //
  732. // Public Function ReadWUPolicyShowTrustUI()
  733. //
  734. // Input: void
  735. //
  736. // Return: BOOL - FALSE means ShowTrustUI regkey is not present, or is set to 0
  737. // TRUE means ShowTrustUI regkey is present and is set to 1
  738. //
  739. //
  740. /////////////////////////////////////////////////////////////////////////////
  741. BOOL ReadWUPolicyShowTrustUI()
  742. {
  743. #if !defined(DISABLE_IU_POLICY)
  744. LOG_Block("ReadWUPolicyShowTrustUI()");
  745. HKEY hkey;
  746. DWORD dwShowTrustUI = 0; // if the key is not present, default to not showing any UI
  747. DWORD dwSize = sizeof(dwShowTrustUI);
  748. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, 0, KEY_READ, &hkey))
  749. {
  750. if (ERROR_SUCCESS == RegQueryValueEx(hkey, _T("WUPolicyShowTrustUI"), 0, 0, (LPBYTE)&dwShowTrustUI, &dwSize))
  751. {
  752. LOG_Trust(_T("Found regval %s\\WUPolicyShowTrustUI=%x"), REGKEY_IUCTL, dwShowTrustUI);
  753. }
  754. RegCloseKey(hkey);
  755. }
  756. return (1 == dwShowTrustUI);
  757. #else
  758. //
  759. // for released build, we never show up UI
  760. //
  761. return FALSE;
  762. #endif
  763. }