我应该从sslstream authenticateAsClient中的LocalCerticateSelection回调中返回什么?

时间:2015-04-29 14:04:12

标签: sslstream

我有一个我自己签名生成的证书,然后由供应商签名。我必须连接到此供应商并使用证书进行身份验证。当我执行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);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

只需确保从回调中返回的证书具有私钥。 您可以通过将证书的PrivateKey属性设置为相应自签名密钥的PrivateKey属性来完成此操作。 如果从证书存储中读取CA颁发的密钥,请确保打开存储ReadWrite而不是ReadOnly。