BerInputStream.java revision f33eae7e84eb6d3b0f4e86b59605bb3de73009f3
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @author Vladimir N. Molotkov, Stepan M. Mishura
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @version $Revision$
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*/
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.security.asn1;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.security.internal.nls.Messages;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 types encoded with BER (X.690)
34f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class BerInputStream {
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Associated <code>InputStream</code>
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected InputStream in;
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
46f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Internal buffer for storing encoded array
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected byte[] buffer;
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The position in the buffer.
52f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Next read must place data into the buffer from this offset
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int offset = 0;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // The buffer increment size.
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Must be reasonable big to reallocate memory not to often.
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Primary is used for decoding indefinite length encoding
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int BUF_INCREASE_SIZE = 1024 * 16;
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
63f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Indicates indefinite length of the current type
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected static final int INDEFINIT_LENGTH = -1;
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates stream for decoding.
69f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param encoded - bytes array to be decoded
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if an error occurs
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BerInputStream(byte[] encoded) throws IOException {
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(encoded, 0, encoded.length);
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates stream for decoding.
79f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param encoded -
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            bytes array to be decoded
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param offset -
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the encoding offset
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param expectedLength -
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            expected length of full encoding, this includes identifier,
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            length an content octets
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException -
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BerInputStream(byte[] encoded, int offset, int expectedLength)
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.buffer = encoded;
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.offset = offset;
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        next();
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // compare expected and decoded length
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length != INDEFINIT_LENGTH
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                && (offset + expectedLength) != (this.offset + this.length)) {
101f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.111"));
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates stream for decoding.
107f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Allocates initial buffer of default size
109f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param is associated <code>InputStream</code>
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BerInputStream(InputStream in) throws IOException {
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(in, BUF_INCREASE_SIZE);
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates stream for decoding.
118f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
119f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Allocates initial buffer of <code>initialSize</code> size
120f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param initialSize the internal buffer initial size
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param is associated <code>InputStream</code>
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BerInputStream(InputStream in, int initialSize) throws IOException {
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.in = in;
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buffer = new byte[initialSize];
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        next();
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length != INDEFINIT_LENGTH) {
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // input stream has definite length encoding
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check allocated length to avoid further reallocations
1342f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes            if (buffer.length < (length + offset)) {
1352f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                byte[] newBuffer = new byte[length + offset];
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                System.arraycopy(buffer, 0, newBuffer, 0, offset);
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer = newBuffer;
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            isIndefinedLength = true;
141f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.112"));
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Resets this stream to initial state.
147f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param encoded - a new bytes array to be decoded
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if an error occurs
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final void reset(byte[] encoded) throws IOException {
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buffer = encoded;
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        next();
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Current decoded tag
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int tag;
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Current decoded length
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int length;
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Current decoded content
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Object content;
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Current decoded tag offset
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int tagOffset;
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Current decoded content offset
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int contentOffset;
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes next encoded type.
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Initializes tag, length, tagOffset and contentOffset variables
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return next decoded tag
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int next() throws IOException {
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        tagOffset = offset;
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // read tag
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        tag = read();
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // read length
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        length = read();
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length != 0x80) { // definite form
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // long or short length form
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ((length & 0x80) != 0) { // long form
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int numOctets = length & 0x7F;
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (numOctets > 5) {
204f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    throw new ASN1Exception(Messages.getString("security.113",
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            tagOffset)); //FIXME message
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // collect this value length
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                length = read();
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                for (int i = 1; i < numOctets; i++) {
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    int ch = read();
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    length = (length << 8) + ch;//read();
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (length > 0xFFFFFF) {
216f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    throw new ASN1Exception(Messages.getString("security.113",
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            tagOffset)); //FIXME message
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else { //indefinite form
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            length = INDEFINIT_LENGTH;
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        contentOffset = offset;
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return tag;
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the length of the encoding
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static int getLength(byte[] encoding) {
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = encoding[1] & 0xFF;
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int numOctets = 0;
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if ((length & 0x80) != 0) { // long form
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            numOctets = length & 0x7F;
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // collect this value length
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            length = encoding[2] & 0xFF;
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 3; i < numOctets + 2; i++) {
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                length = (length << 8) + (encoding[i] & 0xFF);
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        //    tag length long_form content
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return 1 + 1 + numOctets + length;
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 bitstring type
249f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readBitString() throws IOException {
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == ASN1Constants.TAG_BITSTRING) {
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length == 0) {
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new ASN1Exception(
258f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                        Messages.getString("security.114", tagOffset));
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // content: check unused bits
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (buffer[contentOffset] > 7) {
265f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.115",
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        contentOffset));
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length == 1 && buffer[contentOffset] != 0) {
270f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.116",
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        contentOffset));
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == ASN1Constants.TAG_C_BITSTRING) {
275f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.117"));
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ASN1Exception(
278f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    Messages.getString("security.118", tagOffset,
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Integer.toHexString(tag)));
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Enumerated type
285f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readEnumerated() throws IOException {
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_ENUM) {
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ASN1Exception(
292f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    Messages.getString("security.119", tagOffset,
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Integer.toHexString(tag)));
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        //
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // all checks are the same as for ASN.1 integer type
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        //
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded length
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length == 0) {
302fd6bb3510c2f94d636f3572dcf5f7f4dcd1a2726Elliott Hughes            throw new ASN1Exception(Messages.getString("security.11A", tagOffset));
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readContent();
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded content
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length > 1) {
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int bits = buffer[contentOffset] & 0xFF;
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (buffer[contentOffset + 1] < 0) {
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                bits += 0x100;
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (bits == 0 || bits == 0x1FF) {
316f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.11B", contentOffset));
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 boolean type
323f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readBoolean() throws IOException {
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_BOOLEAN) {
329f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.11C",
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    tagOffset, Integer.toHexString(tag)));
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded length
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length != 1) {
335fd6bb3510c2f94d636f3572dcf5f7f4dcd1a2726Elliott Hughes            throw new ASN1Exception(Messages.getString("security.11D", tagOffset));
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readContent();
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The last choice index
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int choiceIndex;
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Keeps last decoded: year, month, day, hour, minute, second, millisecond
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int[] times;
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 GeneralizedTime type
353f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readGeneralizedTime() throws IOException {
357f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == ASN1Constants.TAG_GENERALIZEDTIME) {
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME: any other optimizations?
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME store string somewhere to allow a custom time type perform
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // additional checks
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check syntax: the last char MUST be Z
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (buffer[offset - 1] != 'Z') {
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // FIXME support only format that is acceptable for DER
368f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.11E"));
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check syntax: MUST be YYYYMMDDHHMMSS[(./,)DDD]'Z'
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length != 15 && (length < 17 || length > 19)) // invalid
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                                                // length
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            {
375f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.11F",
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                contentOffset));
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check content: milliseconds
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length > 16) {
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                byte char14 = buffer[contentOffset + 14];
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (char14 != '.' && char14 != ',') {
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    throw new ASN1Exception(
384f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                            Messages.getString("security.11F",
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    contentOffset));
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (times == null) {
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times = new int[7];
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[0] = strToInt(contentOffset, 4); // year
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[1] = strToInt(contentOffset + 4, 2); // month
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[2] = strToInt(contentOffset + 6, 2); // day
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[3] = strToInt(contentOffset + 8, 2); // hour
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[4] = strToInt(contentOffset + 10, 2); // minute
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[5] = strToInt(contentOffset + 12, 2); // second
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length > 16) {
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // FIXME optimize me
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times[6] = strToInt(contentOffset + 15, length - 16);
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (length == 17) {
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    times[6] = times[6] * 100;
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else if (length == 18) {
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    times[6] = times[6] * 10;
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME check all values for valid numbers!!!
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == ASN1Constants.TAG_C_GENERALIZEDTIME) {
412f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.120"));
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
415f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.121",
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            tagOffset, Integer.toHexString(tag)));
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 UTCTime type
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if an I/O error occurs or the end of the stream is reached
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readUTCTime() throws IOException {
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == ASN1Constants.TAG_UTCTIME) {
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            switch (length) {
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ASN1UTCTime.UTC_HM:
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ASN1UTCTime.UTC_HMS:
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ASN1UTCTime.UTC_LOCAL_HM:
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case ASN1UTCTime.UTC_LOCAL_HMS:
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // FIXME only coordinated universal time formats are supported
436f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.122"));
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            default:
438f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.123",
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                tagOffset));
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME: any other optimizations?
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME store string somewhere to allow a custom time type perform
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // additional checks
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check syntax: the last char MUST be Z
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (buffer[offset - 1] != 'Z') {
450f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception("ASN.1 UTCTime wrongly encoded at ["
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        + contentOffset + ']');
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (times == null) {
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times = new int[7];
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[0] = strToInt(contentOffset, 2); // year
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (times[0] > 49) {
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times[0] += 1900;
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times[0] += 2000;
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[1] = strToInt(contentOffset + 2, 2); // month
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[2] = strToInt(contentOffset + 4, 2); // day
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[3] = strToInt(contentOffset + 6, 2); // hour
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            times[4] = strToInt(contentOffset + 8, 2); // minute
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (length == ASN1UTCTime.UTC_HMS) {
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                times[5] = strToInt(contentOffset + 10, 2); // second
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // FIXME check all time values for valid numbers!!!
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == ASN1Constants.TAG_C_UTCTIME) {
476f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.124"));
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
478f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.125",
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    tagOffset, Integer.toHexString(tag)));
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //TODO comment me
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int strToInt(int off, int count) throws ASN1Exception {
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        //FIXME works only with buffer
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int c;
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int result = 0;
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = off, end = off + count; i < end; i++) {
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            c = buffer[i] - 48;
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (c < 0 || c > 9) {
493f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.126"));
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = result * 10 + c;
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Integer type
502f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readInteger() throws IOException {
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_INTEGER) {
508f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.127",
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    tagOffset, Integer.toHexString(tag)));
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded length
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length < 1) {
514f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.128",
515f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    tagOffset));
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readContent();
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded content
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length > 1) {
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte firstByte = buffer[offset - length];
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte secondByte = (byte) (buffer[offset - length + 1] & 0x80);
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (firstByte == 0 && secondByte == 0 || firstByte == (byte) 0xFF
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    && secondByte == (byte) 0x80) {
528f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.129",
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                (offset - length)));
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Octetstring type
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readOctetString() throws IOException {
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == ASN1Constants.TAG_OCTETSTRING) {
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == ASN1Constants.TAG_C_OCTETSTRING) {
544f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.12A"));
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ASN1Exception(
547f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    Messages.getString("security.12B", tagOffset,
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Integer.toHexString(tag)));
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //FIXME comment me
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int oidElement;
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 ObjectIdentifier type
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readOID() throws IOException {
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_OID) {
563f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.12C",
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    tagOffset, Integer.toHexString(tag)));
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check encoded length
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length < 1) {
569f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.12D", tagOffset));
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readContent();
573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check content: last encoded byte (8th bit MUST be zero)
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if ((buffer[offset - 1] & 0x80) != 0) {
576f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.12E", (offset - 1)));
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        oidElement = 1;
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = 0; i < length; i++, ++oidElement) {
581f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // According to ASN.1 BER spec:
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //    leading octet of subidentifier MUST not be 0x80
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // This assertion is not verified
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //if (buffer[contentOffset + i] == (byte)0x80) {
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //    throw new ASN1Exception(
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //            "Wrong content for ASN.1 object identifier at ["
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //                    + contentOffset
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //                    + "]. Subidentifier MUST be encoded in minimum number of octets");
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            //}
592f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while ((buffer[contentOffset + i] & 0x80) == 0x80) {
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                i++;
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Sequence type
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param sequence - ASN.1 sequence to be decoded
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readSequence(ASN1Sequence sequence) throws IOException {
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_C_SEQUENCE) {
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ASN1Exception(
609f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    Messages.getString("security.12F", tagOffset,
610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Integer.toHexString(tag)));
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int begOffset = offset;
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int endOffset = begOffset + length;
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ASN1Type[] type = sequence.type;
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int i = 0;
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (isVerify) {
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (; (offset < endOffset) && (i < type.length); i++) {
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                next();
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                while (!type[i].checkTag(tag)) {
626f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    // check whether it is optional component or not
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (!sequence.OPTIONAL[i] || (i == type.length - 1)) {
628f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                        throw new ASN1Exception(Messages.getString("security.130",
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                        tagOffset));
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    i++;
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                type[i].decode(this);
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check the rest of components
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (; i < type.length; i++) {
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (!sequence.OPTIONAL[i]) {
640f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    throw new ASN1Exception(Messages.getString("security.131",
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            tagOffset));
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int seqTagOffset = tagOffset; //store tag offset
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Object[] values = new Object[type.length];
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (; (offset < endOffset) && (i < type.length); i++) {
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                next();
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                while (!type[i].checkTag(tag)) {
654f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    // check whether it is optional component or not
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (!sequence.OPTIONAL[i] || (i == type.length - 1)) {
656f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                        throw new ASN1Exception(Messages.getString("security.132",
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                        tagOffset));
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // sets default value
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (sequence.DEFAULT[i] != null) {
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        values[i] = sequence.DEFAULT[i];
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    i++;
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                values[i] = type[i].decode(this);
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // check the rest of components
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (; i < type.length; i++) {
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (!sequence.OPTIONAL[i]) {
672f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    throw new ASN1Exception(Messages.getString("security.133",
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            tagOffset));
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (sequence.DEFAULT[i] != null) {
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    values[i] = sequence.DEFAULT[i];
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            content = values;
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            tagOffset = seqTagOffset; //retrieve tag offset
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset != endOffset) {
685f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.134", begOffset));
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 SequenceOf type
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param sequenceOf - ASN.1 sequence to be decoded
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readSequenceOf(ASN1SequenceOf sequenceOf) throws IOException {
696f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_C_SEQUENCEOF) {
698f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.135", tagOffset,
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Integer.toHexString(tag)));
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        decodeValueCollection(sequenceOf);
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 Set type
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param set - ASN.1 set to be decoded
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readSet(ASN1Set set) throws IOException {
712f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_C_SET) {
714f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.136",
715adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    tagOffset, Integer.toHexString(tag)));
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
718f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        throw new ASN1Exception(Messages.getString("security.137"));
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 SetOf type
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param set - ASN.1 set to be decoded
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readSetOf(ASN1SetOf setOf) throws IOException {
728f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag != ASN1Constants.TAG_C_SETOF) {
730f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.138",
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    tagOffset, Integer.toHexString(tag)));
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        decodeValueCollection(setOf);
735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final void decodeValueCollection(ASN1ValueCollection collection)
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int begOffset = offset;
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int endOffset = begOffset + length;
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ASN1Type type = collection.type;
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (isVerify) {
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (endOffset > offset) {
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                next();
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                type.decode(this);
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int seqTagOffset = tagOffset; //store tag offset
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ArrayList values = new ArrayList();
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (endOffset > offset) {
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                next();
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                values.add(type.decode(this));
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            content = values;
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            tagOffset = seqTagOffset; //retrieve tag offset
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset != endOffset) {
766f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.134", begOffset));
767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
768adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
770adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes ASN.1 String type
772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if an I/O error occurs or the end of the stream is reached
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
775adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readString(ASN1StringType type) throws IOException {
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        //FIXME check string content
778adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tag == type.id) {
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            readContent();
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (tag == type.constrId) {
781f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.139"));
782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ASN1Exception(
784f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    Messages.getString("security.13A", tagOffset,
785adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Integer.toHexString(tag)));
786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
789adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns encoded array.
791f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
792f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * MUST be invoked after decoding corresponding ASN.1 notation
793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public byte[] getEncoded() {
795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] encoded = new byte[offset - tagOffset];
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        System.arraycopy(buffer, tagOffset, encoded, 0, encoded.length);
797adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return encoded;
798adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
800adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns internal buffer used for decoding
802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return - buffer
804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
805adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final byte[] getBuffer() {
806adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return buffer;
807adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
808adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
809adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
810adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns length of the current content for decoding
811adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
812adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return - length of content
813adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
814adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getLength() {
815adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return length;
816adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
817adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
818adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
819adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the current offset
820adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
821adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return - offset
822adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
823adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getOffset() {
824adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return offset;
825adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
826adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
827adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
828adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns end offset for the current encoded type
829adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
830adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return - offset
831adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
832adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getEndOffset() {
833adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return offset + length;
834adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
835adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
836adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
837adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns start offset for the current encoded type
838adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
839adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return - offset
840adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
841adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getTagOffset() {
842adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return tagOffset;
843adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
844adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
845adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int getContentOffset() {
846adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return contentOffset;
847adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
848adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
849adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
850adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates verify or store mode.
851f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
852adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * In store mode a decoded content is stored in a newly allocated
853adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * appropriate object. The <code>content</code> variable holds
854adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * a reference to the last created object.
855f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
856adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * In verify mode a decoded content is not stored.
857adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
858adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // FIXME it is used only for one case
859adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // decoding PCKS#8 Private Key Info notation
860adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // remove this option because it does decoding more complex
861adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean isVerify;
862adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
863adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
864adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets verify mode.
865adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
866adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final void setVerify() {
867adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        isVerify = true;
868adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
869adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
870adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
871adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates defined or indefined reading mode for associated InputStream.
872f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
873adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This mode is defined by reading a length
874adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for a first ASN.1 type from InputStream.
875adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
876adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean isIndefinedLength;
877adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
878adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
879adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reads the next encoded byte from the encoded input stream.
880adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
881adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the next encoded byte
882adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
883adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
884adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int read() throws IOException {
885adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
886adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset == buffer.length) {
887f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.13B"));
888adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
889adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
890adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (in == null) {
891adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return buffer[offset++] & 0xFF;
892adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
893adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int octet = in.read();
894adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (octet == -1) {
895f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                throw new ASN1Exception(Messages.getString("security.13B"));
896adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
897f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
898adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer[offset++] = (byte) octet;
899f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
900adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return octet;
901adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
902adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
903adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
904adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
905adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reads the next encoded content from the encoded input stream.
906adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The method MUST be used for reading a primitive encoded content.
907adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
908adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException - if error occured
909adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
910adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readContent() throws IOException {
911adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset + length > buffer.length) {
912f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            throw new ASN1Exception(Messages.getString("security.13B"));
913adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
914adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
915adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (in == null) {
916adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            offset += length;
917adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
9182f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes            int bytesRead = in.read(buffer, offset, length);
9192f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes
9202f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes            if (bytesRead != length) {
9212f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                // if input stream didn't return all data at once
9222f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                // try to read it in several blocks
9232f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                int c = bytesRead;
9242f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                do {
9252f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                    if (c < 1 || bytesRead > length) {
9262f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                        throw new ASN1Exception(Messages
927f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                                .getString("security.13C"));
9282f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                    }
9292f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                    c = in.read(buffer, offset + bytesRead, length - bytesRead);
9302f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                    bytesRead += c;
9312f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes                } while (bytesRead != length);
932adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
9332f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes
934adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            offset += length;
935adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
936adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
937adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
938adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //    // reallocates internal buffer for indefined reading mode
939adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //    private void reallocateBuffer(int n) {
940adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //        int newSize;
941adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //        for (newSize = buffer.length * 2; newSize < buffer.length + n; newSize = newSize * 2)
942adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //            ;
943adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //        byte[] newBuffer = new byte[newSize];
944adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //        System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
945adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //        buffer = newBuffer;
946adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //    }
947adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
948adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
949adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reallocates the buffer in order to make it
950adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * exactly the size of data it contains
951adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
952adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void compactBuffer() {
953adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (offset != buffer.length) {
954adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] newBuffer = new byte[offset];
955adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // restore buffer content
956adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.arraycopy(buffer, 0, newBuffer, 0, offset);
957adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // set new buffer
958adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer = newBuffer;
959adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
960adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
961adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
962adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //
963adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //
964adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //
965adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //
966adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    //
967adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
968adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Object[][] pool;
969adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
970adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void put(Object key, Object entry) {
971adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
972adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (pool == null) {
973adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pool = new Object[2][10];
974adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
975adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
976adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int i = 0;
977adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (; i < pool[0].length && pool[0][i] != null; i++) {
978adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (pool[0][i] == key) {
979adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                pool[1][i] = entry;
980adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
981adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
982adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
983adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
984adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (i == pool[0].length) {
985adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Object[][] newPool = new Object[pool[0].length * 2][2];
986adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.arraycopy(pool[0], 0, newPool[0], 0, pool[0].length);
987adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.arraycopy(pool[1], 0, newPool[1], 0, pool[0].length);
988adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pool = newPool;
989adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
990adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pool[0][i] = key;
991adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            pool[1][i] = entry;
992adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
993adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
994adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
995adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Object get(Object key) {
996adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
997adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (pool == null) {
998adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
999adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1000adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1001adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = 0; i < pool[0].length; i++) {
1002adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (pool[0][i] == key) {
1003adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return pool[1][i];
1004adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1005adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1006adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
1007adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1008adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
1009