PkcsMisc.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / clr / src / ManagedLibraries / Security / System / Security / Cryptography / Pkcs / PkcsMisc.cs / 1 / PkcsMisc.cs

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

// 
// PkcsMisc.cs 
//
// 02/09/2003 
//

namespace System.Security.Cryptography.Pkcs {
    using System.Collections; 
    using System.Globalization;
    using System.Runtime.InteropServices; 
    using System.Security.Cryptography; 
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Cryptography.Xml; 

    public enum KeyAgreeKeyChoice {
        Unknown      = 0,
        EphemeralKey = 1, 
        StaticKey    = 2,
    } 
 
    public enum SubjectIdentifierType {
        Unknown                = 0,  // Use any of the following as appropriate 
        IssuerAndSerialNumber  = 1,  // X509IssuerSerial
        SubjectKeyIdentifier   = 2,  // SKI hex string
        NoSignature            = 3  // NoSignature
    } 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] 
    public sealed class SubjectIdentifier { 
        private SubjectIdentifierType m_type;
        private Object                m_value; 

        private SubjectIdentifier () {}
        internal SubjectIdentifier (CAPI.CERT_INFO certInfo) : this(certInfo.Issuer, certInfo.SerialNumber) {}
        internal SubjectIdentifier (CAPI.CMSG_SIGNER_INFO signerInfo) : this(signerInfo.Issuer, signerInfo.SerialNumber) {} 

        internal SubjectIdentifier (SubjectIdentifierType type, Object value) { 
            Reset(type, value); 
        }
 
        internal unsafe SubjectIdentifier (CAPI.CRYPTOAPI_BLOB issuer, CAPI.CRYPTOAPI_BLOB serialNumber) {
            // If serial number is 0, then it is the special SKI encoding or NoSignature
            bool isSKIorHashOnly = true;
            byte * pb = (byte *) serialNumber.pbData; 
            for (uint i = 0; i < serialNumber.cbData; i++) {
                if (*pb++ != (byte) 0) { 
                    isSKIorHashOnly = false; 
                    break;
                } 
            }

            if (isSKIorHashOnly) {
                byte[] issuerBytes = new byte[issuer.cbData]; 
                Marshal.Copy(issuer.pbData, issuerBytes, 0, issuerBytes.Length);
                X500DistinguishedName dummyName = new X500DistinguishedName(issuerBytes); 
                if (String.Compare(CAPI.DummySignerCommonName, dummyName.Name, StringComparison.OrdinalIgnoreCase) == 0) { 
                    Reset(SubjectIdentifierType.NoSignature, null);
                    return; 
                }
            }

            if (isSKIorHashOnly) { 
                // Decode disguised SKI in issuer field (See WinCrypt.h for more info).
                m_type = SubjectIdentifierType.SubjectKeyIdentifier; 
                m_value = String.Empty; 

                uint cbCertNameInfo = 0; 
                SafeLocalAllocHandle pbCertNameInfo = SafeLocalAllocHandle.InvalidHandle;

                if (!CAPI.DecodeObject(new IntPtr(CAPI.X509_NAME),
                                       issuer.pbData, 
                                       issuer.cbData,
                                       out pbCertNameInfo, 
                                       out cbCertNameInfo)) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                using (pbCertNameInfo) {
                    CAPI.CERT_NAME_INFO certNameInfo = (CAPI.CERT_NAME_INFO) Marshal.PtrToStructure(pbCertNameInfo.DangerousGetHandle(), typeof(CAPI.CERT_NAME_INFO));
                    for (uint i = 0; i < certNameInfo.cRDN; i++) {
                        CAPI.CERT_RDN certRdn = (CAPI.CERT_RDN) Marshal.PtrToStructure(new IntPtr((long) certNameInfo.rgRDN + (long) (i * Marshal.SizeOf(typeof(CAPI.CERT_RDN)))), typeof(CAPI.CERT_RDN)); 

                        for (uint j = 0; j < certRdn.cRDNAttr; j++) { 
                            CAPI.CERT_RDN_ATTR certRdnAttr = (CAPI.CERT_RDN_ATTR) Marshal.PtrToStructure(new IntPtr((long) certRdn.rgRDNAttr + (long) (j * Marshal.SizeOf(typeof(CAPI.CERT_RDN_ATTR)))), typeof(CAPI.CERT_RDN_ATTR)); 

                            if (String.Compare(CAPI.szOID_KEYID_RDN, certRdnAttr.pszObjId, StringComparison.OrdinalIgnoreCase) == 0) { 
                                if (certRdnAttr.dwValueType == CAPI.CERT_RDN_OCTET_STRING) {
                                    byte[] ski = new byte[certRdnAttr.Value.cbData];
                                    Marshal.Copy(certRdnAttr.Value.pbData, ski, 0, ski.Length);
                                    Reset(SubjectIdentifierType.SubjectKeyIdentifier, X509Utils.EncodeHexString(ski)); 
                                    return;
                                } 
                            } 
                        }
                    } 
                }

                throw new CryptographicException(CAPI.CRYPT_E_ISSUER_SERIALNUMBER);
            } 
            else {
                CAPI.CERT_ISSUER_SERIAL_NUMBER IssuerAndSerial; 
                IssuerAndSerial.Issuer = issuer; 
                IssuerAndSerial.SerialNumber = serialNumber;
                X509IssuerSerial issuerSerial = PkcsUtils.DecodeIssuerSerial(IssuerAndSerial); 
                Reset(SubjectIdentifierType.IssuerAndSerialNumber, issuerSerial);
            }
        }
 
        internal SubjectIdentifier (CAPI.CERT_ID certId) {
            switch (certId.dwIdChoice) { 
            case CAPI.CERT_ID_ISSUER_SERIAL_NUMBER: 
                X509IssuerSerial issuerSerial = PkcsUtils.DecodeIssuerSerial(certId.Value.IssuerSerialNumber);
                Reset(SubjectIdentifierType.IssuerAndSerialNumber, issuerSerial); 
                break;
            case CAPI.CERT_ID_KEY_IDENTIFIER:
                byte[] ski = new byte[certId.Value.KeyId.cbData];
                Marshal.Copy(certId.Value.KeyId.pbData, ski, 0, ski.Length); 
                Reset(SubjectIdentifierType.SubjectKeyIdentifier, X509Utils.EncodeHexString(ski));
                break; 
            default: 
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type"), certId.dwIdChoice.ToString(CultureInfo.InvariantCulture));
            } 
        }

        public SubjectIdentifierType Type {
            get { 
                return m_type;
            } 
        } 

        public Object Value { 
            get {
                return m_value;
            }
        } 

        // 
        // Internal methods. 
        //
 
        internal void Reset (SubjectIdentifierType type, Object value) {
            switch (type) {
            case SubjectIdentifierType.NoSignature:
            case SubjectIdentifierType.Unknown: 
                break;
            case SubjectIdentifierType.IssuerAndSerialNumber: 
                if (value.GetType() != typeof(X509IssuerSerial)) { 
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString());
                } 
                break;
            case SubjectIdentifierType.SubjectKeyIdentifier:
                if (!PkcsUtils.CmsSupported()) {
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Not_Supported")); 
                }
                if (value.GetType() != typeof(string)) { 
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString()); 
                }
                break; 
            default:
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type"), type.ToString());
            }
 
            m_type = type;
            m_value = value; 
        } 
    }
 
    public enum SubjectIdentifierOrKeyType {
        Unknown                = 0,  // Use any of the following as appropriate
        IssuerAndSerialNumber  = 1,  // X509IssuerSerial
        SubjectKeyIdentifier   = 2,  // SKI hex string 
        PublicKeyInfo          = 3,  // PublicKeyInfo
    } 
 
    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class PublicKeyInfo { 
        private AlgorithmIdentifier m_algorithm;
        private byte[]              m_keyValue;

        private PublicKeyInfo () {} 

        internal PublicKeyInfo (CAPI.CERT_PUBLIC_KEY_INFO keyInfo) { 
            m_algorithm = new AlgorithmIdentifier(keyInfo); 
            m_keyValue = new byte[keyInfo.PublicKey.cbData];
            if (m_keyValue.Length > 0) { 
                Marshal.Copy(keyInfo.PublicKey.pbData, m_keyValue, 0, m_keyValue.Length);
            }
        }
 
        public AlgorithmIdentifier Algorithm {
            get { 
                return m_algorithm; 
            }
        } 

        public byte[] KeyValue {
            get {
                return m_keyValue; 
            }
        } 
    } 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] 
    public sealed class SubjectIdentifierOrKey {
        private SubjectIdentifierOrKeyType m_type;
        private Object                     m_value;
 
        private SubjectIdentifierOrKey () {}
 
        internal SubjectIdentifierOrKey (SubjectIdentifierOrKeyType type, Object value) { 
            Reset(type, value);
        } 

        internal SubjectIdentifierOrKey (CAPI.CERT_ID certId) {
            switch (certId.dwIdChoice) {
            case CAPI.CERT_ID_ISSUER_SERIAL_NUMBER: 
                X509IssuerSerial issuerSerial = PkcsUtils.DecodeIssuerSerial(certId.Value.IssuerSerialNumber);
                Reset(SubjectIdentifierOrKeyType.IssuerAndSerialNumber, issuerSerial); 
                break; 
            case CAPI.CERT_ID_KEY_IDENTIFIER:
                byte[] ski = new byte[certId.Value.KeyId.cbData]; 
                Marshal.Copy(certId.Value.KeyId.pbData, ski, 0, ski.Length);
                Reset(SubjectIdentifierOrKeyType.SubjectKeyIdentifier, X509Utils.EncodeHexString(ski));
                break;
            default: 
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type"), certId.dwIdChoice.ToString(CultureInfo.InvariantCulture));
            } 
        } 

        internal SubjectIdentifierOrKey (CAPI.CERT_PUBLIC_KEY_INFO publicKeyInfo) { 
            Reset(SubjectIdentifierOrKeyType.PublicKeyInfo, new PublicKeyInfo(publicKeyInfo));
        }

        public SubjectIdentifierOrKeyType Type { 
            get {
                return m_type; 
            } 
        }
 
        public Object Value {
            get {
                return m_value;
            } 
        }
 
        // 
        // Internal methods.
        // 

        internal void Reset (SubjectIdentifierOrKeyType type, Object value) {
            switch (type) {
            case SubjectIdentifierOrKeyType.Unknown: 
                break;
            case SubjectIdentifierOrKeyType.IssuerAndSerialNumber: 
                if (value.GetType() != typeof(X509IssuerSerial)) { 
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString());
                } 
                break;
            case SubjectIdentifierOrKeyType.SubjectKeyIdentifier:
                if (!PkcsUtils.CmsSupported()) {
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Not_Supported")); 
                }
                if (value.GetType() != typeof(string)) { 
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString()); 
                }
                break; 
            case SubjectIdentifierOrKeyType.PublicKeyInfo:
                if (!PkcsUtils.CmsSupported()) {
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Not_Supported"));
                } 
                if (value.GetType() != typeof(PublicKeyInfo)) {
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString()); 
                } 
                break;
            default: 
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type"), type.ToString());
            }

            m_type = type; 
            m_value = value;
        } 
    } 

 
    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class AlgorithmIdentifier {
        private Oid     m_oid;
        private int     m_keyLength; 
        private byte[]  m_parameters;
 
        public AlgorithmIdentifier () { 
            Reset(new Oid(CAPI.szOID_RSA_DES_EDE3_CBC), 0, new byte[0]);
        } 

        public AlgorithmIdentifier (Oid oid) {
            Reset(oid, 0, new byte[0]);
        } 

        public AlgorithmIdentifier (Oid oid, int keyLength) { 
            Reset(oid, keyLength, new byte[0]); 
        }
 
        internal AlgorithmIdentifier (string oidValue) {
            Reset(new Oid(oidValue), 0, new byte[0]);
        }
 
        internal unsafe AlgorithmIdentifier (CAPI.CERT_PUBLIC_KEY_INFO keyInfo) {
            SafeLocalAllocHandle pKeyInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO)))); 
            Marshal.StructureToPtr(keyInfo, pKeyInfo.DangerousGetHandle(), false); 
            int keyLength = (int) CAPI.CertGetPublicKeyLength(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, pKeyInfo.DangerousGetHandle());
            byte[] parameters = new byte[keyInfo.Algorithm.Parameters.cbData]; 
            if (parameters.Length > 0) {
                Marshal.Copy(keyInfo.Algorithm.Parameters.pbData, parameters, 0, parameters.Length);
            }
            Marshal.DestroyStructure(pKeyInfo.DangerousGetHandle(), typeof(CAPI.CERT_PUBLIC_KEY_INFO)); 
            pKeyInfo.Dispose();
            Reset(new Oid(keyInfo.Algorithm.pszObjId), keyLength, parameters); 
        } 

        internal unsafe AlgorithmIdentifier (CAPI.CRYPT_ALGORITHM_IDENTIFIER algorithmIdentifier) { 
            int keyLength = 0;
            uint cbParameters = 0;
            SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle;
            byte[] parameters = new byte[0]; 

            uint algId = X509Utils.OidToAlgId(algorithmIdentifier.pszObjId); 
 
            if (algId == CAPI.CALG_RC2) {
                if (algorithmIdentifier.Parameters.cbData > 0) { 
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS_RC2_CBC_PARAMETERS),
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData,
                                           out pbParameters, 
                                           out cbParameters))
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
                    CAPI.CRYPT_RC2_CBC_PARAMETERS rc2Parameters = (CAPI.CRYPT_RC2_CBC_PARAMETERS) Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPT_RC2_CBC_PARAMETERS));
                    switch (rc2Parameters.dwVersion) { 
                    case CAPI.CRYPT_RC2_40BIT_VERSION:
                        keyLength = 40;
                        break;
                    case CAPI.CRYPT_RC2_56BIT_VERSION: 
                        keyLength = 56;
                        break; 
                    case CAPI.CRYPT_RC2_128BIT_VERSION: 
                        keyLength = 128;
                        break; 
                    }
                    // Retrieve IV if available.
                    if (rc2Parameters.fIV) {
                        parameters = (byte[]) rc2Parameters.rgbIV.Clone(); 
                    }
                } 
            } 
            else if (algId == CAPI.CALG_RC4 || algId == CAPI.CALG_DES || algId == CAPI.CALG_3DES) {
                // Retrieve the IV if available. For non RC2, the parameter contains the IV 
                // (for RC4 the IV is really the salt). There are (128 - KeyLength) / 8
                // bytes of RC4 salt.
                if (algorithmIdentifier.Parameters.cbData > 0) {
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.X509_OCTET_STRING), 
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData, 
                                           out pbParameters, 
                                           out cbParameters))
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 

                    if (cbParameters > 0) {
                        if (algId == CAPI.CALG_RC4) {
                            CAPI.CRYPTOAPI_BLOB saltBlob = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB)); 
                            if (saltBlob.cbData > 0) {
                                parameters = new byte[saltBlob.cbData]; 
                                Marshal.Copy(saltBlob.pbData, parameters, 0, parameters.Length); 
                            }
                        } 
                        else {
                            parameters = new byte[cbParameters];
                            Marshal.Copy(pbParameters.DangerousGetHandle(), parameters, 0, parameters.Length);
                        } 
                    }
                } 
 
                // Determine key length.
                if (algId == CAPI.CALG_RC4) { 
                    // For RC4, keyLength = 128 - (salt length * 8).
                    keyLength = 128 - ((int) parameters.Length * 8);
                }
                else if (algId == CAPI.CALG_DES) { 
                    // DES key length is fixed at 64 (or 56 without the parity bits).
                    keyLength = 64; 
                } 
                else {
                    // 3DES key length is fixed at 192 (or 168 without the parity bits). 
                    keyLength = 192;
                }
            }
            else { 
                // Everything else, don't decode it as CAPI may not expose or know how.
                if (algorithmIdentifier.Parameters.cbData > 0) { 
                    parameters = new byte[algorithmIdentifier.Parameters.cbData]; 
                    Marshal.Copy(algorithmIdentifier.Parameters.pbData, parameters, 0, parameters.Length);
                } 
            }

            Reset(new Oid(algorithmIdentifier.pszObjId), keyLength, parameters);
            pbParameters.Dispose(); 
        }
 
        public Oid Oid { 
            get {
                return m_oid; 
            }
            set {
                m_oid = value;
            } 
        }
 
        public int KeyLength { 
            get {
                return m_keyLength; 
            }
            set {
                m_keyLength = value;
            } 
        }
 
        public byte[] Parameters { 
            get {
                return m_parameters; 
            }
            set {
                m_parameters = value;
            } 
        }
 
        // 
        // Private methods.
        // 

        private void Reset (Oid oid, int keyLength, byte[] parameters) {
            m_oid = oid;
            m_keyLength = keyLength; 
            m_parameters = parameters;
        } 
    } 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] 
    public sealed class ContentInfo {
        private Oid      m_contentType;
        private byte[]   m_content;
        private IntPtr   m_pContent = IntPtr.Zero; 
        private GCHandle m_gcHandle;
        // 
        // Constructors 
        //
 
        private ContentInfo () : this(new Oid(CAPI.szOID_RSA_data), new byte[0]) {}

        public ContentInfo (byte[] content) : this(new Oid(CAPI.szOID_RSA_data), content) {}
 
        internal ContentInfo (string contentType, byte[] content) : this(new Oid(contentType), content) {}
 
        public ContentInfo (Oid contentType, byte[] content) { 
            if (contentType == null)
                throw new ArgumentNullException("contentType"); 
            if (content == null)
                throw new ArgumentNullException("content");

            m_contentType = contentType; 
            m_content = content;
        } 
 
        public Oid ContentType {
            get { 
                return m_contentType;
            }
        }
 
        public byte[] Content {
            get { 
                return m_content; 
            }
        } 

        ~ContentInfo()
        {
            if (m_gcHandle.IsAllocated) { 
                m_gcHandle.Free();
            } 
        } 

        internal IntPtr pContent { 
            get {
                if (IntPtr.Zero == m_pContent) {
                    if (m_content != null && m_content.Length != 0) {
                        m_gcHandle = GCHandle.Alloc(m_content, GCHandleType.Pinned); 
                        //m_pContent = handle.AddrOfPinnedObject();
                        m_pContent = Marshal.UnsafeAddrOfPinnedArrayElement(m_content, 0); 
                    } 
                }
                return m_pContent; 
            }
        }

        public static Oid GetContentType (byte[] encodedMessage) { 
            if (encodedMessage == null)
                throw new ArgumentNullException("encodedMessage"); 
 
            SafeCryptMsgHandle safeCryptMsgHandle = CAPI.CryptMsgOpenToDecode(
                                                            CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                            0,
                                                            0,
                                                            IntPtr.Zero,
                                                            IntPtr.Zero, 
                                                            IntPtr.Zero);
            if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid) 
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, encodedMessage, (uint) encodedMessage.Length, true)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            Oid contentType;
            switch (PkcsUtils.GetMessageType(safeCryptMsgHandle)) { 
            case CAPI.CMSG_DATA:
                contentType = new Oid(CAPI.szOID_RSA_data); 
                break; 
            case CAPI.CMSG_SIGNED:
                contentType = new Oid(CAPI.szOID_RSA_signedData); 
                break;
            case CAPI.CMSG_ENVELOPED:
                contentType = new Oid(CAPI.szOID_RSA_envelopedData);
                break; 
            case CAPI.CMSG_SIGNED_AND_ENVELOPED:
                contentType = new Oid(CAPI.szOID_RSA_signEnvData); 
                break; 
            case CAPI.CMSG_HASHED:
                contentType = new Oid(CAPI.szOID_RSA_hashedData); 
                break;
            case CAPI.CMSG_ENCRYPTED:
                contentType = new Oid(CAPI.szOID_RSA_encryptedData);
                break; 
            default:
                throw new CryptographicException(CAPI.CRYPT_E_INVALID_MSG_TYPE); 
            } 

            safeCryptMsgHandle.Dispose(); 

            return contentType;
        }
    } 
}

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

// 
// PkcsMisc.cs 
//
// 02/09/2003 
//

namespace System.Security.Cryptography.Pkcs {
    using System.Collections; 
    using System.Globalization;
    using System.Runtime.InteropServices; 
    using System.Security.Cryptography; 
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Cryptography.Xml; 

    public enum KeyAgreeKeyChoice {
        Unknown      = 0,
        EphemeralKey = 1, 
        StaticKey    = 2,
    } 
 
    public enum SubjectIdentifierType {
        Unknown                = 0,  // Use any of the following as appropriate 
        IssuerAndSerialNumber  = 1,  // X509IssuerSerial
        SubjectKeyIdentifier   = 2,  // SKI hex string
        NoSignature            = 3  // NoSignature
    } 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] 
    public sealed class SubjectIdentifier { 
        private SubjectIdentifierType m_type;
        private Object                m_value; 

        private SubjectIdentifier () {}
        internal SubjectIdentifier (CAPI.CERT_INFO certInfo) : this(certInfo.Issuer, certInfo.SerialNumber) {}
        internal SubjectIdentifier (CAPI.CMSG_SIGNER_INFO signerInfo) : this(signerInfo.Issuer, signerInfo.SerialNumber) {} 

        internal SubjectIdentifier (SubjectIdentifierType type, Object value) { 
            Reset(type, value); 
        }
 
        internal unsafe SubjectIdentifier (CAPI.CRYPTOAPI_BLOB issuer, CAPI.CRYPTOAPI_BLOB serialNumber) {
            // If serial number is 0, then it is the special SKI encoding or NoSignature
            bool isSKIorHashOnly = true;
            byte * pb = (byte *) serialNumber.pbData; 
            for (uint i = 0; i < serialNumber.cbData; i++) {
                if (*pb++ != (byte) 0) { 
                    isSKIorHashOnly = false; 
                    break;
                } 
            }

            if (isSKIorHashOnly) {
                byte[] issuerBytes = new byte[issuer.cbData]; 
                Marshal.Copy(issuer.pbData, issuerBytes, 0, issuerBytes.Length);
                X500DistinguishedName dummyName = new X500DistinguishedName(issuerBytes); 
                if (String.Compare(CAPI.DummySignerCommonName, dummyName.Name, StringComparison.OrdinalIgnoreCase) == 0) { 
                    Reset(SubjectIdentifierType.NoSignature, null);
                    return; 
                }
            }

            if (isSKIorHashOnly) { 
                // Decode disguised SKI in issuer field (See WinCrypt.h for more info).
                m_type = SubjectIdentifierType.SubjectKeyIdentifier; 
                m_value = String.Empty; 

                uint cbCertNameInfo = 0; 
                SafeLocalAllocHandle pbCertNameInfo = SafeLocalAllocHandle.InvalidHandle;

                if (!CAPI.DecodeObject(new IntPtr(CAPI.X509_NAME),
                                       issuer.pbData, 
                                       issuer.cbData,
                                       out pbCertNameInfo, 
                                       out cbCertNameInfo)) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                using (pbCertNameInfo) {
                    CAPI.CERT_NAME_INFO certNameInfo = (CAPI.CERT_NAME_INFO) Marshal.PtrToStructure(pbCertNameInfo.DangerousGetHandle(), typeof(CAPI.CERT_NAME_INFO));
                    for (uint i = 0; i < certNameInfo.cRDN; i++) {
                        CAPI.CERT_RDN certRdn = (CAPI.CERT_RDN) Marshal.PtrToStructure(new IntPtr((long) certNameInfo.rgRDN + (long) (i * Marshal.SizeOf(typeof(CAPI.CERT_RDN)))), typeof(CAPI.CERT_RDN)); 

                        for (uint j = 0; j < certRdn.cRDNAttr; j++) { 
                            CAPI.CERT_RDN_ATTR certRdnAttr = (CAPI.CERT_RDN_ATTR) Marshal.PtrToStructure(new IntPtr((long) certRdn.rgRDNAttr + (long) (j * Marshal.SizeOf(typeof(CAPI.CERT_RDN_ATTR)))), typeof(CAPI.CERT_RDN_ATTR)); 

                            if (String.Compare(CAPI.szOID_KEYID_RDN, certRdnAttr.pszObjId, StringComparison.OrdinalIgnoreCase) == 0) { 
                                if (certRdnAttr.dwValueType == CAPI.CERT_RDN_OCTET_STRING) {
                                    byte[] ski = new byte[certRdnAttr.Value.cbData];
                                    Marshal.Copy(certRdnAttr.Value.pbData, ski, 0, ski.Length);
                                    Reset(SubjectIdentifierType.SubjectKeyIdentifier, X509Utils.EncodeHexString(ski)); 
                                    return;
                                } 
                            } 
                        }
                    } 
                }

                throw new CryptographicException(CAPI.CRYPT_E_ISSUER_SERIALNUMBER);
            } 
            else {
                CAPI.CERT_ISSUER_SERIAL_NUMBER IssuerAndSerial; 
                IssuerAndSerial.Issuer = issuer; 
                IssuerAndSerial.SerialNumber = serialNumber;
                X509IssuerSerial issuerSerial = PkcsUtils.DecodeIssuerSerial(IssuerAndSerial); 
                Reset(SubjectIdentifierType.IssuerAndSerialNumber, issuerSerial);
            }
        }
 
        internal SubjectIdentifier (CAPI.CERT_ID certId) {
            switch (certId.dwIdChoice) { 
            case CAPI.CERT_ID_ISSUER_SERIAL_NUMBER: 
                X509IssuerSerial issuerSerial = PkcsUtils.DecodeIssuerSerial(certId.Value.IssuerSerialNumber);
                Reset(SubjectIdentifierType.IssuerAndSerialNumber, issuerSerial); 
                break;
            case CAPI.CERT_ID_KEY_IDENTIFIER:
                byte[] ski = new byte[certId.Value.KeyId.cbData];
                Marshal.Copy(certId.Value.KeyId.pbData, ski, 0, ski.Length); 
                Reset(SubjectIdentifierType.SubjectKeyIdentifier, X509Utils.EncodeHexString(ski));
                break; 
            default: 
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type"), certId.dwIdChoice.ToString(CultureInfo.InvariantCulture));
            } 
        }

        public SubjectIdentifierType Type {
            get { 
                return m_type;
            } 
        } 

        public Object Value { 
            get {
                return m_value;
            }
        } 

        // 
        // Internal methods. 
        //
 
        internal void Reset (SubjectIdentifierType type, Object value) {
            switch (type) {
            case SubjectIdentifierType.NoSignature:
            case SubjectIdentifierType.Unknown: 
                break;
            case SubjectIdentifierType.IssuerAndSerialNumber: 
                if (value.GetType() != typeof(X509IssuerSerial)) { 
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString());
                } 
                break;
            case SubjectIdentifierType.SubjectKeyIdentifier:
                if (!PkcsUtils.CmsSupported()) {
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Not_Supported")); 
                }
                if (value.GetType() != typeof(string)) { 
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString()); 
                }
                break; 
            default:
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type"), type.ToString());
            }
 
            m_type = type;
            m_value = value; 
        } 
    }
 
    public enum SubjectIdentifierOrKeyType {
        Unknown                = 0,  // Use any of the following as appropriate
        IssuerAndSerialNumber  = 1,  // X509IssuerSerial
        SubjectKeyIdentifier   = 2,  // SKI hex string 
        PublicKeyInfo          = 3,  // PublicKeyInfo
    } 
 
    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class PublicKeyInfo { 
        private AlgorithmIdentifier m_algorithm;
        private byte[]              m_keyValue;

        private PublicKeyInfo () {} 

        internal PublicKeyInfo (CAPI.CERT_PUBLIC_KEY_INFO keyInfo) { 
            m_algorithm = new AlgorithmIdentifier(keyInfo); 
            m_keyValue = new byte[keyInfo.PublicKey.cbData];
            if (m_keyValue.Length > 0) { 
                Marshal.Copy(keyInfo.PublicKey.pbData, m_keyValue, 0, m_keyValue.Length);
            }
        }
 
        public AlgorithmIdentifier Algorithm {
            get { 
                return m_algorithm; 
            }
        } 

        public byte[] KeyValue {
            get {
                return m_keyValue; 
            }
        } 
    } 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] 
    public sealed class SubjectIdentifierOrKey {
        private SubjectIdentifierOrKeyType m_type;
        private Object                     m_value;
 
        private SubjectIdentifierOrKey () {}
 
        internal SubjectIdentifierOrKey (SubjectIdentifierOrKeyType type, Object value) { 
            Reset(type, value);
        } 

        internal SubjectIdentifierOrKey (CAPI.CERT_ID certId) {
            switch (certId.dwIdChoice) {
            case CAPI.CERT_ID_ISSUER_SERIAL_NUMBER: 
                X509IssuerSerial issuerSerial = PkcsUtils.DecodeIssuerSerial(certId.Value.IssuerSerialNumber);
                Reset(SubjectIdentifierOrKeyType.IssuerAndSerialNumber, issuerSerial); 
                break; 
            case CAPI.CERT_ID_KEY_IDENTIFIER:
                byte[] ski = new byte[certId.Value.KeyId.cbData]; 
                Marshal.Copy(certId.Value.KeyId.pbData, ski, 0, ski.Length);
                Reset(SubjectIdentifierOrKeyType.SubjectKeyIdentifier, X509Utils.EncodeHexString(ski));
                break;
            default: 
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type"), certId.dwIdChoice.ToString(CultureInfo.InvariantCulture));
            } 
        } 

        internal SubjectIdentifierOrKey (CAPI.CERT_PUBLIC_KEY_INFO publicKeyInfo) { 
            Reset(SubjectIdentifierOrKeyType.PublicKeyInfo, new PublicKeyInfo(publicKeyInfo));
        }

        public SubjectIdentifierOrKeyType Type { 
            get {
                return m_type; 
            } 
        }
 
        public Object Value {
            get {
                return m_value;
            } 
        }
 
        // 
        // Internal methods.
        // 

        internal void Reset (SubjectIdentifierOrKeyType type, Object value) {
            switch (type) {
            case SubjectIdentifierOrKeyType.Unknown: 
                break;
            case SubjectIdentifierOrKeyType.IssuerAndSerialNumber: 
                if (value.GetType() != typeof(X509IssuerSerial)) { 
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString());
                } 
                break;
            case SubjectIdentifierOrKeyType.SubjectKeyIdentifier:
                if (!PkcsUtils.CmsSupported()) {
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Not_Supported")); 
                }
                if (value.GetType() != typeof(string)) { 
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString()); 
                }
                break; 
            case SubjectIdentifierOrKeyType.PublicKeyInfo:
                if (!PkcsUtils.CmsSupported()) {
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Not_Supported"));
                } 
                if (value.GetType() != typeof(PublicKeyInfo)) {
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type_Value_Mismatch"), value.GetType().ToString()); 
                } 
                break;
            default: 
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Invalid_Subject_Identifier_Type"), type.ToString());
            }

            m_type = type; 
            m_value = value;
        } 
    } 

 
    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class AlgorithmIdentifier {
        private Oid     m_oid;
        private int     m_keyLength; 
        private byte[]  m_parameters;
 
        public AlgorithmIdentifier () { 
            Reset(new Oid(CAPI.szOID_RSA_DES_EDE3_CBC), 0, new byte[0]);
        } 

        public AlgorithmIdentifier (Oid oid) {
            Reset(oid, 0, new byte[0]);
        } 

        public AlgorithmIdentifier (Oid oid, int keyLength) { 
            Reset(oid, keyLength, new byte[0]); 
        }
 
        internal AlgorithmIdentifier (string oidValue) {
            Reset(new Oid(oidValue), 0, new byte[0]);
        }
 
        internal unsafe AlgorithmIdentifier (CAPI.CERT_PUBLIC_KEY_INFO keyInfo) {
            SafeLocalAllocHandle pKeyInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO)))); 
            Marshal.StructureToPtr(keyInfo, pKeyInfo.DangerousGetHandle(), false); 
            int keyLength = (int) CAPI.CertGetPublicKeyLength(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, pKeyInfo.DangerousGetHandle());
            byte[] parameters = new byte[keyInfo.Algorithm.Parameters.cbData]; 
            if (parameters.Length > 0) {
                Marshal.Copy(keyInfo.Algorithm.Parameters.pbData, parameters, 0, parameters.Length);
            }
            Marshal.DestroyStructure(pKeyInfo.DangerousGetHandle(), typeof(CAPI.CERT_PUBLIC_KEY_INFO)); 
            pKeyInfo.Dispose();
            Reset(new Oid(keyInfo.Algorithm.pszObjId), keyLength, parameters); 
        } 

        internal unsafe AlgorithmIdentifier (CAPI.CRYPT_ALGORITHM_IDENTIFIER algorithmIdentifier) { 
            int keyLength = 0;
            uint cbParameters = 0;
            SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle;
            byte[] parameters = new byte[0]; 

            uint algId = X509Utils.OidToAlgId(algorithmIdentifier.pszObjId); 
 
            if (algId == CAPI.CALG_RC2) {
                if (algorithmIdentifier.Parameters.cbData > 0) { 
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS_RC2_CBC_PARAMETERS),
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData,
                                           out pbParameters, 
                                           out cbParameters))
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
                    CAPI.CRYPT_RC2_CBC_PARAMETERS rc2Parameters = (CAPI.CRYPT_RC2_CBC_PARAMETERS) Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPT_RC2_CBC_PARAMETERS));
                    switch (rc2Parameters.dwVersion) { 
                    case CAPI.CRYPT_RC2_40BIT_VERSION:
                        keyLength = 40;
                        break;
                    case CAPI.CRYPT_RC2_56BIT_VERSION: 
                        keyLength = 56;
                        break; 
                    case CAPI.CRYPT_RC2_128BIT_VERSION: 
                        keyLength = 128;
                        break; 
                    }
                    // Retrieve IV if available.
                    if (rc2Parameters.fIV) {
                        parameters = (byte[]) rc2Parameters.rgbIV.Clone(); 
                    }
                } 
            } 
            else if (algId == CAPI.CALG_RC4 || algId == CAPI.CALG_DES || algId == CAPI.CALG_3DES) {
                // Retrieve the IV if available. For non RC2, the parameter contains the IV 
                // (for RC4 the IV is really the salt). There are (128 - KeyLength) / 8
                // bytes of RC4 salt.
                if (algorithmIdentifier.Parameters.cbData > 0) {
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.X509_OCTET_STRING), 
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData, 
                                           out pbParameters, 
                                           out cbParameters))
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 

                    if (cbParameters > 0) {
                        if (algId == CAPI.CALG_RC4) {
                            CAPI.CRYPTOAPI_BLOB saltBlob = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB)); 
                            if (saltBlob.cbData > 0) {
                                parameters = new byte[saltBlob.cbData]; 
                                Marshal.Copy(saltBlob.pbData, parameters, 0, parameters.Length); 
                            }
                        } 
                        else {
                            parameters = new byte[cbParameters];
                            Marshal.Copy(pbParameters.DangerousGetHandle(), parameters, 0, parameters.Length);
                        } 
                    }
                } 
 
                // Determine key length.
                if (algId == CAPI.CALG_RC4) { 
                    // For RC4, keyLength = 128 - (salt length * 8).
                    keyLength = 128 - ((int) parameters.Length * 8);
                }
                else if (algId == CAPI.CALG_DES) { 
                    // DES key length is fixed at 64 (or 56 without the parity bits).
                    keyLength = 64; 
                } 
                else {
                    // 3DES key length is fixed at 192 (or 168 without the parity bits). 
                    keyLength = 192;
                }
            }
            else { 
                // Everything else, don't decode it as CAPI may not expose or know how.
                if (algorithmIdentifier.Parameters.cbData > 0) { 
                    parameters = new byte[algorithmIdentifier.Parameters.cbData]; 
                    Marshal.Copy(algorithmIdentifier.Parameters.pbData, parameters, 0, parameters.Length);
                } 
            }

            Reset(new Oid(algorithmIdentifier.pszObjId), keyLength, parameters);
            pbParameters.Dispose(); 
        }
 
        public Oid Oid { 
            get {
                return m_oid; 
            }
            set {
                m_oid = value;
            } 
        }
 
        public int KeyLength { 
            get {
                return m_keyLength; 
            }
            set {
                m_keyLength = value;
            } 
        }
 
        public byte[] Parameters { 
            get {
                return m_parameters; 
            }
            set {
                m_parameters = value;
            } 
        }
 
        // 
        // Private methods.
        // 

        private void Reset (Oid oid, int keyLength, byte[] parameters) {
            m_oid = oid;
            m_keyLength = keyLength; 
            m_parameters = parameters;
        } 
    } 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] 
    public sealed class ContentInfo {
        private Oid      m_contentType;
        private byte[]   m_content;
        private IntPtr   m_pContent = IntPtr.Zero; 
        private GCHandle m_gcHandle;
        // 
        // Constructors 
        //
 
        private ContentInfo () : this(new Oid(CAPI.szOID_RSA_data), new byte[0]) {}

        public ContentInfo (byte[] content) : this(new Oid(CAPI.szOID_RSA_data), content) {}
 
        internal ContentInfo (string contentType, byte[] content) : this(new Oid(contentType), content) {}
 
        public ContentInfo (Oid contentType, byte[] content) { 
            if (contentType == null)
                throw new ArgumentNullException("contentType"); 
            if (content == null)
                throw new ArgumentNullException("content");

            m_contentType = contentType; 
            m_content = content;
        } 
 
        public Oid ContentType {
            get { 
                return m_contentType;
            }
        }
 
        public byte[] Content {
            get { 
                return m_content; 
            }
        } 

        ~ContentInfo()
        {
            if (m_gcHandle.IsAllocated) { 
                m_gcHandle.Free();
            } 
        } 

        internal IntPtr pContent { 
            get {
                if (IntPtr.Zero == m_pContent) {
                    if (m_content != null && m_content.Length != 0) {
                        m_gcHandle = GCHandle.Alloc(m_content, GCHandleType.Pinned); 
                        //m_pContent = handle.AddrOfPinnedObject();
                        m_pContent = Marshal.UnsafeAddrOfPinnedArrayElement(m_content, 0); 
                    } 
                }
                return m_pContent; 
            }
        }

        public static Oid GetContentType (byte[] encodedMessage) { 
            if (encodedMessage == null)
                throw new ArgumentNullException("encodedMessage"); 
 
            SafeCryptMsgHandle safeCryptMsgHandle = CAPI.CryptMsgOpenToDecode(
                                                            CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                            0,
                                                            0,
                                                            IntPtr.Zero,
                                                            IntPtr.Zero, 
                                                            IntPtr.Zero);
            if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid) 
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, encodedMessage, (uint) encodedMessage.Length, true)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            Oid contentType;
            switch (PkcsUtils.GetMessageType(safeCryptMsgHandle)) { 
            case CAPI.CMSG_DATA:
                contentType = new Oid(CAPI.szOID_RSA_data); 
                break; 
            case CAPI.CMSG_SIGNED:
                contentType = new Oid(CAPI.szOID_RSA_signedData); 
                break;
            case CAPI.CMSG_ENVELOPED:
                contentType = new Oid(CAPI.szOID_RSA_envelopedData);
                break; 
            case CAPI.CMSG_SIGNED_AND_ENVELOPED:
                contentType = new Oid(CAPI.szOID_RSA_signEnvData); 
                break; 
            case CAPI.CMSG_HASHED:
                contentType = new Oid(CAPI.szOID_RSA_hashedData); 
                break;
            case CAPI.CMSG_ENCRYPTED:
                contentType = new Oid(CAPI.szOID_RSA_encryptedData);
                break; 
            default:
                throw new CryptographicException(CAPI.CRYPT_E_INVALID_MSG_TYPE); 
            } 

            safeCryptMsgHandle.Dispose(); 

            return contentType;
        }
    } 
}

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