在Java程序中发出STARTTLS命令后,startHandshake上出现不受支持或无法识别的ssl消息异常 [英] Unsupported or unrecognized ssl-message exception at startHandshake after issuing STARTTLS command in a java program

查看:117
本文介绍了在Java程序中发出STARTTLS命令后,startHandshake上出现不受支持或无法识别的ssl消息异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用Java编写了一个简单的电子邮件客户端程序,而没有使用JavaMail API,因为从文档中读取的内容看来,似乎有必要将消息分成头部和正文,并在单个MIME部分中进行发送,会使我的应用程序复杂得多.对于SSL端口(465),一切正常,但是现在我试图将客户端与仅支持端口587上的STARTTLS的其他提供程序一起使用.以下代码属于我编写的用于测试对服务器的访问的类./p>

I have written a simple e-mail client in java without using the JavaMail API, as by what I read from the documentation it seems necessary to split the messages up into head and body and in the single MIME-parts for sending which would make my application a lot more complicated. Everything worked fine for a SSL port (465) but now I'm trying to use the client with a different provider that only supports STARTTLS on port 587. The following code is of a class I wrote to test the access to the server.

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();
    }
}

每次执行它时,都会出现以下异常:

Every time I execute it, I get the following exception:

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();",因此以某种方式无法进行握手.我是在错误的点或以错误的方式启动它吗?

It is thrown at line 31, which is 'sslSocket.startHandshake();', so somehow the handshake does not work out. Do I initiate it at the wrong point or in the wrong way?

在此先感谢您的帮助.

如注释中所建议,我启用了日志并找到了以下内容: httpslog .在第五行但最后一行中,有一个无法读取的字符,显然是客户端问候的一部分,因此我的计算机将其发送出去.为什么会这样,我该如何制止呢?

As suggested in the comment, I enabled the logs and found the following: httpslog. In the fifth but last line there is an unreadable character, obviously as part of the client hello, so my computer sends it. Why is this the case and how can I stop that?

推荐答案

要明确,此答案的主要目的是将问题标记为已回答,因为实际上在该问题的注释中找到了解决方案.问题出在readInputRun()上,它读取ServerHello的一部分,因此让读取线程在握手之前中断自身,并在解决之后重新启动它:

To be clear, the main intention behind this answer is to mark the question as answered, because actually the solution is found in the comments to the question. The problem lies in the readInputRun() that reads part of the ServerHello, so letting the reading thread interrupt itself before the handshake and restarting it after it solves it:

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程序中发出STARTTLS命令后,startHandshake上出现不受支持或无法识别的ssl消息异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆