001 /**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package org.apache.geronimo.util.asn1;
020
021 import java.io.ByteArrayInputStream;
022 import java.io.EOFException;
023 import java.io.FilterInputStream;
024 import java.io.IOException;
025 import java.io.InputStream;
026
027 /**
028 * Don't use this class. It will eventually disappear, use ASN1InputStream.
029 * <br>
030 * This class is scheduled for removal.
031 * @deprecated use ASN1InputStream
032 */
033 public class DERInputStream
034 extends FilterInputStream implements DERTags
035 {
036 /**
037 * @deprecated use ASN1InputStream
038 */
039 public DERInputStream(
040 InputStream is)
041 {
042 super(is);
043 }
044
045 protected int readLength()
046 throws IOException
047 {
048 int length = read();
049 if (length < 0)
050 {
051 throw new IOException("EOF found when length expected");
052 }
053
054 if (length == 0x80)
055 {
056 return -1; // indefinite-length encoding
057 }
058
059 if (length > 127)
060 {
061 int size = length & 0x7f;
062
063 if (size > 4)
064 {
065 throw new IOException("DER length more than 4 bytes");
066 }
067
068 length = 0;
069 for (int i = 0; i < size; i++)
070 {
071 int next = read();
072
073 if (next < 0)
074 {
075 throw new IOException("EOF found reading length");
076 }
077
078 length = (length << 8) + next;
079 }
080
081 if (length < 0)
082 {
083 throw new IOException("corrupted steam - negative length found");
084 }
085 }
086
087 return length;
088 }
089
090 protected void readFully(
091 byte[] bytes)
092 throws IOException
093 {
094 int left = bytes.length;
095
096 if (left == 0)
097 {
098 return;
099 }
100
101 while (left > 0)
102 {
103 int l = read(bytes, bytes.length - left, left);
104
105 if (l < 0)
106 {
107 throw new EOFException("unexpected end of stream");
108 }
109
110 left -= l;
111 }
112 }
113
114 /**
115 * build an object given its tag and a byte stream to construct it
116 * from.
117 */
118 protected DERObject buildObject(
119 int tag,
120 byte[] bytes)
121 throws IOException
122 {
123 switch (tag)
124 {
125 case NULL:
126 return null;
127 case SEQUENCE | CONSTRUCTED:
128 ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
129 BERInputStream dIn = new BERInputStream(bIn);
130 DERConstructedSequence seq = new DERConstructedSequence();
131
132 try
133 {
134 for (;;)
135 {
136 DERObject obj = dIn.readObject();
137
138 seq.addObject(obj);
139 }
140 }
141 catch (EOFException ex)
142 {
143 return seq;
144 }
145 case SET | CONSTRUCTED:
146 bIn = new ByteArrayInputStream(bytes);
147 dIn = new BERInputStream(bIn);
148
149 ASN1EncodableVector v = new ASN1EncodableVector();
150
151 try
152 {
153 for (;;)
154 {
155 DERObject obj = dIn.readObject();
156
157 v.add(obj);
158 }
159 }
160 catch (EOFException ex)
161 {
162 return new DERConstructedSet(v);
163 }
164 case BOOLEAN:
165 return new DERBoolean(bytes);
166 case INTEGER:
167 return new DERInteger(bytes);
168 case ENUMERATED:
169 return new DEREnumerated(bytes);
170 case OBJECT_IDENTIFIER:
171 return new DERObjectIdentifier(bytes);
172 case BIT_STRING:
173 int padBits = bytes[0];
174 byte[] data = new byte[bytes.length - 1];
175
176 System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
177
178 return new DERBitString(data, padBits);
179 case UTF8_STRING:
180 return new DERUTF8String(bytes);
181 case PRINTABLE_STRING:
182 return new DERPrintableString(bytes);
183 case IA5_STRING:
184 return new DERIA5String(bytes);
185 case T61_STRING:
186 return new DERT61String(bytes);
187 case VISIBLE_STRING:
188 return new DERVisibleString(bytes);
189 case UNIVERSAL_STRING:
190 return new DERUniversalString(bytes);
191 case GENERAL_STRING:
192 return new DERGeneralString(bytes);
193 case BMP_STRING:
194 return new DERBMPString(bytes);
195 case OCTET_STRING:
196 return new DEROctetString(bytes);
197 case UTC_TIME:
198 return new DERUTCTime(bytes);
199 case GENERALIZED_TIME:
200 return new DERGeneralizedTime(bytes);
201 default:
202 //
203 // with tagged object tag number is bottom 5 bits
204 //
205 if ((tag & TAGGED) != 0)
206 {
207 if ((tag & 0x1f) == 0x1f)
208 {
209 throw new IOException("unsupported high tag encountered");
210 }
211
212 if (bytes.length == 0) // empty tag!
213 {
214 if ((tag & CONSTRUCTED) == 0)
215 {
216 return new DERTaggedObject(false, tag & 0x1f, new DERNull());
217 }
218 else
219 {
220 return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence());
221 }
222 }
223
224 //
225 // simple type - implicit... return an octet string
226 //
227 if ((tag & CONSTRUCTED) == 0)
228 {
229 return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
230 }
231
232 bIn = new ByteArrayInputStream(bytes);
233 dIn = new BERInputStream(bIn);
234
235 DEREncodable dObj = dIn.readObject();
236
237 //
238 // explicitly tagged (probably!) - if it isn't we'd have to
239 // tell from the context
240 //
241 if (dIn.available() == 0)
242 {
243 return new DERTaggedObject(tag & 0x1f, dObj);
244 }
245
246 //
247 // another implicit object, we'll create a sequence...
248 //
249 seq = new DERConstructedSequence();
250
251 seq.addObject(dObj);
252
253 try
254 {
255 for (;;)
256 {
257 dObj = dIn.readObject();
258
259 seq.addObject(dObj);
260 }
261 }
262 catch (EOFException ex)
263 {
264 // ignore --
265 }
266
267 return new DERTaggedObject(false, tag & 0x1f, seq);
268 }
269
270 return new DERUnknownTag(tag, bytes);
271 }
272 }
273
274 public DERObject readObject()
275 throws IOException
276 {
277 int tag = read();
278 if (tag == -1)
279 {
280 throw new EOFException();
281 }
282
283 int length = readLength();
284 byte[] bytes = new byte[length];
285
286 readFully(bytes);
287
288 return buildObject(tag, bytes);
289 }
290 }