Exemple #1
0
        protected X509Certificate SelectClientCertificate(string[] acceptableIssuers)
        {
            if (Settings.DisallowUnauthenticatedCertificateRequest && !IsAuthenticated)
            {
                return(null);
            }

            if (RemoteCertificate == null)
            {
                throw new TlsException(AlertDescription.InternalError, "Cannot request client certificate before receiving one from the server.");
            }

            /*
             * We need to pass null to the user selection callback during the initial handshake, to allow the callback to distinguish
             * between an authenticated and unauthenticated session.
             */
            X509Certificate certificate;
            var             selected = certificateValidator.SelectClientCertificate(
                TargetHost, ClientCertificates, IsAuthenticated ? RemoteCertificate : null, acceptableIssuers, out certificate);

            if (selected)
            {
                return(certificate);
            }

            if (ClientCertificates == null || ClientCertificates.Count == 0)
            {
                return(null);
            }

            /*
             * .NET actually scans the entire collection to ensure the selected certificate has a private key in it.
             *
             * However, since we do not support private key retrieval from the key store, we require all certificates
             * to have a private key in them (explicitly or implicitly via OS X keychain lookup).
             */
            if (acceptableIssuers == null || acceptableIssuers.Length == 0)
            {
                return(ClientCertificates [0]);
            }

            // Copied from the referencesource implementation in referencesource/System/net/System/Net/_SecureChannel.cs.
            for (int i = 0; i < ClientCertificates.Count; i++)
            {
                var certificate2 = ClientCertificates[i] as X509Certificate2;
                if (certificate2 == null)
                {
                    continue;
                }

                X509Chain chain = null;
                try {
                    chain = new X509Chain();
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreInvalidName;
                    chain.Build(certificate2);

                    //
                    // We ignore any errors happened with chain.
                    // Consider: try to locate the "best" client cert that has no errors and the lognest validity internal
                    //
                    if (chain.ChainElements.Count == 0)
                    {
                        continue;
                    }
                    for (int ii = 0; ii < chain.ChainElements.Count; ++ii)
                    {
                        var issuer = chain.ChainElements[ii].Certificate.Issuer;
                        if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                        {
                            return(certificate2);
                        }
                    }
                } catch {
                    ;                     // ignore errors
                } finally {
                    if (chain != null)
                    {
                        chain.Reset();
                    }
                }
            }

            // No certificate matches.
            return(null);
        }