Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JRE created via JLink missing some security certificates (cacerts)

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?

like image 876
Jakg Avatar asked Mar 03 '20 12:03

Jakg


1 Answers

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
like image 104
Chase Avatar answered Oct 01 '22 16:10

Chase