JDK-8344924 : Default CA certificates loaded despite request to use custom keystore
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.net.ssl
  • Affected Version: 24
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2024-11-25
  • Updated: 2024-12-16
  • Resolved: 2024-12-10
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 24 JDK 25
24Fixed 25 b02Fixed
Related Reports
Relates :  
Relates :  
Description
After the changes introduced in JDK-8338383 to X509TrustManagerImpl, the Java runtime forces the loading of the default CA certificates, even if the intention is to load a custom keystore.

The sample code below demonstrates this behavior
// Load the custom truststore
FileInputStream fis = new FileInputStream("CustomKeyStore");
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(fis, "testpass".toCharArray());

// Initialize the TrustManagerFactory with the custom keystore
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);

Comments
A pull request was submitted for review. Branch: jdk24 URL: https://git.openjdk.org/jdk/pull/22672 Date: 2024-12-10 20:58:48 +0000
10-12-2024

Changeset: 4c39e9fa Branch: master Author: Kevin Driver <kdriver@openjdk.org> Date: 2024-12-10 20:49:13 +0000 URL: https://git.openjdk.org/jdk/commit/4c39e9faa0cb8e4fd00d8b9dc0ac5ad64d6b287d
10-12-2024

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/22616 Date: 2024-12-06 21:15:23 +0000
06-12-2024

Marking as P3 in order to ensure inclusion into 24 on the grounds of this being a regression that was also introduced in the 24-cycle. Per the guidance [here](https://openjdk.org/guide/#backporting-to-a-feature-release-stabilization-branch), this will be merged first to master and then backported via Skara.
06-12-2024

The background to this was tests such as httpclient/ManyRequests.java in the http3 branch hanging and timing out in early 2024. If a virtual thread blocks while in a class initializer then it can't unmount and release its carrier due to a VM/native frame on the stack. In these tests, a virtual thread was blocking in X509Factory.addToCache while executing AnchorCertificates.<clinit>. Meanwhile, many other virtual threads were blocked waiting for AnchorCertificates to initialize, also pinning their carriers. The original thread that held the X509Factory.class lock selected an unmounted virtual thread as the successor but the thread could not continue as all carriers were pinned. So starvation and the test eventually timed out. The workaround at the time was to eagerly initialize AnchorCertificate. There was some discussion at the time about re-visiting the initialisation and locking in this area, e.g. addToCache is a static synchronized method so very coarse locking. Since then, the object monitor in the VM has changed to do timed-park that avoids starvation that arises when an unmounted virtual thread is selected as the successor and there is no carriers available. Patricio reminds me that the timed-park work was done after the clinit workaround went in. So we think we can be removed now. Prasad has run httpclient/ManyRequests.java with the change to clinit removed and is unable to reproduce the original issue.
06-12-2024

source code causing the eager initialization of the anchor certificates : src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java: static { // eagerly initialize to avoid pinning virtual thread during TLS handshake try { MethodHandles.lookup().ensureInitialized(AnchorCertificates.class); } catch (IllegalAccessException e) { throw new ExceptionInInitializerError(e); } }
06-12-2024

[~mullan], shouldn't we assign this back to [~pchilanomate] since his change introduced the regression? I'm not sure what else we can do here besides remove the static initialization, but https://bugs.openjdk.org/browse/JDK-8338383 claims there is a deadlock without it.
05-12-2024

[~kdriver] It seems like it is still an issue. Can we re-open this as Prasad has added more details about the issue?
05-12-2024

It incurs an additional load of the default keystore, even though the application explicitly requested a custom keystore. With JDK-8338383 fix: java -Djava.security.debug=pkcs12 KeyStoreRegression.java pkcs12: PKCS12KeyStore: loading "keystore.jks" keystore pkcs12: Loading PKCS#7 data pkcs12: Loading PKCS#7 encryptedData (PBEWithHmacSHA256AndAES_256 iterations: 10000) pkcs12: Checking keystore integrity (HmacPBESHA256 iterations: 10000) pkcs12: PKCS12KeyStore loaded: "keystore.jks" keystore with private key count: 1. secret key count: 0. certificate count: 1 pkcs12: Retrieved a 1-certificate chain at alias 'expiredcert' pkcs12: PKCS12KeyStore: loading "cacerts" keystore pkcs12: Loading PKCS#7 data pkcs12: PKCS12KeyStore loaded: "cacerts" keystore with private key count: 0. secret key count: 0. certificate count: 112 pkcs12: Retrieved a certificate at alias 'actalisauthenticationrootca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'addtrustexternalca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'addtrustqualifiedca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'affirmtrustcommercialca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'affirmtrustnetworkingca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'affirmtrustpremiumca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'affirmtrustpremiumeccca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'amazonrootca1 [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'amazonrootca2 [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'amazonrootca3 [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'amazonrootca4 [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'baltimorecybertrustca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'buypassclass2ca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'buypassclass3ca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'camerfirmachambersca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'camerfirmachamberscommerceca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'camerfirmachambersignca [jdk]' (trusted for any purpose) pkcs12: Retrieved a certificate at alias 'certainlyroote1 [jdk]' (trusted for any purpose) .......... pkcs12: Retrieved a certificate at alias 'xrampglobalca [jdk]' (trusted for any purpose) CN=Expired Certificate Fri Nov 29 03:43:56 UTC 2024 890b8849b15abeb1 without the fix: java -Djava.security.debug=pkcs12 KeyStoreRegression.java pkcs12: PKCS12KeyStore: loading "keystore.jks" keystore pkcs12: Loading PKCS#7 data pkcs12: Loading PKCS#7 encryptedData (PBEWithHmacSHA256AndAES_256 iterations: 10000) pkcs12: Checking keystore integrity (HmacPBESHA256 iterations: 10000) pkcs12: PKCS12KeyStore loaded: "keystore.jks" keystore with private key count: 1. secret key count: 0. certificate count: 1 pkcs12: Retrieved a 1-certificate chain at alias 'expiredcert' CN=Expired Certificate Fri Nov 29 03:43:56 UTC 2024 890b8849b15abeb1
05-12-2024

see previous comments -- marking as closed.
03-12-2024

import java.io.FileInputStream; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Enumeration; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; public class KeyStoreRegression { public static void main(String[] args) { try { FileInputStream fis = new FileInputStream("keystore.jks"); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(fis, "password".toCharArray()); for (Enumeration<String> aliases = ks.aliases(); aliases.hasMoreElements();) { System.out.println(aliases.nextElement()); } TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager myTrustManager = null; for (TrustManager tm : tmf.getTrustManagers()) { if (tm instanceof X509TrustManager x509TrustManager) { myTrustManager = x509TrustManager; for (X509Certificate cert : myTrustManager.getAcceptedIssuers()) { System.out.println(cert.getSubjectX500Principal()); System.out.println(cert.getNotAfter()); System.out.println(cert.getSerialNumber().toString(16)); } break; } } } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException ex) { System.err.println(ex); ex.printStackTrace(); } } } $ keytool -v -list -keystore keystore.jks Enter keystore password: Keystore type: PKCS12 Keystore provider: SUN Your keystore contains 1 entry Alias name: selfsigned Creation date: Dec 3, 2024 Entry type: PrivateKeyEntry Certificate chain length: 1 Certificate[1]: Owner: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown Issuer: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown Serial number: c41943a0541f0b2 Valid from: Tue Dec 03 10:51:07 CST 2024 until: Fri Nov 28 10:51:07 CST 2025 Certificate fingerprints: SHA1: 13:17:47:D5:25:1F:6D:F0:3D:94:EF:82:3A:FA:A4:B0:A6:F5:3C:94 SHA256: 5B:3C:52:E1:E2:3C:85:AF:3D:5A:07:13:42:C3:D5:BA:B8:00:F0:51:69:91:B3:60:E1:D0:1B:FB:45:C2:B0:76 Signature algorithm name: SHA384withRSA Subject Public Key Algorithm: 2048-bit RSA key Version: 3 Extensions: #1: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: 9A EC C0 D8 BA 2B 75 D1 4B 63 B1 67 FE 83 A3 B1 .....+u.Kc.g.... 0010: 45 03 B7 AC E... ] ] ******************************************* ******************************************* $ java KeyStoreRegression selfsigned CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown Fri Nov 28 10:51:07 CST 2025 c41943a0541f0b2 Note the serial numbers match.
03-12-2024