【问题标题】:Convert a TCP Socket to a TLS one for StartTLS将 TCP 套接字转换为用于 StartTLS 的 TLS
【发布时间】:2021-10-26 12:38:25
【问题描述】:

我正在尝试编写一个客户端来连接到 Openfire 服务器。 在我的客户端之前,我正在使用另一个 Openfire 服务器,当两者之间的连接启动时,我可以在 WireShark 上看到:

在服务器端口上进行不同的 TCP 交换,然后在同一端口上进行 TLS 握手。 TCP 请求是这样说的:

Client :
<stream:stream xmlns:db="jabber:server:dialback" xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:server" from="X" to="Y" version="1.0">

Serveur :
<stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:server" from="X" id="e4f15a89" version="1.0">
<stream:features><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="http://www.tridsys.com/TacticalChatServer" ver="y397tZ3lcMRCMkGER0wpix00iPk="/>
    <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls>
    <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></mechanisms>
    <sm xmlns="urn:xmpp:sm:3"><optional/></sm>
</stream:features>

Client :
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>

Serveur :
<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

然后,我想在 TLS 通信之前,两个服务器会互相说是否可以与 TLS 通信,如果答案是肯定的,则它们会启动 TLS 握手。这就是他们所说的 StartTLS。

所以我想用 Java 复制这种情况。这就是我正在尝试的:

public class ClientTrustAll {
    
    public static void main(String[] args) {
        try {
            // Create trust manager which accept all certificates
            X509TrustManager tm = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    // Accept all certificate for client
                    System.out.println("Check client => OK");
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    // Accept all certificate for server
                    System.out.println("Check server => OK");
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            
            // Create trust manager
            TrustManager[] tms = new TrustManager[1];
            tms[0] = tm;
        
            // Create TCP socket
            
            Socket sTcp = new Socket("162.0.126.2", 5269);
            DataOutputStream dos = new DataOutputStream(sTcp.getOutputStream());
            dos.write(5);
            
            // Create TLS context
            SSLContext context = SSLContext.getInstance("TLSv1.2");
            context.init(null, tms, new SecureRandom());
            
            // Create TLS socket with the Tcp one
            SSLSocketFactory sslf = context.getSocketFactory();
            System.out.println("Talk to 162.0.126.2");
            SSLSocket s = (SSLSocket) sslf.createSocket(sTcp, "162.0.126.2", 5269, true);

            // Start TLS handshake (may be omitted, then it will be done during first read or write) 
            //s.startHandshake();
            Thread.sleep(100);
            
            // Write "int"
            s.getOutputStream().write(5);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

但是当我这样做时,我收到以下错误消息:

Talk to 162.0.126.2
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
        at sun.security.ssl.InputRecord.handleUnknownRecord(Unknown Source)
        at sun.security.ssl.InputRecord.read(Unknown Source)
        at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
        at sun.security.ssl.SSLSocketImpl.writeRecord(Unknown Source)
        at sun.security.ssl.AppOutputStream.write(Unknown Source)
        at sun.security.ssl.AppOutputStream.write(Unknown Source)
        at ClientTrustAll.main(ClientTrustAll.java:63)

这意味着我的服务器端口不是 TLS 端口(因为它仍然是 TCP)。 在 Wireshark 上,出于同样的原因,我在 Client Hello 之后出现了一个 Alert Fatal Error。

我确切地说我正在使用 java jdk.1.8.0_121

【问题讨论】:

  • 这意味着您的服务器未正确发送 TLS 握手。那么你的服务器代码在哪里呢?
  • 我没有服务器代码。这是一个 Openfire 服务器,版本非常旧(我无法升级)
  • 如果您尝试使用实际的 Openfire 服务器执行此操作,那么您必须遵守服务器正在实施的协议。只是将字节 5 发送到线路上并不会切断它。请记住,端口没有什么神奇之处,没有“TLS 端口”之类的东西。如果你想用这个服务器做 starttls 你必须至少发送&lt;starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/&gt; 到服务器并在sslf.createSocket() 调用之前读取它的响应。您可能还必须发送其他所有内容,我不熟悉这里的协议。
  • 我发送了所有消息,现在服务器正在回复我,但我仍然无法通过 TLS 访问它。正在努力。感谢您的回答。

标签: java ssl java-8 tls1.2


【解决方案1】:

为那些可能需要它的人找到答案。 我不得不等待服务器回复我,然后向他发送良好的消息组合以重新创建标准交换并强制他切换到 tls 模式。

public class ClientTrustAll {
    
    public static void main(String[] args) {
        try {
            System.setProperty("javax.net.debug", "all");
            // Create trust manager which accept all certificates
            X509TrustManager tm = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    // Accept all certificate for client
                    System.out.println("Check client => OK");
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    // Accept all certificate for server
                    System.out.println("Check server => OK");
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            
            // Create trust manager
            TrustManager[] tms = new TrustManager[1];
            tms[0] = tm;
        
            // Create TCP socket
            Socket sTcp = new Socket("162.0.126.2", 5269);
            
            //For reading
            // BufferedReader in = new BufferedReader(new InputStreamReader(sTcp.getInputStream()));
            DataInputStream in = new DataInputStream(sTcp.getInputStream());
            byte[] messageByte = new byte[1000];
            String dataString = "";
            
            //Writing the first message on this socket
            PrintWriter out = new PrintWriter(sTcp.getOutputStream(), true);
            out.println("<stream:stream xmlns:db=\"jabber:server:dialback\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:server\" from=\"X\" to=\"Y\" version=\"1.0\">");
            System.out.println("Sent: <stream:stream xmlns:db=\"jabber:server:dialback\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:server\" from=\"X\" to=\"Y\" version=\"1.0\">\n");
            
            // Read the answer to send response at the good time
            while (!dataString.contains("stream:features")) {
                int bytesRead = in.read(messageByte);
                dataString += new String(messageByte, 0, bytesRead);
                System.out.println("Answer = " + dataString + "\n");
            }
            
            // Writing the second message on the socket
            out.println("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
            System.out.println("Sent: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n");
            
            while (!dataString.contains("<proceed")) {
                int bytesRead = in.read(messageByte);
                dataString += new String(messageByte, 0, bytesRead);
                System.out.println("Answer = " + dataString + "\n");
            }
            
            // Create TLS context
            SSLContext context = SSLContext.getInstance("TLSv1.2");
            context.init(null, tms, new SecureRandom());
            
            // Create TLS socket
            SSLSocketFactory sslf = context.getSocketFactory();
            System.out.println("Talk to 162.0.126.2");
            SSLSocket s = (SSLSocket) sslf.createSocket(sTcp, "162.0.126.2", 5269, true);

            // Start TLS handshake (may be omitted, then it will be done during first read or write) 
            // s.startHandshake();
            Thread.sleep(100);
            
            // Write "int"
            s.getOutputStream().write(5);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

【讨论】:

    猜你喜欢
    • 2013-04-18
    • 2016-06-13
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 2023-03-08
    • 2013-04-13
    • 2016-05-14
    • 2013-05-15
    相关资源
    最近更新 更多