SignedPkcs7.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 / clr / src / ManagedLibraries / Security / System / Security / Cryptography / Pkcs / SignedPkcs7.cs / 5 / SignedPkcs7.cs

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

// 
// SignedPkcs7.cs 
//
 
namespace System.Security.Cryptography.Pkcs {
    using System.Diagnostics;
    using System.Globalization;
    using System.IO; 
    using System.Runtime.InteropServices;
    using System.Security.Cryptography.X509Certificates; 
    using System.Security.Cryptography.Xml; 
    using System.Security.Permissions;
    using System.Text; 
    using System.Threading;

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class SignedCms { 
        private SafeCryptMsgHandle      m_safeCryptMsgHandle;
        private int                     m_version; 
        private SubjectIdentifierType   m_signerIdentifierType; 
        private ContentInfo             m_contentInfo;
        private bool                    m_detached; 

        //
        // Constructors.
        // 

        public SignedCms () : this(SubjectIdentifierType.IssuerAndSerialNumber, new ContentInfo(new Oid(CAPI.szOID_RSA_data), new byte[0]), false) {} 
 
        public SignedCms (SubjectIdentifierType signerIdentifierType) : this(signerIdentifierType, new ContentInfo(new Oid(CAPI.szOID_RSA_data), new byte[0]), false) {}
 
        public SignedCms (ContentInfo contentInfo) : this(SubjectIdentifierType.IssuerAndSerialNumber, contentInfo, false) {}

        public SignedCms (SubjectIdentifierType signerIdentifierType, ContentInfo contentInfo) : this(signerIdentifierType, contentInfo, false) {}
 
        public SignedCms (ContentInfo contentInfo, bool detached) : this(SubjectIdentifierType.IssuerAndSerialNumber, contentInfo, detached) {}
 
        public SignedCms (SubjectIdentifierType signerIdentifierType, ContentInfo contentInfo, bool detached) { 
            if (contentInfo == null)
                throw new ArgumentNullException("contentInfo"); 

            if (contentInfo.Content == null)
                throw new ArgumentNullException("contentInfo.Content");
 
            // Reset all states.
            if (signerIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier && 
                signerIdentifierType != SubjectIdentifierType.IssuerAndSerialNumber && 
                signerIdentifierType != SubjectIdentifierType.NoSignature) {
                signerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; 
            }

            m_safeCryptMsgHandle = SafeCryptMsgHandle.InvalidHandle;
            m_signerIdentifierType =  signerIdentifierType; 
            m_version = 0;
            m_contentInfo = contentInfo; 
            m_detached = detached; 
        }
 
        //
        // Public APIs.
        //
 
        public int Version {
            get { 
                // SignedData version can change based on user's operation, so 
                // return the value passed in to the constructor if no message handle is
                // available. Otherwise, query the version from the handle 
                if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                    return m_version;

                return (int) PkcsUtils.GetVersion(m_safeCryptMsgHandle); 
            }
        } 
 
        public ContentInfo ContentInfo {
            get { 
                return m_contentInfo;
            }
        }
 
        public bool Detached {
            get { 
                return m_detached; 
            }
        } 

        public X509Certificate2Collection Certificates {
            get {
                if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) { 
                    return new X509Certificate2Collection();
                } 
                return PkcsUtils.GetCertificates(m_safeCryptMsgHandle); 
            }
        } 

        public SignerInfoCollection SignerInfos {
            get {
                if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) { 
                    return new SignerInfoCollection();
                } 
 
                return new SignerInfoCollection(this);
            } 
        }

        public byte[] Encode () {
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) 
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_MessageNotSigned"));
 
            return PkcsUtils.GetMessage(m_safeCryptMsgHandle); 
        }
 
        public void Decode (byte[] encodedMessage) {
            if (encodedMessage == null)
                throw new ArgumentNullException("encodedMessage");
 
            if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) {
                m_safeCryptMsgHandle.Dispose(); 
            } 

            m_safeCryptMsgHandle = OpenToDecode(encodedMessage, this.ContentInfo, this.Detached); 
            if (!this.Detached) {
                Oid contentType = PkcsUtils.GetContentType(m_safeCryptMsgHandle);
                byte[] content = PkcsUtils.GetContent(m_safeCryptMsgHandle);
                m_contentInfo = new ContentInfo(contentType, content); 
            }
        } 
 
        public void ComputeSignature () {
            ComputeSignature(new CmsSigner(m_signerIdentifierType), true); 
        }

        public void ComputeSignature (CmsSigner signer) {
            ComputeSignature(signer, true); 
        }
 
        public void ComputeSignature (CmsSigner signer, bool silent) { 
            if (signer == null)
                throw new ArgumentNullException("signer"); 
            if (ContentInfo.Content.Length == 0)
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Sign_Empty_Content"));

            if (SubjectIdentifierType.NoSignature == signer.SignerIdentifierType) { 
                if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid)
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Sign_No_Signature_First_Signer")); 
 
                // First signer.
                Sign(signer, silent); 
                return;
            }

            if (signer.Certificate == null) { 
                if (silent)
                    throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_RecipientCertificateNotFound")); 
                else 
                    signer.Certificate = PkcsUtils.SelectSignerCertificate();
            } 

            if (!signer.Certificate.HasPrivateKey)
                throw new CryptographicException(CAPI.NTE_NO_KEY);
 
            //
 
 

            CspParameters parameters = new CspParameters(); 
            if (X509Utils.GetPrivateKeyInfo(X509Utils.GetCertContext(signer.Certificate), ref parameters) == false)
                throw new CryptographicException(Marshal.GetLastWin32Error());

            KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags); 
            KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open | KeyContainerPermissionFlags.Sign);
            kp.AccessEntries.Add(entry); 
            kp.Demand(); 

            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) { 
                // First signer.
                Sign(signer, silent);
            }
            else { 
                // Co-signing.
                CoSign(signer, silent); 
            } 
        }
 
        public void RemoveSignature (int index) {
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_MessageNotSigned"));
 
            unsafe {
                uint dwSigners = 0; 
                uint cbCount = (uint) Marshal.SizeOf(typeof(uint)); 

                if (!CAPI.CryptMsgGetParam(m_safeCryptMsgHandle, 
                                           CAPI.CMSG_SIGNER_COUNT_PARAM,
                                           0,
                                           new IntPtr(&dwSigners),
                                           new IntPtr(&cbCount))) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                if (index < 0 || index >= (int) dwSigners) 
                    throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index"));
 
                if (!CAPI.CryptMsgControl(m_safeCryptMsgHandle,
                                          0,
                                          CAPI.CMSG_CTRL_DEL_SIGNER,
                                          new IntPtr(&index))) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            } 
        } 

        public void RemoveSignature (SignerInfo signerInfo) { 
            if (signerInfo == null)
                throw new ArgumentNullException("signerInfo");

            RemoveSignature(PkcsUtils.GetSignerIndex(m_safeCryptMsgHandle, signerInfo, 0)); 
        }
 
        public void CheckSignature (bool verifySignatureOnly) { 
            CheckSignature(new X509Certificate2Collection(), verifySignatureOnly);
        } 

        public void CheckSignature (X509Certificate2Collection extraStore, bool verifySignatureOnly) {
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_MessageNotSigned")); 

            if (extraStore == null) 
                throw new ArgumentNullException("extraStore"); 

            CheckSignatures(this.SignerInfos, extraStore, verifySignatureOnly); 
        }

        public void CheckHash () {
 
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                throw new InvalidOperationException( 
                    SecurityResources.GetResourceString("Cryptography_Cms_MessageNotSigned")); 

            CheckHashes(this.SignerInfos); 
        }

        //
        // Internal methods. 
        //
 
        internal SafeCryptMsgHandle GetCryptMsgHandle() { 
            return m_safeCryptMsgHandle;
        } 

        internal void ReopenToDecode () {
            byte[] encodedMessage = PkcsUtils.GetMessage(m_safeCryptMsgHandle);
            if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) { 
                m_safeCryptMsgHandle.Dispose();
            } 
            m_safeCryptMsgHandle = OpenToDecode(encodedMessage, this.ContentInfo, this.Detached); 
        }
 
        private unsafe void Sign (CmsSigner signer, bool silent) {

            SafeCryptMsgHandle safeCryptMsgHandle = null;
            CAPI.CMSG_SIGNED_ENCODE_INFO signedEncodeInfo = new CAPI.CMSG_SIGNED_ENCODE_INFO(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNED_ENCODE_INFO))); 
            CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer, silent);
 
            byte[] encodedMessage = null; 
            try {
                SafeLocalAllocHandle pSignerEncodeInfo = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO)))); 

                try {
                    Marshal.StructureToPtr(signerEncodeInfo, pSignerEncodeInfo.DangerousGetHandle(), false);
                    X509Certificate2Collection bagOfCerts = PkcsUtils.CreateBagOfCertificates(signer); 
                    SafeLocalAllocHandle pEncodedBagOfCerts = PkcsUtils.CreateEncodedCertBlob(bagOfCerts);
 
                    signedEncodeInfo.cSigners = 1; 
                    signedEncodeInfo.rgSigners = pSignerEncodeInfo.DangerousGetHandle();
                    signedEncodeInfo.cCertEncoded = (uint) bagOfCerts.Count; 
                    if (bagOfCerts.Count > 0)
                        signedEncodeInfo.rgCertEncoded = pEncodedBagOfCerts.DangerousGetHandle();

                    // Because of the way CAPI treats inner content OID, we should pass NULL 
                    // for data type, otherwise detached will not work.
                    if (String.Compare(this.ContentInfo.ContentType.Value, CAPI.szOID_RSA_data, StringComparison.OrdinalIgnoreCase) == 0) { 
                        safeCryptMsgHandle = CAPI.CryptMsgOpenToEncode(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                                       Detached ? CAPI.CMSG_DETACHED_FLAG : 0,
                                                                       CAPI.CMSG_SIGNED, 
                                                                       new IntPtr(&signedEncodeInfo),
                                                                       IntPtr.Zero,
                                                                       IntPtr.Zero);
                    } 
                    else {
                        safeCryptMsgHandle = CAPI.CryptMsgOpenToEncode(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                                       Detached ? CAPI.CMSG_DETACHED_FLAG : 0, 
                                                                       CAPI.CMSG_SIGNED,
                                                                       new IntPtr(&signedEncodeInfo), 
                                                                       this.ContentInfo.ContentType.Value,
                                                                       IntPtr.Zero);
                    }
 
                    if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid)
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 
 

                    if (this.ContentInfo.Content.Length > 0) { 
                        if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, this.ContentInfo.pContent, (uint) this.ContentInfo.Content.Length, true))
                            throw new CryptographicException(Marshal.GetLastWin32Error());
                    }
 
                    // Retrieve encoded message.
                    encodedMessage = PkcsUtils.GetContent(safeCryptMsgHandle); 
                    safeCryptMsgHandle.Dispose(); 

                    pEncodedBagOfCerts.Dispose(); 
                }
                finally {
                    Marshal.DestroyStructure(pSignerEncodeInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_ENCODE_INFO));
                    pSignerEncodeInfo.Dispose(); 
                }
            } 
            finally { 
                // Don't forget to free all the resource still held inside signerEncodeInfo.
                signerEncodeInfo.Dispose(); 
            }

            // Re-open to decode.
            safeCryptMsgHandle = OpenToDecode(encodedMessage, this.ContentInfo, this.Detached); 
            if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) {
                m_safeCryptMsgHandle.Dispose(); 
            } 
            m_safeCryptMsgHandle = safeCryptMsgHandle;
            GC.KeepAlive(signer); 
        }

        private unsafe void CoSign (CmsSigner signer, bool silent) {
            CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer, silent); 

            try { 
                SafeLocalAllocHandle pSignerEncodeInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO)))); 

                try { 
                    // Marshal to unmanaged memory.
                    Marshal.StructureToPtr(signerEncodeInfo, pSignerEncodeInfo.DangerousGetHandle(), false);

                    // Add the signature. 
                    if (!CAPI.CryptMsgControl(m_safeCryptMsgHandle,
                                              0, 
                                              CAPI.CMSG_CTRL_ADD_SIGNER, 
                                              pSignerEncodeInfo.DangerousGetHandle()))
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 
                }
                finally {
                    Marshal.DestroyStructure(pSignerEncodeInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_ENCODE_INFO));
                    pSignerEncodeInfo.Dispose(); 
                }
            } 
            finally { 
                // and don't forget to dispose of resources allocated for the structure.
                signerEncodeInfo.Dispose(); 
            }

            // Finally, add certs to bag of certs.
            PkcsUtils.AddCertsToMessage(m_safeCryptMsgHandle, Certificates, PkcsUtils.CreateBagOfCertificates(signer)); 
        }
 
        // 
        // Private static methods.
        // 
        private static unsafe SafeCryptMsgHandle OpenToDecode (byte[] encodedMessage,
                                                               ContentInfo contentInfo,
                                                               bool detached) {
            // Open the message for decode. 
            SafeCryptMsgHandle safeCryptMsgHandle = CAPI.CryptMsgOpenToDecode(
                                                            CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                            detached ? CAPI.CMSG_DETACHED_FLAG : 0, 
                                                            0,
                                                            IntPtr.Zero, 
                                                            IntPtr.Zero,
                                                            IntPtr.Zero);
            if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            // ---- the message. 
            if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, encodedMessage, (uint) encodedMessage.Length, true)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());
 
            // Make sure this is PKCS7 SignedData type.
            if (CAPI.CMSG_SIGNED != PkcsUtils.GetMessageType(safeCryptMsgHandle))
                throw new CryptographicException(CAPI.CRYPT_E_INVALID_MSG_TYPE);
 
            // If detached, then update message with content if available.
            if (detached) { 
                byte[] content  = contentInfo.Content; 

                if (content != null && content.Length > 0) { 
                    if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, content, (uint) content.Length, true))
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                }
            } 

            return safeCryptMsgHandle; 
        } 

        private static void CheckSignatures (SignerInfoCollection signers, 
                                             X509Certificate2Collection extraStore,
                                             bool verifySignatureOnly) {
            if (signers == null || signers.Count < 1)
                throw new CryptographicException(CAPI.CRYPT_E_NO_SIGNER); 

            foreach (SignerInfo signer in signers) { 
                signer.CheckSignature(extraStore, verifySignatureOnly); 
                if (signer.CounterSignerInfos.Count > 0)
                    CheckSignatures(signer.CounterSignerInfos, extraStore, verifySignatureOnly); 
            }
        }

        private static void CheckHashes (SignerInfoCollection signers) { 
            if (signers == null || signers.Count < 1)
                throw new CryptographicException(CAPI.CRYPT_E_NO_SIGNER); 
 
            foreach (SignerInfo signer in signers) {
                if (signer.SignerIdentifier.Type == SubjectIdentifierType.NoSignature) 
                    signer.CheckHash();
            }
        }
    } 
}

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

// 
// SignedPkcs7.cs 
//
 
namespace System.Security.Cryptography.Pkcs {
    using System.Diagnostics;
    using System.Globalization;
    using System.IO; 
    using System.Runtime.InteropServices;
    using System.Security.Cryptography.X509Certificates; 
    using System.Security.Cryptography.Xml; 
    using System.Security.Permissions;
    using System.Text; 
    using System.Threading;

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class SignedCms { 
        private SafeCryptMsgHandle      m_safeCryptMsgHandle;
        private int                     m_version; 
        private SubjectIdentifierType   m_signerIdentifierType; 
        private ContentInfo             m_contentInfo;
        private bool                    m_detached; 

        //
        // Constructors.
        // 

        public SignedCms () : this(SubjectIdentifierType.IssuerAndSerialNumber, new ContentInfo(new Oid(CAPI.szOID_RSA_data), new byte[0]), false) {} 
 
        public SignedCms (SubjectIdentifierType signerIdentifierType) : this(signerIdentifierType, new ContentInfo(new Oid(CAPI.szOID_RSA_data), new byte[0]), false) {}
 
        public SignedCms (ContentInfo contentInfo) : this(SubjectIdentifierType.IssuerAndSerialNumber, contentInfo, false) {}

        public SignedCms (SubjectIdentifierType signerIdentifierType, ContentInfo contentInfo) : this(signerIdentifierType, contentInfo, false) {}
 
        public SignedCms (ContentInfo contentInfo, bool detached) : this(SubjectIdentifierType.IssuerAndSerialNumber, contentInfo, detached) {}
 
        public SignedCms (SubjectIdentifierType signerIdentifierType, ContentInfo contentInfo, bool detached) { 
            if (contentInfo == null)
                throw new ArgumentNullException("contentInfo"); 

            if (contentInfo.Content == null)
                throw new ArgumentNullException("contentInfo.Content");
 
            // Reset all states.
            if (signerIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier && 
                signerIdentifierType != SubjectIdentifierType.IssuerAndSerialNumber && 
                signerIdentifierType != SubjectIdentifierType.NoSignature) {
                signerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; 
            }

            m_safeCryptMsgHandle = SafeCryptMsgHandle.InvalidHandle;
            m_signerIdentifierType =  signerIdentifierType; 
            m_version = 0;
            m_contentInfo = contentInfo; 
            m_detached = detached; 
        }
 
        //
        // Public APIs.
        //
 
        public int Version {
            get { 
                // SignedData version can change based on user's operation, so 
                // return the value passed in to the constructor if no message handle is
                // available. Otherwise, query the version from the handle 
                if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                    return m_version;

                return (int) PkcsUtils.GetVersion(m_safeCryptMsgHandle); 
            }
        } 
 
        public ContentInfo ContentInfo {
            get { 
                return m_contentInfo;
            }
        }
 
        public bool Detached {
            get { 
                return m_detached; 
            }
        } 

        public X509Certificate2Collection Certificates {
            get {
                if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) { 
                    return new X509Certificate2Collection();
                } 
                return PkcsUtils.GetCertificates(m_safeCryptMsgHandle); 
            }
        } 

        public SignerInfoCollection SignerInfos {
            get {
                if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) { 
                    return new SignerInfoCollection();
                } 
 
                return new SignerInfoCollection(this);
            } 
        }

        public byte[] Encode () {
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) 
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_MessageNotSigned"));
 
            return PkcsUtils.GetMessage(m_safeCryptMsgHandle); 
        }
 
        public void Decode (byte[] encodedMessage) {
            if (encodedMessage == null)
                throw new ArgumentNullException("encodedMessage");
 
            if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) {
                m_safeCryptMsgHandle.Dispose(); 
            } 

            m_safeCryptMsgHandle = OpenToDecode(encodedMessage, this.ContentInfo, this.Detached); 
            if (!this.Detached) {
                Oid contentType = PkcsUtils.GetContentType(m_safeCryptMsgHandle);
                byte[] content = PkcsUtils.GetContent(m_safeCryptMsgHandle);
                m_contentInfo = new ContentInfo(contentType, content); 
            }
        } 
 
        public void ComputeSignature () {
            ComputeSignature(new CmsSigner(m_signerIdentifierType), true); 
        }

        public void ComputeSignature (CmsSigner signer) {
            ComputeSignature(signer, true); 
        }
 
        public void ComputeSignature (CmsSigner signer, bool silent) { 
            if (signer == null)
                throw new ArgumentNullException("signer"); 
            if (ContentInfo.Content.Length == 0)
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Sign_Empty_Content"));

            if (SubjectIdentifierType.NoSignature == signer.SignerIdentifierType) { 
                if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid)
                    throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Sign_No_Signature_First_Signer")); 
 
                // First signer.
                Sign(signer, silent); 
                return;
            }

            if (signer.Certificate == null) { 
                if (silent)
                    throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_RecipientCertificateNotFound")); 
                else 
                    signer.Certificate = PkcsUtils.SelectSignerCertificate();
            } 

            if (!signer.Certificate.HasPrivateKey)
                throw new CryptographicException(CAPI.NTE_NO_KEY);
 
            //
 
 

            CspParameters parameters = new CspParameters(); 
            if (X509Utils.GetPrivateKeyInfo(X509Utils.GetCertContext(signer.Certificate), ref parameters) == false)
                throw new CryptographicException(Marshal.GetLastWin32Error());

            KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags); 
            KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open | KeyContainerPermissionFlags.Sign);
            kp.AccessEntries.Add(entry); 
            kp.Demand(); 

            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) { 
                // First signer.
                Sign(signer, silent);
            }
            else { 
                // Co-signing.
                CoSign(signer, silent); 
            } 
        }
 
        public void RemoveSignature (int index) {
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_MessageNotSigned"));
 
            unsafe {
                uint dwSigners = 0; 
                uint cbCount = (uint) Marshal.SizeOf(typeof(uint)); 

                if (!CAPI.CryptMsgGetParam(m_safeCryptMsgHandle, 
                                           CAPI.CMSG_SIGNER_COUNT_PARAM,
                                           0,
                                           new IntPtr(&dwSigners),
                                           new IntPtr(&cbCount))) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                if (index < 0 || index >= (int) dwSigners) 
                    throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index"));
 
                if (!CAPI.CryptMsgControl(m_safeCryptMsgHandle,
                                          0,
                                          CAPI.CMSG_CTRL_DEL_SIGNER,
                                          new IntPtr(&index))) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            } 
        } 

        public void RemoveSignature (SignerInfo signerInfo) { 
            if (signerInfo == null)
                throw new ArgumentNullException("signerInfo");

            RemoveSignature(PkcsUtils.GetSignerIndex(m_safeCryptMsgHandle, signerInfo, 0)); 
        }
 
        public void CheckSignature (bool verifySignatureOnly) { 
            CheckSignature(new X509Certificate2Collection(), verifySignatureOnly);
        } 

        public void CheckSignature (X509Certificate2Collection extraStore, bool verifySignatureOnly) {
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_MessageNotSigned")); 

            if (extraStore == null) 
                throw new ArgumentNullException("extraStore"); 

            CheckSignatures(this.SignerInfos, extraStore, verifySignatureOnly); 
        }

        public void CheckHash () {
 
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                throw new InvalidOperationException( 
                    SecurityResources.GetResourceString("Cryptography_Cms_MessageNotSigned")); 

            CheckHashes(this.SignerInfos); 
        }

        //
        // Internal methods. 
        //
 
        internal SafeCryptMsgHandle GetCryptMsgHandle() { 
            return m_safeCryptMsgHandle;
        } 

        internal void ReopenToDecode () {
            byte[] encodedMessage = PkcsUtils.GetMessage(m_safeCryptMsgHandle);
            if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) { 
                m_safeCryptMsgHandle.Dispose();
            } 
            m_safeCryptMsgHandle = OpenToDecode(encodedMessage, this.ContentInfo, this.Detached); 
        }
 
        private unsafe void Sign (CmsSigner signer, bool silent) {

            SafeCryptMsgHandle safeCryptMsgHandle = null;
            CAPI.CMSG_SIGNED_ENCODE_INFO signedEncodeInfo = new CAPI.CMSG_SIGNED_ENCODE_INFO(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNED_ENCODE_INFO))); 
            CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer, silent);
 
            byte[] encodedMessage = null; 
            try {
                SafeLocalAllocHandle pSignerEncodeInfo = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO)))); 

                try {
                    Marshal.StructureToPtr(signerEncodeInfo, pSignerEncodeInfo.DangerousGetHandle(), false);
                    X509Certificate2Collection bagOfCerts = PkcsUtils.CreateBagOfCertificates(signer); 
                    SafeLocalAllocHandle pEncodedBagOfCerts = PkcsUtils.CreateEncodedCertBlob(bagOfCerts);
 
                    signedEncodeInfo.cSigners = 1; 
                    signedEncodeInfo.rgSigners = pSignerEncodeInfo.DangerousGetHandle();
                    signedEncodeInfo.cCertEncoded = (uint) bagOfCerts.Count; 
                    if (bagOfCerts.Count > 0)
                        signedEncodeInfo.rgCertEncoded = pEncodedBagOfCerts.DangerousGetHandle();

                    // Because of the way CAPI treats inner content OID, we should pass NULL 
                    // for data type, otherwise detached will not work.
                    if (String.Compare(this.ContentInfo.ContentType.Value, CAPI.szOID_RSA_data, StringComparison.OrdinalIgnoreCase) == 0) { 
                        safeCryptMsgHandle = CAPI.CryptMsgOpenToEncode(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                                       Detached ? CAPI.CMSG_DETACHED_FLAG : 0,
                                                                       CAPI.CMSG_SIGNED, 
                                                                       new IntPtr(&signedEncodeInfo),
                                                                       IntPtr.Zero,
                                                                       IntPtr.Zero);
                    } 
                    else {
                        safeCryptMsgHandle = CAPI.CryptMsgOpenToEncode(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                                       Detached ? CAPI.CMSG_DETACHED_FLAG : 0, 
                                                                       CAPI.CMSG_SIGNED,
                                                                       new IntPtr(&signedEncodeInfo), 
                                                                       this.ContentInfo.ContentType.Value,
                                                                       IntPtr.Zero);
                    }
 
                    if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid)
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 
 

                    if (this.ContentInfo.Content.Length > 0) { 
                        if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, this.ContentInfo.pContent, (uint) this.ContentInfo.Content.Length, true))
                            throw new CryptographicException(Marshal.GetLastWin32Error());
                    }
 
                    // Retrieve encoded message.
                    encodedMessage = PkcsUtils.GetContent(safeCryptMsgHandle); 
                    safeCryptMsgHandle.Dispose(); 

                    pEncodedBagOfCerts.Dispose(); 
                }
                finally {
                    Marshal.DestroyStructure(pSignerEncodeInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_ENCODE_INFO));
                    pSignerEncodeInfo.Dispose(); 
                }
            } 
            finally { 
                // Don't forget to free all the resource still held inside signerEncodeInfo.
                signerEncodeInfo.Dispose(); 
            }

            // Re-open to decode.
            safeCryptMsgHandle = OpenToDecode(encodedMessage, this.ContentInfo, this.Detached); 
            if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) {
                m_safeCryptMsgHandle.Dispose(); 
            } 
            m_safeCryptMsgHandle = safeCryptMsgHandle;
            GC.KeepAlive(signer); 
        }

        private unsafe void CoSign (CmsSigner signer, bool silent) {
            CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer, silent); 

            try { 
                SafeLocalAllocHandle pSignerEncodeInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO)))); 

                try { 
                    // Marshal to unmanaged memory.
                    Marshal.StructureToPtr(signerEncodeInfo, pSignerEncodeInfo.DangerousGetHandle(), false);

                    // Add the signature. 
                    if (!CAPI.CryptMsgControl(m_safeCryptMsgHandle,
                                              0, 
                                              CAPI.CMSG_CTRL_ADD_SIGNER, 
                                              pSignerEncodeInfo.DangerousGetHandle()))
                        throw new CryptographicException(Marshal.GetLastWin32Error()); 
                }
                finally {
                    Marshal.DestroyStructure(pSignerEncodeInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_ENCODE_INFO));
                    pSignerEncodeInfo.Dispose(); 
                }
            } 
            finally { 
                // and don't forget to dispose of resources allocated for the structure.
                signerEncodeInfo.Dispose(); 
            }

            // Finally, add certs to bag of certs.
            PkcsUtils.AddCertsToMessage(m_safeCryptMsgHandle, Certificates, PkcsUtils.CreateBagOfCertificates(signer)); 
        }
 
        // 
        // Private static methods.
        // 
        private static unsafe SafeCryptMsgHandle OpenToDecode (byte[] encodedMessage,
                                                               ContentInfo contentInfo,
                                                               bool detached) {
            // Open the message for decode. 
            SafeCryptMsgHandle safeCryptMsgHandle = CAPI.CryptMsgOpenToDecode(
                                                            CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                            detached ? CAPI.CMSG_DETACHED_FLAG : 0, 
                                                            0,
                                                            IntPtr.Zero, 
                                                            IntPtr.Zero,
                                                            IntPtr.Zero);
            if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 

            // ---- the message. 
            if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, encodedMessage, (uint) encodedMessage.Length, true)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());
 
            // Make sure this is PKCS7 SignedData type.
            if (CAPI.CMSG_SIGNED != PkcsUtils.GetMessageType(safeCryptMsgHandle))
                throw new CryptographicException(CAPI.CRYPT_E_INVALID_MSG_TYPE);
 
            // If detached, then update message with content if available.
            if (detached) { 
                byte[] content  = contentInfo.Content; 

                if (content != null && content.Length > 0) { 
                    if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, content, (uint) content.Length, true))
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                }
            } 

            return safeCryptMsgHandle; 
        } 

        private static void CheckSignatures (SignerInfoCollection signers, 
                                             X509Certificate2Collection extraStore,
                                             bool verifySignatureOnly) {
            if (signers == null || signers.Count < 1)
                throw new CryptographicException(CAPI.CRYPT_E_NO_SIGNER); 

            foreach (SignerInfo signer in signers) { 
                signer.CheckSignature(extraStore, verifySignatureOnly); 
                if (signer.CounterSignerInfos.Count > 0)
                    CheckSignatures(signer.CounterSignerInfos, extraStore, verifySignatureOnly); 
            }
        }

        private static void CheckHashes (SignerInfoCollection signers) { 
            if (signers == null || signers.Count < 1)
                throw new CryptographicException(CAPI.CRYPT_E_NO_SIGNER); 
 
            foreach (SignerInfo signer in signers) {
                if (signer.SignerIdentifier.Type == SubjectIdentifierType.NoSignature) 
                    signer.CheckHash();
            }
        }
    } 
}

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