package org.bouncycastle.asn1; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.util.Vector; public class BERInputStream extends DERInputStream { private DERObject END_OF_STREAM = new DERObject() { void encode( DEROutputStream out) throws IOException { throw new IOException("Eeek!"); } }; public BERInputStream( InputStream is) { super(is); } /** * read a string of bytes representing an indefinite length object. */ private byte[] readIndefiniteLengthFully() throws IOException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); int b, b1; b1 = read(); while ((b = read()) >= 0) { if (b1 == 0 && b == 0) { break; } bOut.write(b1); b1 = b; } return bOut.toByteArray(); } private BERConstructedOctetString buildConstructedOctetString() throws IOException { Vector octs = new Vector(); for (;;) { DERObject o = readObject(); if (o == END_OF_STREAM) { break; } octs.addElement(o); } return new BERConstructedOctetString(octs); } public DERObject readObject() throws IOException { int tag = read(); if (tag == -1) { throw new EOFException(); } int length = readLength(); if (length < 0) // indefinite length method { switch (tag) { case NULL: return null; case SEQUENCE | CONSTRUCTED: BERConstructedSequence seq = new BERConstructedSequence(); for (;;) { DERObject obj = readObject(); if (obj == END_OF_STREAM) { break; } seq.addObject(obj); } return seq; case OCTET_STRING | CONSTRUCTED: return buildConstructedOctetString(); case SET | CONSTRUCTED: ASN1EncodableVector v = new ASN1EncodableVector(); for (;;) { DERObject obj = readObject(); if (obj == END_OF_STREAM) { break; } v.add(obj); } return new BERSet(v); default: // // with tagged object tag number is bottom 5 bits // if ((tag & TAGGED) != 0) { if ((tag & 0x1f) == 0x1f) { throw new IOException("unsupported high tag encountered"); } // // simple type - implicit... return an octet string // if ((tag & CONSTRUCTED) == 0) { byte[] bytes = readIndefiniteLengthFully(); return new BERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes)); } // // either constructed or explicitly tagged // DERObject dObj = readObject(); if (dObj == END_OF_STREAM) // empty tag! { return new DERTaggedObject(tag & 0x1f); } DERObject next = readObject(); // // explicitly tagged (probably!) - if it isn't we'd have to // tell from the context // if (next == END_OF_STREAM) { return new BERTaggedObject(tag & 0x1f, dObj); } // // another implicit object, we'll create a sequence... // seq = new BERConstructedSequence(); seq.addObject(dObj); do { seq.addObject(next); next = readObject(); } while (next != END_OF_STREAM); return new BERTaggedObject(false, tag & 0x1f, seq); } throw new IOException("unknown BER object encountered"); } } else { if (tag == 0 && length == 0) // end of contents marker. { return END_OF_STREAM; } byte[] bytes = new byte[length]; readFully(bytes); return buildObject(tag, bytes); } } }