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 ASN1Primitive 10{ 11 private Vector set = new Vector(); 12 private boolean isSorted = false; 13 14 /** 15 * return an ASN1Set from the given object. 16 * 17 * @param obj the object we want converted. 18 * @exception IllegalArgumentException if the object cannot be converted. 19 */ 20 public static ASN1Set getInstance( 21 Object obj) 22 { 23 if (obj == null || obj instanceof ASN1Set) 24 { 25 return (ASN1Set)obj; 26 } 27 else if (obj instanceof ASN1SetParser) 28 { 29 return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive()); 30 } 31 else if (obj instanceof byte[]) 32 { 33 try 34 { 35 return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); 36 } 37 catch (IOException e) 38 { 39 throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage()); 40 } 41 } 42 else if (obj instanceof ASN1Encodable) 43 { 44 ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); 45 46 if (primitive instanceof ASN1Set) 47 { 48 return (ASN1Set)primitive; 49 } 50 } 51 52 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 53 } 54 55 /** 56 * Return an ASN1 set from a tagged object. There is a special 57 * case here, if an object appears to have been explicitly tagged on 58 * reading but we were expecting it to be implicitly tagged in the 59 * normal course of events it indicates that we lost the surrounding 60 * set - so we need to add it back (this will happen if the tagged 61 * object is a sequence that contains other sequences). If you are 62 * dealing with implicitly tagged sets you really <b>should</b> 63 * be using this method. 64 * 65 * @param obj the tagged object. 66 * @param explicit true if the object is meant to be explicitly tagged 67 * false otherwise. 68 * @exception IllegalArgumentException if the tagged object cannot 69 * be converted. 70 */ 71 public static ASN1Set getInstance( 72 ASN1TaggedObject obj, 73 boolean explicit) 74 { 75 if (explicit) 76 { 77 if (!obj.isExplicit()) 78 { 79 throw new IllegalArgumentException("object implicit - explicit expected."); 80 } 81 82 return (ASN1Set)obj.getObject(); 83 } 84 else 85 { 86 // 87 // constructed object which appears to be explicitly tagged 88 // and it's really implicit means we have to add the 89 // surrounding set. 90 // 91 if (obj.isExplicit()) 92 { 93 if (obj instanceof BERTaggedObject) 94 { 95 return new BERSet(obj.getObject()); 96 } 97 else 98 { 99 return new DLSet(obj.getObject()); 100 } 101 } 102 else 103 { 104 if (obj.getObject() instanceof ASN1Set) 105 { 106 return (ASN1Set)obj.getObject(); 107 } 108 109 // 110 // in this case the parser returns a sequence, convert it 111 // into a set. 112 // 113 if (obj.getObject() instanceof ASN1Sequence) 114 { 115 ASN1Sequence s = (ASN1Sequence)obj.getObject(); 116 117 if (obj instanceof BERTaggedObject) 118 { 119 return new BERSet(s.toArray()); 120 } 121 else 122 { 123 return new DLSet(s.toArray()); 124 } 125 } 126 } 127 } 128 129 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 130 } 131 132 protected ASN1Set() 133 { 134 } 135 136 /** 137 * create a sequence containing one object 138 */ 139 protected ASN1Set( 140 ASN1Encodable obj) 141 { 142 set.addElement(obj); 143 } 144 145 /** 146 * create a sequence containing a vector of objects. 147 */ 148 protected ASN1Set( 149 ASN1EncodableVector v, 150 boolean doSort) 151 { 152 for (int i = 0; i != v.size(); i++) 153 { 154 set.addElement(v.get(i)); 155 } 156 157 if (doSort) 158 { 159 this.sort(); 160 } 161 } 162 163 /** 164 * create a sequence containing a vector of objects. 165 */ 166 protected ASN1Set( 167 ASN1Encodable[] array, 168 boolean doSort) 169 { 170 for (int i = 0; i != array.length; i++) 171 { 172 set.addElement(array[i]); 173 } 174 175 if (doSort) 176 { 177 this.sort(); 178 } 179 } 180 181 public Enumeration getObjects() 182 { 183 return set.elements(); 184 } 185 186 /** 187 * return the object at the set position indicated by index. 188 * 189 * @param index the set number (starting at zero) of the object 190 * @return the object at the set position indicated by index. 191 */ 192 public ASN1Encodable getObjectAt( 193 int index) 194 { 195 return (ASN1Encodable)set.elementAt(index); 196 } 197 198 /** 199 * return the number of objects in this set. 200 * 201 * @return the number of objects in this set. 202 */ 203 public int size() 204 { 205 return set.size(); 206 } 207 208 public ASN1Encodable[] toArray() 209 { 210 ASN1Encodable[] values = new ASN1Encodable[this.size()]; 211 212 for (int i = 0; i != this.size(); i++) 213 { 214 values[i] = this.getObjectAt(i); 215 } 216 217 return values; 218 } 219 220 public ASN1SetParser parser() 221 { 222 final ASN1Set outer = this; 223 224 return new ASN1SetParser() 225 { 226 private final int max = size(); 227 228 private int index; 229 230 public ASN1Encodable readObject() throws IOException 231 { 232 if (index == max) 233 { 234 return null; 235 } 236 237 ASN1Encodable obj = getObjectAt(index++); 238 if (obj instanceof ASN1Sequence) 239 { 240 return ((ASN1Sequence)obj).parser(); 241 } 242 if (obj instanceof ASN1Set) 243 { 244 return ((ASN1Set)obj).parser(); 245 } 246 247 return obj; 248 } 249 250 public ASN1Primitive getLoadedObject() 251 { 252 return outer; 253 } 254 255 public ASN1Primitive toASN1Primitive() 256 { 257 return outer; 258 } 259 }; 260 } 261 262 public int hashCode() 263 { 264 Enumeration e = this.getObjects(); 265 int hashCode = size(); 266 267 while (e.hasMoreElements()) 268 { 269 Object o = getNext(e); 270 hashCode *= 17; 271 272 hashCode ^= o.hashCode(); 273 } 274 275 return hashCode; 276 } 277 278 ASN1Primitive toDERObject() 279 { 280 if (isSorted) 281 { 282 ASN1Set derSet = new DERSet(); 283 284 derSet.set = this.set; 285 286 return derSet; 287 } 288 else 289 { 290 Vector v = new Vector(); 291 292 for (int i = 0; i != set.size(); i++) 293 { 294 v.addElement(set.elementAt(i)); 295 } 296 297 ASN1Set derSet = new DERSet(); 298 299 derSet.set = v; 300 301 derSet.sort(); 302 303 return derSet; 304 } 305 } 306 307 ASN1Primitive toDLObject() 308 { 309 ASN1Set derSet = new DLSet(); 310 311 derSet.set = this.set; 312 313 return derSet; 314 } 315 316 boolean asn1Equals( 317 ASN1Primitive o) 318 { 319 if (!(o instanceof ASN1Set)) 320 { 321 return false; 322 } 323 324 ASN1Set other = (ASN1Set)o; 325 326 if (this.size() != other.size()) 327 { 328 return false; 329 } 330 331 Enumeration s1 = this.getObjects(); 332 Enumeration s2 = other.getObjects(); 333 334 while (s1.hasMoreElements()) 335 { 336 ASN1Encodable obj1 = getNext(s1); 337 ASN1Encodable obj2 = getNext(s2); 338 339 ASN1Primitive o1 = obj1.toASN1Primitive(); 340 ASN1Primitive o2 = obj2.toASN1Primitive(); 341 342 if (o1 == o2 || o1.equals(o2)) 343 { 344 continue; 345 } 346 347 return false; 348 } 349 350 return true; 351 } 352 353 private ASN1Encodable getNext(Enumeration e) 354 { 355 ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); 356 357 // unfortunately null was allowed as a substitute for DER null 358 if (encObj == null) 359 { 360 return DERNull.INSTANCE; 361 } 362 363 return encObj; 364 } 365 366 /** 367 * return true if a <= b (arrays are assumed padded with zeros). 368 */ 369 private boolean lessThanOrEqual( 370 byte[] a, 371 byte[] b) 372 { 373 int len = Math.min(a.length, b.length); 374 for (int i = 0; i != len; ++i) 375 { 376 if (a[i] != b[i]) 377 { 378 return (a[i] & 0xff) < (b[i] & 0xff); 379 } 380 } 381 return len == a.length; 382 } 383 384 private byte[] getEncoded( 385 ASN1Encodable obj) 386 { 387 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 388 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 389 390 try 391 { 392 aOut.writeObject(obj); 393 } 394 catch (IOException e) 395 { 396 throw new IllegalArgumentException("cannot encode object added to SET"); 397 } 398 399 return bOut.toByteArray(); 400 } 401 402 protected void sort() 403 { 404 if (!isSorted) 405 { 406 isSorted = true; 407 if (set.size() > 1) 408 { 409 boolean swapped = true; 410 int lastSwap = set.size() - 1; 411 412 while (swapped) 413 { 414 int index = 0; 415 int swapIndex = 0; 416 byte[] a = getEncoded((ASN1Encodable)set.elementAt(0)); 417 418 swapped = false; 419 420 while (index != lastSwap) 421 { 422 byte[] b = getEncoded((ASN1Encodable)set.elementAt(index + 1)); 423 424 if (lessThanOrEqual(a, b)) 425 { 426 a = b; 427 } 428 else 429 { 430 Object o = set.elementAt(index); 431 432 set.setElementAt(set.elementAt(index + 1), index); 433 set.setElementAt(o, index + 1); 434 435 swapped = true; 436 swapIndex = index; 437 } 438 439 index++; 440 } 441 442 lastSwap = swapIndex; 443 } 444 } 445 } 446 } 447 448 boolean isConstructed() 449 { 450 return true; 451 } 452 453 abstract void encode(ASN1OutputStream out) 454 throws IOException; 455 456 public String toString() 457 { 458 return set.toString(); 459 } 460} 461