FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) Client VM (build 25.60-b23, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]
EXTRA RELEVANT SYSTEM CONFIGURATION :
This issue relates to the following bug fix that was added in JRE 8 u60:
http://bugs.java.com/view_bug.do?bug_id=8062552
A DESCRIPTION OF THE PROBLEM :
Following a call to KeyStore.load() with non-null InputStream and password, the input stream appears to be closed, when using JRE 8 u60 with a default value for security property "keystore.type.compat" (true).
Using previous versions of JRE (e.g. u51) or with "keystore.type.compat" set to "false", the input stream remains open.
I haven't seen anything in documentation for https://docs.oracle.com/javase/8/docs/api/java/security/KeyStore.html#load-java.io.InputStream-char:A- that talks about JRE closing the stream, I think that should be left to the caller to manage.
REGRESSION. Last worked in version 8u51
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) Client VM (build 25.60-b23, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create an instance of JKS keystore (ks1)
2. Persist it on file system or in memory
3. Create a new instance of JKS keystore (ks2)
4. Open the input stream pointing at persisted keystore from step 2
5. Load ks2, using the input stream from 4
6. Attempt to access the input stream after the loading has completed (by performing a call to either .reset, .available, etc)
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expectation is that the stream can continue being used by the caller (e.g. in my application the stream was pointing to a JarInputStream, and the code was attempting to iterate through the Jar entries, processing some of them as keystores)
ACTUAL -
The actual result was IOException: Stream is closed being thrown when trying to use the stream that was passed to KeyStore.load.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.io.IOException: Stream Closed
at java.io.FileInputStream.available(Native Method)
or
java.io.IOException: Stream closed
at java.util.zip.ZipInputStream.ensureOpen(Unknown Source) ~[na:1.8.0_60]
at java.util.zip.ZipInputStream.getNextEntry(Unknown Source) ~[na:1.8.0_60]
at java.util.jar.JarInputStream.getNextEntry(Unknown Source) ~[na:1.8.0_60]
at java.util.jar.JarInputStream.getNextJarEntry(Unknown Source) ~[na:1.8.0_60]
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public class Foo {
public static void main(String[] args) {
try
{
KeyStore keystore1 = KeyStore.getInstance("JKS");
keystore1.load(null, null);
File temp = File.createTempFile("temp-file-name", ".tmp");
FileOutputStream fos = new FileOutputStream(temp);
keystore1.store(fos, "password".toCharArray());
fos.close();
FileInputStream fis = new FileInputStream(temp);
KeyStore keystore2 = KeyStore.getInstance("JKS");
keystore2.load(fis, "password".toCharArray());
fis.available(); // this throws IOException: stream closed since jre8u60
fis.close();
}
catch (Exception e)
{
System.out.println(e);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Temporary workaround seems to be invoking:
Security.setProperty("keystore.type.compat", "false");
on application/applet initialization.