View Javadoc

1   /*
2    *   Copyright 2005 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  
18  package org.apache.asn1.der;
19  
20  import java.io.ByteArrayInputStream;
21  import java.io.ByteArrayOutputStream;
22  import java.io.EOFException;
23  import java.io.FilterInputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.nio.ByteBuffer;
27  import java.util.Vector;
28  
29  /***
30   * General purpose ASN.1 decoder.
31   */
32  public class ASN1InputStream extends FilterInputStream
33  {
34      private boolean EOF_FOUND = false;
35      
36      private DERObject END_OF_STREAM = new DERObject( 0, null ) {
37                                          public void encode( ASN1OutputStream out )
38                                          throws IOException
39                                          {
40                                              throw new IOException("End of stream.");
41                                          }
42                                          public int hashCode()
43                                          {
44                                              return 0;
45                                          }
46                                          public boolean equals( Object o ) 
47                                          {
48                                              return o == this;
49                                          }
50                                      };
51  
52      public ASN1InputStream( ByteBuffer in )
53      {
54          super( newInputStream( in ) );
55      }
56  
57      public ASN1InputStream( byte[] input )
58      {
59          super( new ByteArrayInputStream( input ) );
60      }
61      
62      private static InputStream newInputStream( final ByteBuffer buf )
63      {
64          return new InputStream()
65  		{
66              public synchronized int read() throws IOException
67  			{
68                  if ( !buf.hasRemaining() )
69                  {
70                      return -1;
71                  }
72                  
73                  int result = buf.get() & 0x000000FF;
74                  
75                  return result;
76              }
77      
78              public synchronized int read( byte[] bytes, int off, int len ) throws IOException
79  			{
80                  // Read only what's left
81                  len = Math.min( len, buf.remaining() );
82                  buf.get( bytes, off, len );
83                  return len;
84              }
85          };
86      }
87      
88      protected int readLength()
89          throws IOException
90      {
91          int length = read();
92          if ( length < 0 )
93          {
94              throw new IOException( "EOF found when length expected." );
95          }
96          
97          // Indefinite-length encoding.
98          if ( length == 0x80 )
99          {
100             return -1;
101         }
102 
103         if ( length > 127 )
104         {
105             int size = length & 0x7f;
106 
107             if ( size > 4 )
108             {
109                 throw new IOException( "DER length more than 4 bytes." );
110             }
111             
112             length = 0;
113             for ( int i = 0; i < size; i++ )
114             {
115                 int next = read();
116 
117                 if ( next < 0 )
118                 {
119                     throw new IOException( "EOF found reading length." );
120                 }
121 
122                 length = ( length << 8 ) + next;
123             }
124             
125             if ( length < 0 )
126             {
127                 throw new IOException( "Corrupted steam - negative length found." );
128             }
129         }
130 
131         return length;
132     }
133 
134     protected void readFully( byte[] bytes )
135         throws IOException
136     {
137         int left = bytes.length;
138         int len;
139 
140         if ( left == 0 )
141         {
142             return;
143         }
144 
145         while ( ( len = read( bytes, bytes.length - left, left ) ) > 0 )
146         {
147             if ( ( left -= len ) == 0 )
148             {
149                 return;
150             }
151         }
152 
153         if ( left != 0 )
154         {
155             throw new EOFException( "EOF encountered in middle of object." );
156         }
157     }
158 
159     /***
160      * Build an object given its tag and a byte stream.
161      */
162     protected DEREncodable buildObject( int tag, byte[] bytes )
163         throws IOException
164     {
165         if ( ( tag & DERObject.APPLICATION ) != 0 )
166         {
167             return new DERApplicationSpecific( tag, bytes );
168         }
169         
170         switch ( tag )
171         {
172         case DERObject.NULL:
173             return new DERNull();   
174         case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
175             ASN1InputStream ais = new ASN1InputStream( bytes );
176             
177             DERSequence sequence = new DERSequence();
178 
179             DEREncodable obj = ais.readObject();
180 
181             while ( obj != null )
182             {
183                 sequence.add( obj );
184                 obj = ais.readObject();
185             }
186 
187             return sequence;
188         case DERObject.SET | DERObject.CONSTRUCTED:
189             ais = new ASN1InputStream( bytes );
190             DERSet set = new DERSet();
191 
192             obj = ais.readObject();
193 
194             while ( obj != null )
195             {
196                 set.add( obj );
197                 obj = ais.readObject();
198             }
199 
200             return set;
201         case DERObject.BOOLEAN:
202             return new DERBoolean( bytes );
203         case DERObject.INTEGER:
204             return new DERInteger( bytes );
205         case DERObject.ENUMERATED:
206             return new DEREnumerated( bytes );
207         case DERObject.OBJECT_IDENTIFIER:
208             return new DERObjectIdentifier( bytes );
209         case DERObject.BIT_STRING:
210             return new DERBitString( bytes );
211         case DERObject.NUMERIC_STRING:
212             return new DERNumericString( bytes );
213         case DERObject.UTF8_STRING:
214             return new DERUTF8String( bytes );
215         case DERObject.PRINTABLE_STRING:
216             return new DERPrintableString( bytes );
217         case DERObject.IA5_STRING:
218             return new DERIA5String( bytes );
219         case DERObject.T61_STRING:
220             return new DERTeletexString( bytes );
221         case DERObject.VISIBLE_STRING:
222             return new DERVisibleString( bytes );
223         case DERObject.GENERAL_STRING:
224             return new DERGeneralString( bytes );
225         case DERObject.UNIVERSAL_STRING:
226             return new DERUniversalString( bytes );
227         case DERObject.BMP_STRING:
228             return new DERBMPString( bytes );
229         case DERObject.OCTET_STRING:
230             return new DEROctetString( bytes );
231         case DERObject.UTC_TIME:
232             return new DERUTCTime( bytes );
233         case DERObject.GENERALIZED_TIME:
234             return new DERGeneralizedTime( bytes );
235         default:
236             // Tag number is bottom 5 bits.
237             if ( ( tag & DERObject.TAGGED ) != 0 )  
238             {
239                 int tagNo = tag & 0x1f;
240 
241                 if ( tagNo == 0x1f )
242                 {
243                     int idx = 0;
244 
245                     tagNo = 0;
246 
247                     while ( ( bytes[ idx ] & 0x80 ) != 0 )
248                     {
249                         tagNo |= ( bytes[ idx++ ] & 0x7f );
250                         tagNo <<= 7;
251                     }
252 
253                     tagNo |= ( bytes[ idx ] & 0x7f );
254 
255                     byte[]  tmp = bytes;
256 
257                     bytes = new byte[ tmp.length - ( idx + 1 ) ];
258                     System.arraycopy( tmp, idx + 1, bytes, 0, bytes.length );
259                 }
260                 
261                 // Empty tag.
262                 if ( bytes.length == 0 )
263                 {
264                     if ( ( tag & DERObject.CONSTRUCTED ) == 0)
265                     {
266                         return new DERTaggedObject( tagNo, new DERNull() );
267                     }
268                     
269                     return new DERTaggedObject( false, tagNo, new DERSequence() );
270                 }
271 
272                 // Simple type - implicit, return an octet string.
273                 if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
274                 {
275                     return new DERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
276                 }
277 
278                 ais = new ASN1InputStream( bytes );
279 
280                 DEREncodable encodable = ais.readObject();
281 
282                 // Explicitly tagged - if it isn't we'd have to tell from the context.
283                 if ( ais.available() == 0 )
284                 {
285                     return new DERTaggedObject( true, tagNo, encodable, bytes );
286                 }
287 
288                 // Another implicit object, create a sequence.
289                 DERSequence derSequence = new DERSequence();
290 
291                 while ( encodable != null )
292                 {
293                     derSequence.add( encodable );
294                     encodable = ais.readObject();
295                 }
296 
297                 return new DERTaggedObject( false, tagNo, derSequence );
298             }
299 
300             return new DERUnknownTag( tag, bytes );
301         }
302     }
303 
304     /***
305      * Read a string of bytes representing an indefinite length object.
306      */
307     private byte[] readIndefiniteLengthFully()
308         throws IOException
309     {
310         ByteArrayOutputStream baos = new ByteArrayOutputStream();
311         int b, b1;
312 
313         b1 = read();
314 
315         while ( ( b = read() ) >= 0 )
316         {
317             if ( b1 == 0 && b == 0 )
318             {
319                 break;
320             }
321 
322             baos.write( b1 );
323             b1 = b;
324         }
325 
326         return baos.toByteArray();
327     }
328 
329     private BERConstructedOctetString buildConstructedOctetString()
330         throws IOException
331     {
332         Vector octets = new Vector();
333 
334         for (;;)
335         {
336             DEREncodable encodable = readObject();
337 
338             if ( encodable == END_OF_STREAM )
339             {
340                 break;
341             }
342 
343             octets.addElement( encodable );
344         }
345 
346         return new BERConstructedOctetString( octets );
347     }
348 
349     public DEREncodable readObject()
350         throws IOException
351     {
352         int tag = read();
353         if ( tag == -1 )
354         {
355             if ( EOF_FOUND )
356             {
357                 throw new EOFException( "Attempt to read past end of file." );
358             }
359 
360             EOF_FOUND = true;
361 
362             return null;
363         }
364         
365         int length = readLength();
366         
367         // Indefinite length method.
368         if ( length < 0 )
369         {
370             switch ( tag )
371             {
372             case DERObject.NULL:
373                 return new BERNull();
374             case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
375                 BERSequence sequence = new BERSequence();
376     
377                 for (;;)
378                 {
379                     DEREncodable obj = readObject();
380 
381                     if ( obj == END_OF_STREAM )
382                     {
383                         break;
384                     }
385 
386                     sequence.add( obj );
387                 }
388                 return sequence;
389             case DERObject.SET | DERObject.CONSTRUCTED:
390                 BERSet set = new BERSet();
391     
392                 for (;;)
393                 {
394                     DEREncodable obj = readObject();
395 
396                     if ( obj == END_OF_STREAM )
397                     {
398                         break;
399                     }
400 
401                     set.add( obj );
402                 }
403                 return set;
404             case DERObject.OCTET_STRING | DERObject.CONSTRUCTED:
405                 return buildConstructedOctetString();
406             default:
407                 // Tag number is bottom 5 bits.
408                 if ( ( tag & DERObject.TAGGED ) != 0 )  
409                 {
410                     int tagNo = tag & 0x1f;
411 
412                     if ( tagNo == 0x1f )
413                     {
414                         int b = read();
415 
416                         tagNo = 0;
417 
418                         while ( ( b >= 0 ) && ( ( b & 0x80 ) != 0 ) )
419                         {
420                             tagNo |= ( b & 0x7f );
421                             tagNo <<= 7;
422                             b = read();
423                         }
424 
425                         tagNo |= ( b & 0x7f );
426                     }
427 
428                     // Simple type - implicit, return an octet string.
429                     if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
430                     {
431                         byte[]  bytes = readIndefiniteLengthFully();
432 
433                         return new BERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
434                     }
435 
436                     // Either constructed or explicitly tagged
437                     DEREncodable dObj = readObject();
438                     
439                     // Empty tag!
440                     if ( dObj == END_OF_STREAM )
441                     {
442                         return new DERTaggedObject( tagNo );
443                     }
444 
445                     DEREncodable next = readObject();
446 
447                     // Explicitly tagged.
448                     if ( next == END_OF_STREAM )
449                     {
450                         return new BERTaggedObject( tagNo, dObj );
451                     }
452 
453                     // Another implicit object, create a sequence.
454                     BERSequence berSequence = new BERSequence();
455 
456                     berSequence.add( dObj );
457 
458                     do
459                     {
460                     	berSequence.add( next );
461                         next = readObject();
462                     }
463                     while ( next != END_OF_STREAM );
464 
465                     return new BERTaggedObject( false, tagNo, berSequence );
466                 }
467 
468                 throw new IOException( "Unknown BER object encountered." );
469             }
470         }
471         
472         // End of contents marker.
473         if ( tag == 0 && length == 0 )
474         {
475             return END_OF_STREAM;
476         }
477 
478         byte[] bytes = new byte[ length ];
479 
480         readFully( bytes );
481 
482         return buildObject( tag, bytes );
483     }
484 }
485