Что я должен вернуть из обратного вызова LocalCerticateSelection в sslstream authenticationAsClient?

У меня есть сертификат, который я создал как самоподписанный, а затем подписал поставщик. Я должен подключиться к этому поставщику и пройти аутентификацию с помощью сертификата. Когда я делаю AuthenticateAsClient, мой обратный вызов LocalCertificateSelection вызывается с параметром validIssuers, установленным для того, кто подписал сертификат. Какой сертификат я должен возвращать из обратного вызова? Когда я возвращаю сертификат, выданный поставщиком, я получаю сообщение об ошибке, потому что сертификат не отправлен на сервер. Я использую следующий код.

namespace TestClientAuthenticateHttps {
    using System;
    using System.Linq;
    using System.Net;
    using System.Net.Security;
    using System.Net.Sockets;
    using System.Security.Authentication;
    using System.Security.Cryptography.X509Certificates;

    class Program {
        private readonly X509Certificate2Collection _certs;
        private TcpClient _client;
        private SslStream _sslStream;
        private const string Host = "smr-staging.surescripts.net";
        private const string SsSerial = "40 1f c1 ea 00 00 00 00 02 44";
        private const SslProtocols EnabledSslProtocols = SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;

        private static void Main() {
            var program = new Program();
            program.Execute();
        }
        private Program() {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            certStore.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
            _certs = certStore.Certificates.Find(X509FindType.FindBySerialNumber, SsSerial, false);
            certStore.Close();
        }
        private void Execute() {
            ConnectToHost();
            try {
                OpenSslConnection();
                DoAuthentication();
            } catch (Exception e) {
                do {
                    Console.WriteLine(e.Message);
                    Console.WriteLine(e.StackTrace);
                    e = e.InnerException;
                } while (e != null);
            } finally {
                _sslStream.Close();
            }
            Console.ReadLine();
        }

        private void DoAuthentication() {
            try {
                _sslStream.AuthenticateAsClient(Host, _certs, EnabledSslProtocols, true);
            } catch (Exception) {
                Console.WriteLine($"Host is ({Host})");
                Console.WriteLine($"_certs = ");
                _certs.Cast<X509Certificate>().ToList().ForEach(Console.WriteLine);
                throw;
            }
        }

        private void OpenSslConnection() {
            _sslStream = new SslStream(_client.GetStream(), false, RemoteCertificateValidate,
                LocalCertificateSelection, EncryptionPolicy.AllowNoEncryption);
        }

        private static bool RemoteCertificateValidate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
            return true;
        }

        private static X509Certificate LocalCertificateSelection(object sender, string host,
            X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) {
            Console.WriteLine($"Selecting certificate for ({host})");
            var acceptable = acceptableIssuers.Select(s => new X500DistinguishedName(s).Name?.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)).ToList();
            Console.WriteLine("Acceptable issuers.");
            acceptable.ForEach(Console.WriteLine);
            Console.WriteLine("Local certificate Selected");
            var result = acceptableIssuers.Length == 0 ? localCertificates[0] : localCertificates?.Cast<X509Certificate2>().First(
                c => acceptable.Any(n => n.Equals(c.IssuerName.Name?.Trim(), StringComparison.InvariantCultureIgnoreCase))
                );
            Console.WriteLine(result);
            return result;
        }
        private void ConnectToHost() {
            _client = new TcpClient(Host, 443);
        }
    }
}

person Fila Kolodny    schedule 29.04.2015    source источник


Ответы (1)


Просто убедитесь, что сертификат, возвращенный из обратного вызова, имеет закрытый ключ. Это можно сделать, задав для свойства PrivateKey сертификата значение свойства PrivateKey соответствующего самозаверяющего ключа. При чтении ключа, выданного ЦС, из хранилища сертификатов убедитесь, что хранилище открыто для чтения, а не для чтения.

person Fila Kolodny    schedule 29.04.2015