Migrate WinTrust functions to a common location (#17598)

This commit is contained in:
Jordan Borean
2022-08-08 15:49:29 -07:00
committed by GitHub
parent 2eed0f5f0a
commit 135e94d6cb
4 changed files with 718 additions and 867 deletions
@@ -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
/// </summary>
internal static class SignatureHelper
{
private static Guid WINTRUST_ACTION_GENERIC_VERIFY_V2 = new Guid("00AAC56B-CD44-11d0-8CC2-00C04FC295EE");
/// <summary>
/// Tracer for SignatureHelper.
/// </summary>
@@ -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<WinTrustMethods.WINTRUST_DATA>(),
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<NativeMethods.WINTRUST_DATA>(wtdBuffer);
}
finally
byte[] contentBytes = fileContent == null
? Array.Empty<byte>()
: System.Text.Encoding.Unicode.GetBytes(fileContent);
unsafe
{
Marshal.DestroyStructure<Guid>(WINTRUST_ACTION_GENERIC_VERIFY_V2);
Marshal.FreeCoTaskMem(WINTRUST_ACTION_GENERIC_VERIFY_V2);
Marshal.DestroyStructure<NativeMethods.WINTRUST_DATA>(wtdBuffer);
Marshal.FreeCoTaskMem(wtdBuffer);
}
fixed (char* fileNamePtr = fileName)
{
if (fileContent == null)
{
WinTrustMethods.WINTRUST_FILE_INFO wfi = new()
{
cbStruct = (uint)Marshal.SizeOf<WinTrustMethods.WINTRUST_FILE_INFO>(),
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<WinTrustMethods.WINTRUST_BLOB_INFO>(),
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<NativeMethods.CRYPT_PROVIDER_CERT>(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<NativeMethods.CRYPT_PROVIDER_SGNR>(pProvSigner);
if (provSigner.csCounterSigners == 1)
{
NativeMethods.CRYPT_PROVIDER_SGNR provSigner =
Marshal.PtrToStructure<NativeMethods.CRYPT_PROVIDER_SGNR>(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();
@@ -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
/// </summary>
/// <param name="catalogHandle">Handle to open catalog file.</param>
/// <returns>Version of the catalog.</returns>
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<NativeMethods.CRYPTCATSTORE>(catalogData);
WinTrustMethods.CRYPTCATSTORE catalogInfo = WinTrustMethods.CryptCATStoreFromHandle(catalogHandle);
if (catalogInfo.dwPublicVersion == catalogVersion2)
{
@@ -248,20 +248,32 @@ namespace System.Management.Automation
/// <param name="cdfFilePath">Path to the Input .cdf file.</param>
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 <Hash> 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 <Hash> 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<NativeMethods.CRYPTCATATTRIBUTE>(memberAttrInfo);
WinTrustMethods.CRYPTCATATTRIBUTE currentMemberAttr = Marshal.PtrToStructure<WinTrustMethods.CRYPTCATATTRIBUTE>(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<byte>();
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
/// <returns>Dictionary mapping files relative paths to HashValues.</returns>
internal static Dictionary<string, string> 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<string, string> catalogHashes = new Dictionary<string, string>(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<WinTrustMethods.CRYPTCATMEMBER>(memberInfo);
WinTrustMethods.SIP_INDIRECT_DATA pIndirectData = Marshal.PtrToStructure<WinTrustMethods.SIP_INDIRECT_DATA>(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<NativeMethods.CRYPTCATMEMBER>(memberInfo);
NativeMethods.SIP_INDIRECT_DATA pIndirectData = Marshal.PtrToStructure<NativeMethods.SIP_INDIRECT_DATA>(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
/// <summary>
/// Call back when error is thrown by catalog API's.
/// </summary>
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;
}
}
}
@@ -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
}
/// <summary>
/// Pinvoke methods from wintrust.dll
/// </summary>
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<CRYPTCATSTORE>(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;
}
/// <summary>
/// Signature of call back function used by CryptCATCDFOpen,
/// CryptCATCDFEnumCatAttributes, CryptCATCDFEnumAttributesWithCDFTag, and
/// and CryptCATCDFEnumMembersByCDFTagEx.
/// </summary>
internal delegate void CryptCATCDFParseErrorCallBack(
uint dwErrorArea,
uint dwLocalArea,
[MarshalAs(UnmanagedType.LPWStr)] string pwszLine
);
}
@@ -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<WINTRUST_DATA>(wtdBuffer);
}
finally
{
Marshal.DestroyStructure<WINTRUST_DATA>(wtdBuffer);
Marshal.FreeCoTaskMem(wtdBuffer);
Marshal.DestroyStructure<Guid>(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<WINTRUST_BLOB_INFO>(wtd.Choice.pBlob);
Marshal.FreeCoTaskMem(originalBlob.pbMemObject);
Marshal.DestroyStructure<WINTRUST_BLOB_INFO>(wtd.Choice.pBlob);
Marshal.FreeCoTaskMem(wtd.Choice.pBlob);
}
else
{
Marshal.DestroyStructure<WINTRUST_FILE_INFO>(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;
}
/// <summary>
/// Pinvoke methods from wintrust.dll
/// These are added to Generate and Validate Window Catalog Files.
/// </summary>
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
);
/// <summary>
/// Signature of call back function used by CryptCATCDFOpen.
/// </summary>
internal delegate
void CryptCATCDFOpenCallBack(DWORD NotUsedDWORD1,
DWORD NotUsedDWORD2,
[MarshalAs(UnmanagedType.LPWStr)]
string NotUsedString);
/// <summary>
/// Signature of call back function used by CryptCATCDFEnumMembersByCDFTagEx.
/// </summary>
internal delegate
void CryptCATCDFEnumMembersByCDFTagExErrorCallBack(DWORD NotUsedDWORD1,
DWORD NotUsedDWORD2,
[MarshalAs(UnmanagedType.LPWStr)]
string NotUsedString);
}
}
#pragma warning restore 56523