Example #1
0
        private bool AcquireServerCredentials(ref byte[] thumbPrint)
        {
            X509Certificate serverCertificate = null;

            if (this.m_CertSelectionDelegate != null)
            {
                X509CertificateCollection localCertificates = new X509CertificateCollection();
                localCertificates.Add(this.m_ServerCertificate);
                serverCertificate = this.m_CertSelectionDelegate(string.Empty, localCertificates, null, new string[0]);
            }
            else
            {
                serverCertificate = this.m_ServerCertificate;
            }
            if (serverCertificate == null)
            {
                throw new NotSupportedException(SR.GetString("net_ssl_io_no_server_cert"));
            }
            X509Certificate2 certificate2 = this.EnsurePrivateKey(serverCertificate);

            if (certificate2 == null)
            {
                throw new NotSupportedException(SR.GetString("net_ssl_io_no_server_cert"));
            }
            byte[] certHash = certificate2.GetCertHash();
            try
            {
                SafeFreeCredentials credentials = SslSessionsCache.TryCachedCredential(certHash, this.m_ProtocolFlags, this.m_EncryptionPolicy);
                if (credentials != null)
                {
                    this.m_CredentialsHandle = credentials;
                    this.m_ServerCertificate = serverCertificate;
                    return(true);
                }
                SecureCredential secureCredential = new SecureCredential(4, certificate2, SecureCredential.Flags.Zero, this.m_ProtocolFlags, this.m_EncryptionPolicy);
                this.m_CredentialsHandle = this.AcquireCredentialsHandle(CredentialUse.Inbound, ref secureCredential);
                thumbPrint = certHash;
                this.m_ServerCertificate = serverCertificate;
            }
            finally
            {
                if (serverCertificate != certificate2)
                {
                    certificate2.Reset();
                }
            }
            return(false);
        }
Example #2
0
        private bool AcquireClientCredentials(ref byte[] thumbPrint)
        {
            X509Certificate certificate = null;
            ArrayList       list        = new ArrayList();

            string[] acceptableIssuers = null;
            bool     flag = false;

            if (this.m_CertSelectionDelegate != null)
            {
                if (acceptableIssuers == null)
                {
                    acceptableIssuers = this.GetIssuers();
                }
                X509Certificate2 remoteCertificate = null;
                try
                {
                    X509Certificate2Collection certificates;
                    remoteCertificate = this.GetRemoteCertificate(out certificates);
                    certificate       = this.m_CertSelectionDelegate(this.m_HostName, this.ClientCertificates, remoteCertificate, acceptableIssuers);
                }
                finally
                {
                    if (remoteCertificate != null)
                    {
                        remoteCertificate.Reset();
                    }
                }
                if (certificate != null)
                {
                    if (this.m_CredentialsHandle == null)
                    {
                        flag = true;
                    }
                    list.Add(certificate);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_got_certificate_from_delegate"));
                    }
                }
                else if (this.ClientCertificates.Count == 0)
                {
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_no_delegate_and_have_no_client_cert"));
                    }
                    flag = true;
                }
                else if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_no_delegate_but_have_client_cert"));
                }
            }
            else if (((this.m_CredentialsHandle == null) && (this.m_ClientCertificates != null)) && (this.m_ClientCertificates.Count > 0))
            {
                certificate = this.ClientCertificates[0];
                flag        = true;
                if (certificate != null)
                {
                    list.Add(certificate);
                }
                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_attempting_restart_using_cert", new object[] { (certificate == null) ? "null" : certificate.ToString(true) }));
                }
            }
            else if ((this.m_ClientCertificates != null) && (this.m_ClientCertificates.Count > 0))
            {
                if (acceptableIssuers == null)
                {
                    acceptableIssuers = this.GetIssuers();
                }
                if (Logging.On)
                {
                    if ((acceptableIssuers == null) || (acceptableIssuers.Length == 0))
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_no_issuers_try_all_certs"));
                    }
                    else
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_server_issuers_look_for_matching_certs", new object[] { acceptableIssuers.Length }));
                    }
                }
                for (int j = 0; j < this.m_ClientCertificates.Count; j++)
                {
                    if ((acceptableIssuers != null) && (acceptableIssuers.Length != 0))
                    {
                        X509Certificate2 certificate3 = null;
                        X509Chain        chain        = null;
                        try
                        {
                            certificate3 = MakeEx(this.m_ClientCertificates[j]);
                            if (certificate3 == null)
                            {
                                continue;
                            }
                            chain = new X509Chain {
                                ChainPolicy = { RevocationMode = X509RevocationMode.NoCheck, VerificationFlags = X509VerificationFlags.IgnoreInvalidName }
                            };
                            chain.Build(certificate3);
                            bool flag2 = false;
                            if (chain.ChainElements.Count > 0)
                            {
                                for (int k = 0; k < chain.ChainElements.Count; k++)
                                {
                                    string issuer = chain.ChainElements[k].Certificate.Issuer;
                                    flag2 = Array.IndexOf <string>(acceptableIssuers, issuer) != -1;
                                    if (flag2)
                                    {
                                        break;
                                    }
                                }
                            }
                            if (!flag2)
                            {
                                continue;
                            }
                        }
                        finally
                        {
                            if (chain != null)
                            {
                                chain.Reset();
                            }
                            if ((certificate3 != null) && (certificate3 != this.m_ClientCertificates[j]))
                            {
                                certificate3.Reset();
                            }
                        }
                    }
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_selected_cert", new object[] { this.m_ClientCertificates[j].ToString(true) }));
                    }
                    list.Add(this.m_ClientCertificates[j]);
                }
            }
            X509Certificate2 certificate4 = null;

            certificate = null;
            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_n_certs_after_filtering", new object[] { list.Count }));
                if (list.Count != 0)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_finding_matching_certs"));
                }
            }
            for (int i = 0; i < list.Count; i++)
            {
                certificate  = list[i] as X509Certificate;
                certificate4 = this.EnsurePrivateKey(certificate);
                if (certificate4 != null)
                {
                    break;
                }
                certificate  = null;
                certificate4 = null;
            }
            try
            {
                byte[] buffer = (certificate4 == null) ? null : certificate4.GetCertHash();
                SafeFreeCredentials credentials = SslSessionsCache.TryCachedCredential(buffer, this.m_ProtocolFlags, this.m_EncryptionPolicy);
                if ((flag && (credentials == null)) && (certificate4 != null))
                {
                    if (certificate != certificate4)
                    {
                        certificate4.Reset();
                    }
                    buffer       = null;
                    certificate4 = null;
                    certificate  = null;
                }
                if (credentials != null)
                {
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, SR.GetString("net_log_using_cached_credential"));
                    }
                    this.m_CredentialsHandle         = credentials;
                    this.m_SelectedClientCertificate = certificate;
                    return(true);
                }
                SecureCredential secureCredential = new SecureCredential(4, certificate4, SecureCredential.Flags.NoDefaultCred | SecureCredential.Flags.ValidateManual, this.m_ProtocolFlags, this.m_EncryptionPolicy);
                this.m_CredentialsHandle = this.AcquireCredentialsHandle(CredentialUse.Outbound, ref secureCredential);
                thumbPrint = buffer;
                this.m_SelectedClientCertificate = certificate;
            }
            finally
            {
                if ((certificate4 != null) && (certificate != certificate4))
                {
                    certificate4.Reset();
                }
            }
            return(false);
        }
Example #3
0
        private SecurityStatus GenerateToken(byte[] input, int offset, int count, ref byte[] output)
        {
            if ((offset < 0) || (offset > ((input == null) ? 0 : input.Length)))
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if ((count < 0) || (count > ((input == null) ? 0 : (input.Length - offset))))
            {
                throw new ArgumentOutOfRangeException("count");
            }
            SecurityBuffer inputBuffer = null;

            SecurityBuffer[] inputBuffers = null;
            if (input != null)
            {
                inputBuffer  = new SecurityBuffer(input, offset, count, BufferType.Token);
                inputBuffers = new SecurityBuffer[] { inputBuffer, new SecurityBuffer(null, 0, 0, BufferType.Empty) };
            }
            SecurityBuffer outputBuffer = new SecurityBuffer(null, BufferType.Token);
            int            num          = 0;
            bool           flag         = false;

            byte[] thumbPrint = null;
            try
            {
                do
                {
                    thumbPrint = null;
                    if (this.m_RefreshCredentialNeeded)
                    {
                        flag = this.m_ServerMode ? this.AcquireServerCredentials(ref thumbPrint) : this.AcquireClientCredentials(ref thumbPrint);
                    }
                    if (this.m_ServerMode)
                    {
                        num = SSPIWrapper.AcceptSecurityContext(GlobalSSPI.SSPISecureChannel, ref this.m_CredentialsHandle, ref this.m_SecurityContext, (ContextFlags.AcceptStream | ContextFlags.AllocateMemory | ContextFlags.Confidentiality | ContextFlags.SequenceDetect | ContextFlags.ReplayDetect) | (this.m_RemoteCertRequired ? ContextFlags.MutualAuth : ContextFlags.Zero), Endianness.Native, inputBuffer, outputBuffer, ref this.m_Attributes);
                    }
                    else if (inputBuffer == null)
                    {
                        num = SSPIWrapper.InitializeSecurityContext(GlobalSSPI.SSPISecureChannel, ref this.m_CredentialsHandle, ref this.m_SecurityContext, this.m_Destination, ContextFlags.AcceptIdentify | ContextFlags.AllocateMemory | ContextFlags.Confidentiality | ContextFlags.SequenceDetect | ContextFlags.ReplayDetect, Endianness.Native, inputBuffer, outputBuffer, ref this.m_Attributes);
                    }
                    else
                    {
                        num = SSPIWrapper.InitializeSecurityContext(GlobalSSPI.SSPISecureChannel, this.m_CredentialsHandle, ref this.m_SecurityContext, this.m_Destination, ContextFlags.AcceptIdentify | ContextFlags.AllocateMemory | ContextFlags.Confidentiality | ContextFlags.SequenceDetect | ContextFlags.ReplayDetect, Endianness.Native, inputBuffers, outputBuffer, ref this.m_Attributes);
                    }
                }while (flag && (this.m_CredentialsHandle == null));
            }
            finally
            {
                if (this.m_RefreshCredentialNeeded)
                {
                    this.m_RefreshCredentialNeeded = false;
                    if (this.m_CredentialsHandle != null)
                    {
                        this.m_CredentialsHandle.Close();
                    }
                    if ((!flag && (this.m_SecurityContext != null)) && (!this.m_SecurityContext.IsInvalid && !this.m_CredentialsHandle.IsInvalid))
                    {
                        SslSessionsCache.CacheCredential(this.m_CredentialsHandle, thumbPrint, this.m_ProtocolFlags, this.m_EncryptionPolicy);
                    }
                }
            }
            output = outputBuffer.token;
            return((SecurityStatus)num);
        }
Example #4
0
        /*++
         *  GenerateToken - Called after each successive state
         *  in the Client - Server handshake.  This function
         *  generates a set of bytes that will be sent next to
         *  the server.  The server responds, each response,
         *  is pass then into this function, again, and the cycle
         *  repeats until successful connection, or failure.
         *
         *  Input:
         *      input  - bytes from the wire
         *      output - ref to byte [], what we will send to the
         *          server in response
         *  Return:
         *      errorCode - an SSPI error code
         * --*/
        private SecurityStatusPal GenerateToken(byte[] input, int offset, int count, ref byte[] output)
        {
#if TRACE_VERBOSE
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::GenerateToken, _refreshCredentialNeeded = " + _refreshCredentialNeeded);
#endif

            if (offset < 0 || offset > (input == null ? 0 : input.Length))
            {
                GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::GenerateToken", "Argument 'offset' out of range.");
                throw new ArgumentOutOfRangeException("offset");
            }

            if (count < 0 || count > (input == null ? 0 : input.Length - offset))
            {
                GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::GenerateToken", "Argument 'count' out of range.");
                throw new ArgumentOutOfRangeException("count");
            }

            SecurityBuffer   incomingSecurity        = null;
            SecurityBuffer[] incomingSecurityBuffers = null;

            if (input != null)
            {
                incomingSecurity        = new SecurityBuffer(input, offset, count, SecurityBufferType.Token);
                incomingSecurityBuffers = new SecurityBuffer[]
                {
                    incomingSecurity,
                    new SecurityBuffer(null, 0, 0, SecurityBufferType.Empty)
                };
            }

            SecurityBuffer outgoingSecurity = new SecurityBuffer(null, SecurityBufferType.Token);

            SecurityStatusPal errorCode = 0;

            bool   cachedCreds = false;
            byte[] thumbPrint  = null;

            //
            // Looping through ASC or ISC with potentially cached credential that could have been
            // already disposed from a different thread before ISC or ASC dir increment a cred ref count.
            //
            try
            {
                do
                {
                    thumbPrint = null;
                    if (_refreshCredentialNeeded)
                    {
                        cachedCreds = _serverMode
                                        ? AcquireServerCredentials(ref thumbPrint)
                                        : AcquireClientCredentials(ref thumbPrint);
                    }

                    if (_serverMode)
                    {
                        errorCode = SslStreamPal.AcceptSecurityContext(
                            ref _credentialsHandle,
                            ref _securityContext,
                            incomingSecurity,
                            outgoingSecurity,
                            _remoteCertRequired);
                    }
                    else
                    {
                        if (incomingSecurity == null)
                        {
                            errorCode = SslStreamPal.InitializeSecurityContext(
                                ref _credentialsHandle,
                                ref _securityContext,
                                _destination,
                                incomingSecurity,
                                outgoingSecurity);
                        }
                        else
                        {
                            errorCode = SslStreamPal.InitializeSecurityContext(
                                _credentialsHandle,
                                ref _securityContext,
                                _destination,
                                incomingSecurityBuffers,
                                outgoingSecurity);
                        }
                    }
                } while (cachedCreds && _credentialsHandle == null);
            }
            finally
            {
                if (_refreshCredentialNeeded)
                {
                    _refreshCredentialNeeded = false;

                    //
                    // Assuming the ISC or ASC has referenced the credential,
                    // we want to call dispose so to decrement the effective ref count.
                    //
                    if (_credentialsHandle != null)
                    {
                        _credentialsHandle.Dispose();
                    }

                    //
                    // This call may bump up the credential reference count further.
                    // Note that thumbPrint is retrieved from a safe cert object that was possible cloned from the user passed cert.
                    //
                    if (!cachedCreds && _securityContext != null && !_securityContext.IsInvalid && _credentialsHandle != null && !_credentialsHandle.IsInvalid)
                    {
                        SslSessionsCache.CacheCredential(_credentialsHandle, thumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);
                    }
                }
            }

            output = outgoingSecurity.token;

#if TRACE_VERBOSE
            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::GenerateToken()", Interop.MapSecurityStatus((uint)errorCode));
#endif
            return((SecurityStatusPal)errorCode);
        }
Example #5
0
        //
        // Acquire Server Side Certificate information and set it on the class.
        //
        private bool AcquireServerCredentials(ref byte[] thumbPrint)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials");

            X509Certificate localCertificate = null;
            bool            cachedCred       = false;

            if (_certSelectionDelegate != null)
            {
                X509CertificateCollection tempCollection = new X509CertificateCollection();
                tempCollection.Add(_serverCertificate);
                localCertificate = _certSelectionDelegate(string.Empty, tempCollection, null, Array.Empty <string>());
                GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials() Use delegate selected Cert");
            }
            else
            {
                localCertificate = _serverCertificate;
            }

            if (localCertificate == null)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            // SECURITY: Accessing X509 cert Credential is disabled for semitrust.
            // We no longer need to demand for unmanaged code permissions.
            // EnsurePrivateKey should do the right demand for us.
            X509Certificate2 selectedCert = EnsurePrivateKey(localCertificate);

            if (selectedCert == null)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            GlobalLog.Assert(localCertificate.Equals(selectedCert), "AcquireServerCredentials()|'selectedCert' does not match 'localCertificate'.");

            //
            // Note selectedCert is a safe ref possibly cloned from the user passed Cert object
            //
            byte[] guessedThumbPrint = selectedCert.GetCertHash();
            try
            {
                SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);

                if (cachedCredentialHandle != null)
                {
                    _credentialsHandle = cachedCredentialHandle;
                    _serverCertificate = localCertificate;
                    cachedCred         = true;
                }
                else
                {
                    _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode);
                    thumbPrint         = guessedThumbPrint;
                    _serverCertificate = localCertificate;
                }
            }
            finally
            {
                // An extra cert could have been created, dispose it now.
                if ((object)localCertificate != (object)selectedCert)
                {
                    selectedCert.Dispose();
                }
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireServerCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle));
            return(cachedCred);
        }
Example #6
0
        /*++
         *  AcquireCredentials - Attempts to find Client Credential
         *  Information, that can be sent to the server.  In our case,
         *  this is only Client Certificates, that we have Credential Info.
         *
         *  How it works:
         *      case 0: Cert Selection delegate is present
         *              Always use its result as the client cert answer.
         *              Try to use cached credential handle whenever feasible.
         *              Do not use cached anonymous creds if the delegate has returned null
         *              and the collection is not empty (allow responding with the cert later).
         *
         *      case 1: Certs collection is empty
         *              Always use the same statically acquired anonymous SSL Credential
         *
         *      case 2: Before our Connection with the Server
         *              If we have a cached credential handle keyed by first X509Certificate
         **content** in the passed collection, then we use that cached
         *              credential and hoping to restart a session.
         *
         *              Otherwise create a new anonymous (allow responding with the cert later).
         *
         *      case 3: After our Connection with the Server (i.e. during handshake or re-handshake)
         *              The server has requested that we send it a Certificate then
         *              we Enumerate a list of server sent Issuers trying to match against
         *              our list of Certificates, the first match is sent to the server.
         *
         *              Once we got a cert we again try to match cached credential handle if possible.
         *              This will not restart a session but helps minimizing the number of handles we create.
         *
         *      In the case of an error getting a Certificate or checking its private Key we fall back
         *      to the behavior of having no certs, case 1.
         *
         *  Returns: True if cached creds were used, false otherwise.
         *
         * --*/

        private bool AcquireClientCredentials(ref byte[] thumbPrint)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials");

            // Acquire possible Client Certificate information and set it on the handle.
            X509Certificate clientCertificate = null;            // This is a candidate that can come from the user callback or be guessed when targeting a session restart.
            ArrayList       filteredCerts     = new ArrayList(); // This is an intermediate client certs collection that try to use if no selectedCert is available yet.

            string[] issuers = null;                             // This is a list of issuers sent by the server, only valid is we do know what the server cert is.

            bool sessionRestartAttempt = false;                  // If true and no cached creds we will use anonymous creds.

            if (_certSelectionDelegate != null)
            {
                issuers = GetRequestCertificateAuthorities();

                GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() calling CertificateSelectionCallback");

                X509Certificate2 remoteCert = null;
                try
                {
                    X509Certificate2Collection dummyCollection;
                    remoteCert        = CertificateValidationPal.GetRemoteCertificate(_securityContext, out dummyCollection);
                    clientCertificate = _certSelectionDelegate(_hostName, ClientCertificates, remoteCert, issuers);
                }
                finally
                {
                    if (remoteCert != null)
                    {
                        remoteCert.Dispose();
                    }
                }


                if (clientCertificate != null)
                {
                    if (_credentialsHandle == null)
                    {
                        sessionRestartAttempt = true;
                    }

                    filteredCerts.Add(clientCertificate);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_got_certificate_from_delegate);
                    }
                }
                else
                {
                    if (ClientCertificates.Count == 0)
                    {
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_and_have_no_client_cert);
                        }

                        sessionRestartAttempt = true;
                    }
                    else
                    {
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.Web, this, SR.net_log_no_delegate_but_have_client_cert);
                        }
                    }
                }
            }
            else if (_credentialsHandle == null && _clientCertificates != null && _clientCertificates.Count > 0)
            {
                // This is where we attempt to restart a session by picking the FIRST cert from the collection.
                // Otherwise it is either server sending a client cert request or the session is renegotiated.
                clientCertificate     = ClientCertificates[0];
                sessionRestartAttempt = true;
                if (clientCertificate != null)
                {
                    filteredCerts.Add(clientCertificate);
                }

                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_attempting_restart_using_cert, (clientCertificate == null ? "null" : clientCertificate.ToString(true))));
                }
            }
            else if (_clientCertificates != null && _clientCertificates.Count > 0)
            {
                //
                // This should be a server request for the client cert sent over currently anonymous sessions.
                //
                issuers = GetRequestCertificateAuthorities();

                if (Logging.On)
                {
                    if (issuers == null || issuers.Length == 0)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.net_log_no_issuers_try_all_certs);
                    }
                    else
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_server_issuers_look_for_matching_certs, issuers.Length));
                    }
                }

                for (int i = 0; i < _clientCertificates.Count; ++i)
                {
                    //
                    // Make sure we add only if the cert matches one of the issuers.
                    // If no issuers were sent and then try all client certs starting with the first one.
                    //
                    if (issuers != null && issuers.Length != 0)
                    {
                        X509Certificate2 certificateEx = null;
                        X509Chain        chain         = null;
                        try
                        {
                            certificateEx = MakeEx(_clientCertificates[i]);
                            if (certificateEx == null)
                            {
                                continue;
                            }

                            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() root cert:" + certificateEx.Issuer);
                            chain = new X509Chain();

                            chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName;
                            chain.Build(certificateEx);
                            bool found = false;

                            //
                            // We ignore any errors happened with chain.
                            //
                            if (chain.ChainElements.Count > 0)
                            {
                                for (int ii = 0; ii < chain.ChainElements.Count; ++ii)
                                {
                                    string issuer = chain.ChainElements[ii].Certificate.Issuer;
                                    found = Array.IndexOf(issuers, issuer) != -1;
                                    if (found)
                                    {
                                        GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() matched:" + issuer);
                                        break;
                                    }
                                    GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() no match:" + issuer);
                                }
                            }

                            if (!found)
                            {
                                continue;
                            }
                        }
                        finally
                        {
                            if (chain != null)
                            {
                                chain.Dispose();
                            }

                            if (certificateEx != null && (object)certificateEx != (object)_clientCertificates[i])
                            {
                                certificateEx.Dispose();
                            }
                        }
                    }

                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_selected_cert, _clientCertificates[i].ToString(true)));
                    }

                    filteredCerts.Add(_clientCertificates[i]);
                }
            }

            bool             cachedCred   = false;     // This is a return result from this method.
            X509Certificate2 selectedCert = null;      // This is a final selected cert (ensured that it does have private key with it).

            clientCertificate = null;

            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, this, SR.Format(SR.net_log_n_certs_after_filtering, filteredCerts.Count));
                if (filteredCerts.Count != 0)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.net_log_finding_matching_certs);
                }
            }

            //
            // ATTN: When the client cert was returned by the user callback OR it was guessed AND it has no private key,
            //       THEN anonymous (no client cert) credential will be used.
            //
            // SECURITY: Accessing X509 cert Credential is disabled for semitrust.
            // We no longer need to demand for unmanaged code permissions.
            // EnsurePrivateKey should do the right demand for us.
            for (int i = 0; i < filteredCerts.Count; ++i)
            {
                clientCertificate = filteredCerts[i] as X509Certificate;
                if ((selectedCert = EnsurePrivateKey(clientCertificate)) != null)
                {
                    break;
                }

                clientCertificate = null;
                selectedCert      = null;
            }

            GlobalLog.Assert(((object)clientCertificate == (object)selectedCert) || clientCertificate.Equals(selectedCert), "AcquireClientCredentials()|'selectedCert' does not match 'clientCertificate'.");

            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Selected Cert = " + (selectedCert == null ? "null" : selectedCert.Subject));
            try
            {
                // Try to locate cached creds first.
                //
                // SECURITY: selectedCert ref if not null is a safe object that does not depend on possible **user** inherited X509Certificate type.
                //
                byte[] guessedThumbPrint = selectedCert == null ? null : selectedCert.GetCertHash();
                SafeFreeCredentials cachedCredentialHandle = SslSessionsCache.TryCachedCredential(guessedThumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);

                // We can probably do some optimization here. If the selectedCert is returned by the delegate
                // we can always go ahead and use the certificate to create our credential
                // (instead of going anonymous as we do here).
                if (sessionRestartAttempt && cachedCredentialHandle == null && selectedCert != null)
                {
                    GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials() Reset to anonymous session.");

                    // IIS does not renegotiate a restarted session if client cert is needed.
                    // So we don't want to reuse **anonymous** cached credential for a new SSL connection if the client has passed some certificate.
                    // The following block happens if client did specify a certificate but no cached creds were found in the cache.
                    // Since we don't restart a session the server side can still challenge for a client cert.
                    if ((object)clientCertificate != (object)selectedCert)
                    {
                        selectedCert.Dispose();
                    }

                    guessedThumbPrint = null;
                    selectedCert      = null;
                    clientCertificate = null;
                }

                if (cachedCredentialHandle != null)
                {
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.Web, SR.net_log_using_cached_credential);
                    }

                    _credentialsHandle         = cachedCredentialHandle;
                    _selectedClientCertificate = clientCertificate;
                    cachedCred = true;
                }
                else
                {
                    _credentialsHandle = SslStreamPal.AcquireCredentialsHandle(selectedCert, _sslProtocols, _encryptionPolicy, _serverMode);

                    thumbPrint = guessedThumbPrint; // Delay until here in case something above threw.
                    _selectedClientCertificate = clientCertificate;
                }
            }
            finally
            {
                // An extra cert could have been created, dispose it now.
                if (selectedCert != null && (object)clientCertificate != (object)selectedCert)
                {
                    selectedCert.Dispose();
                }
            }

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::AcquireClientCredentials, cachedCreds = " + cachedCred.ToString(), Logging.ObjectToString(_credentialsHandle));
            return(cachedCred);
        }