Keystore format/Password mismatch after JDK 21 upgrade
search cancel

Keystore format/Password mismatch after JDK 21 upgrade

book

Article ID: 433184

calendar_today

Updated On:

Products

VMware Tanzu Spring Essentials

Issue/Introduction

We are seeing below SSL exception issue post JDK migration from open JDK 17 to AWS corretto JDK 21 version.

We have merged the cacerts file from old and new versions. While merging it asked form password and we have given password as changeit. After merging application is facing with below issue. If we copy cacerts file from old to new jdk version application is working fine. 

Here we are merging cacerts file to have all required certificate from new jdk patch.  

Error while retreiving data:null-
javax.net.ssl.SSLException: (internal_error) Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:132)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:383)
at 

java.base/sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1708)
clientId: 01487 usr: 436840061:null
2026-03-12 17:55:47,376 DEBUG c.a.d.d.BaseDataHandler [tomcat-http--96] [retrieveStartupData] Ti


More error messages for reference:

example app 1

org.springframework.ws.client.WebServiceIOException: I/O error: (internal_error) Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty


example app 2

2026-03-12 17:56:45,790 ERROR c.a.d.e.s.EnrollmentDataService [tomcat-http--129] Error while retreiving data:null-
javax.net.ssl.SSLException: (internal_error) Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

 

Cause

The root cause is a keystore format/password mismatch introduced by the JDK 21 change and your merge process.

In AWS Corretto JDK 21 (and OpenJDK 21+), the bundled cacerts file is now a password-less PKCS12 keystore (this change started around JDK 18 via OpenJDK updates). The JVM loads the default trust store ($JAVA_HOME/lib/security/cacerts) without supplying any password.

Your old OpenJDK 17 cacerts was a JKS keystore (password = `changeit`). JKS files can be read with an empty password, which is why simply copying the old cacerts into the new JDK works.

When you merged the two files (most likely via keytool -importkeystore while supplying password `changeit` for both source and destination), the resulting file became a password-protected PKCS12 keystore (because keytool in JDK 21 defaults to PKCS12 unless you explicitly say otherwise). The JVM cannot open a password-protected PKCS12 without the password, so zero trust anchors are loaded: 

InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty.


This is a common issue after JDK 9/17 to 21 migrations when people merge cacerts files.

Resolution

Recommended Fix (Keep New JDK Patch Certs + Add Old Ones)

Use the new Corretto 21 cacerts as the base (so you keep all the latest/patched root certificates), then merge the old one into it as JKS (JKS is still fully compatible in JDK 21 and loads without a password).

Run these commands using the keytool from your Corretto JDK 21 (not the old JDK):

bash

# 1. Backup the original new cacerts
cp $JAVA_HOME/lib/security/cacerts $JAVA_HOME/lib/security/cacerts.backup

# 2. Merge (old into new, as JKS, with -noprompt)
keytool -importkeystore \
  -srckeystore /path/to/old-openjdk17-cacerts \
  -destkeystore $JAVA_HOME/lib/security/cacerts \
  -srcstorepass changeit \
  -deststorepass changeit \
  -deststoretype JKS \
  -noprompt


- This adds every certificate from the old file to the new one.

- Duplicate aliases (common root CAs) will be overwritten by the old version. In practice this almost never causes problems, because the new JDK patch usually only adds new roots or updates expired ones.

- The resulting file is JKS (password `changeit`), which the JVM can load without any extra flags — exactly like your working “copy old” case.

Restart your application (Tomcat). The SSL error should disappear.

Quick Alternative (If You Don’t Want to Re-Merge)

Just add this JVM argument (or put it in your JAVA_OPTS / Tomcat setenv.sh):

bash

-Djavax.net.ssl.trustStorePassword=changeit


This tells the JVM to supply the password when loading your current merged file. It works immediately but is less “clean” than the proper JKS merge above.

Even Cleaner Long-Term Option (Modern PKCS12 Password-Less)

If you prefer to stay with the native JDK 21 format:

bash

keytool -importkeystore \
  -srckeystore /path/to/old-openjdk17-cacerts \
  -destkeystore $JAVA_HOME/lib/security/cacerts \
  -srcstorepass changeit \
  -deststorepass "" \
  -deststoretype PKCS12 \
  -noprompt


(Empty destination password creates the modern password-less PKCS12 that JDK 21 expects.)

How to Verify the Merge Worked

After the merge, run:

bash

keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit | grep "keystore type"
keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit | wc -l

 

You should see JKS (or PKCS12 if you used the last option) and ~100–200 entries (roughly the sum of both files minus duplicates).

If the number of entries is still 0 after merging, the importkeystore step failed earlier (wrong paths or non-interactive prompts); just re-run the command above.

This exact pattern (copy old + merge as JKS) is the standard workaround used in production migrations from JDK 17 to 21 when applications rely on older internal/root certs that were removed or changed in the new JDK patch.

Additional Information

References:

https://bugs.launchpad.net/ubuntu/+source/ca-certificates-java/+bug/1739631 

https://github.com/adoptium/adoptium-support/issues/1145