-
Bug
-
Resolution: Fixed
-
P3
-
8, 9
-
b15
-
generic
-
generic
-
Verified
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8275564 | 11.0.13 | Martin Balao Alonso | P3 | Resolved | Fixed | b01 |
JDK-8276283 | openjdk8u322 | Martin Balao Alonso | P3 | Resolved | Fixed | b01 |
JDK-8275549 | openjdk8u312 | Martin Balao Alonso | P3 | Resolved | Fixed | b07 |
JDK-8275629 | openjdk7u | Martin Balao Alonso | P3 | Resolved | Fixed | master |
FULL PRODUCT VERSION :
A DESCRIPTION OF THE PROBLEM :
When loading a PKCS12 file (that has a big undefined length DER value in it), i noticed that the loading succeeds when i load it from file directly, but fails when loaded though a servlet:
Exception in thread "main" java.io.IOException: not all indef len BER resolved
at sun.security.util.DerIndefLenConverter.convert(DerIndefLenConverter.java:340)
at sun.security.util.DerValue.init(DerValue.java:376)
at sun.security.util.DerValue.<init>(DerValue.java:320)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1914)
at java.security.KeyStore.load(KeyStore.java:1445)
When loading through a servlet, the container is using a SequenceInputStream (first x bytes are in memory, rest on disk).
Root cause analysis:
When loading a PKCS12 that has an 'indefinite length' value in it, the decoder assumes that stream.available represents the complete 'indefinite.length' section. However, this is not always the case. When using eg a SequenceInputStream, available will only return the available size of one element of the sequence, not the complete sequence.
Relevant code in sun.security.util.DerValue:
if(this.length == -1) {
int bytes = ((InputStream)in).available();
byte offset = 2;
byte[] indefData = new byte[bytes + offset];
indefData[0] = this.tag;
indefData[1] = lenByte;
DataInputStream dis = new DataInputStream((InputStream)in);
dis.readFully(indefData, offset, bytes);
dis.close();
DerIndefLenConverter derIn = new DerIndefLenConverter();
in = new ByteArrayInputStream(derIn.convert(indefData));
if(this.tag != ((InputStream)in).read()) {
throw new IOException("Indefinite length encoding not supported");
}
this.length = DerInputStream.getLength((InputStream)in);
}
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public static void main(String[] args) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException
{
KeyStore p12 = KeyStore.getInstance("pkcs12");
File file = new File("test.p12");
ByteArrayOutputStream os = new ByteArrayOutputStream();
java.nio.file.Files.copy(file.toPath(), os);
os.flush();
byte[] bytes = os.toByteArray();
p12.load(new ByteArrayInputStream(bytes), "motive".toCharArray());
int split = 10;
p12.load(createSplitStream(bytes, split), "motive".toCharArray());
}
private static SequenceInputStream createSplitStream(byte[] bytes, int split) {
return new SequenceInputStream(new ByteArrayInputStream(bytes, 0, split), new ByteArrayInputStream(bytes, split, bytes.length - split));
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Workaround is to store the stream i get from our servlet to a bytearray first and then pass a bytearraystream to keystore.load
A DESCRIPTION OF THE PROBLEM :
When loading a PKCS12 file (that has a big undefined length DER value in it), i noticed that the loading succeeds when i load it from file directly, but fails when loaded though a servlet:
Exception in thread "main" java.io.IOException: not all indef len BER resolved
at sun.security.util.DerIndefLenConverter.convert(DerIndefLenConverter.java:340)
at sun.security.util.DerValue.init(DerValue.java:376)
at sun.security.util.DerValue.<init>(DerValue.java:320)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1914)
at java.security.KeyStore.load(KeyStore.java:1445)
When loading through a servlet, the container is using a SequenceInputStream (first x bytes are in memory, rest on disk).
Root cause analysis:
When loading a PKCS12 that has an 'indefinite length' value in it, the decoder assumes that stream.available represents the complete 'indefinite.length' section. However, this is not always the case. When using eg a SequenceInputStream, available will only return the available size of one element of the sequence, not the complete sequence.
Relevant code in sun.security.util.DerValue:
if(this.length == -1) {
int bytes = ((InputStream)in).available();
byte offset = 2;
byte[] indefData = new byte[bytes + offset];
indefData[0] = this.tag;
indefData[1] = lenByte;
DataInputStream dis = new DataInputStream((InputStream)in);
dis.readFully(indefData, offset, bytes);
dis.close();
DerIndefLenConverter derIn = new DerIndefLenConverter();
in = new ByteArrayInputStream(derIn.convert(indefData));
if(this.tag != ((InputStream)in).read()) {
throw new IOException("Indefinite length encoding not supported");
}
this.length = DerInputStream.getLength((InputStream)in);
}
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public static void main(String[] args) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException
{
KeyStore p12 = KeyStore.getInstance("pkcs12");
File file = new File("test.p12");
ByteArrayOutputStream os = new ByteArrayOutputStream();
java.nio.file.Files.copy(file.toPath(), os);
os.flush();
byte[] bytes = os.toByteArray();
p12.load(new ByteArrayInputStream(bytes), "motive".toCharArray());
int split = 10;
p12.load(createSplitStream(bytes, split), "motive".toCharArray());
}
private static SequenceInputStream createSplitStream(byte[] bytes, int split) {
return new SequenceInputStream(new ByteArrayInputStream(bytes, 0, split), new ByteArrayInputStream(bytes, split, bytes.length - split));
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Workaround is to store the stream i get from our servlet to a bytearray first and then pass a bytearraystream to keystore.load
- backported by
-
JDK-8275549 Unable to read certain PKCS12 keystores from SequenceInputStream
- Resolved
-
JDK-8275564 Unable to read certain PKCS12 keystores from SequenceInputStream
- Resolved
-
JDK-8275629 Unable to read certain PKCS12 keystores from SequenceInputStream
- Resolved
-
JDK-8276283 Unable to read certain PKCS12 keystores from SequenceInputStream
- Resolved