1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.asn1;
2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.ByteArrayInputStream;
4b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.EOFException;
5b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.FilterInputStream;
6b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.IOException;
7b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.InputStream;
8c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
9c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.util.io.Streams;
10b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
11b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam/**
12b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * a general purpose ASN.1 decoder - note: this class differs from the
13b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * others in that it returns null after it has read the last object in
14b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
15b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * returned.
16b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */
17b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic class ASN1InputStream
18b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    extends FilterInputStream
194c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    implements BERTags
20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{
21c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private final int limit;
22c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private final boolean lazyEvaluate;
23b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
244c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    private final byte[][] tmpBuffers;
256e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom
26b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public ASN1InputStream(
27b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        InputStream is)
28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
294c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        this(is, StreamUtil.findLimit(is));
30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
31b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
32b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
33b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Create an ASN1InputStream based on the input byte array. The length of DER objects in
34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * the stream is automatically limited to the length of the input array.
35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
36b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param input array containing ASN.1 encoded data.
37b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public ASN1InputStream(
39b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] input)
40b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this(new ByteArrayInputStream(input), input.length);
42b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
43c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
44c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    /**
45c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * Create an ASN1InputStream based on the input byte array. The length of DER objects in
46c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * the stream is automatically limited to the length of the input array.
47c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     *
48c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * @param input array containing ASN.1 encoded data.
49c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
50c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     */
51c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public ASN1InputStream(
52c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[] input,
53c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        boolean lazyEvaluate)
54c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
55c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this(new ByteArrayInputStream(input), input.length, lazyEvaluate);
56c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Create an ASN1InputStream where no DER object will be longer than limit.
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param input stream containing ASN.1 encoded data.
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param limit maximum size of a DER encoded object.
63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public ASN1InputStream(
65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        InputStream input,
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         limit)
67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
68c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this(input, limit, false);
69c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
70c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
71c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    /**
72c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * Create an ASN1InputStream where no DER object will be longer than limit, and constructed
73c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * objects such as sequences will be parsed lazily.
74c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     *
75c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * @param input stream containing ASN.1 encoded data.
764c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
774c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom     */
784c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    public ASN1InputStream(
794c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        InputStream input,
804c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        boolean     lazyEvaluate)
814c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    {
824c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        this(input, StreamUtil.findLimit(input), lazyEvaluate);
834c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    }
844c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
854c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    /**
864c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom     * Create an ASN1InputStream where no DER object will be longer than limit, and constructed
874c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom     * objects such as sequences will be parsed lazily.
884c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom     *
894c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom     * @param input stream containing ASN.1 encoded data.
90c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * @param limit maximum size of a DER encoded object.
91c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
92c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     */
93c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public ASN1InputStream(
94c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        InputStream input,
95c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int         limit,
96c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        boolean     lazyEvaluate)
97c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
98b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        super(input);
99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.limit = limit;
100c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.lazyEvaluate = lazyEvaluate;
1014c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        this.tmpBuffers = new byte[11][];
1024c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    }
1034c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
1044c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    int getLimit()
1054c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    {
1064c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return limit;
107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
108c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected int readLength()
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
112c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return readLength(this, limit);
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected void readFully(
116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]  bytes)
117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
119c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (Streams.readFully(this, bytes) != bytes.length)
120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new EOFException("EOF encountered in middle of object");
122b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
123b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
124b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
126c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * build an object given its tag and the number of bytes to construct it from.
127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
1284c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    protected ASN1Primitive buildObject(
129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int       tag,
130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int       tagNo,
131c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int       length)
132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
134c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        boolean isConstructed = (tag & CONSTRUCTED) != 0;
135c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
136c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length);
137c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if ((tag & APPLICATION) != 0)
139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
140c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
143c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if ((tag & TAGGED) != 0)
144c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
1456e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo);
146c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
148c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (isConstructed)
149c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
150c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // TODO There are other tags that may be constructed (e.g. BIT_STRING)
151c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            switch (tagNo)
152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
153c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                case OCTET_STRING:
154c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    //
155c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    // yes, people actually do this...
156c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    //
1574c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    ASN1EncodableVector v = buildDEREncodableVector(defIn);
1584c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    ASN1OctetString[] strings = new ASN1OctetString[v.size()];
1594c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
1604c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    for (int i = 0; i != strings.length; i++)
1614c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    {
1624c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                        strings[i] = (ASN1OctetString)v.get(i);
1634c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    }
1644c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
1654c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    return new BEROctetString(strings);
166c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                case SEQUENCE:
167c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    if (lazyEvaluate)
168b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    {
1694c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                        return new LazyEncodedSequence(defIn.toByteArray());
170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    }
171b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    else
172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    {
173c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                        return DERFactory.createSequence(buildDEREncodableVector(defIn));
174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    }
175c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                case SET:
1764c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    return DERFactory.createSet(buildDEREncodableVector(defIn));
177c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                case EXTERNAL:
178c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    return new DERExternal(buildDEREncodableVector(defIn));
179c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                default:
1804c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    throw new IOException("unknown tag " + tagNo + " encountered");
181b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
182b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
183b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1844c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
185b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
186b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
187c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    ASN1EncodableVector buildEncodableVector()
188b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
189b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
190c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        ASN1EncodableVector v = new ASN1EncodableVector();
1914c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        ASN1Primitive o;
192b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
193c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        while ((o = readObject()) != null)
194b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
195c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            v.add(o);
196b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
197b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
198c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return v;
199b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
200c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
201c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    ASN1EncodableVector buildDEREncodableVector(
202c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        DefiniteLengthInputStream dIn) throws IOException
203b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
204c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return new ASN1InputStream(dIn).buildEncodableVector();
205b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
206b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
2074c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    public ASN1Primitive readObject()
208b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
209b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
210b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int tag = read();
211c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (tag <= 0)
212b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
213c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (tag == 0)
214b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
215c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new IOException("unexpected end-of-contents marker");
216b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
217b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
218b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return null;
219b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
220b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
221c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        //
222c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // calculate tag number
223c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        //
224c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int tagNo = readTagNumber(this, tag);
225b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
226c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        boolean isConstructed = (tag & CONSTRUCTED) != 0;
227b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
228c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        //
229c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // calculate length
230c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        //
231c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int length = readLength();
232b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
233c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (length < 0) // indefinite length method
234c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
235c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (!isConstructed)
236c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
237c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new IOException("indefinite length primitive encoding encountered");
238c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
239b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
2406e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit);
2416e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            ASN1StreamParser sp = new ASN1StreamParser(indIn, limit);
242b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
243c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if ((tag & APPLICATION) != 0)
244c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
2456e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject();
246c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
2476e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom
248c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if ((tag & TAGGED) != 0)
249c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
2506e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject();
251c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
252b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
253c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // TODO There are other tags that may be constructed (e.g. BIT_STRING)
254c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            switch (tagNo)
255c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
256c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                case OCTET_STRING:
2576e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                    return new BEROctetStringParser(sp).getLoadedObject();
258c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                case SEQUENCE:
2596e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                    return new BERSequenceParser(sp).getLoadedObject();
260c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                case SET:
2616e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                    return new BERSetParser(sp).getLoadedObject();
262c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                case EXTERNAL:
2636e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                    return new DERExternalParser(sp).getLoadedObject();
264c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                default:
265c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    throw new IOException("unknown BER object encountered");
266b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
267b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
268b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else
269b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
2706e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            try
2716e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            {
2726e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                return buildObject(tag, tagNo, length);
2736e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            }
2746e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            catch (IllegalArgumentException e)
2756e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            {
2766e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                throw new ASN1Exception("corrupted stream detected", e);
2776e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            }
278b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
279b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
280b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
281c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    static int readTagNumber(InputStream s, int tag)
282b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
283b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
284b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int tagNo = tag & 0x1f;
285b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
286c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        //
287c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // with tagged object tag number is bottom 5 bits, or stored at the start of the content
288c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        //
289b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (tagNo == 0x1f)
290b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
291b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            tagNo = 0;
292b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
293c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            int b = s.read();
294c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
295c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // X.690-0207 8.1.2.4.2
296c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
297c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if ((b & 0x7f) == 0) // Note: -1 will pass
298c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
299c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new IOException("corrupted stream - invalid high tag number found");
300c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
301c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
302b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            while ((b >= 0) && ((b & 0x80) != 0))
303b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
304b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                tagNo |= (b & 0x7f);
305b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                tagNo <<= 7;
306c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                b = s.read();
307b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
308b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
309b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (b < 0)
310b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
311b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                throw new EOFException("EOF found inside tag value.");
312b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
313b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
314b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            tagNo |= (b & 0x7f);
315b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
316b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
317b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return tagNo;
318b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
319b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
320c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    static int readLength(InputStream s, int limit)
321c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        throws IOException
322c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
323c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int length = s.read();
324c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (length < 0)
325c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
326c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new EOFException("EOF found when length expected");
327c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
328c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
329c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (length == 0x80)
330c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
331c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            return -1;      // indefinite-length encoding
332c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
333c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
334c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (length > 127)
335c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
336c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            int size = length & 0x7f;
337c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
3386e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
339c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (size > 4)
340c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
341c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new IOException("DER length more than 4 bytes: " + size);
342c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
343c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
344c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            length = 0;
345c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            for (int i = 0; i < size; i++)
346c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
347c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                int next = s.read();
348c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
349c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                if (next < 0)
350c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                {
351c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    throw new EOFException("EOF found reading length");
352c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                }
353c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
354c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                length = (length << 8) + next;
355c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
356c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
357c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (length < 0)
358c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
359c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new IOException("corrupted stream - negative length found");
360c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
361c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
362c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (length >= limit)   // after all we must have read at least 1 byte
363c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
364c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new IOException("corrupted stream - out of bounds length found");
365c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
366c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
367c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
368c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return length;
369c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
370c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
3714c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
3724c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        throws IOException
3734c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    {
3744c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        int len = defIn.getRemaining();
3754c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        if (defIn.getRemaining() < tmpBuffers.length)
3764c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        {
3774c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            byte[] buf = tmpBuffers[len];
3784c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
3794c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            if (buf == null)
3804c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            {
3814c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                buf = tmpBuffers[len] = new byte[len];
3824c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            }
3834c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
3844c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            Streams.readFully(defIn, buf);
3854c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
3864c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            return buf;
3874c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        }
3884c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        else
3894c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        {
3904c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            return defIn.toByteArray();
3914c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        }
3924c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    }
3934c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
3944c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn)
3954c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        throws IOException
3964c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    {
3974c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        int len = defIn.getRemaining() / 2;
3984c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        char[] buf = new char[len];
3994c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        int totalRead = 0;
4004c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        while (totalRead < len)
4014c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        {
4024c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            int ch1 = defIn.read();
4034c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            if (ch1 < 0)
4044c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            {
4054c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                break;
4064c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            }
4074c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            int ch2 = defIn.read();
4084c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            if (ch2 < 0)
4094c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            {
4104c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                break;
4114c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            }
4124c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff));
4134c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        }
4144c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
4154c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return buf;
4164c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    }
4174c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
4184c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    static ASN1Primitive createPrimitiveDERObject(
419c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int     tagNo,
4204c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        DefiniteLengthInputStream defIn,
4214c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        byte[][] tmpBuffers)
4224c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        throws IOException
423c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
424c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        switch (tagNo)
425c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
426c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case BIT_STRING:
4274c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return DERBitString.fromInputStream(defIn.getRemaining(), defIn);
428c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case BMP_STRING:
4294c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DERBMPString(getBMPCharBuffer(defIn));
430c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case BOOLEAN:
4314c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers));
432c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case ENUMERATED:
4334c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers));
434c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case GENERALIZED_TIME:
4354c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new ASN1GeneralizedTime(defIn.toByteArray());
436c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case GENERAL_STRING:
4374c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DERGeneralString(defIn.toByteArray());
438c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case IA5_STRING:
4394c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DERIA5String(defIn.toByteArray());
440c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case INTEGER:
4414c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new ASN1Integer(defIn.toByteArray());
442c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case NULL:
443c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                return DERNull.INSTANCE;   // actual content is ignored (enforce 0 length?)
444c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case NUMERIC_STRING:
4454c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DERNumericString(defIn.toByteArray());
446c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case OBJECT_IDENTIFIER:
4474c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers));
448c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case OCTET_STRING:
4494c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DEROctetString(defIn.toByteArray());
450c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case PRINTABLE_STRING:
4514c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DERPrintableString(defIn.toByteArray());
452c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case T61_STRING:
4534c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DERT61String(defIn.toByteArray());
454c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case UNIVERSAL_STRING:
4554c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DERUniversalString(defIn.toByteArray());
456c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case UTC_TIME:
4574c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new ASN1UTCTime(defIn.toByteArray());
458c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case UTF8_STRING:
4594c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DERUTF8String(defIn.toByteArray());
460c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            case VISIBLE_STRING:
4614c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return new DERVisibleString(defIn.toByteArray());
462c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            default:
4634c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                throw new IOException("unknown tag " + tagNo + " encountered");
464c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
465c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
466c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom}
467