001package org.apache.commons.ssl.org.bouncycastle.asn1;
002
003import java.io.IOException;
004import java.util.Enumeration;
005import java.util.Vector;
006
007/**
008 * ASN.1 <code>SEQUENCE</code> and <code>SEQUENCE OF</code> constructs.
009 * <p>
010 * DER form is always definite form length fields, while
011 * BER support uses indefinite form.
012 * <hr>
013 * <p><b>X.690</b></p>
014 * <p><b>8: Basic encoding rules</b></p>
015 * <p><b>8.9 Encoding of a sequence value </b></p>
016 * 8.9.1 The encoding of a sequence value shall be constructed.
017 * <p>
018 * <b>8.9.2</b> The contents octets shall consist of the complete
019 * encoding of one data value from each of the types listed in
020 * the ASN.1 definition of the sequence type, in the order of
021 * their appearance in the definition, unless the type was referenced
022 * with the keyword <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
023 * </p><p>
024 * <b>8.9.3</b> The encoding of a data value may, but need not,
025 * be present for a type which was referenced with the keyword
026 * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
027 * If present, it shall appear in the encoding at the point
028 * corresponding to the appearance of the type in the ASN.1 definition.
029 * </p><p>
030 * <b>8.10 Encoding of a sequence-of value </b>
031 * </p><p>
032 * <b>8.10.1</b> The encoding of a sequence-of value shall be constructed.
033 * <p>
034 * <b>8.10.2</b> The contents octets shall consist of zero,
035 * one or more complete encodings of data values from the type listed in
036 * the ASN.1 definition.
037 * <p>
038 * <b>8.10.3</b> The order of the encodings of the data values shall be
039 * the same as the order of the data values in the sequence-of value to
040 * be encoded.
041 * </p>
042 * <p><b>9: Canonical encoding rules</b></p>
043 * <p><b>9.1 Length forms</b></p>
044 * If the encoding is constructed, it shall employ the indefinite length form.
045 * If the encoding is primitive, it shall include the fewest length octets necessary.
046 * [Contrast with 8.1.3.2 b).]
047 *
048 * <p><b>11: Restrictions on BER employed by both CER and DER</b></p>
049 * <p><b>11.5 Set and sequence components with default value</b></p>
050 * The encoding of a set value or sequence value shall not include
051 * an encoding for any component value which is equal to
052 * its default value.
053 */
054public abstract class ASN1Sequence
055    extends ASN1Primitive
056{
057    protected Vector seq = new Vector();
058
059    /**
060     * Return an ASN1Sequence from the given object.
061     *
062     * @param obj the object we want converted.
063     * @exception IllegalArgumentException if the object cannot be converted.
064     * @return an ASN1Sequence instance, or null.
065     */
066    public static ASN1Sequence getInstance(
067        Object  obj)
068    {
069        if (obj == null || obj instanceof ASN1Sequence)
070        {
071            return (ASN1Sequence)obj;
072        }
073        else if (obj instanceof ASN1SequenceParser)
074        {
075            return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive());
076        }
077        else if (obj instanceof byte[])
078        {
079            try
080            {
081                return ASN1Sequence.getInstance(fromByteArray((byte[])obj));
082            }
083            catch (IOException e)
084            {
085                throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
086            }
087        }
088        else if (obj instanceof ASN1Encodable)
089        {
090            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
091
092            if (primitive instanceof ASN1Sequence)
093            {
094                return (ASN1Sequence)primitive;
095            }
096        }
097
098        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
099    }
100
101    /**
102     * Return an ASN1 sequence from a tagged object. There is a special
103     * case here, if an object appears to have been explicitly tagged on 
104     * reading but we were expecting it to be implicitly tagged in the 
105     * normal course of events it indicates that we lost the surrounding
106     * sequence - so we need to add it back (this will happen if the tagged
107     * object is a sequence that contains other sequences). If you are
108     * dealing with implicitly tagged sequences you really <b>should</b>
109     * be using this method.
110     *
111     * @param obj the tagged object.
112     * @param explicit true if the object is meant to be explicitly tagged,
113     *          false otherwise.
114     * @exception IllegalArgumentException if the tagged object cannot
115     *          be converted.
116     * @return an ASN1Sequence instance.
117     */
118    public static ASN1Sequence getInstance(
119        ASN1TaggedObject    obj,
120        boolean             explicit)
121    {
122        if (explicit)
123        {
124            if (!obj.isExplicit())
125            {
126                throw new IllegalArgumentException("object implicit - explicit expected.");
127            }
128
129            return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive());
130        }
131        else
132        {
133            //
134            // constructed object which appears to be explicitly tagged
135            // when it should be implicit means we have to add the
136            // surrounding sequence.
137            //
138            if (obj.isExplicit())
139            {
140                if (obj instanceof BERTaggedObject)
141                {
142                    return new BERSequence(obj.getObject());
143                }
144                else
145                {
146                    return new DLSequence(obj.getObject());
147                }
148            }
149            else
150            {
151                if (obj.getObject() instanceof ASN1Sequence)
152                {
153                    return (ASN1Sequence)obj.getObject();
154                }
155            }
156        }
157
158        throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
159    }
160
161    /**
162     * Create an empty sequence
163     */
164    protected ASN1Sequence()
165    {
166    }
167
168    /**
169     * Create a sequence containing one object
170     * @param obj the object to be put in the SEQUENCE.
171     */
172    protected ASN1Sequence(
173        ASN1Encodable obj)
174    {
175        seq.addElement(obj);
176    }
177
178    /**
179     * Create a sequence containing a vector of objects.
180     * @param v the vector of objects to be put in the SEQUENCE
181     */
182    protected ASN1Sequence(
183        ASN1EncodableVector v)
184    {
185        for (int i = 0; i != v.size(); i++)
186        {
187            seq.addElement(v.get(i));
188        }
189    }
190
191    /**
192     * Create a sequence containing a vector of objects.
193     */
194    protected ASN1Sequence(
195        ASN1Encodable[]   array)
196    {
197        for (int i = 0; i != array.length; i++)
198        {
199            seq.addElement(array[i]);
200        }
201    }
202
203    public ASN1Encodable[] toArray()
204    {
205        ASN1Encodable[] values = new ASN1Encodable[this.size()];
206
207        for (int i = 0; i != this.size(); i++)
208        {
209            values[i] = this.getObjectAt(i);
210        }
211
212        return values;
213    }
214
215    public Enumeration getObjects()
216    {
217        return seq.elements();
218    }
219
220    public ASN1SequenceParser parser()
221    {
222        final ASN1Sequence outer = this;
223
224        return new ASN1SequenceParser()
225        {
226            private final int max = size();
227
228            private int index;
229
230            public ASN1Encodable readObject() throws IOException
231            {
232                if (index == max)
233                {
234                    return null;
235                }
236                
237                ASN1Encodable obj = getObjectAt(index++);
238                if (obj instanceof ASN1Sequence)
239                {
240                    return ((ASN1Sequence)obj).parser();
241                }
242                if (obj instanceof ASN1Set)
243                {
244                    return ((ASN1Set)obj).parser();
245                }
246
247                return obj;
248            }
249
250            public ASN1Primitive getLoadedObject()
251            {
252                return outer;
253            }
254            
255            public ASN1Primitive toASN1Primitive()
256            {
257                return outer;
258            }
259        };
260    }
261
262    /**
263     * Return the object at the sequence position indicated by index.
264     *
265     * @param index the sequence number (starting at zero) of the object
266     * @return the object at the sequence position indicated by index.
267     */
268    public ASN1Encodable getObjectAt(
269        int index)
270    {
271        return (ASN1Encodable)seq.elementAt(index);
272    }
273
274    /**
275     * Return the number of objects in this sequence.
276     *
277     * @return the number of objects in this sequence.
278     */
279    public int size()
280    {
281        return seq.size();
282    }
283
284    public int hashCode()
285    {
286        Enumeration             e = this.getObjects();
287        int                     hashCode = size();
288
289        while (e.hasMoreElements())
290        {
291            Object o = getNext(e);
292            hashCode *= 17;
293
294            hashCode ^= o.hashCode();
295        }
296
297        return hashCode;
298    }
299
300    boolean asn1Equals(
301        ASN1Primitive o)
302    {
303        if (!(o instanceof ASN1Sequence))
304        {
305            return false;
306        }
307        
308        ASN1Sequence   other = (ASN1Sequence)o;
309
310        if (this.size() != other.size())
311        {
312            return false;
313        }
314
315        Enumeration s1 = this.getObjects();
316        Enumeration s2 = other.getObjects();
317
318        while (s1.hasMoreElements())
319        {
320            ASN1Encodable obj1 = getNext(s1);
321            ASN1Encodable obj2 = getNext(s2);
322
323            ASN1Primitive o1 = obj1.toASN1Primitive();
324            ASN1Primitive o2 = obj2.toASN1Primitive();
325
326            if (o1 == o2 || o1.equals(o2))
327            {
328                continue;
329            }
330
331            return false;
332        }
333
334        return true;
335    }
336
337    private ASN1Encodable getNext(Enumeration e)
338    {
339        ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
340
341        return encObj;
342    }
343
344    /**
345     * Change current SEQUENCE object to be encoded as {@link DERSequence}.
346     * This is part of Distinguished Encoding Rules form serialization.
347     */
348    ASN1Primitive toDERObject()
349    {
350        ASN1Sequence derSeq = new DERSequence();
351
352        derSeq.seq = this.seq;
353
354        return derSeq;
355    }
356
357    /**
358     * Change current SEQUENCE object to be encoded as {@link DLSequence}.
359     * This is part of Direct Length form serialization.
360     */
361    ASN1Primitive toDLObject()
362    {
363        ASN1Sequence dlSeq = new DLSequence();
364
365        dlSeq.seq = this.seq;
366
367        return dlSeq;
368    }
369
370    boolean isConstructed()
371    {
372        return true;
373    }
374
375    abstract void encode(ASN1OutputStream out)
376        throws IOException;
377
378    public String toString() 
379    {
380        return seq.toString();
381    }
382}