JRE created via JLink missing some security certificates (cacerts)
Asked Answered
T

2

12

I've created a minified JRE using the JLink tool

jlink --add-modules java.base,jdk.crypto.ec --output jre

I've created a very basic application that connects to https://www.example.com

When I run this application using the JDK, everything works fine. When I run this using the minified JRE, I get the following:

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

I've noticed the lib\security\cacerts file in the JDK is much larger than in the minified JRE (246KB vs 156KB). When I copy this file into the minified JRE, then my application works correctly.

This suggests that the JLink process is removing some of the certificates for some reason. I can't see any explanation in the documentation for this, or online. Am I missing something?

Tedra answered 3/3, 2020 at 12:25 Comment(7)
Just for the sake of ruling it out, could you try with Java 13? I don't get the idea that you are missing something here, the few hits that google gives me tend to revolve around manually copying over a cacerts file. What is different in your case is that apparently jlink is not only producing a severely reduced cacerts file - it is producing an empty one. At least that is what I would assume if the error complains about there being no trust anchors.Maloy
Which JDK release and operating system s still?Heterophyllous
Using OpenJDK 11.0.3 for 64-bit Linux, I find that my jlink’d application has exactly the same files in lib/security. Each has the same file size, the same checksum.Ripieno
@Maloy thanks for your response. Having tried OpenJDK13, it works correctly. So perhaps this is a transient bug.Tedra
@AlanBateman I am running on Windows, using Amazon Corretto 11.0.6.10.1 (latest). Having tried OpenJDK11 it works - so it looks to be an issue with Amazon Corretto.Tedra
@Jakg I can confirm: We face the same problem with Amazon Corretto 11.0.6.10.1 2020-01-14 LTSPushing
I think it was solved (because I never saw that before), but is back with Corretto 21 (21.0.3.9.1). My current fix is to just copy lib/security/cacerts from the original JDK to the minimal JRE created by jlink.Ornithorhynchus
F
2

Having seen this on OpenJDK, I don't think it is a Corretto only bug. I think the Corretto bug was just that some AWS certs were added to the regular JDK cacerts file but not the cacerts file in the jlink base mod.

We experienced the same issue when trying to add some new ca certs using keytool, only the lib/security/cacerts file in the JDK was updated and not the one that is inside jmods/java.base.jmod which is where the cacerts file is sourced from when using jlink.

The solution was to update lib/security/cacerts inside of jmods/java.base.jmod before running jlink. The .jmod file format is zip with an extra header at the beginning of the zip which is 4 bytes. The header consists of the initials "JM" followed by the jmod major version number 0x01 and the jmod minor version number 0x00. If you are interested, more at 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

Our fix on Linux was to run the following from the JDK dir:

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
Foulard answered 8/5, 2021 at 19:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.