diff --git a/src/share/classes/com/sun/jndi/ldap/Connection.java b/src/share/classes/com/sun/jndi/ldap/Connection.java index 2807e19d36f27b25a133cb2b731e4db6a9f5a3ee..364f000c839ae089fa27f016103321119c752142 100644 --- a/src/share/classes/com/sun/jndi/ldap/Connection.java +++ b/src/share/classes/com/sun/jndi/ldap/Connection.java @@ -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); diff --git a/src/share/classes/sun/applet/AppletClassLoader.java b/src/share/classes/sun/applet/AppletClassLoader.java index 3489256ae4a2d24c4b098104eb3f703388041a64..0eeba1582dd58ce461e973d39a699e18f29bc362 100644 --- a/src/share/classes/sun/applet/AppletClassLoader.java +++ b/src/share/classes/sun/applet/AppletClassLoader.java @@ -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(); } diff --git a/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java b/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java index a182161271b52b66c57a050e3f177213456a287b..5515d93c423160ba34a5f0149a3ebd35145a5574 100644 --- a/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java +++ b/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java @@ -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); } } diff --git a/src/share/classes/sun/misc/IOUtils.java b/src/share/classes/sun/misc/IOUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..c6f4fb2a13b77c647fb2f1d8fe4276e513aaaa50 --- /dev/null +++ b/src/share/classes/sun/misc/IOUtils.java @@ -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 length of bytes from in + * 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; + } +} diff --git a/src/share/classes/sun/misc/Resource.java b/src/share/classes/sun/misc/Resource.java index 0c3579bc33456a50e63c88e0dafbf36dff94b3a7..43a82b03a70efa5e81123a0318a84881f5616d95 100644 --- a/src/share/classes/sun/misc/Resource.java +++ b/src/share/classes/sun/misc/Resource.java @@ -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; } - // 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; + 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; + } } + pos += cc; } } finally { try { diff --git a/src/share/classes/sun/reflect/misc/MethodUtil.java b/src/share/classes/sun/reflect/misc/MethodUtil.java index 09b14f521d1dcc7e4d145fd0238f2eedb64a69e5..39fa2d8afe99388dfb07d94dcf9524cb929c14db 100644 --- a/src/share/classes/sun/reflect/misc/MethodUtil.java +++ b/src/share/classes/sun/reflect/misc/MethodUtil.java @@ -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(); } diff --git a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java index 04e0649d8ffc0a5188cca9dd0baf2d6410177f17..b9d246c20b0305219804bf4749a892757a4b6184 100644 --- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java +++ b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java @@ -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); diff --git a/src/share/classes/sun/security/timestamp/HttpTimestamper.java b/src/share/classes/sun/security/timestamp/HttpTimestamper.java index bb73514115975217496d8ba5b6f452dd044ab8ea..04c0b67ee82ac42b770afbc3a18c235a4e59501e 100644 --- a/src/share/classes/sun/security/timestamp/HttpTimestamper.java +++ b/src/share/classes/sun/security/timestamp/HttpTimestamper.java @@ -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=" + diff --git a/src/share/classes/sun/security/util/DerValue.java b/src/share/classes/sun/security/util/DerValue.java index 114788beb266550f0fb8b7e386a25d56764ddb23..c0f920d5e332370b7cfed5a987e8df06c00ef58a 100644 --- a/src/share/classes/sun/security/util/DerValue.java +++ b/src/share/classes/sun/security/util/DerValue.java @@ -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); } diff --git a/test/sun/security/util/DerValue/BadValue.java b/test/sun/security/util/DerValue/BadValue.java new file mode 100644 index 0000000000000000000000000000000000000000..cbe2c6ab45fc65abc044d6c994b87ee82bda0fc6 --- /dev/null +++ b/test/sun/security/util/DerValue/BadValue.java @@ -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; + } + } +}