001: /*
002: * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.security.util;
027:
028: import java.io.InputStream;
029: import java.io.IOException;
030: import java.io.EOFException;
031: import java.util.Date;
032: import java.util.Vector;
033: import java.math.BigInteger;
034: import java.io.DataInputStream;
035:
036: /**
037: * A DER input stream, used for parsing ASN.1 DER-encoded data such as
038: * that found in X.509 certificates. DER is a subset of BER/1, which has
039: * the advantage that it allows only a single encoding of primitive data.
040: * (High level data such as dates still support many encodings.) That is,
041: * it uses the "Definite" Encoding Rules (DER) not the "Basic" ones (BER).
042: *
043: * <P>Note that, like BER/1, DER streams are streams of explicitly
044: * tagged data values. Accordingly, this programming interface does
045: * not expose any variant of the java.io.InputStream interface, since
046: * that kind of input stream holds untagged data values and using that
047: * I/O model could prevent correct parsing of the DER data.
048: *
049: * <P>At this time, this class supports only a subset of the types of DER
050: * data encodings which are defined. That subset is sufficient for parsing
051: * most X.509 certificates.
052: *
053: * @version 1.67
054: *
055: * @author David Brownell
056: * @author Amit Kapoor
057: * @author Hemma Prafullchandra
058: */
059:
060: public class DerInputStream {
061:
062: /*
063: * This version only supports fully buffered DER. This is easy to
064: * work with, though if large objects are manipulated DER becomes
065: * awkward to deal with. That's where BER is useful, since BER
066: * handles streaming data relatively well.
067: */
068: DerInputBuffer buffer;
069:
070: /** The DER tag of the value; one of the tag_ constants. */
071: public byte tag;
072:
073: /**
074: * Create a DER input stream from a data buffer. The buffer is not
075: * copied, it is shared. Accordingly, the buffer should be treated
076: * as read-only.
077: *
078: * @param data the buffer from which to create the string (CONSUMED)
079: */
080: public DerInputStream(byte[] data) throws IOException {
081: init(data, 0, data.length);
082: }
083:
084: /**
085: * Create a DER input stream from part of a data buffer.
086: * The buffer is not copied, it is shared. Accordingly, the
087: * buffer should be treated as read-only.
088: *
089: * @param data the buffer from which to create the string (CONSUMED)
090: * @param offset the first index of <em>data</em> which will
091: * be read as DER input in the new stream
092: * @param len how long a chunk of the buffer to use,
093: * starting at "offset"
094: */
095: public DerInputStream(byte[] data, int offset, int len)
096: throws IOException {
097: init(data, offset, len);
098: }
099:
100: /*
101: * private helper routine
102: */
103: private void init(byte[] data, int offset, int len)
104: throws IOException {
105: if ((offset + 2 > data.length) || (offset + len > data.length)) {
106: throw new IOException("Encoding bytes too short");
107: }
108: // check for indefinite length encoding
109: if (DerIndefLenConverter.isIndefinite(data[offset + 1])) {
110: byte[] inData = new byte[len];
111: System.arraycopy(data, offset, inData, 0, len);
112:
113: DerIndefLenConverter derIn = new DerIndefLenConverter();
114: buffer = new DerInputBuffer(derIn.convert(inData));
115: } else
116: buffer = new DerInputBuffer(data, offset, len);
117: buffer.mark(Integer.MAX_VALUE);
118: }
119:
120: DerInputStream(DerInputBuffer buf) {
121: buffer = buf;
122: buffer.mark(Integer.MAX_VALUE);
123: }
124:
125: /**
126: * Creates a new DER input stream from part of this input stream.
127: *
128: * @param len how long a chunk of the current input stream to use,
129: * starting at the current position.
130: * @param do_skip true if the existing data in the input stream should
131: * be skipped. If this value is false, the next data read
132: * on this stream and the newly created stream will be the
133: * same.
134: */
135: public DerInputStream subStream(int len, boolean do_skip)
136: throws IOException {
137: DerInputBuffer newbuf = buffer.dup();
138:
139: newbuf.truncate(len);
140: if (do_skip) {
141: buffer.skip(len);
142: }
143: return new DerInputStream(newbuf);
144: }
145:
146: /**
147: * Return what has been written to this DerInputStream
148: * as a byte array. Useful for debugging.
149: */
150: public byte[] toByteArray() {
151: return buffer.toByteArray();
152: }
153:
154: /*
155: * PRIMITIVES -- these are "universal" ASN.1 simple types.
156: *
157: * INTEGER, ENUMERATED, BIT STRING, OCTET STRING, NULL
158: * OBJECT IDENTIFIER, SEQUENCE (OF), SET (OF)
159: * UTF8String, PrintableString, T61String, IA5String, UTCTime,
160: * GeneralizedTime, BMPString.
161: * Note: UniversalString not supported till encoder is available.
162: */
163:
164: /**
165: * Get an integer from the input stream as an integer.
166: *
167: * @return the integer held in this DER input stream.
168: */
169: public int getInteger() throws IOException {
170: if (buffer.read() != DerValue.tag_Integer) {
171: throw new IOException("DER input, Integer tag error");
172: }
173: return buffer.getInteger(getLength(buffer));
174: }
175:
176: /**
177: * Get a integer from the input stream as a BigInteger object.
178: *
179: * @return the integer held in this DER input stream.
180: */
181: public BigInteger getBigInteger() throws IOException {
182: if (buffer.read() != DerValue.tag_Integer) {
183: throw new IOException("DER input, Integer tag error");
184: }
185: return buffer.getBigInteger(getLength(buffer), false);
186: }
187:
188: /**
189: * Returns an ASN.1 INTEGER value as a positive BigInteger.
190: * This is just to deal with implementations that incorrectly encode
191: * some values as negative.
192: *
193: * @return the integer held in this DER value as a BigInteger.
194: */
195: public BigInteger getPositiveBigInteger() throws IOException {
196: if (buffer.read() != DerValue.tag_Integer) {
197: throw new IOException("DER input, Integer tag error");
198: }
199: return buffer.getBigInteger(getLength(buffer), true);
200: }
201:
202: /**
203: * Get an enumerated from the input stream.
204: *
205: * @return the integer held in this DER input stream.
206: */
207: public int getEnumerated() throws IOException {
208: if (buffer.read() != DerValue.tag_Enumerated) {
209: throw new IOException("DER input, Enumerated tag error");
210: }
211: return buffer.getInteger(getLength(buffer));
212: }
213:
214: /**
215: * Get a bit string from the input stream. Padded bits (if any)
216: * will be stripped off before the bit string is returned.
217: */
218: public byte[] getBitString() throws IOException {
219: if (buffer.read() != DerValue.tag_BitString)
220: throw new IOException("DER input not an bit string");
221:
222: return buffer.getBitString(getLength(buffer));
223: }
224:
225: /**
226: * Get a bit string from the input stream. The bit string need
227: * not be byte-aligned.
228: */
229: public BitArray getUnalignedBitString() throws IOException {
230: if (buffer.read() != DerValue.tag_BitString)
231: throw new IOException("DER input not a bit string");
232:
233: int length = getLength(buffer) - 1;
234:
235: /*
236: * First byte = number of excess bits in the last octet of the
237: * representation.
238: */
239: int validBits = length * 8 - buffer.read();
240:
241: byte[] repn = new byte[length];
242:
243: if ((length != 0) && (buffer.read(repn) != length))
244: throw new IOException("short read of DER bit string");
245: return new BitArray(validBits, repn);
246: }
247:
248: /**
249: * Returns an ASN.1 OCTET STRING from the input stream.
250: */
251: public byte[] getOctetString() throws IOException {
252: if (buffer.read() != DerValue.tag_OctetString)
253: throw new IOException("DER input not an octet string");
254:
255: int length = getLength(buffer);
256: byte[] retval = new byte[length];
257: if ((length != 0) && (buffer.read(retval) != length))
258: throw new IOException("short read of DER octet string");
259:
260: return retval;
261: }
262:
263: /**
264: * Returns the asked number of bytes from the input stream.
265: */
266: public void getBytes(byte[] val) throws IOException {
267: if ((val.length != 0) && (buffer.read(val) != val.length)) {
268: throw new IOException("short read of DER octet string");
269: }
270: }
271:
272: /**
273: * Reads an encoded null value from the input stream.
274: */
275: public void getNull() throws IOException {
276: if (buffer.read() != DerValue.tag_Null || buffer.read() != 0)
277: throw new IOException("getNull, bad data");
278: }
279:
280: /**
281: * Reads an X.200 style Object Identifier from the stream.
282: */
283: public ObjectIdentifier getOID() throws IOException {
284: return new ObjectIdentifier(this );
285: }
286:
287: /**
288: * Return a sequence of encoded entities. ASN.1 sequences are
289: * ordered, and they are often used, like a "struct" in C or C++,
290: * to group data values. They may have optional or context
291: * specific values.
292: *
293: * @param startLen guess about how long the sequence will be
294: * (used to initialize an auto-growing data structure)
295: * @return array of the values in the sequence
296: */
297: public DerValue[] getSequence(int startLen) throws IOException {
298: tag = (byte) buffer.read();
299: if (tag != DerValue.tag_Sequence)
300: throw new IOException("Sequence tag error");
301: return readVector(startLen);
302: }
303:
304: /**
305: * Return a set of encoded entities. ASN.1 sets are unordered,
306: * though DER may specify an order for some kinds of sets (such
307: * as the attributes in an X.500 relative distinguished name)
308: * to facilitate binary comparisons of encoded values.
309: *
310: * @param startLen guess about how large the set will be
311: * (used to initialize an auto-growing data structure)
312: * @return array of the values in the sequence
313: */
314: public DerValue[] getSet(int startLen) throws IOException {
315: tag = (byte) buffer.read();
316: if (tag != DerValue.tag_Set)
317: throw new IOException("Set tag error");
318: return readVector(startLen);
319: }
320:
321: /**
322: * Return a set of encoded entities. ASN.1 sets are unordered,
323: * though DER may specify an order for some kinds of sets (such
324: * as the attributes in an X.500 relative distinguished name)
325: * to facilitate binary comparisons of encoded values.
326: *
327: * @param startLen guess about how large the set will be
328: * (used to initialize an auto-growing data structure)
329: * @param implicit if true tag is assumed implicit.
330: * @return array of the values in the sequence
331: */
332: public DerValue[] getSet(int startLen, boolean implicit)
333: throws IOException {
334: tag = (byte) buffer.read();
335: if (!implicit) {
336: if (tag != DerValue.tag_Set) {
337: throw new IOException("Set tag error");
338: }
339: }
340: return (readVector(startLen));
341: }
342:
343: /*
344: * Read a "vector" of values ... set or sequence have the
345: * same encoding, except for the initial tag, so both use
346: * this same helper routine.
347: */
348: protected DerValue[] readVector(int startLen) throws IOException {
349: DerInputStream newstr;
350:
351: byte lenByte = (byte) buffer.read();
352: int len = getLength((lenByte & 0xff), buffer);
353:
354: if (len == -1) {
355: // indefinite length encoding found
356: int readLen = buffer.available();
357: int offset = 2; // for tag and length bytes
358: byte[] indefData = new byte[readLen + offset];
359: indefData[0] = tag;
360: indefData[1] = lenByte;
361: DataInputStream dis = new DataInputStream(buffer);
362: dis.readFully(indefData, offset, readLen);
363: dis.close();
364: DerIndefLenConverter derIn = new DerIndefLenConverter();
365: buffer = new DerInputBuffer(derIn.convert(indefData));
366: if (tag != buffer.read())
367: throw new IOException("Indefinite length encoding"
368: + " not supported");
369: len = DerInputStream.getLength(buffer);
370: }
371:
372: if (len == 0)
373: // return empty array instead of null, which should be
374: // used only for missing optionals
375: return new DerValue[0];
376:
377: /*
378: * Create a temporary stream from which to read the data,
379: * unless it's not really needed.
380: */
381: if (buffer.available() == len)
382: newstr = this ;
383: else
384: newstr = subStream(len, true);
385:
386: /*
387: * Pull values out of the stream.
388: */
389: Vector<DerValue> vec = new Vector<DerValue>(startLen);
390: DerValue value;
391:
392: do {
393: value = new DerValue(newstr.buffer);
394: vec.addElement(value);
395: } while (newstr.available() > 0);
396:
397: if (newstr.available() != 0)
398: throw new IOException("extra data at end of vector");
399:
400: /*
401: * Now stick them into the array we're returning.
402: */
403: int i, max = vec.size();
404: DerValue[] retval = new DerValue[max];
405:
406: for (i = 0; i < max; i++)
407: retval[i] = vec.elementAt(i);
408:
409: return retval;
410: }
411:
412: /**
413: * Get a single DER-encoded value from the input stream.
414: * It can often be useful to pull a value from the stream
415: * and defer parsing it. For example, you can pull a nested
416: * sequence out with one call, and only examine its elements
417: * later when you really need to.
418: */
419: public DerValue getDerValue() throws IOException {
420: return new DerValue(buffer);
421: }
422:
423: /**
424: * Read a string that was encoded as a UTF8String DER value.
425: */
426: public String getUTF8String() throws IOException {
427: return readString(DerValue.tag_UTF8String, "UTF-8", "UTF8");
428: }
429:
430: /**
431: * Read a string that was encoded as a PrintableString DER value.
432: */
433: public String getPrintableString() throws IOException {
434: return readString(DerValue.tag_PrintableString, "Printable",
435: "ASCII");
436: }
437:
438: /**
439: * Read a string that was encoded as a T61String DER value.
440: */
441: public String getT61String() throws IOException {
442: /*
443: * Works for common characters between T61 and ASCII.
444: */
445: return readString(DerValue.tag_T61String, "T61", "ISO-8859-1");
446: }
447:
448: /**
449: * Read a string that was encoded as a IA5tring DER value.
450: */
451: public String getIA5String() throws IOException {
452: return readString(DerValue.tag_IA5String, "IA5", "ASCII");
453: }
454:
455: /**
456: * Read a string that was encoded as a BMPString DER value.
457: */
458: public String getBMPString() throws IOException {
459: return readString(DerValue.tag_BMPString, "BMP",
460: "UnicodeBigUnmarked");
461: }
462:
463: /**
464: * Read a string that was encoded as a GeneralString DER value.
465: */
466: public String getGeneralString() throws IOException {
467: return readString(DerValue.tag_GeneralString, "General",
468: "ASCII");
469: }
470:
471: /**
472: * Private helper routine to read an encoded string from the input
473: * stream.
474: * @param stringTag the tag for the type of string to read
475: * @param stringName a name to display in error messages
476: * @param enc the encoder to use to interpret the data. Should
477: * correspond to the stringTag above.
478: */
479: private String readString(byte stringTag, String stringName,
480: String enc) throws IOException {
481:
482: if (buffer.read() != stringTag)
483: throw new IOException("DER input not a " + stringName
484: + " string");
485:
486: int length = getLength(buffer);
487: byte[] retval = new byte[length];
488: if ((length != 0) && (buffer.read(retval) != length))
489: throw new IOException("short read of DER " + stringName
490: + " string");
491:
492: return new String(retval, enc);
493: }
494:
495: /**
496: * Get a UTC encoded time value from the input stream.
497: */
498: public Date getUTCTime() throws IOException {
499: if (buffer.read() != DerValue.tag_UtcTime)
500: throw new IOException("DER input, UTCtime tag invalid ");
501: return buffer.getUTCTime(getLength(buffer));
502: }
503:
504: /**
505: * Get a Generalized encoded time value from the input stream.
506: */
507: public Date getGeneralizedTime() throws IOException {
508: if (buffer.read() != DerValue.tag_GeneralizedTime)
509: throw new IOException(
510: "DER input, GeneralizedTime tag invalid ");
511: return buffer.getGeneralizedTime(getLength(buffer));
512: }
513:
514: /*
515: * Get a byte from the input stream.
516: */
517: // package private
518: int getByte() throws IOException {
519: return (0x00ff & buffer.read());
520: }
521:
522: public int peekByte() throws IOException {
523: return buffer.peek();
524: }
525:
526: // package private
527: int getLength() throws IOException {
528: return getLength(buffer);
529: }
530:
531: /*
532: * Get a length from the input stream, allowing for at most 32 bits of
533: * encoding to be used. (Not the same as getting a tagged integer!)
534: *
535: * @return the length or -1 if indefinite length found.
536: * @exception IOException on parsing error or unsupported lengths.
537: */
538: static int getLength(InputStream in) throws IOException {
539: return getLength(in.read(), in);
540: }
541:
542: /*
543: * Get a length from the input stream, allowing for at most 32 bits of
544: * encoding to be used. (Not the same as getting a tagged integer!)
545: *
546: * @return the length or -1 if indefinite length found.
547: * @exception IOException on parsing error or unsupported lengths.
548: */
549: static int getLength(int lenByte, InputStream in)
550: throws IOException {
551: int value, tmp;
552:
553: tmp = lenByte;
554: if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum
555: value = tmp;
556: } else { // long form or indefinite
557: tmp &= 0x07f;
558:
559: /*
560: * NOTE: tmp == 0 indicates indefinite length encoded data.
561: * tmp > 4 indicates more than 4Gb of data.
562: */
563: if (tmp == 0)
564: return -1;
565: if (tmp < 0 || tmp > 4)
566: throw new IOException(
567: "DerInputStream.getLength(): lengthTag="
568: + tmp
569: + ", "
570: + ((tmp < 0) ? "incorrect DER encoding."
571: : "too big."));
572:
573: for (value = 0; tmp > 0; tmp--) {
574: value <<= 8;
575: value += 0x0ff & in.read();
576: }
577: }
578: return value;
579: }
580:
581: /**
582: * Mark the current position in the buffer, so that
583: * a later call to <code>reset</code> will return here.
584: */
585: public void mark(int value) {
586: buffer.mark(value);
587: }
588:
589: /**
590: * Return to the position of the last <code>mark</code>
591: * call. A mark is implicitly set at the beginning of
592: * the stream when it is created.
593: */
594: public void reset() {
595: buffer.reset();
596: }
597:
598: /**
599: * Returns the number of bytes available for reading.
600: * This is most useful for testing whether the stream is
601: * empty.
602: */
603: public int available() {
604: return buffer.available();
605: }
606: }
|