KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > util > asn1 > ASN1InputStream


1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

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

34 public class ASN1InputStream
35     extends FilterInputStream JavaDoc
36     implements DERTags
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                                         public int hashCode()
46                                         {
47                                             return 0;
48                                         }
49                                         public boolean equals(
50                                             Object JavaDoc o)
51                                         {
52                                             return o == this;
53                                         }
54                                     };
55     boolean eofFound = false;
56
57     public ASN1InputStream(
58         InputStream JavaDoc is)
59     {
60         super(is);
61     }
62
63     public ASN1InputStream(
64         byte[] input)
65     {
66         super(new ByteArrayInputStream JavaDoc(input));
67     }
68
69     protected int readLength()
70         throws IOException JavaDoc
71     {
72         int length = read();
73         if (length < 0)
74         {
75             throw new IOException JavaDoc("EOF found when length expected");
76         }
77
78         if (length == 0x80)
79         {
80             return -1; // indefinite-length encoding
81
}
82
83         if (length > 127)
84         {
85             int size = length & 0x7f;
86
87             if (size > 4)
88             {
89                 throw new IOException JavaDoc("DER length more than 4 bytes");
90             }
91
92             length = 0;
93             for (int i = 0; i < size; i++)
94             {
95                 int next = read();
96
97                 if (next < 0)
98                 {
99                     throw new IOException JavaDoc("EOF found reading length");
100                 }
101
102                 length = (length << 8) + next;
103             }
104
105             if (length < 0)
106             {
107                 throw new IOException JavaDoc("corrupted steam - negative length found");
108             }
109         }
110
111         return length;
112     }
113
114     protected void readFully(
115         byte[] bytes)
116         throws IOException JavaDoc
117     {
118         int left = bytes.length;
119         int len;
120
121         if (left == 0)
122         {
123             return;
124         }
125
126         while ((len = read(bytes, bytes.length - left, left)) > 0)
127         {
128             if ((left -= len) == 0)
129             {
130                 return;
131             }
132         }
133
134         if (left != 0)
135         {
136             throw new EOFException JavaDoc("EOF encountered in middle of object");
137         }
138     }
139
140     /**
141      * build an object given its tag and a byte stream to construct it
142      * from.
143      */

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

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