You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

1210 lines
44 KiB

namespace com.hitrust.Security.Certificates
{
using com.hitrust.Security;
using com.hitrust.Security.Cryptography;
using System;
using System.Collections.Specialized;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
public class Certificate : ICloneable
{
internal CertificateInfo m_CertInfo;
private CertificateChain m_Chain;
internal CertificateContext m_Context;
private IntPtr m_Handle;
private CertificateStore m_Store;
public Certificate(Certificate certificate)
{
this.m_Chain = null;
if (certificate == null)
{
throw new ArgumentNullException();
}
this.InitCertificate(certificate.Handle, true, null);
}
public Certificate(IntPtr handle) : this(handle, false)
{
}
internal Certificate(IntPtr handle, CertificateStore store)
{
this.m_Chain = null;
this.InitCertificate(handle, false, store);
}
public Certificate(IntPtr handle, bool duplicate)
{
this.m_Chain = null;
this.InitCertificate(handle, duplicate, null);
}
public void AssociateWithPrivateKey(string pvkFile, string password)
{
this.AssociateWithPrivateKey(pvkFile, password, false);
}
public void AssociateWithPrivateKey(string pvkFile, string password, bool exportable)
{
try
{
if (!File.Exists(pvkFile))
{
throw new FileNotFoundException("The PVK file could not be found.");
}
}
catch (FileNotFoundException fnf)
{
throw fnf;
}
catch (Exception e)
{
throw new FileNotFoundException("The PVK file could not be found.", e);
}
byte[] buffer = new byte[0x18];
FileStream fs = File.Open(pvkFile, FileMode.Open, FileAccess.Read, FileShare.Read);
fs.Read(buffer, 0, buffer.Length);
if (BitConverter.ToUInt32(buffer, 0) != 0xb0b5f11e)
{
throw new CertificateException("The specified file is not a valid PVK file.");
}
int keytype = BitConverter.ToInt32(buffer, 8);
int isEncrypted = BitConverter.ToInt32(buffer, 12);
int saltLength = BitConverter.ToInt32(buffer, 0x10);
int keyLen = BitConverter.ToInt32(buffer, 20);
byte[] salt = new byte[saltLength];
byte[] blob = new byte[keyLen];
fs.Read(salt, 0, salt.Length);
fs.Read(blob, 0, blob.Length);
if (isEncrypted != 0)
{
if (password == null)
{
throw new ArgumentNullException();
}
byte[] pass = Encoding.ASCII.GetBytes(password);
byte[] key = new byte[salt.Length + password.Length];
Array.Copy(salt, 0, key, 0, salt.Length);
Array.Copy(pass, 0, key, salt.Length, pass.Length);
byte[] pkb = this.TryDecrypt(blob, 8, blob.Length - 8, key, 0x10);
if (pkb == null)
{
pkb = this.TryDecrypt(blob, 8, blob.Length - 8, key, 5);
if (pkb == null)
{
throw new CertificateException("The PVK file could not be decrypted. [wrong password?]");
}
}
Array.Copy(pkb, 0, blob, 8, pkb.Length);
Array.Clear(pkb, 0, pkb.Length);
Array.Clear(pass, 0, pass.Length);
Array.Clear(key, 0, key.Length);
}
int hKey = 0;
int flags = 0;
if (exportable)
{
flags = 1;
}
int provider = 0;
if (((SspiProvider.CryptAcquireContext(ref provider, "{48959A69-B181-4cdd-B135-7565701307C5}", null, 1, 8) == 0) && (Marshal.GetLastWin32Error() == -2146893809)) && (SspiProvider.CryptAcquireContext(ref provider, "{48959A69-B181-4cdd-B135-7565701307C5}", null, 1, 0) == 0))
{
throw new CertificateException("Cannot acquire crypto service provider.");
}
if (SspiProvider.CryptImportKey(provider, blob, blob.Length, 0, flags, ref hKey) == 0)
{
throw new CertificateException("Could not import the private key from the PVK file.");
}
com.hitrust.Security.CRYPT_KEY_PROV_INFO kpi = new com.hitrust.Security.CRYPT_KEY_PROV_INFO {
pwszContainerName = "{48959A69-B181-4cdd-B135-7565701307C5}",
pwszProvName = null,
dwProvType = 1,
dwFlags = 0,
cProvParam = 0,
rgProvParam = IntPtr.Zero,
dwKeySpec = keytype
};
if (SspiProvider.CertSetCertificateContextProperty(this.Handle, 2, 0, ref kpi) == 0)
{
throw new CertificateException("Could not associate the private key with the certificate.");
}
SspiProvider.CryptDestroyKey(hKey);
SspiProvider.CryptReleaseContext(provider, 0);
Array.Clear(blob, 0, blob.Length);
}
private string BytesToString(byte[] buffer)
{
string ret = "";
for (int i = 0; i < buffer.Length; i++)
{
ret = ret + buffer[i].ToString("X2");
}
return ret;
}
public object Clone()
{
return new Certificate(SspiProvider.CertDuplicateCertificateContext(this.Handle));
}
internal byte[] ConvertIntToByteArray(int dwInput)
{
int i;
int size = 0;
byte[] temp = new byte[8];
if (dwInput == 0)
{
return new byte[1];
}
int tempByte = dwInput;
while (tempByte > 0)
{
temp[size] = (byte) (tempByte & 0xff);
tempByte = tempByte >> 8;
size++;
}
byte[] ret = new byte[size];
if (BitConverter.IsLittleEndian)
{
for (i = 0; i < size; i++)
{
ret[i] = temp[(size - i) - 1];
}
return ret;
}
for (i = 0; i < size; i++)
{
ret[i] = temp[i];
}
return ret;
}
private CertificateStore CreateCertStore(bool withParents)
{
CertificateStore store = new CertificateStore();
if (withParents)
{
Certificate[] c = this.GetCertificateChain().GetCertificates();
for (int i = 0; i < c.Length; i++)
{
store.AddCertificate(c[i]);
}
return store;
}
store.AddCertificate(this);
return store;
}
public static Certificate CreateFromBase64String(string rawString)
{
if (rawString == null)
{
throw new ArgumentNullException("rawString");
}
return CreateFromCerFile(Convert.FromBase64String(rawString));
}
public static Certificate CreateFromCerFile(string file)
{
return CertificateStore.CreateFromCerFile(file).FindCertificate();
}
public static Certificate CreateFromCerFile(byte[] file)
{
if (file == null)
{
throw new ArgumentNullException();
}
return CreateFromCerFile(file, 0, file.Length);
}
public static Certificate CreateFromCerFile(byte[] file, int offset, int size)
{
if (file == null)
{
throw new ArgumentNullException();
}
if ((offset < 0) || ((offset + size) > file.Length))
{
throw new ArgumentOutOfRangeException();
}
IntPtr data = Marshal.AllocHGlobal(size);
Marshal.Copy(file, offset, data, size);
IntPtr handle = SspiProvider.CertCreateCertificateContext(0x10001, data, size);
Marshal.FreeHGlobal(data);
if (handle == IntPtr.Zero)
{
throw new CertificateException("Unable to load the specified certificate.");
}
return new Certificate(handle);
}
public static Certificate CreateFromPemFile(byte[] file)
{
if (file == null)
{
throw new ArgumentNullException();
}
string pemFile = Encoding.ASCII.GetString(file);
string cert = GetCertString(pemFile, "CERTIFICATE");
if (cert == null)
{
cert = GetCertString(pemFile, "X509 CERTIFICATE");
if (cert == null)
{
throw new CertificateException("The specified PEM file does not contain a certificate.");
}
}
return CreateFromCerFile(Convert.FromBase64String(cert));
}
public static Certificate CreateFromPemFile(string filename)
{
return CreateFromPemFile(CertificateStore.GetFileContents(filename));
}
public static Certificate CreateFromPfxFile(string file, string password)
{
return CertificateStore.CreateFromPfxFile(file, password).FindCertificate();
}
public static Certificate CreateFromPfxFile(byte[] file, string password)
{
return CertificateStore.CreateFromPfxFile(file, password).FindCertificate();
}
public static Certificate CreateFromPfxFile(string file, string password, bool exportable)
{
return CertificateStore.CreateFromPfxFile(file, password, exportable).FindCertificate();
}
public static Certificate CreateFromPfxFile(byte[] file, string password, bool exportable)
{
return CertificateStore.CreateFromPfxFile(file, password, exportable).FindCertificate();
}
public static Certificate CreateFromPfxFile(byte[] file, string password, bool exportable, KeysetLocation location)
{
return CertificateStore.CreateFromPfxFile(file, password, exportable, location).FindCertificate();
}
public static Certificate CreateFromPfxFile(string file, string password, bool exportable, KeysetLocation location)
{
return CertificateStore.CreateFromPfxFile(file, password, exportable, location).FindCertificate();
}
public static Certificate CreateFromX509Certificate(X509Certificate certificate)
{
if (certificate == null)
{
throw new ArgumentNullException();
}
return CreateFromCerFile(certificate.GetRawCertData());
}
public static object DecodeExtension(Extension extension, int oid, Type returnType)
{
return DecodeExtension(extension, new IntPtr(oid), returnType);
}
protected static object DecodeExtension(Extension extension, IntPtr oid, Type returnType)
{
object CS10000;
if ((extension.EncodedValue == null) || (returnType == null))
{
throw new ArgumentNullException();
}
int size = 0;
if (SspiProvider.CryptDecodeObject(0x10001, oid, extension.EncodedValue, extension.EncodedValue.Length, 0, IntPtr.Zero, ref size) == 0)
{
throw new CertificateException("Could not decode the extension.");
}
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
if (SspiProvider.CryptDecodeObject(0x10001, oid, extension.EncodedValue, extension.EncodedValue.Length, 0, buffer, ref size) == 0)
{
throw new CertificateException("Could not decode the extension.");
}
CS10000 = Activator.CreateInstance(returnType, new object[] { buffer, size });
}
catch (CertificateException ce)
{
throw ce;
}
catch (Exception e)
{
throw new CertificateException("Unable to instantiate the specified object type.", e);
}
finally
{
Marshal.FreeHGlobal(buffer);
}
return CS10000;
}
public static object DecodeExtension(Extension extension, string oid, Type returnType)
{
object CS10000;
if (oid == null)
{
throw new ArgumentNullException("oid");
}
IntPtr buffer = Marshal.StringToHGlobalAnsi(oid);
try
{
CS10000 = DecodeExtension(extension, buffer, returnType);
}
finally
{
Marshal.FreeHGlobal(buffer);
}
return CS10000;
}
public virtual bool Equals(Certificate other)
{
if (other == null)
{
return false;
}
return (SspiProvider.CertCompareCertificate(0x10001, this.m_Context.pCertInfo, other.m_Context.pCertInfo) != 0);
}
public override bool Equals(object other)
{
bool CS10000;
try
{
CS10000 = this.Equals((Certificate) other);
}
catch
{
try
{
CS10000 = this.Equals((X509Certificate) other);
}
catch
{
CS10000 = false;
}
}
return CS10000;
}
public virtual bool Equals(X509Certificate other)
{
if (other == null)
{
return false;
}
return (other.GetCertHashString() == this.GetCertHashString());
}
public void ExportPrivateKey(string pvkFile, string password)
{
byte[] salt;
if (!this.HasPrivateKey())
{
throw new CertificateException("The certificate does not have an associated private key.");
}
int flags = 0;
int provider = 0;
int keySpec = 0;
int mustFree = 0;
int privateKey = 0;
int size = 0;
if (!Environment.UserInteractive)
{
flags = 0x40;
}
if (SspiProvider.CryptAcquireCertificatePrivateKey(this.Handle, flags, IntPtr.Zero, ref provider, ref keySpec, ref mustFree) == 0)
{
throw new CertificateException("Could not acquire private key.");
}
if (SspiProvider.CryptGetUserKey(provider, keySpec, ref privateKey) == 0)
{
throw new CertificateException("Could not retrieve a handle of the private key.");
}
if ((SspiProvider.CryptExportKey(privateKey, 0, 7, 0, IntPtr.Zero, ref size) == 0) && (Marshal.GetLastWin32Error() != 0xea))
{
throw new CertificateException("Could not export the private key.");
}
byte[] buffer = new byte[size];
if (SspiProvider.CryptExportKey(privateKey, 0, 7, 0, buffer, ref size) == 0)
{
throw new CertificateException("Could not export the private key.");
}
if (mustFree != 0)
{
SspiProvider.CryptReleaseContext(provider, 0);
}
uint magic = 0xb0b5f11e;
int reserved = 0;
int encrypted = (password == null) ? 0 : 1;
if (encrypted == 0)
{
salt = new byte[0];
}
else
{
salt = new byte[0x10];
new RNGCryptoServiceProvider().GetBytes(salt);
byte[] key = Encoding.ASCII.GetBytes(password);
SHA1 sha1 = SHA1.Create();
sha1.TransformBlock(salt, 0, salt.Length, salt, 0);
sha1.TransformFinalBlock(key, 0, key.Length);
key = new byte[0x10];
Array.Copy(sha1.Hash, 0, key, 0, key.Length);
ICryptoTransform rc4 = RC4.Create().CreateEncryptor(key, null);
rc4.TransformBlock(buffer, 8, buffer.Length - 8, buffer, 8);
rc4.Dispose();
sha1.Clear();
}
int saltlen = salt.Length;
FileStream fs = null;
try
{
fs = File.Open(pvkFile, FileMode.Create, FileAccess.Write, FileShare.Read);
fs.Write(BitConverter.GetBytes(magic), 0, 4);
fs.Write(BitConverter.GetBytes(reserved), 0, 4);
fs.Write(BitConverter.GetBytes(keySpec), 0, 4);
fs.Write(BitConverter.GetBytes(encrypted), 0, 4);
fs.Write(BitConverter.GetBytes(saltlen), 0, 4);
fs.Write(BitConverter.GetBytes(size), 0, 4);
if (salt.Length > 0)
{
fs.Write(salt, 0, salt.Length);
}
fs.Write(buffer, 0, buffer.Length);
}
catch (IOException ioe)
{
throw ioe;
}
catch (Exception e)
{
throw new IOException("An error occurs while writing the file.", e);
}
finally
{
if (fs != null)
{
fs.Close();
}
}
}
~Certificate()
{
if (this.Handle != IntPtr.Zero)
{
SspiProvider.CertFreeCertificateContext(this.Handle);
this.m_Handle = IntPtr.Zero;
}
}
public Extension FindExtension(string oid)
{
if (oid == null)
{
throw new ArgumentNullException();
}
IntPtr ret = SspiProvider.CertFindExtension(oid, this.m_CertInfo.cExtension, this.m_CertInfo.rgExtension);
if (ret == IntPtr.Zero)
{
return null;
}
com.hitrust.Security.CERT_EXTENSION ce = (com.hitrust.Security.CERT_EXTENSION) Marshal.PtrToStructure(ret, typeof(com.hitrust.Security.CERT_EXTENSION));
Extension ext = new Extension(Marshal.PtrToStringAnsi(ce.pszObjId), ce.fCritical != 0, new byte[ce.ValuecbData]);
Marshal.Copy(ce.ValuepbData, ext.EncodedValue, 0, ce.ValuecbData);
return ext;
}
public byte[] GetCertHash()
{
return this.GetCertHash(HashType.SHA1);
}
public byte[] GetCertHash(HashType type)
{
byte[] ret;
IntPtr hash = Marshal.AllocHGlobal(0x100);
try
{
int size = 0x100;
if (((SspiProvider.CertGetCertificateContextProperty(this.Handle, (int) type, hash, ref size) == 0) || (size <= 0)) || (size > 0x100))
{
throw new CertificateException("An error occurs while retrieving the hash of the certificate.");
}
ret = new byte[size];
Marshal.Copy(hash, ret, 0, size);
}
catch (Exception e)
{
throw e;
}
finally
{
Marshal.FreeHGlobal(hash);
}
return ret;
}
public string GetCertHashString()
{
return this.GetCertHashString(HashType.SHA1);
}
public string GetCertHashString(HashType type)
{
return this.BytesToString(this.GetCertHash(type));
}
private byte[] GetCertificateBuffer()
{
byte[] buffer = new byte[this.m_Context.cbCertEncoded];
Marshal.Copy(this.m_Context.pbCertEncoded, buffer, 0, this.m_Context.cbCertEncoded);
return buffer;
}
public CertificateChain GetCertificateChain()
{
if (this.m_Chain == null)
{
this.m_Chain = new CertificateChain(this, this.Store);
}
return this.m_Chain;
}
internal CertificateInfo GetCertificateInfo()
{
return this.m_CertInfo;
}
private static string GetCertString(string cert, string delimiter)
{
int start = cert.IndexOf("-----BEGIN " + delimiter + "-----");
if (start < 0)
{
return null;
}
int end = cert.IndexOf("-----END " + delimiter + "-----", start);
if (end < 0)
{
return null;
}
int sl = delimiter.Length + 0x10;
int length = end - (start + sl);
return cert.Substring(start + sl, length);
}
public DistinguishedName GetDistinguishedName()
{
return new DistinguishedName(this.m_CertInfo.SubjectpbData, this.m_CertInfo.SubjectcbData);
}
public DateTime GetEffectiveDate()
{
return DateTime.FromFileTime(this.m_CertInfo.NotBefore);
}
public StringCollection GetEnhancedKeyUsage()
{
StringCollection CS10000;
StringCollection ret = new StringCollection();
int size = 0;
SspiProvider.CertGetEnhancedKeyUsage(this.Handle, 0, IntPtr.Zero, ref size);
if (size <= 0)
{
return ret;
}
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
if (SspiProvider.CertGetEnhancedKeyUsage(this.Handle, 0, buffer, ref size) == 0)
{
throw new CertificateException("Could not obtain the enhanced key usage.");
}
TrustListUsage cu = (TrustListUsage) Marshal.PtrToStructure(buffer, typeof(TrustListUsage));
for (int i = 0; i < cu.cUsageIdentifier; i++)
{
IntPtr ip = Marshal.ReadIntPtr(cu.rgpszUsageIdentifier, i * IntPtr.Size);
try
{
ret.Add(Marshal.PtrToStringAnsi(ip));
}
catch
{
}
}
CS10000 = ret;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
return CS10000;
}
public DateTime GetExpirationDate()
{
return DateTime.FromFileTime(this.m_CertInfo.NotAfter);
}
public Extension[] GetExtensions()
{
Extension[] ret = new Extension[this.m_CertInfo.cExtension];
int extSize = 8 + (IntPtr.Size * 2);
IntPtr ptr = this.m_CertInfo.rgExtension;
Type cest = typeof(com.hitrust.Security.CERT_EXTENSION);
for (int i = 0; i < this.m_CertInfo.cExtension; i++)
{
com.hitrust.Security.CERT_EXTENSION ce = (com.hitrust.Security.CERT_EXTENSION) Marshal.PtrToStructure(ptr, cest);
ret[i] = new Extension(Marshal.PtrToStringAnsi(ce.pszObjId), ce.fCritical != 0, new byte[ce.ValuecbData]);
Marshal.Copy(ce.ValuepbData, ret[i].EncodedValue, 0, ce.ValuecbData);
ptr = new IntPtr(ptr.ToInt64() + extSize);
}
return ret;
}
public string GetFormat()
{
return "X509";
}
public override int GetHashCode()
{
byte[] hash = this.GetCertHash();
byte[] buffer = new byte[4];
if (hash.Length < buffer.Length)
{
Array.Copy(hash, 0, buffer, 0, hash.Length);
}
else
{
Array.Copy(hash, 0, buffer, 0, buffer.Length);
}
return BitConverter.ToInt32(buffer, 0);
}
public int GetIntendedKeyUsage()
{
IntPtr buffer = Marshal.AllocHGlobal(4);
SspiProvider.CertGetIntendedKeyUsage(0x10001, this.m_Context.pCertInfo, buffer, 4);
byte[] mb = new byte[4];
Marshal.Copy(buffer, mb, 0, 4);
Marshal.FreeHGlobal(buffer);
return BitConverter.ToInt32(mb, 0);
}
public string GetIssuerName()
{
int length = SspiProvider.CertGetNameString(this.Handle, 4, 0x10001, IntPtr.Zero, IntPtr.Zero, 0);
if (length <= 0)
{
throw new CertificateException("An error occurs while requesting the issuer name.");
}
IntPtr name = Marshal.AllocHGlobal(length);
SspiProvider.CertGetNameString(this.Handle, 4, 0x10001, IntPtr.Zero, name, length);
string ret = Marshal.PtrToStringAnsi(name);
Marshal.FreeHGlobal(name);
return ret;
}
public string GetKeyAlgorithm()
{
return Marshal.PtrToStringAnsi(this.m_CertInfo.SignatureAlgorithmpszObjId);
}
public byte[] GetKeyAlgorithmParameters()
{
byte[] ret = new byte[this.m_CertInfo.SignatureAlgorithmParameterscbData];
if (ret.Length > 0)
{
Marshal.Copy(this.m_CertInfo.SignatureAlgorithmParameterspbData, ret, 0, ret.Length);
}
return ret;
}
public string GetKeyAlgorithmParametersString()
{
return this.BytesToString(this.GetKeyAlgorithmParameters());
}
public byte[] GetKeyIdentifier()
{
int size = 0;
SspiProvider.CertGetCertificateContextProperty(this.Handle, 20, (byte[]) null, ref size);
byte[] ret = new byte[size];
SspiProvider.CertGetCertificateContextProperty(this.Handle, 20, ret, ref size);
return ret;
}
public string GetName()
{
int size = 0;
SspiProvider.CryptDecodeObject(0x10001, new IntPtr(20), this.m_CertInfo.SubjectpbData, this.m_CertInfo.SubjectcbData, 0, IntPtr.Zero, ref size);
if (size <= 0)
{
throw new CertificateException("Unable to decode the name of the certificate.");
}
IntPtr buffer = IntPtr.Zero;
string ret = null;
try
{
buffer = Marshal.AllocHGlobal(size);
if (SspiProvider.CryptDecodeObject(0x10001, new IntPtr(20), this.m_CertInfo.SubjectpbData, this.m_CertInfo.SubjectcbData, 0, buffer, ref size) == 0)
{
throw new CertificateException("Unable to decode the name of the certificate.");
}
IntPtr attPointer = SspiProvider.CertFindRDNAttr("2.5.4.3", buffer);
if (attPointer == IntPtr.Zero)
{
attPointer = SspiProvider.CertFindRDNAttr("1.2.840.113549.1.9.2", buffer);
}
if (attPointer == IntPtr.Zero)
{
attPointer = SspiProvider.CertFindRDNAttr("2.5.4.10", buffer);
}
if (attPointer != IntPtr.Zero)
{
RdnAttribute att = (RdnAttribute) Marshal.PtrToStructure(attPointer, typeof(RdnAttribute));
ret = Marshal.PtrToStringUni(att.pbData, att.cbData / 2);
}
}
catch (CertificateException ce)
{
throw ce;
}
catch (Exception e)
{
throw new CertificateException("Could not get certificate attributes.", e);
}
finally
{
if (buffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(buffer);
}
}
if (ret == null)
{
throw new CertificateException("Certificate does not have a name attribute.");
}
return ret;
}
public byte[] GetPublicKey()
{
byte[] key = new byte[this.m_CertInfo.SubjectPublicKeyInfoPublicKeycbData];
Marshal.Copy(this.m_CertInfo.SubjectPublicKeyInfoPublicKeypbData, key, 0, key.Length);
return key;
}
public int GetPublicKeyLength()
{
return SspiProvider.CertGetPublicKeyLength(0x10001, new IntPtr(this.m_Context.pCertInfo.ToInt64() + 0x38L));
}
public string GetPublicKeyString()
{
return this.BytesToString(this.GetPublicKey());
}
public byte[] GetRawCertData()
{
byte[] ret = new byte[this.m_Context.cbCertEncoded];
Marshal.Copy(this.m_Context.pbCertEncoded, ret, 0, ret.Length);
return ret;
}
public string GetRawCertDataString()
{
return this.BytesToString(this.GetRawCertData());
}
public byte[] GetSerialNumber()
{
byte[] ret = new byte[this.m_CertInfo.SerialNumbercbData];
if (ret.Length > 0)
{
Marshal.Copy(this.m_CertInfo.SerialNumberpbData, ret, 0, ret.Length);
}
return ret;
}
public string GetSerialNumberString()
{
return this.BytesToString(this.GetSerialNumber());
}
public static string[] GetValidUsages(Certificate[] certificates)
{
string[] CS10000;
if (certificates == null)
{
throw new ArgumentNullException();
}
IntPtr buffer = IntPtr.Zero;
IntPtr certs = Marshal.AllocHGlobal((int) (certificates.Length * IntPtr.Size));
try
{
int i;
for (i = 0; i < certificates.Length; i++)
{
if (certificates[i] == null)
{
throw new ArgumentException();
}
Marshal.WriteIntPtr(certs, i * IntPtr.Size, certificates[i].Handle);
}
int count = 0;
int bytes = 0;
if (SspiProvider.CertGetValidUsages(certificates.Length, certs, ref count, buffer, ref bytes) == 0)
{
throw new CertificateException("Unable to get the valid usages.");
}
if (count == -1)
{
return null;
}
buffer = Marshal.AllocHGlobal(bytes);
if (SspiProvider.CertGetValidUsages(certificates.Length, certs, ref count, buffer, ref bytes) == 0)
{
throw new CertificateException("Unable to get the valid usages.");
}
string[] ret = new string[count];
for (i = 0; i < count; i++)
{
ret[i] = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(buffer, i * IntPtr.Size));
}
CS10000 = ret;
}
finally
{
Marshal.FreeHGlobal(certs);
if (buffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(buffer);
}
}
return CS10000;
}
public bool HasPrivateKey()
{
int handle = 0;
int keyspec = 0;
int free = 0;
bool ret = false;
if (SspiProvider.CryptAcquireCertificatePrivateKey(this.Handle, 0x44, IntPtr.Zero, ref handle, ref keyspec, ref free) != 0)
{
ret = true;
}
if (free != 0)
{
SspiProvider.CryptReleaseContext(handle, 0);
}
return ret;
}
private void InitCertificate(IntPtr handle, bool duplicate, CertificateStore store)
{
if (handle == IntPtr.Zero)
{
throw new ArgumentException("Invalid certificate handle!");
}
if (duplicate)
{
this.m_Handle = SspiProvider.CertDuplicateCertificateContext(handle);
}
else
{
this.m_Handle = handle;
}
this.m_Context = (CertificateContext) Marshal.PtrToStructure(handle, typeof(CertificateContext));
this.m_CertInfo = (CertificateInfo) Marshal.PtrToStructure(this.m_Context.pCertInfo, typeof(CertificateInfo));
if (store == null)
{
this.m_Store = null;
}
else
{
this.m_Store = store;
}
}
private void SaveToFile(byte[] buffer, string filename)
{
if (filename == null)
{
throw new ArgumentNullException();
}
try
{
FileStream fs = File.Open(filename, FileMode.CreateNew, FileAccess.Write, FileShare.None);
fs.Write(buffer, 0, buffer.Length);
fs.Close();
}
catch (Exception e)
{
throw new IOException("Could not write data to file.", e);
}
}
public string ToBase64String()
{
byte[] cert = this.ToCerBuffer();
return Convert.ToBase64String(cert, 0, cert.Length);
}
public byte[] ToCerBuffer()
{
return this.GetCertificateBuffer();
}
public void ToCerFile(string filename)
{
this.SaveToFile(this.GetCertificateBuffer(), filename);
}
public byte[] ToPemBuffer()
{
return Encoding.ASCII.GetBytes("-----BEGIN CERTIFICATE-----\r\n" + this.ToBase64String() + "\r\n-----END CERTIFICATE-----\r\n");
}
public byte[] ToPfxBuffer(string password, bool withPrivateKeys, bool withParents)
{
return this.CreateCertStore(withParents).ToPfxBuffer(password, withPrivateKeys);
}
public void ToPfxFile(string filename, string password, bool withPrivateKeys, bool withParents)
{
this.CreateCertStore(withParents).ToPfxFile(filename, password, withPrivateKeys);
}
public override string ToString()
{
return base.GetType().FullName;
}
public string ToString(bool verbose)
{
if (verbose)
{
return ("CERTIFICATE:\r\n Format: X509\r\n Name: " + this.GetName() + "\r\n Issuing CA: " + this.GetIssuerName() + "\r\n Key Algorithm: " + this.GetKeyAlgorithm() + "\r\n Serial Number: " + this.GetSerialNumberString() + "\r\n Key Alogrithm Parameters: " + this.GetKeyAlgorithmParametersString() + "\r\n Public Key: " + this.GetPublicKeyString());
}
return this.ToString();
}
public X509Certificate ToX509()
{
return new X509Certificate(SspiProvider.CertDuplicateCertificateContext(this.Handle));
}
private byte[] TryDecrypt(byte[] buffer, int offset, int length, byte[] password, int keyLen)
{
byte[] key = new byte[0x10];
Array.Copy(SHA1.Create().ComputeHash(password, 0, password.Length), 0, key, 0, keyLen);
byte[] ret = RC4.Create().CreateDecryptor(key, null).TransformFinalBlock(buffer, offset, length);
if ((((ret[0] != 0x52) || (ret[1] != 0x53)) || (ret[2] != 0x41)) || (ret[3] != 50))
{
return null;
}
return ret;
}
public bool VerifyRevocation(byte[] crl)
{
if (crl == null)
{
throw new ArgumentNullException();
}
IntPtr crlContextHandle = SspiProvider.CertCreateCRLContext(0x10001, crl, crl.Length);
IntPtr crle = IntPtr.Zero;
if (SspiProvider.CertFindCertificateInCRL(this.Handle, crlContextHandle, 0, IntPtr.Zero, ref crle) == 0)
{
throw new CertificateException("Unable to search the specified CRL for the certificate.");
}
return (crle == IntPtr.Zero);
}
public IntPtr Handle
{
get
{
return this.m_Handle;
}
}
public bool IsCurrent
{
get
{
return (SspiProvider.CertVerifyTimeValidity(IntPtr.Zero, this.m_Context.pCertInfo) == 0);
}
}
public RSACryptoServiceProvider PrivateKey
{
get
{
int flags = 0;
int provider = 0;
int keySpec = 0;
int mustFree = 0;
if (true) {
flags = 0x40;
}
if (SspiProvider.CryptAcquireCertificatePrivateKey(this.Handle, flags, IntPtr.Zero, ref provider, ref keySpec, ref mustFree) == 0)
{
throw new CertificateException("Could not acquire private key."+ SspiProvider.GetLastError());
}
if (mustFree != 0) {
SspiProvider.CryptReleaseContext(provider, 0);
}
if (Environment.UserInteractive) {
flags = 0;
} else {
flags = 0x40;
}
int length = 0;
if ((SspiProvider.CryptFindCertificateKeyProvInfo(this.Handle, flags, IntPtr.Zero) == 0) || (SspiProvider.CertGetCertificateContextProperty(this.Handle, 2, (byte[])null, ref length) == 0)) {
throw new CertificateException("Could not query the associated private key.");
}
IntPtr buffer = Marshal.AllocHGlobal(length);
RSACryptoServiceProvider privateKey = null;
try {
SspiProvider.CertGetCertificateContextProperty(this.Handle, 2, buffer, ref length);
com.hitrust.Security.CRYPT_KEY_PROV_INFO provInfo = (com.hitrust.Security.CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(buffer, typeof(com.hitrust.Security.CRYPT_KEY_PROV_INFO));
CspParameters cspParams = new CspParameters {
KeyContainerName = provInfo.pwszContainerName,
ProviderName = null,
ProviderType = provInfo.dwProvType,
KeyNumber = provInfo.dwKeySpec
};
if ((provInfo.dwFlags & 0x20) != 0) {
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
}
privateKey = new RSACryptoServiceProvider(cspParams);
} catch (CertificateException e) {
throw e;
} catch (Exception e) {
throw new CertificateException("An error occurs while accessing the certificate's private key.", e);
} finally {
Marshal.FreeHGlobal(buffer);
}
return privateKey;
}
}
public RSACryptoServiceProvider PublicKey
{
get
{
IntPtr buffer = IntPtr.Zero;
int provider = 0;
int key = 0;
RSACryptoServiceProvider publicKey = null;
try
{
int flags = 0;
if ((!Environment.UserInteractive && (Environment.OSVersion.Platform == PlatformID.Win32NT)) && (Environment.OSVersion.Version.Major >= 5))
{
flags = 0x40;
}
if ((SspiProvider.CryptAcquireContext(ref provider, IntPtr.Zero, null, 1, flags) == 0) && (SspiProvider.CryptAcquireContext(ref provider, IntPtr.Zero, null, 1, flags | 8) == 0))
{
throw new CertificateException("Could not acquire crypto context.");
}
com.hitrust.Security.CERT_PUBLIC_KEY_INFO pki = new com.hitrust.Security.CERT_PUBLIC_KEY_INFO(this.m_CertInfo);
int size = 0;
if (SspiProvider.CryptImportPublicKeyInfoEx(provider, 0x10001, ref pki, 0, 0, IntPtr.Zero, ref key) == 0)
{
throw new CertificateException("Could not obtain the handle of the public key.");
}
if (SspiProvider.CryptExportKey(key, 0, 6, 0, IntPtr.Zero, ref size) == 0)
{
throw new CertificateException("Could not get the size of the key.");
}
buffer = Marshal.AllocHGlobal(size);
if (SspiProvider.CryptExportKey(key, 0, 6, 0, buffer, ref size) == 0)
{
throw new CertificateException("Could not export the key.");
}
PUBLIC_KEY_BLOB pkb = (PUBLIC_KEY_BLOB) Marshal.PtrToStructure(buffer, typeof(PUBLIC_KEY_BLOB));
if (pkb.magic != 0x31415352)
{
throw new CertificateException("This is not an RSA certificate.");
}
RSAParameters rsap = new RSAParameters {
Exponent = this.ConvertIntToByteArray(pkb.pubexp)
};
IntPtr modulus = new IntPtr(buffer.ToInt64() + Marshal.SizeOf(typeof(PUBLIC_KEY_BLOB)));
rsap.Modulus = new byte[pkb.bitlen / 8];
Marshal.Copy(modulus, rsap.Modulus, 0, rsap.Modulus.Length);
Array.Reverse(rsap.Modulus);
publicKey = new RSACryptoServiceProvider(new CspParameters { Flags = CspProviderFlags.UseMachineKeyStore });
publicKey.ImportParameters(rsap);
}
finally
{
if (key != 0)
{
SspiProvider.CryptDestroyKey(key);
}
if (provider != 0)
{
SspiProvider.CryptReleaseContext(provider, 0);
}
if (buffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(buffer);
}
}
return publicKey;
}
}
internal CertificateStore Store
{
get
{
return this.m_Store;
}
set
{
if (this.m_Store != value)
{
this.m_Chain = null;
}
this.m_Store = value;
}
}
public bool SupportsDataEncryption
{
get
{
return (this.HasPrivateKey() && ((this.GetIntendedKeyUsage() & 0x10) != 0));
}
}
public bool SupportsDigitalSignature
{
get
{
return (this.HasPrivateKey() && ((this.GetIntendedKeyUsage() & 0x80) != 0));
}
}
}
}