• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.asn1;
2 
3 import java.io.IOException;
4 import java.util.Enumeration;
5 import java.util.Iterator;
6 import java.util.Vector;
7 
8 import org.bouncycastle.util.Arrays;
9 
10 /**
11  * ASN.1 <code>SEQUENCE</code> and <code>SEQUENCE OF</code> constructs.
12  * <p>
13  * DER form is always definite form length fields, while
14  * BER support uses indefinite form.
15  * <hr>
16  * <p><b>X.690</b></p>
17  * <p><b>8: Basic encoding rules</b></p>
18  * <p><b>8.9 Encoding of a sequence value </b></p>
19  * 8.9.1 The encoding of a sequence value shall be constructed.
20  * <p>
21  * <b>8.9.2</b> The contents octets shall consist of the complete
22  * encoding of one data value from each of the types listed in
23  * the ASN.1 definition of the sequence type, in the order of
24  * their appearance in the definition, unless the type was referenced
25  * with the keyword <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
26  * </p><p>
27  * <b>8.9.3</b> The encoding of a data value may, but need not,
28  * be present for a type which was referenced with the keyword
29  * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
30  * If present, it shall appear in the encoding at the point
31  * corresponding to the appearance of the type in the ASN.1 definition.
32  * </p><p>
33  * <b>8.10 Encoding of a sequence-of value </b>
34  * </p><p>
35  * <b>8.10.1</b> The encoding of a sequence-of value shall be constructed.
36  * <p>
37  * <b>8.10.2</b> The contents octets shall consist of zero,
38  * one or more complete encodings of data values from the type listed in
39  * the ASN.1 definition.
40  * <p>
41  * <b>8.10.3</b> The order of the encodings of the data values shall be
42  * the same as the order of the data values in the sequence-of value to
43  * be encoded.
44  * </p>
45  * <p><b>9: Canonical encoding rules</b></p>
46  * <p><b>9.1 Length forms</b></p>
47  * If the encoding is constructed, it shall employ the indefinite-length form.
48  * If the encoding is primitive, it shall include the fewest length octets necessary.
49  * [Contrast with 8.1.3.2 b).]
50  *
51  * <p><b>11: Restrictions on BER employed by both CER and DER</b></p>
52  * <p><b>11.5 Set and sequence components with default value</b></p>
53  * The encoding of a set value or sequence value shall not include
54  * an encoding for any component value which is equal to
55  * its default value.
56  */
57 public abstract class ASN1Sequence
58     extends ASN1Primitive
59     implements org.bouncycastle.util.Iterable<ASN1Encodable>
60 {
61     protected Vector seq = new Vector();
62 
63     /**
64      * Return an ASN1Sequence from the given object.
65      *
66      * @param obj the object we want converted.
67      * @exception IllegalArgumentException if the object cannot be converted.
68      * @return an ASN1Sequence instance, or null.
69      */
getInstance( Object obj)70     public static ASN1Sequence getInstance(
71         Object  obj)
72     {
73         if (obj == null || obj instanceof ASN1Sequence)
74         {
75             return (ASN1Sequence)obj;
76         }
77         else if (obj instanceof ASN1SequenceParser)
78         {
79             return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive());
80         }
81         else if (obj instanceof byte[])
82         {
83             try
84             {
85                 return ASN1Sequence.getInstance(fromByteArray((byte[])obj));
86             }
87             catch (IOException e)
88             {
89                 throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
90             }
91         }
92         else if (obj instanceof ASN1Encodable)
93         {
94             ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
95 
96             if (primitive instanceof ASN1Sequence)
97             {
98                 return (ASN1Sequence)primitive;
99             }
100         }
101 
102         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
103     }
104 
105     /**
106      * Return an ASN1 sequence from a tagged object. There is a special
107      * case here, if an object appears to have been explicitly tagged on
108      * reading but we were expecting it to be implicitly tagged in the
109      * normal course of events it indicates that we lost the surrounding
110      * sequence - so we need to add it back (this will happen if the tagged
111      * object is a sequence that contains other sequences). If you are
112      * dealing with implicitly tagged sequences you really <b>should</b>
113      * be using this method.
114      *
115      * @param obj the tagged object.
116      * @param explicit true if the object is meant to be explicitly tagged,
117      *          false otherwise.
118      * @exception IllegalArgumentException if the tagged object cannot
119      *          be converted.
120      * @return an ASN1Sequence instance.
121      */
getInstance( ASN1TaggedObject obj, boolean explicit)122     public static ASN1Sequence getInstance(
123         ASN1TaggedObject    obj,
124         boolean             explicit)
125     {
126         if (explicit)
127         {
128             if (!obj.isExplicit())
129             {
130                 throw new IllegalArgumentException("object implicit - explicit expected.");
131             }
132 
133             return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive());
134         }
135         else
136         {
137             //
138             // constructed object which appears to be explicitly tagged
139             // when it should be implicit means we have to add the
140             // surrounding sequence.
141             //
142             if (obj.isExplicit())
143             {
144                 if (obj instanceof BERTaggedObject)
145                 {
146                     return new BERSequence(obj.getObject());
147                 }
148                 else
149                 {
150                     return new DLSequence(obj.getObject());
151                 }
152             }
153             else
154             {
155                 if (obj.getObject() instanceof ASN1Sequence)
156                 {
157                     return (ASN1Sequence)obj.getObject();
158                 }
159             }
160         }
161 
162         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
163     }
164 
165     /**
166      * Create an empty sequence
167      */
ASN1Sequence()168     protected ASN1Sequence()
169     {
170     }
171 
172     /**
173      * Create a sequence containing one object
174      * @param obj the object to be put in the SEQUENCE.
175      */
ASN1Sequence( ASN1Encodable obj)176     protected ASN1Sequence(
177         ASN1Encodable obj)
178     {
179         seq.addElement(obj);
180     }
181 
182     /**
183      * Create a sequence containing a vector of objects.
184      * @param v the vector of objects to be put in the SEQUENCE
185      */
ASN1Sequence( ASN1EncodableVector v)186     protected ASN1Sequence(
187         ASN1EncodableVector v)
188     {
189         for (int i = 0; i != v.size(); i++)
190         {
191             seq.addElement(v.get(i));
192         }
193     }
194 
195     /*
196      * Create a sequence containing a vector of objects.
197      */
ASN1Sequence( ASN1Encodable[] array)198     protected ASN1Sequence(
199         ASN1Encodable[]   array)
200     {
201         for (int i = 0; i != array.length; i++)
202         {
203             seq.addElement(array[i]);
204         }
205     }
206 
toArray()207     public ASN1Encodable[] toArray()
208     {
209         ASN1Encodable[] values = new ASN1Encodable[this.size()];
210 
211         for (int i = 0; i != this.size(); i++)
212         {
213             values[i] = this.getObjectAt(i);
214         }
215 
216         return values;
217     }
218 
getObjects()219     public Enumeration getObjects()
220     {
221         return seq.elements();
222     }
223 
parser()224     public ASN1SequenceParser parser()
225     {
226         final ASN1Sequence outer = this;
227 
228         return new ASN1SequenceParser()
229         {
230             private final int max = size();
231 
232             private int index;
233 
234             public ASN1Encodable readObject() throws IOException
235             {
236                 if (index == max)
237                 {
238                     return null;
239                 }
240 
241                 ASN1Encodable obj = getObjectAt(index++);
242                 if (obj instanceof ASN1Sequence)
243                 {
244                     return ((ASN1Sequence)obj).parser();
245                 }
246                 if (obj instanceof ASN1Set)
247                 {
248                     return ((ASN1Set)obj).parser();
249                 }
250 
251                 return obj;
252             }
253 
254             public ASN1Primitive getLoadedObject()
255             {
256                 return outer;
257             }
258 
259             public ASN1Primitive toASN1Primitive()
260             {
261                 return outer;
262             }
263         };
264     }
265 
266     /**
267      * Return the object at the sequence position indicated by index.
268      *
269      * @param index the sequence number (starting at zero) of the object
270      * @return the object at the sequence position indicated by index.
271      */
getObjectAt( int index)272     public ASN1Encodable getObjectAt(
273         int index)
274     {
275         return (ASN1Encodable)seq.elementAt(index);
276     }
277 
278     /**
279      * Return the number of objects in this sequence.
280      *
281      * @return the number of objects in this sequence.
282      */
size()283     public int size()
284     {
285         return seq.size();
286     }
287 
hashCode()288     public int hashCode()
289     {
290         Enumeration             e = this.getObjects();
291         int                     hashCode = size();
292 
293         while (e.hasMoreElements())
294         {
295             Object o = getNext(e);
296             hashCode *= 17;
297 
298             hashCode ^= o.hashCode();
299         }
300 
301         return hashCode;
302     }
303 
asn1Equals( ASN1Primitive o)304     boolean asn1Equals(
305         ASN1Primitive o)
306     {
307         if (!(o instanceof ASN1Sequence))
308         {
309             return false;
310         }
311 
312         ASN1Sequence   other = (ASN1Sequence)o;
313 
314         if (this.size() != other.size())
315         {
316             return false;
317         }
318 
319         Enumeration s1 = this.getObjects();
320         Enumeration s2 = other.getObjects();
321 
322         while (s1.hasMoreElements())
323         {
324             ASN1Encodable obj1 = getNext(s1);
325             ASN1Encodable obj2 = getNext(s2);
326 
327             ASN1Primitive o1 = obj1.toASN1Primitive();
328             ASN1Primitive o2 = obj2.toASN1Primitive();
329 
330             if (o1 == o2 || o1.equals(o2))
331             {
332                 continue;
333             }
334 
335             return false;
336         }
337 
338         return true;
339     }
340 
getNext(Enumeration e)341     private ASN1Encodable getNext(Enumeration e)
342     {
343         ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
344 
345         return encObj;
346     }
347 
348     /**
349      * Change current SEQUENCE object to be encoded as {@link DERSequence}.
350      * This is part of Distinguished Encoding Rules form serialization.
351      */
toDERObject()352     ASN1Primitive toDERObject()
353     {
354         ASN1Sequence derSeq = new DERSequence();
355 
356         derSeq.seq = this.seq;
357 
358         return derSeq;
359     }
360 
361     /**
362      * Change current SEQUENCE object to be encoded as {@link DLSequence}.
363      * This is part of Direct Length form serialization.
364      */
toDLObject()365     ASN1Primitive toDLObject()
366     {
367         ASN1Sequence dlSeq = new DLSequence();
368 
369         dlSeq.seq = this.seq;
370 
371         return dlSeq;
372     }
373 
isConstructed()374     boolean isConstructed()
375     {
376         return true;
377     }
378 
encode(ASN1OutputStream out)379     abstract void encode(ASN1OutputStream out)
380         throws IOException;
381 
toString()382     public String toString()
383     {
384         return seq.toString();
385     }
386 
iterator()387     public Iterator<ASN1Encodable> iterator()
388     {
389         return new Arrays.Iterator<ASN1Encodable>(toArray());
390     }
391 }
392