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.

769 lines
19 KiB

  1. #include "stdinc.h"
  2. #include "Sxsp.h"
  3. #include "imagehlp.h"
  4. #include "windows.h"
  5. #include "hashfile.h"
  6. #include "wincrypt.h"
  7. #include "winbase.h"
  8. #include "softpub.h"
  9. #include "strongname.h"
  10. #include "FusionEventLog.h"
  11. #include "Sxsp.h"
  12. BOOL SxspImageDigesterFunc( DIGEST_HANDLE hSomething, PBYTE pbDataBlock, DWORD dwLength);
  13. BOOL SxspSimpleHashRoutine(CFusionHash &rhHash, HANDLE hFile);
  14. BOOL SxspImageHashRoutine(CFusionHash &rhHash, HANDLE hFile, BOOL &bInvalidImage);
  15. CRITICAL_SECTION g_csHashFile;
  16. struct _HASH_ALG_NAME_MAP
  17. {
  18. PWSTR wsName;
  19. ULONG cchName;
  20. ALG_ID cId;
  21. } HashAlgNameMap[] =
  22. {
  23. { L"SHA1", 4, CALG_SHA1 },
  24. { L"SHA", 3, CALG_SHA },
  25. { L"MD5", 3, CALG_MD5 },
  26. { L"MD4", 3, CALG_MD4 },
  27. { L"MD2", 3, CALG_MD2 },
  28. { L"MAC", 3, CALG_MAC },
  29. { L"HMAC", 4, CALG_HMAC }
  30. };
  31. BOOL
  32. SxspEnumKnownHashTypes(
  33. DWORD dwIndex,
  34. OUT CBaseStringBuffer &rbuffHashTypeName,
  35. BOOL &rbNoMoreItems
  36. )
  37. {
  38. FN_PROLOG_WIN32
  39. rbNoMoreItems = FALSE;
  40. if ( dwIndex >= NUMBER_OF( HashAlgNameMap ) )
  41. {
  42. rbNoMoreItems = TRUE;
  43. }
  44. else
  45. {
  46. IFW32FALSE_EXIT( rbuffHashTypeName.Win32Assign(
  47. HashAlgNameMap[dwIndex].wsName,
  48. HashAlgNameMap[dwIndex].cchName ) );
  49. }
  50. FN_EPILOG
  51. }
  52. BOOL
  53. SxspHashAlgFromString(
  54. const CBaseStringBuffer &strAlgName,
  55. ALG_ID &algId
  56. )
  57. {
  58. //
  59. // There's a disconnect that the Win32Equals function requires a real
  60. // C++ 'bool' value, while we want to return TRUE or FALSE, using Win32
  61. // constants and values.
  62. //
  63. bool bSuccessCpp = false;
  64. DWORD idx;
  65. for (idx = 0; (idx < NUMBER_OF(HashAlgNameMap)) && !bSuccessCpp; idx++)
  66. {
  67. if (::FusionpCompareStrings(
  68. strAlgName, strAlgName.Cch(),
  69. HashAlgNameMap[idx].wsName, HashAlgNameMap[idx].cchName,
  70. false) == 0)
  71. {
  72. algId = HashAlgNameMap[idx].cId;
  73. bSuccessCpp = TRUE;
  74. }
  75. }
  76. return bSuccessCpp ? TRUE : FALSE;
  77. }
  78. BOOL
  79. SxspHashStringFromAlg(
  80. ALG_ID algId,
  81. CBaseStringBuffer &strAlgName
  82. )
  83. {
  84. BOOL bSuccess = FALSE;
  85. DWORD idx;
  86. FN_TRACE_WIN32(bSuccess);
  87. strAlgName.Clear();
  88. for (idx = 0; (idx < NUMBER_OF(HashAlgNameMap)) && !bSuccess; idx++)
  89. {
  90. if (HashAlgNameMap[idx].cId == algId)
  91. {
  92. IFW32FALSE_EXIT(strAlgName.Win32Assign(HashAlgNameMap[idx].wsName, HashAlgNameMap[idx].cchName));
  93. break;
  94. }
  95. }
  96. bSuccess = TRUE;
  97. Exit:
  98. return bSuccess;
  99. }
  100. BOOL
  101. SxspCheckHashDuringInstall(
  102. BOOL bHasHashData,
  103. const CBaseStringBuffer &rbuffFile,
  104. const CBaseStringBuffer &rbuffHashDataString,
  105. ALG_ID HashAlgId,
  106. HashValidateResult &rHashValid
  107. )
  108. {
  109. FN_PROLOG_WIN32
  110. rHashValid = HashValidate_OtherProblems;
  111. #if DBG
  112. ::FusionpDbgPrintEx(
  113. FUSION_DBG_LEVEL_INFO,
  114. "SXS.DLL: %s - Validating install-time hash: File=%ls tHasHash=%s tAlgId=0x%08x\n\tHash=%ls\n",
  115. __FUNCTION__,
  116. static_cast<PCWSTR>(rbuffFile),
  117. bHasHashData ? "yes" : "no",
  118. HashAlgId,
  119. static_cast<PCWSTR>(rbuffHashDataString));
  120. #endif
  121. if (bHasHashData)
  122. {
  123. CFusionArray<BYTE> rgbHashData;
  124. IFW32FALSE_EXIT(rgbHashData.Win32Initialize());
  125. if (!::SxspHashStringToBytes(
  126. rbuffHashDataString,
  127. rbuffHashDataString.Cch(),
  128. rgbHashData))
  129. {
  130. CSmallStringBuffer sb;
  131. rHashValid = HashValidate_InvalidPassedHash;
  132. ::SxspHashStringFromAlg(HashAlgId, sb);
  133. ::FusionpLogError(
  134. MSG_SXS_INVALID_FILE_HASH_FROM_COPY_CALLBACK,
  135. CEventLogString(sb),
  136. CEventLogString(rbuffFile));
  137. goto Exit;
  138. }
  139. IFW32FALSE_EXIT(::SxspVerifyFileHash(
  140. 0,
  141. rbuffFile,
  142. rgbHashData,
  143. HashAlgId,
  144. rHashValid));
  145. }
  146. else
  147. {
  148. //
  149. // If there's no hash data, or we're in OS setup mode, then the hash of the
  150. // file is "implicitly" correct.
  151. //
  152. rHashValid = HashValidate_Matches;
  153. }
  154. FN_EPILOG
  155. }
  156. BOOL
  157. SxspCreateFileHash(
  158. DWORD dwFlags,
  159. ALG_ID PreferredAlgorithm,
  160. const CBaseStringBuffer &pwsFileName,
  161. CFusionArray<BYTE> &bHashDestination
  162. )
  163. /*++
  164. Purpose:
  165. Parameters:
  166. Returns:
  167. --*/
  168. {
  169. FN_PROLOG_WIN32
  170. CFusionFile hFile;
  171. CFusionHash hCurrentHash;
  172. // Initialization
  173. hFile = INVALID_HANDLE_VALUE;
  174. PARAMETER_CHECK((dwFlags & ~HASHFLAG_VALID_PARAMS) == 0);
  175. //
  176. // First try and open the file. No sense in doing anything else if we
  177. // can't get to the data to start with. Use a very friendly set of
  178. // rights to check the file. Future users might want to be sure that
  179. // you're in the right security context before doing this - system
  180. // level to check system files, etc.
  181. //
  182. IFW32FALSE_EXIT(hFile.Win32CreateFile(pwsFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
  183. //
  184. // We'll be using SHA1 for the file hash
  185. //
  186. IFW32FALSE_EXIT(hCurrentHash.Win32Initialize(CALG_SHA1));
  187. //
  188. // So first try hashing it via the image, and if that fails, try the
  189. // normal file-reading hash routine instead.
  190. //
  191. if (dwFlags & HASHFLAG_AUTODETECT)
  192. {
  193. BOOL fInvalidImage;
  194. IFW32FALSE_EXIT(::SxspImageHashRoutine(hCurrentHash, hFile, fInvalidImage));
  195. if ( fInvalidImage )
  196. {
  197. IFW32FALSE_EXIT(::SxspSimpleHashRoutine(hCurrentHash, hFile));
  198. }
  199. }
  200. else if (dwFlags & HASHFLAG_STRAIGHT_HASH)
  201. {
  202. IFW32FALSE_EXIT(::SxspSimpleHashRoutine(hCurrentHash, hFile));
  203. }
  204. else if (dwFlags & HASHFLAG_PROCESS_IMAGE)
  205. {
  206. BOOL fInvalidImage;
  207. IFW32FALSE_EXIT(::SxspImageHashRoutine(hCurrentHash, hFile, fInvalidImage));
  208. if ( fInvalidImage )
  209. {
  210. ORIGINATE_WIN32_FAILURE_AND_EXIT(SxspCreateFileHash, ERROR_INVALID_PARAMETER);
  211. }
  212. }
  213. //
  214. // We know the buffer is the right size, so we just call down to the hash parameter
  215. // getter, which will be smart and bop out (setting the pdwDestinationSize parameter)
  216. // if the user passed an incorrect parameter.
  217. //
  218. IFW32FALSE_EXIT(hCurrentHash.Win32GetValue(bHashDestination));
  219. FN_EPILOG
  220. }
  221. BOOL
  222. SxspImageDigesterFunc(
  223. DIGEST_HANDLE hSomething,
  224. PBYTE pbDataBlock,
  225. DWORD dwLength
  226. )
  227. {
  228. FN_PROLOG_WIN32
  229. CFusionHash* pHashObject = reinterpret_cast<CFusionHash*>(hSomething);
  230. if ( pHashObject != NULL )
  231. {
  232. IFW32FALSE_EXIT(pHashObject->Win32HashData(pbDataBlock, dwLength));
  233. }
  234. FN_EPILOG
  235. }
  236. BOOL
  237. SxspSimpleHashRoutine(
  238. CFusionHash &rhHash,
  239. HANDLE hFile
  240. )
  241. {
  242. FN_PROLOG_WIN32
  243. DWORD dwDataRead;
  244. BOOL fKeepReading = TRUE;
  245. BOOL b = FALSE;
  246. CFusionArray<BYTE> pbBuffer;
  247. IFW32FALSE_EXIT( pbBuffer.Win32SetSize( 64 * 1024 ) );
  248. while (fKeepReading)
  249. {
  250. b = ::ReadFile(hFile, pbBuffer.GetArrayPtr(), pbBuffer.GetSizeAsDWORD(), &dwDataRead, NULL);
  251. //
  252. // Returned OK, but we're out of data, so quit.
  253. //
  254. if (b && (dwDataRead == 0))
  255. {
  256. fKeepReading = FALSE;
  257. b = TRUE;
  258. continue;
  259. }
  260. //
  261. // something bad happened so we need to stop
  262. //
  263. else if (!b)
  264. {
  265. const DWORD dwLastError = ::FusionpGetLastWin32Error();
  266. ORIGINATE_WIN32_FAILURE_AND_EXIT( ReadFile, dwLastError );
  267. }
  268. //
  269. // If we've gotten this far, we need to add the data found
  270. // to our existing hash
  271. //
  272. IFW32FALSE_EXIT(rhHash.Win32HashData(pbBuffer.GetArrayPtr(), dwDataRead));
  273. }
  274. FN_EPILOG;
  275. }
  276. BOOL
  277. SxspImageHashRoutine(
  278. CFusionHash &rhHash,
  279. HANDLE hFile,
  280. BOOL &rfInvalidImage
  281. )
  282. {
  283. FN_PROLOG_WIN32
  284. CSxsLockCriticalSection lock(g_csHashFile);
  285. rfInvalidImage = FALSE;
  286. PARAMETER_CHECK( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) );
  287. // The ImageGetDigestStream() function is not thread safe, so we have to ensure that it's
  288. // not called by other threads while we're using it.
  289. IFW32FALSE_EXIT(lock.Lock());
  290. IFW32FALSE_EXIT_UNLESS( ::ImageGetDigestStream(
  291. hFile,
  292. CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO,
  293. &SxspImageDigesterFunc,
  294. (DIGEST_HANDLE)(&rhHash)),
  295. (::FusionpGetLastWin32Error() == ERROR_INVALID_PARAMETER),
  296. rfInvalidImage );
  297. FN_EPILOG
  298. }
  299. BOOL
  300. SxspVerifyFileHash(
  301. const DWORD dwFlags,
  302. const CBaseStringBuffer &hsFullFilePath,
  303. const CFusionArray<BYTE> &baTheoreticalHash,
  304. ALG_ID whichAlg,
  305. HashValidateResult &HashValid
  306. )
  307. {
  308. FN_PROLOG_WIN32
  309. CFusionArray<BYTE> bGotHash;
  310. HashValid = HashValidate_OtherProblems;
  311. BOOL fFileNotFoundError;
  312. LONG ulRetriesLeft = 0;
  313. LONG ulBackoffAmount = 1000;
  314. LONG ulBackoffAmountCap = 3000;
  315. float ulBackoffRate = 1.5f;
  316. PARAMETER_CHECK( (dwFlags == SVFH_DEFAULT_ACTION) ||
  317. (dwFlags == SVFH_RETRY_LOGIC_SIMPLE) ||
  318. (dwFlags == SVFH_RETRY_WAIT_UNTIL));
  319. if ( dwFlags == SVFH_RETRY_LOGIC_SIMPLE )
  320. ulRetriesLeft = 10;
  321. TryAgain:
  322. IFW32FALSE_EXIT_UNLESS2(
  323. ::SxspCreateFileHash(
  324. HASHFLAG_AUTODETECT,
  325. whichAlg,
  326. hsFullFilePath,
  327. bGotHash),
  328. LIST_5( ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_BAD_NETPATH, ERROR_BAD_NET_NAME, ERROR_SHARING_VIOLATION),
  329. fFileNotFoundError);
  330. //
  331. // If this was a sharing violation and we've got retries left, then try again.
  332. //
  333. if ( fFileNotFoundError && (::FusionpGetLastWin32Error() == ERROR_SHARING_VIOLATION) && (ulRetriesLeft > 0))
  334. {
  335. ulRetriesLeft--;
  336. ::Sleep( ulBackoffAmount );
  337. if ( ulBackoffAmount < ulBackoffAmountCap )
  338. {
  339. ulBackoffAmount = (ULONG)((float)ulBackoffAmount * ulBackoffRate);
  340. }
  341. if ( dwFlags == SVFH_RETRY_WAIT_UNTIL )
  342. ulRetriesLeft = 1;
  343. goto TryAgain;
  344. }
  345. //
  346. // If the file was able to be hashed, and the return error isn't "file not found",
  347. // then compare the hashes
  348. //
  349. if (!fFileNotFoundError &&(baTheoreticalHash.GetSize() == bGotHash.GetSize()))
  350. {
  351. HashValid =
  352. (::memcmp(
  353. bGotHash.GetArrayPtr(),
  354. baTheoreticalHash.GetArrayPtr(),
  355. bGotHash.GetSize()) == 0) ? HashValidate_Matches : HashValidate_HashNotMatched;
  356. }
  357. else
  358. {
  359. HashValid = HashValidate_HashesCantBeMatched;
  360. }
  361. FN_EPILOG
  362. }
  363. BOOL
  364. SxspGetStrongNameFromManifestName(
  365. PCWSTR pszManifestName,
  366. CBaseStringBuffer &rbuffStrongName,
  367. BOOL &rfHasPublicKey
  368. )
  369. {
  370. BOOL fSuccess = TRUE;
  371. FN_TRACE_WIN32(fSuccess);
  372. PCWSTR wsCursor;
  373. SIZE_T cchJump, cchPubKey;
  374. rfHasPublicKey = FALSE;
  375. rbuffStrongName.Clear();
  376. wsCursor = pszManifestName;
  377. //
  378. // Tricky: Zips through the name of the manifest to find the strong name string.
  379. //
  380. for (int i = 0; i < 2; i++)
  381. {
  382. cchJump = wcscspn(wsCursor, L"_");
  383. PARAMETER_CHECK(cchJump != 0);
  384. wsCursor += (cchJump + 1); // x86_foo_strongname -> foo_strongname
  385. }
  386. //
  387. // Are we mysteriously at the end of the string?
  388. //
  389. PARAMETER_CHECK(wsCursor[0] != L'\0');
  390. //
  391. // Find the length of the public key string
  392. //
  393. cchPubKey = wcscspn(wsCursor, L"_");
  394. PARAMETER_CHECK(cchPubKey != 0);
  395. IFW32FALSE_EXIT(rbuffStrongName.Win32Assign(wsCursor, cchPubKey));
  396. rfHasPublicKey = (::FusionpCompareStrings(
  397. rbuffStrongName,
  398. rbuffStrongName.Cch(),
  399. SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_PUBLICKEY_MISSING_VALUE,
  400. NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_PUBLICKEY_MISSING_VALUE) - 1,
  401. false) != 0);
  402. FN_EPILOG
  403. }
  404. static GUID p_WintrustVerifyGenericV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
  405. BOOL
  406. SxspValidateManifestAgainstCatalog(
  407. const CBaseStringBuffer &rbuffManifestName, // "c:\foo\x86_comctl32_6.0.0.0_0000.manifest"
  408. ManifestValidationResult &rResult,
  409. DWORD dwOptionsFlags
  410. )
  411. {
  412. BOOL fSuccess = FALSE;
  413. FN_TRACE_WIN32(fSuccess);
  414. CStringBuffer sbCatalogName;
  415. //
  416. // Take the manifest name (which should be c:\foo\bar\blort.manifest) and switch
  417. // it to contain the catalog name instead:
  418. //
  419. // c:\foo\bar\blort.cat
  420. //
  421. IFW32FALSE_EXIT(sbCatalogName.Win32Assign(rbuffManifestName));
  422. IFW32FALSE_EXIT(
  423. sbCatalogName.Win32ChangePathExtension(
  424. FILE_EXTENSION_CATALOG,
  425. FILE_EXTENSION_CATALOG_CCH,
  426. eAddIfNoExtension));
  427. IFW32FALSE_EXIT(::SxspValidateManifestAgainstCatalog(rbuffManifestName, sbCatalogName, rResult, dwOptionsFlags));
  428. fSuccess = TRUE;
  429. Exit:
  430. return fSuccess;
  431. }
  432. void SxspCertFreeCtlContext( PCCTL_CONTEXT CtlContext )
  433. {
  434. if (CtlContext != NULL)
  435. CertFreeCTLContext( CtlContext );
  436. }
  437. void SxspCertFreeCertContext( PCCERT_CONTEXT CertContext )
  438. {
  439. if (CertContext != NULL )
  440. CertFreeCertificateContext(CertContext);
  441. }
  442. BOOL
  443. SxspValidateCatalogAndFindManifestHash(
  444. IN HANDLE hCatalogFile,
  445. IN PBYTE prgbHash,
  446. IN SIZE_T cbHash,
  447. OUT BOOL &rfCatalogOk,
  448. OUT BOOL &rfHashInCatalog
  449. )
  450. {
  451. FN_PROLOG_WIN32
  452. CFileMapping fmCatalogMapping;
  453. CMappedViewOfFile mvCatalogView;
  454. LARGE_INTEGER liCatalogFile;
  455. ULONGLONG ullCatalogFile;
  456. PVOID pvCatalogData;
  457. CRYPT_VERIFY_MESSAGE_PARA vfmParameters;
  458. //
  459. // Default value
  460. //
  461. rfHashInCatalog = FALSE;
  462. rfCatalogOk = FALSE;
  463. //
  464. // Create a CTL context from the catalog file.
  465. //
  466. IFW32FALSE_ORIGINATE_AND_EXIT(GetFileSizeEx(hCatalogFile, &liCatalogFile));
  467. ullCatalogFile = liCatalogFile.QuadPart;
  468. IFW32FALSE_EXIT(fmCatalogMapping.Win32CreateFileMapping(hCatalogFile, PAGE_READONLY, ullCatalogFile, NULL));
  469. IFW32FALSE_EXIT(mvCatalogView.Win32MapViewOfFile(fmCatalogMapping, FILE_MAP_READ, 0, (SIZE_T)ullCatalogFile));
  470. pvCatalogData = mvCatalogView;
  471. //
  472. // First, validate that the message (catalog) is OK
  473. //
  474. ZeroMemory(&vfmParameters, sizeof(vfmParameters));
  475. vfmParameters.cbSize = sizeof(vfmParameters);
  476. vfmParameters.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
  477. rfCatalogOk = CryptVerifyMessageSignature(
  478. &vfmParameters,
  479. 0,
  480. static_cast<PBYTE>(pvCatalogData),
  481. static_cast<DWORD>(ullCatalogFile),
  482. NULL,
  483. NULL,
  484. NULL);
  485. if ( rfCatalogOk )
  486. {
  487. CSxsPointerWithNamedDestructor<const CERT_CONTEXT, SxspCertFreeCertContext> pCertContext;
  488. CSxsPointerWithNamedDestructor<const CTL_CONTEXT, SxspCertFreeCtlContext> pCtlContext;
  489. PCTL_ENTRY pFoundCtlEntry;
  490. CSmallStringBuffer buffStringizedHash;
  491. CTL_ANY_SUBJECT_INFO ctlSubjectInfo;
  492. //
  493. // The search routine needs a string to find, says the crypto guys.
  494. //
  495. IFW32FALSE_EXIT(::SxspHashBytesToString( prgbHash, cbHash, buffStringizedHash));
  496. IFW32FALSE_EXIT(buffStringizedHash.Win32ConvertCase(eConvertToUpperCase));
  497. //
  498. // If this failed, something bad happened with the CTL - maybe the catalog
  499. // was invalid, maybe something else happened. Whatever it was, let the
  500. // caller decide.
  501. //
  502. pCtlContext = CertCreateCTLContext(
  503. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  504. static_cast<PBYTE>(pvCatalogData),
  505. static_cast<DWORD>(ullCatalogFile));
  506. if ( pCtlContext != NULL )
  507. {
  508. //
  509. // Fill out this data with the string information.
  510. //
  511. CStringBufferAccessor sba;
  512. sba.Attach(&buffStringizedHash);
  513. ZeroMemory(&ctlSubjectInfo, sizeof(ctlSubjectInfo));
  514. ctlSubjectInfo.SubjectAlgorithm.pszObjId = NULL;
  515. ctlSubjectInfo.SubjectIdentifier.pbData = static_cast<PBYTE>(static_cast<PVOID>(sba.GetBufferPtr()));
  516. ctlSubjectInfo.SubjectIdentifier.cbData = static_cast<DWORD>((sba.Cch() + 1) * sizeof(WCHAR));
  517. sba.Detach();
  518. //
  519. // Look for it in the CTL
  520. //
  521. pFoundCtlEntry = CertFindSubjectInCTL(
  522. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  523. CTL_ANY_SUBJECT_TYPE,
  524. &ctlSubjectInfo,
  525. pCtlContext,
  526. 0);
  527. rfHashInCatalog = ( pFoundCtlEntry != NULL );
  528. }
  529. }
  530. FN_EPILOG
  531. }
  532. BOOL
  533. SxspValidateManifestAgainstCatalog(
  534. IN const CBaseStringBuffer &rbuffManifestName,
  535. IN const CBaseStringBuffer &rbuffCatalogName,
  536. OUT ManifestValidationResult &rResult,
  537. IN DWORD dwOptionsFlags
  538. )
  539. {
  540. FN_PROLOG_WIN32
  541. CFusionArray<BYTE> ManifestHash;
  542. CSmallStringBuffer rbuffStrongNameString;
  543. BOOL fTempFlag;
  544. BOOL fCatalogOk, fHashFound;
  545. CPublicKeyInformation pkiCatalogInfo;
  546. CFusionFile ffCatalogFile;
  547. //
  548. // Generate the hash of the manifest first
  549. //
  550. IFW32FALSE_EXIT_UNLESS2(::SxspCreateFileHash(
  551. HASHFLAG_STRAIGHT_HASH,
  552. CALG_SHA1,
  553. rbuffManifestName,
  554. ManifestHash),
  555. LIST_4(ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND, ERROR_BAD_NET_NAME, ERROR_BAD_NETPATH),
  556. fTempFlag);
  557. if ( fTempFlag )
  558. {
  559. rResult = ManifestValidate_ManifestMissing;
  560. FN_SUCCESSFUL_EXIT();
  561. }
  562. //
  563. // Open the catalog file for now, we'll use it later.
  564. //
  565. IFW32FALSE_EXIT_UNLESS2(
  566. ffCatalogFile.Win32CreateFile(
  567. rbuffCatalogName,
  568. GENERIC_READ,
  569. FILE_SHARE_READ,
  570. OPEN_EXISTING),
  571. LIST_4(ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND, ERROR_BAD_NET_NAME, ERROR_BAD_NETPATH),
  572. fTempFlag);
  573. if ( fTempFlag )
  574. {
  575. rResult = ManifestValidate_CatalogMissing;
  576. FN_SUCCESSFUL_EXIT();
  577. }
  578. //
  579. // Now look in the file to see if the catalog contains the hash of the manifest
  580. // in the CTL
  581. //
  582. IFW32FALSE_EXIT(SxspValidateCatalogAndFindManifestHash(
  583. ffCatalogFile,
  584. ManifestHash.GetArrayPtr(),
  585. ManifestHash.GetSize(),
  586. fCatalogOk,
  587. fHashFound));
  588. if ( !fCatalogOk )
  589. {
  590. rResult = ManifestValidate_OtherProblems;
  591. FN_SUCCESSFUL_EXIT();
  592. }
  593. else if ( !fHashFound )
  594. {
  595. rResult = ManifestValidate_NotCertified;
  596. FN_SUCCESSFUL_EXIT();
  597. }
  598. //
  599. // Are we supposed to validate the strong name of this catalog?
  600. //
  601. if ( ( dwOptionsFlags & MANIFESTVALIDATE_MODE_NO_STRONGNAME ) == 0 )
  602. {
  603. IFW32FALSE_EXIT(::SxspGetStrongNameFromManifestName(
  604. rbuffManifestName,
  605. rbuffStrongNameString,
  606. fTempFlag));
  607. if ( !fTempFlag )
  608. {
  609. rResult = ManifestValidate_OtherProblems;
  610. FN_SUCCESSFUL_EXIT();
  611. }
  612. IFW32FALSE_EXIT(pkiCatalogInfo.Initialize(rbuffCatalogName));
  613. }
  614. //
  615. // Huzzah!
  616. //
  617. rResult = ManifestValidate_IsIntact;
  618. FN_EPILOG
  619. }
  620. BOOL
  621. SxspIsFullHexString(PCWSTR wsString, SIZE_T Cch)
  622. {
  623. for (SIZE_T i = 0; i < Cch; i++)
  624. {
  625. WCHAR ch = wsString[i];
  626. if (!SxspIsHexDigit(ch))
  627. return FALSE;
  628. }
  629. return TRUE;
  630. }