通过 JLink 创建的 JRE 缺少一些安全证书 (cacerts)
JRE created via JLink missing some security certificates (cacerts)
我使用 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 对 156KB)。当我将此文件复制到缩小的 JRE 中时,我的应用程序可以正常工作。
这表明 JLink 进程出于某种原因正在删除一些证书。我在文档或在线文档中看不到任何解释。我错过了什么吗?
这是 Corretto 中的一个已知错误。
在 OpenJDK 上看到这个,我认为这不是 Corretto 独有的错误。我认为 Corretto 错误只是一些 AWS 证书被添加到常规 JDK cacerts 文件中,而不是 jlink base mod.
中的 cacerts 文件
我们在尝试使用 keytool 添加一些新的 ca 证书时遇到了同样的问题,只有 JDK 中的 lib/security/cacerts 文件被更新,而不是 jmods/java 中的文件.base.jmod 这是使用 jlink 时 cacerts 文件的来源。
解决方案是在 运行ning jlink 之前更新 jmods/java.base.jmod 内部的 lib/security/cacerts。 .jmod 文件格式是 zip,在 zip 的开头有一个额外的 header,它是 4 个字节。 header 由首字母“JM”组成,后跟 jmod 主版本号 0x01 和 jmod 次版本号 0x00。如果您有兴趣,请访问 https://hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java and https://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
我使用 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 对 156KB)。当我将此文件复制到缩小的 JRE 中时,我的应用程序可以正常工作。
这表明 JLink 进程出于某种原因正在删除一些证书。我在文档或在线文档中看不到任何解释。我错过了什么吗?
这是 Corretto 中的一个已知错误。
在 OpenJDK 上看到这个,我认为这不是 Corretto 独有的错误。我认为 Corretto 错误只是一些 AWS 证书被添加到常规 JDK cacerts 文件中,而不是 jlink base mod.
中的 cacerts 文件我们在尝试使用 keytool 添加一些新的 ca 证书时遇到了同样的问题,只有 JDK 中的 lib/security/cacerts 文件被更新,而不是 jmods/java 中的文件.base.jmod 这是使用 jlink 时 cacerts 文件的来源。
解决方案是在 运行ning jlink 之前更新 jmods/java.base.jmod 内部的 lib/security/cacerts。 .jmod 文件格式是 zip,在 zip 的开头有一个额外的 header,它是 4 个字节。 header 由首字母“JM”组成,后跟 jmod 主版本号 0x01 和 jmod 次版本号 0x00。如果您有兴趣,请访问 https://hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java and https://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