X509Certificate2.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / security / system / security / cryptography / x509 / X509Certificate2.cs / 1 / X509Certificate2.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

// 
// X509Certificate2.cs 
//
// 09/22/2002 
//

namespace System.Security.Cryptography.X509Certificates {
    using System; 
    using System.Diagnostics;
    using System.IO; 
    using System.Text; 
    using System.Reflection;
    using System.Runtime.InteropServices; 
    using System.Runtime.InteropServices.ComTypes;
    using System.Security.Cryptography;
    using System.Security.Permissions;
 
    using _FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
 
    public enum X509NameType { 
        SimpleName = 0,
        EmailName, 
        UpnName,
        DnsName,
        DnsFromAlternativeName,
        UrlName 
    }
 
    public enum X509IncludeOption { 
        None = 0,
        ExcludeRoot, 
        EndCertOnly,
        WholeChain
    }
 
    public sealed class PublicKey {
        private AsnEncodedData m_encodedKeyValue; 
        private AsnEncodedData m_encodedParameters; 
        private Oid m_oid;
        private uint m_aiPubKey = 0; 
        private byte[] m_cspBlobData = null;
        private AsymmetricAlgorithm m_key = null;

        private PublicKey() {} 

        public PublicKey (Oid oid, AsnEncodedData parameters, AsnEncodedData keyValue) { 
            m_oid = new Oid(oid); 
            m_encodedParameters = new AsnEncodedData(parameters);
            m_encodedKeyValue = new AsnEncodedData(keyValue); 
        }

        internal PublicKey (PublicKey publicKey) {
            m_oid = new Oid(publicKey.m_oid); 
            m_encodedParameters = new AsnEncodedData(publicKey.m_encodedParameters);
            m_encodedKeyValue = new AsnEncodedData(publicKey.m_encodedKeyValue); 
        } 

        internal uint AlgorithmId { 
            get {
                if (m_aiPubKey == 0)
                    m_aiPubKey = X509Utils.OidToAlgId(m_oid.Value);
                return m_aiPubKey; 
            }
        } 
 
        private byte[] CspBlobData {
            get { 
                if (m_cspBlobData == null)
                    DecodePublicKeyObject(AlgorithmId, m_encodedKeyValue.RawData, m_encodedParameters.RawData, out m_cspBlobData);
                return m_cspBlobData;
            } 
        }
 
        public AsymmetricAlgorithm Key { 
            get {
                if (m_key == null) { 
                    switch (AlgorithmId) {
                    case CAPI.CALG_RSA_KEYX:
                    case CAPI.CALG_RSA_SIGN:
                        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
                        rsa.ImportCspBlob(CspBlobData);
                        m_key = rsa; 
                        break; 

                    case CAPI.CALG_DSS_SIGN: 
                        DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
                        dsa.ImportCspBlob(CspBlobData);
                        m_key = dsa;
                        break; 

                    default: 
                        throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm)); 
                    }
                } 
                return m_key;
            }
        }
 
        public Oid Oid {
            get { return new Oid(m_oid); } 
        } 

        public AsnEncodedData EncodedKeyValue { 
            get { return m_encodedKeyValue; }
        }

        public AsnEncodedData EncodedParameters { 
            get { return m_encodedParameters; }
        } 
 
        //
        // private static methods. 
        //

        private static void DecodePublicKeyObject(uint aiPubKey, byte[] encodedKeyValue, byte[] encodedParameters, out byte[] decodedData) {
            // Initialize the out parameter 
            decodedData = null;
            IntPtr pszStructType = IntPtr.Zero; 
            switch (aiPubKey) { 
            case CAPI.CALG_DSS_SIGN:
                pszStructType = new IntPtr(CAPI.X509_DSS_PUBLICKEY); 
                break;

            case CAPI.CALG_RSA_SIGN:
            case CAPI.CALG_RSA_KEYX: 
                pszStructType = new IntPtr(CAPI.RSA_CSP_PUBLICKEYBLOB);
                break; 
 
            case CAPI.CALG_DH_SF:
            case CAPI.CALG_DH_EPHEM: 
                // We don't support DH for now
                throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm));

            default: 
                // We should never get here
                Debug.Assert(false); 
                throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm)); 
            }
 
            SafeLocalAllocHandle decodedKeyValue = null;
            uint cbDecodedKeyValue = 0;
            bool result = CAPI.DecodeObject(pszStructType,
                                            encodedKeyValue, 
                                            out decodedKeyValue,
                                            out cbDecodedKeyValue); 
            if (!result) 
                throw new CryptographicException(Marshal.GetLastWin32Error());
 
            if ((uint) pszStructType == CAPI.RSA_CSP_PUBLICKEYBLOB) {
                decodedData = new byte[cbDecodedKeyValue];
                Marshal.Copy(decodedKeyValue.DangerousGetHandle(), decodedData, 0, decodedData.Length);
            } else if ((uint) pszStructType == CAPI.X509_DSS_PUBLICKEY) { 
                // We need to decode the parameters as well
                SafeLocalAllocHandle decodedParameters = null; 
                uint cbDecodedParameters = 0; 
                result = CAPI.DecodeObject(new IntPtr(CAPI.X509_DSS_PARAMETERS),
                                           encodedParameters, 
                                           out decodedParameters,
                                           out cbDecodedParameters);
                if (!result)
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 

                decodedData = ConstructDSSPubKeyCspBlob(decodedKeyValue, decodedParameters); 
                decodedParameters.Dispose(); 
            }
            decodedKeyValue.Dispose(); 
        }

        private static byte[] ConstructDSSPubKeyCspBlob (SafeLocalAllocHandle decodedKeyValue,
                                                         SafeLocalAllocHandle decodedParameters) { 

            // The CAPI DSS public key representation consists of the following sequence: 
            //  - PUBLICKEYSTRUC 
            //  - DSSPUBKEY
            //  - rgbP[cbKey] 
            //  - rgbQ[20]
            //  - rgbG[cbKey]
            //  - rgbY[cbKey]
            //  - DSSSEED 

            CAPI.CRYPTOAPI_BLOB pDssPubKey = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decodedKeyValue.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB)); 
            CAPI.CERT_DSS_PARAMETERS pDssParameters = (CAPI.CERT_DSS_PARAMETERS) Marshal.PtrToStructure(decodedParameters.DangerousGetHandle(), typeof(CAPI.CERT_DSS_PARAMETERS)); 

            uint cbKey = pDssParameters.p.cbData; 
            if (cbKey == 0)
                throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY);

            const uint DSS_Q_LEN = 20; 
            uint cbKeyBlob = 8 /* sizeof(CAPI.BLOBHEADER) */ + 8 /* sizeof(CAPI.DSSPUBKEY) */ +
                        cbKey + DSS_Q_LEN + cbKey + cbKey + 24 /* sizeof(CAPI.DSSSEED) */; 
 
            MemoryStream keyBlob = new MemoryStream((int) cbKeyBlob);
            BinaryWriter bw = new BinaryWriter(keyBlob); 

            // PUBLICKEYSTRUC
            bw.Write(CAPI.PUBLICKEYBLOB); // pPubKeyStruc->bType = PUBLICKEYBLOB
            bw.Write(CAPI.CUR_BLOB_VERSION); // pPubKeyStruc->bVersion = CUR_BLOB_VERSION 
            bw.Write((short) 0); // pPubKeyStruc->reserved = 0;
            bw.Write(CAPI.CALG_DSS_SIGN); // pPubKeyStruc->aiKeyAlg = CALG_DSS_SIGN; 
 
            // DSSPUBKEY
            bw.Write(CAPI.DSS_MAGIC); // pCspPubKey->magic = DSS_MAGIC; We are constructing a DSS1 Csp blob. 
            bw.Write(cbKey * 8); // pCspPubKey->bitlen = cbKey * 8;

            // rgbP[cbKey]
            byte[] p = new byte[pDssParameters.p.cbData]; 
            Marshal.Copy(pDssParameters.p.pbData, p, 0, p.Length);
            bw.Write(p); 
 
            // rgbQ[20]
            uint cb = pDssParameters.q.cbData; 
            if (cb == 0 || cb > DSS_Q_LEN)
                throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY);

            byte[] q = new byte[pDssParameters.q.cbData]; 
            Marshal.Copy(pDssParameters.q.pbData, q, 0, q.Length);
            bw.Write(q); 
            if (DSS_Q_LEN > cb) 
                bw.Write(new byte[DSS_Q_LEN - cb]);
 
            // rgbG[cbKey]
            cb = pDssParameters.g.cbData;
            if (cb == 0 || cb > cbKey)
                throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY); 

            byte[] g = new byte[pDssParameters.g.cbData]; 
            Marshal.Copy(pDssParameters.g.pbData, g, 0, g.Length); 
            bw.Write(g);
            if (cbKey > cb) 
                bw.Write(new byte[cbKey - cb]);

            // rgbY[cbKey]
            cb = pDssPubKey.cbData; 
            if (cb == 0 || cb > cbKey)
                throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY); 
 
            byte[] y = new byte[pDssPubKey.cbData];
            Marshal.Copy(pDssPubKey.pbData, y, 0, y.Length); 
            bw.Write(y);
            if (cbKey > cb)
                bw.Write(new byte[cbKey - cb]);
 
            // DSSSEED: set counter to 0xFFFFFFFF to indicate not available
            bw.Write(0xFFFFFFFF); 
            bw.Write(new byte[20]); 

            return keyBlob.ToArray(); 
        }
    }

    public class X509Certificate2 : X509Certificate { 
        private int m_version;
        private DateTime m_notBefore; 
        private DateTime m_notAfter; 
        private AsymmetricAlgorithm m_privateKey;
        private PublicKey m_publicKey; 
        private X509ExtensionCollection m_extensions;
        private Oid m_signatureAlgorithm;
        private X500DistinguishedName m_subjectName;
        private X500DistinguishedName m_issuerName; 
        private SafeCertContextHandle m_safeCertContext = SafeCertContextHandle.InvalidHandle;
        private bool m_randomKeyContainer; 
 
        private static int s_publicKeyOffset;
 
        //
        // public constructors
        //
 
        public X509Certificate2 () : base() {}
 
        public X509Certificate2 (byte[] rawData) : base (rawData) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true; 
        }

        public X509Certificate2 (byte[] rawData, string password) : base (rawData, password) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
            m_randomKeyContainer = true;
        } 
 
        public X509Certificate2 (byte[] rawData, SecureString password) : base (rawData, password) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
            m_randomKeyContainer = true;
        }

        public X509Certificate2 (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) : base (rawData, password, keyStorageFlags) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true; 
        } 

        public X509Certificate2 (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (rawData, password, keyStorageFlags) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true;
        }
 
        public X509Certificate2 (string fileName) : base (fileName) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
            m_randomKeyContainer = true; 
        }
 
        public X509Certificate2 (string fileName, string password) : base (fileName, password) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true;
        } 

        public X509Certificate2 (string fileName, SecureString password) : base (fileName, password) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
            m_randomKeyContainer = true;
        } 

        public X509Certificate2 (string fileName, string password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true; 
        }
 
        public X509Certificate2 (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true; 
        }

        // Package protected constructor for creating a certificate from a PCCERT_CONTEXT
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public X509Certificate2 (IntPtr handle) : base (handle) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        }
 
        public X509Certificate2 (X509Certificate certificate) : base(certificate) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);

            X509Certificate2 source = certificate as X509Certificate2; 
            if (source != null)
                m_randomKeyContainer = source.m_randomKeyContainer; 
        } 

        public override string ToString() { 
            return base.ToString(true);
        }

        public override string ToString(bool verbose) { 
            if (verbose == false || m_safeCertContext.IsInvalid)
                return ToString(); 
 
            StringBuilder sb = new StringBuilder();
 
            // Version
            sb.Append("[Version]" + Environment.NewLine + "  ");
            sb.Append("V" + this.Version);
 
            // Subject
            sb.Append(Environment.NewLine + Environment.NewLine + "[Subject]" + Environment.NewLine + "  "); 
            sb.Append(this.SubjectName.Name); 
            string simpleName = GetNameInfo(X509NameType.SimpleName, false);
            if (simpleName.Length > 0) { 
                sb.Append(Environment.NewLine + "  Simple Name: ");
                sb.Append(simpleName);
            }
            string emailName = GetNameInfo(X509NameType.EmailName, false); 
            if (emailName.Length > 0) {
                sb.Append(Environment.NewLine + "  Email Name: "); 
                sb.Append(emailName); 
            }
            string upnName = GetNameInfo(X509NameType.UpnName, false); 
            if (upnName.Length > 0) {
                sb.Append(Environment.NewLine + "  UPN Name: ");
                sb.Append(upnName);
            } 
            string dnsName = GetNameInfo(X509NameType.DnsName, false);
            if (dnsName.Length > 0) { 
                sb.Append(Environment.NewLine + "  DNS Name: "); 
                sb.Append(dnsName);
            } 

            // Issuer
            sb.Append(Environment.NewLine + Environment.NewLine + "[Issuer]" + Environment.NewLine + "  ");
            sb.Append(this.IssuerName.Name); 
            simpleName = GetNameInfo(X509NameType.SimpleName, true);
            if (simpleName.Length > 0) { 
                sb.Append(Environment.NewLine + "  Simple Name: "); 
                sb.Append(simpleName);
            } 
            emailName = GetNameInfo(X509NameType.EmailName, true);
            if (emailName.Length > 0) {
                sb.Append(Environment.NewLine + "  Email Name: ");
                sb.Append(emailName); 
            }
            upnName = GetNameInfo(X509NameType.UpnName, true); 
            if (upnName.Length > 0) { 
                sb.Append(Environment.NewLine + "  UPN Name: ");
                sb.Append(upnName); 
            }
            dnsName = GetNameInfo(X509NameType.DnsName, true);
            if (dnsName.Length > 0) {
                sb.Append(Environment.NewLine + "  DNS Name: "); 
                sb.Append(dnsName);
            } 
 
            // Serial Number
            sb.Append(Environment.NewLine + Environment.NewLine + "[Serial Number]" + Environment.NewLine + "  "); 
            sb.Append(this.SerialNumber);

            // NotBefore
            sb.Append(Environment.NewLine + Environment.NewLine + "[Not Before]" + Environment.NewLine + "  "); 
            sb.Append(this.NotBefore);
 
            // NotAfter 
            sb.Append(Environment.NewLine + Environment.NewLine + "[Not After]" + Environment.NewLine + "  ");
            sb.Append(this.NotAfter); 

            // Thumbprint
            sb.Append(Environment.NewLine + Environment.NewLine + "[Thumbprint]" + Environment.NewLine + "  ");
            sb.Append(this.Thumbprint); 

            // Signature Algorithm 
            sb.Append(Environment.NewLine + Environment.NewLine + "[Signature Algorithm]" + Environment.NewLine + "  "); 
            sb.Append(this.SignatureAlgorithm.FriendlyName + "(" + this.SignatureAlgorithm.Value + ")");
 
            // Public Key
            PublicKey pubKey = this.PublicKey;
            sb.Append(Environment.NewLine + Environment.NewLine + "[Public Key]" + Environment.NewLine + "  Algorithm: ");
            sb.Append(pubKey.Oid.FriendlyName); 
            sb.Append(Environment.NewLine + "  Length: ");
            sb.Append(pubKey.Key.KeySize); 
            sb.Append(Environment.NewLine + "  Key Blob: "); 
            sb.Append(pubKey.EncodedKeyValue.Format(true));
            sb.Append(Environment.NewLine + "  Parameters: "); 
            sb.Append(pubKey.EncodedParameters.Format(true));

            // Private key
            AppendPrivateKeyInfo(sb); 

            // Extensions 
            X509ExtensionCollection extensions = this.Extensions; 
            if (extensions.Count > 0) {
                sb.Append(Environment.NewLine + Environment.NewLine + "[Extensions]"); 
                foreach(X509Extension extension in extensions) {
                    sb.Append(Environment.NewLine + "* " + extension.Oid.FriendlyName + "(" + extension.Oid.Value + "):" + Environment.NewLine + "  " + extension.Format(true));
                }
            } 

            sb.Append(Environment.NewLine); 
            return sb.ToString(); 
        }
 
        public bool Archived {
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); 

                uint cbData = 0; 
                return CAPI.CertGetCertificateContextProperty(m_safeCertContext, 
                                                              CAPI.CERT_ARCHIVED_PROP_ID,
                                                              SafeLocalAllocHandle.InvalidHandle, 
                                                              ref cbData);
            }
            set {
                SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; 
                if (value == true)
                    ptr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB)))); 
 
                if (!CAPI.CertSetCertificateContextProperty(m_safeCertContext,
                                                            CAPI.CERT_ARCHIVED_PROP_ID, 
                                                            0,
                                                            ptr))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
                ptr.Dispose(); 
            }
        } 
 
        public X509ExtensionCollection Extensions {
            get { 
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (m_extensions == null) 
                    m_extensions = new X509ExtensionCollection(m_safeCertContext);
 
                return m_extensions; 
            }
        } 

        public string FriendlyName {
            get {
                if (m_safeCertContext.IsInvalid) 
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; 
                uint cbData = 0;
                if (!CAPI.CertGetCertificateContextProperty(m_safeCertContext, 
                                                            CAPI.CERT_FRIENDLY_NAME_PROP_ID,
                                                            ptr,
                                                            ref cbData))
                    return String.Empty; 

                ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData)); 
                if (!CAPI.CertGetCertificateContextProperty(m_safeCertContext, 
                                                            CAPI.CERT_FRIENDLY_NAME_PROP_ID,
                                                            ptr, 
                                                            ref cbData))
                    return String.Empty;

                string friendlyName = Marshal.PtrToStringUni(ptr.DangerousGetHandle()); 
                ptr.Dispose();
                return friendlyName; 
            } 
            set {
                if (m_safeCertContext.IsInvalid) 
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (value == null)
                    value = String.Empty; 

                SetFriendlyNameExtendedProperty(m_safeCertContext, value); 
            } 
        }
 
        public X500DistinguishedName IssuerName {
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); 

                if (m_issuerName == null) { 
                    unsafe { 
                        CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle());
                        CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); 
                        m_issuerName = new X500DistinguishedName(pCertInfo.Issuer);
                    }
                }
 
                return m_issuerName;
            } 
        } 

        public DateTime NotAfter { 
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                if (m_notAfter == DateTime.MinValue) {
                    unsafe { 
                        CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); 
                        CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                        long dt = (((long)(uint)pCertInfo.NotAfter.dwHighDateTime) << 32) | ((long)(uint)pCertInfo.NotAfter.dwLowDateTime); 
                        m_notAfter = DateTime.FromFileTime(dt);
                    }
                }
 
                return m_notAfter;
            } 
        } 

        public DateTime NotBefore { 
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                if (m_notBefore == DateTime.MinValue) {
                    unsafe { 
                        CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); 
                        CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                        long dt = (((long)(uint)pCertInfo.NotBefore.dwHighDateTime) << 32) | ((long)(uint)pCertInfo.NotBefore.dwLowDateTime); 
                        m_notBefore = DateTime.FromFileTime(dt);
                    }
                }
 
                return m_notBefore;
            } 
        } 

        public bool HasPrivateKey { 
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                uint cbData = 0;
                return CAPI.CertGetCertificateContextProperty(m_safeCertContext, 
                                                              CAPI.CERT_KEY_PROV_INFO_PROP_ID, 
                                                              SafeLocalAllocHandle.InvalidHandle,
                                                              ref cbData); 
            }
        }

        // flag that RSACryptoServiceProvider will take to mean that the key container name was randomly generated 
        private static uint randomKeyContainerFlag = 0xFFFFFFFF;
        private static uint RandomKeyContainerFlag 
        { 
            get
            { 
                if(randomKeyContainerFlag == 0xFFFFFFFF)
                {
                    FieldInfo keyContainerField = typeof(RSACryptoServiceProvider).GetField(
                        "RandomKeyContainerFlag", 
                        BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly);
 
                    if (keyContainerField != null) 
                        randomKeyContainerFlag = (uint)keyContainerField.GetValue(null);
                    else 
                        randomKeyContainerFlag = 0x00000000;
                }

                return randomKeyContainerFlag; 
            }
        } 
 
        public AsymmetricAlgorithm PrivateKey {
            get { 
                if (!this.HasPrivateKey)
                    return null;

                if (m_privateKey == null) { 
                    CspParameters parameters = new CspParameters();
                    if (!GetPrivateKeyInfo(m_safeCertContext, ref parameters)) 
                        return null; 

                    // We never want to stomp over certificate private keys. 
                    parameters.Flags |= CspProviderFlags.UseExistingKey;
                    switch (this.PublicKey.AlgorithmId) {
                    case CAPI.CALG_RSA_KEYX:
                    case CAPI.CALG_RSA_SIGN: 
                        if (m_randomKeyContainer)
                        { 
                            KeyContainerPermission permission = new KeyContainerPermission(PermissionState.None); 
                            permission.AccessEntries.Add(new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open));
                            permission.Assert(); 

                            // Tell RSACryptoServiceProvider the key container was randomly generated
                            parameters.Flags = (CspProviderFlags)(((uint)parameters.Flags) | RandomKeyContainerFlag);
                        } 

                        m_privateKey = new RSACryptoServiceProvider(parameters); 
 
                        if (m_randomKeyContainer)
                            CodeAccessPermission.RevertAssert(); 
                        break;

                    case CAPI.CALG_DSS_SIGN:
                        m_privateKey = new DSACryptoServiceProvider(parameters); 
                        break;
 
                    default: 
                        throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm));
                    } 
                }

                return m_privateKey;
            } 
            set {
                if (m_safeCertContext.IsInvalid) 
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); 

                // we do not support keys in non-CAPI storage for now. 
                ICspAsymmetricAlgorithm asymmetricAlgorithm = value as ICspAsymmetricAlgorithm;
                if (value != null && asymmetricAlgorithm == null)
                    throw new NotSupportedException(SR.GetString(SR.NotSupported_InvalidKeyImpl));
 
                // A null value can be passed in to remove the link to the private key from the certificate.
                if (asymmetricAlgorithm != null) { 
                    if (asymmetricAlgorithm.CspKeyContainerInfo == null) 
                        throw new ArgumentException("CspKeyContainerInfo");
 
                    // check that the public key in the certificate corresponds to the private key passed in.
                    //
                    // note that it should be legal to set a key which matches in every aspect but the usage
                    // i.e. to use a CALG_RSA_KEYX private key to match a CALG_RSA_SIGN public key. A 
                    // PUBLICKEYBLOB is defined as:
                    // 
                    //  BLOBHEADER publickeystruc 
                    //  RSAPUBKEY rsapubkey
                    //  BYTE modulus[rsapubkey.bitlen/8] 
                    //
                    // To allow keys which differ by key usage only, we skip over the BLOBHEADER of the key,
                    // and start comparing bytes at the RSAPUBKEY structure.
                    if(s_publicKeyOffset == 0) 
                        s_publicKeyOffset = Marshal.SizeOf(typeof(CAPIBase.BLOBHEADER));
 
                    ICspAsymmetricAlgorithm publicKey = this.PublicKey.Key as ICspAsymmetricAlgorithm; 
                    byte[] array1 = publicKey.ExportCspBlob(false);
                    byte[] array2 = asymmetricAlgorithm.ExportCspBlob(false); 
                    if (array1 == null || array2 == null || array1.Length != array2.Length || array1.Length <= s_publicKeyOffset)
                        throw new CryptographicUnexpectedOperationException(SR.GetString(SR.Cryptography_X509_KeyMismatch));
                    for (int index = s_publicKeyOffset; index < array1.Length; index++) {
                        if (array1[index] != array2[index]) 
                            throw new CryptographicUnexpectedOperationException(SR.GetString(SR.Cryptography_X509_KeyMismatch));
                    } 
                } 

                // Establish the link between the certificate and the key container. 
                SetPrivateKeyProperty(m_safeCertContext, asymmetricAlgorithm);

                m_privateKey = value;
            } 
        }
 
        public PublicKey PublicKey { 
            get {
                if (m_safeCertContext.IsInvalid) 
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (m_publicKey == null) {
                    string friendlyName = this.GetKeyAlgorithm(); 
                    byte[] parameters = this.GetKeyAlgorithmParameters();
                    byte[] keyValue = this.GetPublicKey(); 
                    Oid oid = new Oid(friendlyName, OidGroup.PublicKeyAlgorithm, true); 
                    m_publicKey = new PublicKey(oid, new AsnEncodedData(oid, parameters), new AsnEncodedData(oid, keyValue));
                } 

                return m_publicKey;
            }
        } 

        public byte[] RawData { 
            get { 
                return GetRawCertData();
            } 
        }

        public string SerialNumber {
            get { 
                return GetSerialNumberString();
            } 
        } 

        public X500DistinguishedName SubjectName { 
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                if (m_subjectName == null) {
                    unsafe { 
                        CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); 
                        CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                        m_subjectName = new X500DistinguishedName(pCertInfo.Subject); 
                    }
                }

                return m_subjectName; 
            }
        } 
 
        public Oid SignatureAlgorithm {
            get { 
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (m_signatureAlgorithm == null) 
                    m_signatureAlgorithm = GetSignatureAlgorithm(m_safeCertContext);
 
                return m_signatureAlgorithm; 
            }
        } 

        public string Thumbprint {
            get {
                return GetCertHashString(); 
            }
        } 
 
        public int Version {
            get { 
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (m_version == 0) 
                    m_version = (int) GetVersion(m_safeCertContext);
 
                return m_version; 
            }
        } 

        public unsafe string GetNameInfo(X509NameType nameType, bool forIssuer) {
            uint issuerFlag = forIssuer ? CAPI.CERT_NAME_ISSUER_FLAG : 0;
            uint type = X509Utils.MapNameType(nameType); 

            switch(type) { 
            case CAPI.CERT_NAME_SIMPLE_DISPLAY_TYPE: 
                return CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, type);
 
            case CAPI.CERT_NAME_EMAIL_TYPE:
                return CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, type);
            }
 
            string name = String.Empty;
            // If the type requested is not supported in downlevel platforms; we try to decode the alt name extension by hand. 
            CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); 
            CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
 
            IntPtr[] pAltName = new IntPtr[2];
            pAltName[0] = CAPI.CertFindExtension(forIssuer ? CAPI.szOID_ISSUER_ALT_NAME : CAPI.szOID_SUBJECT_ALT_NAME,
                                                 pCertInfo.cExtension,
                                                 pCertInfo.rgExtension); 
            pAltName[1] = CAPI.CertFindExtension(forIssuer ? CAPI.szOID_ISSUER_ALT_NAME2 : CAPI.szOID_SUBJECT_ALT_NAME2,
                                                 pCertInfo.cExtension, 
                                                 pCertInfo.rgExtension); 
            for (int i = 0; i < pAltName.Length; i++) {
                if (pAltName[i] != IntPtr.Zero) { 
                    CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pAltName[i], typeof(CAPI.CERT_EXTENSION));
                    byte[] rawData = new byte[extension.Value.cbData];
                    Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length);
 
                    uint cbDecoded = 0;
                    SafeLocalAllocHandle decoded = null; 
                    // Decode the extension. 
                    SafeLocalAllocHandle ptr = X509Utils.StringToAnsiPtr(extension.pszObjId);
                    bool result = CAPI.DecodeObject(ptr.DangerousGetHandle(), 
                                                    rawData,
                                                    out decoded,
                                                    out cbDecoded);
                    ptr.Dispose(); 
                    if (result) {
                        CAPI.CERT_ALT_NAME_INFO altNameInfo = (CAPI.CERT_ALT_NAME_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_ALT_NAME_INFO)); 
 
                        for (int index = 0; index < altNameInfo.cAltEntry; index++) {
                            IntPtr pAltInfoPtr = new IntPtr((long) altNameInfo.rgAltEntry + index * Marshal.SizeOf(typeof(CAPI.CERT_ALT_NAME_ENTRY))); 
                            CAPI.CERT_ALT_NAME_ENTRY altNameEntry = (CAPI.CERT_ALT_NAME_ENTRY) Marshal.PtrToStructure(pAltInfoPtr, typeof(CAPI.CERT_ALT_NAME_ENTRY));

                            switch(type) {
                            case CAPI.CERT_NAME_UPN_TYPE: 
                                if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_OTHER_NAME) {
                                    CAPI.CERT_OTHER_NAME otherName = (CAPI.CERT_OTHER_NAME) Marshal.PtrToStructure(altNameEntry.Value.pOtherName, typeof(CAPI.CERT_OTHER_NAME)); 
                                    if (otherName.pszObjId == CAPI.szOID_NT_PRINCIPAL_NAME) { 
                                        uint cbUpnName = 0;
                                        SafeLocalAllocHandle pUpnName = null; 
                                        result = CAPI.DecodeObject(new IntPtr(CAPI.X509_UNICODE_ANY_STRING),
                                                                   X509Utils.PtrToByte(otherName.Value.pbData, otherName.Value.cbData),
                                                                   out pUpnName,
                                                                   out cbUpnName); 
                                        if (result) {
                                            CAPI.CERT_NAME_VALUE nameValue = (CAPI.CERT_NAME_VALUE) Marshal.PtrToStructure(pUpnName.DangerousGetHandle(), typeof(CAPI.CERT_NAME_VALUE)); 
                                            if (X509Utils.IsCertRdnCharString(nameValue.dwValueType)) 
                                                name = Marshal.PtrToStringUni(nameValue.Value.pbData);
                                            pUpnName.Dispose(); 
                                        }
                                    }
                                }
                                break; 

                            case CAPI.CERT_NAME_DNS_TYPE: 
                                if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_DNS_NAME) 
                                    name = Marshal.PtrToStringUni(altNameEntry.Value.pwszDNSName);
 
                                break;

                            case CAPI.CERT_NAME_URL_TYPE:
                                if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_URL) 
                                    name = Marshal.PtrToStringUni(altNameEntry.Value.pwszURL);
 
                                break; 
                            }
                        } 
                        decoded.Dispose();
                    }
                }
            } 

            if (nameType == X509NameType.DnsName) { 
                // If no DNS name is found in the CERT_ALT_NAME extension, return the CommonName. 
                // Commercial CAs such as Verisign don't include a SubjectAltName extension in the certificates they use for SSL server authentication.
                // Instead they use the CommonName in the subject RDN as the server's DNS name. 

                if (name == null || name.Length == 0)
                    name = CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, CAPI.CERT_NAME_ATTR_TYPE);
            } 

            return name; 
        } 

        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
        public override void Import(byte[] rawData) {
            Reset();
            base.Import(rawData); 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 
 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        public override void Import(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) {
            Reset();
            base.Import(rawData, password, keyStorageFlags);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        }
 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
        public override void Import(byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) { 
            Reset();
            base.Import(rawData, password, keyStorageFlags);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 

        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        public override void Import(string fileName) {
            Reset(); 
            base.Import(fileName);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }
 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        public override void Import(string fileName, string password, X509KeyStorageFlags keyStorageFlags) { 
            Reset();
            base.Import(fileName, password, keyStorageFlags); 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }

        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
        public override void Import(string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) { 
            Reset(); 
            base.Import(fileName, password, keyStorageFlags);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        }

        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        public override void Reset () {
            m_version = 0; 
            m_notBefore = DateTime.MinValue; 
            m_notAfter = DateTime.MinValue;
            m_privateKey = null; 
            m_publicKey = null;
            m_extensions = null;
            m_signatureAlgorithm = null;
            m_subjectName = null; 
            m_issuerName = null;
            if (!m_safeCertContext.IsInvalid) { 
                // Free the current certificate handle 
                m_safeCertContext.Dispose();
                m_safeCertContext = SafeCertContextHandle.InvalidHandle; 
            }
            base.Reset();
        }
 
        public bool Verify () {
            if (m_safeCertContext.IsInvalid) 
                throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); 

            int hr = X509Utils.VerifyCertificate(this.CertContext, 
                                   null,
                                   null,
                                   X509RevocationMode.Online, // We default to online revocation check.
                                   X509RevocationFlag.ExcludeRoot, 
                                   DateTime.Now,
                                   new TimeSpan(0, 0, 0), // default 
                                   null, 
                                   new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE),
                                   IntPtr.Zero); 
            return (hr == CAPI.S_OK);
        }

        // 
        // public static methods
        // 
 
        public static X509ContentType GetCertContentType (byte[] rawData) {
            if (rawData == null || rawData.Length == 0) 
                throw new ArgumentException(SR.GetString(SR.Arg_EmptyOrNullArray), "rawData");

            uint contentType = QueryCertBlobType(rawData);
            return X509Utils.MapContentType(contentType); 
        }
 
        public static X509ContentType GetCertContentType (string fileName) { 
            if (fileName == null)
                throw new ArgumentNullException("fileName"); 

            string fullPath = Path.GetFullPath(fileName);
            new FileIOPermission (FileIOPermissionAccess.Read, fullPath).Demand();
            uint contentType = QueryCertFileType(fileName); 
            return X509Utils.MapContentType(contentType);
        } 
 
        //
        // Internal 
        //

        internal SafeCertContextHandle CertContext {
            get { 
                return m_safeCertContext;
            } 
        } 

        internal static bool GetPrivateKeyInfo (SafeCertContextHandle safeCertContext, ref CspParameters parameters) { 
            SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle;
            uint cbData = 0;
            if (!CAPI.CertGetCertificateContextProperty(safeCertContext,
                                                        CAPI.CERT_KEY_PROV_INFO_PROP_ID, 
                                                        ptr,
                                                        ref cbData)) { 
                int dwErrorCode = Marshal.GetLastWin32Error(); 
                if (dwErrorCode == CAPI.CRYPT_E_NOT_FOUND)
                    return false; 
                else
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            }
 
            ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData));
            if (!CAPI.CertGetCertificateContextProperty(safeCertContext, 
                                                        CAPI.CERT_KEY_PROV_INFO_PROP_ID, 
                                                        ptr,
                                                        ref cbData)) { 
                int dwErrorCode = Marshal.GetLastWin32Error();
                if (dwErrorCode == CAPI.CRYPT_E_NOT_FOUND)
                    return false;
                else 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            } 
 
            CAPI.CRYPT_KEY_PROV_INFO pKeyProvInfo = (CAPI.CRYPT_KEY_PROV_INFO) Marshal.PtrToStructure(ptr.DangerousGetHandle(), typeof(CAPI.CRYPT_KEY_PROV_INFO));
            parameters.ProviderName = pKeyProvInfo.pwszProvName; 
            parameters.KeyContainerName = pKeyProvInfo.pwszContainerName;
            parameters.ProviderType = (int) pKeyProvInfo.dwProvType;
            parameters.KeyNumber = (int) pKeyProvInfo.dwKeySpec;
            parameters.Flags = (CspProviderFlags) ((pKeyProvInfo.dwFlags & CAPI.CRYPT_MACHINE_KEYSET) == CAPI.CRYPT_MACHINE_KEYSET ? CspProviderFlags.UseMachineKeyStore : 0); 

            ptr.Dispose(); 
            return true; 
        }
 
        //
        // Private
        //
 
        private void AppendPrivateKeyInfo (StringBuilder sb) {
            CspKeyContainerInfo cspKeyContainerInfo = null; 
            try { 
                if (this.HasPrivateKey) {
                    CspParameters parameters = new CspParameters(); 
                    if (GetPrivateKeyInfo(m_safeCertContext, ref parameters))
                        cspKeyContainerInfo = new CspKeyContainerInfo(parameters);
                }
            } 
            // We don't have the permission to access the key container. Just return.
            catch (SecurityException) {} 
            // We could not access the key container. Just return. 
            catch (CryptographicException) {}
 
            if (cspKeyContainerInfo == null)
                return;

            sb.Append(Environment.NewLine + Environment.NewLine + "[Private Key]"); 
            sb.Append(Environment.NewLine + "  Key Store: ");
            sb.Append(cspKeyContainerInfo.MachineKeyStore ? "Machine" : "User"); 
            sb.Append(Environment.NewLine + "  Provider Name: "); 
            sb.Append(cspKeyContainerInfo.ProviderName);
            sb.Append(Environment.NewLine + "  Provider type: "); 
            sb.Append(cspKeyContainerInfo.ProviderType);
            sb.Append(Environment.NewLine + "  Key Spec: ");
            sb.Append(cspKeyContainerInfo.KeyNumber);
            sb.Append(Environment.NewLine + "  Key Container Name: "); 
            sb.Append(cspKeyContainerInfo.KeyContainerName);
 
            try { 
                string uniqueKeyContainer = cspKeyContainerInfo.UniqueKeyContainerName;
                sb.Append(Environment.NewLine + "  Unique Key Container Name: "); 
                sb.Append(uniqueKeyContainer);
            }
            catch (CryptographicException) {}
            catch (NotSupportedException) {} 

            bool b = false; 
            try { 
                b = cspKeyContainerInfo.HardwareDevice;
                sb.Append(Environment.NewLine + "  Hardware Device: "); 
                sb.Append(b);
            }
            catch (CryptographicException) {}
 
            try {
                b = cspKeyContainerInfo.Removable; 
                sb.Append(Environment.NewLine + "  Removable: "); 
                sb.Append(b);
            } 
            catch (CryptographicException) {}

            try {
                b = cspKeyContainerInfo.Protected; 
                sb.Append(Environment.NewLine + "  Protected: ");
                sb.Append(b); 
            } 
            catch (CryptographicException) {}
            catch (NotSupportedException) {} 
        }

        private static unsafe Oid GetSignatureAlgorithm (SafeCertContextHandle safeCertContextHandle) {
            CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle()); 
            CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
            return new Oid(pCertInfo.SignatureAlgorithm.pszObjId, OidGroup.SignatureAlgorithm, false); 
        } 

        private static unsafe uint GetVersion (SafeCertContextHandle safeCertContextHandle) { 
            CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
            CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
            return (pCertInfo.dwVersion + 1);
        } 

        private static unsafe uint QueryCertBlobType(byte[] rawData) { 
            uint contentType = 0; 
            if (!CAPI.CryptQueryObject(CAPI.CERT_QUERY_OBJECT_BLOB,
                                       rawData, 
                                       CAPI.CERT_QUERY_CONTENT_FLAG_ALL,
                                       CAPI.CERT_QUERY_FORMAT_FLAG_ALL,
                                       0,
                                       IntPtr.Zero, 
                                       new IntPtr(&contentType),
                                       IntPtr.Zero, 
                                       IntPtr.Zero, 
                                       IntPtr.Zero,
                                       IntPtr.Zero)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            return contentType;
        } 

        private static unsafe uint QueryCertFileType(string fileName) { 
            uint contentType = 0; 
            if (!CAPI.CryptQueryObject(CAPI.CERT_QUERY_OBJECT_FILE,
                                       fileName, 
                                       CAPI.CERT_QUERY_CONTENT_FLAG_ALL,
                                       CAPI.CERT_QUERY_FORMAT_FLAG_ALL,
                                       0,
                                       IntPtr.Zero, 
                                       new IntPtr(&contentType),
                                       IntPtr.Zero, 
                                       IntPtr.Zero, 
                                       IntPtr.Zero,
                                       IntPtr.Zero)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            return contentType;
        } 

        private static unsafe void SetFriendlyNameExtendedProperty (SafeCertContextHandle safeCertContextHandle, string name) { 
            SafeLocalAllocHandle ptr = X509Utils.StringToUniPtr(name); 
            using (ptr) {
                CAPI.CRYPTOAPI_BLOB DataBlob = new CAPI.CRYPTOAPI_BLOB(); 
                DataBlob.cbData = 2 * ((uint) name.Length + 1);
                DataBlob.pbData = ptr.DangerousGetHandle();

                if (!CAPI.CertSetCertificateContextProperty(safeCertContextHandle, 
                                                            CAPI.CERT_FRIENDLY_NAME_PROP_ID,
                                                            0, 
                                                            new IntPtr(&DataBlob))) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            } 
        }

        private static unsafe void SetPrivateKeyProperty (SafeCertContextHandle safeCertContextHandle, ICspAsymmetricAlgorithm asymmetricAlgorithm) {
            SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; 
            if (asymmetricAlgorithm != null) {
                CAPI.CRYPT_KEY_PROV_INFO keyProvInfo = new CAPI.CRYPT_KEY_PROV_INFO(); 
                keyProvInfo.pwszContainerName = asymmetricAlgorithm.CspKeyContainerInfo.KeyContainerName; 
                keyProvInfo.pwszProvName = asymmetricAlgorithm.CspKeyContainerInfo.ProviderName;
                keyProvInfo.dwProvType = (uint) asymmetricAlgorithm.CspKeyContainerInfo.ProviderType; 
                keyProvInfo.dwFlags = asymmetricAlgorithm.CspKeyContainerInfo.MachineKeyStore ? CAPI.CRYPT_MACHINE_KEYSET : 0;
                keyProvInfo.cProvParam = 0;
                keyProvInfo.rgProvParam = IntPtr.Zero;
                keyProvInfo.dwKeySpec = (uint) asymmetricAlgorithm.CspKeyContainerInfo.KeyNumber; 

                ptr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_KEY_PROV_INFO)))); 
                Marshal.StructureToPtr(keyProvInfo, ptr.DangerousGetHandle(), false); 
            }
 
            try {
                if (!CAPI.CertSetCertificateContextProperty(safeCertContextHandle,
                                                            CAPI.CERT_KEY_PROV_INFO_PROP_ID,
                                                            0, 
                                                            ptr))
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
            } finally { 
                if (!ptr.IsInvalid) {
                    Marshal.DestroyStructure(ptr.DangerousGetHandle(), typeof(CAPI.CRYPT_KEY_PROV_INFO)); 
                    ptr.Dispose();
                }
            }
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

// 
// X509Certificate2.cs 
//
// 09/22/2002 
//

namespace System.Security.Cryptography.X509Certificates {
    using System; 
    using System.Diagnostics;
    using System.IO; 
    using System.Text; 
    using System.Reflection;
    using System.Runtime.InteropServices; 
    using System.Runtime.InteropServices.ComTypes;
    using System.Security.Cryptography;
    using System.Security.Permissions;
 
    using _FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
 
    public enum X509NameType { 
        SimpleName = 0,
        EmailName, 
        UpnName,
        DnsName,
        DnsFromAlternativeName,
        UrlName 
    }
 
    public enum X509IncludeOption { 
        None = 0,
        ExcludeRoot, 
        EndCertOnly,
        WholeChain
    }
 
    public sealed class PublicKey {
        private AsnEncodedData m_encodedKeyValue; 
        private AsnEncodedData m_encodedParameters; 
        private Oid m_oid;
        private uint m_aiPubKey = 0; 
        private byte[] m_cspBlobData = null;
        private AsymmetricAlgorithm m_key = null;

        private PublicKey() {} 

        public PublicKey (Oid oid, AsnEncodedData parameters, AsnEncodedData keyValue) { 
            m_oid = new Oid(oid); 
            m_encodedParameters = new AsnEncodedData(parameters);
            m_encodedKeyValue = new AsnEncodedData(keyValue); 
        }

        internal PublicKey (PublicKey publicKey) {
            m_oid = new Oid(publicKey.m_oid); 
            m_encodedParameters = new AsnEncodedData(publicKey.m_encodedParameters);
            m_encodedKeyValue = new AsnEncodedData(publicKey.m_encodedKeyValue); 
        } 

        internal uint AlgorithmId { 
            get {
                if (m_aiPubKey == 0)
                    m_aiPubKey = X509Utils.OidToAlgId(m_oid.Value);
                return m_aiPubKey; 
            }
        } 
 
        private byte[] CspBlobData {
            get { 
                if (m_cspBlobData == null)
                    DecodePublicKeyObject(AlgorithmId, m_encodedKeyValue.RawData, m_encodedParameters.RawData, out m_cspBlobData);
                return m_cspBlobData;
            } 
        }
 
        public AsymmetricAlgorithm Key { 
            get {
                if (m_key == null) { 
                    switch (AlgorithmId) {
                    case CAPI.CALG_RSA_KEYX:
                    case CAPI.CALG_RSA_SIGN:
                        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
                        rsa.ImportCspBlob(CspBlobData);
                        m_key = rsa; 
                        break; 

                    case CAPI.CALG_DSS_SIGN: 
                        DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
                        dsa.ImportCspBlob(CspBlobData);
                        m_key = dsa;
                        break; 

                    default: 
                        throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm)); 
                    }
                } 
                return m_key;
            }
        }
 
        public Oid Oid {
            get { return new Oid(m_oid); } 
        } 

        public AsnEncodedData EncodedKeyValue { 
            get { return m_encodedKeyValue; }
        }

        public AsnEncodedData EncodedParameters { 
            get { return m_encodedParameters; }
        } 
 
        //
        // private static methods. 
        //

        private static void DecodePublicKeyObject(uint aiPubKey, byte[] encodedKeyValue, byte[] encodedParameters, out byte[] decodedData) {
            // Initialize the out parameter 
            decodedData = null;
            IntPtr pszStructType = IntPtr.Zero; 
            switch (aiPubKey) { 
            case CAPI.CALG_DSS_SIGN:
                pszStructType = new IntPtr(CAPI.X509_DSS_PUBLICKEY); 
                break;

            case CAPI.CALG_RSA_SIGN:
            case CAPI.CALG_RSA_KEYX: 
                pszStructType = new IntPtr(CAPI.RSA_CSP_PUBLICKEYBLOB);
                break; 
 
            case CAPI.CALG_DH_SF:
            case CAPI.CALG_DH_EPHEM: 
                // We don't support DH for now
                throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm));

            default: 
                // We should never get here
                Debug.Assert(false); 
                throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm)); 
            }
 
            SafeLocalAllocHandle decodedKeyValue = null;
            uint cbDecodedKeyValue = 0;
            bool result = CAPI.DecodeObject(pszStructType,
                                            encodedKeyValue, 
                                            out decodedKeyValue,
                                            out cbDecodedKeyValue); 
            if (!result) 
                throw new CryptographicException(Marshal.GetLastWin32Error());
 
            if ((uint) pszStructType == CAPI.RSA_CSP_PUBLICKEYBLOB) {
                decodedData = new byte[cbDecodedKeyValue];
                Marshal.Copy(decodedKeyValue.DangerousGetHandle(), decodedData, 0, decodedData.Length);
            } else if ((uint) pszStructType == CAPI.X509_DSS_PUBLICKEY) { 
                // We need to decode the parameters as well
                SafeLocalAllocHandle decodedParameters = null; 
                uint cbDecodedParameters = 0; 
                result = CAPI.DecodeObject(new IntPtr(CAPI.X509_DSS_PARAMETERS),
                                           encodedParameters, 
                                           out decodedParameters,
                                           out cbDecodedParameters);
                if (!result)
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 

                decodedData = ConstructDSSPubKeyCspBlob(decodedKeyValue, decodedParameters); 
                decodedParameters.Dispose(); 
            }
            decodedKeyValue.Dispose(); 
        }

        private static byte[] ConstructDSSPubKeyCspBlob (SafeLocalAllocHandle decodedKeyValue,
                                                         SafeLocalAllocHandle decodedParameters) { 

            // The CAPI DSS public key representation consists of the following sequence: 
            //  - PUBLICKEYSTRUC 
            //  - DSSPUBKEY
            //  - rgbP[cbKey] 
            //  - rgbQ[20]
            //  - rgbG[cbKey]
            //  - rgbY[cbKey]
            //  - DSSSEED 

            CAPI.CRYPTOAPI_BLOB pDssPubKey = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decodedKeyValue.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB)); 
            CAPI.CERT_DSS_PARAMETERS pDssParameters = (CAPI.CERT_DSS_PARAMETERS) Marshal.PtrToStructure(decodedParameters.DangerousGetHandle(), typeof(CAPI.CERT_DSS_PARAMETERS)); 

            uint cbKey = pDssParameters.p.cbData; 
            if (cbKey == 0)
                throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY);

            const uint DSS_Q_LEN = 20; 
            uint cbKeyBlob = 8 /* sizeof(CAPI.BLOBHEADER) */ + 8 /* sizeof(CAPI.DSSPUBKEY) */ +
                        cbKey + DSS_Q_LEN + cbKey + cbKey + 24 /* sizeof(CAPI.DSSSEED) */; 
 
            MemoryStream keyBlob = new MemoryStream((int) cbKeyBlob);
            BinaryWriter bw = new BinaryWriter(keyBlob); 

            // PUBLICKEYSTRUC
            bw.Write(CAPI.PUBLICKEYBLOB); // pPubKeyStruc->bType = PUBLICKEYBLOB
            bw.Write(CAPI.CUR_BLOB_VERSION); // pPubKeyStruc->bVersion = CUR_BLOB_VERSION 
            bw.Write((short) 0); // pPubKeyStruc->reserved = 0;
            bw.Write(CAPI.CALG_DSS_SIGN); // pPubKeyStruc->aiKeyAlg = CALG_DSS_SIGN; 
 
            // DSSPUBKEY
            bw.Write(CAPI.DSS_MAGIC); // pCspPubKey->magic = DSS_MAGIC; We are constructing a DSS1 Csp blob. 
            bw.Write(cbKey * 8); // pCspPubKey->bitlen = cbKey * 8;

            // rgbP[cbKey]
            byte[] p = new byte[pDssParameters.p.cbData]; 
            Marshal.Copy(pDssParameters.p.pbData, p, 0, p.Length);
            bw.Write(p); 
 
            // rgbQ[20]
            uint cb = pDssParameters.q.cbData; 
            if (cb == 0 || cb > DSS_Q_LEN)
                throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY);

            byte[] q = new byte[pDssParameters.q.cbData]; 
            Marshal.Copy(pDssParameters.q.pbData, q, 0, q.Length);
            bw.Write(q); 
            if (DSS_Q_LEN > cb) 
                bw.Write(new byte[DSS_Q_LEN - cb]);
 
            // rgbG[cbKey]
            cb = pDssParameters.g.cbData;
            if (cb == 0 || cb > cbKey)
                throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY); 

            byte[] g = new byte[pDssParameters.g.cbData]; 
            Marshal.Copy(pDssParameters.g.pbData, g, 0, g.Length); 
            bw.Write(g);
            if (cbKey > cb) 
                bw.Write(new byte[cbKey - cb]);

            // rgbY[cbKey]
            cb = pDssPubKey.cbData; 
            if (cb == 0 || cb > cbKey)
                throw new CryptographicException(CAPI.NTE_BAD_PUBLIC_KEY); 
 
            byte[] y = new byte[pDssPubKey.cbData];
            Marshal.Copy(pDssPubKey.pbData, y, 0, y.Length); 
            bw.Write(y);
            if (cbKey > cb)
                bw.Write(new byte[cbKey - cb]);
 
            // DSSSEED: set counter to 0xFFFFFFFF to indicate not available
            bw.Write(0xFFFFFFFF); 
            bw.Write(new byte[20]); 

            return keyBlob.ToArray(); 
        }
    }

    public class X509Certificate2 : X509Certificate { 
        private int m_version;
        private DateTime m_notBefore; 
        private DateTime m_notAfter; 
        private AsymmetricAlgorithm m_privateKey;
        private PublicKey m_publicKey; 
        private X509ExtensionCollection m_extensions;
        private Oid m_signatureAlgorithm;
        private X500DistinguishedName m_subjectName;
        private X500DistinguishedName m_issuerName; 
        private SafeCertContextHandle m_safeCertContext = SafeCertContextHandle.InvalidHandle;
        private bool m_randomKeyContainer; 
 
        private static int s_publicKeyOffset;
 
        //
        // public constructors
        //
 
        public X509Certificate2 () : base() {}
 
        public X509Certificate2 (byte[] rawData) : base (rawData) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true; 
        }

        public X509Certificate2 (byte[] rawData, string password) : base (rawData, password) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
            m_randomKeyContainer = true;
        } 
 
        public X509Certificate2 (byte[] rawData, SecureString password) : base (rawData, password) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
            m_randomKeyContainer = true;
        }

        public X509Certificate2 (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) : base (rawData, password, keyStorageFlags) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true; 
        } 

        public X509Certificate2 (byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (rawData, password, keyStorageFlags) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true;
        }
 
        public X509Certificate2 (string fileName) : base (fileName) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
            m_randomKeyContainer = true; 
        }
 
        public X509Certificate2 (string fileName, string password) : base (fileName, password) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true;
        } 

        public X509Certificate2 (string fileName, SecureString password) : base (fileName, password) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
            m_randomKeyContainer = true;
        } 

        public X509Certificate2 (string fileName, string password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true; 
        }
 
        public X509Certificate2 (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
            m_randomKeyContainer = true; 
        }

        // Package protected constructor for creating a certificate from a PCCERT_CONTEXT
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        public X509Certificate2 (IntPtr handle) : base (handle) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        }
 
        public X509Certificate2 (X509Certificate certificate) : base(certificate) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);

            X509Certificate2 source = certificate as X509Certificate2; 
            if (source != null)
                m_randomKeyContainer = source.m_randomKeyContainer; 
        } 

        public override string ToString() { 
            return base.ToString(true);
        }

        public override string ToString(bool verbose) { 
            if (verbose == false || m_safeCertContext.IsInvalid)
                return ToString(); 
 
            StringBuilder sb = new StringBuilder();
 
            // Version
            sb.Append("[Version]" + Environment.NewLine + "  ");
            sb.Append("V" + this.Version);
 
            // Subject
            sb.Append(Environment.NewLine + Environment.NewLine + "[Subject]" + Environment.NewLine + "  "); 
            sb.Append(this.SubjectName.Name); 
            string simpleName = GetNameInfo(X509NameType.SimpleName, false);
            if (simpleName.Length > 0) { 
                sb.Append(Environment.NewLine + "  Simple Name: ");
                sb.Append(simpleName);
            }
            string emailName = GetNameInfo(X509NameType.EmailName, false); 
            if (emailName.Length > 0) {
                sb.Append(Environment.NewLine + "  Email Name: "); 
                sb.Append(emailName); 
            }
            string upnName = GetNameInfo(X509NameType.UpnName, false); 
            if (upnName.Length > 0) {
                sb.Append(Environment.NewLine + "  UPN Name: ");
                sb.Append(upnName);
            } 
            string dnsName = GetNameInfo(X509NameType.DnsName, false);
            if (dnsName.Length > 0) { 
                sb.Append(Environment.NewLine + "  DNS Name: "); 
                sb.Append(dnsName);
            } 

            // Issuer
            sb.Append(Environment.NewLine + Environment.NewLine + "[Issuer]" + Environment.NewLine + "  ");
            sb.Append(this.IssuerName.Name); 
            simpleName = GetNameInfo(X509NameType.SimpleName, true);
            if (simpleName.Length > 0) { 
                sb.Append(Environment.NewLine + "  Simple Name: "); 
                sb.Append(simpleName);
            } 
            emailName = GetNameInfo(X509NameType.EmailName, true);
            if (emailName.Length > 0) {
                sb.Append(Environment.NewLine + "  Email Name: ");
                sb.Append(emailName); 
            }
            upnName = GetNameInfo(X509NameType.UpnName, true); 
            if (upnName.Length > 0) { 
                sb.Append(Environment.NewLine + "  UPN Name: ");
                sb.Append(upnName); 
            }
            dnsName = GetNameInfo(X509NameType.DnsName, true);
            if (dnsName.Length > 0) {
                sb.Append(Environment.NewLine + "  DNS Name: "); 
                sb.Append(dnsName);
            } 
 
            // Serial Number
            sb.Append(Environment.NewLine + Environment.NewLine + "[Serial Number]" + Environment.NewLine + "  "); 
            sb.Append(this.SerialNumber);

            // NotBefore
            sb.Append(Environment.NewLine + Environment.NewLine + "[Not Before]" + Environment.NewLine + "  "); 
            sb.Append(this.NotBefore);
 
            // NotAfter 
            sb.Append(Environment.NewLine + Environment.NewLine + "[Not After]" + Environment.NewLine + "  ");
            sb.Append(this.NotAfter); 

            // Thumbprint
            sb.Append(Environment.NewLine + Environment.NewLine + "[Thumbprint]" + Environment.NewLine + "  ");
            sb.Append(this.Thumbprint); 

            // Signature Algorithm 
            sb.Append(Environment.NewLine + Environment.NewLine + "[Signature Algorithm]" + Environment.NewLine + "  "); 
            sb.Append(this.SignatureAlgorithm.FriendlyName + "(" + this.SignatureAlgorithm.Value + ")");
 
            // Public Key
            PublicKey pubKey = this.PublicKey;
            sb.Append(Environment.NewLine + Environment.NewLine + "[Public Key]" + Environment.NewLine + "  Algorithm: ");
            sb.Append(pubKey.Oid.FriendlyName); 
            sb.Append(Environment.NewLine + "  Length: ");
            sb.Append(pubKey.Key.KeySize); 
            sb.Append(Environment.NewLine + "  Key Blob: "); 
            sb.Append(pubKey.EncodedKeyValue.Format(true));
            sb.Append(Environment.NewLine + "  Parameters: "); 
            sb.Append(pubKey.EncodedParameters.Format(true));

            // Private key
            AppendPrivateKeyInfo(sb); 

            // Extensions 
            X509ExtensionCollection extensions = this.Extensions; 
            if (extensions.Count > 0) {
                sb.Append(Environment.NewLine + Environment.NewLine + "[Extensions]"); 
                foreach(X509Extension extension in extensions) {
                    sb.Append(Environment.NewLine + "* " + extension.Oid.FriendlyName + "(" + extension.Oid.Value + "):" + Environment.NewLine + "  " + extension.Format(true));
                }
            } 

            sb.Append(Environment.NewLine); 
            return sb.ToString(); 
        }
 
        public bool Archived {
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); 

                uint cbData = 0; 
                return CAPI.CertGetCertificateContextProperty(m_safeCertContext, 
                                                              CAPI.CERT_ARCHIVED_PROP_ID,
                                                              SafeLocalAllocHandle.InvalidHandle, 
                                                              ref cbData);
            }
            set {
                SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; 
                if (value == true)
                    ptr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB)))); 
 
                if (!CAPI.CertSetCertificateContextProperty(m_safeCertContext,
                                                            CAPI.CERT_ARCHIVED_PROP_ID, 
                                                            0,
                                                            ptr))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
                ptr.Dispose(); 
            }
        } 
 
        public X509ExtensionCollection Extensions {
            get { 
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (m_extensions == null) 
                    m_extensions = new X509ExtensionCollection(m_safeCertContext);
 
                return m_extensions; 
            }
        } 

        public string FriendlyName {
            get {
                if (m_safeCertContext.IsInvalid) 
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; 
                uint cbData = 0;
                if (!CAPI.CertGetCertificateContextProperty(m_safeCertContext, 
                                                            CAPI.CERT_FRIENDLY_NAME_PROP_ID,
                                                            ptr,
                                                            ref cbData))
                    return String.Empty; 

                ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData)); 
                if (!CAPI.CertGetCertificateContextProperty(m_safeCertContext, 
                                                            CAPI.CERT_FRIENDLY_NAME_PROP_ID,
                                                            ptr, 
                                                            ref cbData))
                    return String.Empty;

                string friendlyName = Marshal.PtrToStringUni(ptr.DangerousGetHandle()); 
                ptr.Dispose();
                return friendlyName; 
            } 
            set {
                if (m_safeCertContext.IsInvalid) 
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (value == null)
                    value = String.Empty; 

                SetFriendlyNameExtendedProperty(m_safeCertContext, value); 
            } 
        }
 
        public X500DistinguishedName IssuerName {
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); 

                if (m_issuerName == null) { 
                    unsafe { 
                        CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle());
                        CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); 
                        m_issuerName = new X500DistinguishedName(pCertInfo.Issuer);
                    }
                }
 
                return m_issuerName;
            } 
        } 

        public DateTime NotAfter { 
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                if (m_notAfter == DateTime.MinValue) {
                    unsafe { 
                        CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); 
                        CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                        long dt = (((long)(uint)pCertInfo.NotAfter.dwHighDateTime) << 32) | ((long)(uint)pCertInfo.NotAfter.dwLowDateTime); 
                        m_notAfter = DateTime.FromFileTime(dt);
                    }
                }
 
                return m_notAfter;
            } 
        } 

        public DateTime NotBefore { 
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                if (m_notBefore == DateTime.MinValue) {
                    unsafe { 
                        CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); 
                        CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                        long dt = (((long)(uint)pCertInfo.NotBefore.dwHighDateTime) << 32) | ((long)(uint)pCertInfo.NotBefore.dwLowDateTime); 
                        m_notBefore = DateTime.FromFileTime(dt);
                    }
                }
 
                return m_notBefore;
            } 
        } 

        public bool HasPrivateKey { 
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                uint cbData = 0;
                return CAPI.CertGetCertificateContextProperty(m_safeCertContext, 
                                                              CAPI.CERT_KEY_PROV_INFO_PROP_ID, 
                                                              SafeLocalAllocHandle.InvalidHandle,
                                                              ref cbData); 
            }
        }

        // flag that RSACryptoServiceProvider will take to mean that the key container name was randomly generated 
        private static uint randomKeyContainerFlag = 0xFFFFFFFF;
        private static uint RandomKeyContainerFlag 
        { 
            get
            { 
                if(randomKeyContainerFlag == 0xFFFFFFFF)
                {
                    FieldInfo keyContainerField = typeof(RSACryptoServiceProvider).GetField(
                        "RandomKeyContainerFlag", 
                        BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly);
 
                    if (keyContainerField != null) 
                        randomKeyContainerFlag = (uint)keyContainerField.GetValue(null);
                    else 
                        randomKeyContainerFlag = 0x00000000;
                }

                return randomKeyContainerFlag; 
            }
        } 
 
        public AsymmetricAlgorithm PrivateKey {
            get { 
                if (!this.HasPrivateKey)
                    return null;

                if (m_privateKey == null) { 
                    CspParameters parameters = new CspParameters();
                    if (!GetPrivateKeyInfo(m_safeCertContext, ref parameters)) 
                        return null; 

                    // We never want to stomp over certificate private keys. 
                    parameters.Flags |= CspProviderFlags.UseExistingKey;
                    switch (this.PublicKey.AlgorithmId) {
                    case CAPI.CALG_RSA_KEYX:
                    case CAPI.CALG_RSA_SIGN: 
                        if (m_randomKeyContainer)
                        { 
                            KeyContainerPermission permission = new KeyContainerPermission(PermissionState.None); 
                            permission.AccessEntries.Add(new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open));
                            permission.Assert(); 

                            // Tell RSACryptoServiceProvider the key container was randomly generated
                            parameters.Flags = (CspProviderFlags)(((uint)parameters.Flags) | RandomKeyContainerFlag);
                        } 

                        m_privateKey = new RSACryptoServiceProvider(parameters); 
 
                        if (m_randomKeyContainer)
                            CodeAccessPermission.RevertAssert(); 
                        break;

                    case CAPI.CALG_DSS_SIGN:
                        m_privateKey = new DSACryptoServiceProvider(parameters); 
                        break;
 
                    default: 
                        throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyAlgorithm));
                    } 
                }

                return m_privateKey;
            } 
            set {
                if (m_safeCertContext.IsInvalid) 
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); 

                // we do not support keys in non-CAPI storage for now. 
                ICspAsymmetricAlgorithm asymmetricAlgorithm = value as ICspAsymmetricAlgorithm;
                if (value != null && asymmetricAlgorithm == null)
                    throw new NotSupportedException(SR.GetString(SR.NotSupported_InvalidKeyImpl));
 
                // A null value can be passed in to remove the link to the private key from the certificate.
                if (asymmetricAlgorithm != null) { 
                    if (asymmetricAlgorithm.CspKeyContainerInfo == null) 
                        throw new ArgumentException("CspKeyContainerInfo");
 
                    // check that the public key in the certificate corresponds to the private key passed in.
                    //
                    // note that it should be legal to set a key which matches in every aspect but the usage
                    // i.e. to use a CALG_RSA_KEYX private key to match a CALG_RSA_SIGN public key. A 
                    // PUBLICKEYBLOB is defined as:
                    // 
                    //  BLOBHEADER publickeystruc 
                    //  RSAPUBKEY rsapubkey
                    //  BYTE modulus[rsapubkey.bitlen/8] 
                    //
                    // To allow keys which differ by key usage only, we skip over the BLOBHEADER of the key,
                    // and start comparing bytes at the RSAPUBKEY structure.
                    if(s_publicKeyOffset == 0) 
                        s_publicKeyOffset = Marshal.SizeOf(typeof(CAPIBase.BLOBHEADER));
 
                    ICspAsymmetricAlgorithm publicKey = this.PublicKey.Key as ICspAsymmetricAlgorithm; 
                    byte[] array1 = publicKey.ExportCspBlob(false);
                    byte[] array2 = asymmetricAlgorithm.ExportCspBlob(false); 
                    if (array1 == null || array2 == null || array1.Length != array2.Length || array1.Length <= s_publicKeyOffset)
                        throw new CryptographicUnexpectedOperationException(SR.GetString(SR.Cryptography_X509_KeyMismatch));
                    for (int index = s_publicKeyOffset; index < array1.Length; index++) {
                        if (array1[index] != array2[index]) 
                            throw new CryptographicUnexpectedOperationException(SR.GetString(SR.Cryptography_X509_KeyMismatch));
                    } 
                } 

                // Establish the link between the certificate and the key container. 
                SetPrivateKeyProperty(m_safeCertContext, asymmetricAlgorithm);

                m_privateKey = value;
            } 
        }
 
        public PublicKey PublicKey { 
            get {
                if (m_safeCertContext.IsInvalid) 
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (m_publicKey == null) {
                    string friendlyName = this.GetKeyAlgorithm(); 
                    byte[] parameters = this.GetKeyAlgorithmParameters();
                    byte[] keyValue = this.GetPublicKey(); 
                    Oid oid = new Oid(friendlyName, OidGroup.PublicKeyAlgorithm, true); 
                    m_publicKey = new PublicKey(oid, new AsnEncodedData(oid, parameters), new AsnEncodedData(oid, keyValue));
                } 

                return m_publicKey;
            }
        } 

        public byte[] RawData { 
            get { 
                return GetRawCertData();
            } 
        }

        public string SerialNumber {
            get { 
                return GetSerialNumberString();
            } 
        } 

        public X500DistinguishedName SubjectName { 
            get {
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");
 
                if (m_subjectName == null) {
                    unsafe { 
                        CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); 
                        CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                        m_subjectName = new X500DistinguishedName(pCertInfo.Subject); 
                    }
                }

                return m_subjectName; 
            }
        } 
 
        public Oid SignatureAlgorithm {
            get { 
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (m_signatureAlgorithm == null) 
                    m_signatureAlgorithm = GetSignatureAlgorithm(m_safeCertContext);
 
                return m_signatureAlgorithm; 
            }
        } 

        public string Thumbprint {
            get {
                return GetCertHashString(); 
            }
        } 
 
        public int Version {
            get { 
                if (m_safeCertContext.IsInvalid)
                    throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext");

                if (m_version == 0) 
                    m_version = (int) GetVersion(m_safeCertContext);
 
                return m_version; 
            }
        } 

        public unsafe string GetNameInfo(X509NameType nameType, bool forIssuer) {
            uint issuerFlag = forIssuer ? CAPI.CERT_NAME_ISSUER_FLAG : 0;
            uint type = X509Utils.MapNameType(nameType); 

            switch(type) { 
            case CAPI.CERT_NAME_SIMPLE_DISPLAY_TYPE: 
                return CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, type);
 
            case CAPI.CERT_NAME_EMAIL_TYPE:
                return CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, type);
            }
 
            string name = String.Empty;
            // If the type requested is not supported in downlevel platforms; we try to decode the alt name extension by hand. 
            CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) m_safeCertContext.DangerousGetHandle()); 
            CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
 
            IntPtr[] pAltName = new IntPtr[2];
            pAltName[0] = CAPI.CertFindExtension(forIssuer ? CAPI.szOID_ISSUER_ALT_NAME : CAPI.szOID_SUBJECT_ALT_NAME,
                                                 pCertInfo.cExtension,
                                                 pCertInfo.rgExtension); 
            pAltName[1] = CAPI.CertFindExtension(forIssuer ? CAPI.szOID_ISSUER_ALT_NAME2 : CAPI.szOID_SUBJECT_ALT_NAME2,
                                                 pCertInfo.cExtension, 
                                                 pCertInfo.rgExtension); 
            for (int i = 0; i < pAltName.Length; i++) {
                if (pAltName[i] != IntPtr.Zero) { 
                    CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pAltName[i], typeof(CAPI.CERT_EXTENSION));
                    byte[] rawData = new byte[extension.Value.cbData];
                    Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length);
 
                    uint cbDecoded = 0;
                    SafeLocalAllocHandle decoded = null; 
                    // Decode the extension. 
                    SafeLocalAllocHandle ptr = X509Utils.StringToAnsiPtr(extension.pszObjId);
                    bool result = CAPI.DecodeObject(ptr.DangerousGetHandle(), 
                                                    rawData,
                                                    out decoded,
                                                    out cbDecoded);
                    ptr.Dispose(); 
                    if (result) {
                        CAPI.CERT_ALT_NAME_INFO altNameInfo = (CAPI.CERT_ALT_NAME_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_ALT_NAME_INFO)); 
 
                        for (int index = 0; index < altNameInfo.cAltEntry; index++) {
                            IntPtr pAltInfoPtr = new IntPtr((long) altNameInfo.rgAltEntry + index * Marshal.SizeOf(typeof(CAPI.CERT_ALT_NAME_ENTRY))); 
                            CAPI.CERT_ALT_NAME_ENTRY altNameEntry = (CAPI.CERT_ALT_NAME_ENTRY) Marshal.PtrToStructure(pAltInfoPtr, typeof(CAPI.CERT_ALT_NAME_ENTRY));

                            switch(type) {
                            case CAPI.CERT_NAME_UPN_TYPE: 
                                if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_OTHER_NAME) {
                                    CAPI.CERT_OTHER_NAME otherName = (CAPI.CERT_OTHER_NAME) Marshal.PtrToStructure(altNameEntry.Value.pOtherName, typeof(CAPI.CERT_OTHER_NAME)); 
                                    if (otherName.pszObjId == CAPI.szOID_NT_PRINCIPAL_NAME) { 
                                        uint cbUpnName = 0;
                                        SafeLocalAllocHandle pUpnName = null; 
                                        result = CAPI.DecodeObject(new IntPtr(CAPI.X509_UNICODE_ANY_STRING),
                                                                   X509Utils.PtrToByte(otherName.Value.pbData, otherName.Value.cbData),
                                                                   out pUpnName,
                                                                   out cbUpnName); 
                                        if (result) {
                                            CAPI.CERT_NAME_VALUE nameValue = (CAPI.CERT_NAME_VALUE) Marshal.PtrToStructure(pUpnName.DangerousGetHandle(), typeof(CAPI.CERT_NAME_VALUE)); 
                                            if (X509Utils.IsCertRdnCharString(nameValue.dwValueType)) 
                                                name = Marshal.PtrToStringUni(nameValue.Value.pbData);
                                            pUpnName.Dispose(); 
                                        }
                                    }
                                }
                                break; 

                            case CAPI.CERT_NAME_DNS_TYPE: 
                                if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_DNS_NAME) 
                                    name = Marshal.PtrToStringUni(altNameEntry.Value.pwszDNSName);
 
                                break;

                            case CAPI.CERT_NAME_URL_TYPE:
                                if (altNameEntry.dwAltNameChoice == CAPI.CERT_ALT_NAME_URL) 
                                    name = Marshal.PtrToStringUni(altNameEntry.Value.pwszURL);
 
                                break; 
                            }
                        } 
                        decoded.Dispose();
                    }
                }
            } 

            if (nameType == X509NameType.DnsName) { 
                // If no DNS name is found in the CERT_ALT_NAME extension, return the CommonName. 
                // Commercial CAs such as Verisign don't include a SubjectAltName extension in the certificates they use for SSL server authentication.
                // Instead they use the CommonName in the subject RDN as the server's DNS name. 

                if (name == null || name.Length == 0)
                    name = CAPI.GetCertNameInfo(m_safeCertContext, issuerFlag, CAPI.CERT_NAME_ATTR_TYPE);
            } 

            return name; 
        } 

        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
        public override void Import(byte[] rawData) {
            Reset();
            base.Import(rawData); 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 
 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        public override void Import(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) {
            Reset();
            base.Import(rawData, password, keyStorageFlags);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        }
 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
        public override void Import(byte[] rawData, SecureString password, X509KeyStorageFlags keyStorageFlags) { 
            Reset();
            base.Import(rawData, password, keyStorageFlags);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 

        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        public override void Import(string fileName) {
            Reset(); 
            base.Import(fileName);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }
 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        public override void Import(string fileName, string password, X509KeyStorageFlags keyStorageFlags) { 
            Reset();
            base.Import(fileName, password, keyStorageFlags); 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }

        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
        public override void Import(string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) { 
            Reset(); 
            base.Import(fileName, password, keyStorageFlags);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        }

        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        public override void Reset () {
            m_version = 0; 
            m_notBefore = DateTime.MinValue; 
            m_notAfter = DateTime.MinValue;
            m_privateKey = null; 
            m_publicKey = null;
            m_extensions = null;
            m_signatureAlgorithm = null;
            m_subjectName = null; 
            m_issuerName = null;
            if (!m_safeCertContext.IsInvalid) { 
                // Free the current certificate handle 
                m_safeCertContext.Dispose();
                m_safeCertContext = SafeCertContextHandle.InvalidHandle; 
            }
            base.Reset();
        }
 
        public bool Verify () {
            if (m_safeCertContext.IsInvalid) 
                throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidHandle), "m_safeCertContext"); 

            int hr = X509Utils.VerifyCertificate(this.CertContext, 
                                   null,
                                   null,
                                   X509RevocationMode.Online, // We default to online revocation check.
                                   X509RevocationFlag.ExcludeRoot, 
                                   DateTime.Now,
                                   new TimeSpan(0, 0, 0), // default 
                                   null, 
                                   new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE),
                                   IntPtr.Zero); 
            return (hr == CAPI.S_OK);
        }

        // 
        // public static methods
        // 
 
        public static X509ContentType GetCertContentType (byte[] rawData) {
            if (rawData == null || rawData.Length == 0) 
                throw new ArgumentException(SR.GetString(SR.Arg_EmptyOrNullArray), "rawData");

            uint contentType = QueryCertBlobType(rawData);
            return X509Utils.MapContentType(contentType); 
        }
 
        public static X509ContentType GetCertContentType (string fileName) { 
            if (fileName == null)
                throw new ArgumentNullException("fileName"); 

            string fullPath = Path.GetFullPath(fileName);
            new FileIOPermission (FileIOPermissionAccess.Read, fullPath).Demand();
            uint contentType = QueryCertFileType(fileName); 
            return X509Utils.MapContentType(contentType);
        } 
 
        //
        // Internal 
        //

        internal SafeCertContextHandle CertContext {
            get { 
                return m_safeCertContext;
            } 
        } 

        internal static bool GetPrivateKeyInfo (SafeCertContextHandle safeCertContext, ref CspParameters parameters) { 
            SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle;
            uint cbData = 0;
            if (!CAPI.CertGetCertificateContextProperty(safeCertContext,
                                                        CAPI.CERT_KEY_PROV_INFO_PROP_ID, 
                                                        ptr,
                                                        ref cbData)) { 
                int dwErrorCode = Marshal.GetLastWin32Error(); 
                if (dwErrorCode == CAPI.CRYPT_E_NOT_FOUND)
                    return false; 
                else
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            }
 
            ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData));
            if (!CAPI.CertGetCertificateContextProperty(safeCertContext, 
                                                        CAPI.CERT_KEY_PROV_INFO_PROP_ID, 
                                                        ptr,
                                                        ref cbData)) { 
                int dwErrorCode = Marshal.GetLastWin32Error();
                if (dwErrorCode == CAPI.CRYPT_E_NOT_FOUND)
                    return false;
                else 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            } 
 
            CAPI.CRYPT_KEY_PROV_INFO pKeyProvInfo = (CAPI.CRYPT_KEY_PROV_INFO) Marshal.PtrToStructure(ptr.DangerousGetHandle(), typeof(CAPI.CRYPT_KEY_PROV_INFO));
            parameters.ProviderName = pKeyProvInfo.pwszProvName; 
            parameters.KeyContainerName = pKeyProvInfo.pwszContainerName;
            parameters.ProviderType = (int) pKeyProvInfo.dwProvType;
            parameters.KeyNumber = (int) pKeyProvInfo.dwKeySpec;
            parameters.Flags = (CspProviderFlags) ((pKeyProvInfo.dwFlags & CAPI.CRYPT_MACHINE_KEYSET) == CAPI.CRYPT_MACHINE_KEYSET ? CspProviderFlags.UseMachineKeyStore : 0); 

            ptr.Dispose(); 
            return true; 
        }
 
        //
        // Private
        //
 
        private void AppendPrivateKeyInfo (StringBuilder sb) {
            CspKeyContainerInfo cspKeyContainerInfo = null; 
            try { 
                if (this.HasPrivateKey) {
                    CspParameters parameters = new CspParameters(); 
                    if (GetPrivateKeyInfo(m_safeCertContext, ref parameters))
                        cspKeyContainerInfo = new CspKeyContainerInfo(parameters);
                }
            } 
            // We don't have the permission to access the key container. Just return.
            catch (SecurityException) {} 
            // We could not access the key container. Just return. 
            catch (CryptographicException) {}
 
            if (cspKeyContainerInfo == null)
                return;

            sb.Append(Environment.NewLine + Environment.NewLine + "[Private Key]"); 
            sb.Append(Environment.NewLine + "  Key Store: ");
            sb.Append(cspKeyContainerInfo.MachineKeyStore ? "Machine" : "User"); 
            sb.Append(Environment.NewLine + "  Provider Name: "); 
            sb.Append(cspKeyContainerInfo.ProviderName);
            sb.Append(Environment.NewLine + "  Provider type: "); 
            sb.Append(cspKeyContainerInfo.ProviderType);
            sb.Append(Environment.NewLine + "  Key Spec: ");
            sb.Append(cspKeyContainerInfo.KeyNumber);
            sb.Append(Environment.NewLine + "  Key Container Name: "); 
            sb.Append(cspKeyContainerInfo.KeyContainerName);
 
            try { 
                string uniqueKeyContainer = cspKeyContainerInfo.UniqueKeyContainerName;
                sb.Append(Environment.NewLine + "  Unique Key Container Name: "); 
                sb.Append(uniqueKeyContainer);
            }
            catch (CryptographicException) {}
            catch (NotSupportedException) {} 

            bool b = false; 
            try { 
                b = cspKeyContainerInfo.HardwareDevice;
                sb.Append(Environment.NewLine + "  Hardware Device: "); 
                sb.Append(b);
            }
            catch (CryptographicException) {}
 
            try {
                b = cspKeyContainerInfo.Removable; 
                sb.Append(Environment.NewLine + "  Removable: "); 
                sb.Append(b);
            } 
            catch (CryptographicException) {}

            try {
                b = cspKeyContainerInfo.Protected; 
                sb.Append(Environment.NewLine + "  Protected: ");
                sb.Append(b); 
            } 
            catch (CryptographicException) {}
            catch (NotSupportedException) {} 
        }

        private static unsafe Oid GetSignatureAlgorithm (SafeCertContextHandle safeCertContextHandle) {
            CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle()); 
            CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
            return new Oid(pCertInfo.SignatureAlgorithm.pszObjId, OidGroup.SignatureAlgorithm, false); 
        } 

        private static unsafe uint GetVersion (SafeCertContextHandle safeCertContextHandle) { 
            CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
            CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
            return (pCertInfo.dwVersion + 1);
        } 

        private static unsafe uint QueryCertBlobType(byte[] rawData) { 
            uint contentType = 0; 
            if (!CAPI.CryptQueryObject(CAPI.CERT_QUERY_OBJECT_BLOB,
                                       rawData, 
                                       CAPI.CERT_QUERY_CONTENT_FLAG_ALL,
                                       CAPI.CERT_QUERY_FORMAT_FLAG_ALL,
                                       0,
                                       IntPtr.Zero, 
                                       new IntPtr(&contentType),
                                       IntPtr.Zero, 
                                       IntPtr.Zero, 
                                       IntPtr.Zero,
                                       IntPtr.Zero)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            return contentType;
        } 

        private static unsafe uint QueryCertFileType(string fileName) { 
            uint contentType = 0; 
            if (!CAPI.CryptQueryObject(CAPI.CERT_QUERY_OBJECT_FILE,
                                       fileName, 
                                       CAPI.CERT_QUERY_CONTENT_FLAG_ALL,
                                       CAPI.CERT_QUERY_FORMAT_FLAG_ALL,
                                       0,
                                       IntPtr.Zero, 
                                       new IntPtr(&contentType),
                                       IntPtr.Zero, 
                                       IntPtr.Zero, 
                                       IntPtr.Zero,
                                       IntPtr.Zero)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            return contentType;
        } 

        private static unsafe void SetFriendlyNameExtendedProperty (SafeCertContextHandle safeCertContextHandle, string name) { 
            SafeLocalAllocHandle ptr = X509Utils.StringToUniPtr(name); 
            using (ptr) {
                CAPI.CRYPTOAPI_BLOB DataBlob = new CAPI.CRYPTOAPI_BLOB(); 
                DataBlob.cbData = 2 * ((uint) name.Length + 1);
                DataBlob.pbData = ptr.DangerousGetHandle();

                if (!CAPI.CertSetCertificateContextProperty(safeCertContextHandle, 
                                                            CAPI.CERT_FRIENDLY_NAME_PROP_ID,
                                                            0, 
                                                            new IntPtr(&DataBlob))) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            } 
        }

        private static unsafe void SetPrivateKeyProperty (SafeCertContextHandle safeCertContextHandle, ICspAsymmetricAlgorithm asymmetricAlgorithm) {
            SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; 
            if (asymmetricAlgorithm != null) {
                CAPI.CRYPT_KEY_PROV_INFO keyProvInfo = new CAPI.CRYPT_KEY_PROV_INFO(); 
                keyProvInfo.pwszContainerName = asymmetricAlgorithm.CspKeyContainerInfo.KeyContainerName; 
                keyProvInfo.pwszProvName = asymmetricAlgorithm.CspKeyContainerInfo.ProviderName;
                keyProvInfo.dwProvType = (uint) asymmetricAlgorithm.CspKeyContainerInfo.ProviderType; 
                keyProvInfo.dwFlags = asymmetricAlgorithm.CspKeyContainerInfo.MachineKeyStore ? CAPI.CRYPT_MACHINE_KEYSET : 0;
                keyProvInfo.cProvParam = 0;
                keyProvInfo.rgProvParam = IntPtr.Zero;
                keyProvInfo.dwKeySpec = (uint) asymmetricAlgorithm.CspKeyContainerInfo.KeyNumber; 

                ptr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_KEY_PROV_INFO)))); 
                Marshal.StructureToPtr(keyProvInfo, ptr.DangerousGetHandle(), false); 
            }
 
            try {
                if (!CAPI.CertSetCertificateContextProperty(safeCertContextHandle,
                                                            CAPI.CERT_KEY_PROV_INFO_PROP_ID,
                                                            0, 
                                                            ptr))
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
            } finally { 
                if (!ptr.IsInvalid) {
                    Marshal.DestroyStructure(ptr.DangerousGetHandle(), typeof(CAPI.CRYPT_KEY_PROV_INFO)); 
                    ptr.Dispose();
                }
            }
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK