使用STARTTLS将套接字升级到SSLSocket:recv失败

我正在尝试使用STARTTLS将套接字升级到SSLSocket。 在InspIRCd的维基上,这是它应该如何工作的

>> STARTTLS << :test2.chatspike.net 670 nickname :STARTTLS successful, go ahead with TLS handshake (SSL Handshake) 

所以在我的代码中我写了(稍微简化)

 else if (code.equals("670")) { SSLSocketFactory sslSocketFactory = ((SSLSocketFactory) SSLSocketFactory.getDefault()); SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket( socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true); sslSocket.startHandshake(); bufferedReader = new BufferedReader(new InputStreamReader(sslSocket.getInputStream(), getEncoding())); bufferedWriter = new BufferedWriter(new OutputStreamWriter(sslSocket.getOutputStream(), getEncoding())); socket = sslSocket; } 

然而,有了和没有startHandshake()我总是得到一个recv失败(没有我只是当我尝试从新的bufferedReader读取时得到它

 java.io.IOException: Can't connect to server at org.pircbotx.PircBotX.connect(PircBotX.java:472) [Exception handling] at org.pircbotx.PircBotX.connect(PircBotX.java:224) [Overridden constructor] at org.pircbotx.impl.PircBotXExample.main(PircBotXExample.java:185) Caused by: java.net.SocketException: Software caused connection abort: recv failed at java.net.SocketInputStream.read(SocketInputStream.java:150) at java.net.SocketInputStream.read(SocketInputStream.java:121) at sun.security.ssl.InputRecord.readFully(InputRecord.java:442) at sun.security.ssl.InputRecord.read(InputRecord.java:480) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927) at sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1707) at sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:122) at sun.security.ssl.Handshaker.kickstart(Handshaker.java:909) at sun.security.ssl.SSLSocketImpl.kickstartHandshake(SSLSocketImpl.java:1423) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1288) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323) at org.pircbotx.PircBotX.connect(PircBotX.java:411) [startHandshake line] ... 2 more 

完整日志(使用-Djavax.net.debug=all

 1365707641940 <<...4.2... 0060: 01 00 03 00 13 00 15 00 06 00 07 00 09 00 0A 00 ................ 0070: 18 00 0B 00 0C 00 19 00 0D 00 0E 00 0F 00 10 00 ................ 0080: 11 00 02 00 12 00 04 00 05 00 14 00 08 00 16 00 ................ 0090: 0B 00 02 01 00 ..... main, WRITE: TLSv1 Handshake, length = 149 main, waiting for close_notify or alert: state 1 main, Exception while waiting for close java.net.SocketException: Software caused connection abort: recv failed main, handling exception: java.net.SocketException: Software caused connection abort: recv failed main, SEND TLSv1 ALERT: fatal, description = unexpected_message at java.net.SocketInputStream.socketRead0(Native Method) main, WRITE: TLSv1 Alert, length = 2 main, Exception sending alert: java.net.SocketException: Software caused connection abort: socket write error main, called closeSocket() 1365707642425 *** Disconnected. 

我可能做错什么会导致此错误? 我知道这个function有效,因为其他客户端可以做到这一点,但我无法弄清楚如何从Java中做到这一点

有什么建议么?

我做了一些测试,并在sslSocket握手时在socket上接收数据时遇到此错误。 如果您例如注册(发送NICK / LOGIN)到socket而不是sslSocket发生这种sslSocket 。 尝试在连接TLSSTART之后对服务器发出第一个命令,并在发送任何其他内容之前等待670/691代码。

以下内容不会对我产生任何exception,并设法在没有任何问题的情况下进行握手:

 public static void main(String[] args) throws Exception { Socket socket = new Socket("irc.chatspike.net",6667); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String line; writer.write("STARTTLS\r\n"); writer.flush(); while ((line = reader.readLine()) != null) { if (line.contains(" 670 ")) { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }, new java.security.SecureRandom()); SSLSocketFactory sslSocketFactory = ((SSLSocketFactory) sc.getSocketFactory()); SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket( socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true); sslSocket.startHandshake(); } } 

这里的问题是,您通过明文套接字在STARTTLS命令之后发送除SSL握手之外的其他内容。 一旦你发布了STARTTLS并且它已被接受,必须停止使用明文套接字。