X509Certificate2.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / security / system / security / cryptography / x509 / X509Certificate2.cs / 1305376 / 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.Diagnostics.CodeAnalysis; 
    using System.IO; 
    using System.Text;
    using System.Runtime.InteropServices; 
    using System.Runtime.InteropServices.ComTypes;
    using System.Runtime.Serialization;
    using System.Security.Cryptography;
    using System.Security.Permissions; 
    using System.Runtime.Versioning;
 
    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();
        }
    } 

    [Serializable] 
    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 static int s_publicKeyOffset;

        //
        // public constructors 
        //
 
        public X509Certificate2 () : base() {} 

        public X509Certificate2 (byte[] rawData) : base (rawData) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }

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

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

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public X509Certificate2 (string fileName) : base (fileName) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public X509Certificate2 (string fileName, string password) : base (fileName, password) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public X509Certificate2 (string fileName, SecureString password) : base (fileName, password) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public X509Certificate2 (string fileName, string password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public X509Certificate2 (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }
 
        // 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); 
        }
 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
        [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected X509Certificate2(SerializationInfo info, StreamingContext context) : base(info, context) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }

        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(FormatDate(this.NotBefore)); 

            // NotAfter
            sb.Append(Environment.NewLine + Environment.NewLine + "[Not After]" + Environment.NewLine + "  ");
            sb.Append(FormatDate(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); 
            }
        } 
 
        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: 
                        m_privateKey = new RSACryptoServiceProvider(parameters);
                        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;
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [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);
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [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);
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [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);
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public override void Import(string fileName) {
            Reset();
            base.Import(fileName);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")] 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public override void Import(string fileName, string password, X509KeyStorageFlags keyStorageFlags) {
            Reset(); 
            base.Import(fileName, password, keyStorageFlags);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        } 

        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")] 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public override void Import(string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) {
            Reset(); 
            base.Import(fileName, password, keyStorageFlags); 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 

        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [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); 
        }
 
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        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);
        } 
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        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; 
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        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.Diagnostics.CodeAnalysis; 
    using System.IO; 
    using System.Text;
    using System.Runtime.InteropServices; 
    using System.Runtime.InteropServices.ComTypes;
    using System.Runtime.Serialization;
    using System.Security.Cryptography;
    using System.Security.Permissions; 
    using System.Runtime.Versioning;
 
    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();
        }
    } 

    [Serializable] 
    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 static int s_publicKeyOffset;

        //
        // public constructors 
        //
 
        public X509Certificate2 () : base() {} 

        public X509Certificate2 (byte[] rawData) : base (rawData) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }

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

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

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public X509Certificate2 (string fileName) : base (fileName) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public X509Certificate2 (string fileName, string password) : base (fileName, password) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public X509Certificate2 (string fileName, SecureString password) : base (fileName, password) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public X509Certificate2 (string fileName, string password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public X509Certificate2 (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) : base (fileName, password, keyStorageFlags) {
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }
 
        // 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); 
        }
 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
        [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected X509Certificate2(SerializationInfo info, StreamingContext context) : base(info, context) { 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        }

        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(FormatDate(this.NotBefore)); 

            // NotAfter
            sb.Append(Environment.NewLine + Environment.NewLine + "[Not After]" + Environment.NewLine + "  ");
            sb.Append(FormatDate(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); 
            }
        } 
 
        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: 
                        m_privateKey = new RSACryptoServiceProvider(parameters);
                        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;
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [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);
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [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);
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [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);
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)] 
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public override void Import(string fileName) {
            Reset();
            base.Import(fileName);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        }
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")] 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)] 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public override void Import(string fileName, string password, X509KeyStorageFlags keyStorageFlags) {
            Reset(); 
            base.Import(fileName, password, keyStorageFlags);
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle); 
        } 

        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")] 
        [PermissionSetAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
        [PermissionSetAttribute(SecurityAction.InheritanceDemand, Unrestricted=true)]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public override void Import(string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags) {
            Reset(); 
            base.Import(fileName, password, keyStorageFlags); 
            m_safeCertContext = CAPI.CertDuplicateCertificateContext(this.Handle);
        } 

        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
        [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); 
        }
 
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        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);
        } 
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        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; 
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        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