001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.util.asn1;
019    
020    import java.io.ByteArrayInputStream;
021    import java.io.ByteArrayOutputStream;
022    import java.io.EOFException;
023    import java.io.FilterInputStream;
024    import java.io.IOException;
025    import java.io.InputStream;
026    import java.util.Vector;
027    
028    /**
029     * a general purpose ASN.1 decoder - note: this class differs from the
030     * others in that it returns null after it has read the last object in
031     * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
032     * returned.
033     */
034    public class ASN1InputStream
035        extends FilterInputStream
036        implements DERTags
037    {
038        private DERObject END_OF_STREAM = new DERObject() {
039                                            void encode(
040                                                DEROutputStream out)
041                                            throws IOException
042                                            {
043                                                throw new IOException("Eeek!");
044                                            }
045                                            public int hashCode()
046                                            {
047                                                return 0;
048                                            }
049                                            public boolean equals(
050                                                Object o)
051                                            {
052                                                return o == this;
053                                            }
054                                        };
055        boolean eofFound = false;
056    
057        public ASN1InputStream(
058            InputStream is)
059        {
060            super(is);
061        }
062    
063        public ASN1InputStream(
064            byte[] input)
065        {
066            super(new ByteArrayInputStream(input));
067        }
068    
069        protected int readLength()
070            throws IOException
071        {
072            int length = read();
073            if (length < 0)
074            {
075                throw new IOException("EOF found when length expected");
076            }
077    
078            if (length == 0x80)
079            {
080                return -1;      // indefinite-length encoding
081            }
082    
083            if (length > 127)
084            {
085                int size = length & 0x7f;
086    
087                if (size > 4)
088                {
089                    throw new IOException("DER length more than 4 bytes");
090                }
091    
092                length = 0;
093                for (int i = 0; i < size; i++)
094                {
095                    int next = read();
096    
097                    if (next < 0)
098                    {
099                        throw new IOException("EOF found reading length");
100                    }
101    
102                    length = (length << 8) + next;
103                }
104    
105                if (length < 0)
106                {
107                    throw new IOException("corrupted steam - negative length found");
108                }
109            }
110    
111            return length;
112        }
113    
114        protected void readFully(
115            byte[]  bytes)
116            throws IOException
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("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
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    bIn = new ByteArrayInputStream(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(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(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
310        {
311            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
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
332        {
333            Vector               octs = new Vector();
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
352        {
353            int tag = read();
354            if (tag == -1)
355            {
356                if (eofFound)
357                {
358                    throw new EOFException("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("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    }