在 java 程序中发出 STARTTLS 命令后,startHandshake 出现不支持或无法识别的 ssl-message 异常
Unsupported or unrecognized ssl-message exception at startHandshake after issuing STARTTLS command in a java program
我在 java 中编写了一个简单的 e-mail 客户端,但没有使用 JavaMail API,根据我从文档中读到的内容,似乎有必要将消息拆分为头部和 body 并在单个 MIME-parts 中发送,这会使我的应用程序变得更加复杂。对于 SSL 端口 (465) 一切正常,但现在我正在尝试将客户端与仅支持端口 587 上的 STARTTLS 的不同提供商一起使用。以下代码是我编写的 class 测试访问权限的代码服务器。
private static DataOutputStream dos; //Streams to communicate with the server
private static DataInputStream dis;
public static void main(String[] args) {
try {
Socket socket = new Socket("mail.arcor.de", 587);
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
new Thread(() -> {readInputRun();}).start(); //see below, every input from the server is printed to the standard output.
dos.write(("EHLO " + InetAddress.getLocalHost().getHostAddress() + "\r\n").getBytes());
dos.write("STARTTLS\r\n".getBytes());
SSLSocket sslSocket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(socket, "mail.arcor.de", 587, true);
dos = new DataOutputStream(sslSocket.getOutputStream());
dis = new DataInputStream(sslSocket.getInputStream());
sslSocket.startHandshake();
dos.write(("EHLO " + InetAddress.getLocalHost().getHostAddress() + "\r\n").getBytes());
dos.write("QUIT\r\n".getBytes());
Thread.sleep(5000);
dis.close();
dos.close();
socket.close();
} catch(Exception e) {
e.printStackTrace();
}
}
private static void readInputRun() {
try {
int input;
while((input = dis.read()) >= 0) {
System.out.print((char) input);
}
} catch(Exception e) {
e.printStackTrace();
}
}
每次执行时,都会出现以下异常:
javax.net.ssl.SSLException: Unsupported or unrecognized SSL message
at java.base/sun.security.ssl.SSLSocketInputRecord.handleUnknownRecord(SSLSocketInputRecord.java:416)
at java.base/sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:173)
at java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1031)
at java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
at java.base/sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1402)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1429)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
at accessTest.AccessTestSTARTTLS.main(AccessTestSTARTTLS.java:31)
它在第 31 行被抛出,也就是 'sslSocket.startHandshake();',所以不知何故握手没有成功。我是否在错误的点或以错误的方式启动它?
在此先感谢您的帮助。
编辑:正如评论中所建议的,我启用了日志并发现了以下内容:
httpslog。在第五行也是最后一行中有一个不可读的字符,显然是客户端问候的一部分,所以我的计算机发送了它。为什么会这样,我该如何阻止?
需要说明的是,这个答案的主要目的是将问题标记为已回答,因为实际上在问题的评论中可以找到解决方案。问题出在readInputRun()读取部分ServerHello,所以让读取线程在握手前自己中断,解决后再重启:
dos.write("STARTTLS\r\n".getBytes());
SSLSocket sslSocket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(socket, "mail.arcor.de", 587, true);
dos = new DataOutputStream(sslSocket.getOutputStream());
dis = new DataInputStream(sslSocket.getInputStream());
sslSocket.startHandshake();
new Thread(() -> {readInputRun();}).start();
dos.write(("EHLO " + InetAddress.getLocalHost().getHostAddress() + "\r\n").getBytes());
dos.write("QUIT\r\n".getBytes());
和:
private static void readInputRun() {
try {
int input;
String allInput = "";
while((input = dis.read()) >= 0) {
allInput += (char) input;
System.out.print(allInput.charAt(allInput.length() - 1));
if(allInput.endsWith("Start TLS\r\n")) {
break;
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
我在 java 中编写了一个简单的 e-mail 客户端,但没有使用 JavaMail API,根据我从文档中读到的内容,似乎有必要将消息拆分为头部和 body 并在单个 MIME-parts 中发送,这会使我的应用程序变得更加复杂。对于 SSL 端口 (465) 一切正常,但现在我正在尝试将客户端与仅支持端口 587 上的 STARTTLS 的不同提供商一起使用。以下代码是我编写的 class 测试访问权限的代码服务器。
private static DataOutputStream dos; //Streams to communicate with the server
private static DataInputStream dis;
public static void main(String[] args) {
try {
Socket socket = new Socket("mail.arcor.de", 587);
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
new Thread(() -> {readInputRun();}).start(); //see below, every input from the server is printed to the standard output.
dos.write(("EHLO " + InetAddress.getLocalHost().getHostAddress() + "\r\n").getBytes());
dos.write("STARTTLS\r\n".getBytes());
SSLSocket sslSocket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(socket, "mail.arcor.de", 587, true);
dos = new DataOutputStream(sslSocket.getOutputStream());
dis = new DataInputStream(sslSocket.getInputStream());
sslSocket.startHandshake();
dos.write(("EHLO " + InetAddress.getLocalHost().getHostAddress() + "\r\n").getBytes());
dos.write("QUIT\r\n".getBytes());
Thread.sleep(5000);
dis.close();
dos.close();
socket.close();
} catch(Exception e) {
e.printStackTrace();
}
}
private static void readInputRun() {
try {
int input;
while((input = dis.read()) >= 0) {
System.out.print((char) input);
}
} catch(Exception e) {
e.printStackTrace();
}
}
每次执行时,都会出现以下异常:
javax.net.ssl.SSLException: Unsupported or unrecognized SSL message
at java.base/sun.security.ssl.SSLSocketInputRecord.handleUnknownRecord(SSLSocketInputRecord.java:416)
at java.base/sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:173)
at java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1031)
at java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
at java.base/sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1402)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1429)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
at accessTest.AccessTestSTARTTLS.main(AccessTestSTARTTLS.java:31)
它在第 31 行被抛出,也就是 'sslSocket.startHandshake();',所以不知何故握手没有成功。我是否在错误的点或以错误的方式启动它?
在此先感谢您的帮助。
编辑:正如评论中所建议的,我启用了日志并发现了以下内容: httpslog。在第五行也是最后一行中有一个不可读的字符,显然是客户端问候的一部分,所以我的计算机发送了它。为什么会这样,我该如何阻止?
需要说明的是,这个答案的主要目的是将问题标记为已回答,因为实际上在问题的评论中可以找到解决方案。问题出在readInputRun()读取部分ServerHello,所以让读取线程在握手前自己中断,解决后再重启:
dos.write("STARTTLS\r\n".getBytes());
SSLSocket sslSocket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(socket, "mail.arcor.de", 587, true);
dos = new DataOutputStream(sslSocket.getOutputStream());
dis = new DataInputStream(sslSocket.getInputStream());
sslSocket.startHandshake();
new Thread(() -> {readInputRun();}).start();
dos.write(("EHLO " + InetAddress.getLocalHost().getHostAddress() + "\r\n").getBytes());
dos.write("QUIT\r\n".getBytes());
和:
private static void readInputRun() {
try {
int input;
String allInput = "";
while((input = dis.read()) >= 0) {
allInput += (char) input;
System.out.print(allInput.charAt(allInput.length() - 1));
if(allInput.endsWith("Start TLS\r\n")) {
break;
}
}
} catch(Exception e) {
e.printStackTrace();
}
}