SignerInfo.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / ManagedLibraries / Security / System / Security / Cryptography / Pkcs / SignerInfo.cs / 1305376 / 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.Runtime.Versioning; 
    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;
        [SecurityCritical] 
        private SafeLocalAllocHandle        m_pbCmsgSignerInfo;
        private CAPI.CMSG_SIGNER_INFO       m_cmsgSignerInfo; 
 
        //
        // Constructors. 
        //

        private SignerInfo () {}
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        [SecurityCritical] 
        internal 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)); 
        }
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [SecuritySafeCritical]
        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 {
            [SecuritySafeCritical]
            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 { 
            [SecuritySafeCritical]
            get {
                if (m_signedAttributes == null)
                    m_signedAttributes = new CryptographicAttributeObjectCollection(m_cmsgSignerInfo.AuthAttrs); 

                return m_signedAttributes; 
            } 
        }
 
        public CryptographicAttributeObjectCollection UnsignedAttributes {
            [SecuritySafeCritical]
            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);
        }
 
        [SecuritySafeCritical]
        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; 
        }
 
        [SecuritySafeCritical] 
        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);
        }

        [SecuritySafeCritical] 
        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.
        // 

        [SecuritySafeCritical] 
        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;
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        [SecuritySafeCritical]
        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.CAPISafe.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.CAPISafe.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.CAPISafe.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(); 
        }
 
        [SecuritySafeCritical]
        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.
        // 

        [SecuritySafeCritical] 
        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]; 
        }

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

            if (!CAPI.CAPISafe.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.CAPISafe.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.CAPISafe.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;
        }
 
        [SecuritySafeCritical]
        internal 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