JDK-8129988 : JSSE should create a single instance of the cacerts KeyStore
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.net.ssl
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2015-06-26
  • Updated: 2021-08-25
  • Resolved: 2017-01-06
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 7 JDK 8 JDK 9 Other
7u211Fixed 8u192Fixed 9 b152Fixed openjdk8u222Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
Currently, each TrustManagerFactory instance reads the cacerts file and creates a KeyStore. This is wasteful and can negatively affect performance, especially when multiple threads are involved, each establishing their own SSLContext.

Instead, we should investigate creating a single instance of the cacerts KeyStore. There is already a method in sun.security.validator.KeyStores.getCaCerts() that does this, but it is commented out. 



Comments
I've restarted the discussion on the backwards-compatibility breaking post-JDK-8219988 behavior of the "javax.net.ssl.trustStore" handling on the security-dev mailing list (https://mail.openjdk.java.net/pipermail/security-dev/2021-August/027213.html).
25-08-2021

Some more context to Bernd's comment above (from https://mail.openjdk.java.net/pipermail/jdk8u-dev/2019-August/009999.html). David Alvarez wrote: We have detected that JDK-8219988 [1], that has been included in OpenJDK 8u222 included a non-documented change in the behavior of the javax.net.ssl.trustStore property. In previous versions, should this property point to a non-existent file, an empty KeyStore would be used instead. [2] In newer versions, if the value of the property contains an invalid URL, the code will instead fall back and use the lib/security/cacerts file. [3] However, there are two things about that change that caught our attention: - Whenever there is no javax.net.ssl.trustStore property set, the code will first look for lib/security/jssecacerts. If that file does not exist, then it will look for lib/security/cacerts. However, when the property is set to an invalid file, the fallback mechanism jumps directly to lib/security/cacerts, never checking lib/security/jssecacerts. - This fallback mechanism for invalid javax.net.ssl.trustStore values reuses the value of javax.net.ssl.trustStorePassword. If that property is set in conjunction with an invalid value in javax.net.ssl.trustStore the specified password will be used when attempting to read the lib/security/cacerts store. It seems unclear why this path of action is chosen here. If the lib/security/cacerts has no password (and as far as I'm aware, that is the case in the majority of OpenJDK distributions, if not all), the operation will raise an exception. This exception mentions that 'Password verification failed', hiding the underlying cause (the property pointing to a bad store).[4] Although the new behavior isn't necessarily wrong, I think there is room for Improvement. Suggestions: - Make sure lib/security/jssecacerts is checked during the fallback process. - Ignore the value of javax.net.ssl.trustStorePassword when we fallback to use the bundled jssecacerts or cacerts file. - Change the exception message to avoid confusion. I would like to have your opinion on this. Thanks, David -- [1] https://bugs.openjdk.java.net/browse/JDK-8129988 [2] http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/ac2ef877d3e8/src/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java#l132 [3] http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/2a9bea6e5e03/src/share/classes/sun/security/ssl/TrustStoreManager.java#l128 [4] Here is a copy of the exception: Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:785) at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56) at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224) at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70) at java.security.KeyStore.load(KeyStore.java:1445) at sun.security.ssl.TrustStoreManager$TrustAnchorManager.loadKeyStore(TrustStoreManager.java:367) at sun.security.ssl.TrustStoreManager$TrustAnchorManager.getTrustedCerts(TrustStoreManager.java:315) at sun.security.ssl.TrustStoreManager.getTrustedCerts(TrustStoreManager.java:59) at sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:51) Caused by: java.security.UnrecoverableKeyException: Password verification failed at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:783)
06-11-2020

Now that we have deployed this fix, we occasionally see junit test failures like this: ``` Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:785) at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56) at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224) at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70) at java.security.KeyStore.load(KeyStore.java:1445) at sun.security.ssl.TrustStoreManager$TrustAnchorManager.loadKeyStore(TrustStoreManager.java:368) at sun.security.ssl.TrustStoreManager$TrustAnchorManager.getTrustedCerts(TrustStoreManager.java:316) at sun.security.ssl.TrustStoreManager.getTrustedCerts(TrustStoreManager.java:59) at sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:51) Caused by: java.security.UnrecoverableKeyException: Password verification failed at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:783) ```
07-08-2019

Looks good. I noticed this when reviewing the backports for 7u221 and realised it had been missed in 8u212. I'm guessing our filter fell foul of cases where the bugs were marked as fixed in 8u202 with a high build ID not in the OpenJDK repositories. It may be worth checking for other such cases.
24-04-2019

Fix Request. Webrev at http://cr.openjdk.java.net/~phh/8129988/webrev.8u.02/. Patch applies cleanly net of file names, line numbers, and javac limitations. Passes jdk/test/sun/security jtreg tests as well as does jdk8u-dev, modified tests pass. 8u202 and 8u192 backport issues do not include changeset references, and the patch is not in the jdk8u/jdk repo. This issue was mentioned in Oracle's 8u211 release notes at https://www.oracle.com/technetwork/java/javase/2col/8u211-bugfixes-5292912.html.
22-04-2019

URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/904861872c0e User: lana Date: 2017-01-11 20:48:03 +0000
11-01-2017

URL: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/904861872c0e User: xuelei Date: 2017-01-06 02:04:55 +0000
06-01-2017

The attached SSLContextPerform.java can be used as a simple test to verify the performance improvement.
27-11-2016

This also causes issues if the cacerts database is altered or moved while there is a running JVM. See https://bugs.centos.org/view.php?id=9088
21-03-2016