KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > maverick > crypto > asn1 > ASN1InputStream


1 /*
2  * SSL-Explorer
3  *
4  * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */

19             
20 package com.maverick.crypto.asn1;
21
22 import java.io.ByteArrayInputStream JavaDoc;
23 import java.io.ByteArrayOutputStream JavaDoc;
24 import java.io.EOFException JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.util.Vector JavaDoc;
28
29 /**
30  * a general purpose ASN.1 decoder - note: this class differs from the
31  * others in that it returns null after it has read the last object in
32  * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
33  * returned.
34  */

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

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

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