为什么 SSL 在构建的 JAR 内部无法正常工作?

huangapple go评论78阅读模式
英文:

Why does SSL not work inside a build jar?

问题

以下是您要求的内容的翻译:

我有一个小项目,想要使用TLS 1.3。

我使用了这个示例库作为主要示例:https://github.com/williamswhy/SSLSocket

这是我的服务器:

Server() {
    SSLServerSocket serverSocket = null;
    SSLSocket socket = null;

    try {
        SSLServerSocketFactory sslServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
        serverSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(3122);
        MariaDB mariaDB = new MariaDB();
        new Thread(mariaDB).start();
        while (true) {
            socket = (SSLSocket) serverSocket.accept();
            new Thread(new ClientConnection(socket, mariaDB)).start();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    //System.setProperty("javax.net.debug", "all");
    System.setProperty("javax.net.ssl.keyStore", "sslserverkeys");
    System.setProperty("javax.net.ssl.keyStorePassword", "password");
    new Server();
}

我的客户端使用以下类:

try {
    System.setProperty("javax.net.ssl.trustStore", "sslclienttrust");
    System.setProperty("javax.net.ssl.trustStorePassword", "password");

    //不要更改这部分
    SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
    sslContext.init(null, null, new SecureRandom());
    SSLSocketFactory socketFactory = sslContext.getSocketFactory();
    socket = (SSLSocket) socketFactory.createSocket("localhost", 3122);
    System.out.println("成功初始化连接");

    try {
        this.out = new ObjectOutputStream(this.socket.getOutputStream());
        System.out.println("成功打开ObjectOutputStream");
    } catch (IOException var4) {
        var4.printStackTrace();
        try {
            this.out.close();
        } catch (IOException var3) {
            var3.printStackTrace();
        }
    }
} catch (NoSuchAlgorithmException | KeyManagementException | IOException e) {
    e.printStackTrace();
}

我在客户端的根文件夹中有一个名为"sslclienttrust"的文件,而在服务器的根文件夹中有一个名为"sslserverkeys"的文件。我在使用Maven和IntelliJ Ultimate进行编码,连接在该环境中运行得非常顺利。
但是,当我构建一个.jar文件(使用maven-shade-plugin)时,会出现异常。

服务器抛出以下异常:

javax.net.ssl.SSLException: readHandshakeRecord
    at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1392)
    // 更多异常信息...

客户端抛出以下异常:

the last modified time is: Mon Sep 28 00:44:21 CEST 2020
javax.net.ssl|DEBUG|15|Thread-4|2020-09-29 24:55:10.430 CEST|TrustStoreManager.java:334|Reload the trust store
javax.net.ssl|DEBUG|15|Thread-4|2020-09-29 24:55:10.468 CEST|TrustManagerFactoryImpl.java:70|SunX509: skip default keystore (
"throwable" : {
  java.io.IOException: Keystore was tampered with, or password was incorrect
        // 更多异常信息...

起初,我认为这可能与错误的路径有关,所以我尝试了一些在stackoverflow上提到的方法。但是密码错误或密钥库被篡改的错误让我感到困惑。密码不能错误,因为在IDE中可以工作。

为什么SSL在IDE中工作正常,但在.jar文件中却不行?
我看到一些关于SSL根本无法工作的帖子,但与这种情况不同。

英文:

I have a small project in which i want to use TLS 1.3.

As main example i used this respo: https://github.com/williamswhy/SSLSocket

This is my server:

Server() {
    SSLServerSocket serverSocket = null;
    SSLSocket socket = null;

    try {
        SSLServerSocketFactory sslServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
        serverSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(3122);
        MariaDB mariaDB = new MariaDB();
        new Thread(mariaDB).start();
        while (true) {
            socket = (SSLSocket) serverSocket.accept();
            new Thread(new ClientConnection(socket,mariaDB)).start();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    //System.setProperty("javax.net.debug", "all");
    System.setProperty("javax.net.ssl.keyStore", "sslserverkeys");
    System.setProperty("javax.net.ssl.keyStorePassword", "password");
    new Server();
}

My Client uses the following class:

try {
    System.setProperty("javax.net.ssl.trustStore", "sslclienttrust");
    System.setProperty("javax.net.ssl.trustStorePassword", "password");

    //DO NOT CHANGE THIS
    SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
    sslContext.init(null, null, new SecureRandom());
    SSLSocketFactory socketFactory = sslContext.getSocketFactory();
    socket = (SSLSocket) socketFactory.createSocket("localhost", 3122);
    System.out.println("Successfully initialized connection");

    try {
        this.out = new ObjectOutputStream(this.socket.getOutputStream());
        System.out.println("Successfully opened ObjectOutputStream");
    } catch (IOException var4) {
        var4.printStackTrace();
        try {
            this.out.close();
        } catch (IOException var3) {
            var3.printStackTrace();
        }
    }
} catch (NoSuchAlgorithmException | KeyManagementException | IOException e) {
    e.printStackTrace();
}

I have a sslclienttrust file in the root folder of my client and sslserverkeys in the root folder of my server. I'm coding in IntelliJ Ultimate with Maven and the connection works like a charm in it.
But when i build a .jar (using maven-shade-plugin) I get an exception.

The Server throws the following exception:

javax.net.ssl.SSLException: readHandshakeRecord
	at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1392)
	at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:441)
	at java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:889)
	at java.base/sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:1251)
	at java.base/java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1893)
	at java.base/java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1802)
	at java.base/java.io.ObjectOutputStream.<init>(ObjectOutputStream.java:252)
	at ClientConnection.<init>(ClientConnection.java:21)
	at Server.<init>(Server.java:20)
	at Server.main(Server.java:36)
	Suppressed: java.net.SocketException: An established connection was aborted by the software in your host machine
		at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:420)
		at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:440)
		at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:826)
		at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1052)
		at java.base/sun.security.ssl.SSLSocketOutputRecord.encodeAlert(SSLSocketOutputRecord.java:82)
		at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:356)
		at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:268)
		at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:451)
		... 8 more
Caused by: java.net.SocketException: An established connection was aborted by the software in your host machine
	at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:420)
	at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:440)
	at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:826)
	at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1052)
	at java.base/sun.security.ssl.SSLSocketOutputRecord.flush(SSLSocketOutputRecord.java:268)
	at java.base/sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:89)
	at java.base/sun.security.ssl.Finished$T13FinishedProducer.onProduceFinished(Finished.java:783)
	at java.base/sun.security.ssl.Finished$T13FinishedProducer.produce(Finished.java:671)
	at java.base/sun.security.ssl.SSLHandshake.produce(SSLHandshake.java:440)
	at java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.goServerHello(ClientHello.java:1252)
	at java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.consume(ClientHello.java:1188)
	at java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.onClientHello(ClientHello.java:851)
	at java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.consume(ClientHello.java:812)
	at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396)
	at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:445)
	at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:423)
	at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:182)
	at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:171)
	at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1475)
	at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1381)
	... 9 more

The client throws the following:

the last modified time is: Mon Sep 28 00:44:21 CEST 2020
javax.net.ssl|DEBUG|15|Thread-4|2020-09-29 24:55:10.430 CEST|TrustStoreManager.java:334|Reload the trust store
javax.net.ssl|DEBUG|15|Thread-4|2020-09-29 24:55:10.468 CEST|TrustManagerFactoryImpl.java:70|SunX509: skip default keystore (
"throwable" : {
  java.io.IOException: Keystore was tampered with, or password was incorrect
        at java.base/sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:794)
        at java.base/sun.security.util.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:241)
        at java.base/java.security.KeyStore.load(KeyStore.java:1472)
        at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.loadKeyStore(TrustStoreManager.java:390)
        at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.getTrustedCerts(TrustStoreManager.java:336)
        at java.base/sun.security.ssl.TrustStoreManager.getTrustedCerts(TrustStoreManager.java:56)
        at java.base/sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:49)
        at java.base/javax.net.ssl.TrustManagerFactory.init(TrustManagerFactory.java:281)
        at java.base/sun.security.ssl.SSLContextImpl.engineInit(SSLContextImpl.java:94)
        at java.base/javax.net.ssl.SSLContext.init(SSLContext.java:313)
        at connection.ServerConnection.connectToServer(ServerConnection.java:204)
        at connection.ServerConnection.run(ServerConnection.java:42)
        at java.base/java.lang.Thread.run(Thread.java:832)
  Caused by: java.security.UnrecoverableKeyException: Password verification failed
        at java.base/sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:792)
        ... 12 more}

At first i thought this has something to do with wrong pathing, so i tried a couple of ways mentioned on sof. But the error, that the password is incorrect or the keystore is tampered confuses me. The password cannot be wrong, because it is working in the IDE.

Why does the SSL work in my IDE, but not inside the .jar
I saw some threads about SSL not working at all, but not like this.

答案1

得分: 4

System property javax.net.ssl.trustStore requires that you pass a file in, and that file must.. exist.

entries in jars are file-like, but not files, so you cannot use a truststore file packed inside a jar file. That kinda explodes the point of a jar in the first place, and is why this isn't 'working' - you're running the jar from someplace where the working dir isn't proper. In general passing a relative entry (something that doesn't start with / or C:\ or whatnot) to javax.net.ssl.trustStore is never going to work in the hands of end users and requires careful scripting by the ops team if you try to deploy that on your own servers.

To load a trust store from any random source, such as 'a resource 'file' that is in the same place my class files live; look in the jar file if you have to', check this tutorial.

英文:

System property javax.net.ssl.trustStore requires that you pass a file in, and that file must.. exist.

entries in jars are file-like, but not files, so you cannot use a truststore file packed inside a jar file. That kinda explodes the point of a jar in the first place, and is why this isn't 'working' - you're running the jar from someplace where the working dir isn't proper. In general passing a relative entry (something that doesn't start with / or C:\ or whatnot) to javax.net.ssl.trustStore is never going to work in the hands of end users and requires careful scripting by the ops team if you try to deploy that on your own servers.

To load a trust store from any random source, such as 'a resource 'file' that is in the same place my class files live; look in the jar file if you have to', check this tutorial.

huangapple
  • 本文由 发表于 2020年9月29日 07:01:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/64110711.html
匿名

发表评论

匿名网友

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

确定