@msdn=http://search.microsoft.com/search/results.aspx?qu=$$$ @pinvoke=http://pinvoke.net/$$$.htm Summary: P/Invoke wintrust.WinVerifyTrust() function to check f.e. executable file AuthentiCode digital signature !!!!C# Signature: [DllImport("wintrust.dll", ExactSpelling = true, SetLastError = false, CharSet = CharSet.Unicode)] static extern WinVerifyTrustResult WinVerifyTrust( [In] IntPtr hwnd, [In] [MarshalAs(UnmanagedType.LPStruct)] Guid pgActionID, [In] WinTrustData pWVTData ); !!!!VB Signature: Declare Function WinVerifyTrust Lib "wintrust.dll" (TODO) As TODO !!!!User-Defined Types: namespace Security.WinTrust { using System; using System.Runtime.InteropServices; #region WinTrustData struct field enums enum WinTrustDataUIChoice : uint { All = 1, None = 2, NoBad = 3, NoGood = 4 } enum WinTrustDataRevocationChecks : uint { None = 0x00000000, WholeChain = 0x00000001 } enum WinTrustDataChoice : uint { File = 1, Catalog = 2, Blob = 3, Signer = 4, Certificate = 5 } enum WinTrustDataStateAction : uint { Ignore = 0x00000000, Verify = 0x00000001, Close = 0x00000002, AutoCache = 0x00000003, AutoCacheFlush = 0x00000004 } [FlagsAttribute] enum WinTrustDataProvFlags : uint { UseIe4TrustFlag = 0x00000001, NoIe4ChainFlag = 0x00000002, NoPolicyUsageFlag = 0x00000004, RevocationCheckNone = 0x00000010, RevocationCheckEndCert = 0x00000020, RevocationCheckChain = 0x00000040, RevocationCheckChainExcludeRoot = 0x00000080, SaferFlag = 0x00000100, // Used by software restriction policies. Should not be used. HashOnlyFlag = 0x00000200, UseDefaultOsverCheck = 0x00000400, LifetimeSigningFlag = 0x00000800, CacheOnlyUrlRetrieval = 0x00001000, // affects CRL retrieval and AIA retrieval DisableMD2andMD4 = 0x00002000 // Win7 SP1+: Disallows use of MD2 or MD4 in the chain except for the root } enum WinTrustDataUIContext : uint { Execute = 0, Install = 1 } #endregion #region WinTrust structures [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] class WinTrustFileInfo { UInt32 StructSize = (UInt32)Marshal.SizeOf(typeof(WinTrustFileInfo)); IntPtr pszFilePath; // required, file name to be verified IntPtr hFile = IntPtr.Zero; // optional, open handle to FilePath IntPtr pgKnownSubject = IntPtr.Zero; // optional, subject type if it is known public WinTrustFileInfo(String _filePath) { pszFilePath = Marshal.StringToCoTaskMemAuto(_filePath); } public void Dispose() { if(pszFilePath != IntPtr.Zero) { Marshal.FreeCoTaskMem(pszFilePath); pszFilePath = IntPtr.Zero; } } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] class WinTrustData { UInt32 StructSize = (UInt32)Marshal.SizeOf(typeof(WinTrustData)); IntPtr PolicyCallbackData = IntPtr.Zero; IntPtr SIPClientData = IntPtr.Zero; // required: UI choice WinTrustDataUIChoice UIChoice = WinTrustDataUIChoice.None; // required: certificate revocation check options WinTrustDataRevocationChecks RevocationChecks = WinTrustDataRevocationChecks.None; // required: which structure is being passed in? WinTrustDataChoice UnionChoice = WinTrustDataChoice.File; // individual file IntPtr FileInfoPtr; WinTrustDataStateAction StateAction = WinTrustDataStateAction.Ignore; IntPtr StateData = IntPtr.Zero; String URLReference = null; WinTrustDataProvFlags ProvFlags = WinTrustDataProvFlags.RevocationCheckChainExcludeRoot; WinTrustDataUIContext UIContext = WinTrustDataUIContext.Execute; // constructor for silent WinTrustDataChoice.File check public WinTrustData(WinTrustFileInfo _fileInfo) { // On Win7SP1+, don't allow MD2 or MD4 signatures if ((Environment.OSVersion.Version.Major > 6) || ((Environment.OSVersion.Version.Major == 6) && (Environment.OSVersion.Version.Minor > 1)) || ((Environment.OSVersion.Version.Major == 6) && (Environment.OSVersion.Version.Minor == 1) && !String.IsNullOrEmpty(Environment.OSVersion.ServicePack))) { ProvFlags |= WinTrustDataProvFlags.DisableMD2andMD4; } WinTrustFileInfo wtfiData = _fileInfo; FileInfoPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(WinTrustFileInfo))); Marshal.StructureToPtr(wtfiData, FileInfoPtr, false); } public void Dispose() { if(FileInfoPtr != IntPtr.Zero) { Marshal.FreeCoTaskMem(FileInfoPtr); FileInfoPtr = IntPtr.Zero; } } } #endregion enum WinVerifyTrustResult : uint { Success = 0, ProviderUnknown = 0x800b0001, // Trust provider is not recognized on this system ActionUnknown = 0x800b0002, // Trust provider does not support the specified action SubjectFormUnknown = 0x800b0003, // Trust provider does not support the form specified for the subject SubjectNotTrusted = 0x800b0004, // Subject failed the specified verification action FileNotSigned = 0x800B0100, // TRUST_E_NOSIGNATURE - File was not signed SubjectExplicitlyDistrusted = 0x800B0111, // Signer's certificate is in the Untrusted Publishers store SignatureOrFileCorrupt = 0x80096010, // TRUST_E_BAD_DIGEST - file was probably corrupt SubjectCertExpired = 0x800B0101, // CERT_E_EXPIRED - Signer's certificate was expired SubjectCertificateRevoked = 0x800B010C, // CERT_E_REVOKED Subject's certificate was revoked UntrustedRoot = 0x800B0109 // CERT_E_UNTRUSTEDROOT - A certification chain processed correctly but terminated in a root certificate that is not trusted by the trust provider. } sealed class WinTrust { private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); // GUID of the action to perform private const string WINTRUST_ACTION_GENERIC_VERIFY_V2 = "{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}"; [DllImport("wintrust.dll", ExactSpelling = true, SetLastError = false, CharSet = CharSet.Unicode)] static extern WinVerifyTrustResult WinVerifyTrust( [In] IntPtr hwnd, [In] [MarshalAs(UnmanagedType.LPStruct)] Guid pgActionID, [In] WinTrustData pWVTData ); // call WinTrust.WinVerifyTrust() to check embedded file signature public static bool VerifyEmbeddedSignature(string fileName) { WinTrustFileInfo wtfi = new WinTrustFileInfo(fileName); WinTrustData wtd = new WinTrustData(wtfi); Guid guidAction = new Guid(WINTRUST_ACTION_GENERIC_VERIFY_V2); WinVerifyTrustResult result = WinVerifyTrust(INVALID_HANDLE_VALUE, guidAction, wtd); bool ret = (result == WinVerifyTrustResult.Success); wtfi.Dispose(); wtd.Dispose(); return ret; } private WinTrust() { } } } !!!!Alternative Managed API: CAPICOM [http://msdn2.microsoft.com/en-us/library/ms867087.aspx] !!!!Notes: Updated the code sample to remove a global memory corruption bug caused by freeing memory in destructors. !!!!Notes: I noted that under some cicumstances the destructors are called too early and memory is corrupted, therefore WinVerifyTrust returning FileNotSigned even if the file was actually signed. I recommend replacing the destructors with Dispose() and calling dispose at the end of VerifyEmbeddedSignature(). !!!!Notes: [Michael Zarlenga] First, thank you so much for this code! You saved me a lot of work and time. I also experienced corrupted memory issues (access violation exceptions). The problem is, as soon as you exit the WinTrustData constructor, WinTrustFileInfo can be destroyed, before (or even during) the call into WinVerifyTrust. To explicitly call .Dispose() on WinTrustFileInfo from WinTrustData, you need the object reference held in a scope external to the constructor but then sizeof WinTrustData will be wrong. Long story short, I solved that by instantiating a WinTrustFileInfo object myself and passing that to the WinTrustData constructor to use. I implemented .Dispose() on WinTrustData and WinTrustFileInfo and called them both, myself, after the call to WinVerifyTrust completed: ... WinTrustFileInfo winTrustFileInfo = null; WinTrustData winTrustData = null; try { // specify the WinVerifyTrust function/action that we want Guid action = new Guid(WINTRUST_ACTION_GENERIC_VERIFY_V2); // instantiate our WinTrustFileInfo and WinTrustData data structures winTrustFileInfo = new WinTrustFileInfo(filename); winTrustData = new WinTrustData(filename, winTrustFileInfo); // call into WinVerifyTrust return WinVerifyTrust(INVALID_HANDLE_VALUE, action, winTrustData); } finally { // free the locally-held unmanaged memory in the data structures if (winTrustFileInfo != null) winTrustFileInfo.Dispose(); if (winTrustData != null) winTrustData.Dispose(); } ... !!!!Tips & Tricks: static public bool CheckFile(string filename) { // check digital signature bool ret = WinTrust.VerifyEmbeddedSignature(filename); // do some other checks - for example verify the subject X509Certificate2 cert = new X509Certificate2(filename); return ret && cert.Verify() && cert.Subject == <CN=you, O=you,....>; } !!!!Sample Code: System.Console.WriteLine("Signature is OK: {0}", WinTrust.VerifyEmbeddedSignature(fileName)); Documentation: [http://msdn2.microsoft.com/en-us/library/aa388208.aspx] Working examples: [http://github.com/kg/shootblues/blob/master/SignatureCheck.cs], and [http://stackoverflow.com/a/6597017/640326]
Edit wintrust.winverif...
You do not have permission to change this page. If you feel this is in error, please send feedback with the contact link on the main page.