如何在C#和Java之间正确设置ssl socket连接?

时间:2015-04-03 13:38:02

标签: java c# sockets ssl

我遇到了将C#套接字客户端连接到Java套接字服务器的问题。

Java服务器(部署在CentOS服务器上)

System.setProperty( "javax.net.ssl.keyStore", "/etc/ssl/servercert" );
System.setProperty( "javax.net.ssl.keyStorePassword", "pass" );

SSLServerSocket serverSocket = SSLServerSocketFactory.getDefault().createServerSocket( PORT );
SSLSocket sslSocket = serverSocket.accept();
sslSocket.startHandshake();

InputStream inputStream = socket.getInputStream();
...

servercert是包含私钥和整个信任链(主要,中间,根)的密钥库

C#Client(从我的笔记本电脑运行 - Win7 x64)

var sock = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
sock.Connect(server, port );
NetworkStream stream = new NetworkStream(sock);
SslStream ssl = new SslStream(stream);
ssl.AuthenticateAsClient(server);

ssl.Write("test");
...

Java客户端(从我的笔记本电脑运行 - Win7 x64)

SSLSocket sslSocket = SSLSocketFactory.getDefault().createSocket( host, port );
sslSocket.startHandshake();

UTF8OutputStreamWriter outputStreamWriter = new UTF8OutputStreamWriter( socket.getOutputStream() );
outputStreamWriter.write( "test" );

Java客户端 - > Java Server - 成功

C#客户端 - > Java服务器 - 失败


Java服务器错误

Exception in thread "main" javax.net.ssl.SSLHandshakeException: no cipher suites in common
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1937)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:292)
        at sun.security.ssl.ServerHandshaker.chooseCipherSuite(ServerHandshaker.java:1014)
        at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:731)
        at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:213)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:957)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:892)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1050)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)

C#客户端错误

System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> System.ComponentModel.Win32Exception: The message received was unexpected or badly formatted
   --- End of inner exception stack trace ---
   at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
   at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost)

我做错了什么?


编辑:

我已经完成了一些测试,现在我知道这不是C#客户端的错,因为同一个客户端可以连接到任何HTTPS网站并交换HTTP请求(应用程序不会在{{1}崩溃})

3 个答案:

答案 0 :(得分:1)

jave server返回的“没有共同的密码套件”错误显示问题出在哪里?如果我正确地回想起TLS协议,客户端首先发送客户端hello,在其中指定可能的安全套件(支持)。服务器应该选择一个(基于其支持的安全套件)并在服务器hello中指定它。 Java服务器找不到任何匹配的安全套件,而是抛出异常。为什么java服务器与java客户端一起工作是因为它们都支持相同的密码套件。尝试制作C#服务器和C#客户端,它应该工作相同......

答案 1 :(得分:1)

我最近不得不通过C ++ / Win API通过SSL与Apache服务器通信,因此我可以同情。您可能在Windows机器(公钥)上缺少与Linux(java)计算机上的私钥有关的证书。我必须做的一件事是获得WireShark并观察交易。如果您可以从Linux机器获取私钥,则可以将其提供给WireShark,它将提供对数据包内容的非常好(解密)细分。通过这种方式,您可以查看事务并查看失败的位置以及密码套件列表的交换。我可以告诉你,有时你从软件堆栈中得到的错误与看到有线协议的错误不符。他们似乎不太可能找不到一个共同的密码套件(有很多常用的密码套件)。我怀疑它是初始交换期间的密钥(证书)问题或对话框中的失败。 WireShark是你的朋友。

答案 2 :(得分:1)

见这里:https://blogs.oracle.com/java-platform-group/entry/diagnosing_tls_ssl_and_https

如果您升级到较新的Oracle JDK 7或8,那么应解决您的问题。