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.
 
 

513 lines
16 KiB

namespace com.hitrust.Security.Certificates
{
using Security;
using System;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
public class CertificateStore
{
public const string CAStore = "CA";
private IntPtr m_Handle;
public const string MyStore = "My";
public const string RootStore = "Root";
public const string SoftwarePublisherStore = "SPC";
public const string TrustStore = "Trust";
public const string UnTrustedStore = "Disallowed";
public CertificateStore()
{
this.m_Handle = SspiProvider.CertOpenStore(new IntPtr(2), 0x10001, IntPtr.Zero, 0, null);
if (this.m_Handle == IntPtr.Zero) {
throw new CertificateException("An error occurs while creating the store.");
}
}
public CertificateStore(CertificateStore store)
{
if (store == null) {
throw new ArgumentNullException();
}
this.InitStore(store.m_Handle, true);
}
public CertificateStore(IEnumerable certs) : this()
{
IEnumerator enumerator = certs.GetEnumerator();
while (enumerator.MoveNext()) {
this.AddCertificate((Certificate)enumerator.Current);
}
}
public CertificateStore(IntPtr handle) : this(handle, false) {}
public CertificateStore(string store) : this(StoreLocation.Users, store) {}
public CertificateStore(byte[] buffer, CertificateStoreType type)
{
DataBlob blob;
IntPtr ptr;
if (buffer == null) {
throw new ArgumentNullException();
}
blob = new DataBlob();
blob.cbData = buffer.Length;
blob.pbData = Marshal.AllocHGlobal(blob.cbData);
Marshal.Copy(buffer, 0, blob.pbData, buffer.Length);
if (type == CertificateStoreType.Pkcs7Message) {
ptr = new IntPtr(5);
} else {
ptr = new IntPtr(6);
}
this.m_Handle = SspiProvider.CertOpenStoreData(ptr, 0x10001, IntPtr.Zero, 0, ref blob);
Marshal.FreeHGlobal(blob.pbData);
if (this.m_Handle == IntPtr.Zero) {
throw new CertificateException("An error occurs while opening the store.");
}
}
public CertificateStore(StoreLocation location, string store)
{
if (store == null) {
throw new ArgumentNullException("The name of the store cannot be a null reference.");
}
this.m_Handle = SspiProvider.CertOpenStore(new IntPtr(9), 0, IntPtr.Zero, (int)location, store);
if (this.m_Handle == IntPtr.Zero) {
throw new CertificateException("An error occurs while opening the specified store.");
}
}
public CertificateStore(IntPtr handle, bool duplicate)
{
this.InitStore(handle, duplicate);
}
public void AddCertificate(Certificate cert)
{
if (cert == null) {
throw new ArgumentNullException();
}
if ((SspiProvider.CertAddCertificateContextToStore(this.Handle, cert.Handle, 1, IntPtr.Zero) == 0) && (Marshal.GetLastWin32Error() != -2146885627)) {
throw new CertificateException("An error occurs while adding the certificate to the store.");
}
}
public static CertificateStore CreateFromCerFile(string file)
{
if (file == null) {
throw new ArgumentNullException("The filename cannot be a null reference.");
}
IntPtr handle = SspiProvider.CertOpenStore(new IntPtr(7), 0x10001, IntPtr.Zero, 0, file);
if (handle == IntPtr.Zero) {
throw new CertificateException("An error occurs while opening the specified store.");
}
return new CertificateStore(handle);
}
public static CertificateStore CreateFromPfxFile(byte[] file, string password)
{
return CreateFromPfxFile(file, password, false);
}
public static CertificateStore CreateFromPfxFile(string file, string password)
{
return CreateFromPfxFile(GetFileContents(file), password);
}
public static CertificateStore CreateFromPfxFile(byte[] file, string password, bool exportable)
{
return CreateFromPfxFile(file, password, exportable, KeysetLocation.Default);
}
public static CertificateStore CreateFromPfxFile(string file, string password, bool exportable)
{
return CreateFromPfxFile(GetFileContents(file), password, exportable);
}
public static CertificateStore CreateFromPfxFile(byte[] file, string password, bool exportable, KeysetLocation location)
{
if ((password == null) || (file == null)) {
throw new ArgumentNullException("The arguments cannot be null references.");
}
DataBlob pPFX = new DataBlob {
cbData = file.Length
};
IntPtr destination = Marshal.AllocHGlobal(file.Length);
Marshal.Copy(file, 0, destination, file.Length);
pPFX.pbData = destination;
try {
if (SspiProvider.PFXIsPFXBlob(ref pPFX) == 0) {
throw new CertificateException("The specified file is not a PFX file.");
}
if (SspiProvider.PFXVerifyPassword(ref pPFX, password, 0) == 0) {
throw new CertificateException("The specified password is invalid.");
}
int dwFlags = (int)location;
if (exportable) {
dwFlags |= 1;
}
IntPtr handle = SspiProvider.PFXImportCertStore(ref pPFX, password, dwFlags);
if (handle.Equals(IntPtr.Zero)) {
throw new CertificateException("Unable to import the PFX file! [error code = " + Marshal.GetLastWin32Error() + "]");
}
return new CertificateStore(handle);
} finally {
Marshal.FreeHGlobal(destination);
}
}
public static CertificateStore CreateFromPfxFile(string file, string password, bool exportable, KeysetLocation location)
{
return CreateFromPfxFile(GetFileContents(file), password, exportable, location);
}
public void DeleteCertificate(Certificate cert)
{
if (cert == null) {
throw new ArgumentNullException();
}
Certificate certificate = this.FindCertificateByHash(cert.GetCertHash(HashType.SHA1), HashType.SHA1);
if (certificate == null) {
throw new CertificateException("The certificate could not be found in the store.");
}
if (SspiProvider.CertDeleteCertificateFromStore(certificate.Handle) == 0) {
throw new CertificateException("An error occurs while removing the certificate from the store.");
}
}
public Certificate[] EnumCertificates()
{
ArrayList list = new ArrayList();
for (Certificate certificate = this.FindCertificate(); certificate != null; certificate = this.FindCertificate(certificate)) {
list.Add(certificate);
}
return (Certificate[])list.ToArray(typeof(Certificate));
}
public Certificate[] EnumCertificates(string[] keyUsage)
{
ArrayList list = new ArrayList();
for (Certificate certificate = this.FindCertificateByUsage(keyUsage); certificate != null; certificate = this.FindCertificateByUsage(keyUsage, certificate)) {
list.Add(certificate);
}
return (Certificate[])list.ToArray(typeof(Certificate));
}
~CertificateStore()
{
if (this.Handle != IntPtr.Zero) {
SspiProvider.CertCloseStore(this.Handle, 0);
this.m_Handle = IntPtr.Zero;
}
}
public Certificate FindCertificate()
{
return this.FindCertificate(null);
}
public Certificate FindCertificate(Certificate previous)
{
IntPtr zero;
if (previous == null) {
zero = IntPtr.Zero;
} else {
zero = SspiProvider.CertDuplicateCertificateContext(previous.Handle);
}
IntPtr handle = SspiProvider.CertFindCertificateInStore(this.Handle, 1, 0, 0, IntPtr.Zero, zero);
if (handle.Equals(IntPtr.Zero)) {
return null;
}
return new Certificate(handle, this);
}
public Certificate FindCertificateByHash(byte[] hash)
{
return this.FindCertificateByHash(hash, HashType.SHA1);
}
public Certificate FindCertificateByHash(byte[] hash, HashType hashType)
{
int num;
if (hash == null) {
throw new ArgumentNullException();
}
if (hashType == HashType.SHA1) {
num = 0x10000;
} else if (hashType == HashType.MD5) {
num = 0x40000;
} else {
num = 0x10000;
}
DataBlob pvFindPara = new DataBlob {
cbData = hash.Length,
pbData = Marshal.AllocHGlobal(hash.Length)
};
Marshal.Copy(hash, 0, pvFindPara.pbData, hash.Length);
IntPtr handle = SspiProvider.CertFindDataBlobCertificateInStore(this.Handle, 0x10001, 0, num, ref pvFindPara, IntPtr.Zero);
Marshal.FreeHGlobal(pvFindPara.pbData);
if (handle == IntPtr.Zero) {
return null;
}
return new Certificate(handle);
}
public Certificate FindCertificateByKeyIdentifier(byte[] keyID)
{
if (keyID == null) {
throw new ArgumentNullException();
}
if (keyID.Length == 0) {
throw new ArgumentException();
}
DataBlob pvFindPara = new DataBlob {
cbData = keyID.Length,
pbData = Marshal.AllocHGlobal(keyID.Length)
};
Marshal.Copy(keyID, 0, pvFindPara.pbData, keyID.Length);
IntPtr handle = SspiProvider.CertFindDataBlobCertificateInStore(this.Handle, 0x10001, 0, 0xf0000, ref pvFindPara, IntPtr.Zero);
Marshal.FreeHGlobal(pvFindPara.pbData);
if (handle == IntPtr.Zero) {
return null;
}
return new Certificate(handle);
}
public Certificate FindCertificateBySubjectName(string name)
{
return this.FindCertificateBySubjectName(name, null);
}
public Certificate FindCertificateBySubjectName(string name, Certificate previous)
{
IntPtr ptr;
if (name == null) {
throw new ArgumentNullException();
}
if (name.Length == 0) {
throw new ArgumentException();
}
IntPtr zero = IntPtr.Zero;
if (previous == null) {
ptr = IntPtr.Zero;
} else {
ptr = SspiProvider.CertDuplicateCertificateContext(previous.Handle);
}
DataBlob pvFindPara = new DataBlob();
if (SspiProvider.CertStrToName(0x10001, name, 3, IntPtr.Zero, IntPtr.Zero, ref pvFindPara.cbData, IntPtr.Zero) == 0) {
throw new CertificateException("Could not encode the specified string. [is the string a valid X500 string?]");
}
pvFindPara.pbData = Marshal.AllocHGlobal(pvFindPara.cbData);
try {
if (SspiProvider.CertStrToName(0x10001, name, 3, IntPtr.Zero, pvFindPara.pbData, ref pvFindPara.cbData, IntPtr.Zero) == 0) {
throw new CertificateException("Could not encode the specified string.");
}
zero = SspiProvider.CertFindDataBlobCertificateInStore(this.Handle, 0x10001, 0, 0x20007, ref pvFindPara, ptr);
} finally {
Marshal.FreeHGlobal(pvFindPara.pbData);
}
if (zero == IntPtr.Zero) {
return null;
}
return new Certificate(zero);
}
public Certificate FindCertificateBySubjectString(string subject)
{
return this.FindCertificateBySubjectString(subject, null);
}
public Certificate FindCertificateBySubjectString(string subject, Certificate previous)
{
IntPtr zero;
if (subject == null) {
throw new ArgumentNullException();
}
if (subject.Length == 0) {
throw new ArgumentException();
}
if (previous == null) {
zero = IntPtr.Zero;
} else {
zero = SspiProvider.CertDuplicateCertificateContext(previous.Handle);
}
IntPtr handle = SspiProvider.CertFindStringCertificateInStore(this.Handle, 0x10001, 0, 0x80007, subject, zero);
if (handle == IntPtr.Zero) {
return null;
}
return new Certificate(handle);
}
public Certificate FindCertificateByUsage(string[] keyUsage)
{
return this.FindCertificateByUsage(keyUsage, null);
}
public Certificate FindCertificateByUsage(string[] keyUsage, Certificate previous)
{
IntPtr zero;
if (keyUsage == null) {
throw new ArgumentNullException();
}
if (keyUsage.Length == 0) {
throw new ArgumentException();
}
int cb = 0;
for (int i = 0; i < keyUsage.Length; i++) {
if ((keyUsage[i] == null) || (keyUsage[i].Length == 0)) {
throw new ArgumentException();
}
cb += keyUsage[i].Length + 1;
}
IntPtr hglobal = Marshal.AllocHGlobal(cb);
IntPtr ptr = Marshal.AllocHGlobal((int)(IntPtr.Size * keyUsage.Length));
cb = 0;
IntPtr destination = hglobal;
for (int j = 0; j < keyUsage.Length; j++) {
Marshal.Copy(Encoding.ASCII.GetBytes(keyUsage[j] + "\0"), 0, destination, keyUsage[j].Length + 1);
Marshal.WriteIntPtr(ptr, j * IntPtr.Size, destination);
destination = new IntPtr((hglobal.ToInt64() + keyUsage[j].Length) + 1L);
}
TrustListUsage pvFindPara = new TrustListUsage {
cUsageIdentifier = keyUsage.Length,
rgpszUsageIdentifier = ptr
};
if (previous == null) {
zero = IntPtr.Zero;
} else {
zero = SspiProvider.CertDuplicateCertificateContext(previous.Handle);
}
IntPtr handle = SspiProvider.CertFindUsageCertificateInStore(this.Handle, 0x10001, 0, 0xa0000, ref pvFindPara, zero);
Marshal.FreeHGlobal(ptr);
Marshal.FreeHGlobal(hglobal);
if (handle.Equals(IntPtr.Zero)) {
return null;
}
return new Certificate(handle, this);
}
private byte[] GetCerBuffer(CertificateStoreType type)
{
byte[] buffer2;
DataBlob pvSaveToPara = new DataBlob();
try {
pvSaveToPara.cbData = 0;
pvSaveToPara.pbData = IntPtr.Zero;
if (SspiProvider.CertSaveStore(this.Handle, 0x10001, (int)type, 2, ref pvSaveToPara, 0) == 0) {
throw new CertificateException("Unable to get the certificate data.");
}
pvSaveToPara.pbData = Marshal.AllocHGlobal(pvSaveToPara.cbData);
if (SspiProvider.CertSaveStore(this.Handle, 0x10001, (int)type, 2, ref pvSaveToPara, 0) == 0) {
throw new CertificateException("Unable to get the certificate data.");
}
byte[] destination = new byte[pvSaveToPara.cbData];
Marshal.Copy(pvSaveToPara.pbData, destination, 0, pvSaveToPara.cbData);
buffer2 = destination;
} finally {
if (pvSaveToPara.pbData != IntPtr.Zero) {
Marshal.FreeHGlobal(pvSaveToPara.pbData);
}
}
return buffer2;
}
internal static byte[] GetFileContents(string file)
{
byte[] buffer;
if (file == null) {
throw new ArgumentNullException();
}
try {
FileStream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
buffer = new byte[stream.Length];
for (int i = stream.Read(buffer, 0, buffer.Length); i < stream.Length; i += stream.Read(buffer, i, buffer.Length - i)) {}
stream.Close();
} catch (Exception exception) {
throw new IOException("An error occurs while reading from the file.", exception);
}
return buffer;
}
private byte[] GetPfxBuffer(string password, bool exportPrivateKeys)
{
byte[] buffer2;
if (password == null) {
throw new ArgumentNullException();
}
DataBlob pPFX = new DataBlob();
try {
pPFX.pbData = IntPtr.Zero;
pPFX.cbData = 0;
if (SspiProvider.PFXExportCertStoreEx(this.Handle, ref pPFX, password, IntPtr.Zero, exportPrivateKeys ? 4 : 0) == 0) {
throw new CertificateException("Could not export the certificate store.");
}
pPFX.pbData = Marshal.AllocHGlobal(pPFX.cbData);
if (SspiProvider.PFXExportCertStoreEx(this.Handle, ref pPFX, password, IntPtr.Zero, exportPrivateKeys ? 4 : 0) == 0) {
throw new CertificateException("Could not export the certificate store.");
}
byte[] destination = new byte[pPFX.cbData];
Marshal.Copy(pPFX.pbData, destination, 0, destination.Length);
buffer2 = destination;
} finally {
if (pPFX.pbData != IntPtr.Zero) {
Marshal.FreeHGlobal(pPFX.pbData);
}
}
return buffer2;
}
protected void InitStore(IntPtr handle, bool duplicate)
{
if (handle == IntPtr.Zero) {
throw new ArgumentException("Invalid certificate store handle!");
}
if (duplicate) {
this.m_Handle = SspiProvider.CertDuplicateStore(handle);
} else {
this.m_Handle = handle;
}
}
private void SaveToFile(byte[] buffer, string filename)
{
if ((filename == null) || (buffer == null)) {
throw new ArgumentNullException();
}
try {
FileStream stream = File.Open(filename, FileMode.CreateNew, FileAccess.Write, FileShare.None);
stream.Write(buffer, 0, buffer.Length);
stream.Close();
} catch (Exception exception) {
throw new IOException("Could not write data to file.", exception);
}
}
public byte[] ToCerBuffer(CertificateStoreType type)
{
return this.GetCerBuffer(type);
}
public void ToCerFile(string filename, CertificateStoreType type)
{
this.SaveToFile(this.GetCerBuffer(type), filename);
}
public byte[] ToPfxBuffer(string password, bool exportPrivateKeys)
{
return this.GetPfxBuffer(password, exportPrivateKeys);
}
public void ToPfxFile(string filename, string password, bool exportPrivateKeys)
{
this.SaveToFile(this.GetPfxBuffer(password, exportPrivateKeys), filename);
}
public IntPtr Handle
{
get { return this.m_Handle; }
}
}
}