6864911: ASN.1/DER input stream parser needs more work

Reviewed-by: mullan, xuelei
This commit is contained in:
Weijun Wang 2009-08-18 12:10:12 +08:00
parent 04185fd4b8
commit 94bafe8b8f
10 changed files with 251 additions and 174 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 Sun Microsystems, Inc. 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
@ -32,12 +32,8 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.net.Socket;
import java.util.Vector;
import java.util.Hashtable;
import javax.naming.CommunicationException;
import javax.naming.AuthenticationException;
import javax.naming.AuthenticationNotSupportedException;
import javax.naming.ServiceUnavailableException;
import javax.naming.NamingException;
import javax.naming.InterruptedNamingException;
@ -47,6 +43,8 @@ import javax.naming.ldap.Control;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import sun.misc.IOUtils;
//import javax.net.SocketFactory;
/**
@ -799,7 +797,6 @@ public final class Connection implements Runnable {
byte inbuf[]; // Buffer for reading incoming bytes
int inMsgId; // Message id of incoming response
int bytesread; // Number of bytes in inbuf
int bytesleft; // Number of bytes that need to read for completing resp
int br; // Temp; number of bytes read from stream
int offset; // Offset of where to store bytes in inbuf
int seqlen; // Length of ASN sequence
@ -811,7 +808,7 @@ public final class Connection implements Runnable {
try {
while (true) {
try {
inbuf = new byte[2048];
inbuf = new byte[10];
offset = 0;
seqlen = 0;
@ -871,19 +868,10 @@ public final class Connection implements Runnable {
}
// read in seqlen bytes
bytesleft = seqlen;
if ((offset + bytesleft) > inbuf.length) {
byte nbuf[] = new byte[offset + bytesleft];
System.arraycopy(inbuf, 0, nbuf, 0, offset);
inbuf = nbuf;
}
while (bytesleft > 0) {
bytesread = in.read(inbuf, offset, bytesleft);
if (bytesread < 0)
break; // EOF
offset += bytesread;
bytesleft -= bytesread;
}
byte[] left = IOUtils.readFully(in, seqlen, false);
inbuf = Arrays.copyOf(inbuf, offset + left.length);
System.arraycopy(left, 0, inbuf, offset, left.length);
offset += left.length;
/*
if (dump > 0) {
System.err.println("seqlen: " + seqlen);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1995-2005 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1995-2009 Sun Microsystems, Inc. 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
@ -51,6 +51,7 @@ import java.security.Permission;
import java.security.PermissionCollection;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
import sun.misc.IOUtils;
import sun.net.www.ParseUtil;
import sun.security.util.SecurityConstants;
@ -331,36 +332,7 @@ public class AppletClassLoader extends URLClassLoader {
byte[] b;
try {
if (len != -1) {
// Read exactly len bytes from the input stream
b = new byte[len];
while (len > 0) {
int n = in.read(b, b.length - len, len);
if (n == -1) {
throw new IOException("unexpected EOF");
}
len -= n;
}
} else {
// Read until end of stream is reached - use 8K buffer
// to speed up performance [stanleyh]
b = new byte[8192];
int total = 0;
while ((len = in.read(b, total, b.length - total)) != -1) {
total += len;
if (total >= b.length) {
byte[] tmp = new byte[total * 2];
System.arraycopy(b, 0, tmp, 0, total);
b = tmp;
}
}
// Trim array to correct size, if necessary
if (total != b.length) {
byte[] tmp = new byte[total];
System.arraycopy(b, 0, tmp, 0, total);
b = tmp;
}
}
b = IOUtils.readFully(in, len, true);
} finally {
in.close();
}

View File

@ -26,9 +26,9 @@
package sun.dyn.anon;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import sun.misc.IOUtils;
/**
* Anonymous class loader. Will load any valid classfile, producing
@ -285,13 +285,6 @@ public class AnonymousClassLoader {
if (contentLength < 0)
throw new IOException("invalid content length "+contentLength);
byte[] classFile = new byte[contentLength];
InputStream tcs = connection.getInputStream();
for (int fill = 0, nr; fill < classFile.length; fill += nr) {
nr = tcs.read(classFile, fill, classFile.length - fill);
if (nr < 0)
throw new IOException("premature end of file");
}
return classFile;
return IOUtils.readFully(connection.getInputStream(), contentLength, true);
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2009 Sun Microsystems, Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* IOUtils: A collection of IO-related public static methods.
*/
package sun.misc;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
public class IOUtils {
/**
* Read up to <code>length</code> of bytes from <code>in</code>
* until EOF is detected.
* @param in input stream, must not be null
* @param length number of bytes to read, -1 or Integer.MAX_VALUE means
* read as much as possible
* @param readAll if true, an EOFException will be thrown if not enough
* bytes are read. Ignored when length is -1 or Integer.MAX_VALUE
* @return bytes read
* @throws IOException Any IO error or a premature EOF is detected
*/
public static byte[] readFully(InputStream is, int length, boolean readAll)
throws IOException {
byte[] output = {};
if (length == -1) length = Integer.MAX_VALUE;
int pos = 0;
while (pos < length) {
int bytesToRead;
if (pos >= output.length) { // Only expand when there's no room
bytesToRead = Math.min(length - pos, output.length + 1024);
if (output.length < pos + bytesToRead) {
output = Arrays.copyOf(output, pos + bytesToRead);
}
} else {
bytesToRead = output.length - pos;
}
int cc = is.read(output, pos, bytesToRead);
if (cc < 0) {
if (readAll && length != Integer.MAX_VALUE) {
throw new EOFException("Detect premature EOF");
} else {
if (output.length != pos) {
output = Arrays.copyOf(output, pos);
}
break;
}
}
pos += cc;
}
return output;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2009 Sun Microsystems, Inc. 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
@ -25,14 +25,15 @@
package sun.misc;
import java.io.EOFException;
import java.net.URL;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.InputStream;
import java.security.CodeSigner;
import java.util.jar.Manifest;
import java.util.jar.Attributes;
import java.nio.ByteBuffer;
import java.util.Arrays;
import sun.nio.ByteBuffered;
/**
@ -105,49 +106,37 @@ public abstract class Resource {
}
try {
if (len != -1) {
// Read exactly len bytes from the input stream
b = new byte[len];
while (len > 0) {
int n = 0;
try {
n = in.read(b, b.length - len, len);
} catch (InterruptedIOException iioe) {
Thread.interrupted();
isInterrupted = true;
b = new byte[0];
if (len == -1) len = Integer.MAX_VALUE;
int pos = 0;
while (pos < len) {
int bytesToRead;
if (pos >= b.length) { // Only expand when there's no room
bytesToRead = Math.min(len - pos, b.length + 1024);
if (b.length < pos + bytesToRead) {
b = Arrays.copyOf(b, pos + bytesToRead);
}
if (n == -1) {
throw new IOException("unexpected EOF");
}
len -= n;
} else {
bytesToRead = b.length - pos;
}
} else {
// Read until end of stream is reached
b = new byte[1024];
int total = 0;
for (;;) {
len = 0;
try {
len = in.read(b, total, b.length - total);
if (len == -1)
break;
} catch (InterruptedIOException iioe) {
Thread.interrupted();
isInterrupted = true;
}
total += len;
if (total >= b.length) {
byte[] tmp = new byte[total * 2];
System.arraycopy(b, 0, tmp, 0, total);
b = tmp;
int cc = 0;
try {
cc = in.read(b, pos, bytesToRead);
} catch (InterruptedIOException iioe) {
Thread.interrupted();
isInterrupted = true;
}
if (cc < 0) {
if (len != Integer.MAX_VALUE) {
throw new EOFException("Detect premature EOF");
} else {
if (b.length != pos) {
b = Arrays.copyOf(b, pos);
}
break;
}
}
// Trim array to correct size, if necessary
if (total != b.length) {
byte[] tmp = new byte[total];
System.arraycopy(b, 0, tmp, 0, total);
b = tmp;
}
pos += cc;
}
} finally {
try {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2005-2009 Sun Microsystems, Inc. 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
@ -44,6 +44,7 @@ import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import sun.misc.IOUtils;
import sun.net.www.ParseUtil;
import sun.security.util.SecurityConstants;
@ -373,34 +374,7 @@ public final class MethodUtil extends SecureClassLoader {
byte[] b;
try {
if (len != -1) {
// Read exactly len bytes from the input stream
b = new byte[len];
while (len > 0) {
int n = in.read(b, b.length - len, len);
if (n == -1) {
throw new IOException("unexpected EOF");
}
len -= n;
}
} else {
b = new byte[8192];
int total = 0;
while ((len = in.read(b, total, b.length - total)) != -1) {
total += len;
if (total >= b.length) {
byte[] tmp = new byte[total * 2];
System.arraycopy(b, 0, tmp, 0, total);
b = tmp;
}
}
// Trim array to correct size, if necessary
if (total != b.length) {
byte[] tmp = new byte[total];
System.arraycopy(b, 0, tmp, 0, total);
b = tmp;
}
}
b = IOUtils.readFully(in, len, true);
} finally {
in.close();
}

View File

@ -37,6 +37,7 @@ import java.security.cert.CertPathValidatorException.BasicReason;
import java.net.*;
import javax.security.auth.x500.X500Principal;
import sun.misc.IOUtils;
import sun.security.util.*;
import sun.security.x509.*;
@ -351,27 +352,8 @@ class OCSPChecker extends PKIXCertPathChecker {
}
in = con.getInputStream();
byte[] response = null;
int total = 0;
int contentLength = con.getContentLength();
if (contentLength != -1) {
response = new byte[contentLength];
} else {
response = new byte[2048];
contentLength = Integer.MAX_VALUE;
}
while (total < contentLength) {
int count = in.read(response, total, response.length - total);
if (count < 0)
break;
total += count;
if (total >= response.length && total < contentLength) {
response = Arrays.copyOf(response, total * 2);
}
}
response = Arrays.copyOf(response, total);
byte[] response = IOUtils.readFully(in, contentLength, false);
OCSPResponse ocspResponse = new OCSPResponse(response, pkixParams,
responderCert);

View File

@ -34,6 +34,7 @@ import java.util.Iterator;
import java.util.Set;
import java.util.Arrays;
import sun.misc.IOUtils;
import sun.security.pkcs.*;
/**
@ -142,25 +143,7 @@ public class HttpTimestamper implements Timestamper {
int total = 0;
int contentLength = connection.getContentLength();
if (contentLength != -1) {
replyBuffer = new byte[contentLength];
} else {
replyBuffer = new byte[2048];
contentLength = Integer.MAX_VALUE;
}
while (total < contentLength) {
int count = input.read(replyBuffer, total,
replyBuffer.length - total);
if (count < 0)
break;
total += count;
if (total >= replyBuffer.length && total < contentLength) {
replyBuffer = Arrays.copyOf(replyBuffer, total * 2);
}
}
replyBuffer = Arrays.copyOf(replyBuffer, total);
replyBuffer = IOUtils.readFully(input, contentLength, false);
if (DEBUG) {
System.out.println("received timestamp response (length=" +

View File

@ -28,6 +28,7 @@ package sun.security.util;
import java.io.*;
import java.math.BigInteger;
import java.util.Date;
import sun.misc.IOUtils;
/**
* Represents a single DER-encoded value. DER encoding rules are a subset
@ -382,12 +383,8 @@ public class DerValue {
if (fullyBuffered && in.available() != length)
throw new IOException("extra data given to DerValue constructor");
byte[] bytes = new byte[length];
byte[] bytes = IOUtils.readFully(in, length, true);
// n.b. readFully not needed in normal fullyBuffered case
DataInputStream dis = new DataInputStream(in);
dis.readFully(bytes);
buffer = new DerInputBuffer(bytes);
return new DerInputStream(buffer);
}

View File

@ -0,0 +1,119 @@
/*
* Copyright 2009 Sun Microsystems, Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6864911
* @summary ASN.1/DER input stream parser needs more work
*/
import java.io.*;
import sun.security.util.*;
import sun.misc.IOUtils;
public class BadValue {
public static void main(String[] args) throws Exception {
// Test IOUtils.readFully
// We have 4 bytes
InputStream in = new ByteArrayInputStream(new byte[10]);
byte[] bs = IOUtils.readFully(in, 4, true);
if (bs.length != 4 || in.available() != 6) {
throw new Exception("First read error");
}
// But only 6 left
bs = IOUtils.readFully(in, 10, false);
if (bs.length != 6 || in.available() != 0) {
throw new Exception("Second read error");
}
// MAX read as much as it can
in = new ByteArrayInputStream(new byte[10]);
bs = IOUtils.readFully(in, Integer.MAX_VALUE, true);
if (bs.length != 10 || in.available() != 0) {
throw new Exception("Second read error");
}
// MAX ignore readAll
in = new ByteArrayInputStream(new byte[10]);
bs = IOUtils.readFully(in, Integer.MAX_VALUE, false);
if (bs.length != 10 || in.available() != 0) {
throw new Exception("Second read error");
}
// 20>10, readAll means failure
in = new ByteArrayInputStream(new byte[10]);
try {
bs = IOUtils.readFully(in, 20, true);
throw new Exception("Third read error");
} catch (EOFException e) {
// OK
}
int bignum = 10 * 1024 * 1024;
bs = IOUtils.readFully(new SuperSlowStream(bignum), -1, true);
if (bs.length != bignum) {
throw new Exception("Fourth read error");
}
// Test DerValue
byte[] input = {0x04, (byte)0x84, 0x40, 0x00, 0x42, 0x46, 0x4b};
try {
new DerValue(new ByteArrayInputStream(input));
} catch (IOException ioe) {
// This is OK
}
}
}
/**
* An InputStream contains a given number of bytes, but only returns one byte
* per read.
*/
class SuperSlowStream extends InputStream {
private int p;
/**
* @param Initial capacity
*/
public SuperSlowStream(int capacity) {
p = capacity;
}
@Override
public int read() throws IOException {
if (p > 0) {
p--;
return 0;
} else {
return -1;
}
}
@Override
public int read(byte b[], int off, int len) throws IOException {
if (len == 0) return 0;
if (p > 0) {
p--;
b[off] = 0;
return 1;
} else {
return -1;
}
}
}