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