1 package org.bouncycastle.asn1;
2 
3 import java.io.IOException;
4 import java.util.Enumeration;
5 import java.util.Vector;
6 
7 /**
8  * ASN.1 <code>SEQUENCE</code> and <code>SEQUENCE OF</code> constructs.
9  * <p>
10  * DER form is always definite form length fields, while
11  * BER support uses indefinite form.
12  * <hr>
13  * <p><b>X.690</b></p>
14  * <p><b>8: Basic encoding rules</b></p>
15  * <p><b>8.9 Encoding of a sequence value </b></p>
16  * 8.9.1 The encoding of a sequence value shall be constructed.
17  * <p>
18  * <b>8.9.2</b> The contents octets shall consist of the complete
19  * encoding of one data value from each of the types listed in
20  * the ASN.1 definition of the sequence type, in the order of
21  * their appearance in the definition, unless the type was referenced
22  * with the keyword <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
23  * </p><p>
24  * <b>8.9.3</b> The encoding of a data value may, but need not,
25  * be present for a type which was referenced with the keyword
26  * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
27  * If present, it shall appear in the encoding at the point
28  * corresponding to the appearance of the type in the ASN.1 definition.
29  * </p><p>
30  * <b>8.10 Encoding of a sequence-of value </b>
31  * </p><p>
32  * <b>8.10.1</b> The encoding of a sequence-of value shall be constructed.
33  * <p>
34  * <b>8.10.2</b> The contents octets shall consist of zero,
35  * one or more complete encodings of data values from the type listed in
36  * the ASN.1 definition.
37  * <p>
38  * <b>8.10.3</b> The order of the encodings of the data values shall be
39  * the same as the order of the data values in the sequence-of value to
40  * be encoded.
41  * </p>
42  * <p><b>9: Canonical encoding rules</b></p>
43  * <p><b>9.1 Length forms</b></p>
44  * If the encoding is constructed, it shall employ the indefinite length form.
45  * If the encoding is primitive, it shall include the fewest length octets necessary.
46  * [Contrast with 8.1.3.2 b).]
47  *
48  * <p><b>11: Restrictions on BER employed by both CER and DER</b></p>
49  * <p><b>11.5 Set and sequence components with default value</b></p>
50  * The encoding of a set value or sequence value shall not include
51  * an encoding for any component value which is equal to
52  * its default value.
53  */
54 public abstract class ASN1Sequence
55     extends ASN1Primitive
56 {
57     protected Vector seq = new Vector();
58 
59     /**
60      * Return an ASN1Sequence from the given object.
61      *
62      * @param obj the object we want converted.
63      * @exception IllegalArgumentException if the object cannot be converted.
64      * @return an ASN1Sequence instance, or null.
65      */
getInstance( Object obj)66     public static ASN1Sequence getInstance(
67         Object  obj)
68     {
69         if (obj == null || obj instanceof ASN1Sequence)
70         {
71             return (ASN1Sequence)obj;
72         }
73         else if (obj instanceof ASN1SequenceParser)
74         {
75             return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive());
76         }
77         else if (obj instanceof byte[])
78         {
79             try
80             {
81                 return ASN1Sequence.getInstance(fromByteArray((byte[])obj));
82             }
83             catch (IOException e)
84             {
85                 throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
86             }
87         }
88         else if (obj instanceof ASN1Encodable)
89         {
90             ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
91 
92             if (primitive instanceof ASN1Sequence)
93             {
94                 return (ASN1Sequence)primitive;
95             }
96         }
97 
98         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
99     }
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      */
getInstance( ASN1TaggedObject obj, boolean explicit)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      */
ASN1Sequence()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      */
ASN1Sequence( ASN1Encodable obj)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      */
ASN1Sequence( ASN1EncodableVector v)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      */
ASN1Sequence( ASN1Encodable[] array)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 
toArray()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 
getObjects()215     public Enumeration getObjects()
216     {
217         return seq.elements();
218     }
219 
parser()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      */
getObjectAt( int index)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      */
size()279     public int size()
280     {
281         return seq.size();
282     }
283 
hashCode()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 
asn1Equals( ASN1Primitive o)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 
getNext(Enumeration e)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      */
toDERObject()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      */
toDLObject()361     ASN1Primitive toDLObject()
362     {
363         ASN1Sequence dlSeq = new DLSequence();
364 
365         dlSeq.seq = this.seq;
366 
367         return dlSeq;
368     }
369 
isConstructed()370     boolean isConstructed()
371     {
372         return true;
373     }
374 
encode(ASN1OutputStream out)375     abstract void encode(ASN1OutputStream out)
376         throws IOException;
377 
toString()378     public String toString()
379     {
380         return seq.toString();
381     }
382 }
383