• 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>SET</code> and <code>SET OF</code> constructs.
12  * <p>
13  * Note: This does not know which syntax the set is!
14  * (The difference: ordering of SET elements or not ordering.)
15  * <p>
16  * DER form is always definite form length fields, while
17  * BER support uses indefinite form.
18  * <p>
19  * The CER form support does not exist.
20  * <p>
21  * <hr>
22  * <h2>X.690</h2>
23  * <h3>8: Basic encoding rules</h3>
24  * <h4>8.11 Encoding of a set value </h4>
25  * <b>8.11.1</b> The encoding of a set value shall be constructed
26  * <p>
27  * <b>8.11.2</b> The contents octets shall consist of the complete
28  * encoding of a data value from each of the types listed in the
29  * ASN.1 definition of the set type, in an order chosen by the sender,
30  * unless the type was referenced with the keyword
31  * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
32  * <p>
33  * <b>8.11.3</b> The encoding of a data value may, but need not,
34  * be present for a type which was referenced with the keyword
35  * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>.
36  * <blockquote>
37  * NOTE &mdash; The order of data values in a set value is not significant,
38  * and places no constraints on the order during transfer
39  * </blockquote>
40  * <h4>8.12 Encoding of a set-of value</h4>
41  * <b>8.12.1</b> The encoding of a set-of value shall be constructed.
42  * <p>
43  * <b>8.12.2</b> The text of 8.10.2 applies:
44  * <i>The contents octets shall consist of zero,
45  * one or more complete encodings of data values from the type listed in
46  * the ASN.1 definition.</i>
47  * <p>
48  * <b>8.12.3</b> The order of data values need not be preserved by
49  * the encoding and subsequent decoding.
50  *
51  * <h3>9: Canonical encoding rules</h3>
52  * <h4>9.1 Length forms</h4>
53  * If the encoding is constructed, it shall employ the indefinite-length form.
54  * If the encoding is primitive, it shall include the fewest length octets necessary.
55  * [Contrast with 8.1.3.2 b).]
56  * <h4>9.3 Set components</h4>
57  * The encodings of the component values of a set value shall
58  * appear in an order determined by their tags as specified
59  * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
60  * Additionally, for the purposes of determining the order in which
61  * components are encoded when one or more component is an untagged
62  * choice type, each untagged choice type is ordered as though it
63  * has a tag equal to that of the smallest tag in that choice type
64  * or any untagged choice types nested within.
65  *
66  * <h3>10: Distinguished encoding rules</h3>
67  * <h4>10.1 Length forms</h4>
68  * The definite form of length encoding shall be used,
69  * encoded in the minimum number of octets.
70  * [Contrast with 8.1.3.2 b).]
71  * <h4>10.3 Set components</h4>
72  * The encodings of the component values of a set value shall appear
73  * in an order determined by their tags as specified
74  * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1.
75  * <blockquote>
76  * NOTE &mdash; Where a component of the set is an untagged choice type,
77  * the location of that component in the ordering will depend on
78  * the tag of the choice component being encoded.
79  * </blockquote>
80  *
81  * <h3>11: Restrictions on BER employed by both CER and DER</h3>
82  * <h4>11.5 Set and sequence components with default value </h4>
83  * The encoding of a set value or sequence value shall not include
84  * an encoding for any component value which is equal to
85  * its default value.
86  * <h4>11.6 Set-of components </h4>
87  * <p>
88  * The encodings of the component values of a set-of value
89  * shall appear in ascending order, the encodings being compared
90  * as octet strings with the shorter components being padded at
91  * their trailing end with 0-octets.
92  * <blockquote>
93  * NOTE &mdash; The padding octets are for comparison purposes only
94  * and do not appear in the encodings.
95  * </blockquote>
96  */
97 public abstract class ASN1Set
98     extends ASN1Primitive
99     implements org.bouncycastle.util.Iterable<ASN1Encodable>
100 {
101     private Vector set = new Vector();
102     private boolean isSorted = false;
103 
104     /**
105      * return an ASN1Set from the given object.
106      *
107      * @param obj the object we want converted.
108      * @exception IllegalArgumentException if the object cannot be converted.
109      * @return an ASN1Set instance, or null.
110      */
getInstance( Object obj)111     public static ASN1Set getInstance(
112         Object  obj)
113     {
114         if (obj == null || obj instanceof ASN1Set)
115         {
116             return (ASN1Set)obj;
117         }
118         else if (obj instanceof ASN1SetParser)
119         {
120             return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive());
121         }
122         else if (obj instanceof byte[])
123         {
124             try
125             {
126                 return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
127             }
128             catch (IOException e)
129             {
130                 throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage());
131             }
132         }
133         else if (obj instanceof ASN1Encodable)
134         {
135             ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
136 
137             if (primitive instanceof ASN1Set)
138             {
139                 return (ASN1Set)primitive;
140             }
141         }
142 
143         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
144     }
145 
146     /**
147      * Return an ASN1 set from a tagged object. There is a special
148      * case here, if an object appears to have been explicitly tagged on
149      * reading but we were expecting it to be implicitly tagged in the
150      * normal course of events it indicates that we lost the surrounding
151      * set - so we need to add it back (this will happen if the tagged
152      * object is a sequence that contains other sequences). If you are
153      * dealing with implicitly tagged sets you really <b>should</b>
154      * be using this method.
155      *
156      * @param obj the tagged object.
157      * @param explicit true if the object is meant to be explicitly tagged
158      *          false otherwise.
159      * @exception IllegalArgumentException if the tagged object cannot
160      *          be converted.
161      * @return an ASN1Set instance.
162      */
getInstance( ASN1TaggedObject obj, boolean explicit)163     public static ASN1Set getInstance(
164         ASN1TaggedObject    obj,
165         boolean             explicit)
166     {
167         if (explicit)
168         {
169             if (!obj.isExplicit())
170             {
171                 throw new IllegalArgumentException("object implicit - explicit expected.");
172             }
173 
174             return (ASN1Set)obj.getObject();
175         }
176         else
177         {
178             //
179             // constructed object which appears to be explicitly tagged
180             // and it's really implicit means we have to add the
181             // surrounding set.
182             //
183             if (obj.isExplicit())
184             {
185                 if (obj instanceof BERTaggedObject)
186                 {
187                     return new BERSet(obj.getObject());
188                 }
189                 else
190                 {
191                     return new DLSet(obj.getObject());
192                 }
193             }
194             else
195             {
196                 if (obj.getObject() instanceof ASN1Set)
197                 {
198                     return (ASN1Set)obj.getObject();
199                 }
200 
201                 //
202                 // in this case the parser returns a sequence, convert it
203                 // into a set.
204                 //
205                 if (obj.getObject() instanceof ASN1Sequence)
206                 {
207                     ASN1Sequence s = (ASN1Sequence)obj.getObject();
208 
209                     if (obj instanceof BERTaggedObject)
210                     {
211                         return new BERSet(s.toArray());
212                     }
213                     else
214                     {
215                         return new DLSet(s.toArray());
216                     }
217                 }
218             }
219         }
220 
221         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
222     }
223 
ASN1Set()224     protected ASN1Set()
225     {
226     }
227 
228     /**
229      * create a sequence containing one object
230      * @param obj object to be added to the SET.
231      */
ASN1Set( ASN1Encodable obj)232     protected ASN1Set(
233         ASN1Encodable obj)
234     {
235         set.addElement(obj);
236     }
237 
238     /**
239      * create a sequence containing a vector of objects.
240      * @param v a vector of objects to make up the SET.
241      * @param doSort true if should be sorted DER style, false otherwise.
242      */
ASN1Set( ASN1EncodableVector v, boolean doSort)243     protected ASN1Set(
244         ASN1EncodableVector v,
245         boolean                  doSort)
246     {
247         for (int i = 0; i != v.size(); i++)
248         {
249             set.addElement(v.get(i));
250         }
251 
252         if (doSort)
253         {
254             this.sort();
255         }
256     }
257 
258     /*
259      * create a sequence containing a vector of objects.
260      */
ASN1Set( ASN1Encodable[] array, boolean doSort)261     protected ASN1Set(
262         ASN1Encodable[]   array,
263         boolean doSort)
264     {
265         for (int i = 0; i != array.length; i++)
266         {
267             set.addElement(array[i]);
268         }
269 
270         if (doSort)
271         {
272             this.sort();
273         }
274     }
275 
getObjects()276     public Enumeration getObjects()
277     {
278         return set.elements();
279     }
280 
281     /**
282      * return the object at the set position indicated by index.
283      *
284      * @param index the set number (starting at zero) of the object
285      * @return the object at the set position indicated by index.
286      */
getObjectAt( int index)287     public ASN1Encodable getObjectAt(
288         int index)
289     {
290         return (ASN1Encodable)set.elementAt(index);
291     }
292 
293     /**
294      * return the number of objects in this set.
295      *
296      * @return the number of objects in this set.
297      */
size()298     public int size()
299     {
300         return set.size();
301     }
302 
toArray()303     public ASN1Encodable[] toArray()
304     {
305         ASN1Encodable[] values = new ASN1Encodable[this.size()];
306 
307         for (int i = 0; i != this.size(); i++)
308         {
309             values[i] = this.getObjectAt(i);
310         }
311 
312         return values;
313     }
314 
parser()315     public ASN1SetParser parser()
316     {
317         final ASN1Set outer = this;
318 
319         return new ASN1SetParser()
320         {
321             private final int max = size();
322 
323             private int index;
324 
325             public ASN1Encodable readObject() throws IOException
326             {
327                 if (index == max)
328                 {
329                     return null;
330                 }
331 
332                 ASN1Encodable obj = getObjectAt(index++);
333                 if (obj instanceof ASN1Sequence)
334                 {
335                     return ((ASN1Sequence)obj).parser();
336                 }
337                 if (obj instanceof ASN1Set)
338                 {
339                     return ((ASN1Set)obj).parser();
340                 }
341 
342                 return obj;
343             }
344 
345             public ASN1Primitive getLoadedObject()
346             {
347                 return outer;
348             }
349 
350             public ASN1Primitive toASN1Primitive()
351             {
352                 return outer;
353             }
354         };
355     }
356 
hashCode()357     public int hashCode()
358     {
359         Enumeration             e = this.getObjects();
360         int                     hashCode = size();
361 
362         while (e.hasMoreElements())
363         {
364             Object o = getNext(e);
365             hashCode *= 17;
366 
367             hashCode ^= o.hashCode();
368         }
369 
370         return hashCode;
371     }
372 
373     /**
374      * Change current SET object to be encoded as {@link DERSet}.
375      * This is part of Distinguished Encoding Rules form serialization.
376      */
toDERObject()377     ASN1Primitive toDERObject()
378     {
379         if (isSorted)
380         {
381             ASN1Set derSet = new DERSet();
382 
383             derSet.set = this.set;
384 
385             return derSet;
386         }
387         else
388         {
389             Vector v = new Vector();
390 
391             for (int i = 0; i != set.size(); i++)
392             {
393                 v.addElement(set.elementAt(i));
394             }
395 
396             ASN1Set derSet = new DERSet();
397 
398             derSet.set = v;
399 
400             derSet.sort();
401 
402             return derSet;
403         }
404     }
405 
406     /**
407      * Change current SET object to be encoded as {@link DLSet}.
408      * This is part of Direct Length form serialization.
409      */
toDLObject()410     ASN1Primitive toDLObject()
411     {
412         ASN1Set derSet = new DLSet();
413 
414         derSet.set = this.set;
415 
416         return derSet;
417     }
418 
asn1Equals( ASN1Primitive o)419     boolean asn1Equals(
420         ASN1Primitive o)
421     {
422         if (!(o instanceof ASN1Set))
423         {
424             return false;
425         }
426 
427         ASN1Set   other = (ASN1Set)o;
428 
429         if (this.size() != other.size())
430         {
431             return false;
432         }
433 
434         Enumeration s1 = this.getObjects();
435         Enumeration s2 = other.getObjects();
436 
437         while (s1.hasMoreElements())
438         {
439             ASN1Encodable obj1 = getNext(s1);
440             ASN1Encodable obj2 = getNext(s2);
441 
442             ASN1Primitive o1 = obj1.toASN1Primitive();
443             ASN1Primitive o2 = obj2.toASN1Primitive();
444 
445             if (o1 == o2 || o1.equals(o2))
446             {
447                 continue;
448             }
449 
450             return false;
451         }
452 
453         return true;
454     }
455 
getNext(Enumeration e)456     private ASN1Encodable getNext(Enumeration e)
457     {
458         ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
459 
460         // unfortunately null was allowed as a substitute for DER null
461         if (encObj == null)
462         {
463             return DERNull.INSTANCE;
464         }
465 
466         return encObj;
467     }
468 
469     /**
470      * return true if a <= b (arrays are assumed padded with zeros).
471      */
lessThanOrEqual( byte[] a, byte[] b)472     private boolean lessThanOrEqual(
473          byte[] a,
474          byte[] b)
475     {
476         int len = Math.min(a.length, b.length);
477         for (int i = 0; i != len; ++i)
478         {
479             if (a[i] != b[i])
480             {
481                 return (a[i] & 0xff) < (b[i] & 0xff);
482             }
483         }
484         return len == a.length;
485     }
486 
getDEREncoded( ASN1Encodable obj)487     private byte[] getDEREncoded(
488         ASN1Encodable obj)
489     {
490         try
491         {
492             return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
493         }
494         catch (IOException e)
495         {
496             throw new IllegalArgumentException("cannot encode object added to SET");
497         }
498     }
499 
sort()500     protected void sort()
501     {
502         if (!isSorted)
503         {
504             isSorted = true;
505             if (set.size() > 1)
506             {
507                 boolean    swapped = true;
508                 int        lastSwap = set.size() - 1;
509 
510                 while (swapped)
511                 {
512                     int    index = 0;
513                     int    swapIndex = 0;
514                     byte[] a = getDEREncoded((ASN1Encodable)set.elementAt(0));
515 
516                     swapped = false;
517 
518                     while (index != lastSwap)
519                     {
520                         byte[] b = getDEREncoded((ASN1Encodable)set.elementAt(index + 1));
521 
522                         if (lessThanOrEqual(a, b))
523                         {
524                             a = b;
525                         }
526                         else
527                         {
528                             Object  o = set.elementAt(index);
529 
530                             set.setElementAt(set.elementAt(index + 1), index);
531                             set.setElementAt(o, index + 1);
532 
533                             swapped = true;
534                             swapIndex = index;
535                         }
536 
537                         index++;
538                     }
539 
540                     lastSwap = swapIndex;
541                 }
542             }
543         }
544     }
545 
isConstructed()546     boolean isConstructed()
547     {
548         return true;
549     }
550 
encode(ASN1OutputStream out)551     abstract void encode(ASN1OutputStream out)
552             throws IOException;
553 
toString()554     public String toString()
555     {
556         return set.toString();
557     }
558 
iterator()559     public Iterator<ASN1Encodable> iterator()
560     {
561         return new Arrays.Iterator<ASN1Encodable>(toArray());
562     }
563 }
564