Java和C#应用程序之间的SSL通信

5
我的目标是在Java服务器和使用C#编写的客户端之间建立安全通信。 java服务器代码:
  System.setProperty("javax.net.ssl.keyStore","cert/mySrvKeystore");
  System.setProperty("javax.net.ssl.keyStorePassword","myPassword");

  SSLServerSocketFactory sslserversocketfactory =
            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
  SSLServerSocket sslserversocket =  = (SSLServerSocket) sslserversocketfactory.createServerSocket(2389);

    while(true) {
    System.err.println("server w8 new connection");
     try {

            SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();
            //sslsocket.startHandshake();

            in = sslsocket.getInputStream();
            out = sslsocket.getOutputStream();
            out.flush();

            String response = new String(receiveMessage());
            while (response != "end") {
                System.out.println("Server recv="+response);
                response = new String(receiveMessage());
                sendMessage(("echo="+response).getBytes());
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

一个用C#编写的客户端:

        client = new TcpClient() { SendTimeout = 5000, ReceiveTimeout = 5000 };
        IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(host), port);

        client.Connect(serverEndPoint);
        client.NoDelay = true;
        Console.WriteLine("Client connected.");

        // Create an SSL stream that will close the client's stream.
        SslStream sslStream = new SslStream(client.GetStream(), false, ValidateServerCertificate, null);
        // The server name must match the name on the server certificate.
        try
        {
            sslStream.AuthenticateAsClient("someName");
        }
        catch (AuthenticationException error)
        {
            Console.WriteLine("Exception: {0}", error.Message);
            if (error.InnerException != null)
            {
                Console.WriteLine("Inner exception: {0}", error.InnerException.Message);
            }
            Console.WriteLine("Authentication failed - closing the connection.");
            client.Close();
            return;
        }

        ASCIIEncoding ascii = new ASCIIEncoding();
        SendData(ascii.GetBytes("Hello World"));     

并且。
    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;
    }

我遇到了以下错误:在C#中。
 A first chance exception of type "System.Security.Authentication.AuthenticationException" occurred in System.dll
 Certificate error: RemoteCertificateChainErrors
 Exception: The remote certificate is invalid according to the validation procedure.
 Authentication failed - closing the connection.

我知道问题可能是我使用了不同类型的证书,但我不知道如何在Java中创建一个带有X509Certificate的标准sslServerSocket。有人能帮我提供好的例子或者一些建议吗?
附言:我正在查找bouncycastle库,因为它具有Java和C#实现,但我想使用标准库和语言的内置功能。

这有点类似于StackOverflow上的另一个问题,但我不能发评论。问题:x509 Creating a certificate without BouncyCastle 这里有一个链接,描述了如何做到这一点:Creating an x509 Certificate in Java - ry8806
谢谢,这确实帮助我生成了X509证书,但是现在我怎样把它绑定到Java中的SSLServerSocket上呢? - savionok
@ry8806,我不确定这对此有什么帮助,因为似乎没有在应用程序内生成证书的要求。使用工具(例如keytool)应该更容易。 - Bruno
2
啊,回忆。(我在SO上的第一个问题之一) - Scott Chamberlain
@savionok 我认为这个链接可能会帮助你将x509与SSLServerSocket结合起来,它是一个小的代码示例,但应该能帮助你走上正确的道路 链接 - ry8806
其实我想反过来做。使用 C# 服务器和 Android 客户端。我该如何为C#服务器和Android客户端创建自签名 SSL 证书呢?任何帮助将不胜感激。 - Mr.Noob
1个回答

2

从你的例子来看,看起来你并不需要通过编程来生成证书和私钥。你可以使用keytool在服务器密钥库中生成证书:

keytool -genkey -alias myalias -keystore mykeystore.jks -dname "CN=www.example.com"

如果您使用Java 7的keytool,最好还使用SAN扩展:

keytool -genkey -alias myalias -keystore mykeystore.jks -dname "CN=www.example.com" -ext san=dns:www.example.com

这里,“www.example.com”是客户端看到的主机名。您可以在主题DN(“dname”)中添加其他内容,但请确保“CN”是主机名。
生成证书后,使用以下命令导出自签名证书:
keytool -export myservercert.crt -alias myalias -keystore mykeystore.jks

然后,您应该能够将其作为受信任的证书导入到Windows证书存储中,并从C#中使用。


为什么你会需要通过编程生成证书的私钥呢?谁会相信它呢? - user207421
@EJP同意,它并没有太大用处。但如果你编写一个“中间人代理”(如Fiddler或[Squid的SslBump](http://wiki.squid-cache.org/Features/SslBump)),那么它可能很方便,你可以将代理的CA证书导入到浏览器中,但会为请求的主机实时生成一个新的证书。 - Bruno
导出JKS为CRT格式,并将该CRT作为受信任的证书导入操作系统,解决了我的问题!谢谢! - savionok

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接