Beispiel #1
0
        /// <summary>
        /// Creates a Windows SID Claim and adds to collection of claims.
        /// </summary>
        private void AddPrimarySidClaim(List<Claim> instanceClaims)
        {
            // special case the anonymous identity.
            if (_safeTokenHandle.IsInvalid)
                return;

            SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
            try
            {
                safeAllocHandle = GetTokenInformation(_safeTokenHandle, TokenInformationClass.TokenUser);
                Interop.SID_AND_ATTRIBUTES user = (Interop.SID_AND_ATTRIBUTES)Marshal.PtrToStructure<Interop.SID_AND_ATTRIBUTES>(safeAllocHandle.DangerousGetHandle());
                uint mask = Interop.SecurityGroups.SE_GROUP_USE_FOR_DENY_ONLY;

                SecurityIdentifier sid = new SecurityIdentifier(user.Sid, true);
                Claim claim;
                if (user.Attributes == 0)
                {
                    claim = new Claim(ClaimTypes.PrimarySid, sid.Value, ClaimValueTypes.String, _issuerName, _issuerName, this);
                    claim.Properties.Add(ClaimTypes.WindowsSubAuthority, sid.IdentifierAuthority.ToString());
                    instanceClaims.Add(claim);
                }
                else if ((user.Attributes & mask) == Interop.SecurityGroups.SE_GROUP_USE_FOR_DENY_ONLY)
                {
                    claim = new Claim(ClaimTypes.DenyOnlyPrimarySid, sid.Value, ClaimValueTypes.String, _issuerName, _issuerName, this);
                    claim.Properties.Add(ClaimTypes.WindowsSubAuthority, sid.IdentifierAuthority.ToString());
                    instanceClaims.Add(claim);
                }
            }
            finally
            {
                safeAllocHandle.Dispose();
            }
        }
        private static SafeLocalAllocHandle GetTokenInformation(SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass)
        {
            SafeLocalAllocHandle invalidHandle = SafeLocalAllocHandle.InvalidHandle;
            uint returnLength = (uint)Marshal.SizeOf(typeof(uint));
            bool flag         = Win32Native.GetTokenInformation(tokenHandle, (uint)tokenInformationClass, invalidHandle, 0, out returnLength);
            int  errorCode    = Marshal.GetLastWin32Error();
            int  num3         = errorCode;

            if (num3 == 6)
            {
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
            }
            if ((num3 != 0x18) && (num3 != 0x7a))
            {
                throw new SecurityException(Win32Native.GetMessage(errorCode));
            }
            IntPtr sizetdwBytes = new IntPtr((long)returnLength);

            invalidHandle.Dispose();
            invalidHandle = Win32Native.LocalAlloc(0, sizetdwBytes);
            if ((invalidHandle == null) || invalidHandle.IsInvalid)
            {
                throw new OutOfMemoryException();
            }
            invalidHandle.Initialize((ulong)returnLength);
            if (!Win32Native.GetTokenInformation(tokenHandle, (uint)tokenInformationClass, invalidHandle, returnLength, out returnLength))
            {
                throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
            }
            return(invalidHandle);
        }
Beispiel #3
0
        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;
        }
Beispiel #4
0
        /*private*/
        partial void InternalDisposeCore()
        {
            if (_handlePingV4 != null)
            {
                _handlePingV4.Dispose();
                _handlePingV4 = null;
            }

            if (_handlePingV6 != null)
            {
                _handlePingV6.Dispose();
                _handlePingV6 = null;
            }

            UnregisterWaitHandle();

            if (_pingEvent != null)
            {
                _pingEvent.Dispose();
                _pingEvent = null;
            }

            if (_replyBuffer != null)
            {
                _replyBuffer.Dispose();
                _replyBuffer = null;
            }
        }
Beispiel #5
0
        private void CoSign(CmsSigner signer, bool silent)
        {
            CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer, silent);

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

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

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

            // Finally, add certs to bag of certs.
            PkcsUtils.AddCertsToMessage(m_safeCryptMsgHandle, Certificates, PkcsUtils.CreateBagOfCertificates(signer));
        }
Beispiel #6
0
 // Releases the unmanaged memory after ping completion.
 private void FreeUnmanagedStructures()
 {
     if (_requestBuffer != null)
     {
         _requestBuffer.Dispose();
         _requestBuffer = null;
     }
 }
Beispiel #7
0
        internal AlgorithmIdentifier(CAPI.CERT_PUBLIC_KEY_INFO keyInfo)
        {
            SafeLocalAllocHandle pKeyInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO))));

            Marshal.StructureToPtr(keyInfo, pKeyInfo.DangerousGetHandle(), false);
            int keyLength = (int)CAPI.CAPISafe.CertGetPublicKeyLength(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, pKeyInfo.DangerousGetHandle());

            byte[] parameters = new byte[keyInfo.Algorithm.Parameters.cbData];
            if (parameters.Length > 0)
            {
                Marshal.Copy(keyInfo.Algorithm.Parameters.pbData, parameters, 0, parameters.Length);
            }
            Marshal.DestroyStructure(pKeyInfo.DangerousGetHandle(), typeof(CAPI.CERT_PUBLIC_KEY_INFO));
            pKeyInfo.Dispose();
            Reset(Oid.FromOidValue(keyInfo.Algorithm.pszObjId, OidGroup.PublicKeyAlgorithm), keyLength, parameters);
        }
Beispiel #8
0
        private static byte[] Encode(DateTime signingTime)
        {
            long ft = signingTime.ToFileTimeUtc();
            SafeLocalAllocHandle pbSigningTime = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(Int64))));

            Marshal.WriteInt64(pbSigningTime.DangerousGetHandle(), ft);

            byte[] encodedSigningTime = new byte[0];
            if (!CAPI.EncodeObject(CAPI.szOID_RSA_signingTime, pbSigningTime.DangerousGetHandle(), out encodedSigningTime))
            {
                throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            pbSigningTime.Dispose();

            return(encodedSigningTime);
        }
Beispiel #9
0
        private static SafeLocalAllocHandle GetTokenInformation(SafeAccessTokenHandle tokenHandle, TokenInformationClass tokenInformationClass)
        {
            SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
            uint dwLength = (uint)sizeof(uint);
            bool result   = Interop.Advapi32.GetTokenInformation(tokenHandle,
                                                                 (uint)tokenInformationClass,
                                                                 safeLocalAllocHandle,
                                                                 0,
                                                                 out dwLength);
            int dwErrorCode = Marshal.GetLastWin32Error();

            switch (dwErrorCode)
            {
            case Interop.Errors.ERROR_BAD_LENGTH:
            // special case for TokenSessionId. Falling through
            case Interop.Errors.ERROR_INSUFFICIENT_BUFFER:
                // ptrLength is an [In] param to LocalAlloc
                UIntPtr ptrLength = new UIntPtr(dwLength);
                safeLocalAllocHandle.Dispose();
                safeLocalAllocHandle = Interop.Kernel32.LocalAlloc(0, ptrLength);
                if (safeLocalAllocHandle == null || safeLocalAllocHandle.IsInvalid)
                {
                    throw new OutOfMemoryException();
                }
                safeLocalAllocHandle.Initialize(dwLength);

                result = Interop.Advapi32.GetTokenInformation(tokenHandle,
                                                              (uint)tokenInformationClass,
                                                              safeLocalAllocHandle,
                                                              dwLength,
                                                              out dwLength);
                if (!result)
                {
                    throw new SecurityException(new Win32Exception().Message);
                }
                break;

            case Interop.Errors.ERROR_INVALID_HANDLE:
                throw new ArgumentException(SR.Argument_InvalidImpersonationToken);

            default:
                throw new SecurityException(new Win32Exception(dwErrorCode).Message);
            }
            return(safeLocalAllocHandle);
        }
Beispiel #10
0
        // Cancels pending async requests, closes the handles.
        private void InternalDispose()
        {
            _disposeRequested = true;

            if (Interlocked.CompareExchange(ref _status, Disposed, Free) != Free)
            {
                // Already disposed, or Finish will call Dispose again once Free.
                return;
            }

            if (_handlePingV4 != null)
            {
                _handlePingV4.Dispose();
                _handlePingV4 = null;
            }

            if (_handlePingV6 != null)
            {
                _handlePingV6.Dispose();
                _handlePingV6 = null;
            }

            UnregisterWaitHandle();

            if (pingEvent != null)
            {
                pingEvent.Dispose();
                pingEvent = null;
            }

            if (_replyBuffer != null)
            {
                _replyBuffer.Dispose();
                _replyBuffer = null;
            }

            if (_asyncFinished != null)
            {
                _asyncFinished.Dispose();
                _asyncFinished = null;
            }
        }
Beispiel #11
0
        private void Decode()
        {
            uint cbDecoded = 0;
            SafeLocalAllocHandle pbDecoded = null;

            if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS_UTC_TIME),
                                   RawData,
                                   out pbDecoded,
                                   out cbDecoded))
            {
                throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            long signingTime = Marshal.ReadInt64(pbDecoded.DangerousGetHandle());

            pbDecoded.Dispose();

            m_signingTime = DateTime.FromFileTimeUtc(signingTime);
            m_decoded     = true;
        }
Beispiel #12
0
        /// <summary>
        /// Creates a collection of SID claims that represent the users groups.
        /// </summary>
        private void AddGroupSidClaims(List <Claim> instanceClaims)
        {
            // special case the anonymous identity.
            if (_safeTokenHandle.IsInvalid)
            {
                return;
            }

            SafeLocalAllocHandle safeAllocHandle             = SafeLocalAllocHandle.InvalidHandle;
            SafeLocalAllocHandle safeAllocHandlePrimaryGroup = SafeLocalAllocHandle.InvalidHandle;

            try
            {
                // Retrieve the primary group sid
                safeAllocHandlePrimaryGroup = GetTokenInformation(_safeTokenHandle, TokenInformationClass.TokenPrimaryGroup);
                Interop.TOKEN_PRIMARY_GROUP primaryGroup    = (Interop.TOKEN_PRIMARY_GROUP)Marshal.PtrToStructure <Interop.TOKEN_PRIMARY_GROUP>(safeAllocHandlePrimaryGroup.DangerousGetHandle());
                SecurityIdentifier          primaryGroupSid = new SecurityIdentifier(primaryGroup.PrimaryGroup, true);

                // only add one primary group sid
                bool foundPrimaryGroupSid = false;

                // Retrieve all group sids, primary group sid is one of them
                safeAllocHandle = GetTokenInformation(_safeTokenHandle, TokenInformationClass.TokenGroups);
                int    count             = Marshal.ReadInt32(safeAllocHandle.DangerousGetHandle());
                IntPtr pSidAndAttributes = new IntPtr((long)safeAllocHandle.DangerousGetHandle() + (long)Marshal.OffsetOf <Interop.TOKEN_GROUPS>("Groups"));
                Claim  claim;
                for (int i = 0; i < count; ++i)
                {
                    Interop.SID_AND_ATTRIBUTES group = (Interop.SID_AND_ATTRIBUTES)Marshal.PtrToStructure <Interop.SID_AND_ATTRIBUTES>(pSidAndAttributes);
                    uint mask = Interop.SecurityGroups.SE_GROUP_ENABLED | Interop.SecurityGroups.SE_GROUP_LOGON_ID | Interop.SecurityGroups.SE_GROUP_USE_FOR_DENY_ONLY;
                    SecurityIdentifier groupSid = new SecurityIdentifier(group.Sid, true);

                    if ((group.Attributes & mask) == Interop.SecurityGroups.SE_GROUP_ENABLED)
                    {
                        if (!foundPrimaryGroupSid && StringComparer.Ordinal.Equals(groupSid.Value, primaryGroupSid.Value))
                        {
                            claim = new Claim(ClaimTypes.PrimaryGroupSid, groupSid.Value, ClaimValueTypes.String, _issuerName, _issuerName, this);
                            claim.Properties.Add(ClaimTypes.WindowsSubAuthority, groupSid.IdentifierAuthority.ToString());
                            instanceClaims.Add(claim);
                            foundPrimaryGroupSid = true;
                        }
                        //Primary group sid generates both regular groupsid claim and primary groupsid claim
                        claim = new Claim(ClaimTypes.GroupSid, groupSid.Value, ClaimValueTypes.String, _issuerName, _issuerName, this);
                        claim.Properties.Add(ClaimTypes.WindowsSubAuthority, groupSid.IdentifierAuthority.ToString());
                        instanceClaims.Add(claim);
                    }
                    else if ((group.Attributes & mask) == Interop.SecurityGroups.SE_GROUP_USE_FOR_DENY_ONLY)
                    {
                        if (!foundPrimaryGroupSid && StringComparer.Ordinal.Equals(groupSid.Value, primaryGroupSid.Value))
                        {
                            claim = new Claim(ClaimTypes.DenyOnlyPrimaryGroupSid, groupSid.Value, ClaimValueTypes.String, _issuerName, _issuerName, this);
                            claim.Properties.Add(ClaimTypes.WindowsSubAuthority, groupSid.IdentifierAuthority.ToString());
                            instanceClaims.Add(claim);
                            foundPrimaryGroupSid = true;
                        }
                        //Primary group sid generates both regular groupsid claim and primary groupsid claim
                        claim = new Claim(ClaimTypes.DenyOnlySid, groupSid.Value, ClaimValueTypes.String, _issuerName, _issuerName, this);
                        claim.Properties.Add(ClaimTypes.WindowsSubAuthority, groupSid.IdentifierAuthority.ToString());
                        instanceClaims.Add(claim);
                    }
                    pSidAndAttributes = new IntPtr((long)pSidAndAttributes + Marshal.SizeOf <Interop.SID_AND_ATTRIBUTES>());
                }
            }
            finally
            {
                safeAllocHandle.Dispose();
                safeAllocHandlePrimaryGroup.Dispose();
            }
        }
Beispiel #13
0
        internal AlgorithmIdentifier(CAPI.CRYPT_ALGORITHM_IDENTIFIER algorithmIdentifier)
        {
            int  keyLength    = 0;
            uint cbParameters = 0;
            SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle;

            byte[] parameters = new byte[0];

            uint algId = X509Utils.OidToAlgId(algorithmIdentifier.pszObjId);

            if (algId == CAPI.CALG_RC2)
            {
                if (algorithmIdentifier.Parameters.cbData > 0)
                {
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS_RC2_CBC_PARAMETERS),
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData,
                                           out pbParameters,
                                           out cbParameters))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    CAPI.CRYPT_RC2_CBC_PARAMETERS rc2Parameters = (CAPI.CRYPT_RC2_CBC_PARAMETERS)Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPT_RC2_CBC_PARAMETERS));
                    switch (rc2Parameters.dwVersion)
                    {
                    case CAPI.CRYPT_RC2_40BIT_VERSION:
                        keyLength = 40;
                        break;

                    case CAPI.CRYPT_RC2_56BIT_VERSION:
                        keyLength = 56;
                        break;

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

                    if (cbParameters > Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB)))
                    {
                        CAPI.CRYPTOAPI_BLOB blob = (CAPI.CRYPTOAPI_BLOB)Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));

                        if (algId == CAPI.CALG_RC4)
                        {
                            if (blob.cbData > 0)
                            {
                                parameters = new byte[blob.cbData];
                                Marshal.Copy(blob.pbData, parameters, 0, parameters.Length);
                            }
                        }
                        else
                        {
                            // This should be the same as the RC4 code, but for compatibility
                            // * Allocate an array as big as the CRYPTOAPI_BLOB
                            // * Copy in the cbData value
                            // * Copy in the (pbData) value
                            //
                            // But don't copy in the pbData pointer value (or, rather, clear it out),
                            // among other things it makes decoding the same contents into two
                            // different EnvelopedCms objects say the parameters were different.
                            parameters = new byte[cbParameters];
                            Marshal.Copy(pbParameters.DangerousGetHandle(), parameters, 0, parameters.Length);
                            Array.Clear(parameters, sizeof(uint), (int)(parameters.Length - blob.cbData - sizeof(uint)));
                        }
                    }
                }

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

            Reset(Oid.FromOidValue(algorithmIdentifier.pszObjId, OidGroup.All), keyLength, parameters);
            pbParameters.Dispose();
        }
Beispiel #14
0
        private unsafe void Sign(CmsSigner signer, bool silent)
        {
            SafeCryptMsgHandle safeCryptMsgHandle = null;

            CAPI.CMSG_SIGNED_ENCODE_INFO signedEncodeInfo = new CAPI.CMSG_SIGNED_ENCODE_INFO(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNED_ENCODE_INFO)));
            SafeCryptProvHandle          safeCryptProvHandle;

            CAPI.CMSG_SIGNER_ENCODE_INFO signerEncodeInfo = PkcsUtils.CreateSignerEncodeInfo(signer, silent, out safeCryptProvHandle);

            byte[] encodedMessage = null;
            try {
                SafeLocalAllocHandle pSignerEncodeInfo = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_SIGNER_ENCODE_INFO))));

                try {
                    Marshal.StructureToPtr(signerEncodeInfo, pSignerEncodeInfo.DangerousGetHandle(), false);
                    X509Certificate2Collection bagOfCerts         = PkcsUtils.CreateBagOfCertificates(signer);
                    SafeLocalAllocHandle       pEncodedBagOfCerts = PkcsUtils.CreateEncodedCertBlob(bagOfCerts);

                    signedEncodeInfo.cSigners     = 1;
                    signedEncodeInfo.rgSigners    = pSignerEncodeInfo.DangerousGetHandle();
                    signedEncodeInfo.cCertEncoded = (uint)bagOfCerts.Count;
                    if (bagOfCerts.Count > 0)
                    {
                        signedEncodeInfo.rgCertEncoded = pEncodedBagOfCerts.DangerousGetHandle();
                    }

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

                    if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid)
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }


                    if (this.ContentInfo.Content.Length > 0)
                    {
                        if (!CAPI.CAPISafe.CryptMsgUpdate(safeCryptMsgHandle, this.ContentInfo.pContent, (uint)this.ContentInfo.Content.Length, true))
                        {
                            throw new CryptographicException(Marshal.GetLastWin32Error());
                        }
                    }

                    // Retrieve encoded message.
                    encodedMessage = PkcsUtils.GetContent(safeCryptMsgHandle);
                    safeCryptMsgHandle.Dispose();

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

            // Re-open to decode.
            safeCryptMsgHandle = OpenToDecode(encodedMessage, this.ContentInfo, this.Detached);
            if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid)
            {
                m_safeCryptMsgHandle.Dispose();
            }
            m_safeCryptMsgHandle = safeCryptMsgHandle;
            GC.KeepAlive(signer);
        }
        internal AlgorithmIdentifier(CAPI.CRYPT_ALGORITHM_IDENTIFIER algorithmIdentifier)
        {
            int  keyLength    = 0;
            uint cbParameters = 0;
            SafeLocalAllocHandle pbParameters = SafeLocalAllocHandle.InvalidHandle;

            byte[] parameters = new byte[0];

            uint algId = X509Utils.OidToAlgId(algorithmIdentifier.pszObjId);

            if (algId == CAPI.CALG_RC2)
            {
                if (algorithmIdentifier.Parameters.cbData > 0)
                {
                    if (!CAPI.DecodeObject(new IntPtr(CAPI.PKCS_RC2_CBC_PARAMETERS),
                                           algorithmIdentifier.Parameters.pbData,
                                           algorithmIdentifier.Parameters.cbData,
                                           out pbParameters,
                                           out cbParameters))
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }

                    CAPI.CRYPT_RC2_CBC_PARAMETERS rc2Parameters = (CAPI.CRYPT_RC2_CBC_PARAMETERS)Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPT_RC2_CBC_PARAMETERS));
                    switch (rc2Parameters.dwVersion)
                    {
                    case CAPI.CRYPT_RC2_40BIT_VERSION:
                        keyLength = 40;
                        break;

                    case CAPI.CRYPT_RC2_56BIT_VERSION:
                        keyLength = 56;
                        break;

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

                    if (cbParameters > 0)
                    {
                        if (algId == CAPI.CALG_RC4)
                        {
                            CAPI.CRYPTOAPI_BLOB saltBlob = (CAPI.CRYPTOAPI_BLOB)Marshal.PtrToStructure(pbParameters.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));
                            if (saltBlob.cbData > 0)
                            {
                                parameters = new byte[saltBlob.cbData];
                                Marshal.Copy(saltBlob.pbData, parameters, 0, parameters.Length);
                            }
                        }
                        else
                        {
                            parameters = new byte[cbParameters];
                            Marshal.Copy(pbParameters.DangerousGetHandle(), parameters, 0, parameters.Length);
                        }
                    }
                }

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

            Reset(Oid.FromOidValue(algorithmIdentifier.pszObjId, OidGroup.All), keyLength, parameters);
            pbParameters.Dispose();
        }
Beispiel #16
0
        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++)
            {
                checked {
                    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);
        }
Beispiel #17
0
        private unsafe void Verify(X509Certificate2Collection extraStore, X509Certificate2 certificate, bool verifySignatureOnly)
        {
            checked {
                // 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();
            }
        }