1package org.bouncycastle.asn1; 2 3import java.io.ByteArrayOutputStream; 4import java.io.IOException; 5import java.util.Enumeration; 6import java.util.Vector; 7 8abstract 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 */ 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: " + obj.getClass().getName()); 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 implicitly 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 */ 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("unknown object in getInstance: " + obj.getClass().getName()); 101 } 102 103 public ASN1Set() 104 { 105 } 106 107 public Enumeration getObjects() 108 { 109 return set.elements(); 110 } 111 112 /** 113 * return the object at the set position indicated by index. 114 * 115 * @param index the set number (starting at zero) of the object 116 * @return the object at the set position indicated by index. 117 */ 118 public DEREncodable getObjectAt( 119 int index) 120 { 121 return (DEREncodable)set.elementAt(index); 122 } 123 124 /** 125 * return the number of objects in this set. 126 * 127 * @return the number of objects in this set. 128 */ 129 public int size() 130 { 131 return set.size(); 132 } 133 134 public ASN1Encodable[] toArray() 135 { 136 ASN1Encodable[] values = new ASN1Encodable[this.size()]; 137 138 for (int i = 0; i != this.size(); i++) 139 { 140 values[i] = (ASN1Encodable)this.getObjectAt(i); 141 } 142 143 return values; 144 } 145 146 public ASN1SetParser parser() 147 { 148 final ASN1Set outer = this; 149 150 return new ASN1SetParser() 151 { 152 private final int max = size(); 153 154 private int index; 155 156 public DEREncodable readObject() throws IOException 157 { 158 if (index == max) 159 { 160 return null; 161 } 162 163 DEREncodable obj = getObjectAt(index++); 164 if (obj instanceof ASN1Sequence) 165 { 166 return ((ASN1Sequence)obj).parser(); 167 } 168 if (obj instanceof ASN1Set) 169 { 170 return ((ASN1Set)obj).parser(); 171 } 172 173 return obj; 174 } 175 176 public DERObject getLoadedObject() 177 { 178 return outer; 179 } 180 181 public DERObject getDERObject() 182 { 183 return outer; 184 } 185 }; 186 } 187 188 public int hashCode() 189 { 190 Enumeration e = this.getObjects(); 191 int hashCode = size(); 192 193 while (e.hasMoreElements()) 194 { 195 Object o = getNext(e); 196 hashCode *= 17; 197 198 hashCode ^= o.hashCode(); 199 } 200 201 return hashCode; 202 } 203 204 boolean asn1Equals( 205 DERObject o) 206 { 207 if (!(o instanceof ASN1Set)) 208 { 209 return false; 210 } 211 212 ASN1Set other = (ASN1Set)o; 213 214 if (this.size() != other.size()) 215 { 216 return false; 217 } 218 219 Enumeration s1 = this.getObjects(); 220 Enumeration s2 = other.getObjects(); 221 222 while (s1.hasMoreElements()) 223 { 224 DEREncodable obj1 = getNext(s1); 225 DEREncodable obj2 = getNext(s2); 226 227 DERObject o1 = obj1.getDERObject(); 228 DERObject o2 = obj2.getDERObject(); 229 230 if (o1 == o2 || o1.equals(o2)) 231 { 232 continue; 233 } 234 235 return false; 236 } 237 238 return true; 239 } 240 241 private DEREncodable getNext(Enumeration e) 242 { 243 DEREncodable encObj = (DEREncodable)e.nextElement(); 244 245 // unfortunately null was allowed as a substitute for DER null 246 if (encObj == null) 247 { 248 return DERNull.INSTANCE; 249 } 250 251 return encObj; 252 } 253 254 /** 255 * return true if a <= b (arrays are assumed padded with zeros). 256 */ 257 private boolean lessThanOrEqual( 258 byte[] a, 259 byte[] b) 260 { 261 int len = Math.min(a.length, b.length); 262 for (int i = 0; i != len; ++i) 263 { 264 if (a[i] != b[i]) 265 { 266 return (a[i] & 0xff) < (b[i] & 0xff); 267 } 268 } 269 return len == a.length; 270 } 271 272 private byte[] getEncoded( 273 DEREncodable obj) 274 { 275 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 276 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 277 278 try 279 { 280 aOut.writeObject(obj); 281 } 282 catch (IOException e) 283 { 284 throw new IllegalArgumentException("cannot encode object added to SET"); 285 } 286 287 return bOut.toByteArray(); 288 } 289 290 protected void sort() 291 { 292 if (set.size() > 1) 293 { 294 boolean swapped = true; 295 int lastSwap = set.size() - 1; 296 297 while (swapped) 298 { 299 int index = 0; 300 int swapIndex = 0; 301 byte[] a = getEncoded((DEREncodable)set.elementAt(0)); 302 303 swapped = false; 304 305 while (index != lastSwap) 306 { 307 byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1)); 308 309 if (lessThanOrEqual(a, b)) 310 { 311 a = b; 312 } 313 else 314 { 315 Object o = set.elementAt(index); 316 317 set.setElementAt(set.elementAt(index + 1), index); 318 set.setElementAt(o, index + 1); 319 320 swapped = true; 321 swapIndex = index; 322 } 323 324 index++; 325 } 326 327 lastSwap = swapIndex; 328 } 329 } 330 } 331 332 protected void addObject( 333 DEREncodable obj) 334 { 335 set.addElement(obj); 336 } 337 338 abstract void encode(DEROutputStream out) 339 throws IOException; 340 341 public String toString() 342 { 343 return set.toString(); 344 } 345} 346