【发布时间】: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 你必须至少发送
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>到服务器并在sslf.createSocket()调用之前读取它的响应。您可能还必须发送其他所有内容,我不熟悉这里的协议。 -
我发送了所有消息,现在服务器正在回复我,但我仍然无法通过 TLS 访问它。正在努力。感谢您的回答。