View Javadoc

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