001 package org.apache.commons.ssl.asn1;
002
003 import java.io.ByteArrayInputStream;
004 import java.io.EOFException;
005 import java.io.FilterInputStream;
006 import java.io.IOException;
007 import java.io.InputStream;
008
009 /**
010 * Don't use this class. It will eventually disappear, use ASN1InputStream.
011 * <br>
012 * This class is scheduled for removal.
013 *
014 * @deprecated use ASN1InputStream
015 */
016 public class DERInputStream
017 extends FilterInputStream implements DERTags {
018 /** @deprecated use ASN1InputStream */
019 public DERInputStream(
020 InputStream is) {
021 super(is);
022 }
023
024 protected int readLength()
025 throws IOException {
026 int length = read();
027 if (length < 0) {
028 throw new IOException("EOF found when length expected");
029 }
030
031 if (length == 0x80) {
032 return -1; // indefinite-length encoding
033 }
034
035 if (length > 127) {
036 int size = length & 0x7f;
037
038 if (size > 4) {
039 throw new IOException("DER length more than 4 bytes");
040 }
041
042 length = 0;
043 for (int i = 0; i < size; i++) {
044 int next = read();
045
046 if (next < 0) {
047 throw new IOException("EOF found reading length");
048 }
049
050 length = (length << 8) + next;
051 }
052
053 if (length < 0) {
054 throw new IOException("corrupted stream - negative length found");
055 }
056 }
057
058 return length;
059 }
060
061 protected void readFully(
062 byte[] bytes)
063 throws IOException {
064 int left = bytes.length;
065
066 if (left == 0) {
067 return;
068 }
069
070 while (left > 0) {
071 int l = read(bytes, bytes.length - left, left);
072
073 if (l < 0) {
074 throw new EOFException("unexpected end of stream");
075 }
076
077 left -= l;
078 }
079 }
080
081 /**
082 * build an object given its tag and a byte stream to construct it
083 * from.
084 */
085 protected DERObject buildObject(
086 int tag,
087 byte[] bytes)
088 throws IOException {
089 switch (tag) {
090 case NULL:
091 return null;
092 case SEQUENCE | CONSTRUCTED:
093 ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
094 BERInputStream dIn = new BERInputStream(bIn);
095 DERConstructedSequence seq = new DERConstructedSequence();
096
097 try {
098 for (; ;) {
099 DERObject obj = dIn.readObject();
100
101 seq.addObject(obj);
102 }
103 }
104 catch (EOFException ex) {
105 return seq;
106 }
107 case SET | CONSTRUCTED:
108 bIn = new ByteArrayInputStream(bytes);
109 dIn = new BERInputStream(bIn);
110
111 ASN1EncodableVector v = new ASN1EncodableVector();
112
113 try {
114 for (; ;) {
115 DERObject obj = dIn.readObject();
116
117 v.add(obj);
118 }
119 }
120 catch (EOFException ex) {
121 return new DERConstructedSet(v);
122 }
123 case BOOLEAN:
124 return new DERBoolean(bytes);
125 case INTEGER:
126 return new DERInteger(bytes);
127 case ENUMERATED:
128 return new DEREnumerated(bytes);
129 case OBJECT_IDENTIFIER:
130 return new DERObjectIdentifier(bytes);
131 case BIT_STRING:
132 int padBits = bytes[0];
133 byte[] data = new byte[bytes.length - 1];
134
135 System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
136
137 return new DERBitString(data, padBits);
138 case UTF8_STRING:
139 return new DERUTF8String(bytes);
140 case PRINTABLE_STRING:
141 return new DERPrintableString(bytes);
142 case IA5_STRING:
143 return new DERIA5String(bytes);
144 case T61_STRING:
145 return new DERT61String(bytes);
146 case VISIBLE_STRING:
147 return new DERVisibleString(bytes);
148 case UNIVERSAL_STRING:
149 return new DERUniversalString(bytes);
150 case GENERAL_STRING:
151 return new DERGeneralString(bytes);
152 case BMP_STRING:
153 return new DERBMPString(bytes);
154 case OCTET_STRING:
155 return new DEROctetString(bytes);
156 case UTC_TIME:
157 return new DERUTCTime(bytes);
158 case GENERALIZED_TIME:
159 return new DERGeneralizedTime(bytes);
160 default:
161 //
162 // with tagged object tag number is bottom 5 bits
163 //
164 if ((tag & TAGGED) != 0) {
165 if ((tag & 0x1f) == 0x1f) {
166 throw new IOException("unsupported high tag encountered");
167 }
168
169 if (bytes.length == 0) // empty tag!
170 {
171 if ((tag & CONSTRUCTED) == 0) {
172 return new DERTaggedObject(false, tag & 0x1f, new DERNull());
173 } else {
174 return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence());
175 }
176 }
177
178 //
179 // simple type - implicit... return an octet string
180 //
181 if ((tag & CONSTRUCTED) == 0) {
182 return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
183 }
184
185 bIn = new ByteArrayInputStream(bytes);
186 dIn = new BERInputStream(bIn);
187
188 DEREncodable dObj = dIn.readObject();
189
190 //
191 // explicitly tagged (probably!) - if it isn't we'd have to
192 // tell from the context
193 //
194 if (dIn.available() == 0) {
195 return new DERTaggedObject(tag & 0x1f, dObj);
196 }
197
198 //
199 // another implicit object, we'll create a sequence...
200 //
201 seq = new DERConstructedSequence();
202
203 seq.addObject(dObj);
204
205 try {
206 for (; ;) {
207 dObj = dIn.readObject();
208
209 seq.addObject(dObj);
210 }
211 }
212 catch (EOFException ex) {
213 // ignore --
214 }
215
216 return new DERTaggedObject(false, tag & 0x1f, seq);
217 }
218
219 return new DERUnknownTag(tag, bytes);
220 }
221 }
222
223 public DERObject readObject()
224 throws IOException {
225 int tag = read();
226 if (tag == -1) {
227 throw new EOFException();
228 }
229
230 int length = readLength();
231 byte[] bytes = new byte[length];
232
233 readFully(bytes);
234
235 return buildObject(tag, bytes);
236 }
237 }