    001package org.apache.commons.ssl.asn1;
    002
    003import java.io.ByteArrayInputStream;
    004import java.io.EOFException;
    005import java.io.FilterInputStream;
    006import java.io.IOException;
    007import 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 */
    016public 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}