JDK-8156715 : TrustStoreManager does not buffer keystore input stream
  • Type: Enhancement
  • Component: security-libs
  • Sub-Component: javax.net.ssl
  • Affected Version: 8u92,9
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2016-05-03
  • Updated: 2025-08-04
  • Resolved: 2025-06-24
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 26
26 b04Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
During an analysis of a java application startup time the following performance problem was found: some libraries create SSLContext. As a part of this context creation sun.security.ssl.TrustManagerFactoryImpl class loads default JDK keystore (jre/lib/security/cacerts). sun.security.ssl.TrustManagerFactoryImpl creates a FileInputStream and passes it to java.security.KeyStore which delegates the load to sun.security.provider.JavaKeyStore#engineStore method. In this method the keystore content is loaded from the provided input stream. TrustManagerFactoryImpl and JavaKeyStore does not create a buffered input stream for this input stream, as a result JavaKeyStore spends time to read a keystore content by few bytes multiple times directly from the file.

Example 1:
java.io.FileInputStream.read() FileInputStream.java
java.io.DataInputStream.readInt() DataInputStream.java:389
sun.security.provider.JavaKeyStore.engineLoad(InputStream, char[]) JavaKeyStore.java:745
sun.security.provider.JavaKeyStore$JKS.engineLoad(InputStream, char[]) JavaKeyStore.java:55
java.security.KeyStore.load(InputStream, char[]) KeyStore.java:1445
sun.security.ssl.TrustManagerFactoryImpl.getCacertsKeyStore(String) TrustManagerFactoryImpl.java:226
sun.security.ssl.SSLContextImpl$DefaultSSLContext.getDefaultTrustManager() SSLContextImpl.java:767
sun.security.ssl.SSLContextImpl$DefaultSSLContext.<init>() SSLContextImpl.java:733
sun.reflect.NativeConstructorAccessorImpl.newInstance(Object[]) NativeConstructorAccessorImpl.java:62
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Object[]) DelegatingConstructorAccessorImpl.java:45
java.lang.reflect.Constructor.newInstance(Object[]) Constructor.java:422
java.security.Provider$Service.newInstance(Object) Provider.java:1595
sun.security.jca.GetInstance.getInstance(Provider$Service, Class) GetInstance.java:236
sun.security.jca.GetInstance.getInstance(String, Class, String) GetInstance.java:164
javax.net.ssl.SSLContext.getInstance(String) SSLContext.java:156
javax.net.ssl.SSLContext.getDefault() SSLContext.java:96
javax.net.ssl.SSLSocketFactory.getDefault() SSLSocketFactory.java:122
org.apache.http.impl.client.HttpClientBuilder.build() HttpClientBuilder.java
io.hawt.web.ProxyServlet.init(ServletConfig) ProxyServlet.java:152
org.eclipse.jetty.servlet.ServletHolder.initServlet() ServletHolder.java:612

Example 2:
java.io.FileInputStream.read() FileInputStream.java
java.io.DataInputStream.readInt() DataInputStream.java:388
sun.security.provider.JavaKeyStore.engineLoad(InputStream, char[]) JavaKeyStore.java:745
sun.security.provider.JavaKeyStore$JKS.engineLoad(InputStream, char[]) JavaKeyStore.java:55
java.security.KeyStore.load(InputStream, char[]) KeyStore.java:1445
sun.security.ssl.TrustManagerFactoryImpl.getCacertsKeyStore(String) TrustManagerFactoryImpl.java:226
sun.security.ssl.TrustManagerFactoryImpl.engineInit(KeyStore) TrustManagerFactoryImpl.java:50
javax.net.ssl.TrustManagerFactory.init(KeyStore) TrustManagerFactory.java:250
shaded.org.apache.http.conn.ssl.SSLContextBuilder.loadTrustMaterial(KeyStore, TrustStrategy) SSLContextBuilder.java:103

JUSTIFICATION :
Many libraries, client applications (like Maven) and application servers initialise SSL on startup, reducing of time to load SSL kestores will reduce startup time for such applications.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
TrustManagerFactoryImpl or JavaKeyStore wrap the FileInputStream into a BufferedInputStream which reduces number of actual file reads
ACTUAL -
JavaKeyStore reads from a raw FileInputStream small portions of data multiple times.


Comments
Changeset: 2af869b1 Branch: master Author: Artur Barashev <abarashev@openjdk.org> Date: 2025-06-24 15:32:13 +0000 URL: https://git.openjdk.org/jdk/commit/2af869b193017bbd8bec4cfef9f0870de6ec1285
24-06-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/25920 Date: 2025-06-20 20:21:19 +0000
23-06-2025

These may have moved to a different file, possibly as part of the TLSv1.3 rewrite. During a RFE meeting, we noted: 1. Mentions of cacerts in TrustManagerFactoryImpl no longer exist. 2. The code mentioned in the bug description has been rewritten since the bug was filed. TrustManagerFactoryImpl does not currently use a FileInputStream, except in the private method TrustManagerFactoryImpl.getFileInputStream() which is no longer used. (can probably remove) 3. This issue may still apply to the current TrustStoreManager.java and SSLContextImpl.java, which create FileInputStreams without BufferedInputStreams. Should look around to see if there are other cases in the security-libs code that might benefit.
13-05-2022

If we want to make further evaluation, it may be time to consider asynchronous file channels instead.
12-05-2022

https://github.com/openjdk/jdk/blob/1904e9d280d1cce2deead4d4aa39dda1beb9dff1/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java#L388 Wrapping the FileInputStream in a BufferedInputStream in the code above might help. Some basic performance tests showing loading the cacerts keystore with and without a BufferedInputStream would be useful to see how much this helps.
12-05-2022