【问题标题】:How to properly set up ssl socket connection between C# and Java?如何在 C# 和 Java 之间正确设置 ssl 套接字连接?
【发布时间】:2015-06-08 14:36:37
【问题描述】:

我在将 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# 客户端(在我的笔记本电脑上运行 - 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 服务器 - 成功

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 请求(应用程序不会在 AuthenticateAsClient 崩溃)

【问题讨论】:

标签: java c# sockets ssl


【解决方案1】:

jave 服务器返回的“no cipher suites in common”错误是否表明问题出在哪里?如果我没记错 TLS 协议,客户端首先发送客户端问候语,其中指定了可能的安全套件(支持)。服务器应该选择一个(基于其支持的安全套件)并在服务器 hello 中指定它。 Java 服务器没有找到任何匹配的安全套件,而是抛出了异常。为什么 java 服务器与 java 客户端一起工作是因为两者都支持相同的密码套装。尝试制作 C# 服务器和 C# 客户端,它应该工作相同...

【讨论】:

  • 服务器托管在 Linux 机器上,客户端必须用 C# 编写,因为它是另一个应用程序的一部分。有什么方法可以安装缺少的密码套件来支持 C# 客户端?
  • 好吧,如果这确实是问题...使用 SSL 的不同 C# 实现可能会解决它(我认为您不能在不更改的情况下“添加”对默认 .NET 实现的额外支持框架什么的)。尝试使用 OpenSSL 快速制作原型。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    如果您升级到更新的 Oracle JDK 7 或 8,应该可以解决您的问题。

    【讨论】:

    • 客户端安装oracle JDK 8,服务器安装open JDK 8。
    【解决方案4】:

    我找到了。问题:不正确的密钥库。我合并了 2 个关于创建密钥库的教程。第一:将私钥和整个信任链合并为pem。第二:将pem导入密钥库。但结果我的密钥库只包含主证书。最近想在 Windows 上验证密钥库,我使用了KeyStore Explorer。然后我意识到出了什么问题,并使用此工具成功创建了新的密钥库。

    【讨论】:

      猜你喜欢
      • 2017-03-17
      • 2015-04-06
      • 2014-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-21
      • 2015-11-12
      相关资源
      最近更新 更多