带有 KeyStore 和 ServerSockets 的 Java SSL/TLS

Posted

技术标签:

【中文标题】带有 KeyStore 和 ServerSockets 的 Java SSL/TLS【英文标题】:Java SSL/TLS with KeyStore and ServerSockets 【发布时间】:2021-09-15 12:27:59 【问题描述】:

我正在使用 TLS/SSL 函数编写 SocketServer Lib,但我的代码有问题。

如果我加载密钥库文件,它会引发 IOException,但证书会完全显示在浏览器中。

我的代码:

SSLServerSocketFactory factoryIO;
FileManager certificateIO = new FileManager(CacheHandler.fileIO.getPath("database") + "letsencrypt.jks");
char[] passphraseIO = "12345678".toCharArray();

if (certificateIO.exits()) 
    //this.socketIO = SSLServerSocketFactory.getDefault().createServerSocket(this.networkIO.getPort(), 10, this.networkIO.getAddress());
    //this.socketIO = this.getContext().getServerSocketFactory().createServerSocket(this.networkIO.getPort(), 10, this.networkIO.getAddress());

    // Load Key Store.
    KeyStore storeIO = KeyStore.getInstance("JKS");
    storeIO.load(certificateIO.stream(), passphraseIO);

    // Initialize Key Manger.
    KeyManagerFactory managerIO = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    managerIO.init(storeIO, passphraseIO);

    // Initialize Trust Manger.
    // TrustManagerFactory trustIO = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    //trustIO.init(storeIO);

    // Initialize SSL Context with Trust and Key Manager.
    SSLContext contextIO = SSLContext.getInstance(this.protocolIO);
    contextIO.init(managerIO.getKeyManagers(), null /*trustIO.getTrustManagers()*/, null);


    factoryIO = contextIO.getServerSocketFactory();
    // ((SSLServerSocket) this.socketIO).setWantClientAuth(true);
    //((SSLServerSocket) this.socketIO).setEnabledCipherSuites(new String[]"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256");
    //((SSLServerSocket) this.socketIO).setEnabledProtocols(new String[]"TLSv1.2");

我尝试了很多东西,但如果没有这个错误,我就无法让它运行,它运行了一段时间,但我不知道我做了什么,产生了这个错误。

这会引发以下异常:

java.io.IOException: Invalid keystore format
    at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:658)
    at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56)
    at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224)
    at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70)
    at java.security.KeyStore.load(KeyStore.java:1445)
    at sun.security.util.AnchorCertificates$1.run(AnchorCertificates.java:61)
    at sun.security.util.AnchorCertificates$1.run(AnchorCertificates.java:52)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.security.util.AnchorCertificates.<clinit>(AnchorCertificates.java:52)
    at sun.security.provider.certpath.AlgorithmChecker.checkFingerprint(AlgorithmChecker.java:214)
    at sun.security.provider.certpath.AlgorithmChecker.<init>(AlgorithmChecker.java:164)
    at sun.security.provider.certpath.AlgorithmChecker.<init>(AlgorithmChecker.java:118)
    at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:157)
    at sun.security.validator.Validator.validate(Validator.java:262)
    at sun.security.validator.Validator.validate(Validator.java:238)
    at sun.security.validator.Validator.validate(Validator.java:207)
    at javax.crypto.JarVerifier.isTrusted(JarVerifier.java:610)
    at javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:530)
    at javax.crypto.JarVerifier.verifyJars(JarVerifier.java:363)
    at javax.crypto.JarVerifier.verify(JarVerifier.java:289)
    at javax.crypto.JceSecurity.verifyProviderJar(JceSecurity.java:164)
    at javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:190)
    at javax.crypto.JceSecurity.canUseProvider(JceSecurity.java:204)
    at javax.crypto.KeyAgreement.getInstance(KeyAgreement.java:179)
    at sun.security.ssl.JsseJce.getKeyAgreement(JsseJce.java:269)
    at sun.security.ssl.JsseJce$EcAvailability.<clinit>(JsseJce.java:418)
    at sun.security.ssl.JsseJce.isEcAvailable(JsseJce.java:194)
    at sun.security.ssl.CipherSuite$KeyExchange.isAvailable(CipherSuite.java:371)
    at sun.security.ssl.CipherSuite.isAvailable(CipherSuite.java:185)
    at sun.security.ssl.SSLContextImpl.getApplicableCipherSuiteList(SSLContextImpl.java:304)
    at sun.security.ssl.SSLContextImpl.access$100(SSLContextImpl.java:42)
    at sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(SSLContextImpl.java:432)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at java.security.Provider$Service.getImplClass(Provider.java:1634)
    at java.security.Provider$Service.newInstance(Provider.java:1592)
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
    at javax.net.ssl.SSLContext.getInstance(SSLContext.java:156)
    at de.bytestore.mytriox.network.server.ServerSocket.startIO(ServerSocket.java:203)
    at de.bytestore.mytriox.network.server.ServerSocket.start(ServerSocket.java:172)
    at de.bytestore.mytriox.web.WebServer.start(WebServer.java:44)
    at de.bytestore.mytriox.web.WebService.start(WebService.java:54)
    at de.bytestore.mytriox.service.ServiceHandler.start(ServiceHandler.java:63)
    at de.bytestore.mytriox.service.ServiceHandler.start(ServiceHandler.java:48)
    at de.bytestore.mytriox.guardian.GuardianHandler.init(GuardianHandler.java:121)
    at de.bytestore.mytriox.guardian.GuardianHandler.load(GuardianHandler.java:82)
    at de.bytestore.mytriox.Controller.main(Controller.java:11)

我通过以下命令生成我的 KeyStore 文件:

keytool -genkeypair -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass 12345678 -dname "CN=localhost, OU=Developers, O=Bull Bytes, L=Linz, C=AT"

【问题讨论】:

您应该发布完整的堆栈跟踪。现在我们甚至错过了异常消息! 对不起,markdown 有问题^^ 那里有DualFormatJKS,我想知道它是否首先尝试将其加载为“JKS”或“PKCS12”密钥库,然后发现它需要使用另一个......只是预感,不是答案。您是否在使用较旧的 Java,例如 Java 8? 是的,我使用的是 Java 8,但我将 Method 实例用于 JKS 而没有其他 Store Type。 如果在keytool 中将密钥库明确指定为“JKS”会发生什么?你确定keytool 本身也在使用 Java 8 吗?如果您正在使用例如Maven,请看here 【参考方案1】:

问题是我的 KeyStore 的流方法。

我将 URL 转换为 URI 以打开 Stream,由于相对路径错误,因此无法正常工作。

所以我现在使用 FileInputStream 并获取错误路径的异常。

【讨论】:

啊,是的,这超出了我的理解范围,感谢您的反馈。对其他人来说不是那么有用,因为问题在KeyStore 之外,以防万一有人在查找。 Fwiw,根据文件的前两个字抛出错误。 github.com/frohoff/jdk8u-jdk/blob/master/src/share/classes/sun/… 所以它要么是坏数据要么是坏 i/o。 很抱歉回复评论,但我的错误没有完全解决。我是这么想的,但是之前很多行都有同样的错误。【参考方案2】:

通过更改 Java 版本解决了我的问题。

Oracle 给出了我的代码问题,我切换到 Java 14,它工作了......

【讨论】:

以上是关于带有 KeyStore 和 ServerSockets 的 Java SSL/TLS的主要内容,如果未能解决你的问题,请参考以下文章

在 Java KeyStore 中导入私钥/公钥对 [重复]

安卓签名文件.keystore 和 .jks

cacerts 和 keystore 有啥区别?

cacerts 和 keystore 有啥区别?

KeyStore 和 KeyManager/TrustManager 的区别

keystore文件