英文:
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?
专注分享java语言的经验与见解,让所有开发者获益!
评论