softether-vpn/src/BuildUtil/CoreUtil/Secure.cs

1045 lines
25 KiB
C#

// CoreUtil
//
// Copyright (C) 2012-2014 Daiyuu Nobori. All Rights Reserved.
// Copyright (C) 2012-2014 SoftEther VPN Project at University of Tsukuba. All Rights Reserved.
//
// License: The Apache License, Version 2.0
// https://www.apache.org/licenses/LICENSE-2.0
//
// DISCLAIMER
// ==========
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
// JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
// DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
// JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
// AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
// SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
// OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
// AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
// JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
// ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
// PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
// LAW OR COURT RULE.
//
// USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS YOU HAVE
// A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY CRIMINAL LAWS OR CIVIL
// RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS SOFTWARE IN OTHER COUNTRIES IS
// COMPLETELY AT YOUR OWN RISK. THE SOFTETHER VPN PROJECT HAS DEVELOPED AND
// DISTRIBUTED THIS SOFTWARE TO COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING
// CIVIL RIGHTS INCLUDING PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER
// COUNTRIES' LAWS OR CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES.
// WE HAVE NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
// INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ COUNTRIES
// AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE WORLD, WITH
// DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY COUNTRIES' LAWS, REGULATIONS
// AND CIVIL RIGHTS TO MAKE THE SOFTWARE COMPLY WITH ALL COUNTRIES' LAWS BY THE
// PROJECT. EVEN IF YOU WILL BE SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A
// PUBLIC SERVANT IN YOUR COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE
// LIABLE TO RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
// RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT JUST A
// STATEMENT FOR WARNING AND DISCLAIMER.
//
// READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE.
// SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH
// LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE.
//
//
// SOURCE CODE CONTRIBUTION
// ------------------------
//
// Your contribution to SoftEther VPN Project is much appreciated.
// Please send patches to us through GitHub.
// Read the SoftEther VPN Patch Acceptance Policy in advance:
// http://www.softether.org/5-download/src/9.patch
//
//
// DEAR SECURITY EXPERTS
// ---------------------
//
// If you find a bug or a security vulnerability please kindly inform us
// about the problem immediately so that we can fix the security problem
// to protect a lot of users around the world as soon as possible.
//
// Our e-mail address for security reports is:
// softether-vpn-security [at] softether.org
//
// Please note that the above e-mail address is not a technical support
// inquiry address. If you need technical assistance, please visit
// http://www.softether.org/ and ask your question on the users forum.
//
// Thank you for your cooperation.
//
//
// NO MEMORY OR RESOURCE LEAKS
// ---------------------------
//
// The memory-leaks and resource-leaks verification under the stress
// test has been passed before release this source code.
using System;
using System.Threading;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Text;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Web.Mail;
using System.Runtime.InteropServices;
namespace CoreUtil
{
public class CommonSign
{
byte[] keyData;
static uint init_dummy = CryptoConfigHelper.Init();
public CommonSign(byte[] key)
{
init(key);
}
public CommonSign(Buf buf)
{
init(buf.ByteData);
}
public CommonSign(string filename)
{
init(Buf.ReadFromFile(filename).ByteData);
}
void init(byte[] key)
{
keyData = (byte[])key.Clone();
}
public byte[] Sign(byte[] data)
{
Buf b = new Buf(data);
b.SeekToEnd();
b.Write(keyData);
return Secure.HashSHA1(b.ByteData);
}
public bool Verify(byte[] data, byte[] sign)
{
byte[] sign2 = Sign(data);
return Util.CompareByte(sign, sign2);
}
}
public class Rsa
{
byte[] data;
Cert cert;
static uint init_dummy = CryptoConfigHelper.Init();
static object lockObj = new object();
public Rsa(byte[] data)
{
init(data);
}
public Rsa(string filename)
{
Buf b = Buf.ReadFromFile(filename);
init(b.ByteData);
}
public Rsa(Buf b)
{
init(b.ByteData);
}
void init(byte[] data)
{
this.data = (byte[])data.Clone();
this.cert = null;
Cert.deleteOldTempFiles();
}
public Rsa(Cert cert)
{
init(cert);
}
void init(Cert cert)
{
this.cert = (Cert)cert.Clone();
this.data = null;
Cert.deleteOldTempFiles();
}
public byte[] SignData(byte[] data)
{
lock (lockObj)
{
byte[] ret;
using (RsaInner rsa = new RsaInner(this.data, this.cert))
{
ret = rsa.SignData(data);
}
return ret;
}
}
public byte[] SignHash(byte[] hash)
{
lock (lockObj)
{
byte[] ret;
using (RsaInner rsa = new RsaInner(this.data, this.cert))
{
ret = rsa.SignHash(hash);
}
return ret;
}
}
public bool VerifyData(byte[] data, byte[] sign)
{
lock (lockObj)
{
bool ret;
using (RsaInner rsa = new RsaInner(this.data, this.cert))
{
ret = rsa.VerifyData(data, sign);
}
return ret;
}
}
public bool VerifyHash(byte[] hash, byte[] sign)
{
lock (lockObj)
{
bool ret;
using (RsaInner rsa = new RsaInner(this.data, this.cert))
{
ret = rsa.VerifyHash(hash, sign);
}
return ret;
}
}
public byte[] Encrypt(byte[] data)
{
lock (lockObj)
{
using (RsaInner rsa = new RsaInner(this.data, this.cert))
{
return rsa.Encrypt(data);
}
}
}
public byte[] Decrypt(byte[] data)
{
lock (lockObj)
{
using (RsaInner rsa = new RsaInner(this.data, this.cert))
{
return rsa.Decrypt(data);
}
}
}
public int KeySizeBit
{
get
{
lock (lockObj)
{
using (RsaInner rsa = new RsaInner(this.data, this.cert))
{
return rsa.KeySizeBit;
}
}
}
}
}
class RsaInner : IDisposable
{
static string sha1rsa = CryptoConfig.MapNameToOID("SHA1");
RSACryptoServiceProvider rsa;
static object lockObj = new Object();
static LocalDataStoreSlot slot = Thread.AllocateDataSlot();
static LocalDataStoreSlot slot2 = Thread.AllocateDataSlot();
static uint init_dummy = CryptoConfigHelper.Init();
public static void Lock()
{
}
public static void Unlock()
{
}
public RsaInner(byte[] data, Cert cert)
{
if (data != null)
{
init(data);
}
else
{
init(cert);
}
}
public RsaInner(byte[] data)
{
init(data);
}
public RsaInner(string filename)
{
Buf b = Buf.ReadFromFile(filename);
init(b.ByteData);
}
public RsaInner(Buf b)
{
init(b.ByteData);
}
void init(byte[] data)
{
Lock();
rsa = readRsaPrivate(data);
}
public RsaInner(Cert cert)
{
init(cert);
}
void init(Cert cert)
{
Lock();
string text1 = cert.X509Cert.GetKeyAlgorithm();
byte[] buffer1 = cert.X509Cert.GetKeyAlgorithmParameters();
byte[] buffer2 = cert.X509Cert.GetPublicKey();
Oid oid1 = new Oid("1.2.840.113549.1.1.1", "RSA");
rsa = (RSACryptoServiceProvider)(new PublicKey(oid1, new AsnEncodedData(oid1, buffer1), new AsnEncodedData(oid1, buffer2))).Key;
}
public byte[] SignData(byte[] data)
{
byte[] hash = Secure.HashSHA1(data);
return SignHash(hash);
}
public byte[] SignHash(byte[] hash)
{
byte[] ret = null;
ret = rsa.SignHash(hash, sha1rsa);
return ret;
}
public bool VerifyData(byte[] data, byte[] sign)
{
byte[] hash = Secure.HashSHA1(data);
return VerifyHash(hash, sign);
}
public bool VerifyHash(byte[] hash, byte[] sign)
{
return rsa.VerifyHash(hash, sha1rsa, sign);
}
public byte[] Encrypt(byte[] data)
{
return rsa.Encrypt(data, false);
}
public byte[] Decrypt(byte[] data)
{
return rsa.Decrypt(data, false);
}
static RSACryptoServiceProvider readRsaPrivate(byte[] data)
{
// From http://forums.l-space-design.com/blogs/day_of_the_developer/archive/2006/06/08/216.aspx
string t = Str.AsciiEncoding.GetString(data);
if (!t.StartsWith("-----BEGIN RSA PRIVATE KEY-----"))
{
throw new ArgumentException("Not an RSA Private Key");
}
t = t.Substring("-----BEGIN RSA PRIVATE KEY-----".Length);
t = t.Substring(0, t.IndexOf("----"));
t = t.Replace("\r", "").Replace("\n", "");
byte[] byteArray = System.Convert.FromBase64String(t);
System.IO.MemoryStream s = new MemoryStream(byteArray);
BinaryReader binr = new BinaryReader(s, Str.AsciiEncoding);
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
byte bt = 0;
ushort twobytes = 0;
int elems = 0;
RSAParameters result = new RSAParameters();
try
{
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;
twobytes = binr.ReadUInt16();
if (twobytes != 0x0102) //version number
return null;
bt = binr.ReadByte();
if (bt != 0x00)
return null;
//------ all private key components are Integer sequences ----
elems = getIntegerSize(binr);
MODULUS = binr.ReadBytes(elems);
elems = getIntegerSize(binr);
E = binr.ReadBytes(elems);
elems = getIntegerSize(binr);
D = binr.ReadBytes(elems);
elems = getIntegerSize(binr);
P = binr.ReadBytes(elems);
elems = getIntegerSize(binr);
Q = binr.ReadBytes(elems);
elems = getIntegerSize(binr);
DP = binr.ReadBytes(elems);
elems = getIntegerSize(binr);
DQ = binr.ReadBytes(elems);
elems = getIntegerSize(binr);
IQ = binr.ReadBytes(elems);
result.Modulus = MODULUS;
result.Exponent = E;
result.D = D;
result.P = P;
result.Q = Q;
result.DP = DP;
result.DQ = DQ;
result.InverseQ = IQ;
}
catch (Exception)
{
return null;
}
finally
{
binr.Close();
}
CspParameters cp = new CspParameters();
cp.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(cp);
RSA.PersistKeyInCsp = false;
RSA.ImportParameters(result);
return RSA;
}
static int getIntegerSize(BinaryReader binr)
{
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02) //expect integer
return 0;
bt = binr.ReadByte();
if (bt == 0x81)
count = binr.ReadByte(); // data size in next byte
else
if (bt == 0x82)
{
highbyte = binr.ReadByte(); // data size in next 2 bytes
lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
}
else
{
count = bt; // we already have the data size
}
while (binr.PeekChar() == 0x00)
{ //remove high order zeros in data
binr.ReadByte();
count -= 1;
}
return count;
}
public void Dispose()
{
rsa.Clear();
rsa = null;
Unlock();
}
public int KeySizeBit
{
get
{
return rsa.KeySize;
}
}
}
public class Cert
{
X509Certificate2 x509;
static TimeSpan deleteOldCertSpan = new TimeSpan(0, 0, 30);
static object lockObj = new Object();
static RSACryptoServiceProvider rsaDummy = null;
static uint init_dummy = CryptoConfigHelper.Init();
public int KeySizeBit
{
get
{
Rsa r = new Rsa(this);
return r.KeySizeBit;
}
}
public X509Certificate2 X509Cert
{
get { return x509; }
}
public Rsa RsaPublicKey
{
get
{
return new Rsa(this);
}
}
public Cert(byte[] data)
{
init(data);
}
public Cert(string filename)
{
init(IO.ReadFile(filename));
}
public Cert(Buf buf)
{
init(buf.ByteData);
}
void init(byte[] data)
{
deleteOldTempFiles();
x509 = new X509Certificate2(data);
if (rsaDummy == null)
{
rsaDummy = (RSACryptoServiceProvider)(new X509Certificate2(data).PublicKey.Key);
}
}
public byte[] Hash
{
get
{
return x509.GetCertHash();
}
}
public byte[] PublicKey
{
get
{
return x509.GetPublicKey();
}
}
public byte[] ByteData
{
get
{
return x509.Export(X509ContentType.Cert);
}
}
public Buf ToBuf()
{
return new Buf(ByteData);
}
public void ToFile(string filename)
{
ToBuf().WriteToFile(filename);
}
public Cert Clone()
{
return new Cert(this.ByteData);
}
static DateTime lastDeletedDateTime = new DateTime();
static readonly TimeSpan deleteTimeSpan = new TimeSpan(0, 1, 0);
internal static void deleteOldTempFiles()
{
lock (lockObj)
{
DateTime now = Time.NowDateTime;
if (lastDeletedDateTime.Ticks == 0 ||
now >= (lastDeletedDateTime + deleteTimeSpan))
{
lastDeletedDateTime = now;
string tempDir = Path.GetTempPath();
string[] files = Directory.GetFiles(tempDir);
if (files != null)
{
foreach (string name in files)
{
try
{
if (Str.StrCmpi(Path.GetExtension(name), ".tmp") && Path.GetFileName(name).StartsWith("tmp", StringComparison.CurrentCultureIgnoreCase))
{
DateTime dt = File.GetLastWriteTimeUtc(name);
if ((DateTime.UtcNow - dt) >= deleteOldCertSpan)
{
FileInfo info = new FileInfo(name);
if (info.Length == 0)
{
try
{
File.Delete(name);
}
catch
{
}
}
}
}
}
catch
{
}
}
}
}
}
}
}
public class Secure
{
static RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
static MD5 md5 = new MD5CryptoServiceProvider();
static uint init_dummy = CryptoConfigHelper.Init();
public const uint SHA1Size = 20;
public const uint MD5Size = 16;
static object rand_lock = new object();
public static byte[] Rand(uint size)
{
lock (rand_lock)
{
byte[] ret = new byte[size];
rng.GetBytes(ret);
return ret;
}
}
public static uint Rand32()
{
return BitConverter.ToUInt32(Rand(4), 0);
}
public static ulong Rand64()
{
return BitConverter.ToUInt64(Rand(8), 0);
}
public static ushort Rand16()
{
return BitConverter.ToUInt16(Rand(2), 0);
}
public static int Rand32i()
{
return BitConverter.ToInt32(Rand(4), 0);
}
public static long Rand64i()
{
return BitConverter.ToInt64(Rand(8), 0);
}
public static short Rand16i()
{
return BitConverter.ToInt16(Rand(2), 0);
}
public static int Rand31i()
{
while (true)
{
int i = Rand32i();
if (i >= 0)
{
return i;
}
}
}
public static long Rand63i()
{
while (true)
{
long i = Rand64i();
if (i >= 0)
{
return i;
}
}
}
public static short Rand15i()
{
while (true)
{
short i = Rand16i();
if (i >= 0)
{
return i;
}
}
}
public static byte Rand8()
{
return Rand(1)[0];
}
public static bool Rand1()
{
return (Rand32() % 2) == 0;
}
// MD5
public static byte[] HashMD5(byte[] data)
{
byte[] ret;
RsaInner.Lock();
try
{
ret = md5.ComputeHash(data);
}
finally
{
RsaInner.Unlock();
}
return ret;
}
// SHA1
public static byte[] HashSHA1(byte[] data)
{
SHA1 sha1 = new SHA1Managed();
return sha1.ComputeHash(data);
}
// SHA256
public static byte[] HashSHA256(byte[] data)
{
SHA256 sha256 = new SHA256Managed();
return sha256.ComputeHash(data);
}
public static byte[] PkcsPadding(byte[] srcData, int destSize)
{
int srcSize = srcData.Length;
if ((srcSize + 11) > destSize)
{
throw new OverflowException();
}
int randSize = destSize - srcSize - 3;
byte[] rand = Secure.Rand((uint)randSize);
Buf b = new Buf();
b.WriteByte(0x00);
b.WriteByte(0x02);
b.Write(rand);
b.WriteByte(0x00);
b.Write(srcData);
return b.ByteData;
}
}
public class CryptoConfigHelper
{
static object objLock = new Object();
static bool flag = false;
public static uint Init()
{
try
{
lock (objLock)
{
if (flag == false)
{
flag = true;
Type t = typeof(CryptoConfig);
Hashtable ht = (Hashtable)t.InvokeMember("DefaultOidHT", System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static,
null, null, null);
List<string> values = new List<string>();
foreach (string key in ht.Keys)
{
string value = (string)ht[key];
values.Add(value);
}
foreach (string s in values)
{
ht.Add(s, s);
}
}
}
}
catch
{
}
return 0;
}
}
public static class ExeSignChecker
{
public static bool IsKernelModeSignedFile(string fileName)
{
return IsKernelModeSignedFile(File.ReadAllBytes(fileName));
}
public static bool IsKernelModeSignedFile(byte[] data)
{
string str = Str.AsciiEncoding.GetString(data);
if (str.IndexOf("Microsoft Code Verification Root") != -1 &&
str.IndexOf("http://crl.microsoft.com/pki/crl/products/MicrosoftCodeVerifRoot.crl") != -1)
{
return true;
}
return false;
}
enum SignChecker_MemoryAllocator { HGlobal, CoTaskMem };
enum SignChecker_UiChoice { All = 1, NoUI, NoBad, NoGood };
enum SignChecker_StateAction { Ignore = 0, Verify, Close, AutoCache, AutoCacheFlush };
enum SignChecker_UnionChoice { File = 1, Catalog, Blob, Signer, Cert };
enum SignChecker_RevocationCheckFlags { None = 0, WholeChain };
enum SignChecker_TrustProviderFlags
{
UseIE4Trust = 1,
NoIE4Chain = 2,
NoPolicyUsage = 4,
RevocationCheckNone = 16,
RevocationCheckEndCert = 32,
RevocationCheckChain = 64,
RecovationCheckChainExcludeRoot = 128,
Safer = 256,
HashOnly = 512,
UseDefaultOSVerCheck = 1024,
LifetimeSigning = 2048
};
enum SignChecker_UIContext { Execute = 0, Install };
[DllImport("Wintrust.dll", PreserveSig = true, SetLastError = false)]
static extern uint WinVerifyTrust(IntPtr hWnd, IntPtr pgActionID, IntPtr pWinTrustData);
sealed class SignCheckerUnmanagedPointer : IDisposable
{
private IntPtr m_ptr;
private SignChecker_MemoryAllocator m_meth;
public SignCheckerUnmanagedPointer(IntPtr ptr, SignChecker_MemoryAllocator method)
{
m_meth = method;
m_ptr = ptr;
}
~SignCheckerUnmanagedPointer()
{
Dispose(false);
}
void Dispose(bool disposing)
{
if (m_ptr != IntPtr.Zero)
{
if (m_meth == SignChecker_MemoryAllocator.HGlobal)
{
Marshal.FreeHGlobal(m_ptr);
}
else if (m_meth == SignChecker_MemoryAllocator.CoTaskMem)
{
Marshal.FreeCoTaskMem(m_ptr);
}
m_ptr = IntPtr.Zero;
}
if (disposing)
{
GC.SuppressFinalize(this);
}
}
public void Dispose()
{
Dispose(true);
}
public static implicit operator IntPtr(SignCheckerUnmanagedPointer ptr)
{
return ptr.m_ptr;
}
}
struct WINTRUST_FILE_INFO : IDisposable
{
public WINTRUST_FILE_INFO(string fileName, Guid subject)
{
cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_FILE_INFO));
pcwszFilePath = fileName;
if (subject != Guid.Empty)
{
tmp = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
Marshal.StructureToPtr(subject, tmp, false);
}
else
{
tmp = IntPtr.Zero;
}
hFile = IntPtr.Zero;
}
public uint cbStruct;
[MarshalAs(UnmanagedType.LPTStr)]
public string pcwszFilePath;
public IntPtr hFile;
public IntPtr tmp;
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
if (tmp != IntPtr.Zero)
{
Marshal.DestroyStructure(this.tmp, typeof(Guid));
Marshal.FreeHGlobal(this.tmp);
}
}
}
[StructLayout(LayoutKind.Sequential)]
struct WINTRUST_DATA : IDisposable
{
public WINTRUST_DATA(WINTRUST_FILE_INFO fileInfo)
{
this.cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_DATA));
pInfoStruct = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)));
Marshal.StructureToPtr(fileInfo, pInfoStruct, false);
dwUnionChoice = SignChecker_UnionChoice.File;
pPolicyCallbackData = IntPtr.Zero;
pSIPCallbackData = IntPtr.Zero;
dwUIChoice = SignChecker_UiChoice.NoUI;
fdwRevocationChecks = SignChecker_RevocationCheckFlags.WholeChain;
dwStateAction = SignChecker_StateAction.Ignore;
hWVTStateData = IntPtr.Zero;
pwszURLReference = IntPtr.Zero;
dwProvFlags = SignChecker_TrustProviderFlags.RevocationCheckChain;
dwUIContext = SignChecker_UIContext.Execute;
}
public uint cbStruct;
public IntPtr pPolicyCallbackData;
public IntPtr pSIPCallbackData;
public SignChecker_UiChoice dwUIChoice;
public SignChecker_RevocationCheckFlags fdwRevocationChecks;
public SignChecker_UnionChoice dwUnionChoice;
public IntPtr pInfoStruct;
public SignChecker_StateAction dwStateAction;
public IntPtr hWVTStateData;
private IntPtr pwszURLReference;
public SignChecker_TrustProviderFlags dwProvFlags;
public SignChecker_UIContext dwUIContext;
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
if (dwUnionChoice == SignChecker_UnionChoice.File)
{
WINTRUST_FILE_INFO info = new WINTRUST_FILE_INFO();
Marshal.PtrToStructure(pInfoStruct, info);
info.Dispose();
Marshal.DestroyStructure(pInfoStruct, typeof(WINTRUST_FILE_INFO));
}
Marshal.FreeHGlobal(pInfoStruct);
}
}
public static bool CheckFileDigitalSignature(string fileName)
{
Guid wintrust_action_generic_verify_v2 = new Guid("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}");
WINTRUST_FILE_INFO fileInfo = new WINTRUST_FILE_INFO(fileName, Guid.Empty);
WINTRUST_DATA data = new WINTRUST_DATA(fileInfo);
uint ret = 0;
using (SignCheckerUnmanagedPointer guidPtr = new SignCheckerUnmanagedPointer(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid))), SignChecker_MemoryAllocator.HGlobal))
using (SignCheckerUnmanagedPointer wvtDataPtr = new SignCheckerUnmanagedPointer(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_DATA))), SignChecker_MemoryAllocator.HGlobal))
{
IntPtr pGuid = guidPtr;
IntPtr pData = wvtDataPtr;
Marshal.StructureToPtr(wintrust_action_generic_verify_v2, pGuid, false);
Marshal.StructureToPtr(data, pData, false);
ret = WinVerifyTrust(IntPtr.Zero, pGuid, pData);
}
if (ret != 0)
{
return false;
}
return true;
}
}
}