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