From 135e94d6cb1d73b41f23785a790a97615c714f20 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Tue, 9 Aug 2022 08:49:29 +1000 Subject: [PATCH] Migrate `WinTrust` functions to a common location (#17598) --- .../security/Authenticode.cs | 193 +++--- .../security/CatalogHelper.cs | 359 +++++------ .../security/Win32Native/WinTrust.cs | 440 +++++++++++++ .../security/nativeMethods.cs | 593 ------------------ 4 files changed, 718 insertions(+), 867 deletions(-) create mode 100644 src/System.Management.Automation/security/Win32Native/WinTrust.cs diff --git a/src/System.Management.Automation/security/Authenticode.cs b/src/System.Management.Automation/security/Authenticode.cs index 1906d18bf6..0b205cc663 100644 --- a/src/System.Management.Automation/security/Authenticode.cs +++ b/src/System.Management.Automation/security/Authenticode.cs @@ -7,14 +7,15 @@ #if !UNIX using Microsoft.Security.Extensions; #endif +using System.ComponentModel; using System.IO; using System.Management.Automation.Internal; using System.Management.Automation.Security; +using System.Management.Automation.Win32Native; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using Dbg = System.Management.Automation; -using DWORD = System.UInt32; namespace System.Management.Automation { @@ -52,6 +53,8 @@ namespace System.Management.Automation /// internal static class SignatureHelper { + private static Guid WINTRUST_ACTION_GENERIC_VERIFY_V2 = new Guid("00AAC56B-CD44-11d0-8CC2-00C04FC295EE"); + /// /// Tracer for SignatureHelper. /// @@ -103,7 +106,7 @@ namespace System.Management.Automation bool result = false; Signature signature = null; IntPtr pSignInfo = IntPtr.Zero; - DWORD error = 0; + uint error = 0; string hashOid = null; Utils.CheckArgForNullOrEmpty(fileName, "fileName"); @@ -190,7 +193,7 @@ namespace System.Management.Automation // able to see that. #pragma warning disable 56523 result = NativeMethods.CryptUIWizDigitalSign( - (DWORD)NativeMethods.CryptUIFlags.CRYPTUI_WIZ_NO_UI, + (uint)NativeMethods.CryptUIFlags.CRYPTUI_WIZ_NO_UI, IntPtr.Zero, IntPtr.Zero, pSignInfo, @@ -246,7 +249,7 @@ namespace System.Management.Automation } else { - signature = new Signature(fileName, (DWORD)error); + signature = new Signature(fileName, (uint)error); } } finally @@ -330,7 +333,7 @@ namespace System.Management.Automation } } - DWORD error = GetErrorFromSignatureState(fileSigInfo.State); + uint error = GetErrorFromSignatureState(fileSigInfo.State); if (fileSigInfo.SigningCertificate is null) { @@ -374,7 +377,7 @@ namespace System.Management.Automation } #if !UNIX - private static DWORD GetErrorFromSignatureState(SignatureState signatureState) + private static uint GetErrorFromSignatureState(SignatureState signatureState) { switch (signatureState) { @@ -401,8 +404,8 @@ namespace System.Management.Automation { Signature signature = null; - NativeMethods.WINTRUST_DATA wtd; - DWORD error = Win32Errors.E_FAIL; + WinTrustMethods.WINTRUST_DATA wtd; + uint error = Win32Errors.E_FAIL; if (fileContent == null) { @@ -422,7 +425,10 @@ namespace System.Management.Automation signature = GetSignatureFromWintrustData(fileName, error, wtd); - error = NativeMethods.DestroyWintrustDataStruct(wtd); + wtd.dwStateAction = WinTrustAction.WTD_STATEACTION_CLOSE; + error = WinTrustMethods.WinVerifyTrust(IntPtr.Zero, + ref WINTRUST_ACTION_GENERIC_VERIFY_V2, + ref wtd); if (error != Win32Errors.NO_ERROR) { @@ -438,89 +444,83 @@ namespace System.Management.Automation } [ArchitectureSensitive] - private static DWORD GetWinTrustData(string fileName, string fileContent, - out NativeMethods.WINTRUST_DATA wtData) + private static uint GetWinTrustData(string fileName, string fileContent, + out WinTrustMethods.WINTRUST_DATA wtData) { - DWORD dwResult = Win32Errors.E_FAIL; - IntPtr WINTRUST_ACTION_GENERIC_VERIFY_V2 = IntPtr.Zero; - IntPtr wtdBuffer = IntPtr.Zero; - - Guid actionVerify = - new Guid("00AAC56B-CD44-11d0-8CC2-00C04FC295EE"); - - try + wtData = new() { - WINTRUST_ACTION_GENERIC_VERIFY_V2 = - Marshal.AllocCoTaskMem(Marshal.SizeOf(actionVerify)); - Marshal.StructureToPtr(actionVerify, - WINTRUST_ACTION_GENERIC_VERIFY_V2, - false); + cbStruct = (uint)Marshal.SizeOf(), + dwUIChoice = WinTrustUIChoice.WTD_UI_NONE, + dwStateAction = WinTrustAction.WTD_STATEACTION_VERIFY, + }; - NativeMethods.WINTRUST_DATA wtd; - - if (fileContent == null) - { - NativeMethods.WINTRUST_FILE_INFO wfi = NativeMethods.InitWintrustFileInfoStruct(fileName); - wtd = NativeMethods.InitWintrustDataStructFromFile(wfi); - } - else - { - NativeMethods.WINTRUST_BLOB_INFO wbi = NativeMethods.InitWintrustBlobInfoStruct(fileName, fileContent); - wtd = NativeMethods.InitWintrustDataStructFromBlob(wbi); - } - - wtdBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(wtd)); - Marshal.StructureToPtr(wtd, wtdBuffer, false); - - // The result is returned to the caller, and handled generically. - // Disable the PreFast check for Win32 error codes, as we don't care. -#pragma warning disable 56523 - dwResult = NativeMethods.WinVerifyTrust( - IntPtr.Zero, - WINTRUST_ACTION_GENERIC_VERIFY_V2, - wtdBuffer); -#pragma warning restore 56523 - - wtData = Marshal.PtrToStructure(wtdBuffer); - } - finally + byte[] contentBytes = fileContent == null + ? Array.Empty() + : System.Text.Encoding.Unicode.GetBytes(fileContent); + unsafe { - Marshal.DestroyStructure(WINTRUST_ACTION_GENERIC_VERIFY_V2); - Marshal.FreeCoTaskMem(WINTRUST_ACTION_GENERIC_VERIFY_V2); - Marshal.DestroyStructure(wtdBuffer); - Marshal.FreeCoTaskMem(wtdBuffer); - } + fixed (char* fileNamePtr = fileName) + { + if (fileContent == null) + { + WinTrustMethods.WINTRUST_FILE_INFO wfi = new() + { + cbStruct = (uint)Marshal.SizeOf(), + pcwszFilePath = fileNamePtr, + }; + wtData.dwUnionChoice = WinTrustUnionChoice.WTD_CHOICE_FILE; + wtData.pChoice = &wfi; - return dwResult; + return WinTrustMethods.WinVerifyTrust(IntPtr.Zero, + ref WINTRUST_ACTION_GENERIC_VERIFY_V2, + ref wtData); + } + + fixed (byte* contentPtr = contentBytes) + { + Guid pwshSIP = new("603BCC1F-4B59-4E08-B724-D2C6297EF351"); + WinTrustMethods.WINTRUST_BLOB_INFO wbi = new() + { + cbStruct = (uint)Marshal.SizeOf(), + gSubject = pwshSIP, + pcwszDisplayName = fileNamePtr, + cbMemObject = (uint)contentBytes.Length, + pbMemObject = contentPtr, + }; + wtData.dwUnionChoice = WinTrustUnionChoice.WTD_CHOICE_BLOB; + wtData.pChoice = &wbi; + + return WinTrustMethods.WinVerifyTrust(IntPtr.Zero, + ref WINTRUST_ACTION_GENERIC_VERIFY_V2, + ref wtData); + } + } + } } [ArchitectureSensitive] private static X509Certificate2 GetCertFromChain(IntPtr pSigner) { - X509Certificate2 signerCert = null; - - // We don't care about the Win32 error code here, so disable - // the PreFast complaint that we're not retrieving it. -#pragma warning disable 56523 - IntPtr pCert = - NativeMethods.WTHelperGetProvCertFromChain(pSigner, 0); -#pragma warning restore 56523 - - if (pCert != IntPtr.Zero) + try { + IntPtr pCert = WinTrustMethods.WTHelperGetProvCertFromChain(pSigner, 0); NativeMethods.CRYPT_PROVIDER_CERT provCert = Marshal.PtrToStructure(pCert); - signerCert = new X509Certificate2(provCert.pCert); + return new X509Certificate2(provCert.pCert); + } + catch (Win32Exception) + { + // We don't care about the Win32 error code here, so return + // null on a failure and let the caller handle it. + return null; } - - return signerCert; } [ArchitectureSensitive] private static Signature GetSignatureFromWintrustData( string filePath, - DWORD error, - NativeMethods.WINTRUST_DATA wtd) + uint error, + WinTrustMethods.WINTRUST_DATA wtd) { s_tracer.WriteLine("GetSignatureFromWintrustData: error: {0}", error); @@ -568,39 +568,36 @@ namespace System.Management.Automation pProvSigner = IntPtr.Zero; timestamperCert = null; - // The GetLastWin32Error of this is checked, but PreSharp doesn't seem to be - // able to see that. -#pragma warning disable 56523 - IntPtr pProvData = - NativeMethods.WTHelperProvDataFromStateData(wvtStateData); -#pragma warning restore 56523 - - if (pProvData != IntPtr.Zero) + try { - pProvSigner = - NativeMethods.WTHelperGetProvSignerFromChain(pProvData, 0, 0, 0); + IntPtr pProvData = WinTrustMethods.WTHelperProvDataFromStateData(wvtStateData); - if (pProvSigner != IntPtr.Zero) + pProvSigner = WinTrustMethods.WTHelperGetProvSignerFromChain( + pProvData, + signerIdx: 0, + counterSigner: false, + counterSignerIdx: 0); + + NativeMethods.CRYPT_PROVIDER_SGNR provSigner = + Marshal.PtrToStructure(pProvSigner); + if (provSigner.csCounterSigners == 1) { - NativeMethods.CRYPT_PROVIDER_SGNR provSigner = - Marshal.PtrToStructure(pProvSigner); - if (provSigner.csCounterSigners == 1) - { - // - // time stamper cert available - // - timestamperCert = GetCertFromChain(provSigner.pasCounterSigners); - } - - return true; + // + // time stamper cert available + // + timestamperCert = GetCertFromChain(provSigner.pasCounterSigners); } - } - return false; + return true; + } + catch (Win32Exception) + { + return false; + } } [ArchitectureSensitive] - private static DWORD GetLastWin32Error() + private static uint GetLastWin32Error() { int error = Marshal.GetLastWin32Error(); diff --git a/src/System.Management.Automation/security/CatalogHelper.cs b/src/System.Management.Automation/security/CatalogHelper.cs index 585ef80188..5f71d1f86b 100644 --- a/src/System.Management.Automation/security/CatalogHelper.cs +++ b/src/System.Management.Automation/security/CatalogHelper.cs @@ -6,12 +6,13 @@ using System.Security.Cryptography; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.IO; using System.Linq; using System.Management.Automation.Internal; using System.Management.Automation.Security; +using System.Management.Automation.Win32Native; using System.Runtime.InteropServices; -using DWORD = System.UInt32; namespace System.Management.Automation { @@ -83,12 +84,11 @@ namespace System.Management.Automation /// /// Handle to open catalog file. /// Version of the catalog. - private static int GetCatalogVersion(IntPtr catalogHandle) + private static int GetCatalogVersion(SafeCATHandle catalogHandle) { int catalogVersion = -1; - IntPtr catalogData = NativeMethods.CryptCATStoreFromHandle(catalogHandle); - NativeMethods.CRYPTCATSTORE catalogInfo = Marshal.PtrToStructure(catalogData); + WinTrustMethods.CRYPTCATSTORE catalogInfo = WinTrustMethods.CryptCATStoreFromHandle(catalogHandle); if (catalogInfo.dwPublicVersion == catalogVersion2) { @@ -248,20 +248,32 @@ namespace System.Management.Automation /// Path to the Input .cdf file. internal static void GenerateCatalogFile(string cdfFilePath) { - string pwszFilePath = cdfFilePath; - NativeMethods.CryptCATCDFOpenCallBack catOpenCallBack = new NativeMethods.CryptCATCDFOpenCallBack(ParseErrorCallback); - // Open CDF File - IntPtr resultCDF = NativeMethods.CryptCATCDFOpen(pwszFilePath, catOpenCallBack); + SafeCATCDFHandle resultCDF; + try + { + resultCDF = WinTrustMethods.CryptCATCDFOpen(cdfFilePath, ParseErrorCallback); + } + catch (Win32Exception e) + { + // If we are not able to open CDF file we can not continue generating catalog + ErrorRecord errorRecord = new ErrorRecord( + new InvalidOperationException(CatalogStrings.UnableToOpenCatalogDefinitionFile, e), + "UnableToOpenCatalogDefinitionFile", + ErrorCategory.InvalidOperation, + null); + _cmdlet.ThrowTerminatingError(errorRecord); + return; + } // navigate CDF header and files sections - if (resultCDF != IntPtr.Zero) + using (resultCDF) { // First navigate all catalog level attributes entries first, they represent zero size files IntPtr catalogAttr = IntPtr.Zero; do { - catalogAttr = NativeMethods.CryptCATCDFEnumCatAttributes(resultCDF, catalogAttr, catOpenCallBack); + catalogAttr = WinTrustMethods.CryptCATCDFEnumCatAttributes(resultCDF, catalogAttr, ParseErrorCallback); if (catalogAttr != IntPtr.Zero) { @@ -272,51 +284,38 @@ namespace System.Management.Automation // navigate all the files hash entries in the .cdf file IntPtr memberInfo = IntPtr.Zero; - try + IntPtr memberFile = IntPtr.Zero; + string fileName = string.Empty; + do { - IntPtr memberFile = IntPtr.Zero; - NativeMethods.CryptCATCDFEnumMembersByCDFTagExErrorCallBack memberCallBack = new NativeMethods.CryptCATCDFEnumMembersByCDFTagExErrorCallBack(ParseErrorCallback); - string fileName = string.Empty; - do + memberFile = WinTrustMethods.CryptCATCDFEnumMembersByCDFTagEx(resultCDF, memberFile, ParseErrorCallback, ref memberInfo, + fContinueOnError: true, pvReserved: IntPtr.Zero); + fileName = Marshal.PtrToStringUni(memberFile); + + if (!string.IsNullOrEmpty(fileName)) { - memberFile = NativeMethods.CryptCATCDFEnumMembersByCDFTagEx(resultCDF, memberFile, memberCallBack, ref memberInfo, true, IntPtr.Zero); - fileName = Marshal.PtrToStringUni(memberFile); - - if (!string.IsNullOrEmpty(fileName)) + IntPtr memberAttr = IntPtr.Zero; + string fileRelativePath = string.Empty; + do { - IntPtr memberAttr = IntPtr.Zero; - string fileRelativePath = string.Empty; - do - { - memberAttr = NativeMethods.CryptCATCDFEnumAttributesWithCDFTag(resultCDF, memberFile, memberInfo, memberAttr, memberCallBack); + memberAttr = WinTrustMethods.CryptCATCDFEnumAttributesWithCDFTag(resultCDF, memberFile, memberInfo, memberAttr, ParseErrorCallback); - if (memberAttr != IntPtr.Zero) + if (memberAttr != IntPtr.Zero) + { + fileRelativePath = ProcessFilePathAttributeInCatalog(memberAttr); + if (!string.IsNullOrEmpty(fileRelativePath)) { - fileRelativePath = ProcessFilePathAttributeInCatalog(memberAttr); - if (!string.IsNullOrEmpty(fileRelativePath)) - { - // Found the attribute we are looking for - // Filename we read from the above API has appended to its name as per CDF file tags convention - // Truncating that Information from the string. - string itemName = fileName.Substring(6); - _cmdlet.WriteVerbose(StringUtil.Format(CatalogStrings.AddFileToCatalog, itemName, fileRelativePath)); - break; - } + // Found the attribute we are looking for + // Filename we read from the above API has appended to its name as per CDF file tags convention + // Truncating that Information from the string. + string itemName = fileName.Substring(6); + _cmdlet.WriteVerbose(StringUtil.Format(CatalogStrings.AddFileToCatalog, itemName, fileRelativePath)); + break; } - } while (memberAttr != IntPtr.Zero); - } - } while (fileName != null); - } - finally - { - NativeMethods.CryptCATCDFClose(resultCDF); - } - } - else - { - // If we are not able to open CDF file we can not continue generating catalog - ErrorRecord errorRecord = new ErrorRecord(new InvalidOperationException(CatalogStrings.UnableToOpenCatalogDefinitionFile), "UnableToOpenCatalogDefinitionFile", ErrorCategory.InvalidOperation, null); - _cmdlet.ThrowTerminatingError(errorRecord); + } + } while (memberAttr != IntPtr.Zero); + } + } while (fileName != null); } } @@ -374,7 +373,7 @@ namespace System.Management.Automation { string relativePath = string.Empty; - NativeMethods.CRYPTCATATTRIBUTE currentMemberAttr = Marshal.PtrToStructure(memberAttrInfo); + WinTrustMethods.CRYPTCATATTRIBUTE currentMemberAttr = Marshal.PtrToStructure(memberAttrInfo); // check if this is the attribute we are looking for // catalog generated other way not using New-FileCatalog can have attributes we don't understand @@ -400,69 +399,65 @@ namespace System.Management.Automation internal static string CalculateFileHash(string filePath, string hashAlgorithm) { string hashValue = string.Empty; - IntPtr catAdmin = IntPtr.Zero; // To get handle to the hash algorithm to be used to calculate hashes - if (!NativeMethods.CryptCATAdminAcquireContext2(ref catAdmin, IntPtr.Zero, hashAlgorithm, IntPtr.Zero, 0)) + SafeCATAdminHandle catAdmin; + try { - ErrorRecord errorRecord = new ErrorRecord(new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToAcquireHashAlgorithmContext, hashAlgorithm)), "UnableToAcquireHashAlgorithmContext", ErrorCategory.InvalidOperation, null); - _cmdlet.ThrowTerminatingError(errorRecord); + catAdmin = WinTrustMethods.CryptCATAdminAcquireContext2(hashAlgorithm); } + catch (Win32Exception e) + { + ErrorRecord errorRecord = new ErrorRecord( + new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToAcquireHashAlgorithmContext, hashAlgorithm), e), + "UnableToAcquireHashAlgorithmContext", + ErrorCategory.InvalidOperation, + null); + _cmdlet.ThrowTerminatingError(errorRecord); - const DWORD GENERIC_READ = 0x80000000; - const DWORD OPEN_EXISTING = 3; - IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); + // The method returns an empty string on a failure. + return hashValue; + } // Open the file that is to be hashed for reading and get its handle - IntPtr fileHandle = NativeMethods.CreateFile(filePath, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, IntPtr.Zero); - if (fileHandle != INVALID_HANDLE_VALUE) + FileStream fileStream; + try { - try - { - DWORD hashBufferSize = 0; - IntPtr hashBuffer = IntPtr.Zero; - - // Call first time to get the size of expected buffer to hold new hash value - if (!NativeMethods.CryptCATAdminCalcHashFromFileHandle2(catAdmin, fileHandle, ref hashBufferSize, hashBuffer, 0)) - { - ErrorRecord errorRecord = new ErrorRecord(new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToCreateFileHash, filePath)), "UnableToCreateFileHash", ErrorCategory.InvalidOperation, null); - _cmdlet.ThrowTerminatingError(errorRecord); - } - - int size = (int)hashBufferSize; - hashBuffer = Marshal.AllocHGlobal(size); - try - { - // Call second time to actually get the hash value - if (!NativeMethods.CryptCATAdminCalcHashFromFileHandle2(catAdmin, fileHandle, ref hashBufferSize, hashBuffer, 0)) - { - ErrorRecord errorRecord = new ErrorRecord(new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToCreateFileHash, filePath)), "UnableToCreateFileHash", ErrorCategory.InvalidOperation, null); - _cmdlet.ThrowTerminatingError(errorRecord); - } - - byte[] hashBytes = new byte[size]; - Marshal.Copy(hashBuffer, hashBytes, 0, size); - hashValue = BitConverter.ToString(hashBytes).Replace("-", string.Empty); - } - finally - { - if (hashBuffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(hashBuffer); - } - } - } - finally - { - NativeMethods.CryptCATAdminReleaseContext(catAdmin, 0); - NativeMethods.CloseHandle(fileHandle); - } + fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read); } - else + catch (Exception e) { // If we are not able to open file that is to be hashed we can not continue with catalog validation - ErrorRecord errorRecord = new ErrorRecord(new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToReadFileToHash, filePath)), "UnableToReadFileToHash", ErrorCategory.InvalidOperation, null); + ErrorRecord errorRecord = new ErrorRecord( + new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToReadFileToHash, filePath), e), + "UnableToReadFileToHash", + ErrorCategory.InvalidOperation, + null); _cmdlet.ThrowTerminatingError(errorRecord); + + // The method returns an empty string on a failure. + return hashValue; + } + + using (catAdmin) + using (fileStream) + { + byte[] hashBytes = Array.Empty(); + try + { + hashBytes = WinTrustMethods.CryptCATAdminCalcHashFromFileHandle2(catAdmin, fileStream.SafeFileHandle); + } + catch (Win32Exception e) + { + ErrorRecord errorRecord = new ErrorRecord( + new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToCreateFileHash, filePath), e), + "UnableToCreateFileHash", + ErrorCategory.InvalidOperation, + null); + _cmdlet.ThrowTerminatingError(errorRecord); + } + + hashValue = BitConverter.ToString(hashBytes).Replace("-", string.Empty); } return hashValue; @@ -477,90 +472,92 @@ namespace System.Management.Automation /// Dictionary mapping files relative paths to HashValues. internal static Dictionary GetHashesFromCatalog(string catalogFilePath, WildcardPattern[] excludedPatterns, out int catalogVersion) { - IntPtr resultCatalog = NativeMethods.CryptCATOpen(catalogFilePath, 0, IntPtr.Zero, 1, 0); - IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); Dictionary catalogHashes = new Dictionary(StringComparer.CurrentCultureIgnoreCase); catalogVersion = 0; - if (resultCatalog != INVALID_HANDLE_VALUE) + SafeCATHandle resultCatalog; + try { - try + resultCatalog = WinTrustMethods.CryptCATOpen(catalogFilePath, 0, IntPtr.Zero, 1, 0); + } + catch (Win32Exception e) + { + ErrorRecord errorRecord = new ErrorRecord( + new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToOpenCatalogFile, catalogFilePath), e), + "UnableToOpenCatalogFile", + ErrorCategory.InvalidOperation, + null); + _cmdlet.ThrowTerminatingError(errorRecord); + return catalogHashes; + } + + using (resultCatalog) + { + IntPtr catAttrInfo = IntPtr.Zero; + + // First traverse all catalog level attributes to get information about zero size file. + do { - IntPtr catAttrInfo = IntPtr.Zero; + catAttrInfo = WinTrustMethods.CryptCATEnumerateCatAttr(resultCatalog, catAttrInfo); - // First traverse all catalog level attributes to get information about zero size file. - do + // If we found attribute it is a file information retrieve its relative path + // and add it to catalog hash collection if its not in excluded files criteria + if (catAttrInfo != IntPtr.Zero) { - catAttrInfo = NativeMethods.CryptCATEnumerateCatAttr(resultCatalog, catAttrInfo); - - // If we found attribute it is a file information retrieve its relative path - // and add it to catalog hash collection if its not in excluded files criteria - if (catAttrInfo != IntPtr.Zero) + string relativePath = ProcessFilePathAttributeInCatalog(catAttrInfo); + if (!string.IsNullOrEmpty(relativePath)) { - string relativePath = ProcessFilePathAttributeInCatalog(catAttrInfo); - if (!string.IsNullOrEmpty(relativePath)) - { - ProcessCatalogFile(relativePath, string.Empty, excludedPatterns, ref catalogHashes); - } + ProcessCatalogFile(relativePath, string.Empty, excludedPatterns, ref catalogHashes); } - } while (catAttrInfo != IntPtr.Zero); + } + } while (catAttrInfo != IntPtr.Zero); - catalogVersion = GetCatalogVersion(resultCatalog); + catalogVersion = GetCatalogVersion(resultCatalog); - IntPtr memberInfo = IntPtr.Zero; - // Next Navigate all members in Catalog files and get their relative paths and hashes - do + IntPtr memberInfo = IntPtr.Zero; + // Next Navigate all members in Catalog files and get their relative paths and hashes + do + { + memberInfo = WinTrustMethods.CryptCATEnumerateMember(resultCatalog, memberInfo); + if (memberInfo != IntPtr.Zero) { - memberInfo = NativeMethods.CryptCATEnumerateMember(resultCatalog, memberInfo); - if (memberInfo != IntPtr.Zero) + WinTrustMethods.CRYPTCATMEMBER currentMember = Marshal.PtrToStructure(memberInfo); + WinTrustMethods.SIP_INDIRECT_DATA pIndirectData = Marshal.PtrToStructure(currentMember.pIndirectData); + + // For Catalog version 2 CryptoAPI puts hashes of file attributes(relative path in our case) in Catalog as well + // We validate those along with file hashes so we are skipping duplicate entries + if (!((catalogVersion == 2) && (pIndirectData.DigestAlgorithm.pszObjId.Equals(new Oid("SHA1").Value, StringComparison.OrdinalIgnoreCase)))) { - NativeMethods.CRYPTCATMEMBER currentMember = Marshal.PtrToStructure(memberInfo); - NativeMethods.SIP_INDIRECT_DATA pIndirectData = Marshal.PtrToStructure(currentMember.pIndirectData); - - // For Catalog version 2 CryptoAPI puts hashes of file attributes(relative path in our case) in Catalog as well - // We validate those along with file hashes so we are skipping duplicate entries - if (!((catalogVersion == 2) && (pIndirectData.DigestAlgorithm.pszObjId.Equals(new Oid("SHA1").Value, StringComparison.OrdinalIgnoreCase)))) + string relativePath = string.Empty; + IntPtr memberAttrInfo = IntPtr.Zero; + do { - string relativePath = string.Empty; - IntPtr memberAttrInfo = IntPtr.Zero; - do - { - memberAttrInfo = NativeMethods.CryptCATEnumerateAttr(resultCatalog, memberInfo, memberAttrInfo); + memberAttrInfo = WinTrustMethods.CryptCATEnumerateAttr(resultCatalog, memberInfo, memberAttrInfo); - if (memberAttrInfo != IntPtr.Zero) + if (memberAttrInfo != IntPtr.Zero) + { + relativePath = ProcessFilePathAttributeInCatalog(memberAttrInfo); + if (!string.IsNullOrEmpty(relativePath)) { - relativePath = ProcessFilePathAttributeInCatalog(memberAttrInfo); - if (!string.IsNullOrEmpty(relativePath)) - { - break; - } + break; } } - while (memberAttrInfo != IntPtr.Zero); - - // If we did not find any Relative Path for the item in catalog we should quit - // This catalog must not be valid for our use as catalogs generated using New-FileCatalog - // always contains relative file Paths - if (string.IsNullOrEmpty(relativePath)) - { - ErrorRecord errorRecord = new ErrorRecord(new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToOpenCatalogFile, catalogFilePath)), "UnableToOpenCatalogFile", ErrorCategory.InvalidOperation, null); - _cmdlet.ThrowTerminatingError(errorRecord); - } - - ProcessCatalogFile(relativePath, currentMember.pwszReferenceTag, excludedPatterns, ref catalogHashes); } + while (memberAttrInfo != IntPtr.Zero); + + // If we did not find any Relative Path for the item in catalog we should quit + // This catalog must not be valid for our use as catalogs generated using New-FileCatalog + // always contains relative file Paths + if (string.IsNullOrEmpty(relativePath)) + { + ErrorRecord errorRecord = new ErrorRecord(new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToOpenCatalogFile, catalogFilePath)), "UnableToOpenCatalogFile", ErrorCategory.InvalidOperation, null); + _cmdlet.ThrowTerminatingError(errorRecord); + } + + ProcessCatalogFile(relativePath, currentMember.pwszReferenceTag, excludedPatterns, ref catalogHashes); } - } while (memberInfo != IntPtr.Zero); - } - finally - { - NativeMethods.CryptCATClose(resultCatalog); - } - } - else - { - ErrorRecord errorRecord = new ErrorRecord(new InvalidOperationException(StringUtil.Format(CatalogStrings.UnableToOpenCatalogFile, catalogFilePath)), "UnableToOpenCatalogFile", ErrorCategory.InvalidOperation, null); - _cmdlet.ThrowTerminatingError(errorRecord); + } + } while (memberInfo != IntPtr.Zero); } return catalogHashes; @@ -785,14 +782,18 @@ namespace System.Management.Automation /// /// Call back when error is thrown by catalog API's. /// - private static void ParseErrorCallback(DWORD dwErrorArea, DWORD dwLocalError, string pwszLine) + private static void ParseErrorCallback(uint dwErrorArea, uint dwLocalError, string pwszLine) { switch (dwErrorArea) { - case NativeConstants.CRYPTCAT_E_AREA_HEADER: break; - case NativeConstants.CRYPTCAT_E_AREA_MEMBER: break; - case NativeConstants.CRYPTCAT_E_AREA_ATTRIBUTE: break; - default: break; + case NativeConstants.CRYPTCAT_E_AREA_HEADER: + break; + case NativeConstants.CRYPTCAT_E_AREA_MEMBER: + break; + case NativeConstants.CRYPTCAT_E_AREA_ATTRIBUTE: + break; + default: + break; } switch (dwLocalError) @@ -815,18 +816,24 @@ namespace System.Management.Automation _cmdlet.ThrowTerminatingError(errorRecord); break; } - case NativeConstants.CRYPTCAT_E_CDF_BAD_GUID_CONV: break; - case NativeConstants.CRYPTCAT_E_CDF_ATTR_TYPECOMBO: break; - case NativeConstants.CRYPTCAT_E_CDF_ATTR_TOOFEWVALUES: break; - case NativeConstants.CRYPTCAT_E_CDF_UNSUPPORTED: break; + case NativeConstants.CRYPTCAT_E_CDF_BAD_GUID_CONV: + break; + case NativeConstants.CRYPTCAT_E_CDF_ATTR_TYPECOMBO: + break; + case NativeConstants.CRYPTCAT_E_CDF_ATTR_TOOFEWVALUES: + break; + case NativeConstants.CRYPTCAT_E_CDF_UNSUPPORTED: + break; case NativeConstants.CRYPTCAT_E_CDF_DUPLICATE: { ErrorRecord errorRecord = new ErrorRecord(new InvalidOperationException(StringUtil.Format(CatalogStrings.FoundDuplicateFileMemberInCatalog, pwszLine)), "FoundDuplicateFileMemberInCatalog", ErrorCategory.InvalidOperation, null); _cmdlet.ThrowTerminatingError(errorRecord); break; } - case NativeConstants.CRYPTCAT_E_CDF_TAGNOTFOUND: break; - default: break; + case NativeConstants.CRYPTCAT_E_CDF_TAGNOTFOUND: + break; + default: + break; } } } diff --git a/src/System.Management.Automation/security/Win32Native/WinTrust.cs b/src/System.Management.Automation/security/Win32Native/WinTrust.cs new file mode 100644 index 0000000000..c3b7bb85d9 --- /dev/null +++ b/src/System.Management.Automation/security/Win32Native/WinTrust.cs @@ -0,0 +1,440 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace System.Management.Automation.Win32Native; + +internal class SafeCATAdminHandle : SafeHandle +{ + internal SafeCATAdminHandle() : base(IntPtr.Zero, true) { } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() => WinTrustMethods.CryptCATAdminReleaseContext(handle, 0); +} + +internal class SafeCATHandle : SafeHandle +{ + internal SafeCATHandle() : base(IntPtr.Zero, true) { } + + public override bool IsInvalid => handle == (IntPtr)(-1); + + protected override bool ReleaseHandle() => WinTrustMethods.CryptCATClose(handle); +} + +internal class SafeCATCDFHandle : SafeHandle +{ + internal SafeCATCDFHandle() : base(IntPtr.Zero, true) { } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() => WinTrustMethods.CryptCATCDFClose(handle); +} + +[Flags] +internal enum WinTrustUIChoice +{ + WTD_UI_ALL = 1, + WTD_UI_NONE = 2, + WTD_UI_NOBAD = 3, + WTD_UI_NOGOOD = 4 +} + +[Flags] +internal enum WinTrustUnionChoice +{ + WTD_CHOICE_FILE = 1, + WTD_CHOICE_CATALOG = 2, + WTD_CHOICE_BLOB = 3, + WTD_CHOICE_SIGNER = 4, + WTD_CHOICE_CERT = 5, +} + +[Flags] +internal enum WinTrustAction +{ + WTD_STATEACTION_IGNORE = 0x00000000, + WTD_STATEACTION_VERIFY = 0x00000001, + WTD_STATEACTION_CLOSE = 0x00000002, + WTD_STATEACTION_AUTO_CACHE = 0x00000003, + WTD_STATEACTION_AUTO_CACHE_FLUSH = 0x00000004 +} + +[Flags] +internal enum WinTrustProviderFlags +{ + WTD_PROV_FLAGS_MASK = 0x0000FFFF, + WTD_USE_IE4_TRUST_FLAG = 0x00000001, + WTD_NO_IE4_CHAIN_FLAG = 0x00000002, + WTD_NO_POLICY_USAGE_FLAG = 0x00000004, + WTD_REVOCATION_CHECK_NONE = 0x00000010, + WTD_REVOCATION_CHECK_END_CERT = 0x00000020, + WTD_REVOCATION_CHECK_CHAIN = 0x00000040, + WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x00000080, + WTD_SAFER_FLAG = 0x00000100, + WTD_HASH_ONLY_FLAG = 0x00000200, + WTD_USE_DEFAULT_OSVER_CHECK = 0x00000400, + WTD_LIFETIME_SIGNING_FLAG = 0x00000800, + WTD_CACHE_ONLY_URL_RETRIEVAL = 0x00001000 +} + +/// +/// Pinvoke methods from wintrust.dll +/// +internal static class WinTrustMethods +{ + private const string WinTrustDll = "wintrust.dll"; + + [StructLayout(LayoutKind.Sequential)] + internal struct CRYPT_ATTR_BLOB + { + public uint cbData; + public IntPtr pbData; + } + + [StructLayoutAttribute(LayoutKind.Sequential)] + internal struct CRYPT_ALGORITHM_IDENTIFIER + { + [MarshalAsAttribute(UnmanagedType.LPStr)] public string pszObjId; + public CRYPT_ATTR_BLOB Parameters; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct CRYPT_ATTRIBUTE_TYPE_VALUE + { + [MarshalAs(UnmanagedType.LPStr)] public string pszObjId; + public CRYPT_ATTR_BLOB Value; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SIP_INDIRECT_DATA + { + public CRYPT_ATTRIBUTE_TYPE_VALUE Data; + public CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm; + public CRYPT_ATTR_BLOB Digest; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct CRYPTCATMEMBER + { + public uint cbStruct; + [MarshalAs(UnmanagedType.LPWStr)] public string pwszReferenceTag; + [MarshalAs(UnmanagedType.LPWStr)] public string pwszFileName; + public Guid gSubjectType; + public uint fdwMemberFlags; + public IntPtr pIndirectData; + public uint dwCertVersion; + public uint dwReserved; + public IntPtr hReserved; + public CRYPT_ATTR_BLOB sEncodedIndirectData; + public CRYPT_ATTR_BLOB sEncodedMemberInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct CRYPTCATATTRIBUTE + { + public uint cbStruct; + [MarshalAs(UnmanagedType.LPWStr)] public string pwszReferenceTag; + public uint dwAttrTypeAndAction; + public uint cbValue; + public IntPtr pbValue; + public uint dwReserved; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct CRYPTCATSTORE + { + public uint cbStruct; + public uint dwPublicVersion; + [MarshalAs(UnmanagedType.LPWStr)] public string pwszP7File; + public IntPtr hProv; + public uint dwEncodingType; + public uint fdwStoreFlags; + public IntPtr hReserved; + public IntPtr hAttrs; + public IntPtr hCryptMsg; + public IntPtr hSorted; + } + + [StructLayoutAttribute(LayoutKind.Sequential)] + internal struct WINTRUST_DATA + { + public uint cbStruct; + public IntPtr pPolicyCallbackData; + public IntPtr pSIPClientData; + public WinTrustUIChoice dwUIChoice; + public uint fdwRevocationChecks; + public WinTrustUnionChoice dwUnionChoice; + public unsafe void* pChoice; + public WinTrustAction dwStateAction; + public IntPtr hWVTStateData; + public IntPtr pwszURLReference; + public WinTrustProviderFlags dwProvFlags; + public uint dwUIContext; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct WINTRUST_FILE_INFO + { + public uint cbStruct; + public unsafe char* pcwszFilePath; + public IntPtr hFile; + public IntPtr pgKnownSubject; + } + + [StructLayoutAttribute(LayoutKind.Sequential)] + internal struct WINTRUST_BLOB_INFO + { + public uint cbStruct; + public Guid gSubject; + public unsafe char* pcwszDisplayName; + public uint cbMemObject; + public unsafe byte* pbMemObject; + public uint cbMemSignedMsg; + public IntPtr pbMemSignedMsg; + } + + [DllImport( + WinTrustDll, + CharSet = CharSet.Unicode, + EntryPoint = "CryptCATAdminAcquireContext2", + SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool NativeCryptCATAdminAcquireContext2( + out SafeCATAdminHandle phCatAdmin, + IntPtr pgSubsystem, + [MarshalAs(UnmanagedType.LPWStr)] string pwszHashAlgorithm, + IntPtr pStrongHashPolicy, + uint dwFlags + ); + + internal static SafeCATAdminHandle CryptCATAdminAcquireContext2(string hashAlgorithm) + { + if (!NativeCryptCATAdminAcquireContext2(out var adminHandle, IntPtr.Zero, hashAlgorithm, IntPtr.Zero, 0)) + { + throw new Win32Exception(); + } + + return adminHandle; + } + + [DllImport( + WinTrustDll, + CharSet = CharSet.Unicode, + EntryPoint = "CryptCATAdminCalcHashFromFileHandle2", + SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern unsafe bool NativeCryptCATAdminCalcHashFromFileHandle2( + SafeCATAdminHandle hCatAdmin, + SafeHandle hFile, + [In, Out] ref int pcbHash, + byte* pbHash, + uint dwFlags + ); + + internal static byte[] CryptCATAdminCalcHashFromFileHandle2(SafeCATAdminHandle catAdmin, SafeHandle file) + { + unsafe + { + int hashLength = 0; + NativeCryptCATAdminCalcHashFromFileHandle2(catAdmin, file, ref hashLength, null, 0); + + byte[] hash = new byte[hashLength]; + fixed (byte* hashPtr = hash) + { + if (!NativeCryptCATAdminCalcHashFromFileHandle2(catAdmin, file, ref hashLength, hashPtr, 0)) + { + throw new Win32Exception(); + } + } + + return hash; + } + } + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool CryptCATAdminReleaseContext( + IntPtr phCatAdmin, + uint dwFlags + ); + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode, EntryPoint = "CryptCATCDFOpen")] + private static extern SafeCATCDFHandle NativeCryptCATCDFOpen( + [MarshalAs(UnmanagedType.LPWStr)] string pwszFilePath, + CryptCATCDFParseErrorCallBack pfnParseError + ); + + internal static SafeCATCDFHandle CryptCATCDFOpen(string filePath, CryptCATCDFParseErrorCallBack parseError) + { + SafeCATCDFHandle handle = NativeCryptCATCDFOpen(filePath, parseError); + if (handle.IsInvalid) + { + throw new Win32Exception(); + } + + return handle; + } + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode)] + internal static extern IntPtr CryptCATCDFEnumCatAttributes( + SafeCATCDFHandle pCDF, + IntPtr pPrevAttr, + CryptCATCDFParseErrorCallBack pfnParseError + ); + + [DllImport(WinTrustDll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool CryptCATCDFClose( + IntPtr pCDF + ); + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode)] + internal static extern IntPtr CryptCATCDFEnumMembersByCDFTagEx( + SafeCATCDFHandle pCDF, + IntPtr pwszPrevCDFTag, + CryptCATCDFParseErrorCallBack fn, + ref IntPtr ppMember, + bool fContinueOnError, + IntPtr pvReserved + ); + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode)] + internal static extern IntPtr CryptCATCDFEnumAttributesWithCDFTag( + SafeCATCDFHandle pCDF, + IntPtr pwszMemberTag, + IntPtr pMember, + IntPtr pPrevAttr, + CryptCATCDFParseErrorCallBack fn + ); + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode)] + internal static extern IntPtr CryptCATEnumerateCatAttr( + SafeCATHandle hCatalog, + IntPtr pPrevAttr + ); + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode, EntryPoint = "CryptCATOpen", SetLastError = true)] + internal static extern SafeCATHandle NativeCryptCATOpen( + [MarshalAs(UnmanagedType.LPWStr)] string pwszFilePath, + uint fdwOpenFlags, + IntPtr hProv, + uint dwPublicVersion, + uint dwEncodingType + ); + + internal static SafeCATHandle CryptCATOpen(string filePath, uint openFlags, IntPtr provider, uint publicVersion, + uint encodingType) + { + SafeCATHandle handle = NativeCryptCATOpen(filePath, openFlags, provider, publicVersion, encodingType); + if (handle.IsInvalid) + { + throw new Win32Exception(); + } + + return handle; + } + + [DllImport(WinTrustDll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool CryptCATClose( + IntPtr hCatalog + ); + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode, EntryPoint = "CryptCATStoreFromHandle")] + private static extern IntPtr NativeCryptCATStoreFromHandle( + SafeCATHandle hCatalog + ); + + internal static CRYPTCATSTORE CryptCATStoreFromHandle(SafeCATHandle catalog) + { + IntPtr catStore = NativeCryptCATStoreFromHandle(catalog); + return Marshal.PtrToStructure(catStore); + } + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode)] + internal static extern IntPtr CryptCATEnumerateMember( + SafeCATHandle hCatalog, + IntPtr pPrevMember + ); + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode)] + internal static extern IntPtr CryptCATEnumerateAttr( + SafeCATHandle hCatalog, + IntPtr pCatMember, + IntPtr pPrevAttr + ); + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode)] + internal static extern uint WinVerifyTrust( + IntPtr hWnd, + ref Guid pgActionID, + ref WINTRUST_DATA pWVTData + ); + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode, EntryPoint = "WTHelperGetProvCertFromChain")] + private static extern IntPtr NativeWTHelperGetProvCertFromChain( + IntPtr pSgnr, + uint idxCert + ); + + internal static IntPtr WTHelperGetProvCertFromChain(IntPtr signer, uint certIdx) + { + IntPtr data = NativeWTHelperGetProvCertFromChain(signer, certIdx); + if (data == IntPtr.Zero) + { + throw new Win32Exception("WTHelperGetProvCertFromChain failed"); + } + + return data; + } + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode, EntryPoint = "WTHelperGetProvSignerFromChain")] + private static extern IntPtr NativeWTHelperGetProvSignerFromChain( + IntPtr pProvData, + uint idxSigner, + bool fCounterSigner, + uint idxCounterSigner + ); + + internal static IntPtr WTHelperGetProvSignerFromChain(IntPtr providerData, uint signerIdx, bool counterSigner, + uint counterSignerIdx) + { + IntPtr data = NativeWTHelperGetProvSignerFromChain(providerData, signerIdx, counterSigner, counterSignerIdx); + if (data == IntPtr.Zero) + { + throw new Win32Exception("WTHelperGetProvSignerFromChain failed"); + } + + return data; + } + + [DllImport(WinTrustDll, CharSet = CharSet.Unicode, EntryPoint = "WTHelperProvDataFromStateData")] + private static extern IntPtr NativeWTHelperProvDataFromStateData( + IntPtr hStateData + ); + + internal static IntPtr WTHelperProvDataFromStateData(IntPtr stateData) + { + IntPtr data = NativeWTHelperProvDataFromStateData(stateData); + if (data == IntPtr.Zero) + { + throw new Win32Exception("WTHelperProvDataFromStateData failed"); + } + + return data; + } + + /// + /// Signature of call back function used by CryptCATCDFOpen, + /// CryptCATCDFEnumCatAttributes, CryptCATCDFEnumAttributesWithCDFTag, and + /// and CryptCATCDFEnumMembersByCDFTagEx. + /// + internal delegate void CryptCATCDFParseErrorCallBack( + uint dwErrorArea, + uint dwLocalArea, + [MarshalAs(UnmanagedType.LPWStr)] string pwszLine + ); +} diff --git a/src/System.Management.Automation/security/nativeMethods.cs b/src/System.Management.Automation/security/nativeMethods.cs index 69ed655963..782b6f4339 100644 --- a/src/System.Management.Automation/security/nativeMethods.cs +++ b/src/System.Management.Automation/security/nativeMethods.cs @@ -779,312 +779,6 @@ namespace System.Management.Automation.Security return si; } - // ----------------------------------------------------------------- - // wintrust.dll stuff - // - - // - // WinVerifyTrust() function and associated structures/enums - // - - [DllImport("wintrust.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern - DWORD WinVerifyTrust( - IntPtr hWndNotUsed, // HWND - IntPtr pgActionID, // GUID* - IntPtr pWinTrustData // WINTRUST_DATA* - ); - - [StructLayout(LayoutKind.Sequential)] - internal struct WINTRUST_FILE_INFO - { - internal DWORD cbStruct; // = sizeof(WINTRUST_FILE_INFO) - - [MarshalAs(UnmanagedType.LPWStr)] - internal string pcwszFilePath; // LPCWSTR - - internal IntPtr hFileNotUsed; // optional, HANDLE to pcwszFilePath - internal IntPtr pgKnownSubjectNotUsed; // optional: GUID* : fill if the - // subject type is known - } - - [StructLayoutAttribute(LayoutKind.Sequential)] - internal struct WINTRUST_BLOB_INFO - { - /// DWORD->unsigned int - internal uint cbStruct; - - /// GUID->_GUID - internal Guid gSubject; - - /// LPCWSTR->WCHAR* - [MarshalAsAttribute(UnmanagedType.LPWStr)] - internal string pcwszDisplayName; - - /// DWORD->unsigned int - internal uint cbMemObject; - - /// BYTE* - internal System.IntPtr pbMemObject; - - /// DWORD->unsigned int - internal uint cbMemSignedMsg; - - /// BYTE* - internal System.IntPtr pbMemSignedMsg; - } - - [ArchitectureSensitive] - internal static WINTRUST_FILE_INFO InitWintrustFileInfoStruct(string fileName) - { - WINTRUST_FILE_INFO fi = new WINTRUST_FILE_INFO(); - - fi.cbStruct = (DWORD)Marshal.SizeOf(fi); - fi.pcwszFilePath = fileName; - fi.hFileNotUsed = IntPtr.Zero; - fi.pgKnownSubjectNotUsed = IntPtr.Zero; - - return fi; - } - - [ArchitectureSensitive] - internal static WINTRUST_BLOB_INFO InitWintrustBlobInfoStruct(string fileName, string content) - { - WINTRUST_BLOB_INFO bi = new WINTRUST_BLOB_INFO(); - byte[] contentBytes = System.Text.Encoding.Unicode.GetBytes(content); - - // The GUID of the PowerShell SIP - bi.gSubject = new Guid(0x603bcc1f, 0x4b59, 0x4e08, new byte[] { 0xb7, 0x24, 0xd2, 0xc6, 0x29, 0x7e, 0xf3, 0x51 }); - bi.cbStruct = (DWORD)Marshal.SizeOf(bi); - bi.pcwszDisplayName = fileName; - bi.cbMemObject = (uint)contentBytes.Length; - bi.pbMemObject = Marshal.AllocCoTaskMem(contentBytes.Length); - Marshal.Copy(contentBytes, 0, bi.pbMemObject, contentBytes.Length); - - return bi; - } - - [Flags] - internal enum WintrustUIChoice - { - WTD_UI_ALL = 1, - WTD_UI_NONE = 2, - WTD_UI_NOBAD = 3, - WTD_UI_NOGOOD = 4 - } - - [Flags] - internal enum WintrustUnionChoice - { - WTD_CHOICE_FILE = 1, - // WTD_CHOICE_CATALOG = 2, - WTD_CHOICE_BLOB = 3, - // WTD_CHOICE_SIGNER = 4, - // WTD_CHOICE_CERT = 5, - } - - [Flags] - internal enum WintrustProviderFlags - { - WTD_PROV_FLAGS_MASK = 0x0000FFFF, - WTD_USE_IE4_TRUST_FLAG = 0x00000001, - WTD_NO_IE4_CHAIN_FLAG = 0x00000002, - WTD_NO_POLICY_USAGE_FLAG = 0x00000004, - WTD_REVOCATION_CHECK_NONE = 0x00000010, - WTD_REVOCATION_CHECK_END_CERT = 0x00000020, - WTD_REVOCATION_CHECK_CHAIN = 0x00000040, - WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x00000080, - WTD_SAFER_FLAG = 0x00000100, - WTD_HASH_ONLY_FLAG = 0x00000200, - WTD_USE_DEFAULT_OSVER_CHECK = 0x00000400, - WTD_LIFETIME_SIGNING_FLAG = 0x00000800, - WTD_CACHE_ONLY_URL_RETRIEVAL = 0x00001000 - } - - [Flags] - internal enum WintrustAction - { - WTD_STATEACTION_IGNORE = 0x00000000, - WTD_STATEACTION_VERIFY = 0x00000001, - WTD_STATEACTION_CLOSE = 0x00000002, - WTD_STATEACTION_AUTO_CACHE = 0x00000003, - WTD_STATEACTION_AUTO_CACHE_FLUSH = 0x00000004 - } - - [StructLayoutAttribute(LayoutKind.Explicit)] - internal struct WinTrust_Choice - { - /// WINTRUST_FILE_INFO_* - [FieldOffsetAttribute(0)] - internal System.IntPtr pFile; - - /// WINTRUST_CATALOG_INFO_* - [FieldOffsetAttribute(0)] - internal System.IntPtr pCatalog; - - /// WINTRUST_BLOB_INFO_* - [FieldOffsetAttribute(0)] - internal System.IntPtr pBlob; - - /// WINTRUST_SGNR_INFO_* - [FieldOffsetAttribute(0)] - internal System.IntPtr pSgnr; - - /// WINTRUST_CERT_INFO_* - [FieldOffsetAttribute(0)] - internal System.IntPtr pCert; - } - - [StructLayoutAttribute(LayoutKind.Sequential)] - internal struct WINTRUST_DATA - { - /// DWORD->unsigned int - internal uint cbStruct; - - /// LPVOID->void* - internal System.IntPtr pPolicyCallbackData; - - /// LPVOID->void* - internal System.IntPtr pSIPClientData; - - /// DWORD->unsigned int - internal uint dwUIChoice; - - /// DWORD->unsigned int - internal uint fdwRevocationChecks; - - /// DWORD->unsigned int - internal uint dwUnionChoice; - - /// WinTrust_Choice struct - internal WinTrust_Choice Choice; - - /// DWORD->unsigned int - internal uint dwStateAction; - - /// HANDLE->void* - internal System.IntPtr hWVTStateData; - - /// WCHAR* - [MarshalAsAttribute(UnmanagedType.LPWStr)] - internal string pwszURLReference; - - /// DWORD->unsigned int - internal uint dwProvFlags; - - /// DWORD->unsigned int - internal uint dwUIContext; - } - - [ArchitectureSensitive] - internal static WINTRUST_DATA InitWintrustDataStructFromFile(WINTRUST_FILE_INFO wfi) - { - WINTRUST_DATA wtd = new WINTRUST_DATA(); - - wtd.cbStruct = (DWORD)Marshal.SizeOf(wtd); - wtd.pPolicyCallbackData = IntPtr.Zero; - wtd.pSIPClientData = IntPtr.Zero; - wtd.dwUIChoice = (DWORD)WintrustUIChoice.WTD_UI_NONE; - wtd.fdwRevocationChecks = 0; - wtd.dwUnionChoice = (DWORD)WintrustUnionChoice.WTD_CHOICE_FILE; - - IntPtr pFileBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(wfi)); - Marshal.StructureToPtr(wfi, pFileBuffer, false); - wtd.Choice.pFile = pFileBuffer; - - wtd.dwStateAction = (DWORD)WintrustAction.WTD_STATEACTION_VERIFY; - wtd.hWVTStateData = IntPtr.Zero; - wtd.pwszURLReference = null; - wtd.dwProvFlags = 0; - - return wtd; - } - - [ArchitectureSensitive] - internal static WINTRUST_DATA InitWintrustDataStructFromBlob(WINTRUST_BLOB_INFO wbi) - { - WINTRUST_DATA wtd = new WINTRUST_DATA(); - - wtd.cbStruct = (DWORD)Marshal.SizeOf(wbi); - wtd.pPolicyCallbackData = IntPtr.Zero; - wtd.pSIPClientData = IntPtr.Zero; - wtd.dwUIChoice = (DWORD)WintrustUIChoice.WTD_UI_NONE; - wtd.fdwRevocationChecks = 0; - wtd.dwUnionChoice = (DWORD)WintrustUnionChoice.WTD_CHOICE_BLOB; - - IntPtr pBlob = Marshal.AllocCoTaskMem(Marshal.SizeOf(wbi)); - Marshal.StructureToPtr(wbi, pBlob, false); - wtd.Choice.pBlob = pBlob; - - wtd.dwStateAction = (DWORD)WintrustAction.WTD_STATEACTION_VERIFY; - wtd.hWVTStateData = IntPtr.Zero; - wtd.pwszURLReference = null; - wtd.dwProvFlags = 0; - - return wtd; - } - - [ArchitectureSensitive] - internal static DWORD DestroyWintrustDataStruct(WINTRUST_DATA wtd) - { - DWORD dwResult = Win32Errors.E_FAIL; - IntPtr WINTRUST_ACTION_GENERIC_VERIFY_V2 = IntPtr.Zero; - IntPtr wtdBuffer = IntPtr.Zero; - - Guid actionVerify = - new Guid("00AAC56B-CD44-11d0-8CC2-00C04FC295EE"); - - try - { - WINTRUST_ACTION_GENERIC_VERIFY_V2 = - Marshal.AllocCoTaskMem(Marshal.SizeOf(actionVerify)); - Marshal.StructureToPtr(actionVerify, - WINTRUST_ACTION_GENERIC_VERIFY_V2, - false); - - wtd.dwStateAction = (DWORD)WintrustAction.WTD_STATEACTION_CLOSE; - wtdBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(wtd)); - Marshal.StructureToPtr(wtd, wtdBuffer, false); - - // The GetLastWin32Error of this is checked, but PreSharp doesn't seem to be - // able to see that. -#pragma warning disable 56523 - dwResult = WinVerifyTrust( - IntPtr.Zero, - WINTRUST_ACTION_GENERIC_VERIFY_V2, - wtdBuffer); -#pragma warning restore 56523 - - wtd = Marshal.PtrToStructure(wtdBuffer); - } - finally - { - Marshal.DestroyStructure(wtdBuffer); - Marshal.FreeCoTaskMem(wtdBuffer); - Marshal.DestroyStructure(WINTRUST_ACTION_GENERIC_VERIFY_V2); - Marshal.FreeCoTaskMem(WINTRUST_ACTION_GENERIC_VERIFY_V2); - } - - // Clear the blob or file info, depending on the type of - // verification that was done. - if (wtd.dwUnionChoice == (DWORD)WintrustUnionChoice.WTD_CHOICE_BLOB) - { - WINTRUST_BLOB_INFO originalBlob = - (WINTRUST_BLOB_INFO)Marshal.PtrToStructure(wtd.Choice.pBlob); - Marshal.FreeCoTaskMem(originalBlob.pbMemObject); - - Marshal.DestroyStructure(wtd.Choice.pBlob); - Marshal.FreeCoTaskMem(wtd.Choice.pBlob); - } - else - { - Marshal.DestroyStructure(wtd.Choice.pFile); - Marshal.FreeCoTaskMem(wtd.Choice.pFile); - } - - return dwResult; - } - [StructLayout(LayoutKind.Sequential)] internal struct CRYPT_PROVIDER_CERT { @@ -1122,29 +816,6 @@ namespace System.Management.Automation.Security private readonly IntPtr _pChainContext; // PCCERT_CHAIN_CONTEXT } - [DllImport("wintrust.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern - IntPtr // CRYPT_PROVIDER_DATA* - WTHelperProvDataFromStateData(IntPtr hStateData); - - [DllImport("wintrust.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern - IntPtr // CRYPT_PROVIDER_SGNR* - WTHelperGetProvSignerFromChain( - IntPtr pProvData, // CRYPT_PROVIDER_DATA* - DWORD idxSigner, - BOOL fCounterSigner, - DWORD idxCounterSigner - ); - - [DllImport("wintrust.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern - IntPtr // CRYPT_PROVIDER_CERT* - WTHelperGetProvCertFromChain( - IntPtr pSgnr, // CRYPT_PROVIDER_SGNR* - DWORD idxCert - ); - // // stuff required for getting cert extensions // @@ -1799,42 +1470,6 @@ namespace System.Management.Automation.Security internal const uint LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400; internal const uint LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800; internal const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000; - - [DllImport(PinvokeDllNames.LoadLibraryEx, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern IntPtr LoadLibraryExW( - string DllName, - IntPtr reserved, - uint Flags); - - [DllImport(PinvokeDllNames.FreeLibrary, CharSet = CharSet.Unicode, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool FreeLibrary( - IntPtr Module); - - internal static bool IsSystem32DllPresent(string DllName) - { - bool DllExists = false; - - try - { - IntPtr module = LoadLibraryExW( - DllName, - IntPtr.Zero, - NativeMethods.LOAD_LIBRARY_AS_DATAFILE | - NativeMethods.LOAD_LIBRARY_AS_IMAGE_RESOURCE | - NativeMethods.LOAD_LIBRARY_SEARCH_SYSTEM32); - if (module != IntPtr.Zero) - { - FreeLibrary(module); - DllExists = true; - } - } - catch (Exception) - { - } - - return DllExists; - } } // Constants needed for Catalog Error Handling @@ -1876,234 +1511,6 @@ namespace System.Management.Automation.Security // CRYPTCAT_E_CDF_ATTR_TYPECOMBO = "0x00020004"; public const int CRYPTCAT_E_CDF_ATTR_TYPECOMBO = 131076; } - - /// - /// Pinvoke methods from wintrust.dll - /// These are added to Generate and Validate Window Catalog Files. - /// - internal static partial class NativeMethods - { - [StructLayout(LayoutKind.Sequential)] - internal struct CRYPT_ATTRIBUTE_TYPE_VALUE - { - [MarshalAs(UnmanagedType.LPStr)] - internal string pszObjId; - - internal CRYPT_ATTR_BLOB Value; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SIP_INDIRECT_DATA - { - internal CRYPT_ATTRIBUTE_TYPE_VALUE Data; - internal CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm; - internal CRYPT_ATTR_BLOB Digest; - } - - [StructLayout(LayoutKind.Sequential)] - internal readonly struct CRYPTCATCDF - { - private readonly DWORD _cbStruct; - private readonly IntPtr _hFile; - private readonly DWORD _dwCurFilePos; - private readonly DWORD _dwLastMemberOffset; - private readonly BOOL _fEOF; - - [MarshalAs(UnmanagedType.LPWStr)] - private readonly string _pwszResultDir; - - private readonly IntPtr _hCATStore; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct CRYPTCATMEMBER - { - internal DWORD cbStruct; - - [MarshalAs(UnmanagedType.LPWStr)] - internal string pwszReferenceTag; - - [MarshalAs(UnmanagedType.LPWStr)] - internal string pwszFileName; - - internal Guid gSubjectType; - internal DWORD fdwMemberFlags; - internal IntPtr pIndirectData; - internal DWORD dwCertVersion; - internal DWORD dwReserved; - internal IntPtr hReserved; - internal CRYPT_ATTR_BLOB sEncodedIndirectData; - internal CRYPT_ATTR_BLOB sEncodedMemberInfo; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct CRYPTCATATTRIBUTE - { - private readonly DWORD _cbStruct; - - [MarshalAs(UnmanagedType.LPWStr)] - internal string pwszReferenceTag; - - private readonly DWORD _dwAttrTypeAndAction; - internal DWORD cbValue; - internal System.IntPtr pbValue; - private readonly DWORD _dwReserved; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct CRYPTCATSTORE - { - private readonly DWORD _cbStruct; - internal DWORD dwPublicVersion; - - [MarshalAs(UnmanagedType.LPWStr)] - internal string pwszP7File; - - private readonly IntPtr _hProv; - private readonly DWORD _dwEncodingType; - private readonly DWORD _fdwStoreFlags; - private readonly IntPtr _hReserved; - private readonly IntPtr _hAttrs; - private readonly IntPtr _hCryptMsg; - private readonly IntPtr _hSorted; - } - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr CryptCATCDFOpen( - [MarshalAs(UnmanagedType.LPWStr)] - string pwszFilePath, - CryptCATCDFOpenCallBack pfnParseError - ); - - [DllImport("wintrust.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CryptCATCDFClose( - IntPtr pCDF - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr CryptCATCDFEnumCatAttributes( - IntPtr pCDF, - IntPtr pPrevAttr, - CryptCATCDFOpenCallBack pfnParseError - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr CryptCATCDFEnumMembersByCDFTagEx( - IntPtr pCDF, - IntPtr pwszPrevCDFTag, - CryptCATCDFEnumMembersByCDFTagExErrorCallBack fn, - ref IntPtr ppMember, - bool fContinueOnError, - IntPtr pvReserved - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr CryptCATCDFEnumAttributesWithCDFTag( - IntPtr pCDF, - IntPtr pwszMemberTag, - IntPtr pMember, - IntPtr pPrevAttr, - CryptCATCDFEnumMembersByCDFTagExErrorCallBack fn - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr CryptCATOpen( - [MarshalAs(UnmanagedType.LPWStr)] - string pwszFilePath, - DWORD fdwOpenFlags, - IntPtr hProv, - DWORD dwPublicVersion, - DWORD dwEncodingType - ); - - [DllImport("wintrust.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CryptCATClose( - IntPtr hCatalog - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr CryptCATStoreFromHandle( - IntPtr hCatalog - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CryptCATAdminAcquireContext2( - ref IntPtr phCatAdmin, - IntPtr pgSubsystem, - [MarshalAs(UnmanagedType.LPWStr)] - string pwszHashAlgorithm, - IntPtr pStrongHashPolicy, - DWORD dwFlags - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CryptCATAdminReleaseContext( - IntPtr phCatAdmin, - DWORD dwFlags - ); - - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern unsafe IntPtr CreateFile( - string lpFileName, - DWORD dwDesiredAccess, - DWORD dwShareMode, - DWORD lpSecurityAttributes, - DWORD dwCreationDisposition, - DWORD dwFlagsAndAttributes, - IntPtr hTemplateFile - ); - - [DllImport("wintrust.dll", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CryptCATAdminCalcHashFromFileHandle2( - IntPtr hCatAdmin, - IntPtr hFile, - [In, Out] ref DWORD pcbHash, - IntPtr pbHash, - DWORD dwFlags - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr CryptCATEnumerateCatAttr( - IntPtr hCatalog, - IntPtr pPrevAttr - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr CryptCATEnumerateMember( - IntPtr hCatalog, - IntPtr pPrevMember - ); - - [DllImport("wintrust.dll", CharSet = CharSet.Unicode)] - internal static extern IntPtr CryptCATEnumerateAttr( - IntPtr hCatalog, - IntPtr pCatMember, - IntPtr pPrevAttr - ); - - /// - /// Signature of call back function used by CryptCATCDFOpen. - /// - internal delegate - void CryptCATCDFOpenCallBack(DWORD NotUsedDWORD1, - DWORD NotUsedDWORD2, - [MarshalAs(UnmanagedType.LPWStr)] - string NotUsedString); - - /// - /// Signature of call back function used by CryptCATCDFEnumMembersByCDFTagEx. - /// - internal delegate - void CryptCATCDFEnumMembersByCDFTagExErrorCallBack(DWORD NotUsedDWORD1, - DWORD NotUsedDWORD2, - [MarshalAs(UnmanagedType.LPWStr)] - string NotUsedString); - } } #pragma warning restore 56523