C#SSLStream读取,流读取tcpclient

时间:2015-08-15 13:05:27

标签: c# .net ssl

我正在编写一个需要通过SSL / TLS进行通信的应用程序。

当我使用以下代码时,设备连接,但我总是读取0字节:

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

        do
        {
            // Read the client's test message.
            bytes = sslStream.Read(buffer, 0, buffer.Length);

            sslStream.Flush();

            // 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);

当我使用此代码时,我能够读取字节但显然不能解码它们。这段代码读取正确的字节数,SSl出了什么问题,我不会得到任何字节?

            var client = server.AcceptTcpClient();
            Console.WriteLine("Connected!");

            // Get a stream object for reading and writing
            var stream = client.GetStream();

            // Loop to receive all the data sent by the client. 
            while (stream.Read(bytes, 0, bytes.Length) != 0)
            {
                var base64 = Convert.ToBase64String(bytes);
                Console.WriteLine(base64);

更大的样本,我认为这是来自MSDN:

    static void ProcessClient(TcpClient client)
    {
        // A client has connected. Create the  
        // SslStream using the client's network stream.
        SslStream sslStream = new SslStream(client.GetStream(), false);
        // Authenticate the server but don't require the client to authenticate. 
        try
        {
            sslStream.AuthenticateAsServer(serverCertificate,
                false, SslProtocols.Tls, true);
            // Display the properties and settings for the authenticated stream.
            DisplaySecurityLevel(sslStream);
            DisplaySecurityServices(sslStream);
            DisplayCertificateInformation(sslStream);
            DisplayStreamProperties(sslStream);

            // Set timeouts for the read and write to 5 seconds.
            sslStream.ReadTimeout = 5000;
            sslStream.WriteTimeout = 5000;
            // Read a message from the client.   
            Console.WriteLine("Waiting for client message...");
            string messageData = ReadMessage(sslStream);
            Console.WriteLine("Received: {0}", messageData);

            // Write a message to the client. 
            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
        {
            // The client stream will be closed with the sslStream 
            // because we specified this behavior when creating 
            // the sslStream.
            sslStream.Close();
            client.Close();
        }
    }

    static string ReadMessage(SslStream sslStream)
    {
        // Read the  message sent by the client. 
        // The client signals the end of the message using the 
        // "<EOF>" marker.
        byte[] buffer = new byte[2048];
        StringBuilder messageData = new StringBuilder();
        int bytes = -1;

        do
        {
            // Read the client's test message.
            bytes = sslStream.Read(buffer, 0, buffer.Length);

            sslStream.Flush();

            // 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 or an empty message. 
            if (messageData.ToString().IndexOf("<EOF>") != -1)
            {
                break;
            }
        } while (bytes != 0);

        return messageData.ToString();
    }

2 个答案:

答案 0 :(得分:0)

我最终确实解决了这个问题,并希望为每个人发布答案。证书是自签名的,因此“无效”,但这在设备上很常见。我必须创建一个始终返回 true 的验证回调。

我忘记在哪里找到这段代码了,但我认为是 MSDN

    // The following method is invoked by the RemoteCertificateValidationDelegate.
    private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        //DisplayCertificateInformation((SslStream)sender);

        if (sslPolicyErrors == SslPolicyErrors.None)
            return true;

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

        // Allow this client to communicate with unauthenticated servers.
        return true;
    }

我最终扩展了 TcpClient 类:

public class TlsTcpClient : TcpClient
{
    public TlsTcpClient()
    {

    }

    public TlsTcpClient(string ip, int port) : base(ip, port)
    {

    }

    public new SslStream GetStream()
    {
        var sslStream = new SslStream(base.GetStream(),
            true,
            ValidateServerCertificate,
            null);

        try
        {
            sslStream.AuthenticateAsClient("Certname goes here");
        }
        catch (AuthenticationException e)
        {
            Debug.WriteLine($"Exception: {e.Message}");
            if (e.InnerException != null)
            {
                Debug.WriteLine($"Inner exception: {e.InnerException.Message}");
            }
            Debug.WriteLine("Authentication failed - closing the connection.");
            return null;
        }

        return sslStream;
    }
  }

答案 1 :(得分:-1)

下面找到一个通过sslstream original source here进行通信的客户端服务器示例。

服务器

static void Main(string[] args)
    {
        var _certificate = "certificate-string";
        TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 13000);

        server.Start();

        TcpClient client = server.AcceptTcpClient();

        SslStream stream = new SslStream(client.GetStream(), false, VerifyClientCertificate, null);

        X509Certificate2 certificate = new X509Certificate2(Convert.FromBase64String(_certificate));

        stream.AuthenticateAsServer(certificate, false, 
            SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13, false);

        if (stream.RemoteCertificate != null)
        {
            System.Console.WriteLine(stream.RemoteCertificate.Subject);
        }
        else
        {
            System.Console.WriteLine("No client certificate.");
        }

        StreamReader reader = new StreamReader(stream);
        StreamWriter writer = new StreamWriter(stream);

        bool clientClose = false;
        while (!System.Console.KeyAvailable)
        {
            System.Console.WriteLine("Waiting for data...");
            string line = reader.ReadLine();
            System.Console.WriteLine("Received: {0}", line);
             
            if (line == "close")
            {
                clientClose = true;
                break;
            }

            writer.WriteLine(line);
            writer.Flush();
        }

        if (!clientClose) System.Console.ReadKey();

        stream.Close();
        server.Stop();
    }

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

客户

static void Main(string[] args)
    {
        var _certificate = "certificate-string";
        TcpClient client = new TcpClient("127.0.0.1", 13000);

        SslStream stream = new SslStream(client.GetStream(), false, VerifyServerCertificate, null);

        X509Certificate2 certificate = new X509Certificate2(Convert.FromBase64String(_certificate));

        stream.AuthenticateAsClient("127.0.0.1", new X509Certificate2Collection(certificate), 
            SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13, false);

        StreamReader reader = new StreamReader(stream);
        StreamWriter writer = new StreamWriter(stream);

        while (true)
        {
            string line = System.Console.ReadLine();
            writer.WriteLine(line);
            writer.Flush();
            if (line == "close") break;
            line = reader.ReadLine();
            System.Console.WriteLine("Received: {0}", line);
        }

        stream.Close();
        client.Close();
    }

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