KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > bc > asn1 > ASN1InputStream


1 package com.lowagie.bc.asn1;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.EOFException;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.util.Vector;
9
10 /**
11  * a general purpose ASN.1 decoder - note: this class differs from the
12  * others in that it returns null after it has read the last object in
13  * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
14  * returned.
15  */

16 public class ASN1InputStream
17     extends DERInputStream
18 {
19     private DERObject END_OF_STREAM = new DERObject() {
20                                         void encode(
21                                             DEROutputStream out)
22                                         throws IOException
23                                         {
24                                             throw new IOException("Eeek!");
25                                         }
26
27                                     };
28     boolean eofFound = false;
29
30     public ASN1InputStream(
31         InputStream is)
32     {
33         super(is);
34     }
35
36     protected int readLength()
37         throws IOException
38     {
39         int length = read();
40         if (length < 0)
41         {
42             throw new IOException("EOF found when length expected");
43         }
44
45         if (length == 0x80)
46         {
47             return -1; // indefinite-length encoding
48
}
49
50         if (length > 127)
51         {
52             int size = length & 0x7f;
53
54             length = 0;
55             for (int i = 0; i < size; i++)
56             {
57                 int next = read();
58
59                 if (next < 0)
60                 {
61                     throw new IOException("EOF found reading length");
62                 }
63
64                 length = (length << 8) + next;
65             }
66         }
67
68         return length;
69     }
70
71     protected void readFully(
72         byte[] bytes)
73         throws IOException
74     {
75         int left = bytes.length;
76         int len;
77
78         if (left == 0)
79         {
80             return;
81         }
82
83         while ((len = read(bytes, bytes.length - left, left)) > 0)
84         {
85             if ((left -= len) == 0)
86             {
87                 return;
88             }
89         }
90
91         if (left != 0)
92         {
93             throw new EOFException("EOF encountered in middle of object");
94         }
95     }
96
97     /**
98      * build an object given its tag and a byte stream to construct it
99      * from.
100      */

101     protected DERObject buildObject(
102         int tag,
103         byte[] bytes)
104         throws IOException
105     {
106         if ((tag & APPLICATION) != 0)
107         {
108             return new DERApplicationSpecific(tag, bytes);
109         }
110         
111         switch (tag)
112         {
113         case NULL:
114             return new DERNull();
115         case SEQUENCE | CONSTRUCTED:
116             ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
117             ASN1InputStream aIn = new ASN1InputStream(bIn);
118             ASN1EncodableVector v = new ASN1EncodableVector();
119
120             DERObject obj = aIn.readObject();
121
122             while (obj != null)
123             {
124                 v.add(obj);
125                 obj = aIn.readObject();
126             }
127
128             return new DERSequence(v);
129         case SET | CONSTRUCTED:
130             bIn = new ByteArrayInputStream(bytes);
131             aIn = new ASN1InputStream(bIn);
132             v = new ASN1EncodableVector();
133
134             obj = aIn.readObject();
135
136             while (obj != null)
137             {
138                 v.add(obj);
139                 obj = aIn.readObject();
140             }
141
142             return new DERSet(v);
143         case BOOLEAN:
144             return new DERBoolean(bytes);
145         case INTEGER:
146             return new DERInteger(bytes);
147         case ENUMERATED:
148             return new DEREnumerated(bytes);
149         case OBJECT_IDENTIFIER:
150             return new DERObjectIdentifier(bytes);
151         case BIT_STRING:
152             int padBits = bytes[0];
153             byte[] data = new byte[bytes.length - 1];
154
155             System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
156
157             return new DERBitString(data, padBits);
158         case UTF8_STRING:
159             return new DERUTF8String(bytes);
160         case PRINTABLE_STRING:
161             return new DERPrintableString(bytes);
162         case IA5_STRING:
163             return new DERIA5String(bytes);
164         case T61_STRING:
165             return new DERT61String(bytes);
166         case VISIBLE_STRING:
167             return new DERVisibleString(bytes);
168         case GENERAL_STRING:
169             return new DERGeneralString(bytes);
170         case UNIVERSAL_STRING:
171             return new DERUniversalString(bytes);
172         case BMP_STRING:
173             return new DERBMPString(bytes);
174         case OCTET_STRING:
175             return new DEROctetString(bytes);
176         case UTC_TIME:
177             return new DERUTCTime(bytes);
178         case GENERALIZED_TIME:
179             return new DERGeneralizedTime(bytes);
180         default:
181             //
182
// with tagged object tag number is bottom 5 bits
183
//
184
if ((tag & TAGGED) != 0)
185             {
186                 int tagNo = tag & 0x1f;
187
188                 if (tagNo == 0x1f)
189                 {
190                     int idx = 0;
191
192                     tagNo = 0;
193
194                     while ((bytes[idx] & 0x80) != 0)
195                     {
196                         tagNo |= (bytes[idx++] & 0x7f);
197                         tagNo <<= 7;
198                     }
199
200                     tagNo |= (bytes[idx] & 0x7f);
201
202                     byte[] tmp = bytes;
203
204                     bytes = new byte[tmp.length - (idx + 1)];
205                     System.arraycopy(tmp, idx + 1, bytes, 0, bytes.length);
206                 }
207
208                 if (bytes.length == 0) // empty tag!
209
{
210                     if ((tag & CONSTRUCTED) == 0)
211                     {
212                         return new DERTaggedObject(false, tagNo, new DERNull());
213                     }
214                     else
215                     {
216                         return new DERTaggedObject(false, tagNo, new DERSequence());
217                     }
218                 }
219
220                 //
221
// simple type - implicit... return an octet string
222
//
223
if ((tag & CONSTRUCTED) == 0)
224                 {
225                     return new DERTaggedObject(false, tagNo, new DEROctetString(bytes));
226                 }
227
228                 bIn = new ByteArrayInputStream(bytes);
229                 aIn = new ASN1InputStream(bIn);
230
231                 DEREncodable dObj = aIn.readObject();
232
233                 //
234
// explicitly tagged (probably!) - if it isn't we'd have to
235
// tell from the context
236
//
237
if (aIn.available() == 0)
238                 {
239                     return new DERTaggedObject(tagNo, dObj);
240                 }
241
242                 //
243
// another implicit object, we'll create a sequence...
244
//
245
v = new ASN1EncodableVector();
246
247                 while (dObj != null)
248                 {
249                     v.add(dObj);
250                     dObj = aIn.readObject();
251                 }
252
253                 return new DERTaggedObject(false, tagNo, new DERSequence(v));
254             }
255
256             return new DERUnknownTag(tag, bytes);
257         }
258     }
259
260     /**
261      * read a string of bytes representing an indefinite length object.
262      */

263     private byte[] readIndefiniteLengthFully()
264         throws IOException
265     {
266         ByteArrayOutputStream bOut = new ByteArrayOutputStream();
267         int b, b1;
268
269         b1 = read();
270
271         while ((b = read()) >= 0)
272         {
273             if (b1 == 0 && b == 0)
274             {
275                 break;
276             }
277
278             bOut.write(b1);
279             b1 = b;
280         }
281
282         return bOut.toByteArray();
283     }
284
285     private BERConstructedOctetString buildConstructedOctetString()
286         throws IOException
287     {
288         Vector octs = new Vector();
289
290         for (;;)
291         {
292             DERObject o = readObject();
293
294             if (o == END_OF_STREAM)
295             {
296                 break;
297             }
298
299             octs.addElement(o);
300         }
301
302         return new BERConstructedOctetString(octs);
303     }
304
305     public DERObject readObject()
306         throws IOException
307     {
308         int tag = read();
309         if (tag == -1)
310         {
311             if (eofFound)
312             {
313                 throw new EOFException("attempt to read past end of file.");
314             }
315
316             eofFound = true;
317
318             return null;
319         }
320     
321         int length = readLength();
322
323         if (length < 0) // indefinite length method
324
{
325             switch (tag)
326             {
327             case NULL:
328                 return new BERNull();
329             case SEQUENCE | CONSTRUCTED:
330                 ASN1EncodableVector v = new ASN1EncodableVector();
331     
332                 for (;;)
333                 {
334                     DERObject obj = readObject();
335
336                     if (obj == END_OF_STREAM)
337                     {
338                         break;
339                     }
340
341                     v.add(obj);
342                 }
343                 return new BERSequence(v);
344             case SET | CONSTRUCTED:
345                 v = new ASN1EncodableVector();
346     
347                 for (;;)
348                 {
349                     DERObject obj = readObject();
350
351                     if (obj == END_OF_STREAM)
352                     {
353                         break;
354                     }
355
356                     v.add(obj);
357                 }
358                 return new BERSet(v);
359             case OCTET_STRING | CONSTRUCTED:
360                 return buildConstructedOctetString();
361             default:
362                 //
363
// with tagged object tag number is bottom 5 bits
364
//
365
if ((tag & TAGGED) != 0)
366                 {
367                     int tagNo = tag & 0x1f;
368
369                     if (tagNo == 0x1f)
370                     {
371                         int b = read();
372
373                         tagNo = 0;
374
375                         while ((b >= 0) && ((b & 0x80) != 0))
376                         {
377                             tagNo |= (b & 0x7f);
378                             tagNo <<= 7;
379                             b = read();
380                         }
381
382                         tagNo |= (b & 0x7f);
383                     }
384
385                     //
386
// simple type - implicit... return an octet string
387
//
388
if ((tag & CONSTRUCTED) == 0)
389                     {
390                         byte[] bytes = readIndefiniteLengthFully();
391
392                         return new BERTaggedObject(false, tagNo, new DEROctetString(bytes));
393                     }
394
395                     //
396
// either constructed or explicitly tagged
397
//
398
DERObject dObj = readObject();
399
400                     if (dObj == END_OF_STREAM) // empty tag!
401
{
402                         return new DERTaggedObject(tagNo);
403                     }
404
405                     DERObject next = readObject();
406
407                     //
408
// explicitly tagged (probably!) - if it isn't we'd have to
409
// tell from the context
410
//
411
if (next == END_OF_STREAM)
412                     {
413                         return new BERTaggedObject(tagNo, dObj);
414                     }
415
416                     //
417
// another implicit object, we'll create a sequence...
418
//
419
v = new ASN1EncodableVector();
420
421                     v.add(dObj);
422
423                     do
424                     {
425                         v.add(next);
426                         next = readObject();
427                     }
428                     while (next != END_OF_STREAM);
429
430                     return new BERTaggedObject(false, tagNo, new BERSequence(v));
431                 }
432
433                 throw new IOException("unknown BER object encountered");
434             }
435         }
436         else
437         {
438             if (tag == 0 && length == 0) // end of contents marker.
439
{
440                 return END_OF_STREAM;
441             }
442
443             byte[] bytes = new byte[length];
444     
445             readFully(bytes);
446     
447             return buildObject(tag, bytes);
448         }
449     }
450 }
451
Popular Tags