SignerInfo.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / clr / src / ManagedLibraries / Security / System / Security / Cryptography / Pkcs / SignerInfo.cs / 1 / SignerInfo.cs

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

// 
// SignerInfo.cs 
//
 
namespace System.Security.Cryptography.Pkcs {
    using System.Collections;
    using System.Diagnostics;
    using System.Globalization; 
    using System.Runtime.InteropServices;
    using System.Security.Permissions; 
    using System.Security.Cryptography; 
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Cryptography.Xml; 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class SignerInfo {
        private X509Certificate2                m_certificate; 
        private SubjectIdentifier                m_signerIdentifier;
        private CryptographicAttributeObjectCollection m_signedAttributes; 
        private CryptographicAttributeObjectCollection m_unsignedAttributes; 

        private SignedCms                   m_signedCms; 
        private SignerInfo                  m_parentSignerInfo;
        private byte[]                      m_encodedSignerInfo;
        private SafeLocalAllocHandle        m_pbCmsgSignerInfo;
        private CAPI.CMSG_SIGNER_INFO       m_cmsgSignerInfo; 

        // 
        // Constructors. 
        //
 
        private SignerInfo () {}

        internal unsafe SignerInfo (SignedCms signedCms, SafeLocalAllocHandle pbCmsgSignerInfo) {
            // Sanity check. 
            Debug.Assert(signedCms != null && pbCmsgSignerInfo != null && !pbCmsgSignerInfo.IsInvalid);
 
            m_signedCms = signedCms; 
            m_parentSignerInfo = null;
            m_encodedSignerInfo = null; 
            m_pbCmsgSignerInfo = pbCmsgSignerInfo;
            m_cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO));
        }
 
        internal unsafe SignerInfo (SignedCms signedCms, SignerInfo parentSignerInfo, byte[] encodedSignerInfo) {
            // Sanity check. 
            Debug.Assert(signedCms != null && encodedSignerInfo != null && encodedSignerInfo.Length > 0); 

            uint cbCmsgSignerInfo = 0; 
            SafeLocalAllocHandle pbCmsgSignerInfo = SafeLocalAllocHandle.InvalidHandle;

            fixed (byte * pEncodedSignerInfo = &encodedSignerInfo[0]) {
                if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS7_SIGNER_INFO), 
                                       new IntPtr(pEncodedSignerInfo),
                                       (uint) encodedSignerInfo.Length, 
                                       out pbCmsgSignerInfo, 
                                       out cbCmsgSignerInfo))
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
            }

            m_signedCms = signedCms;
            m_parentSignerInfo = parentSignerInfo; 
            m_encodedSignerInfo = (byte[]) encodedSignerInfo.Clone();
            m_pbCmsgSignerInfo = pbCmsgSignerInfo; 
            m_cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO)); 
        }
 
        //
        // Public APIs.
        //
 
        public int Version {
            get { 
                return (int) m_cmsgSignerInfo.dwVersion; 
            }
        } 


        public X509Certificate2 Certificate {
            get { 
                if (m_certificate == null)
                    m_certificate = PkcsUtils.FindCertificate(this.SignerIdentifier, m_signedCms.Certificates); 
 
                return m_certificate;
            } 
        }

        public SubjectIdentifier SignerIdentifier {
            get { 
                if (m_signerIdentifier == null)
                    m_signerIdentifier = new SubjectIdentifier(m_cmsgSignerInfo); 
 
                return m_signerIdentifier;
            } 
        }

        public Oid DigestAlgorithm {
            get { 
                return new Oid(m_cmsgSignerInfo.HashAlgorithm.pszObjId);
            } 
        } 

        public CryptographicAttributeObjectCollection SignedAttributes { 
            get {
                if (m_signedAttributes == null)
                    m_signedAttributes = new CryptographicAttributeObjectCollection(m_cmsgSignerInfo.AuthAttrs);
 
                return m_signedAttributes;
            } 
        } 

        public CryptographicAttributeObjectCollection UnsignedAttributes { 
            get {
                if (m_unsignedAttributes == null)
                    m_unsignedAttributes = new CryptographicAttributeObjectCollection(m_cmsgSignerInfo.UnauthAttrs);
 
                return m_unsignedAttributes;
            } 
        } 

        public SignerInfoCollection CounterSignerInfos { 
            get {
                // We only support one level of counter signing.
                if (m_parentSignerInfo != null)
                    return new SignerInfoCollection(); 

                return new SignerInfoCollection(m_signedCms, this); 
            } 
        }
 
        public void ComputeCounterSignature () {
            ComputeCounterSignature(new CmsSigner(m_signedCms.Version == 2 ? SubjectIdentifierType.SubjectKeyIdentifier : SubjectIdentifierType.IssuerAndSerialNumber));
        }
 
        public void ComputeCounterSignature (CmsSigner signer) {
            // We only support one level of counter signing. 
            if (m_parentSignerInfo != null) 
                throw new CryptographicException(CAPI.E_NOTIMPL);
            if (signer == null) 
                throw new ArgumentNullException("signer");

            if (signer.Certificate == null)
                signer.Certificate = PkcsUtils.SelectSignerCertificate(); 

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

            CounterSign(signer); 
        }

        public void RemoveCounterSignature (int index) {
            // We only support one level of counter signing. 
            if (m_parentSignerInfo != null)
                throw new CryptographicException(CAPI.E_NOTIMPL); 
 
            RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index);
 
            return;
        }

        public void RemoveCounterSignature (SignerInfo counterSignerInfo) { 
            // We only support one level of counter signing.
            if (m_parentSignerInfo != null) 
                throw new CryptographicException(CAPI.E_NOTIMPL); 
            if (counterSignerInfo == null)
                throw new ArgumentNullException("counterSignerInfo"); 

            foreach (CryptographicAttributeObject attribute in UnsignedAttributes) {
                if (String.Compare(attribute.Oid.Value, CAPI.szOID_RSA_counterSign, StringComparison.OrdinalIgnoreCase) == 0) {
                    for (int index = 0; index < attribute.Values.Count; index++) { 
                        AsnEncodedData encodedCounterSignature = (AsnEncodedData) attribute.Values[index];
                        SignerInfo counterSignerInfo2 = new SignerInfo(m_signedCms, m_parentSignerInfo, encodedCounterSignature.RawData); 
 
                        if ((counterSignerInfo.SignerIdentifier.Type == SubjectIdentifierType.IssuerAndSerialNumber) &&
                            (counterSignerInfo2.SignerIdentifier.Type == SubjectIdentifierType.IssuerAndSerialNumber)) { 
                            X509IssuerSerial issuerSerial1 = (X509IssuerSerial) counterSignerInfo.SignerIdentifier.Value;
                            X509IssuerSerial issuerSerial2 = (X509IssuerSerial) counterSignerInfo2.SignerIdentifier.Value;

                            if ((String.Compare(issuerSerial1.IssuerName, issuerSerial2.IssuerName, StringComparison.OrdinalIgnoreCase) == 0) && 
                                (String.Compare(issuerSerial1.SerialNumber, issuerSerial2.SerialNumber, StringComparison.OrdinalIgnoreCase) == 0)) {
                                RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); 
                                return; 
                            }
                        } 
                        else if ((counterSignerInfo.SignerIdentifier.Type == SubjectIdentifierType.SubjectKeyIdentifier) &&
                                 (counterSignerInfo2.SignerIdentifier.Type == SubjectIdentifierType.SubjectKeyIdentifier)) {
                            string keyIdentifier1 = counterSignerInfo.SignerIdentifier.Value as string;
                            string keyIdentifier2 = counterSignerInfo2.SignerIdentifier.Value as string; 

                            if (String.Compare(keyIdentifier1, keyIdentifier2, StringComparison.OrdinalIgnoreCase) == 0) { 
                                RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); 
                                return;
                            } 
                        }
                    }
                }
            } 

            throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND); 
        } 

        public void CheckSignature (bool verifySignatureOnly) { 
            CheckSignature(new X509Certificate2Collection(), verifySignatureOnly);
        }

        public void CheckSignature (X509Certificate2Collection extraStore, bool verifySignatureOnly) { 
            if (extraStore == null)
                throw new ArgumentNullException("extraStore"); 
 
            X509Certificate2 certificate = this.Certificate;
            if (certificate == null) { 
                certificate = PkcsUtils.FindCertificate(SignerIdentifier, extraStore);
                if (certificate == null)
                    throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND);
            } 

            Verify(extraStore, certificate, verifySignatureOnly); 
        } 

        public void CheckHash() { 

            int cvseSize = Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA));
            CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA cvse = new CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA(cvseSize);
            cvse.dwSignerType  = CAPI.CMSG_VERIFY_SIGNER_NULL; 
            cvse.dwSignerIndex = (uint) PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0);
 
            unsafe { 
                if (!CAPI.CryptMsgControl(m_signedCms.GetCryptMsgHandle(),
                                            0, 
                                            CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX,
                                            new IntPtr(&cvse)))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            } 
        }
 
        // 
        // Internal methods.
        // 

        internal CAPI.CMSG_SIGNER_INFO GetCmsgSignerInfo () {
            return m_cmsgSignerInfo;
        } 

        // 
        // Private methods. 
        //
 
        private unsafe void CounterSign (CmsSigner signer) {
            // Sanity check.
            Debug.Assert(signer != null);
 
            //
 
 
            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(); 
 
            // Get the signer's index.
            uint index = (uint) PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0); 

            // Create CMSG_SIGNER_ENCODE_INFO structure.
            SafeLocalAllocHandle pSignerEncodeInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO))));
            CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer); 

            try { 
                // Marshal to unmanaged memory. 
                Marshal.StructureToPtr(signerEncodeInfo, pSignerEncodeInfo.DangerousGetHandle(), false);
 
                // Counter sign.
                if (!CAPI.CryptMsgCountersign(m_signedCms.GetCryptMsgHandle(),
                                              index,
                                              1, 
                                              pSignerEncodeInfo.DangerousGetHandle()))
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
                // CAPI requires that the messge be re-encoded if any unauthenticated
                // attribute has been added. So, let's re-open it to decode to work 
                // around this limitation.
                m_signedCms.ReopenToDecode();
            }
            finally { 
                Marshal.DestroyStructure(pSignerEncodeInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_ENCODE_INFO));
                pSignerEncodeInfo.Dispose(); 
 
                // and don't forget to dispose of resources allocated for the structure.
                signerEncodeInfo.Dispose(); 
            }

            // Finally, add certs to bag of certs.
            PkcsUtils.AddCertsToMessage(m_signedCms.GetCryptMsgHandle(), m_signedCms.Certificates, PkcsUtils.CreateBagOfCertificates(signer)); 

            return; 
        } 

        private unsafe void Verify (X509Certificate2Collection extraStore, X509Certificate2 certificate, bool verifySignatureOnly) { 
            // We need to find out if DSS parameters inheritance is necessary. If so, we need to
            // first build the chain to cause CAPI to inherit and set the parameters in the
            // CERT_PUBKEY_ALG_PARA_PROP_ID extended property. Once we have the parameters in
            // the property, we then need to retrieve a copy and point to it in the CERT_INFO 
            // structure.
 
            SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle; 
            CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(certificate).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT));
 
            // Point to SubjectPublicKeyInfo field inside the CERT_INFO structure.
            IntPtr pSubjectPublicKeyInfo = new IntPtr((long) pCertContext.pCertInfo + (long) Marshal.OffsetOf(typeof(CAPI.CERT_INFO), "SubjectPublicKeyInfo"));

            // Point to Algorithm field inside the SubjectPublicKeyInfo field. 
            IntPtr pAlgorithm = new IntPtr((long) pSubjectPublicKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO), "Algorithm"));
 
            // Point to Parameters field inside the Algorithm field. 
            IntPtr pParameters = new IntPtr((long) pAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "Parameters"));
 
            // Retrieve the pszObjId pointer.
            IntPtr pObjId = Marshal.ReadIntPtr(pAlgorithm);

            // Translate the OID to AlgId value. 
            CAPI.CRYPT_OID_INFO pOIDInfo = CAPI.CryptFindOIDInfo(CAPI.CRYPT_OID_INFO_OID_KEY, pObjId, CAPI.CRYPT_PUBKEY_ALG_OID_GROUP_ID);
 
            // Is this DSS? 
            if (pOIDInfo.Algid == CAPI.CALG_DSS_SIGN) {
                bool inheritParameters = false; 

                // This is DSS, so inherit the parameters if necessary.
                IntPtr pcbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                IntPtr ppbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); 
                if (Marshal.ReadInt32(pcbData) == 0) {
                    inheritParameters = true; 
                } 
                else {
                    // Need to inherit if NULL pbData or *pbData is 0x05 (NULL ASN tag). 
                    if (Marshal.ReadIntPtr(ppbData) == IntPtr.Zero) {
                        inheritParameters = true;
                    }
                    else { 
                        IntPtr pbData = Marshal.ReadIntPtr(ppbData);
                        if ((uint) Marshal.ReadInt32(pbData) == CAPI.ASN_TAG_NULL) { 
                            inheritParameters = true; 
                        }
                    } 
                }

                // Do we need to copy inherited DSS parameters?
                if (inheritParameters) { 
                    // Build the chain to force CAPI to propagate the parameters to
                    // CERT_PUBKEY_ALG_PARA_PROP_ID extended property. 
                    SafeCertChainHandle pChainContext = SafeCertChainHandle.InvalidHandle; 
                    X509Utils.BuildChain(new IntPtr(CAPI.HCCE_CURRENT_USER),
                                         X509Utils.GetCertContext(certificate), 
                                         null,
                                         null,
                                         null,
                                         X509RevocationMode.NoCheck, 
                                         X509RevocationFlag.ExcludeRoot,
                                         DateTime.Now, 
                                         new TimeSpan(0, 0, 0), // default 
                                         ref pChainContext);
                    pChainContext.Dispose(); 

                    // The parameter is inherited in the extended property, but not copied
                    // to CERT_INFO, so we need to do it ourselves.
                    uint cbParameters = 0; 

                    if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate), 
                                                                CAPI.CERT_PUBKEY_ALG_PARA_PROP_ID, 
                                                                pbParameters,
                                                                ref cbParameters)) 
                        throw new CryptographicException(Marshal.GetLastWin32Error());

                    if (cbParameters > 0) {
                        pbParameters = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbParameters)); 
                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate),
                                                                    CAPI.CERT_PUBKEY_ALG_PARA_PROP_ID, 
                                                                    pbParameters, 
                                                                    ref cbParameters))
                            throw new CryptographicException(Marshal.GetLastWin32Error()); 

                        Marshal.WriteInt32(pcbData, (int)cbParameters);
                        Marshal.WriteIntPtr(ppbData, pbParameters.DangerousGetHandle());
                    } 
                }
            } 
 
            // Is this counter signer?
            if (m_parentSignerInfo == null) { 
                // Just plain signer.
                if (!CAPI.CryptMsgControl(m_signedCms.GetCryptMsgHandle(),
                                          0,
                                          CAPI.CMSG_CTRL_VERIFY_SIGNATURE, 
                                          pCertContext.pCertInfo)) {
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
                } 
            }
            else { 
                // Counter signer, so need to first find parent signer's index.
                int index = -1;
                int lastWin32Error = 0;
 
                // Since we allow the same signer to sign more than once,
                // we must than try all signatures of the same signer. 
                while (true) { 
                    try {
                        // Find index of parent signer. 
                        index = PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), m_parentSignerInfo, index + 1);
                    }
                    catch (CryptographicException) {
                        // Did we ever find a signature of the same signer? 
                        if (lastWin32Error == 0) {
                            // No. So we just re-throw, which is most likely CAPI.CRYPT_E_SIGNER_NOT_FOUND. 
                            throw; 
                        }
                        else { 
                            // Yes. Throw previous error, which is most likely CAPI.NTE_BAD_SIGNATURE.
                            throw new CryptographicException(lastWin32Error);
                        }
                    } 

                    // Now get the parent encoded singer info. 
                    uint cbParentEncodedSignerInfo = 0; 
                    SafeLocalAllocHandle pbParentEncodedSignerInfo = SafeLocalAllocHandle.InvalidHandle;
 
                    PkcsUtils.GetParam(m_signedCms.GetCryptMsgHandle(),
                                       CAPI.CMSG_ENCODED_SIGNER,
                                       (uint) index,
                                       out pbParentEncodedSignerInfo, 
                                       out cbParentEncodedSignerInfo);
 
                    // Try next signer if we can't get parent of this signer. 
                    if (cbParentEncodedSignerInfo == 0) {
                        lastWin32Error = CAPI.CRYPT_E_NO_SIGNER; 
                        continue;
                    }

                    fixed (byte * pbEncodedSignerInfo = m_encodedSignerInfo) { 
                        if (!CAPI.CryptMsgVerifyCountersignatureEncoded(IntPtr.Zero,
                                                                        CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                                        pbParentEncodedSignerInfo.DangerousGetHandle(), 
                                                                        cbParentEncodedSignerInfo,
                                                                        new IntPtr(pbEncodedSignerInfo), 
                                                                        (uint) m_encodedSignerInfo.Length,
                                                                        pCertContext.pCertInfo)) {
                            // Cache the error, and try next signer.
                            lastWin32Error = Marshal.GetLastWin32Error(); 
                            continue;
                        } 
                    } 

                    // Keep alive. 
                    pbParentEncodedSignerInfo.Dispose();

                    // The signature is successfully verified.
                    break; 
                }
            } 
 
            // Verfiy the cert if requested.
            if (!verifySignatureOnly) { 
                int hr = VerifyCertificate(certificate, extraStore);
                if (hr != CAPI.S_OK)
                    throw new CryptographicException(hr);
            } 

            // Keep alive. 
            pbParameters.Dispose(); 
        }
 
        private unsafe void RemoveCounterSignature (int parentIndex, int childIndex) {
            // Just make sure this is non-negative.
            if (parentIndex < 0)
                throw new ArgumentOutOfRangeException("parentIndex"); 
            if (childIndex < 0)
                throw new ArgumentOutOfRangeException("childIndex"); 
 
            uint cbCmsgCmsSignerInfo = 0;
            SafeLocalAllocHandle pbCmsgCmsSignerInfo = SafeLocalAllocHandle.InvalidHandle; 

            uint cbCmsgSignerInfo = 0;
            SafeLocalAllocHandle pbCmsgSignerInfo = SafeLocalAllocHandle.InvalidHandle;
 
            uint index = 0;
            uint cAttr = 0; 
            IntPtr pAttr = IntPtr.Zero; 
            SafeCryptMsgHandle hMsg = m_signedCms.GetCryptMsgHandle();
 
            if (PkcsUtils.CmsSupported()) {
                PkcsUtils.GetParam(hMsg,
                                   CAPI.CMSG_CMS_SIGNER_INFO_PARAM,
                                   (uint) parentIndex, 
                                   out pbCmsgCmsSignerInfo,
                                   out cbCmsgCmsSignerInfo); 
 
                CAPI.CMSG_CMS_SIGNER_INFO cmsgCmsSignerInfo = (CAPI.CMSG_CMS_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgCmsSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_CMS_SIGNER_INFO));
                cAttr = cmsgCmsSignerInfo.UnauthAttrs.cAttr; 
                pAttr = new IntPtr((long) cmsgCmsSignerInfo.UnauthAttrs.rgAttr);
            }
            else {
                PkcsUtils.GetParam(hMsg, 
                                   CAPI.CMSG_SIGNER_INFO_PARAM,
                                   (uint) parentIndex, 
                                   out pbCmsgSignerInfo, 
                                   out cbCmsgSignerInfo);
 
                CAPI.CMSG_SIGNER_INFO cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO));
                cAttr = cmsgSignerInfo.UnauthAttrs.cAttr;
                pAttr = new IntPtr((long) cmsgSignerInfo.UnauthAttrs.rgAttr);
            } 

            // Find index for counter signature attribute. 
            // Note: It is not guaranteed that CAPI will keep all counter signatures 
            // in one single unauthenticated attribute. So we need to find the correct
            // unauthenticated attribute containing this counter signer which is 
            // identified by index.
            for (index = 0; index < cAttr; index++) {
                CAPI.CRYPT_ATTRIBUTE attr = (CAPI.CRYPT_ATTRIBUTE) Marshal.PtrToStructure(pAttr, typeof(CAPI.CRYPT_ATTRIBUTE));
                if (String.Compare(attr.pszObjId, CAPI.szOID_RSA_counterSign, StringComparison.OrdinalIgnoreCase) == 0) { 
                    if (attr.cValue > 0) {
                        // Is it in this attribute? 
                        if (childIndex < (int) attr.cValue) { 
                            // Found the desired counter signature attribute. So, first remove the
                            // entire attribute, then remove just the counter signature from the 
                            // retrieved attribute, and finally add back the modified attribute,
                            // if necessary.
                            CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA delPara = new CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA)));
                            delPara.dwSignerIndex = (uint) parentIndex; 
                            delPara.dwUnauthAttrIndex = index;
 
                            if (!CAPI.CryptMsgControl(hMsg, 
                                                      0,
                                                      CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR, 
                                                      new IntPtr(&delPara)))
                                throw new CryptographicException(Marshal.GetLastWin32Error());

                            // No need to add back if only one counter signature in this attribute. 
                            if (attr.cValue > 1) {
                                try { 
                                    // There were more than one counter signatures in this attribute, so 
                                    // need to add back a new counter signature attribute which includes
                                    // the remaining counter signatures. 
                                    uint cbCounterSignatureValue = (uint) ((attr.cValue - 1) * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB)));
                                    SafeLocalAllocHandle pbCounterSignatureValue = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbCounterSignatureValue));

                                    // Copy everything except the one being removed. 
                                    CAPI.CRYPTOAPI_BLOB * pOldValue =  (CAPI.CRYPTOAPI_BLOB *) attr.rgValue;
                                    CAPI.CRYPTOAPI_BLOB * pNewValue =  (CAPI.CRYPTOAPI_BLOB *) pbCounterSignatureValue.DangerousGetHandle(); 
 
                                    for (int i = 0; i < (int) attr.cValue; i++, pOldValue++, pNewValue++) {
                                        if (i != childIndex) { 
                                            *pNewValue = *pOldValue;
                                        }
                                    }
 
                                    // Encode the new counter signature attribute.
                                    byte[] encodedNewAttribute; 
                                    CAPI.CRYPT_ATTRIBUTE newAttr = new CAPI.CRYPT_ATTRIBUTE(); 
                                    newAttr.pszObjId = attr.pszObjId;
                                    newAttr.cValue = attr.cValue - 1; 
                                    newAttr.rgValue = pbCounterSignatureValue.DangerousGetHandle();

                                    SafeLocalAllocHandle pNewAttr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_ATTRIBUTE))));
                                    Marshal.StructureToPtr(newAttr, pNewAttr.DangerousGetHandle(), false); 

                                    try { 
                                        if (!CAPI.EncodeObject(new IntPtr(CAPI.PKCS_ATTRIBUTE), 
                                                               pNewAttr.DangerousGetHandle(),
                                                               out encodedNewAttribute)) 
                                            throw new CryptographicException(Marshal.GetLastWin32Error());
                                    }
                                    finally {
                                        Marshal.DestroyStructure(pNewAttr.DangerousGetHandle(), typeof(CAPI.CRYPT_ATTRIBUTE)); 
                                        pNewAttr.Dispose();
                                    } 
 
                                    // Finally, add it back.
                                    fixed (byte * pbData = &encodedNewAttribute[0]) { 
                                        CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA addPara = new CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA)));
                                        addPara.dwSignerIndex = (uint) parentIndex;
                                        addPara.blob.cbData = (uint) encodedNewAttribute.Length;
                                        addPara.blob.pbData = new IntPtr(pbData); 

                                        if (!CAPI.CryptMsgControl(hMsg, 
                                                                  0, 
                                                                  CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR,
                                                                  new IntPtr(&addPara))) 
                                            throw new CryptographicException(Marshal.GetLastWin32Error());
                                    }

                                    // Keep alive. 
                                    pbCounterSignatureValue.Dispose();
                                } 
                                catch (CryptographicException) { 
                                    // Roll back.
                                    byte[] encodedAttribute; 
                                    if (CAPI.EncodeObject(new IntPtr(CAPI.PKCS_ATTRIBUTE),
                                                          pAttr,
                                                          out encodedAttribute)) {
                                        fixed (byte * pbData = &encodedAttribute[0]) { 
                                            CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA addPara = new CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA)));
                                            addPara.dwSignerIndex = (uint) parentIndex; 
                                            addPara.blob.cbData = (uint) encodedAttribute.Length; 
                                            addPara.blob.pbData = new IntPtr(pbData);
                                            CAPI.CryptMsgControl(hMsg, 0, CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, new IntPtr(&addPara)); 
                                        }
                                    }
                                    throw;
                                } 
                            }
 
                            return; 
                        }
 
                        childIndex -= (int) attr.cValue;
                    }
                }
 
                pAttr = new IntPtr((long) pAttr + (long) Marshal.SizeOf(typeof(CAPI.CRYPT_ATTRIBUTE)));
            } 
 
            // Keep alive.
            if (pbCmsgCmsSignerInfo != null && !pbCmsgCmsSignerInfo.IsInvalid) { 
                pbCmsgCmsSignerInfo.Dispose();
            }
            if (pbCmsgSignerInfo != null && !pbCmsgSignerInfo.IsInvalid) {
                pbCmsgSignerInfo.Dispose(); 
            }
 
            throw new CryptographicException(CAPI.CRYPT_E_NO_SIGNER); 
        }
 
        //
        // Private static.
        //
 
        private static unsafe int VerifyCertificate (X509Certificate2 certificate,
                                                     X509Certificate2Collection extraStore) { 
            int dwErrorStatus; 
            int hr = X509Utils.VerifyCertificate(X509Utils.GetCertContext(certificate),
                                                 null, 
                                                 null,
                                                 X509RevocationMode.Online,
                                                 X509RevocationFlag.ExcludeRoot,
                                                 DateTime.Now, 
                                                 new TimeSpan(0, 0, 0),
                                                 extraStore, 
                                                 new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE), 
                                                 new IntPtr(&dwErrorStatus));
            if (hr != CAPI.S_OK) 
                return dwErrorStatus;

            // Check key usages to make sure it is good for signing.
            foreach (X509Extension extension in certificate.Extensions) { 
                if (String.Compare(extension.Oid.Value, CAPI.szOID_KEY_USAGE, StringComparison.OrdinalIgnoreCase) == 0) {
                    X509KeyUsageExtension keyUsage = new X509KeyUsageExtension(); 
                    keyUsage.CopyFrom(extension); 
                    if ((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == 0 &&
                        (keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == 0) { 
                        hr = CAPI.CERT_E_WRONG_USAGE;
                        break;
                    }
                } 
            }
 
            return hr; 
        }
    } 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class SignerInfoCollection : ICollection {
        private SignerInfo[] m_signerInfos; 

        internal SignerInfoCollection () { 
            m_signerInfos = new SignerInfo[0]; 
        }
 
        internal unsafe SignerInfoCollection (SignedCms signedCms) {
            uint dwSigners = 0;
            uint cbCount = (uint) Marshal.SizeOf(typeof(uint));
            SafeCryptMsgHandle safeCryptMsgHandle = signedCms.GetCryptMsgHandle(); 

            if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, 
                                       CAPI.CMSG_SIGNER_COUNT_PARAM, 
                                       0,
                                       new IntPtr(&dwSigners), 
                                       new IntPtr(&cbCount)))
                throw new CryptographicException(Marshal.GetLastWin32Error());

            SignerInfo[] signerInfos = new SignerInfo[dwSigners]; 
            for (int index = 0; index < dwSigners; index++) {
                uint cbCmsgSignerInfo = 0; 
                if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, 
                                           CAPI.CMSG_SIGNER_INFO_PARAM,
                                           (uint) index, 
                                           IntPtr.Zero,
                                           new IntPtr(&cbCmsgSignerInfo)))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                SafeLocalAllocHandle pbCmsgSignerInfo = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbCmsgSignerInfo));
 
                if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, 
                                           CAPI.CMSG_SIGNER_INFO_PARAM,
                                           (uint) index, 
                                           pbCmsgSignerInfo,
                                           new IntPtr(&cbCmsgSignerInfo)))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                signerInfos[index] = new SignerInfo(signedCms, pbCmsgSignerInfo);
            } 
 
            m_signerInfos = signerInfos;
        } 

        internal unsafe SignerInfoCollection (SignedCms signedCms, SignerInfo signerInfo) {
            SignerInfo[] signerInfos = new SignerInfo[0];
 
            int count = 0;
            int index = 0; 
 
            foreach (CryptographicAttributeObject attribute in signerInfo.UnsignedAttributes) {
                if (attribute.Oid.Value == CAPI.szOID_RSA_counterSign) { 
                    count += attribute.Values.Count;
                }
            }
 
            signerInfos = new SignerInfo[count];
 
            foreach (CryptographicAttributeObject attribute in signerInfo.UnsignedAttributes) { 
                if (attribute.Oid.Value == CAPI.szOID_RSA_counterSign) {
                    for (int i = 0; i < attribute.Values.Count; i++) { 
                        AsnEncodedData encodedSignerInfo = (AsnEncodedData) attribute.Values[i];
                        signerInfos[index++] = new SignerInfo(signedCms, signerInfo, encodedSignerInfo.RawData);
                    }
                } 
            }
 
            m_signerInfos = signerInfos; 
        }
 
        public SignerInfo this[int index] {
            get {
                if (index < 0 || index >= m_signerInfos.Length)
                    throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index")); 

                Debug.Assert(m_signerInfos[index] != null); 
                return m_signerInfos[index]; 
            }
        } 

        public int Count {
            get {
                return m_signerInfos.Length; 
            }
        } 
 
        public SignerInfoEnumerator GetEnumerator() {
            return new SignerInfoEnumerator(this); 
        }

        /// 
        IEnumerator IEnumerable.GetEnumerator() { 
            return new SignerInfoEnumerator(this);
        } 
 
        public void CopyTo(Array array, int index) {
            if (array == null) 
                throw new ArgumentNullException("array");
            if (array.Rank != 1)
                throw new ArgumentException(SecurityResources.GetResourceString("Arg_RankMultiDimNotSupported"));
            if (index < 0 || index >= array.Length) 
                throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index"));
            if (index + this.Count > array.Length) 
                throw new ArgumentException(SecurityResources.GetResourceString("Argument_InvalidOffLen")); 

            for (int i=0; i < this.Count; i++) { 
                array.SetValue(this[i], index);
                index++;
            }
        } 

        public void CopyTo(SignerInfo[] array, int index) { 
            ((ICollection)this).CopyTo(array, index); 
        }
 
        public bool IsSynchronized {
            get {
                return false;
            } 
        }
 
        public Object SyncRoot { 
            get {
                return this; 
            }
        }
    }
 
    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class SignerInfoEnumerator : IEnumerator { 
        private SignerInfoCollection m_signerInfos; 
        private int m_current;
 
        private SignerInfoEnumerator() {}
        internal SignerInfoEnumerator(SignerInfoCollection signerInfos) {
            m_signerInfos = signerInfos;
            m_current = -1; 
        }
 
        public SignerInfo Current { 
            get {
                return m_signerInfos[m_current]; 
            }
        }

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

        public bool MoveNext() {
            if (m_current == ((int) m_signerInfos.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.
//
// ==--== 

// 
// SignerInfo.cs 
//
 
namespace System.Security.Cryptography.Pkcs {
    using System.Collections;
    using System.Diagnostics;
    using System.Globalization; 
    using System.Runtime.InteropServices;
    using System.Security.Permissions; 
    using System.Security.Cryptography; 
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Cryptography.Xml; 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class SignerInfo {
        private X509Certificate2                m_certificate; 
        private SubjectIdentifier                m_signerIdentifier;
        private CryptographicAttributeObjectCollection m_signedAttributes; 
        private CryptographicAttributeObjectCollection m_unsignedAttributes; 

        private SignedCms                   m_signedCms; 
        private SignerInfo                  m_parentSignerInfo;
        private byte[]                      m_encodedSignerInfo;
        private SafeLocalAllocHandle        m_pbCmsgSignerInfo;
        private CAPI.CMSG_SIGNER_INFO       m_cmsgSignerInfo; 

        // 
        // Constructors. 
        //
 
        private SignerInfo () {}

        internal unsafe SignerInfo (SignedCms signedCms, SafeLocalAllocHandle pbCmsgSignerInfo) {
            // Sanity check. 
            Debug.Assert(signedCms != null && pbCmsgSignerInfo != null && !pbCmsgSignerInfo.IsInvalid);
 
            m_signedCms = signedCms; 
            m_parentSignerInfo = null;
            m_encodedSignerInfo = null; 
            m_pbCmsgSignerInfo = pbCmsgSignerInfo;
            m_cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO));
        }
 
        internal unsafe SignerInfo (SignedCms signedCms, SignerInfo parentSignerInfo, byte[] encodedSignerInfo) {
            // Sanity check. 
            Debug.Assert(signedCms != null && encodedSignerInfo != null && encodedSignerInfo.Length > 0); 

            uint cbCmsgSignerInfo = 0; 
            SafeLocalAllocHandle pbCmsgSignerInfo = SafeLocalAllocHandle.InvalidHandle;

            fixed (byte * pEncodedSignerInfo = &encodedSignerInfo[0]) {
                if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS7_SIGNER_INFO), 
                                       new IntPtr(pEncodedSignerInfo),
                                       (uint) encodedSignerInfo.Length, 
                                       out pbCmsgSignerInfo, 
                                       out cbCmsgSignerInfo))
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
            }

            m_signedCms = signedCms;
            m_parentSignerInfo = parentSignerInfo; 
            m_encodedSignerInfo = (byte[]) encodedSignerInfo.Clone();
            m_pbCmsgSignerInfo = pbCmsgSignerInfo; 
            m_cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO)); 
        }
 
        //
        // Public APIs.
        //
 
        public int Version {
            get { 
                return (int) m_cmsgSignerInfo.dwVersion; 
            }
        } 


        public X509Certificate2 Certificate {
            get { 
                if (m_certificate == null)
                    m_certificate = PkcsUtils.FindCertificate(this.SignerIdentifier, m_signedCms.Certificates); 
 
                return m_certificate;
            } 
        }

        public SubjectIdentifier SignerIdentifier {
            get { 
                if (m_signerIdentifier == null)
                    m_signerIdentifier = new SubjectIdentifier(m_cmsgSignerInfo); 
 
                return m_signerIdentifier;
            } 
        }

        public Oid DigestAlgorithm {
            get { 
                return new Oid(m_cmsgSignerInfo.HashAlgorithm.pszObjId);
            } 
        } 

        public CryptographicAttributeObjectCollection SignedAttributes { 
            get {
                if (m_signedAttributes == null)
                    m_signedAttributes = new CryptographicAttributeObjectCollection(m_cmsgSignerInfo.AuthAttrs);
 
                return m_signedAttributes;
            } 
        } 

        public CryptographicAttributeObjectCollection UnsignedAttributes { 
            get {
                if (m_unsignedAttributes == null)
                    m_unsignedAttributes = new CryptographicAttributeObjectCollection(m_cmsgSignerInfo.UnauthAttrs);
 
                return m_unsignedAttributes;
            } 
        } 

        public SignerInfoCollection CounterSignerInfos { 
            get {
                // We only support one level of counter signing.
                if (m_parentSignerInfo != null)
                    return new SignerInfoCollection(); 

                return new SignerInfoCollection(m_signedCms, this); 
            } 
        }
 
        public void ComputeCounterSignature () {
            ComputeCounterSignature(new CmsSigner(m_signedCms.Version == 2 ? SubjectIdentifierType.SubjectKeyIdentifier : SubjectIdentifierType.IssuerAndSerialNumber));
        }
 
        public void ComputeCounterSignature (CmsSigner signer) {
            // We only support one level of counter signing. 
            if (m_parentSignerInfo != null) 
                throw new CryptographicException(CAPI.E_NOTIMPL);
            if (signer == null) 
                throw new ArgumentNullException("signer");

            if (signer.Certificate == null)
                signer.Certificate = PkcsUtils.SelectSignerCertificate(); 

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

            CounterSign(signer); 
        }

        public void RemoveCounterSignature (int index) {
            // We only support one level of counter signing. 
            if (m_parentSignerInfo != null)
                throw new CryptographicException(CAPI.E_NOTIMPL); 
 
            RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index);
 
            return;
        }

        public void RemoveCounterSignature (SignerInfo counterSignerInfo) { 
            // We only support one level of counter signing.
            if (m_parentSignerInfo != null) 
                throw new CryptographicException(CAPI.E_NOTIMPL); 
            if (counterSignerInfo == null)
                throw new ArgumentNullException("counterSignerInfo"); 

            foreach (CryptographicAttributeObject attribute in UnsignedAttributes) {
                if (String.Compare(attribute.Oid.Value, CAPI.szOID_RSA_counterSign, StringComparison.OrdinalIgnoreCase) == 0) {
                    for (int index = 0; index < attribute.Values.Count; index++) { 
                        AsnEncodedData encodedCounterSignature = (AsnEncodedData) attribute.Values[index];
                        SignerInfo counterSignerInfo2 = new SignerInfo(m_signedCms, m_parentSignerInfo, encodedCounterSignature.RawData); 
 
                        if ((counterSignerInfo.SignerIdentifier.Type == SubjectIdentifierType.IssuerAndSerialNumber) &&
                            (counterSignerInfo2.SignerIdentifier.Type == SubjectIdentifierType.IssuerAndSerialNumber)) { 
                            X509IssuerSerial issuerSerial1 = (X509IssuerSerial) counterSignerInfo.SignerIdentifier.Value;
                            X509IssuerSerial issuerSerial2 = (X509IssuerSerial) counterSignerInfo2.SignerIdentifier.Value;

                            if ((String.Compare(issuerSerial1.IssuerName, issuerSerial2.IssuerName, StringComparison.OrdinalIgnoreCase) == 0) && 
                                (String.Compare(issuerSerial1.SerialNumber, issuerSerial2.SerialNumber, StringComparison.OrdinalIgnoreCase) == 0)) {
                                RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); 
                                return; 
                            }
                        } 
                        else if ((counterSignerInfo.SignerIdentifier.Type == SubjectIdentifierType.SubjectKeyIdentifier) &&
                                 (counterSignerInfo2.SignerIdentifier.Type == SubjectIdentifierType.SubjectKeyIdentifier)) {
                            string keyIdentifier1 = counterSignerInfo.SignerIdentifier.Value as string;
                            string keyIdentifier2 = counterSignerInfo2.SignerIdentifier.Value as string; 

                            if (String.Compare(keyIdentifier1, keyIdentifier2, StringComparison.OrdinalIgnoreCase) == 0) { 
                                RemoveCounterSignature(PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0), index); 
                                return;
                            } 
                        }
                    }
                }
            } 

            throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND); 
        } 

        public void CheckSignature (bool verifySignatureOnly) { 
            CheckSignature(new X509Certificate2Collection(), verifySignatureOnly);
        }

        public void CheckSignature (X509Certificate2Collection extraStore, bool verifySignatureOnly) { 
            if (extraStore == null)
                throw new ArgumentNullException("extraStore"); 
 
            X509Certificate2 certificate = this.Certificate;
            if (certificate == null) { 
                certificate = PkcsUtils.FindCertificate(SignerIdentifier, extraStore);
                if (certificate == null)
                    throw new CryptographicException(CAPI.CRYPT_E_SIGNER_NOT_FOUND);
            } 

            Verify(extraStore, certificate, verifySignatureOnly); 
        } 

        public void CheckHash() { 

            int cvseSize = Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA));
            CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA cvse = new CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA(cvseSize);
            cvse.dwSignerType  = CAPI.CMSG_VERIFY_SIGNER_NULL; 
            cvse.dwSignerIndex = (uint) PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0);
 
            unsafe { 
                if (!CAPI.CryptMsgControl(m_signedCms.GetCryptMsgHandle(),
                                            0, 
                                            CAPI.CMSG_CTRL_VERIFY_SIGNATURE_EX,
                                            new IntPtr(&cvse)))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            } 
        }
 
        // 
        // Internal methods.
        // 

        internal CAPI.CMSG_SIGNER_INFO GetCmsgSignerInfo () {
            return m_cmsgSignerInfo;
        } 

        // 
        // Private methods. 
        //
 
        private unsafe void CounterSign (CmsSigner signer) {
            // Sanity check.
            Debug.Assert(signer != null);
 
            //
 
 
            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(); 
 
            // Get the signer's index.
            uint index = (uint) PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), this, 0); 

            // Create CMSG_SIGNER_ENCODE_INFO structure.
            SafeLocalAllocHandle pSignerEncodeInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO))));
            CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer); 

            try { 
                // Marshal to unmanaged memory. 
                Marshal.StructureToPtr(signerEncodeInfo, pSignerEncodeInfo.DangerousGetHandle(), false);
 
                // Counter sign.
                if (!CAPI.CryptMsgCountersign(m_signedCms.GetCryptMsgHandle(),
                                              index,
                                              1, 
                                              pSignerEncodeInfo.DangerousGetHandle()))
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
                // CAPI requires that the messge be re-encoded if any unauthenticated
                // attribute has been added. So, let's re-open it to decode to work 
                // around this limitation.
                m_signedCms.ReopenToDecode();
            }
            finally { 
                Marshal.DestroyStructure(pSignerEncodeInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_ENCODE_INFO));
                pSignerEncodeInfo.Dispose(); 
 
                // and don't forget to dispose of resources allocated for the structure.
                signerEncodeInfo.Dispose(); 
            }

            // Finally, add certs to bag of certs.
            PkcsUtils.AddCertsToMessage(m_signedCms.GetCryptMsgHandle(), m_signedCms.Certificates, PkcsUtils.CreateBagOfCertificates(signer)); 

            return; 
        } 

        private unsafe void Verify (X509Certificate2Collection extraStore, X509Certificate2 certificate, bool verifySignatureOnly) { 
            // We need to find out if DSS parameters inheritance is necessary. If so, we need to
            // first build the chain to cause CAPI to inherit and set the parameters in the
            // CERT_PUBKEY_ALG_PARA_PROP_ID extended property. Once we have the parameters in
            // the property, we then need to retrieve a copy and point to it in the CERT_INFO 
            // structure.
 
            SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle; 
            CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(certificate).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT));
 
            // Point to SubjectPublicKeyInfo field inside the CERT_INFO structure.
            IntPtr pSubjectPublicKeyInfo = new IntPtr((long) pCertContext.pCertInfo + (long) Marshal.OffsetOf(typeof(CAPI.CERT_INFO), "SubjectPublicKeyInfo"));

            // Point to Algorithm field inside the SubjectPublicKeyInfo field. 
            IntPtr pAlgorithm = new IntPtr((long) pSubjectPublicKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO), "Algorithm"));
 
            // Point to Parameters field inside the Algorithm field. 
            IntPtr pParameters = new IntPtr((long) pAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "Parameters"));
 
            // Retrieve the pszObjId pointer.
            IntPtr pObjId = Marshal.ReadIntPtr(pAlgorithm);

            // Translate the OID to AlgId value. 
            CAPI.CRYPT_OID_INFO pOIDInfo = CAPI.CryptFindOIDInfo(CAPI.CRYPT_OID_INFO_OID_KEY, pObjId, CAPI.CRYPT_PUBKEY_ALG_OID_GROUP_ID);
 
            // Is this DSS? 
            if (pOIDInfo.Algid == CAPI.CALG_DSS_SIGN) {
                bool inheritParameters = false; 

                // This is DSS, so inherit the parameters if necessary.
                IntPtr pcbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                IntPtr ppbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); 
                if (Marshal.ReadInt32(pcbData) == 0) {
                    inheritParameters = true; 
                } 
                else {
                    // Need to inherit if NULL pbData or *pbData is 0x05 (NULL ASN tag). 
                    if (Marshal.ReadIntPtr(ppbData) == IntPtr.Zero) {
                        inheritParameters = true;
                    }
                    else { 
                        IntPtr pbData = Marshal.ReadIntPtr(ppbData);
                        if ((uint) Marshal.ReadInt32(pbData) == CAPI.ASN_TAG_NULL) { 
                            inheritParameters = true; 
                        }
                    } 
                }

                // Do we need to copy inherited DSS parameters?
                if (inheritParameters) { 
                    // Build the chain to force CAPI to propagate the parameters to
                    // CERT_PUBKEY_ALG_PARA_PROP_ID extended property. 
                    SafeCertChainHandle pChainContext = SafeCertChainHandle.InvalidHandle; 
                    X509Utils.BuildChain(new IntPtr(CAPI.HCCE_CURRENT_USER),
                                         X509Utils.GetCertContext(certificate), 
                                         null,
                                         null,
                                         null,
                                         X509RevocationMode.NoCheck, 
                                         X509RevocationFlag.ExcludeRoot,
                                         DateTime.Now, 
                                         new TimeSpan(0, 0, 0), // default 
                                         ref pChainContext);
                    pChainContext.Dispose(); 

                    // The parameter is inherited in the extended property, but not copied
                    // to CERT_INFO, so we need to do it ourselves.
                    uint cbParameters = 0; 

                    if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate), 
                                                                CAPI.CERT_PUBKEY_ALG_PARA_PROP_ID, 
                                                                pbParameters,
                                                                ref cbParameters)) 
                        throw new CryptographicException(Marshal.GetLastWin32Error());

                    if (cbParameters > 0) {
                        pbParameters = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbParameters)); 
                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate),
                                                                    CAPI.CERT_PUBKEY_ALG_PARA_PROP_ID, 
                                                                    pbParameters, 
                                                                    ref cbParameters))
                            throw new CryptographicException(Marshal.GetLastWin32Error()); 

                        Marshal.WriteInt32(pcbData, (int)cbParameters);
                        Marshal.WriteIntPtr(ppbData, pbParameters.DangerousGetHandle());
                    } 
                }
            } 
 
            // Is this counter signer?
            if (m_parentSignerInfo == null) { 
                // Just plain signer.
                if (!CAPI.CryptMsgControl(m_signedCms.GetCryptMsgHandle(),
                                          0,
                                          CAPI.CMSG_CTRL_VERIFY_SIGNATURE, 
                                          pCertContext.pCertInfo)) {
                    throw new CryptographicException(Marshal.GetLastWin32Error()); 
                } 
            }
            else { 
                // Counter signer, so need to first find parent signer's index.
                int index = -1;
                int lastWin32Error = 0;
 
                // Since we allow the same signer to sign more than once,
                // we must than try all signatures of the same signer. 
                while (true) { 
                    try {
                        // Find index of parent signer. 
                        index = PkcsUtils.GetSignerIndex(m_signedCms.GetCryptMsgHandle(), m_parentSignerInfo, index + 1);
                    }
                    catch (CryptographicException) {
                        // Did we ever find a signature of the same signer? 
                        if (lastWin32Error == 0) {
                            // No. So we just re-throw, which is most likely CAPI.CRYPT_E_SIGNER_NOT_FOUND. 
                            throw; 
                        }
                        else { 
                            // Yes. Throw previous error, which is most likely CAPI.NTE_BAD_SIGNATURE.
                            throw new CryptographicException(lastWin32Error);
                        }
                    } 

                    // Now get the parent encoded singer info. 
                    uint cbParentEncodedSignerInfo = 0; 
                    SafeLocalAllocHandle pbParentEncodedSignerInfo = SafeLocalAllocHandle.InvalidHandle;
 
                    PkcsUtils.GetParam(m_signedCms.GetCryptMsgHandle(),
                                       CAPI.CMSG_ENCODED_SIGNER,
                                       (uint) index,
                                       out pbParentEncodedSignerInfo, 
                                       out cbParentEncodedSignerInfo);
 
                    // Try next signer if we can't get parent of this signer. 
                    if (cbParentEncodedSignerInfo == 0) {
                        lastWin32Error = CAPI.CRYPT_E_NO_SIGNER; 
                        continue;
                    }

                    fixed (byte * pbEncodedSignerInfo = m_encodedSignerInfo) { 
                        if (!CAPI.CryptMsgVerifyCountersignatureEncoded(IntPtr.Zero,
                                                                        CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                                        pbParentEncodedSignerInfo.DangerousGetHandle(), 
                                                                        cbParentEncodedSignerInfo,
                                                                        new IntPtr(pbEncodedSignerInfo), 
                                                                        (uint) m_encodedSignerInfo.Length,
                                                                        pCertContext.pCertInfo)) {
                            // Cache the error, and try next signer.
                            lastWin32Error = Marshal.GetLastWin32Error(); 
                            continue;
                        } 
                    } 

                    // Keep alive. 
                    pbParentEncodedSignerInfo.Dispose();

                    // The signature is successfully verified.
                    break; 
                }
            } 
 
            // Verfiy the cert if requested.
            if (!verifySignatureOnly) { 
                int hr = VerifyCertificate(certificate, extraStore);
                if (hr != CAPI.S_OK)
                    throw new CryptographicException(hr);
            } 

            // Keep alive. 
            pbParameters.Dispose(); 
        }
 
        private unsafe void RemoveCounterSignature (int parentIndex, int childIndex) {
            // Just make sure this is non-negative.
            if (parentIndex < 0)
                throw new ArgumentOutOfRangeException("parentIndex"); 
            if (childIndex < 0)
                throw new ArgumentOutOfRangeException("childIndex"); 
 
            uint cbCmsgCmsSignerInfo = 0;
            SafeLocalAllocHandle pbCmsgCmsSignerInfo = SafeLocalAllocHandle.InvalidHandle; 

            uint cbCmsgSignerInfo = 0;
            SafeLocalAllocHandle pbCmsgSignerInfo = SafeLocalAllocHandle.InvalidHandle;
 
            uint index = 0;
            uint cAttr = 0; 
            IntPtr pAttr = IntPtr.Zero; 
            SafeCryptMsgHandle hMsg = m_signedCms.GetCryptMsgHandle();
 
            if (PkcsUtils.CmsSupported()) {
                PkcsUtils.GetParam(hMsg,
                                   CAPI.CMSG_CMS_SIGNER_INFO_PARAM,
                                   (uint) parentIndex, 
                                   out pbCmsgCmsSignerInfo,
                                   out cbCmsgCmsSignerInfo); 
 
                CAPI.CMSG_CMS_SIGNER_INFO cmsgCmsSignerInfo = (CAPI.CMSG_CMS_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgCmsSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_CMS_SIGNER_INFO));
                cAttr = cmsgCmsSignerInfo.UnauthAttrs.cAttr; 
                pAttr = new IntPtr((long) cmsgCmsSignerInfo.UnauthAttrs.rgAttr);
            }
            else {
                PkcsUtils.GetParam(hMsg, 
                                   CAPI.CMSG_SIGNER_INFO_PARAM,
                                   (uint) parentIndex, 
                                   out pbCmsgSignerInfo, 
                                   out cbCmsgSignerInfo);
 
                CAPI.CMSG_SIGNER_INFO cmsgSignerInfo = (CAPI.CMSG_SIGNER_INFO) Marshal.PtrToStructure(pbCmsgSignerInfo.DangerousGetHandle(), typeof(CAPI.CMSG_SIGNER_INFO));
                cAttr = cmsgSignerInfo.UnauthAttrs.cAttr;
                pAttr = new IntPtr((long) cmsgSignerInfo.UnauthAttrs.rgAttr);
            } 

            // Find index for counter signature attribute. 
            // Note: It is not guaranteed that CAPI will keep all counter signatures 
            // in one single unauthenticated attribute. So we need to find the correct
            // unauthenticated attribute containing this counter signer which is 
            // identified by index.
            for (index = 0; index < cAttr; index++) {
                CAPI.CRYPT_ATTRIBUTE attr = (CAPI.CRYPT_ATTRIBUTE) Marshal.PtrToStructure(pAttr, typeof(CAPI.CRYPT_ATTRIBUTE));
                if (String.Compare(attr.pszObjId, CAPI.szOID_RSA_counterSign, StringComparison.OrdinalIgnoreCase) == 0) { 
                    if (attr.cValue > 0) {
                        // Is it in this attribute? 
                        if (childIndex < (int) attr.cValue) { 
                            // Found the desired counter signature attribute. So, first remove the
                            // entire attribute, then remove just the counter signature from the 
                            // retrieved attribute, and finally add back the modified attribute,
                            // if necessary.
                            CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA delPara = new CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA)));
                            delPara.dwSignerIndex = (uint) parentIndex; 
                            delPara.dwUnauthAttrIndex = index;
 
                            if (!CAPI.CryptMsgControl(hMsg, 
                                                      0,
                                                      CAPI.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR, 
                                                      new IntPtr(&delPara)))
                                throw new CryptographicException(Marshal.GetLastWin32Error());

                            // No need to add back if only one counter signature in this attribute. 
                            if (attr.cValue > 1) {
                                try { 
                                    // There were more than one counter signatures in this attribute, so 
                                    // need to add back a new counter signature attribute which includes
                                    // the remaining counter signatures. 
                                    uint cbCounterSignatureValue = (uint) ((attr.cValue - 1) * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB)));
                                    SafeLocalAllocHandle pbCounterSignatureValue = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbCounterSignatureValue));

                                    // Copy everything except the one being removed. 
                                    CAPI.CRYPTOAPI_BLOB * pOldValue =  (CAPI.CRYPTOAPI_BLOB *) attr.rgValue;
                                    CAPI.CRYPTOAPI_BLOB * pNewValue =  (CAPI.CRYPTOAPI_BLOB *) pbCounterSignatureValue.DangerousGetHandle(); 
 
                                    for (int i = 0; i < (int) attr.cValue; i++, pOldValue++, pNewValue++) {
                                        if (i != childIndex) { 
                                            *pNewValue = *pOldValue;
                                        }
                                    }
 
                                    // Encode the new counter signature attribute.
                                    byte[] encodedNewAttribute; 
                                    CAPI.CRYPT_ATTRIBUTE newAttr = new CAPI.CRYPT_ATTRIBUTE(); 
                                    newAttr.pszObjId = attr.pszObjId;
                                    newAttr.cValue = attr.cValue - 1; 
                                    newAttr.rgValue = pbCounterSignatureValue.DangerousGetHandle();

                                    SafeLocalAllocHandle pNewAttr = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_ATTRIBUTE))));
                                    Marshal.StructureToPtr(newAttr, pNewAttr.DangerousGetHandle(), false); 

                                    try { 
                                        if (!CAPI.EncodeObject(new IntPtr(CAPI.PKCS_ATTRIBUTE), 
                                                               pNewAttr.DangerousGetHandle(),
                                                               out encodedNewAttribute)) 
                                            throw new CryptographicException(Marshal.GetLastWin32Error());
                                    }
                                    finally {
                                        Marshal.DestroyStructure(pNewAttr.DangerousGetHandle(), typeof(CAPI.CRYPT_ATTRIBUTE)); 
                                        pNewAttr.Dispose();
                                    } 
 
                                    // Finally, add it back.
                                    fixed (byte * pbData = &encodedNewAttribute[0]) { 
                                        CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA addPara = new CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA)));
                                        addPara.dwSignerIndex = (uint) parentIndex;
                                        addPara.blob.cbData = (uint) encodedNewAttribute.Length;
                                        addPara.blob.pbData = new IntPtr(pbData); 

                                        if (!CAPI.CryptMsgControl(hMsg, 
                                                                  0, 
                                                                  CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR,
                                                                  new IntPtr(&addPara))) 
                                            throw new CryptographicException(Marshal.GetLastWin32Error());
                                    }

                                    // Keep alive. 
                                    pbCounterSignatureValue.Dispose();
                                } 
                                catch (CryptographicException) { 
                                    // Roll back.
                                    byte[] encodedAttribute; 
                                    if (CAPI.EncodeObject(new IntPtr(CAPI.PKCS_ATTRIBUTE),
                                                          pAttr,
                                                          out encodedAttribute)) {
                                        fixed (byte * pbData = &encodedAttribute[0]) { 
                                            CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA addPara = new CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA)));
                                            addPara.dwSignerIndex = (uint) parentIndex; 
                                            addPara.blob.cbData = (uint) encodedAttribute.Length; 
                                            addPara.blob.pbData = new IntPtr(pbData);
                                            CAPI.CryptMsgControl(hMsg, 0, CAPI.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, new IntPtr(&addPara)); 
                                        }
                                    }
                                    throw;
                                } 
                            }
 
                            return; 
                        }
 
                        childIndex -= (int) attr.cValue;
                    }
                }
 
                pAttr = new IntPtr((long) pAttr + (long) Marshal.SizeOf(typeof(CAPI.CRYPT_ATTRIBUTE)));
            } 
 
            // Keep alive.
            if (pbCmsgCmsSignerInfo != null && !pbCmsgCmsSignerInfo.IsInvalid) { 
                pbCmsgCmsSignerInfo.Dispose();
            }
            if (pbCmsgSignerInfo != null && !pbCmsgSignerInfo.IsInvalid) {
                pbCmsgSignerInfo.Dispose(); 
            }
 
            throw new CryptographicException(CAPI.CRYPT_E_NO_SIGNER); 
        }
 
        //
        // Private static.
        //
 
        private static unsafe int VerifyCertificate (X509Certificate2 certificate,
                                                     X509Certificate2Collection extraStore) { 
            int dwErrorStatus; 
            int hr = X509Utils.VerifyCertificate(X509Utils.GetCertContext(certificate),
                                                 null, 
                                                 null,
                                                 X509RevocationMode.Online,
                                                 X509RevocationFlag.ExcludeRoot,
                                                 DateTime.Now, 
                                                 new TimeSpan(0, 0, 0),
                                                 extraStore, 
                                                 new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE), 
                                                 new IntPtr(&dwErrorStatus));
            if (hr != CAPI.S_OK) 
                return dwErrorStatus;

            // Check key usages to make sure it is good for signing.
            foreach (X509Extension extension in certificate.Extensions) { 
                if (String.Compare(extension.Oid.Value, CAPI.szOID_KEY_USAGE, StringComparison.OrdinalIgnoreCase) == 0) {
                    X509KeyUsageExtension keyUsage = new X509KeyUsageExtension(); 
                    keyUsage.CopyFrom(extension); 
                    if ((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == 0 &&
                        (keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == 0) { 
                        hr = CAPI.CERT_E_WRONG_USAGE;
                        break;
                    }
                } 
            }
 
            return hr; 
        }
    } 

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class SignerInfoCollection : ICollection {
        private SignerInfo[] m_signerInfos; 

        internal SignerInfoCollection () { 
            m_signerInfos = new SignerInfo[0]; 
        }
 
        internal unsafe SignerInfoCollection (SignedCms signedCms) {
            uint dwSigners = 0;
            uint cbCount = (uint) Marshal.SizeOf(typeof(uint));
            SafeCryptMsgHandle safeCryptMsgHandle = signedCms.GetCryptMsgHandle(); 

            if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, 
                                       CAPI.CMSG_SIGNER_COUNT_PARAM, 
                                       0,
                                       new IntPtr(&dwSigners), 
                                       new IntPtr(&cbCount)))
                throw new CryptographicException(Marshal.GetLastWin32Error());

            SignerInfo[] signerInfos = new SignerInfo[dwSigners]; 
            for (int index = 0; index < dwSigners; index++) {
                uint cbCmsgSignerInfo = 0; 
                if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, 
                                           CAPI.CMSG_SIGNER_INFO_PARAM,
                                           (uint) index, 
                                           IntPtr.Zero,
                                           new IntPtr(&cbCmsgSignerInfo)))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                SafeLocalAllocHandle pbCmsgSignerInfo = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbCmsgSignerInfo));
 
                if (!CAPI.CryptMsgGetParam(safeCryptMsgHandle, 
                                           CAPI.CMSG_SIGNER_INFO_PARAM,
                                           (uint) index, 
                                           pbCmsgSignerInfo,
                                           new IntPtr(&cbCmsgSignerInfo)))
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                signerInfos[index] = new SignerInfo(signedCms, pbCmsgSignerInfo);
            } 
 
            m_signerInfos = signerInfos;
        } 

        internal unsafe SignerInfoCollection (SignedCms signedCms, SignerInfo signerInfo) {
            SignerInfo[] signerInfos = new SignerInfo[0];
 
            int count = 0;
            int index = 0; 
 
            foreach (CryptographicAttributeObject attribute in signerInfo.UnsignedAttributes) {
                if (attribute.Oid.Value == CAPI.szOID_RSA_counterSign) { 
                    count += attribute.Values.Count;
                }
            }
 
            signerInfos = new SignerInfo[count];
 
            foreach (CryptographicAttributeObject attribute in signerInfo.UnsignedAttributes) { 
                if (attribute.Oid.Value == CAPI.szOID_RSA_counterSign) {
                    for (int i = 0; i < attribute.Values.Count; i++) { 
                        AsnEncodedData encodedSignerInfo = (AsnEncodedData) attribute.Values[i];
                        signerInfos[index++] = new SignerInfo(signedCms, signerInfo, encodedSignerInfo.RawData);
                    }
                } 
            }
 
            m_signerInfos = signerInfos; 
        }
 
        public SignerInfo this[int index] {
            get {
                if (index < 0 || index >= m_signerInfos.Length)
                    throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index")); 

                Debug.Assert(m_signerInfos[index] != null); 
                return m_signerInfos[index]; 
            }
        } 

        public int Count {
            get {
                return m_signerInfos.Length; 
            }
        } 
 
        public SignerInfoEnumerator GetEnumerator() {
            return new SignerInfoEnumerator(this); 
        }

        /// 
        IEnumerator IEnumerable.GetEnumerator() { 
            return new SignerInfoEnumerator(this);
        } 
 
        public void CopyTo(Array array, int index) {
            if (array == null) 
                throw new ArgumentNullException("array");
            if (array.Rank != 1)
                throw new ArgumentException(SecurityResources.GetResourceString("Arg_RankMultiDimNotSupported"));
            if (index < 0 || index >= array.Length) 
                throw new ArgumentOutOfRangeException("index", SecurityResources.GetResourceString("ArgumentOutOfRange_Index"));
            if (index + this.Count > array.Length) 
                throw new ArgumentException(SecurityResources.GetResourceString("Argument_InvalidOffLen")); 

            for (int i=0; i < this.Count; i++) { 
                array.SetValue(this[i], index);
                index++;
            }
        } 

        public void CopyTo(SignerInfo[] array, int index) { 
            ((ICollection)this).CopyTo(array, index); 
        }
 
        public bool IsSynchronized {
            get {
                return false;
            } 
        }
 
        public Object SyncRoot { 
            get {
                return this; 
            }
        }
    }
 
    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
    public sealed class SignerInfoEnumerator : IEnumerator { 
        private SignerInfoCollection m_signerInfos; 
        private int m_current;
 
        private SignerInfoEnumerator() {}
        internal SignerInfoEnumerator(SignerInfoCollection signerInfos) {
            m_signerInfos = signerInfos;
            m_current = -1; 
        }
 
        public SignerInfo Current { 
            get {
                return m_signerInfos[m_current]; 
            }
        }

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

        public bool MoveNext() {
            if (m_current == ((int) m_signerInfos.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