简体   繁体   English

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

[英]How to properly set up ssl socket connection between C# and Java?

I have problems with connect C# socket client to Java socket server. 我有连接C#套接字客户端到Java套接字服务器的问题。

Java server ( deployed on CentOS server ) 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 is keystore containing private key and entire trust chain ( primary, intermediate, root ) servercert是包含私钥和整个信任链的密钥库(主要,中间,根)

C# Client ( running from my laptop - Win7 x64 ) C#客户端(从我的笔记本电脑运行 - 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 Client ( running from my laptop - Win7 x64 ) Java客户端(从我的笔记本电脑运行 - Win7 x64)

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

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

Java Client -> Java Server - success Java客户端 - > Java服务器 - 成功

C# Client -> Java Server - fail C#Client - > Java Server - 失败


Java Server errors Java Server错误

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# Client errors 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)

What I am doing wrong? 我做错了什么?


edit: 编辑:

I've done some tests and now I know that this is not fault of C# client, because same client can connect to any HTTPS website and exchange HTTP requests ( application doesn't crash at AuthenticateAsClient ) 我做了一些测试,现在我知道这不是C#客户端的错,因为同一个客户端可以连接到任何HTTPS网站并交换HTTP请求(应用程序不会在AuthenticateAsClient崩溃)

I found it. 我找到了。 The problem: incorrect keystore. 问题:密钥库不正确。 I merged 2 tutorials on creating keystore. 我合并了2个关于创建密钥库的教程。 First: merge private key and entire trust chain as pem. 第一:将私钥和整个信任链合并为pem。 Second: import pem to keystore. 第二步:将密码导入密钥库。 But in the result I had keystore containing only main cert. 但在结果中,我的密钥库只包含主要证书。 Recently I wanted to verify keystore on Windows, and I used KeyStore Explorer . 最近我想在Windows上验证密钥库,我使用了KeyStore Explorer Then I realized what was wrong and made new keystore successful using this tool. 然后我意识到出了什么问题,并使用这个工具使新的密钥库成功。

Doesn't "no cipher suites in common" error returned by jave server show where the problem lies? jave server返回的“没有共同的密码套件”错误显示问题出在哪里? If I recall TLS protocol correctly, client first sends client hello in which it specifies possible security suites (supported). 如果我正确地回想起TLS协议,客户端首先发送客户端hello,在其中指定可能的安全套件(支持)。 Server is supposed to pick one (based on its supported security suites) and specify it in server hello. 服务器应该选择一个(基于其支持的安全套件)并在服务器hello中指定它。 Java server didn't find any matching security suite and threw exception instead. Java服务器找不到任何匹配的安全套件,而是抛出异常。 Why java server works with java client is because both support the same cipher suits. 为什么java服务器与java客户端一起工作是因为它们都支持相同的密码套件。 Try making C# server and C# client and it should work the same... 尝试制作C#服务器和C#客户端,它应该工作相同...

I recently had to get a Windows machine via C++/Win API talking to an Apache server over SSL, so I can sympathize. 我最近不得不通过C ++ / Win API通过SSL与Apache服务器通信获得Windows机器,所以我可以同情。 You may be missing a certificate on your Windows machine (a public key) what works with the private key on the Linux (java) machine. 您可能在Windows机器(公钥)上缺少与Linux(java)计算机上的私钥有关的证书。 One thing I had to do is get WireShark and watch the transactions. 我必须做的一件事是获取WireShark并观察交易。 If you can get the private key from your Linux machine you can provide it to WireShark and it will provide a very good (decrypted) breakdown of your packet contents. 如果您可以从Linux机器获取私钥,则可以将其提供给WireShark,它将提供对数据包内容的非常好(解密)细分。 This way you can watch the transaction and see where it fails as well as the exchange of the list of cipher suites. 通过这种方式,您可以查看事务并查看失败的位置以及密码套件列表的交换。 I can tell you that sometimes the error you get back from the software stack doesn't match the error you see watching the wire protocols. 我可以告诉你,有时你从软件堆栈中得到的错误与看到有线协议的错误不符。 It seems unlikely that they can't find a common cipher suite (there are quite a few commonly used). 他们似乎不太可能找不到一个共同的密码套件(有很多常用的密码套件)。 I suspect it is either a key (certificate) issue or a failure in the dialog during the initial exchange. 我怀疑它是初始交换期间的密钥(证书)问题或对话框中的失败。 WireShark is your friend. WireShark是你的朋友。

See here: https://blogs.oracle.com/java-platform-group/entry/diagnosing_tls_ssl_and_https 请参见: https//blogs.oracle.com/java-platform-group/entry/diagnosing_tls_ssl_and_https

If you upgrade to a newer Oracle JDK 7 or 8, that should resolve your issue. 如果升级到较新的Oracle JDK 7或8,则应解决您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM