X509Extension.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / security / system / security / cryptography / x509 / X509Extension.cs / 4 / X509Extension.cs

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

// 
// X509Extension.cs 
//
 
namespace System.Security.Cryptography.X509Certificates {
    using System.Collections;
    using System.Globalization;
    using System.Runtime.InteropServices; 
    using System.Security.Cryptography;
    using System.Text; 
 
    public class X509Extension : AsnEncodedData {
        private bool m_critical = false; 

        internal X509Extension(string oid) : base (new Oid(oid, OidGroup.ExtensionOrAttribute, false)) {}

        internal X509Extension(IntPtr pExtension) { 
            CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pExtension, typeof(CAPI.CERT_EXTENSION));
            m_critical = extension.fCritical; 
            string oidValue = extension.pszObjId; 
            m_oid = new Oid(oidValue, OidGroup.ExtensionOrAttribute, false);
            byte[] rawData = new byte[extension.Value.cbData]; 
            if (extension.Value.pbData != IntPtr.Zero)
                Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length);
            m_rawData = rawData;
        } 

        protected X509Extension() : base () {} 
 
        public X509Extension (string oid, byte[] rawData, bool critical) : this (new Oid(oid, OidGroup.ExtensionOrAttribute, true), rawData, critical) {}
 
        public X509Extension (AsnEncodedData encodedExtension, bool critical) : this (encodedExtension.Oid, encodedExtension.RawData, critical) {}

        public X509Extension (Oid oid, byte[] rawData, bool critical) : base (oid, rawData) {
            if (base.Oid == null || base.Oid.Value == null) 
                throw new ArgumentNullException("oid");
            if (base.Oid.Value.Length == 0) 
                throw new ArgumentException(SR.GetString(SR.Arg_EmptyOrNullString), "oid.Value"); 
            m_critical = critical;
        } 

        public bool Critical {
            get {
                return m_critical; 
            }
            set { 
                m_critical = value; 
            }
        } 

        public override void CopyFrom (AsnEncodedData asnEncodedData) {
            if (asnEncodedData == null)
            { 
                throw new ArgumentNullException("asnEncodedData");
            } 
            X509Extension extension = asnEncodedData as X509Extension; 
            if (extension == null)
                throw new ArgumentException(SR.GetString(SR.Cryptography_X509_ExtensionMismatch)); 
            base.CopyFrom(asnEncodedData);
            m_critical = extension.Critical;
        }
    } 

    // 
    // Key Usage flags map the definition in wincrypt.h, so that no mapping will be necessary. 
    //
 
    [Flags]
    public enum X509KeyUsageFlags {
        None             = 0x0000,
        EncipherOnly     = 0x0001, 
        CrlSign          = 0x0002,
        KeyCertSign      = 0x0004, 
        KeyAgreement     = 0x0008, 
        DataEncipherment = 0x0010,
        KeyEncipherment  = 0x0020, 
        NonRepudiation   = 0x0040,
        DigitalSignature = 0x0080,
        DecipherOnly     = 0x8000
    } 

    public sealed class X509KeyUsageExtension : X509Extension { 
        private uint m_keyUsages = 0; 
        private bool m_decoded = false;
 
        public X509KeyUsageExtension() : base (CAPI.szOID_KEY_USAGE) {
            m_decoded = true;
        }
 
        public X509KeyUsageExtension (X509KeyUsageFlags keyUsages, bool critical) :
            base (CAPI.szOID_KEY_USAGE, EncodeExtension(keyUsages), critical) {} 
 
        public X509KeyUsageExtension (AsnEncodedData encodedKeyUsage, bool critical) :
            base (CAPI.szOID_KEY_USAGE, encodedKeyUsage.RawData, critical) {} 

        public X509KeyUsageFlags KeyUsages {
            get {
                if (!m_decoded) 
                    DecodeExtension();
                return (X509KeyUsageFlags) m_keyUsages; 
            } 
        }
 
        public override void CopyFrom (AsnEncodedData asnEncodedData) {
            base.CopyFrom(asnEncodedData);
            m_decoded = false;
        } 

        private void DecodeExtension () { 
            uint cbDecoded = 0; 
            SafeLocalAllocHandle decoded = null;
 
            bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_KEY_USAGE),
                                            m_rawData,
                                            out decoded,
                                            out cbDecoded); 
            if (result == false)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
            CAPI.CRYPTOAPI_BLOB pKeyUsage = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));
            if (pKeyUsage.cbData > 4) 
                pKeyUsage.cbData = 4;
            byte[] keyUsage = new byte[4];
            if (pKeyUsage.pbData != IntPtr.Zero)
                Marshal.Copy(pKeyUsage.pbData, keyUsage, 0, (int) pKeyUsage.cbData); 
            m_keyUsages = BitConverter.ToUInt32(keyUsage, 0);
            m_decoded = true; 
 
            decoded.Dispose();
        } 

        private static unsafe byte[] EncodeExtension (X509KeyUsageFlags keyUsages) {
            CAPI.CRYPT_BIT_BLOB blob = new CAPI.CRYPT_BIT_BLOB();
            blob.cbData = 2; 
            blob.pbData = new IntPtr(&keyUsages);
            blob.cUnusedBits = 0; 
 
            byte[] encodedKeyUsages = null;
            if (!CAPI.EncodeObject(CAPI.szOID_KEY_USAGE, new IntPtr(&blob), out encodedKeyUsages)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            return encodedKeyUsages;
        } 
    }
 
    public sealed class X509BasicConstraintsExtension : X509Extension { 
        private bool m_isCA = false;
        private bool m_hasPathLenConstraint = false; 
        private int m_pathLenConstraint = 0;
        private bool m_decoded = false;

        public X509BasicConstraintsExtension() : base (CAPI.szOID_BASIC_CONSTRAINTS2) { 
            m_decoded = true;
        } 
 
        public X509BasicConstraintsExtension (bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint, bool critical) :
            base (CAPI.szOID_BASIC_CONSTRAINTS2, EncodeExtension(certificateAuthority, hasPathLengthConstraint, pathLengthConstraint), critical) {} 

        public X509BasicConstraintsExtension (AsnEncodedData encodedBasicConstraints, bool critical) :
            base (CAPI.szOID_BASIC_CONSTRAINTS2, encodedBasicConstraints.RawData, critical) {}
 
        public bool CertificateAuthority {
            get { 
                if (!m_decoded) 
                    DecodeExtension();
                return m_isCA; 
            }
        }

        public bool HasPathLengthConstraint { 
            get {
                if (!m_decoded) 
                    DecodeExtension(); 
                return m_hasPathLenConstraint;
            } 
        }

        public int PathLengthConstraint {
            get { 
                if (!m_decoded)
                    DecodeExtension(); 
                return m_pathLenConstraint; 
            }
        } 

        public override void CopyFrom (AsnEncodedData asnEncodedData) {
            base.CopyFrom(asnEncodedData);
            m_decoded = false; 
        }
 
        private void DecodeExtension () { 
            uint cbDecoded = 0;
            SafeLocalAllocHandle decoded = null; 

            if (Oid.Value == CAPI.szOID_BASIC_CONSTRAINTS) {
                bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_BASIC_CONSTRAINTS),
                                                m_rawData, 
                                                out decoded,
                                                out cbDecoded); 
                if (result == false) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                CAPI.CERT_BASIC_CONSTRAINTS_INFO pBasicConstraints = (CAPI.CERT_BASIC_CONSTRAINTS_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(),
                                                                                typeof(CAPI.CERT_BASIC_CONSTRAINTS_INFO));

                // take the first byte. 
                byte[] isCA = new byte[1];
                Marshal.Copy(pBasicConstraints.SubjectType.pbData, isCA, 0, 1); 
 
                m_isCA = (isCA[0] & CAPI.CERT_CA_SUBJECT_FLAG) != 0 ? true : false;
                m_hasPathLenConstraint = pBasicConstraints.fPathLenConstraint; 
                m_pathLenConstraint = (int) pBasicConstraints.dwPathLenConstraint;
            } else {
                bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_BASIC_CONSTRAINTS2),
                                                m_rawData, 
                                                out decoded,
                                                out cbDecoded); 
                if (result == false) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                CAPI.CERT_BASIC_CONSTRAINTS2_INFO pBasicConstraints2 = (CAPI.CERT_BASIC_CONSTRAINTS2_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(),
                                                                                typeof(CAPI.CERT_BASIC_CONSTRAINTS2_INFO));

                m_isCA = pBasicConstraints2.fCA == 0 ? false : true; 
                m_hasPathLenConstraint = pBasicConstraints2.fPathLenConstraint == 0 ? false : true;
                m_pathLenConstraint = (int) pBasicConstraints2.dwPathLenConstraint; 
            } 

            m_decoded = true; 
            decoded.Dispose();
        }

        private static unsafe byte[] EncodeExtension (bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint) { 
            CAPI.CERT_BASIC_CONSTRAINTS2_INFO pBasicConstraints2 = new CAPI.CERT_BASIC_CONSTRAINTS2_INFO();
            pBasicConstraints2.fCA = certificateAuthority ? 1 : 0; 
            pBasicConstraints2.fPathLenConstraint = hasPathLengthConstraint ? 1 : 0; 
            if (hasPathLengthConstraint) {
                if (pathLengthConstraint < 0) 
                    throw new ArgumentOutOfRangeException("pathLengthConstraint", SR.GetString(SR.Arg_OutOfRange_NeedNonNegNum));
                pBasicConstraints2.dwPathLenConstraint = (uint) pathLengthConstraint;
            }
 
            byte[] encodedBasicConstraints = null;
            if (!CAPI.EncodeObject(CAPI.szOID_BASIC_CONSTRAINTS2, new IntPtr(&pBasicConstraints2), out encodedBasicConstraints)) 
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            return encodedBasicConstraints; 
        }
    }

    public sealed class X509EnhancedKeyUsageExtension : X509Extension { 
        private OidCollection m_enhancedKeyUsages;
        private bool m_decoded = false; 
 
        public X509EnhancedKeyUsageExtension() : base (CAPI.szOID_ENHANCED_KEY_USAGE) {
            m_enhancedKeyUsages = new OidCollection(); 
            m_decoded = true;
        }

        public X509EnhancedKeyUsageExtension(OidCollection enhancedKeyUsages, bool critical) : 
            base (CAPI.szOID_ENHANCED_KEY_USAGE, EncodeExtension(enhancedKeyUsages), critical) {}
 
        public X509EnhancedKeyUsageExtension(AsnEncodedData encodedEnhancedKeyUsages, bool critical) : 
            base (CAPI.szOID_ENHANCED_KEY_USAGE, encodedEnhancedKeyUsages.RawData, critical) {}
 
        public OidCollection EnhancedKeyUsages {
            get {
                if (!m_decoded)
                    DecodeExtension(); 
                OidCollection oids = new OidCollection();
                foreach(Oid oid in m_enhancedKeyUsages) { 
                    oids.Add(oid); 
                }
                return oids; 
            }
        }

        public override void CopyFrom (AsnEncodedData asnEncodedData) { 
            base.CopyFrom(asnEncodedData);
            m_decoded = false; 
        } 

        private void DecodeExtension () { 
            uint cbDecoded = 0;
            SafeLocalAllocHandle decoded = null;

            bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_ENHANCED_KEY_USAGE), 
                                            m_rawData,
                                            out decoded, 
                                            out cbDecoded); 
            if (result == false)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            CAPI.CERT_ENHKEY_USAGE pEnhKeyUsage = (CAPI.CERT_ENHKEY_USAGE) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_ENHKEY_USAGE));

            m_enhancedKeyUsages = new OidCollection(); 
            for (int index = 0; index < pEnhKeyUsage.cUsageIdentifier; index++) {
                IntPtr pszOid = Marshal.ReadIntPtr(new IntPtr((long) pEnhKeyUsage.rgpszUsageIdentifier + index * Marshal.SizeOf(typeof(IntPtr)))); 
                string oidValue = Marshal.PtrToStringAnsi(pszOid); 
                Oid oid = new Oid(oidValue, OidGroup.ExtensionOrAttribute, false);
                m_enhancedKeyUsages.Add(oid); 
            }

            m_decoded = true;
            decoded.Dispose(); 
        }
 
        private static unsafe byte[] EncodeExtension (OidCollection enhancedKeyUsages) { 
            if (enhancedKeyUsages == null)
                throw new ArgumentNullException("enhancedKeyUsages"); 

            SafeLocalAllocHandle safeLocalAllocHandle = X509Utils.CopyOidsToUnmanagedMemory(enhancedKeyUsages);
            byte[] encodedEnhancedKeyUsages = null;
            using (safeLocalAllocHandle) { 
                CAPI.CERT_ENHKEY_USAGE pEnhKeyUsage = new CAPI.CERT_ENHKEY_USAGE();
                pEnhKeyUsage.cUsageIdentifier = (uint) enhancedKeyUsages.Count; 
                pEnhKeyUsage.rgpszUsageIdentifier = safeLocalAllocHandle.DangerousGetHandle(); 
                if (!CAPI.EncodeObject(CAPI.szOID_ENHANCED_KEY_USAGE, new IntPtr(&pEnhKeyUsage), out encodedEnhancedKeyUsages))
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
            }

            return encodedEnhancedKeyUsages;
        } 
    }
 
    public enum X509SubjectKeyIdentifierHashAlgorithm { 
        Sha1        = 0,
        ShortSha1   = 1, 
        CapiSha1    = 2,
    }

    public sealed class X509SubjectKeyIdentifierExtension : X509Extension { 
        private string m_subjectKeyIdentifier;
        private bool m_decoded = false; 
 
        public X509SubjectKeyIdentifierExtension() : base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER) {
            m_subjectKeyIdentifier = null; 
            m_decoded = true;
        }

        public X509SubjectKeyIdentifierExtension (string subjectKeyIdentifier, bool critical) : 
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodeExtension(subjectKeyIdentifier), critical) {}
 
        public X509SubjectKeyIdentifierExtension (byte[] subjectKeyIdentifier, bool critical) : 
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodeExtension(subjectKeyIdentifier), critical) {}
 
        public X509SubjectKeyIdentifierExtension (AsnEncodedData encodedSubjectKeyIdentifier, bool critical) :
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, encodedSubjectKeyIdentifier.RawData, critical) {}

        public X509SubjectKeyIdentifierExtension (PublicKey key, bool critical) : 
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodePublicKey(key, X509SubjectKeyIdentifierHashAlgorithm.Sha1), critical) {}
 
        public X509SubjectKeyIdentifierExtension (PublicKey key, X509SubjectKeyIdentifierHashAlgorithm algorithm, bool critical) : 
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodePublicKey(key, algorithm), critical) {}
 
        public string SubjectKeyIdentifier {
            get {
                if (!m_decoded)
                    DecodeExtension(); 
                return m_subjectKeyIdentifier;
            } 
        } 

        public override void CopyFrom (AsnEncodedData asnEncodedData) { 
            base.CopyFrom(asnEncodedData);
            m_decoded = false;
        }
 
        private void DecodeExtension () {
            uint cbDecoded = 0; 
            SafeLocalAllocHandle decoded = null; 

            SafeLocalAllocHandle pb = X509Utils.StringToAnsiPtr(CAPI.szOID_SUBJECT_KEY_IDENTIFIER); 
            bool result = CAPI.DecodeObject(pb.DangerousGetHandle(),
                                            m_rawData,
                                            out decoded,
                                            out cbDecoded); 
            if (!result)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
            CAPI.CRYPTOAPI_BLOB pSubjectKeyIdentifier = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));
            byte[] hexArray = CAPI.BlobToByteArray(pSubjectKeyIdentifier); 
            m_subjectKeyIdentifier = X509Utils.EncodeHexString(hexArray);

            m_decoded = true;
            decoded.Dispose(); 
            pb.Dispose();
        } 
 
        private static unsafe byte[] EncodeExtension (string subjectKeyIdentifier) {
            if (subjectKeyIdentifier == null) 
                throw new ArgumentNullException("subjectKeyIdentifier");

            return EncodeExtension(X509Utils.DecodeHexString(subjectKeyIdentifier));
        } 

        private static unsafe byte[] EncodeExtension (byte[] subjectKeyIdentifier) { 
            if (subjectKeyIdentifier == null) 
                throw new ArgumentNullException("subjectKeyIdentifier");
            if (subjectKeyIdentifier.Length == 0) 
                throw new ArgumentException("subjectKeyIdentifier");

            byte[] encodedSubjectKeyIdentifier = null;
            fixed (byte* pb = subjectKeyIdentifier) { 
                CAPI.CRYPTOAPI_BLOB pSubjectKeyIdentifier = new CAPI.CRYPTOAPI_BLOB();
                pSubjectKeyIdentifier.pbData = new IntPtr(pb); 
                pSubjectKeyIdentifier.cbData = (uint) subjectKeyIdentifier.Length; 

                if (!CAPI.EncodeObject(CAPI.szOID_SUBJECT_KEY_IDENTIFIER, new IntPtr(&pSubjectKeyIdentifier), out encodedSubjectKeyIdentifier)) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            return encodedSubjectKeyIdentifier; 
        }
 
        // Construct CERT_PUBLIC_KEY_INFO2 in unmanged memory from given encoded blobs. 
        private static unsafe SafeLocalAllocHandle EncodePublicKey (PublicKey key) {
            SafeLocalAllocHandle publicKeyInfo = SafeLocalAllocHandle.InvalidHandle; 
            CAPI.CERT_PUBLIC_KEY_INFO2 * pPublicKeyInfo = null;
            string objId = key.Oid.Value;
            byte[] encodedParameters = key.EncodedParameters.RawData;
            byte[] encodedKeyValue = key.EncodedKeyValue.RawData; 

            uint cbPublicKeyInfo = (uint) (Marshal.SizeOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO2)) + 
                                                          X509Utils.AlignedLength((uint) (objId.Length + 1)) + 
                                                          X509Utils.AlignedLength((uint) encodedParameters.Length) +
                                                          encodedKeyValue.Length); 

            publicKeyInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbPublicKeyInfo));
            pPublicKeyInfo = (CAPI.CERT_PUBLIC_KEY_INFO2 *) publicKeyInfo.DangerousGetHandle();
            IntPtr pszObjId =  new IntPtr((long) pPublicKeyInfo + Marshal.SizeOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO2))); 
            IntPtr pbParameters = new IntPtr((long) pszObjId + X509Utils.AlignedLength(((uint) (objId.Length + 1))));
            IntPtr pbPublicKey = new IntPtr((long) pbParameters + X509Utils.AlignedLength((uint) encodedParameters.Length)); 
 
            pPublicKeyInfo->Algorithm.pszObjId = pszObjId;
            byte[] szObjId = new byte[objId.Length + 1]; 
            Encoding.ASCII.GetBytes(objId, 0, objId.Length, szObjId, 0);
            Marshal.Copy(szObjId, 0, pszObjId, szObjId.Length);
            if (encodedParameters.Length > 0) {
                pPublicKeyInfo->Algorithm.Parameters.cbData = (uint) encodedParameters.Length; 
                pPublicKeyInfo->Algorithm.Parameters.pbData = pbParameters;
                Marshal.Copy(encodedParameters, 0, pbParameters, encodedParameters.Length); 
            } 
            pPublicKeyInfo->PublicKey.cbData = (uint) encodedKeyValue.Length;
            pPublicKeyInfo->PublicKey.pbData = pbPublicKey; 
            Marshal.Copy(encodedKeyValue, 0, pbPublicKey, encodedKeyValue.Length);
            return publicKeyInfo;
        }
 
        private static unsafe byte[] EncodePublicKey (PublicKey key, X509SubjectKeyIdentifierHashAlgorithm algorithm) {
            if (key == null) 
                throw new ArgumentNullException("key"); 

            // Construct CERT_PUBLIC_KEY_INFO2 in unmanged memory from given encoded blobs. 
            SafeLocalAllocHandle publicKeyInfo = EncodePublicKey(key);
            CAPI.CERT_PUBLIC_KEY_INFO2 * pPublicKeyInfo = (CAPI.CERT_PUBLIC_KEY_INFO2 *) publicKeyInfo.DangerousGetHandle();

            byte [] buffer = new byte[20]; 
            byte [] identifier = null;
 
            fixed (byte * pBuffer = buffer) { 
                uint cbData = (uint)buffer.Length;
                IntPtr pbData = new IntPtr(pBuffer); 

                try {
                    if ((X509SubjectKeyIdentifierHashAlgorithm.Sha1 == algorithm)
                        || (X509SubjectKeyIdentifierHashAlgorithm.ShortSha1 == algorithm)) { 
                    //+==================================================================
                    // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of 
                    // the value of the BIT STRING subjectPublicKey (excluding the tag, 
                    // length, and number of unused bits).
                        if (!CAPI.CryptHashCertificate( 
                                    IntPtr.Zero,        // hCryptProv
                                    CAPI.CALG_SHA1,
                                    0,                  // dwFlags,
                                    pPublicKeyInfo->PublicKey.pbData, 
                                    pPublicKeyInfo->PublicKey.cbData,
                                    pbData, 
                                    new IntPtr(&cbData))) 
                            throw new CryptographicException(Marshal.GetHRForLastWin32Error());
                    } 
                    //+=================================================================
                    // Microsoft convention: The keyIdentifier is composed of the
                    // 160-bit SHA-1 hash of the encoded subjectPublicKey BITSTRING
                    // (including the tag, length, and number of unused bits). 
                    else if (X509SubjectKeyIdentifierHashAlgorithm.CapiSha1 == algorithm) {
                        if (!CAPI.CryptHashPublicKeyInfo( 
                                    IntPtr.Zero,        // hCryptProv 
                                    CAPI.CALG_SHA1,
                                    0,                  // dwFlags, 
                                    CAPI.X509_ASN_ENCODING,
                                    new IntPtr(pPublicKeyInfo),
                                    pbData,
                                    new IntPtr(&cbData))) { 
                            throw new CryptographicException(Marshal.GetHRForLastWin32Error());
                        } 
                    } else { 
                        throw new ArgumentException("algorithm");
                    } 

                    //+=================================================================
                    // (2) The keyIdentifier is composed of a four bit type field with
                    //  the value 0100 followed by the least significant 60 bits of the 
                    //  SHA-1 hash of the value of the BIT STRING subjectPublicKey
                    // (excluding the tag, length, and number of unused bit string bits) 
                    if (X509SubjectKeyIdentifierHashAlgorithm.ShortSha1 == algorithm) { 
                        identifier = new byte[8];
                        Array.Copy(buffer, buffer.Length - 8, identifier, 0, identifier.Length); 
                        identifier[0] &= 0x0f;
                        identifier[0] |= 0x40;
                    } else {
                        identifier = buffer; 
                        // return the meaningful part only
                        if (buffer.Length > (int)cbData) { 
                            identifier = new byte[cbData]; 
                            Array.Copy(buffer, 0, identifier, 0, identifier.Length);
                        } 
                    }
                } finally {
                    publicKeyInfo.Dispose();
                } 
            }
 
            return EncodeExtension(identifier); 
        }
    } 

    public sealed class X509ExtensionCollection : ICollection {
        private ArrayList m_list = new ArrayList();
 
        //
        // Constructors. 
        // 

        public X509ExtensionCollection() {} 

        internal unsafe X509ExtensionCollection(SafeCertContextHandle safeCertContextHandle) {
            using (SafeCertContextHandle certContext = CAPI.CertDuplicateCertificateContext(safeCertContextHandle)) {
                CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) certContext.DangerousGetHandle()); 
                CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                uint cExtensions = pCertInfo.cExtension; 
                IntPtr rgExtensions = pCertInfo.rgExtension; 

                for (uint index = 0; index < cExtensions; index++) { 
                    X509Extension extension = new X509Extension(new IntPtr((long)rgExtensions + (index * Marshal.SizeOf(typeof(CAPI.CERT_EXTENSION)))));
                    X509Extension customExtension = CryptoConfig.CreateFromName(extension.Oid.Value) as X509Extension;
                    if (customExtension != null) {
                        customExtension.CopyFrom(extension); 
                        extension = customExtension;
                    } 
                    Add(extension); 
                }
            } 
        }

        public X509Extension this[int index] {
            get { 
                if (index < 0)
                    throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumNotStarted)); 
                if (index >= m_list.Count) 
                    throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_Index));
 
                return (X509Extension) m_list[index];
            }
        }
 
        // Indexer using an OID friendly name or value.
        public X509Extension this[string oid] { 
            get { 
                // If we were passed the friendly name, retrieve the value string.
                string oidValue = X509Utils.FindOidInfo(CAPI.CRYPT_OID_INFO_NAME_KEY, oid, OidGroup.ExtensionOrAttribute); 
                if (oidValue == null)
                    oidValue = oid;

                foreach (X509Extension extension in m_list) { 
                    if (String.Compare(extension.Oid.Value, oidValue, StringComparison.OrdinalIgnoreCase) == 0)
                        return extension; 
                } 
                return null;
            } 
        }

        public int Count {
            get { 
                return m_list.Count;
            } 
        } 

        public int Add (X509Extension extension) { 
            if (extension == null)
                throw new ArgumentNullException("extension");
            return m_list.Add(extension);
        } 

        public X509ExtensionEnumerator GetEnumerator() { 
            return new X509ExtensionEnumerator(this); 
        }
 
        /// 
        IEnumerator IEnumerable.GetEnumerator() {
            return new X509ExtensionEnumerator(this);
        } 

        ///  
        void ICollection.CopyTo(Array array, int index) { 
            if (array == null)
                throw new ArgumentNullException("array"); 
            if (array.Rank != 1)
                throw new ArgumentException(SR.GetString(SR.Arg_RankMultiDimNotSupported));
            if (index < 0 || index >= array.Length)
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_Index)); 
            if (index + this.Count > array.Length)
                throw new ArgumentException(SR.GetString(SR.Argument_InvalidOffLen)); 
 
            for (int i=0; i < this.Count; i++) {
                array.SetValue(this[i], index); 
                index++;
            }
        }
 
        public void CopyTo(X509Extension[] array, int index) {
            ((ICollection)this).CopyTo(array, index); 
        } 

        public bool IsSynchronized { 
            get {
                return false;
            }
        } 

        public Object SyncRoot { 
            get { 
                return this;
            } 
        }
    }

    public sealed class X509ExtensionEnumerator : IEnumerator { 
        private X509ExtensionCollection m_extensions;
        private int m_current; 
 
        private X509ExtensionEnumerator() {}
        internal X509ExtensionEnumerator(X509ExtensionCollection extensions) { 
            m_extensions = extensions;
            m_current = -1;
        }
 
        public X509Extension Current {
            get { 
                return m_extensions[m_current]; 
            }
        } 

        /// 
        Object IEnumerator.Current {
            get { 
                return (Object) m_extensions[m_current];
            } 
        } 

        public bool MoveNext() { 
            if (m_current == ((int) m_extensions.Count - 1))
                return false;
            m_current++;
            return true; 
        }
 
        public void Reset() { 
            m_current = -1;
        } 
    }
}

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

// 
// X509Extension.cs 
//
 
namespace System.Security.Cryptography.X509Certificates {
    using System.Collections;
    using System.Globalization;
    using System.Runtime.InteropServices; 
    using System.Security.Cryptography;
    using System.Text; 
 
    public class X509Extension : AsnEncodedData {
        private bool m_critical = false; 

        internal X509Extension(string oid) : base (new Oid(oid, OidGroup.ExtensionOrAttribute, false)) {}

        internal X509Extension(IntPtr pExtension) { 
            CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pExtension, typeof(CAPI.CERT_EXTENSION));
            m_critical = extension.fCritical; 
            string oidValue = extension.pszObjId; 
            m_oid = new Oid(oidValue, OidGroup.ExtensionOrAttribute, false);
            byte[] rawData = new byte[extension.Value.cbData]; 
            if (extension.Value.pbData != IntPtr.Zero)
                Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length);
            m_rawData = rawData;
        } 

        protected X509Extension() : base () {} 
 
        public X509Extension (string oid, byte[] rawData, bool critical) : this (new Oid(oid, OidGroup.ExtensionOrAttribute, true), rawData, critical) {}
 
        public X509Extension (AsnEncodedData encodedExtension, bool critical) : this (encodedExtension.Oid, encodedExtension.RawData, critical) {}

        public X509Extension (Oid oid, byte[] rawData, bool critical) : base (oid, rawData) {
            if (base.Oid == null || base.Oid.Value == null) 
                throw new ArgumentNullException("oid");
            if (base.Oid.Value.Length == 0) 
                throw new ArgumentException(SR.GetString(SR.Arg_EmptyOrNullString), "oid.Value"); 
            m_critical = critical;
        } 

        public bool Critical {
            get {
                return m_critical; 
            }
            set { 
                m_critical = value; 
            }
        } 

        public override void CopyFrom (AsnEncodedData asnEncodedData) {
            if (asnEncodedData == null)
            { 
                throw new ArgumentNullException("asnEncodedData");
            } 
            X509Extension extension = asnEncodedData as X509Extension; 
            if (extension == null)
                throw new ArgumentException(SR.GetString(SR.Cryptography_X509_ExtensionMismatch)); 
            base.CopyFrom(asnEncodedData);
            m_critical = extension.Critical;
        }
    } 

    // 
    // Key Usage flags map the definition in wincrypt.h, so that no mapping will be necessary. 
    //
 
    [Flags]
    public enum X509KeyUsageFlags {
        None             = 0x0000,
        EncipherOnly     = 0x0001, 
        CrlSign          = 0x0002,
        KeyCertSign      = 0x0004, 
        KeyAgreement     = 0x0008, 
        DataEncipherment = 0x0010,
        KeyEncipherment  = 0x0020, 
        NonRepudiation   = 0x0040,
        DigitalSignature = 0x0080,
        DecipherOnly     = 0x8000
    } 

    public sealed class X509KeyUsageExtension : X509Extension { 
        private uint m_keyUsages = 0; 
        private bool m_decoded = false;
 
        public X509KeyUsageExtension() : base (CAPI.szOID_KEY_USAGE) {
            m_decoded = true;
        }
 
        public X509KeyUsageExtension (X509KeyUsageFlags keyUsages, bool critical) :
            base (CAPI.szOID_KEY_USAGE, EncodeExtension(keyUsages), critical) {} 
 
        public X509KeyUsageExtension (AsnEncodedData encodedKeyUsage, bool critical) :
            base (CAPI.szOID_KEY_USAGE, encodedKeyUsage.RawData, critical) {} 

        public X509KeyUsageFlags KeyUsages {
            get {
                if (!m_decoded) 
                    DecodeExtension();
                return (X509KeyUsageFlags) m_keyUsages; 
            } 
        }
 
        public override void CopyFrom (AsnEncodedData asnEncodedData) {
            base.CopyFrom(asnEncodedData);
            m_decoded = false;
        } 

        private void DecodeExtension () { 
            uint cbDecoded = 0; 
            SafeLocalAllocHandle decoded = null;
 
            bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_KEY_USAGE),
                                            m_rawData,
                                            out decoded,
                                            out cbDecoded); 
            if (result == false)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
            CAPI.CRYPTOAPI_BLOB pKeyUsage = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));
            if (pKeyUsage.cbData > 4) 
                pKeyUsage.cbData = 4;
            byte[] keyUsage = new byte[4];
            if (pKeyUsage.pbData != IntPtr.Zero)
                Marshal.Copy(pKeyUsage.pbData, keyUsage, 0, (int) pKeyUsage.cbData); 
            m_keyUsages = BitConverter.ToUInt32(keyUsage, 0);
            m_decoded = true; 
 
            decoded.Dispose();
        } 

        private static unsafe byte[] EncodeExtension (X509KeyUsageFlags keyUsages) {
            CAPI.CRYPT_BIT_BLOB blob = new CAPI.CRYPT_BIT_BLOB();
            blob.cbData = 2; 
            blob.pbData = new IntPtr(&keyUsages);
            blob.cUnusedBits = 0; 
 
            byte[] encodedKeyUsages = null;
            if (!CAPI.EncodeObject(CAPI.szOID_KEY_USAGE, new IntPtr(&blob), out encodedKeyUsages)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            return encodedKeyUsages;
        } 
    }
 
    public sealed class X509BasicConstraintsExtension : X509Extension { 
        private bool m_isCA = false;
        private bool m_hasPathLenConstraint = false; 
        private int m_pathLenConstraint = 0;
        private bool m_decoded = false;

        public X509BasicConstraintsExtension() : base (CAPI.szOID_BASIC_CONSTRAINTS2) { 
            m_decoded = true;
        } 
 
        public X509BasicConstraintsExtension (bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint, bool critical) :
            base (CAPI.szOID_BASIC_CONSTRAINTS2, EncodeExtension(certificateAuthority, hasPathLengthConstraint, pathLengthConstraint), critical) {} 

        public X509BasicConstraintsExtension (AsnEncodedData encodedBasicConstraints, bool critical) :
            base (CAPI.szOID_BASIC_CONSTRAINTS2, encodedBasicConstraints.RawData, critical) {}
 
        public bool CertificateAuthority {
            get { 
                if (!m_decoded) 
                    DecodeExtension();
                return m_isCA; 
            }
        }

        public bool HasPathLengthConstraint { 
            get {
                if (!m_decoded) 
                    DecodeExtension(); 
                return m_hasPathLenConstraint;
            } 
        }

        public int PathLengthConstraint {
            get { 
                if (!m_decoded)
                    DecodeExtension(); 
                return m_pathLenConstraint; 
            }
        } 

        public override void CopyFrom (AsnEncodedData asnEncodedData) {
            base.CopyFrom(asnEncodedData);
            m_decoded = false; 
        }
 
        private void DecodeExtension () { 
            uint cbDecoded = 0;
            SafeLocalAllocHandle decoded = null; 

            if (Oid.Value == CAPI.szOID_BASIC_CONSTRAINTS) {
                bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_BASIC_CONSTRAINTS),
                                                m_rawData, 
                                                out decoded,
                                                out cbDecoded); 
                if (result == false) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                CAPI.CERT_BASIC_CONSTRAINTS_INFO pBasicConstraints = (CAPI.CERT_BASIC_CONSTRAINTS_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(),
                                                                                typeof(CAPI.CERT_BASIC_CONSTRAINTS_INFO));

                // take the first byte. 
                byte[] isCA = new byte[1];
                Marshal.Copy(pBasicConstraints.SubjectType.pbData, isCA, 0, 1); 
 
                m_isCA = (isCA[0] & CAPI.CERT_CA_SUBJECT_FLAG) != 0 ? true : false;
                m_hasPathLenConstraint = pBasicConstraints.fPathLenConstraint; 
                m_pathLenConstraint = (int) pBasicConstraints.dwPathLenConstraint;
            } else {
                bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_BASIC_CONSTRAINTS2),
                                                m_rawData, 
                                                out decoded,
                                                out cbDecoded); 
                if (result == false) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                CAPI.CERT_BASIC_CONSTRAINTS2_INFO pBasicConstraints2 = (CAPI.CERT_BASIC_CONSTRAINTS2_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(),
                                                                                typeof(CAPI.CERT_BASIC_CONSTRAINTS2_INFO));

                m_isCA = pBasicConstraints2.fCA == 0 ? false : true; 
                m_hasPathLenConstraint = pBasicConstraints2.fPathLenConstraint == 0 ? false : true;
                m_pathLenConstraint = (int) pBasicConstraints2.dwPathLenConstraint; 
            } 

            m_decoded = true; 
            decoded.Dispose();
        }

        private static unsafe byte[] EncodeExtension (bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint) { 
            CAPI.CERT_BASIC_CONSTRAINTS2_INFO pBasicConstraints2 = new CAPI.CERT_BASIC_CONSTRAINTS2_INFO();
            pBasicConstraints2.fCA = certificateAuthority ? 1 : 0; 
            pBasicConstraints2.fPathLenConstraint = hasPathLengthConstraint ? 1 : 0; 
            if (hasPathLengthConstraint) {
                if (pathLengthConstraint < 0) 
                    throw new ArgumentOutOfRangeException("pathLengthConstraint", SR.GetString(SR.Arg_OutOfRange_NeedNonNegNum));
                pBasicConstraints2.dwPathLenConstraint = (uint) pathLengthConstraint;
            }
 
            byte[] encodedBasicConstraints = null;
            if (!CAPI.EncodeObject(CAPI.szOID_BASIC_CONSTRAINTS2, new IntPtr(&pBasicConstraints2), out encodedBasicConstraints)) 
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            return encodedBasicConstraints; 
        }
    }

    public sealed class X509EnhancedKeyUsageExtension : X509Extension { 
        private OidCollection m_enhancedKeyUsages;
        private bool m_decoded = false; 
 
        public X509EnhancedKeyUsageExtension() : base (CAPI.szOID_ENHANCED_KEY_USAGE) {
            m_enhancedKeyUsages = new OidCollection(); 
            m_decoded = true;
        }

        public X509EnhancedKeyUsageExtension(OidCollection enhancedKeyUsages, bool critical) : 
            base (CAPI.szOID_ENHANCED_KEY_USAGE, EncodeExtension(enhancedKeyUsages), critical) {}
 
        public X509EnhancedKeyUsageExtension(AsnEncodedData encodedEnhancedKeyUsages, bool critical) : 
            base (CAPI.szOID_ENHANCED_KEY_USAGE, encodedEnhancedKeyUsages.RawData, critical) {}
 
        public OidCollection EnhancedKeyUsages {
            get {
                if (!m_decoded)
                    DecodeExtension(); 
                OidCollection oids = new OidCollection();
                foreach(Oid oid in m_enhancedKeyUsages) { 
                    oids.Add(oid); 
                }
                return oids; 
            }
        }

        public override void CopyFrom (AsnEncodedData asnEncodedData) { 
            base.CopyFrom(asnEncodedData);
            m_decoded = false; 
        } 

        private void DecodeExtension () { 
            uint cbDecoded = 0;
            SafeLocalAllocHandle decoded = null;

            bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_ENHANCED_KEY_USAGE), 
                                            m_rawData,
                                            out decoded, 
                                            out cbDecoded); 
            if (result == false)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            CAPI.CERT_ENHKEY_USAGE pEnhKeyUsage = (CAPI.CERT_ENHKEY_USAGE) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_ENHKEY_USAGE));

            m_enhancedKeyUsages = new OidCollection(); 
            for (int index = 0; index < pEnhKeyUsage.cUsageIdentifier; index++) {
                IntPtr pszOid = Marshal.ReadIntPtr(new IntPtr((long) pEnhKeyUsage.rgpszUsageIdentifier + index * Marshal.SizeOf(typeof(IntPtr)))); 
                string oidValue = Marshal.PtrToStringAnsi(pszOid); 
                Oid oid = new Oid(oidValue, OidGroup.ExtensionOrAttribute, false);
                m_enhancedKeyUsages.Add(oid); 
            }

            m_decoded = true;
            decoded.Dispose(); 
        }
 
        private static unsafe byte[] EncodeExtension (OidCollection enhancedKeyUsages) { 
            if (enhancedKeyUsages == null)
                throw new ArgumentNullException("enhancedKeyUsages"); 

            SafeLocalAllocHandle safeLocalAllocHandle = X509Utils.CopyOidsToUnmanagedMemory(enhancedKeyUsages);
            byte[] encodedEnhancedKeyUsages = null;
            using (safeLocalAllocHandle) { 
                CAPI.CERT_ENHKEY_USAGE pEnhKeyUsage = new CAPI.CERT_ENHKEY_USAGE();
                pEnhKeyUsage.cUsageIdentifier = (uint) enhancedKeyUsages.Count; 
                pEnhKeyUsage.rgpszUsageIdentifier = safeLocalAllocHandle.DangerousGetHandle(); 
                if (!CAPI.EncodeObject(CAPI.szOID_ENHANCED_KEY_USAGE, new IntPtr(&pEnhKeyUsage), out encodedEnhancedKeyUsages))
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
            }

            return encodedEnhancedKeyUsages;
        } 
    }
 
    public enum X509SubjectKeyIdentifierHashAlgorithm { 
        Sha1        = 0,
        ShortSha1   = 1, 
        CapiSha1    = 2,
    }

    public sealed class X509SubjectKeyIdentifierExtension : X509Extension { 
        private string m_subjectKeyIdentifier;
        private bool m_decoded = false; 
 
        public X509SubjectKeyIdentifierExtension() : base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER) {
            m_subjectKeyIdentifier = null; 
            m_decoded = true;
        }

        public X509SubjectKeyIdentifierExtension (string subjectKeyIdentifier, bool critical) : 
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodeExtension(subjectKeyIdentifier), critical) {}
 
        public X509SubjectKeyIdentifierExtension (byte[] subjectKeyIdentifier, bool critical) : 
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodeExtension(subjectKeyIdentifier), critical) {}
 
        public X509SubjectKeyIdentifierExtension (AsnEncodedData encodedSubjectKeyIdentifier, bool critical) :
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, encodedSubjectKeyIdentifier.RawData, critical) {}

        public X509SubjectKeyIdentifierExtension (PublicKey key, bool critical) : 
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodePublicKey(key, X509SubjectKeyIdentifierHashAlgorithm.Sha1), critical) {}
 
        public X509SubjectKeyIdentifierExtension (PublicKey key, X509SubjectKeyIdentifierHashAlgorithm algorithm, bool critical) : 
            base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodePublicKey(key, algorithm), critical) {}
 
        public string SubjectKeyIdentifier {
            get {
                if (!m_decoded)
                    DecodeExtension(); 
                return m_subjectKeyIdentifier;
            } 
        } 

        public override void CopyFrom (AsnEncodedData asnEncodedData) { 
            base.CopyFrom(asnEncodedData);
            m_decoded = false;
        }
 
        private void DecodeExtension () {
            uint cbDecoded = 0; 
            SafeLocalAllocHandle decoded = null; 

            SafeLocalAllocHandle pb = X509Utils.StringToAnsiPtr(CAPI.szOID_SUBJECT_KEY_IDENTIFIER); 
            bool result = CAPI.DecodeObject(pb.DangerousGetHandle(),
                                            m_rawData,
                                            out decoded,
                                            out cbDecoded); 
            if (!result)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
            CAPI.CRYPTOAPI_BLOB pSubjectKeyIdentifier = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));
            byte[] hexArray = CAPI.BlobToByteArray(pSubjectKeyIdentifier); 
            m_subjectKeyIdentifier = X509Utils.EncodeHexString(hexArray);

            m_decoded = true;
            decoded.Dispose(); 
            pb.Dispose();
        } 
 
        private static unsafe byte[] EncodeExtension (string subjectKeyIdentifier) {
            if (subjectKeyIdentifier == null) 
                throw new ArgumentNullException("subjectKeyIdentifier");

            return EncodeExtension(X509Utils.DecodeHexString(subjectKeyIdentifier));
        } 

        private static unsafe byte[] EncodeExtension (byte[] subjectKeyIdentifier) { 
            if (subjectKeyIdentifier == null) 
                throw new ArgumentNullException("subjectKeyIdentifier");
            if (subjectKeyIdentifier.Length == 0) 
                throw new ArgumentException("subjectKeyIdentifier");

            byte[] encodedSubjectKeyIdentifier = null;
            fixed (byte* pb = subjectKeyIdentifier) { 
                CAPI.CRYPTOAPI_BLOB pSubjectKeyIdentifier = new CAPI.CRYPTOAPI_BLOB();
                pSubjectKeyIdentifier.pbData = new IntPtr(pb); 
                pSubjectKeyIdentifier.cbData = (uint) subjectKeyIdentifier.Length; 

                if (!CAPI.EncodeObject(CAPI.szOID_SUBJECT_KEY_IDENTIFIER, new IntPtr(&pSubjectKeyIdentifier), out encodedSubjectKeyIdentifier)) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            return encodedSubjectKeyIdentifier; 
        }
 
        // Construct CERT_PUBLIC_KEY_INFO2 in unmanged memory from given encoded blobs. 
        private static unsafe SafeLocalAllocHandle EncodePublicKey (PublicKey key) {
            SafeLocalAllocHandle publicKeyInfo = SafeLocalAllocHandle.InvalidHandle; 
            CAPI.CERT_PUBLIC_KEY_INFO2 * pPublicKeyInfo = null;
            string objId = key.Oid.Value;
            byte[] encodedParameters = key.EncodedParameters.RawData;
            byte[] encodedKeyValue = key.EncodedKeyValue.RawData; 

            uint cbPublicKeyInfo = (uint) (Marshal.SizeOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO2)) + 
                                                          X509Utils.AlignedLength((uint) (objId.Length + 1)) + 
                                                          X509Utils.AlignedLength((uint) encodedParameters.Length) +
                                                          encodedKeyValue.Length); 

            publicKeyInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbPublicKeyInfo));
            pPublicKeyInfo = (CAPI.CERT_PUBLIC_KEY_INFO2 *) publicKeyInfo.DangerousGetHandle();
            IntPtr pszObjId =  new IntPtr((long) pPublicKeyInfo + Marshal.SizeOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO2))); 
            IntPtr pbParameters = new IntPtr((long) pszObjId + X509Utils.AlignedLength(((uint) (objId.Length + 1))));
            IntPtr pbPublicKey = new IntPtr((long) pbParameters + X509Utils.AlignedLength((uint) encodedParameters.Length)); 
 
            pPublicKeyInfo->Algorithm.pszObjId = pszObjId;
            byte[] szObjId = new byte[objId.Length + 1]; 
            Encoding.ASCII.GetBytes(objId, 0, objId.Length, szObjId, 0);
            Marshal.Copy(szObjId, 0, pszObjId, szObjId.Length);
            if (encodedParameters.Length > 0) {
                pPublicKeyInfo->Algorithm.Parameters.cbData = (uint) encodedParameters.Length; 
                pPublicKeyInfo->Algorithm.Parameters.pbData = pbParameters;
                Marshal.Copy(encodedParameters, 0, pbParameters, encodedParameters.Length); 
            } 
            pPublicKeyInfo->PublicKey.cbData = (uint) encodedKeyValue.Length;
            pPublicKeyInfo->PublicKey.pbData = pbPublicKey; 
            Marshal.Copy(encodedKeyValue, 0, pbPublicKey, encodedKeyValue.Length);
            return publicKeyInfo;
        }
 
        private static unsafe byte[] EncodePublicKey (PublicKey key, X509SubjectKeyIdentifierHashAlgorithm algorithm) {
            if (key == null) 
                throw new ArgumentNullException("key"); 

            // Construct CERT_PUBLIC_KEY_INFO2 in unmanged memory from given encoded blobs. 
            SafeLocalAllocHandle publicKeyInfo = EncodePublicKey(key);
            CAPI.CERT_PUBLIC_KEY_INFO2 * pPublicKeyInfo = (CAPI.CERT_PUBLIC_KEY_INFO2 *) publicKeyInfo.DangerousGetHandle();

            byte [] buffer = new byte[20]; 
            byte [] identifier = null;
 
            fixed (byte * pBuffer = buffer) { 
                uint cbData = (uint)buffer.Length;
                IntPtr pbData = new IntPtr(pBuffer); 

                try {
                    if ((X509SubjectKeyIdentifierHashAlgorithm.Sha1 == algorithm)
                        || (X509SubjectKeyIdentifierHashAlgorithm.ShortSha1 == algorithm)) { 
                    //+==================================================================
                    // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of 
                    // the value of the BIT STRING subjectPublicKey (excluding the tag, 
                    // length, and number of unused bits).
                        if (!CAPI.CryptHashCertificate( 
                                    IntPtr.Zero,        // hCryptProv
                                    CAPI.CALG_SHA1,
                                    0,                  // dwFlags,
                                    pPublicKeyInfo->PublicKey.pbData, 
                                    pPublicKeyInfo->PublicKey.cbData,
                                    pbData, 
                                    new IntPtr(&cbData))) 
                            throw new CryptographicException(Marshal.GetHRForLastWin32Error());
                    } 
                    //+=================================================================
                    // Microsoft convention: The keyIdentifier is composed of the
                    // 160-bit SHA-1 hash of the encoded subjectPublicKey BITSTRING
                    // (including the tag, length, and number of unused bits). 
                    else if (X509SubjectKeyIdentifierHashAlgorithm.CapiSha1 == algorithm) {
                        if (!CAPI.CryptHashPublicKeyInfo( 
                                    IntPtr.Zero,        // hCryptProv 
                                    CAPI.CALG_SHA1,
                                    0,                  // dwFlags, 
                                    CAPI.X509_ASN_ENCODING,
                                    new IntPtr(pPublicKeyInfo),
                                    pbData,
                                    new IntPtr(&cbData))) { 
                            throw new CryptographicException(Marshal.GetHRForLastWin32Error());
                        } 
                    } else { 
                        throw new ArgumentException("algorithm");
                    } 

                    //+=================================================================
                    // (2) The keyIdentifier is composed of a four bit type field with
                    //  the value 0100 followed by the least significant 60 bits of the 
                    //  SHA-1 hash of the value of the BIT STRING subjectPublicKey
                    // (excluding the tag, length, and number of unused bit string bits) 
                    if (X509SubjectKeyIdentifierHashAlgorithm.ShortSha1 == algorithm) { 
                        identifier = new byte[8];
                        Array.Copy(buffer, buffer.Length - 8, identifier, 0, identifier.Length); 
                        identifier[0] &= 0x0f;
                        identifier[0] |= 0x40;
                    } else {
                        identifier = buffer; 
                        // return the meaningful part only
                        if (buffer.Length > (int)cbData) { 
                            identifier = new byte[cbData]; 
                            Array.Copy(buffer, 0, identifier, 0, identifier.Length);
                        } 
                    }
                } finally {
                    publicKeyInfo.Dispose();
                } 
            }
 
            return EncodeExtension(identifier); 
        }
    } 

    public sealed class X509ExtensionCollection : ICollection {
        private ArrayList m_list = new ArrayList();
 
        //
        // Constructors. 
        // 

        public X509ExtensionCollection() {} 

        internal unsafe X509ExtensionCollection(SafeCertContextHandle safeCertContextHandle) {
            using (SafeCertContextHandle certContext = CAPI.CertDuplicateCertificateContext(safeCertContextHandle)) {
                CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) certContext.DangerousGetHandle()); 
                CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                uint cExtensions = pCertInfo.cExtension; 
                IntPtr rgExtensions = pCertInfo.rgExtension; 

                for (uint index = 0; index < cExtensions; index++) { 
                    X509Extension extension = new X509Extension(new IntPtr((long)rgExtensions + (index * Marshal.SizeOf(typeof(CAPI.CERT_EXTENSION)))));
                    X509Extension customExtension = CryptoConfig.CreateFromName(extension.Oid.Value) as X509Extension;
                    if (customExtension != null) {
                        customExtension.CopyFrom(extension); 
                        extension = customExtension;
                    } 
                    Add(extension); 
                }
            } 
        }

        public X509Extension this[int index] {
            get { 
                if (index < 0)
                    throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumNotStarted)); 
                if (index >= m_list.Count) 
                    throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_Index));
 
                return (X509Extension) m_list[index];
            }
        }
 
        // Indexer using an OID friendly name or value.
        public X509Extension this[string oid] { 
            get { 
                // If we were passed the friendly name, retrieve the value string.
                string oidValue = X509Utils.FindOidInfo(CAPI.CRYPT_OID_INFO_NAME_KEY, oid, OidGroup.ExtensionOrAttribute); 
                if (oidValue == null)
                    oidValue = oid;

                foreach (X509Extension extension in m_list) { 
                    if (String.Compare(extension.Oid.Value, oidValue, StringComparison.OrdinalIgnoreCase) == 0)
                        return extension; 
                } 
                return null;
            } 
        }

        public int Count {
            get { 
                return m_list.Count;
            } 
        } 

        public int Add (X509Extension extension) { 
            if (extension == null)
                throw new ArgumentNullException("extension");
            return m_list.Add(extension);
        } 

        public X509ExtensionEnumerator GetEnumerator() { 
            return new X509ExtensionEnumerator(this); 
        }
 
        /// 
        IEnumerator IEnumerable.GetEnumerator() {
            return new X509ExtensionEnumerator(this);
        } 

        ///  
        void ICollection.CopyTo(Array array, int index) { 
            if (array == null)
                throw new ArgumentNullException("array"); 
            if (array.Rank != 1)
                throw new ArgumentException(SR.GetString(SR.Arg_RankMultiDimNotSupported));
            if (index < 0 || index >= array.Length)
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_Index)); 
            if (index + this.Count > array.Length)
                throw new ArgumentException(SR.GetString(SR.Argument_InvalidOffLen)); 
 
            for (int i=0; i < this.Count; i++) {
                array.SetValue(this[i], index); 
                index++;
            }
        }
 
        public void CopyTo(X509Extension[] array, int index) {
            ((ICollection)this).CopyTo(array, index); 
        } 

        public bool IsSynchronized { 
            get {
                return false;
            }
        } 

        public Object SyncRoot { 
            get { 
                return this;
            } 
        }
    }

    public sealed class X509ExtensionEnumerator : IEnumerator { 
        private X509ExtensionCollection m_extensions;
        private int m_current; 
 
        private X509ExtensionEnumerator() {}
        internal X509ExtensionEnumerator(X509ExtensionCollection extensions) { 
            m_extensions = extensions;
            m_current = -1;
        }
 
        public X509Extension Current {
            get { 
                return m_extensions[m_current]; 
            }
        } 

        /// 
        Object IEnumerator.Current {
            get { 
                return (Object) m_extensions[m_current];
            } 
        } 

        public bool MoveNext() { 
            if (m_current == ((int) m_extensions.Count - 1))
                return false;
            m_current++;
            return true; 
        }
 
        public void Reset() { 
            m_current = -1;
        } 
    }
}

// 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