通过JLink创建的JRE缺少一些安全证书(cacerts)。

10
我使用JLink工具创建了一个被精简过的JRE。
jlink --add-modules java.base,jdk.crypto.ec --output jre

我创建了一个连接到 https://www.example.com 的非常基本的应用程序。

当我使用JDK运行该应用程序时,一切正常。 当我使用压缩版的JRE运行它时,我会得到以下错误:

Exception in thread "main" javax.net.ssl.SSLException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:133)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:320)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:263)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:258)
        at java.base/sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1313)
        at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:408)
        at java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:567)
        at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
        at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1587)
        at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1515)
        at java.base/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:527)
        at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:334)
        at URLTest.printResponseCode(URLTest.java:68)
        at URLTest.main(URLTest.java:47)
Caused by: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
        at java.base/sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:102)
        at java.base/sun.security.validator.Validator.getInstance(Validator.java:181)
        at java.base/sun.security.ssl.X509TrustManagerImpl.getValidator(X509TrustManagerImpl.java:300)
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrustedInit(X509TrustManagerImpl.java:176)
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:189)
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129)
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1316)
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1207)
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1150)
        at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
        at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
        at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
        at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:177)
        at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
        at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1151)
        at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1062)
        at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
        ... 8 more
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
        at java.base/java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:200)
        at java.base/java.security.cert.PKIXParameters.<init>(PKIXParameters.java:120)
        at java.base/java.security.cert.PKIXBuilderParameters.<init>(PKIXBuilderParameters.java:104)
        at java.base/sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:99)
        ... 24 more

我注意到JDK中的lib\security\cacerts文件比被压缩的JRE中的要大得多(246KB vs 156KB)。当我将此文件复制到被压缩的JRE中时,我的应用程序就可以正常工作。

这表明JLink进程因某种原因删除了某些证书。我在文档或在线上找不到任何解释。我有什么遗漏吗?


4
为了排除可能性,你可以尝试使用Java 13版本。我认为你并没有错过什么,谷歌给出的一些结果都围绕手动复制cacerts文件。在你的情况下,不同的是jlink似乎不仅生成了一个大幅缩减的cacerts文件 - 它生成了一个空文件。至少这就是我所假设的,如果错误提示没有信任锚点,则说明如此。 - Gimby
哪个JDK版本和操作系统仍然可用? - Alan Bateman
使用OpenJDK 11.0.3适用于64位Linux,我发现我的jlink应用程序在lib/security中具有完全相同的文件。每个文件都具有相同的文件大小和校验和。 - VGR
1
@Gimby 感谢您的回复。我已经尝试了OpenJDK13,它可以正常工作。因此可能这只是一个暂时性的错误。 - Jakg
3
我在Windows上运行,使用的是Amazon Corretto 11.0.6.10.1(最新版)。尝试过OpenJDK11,它可以工作 - 所以看起来是Amazon Corretto的问题。 - Jakg
1
@Jakg 我可以确认:我们在使用 Amazon Corretto 11.0.6.10.1 2020-01-14 LTS 时遇到了相同的问题。 - Michael
2个回答

2

我在OpenJDK上看到过这个问题,我认为这不是Corretto独有的bug。我认为Corretto bug只是将一些AWS证书添加到了常规JDK cacerts文件中,但没有添加到jlink base mod中的cacerts文件中。

当我们尝试使用keytool添加一些新的ca证书时,我们遇到了相同的问题,只有JDK中的lib/security/cacerts文件被更新了,而不是源自jmods/java.base.jmod的cacerts文件,这是在使用jlink时需要的。

解决办法是在运行jlink之前更新jmods/java.base.jmod中的lib/security/cacerts文件。 .jmod文件格式是带有zip格式和额外头部的zip文件,头部由字母“JM”组成,后跟jmod主要版本号0x01和jmod次要版本号0x00。如果您感兴趣,更多信息请参见https://hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/java.base/share/classes/jdk/internal/jmod/JmodFile.javahttps://bugs.astron.com/view.php?id=59

我们在Linux上的解决方法是从JDK目录运行以下命令:

tail -c +5 jmods/java.base.jmod > jmods/java.base.jmod.zip
zip -ur jmods/java.base.jmod.zip lib/security/cacerts
printf "\x4a\x4d\x01\x00" | cat - jmods/java.base.jmod.zip > jmods/java.base.jmod
rm jmods/java.base.jmod.zip


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接