001: package org.bouncycastle.asn1;
002:
003: import java.io.ByteArrayInputStream;
004: import java.io.EOFException;
005: import java.io.IOException;
006: import java.io.InputStream;
007:
008: public class ASN1StreamParser {
009: InputStream _in;
010:
011: private int _limit;
012: private boolean _eofFound;
013:
014: public ASN1StreamParser(InputStream in) {
015: this (in, Integer.MAX_VALUE);
016: }
017:
018: public ASN1StreamParser(InputStream in, int limit) {
019: this ._in = in;
020: this ._limit = limit;
021: }
022:
023: public ASN1StreamParser(byte[] encoding) {
024: this (new ByteArrayInputStream(encoding), encoding.length);
025: }
026:
027: InputStream getParentStream() {
028: return _in;
029: }
030:
031: private int readLength() throws IOException {
032: int length = _in.read();
033: if (length < 0) {
034: throw new EOFException("EOF found when length expected");
035: }
036:
037: if (length == 0x80) {
038: return -1; // indefinite-length encoding
039: }
040:
041: if (length > 127) {
042: int size = length & 0x7f;
043:
044: if (size > 4) {
045: throw new IOException("DER length more than 4 bytes");
046: }
047:
048: length = 0;
049: for (int i = 0; i < size; i++) {
050: int next = _in.read();
051:
052: if (next < 0) {
053: throw new EOFException("EOF found reading length");
054: }
055:
056: length = (length << 8) + next;
057: }
058:
059: if (length < 0) {
060: throw new IOException(
061: "corrupted stream - negative length found");
062: }
063:
064: if (length >= _limit) // after all we must have read at least 1 byte
065: {
066: throw new IOException(
067: "corrupted stream - out of bounds length found");
068: }
069: }
070:
071: return length;
072: }
073:
074: public DEREncodable readObject() throws IOException {
075: int tag = _in.read();
076: if (tag == -1) {
077: if (_eofFound) {
078: throw new EOFException(
079: "attempt to read past end of file.");
080: }
081:
082: _eofFound = true;
083:
084: return null;
085: }
086:
087: //
088: // turn of looking for "00" while we resolve the tag
089: //
090: set00Check(false);
091:
092: //
093: // calculate tag number
094: //
095: int baseTagNo = tag & ~DERTags.CONSTRUCTED;
096: int tagNo = baseTagNo;
097:
098: if ((tag & DERTags.TAGGED) != 0) {
099: tagNo = tag & 0x1f;
100:
101: //
102: // with tagged object tag number is bottom 5 bits, or stored at the start of the content
103: //
104: if (tagNo == 0x1f) {
105: tagNo = 0;
106:
107: int b = _in.read();
108:
109: while ((b >= 0) && ((b & 0x80) != 0)) {
110: tagNo |= (b & 0x7f);
111: tagNo <<= 7;
112: b = _in.read();
113: }
114:
115: if (b < 0) {
116: _eofFound = true;
117:
118: throw new EOFException(
119: "EOF encountered inside tag value.");
120: }
121:
122: tagNo |= (b & 0x7f);
123: }
124: }
125:
126: //
127: // calculate length
128: //
129: int length = readLength();
130:
131: if (length < 0) // indefinite length
132: {
133: IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(
134: _in);
135:
136: switch (baseTagNo) {
137: case DERTags.NULL:
138: while (indIn.read() >= 0) {
139: // make sure we skip to end of object
140: }
141: return BERNull.INSTANCE;
142: case DERTags.OCTET_STRING:
143: return new BEROctetStringParser(new ASN1ObjectParser(
144: tag, tagNo, indIn));
145: case DERTags.SEQUENCE:
146: return new BERSequenceParser(new ASN1ObjectParser(tag,
147: tagNo, indIn));
148: case DERTags.SET:
149: return new BERSetParser(new ASN1ObjectParser(tag,
150: tagNo, indIn));
151: default:
152: return new BERTaggedObjectParser(tag, tagNo, indIn);
153: }
154: } else {
155: DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(
156: _in, length);
157:
158: switch (baseTagNo) {
159: case DERTags.INTEGER:
160: return new DERInteger(defIn.toByteArray());
161: case DERTags.NULL:
162: defIn.toByteArray(); // make sure we read to end of object bytes.
163: return DERNull.INSTANCE;
164: case DERTags.OBJECT_IDENTIFIER:
165: return new DERObjectIdentifier(defIn.toByteArray());
166: case DERTags.OCTET_STRING:
167: return new DEROctetString(defIn.toByteArray());
168: case DERTags.SEQUENCE:
169: return new DERSequence(loadVector(defIn, length))
170: .parser();
171: case DERTags.SET:
172: return new DERSet(loadVector(defIn, length)).parser();
173: default:
174: return new BERTaggedObjectParser(tag, tagNo, defIn);
175: }
176: }
177: }
178:
179: private void set00Check(boolean enabled) {
180: if (_in instanceof IndefiniteLengthInputStream) {
181: ((IndefiniteLengthInputStream) _in).setEofOn00(enabled);
182: }
183: }
184:
185: private ASN1EncodableVector loadVector(InputStream in, int length)
186: throws IOException {
187: ASN1InputStream aIn = new ASN1InputStream(in, length);
188: ASN1EncodableVector v = new ASN1EncodableVector();
189:
190: DERObject obj;
191: while ((obj = aIn.readObject()) != null) {
192: v.add(obj);
193: }
194:
195: return v;
196: }
197: }
|