0

我正在通过 OpenSSL 和 Windows 套接字在 Windows 上以 C++ 运行本地 TCP 服务器。我正在使用 SSL 套接字在 Java 中运行客户端。对于大多数用户来说,这个设置是有效的,但是,一些用户在尝试 SSL 握手时会遇到以下 Java 异常:

javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
    at sun.security.ssl.SSLSocketImpl.handleEOF(Unknown Source) ~[?:1.8.0_321]
    at sun.security.ssl.SSLSocketImpl.decode(Unknown Source) ~[?:1.8.0_321]
    at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(Unknown Source) ~[?:1.8.0_321]
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) ~[?:1.8.0_321]
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) ~[?:1.8.0_321]
    ...
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at sun.security.ssl.SSLSocketInputRecord.read(Unknown Source) ~[?:1.8.0_321]
    at sun.security.ssl.SSLSocketInputRecord.readHeader(Unknown Source) ~[?:1.8.0_321]
    at sun.security.ssl.SSLSocketInputRecord.decode(Unknown Source) ~[?:1.8.0_321]
    at sun.security.ssl.SSLTransport.decode(Unknown Source) ~[?:1.8.0_321]
    ... 10 more

我的 Java 客户端套接字代码如下所示:

public static Socket getClientSocket() throws Exception
{
    InetSocketAddress socketAddress = new InetSocketAddress("localhost", 54321);
    SSLSocketFactory socketFactory = getSSLSocketFactory();
    Socket clientSocket = socketFactory.createSocket();
    clientSocket.connect(socketAddress, 1_000);
    ((SSLSocket) clientSocket).startHandshake(); // <-- Exception here for some users
    return clientSocket;
}

private static SSLSocketFactory getSSLSocketFactory() throws Exception
{
    // Create a trust manager that does not validate certificate chains
    X509TrustManager trustManager = new X509TrustManager()
    {
        @Override
        public X509Certificate[] getAcceptedIssuers()
        {
            // TODO Returning null is not allowed but it still works
            return null;
        }

        @Override
        public void checkClientTrusted(final X509Certificate[] certificates, final String authType)
        {

        }

        @Override
        public void checkServerTrusted(final X509Certificate[] certificates, final String authType)
        {
            for (X509Certificate certificate : certificates)
            {
                String certificateString = certificate.toString();
                if (!certificateString.contains("blablabla"))
                {
                    throw new SSLException("Certificate not trusted");
                }
            }
        }
    };
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
    return sslContext.getSocketFactory();
}

尝试的解决方案:

  • 连接前调用System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2")不起作用(参考
  • 我不想告诉用户将任何 SSL 证书导入他们的信任库(除非我可以轻松地自动执行此操作)

不一致的行为从何而来,如何为每个遇到异常的人彻底解决?我可以访问服务器源代码和证书。也欢迎任何关键问题或建议。如有必要,我可以提供更多信息。

4

0 回答 0