【问题标题】:How can I get/store client certificate using Ssl Stream?如何使用 Ssl Stream 获取/存储客户端证书?
【发布时间】:2016-05-26 11:44:53
【问题描述】:

我已经使用MSDN sslstream Article 创建了 TCP 客户端/服务器应用程序。客户端和服务器都正常工作。我还为客户端和服务器附加了 ssl 证书。

当我运行客户端和服务器程序时,服务器总是定义“RemoteCertificate=null”。我想读取客户端证书并复制/存储该证书以进行存储。

我也有使用X509Store 类存储证书的演示程序。现在唯一的问题是获取客户端证书。

这是服务器的代码:

using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.IO;

namespace Examples.System.Net
{
    public sealed class SslTcpServer
    {
        static X509Certificate serverCertificate = null;

        public static void RunServer(string certificate)
        {
            serverCertificate = X509Certificate.CreateFromCertFile(certificate);

            TcpListener listener = new TcpListener(IPAddress.Any, 8080);
            listener.Start();
            while (true)
            {
                Console.WriteLine("Waiting for a client to connect...");

                TcpClient client = listener.AcceptTcpClient();
                ProcessClient(client);
            }
        }
        static void ProcessClient(TcpClient client)
        {

            SslStream sslStream = new SslStream(
                client.GetStream(), false);

            try
            {
                sslStream.AuthenticateAsServer(serverCertificate,
                    false, SslProtocols.Tls, true);

                DisplaySecurityLevel(sslStream);
                DisplaySecurityServices(sslStream);
                DisplayCertificateInformation(sslStream);
                DisplayStreamProperties(sslStream);


                sslStream.ReadTimeout = 5000;
                sslStream.WriteTimeout = 5000;

                Console.WriteLine("Waiting for client message...");
                string messageData = ReadMessage(sslStream);
                Console.WriteLine("Received: {0}", messageData);


                byte[] message = Encoding.UTF8.GetBytes("Hello from the server.<EOF>");
                Console.WriteLine("Sending hello message.");
                sslStream.Write(message);
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
                if (e.InnerException != null)
                {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                Console.WriteLine("Authentication failed - closing the connection.");
                sslStream.Close();
                client.Close();
                return;
            }
            finally
            {

                sslStream.Close();
                client.Close();
            }
        }
        static string ReadMessage(SslStream sslStream)
        {

            byte[] buffer = new byte[2048];
            StringBuilder messageData = new StringBuilder();
            int bytes = -1;
            do
            {

                bytes = sslStream.Read(buffer, 0, buffer.Length);


                Decoder decoder = Encoding.UTF8.GetDecoder();
                char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                decoder.GetChars(buffer, 0, bytes, chars, 0);
                messageData.Append(chars);

                if (messageData.ToString().IndexOf("<EOF>") != -1)
                {
                    break;
                }
            } while (bytes != 0);

            return messageData.ToString();
        }
        static void DisplaySecurityLevel(SslStream stream)
        {
            Console.WriteLine("Cipher: {0} strength {1}", stream.CipherAlgorithm, stream.CipherStrength);
            Console.WriteLine("Hash: {0} strength {1}", stream.HashAlgorithm, stream.HashStrength);
            Console.WriteLine("Key exchange: {0} strength {1}", stream.KeyExchangeAlgorithm, stream.KeyExchangeStrength);
            Console.WriteLine("Protocol: {0}", stream.SslProtocol);
        }
        static void DisplaySecurityServices(SslStream stream)
        {
            Console.WriteLine("Is authenticated: {0} as server? {1}", stream.IsAuthenticated, stream.IsServer);
            Console.WriteLine("IsSigned: {0}", stream.IsSigned);
            Console.WriteLine("Is Encrypted: {0}", stream.IsEncrypted);
        }
        static void DisplayStreamProperties(SslStream stream)
        {
            Console.WriteLine("Can read: {0}, write {1}", stream.CanRead, stream.CanWrite);
            Console.WriteLine("Can timeout: {0}", stream.CanTimeout);
        }
        static void DisplayCertificateInformation(SslStream stream)
        {
            Console.WriteLine("Certificate revocation list checked: {0}", stream.CheckCertRevocationStatus);

            X509Certificate localCertificate = stream.LocalCertificate;
            if (stream.LocalCertificate != null)
            {
                Console.WriteLine("Local cert was issued to {0} and is valid from {1} until {2}.",
                    localCertificate.Subject,
                    localCertificate.GetEffectiveDateString(),
                    localCertificate.GetExpirationDateString());
            }
            else
            {
                Console.WriteLine("Local certificate is null.");
            }

            X509Certificate remoteCertificate = stream.RemoteCertificate;
            if (stream.RemoteCertificate != null)
            {
                Console.WriteLine("Remote cert was issued to {0} and is valid from {1} until {2}.",
                    remoteCertificate.Subject,
                    remoteCertificate.GetEffectiveDateString(),
                    remoteCertificate.GetExpirationDateString());
            }
            else
            {
                Console.WriteLine("Remote certificate is null.");
            }
        }
        public static void Main(string[] args)
        {
            string certificate = "c:/Test.cer";
            SslTcpServer.RunServer(certificate);
        }
    }
}

这是客户端的代码:

using System;
using System.Collections;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.IO;

namespace Examples.System.Net
{
    public class SslTcpClient
    {
        private static Hashtable certificateErrors = new Hashtable();

        // The following method is invoked by the RemoteCertificateValidationDelegate. 
        public static bool ValidateServerCertificate(
              object sender,
              X509Certificate certificate,
              X509Chain chain,
              SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;

            Console.WriteLine("Certificate error: {0}", sslPolicyErrors);

            // Do not allow this client to communicate with unauthenticated servers. 
            return false;
        }
        public static void RunClient(string machineName, string serverName)
        {
            // Create a TCP/IP client socket. 
            // machineName is the host running the server application.
            TcpClient client = new TcpClient(machineName, 8080);
            Console.WriteLine("Client connected.");
            // Create an SSL stream that will close the client's stream.
            SslStream sslStream = new SslStream(
                client.GetStream(),
                false,
                new RemoteCertificateValidationCallback(ValidateServerCertificate),
                null
                );
            // The server name must match the name on the server certificate. 
            try
            {
                sslStream.AuthenticateAsClient(serverName);
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
                if (e.InnerException != null)
                {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                Console.WriteLine("Authentication failed - closing the connection.");
                client.Close();
                return;
            }

            X509Certificate remoteCertificate = sslStream.RemoteCertificate;
            if (sslStream.RemoteCertificate != null)
            {
                Console.WriteLine("Remote cert was issued to {0} and is valid from {1} until {2}.",
                    remoteCertificate.Subject,
                    remoteCertificate.GetEffectiveDateString(),
                    remoteCertificate.GetExpirationDateString());
            }
            else
            {
                Console.WriteLine("Remote certificate is null.");
            }

            // Encode a test message into a byte array. 
            // Signal the end of the message using the "<EOF>".
            byte[] messsage = Encoding.UTF8.GetBytes("Hello from the client.<EOF>");
            // Send hello message to the server. 
            sslStream.Write(messsage);
            sslStream.Flush();
            // Read message from the server. 
            string serverMessage = ReadMessage(sslStream);
            Console.WriteLine("Server says: {0}", serverMessage);
            // Close the client connection.
            client.Close();
            Console.WriteLine("Client closed.");
        }
        static string ReadMessage(SslStream sslStream)
        {
            // Read the  message sent by the server. 
            // The end of the message is signaled using the 
            // "<EOF>" marker.
            byte[] buffer = new byte[2048];
            StringBuilder messageData = new StringBuilder();
            int bytes = -1;
            do
            {
                bytes = sslStream.Read(buffer, 0, buffer.Length);

                // Use Decoder class to convert from bytes to UTF8 
                // in case a character spans two buffers.
                Decoder decoder = Encoding.UTF8.GetDecoder();
                char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                decoder.GetChars(buffer, 0, bytes, chars, 0);
                messageData.Append(chars);
                // Check for EOF. 
                if (messageData.ToString().IndexOf("<EOF>") != -1)
                {
                    break;
                }
            } while (bytes != 0);

            return messageData.ToString();
        }
        public static void Main(string[] args)
        {
            string serverCertificateName = null;
            string machineName = null;
            /*
            // User can specify the machine name and server name. 
            // Server name must match the name on the server's certificate. 
            machineName = args[0];
            if (args.Length < 2)
            {
                serverCertificateName = machineName;
            }
            else
            {
                serverCertificateName = args[1];
            }*/
            machineName = "127.0.0.1";
            serverCertificateName = "David-PC";// tried Test, LocalMachine and 127.0.0.1
            SslTcpClient.RunClient(machineName, serverCertificateName);
            Console.ReadKey();
        }
    }
}

有人帮忙吗?谢谢!

【问题讨论】:

    标签: c# asp.net security ssl


    【解决方案1】:

    在我们交谈之后,您可以使用 SSL Stream 进行身份验证。要实际提取服务器公钥,您需要尝试另一种解决方案。因此,要回答您的问题,您无法获取公钥或将其存储在 ssl 流中。您需要关注 this 之类的信息。

    此外,您将无法存储私钥,只能存储公钥。这就是密钥对如何工作的本质。

    【讨论】:

    • +1 感谢您的支持。所以无法获得客户端证书?并且使用 MSDN Ssl 流文章(问题中提供的链接),我总是收到“RemoteCertificate=null”。另一个问题是:如何获得客户的公共证书?@Nick McGinnis
    • @Jaimesh 可以使用他们的公钥是的,你能发布一些你的代码,这样我就可以看到你在做什么。如果代码运行正确,我认为问题出在客户端提供的证书上。如果您将 MSDN 页面中的示例用于 ssl 流,则您正在设置 RemoteCertificate = stream.remotecertificate。如果客户没有证书或提供了错误的证书,则可能导致 null 问题。
    • 是的。我正在使用 MSDN 页面的示例。没有编辑任何一行代码。我只是把代码放在有问题的地方,以便您更好地理解。
    • @ Nick McGinnis :我还想在客户端读取服务器的公钥/私钥。我在客户端使用了 RemoteCertificate 并成功读取服务器证书,但无法读取服务器的公钥/私钥。
    • 我将您的代码与 MSDN 页面代码进行比较,您还向客户端代码添加了另一个 RemoteCertificate。这是空的部分吗?尝试回到 MSDN 示例中的代码,首先让它工作。查看您的代码,您的服务器似乎正在拉取客户端证书,但客户端可以拉取服务器。这可能是服务器上的安全设置。所以我会尝试只做示例首先显示的内容,然后尝试添加。
    【解决方案2】:

    在服务器代码更改中:

    slStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, true);
    

    slStream.AuthenticateAsServer(serverCertificate, true, SslProtocols.Tls, true);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-29
      • 2013-08-04
      • 1970-01-01
      • 2010-10-16
      相关资源
      最近更新 更多