/* * Mentalis.org Security Library * * Copyright © 2002-2005, The KPD-Team * All rights reserved. * http://www.mentalis.org/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Neither the name of the KPD-Team, nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.IO; using System.Text; using System.Security; using System.Collections; using System.Runtime.InteropServices; namespace Org.Mentalis.Security.Certificates { /// /// Defines a certificate store. /// public class CertificateStore { /// /// Creates a new certificate store from a PFX/P12 encoded file. /// /// The full path to the PFX file. /// The password used to encrypt the private key. /// A instance. /// or is a null reference (Nothing in Visual Basic). /// An error occurs whil reading from the specified file. /// An error occurs while loading the PFX file. /// is invalid. public static CertificateStore CreateFromPfxFile(string file, string password) { return CreateFromPfxFile(GetFileContents(file), password); } /// /// Creates a new certificate store from a PFX/P12 encoded file. /// /// The full path to the PFX file. /// The password used to encrypt the private key. /// true if the private keys associated with the certificates should be marked as exportable, false otherwise. /// A instance. /// or is a null reference (Nothing in Visual Basic). /// An error occurs whil reading from the specified file. /// An error occurs while loading the PFX file. /// is invalid. public static CertificateStore CreateFromPfxFile(string file, string password, bool exportable) { return CreateFromPfxFile(GetFileContents(file), password, exportable); } /// /// Creates a new certificate store from a PFX/P12 encoded file. /// /// The full path to the PFX file. /// The password used to encrypt the private key. /// true if the private keys associated with the certificates should be marked as exportable, false otherwise. /// One of the values. /// A instance. /// or is a null reference (Nothing in Visual Basic). /// An error occurs whil reading from the specified file. /// An error occurs while loading the PFX file. /// is invalid. public static CertificateStore CreateFromPfxFile(string file, string password, bool exportable, KeysetLocation location) { return CreateFromPfxFile(GetFileContents(file), password, exportable, location); } /// /// Creates a new certificate store from a PFX/P12 encoded file. /// /// The contents of a PFX file. /// The password used to encrypt the private key. /// A instance. /// or is a null reference (Nothing in Visual Basic). /// is invalid. /// An error occurs while loading the PFX file. public static CertificateStore CreateFromPfxFile(byte[] file, string password) { return CreateFromPfxFile(file, password, false); } /// /// Creates a new certificate store from a PFX/P12 encoded file. /// /// The contents of a PFX file. /// The password used to encrypt the private key. /// true if the private keys associated with the certificates should be marked as exportable, false otherwise. /// A instance. /// or is a null reference (Nothing in Visual Basic). /// is invalid. /// An error occurs while loading the PFX file. public static CertificateStore CreateFromPfxFile(byte[] file, string password, bool exportable) { return CreateFromPfxFile(file, password, exportable, KeysetLocation.Default); } /// /// Creates a new certificate store from a PFX/P12 encoded file. /// /// The contents of a PFX file. /// The password used to encrypt the private key. /// true if the private keys associated with the certificates should be marked as exportable, false otherwise. /// One of the values. /// A instance. /// or is a null reference (Nothing in Visual Basic). /// is invalid. /// An error occurs while loading the PFX file. // Thanks go out to Chris Hudel for the implementation of this method. 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."); CertificateStore cs; DataBlob pPFX = new DataBlob(); // Crypt_data_blob contains two elements, // cbData = the size of the blob // pbData = a byte array of [cbData] size containing contents of the .p12 file pPFX.cbData = file.Length; // We need to marshal the byte array Bytes into a pointer so that it can be placed // in the structure (class) for the WinAPI call IntPtr buffer = Marshal.AllocHGlobal(file.Length); Marshal.Copy(file, 0, buffer, file.Length); pPFX.pbData = buffer; // IF this really is a valid PFX file, then do some work on it try { if (SspiProvider.PFXIsPFXBlob(ref pPFX) != 0) { if (SspiProvider.PFXVerifyPassword(ref pPFX, password, 0) != 0) { int flags = (int)location; if (exportable) flags |= SecurityConstants.CRYPT_EXPORTABLE; IntPtr m_Handle = SspiProvider.PFXImportCertStore(ref pPFX, password, flags); if (m_Handle.Equals(IntPtr.Zero)) { throw new CertificateException("Unable to import the PFX file! [error code = " + Marshal.GetLastWin32Error() + "]"); } cs = new CertificateStore(m_Handle); } else { throw new ArgumentException("The specified password is invalid."); } } else { throw new CertificateException("The specified file is not a PFX file."); } } finally { // Free the pointer Marshal.FreeHGlobal(buffer); } return cs; } /// /// Returns the contents of a file. /// /// The file to read from. /// A byte array with the contents of the specified file. /// is a null reference (Nothing in Visual Basic). /// An error occurs while reading from the specified file. internal static byte[] GetFileContents(string file) { if (file == null) throw new ArgumentNullException(); byte[] ret; try { FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); ret = new byte[fs.Length]; int read = fs.Read(ret, 0, ret.Length); while(read < fs.Length) { read += fs.Read(ret, read, ret.Length - read); } fs.Close(); } catch (Exception e) { throw new IOException("An error occurs while reading from the file.", e); } return ret; } /// /// Creates a new certificate store from a certificate file. /// /// The certificate file. /// A instance. /// is a null reference (Nothing in Visual Basic). /// An error occurs while loading the certificate. /// The provider opens the file and first attempts to read the file as a serialized store, then as a PKCS #7 signed message, and finally as a single encoded certificate. public static CertificateStore CreateFromCerFile(string file) { if (file == null) throw new ArgumentNullException("The filename cannot be a null reference."); IntPtr cs = SspiProvider.CertOpenStore(new IntPtr(SecurityConstants.CERT_STORE_PROV_FILENAME_A), SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, 0, 0, file); if (cs == IntPtr.Zero) throw new CertificateException("An error occurs while opening the specified store."); return new CertificateStore(cs); } /// /// Duplicates an exisiting . /// /// The store to duplicate. /// is a null reference (Nothing in Visual Basic). public CertificateStore(CertificateStore store) { if (store == null) throw new ArgumentNullException(); InitStore(store.m_Handle, true); } /// /// Initializes a new from a given handle. /// /// The handle from which to initialize the CertificateStore from. /// The handle will not be duplicated; when this CertificateStore instance is garbage collected, the handle will be freed. /// is invalid. public CertificateStore(IntPtr handle) : this(handle, false) {} /// /// Initializes a new from a given handle. /// /// The handle from which to initialize the CertificateStore from. /// true if the handle should be duplicated, false otherwise. /// is invalid. public CertificateStore(IntPtr handle, bool duplicate) { InitStore(handle, duplicate); } /// /// Initializes a new from a given store name. /// /// The name of the system store to open. /// is a null reference (Nothing in Visual Basic). /// An error occurs while opening the specified store. /// ///

If the system store name provided in this parameter is not the name of an existing system store, a new system store will be created and used.

///

Some example system stores are listed in the following table. /// /// /// Predefined system store name /// Meaning /// /// /// "CA" /// Certification authority certificates. /// /// /// "MY" /// A certificate store holding "My" certificates with their associated private keys. /// /// /// "ROOT" /// Root certificates. /// /// /// "SPC" /// Software publisher certificates. /// ///

///
public CertificateStore(string store) : this(StoreLocation.Users, store) {} /// /// Initializes a new from a given store name and a given store location. /// /// The location of the store. /// The name of the store to open. /// is a null reference (Nothing in Visual Basic). /// An error occurs while opening the specified store. public CertificateStore(StoreLocation location, string store) { if (store == null) throw new ArgumentNullException("The name of the store cannot be a null reference."); m_Handle = SspiProvider.CertOpenStore(new IntPtr(SecurityConstants.CERT_STORE_PROV_SYSTEM_A), 0, 0, (int)location, store); if (m_Handle == IntPtr.Zero) throw new CertificateException("An error occurs while opening the specified store."); } /// /// Initializes a new temporary in memory. /// /// If the store is closed, all the data in the store is lost. /// An error occurs while creating the store. public CertificateStore() { m_Handle = SspiProvider.CertOpenStore(new IntPtr(SecurityConstants.CERT_STORE_PROV_MEMORY), SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, 0, 0, null); if (m_Handle == IntPtr.Zero) throw new CertificateException("An error occurs while creating the store."); } /// /// Initializes a new temporary in memory and adds the specified certificates to it. /// /// A set of certificates. /// If the store is closed, all the data in the store is lost. /// certs contains at least one object that is not of type . public CertificateStore(IEnumerable certs) : this() { IEnumerator enm = certs.GetEnumerator(); while(enm.MoveNext()) { AddCertificate((Certificate)enm.Current); } } /// /// Opens a serialized certificate store or a certificate store with signed PKCS7 messages. /// /// The bytes of the store to open. /// One of the values. /// is a null reference (Nothing in Visual Basic). /// An error occurs while opening the store. public CertificateStore(byte[] buffer, CertificateStoreType type) { if (buffer == null) throw new ArgumentNullException(); DataBlob data = new DataBlob(); data.cbData = buffer.Length; data.pbData = Marshal.AllocHGlobal(data.cbData); Marshal.Copy(buffer, 0, data.pbData, buffer.Length); IntPtr provider; if (type == CertificateStoreType.Pkcs7Message) provider = new IntPtr(SecurityConstants.CERT_STORE_PROV_PKCS7); else provider = new IntPtr(SecurityConstants.CERT_STORE_PROV_SERIALIZED); m_Handle = SspiProvider.CertOpenStoreData(provider, SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, IntPtr.Zero, 0, ref data); Marshal.FreeHGlobal(data.pbData); if (m_Handle == IntPtr.Zero) throw new CertificateException("An error occurs while opening the store."); } /// /// Initializes a new from a given handle. /// /// The handle from which to initialize the CertificateStore from. /// true if the handle should be duplicated, false otherwise. /// is invalid. protected void InitStore(IntPtr handle, bool duplicate) { if (handle == IntPtr.Zero) throw new ArgumentException("Invalid certificate store handle!"); if(duplicate) m_Handle = SspiProvider.CertDuplicateStore(handle); else m_Handle = handle; } /// /// Returns the first certificate from the . /// /// A from the store. public Certificate FindCertificate() { return FindCertificate((Certificate)null); } /// /// Returns a certificate from the . /// /// The previous certificate. /// The that comes after -or- a null reference (Nothing in Visual Basic) if there is no certificate after . public Certificate FindCertificate(Certificate previous) { IntPtr prev; if (previous == null) prev = IntPtr.Zero; else prev = SspiProvider.CertDuplicateCertificateContext(previous.Handle); IntPtr ret = SspiProvider.CertFindCertificateInStore(Handle, SecurityConstants.X509_ASN_ENCODING, 0, SecurityConstants.CERT_FIND_ANY, IntPtr.Zero, prev); if (ret.Equals(IntPtr.Zero)) return null; else return new Certificate(ret, this); } /// /// Finds a certificate having an enhanced key extension that matches one of the members. /// /// The list of enhanced key usages to search for. /// A that has at least one of the specified key usages -or- a null reference (Nothing in Visual Basic) if no valid certificate could be found. /// is a null reference (Nothing in Visual Basic). /// is invalid. public Certificate FindCertificateByUsage(string[] keyUsage) { return FindCertificateByUsage(keyUsage, null); } /// /// Finds a certificate having an enhanced key extension that matches one of the members. /// /// The list of enhanced key usages to search for. /// The previous certificate. /// The that comes after and that has at least one of the specified key usages -or- a null reference (Nothing in Visual Basic) if no other valid certificate could be found. /// is a null reference (Nothing in Visual Basic). /// is invalid. public Certificate FindCertificateByUsage(string[] keyUsage, Certificate previous) { // "1.3.6.1.5.5.7.3.1" is the Server Authentication OID as defined in RFC2459 if (keyUsage == null) throw new ArgumentNullException(); if (keyUsage.Length == 0) throw new ArgumentException(); int total = 0; for(int i = 0; i < keyUsage.Length; i++) { if (keyUsage[i] == null || keyUsage[i].Length == 0) throw new ArgumentException(); total += keyUsage[i].Length + 1; } IntPtr storage = Marshal.AllocHGlobal(total); // block of memory that contains all the strings IntPtr list = Marshal.AllocHGlobal(IntPtr.Size * keyUsage.Length); // list of pointers to the strings total = 0; IntPtr s = storage; for(int i = 0; i < keyUsage.Length; i++) { Marshal.Copy(Encoding.ASCII.GetBytes(keyUsage[i] + "\0"), 0, s, keyUsage[i].Length + 1); Marshal.WriteIntPtr(list, i * IntPtr.Size, s); s = new IntPtr(storage.ToInt64() + keyUsage[i].Length + 1); } // search for a certificate TrustListUsage usage = new TrustListUsage(); usage.cUsageIdentifier = keyUsage.Length; usage.rgpszUsageIdentifier = list; IntPtr prev; if (previous == null) prev = IntPtr.Zero; else prev = SspiProvider.CertDuplicateCertificateContext(previous.Handle); IntPtr ret = SspiProvider.CertFindUsageCertificateInStore(Handle, SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, 0, SecurityConstants.CERT_FIND_CTL_USAGE, ref usage, prev); Marshal.FreeHGlobal(list); Marshal.FreeHGlobal(storage); if (ret.Equals(IntPtr.Zero)) return null; else return new Certificate(ret, this); } /// /// Finds a certificate with a matching hash. /// /// The hash to search for. /// The with the matching default hash -or- a null reference (Nothing in Visual Basic) if no certificate with that hash could be found in the store. /// is a null reference (Nothing in Visual Basic). public Certificate FindCertificateByHash(byte[] hash) { return FindCertificateByHash(hash, HashType.Default); } /// /// Finds a certificate with a matching hash. /// /// The hash to search for. /// One of the HashType values. /// The with the matching hash -or- a null reference (Nothing in Visual Basic) if no certificate with that hash could be found in the store. /// is a null reference (Nothing in Visual Basic). public Certificate FindCertificateByHash(byte[] hash, HashType hashType) { if (hash == null) throw new ArgumentNullException(); int findType; if (hashType == HashType.SHA1) findType = SecurityConstants.CERT_FIND_SHA1_HASH; else if (hashType == HashType.MD5) findType = SecurityConstants.CERT_FIND_MD5_HASH; else findType = SecurityConstants.CERT_FIND_HASH; DataBlob data = new DataBlob(); data.cbData = hash.Length; data.pbData = Marshal.AllocHGlobal(hash.Length); Marshal.Copy(hash, 0, data.pbData, hash.Length); IntPtr cert = SspiProvider.CertFindDataBlobCertificateInStore(this.Handle, SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, 0, findType, ref data, IntPtr.Zero); Marshal.FreeHGlobal(data.pbData); if (cert == IntPtr.Zero) return null; else return new Certificate(cert); } /// /// Finds a certificate with a matching key identifier. /// /// The key identifier to search for. /// The with the matching key identifier -or- a null reference (Nothing in Visual Basic) if no matching certificate could be found in the store. /// is a null reference (Nothing in Visual Basic). /// is invalid. public Certificate FindCertificateByKeyIdentifier(byte[] keyID) { if (keyID == null) throw new ArgumentNullException(); if (keyID.Length == 0) throw new ArgumentException(); DataBlob data = new DataBlob(); data.cbData = keyID.Length; data.pbData = Marshal.AllocHGlobal(keyID.Length); Marshal.Copy(keyID, 0, data.pbData, keyID.Length); IntPtr cert = SspiProvider.CertFindDataBlobCertificateInStore(this.Handle, SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, 0, SecurityConstants.CERT_FIND_KEY_IDENTIFIER, ref data, IntPtr.Zero); Marshal.FreeHGlobal(data.pbData); if (cert == IntPtr.Zero) return null; else return new Certificate(cert); } /// /// Finds a certificate with a matching subject name. /// /// The X500 string to search for. /// A with a matching subject name -or- a null reference (Nothing in Visual Basic) if no matching certificate could be found in the store. /// is a null reference (Nothing in Visual Basic). /// is invalid. public Certificate FindCertificateBySubjectName(string name) { return FindCertificateBySubjectName(name, null); } /// /// Finds a certificate with a matching subject name. /// /// The X500 string to search for. /// The previous certificate. /// A with a matching subject name -or- a null reference (Nothing in Visual Basic) if no matching certificate could be found in the store. /// is a null reference (Nothing in Visual Basic). /// is invalid. /// An error occurs while encoding the specified string. public Certificate FindCertificateBySubjectName(string name, Certificate previous) { if (name == null) throw new ArgumentNullException(); if (name.Length == 0) throw new ArgumentException(); IntPtr prev, cert = IntPtr.Zero; if (previous == null) prev = IntPtr.Zero; else prev = SspiProvider.CertDuplicateCertificateContext(previous.Handle); DataBlob data = new DataBlob(); if (SspiProvider.CertStrToName(SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, name, SecurityConstants.CERT_X500_NAME_STR, IntPtr.Zero, IntPtr.Zero, ref data.cbData, IntPtr.Zero) == 0) throw new CertificateException("Could not encode the specified string. [is the string a valid X500 string?]"); data.pbData = Marshal.AllocHGlobal(data.cbData); try { if (SspiProvider.CertStrToName(SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, name, SecurityConstants.CERT_X500_NAME_STR, IntPtr.Zero, data.pbData, ref data.cbData, IntPtr.Zero) == 0) throw new CertificateException("Could not encode the specified string."); cert = SspiProvider.CertFindDataBlobCertificateInStore(this.Handle, SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, 0, SecurityConstants.CERT_FIND_SUBJECT_NAME, ref data, prev); } finally { Marshal.FreeHGlobal(data.pbData); } if (cert == IntPtr.Zero) return null; else return new Certificate(cert); } /// /// Finds a certificate with a subject that contains a specified string. /// /// The string to search for. /// A with a matching subject string -or- a null reference (Nothing in Visual Basic) if no matching certificate could be found in the store. /// is a null reference (Nothing in Visual Basic). /// is invalid. /// The string matching algorithm used is case-insensitive. public Certificate FindCertificateBySubjectString(string subject) { return FindCertificateBySubjectString(subject, null); } /// /// Finds a certificate with a subject that contains a specified string. /// /// The string to search for. /// The previous certificate. /// A with a matching subject string -or- a null reference (Nothing in Visual Basic) if no matching certificate could be found in the store. /// is a null reference (Nothing in Visual Basic). /// is invalid. /// The string matching algorithm used is case-insensitive. public Certificate FindCertificateBySubjectString(string subject, Certificate previous) { if (subject == null) throw new ArgumentNullException(); if (subject.Length == 0) throw new ArgumentException(); IntPtr prev; if (previous == null) prev = IntPtr.Zero; else prev = SspiProvider.CertDuplicateCertificateContext(previous.Handle); IntPtr cert = SspiProvider.CertFindStringCertificateInStore(this.Handle, SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, 0, SecurityConstants.CERT_FIND_SUBJECT_STR_W, subject, prev); if (cert == IntPtr.Zero) return null; else return new Certificate(cert); } /// /// Enumerates all the certificates in the store. /// /// An array of instances. public Certificate[] EnumCertificates() { ArrayList certs = new ArrayList(); Certificate prev = FindCertificate(); while(prev != null) { certs.Add(prev); prev = FindCertificate(prev); } return (Certificate[])certs.ToArray(typeof(Certificate)); } /// /// Enumerates all the certificates in the store. /// /// The list of enhanced key usages to search for. /// An array of instances. /// is a null reference (Nothing in Visual Basic). /// is invalid. public Certificate[] EnumCertificates(string[] keyUsage) { ArrayList certs = new ArrayList(); Certificate prev = FindCertificateByUsage(keyUsage); while(prev != null) { certs.Add(prev); prev = FindCertificateByUsage(keyUsage, prev); } return (Certificate[])certs.ToArray(typeof(Certificate)); } /// /// Saves the as a PFX encoded file. /// /// The filename of the new PFX file. /// The password to use when encrypting the private keys. /// true if the private keys should be exported [if possible], false otherwise. /// If the specified file already exists, the method will throw an exception. /// or is a null reference (Nothing in Visual Basic). /// An error occurs while exporting the certificate store. /// An error occurs while writing the data to the file. public void ToPfxFile(string filename, string password, bool exportPrivateKeys) { SaveToFile(GetPfxBuffer(password, exportPrivateKeys), filename); } /// /// Saves the as a PFX encoded file. /// /// The password to use when encrypting the private keys. /// true if the private keys should be exported [if possible], false otherwise. /// An array of bytes that represents the PFX encoded store. /// is a null reference (Nothing in Visual Basic). /// An error occurs while exporting the certificate store. public byte[] ToPfxBuffer(string password, bool exportPrivateKeys) { return GetPfxBuffer(password, exportPrivateKeys); } /// /// Returns the byte representation of the PFX encoded store. /// /// The password to use when encrypting the private keys. /// true if the private keys should be exported [if possible], false otherwise. /// An array of bytes that represents the PFX encoded store. /// is a null reference (Nothing in Visual Basic). private byte[] GetPfxBuffer(string password, bool exportPrivateKeys) { if (password == null) throw new ArgumentNullException(); DataBlob data = new DataBlob(); try { data.pbData = IntPtr.Zero; data.cbData = 0; if (SspiProvider.PFXExportCertStoreEx(Handle, ref data, password, IntPtr.Zero, exportPrivateKeys ? SecurityConstants.EXPORT_PRIVATE_KEYS : 0) == 0) throw new CertificateException("Could not export the certificate store."); data.pbData = Marshal.AllocHGlobal(data.cbData); if (SspiProvider.PFXExportCertStoreEx(Handle, ref data, password, IntPtr.Zero, exportPrivateKeys ? SecurityConstants.EXPORT_PRIVATE_KEYS : 0) == 0) throw new CertificateException("Could not export the certificate store."); byte[] buffer = new byte[data.cbData]; Marshal.Copy(data.pbData, buffer, 0, buffer.Length); return buffer; } finally { if (data.pbData != IntPtr.Zero) Marshal.FreeHGlobal(data.pbData); } } /// /// Saves the in a file. /// /// The filename of the serialized store. /// One of the values. /// is a null reference (Nothing in Visual Basic). /// An error occurs while saving the store to the memory buffer. /// An error occurs while writing the data. public void ToCerFile(string filename, CertificateStoreType type) { SaveToFile(GetCerBuffer(type), filename); } /// /// Saves the in a buffer. /// /// One of the values. /// An array of bytes that represents the encoded store. /// An error occurs while saving the store to the memory buffer. public byte[] ToCerBuffer(CertificateStoreType type) { return GetCerBuffer(type); } /// /// Returns the byte representation of the serialized store. /// /// One of the values. /// An array of bytes that represents the encoded store. /// An error occurs while saving the store to the memory buffer. private byte[] GetCerBuffer(CertificateStoreType type) { DataBlob data = new DataBlob(); try { data.cbData = 0; data.pbData = IntPtr.Zero; if (SspiProvider.CertSaveStore(this.Handle, SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, (int)type, SecurityConstants.CERT_STORE_SAVE_TO_MEMORY, ref data, 0) == 0) throw new CertificateException("Unable to get the certificate data."); data.pbData = Marshal.AllocHGlobal(data.cbData); if (SspiProvider.CertSaveStore(this.Handle, SecurityConstants.X509_ASN_ENCODING | SecurityConstants.PKCS_7_ASN_ENCODING, (int)type, SecurityConstants.CERT_STORE_SAVE_TO_MEMORY, ref data, 0) == 0) throw new CertificateException("Unable to get the certificate data."); byte[] ret = new byte[data.cbData]; Marshal.Copy(data.pbData, ret, 0, data.cbData); return ret; } finally { if (data.pbData != IntPtr.Zero) Marshal.FreeHGlobal(data.pbData); } } /// /// Writes a buffer with data to a file. /// /// The buffer to write. /// The filename to write the data to. /// or is a null reference (Nothing in Visual Basic). /// An error occurs while writing the data. private void SaveToFile(byte[] buffer, string filename) { if (filename == null || buffer == 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); } } /// /// Adds a to the . /// /// The certificate to add to the store. /// is a null reference (Nothing in Visual Basic). /// An error occurs while adding the certificate to the store. public void AddCertificate(Certificate cert) { if (cert == null) throw new ArgumentNullException(); if (SspiProvider.CertAddCertificateContextToStore(this.Handle, cert.Handle, SecurityConstants.CERT_STORE_ADD_NEW, IntPtr.Zero) == 0) { if (Marshal.GetLastWin32Error() != SecurityConstants.CRYPT_E_EXISTS) throw new CertificateException("An error occurs while adding the certificate to the store."); } } /// /// Deletes a from the . /// /// is a null reference (Nothing in Visual Basic). /// An error occurs while removing the certificate from the store. public void DeleteCertificate(Certificate cert) { if (cert == null) throw new ArgumentNullException(); Certificate sci = FindCertificateByHash(cert.GetCertHash(HashType.SHA1), HashType.SHA1); if (sci == null) throw new CertificateException("The certificate could not be found in the store."); if (SspiProvider.CertDeleteCertificateFromStore(SspiProvider.CertDuplicateCertificateContext(sci.Handle)) == 0) throw new CertificateException("An error occurs while removing the certificate from the store."); } /// /// Gets the handle of the CertificateStore. /// /// An IntPtr that represents the handle of the certificate. /// The handle returned by this property should not be closed. If the handle is closed by an external actor, the methods of the CertificateStore object may fail in undocumented ways [for instance, an Access Violation may occur]. public IntPtr Handle { get { return m_Handle; } } /// /// Disposes of the . /// ~CertificateStore() { if (Handle != IntPtr.Zero) { SspiProvider.CertCloseStore(Handle, 0); m_Handle = IntPtr.Zero; } } /// /// Holds the handle of the certificate store. /// private IntPtr m_Handle; /// Represents the predefined system certificate store "CA". This field is constant. public const string CAStore = "CA"; /// Represents the predefined system certificate store "My". This field is constant. public const string MyStore = "My"; /// Represents the predefined system certificate store "Root". This field is constant. public const string RootStore = "Root"; /// Represents the predefined system certificate store "Trust". This field is constant. public const string TrustStore = "Trust"; /// Represents the untrusted certificate store. This field is constant. public const string UnTrustedStore = "Disallowed"; /// Represents the software publisher certificate store. This field is constant. public const string SoftwarePublisherStore = "SPC"; } }