8157404: Unable to read certain PKCS12 keystores from SequenceInputStream

Reviewed-by: xuelei
This commit is contained in:
Weijun Wang 2019-04-02 10:17:30 +08:00
parent 460c22f03d
commit e0f37c15e4
3 changed files with 75 additions and 41 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,9 @@
package sun.security.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
/**
* A package private utility class to convert indefinite length DER
@ -143,6 +145,10 @@ class DerIndefLenConverter {
/**
* Parse the length and if it is an indefinite length then add
* the current position to the <code>ndefsList</code> vector.
*
* @return the length of definite length data next, or -1 if there is
* not enough bytes to determine it
* @throws IOException if invalid data is read
*/
private int parseLength() throws IOException {
int curLen = 0;
@ -160,7 +166,7 @@ class DerIndefLenConverter {
throw new IOException("Too much data");
}
if ((dataSize - dataPos) < (lenByte + 1)) {
throw new IOException("Too little data");
return -1;
}
for (int i = 0; i < lenByte; i++) {
curLen = (curLen << 8) + (data[dataPos++] & 0xff);
@ -314,10 +320,10 @@ class DerIndefLenConverter {
* @param indefData the byte array holding the indefinite
* length encoding.
* @return the byte array containing the definite length
* DER encoding.
* DER encoding, or null if there is not enough data.
* @exception IOException on parsing or re-writing errors.
*/
byte[] convert(byte[] indefData) throws IOException {
byte[] convertBytes(byte[] indefData) throws IOException {
data = indefData;
dataPos=0; index=0;
dataSize = data.length;
@ -328,6 +334,9 @@ class DerIndefLenConverter {
while (dataPos < dataSize) {
parseTag();
len = parseLength();
if (len < 0) {
return null;
}
parseValue(len);
if (unresolved == 0) {
unused = dataSize - dataPos;
@ -337,7 +346,7 @@ class DerIndefLenConverter {
}
if (unresolved != 0) {
throw new IOException("not all indef len BER resolved");
return null;
}
newData = new byte[dataSize + numOfTotalLenBytes + unused];
@ -354,4 +363,48 @@ class DerIndefLenConverter {
return newData;
}
/**
* Read the input stream into a DER byte array. If an indef len BER is
* not resolved this method will try to read more data until EOF is reached.
* This may block.
*
* @param in the input stream with tag and lenByte already read
* @param lenByte the length of the length field to remember
* @param tag the tag to remember
* @return a DER byte array
* @throws IOException if not all indef len BER
* can be resolved or another I/O error happens
*/
public static byte[] convertStream(InputStream in, byte lenByte, byte tag)
throws IOException {
int offset = 2; // for tag and length bytes
int readLen = in.available();
byte[] indefData = new byte[readLen + offset];
indefData[0] = tag;
indefData[1] = lenByte;
while (true) {
int bytesRead = in.readNBytes(indefData, offset, readLen);
if (bytesRead != readLen) {
readLen = bytesRead;
indefData = Arrays.copyOf(indefData, offset + bytesRead);
}
DerIndefLenConverter derIn = new DerIndefLenConverter();
byte[] result = derIn.convertBytes(indefData);
if (result == null) {
int next = in.read(); // This could block, but we need more
if (next == -1) {
throw new IOException("not all indef len BER resolved");
}
int more = in.available();
// expand array to include next and more
indefData = Arrays.copyOf(indefData, offset + readLen + 1 + more);
indefData[offset + readLen] = (byte)next;
offset = offset + readLen + 1;
readLen = more;
} else {
return result;
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,11 +27,9 @@ package sun.security.util;
import java.io.InputStream;
import java.io.IOException;
import java.io.EOFException;
import java.util.Date;
import java.util.Vector;
import java.math.BigInteger;
import java.io.DataInputStream;
/**
* A DER input stream, used for parsing ASN.1 DER-encoded data such as
@ -130,7 +128,12 @@ public class DerInputStream {
System.arraycopy(data, offset, inData, 0, len);
DerIndefLenConverter derIn = new DerIndefLenConverter();
buffer = new DerInputBuffer(derIn.convert(inData), allowBER);
byte[] result = derIn.convertBytes(inData);
if (result == null) {
throw new IOException("not all indef len BER resolved");
} else {
buffer = new DerInputBuffer(result, allowBER);
}
}
} else {
buffer = new DerInputBuffer(data, offset, len, allowBER);
@ -389,16 +392,9 @@ public class DerInputStream {
if (len == -1) {
// indefinite length encoding found
int readLen = buffer.available();
int offset = 2; // for tag and length bytes
byte[] indefData = new byte[readLen + offset];
indefData[0] = tag;
indefData[1] = lenByte;
DataInputStream dis = new DataInputStream(buffer);
dis.readFully(indefData, offset, readLen);
dis.close();
DerIndefLenConverter derIn = new DerIndefLenConverter();
buffer = new DerInputBuffer(derIn.convert(indefData), buffer.allowBER);
buffer = new DerInputBuffer(
DerIndefLenConverter.convertStream(buffer, lenByte, tag),
buffer.allowBER);
if (tag != buffer.read())
throw new IOException("Indefinite length encoding" +

View File

@ -1,5 +1,5 @@
/**
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -257,16 +257,9 @@ public class DerValue {
length = DerInputStream.getLength(lenByte, in);
if (length == -1) { // indefinite length encoding found
DerInputBuffer inbuf = in.dup();
int readLen = inbuf.available();
int offset = 2; // for tag and length bytes
byte[] indefData = new byte[readLen + offset];
indefData[0] = tag;
indefData[1] = lenByte;
DataInputStream dis = new DataInputStream(inbuf);
dis.readFully(indefData, offset, readLen);
dis.close();
DerIndefLenConverter derIn = new DerIndefLenConverter();
inbuf = new DerInputBuffer(derIn.convert(indefData), in.allowBER);
inbuf = new DerInputBuffer(
DerIndefLenConverter.convertStream(inbuf, lenByte, tag),
in.allowBER);
if (tag != inbuf.read())
throw new IOException
("Indefinite length encoding not supported");
@ -277,7 +270,7 @@ public class DerValue {
// indefinite form is encoded by sending a length field with a
// length of 0. - i.e. [1000|0000].
// the object is ended by sending two zero bytes.
in.skip(length + offset);
in.skip(length + 2);
} else {
buffer = in.dup();
@ -389,16 +382,8 @@ public class DerValue {
byte lenByte = (byte)in.read();
length = DerInputStream.getLength(lenByte, in);
if (length == -1) { // indefinite length encoding found
int readLen = in.available();
int offset = 2; // for tag and length bytes
byte[] indefData = new byte[readLen + offset];
indefData[0] = tag;
indefData[1] = lenByte;
DataInputStream dis = new DataInputStream(in);
dis.readFully(indefData, offset, readLen);
dis.close();
DerIndefLenConverter derIn = new DerIndefLenConverter();
in = new ByteArrayInputStream(derIn.convert(indefData));
in = new ByteArrayInputStream(
DerIndefLenConverter.convertStream(in, lenByte, tag));
if (tag != in.read())
throw new IOException
("Indefinite length encoding not supported");