1 package org.gudy.bouncycastle.asn1;
2 
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.util.Enumeration;
6 import java.util.Vector;
7 
8 abstract public class ASN1Set
9     extends ASN1Object
10 {
11     protected Vector set = new Vector();
12 
13     /**
14      * return an ASN1Set from the given object.
15      *
16      * @param obj the object we want converted.
17      * @exception IllegalArgumentException if the object cannot be converted.
18      */
getInstance( Object obj)19     public static ASN1Set getInstance(
20         Object  obj)
21     {
22         if (obj == null || obj instanceof ASN1Set)
23         {
24             return (ASN1Set)obj;
25         }
26 
27         throw new IllegalArgumentException("unknown object in getInstance");
28     }
29 
30     /**
31      * Return an ASN1 set from a tagged object. There is a special
32      * case here, if an object appears to have been explicitly tagged on
33      * reading but we were expecting it to be implictly tagged in the
34      * normal course of events it indicates that we lost the surrounding
35      * set - so we need to add it back (this will happen if the tagged
36      * object is a sequence that contains other sequences). If you are
37      * dealing with implicitly tagged sets you really <b>should</b>
38      * be using this method.
39      *
40      * @param obj the tagged object.
41      * @param explicit true if the object is meant to be explicitly tagged
42      *          false otherwise.
43      * @exception IllegalArgumentException if the tagged object cannot
44      *          be converted.
45      */
getInstance( ASN1TaggedObject obj, boolean explicit)46     public static ASN1Set getInstance(
47         ASN1TaggedObject    obj,
48         boolean             explicit)
49     {
50         if (explicit)
51         {
52             if (!obj.isExplicit())
53             {
54                 throw new IllegalArgumentException("object implicit - explicit expected.");
55             }
56 
57             return (ASN1Set)obj.getObject();
58         }
59         else
60         {
61             //
62             // constructed object which appears to be explicitly tagged
63             // and it's really implicit means we have to add the
64             // surrounding sequence.
65             //
66             if (obj.isExplicit())
67             {
68                 ASN1Set    set = new DERSet(obj.getObject());
69 
70                 return set;
71             }
72             else
73             {
74                 if (obj.getObject() instanceof ASN1Set)
75                 {
76                     return (ASN1Set)obj.getObject();
77                 }
78 
79                 //
80                 // in this case the parser returns a sequence, convert it
81                 // into a set.
82                 //
83                 ASN1EncodableVector  v = new ASN1EncodableVector();
84 
85                 if (obj.getObject() instanceof ASN1Sequence)
86                 {
87                     ASN1Sequence s = (ASN1Sequence)obj.getObject();
88                     Enumeration e = s.getObjects();
89 
90                     while (e.hasMoreElements())
91                     {
92                         v.add((DEREncodable)e.nextElement());
93                     }
94 
95                     return new DERSet(v, false);
96                 }
97             }
98         }
99 
100         throw new IllegalArgumentException(
101                     "unknown object in getInstanceFromTagged");
102     }
103 
ASN1Set()104     public ASN1Set()
105     {
106     }
107 
getObjects()108     public Enumeration getObjects()
109     {
110         return set.elements();
111     }
112 
113     /**
114      * return the object at the set postion indicated by index.
115      *
116      * @param index the set number (starting at zero) of the object
117      * @return the object at the set postion indicated by index.
118      */
getObjectAt( int index)119     public DEREncodable getObjectAt(
120         int index)
121     {
122         return (DEREncodable)set.elementAt(index);
123     }
124 
125     /**
126      * return the number of objects in this set.
127      *
128      * @return the number of objects in this set.
129      */
size()130     public int size()
131     {
132         return set.size();
133     }
134 
parser()135     public ASN1SetParser parser()
136     {
137         final ASN1Set outer = this;
138 
139         return new ASN1SetParser()
140         {
141             private final int max = size();
142 
143             private int index;
144 
145             public DEREncodable readObject() throws IOException
146             {
147                 if (index == max)
148                 {
149                     return null;
150                 }
151 
152                 DEREncodable obj = getObjectAt(index++);
153                 if (obj instanceof ASN1Sequence)
154                 {
155                     return ((ASN1Sequence)obj).parser();
156                 }
157                 if (obj instanceof ASN1Set)
158                 {
159                     return ((ASN1Set)obj).parser();
160                 }
161 
162                 return obj;
163             }
164 
165             public DERObject getDERObject()
166             {
167                 return outer;
168             }
169         };
170     }
171 
hashCode()172     public int hashCode()
173     {
174         Enumeration             e = this.getObjects();
175         int                     hashCode = 0;
176 
177         while (e.hasMoreElements())
178         {
179             hashCode ^= e.nextElement().hashCode();
180         }
181 
182         return hashCode;
183     }
184 
asn1Equals( DERObject o)185     boolean asn1Equals(
186         DERObject  o)
187     {
188         if (!(o instanceof ASN1Set))
189         {
190             return false;
191         }
192 
193         ASN1Set   other = (ASN1Set)o;
194 
195         if (this.size() != other.size())
196         {
197             return false;
198         }
199 
200         Enumeration s1 = this.getObjects();
201         Enumeration s2 = other.getObjects();
202 
203         while (s1.hasMoreElements())
204         {
205             DERObject  o1 = ((DEREncodable)s1.nextElement()).getDERObject();
206             DERObject  o2 = ((DEREncodable)s2.nextElement()).getDERObject();
207 
208             if (o1 == o2 || (o1 != null && o1.equals(o2)))
209             {
210                 continue;
211             }
212 
213             return false;
214         }
215 
216         return true;
217     }
218 
219     /**
220      * return true if a <= b (arrays are assumed padded with zeros).
221      */
lessThanOrEqual( byte[] a, byte[] b)222     private boolean lessThanOrEqual(
223          byte[] a,
224          byte[] b)
225     {
226          if (a.length <= b.length)
227          {
228              for (int i = 0; i != a.length; i++)
229              {
230                  int    l = a[i] & 0xff;
231                  int    r = b[i] & 0xff;
232 
233                  if (r > l)
234                  {
235                      return true;
236                  }
237                  else if (l > r)
238                  {
239                      return false;
240                  }
241              }
242 
243              return true;
244          }
245          else
246          {
247              for (int i = 0; i != b.length; i++)
248              {
249                  int    l = a[i] & 0xff;
250                  int    r = b[i] & 0xff;
251 
252                  if (r > l)
253                  {
254                      return true;
255                  }
256                  else if (l > r)
257                  {
258                      return false;
259                  }
260              }
261 
262              return false;
263          }
264     }
265 
getEncoded( DEREncodable obj)266     private byte[] getEncoded(
267         DEREncodable obj)
268     {
269         ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
270         ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
271 
272         try
273         {
274             aOut.writeObject(obj);
275         }
276         catch (IOException e)
277         {
278             throw new IllegalArgumentException("cannot encode object added to SET");
279         }
280 
281         return bOut.toByteArray();
282     }
283 
sort()284     protected void sort()
285     {
286         if (set.size() > 1)
287         {
288             boolean    swapped = true;
289             int        lastSwap = set.size() - 1;
290 
291             while (swapped)
292             {
293                 int    index = 0;
294                 int    swapIndex = 0;
295                 byte[] a = getEncoded((DEREncodable)set.elementAt(0));
296 
297                 swapped = false;
298 
299                 while (index != lastSwap)
300                 {
301                     byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1));
302 
303                     if (lessThanOrEqual(a, b))
304                     {
305                         a = b;
306                     }
307                     else
308                     {
309                         Object  o = set.elementAt(index);
310 
311                         set.setElementAt(set.elementAt(index + 1), index);
312                         set.setElementAt(o, index + 1);
313 
314                         swapped = true;
315                         swapIndex = index;
316                     }
317 
318                     index++;
319                 }
320 
321                 lastSwap = swapIndex;
322             }
323         }
324     }
325 
addObject( DEREncodable obj)326     protected void addObject(
327         DEREncodable obj)
328     {
329         set.addElement(obj);
330     }
331 
encode(DEROutputStream out)332     abstract void encode(DEROutputStream out)
333             throws IOException;
334 
toString()335     public String toString()
336     {
337       return set.toString();
338     }
339 }
340