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 — 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 — 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 — 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