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