Java SSL Socket issues: ServerSocket does not receive data and handshake fails.

huangapple 未分类评论45阅读模式
英文:

Java SSL Socket issues: ServerSocket does not receive data and handshake fails

问题

package test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executors;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public final class Test {

    public static void main(String[] args) throws InterruptedException {
        System.setProperty("javax.net.ssl.trustStore", "D:\\Documents\\NetBeansProjects\\test\\test.store");
        System.setProperty("javax.net.ssl.keyStorePassword", "123456");

        Executors.newSingleThreadExecutor().execute(new Server(1));
        Executors.newSingleThreadExecutor().execute(new Client("localhost", 1));
    }
}

class Server implements Runnable {

    private int port;

    public Server(int port) {
        this.port = port;
    }

    @Override
    public void run() {
        try (SSLServerSocket sslServerSocket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(port); Socket socket = sslServerSocket.accept(); InputStream inputStream = socket.getInputStream(); Scanner scanner = new Scanner(inputStream)) {
            System.out.println("Server: " + String.join(", ", sslServerSocket.getEnabledCipherSuites()));
            System.out.println("Server: " + String.join(", ", sslServerSocket.getEnabledProtocols()));
            
            if (scanner.hasNextLine()) {
                System.out.println(scanner.nextLine());
            } else {
                System.out.println("No next line!");
            }
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }
}

class Client implements Runnable {

    private String host;
    private int port;

    public Client(String host, int port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public void run() {
        try (SSLSocket sslSocket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(host, port); OutputStream outputStream = sslSocket.getOutputStream(); PrintWriter printWriter = new PrintWriter(outputStream)) {
            System.out.println("Client: " + String.join(", ", sslSocket.getEnabledCipherSuites()));
            System.out.println("Client: " + String.join(", ", sslSocket.getEnabledProtocols()));
            
            // sslSocket.startHandshake();

            printWriter.println("A next line!");
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }
}

Output:

Server: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, ...
Server: TLSv1.3, TLSv1.2, TLSv1.1, TLSv1, SSLv2Hello
Client: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, ...
Client: TLSv1.3, TLSv1.2, TLSv1.1, TLSv1
A next line!

To fix the handshake issue, remove the line sslSocket.startHandshake(); in the Client class.

英文:

Running this code:

package test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executors;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public final class Test {

    public static void main(String[] args) throws InterruptedException {
        System.setProperty("javax.net.ssl.trustStore", "D:\\Documents\\NetBeansProjects\\test\\test.store");
        System.setProperty("javax.net.ssl.keyStorePassword", "123456");

        Executors.newSingleThreadExecutor().execute(new Server(1));
        Executors.newSingleThreadExecutor().execute(new Client("localhost", 1));
    }
}

class Server implements Runnable {

    private int port;

    public Server(int port) {
        this.port = port;
    }

    @Override
    public void run() {
        try (SSLServerSocket sslServerSocket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(port); Socket socket = sslServerSocket.accept(); InputStream inputStream = socket.getInputStream(); Scanner scanner = new Scanner(inputStream)) {
            System.out.println("Server: " + String.join(", ", sslServerSocket.getEnabledCipherSuites()));
            System.out.println("Server: " + String.join(", ", sslServerSocket.getEnabledProtocols()));
            
            if (scanner.hasNextLine()) {
                System.out.println(scanner.nextLine());
            } else {
                System.out.println("No next line!");
            }
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }
}

class Client implements Runnable {

    private String host;
    private int port;

    public Client(String host, int port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public void run() {
        try (SSLSocket sslSocket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(host, port); OutputStream outputStream = sslSocket.getOutputStream(); PrintWriter printWriter = new PrintWriter(outputStream)) {
            System.out.println("Client: " + String.join(", ", sslSocket.getEnabledCipherSuites()));
            System.out.println("Client: " + String.join(", ", sslSocket.getEnabledProtocols()));
            
            sslSocket.startHandshake();

            printWriter.println("A next line!");
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }
}

... I am always getting this output:

Server: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV
Client: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV
Server: TLSv1.3, TLSv1.2, TLSv1.1, TLSv1, SSLv2Hello
Client: TLSv1.3, TLSv1.2, TLSv1.1, TLSv1
No next line!
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
	at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
	at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
	at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:308)
	at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:285)
	at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:181)
	at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
	at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152)
	at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063)
	at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
	at test.Client.run(Test.java:67)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

The certificate is at the right position: D:\Documents\NetBeansProjects\test\test.store I created it with this command:keytool -genkey -alias test -keystore test.store I also do not understand why the exception is only thrown if I call #startHandshake(). The Javadoc states that writing or reading on the socket will also start the handshake. But if I remove #startHandshake(), there is not an exception anymore but the Server does not print the received message as well.

I use Java 11.

How can I fix this?

huangapple
  • 本文由 发表于 2020年4月8日 19:47:48
  • 转载请务必保留本文链接:https://java.coder-hub.com/61099928.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定