001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    
019    package org.apache.geronimo.util.asn1;
020    
021    import java.io.ByteArrayInputStream;
022    import java.io.EOFException;
023    import java.io.FilterInputStream;
024    import java.io.IOException;
025    import java.io.InputStream;
026    
027    /**
028     * Don't use this class. It will eventually disappear, use ASN1InputStream.
029     * <br>
030     * This class is scheduled for removal.
031     * @deprecated use ASN1InputStream
032     */
033    public class DERInputStream
034        extends FilterInputStream implements DERTags
035    {
036        /**
037         * @deprecated use ASN1InputStream
038         */
039        public DERInputStream(
040            InputStream is)
041        {
042            super(is);
043        }
044    
045        protected int readLength()
046            throws IOException
047        {
048            int length = read();
049            if (length < 0)
050            {
051                throw new IOException("EOF found when length expected");
052            }
053    
054            if (length == 0x80)
055            {
056                return -1;      // indefinite-length encoding
057            }
058    
059            if (length > 127)
060            {
061                int size = length & 0x7f;
062    
063                if (size > 4)
064                {
065                    throw new IOException("DER length more than 4 bytes");
066                }
067    
068                length = 0;
069                for (int i = 0; i < size; i++)
070                {
071                    int next = read();
072    
073                    if (next < 0)
074                    {
075                        throw new IOException("EOF found reading length");
076                    }
077    
078                    length = (length << 8) + next;
079                }
080    
081                if (length < 0)
082                {
083                    throw new IOException("corrupted steam - negative length found");
084                }
085            }
086    
087            return length;
088        }
089    
090        protected void readFully(
091            byte[]  bytes)
092            throws IOException
093        {
094            int     left = bytes.length;
095    
096            if (left == 0)
097            {
098                return;
099            }
100    
101            while (left > 0)
102            {
103                int    l = read(bytes, bytes.length - left, left);
104    
105                if (l < 0)
106                {
107                    throw new EOFException("unexpected end of stream");
108                }
109    
110                left -= l;
111            }
112        }
113    
114        /**
115         * build an object given its tag and a byte stream to construct it
116         * from.
117         */
118        protected DERObject buildObject(
119            int       tag,
120            byte[]    bytes)
121            throws IOException
122        {
123            switch (tag)
124            {
125            case NULL:
126                return null;
127            case SEQUENCE | CONSTRUCTED:
128                ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
129                BERInputStream          dIn = new BERInputStream(bIn);
130                DERConstructedSequence  seq = new DERConstructedSequence();
131    
132                try
133                {
134                    for (;;)
135                    {
136                        DERObject   obj = dIn.readObject();
137    
138                        seq.addObject(obj);
139                    }
140                }
141                catch (EOFException ex)
142                {
143                    return seq;
144                }
145            case SET | CONSTRUCTED:
146                bIn = new ByteArrayInputStream(bytes);
147                dIn = new BERInputStream(bIn);
148    
149                ASN1EncodableVector    v = new ASN1EncodableVector();
150    
151                try
152                {
153                    for (;;)
154                    {
155                        DERObject   obj = dIn.readObject();
156    
157                        v.add(obj);
158                    }
159                }
160                catch (EOFException ex)
161                {
162                    return new DERConstructedSet(v);
163                }
164            case BOOLEAN:
165                return new DERBoolean(bytes);
166            case INTEGER:
167                return new DERInteger(bytes);
168            case ENUMERATED:
169                return new DEREnumerated(bytes);
170            case OBJECT_IDENTIFIER:
171                return new DERObjectIdentifier(bytes);
172            case BIT_STRING:
173                int     padBits = bytes[0];
174                byte[]  data = new byte[bytes.length - 1];
175    
176                System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
177    
178                return new DERBitString(data, padBits);
179            case UTF8_STRING:
180                return new DERUTF8String(bytes);
181            case PRINTABLE_STRING:
182                return new DERPrintableString(bytes);
183            case IA5_STRING:
184                return new DERIA5String(bytes);
185            case T61_STRING:
186                return new DERT61String(bytes);
187            case VISIBLE_STRING:
188                return new DERVisibleString(bytes);
189            case UNIVERSAL_STRING:
190                return new DERUniversalString(bytes);
191            case GENERAL_STRING:
192                return new DERGeneralString(bytes);
193            case BMP_STRING:
194                return new DERBMPString(bytes);
195            case OCTET_STRING:
196                return new DEROctetString(bytes);
197            case UTC_TIME:
198                return new DERUTCTime(bytes);
199            case GENERALIZED_TIME:
200                return new DERGeneralizedTime(bytes);
201            default:
202                //
203                // with tagged object tag number is bottom 5 bits
204                //
205                if ((tag & TAGGED) != 0)
206                {
207                    if ((tag & 0x1f) == 0x1f)
208                    {
209                        throw new IOException("unsupported high tag encountered");
210                    }
211    
212                    if (bytes.length == 0)        // empty tag!
213                    {
214                        if ((tag & CONSTRUCTED) == 0)
215                        {
216                            return new DERTaggedObject(false, tag & 0x1f, new DERNull());
217                        }
218                        else
219                        {
220                            return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence());
221                        }
222                    }
223    
224                    //
225                    // simple type - implicit... return an octet string
226                    //
227                    if ((tag & CONSTRUCTED) == 0)
228                    {
229                        return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
230                    }
231    
232                    bIn = new ByteArrayInputStream(bytes);
233                    dIn = new BERInputStream(bIn);
234    
235                    DEREncodable dObj = dIn.readObject();
236    
237                    //
238                    // explicitly tagged (probably!) - if it isn't we'd have to
239                    // tell from the context
240                    //
241                    if (dIn.available() == 0)
242                    {
243                        return new DERTaggedObject(tag & 0x1f, dObj);
244                    }
245    
246                    //
247                    // another implicit object, we'll create a sequence...
248                    //
249                    seq = new DERConstructedSequence();
250    
251                    seq.addObject(dObj);
252    
253                    try
254                    {
255                        for (;;)
256                        {
257                            dObj = dIn.readObject();
258    
259                            seq.addObject(dObj);
260                        }
261                    }
262                    catch (EOFException ex)
263                    {
264                        // ignore --
265                    }
266    
267                    return new DERTaggedObject(false, tag & 0x1f, seq);
268                }
269    
270                return new DERUnknownTag(tag, bytes);
271            }
272        }
273    
274        public DERObject readObject()
275            throws IOException
276        {
277            int tag = read();
278            if (tag == -1)
279            {
280                throw new EOFException();
281            }
282    
283            int     length = readLength();
284            byte[]  bytes = new byte[length];
285    
286            readFully(bytes);
287    
288            return buildObject(tag, bytes);
289        }
290    }