001    /*
002     * Copyright (c) 2000 - 2006 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
003     * 
004     * Permission is hereby granted, free of charge, to any person obtaining a copy of this
005     * software and associated documentation files (the "Software"), to deal in the Software
006     * without restriction, including without limitation the rights to use, copy, modify,
007     * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
008     * permit persons to whom the Software is furnished to do so, subject to the following
009     * conditions:
010     * 
011     * The above copyright notice and this permission notice shall be included in all copies
012     * or substantial portions of the Software.
013     * 
014     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
015     * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
016     * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
017     * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
018     * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
019     * DEALINGS IN THE SOFTWARE.
020     * 
021     */
022    
023    package org.apache.directory.shared.asn1.der;
024    
025    
026    import java.io.ByteArrayInputStream;
027    import java.io.ByteArrayOutputStream;
028    import java.io.EOFException;
029    import java.io.FilterInputStream;
030    import java.io.IOException;
031    import java.io.InputStream;
032    import java.nio.ByteBuffer;
033    import java.util.Vector;
034    
035    
036    /**
037     * General purpose ASN.1 decoder.
038     */
039    public class ASN1InputStream extends FilterInputStream
040    {
041        private boolean EOF_FOUND = false;
042    
043        private DERObject END_OF_STREAM = new DERObject( 0, null )
044        {
045            public void encode( ASN1OutputStream out ) throws IOException
046            {
047                throw new IOException( "End of stream." );
048            }
049    
050    
051            /**
052             * Compute the instance hash code
053             * @return the instance's hashcode 
054             */
055            public int hashCode()
056            {
057                return 0;
058            }
059    
060    
061            public boolean equals( Object o )
062            {
063                return o == this;
064            }
065        };
066    
067    
068        public ASN1InputStream(ByteBuffer in)
069        {
070            super( newInputStream( in ) );
071        }
072    
073    
074        public ASN1InputStream(byte[] input)
075        {
076            super( new ByteArrayInputStream( input ) );
077        }
078    
079    
080        private static InputStream newInputStream( final ByteBuffer buf )
081        {
082            return new InputStream()
083            {
084                public synchronized int read() throws IOException
085                {
086                    if ( !buf.hasRemaining() )
087                    {
088                        return -1;
089                    }
090    
091                    int result = buf.get() & 0x000000FF;
092    
093                    return result;
094                }
095    
096    
097                public synchronized int read( byte[] bytes, int off, int len ) throws IOException
098                {
099                    // Read only what's left
100                    len = Math.min( len, buf.remaining() );
101                    buf.get( bytes, off, len );
102                    return len;
103                }
104            };
105        }
106    
107    
108        protected int readLength() throws IOException
109        {
110            int length = read();
111            if ( length < 0 )
112            {
113                throw new IOException( "EOF found when length expected." );
114            }
115    
116            // Indefinite-length encoding.
117            if ( length == 0x80 )
118            {
119                return -1;
120            }
121    
122            if ( length > 127 )
123            {
124                int size = length & 0x7f;
125    
126                if ( size > 4 )
127                {
128                    throw new IOException( "DER length more than 4 bytes." );
129                }
130    
131                length = 0;
132                for ( int i = 0; i < size; i++ )
133                {
134                    int next = read();
135    
136                    if ( next < 0 )
137                    {
138                        throw new IOException( "EOF found reading length." );
139                    }
140    
141                    length = ( length << 8 ) + next;
142                }
143    
144                if ( length < 0 )
145                {
146                    throw new IOException( "Corrupted steam - negative length found." );
147                }
148            }
149    
150            return length;
151        }
152    
153    
154        protected void readFully( byte[] bytes ) throws IOException
155        {
156            int left = bytes.length;
157            int len;
158    
159            if ( left == 0 )
160            {
161                return;
162            }
163    
164            while ( ( len = read( bytes, bytes.length - left, left ) ) > 0 )
165            {
166                if ( ( left -= len ) == 0 )
167                {
168                    return;
169                }
170            }
171    
172            if ( left != 0 )
173            {
174                throw new EOFException( "EOF encountered in middle of object." );
175            }
176        }
177    
178    
179        /**
180         * Build an object given its tag and a byte stream.
181         */
182        protected DEREncodable buildObject( int tag, byte[] bytes ) throws IOException
183        {
184            if ( ( tag & DERObject.APPLICATION ) != 0 )
185            {
186                return new DERApplicationSpecific( tag, bytes );
187            }
188    
189            switch ( tag )
190            {
191                case DERObject.NULL:
192                    return new DERNull();
193                case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
194                    ASN1InputStream ais = new ASN1InputStream( bytes );
195                    DEREncodable obj = null;
196                    DERSequence sequence = new DERSequence();
197    
198                    try
199                    {
200                        obj = ais.readObject();
201        
202                        while ( obj != null )
203                        {
204                            sequence.add( obj );
205                            obj = ais.readObject();
206                        }
207                    }
208                    finally
209                    {
210                        ais.close();
211                    }
212    
213                    return sequence;
214                case DERObject.SET | DERObject.CONSTRUCTED:
215                    ais = new ASN1InputStream( bytes );
216                    DERSet set = new DERSet();
217    
218                    try
219                    {
220                        obj = ais.readObject();
221        
222                        while ( obj != null )
223                        {
224                            set.add( obj );
225                            obj = ais.readObject();
226                        }
227                    }
228                    finally
229                    {
230                        ais.close();
231                    }
232    
233                    return set;
234                case DERObject.BOOLEAN:
235                    return new DERBoolean( bytes );
236                case DERObject.INTEGER:
237                    return new DERInteger( bytes );
238                case DERObject.ENUMERATED:
239                    return new DEREnumerated( bytes );
240                case DERObject.OBJECT_IDENTIFIER:
241                    return new DERObjectIdentifier( bytes );
242                case DERObject.BIT_STRING:
243                    return new DERBitString( bytes );
244                case DERObject.NUMERIC_STRING:
245                    return new DERNumericString( bytes );
246                case DERObject.UTF8_STRING:
247                    return new DERUTF8String( bytes );
248                case DERObject.PRINTABLE_STRING:
249                    return new DERPrintableString( bytes );
250                case DERObject.IA5_STRING:
251                    return new DERIA5String( bytes );
252                case DERObject.T61_STRING:
253                    return new DERTeletexString( bytes );
254                case DERObject.VISIBLE_STRING:
255                    return new DERVisibleString( bytes );
256                case DERObject.GENERAL_STRING:
257                    return new DERGeneralString( bytes );
258                case DERObject.UNIVERSAL_STRING:
259                    return new DERUniversalString( bytes );
260                case DERObject.BMP_STRING:
261                    return new DERBMPString( bytes );
262                case DERObject.OCTET_STRING:
263                    return new DEROctetString( bytes );
264                case DERObject.UTC_TIME:
265                    return new DERUTCTime( bytes );
266                case DERObject.GENERALIZED_TIME:
267                    return new DERGeneralizedTime( bytes );
268                default:
269                    // Tag number is bottom 5 bits.
270                    if ( ( tag & DERObject.TAGGED ) != 0 )
271                    {
272                        int tagNo = tag & 0x1f;
273    
274                        if ( tagNo == 0x1f )
275                        {
276                            int idx = 0;
277    
278                            tagNo = 0;
279    
280                            while ( ( bytes[idx] & 0x80 ) != 0 )
281                            {
282                                tagNo |= ( bytes[idx++] & 0x7f );
283                                tagNo <<= 7;
284                            }
285    
286                            tagNo |= ( bytes[idx] & 0x7f );
287    
288                            byte[] tmp = bytes;
289    
290                            bytes = new byte[tmp.length - ( idx + 1 )];
291                            System.arraycopy( tmp, idx + 1, bytes, 0, bytes.length );
292                        }
293    
294                        // Empty tag.
295                        if ( bytes.length == 0 )
296                        {
297                            if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
298                            {
299                                return new DERTaggedObject( tagNo, new DERNull() );
300                            }
301    
302                            return new DERTaggedObject( false, tagNo, new DERSequence() );
303                        }
304    
305                        // Simple type - implicit, return an octet string.
306                        if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
307                        {
308                            return new DERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
309                        }
310    
311                        ais = new ASN1InputStream( bytes );
312    
313                        try
314                        {
315                            DEREncodable encodable = ais.readObject();
316        
317                            // Explicitly tagged - if it isn't we'd have to tell from
318                            // the context.
319                            if ( ais.available() == 0 )
320                            {
321                                return new DERTaggedObject( true, tagNo, encodable, bytes );
322                            }
323        
324                            // Another implicit object, create a sequence.
325                            DERSequence derSequence = new DERSequence();
326        
327                            while ( encodable != null )
328                            {
329                                derSequence.add( encodable );
330                                encodable = ais.readObject();
331                            }
332    
333                            return new DERTaggedObject( false, tagNo, derSequence );
334                        }
335                        finally
336                        {
337                            ais.close();
338                        }
339                    }
340    
341                    return new DERUnknownTag( tag, bytes );
342            }
343        }
344    
345    
346        /**
347         * Read a string of bytes representing an indefinite length object.
348         */
349        private byte[] readIndefiniteLengthFully() throws IOException
350        {
351            ByteArrayOutputStream baos = new ByteArrayOutputStream();
352            int b, b1;
353    
354            b1 = read();
355    
356            while ( ( b = read() ) >= 0 )
357            {
358                if ( b1 == 0 && b == 0 )
359                {
360                    break;
361                }
362    
363                baos.write( b1 );
364                b1 = b;
365            }
366    
367            return baos.toByteArray();
368        }
369    
370    
371        private BERConstructedOctetString buildConstructedOctetString() throws IOException
372        {
373            Vector<DEREncodable> octets = new Vector<DEREncodable>();
374    
375            for ( ;; )
376            {
377                DEREncodable encodable = readObject();
378    
379                if ( encodable == END_OF_STREAM )
380                {
381                    break;
382                }
383    
384                octets.addElement( encodable );
385            }
386    
387            return new BERConstructedOctetString( octets );
388        }
389    
390    
391        public DEREncodable readObject() throws IOException
392        {
393            int tag = read();
394            if ( tag == -1 )
395            {
396                if ( EOF_FOUND )
397                {
398                    throw new EOFException( "Attempt to read past end of file." );
399                }
400    
401                EOF_FOUND = true;
402    
403                return null;
404            }
405    
406            int length = readLength();
407    
408            // Indefinite length method.
409            if ( length < 0 )
410            {
411                switch ( tag )
412                {
413                    case DERObject.NULL:
414                        return new BERNull();
415                    case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
416                        BERSequence sequence = new BERSequence();
417    
418                        for ( ;; )
419                        {
420                            DEREncodable obj = readObject();
421    
422                            if ( obj == END_OF_STREAM )
423                            {
424                                break;
425                            }
426    
427                            sequence.add( obj );
428                        }
429                        return sequence;
430                    case DERObject.SET | DERObject.CONSTRUCTED:
431                        BERSet set = new BERSet();
432    
433                        for ( ;; )
434                        {
435                            DEREncodable obj = readObject();
436    
437                            if ( obj == END_OF_STREAM )
438                            {
439                                break;
440                            }
441    
442                            set.add( obj );
443                        }
444                        return set;
445                    case DERObject.OCTET_STRING | DERObject.CONSTRUCTED:
446                        return buildConstructedOctetString();
447                    default:
448                        // Tag number is bottom 5 bits.
449                        if ( ( tag & DERObject.TAGGED ) != 0 )
450                        {
451                            int tagNo = tag & 0x1f;
452    
453                            if ( tagNo == 0x1f )
454                            {
455                                int b = read();
456    
457                                tagNo = 0;
458    
459                                while ( ( b >= 0 ) && ( ( b & 0x80 ) != 0 ) )
460                                {
461                                    tagNo |= ( b & 0x7f );
462                                    tagNo <<= 7;
463                                    b = read();
464                                }
465    
466                                tagNo |= ( b & 0x7f );
467                            }
468    
469                            // Simple type - implicit, return an octet string.
470                            if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
471                            {
472                                byte[] bytes = readIndefiniteLengthFully();
473    
474                                return new BERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
475                            }
476    
477                            // Either constructed or explicitly tagged
478                            DEREncodable dObj = readObject();
479    
480                            // Empty tag!
481                            if ( dObj == END_OF_STREAM )
482                            {
483                                return new DERTaggedObject( tagNo );
484                            }
485    
486                            DEREncodable next = readObject();
487    
488                            // Explicitly tagged.
489                            if ( next == END_OF_STREAM )
490                            {
491                                return new BERTaggedObject( tagNo, dObj );
492                            }
493    
494                            // Another implicit object, create a sequence.
495                            BERSequence berSequence = new BERSequence();
496    
497                            berSequence.add( dObj );
498    
499                            do
500                            {
501                                berSequence.add( next );
502                                next = readObject();
503                            }
504                            while ( next != END_OF_STREAM );
505    
506                            return new BERTaggedObject( false, tagNo, berSequence );
507                        }
508    
509                        throw new IOException( "Unknown BER object encountered." );
510                }
511            }
512    
513            // End of contents marker.
514            if ( tag == 0 && length == 0 )
515            {
516                return END_OF_STREAM;
517            }
518    
519            byte[] bytes = new byte[length];
520    
521            readFully( bytes );
522    
523            return buildObject( tag, bytes );
524        }
525    }