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    import org.apache.directory.shared.i18n.I18n;
036    
037    
038    /**
039     * General purpose ASN.1 decoder.
040     */
041    public class ASN1InputStream extends FilterInputStream
042    {
043        private boolean EOF_FOUND = false;
044    
045        private DERObject END_OF_STREAM = new DERObject( 0, null )
046        {
047            public void encode( ASN1OutputStream out ) throws IOException
048            {
049                throw new IOException( I18n.err( I18n.ERR_00016 ) );
050            }
051    
052    
053            /**
054             * Compute the instance hash code
055             * @return the instance's hashcode 
056             */
057            public int hashCode()
058            {
059                return 0;
060            }
061    
062    
063            public boolean equals( Object o )
064            {
065                return o == this;
066            }
067        };
068    
069    
070        public ASN1InputStream(ByteBuffer in)
071        {
072            super( newInputStream( in ) );
073        }
074    
075    
076        public ASN1InputStream(byte[] input)
077        {
078            super( new ByteArrayInputStream( input ) );
079        }
080    
081    
082        private static InputStream newInputStream( final ByteBuffer buf )
083        {
084            return new InputStream()
085            {
086                public synchronized int read() throws IOException
087                {
088                    if ( !buf.hasRemaining() )
089                    {
090                        return -1;
091                    }
092    
093                    int result = buf.get() & 0x000000FF;
094    
095                    return result;
096                }
097    
098    
099                public synchronized int read( byte[] bytes, int off, int len ) throws IOException
100                {
101                    // Read only what's left
102                    len = Math.min( len, buf.remaining() );
103                    buf.get( bytes, off, len );
104                    return len;
105                }
106            };
107        }
108    
109    
110        protected int readLength() throws IOException
111        {
112            int length = read();
113            if ( length < 0 )
114            {
115                throw new IOException( I18n.err( I18n.ERR_00017 ) );
116            }
117    
118            // Indefinite-length encoding.
119            if ( length == 0x80 )
120            {
121                return -1;
122            }
123    
124            if ( length > 127 )
125            {
126                int size = length & 0x7f;
127    
128                if ( size > 4 )
129                {
130                    throw new IOException( I18n.err( I18n.ERR_00018 ) );
131                }
132    
133                length = 0;
134                for ( int i = 0; i < size; i++ )
135                {
136                    int next = read();
137    
138                    if ( next < 0 )
139                    {
140                        throw new IOException( I18n.err( I18n.ERR_00019 ) );
141                    }
142    
143                    length = ( length << 8 ) + next;
144                }
145    
146                if ( length < 0 )
147                {
148                    throw new IOException( I18n.err( I18n.ERR_00020 ) );
149                }
150            }
151    
152            return length;
153        }
154    
155    
156        protected void readFully( byte[] bytes ) throws IOException
157        {
158            int left = bytes.length;
159            int len;
160    
161            if ( left == 0 )
162            {
163                return;
164            }
165    
166            while ( ( len = read( bytes, bytes.length - left, left ) ) > 0 )
167            {
168                if ( ( left -= len ) == 0 )
169                {
170                    return;
171                }
172            }
173    
174            if ( left != 0 )
175            {
176                throw new EOFException( I18n.err( I18n.ERR_00021 ) );
177            }
178        }
179    
180    
181        /**
182         * Build an object given its tag and a byte stream.
183         */
184        protected DEREncodable buildObject( int tag, byte[] bytes ) throws IOException
185        {
186            if ( ( tag & DERObject.APPLICATION ) != 0 )
187            {
188                return new DERApplicationSpecific( tag, bytes );
189            }
190    
191            switch ( tag )
192            {
193                case DERObject.NULL:
194                    return new DERNull();
195                case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
196                    ASN1InputStream ais = new ASN1InputStream( bytes );
197                    DEREncodable obj = null;
198                    DERSequence sequence = new DERSequence();
199    
200                    try
201                    {
202                        obj = ais.readObject();
203        
204                        while ( obj != null )
205                        {
206                            sequence.add( obj );
207                            obj = ais.readObject();
208                        }
209                    }
210                    finally
211                    {
212                        ais.close();
213                    }
214    
215                    return sequence;
216                case DERObject.SET | DERObject.CONSTRUCTED:
217                    ais = new ASN1InputStream( bytes );
218                    DERSet set = new DERSet();
219    
220                    try
221                    {
222                        obj = ais.readObject();
223        
224                        while ( obj != null )
225                        {
226                            set.add( obj );
227                            obj = ais.readObject();
228                        }
229                    }
230                    finally
231                    {
232                        ais.close();
233                    }
234    
235                    return set;
236                case DERObject.BOOLEAN:
237                    return new DERBoolean( bytes );
238                case DERObject.INTEGER:
239                    return new DERInteger( bytes );
240                case DERObject.ENUMERATED:
241                    return new DEREnumerated( bytes );
242                case DERObject.OBJECT_IDENTIFIER:
243                    return new DERObjectIdentifier( bytes );
244                case DERObject.BIT_STRING:
245                    return new DERBitString( bytes );
246                case DERObject.NUMERIC_STRING:
247                    return new DERNumericString( bytes );
248                case DERObject.UTF8_STRING:
249                    return new DERUTF8String( bytes );
250                case DERObject.PRINTABLE_STRING:
251                    return new DERPrintableString( bytes );
252                case DERObject.IA5_STRING:
253                    return new DERIA5String( bytes );
254                case DERObject.T61_STRING:
255                    return new DERTeletexString( bytes );
256                case DERObject.VISIBLE_STRING:
257                    return new DERVisibleString( bytes );
258                case DERObject.GENERAL_STRING:
259                    return new DERGeneralString( bytes );
260                case DERObject.UNIVERSAL_STRING:
261                    return new DERUniversalString( bytes );
262                case DERObject.BMP_STRING:
263                    return new DERBMPString( bytes );
264                case DERObject.OCTET_STRING:
265                    return new DEROctetString( bytes );
266                case DERObject.UTC_TIME:
267                    return new DERUTCTime( bytes );
268                case DERObject.GENERALIZED_TIME:
269                    return new DERGeneralizedTime( bytes );
270                default:
271                    // Tag number is bottom 5 bits.
272                    if ( ( tag & DERObject.TAGGED ) != 0 )
273                    {
274                        int tagNo = tag & 0x1f;
275    
276                        if ( tagNo == 0x1f )
277                        {
278                            int idx = 0;
279    
280                            tagNo = 0;
281    
282                            while ( ( bytes[idx] & 0x80 ) != 0 )
283                            {
284                                tagNo |= ( bytes[idx++] & 0x7f );
285                                tagNo <<= 7;
286                            }
287    
288                            tagNo |= ( bytes[idx] & 0x7f );
289    
290                            byte[] tmp = bytes;
291    
292                            bytes = new byte[tmp.length - ( idx + 1 )];
293                            System.arraycopy( tmp, idx + 1, bytes, 0, bytes.length );
294                        }
295    
296                        // Empty tag.
297                        if ( bytes.length == 0 )
298                        {
299                            if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
300                            {
301                                return new DERTaggedObject( tagNo, new DERNull() );
302                            }
303    
304                            return new DERTaggedObject( false, tagNo, new DERSequence() );
305                        }
306    
307                        // Simple type - implicit, return an octet string.
308                        if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
309                        {
310                            return new DERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
311                        }
312    
313                        ais = new ASN1InputStream( bytes );
314    
315                        try
316                        {
317                            DEREncodable encodable = ais.readObject();
318        
319                            // Explicitly tagged - if it isn't we'd have to tell from
320                            // the context.
321                            if ( ais.available() == 0 )
322                            {
323                                return new DERTaggedObject( true, tagNo, encodable, bytes );
324                            }
325        
326                            // Another implicit object, create a sequence.
327                            DERSequence derSequence = new DERSequence();
328        
329                            while ( encodable != null )
330                            {
331                                derSequence.add( encodable );
332                                encodable = ais.readObject();
333                            }
334    
335                            return new DERTaggedObject( false, tagNo, derSequence );
336                        }
337                        finally
338                        {
339                            ais.close();
340                        }
341                    }
342    
343                    return new DERUnknownTag( tag, bytes );
344            }
345        }
346    
347    
348        /**
349         * Read a string of bytes representing an indefinite length object.
350         */
351        private byte[] readIndefiniteLengthFully() throws IOException
352        {
353            ByteArrayOutputStream baos = new ByteArrayOutputStream();
354            int b, b1;
355    
356            b1 = read();
357    
358            while ( ( b = read() ) >= 0 )
359            {
360                if ( b1 == 0 && b == 0 )
361                {
362                    break;
363                }
364    
365                baos.write( b1 );
366                b1 = b;
367            }
368    
369            return baos.toByteArray();
370        }
371    
372    
373        private BERConstructedOctetString buildConstructedOctetString() throws IOException
374        {
375            Vector<DEREncodable> octets = new Vector<DEREncodable>();
376    
377            for ( ;; )
378            {
379                DEREncodable encodable = readObject();
380    
381                if ( encodable == END_OF_STREAM )
382                {
383                    break;
384                }
385    
386                octets.addElement( encodable );
387            }
388    
389            return new BERConstructedOctetString( octets );
390        }
391    
392    
393        public DEREncodable readObject() throws IOException
394        {
395            int tag = read();
396            if ( tag == -1 )
397            {
398                if ( EOF_FOUND )
399                {
400                    throw new EOFException( I18n.err( I18n.ERR_00022 ) );
401                }
402    
403                EOF_FOUND = true;
404    
405                return null;
406            }
407    
408            int length = readLength();
409    
410            // Indefinite length method.
411            if ( length < 0 )
412            {
413                switch ( tag )
414                {
415                    case DERObject.NULL:
416                        return new BERNull();
417                    case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
418                        BERSequence sequence = new BERSequence();
419    
420                        for ( ;; )
421                        {
422                            DEREncodable obj = readObject();
423    
424                            if ( obj == END_OF_STREAM )
425                            {
426                                break;
427                            }
428    
429                            sequence.add( obj );
430                        }
431                        return sequence;
432                    case DERObject.SET | DERObject.CONSTRUCTED:
433                        BERSet set = new BERSet();
434    
435                        for ( ;; )
436                        {
437                            DEREncodable obj = readObject();
438    
439                            if ( obj == END_OF_STREAM )
440                            {
441                                break;
442                            }
443    
444                            set.add( obj );
445                        }
446                        return set;
447                    case DERObject.OCTET_STRING | DERObject.CONSTRUCTED:
448                        return buildConstructedOctetString();
449                    default:
450                        // Tag number is bottom 5 bits.
451                        if ( ( tag & DERObject.TAGGED ) != 0 )
452                        {
453                            int tagNo = tag & 0x1f;
454    
455                            if ( tagNo == 0x1f )
456                            {
457                                int b = read();
458    
459                                tagNo = 0;
460    
461                                while ( ( b >= 0 ) && ( ( b & 0x80 ) != 0 ) )
462                                {
463                                    tagNo |= ( b & 0x7f );
464                                    tagNo <<= 7;
465                                    b = read();
466                                }
467    
468                                tagNo |= ( b & 0x7f );
469                            }
470    
471                            // Simple type - implicit, return an octet string.
472                            if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
473                            {
474                                byte[] bytes = readIndefiniteLengthFully();
475    
476                                return new BERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
477                            }
478    
479                            // Either constructed or explicitly tagged
480                            DEREncodable dObj = readObject();
481    
482                            // Empty tag!
483                            if ( dObj == END_OF_STREAM )
484                            {
485                                return new DERTaggedObject( tagNo );
486                            }
487    
488                            DEREncodable next = readObject();
489    
490                            // Explicitly tagged.
491                            if ( next == END_OF_STREAM )
492                            {
493                                return new BERTaggedObject( tagNo, dObj );
494                            }
495    
496                            // Another implicit object, create a sequence.
497                            BERSequence berSequence = new BERSequence();
498    
499                            berSequence.add( dObj );
500    
501                            do
502                            {
503                                berSequence.add( next );
504                                next = readObject();
505                            }
506                            while ( next != END_OF_STREAM );
507    
508                            return new BERTaggedObject( false, tagNo, berSequence );
509                        }
510    
511                        throw new IOException( I18n.err( I18n.ERR_00023 ) );
512                }
513            }
514    
515            // End of contents marker.
516            if ( tag == 0 && length == 0 )
517            {
518                return END_OF_STREAM;
519            }
520    
521            byte[] bytes = new byte[length];
522    
523            readFully( bytes );
524    
525            return buildObject( tag, bytes );
526        }
527    }