mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2025-04-03 18:00:08 +03:00
959 lines
21 KiB
C#
959 lines
21 KiB
C#
// CoreUtil
|
|
|
|
|
|
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,
|
|
RevocationCheckChainExcludeRoot = 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|