【问题标题】:Connect to openssl server using .Net使用 .Net 连接到 openssl 服务器
【发布时间】:2018-01-26 00:35:18
【问题描述】:

我得到了一个正在侦听客户端连接的服务器应用程序。以下 openssl 命令确实连接...

openssl s_client -key provided.key -cert provided.crt -CAfile provided.pem -connect 127.0.0.1:59123

我有一个创建 TcpClient 并尝试对 SslStream 进行身份验证的 C# 应用程序。 BeginAuthenticateAsClient 需要证书。显然,提供的 .crt 文件还不够好,因为需要涉及提供的 .key 。我尝试使用 openssl 从 .crt 和 .key 文件创建一个 .pfx 文件,但这不起作用(文件已创建但服务器关闭了连接)。模仿 .net 中的 open ssl 命令并不太难,但我还没有在网上找到任何可以工作甚至接近我想要做的东西。有谁知道如何做到这一点,或者我应该使用不同的方法吗? 附言第三方软件不是一个真正的选择。

【问题讨论】:

  • 你有没有找到解决这个@Hendrik的方法?我目前有类似的问题。
  • 很遗憾没有。我仍在为此苦苦挣扎。我导入了 openssl C# 包装器,但找不到任何有关如何使用它来实际连接到服务器的信息。可以找到大量有关创建密钥的信息,但没有任何关于使用它来实际连接的信息。
  • 我找到了解决问题的方法。我只是将RemoteCertificateValidationCallback 设置为始终返回true。显然不是生产的正确方法,但有助于测试目的。我将在下面发布我的解决方案,这可能不是您问题的解决方案,但希望对您有所帮助。

标签: c# ssl client-certificates x509certificate2 mutual-authentication


【解决方案1】:
openssl pkcs12 -export -out provided.pfx -inkey provided.key -in provided.crt

...

var coll = new X509Certificate2Collection();
var cert = new X509Certificate2("provided.pfx", "WhateverPasswordYouGaveIt");
coll.Add(cert);

// do TcpClient stuff
var sslStream = new SslStream(tcpClient.GetStream());
const SslProtocols allowedProtocols = SslProtocols.Tls12 | SslProtocols.Tls11;
sslStream.AuthenticateAsClient("127.0.0.1", coll, allowedProtocols, checkCertificateRevocation: true);

对于 -CAFile 等效项,您需要执行自定义回调并将 chain.ChainElements[chain.ChainElements.Length - 1].Certificate 中的证书与您期望的证书进行比较。

【讨论】:

  • 感谢 bartonjs。我几乎正在这样做,服务器关闭了我的连接。如果指定拒绝的原因会很好,但是当我调用 EndAuthenticateAsClient 时,我只会得到 ole“远程方已关闭传输流”。
  • openssl 命令工作并连接。我在 C# 中以编程方式尝试它,但它没有连接。你的建议和我正在做的唯一区别是我是异步的。
  • 好的,这就是我感到困惑的地方。服务器需要客户端的私钥吗?服务器设置为不要求客户端拥有证书。那么如何在客户端提供没有证书的密钥呢?
  • 服务器不需要私钥。它需要证书(公共数据)和客户端来证明它拥有私钥。我建议使用openssl s_server 主持一个会话并尝试连接,OpenSSL 应该报告哪里出了问题。
  • 这就是我对整个 SSL 事情的无知发挥作用的地方。正如您所建议的,我将 openssl s_server 与提供的服务器密钥和证书文件一起使用,并尝试使用我的软件进行连接。我在服务器端收到以下错误: 3524:error:1408A0C1:SSLroutines:ssl3_get_client_hello:no shared cipher:.\ssl\s3 _srvr.c:1411: 但是...如果我使用 openssl 和我提供的客户端密钥进行连接和crt,我连接正常。我在 C# 中缺少一些东西。
【解决方案2】:

如前所述,这仅用于测试目的,因为验证服务器证书不应该只返回 true。

SslStream 测试类:

    public string TestingSSL(string sessionId)
    {
        TcpClient client = new TcpClient("name of the server", port);

        //Create certificate
        var collection = new X509Certificate2Collection();

        var certificate = new X509Certificate2("provided.pfx", "Passwordyouchoosewhencreatingthe.pfx", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
        collection.Add(certificate);

        const SslProtocols allowedProtocols = SslProtocols.Tls12 | SslProtocols.Tls11;
        // Create an SSL stream that will close the client's stream.
        SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificateTrue), null);

        // The server name must match the name on the server certificate.
        try
        {
            sslStream.AuthenticateAsClient("name of the server", collection, allowedProtocols, checkCertificateRevocation: true);
        }
        catch (AuthenticationException e)
        {
            if (e.InnerException != null)
            {
                return e.InnerException.ToString();
            }
        }

        // Read message from the server.
        string serverMessage = ServerResponseMessage(sslStream);

        byte[] sessionBill = Encoding.UTF8.GetBytes("sessions.bill\r\n");
        byte[] sessionBillId = Encoding.UTF8.GetBytes($",session_uuid,{sessionId}\r\n");

        // Send command to the server. 
        sslStream.Write(sessionBill, 0, sessionBill.Length);
        sslStream.Flush();
        sslStream.Write(sessionBillId, 0, sessionBillId.Length);
        sslStream.Flush();

        string sessionBillResponseMessage = ServerResponseMessage(sslStream);

        // Close the client connection.
        client.Close();

        return sessionBillResponseMessage;
    }


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


    static string ServerResponseMessage(SslStream sslStream)
    {     
        byte[] buffer = new byte[2048];
        StringBuilder messageData = new StringBuilder();

        int bytes = -1;

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

        return messageData.ToString();
    }

【讨论】:

  • 感谢 M0rty,只要服务器使用 .NET 就可以使用,但是,我的服务器使用的是 openssl,但似乎没有任何效果。
猜你喜欢
  • 2012-10-29
  • 2016-05-28
  • 1970-01-01
  • 2023-02-01
  • 2017-01-11
  • 2019-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多