From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- .../classpath/gnu/java/security/der/BitString.java | 332 ++++++++++++++++ libjava/classpath/gnu/java/security/der/DER.java | 86 ++++ .../java/security/der/DEREncodingException.java | 54 +++ .../classpath/gnu/java/security/der/DERReader.java | 439 +++++++++++++++++++++ .../classpath/gnu/java/security/der/DERValue.java | 189 +++++++++ .../classpath/gnu/java/security/der/DERWriter.java | 355 +++++++++++++++++ .../classpath/gnu/java/security/der/package.html | 46 +++ 7 files changed, 1501 insertions(+) create mode 100644 libjava/classpath/gnu/java/security/der/BitString.java create mode 100644 libjava/classpath/gnu/java/security/der/DER.java create mode 100644 libjava/classpath/gnu/java/security/der/DEREncodingException.java create mode 100644 libjava/classpath/gnu/java/security/der/DERReader.java create mode 100644 libjava/classpath/gnu/java/security/der/DERValue.java create mode 100644 libjava/classpath/gnu/java/security/der/DERWriter.java create mode 100644 libjava/classpath/gnu/java/security/der/package.html (limited to 'libjava/classpath/gnu/java/security/der') diff --git a/libjava/classpath/gnu/java/security/der/BitString.java b/libjava/classpath/gnu/java/security/der/BitString.java new file mode 100644 index 000000000..ac10be22e --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/BitString.java @@ -0,0 +1,332 @@ +/* BitString.java -- Java representation of the BIT STRING type. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.der; + +import gnu.java.lang.CPStringBuilder; + +import java.math.BigInteger; +import java.util.Arrays; + +/** + * Immutable representation of a bit string, which is equivalent to a + * byte array except some number of the rightmost bits are ignored. For + * example, this could be the bit string: + * + *
   00010101 11101101 11010xxx
+ * + *

Where the "xxx" represents three bits that should be ignored, and + * can have any value. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class BitString implements Cloneable, Comparable +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The bits themselves. */ + private final byte[] bytes; + + /** + * The exportable byte array. This array has the ignored bits + * removed. + */ + private transient byte[] externBytes; + + /** The number of bits ignored at the end of the byte array. */ + private final int ignoredBits; + + /** This bit string as a boolean array. */ + private transient boolean[] boolVal; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new bit string, shifting the given byte array if needed. + * + * @param bytes The byte array holding the bit string. + * @param ignoredBits The number of bits to ignore. + * @param doShift Pass true in this parameter if the byte array has + * not yet been shifted left by ignoredBits. + * @throws IllegalArgumentException If ignoredBits is negative + * or greater than 7. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int ignoredBits, boolean doShift) + { + this(bytes, 0, bytes.length, ignoredBits, doShift); + } + + /** + * Create a new bit string, shifting the given byte array if needed. + * + * @param bytes The byte array holding the bit string. + * @param offset The offset where the meaningful bytes begin. + * @param length The number of meaningful bytes. + * @param ignoredBits The number of bits to ignore. + * @param doShift Pass true in this parameter if the byte array has + * not yet been shifted left by ignoredBits. + * @throws IllegalArgumentException If ignoredBits is negative + * or greater than 7. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int offset, int length, + int ignoredBits, boolean doShift) + { + if (ignoredBits < 0 || ignoredBits > 7) + throw new IllegalArgumentException(); + if (bytes == null) + throw new NullPointerException(); + if (doShift && ignoredBits > 0) + { + this.externBytes = new byte[length]; + System.arraycopy(bytes, offset, externBytes, 0, length); + this.bytes = new BigInteger(externBytes).shiftLeft(ignoredBits) + .toByteArray(); + } + else + { + this.bytes = new byte[length]; + System.arraycopy(bytes, offset, this.bytes, 0, length); + } + this.ignoredBits = ignoredBits; + } + + /** + * Create a new bit string. + * + * @param bytes The byte array holding the bit string. + * @param offset The offset where the meaningful bytes begin. + * @param length The number of meaningful bytes. + * @param ignoredBits The number of bits to ignore. + * @throws IllegalArgumentException If ignoredBits is negative + * or greater than 7. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int offset, int length, int ignoredBits) + { + this(bytes, offset, length, ignoredBits, false); + } + + /** + * Create a new bit string. + * + * @param bytes The byte array holding the bit string. + * @param ignoredBits The number of bits to ignore. + * @throws IllegalArgumentException If ignoredBits is negative + * or greater than 7. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int ignoredBits) + { + this(bytes, 0, bytes.length, ignoredBits, false); + } + + /** + * Create a new bit string. + * + * @param bytes The byte array holding the bit string. + * @param offset The offset where the meaningful bytes begin. + * @param length The number of meaningful bytes. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int offset, int length) + { + this(bytes, offset, length, 0, false); + } + + /** + * Create a new bit string. + * + * @param bytes The byte array holding the bit string. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes) + { + this(bytes, 0, bytes.length, 0, false); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Return this bit string as a byte array, with the ignored bits + * trimmed off. The byte array is cloned every time this method is + * called to prevent modification. + * + * @return The trimmed byte array. + */ + public byte[] toByteArray() + { + if (ignoredBits == 0) + return (byte[]) bytes.clone(); + if (externBytes == null) + externBytes = new BigInteger(bytes).shiftRight(ignoredBits).toByteArray(); + return (byte[]) externBytes.clone(); + } + + /** + * Returns this bit string as a byte array, with the ignored bits + * present. The byte array is cloned every time this method is + * called to prevent modification. + * + * @return The byte array. + */ + public byte[] getShiftedByteArray() + { + return (byte[]) bytes.clone(); + } + + /** + * Returns the number of ignored bits. + * + * @return The number of ignored bits. + */ + public int getIgnoredBits() + { + return ignoredBits; + } + + /** + * Returns the size, in bits, of this bit string. + * + * @return The size of this bit string. + */ + public int size() + { + return (bytes.length << 3) - ignoredBits; + } + + /** + * Return this bit string as a boolean array. The value returned is of + * size {@link #size()}, and each true value + * corresponding to each "1" in this bit string. The boolean array is + * cloned before it is returned. + * + * @return The boolean array. + */ + public boolean[] toBooleanArray() + { + if (boolVal == null) + { + boolVal = new boolean[size()]; + for (int i = 0, j = 7, k = 0; i < boolVal.length; i++) + { + boolVal[i] = (bytes[k] & 1 << j--) != 0; + if (j < 0) + { + j = 7; + k++; + } + } + } + return (boolean[]) boolVal.clone(); + } + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException cce) + { + throw new InternalError(cce.getMessage()); + } + } + + public int compareTo(Object o) + { + BitString that = (BitString) o; + if (this.equals(that)) + return 0; + if (this.bytes.length != that.bytes.length) + return (this.bytes.length < that.bytes.length) ? -1 : 1; + if (this.ignoredBits != that.ignoredBits) + return (this.ignoredBits < that.ignoredBits) ? -1 : 1; + for (int i = 0; i < this.bytes.length; i++) + if (this.bytes[i] != that.bytes[i]) + return (this.bytes[i] < that.bytes[i]) ? -1 : 1; + return 0; // not reached. + } + + public int hashCode() + { + int result = 0; + for (int i = 0; i < bytes.length - 1; ++i) + result = result * 31 + bytes[i]; + if (bytes.length > 0) + { + int lastByte = bytes[bytes.length - 1] & ~ ((1 << ignoredBits) - 1); + result = result * 31 + lastByte; + } + return result; + } + + public boolean equals(Object o) + { + if (!(o instanceof BitString)) + return false; + BitString that = (BitString) o; + // True for cloned instances. + if (this.bytes == that.bytes && this.ignoredBits == that.ignoredBits) + return true; + if (this.ignoredBits == that.ignoredBits) + return Arrays.equals(this.bytes, that.bytes); + return false; + } + + public String toString() + { + CPStringBuilder sb = new CPStringBuilder(); + for (int i = 0, j = 7, k = 0; i < size(); i++) + { + sb.append((bytes[k] & 1 << j) != 0 ? "1" : "0"); + j--; + if (j < 0) + { + j = 7; + k++; + } + } + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/java/security/der/DER.java b/libjava/classpath/gnu/java/security/der/DER.java new file mode 100644 index 000000000..a7eb4a689 --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DER.java @@ -0,0 +1,86 @@ +/* DER.java -- Basic constants in DER sequences. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.der; + +/** + * The set of tags for DER types. + * + * @author Casey Marshall (csm@gnu.org) + */ +public interface DER +{ + int UNIVERSAL = 0x00; + int APPLICATION = 0x40; + int CONTEXT = 0x80; + int PRIVATE = 0xC0; + + int CONSTRUCTED = 0x20; + + int ANY = 0x00; + int BOOLEAN = 0x01; + int INTEGER = 0x02; + int BIT_STRING = 0x03; + int OCTET_STRING = 0x04; + int NULL = 0x05; + int OBJECT_IDENTIFIER = 0x06; + int REAL = 0x09; + int ENUMERATED = 0x0a; + int RELATIVE_OID = 0x0d; + + int SEQUENCE = 0x10; + int SET = 0x11; + + Object CONSTRUCTED_VALUE = new Object(); + + int NUMERIC_STRING = 0x12; + int PRINTABLE_STRING = 0x13; + int T61_STRING = 0x14; + int VIDEOTEX_STRING = 0x15; + int IA5_STRING = 0x16; + int GRAPHIC_STRING = 0x19; + int ISO646_STRING = 0x1A; + int GENERAL_STRING = 0x1B; + + int UTF8_STRING = 0x0C; + int UNIVERSAL_STRING = 0x1C; + int BMP_STRING = 0x1E; + + int UTC_TIME = 0x17; + int GENERALIZED_TIME = 0x18; +} diff --git a/libjava/classpath/gnu/java/security/der/DEREncodingException.java b/libjava/classpath/gnu/java/security/der/DEREncodingException.java new file mode 100644 index 000000000..90042a3fc --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DEREncodingException.java @@ -0,0 +1,54 @@ +/* DEREncodingException.java --- DER Encoding Exception + Copyright (C) 1999,2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.der; + +import java.io.IOException; + +public class DEREncodingException extends IOException +{ + public DEREncodingException() + { + super (); + } + + public DEREncodingException (String msg) + { + super (msg); + } +} diff --git a/libjava/classpath/gnu/java/security/der/DERReader.java b/libjava/classpath/gnu/java/security/der/DERReader.java new file mode 100644 index 000000000..cd552c8be --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DERReader.java @@ -0,0 +1,439 @@ +/* DERReader.java -- parses ASN.1 DER sequences + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.der; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.OID; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +/** + * This class decodes DER sequences into Java objects. The methods of + * this class do not have knowledge of higher-levels of structure in the + * DER stream -- such as ASN.1 constructions -- and it is therefore up + * to the calling application to determine if the data are structured + * properly by inspecting the {@link DERValue} that is returned. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class DERReader implements DER +{ + + // Fields. + // ------------------------------------------------------------------------ + + protected InputStream in; + + protected final ByteArrayOutputStream encBuf; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Create a new DER reader from a byte array. + * + * @param in The encoded bytes. + */ + public DERReader(byte[] in) + { + this(new ByteArrayInputStream(in)); + } + + public DERReader (byte[] in, int off, int len) + { + this (new ByteArrayInputStream (in, off, len)); + } + + /** + * Create a new DER readed from an input stream. + * + * @param in The encoded bytes. + */ + public DERReader(InputStream in) + { + if (!in.markSupported()) + this.in = new BufferedInputStream(in, 16384); + else + this.in = in; + encBuf = new ByteArrayOutputStream(2048); + } + + // Class methods. + // ------------------------------------------------------------------------ + + /** + * Convenience method for reading a single primitive value from the + * given byte array. + * + * @param encoded The encoded bytes. + * @throws IOException If the bytes do not represent an encoded + * object. + */ + public static DERValue read(byte[] encoded) throws IOException + { + return new DERReader(encoded).read(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public void skip (int bytes) throws IOException + { + in.skip (bytes); + } + + /** + * Decode a single value from the input stream, returning it in a new + * {@link DERValue}. By "single value" we mean any single type in its + * entirety -- including constructed types such as SEQUENCE and all + * the values they contain. Usually it is sufficient to call this + * method once to parse and return the top-level structure, then to + * inspect the returned value for the proper contents. + * + * @return The parsed DER structure. + * @throws IOException If an error occurs reading from the input + * stream. + * @throws DEREncodingException If the input does not represent a + * valid DER stream. + */ + public DERValue read() throws IOException + { + int tag = in.read(); + if (tag == -1) + throw new EOFException(); + encBuf.write(tag); + int len = readLength(); + DERValue value = null; + if ((tag & CONSTRUCTED) == CONSTRUCTED) + { + in.mark(2048); + byte[] encoded = new byte[len]; + in.read(encoded); + encBuf.write(encoded); + value = new DERValue(tag, len, CONSTRUCTED_VALUE, encBuf.toByteArray()); + in.reset(); + encBuf.reset(); + return value; + } + switch (tag & 0xC0) + { + case UNIVERSAL: + value = new DERValue(tag, len, readUniversal(tag, len), + encBuf.toByteArray()); + encBuf.reset(); + break; + case CONTEXT: + byte[] encoded = new byte[len]; + in.read(encoded); + encBuf.write(encoded); + value = new DERValue(tag, len, encoded, encBuf.toByteArray()); + encBuf.reset(); + break; + case APPLICATION: + // This should not be reached, since (I think) APPLICATION is + // always constructed. + throw new DEREncodingException("non-constructed APPLICATION data"); + default: + throw new DEREncodingException("PRIVATE class not supported"); + } + return value; + } + + protected int readLength() throws IOException + { + int i = in.read(); + if (i == -1) + throw new EOFException(); + encBuf.write(i); + if ((i & ~0x7F) == 0) + { + return i; + } + else if (i < 0xFF) + { + byte[] octets = new byte[i & 0x7F]; + in.read(octets); + encBuf.write(octets); + return new BigInteger(1, octets).intValue(); + } + throw new DEREncodingException(); + } + + // Own methods. + // ------------------------------------------------------------------------ + + private Object readUniversal(int tag, int len) throws IOException + { + byte[] value = new byte[len]; + in.read(value); + encBuf.write(value); + switch (tag & 0x1F) + { + case BOOLEAN: + if (value.length != 1) + throw new DEREncodingException(); + return Boolean.valueOf(value[0] != 0); + case NULL: + if (len != 0) + throw new DEREncodingException(); + return null; + case INTEGER: + case ENUMERATED: + return new BigInteger(value); + case BIT_STRING: + byte[] bits = new byte[len - 1]; + System.arraycopy(value, 1, bits, 0, bits.length); + return new BitString(bits, value[0] & 0xFF); + case OCTET_STRING: + return value; + case NUMERIC_STRING: + case PRINTABLE_STRING: + case T61_STRING: + case VIDEOTEX_STRING: + case IA5_STRING: + case GRAPHIC_STRING: + case ISO646_STRING: + case GENERAL_STRING: + case UNIVERSAL_STRING: + case BMP_STRING: + case UTF8_STRING: + return makeString(tag, value); + case UTC_TIME: + case GENERALIZED_TIME: + return makeTime(tag, value); + case OBJECT_IDENTIFIER: + return new OID(value); + case RELATIVE_OID: + return new OID(value, true); + default: + throw new DEREncodingException("unknown tag " + tag); + } + } + + private static String makeString(int tag, byte[] value) + throws IOException + { + switch (tag & 0x1F) + { + case NUMERIC_STRING: + case PRINTABLE_STRING: + case T61_STRING: + case VIDEOTEX_STRING: + case IA5_STRING: + case GRAPHIC_STRING: + case ISO646_STRING: + case GENERAL_STRING: + return fromIso88591(value); + + case UNIVERSAL_STRING: + // XXX The docs say UniversalString is encoded in four bytes + // per character, but Java has no support (yet) for UTF-32. + //return new String(buf, "UTF-32"); + case BMP_STRING: + return fromUtf16Be(value); + + case UTF8_STRING: + return fromUtf8(value); + + default: + throw new DEREncodingException("unknown string tag"); + } + } + + private static String fromIso88591(byte[] bytes) + { + CPStringBuilder str = new CPStringBuilder(bytes.length); + for (int i = 0; i < bytes.length; i++) + str.append((char) (bytes[i] & 0xFF)); + return str.toString(); + } + + private static String fromUtf16Be(byte[] bytes) throws IOException + { + if ((bytes.length & 0x01) != 0) + throw new IOException("UTF-16 bytes are odd in length"); + CPStringBuilder str = new CPStringBuilder(bytes.length / 2); + for (int i = 0; i < bytes.length; i += 2) + { + char c = (char) ((bytes[i] << 8) & 0xFF); + c |= (char) (bytes[i+1] & 0xFF); + str.append(c); + } + return str.toString(); + } + + private static String fromUtf8(byte[] bytes) throws IOException + { + CPStringBuilder str = new CPStringBuilder((int)(bytes.length / 1.5)); + for (int i = 0; i < bytes.length; ) + { + char c = 0; + if ((bytes[i] & 0xE0) == 0xE0) + { + if ((i + 2) >= bytes.length) + throw new IOException("short UTF-8 input"); + c = (char) ((bytes[i++] & 0x0F) << 12); + if ((bytes[i] & 0x80) != 0x80) + throw new IOException("malformed UTF-8 input"); + c |= (char) ((bytes[i++] & 0x3F) << 6); + if ((bytes[i] & 0x80) != 0x80) + throw new IOException("malformed UTF-8 input"); + c |= (char) (bytes[i++] & 0x3F); + } + else if ((bytes[i] & 0xC0) == 0xC0) + { + if ((i + 1) >= bytes.length) + throw new IOException("short input"); + c = (char) ((bytes[i++] & 0x1F) << 6); + if ((bytes[i] & 0x80) != 0x80) + throw new IOException("malformed UTF-8 input"); + c |= (char) (bytes[i++] & 0x3F); + } + else if ((bytes[i] & 0xFF) < 0x80) + { + c = (char) (bytes[i++] & 0xFF); + } + else + throw new IOException("badly formed UTF-8 sequence"); + str.append(c); + } + return str.toString(); + } + + private Date makeTime(int tag, byte[] value) throws IOException + { + Calendar calendar = Calendar.getInstance(); + String str = makeString(PRINTABLE_STRING, value); + + // Classpath's SimpleDateFormat does not work for parsing these + // types of times, so we do this by hand. + String date = str; + String tz = ""; + if (str.indexOf("+") > 0) + { + date = str.substring(0, str.indexOf("+")); + tz = str.substring(str.indexOf("+")); + } + else if (str.indexOf("-") > 0) + { + date = str.substring(0, str.indexOf("-")); + tz = str.substring(str.indexOf("-")); + } + else if (str.endsWith("Z")) + { + date = str.substring(0, str.length()-2); + tz = "Z"; + } + if (!tz.equals("Z") && tz.length() > 0) + calendar.setTimeZone(TimeZone.getTimeZone(tz)); + else + calendar.setTimeZone(TimeZone.getTimeZone("UTC")); + if ((tag & 0x1F) == UTC_TIME) + { + if (date.length() < 10) // must be at least 10 chars long + throw new DEREncodingException("cannot parse date"); + // UTCTime is of the form "yyMMddHHmm[ss](Z|(+|-)hhmm)" + try + { + int year = Integer.parseInt(str.substring(0, 2)); + if (year < 50) + year += 2000; + else + year += 1900; + calendar.set(year, + Integer.parseInt(str.substring( 2, 4))-1, // month + Integer.parseInt(str.substring( 4, 6)), // day + Integer.parseInt(str.substring( 6, 8)), // hour + Integer.parseInt(str.substring( 8, 10))); // minute + if (date.length() == 12) + calendar.set(Calendar.SECOND, + Integer.parseInt(str.substring(10, 12))); + } + catch (NumberFormatException nfe) + { + throw new DEREncodingException("cannot parse date"); + } + } + else + { + if (date.length() < 10) // must be at least 10 chars long + throw new DEREncodingException("cannot parse date"); + // GeneralTime is of the form "yyyyMMddHH[mm[ss[(.|,)SSSS]]]" + // followed by "Z" or "(+|-)hh[mm]" + try + { + calendar.set( + Integer.parseInt(date.substring(0, 4)), // year + Integer.parseInt(date.substring(4, 6))-1, // month + Integer.parseInt(date.substring(6, 8)), // day + Integer.parseInt(date.substring(8, 10)), 0); // hour, min + switch (date.length()) + { + case 19: + case 18: + case 17: + case 16: + calendar.set(Calendar.MILLISECOND, + Integer.parseInt(date.substring(15))); + case 14: + calendar.set(Calendar.SECOND, + Integer.parseInt(date.substring(12, 14))); + case 12: + calendar.set(Calendar.MINUTE, + Integer.parseInt(date.substring(10, 12))); + } + } + catch (NumberFormatException nfe) + { + throw new DEREncodingException("cannot parse date"); + } + } + return calendar.getTime(); + } +} diff --git a/libjava/classpath/gnu/java/security/der/DERValue.java b/libjava/classpath/gnu/java/security/der/DERValue.java new file mode 100644 index 000000000..2cbe34573 --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DERValue.java @@ -0,0 +1,189 @@ +/* DERValue.java -- a value read or written to a DER encoding. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.der; + +import gnu.java.security.x509.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class DERValue implements DER +{ + + // Fields. + // ------------------------------------------------------------------------ + + private final int tagClass; + private final boolean constructed; + private final int tag; + private int length; + private final Object value; + private byte[] encoded; + + // Constructor. + // ------------------------------------------------------------------------ + + public DERValue(int tag, int length, Object value, byte[] encoded) + { + tagClass = tag & 0xC0; + this.tag = tag & 0x1F; + constructed = (tag & CONSTRUCTED) == CONSTRUCTED; + this.length = length; + this.value = value; + if (encoded != null) + this.encoded = (byte[]) encoded.clone(); + } + + public DERValue(int tag, Object value) + { + this(tag, 0, value, null); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public int getExternalTag() + { + return tagClass | tag | (constructed ? 0x20 : 0x00); + } + + public int getTag() + { + return tag; + } + + public int getTagClass() + { + return tagClass; + } + + public boolean isConstructed() + { + return constructed; + } + + public int getLength() + { + if (encoded == null) + { + try + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + length = DERWriter.write(out, this); + encoded = out.toByteArray(); + } + catch (IOException ioe) + { + IllegalArgumentException iae = new IllegalArgumentException (); + iae.initCause (ioe); + throw iae; + } + } + return length; + } + + public Object getValue() + { + return value; + } + + public Object getValueAs (final int derType) throws IOException + { + byte[] encoded = getEncoded (); + encoded[0] = (byte) derType; + return DERReader.read (encoded).getValue (); + } + + public byte[] getEncoded() + { + if (encoded == null) + { + try + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + length = DERWriter.write(out, this); + encoded = out.toByteArray(); + } + catch (IOException ioe) + { + IllegalArgumentException iae = new IllegalArgumentException (); + iae.initCause (ioe); + throw iae; + } + } + return (byte[]) encoded.clone(); + } + + public int getEncodedLength() + { + if (encoded == null) + { + try + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + length = DERWriter.write(out, this); + encoded = out.toByteArray(); + } + catch (IOException ioe) + { + IllegalArgumentException iae = new IllegalArgumentException (); + iae.initCause (ioe); + throw iae; + } + } + return encoded.length; + } + + public String toString() + { + String start = "DERValue ( ["; + if (tagClass == DER.UNIVERSAL) + start = start + "UNIVERSAL "; + else if (tagClass == DER.PRIVATE) + start = start + "PRIVATE "; + else if (tagClass == DER.APPLICATION) + start = start + "APPLICATION "; + start = start + tag + "] constructed=" + constructed + ", value="; + if (constructed) + start = start + "\n" + Util.hexDump(getEncoded(), "\t"); + else + start = start + value; + return start + " )"; + } +} diff --git a/libjava/classpath/gnu/java/security/der/DERWriter.java b/libjava/classpath/gnu/java/security/der/DERWriter.java new file mode 100644 index 000000000..0c2633605 --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DERWriter.java @@ -0,0 +1,355 @@ +/* DERWriter.java -- write Java types in DER format. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.der; + +import gnu.java.security.OID; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.math.BigInteger; + +import java.text.SimpleDateFormat; + +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TimeZone; + +/** + * Methods that allow various Java types to be written as a DER + * (Distinguished Encoding Rules) stream to the specified output stream. + * DER is used to encode ASN.1 constructions, but this class provides no + * methods for interacting with ASN.1. Rather, callers should construct + * their output objects properly for whatever ASN.1 construct is being + * output. + * + *

This class only defines static methods; there are no instance + * variables needed. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class DERWriter implements DER +{ + + // Constructors. + // ------------------------------------------------------------------------ + + /** This class only has static methods. */ + private DERWriter() + { + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static int write(OutputStream out, DERValue object) + throws IOException + { + if (DER.CONSTRUCTED_VALUE.equals (object.getValue ())) + { + out.write (object.getEncoded ()); + return object.getLength (); + } + + out.write(object.getExternalTag()); + Object value = object.getValue(); + if (value == null) + { + writeLength(out, 0); + return 0; + } + if (value instanceof Boolean) + return writeBoolean(out, (Boolean) value); + else if (value instanceof BigInteger) + return writeInteger(out, (BigInteger) value); + else if (value instanceof Date) + return writeDate(out, object.getExternalTag(), (Date) value); + else if (value instanceof String) + return writeString(out, object.getExternalTag(), (String) value); + else if (value instanceof List) + return writeSequence(out, (List) value); + else if (value instanceof Set) + return writeSet(out, (Set) value); + else if (value instanceof BitString) + return writeBitString(out, (BitString) value); + else if (value instanceof OID) + return writeOID(out, (OID) value); + else if (value instanceof byte[]) + { + writeLength(out, ((byte[]) value).length); + out.write((byte[]) value); + return ((byte[]) value).length; + } + else if (value instanceof DERValue) + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + write(bout, (DERValue) value); + byte[] buf = bout.toByteArray(); + writeLength(out, buf.length); + out.write(buf); + return buf.length; + } + else + throw new DEREncodingException("cannot encode " + value.getClass().getName()); + } + + public static int definiteEncodingSize(int length) + { + if (length < 128) + return 1; + else if (length < 256) + return 2; + else if (length < 65536) + return 3; + else if (length < 16777216) + return 4; + else + return 5; + } + + // Own methods. + // ------------------------------------------------------------------------ + + /** + * Write a BOOLEAN type to the given output stream. + * + * @param out The sink output stream. + * @param b The boolean value to write. + */ + private static int writeBoolean(OutputStream out, Boolean b) + throws IOException + { + writeLength(out, 1); + if (b.booleanValue()) + out.write(0xFF); + else + out.write(0); + return 1; + } + + /** + * Write an INTEGER type to the given output stream. + * + * @param out The sink output stream. + * @param integer The integer to write. + */ + private static int writeInteger(OutputStream out, BigInteger integer) + throws IOException + { + byte[] bytes = integer.toByteArray(); + writeLength(out, bytes.length); + out.write(bytes); + return bytes.length; + } + + private static int writeSequence(OutputStream out, List sequence) + throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + for (Iterator i = sequence.iterator(); i.hasNext(); ) + { + write(bout, (DERValue) i.next()); + } + byte[] buf = bout.toByteArray(); + writeLength(out, buf.length); + out.write(buf); + return buf.length; + } + + private static int writeSet(OutputStream out, Set set) + throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + for (Iterator i = set.iterator(); i.hasNext(); ) + { + write(bout, (DERValue) i.next()); + } + byte[] buf = bout.toByteArray(); + writeLength(out, buf.length); + out.write(buf); + return buf.length; + } + + private static int writeOID(OutputStream out, OID oid) + throws IOException + { + byte[] der = oid.getDER(); + writeLength(out, der.length); + out.write(der); + return der.length; + } + + private static int writeBitString(OutputStream out, BitString bs) + throws IOException + { + byte[] buf = bs.getShiftedByteArray(); + writeLength(out, buf.length + 1); + out.write(bs.getIgnoredBits()); + out.write(buf); + return buf.length + 1; + } + + private static int writeString(OutputStream out, int tag, String str) + throws IOException + { + byte[] b = null; + switch (tag & 0x1F) + { + case NUMERIC_STRING: + case PRINTABLE_STRING: + case T61_STRING: + case VIDEOTEX_STRING: + case IA5_STRING: + case GRAPHIC_STRING: + case ISO646_STRING: + case GENERAL_STRING: + b = toIso88591(str); + break; + + case UNIVERSAL_STRING: + case BMP_STRING: + b = toUtf16Be(str); + break; + + case UTF8_STRING: + default: + b = toUtf8(str); + break; + } + writeLength(out, b.length); + out.write(b); + return b.length; + } + + private static byte[] toIso88591(String string) + { + byte[] result = new byte[string.length()]; + for (int i = 0; i < string.length(); i++) + result[i] = (byte) string.charAt(i); + return result; + } + + private static byte[] toUtf16Be(String string) + { + byte[] result = new byte[string.length() * 2]; + for (int i = 0; i < string.length(); i++) + { + result[i*2 ] = (byte) ((string.charAt(i) >>> 8) & 0xFF); + result[i*2+1] = (byte) (string.charAt(i) & 0xFF); + } + return result; + } + + private static byte[] toUtf8(String string) + { + ByteArrayOutputStream buf = + new ByteArrayOutputStream((int)(string.length() * 1.5)); + for (int i = 0; i < string.length(); i++) + { + char c = string.charAt(i); + if (c < 0x0080) + buf.write(c & 0xFF); + else if (c < 0x0800) + { + buf.write(0xC0 | ((c >>> 6) & 0x3F)); + buf.write(0x80 | (c & 0x3F)); + } + else + { + buf.write(0xE0 | ((c >>> 12) & 0x0F)); + buf.write(0x80 | ((c >>> 6) & 0x3F)); + buf.write(0x80 | (c & 0x3F)); + } + } + return buf.toByteArray(); + } + + private static int writeDate(OutputStream out, int tag, Date date) + throws IOException + { + SimpleDateFormat sdf = null; + if ((tag & 0x1F) == UTC_TIME) + sdf = new SimpleDateFormat("yyMMddHHmmss'Z'"); + else + sdf = new SimpleDateFormat("yyyyMMddHHmmss'.'SSS'Z'"); + sdf.setTimeZone(TimeZone.getTimeZone("UTC")); + byte[] b = sdf.format(date).getBytes("ISO-8859-1"); + writeLength(out, b.length); + out.write(b); + return b.length; + } + + // Package method. + // ------------------------------------------------------------------------ + + static void writeLength(OutputStream out, int len) throws IOException + { + if (len < 128) + out.write(len); + else if (len < 256) + { + out.write(0x81); + out.write(len); + } + else if (len < 65536) + { + out.write(0x82); + out.write(len >> 8); + out.write(len); + } + else if (len < 16777216) + { + out.write(0x83); + out.write(len >> 16); + out.write(len >> 8); + out.write(len); + } + else + { + out.write(0x84); + out.write(len >> 24); + out.write(len >> 16); + out.write(len >> 8); + out.write(len); + } + } +} diff --git a/libjava/classpath/gnu/java/security/der/package.html b/libjava/classpath/gnu/java/security/der/package.html new file mode 100644 index 000000000..e74b0db4e --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.der + + +

+ + + -- cgit v1.2.3