1 package org.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 /** 9 * ASN.1 <code>SET</code> and <code>SET OF</code> constructs. 10 * <p> 11 * Note: This does not know which syntax the set is! 12 * (The difference: ordering of SET elements or not ordering.) 13 * <p> 14 * DER form is always definite form length fields, while 15 * BER support uses indefinite form. 16 * <p> 17 * The CER form support does not exist. 18 * <p> 19 * <hr> 20 * <h2>X.690</h2> 21 * <h3>8: Basic encoding rules</h3> 22 * <h4>8.11 Encoding of a set value </h4> 23 * <b>8.11.1</b> The encoding of a set value shall be constructed 24 * <p> 25 * <b>8.11.2</b> The contents octets shall consist of the complete 26 * encoding of a data value from each of the types listed in the 27 * ASN.1 definition of the set type, in an order chosen by the sender, 28 * unless the type was referenced with the keyword 29 * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. 30 * <p> 31 * <b>8.11.3</b> The encoding of a data value may, but need not, 32 * be present for a type which was referenced with the keyword 33 * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. 34 * <blockquote> 35 * NOTE — The order of data values in a set value is not significant, 36 * and places no constraints on the order during transfer 37 * </blockquote> 38 * <h4>8.12 Encoding of a set-of value</h4> 39 * <b>8.12.1</b> The encoding of a set-of value shall be constructed. 40 * <p> 41 * <b>8.12.2</b> The text of 8.10.2 applies: 42 * <i>The contents octets shall consist of zero, 43 * one or more complete encodings of data values from the type listed in 44 * the ASN.1 definition.</i> 45 * <p> 46 * <b>8.12.3</b> The order of data values need not be preserved by 47 * the encoding and subsequent decoding. 48 * 49 * <h3>9: Canonical encoding rules</h3> 50 * <h4>9.1 Length forms</h4> 51 * If the encoding is constructed, it shall employ the indefinite length form. 52 * If the encoding is primitive, it shall include the fewest length octets necessary. 53 * [Contrast with 8.1.3.2 b).] 54 * <h4>9.3 Set components</h4> 55 * The encodings of the component values of a set value shall 56 * appear in an order determined by their tags as specified 57 * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. 58 * Additionally, for the purposes of determining the order in which 59 * components are encoded when one or more component is an untagged 60 * choice type, each untagged choice type is ordered as though it 61 * has a tag equal to that of the smallest tag in that choice type 62 * or any untagged choice types nested within. 63 * 64 * <h3>10: Distinguished encoding rules</h3> 65 * <h4>10.1 Length forms</h4> 66 * The definite form of length encoding shall be used, 67 * encoded in the minimum number of octets. 68 * [Contrast with 8.1.3.2 b).] 69 * <h4>10.3 Set components</h4> 70 * The encodings of the component values of a set value shall appear 71 * in an order determined by their tags as specified 72 * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. 73 * <blockquote> 74 * NOTE — Where a component of the set is an untagged choice type, 75 * the location of that component in the ordering will depend on 76 * the tag of the choice component being encoded. 77 * </blockquote> 78 * 79 * <h3>11: Restrictions on BER employed by both CER and DER</h3> 80 * <h4>11.5 Set and sequence components with default value </h4> 81 * The encoding of a set value or sequence value shall not include 82 * an encoding for any component value which is equal to 83 * its default value. 84 * <h4>11.6 Set-of components </h4> 85 * <p> 86 * The encodings of the component values of a set-of value 87 * shall appear in ascending order, the encodings being compared 88 * as octet strings with the shorter components being padded at 89 * their trailing end with 0-octets. 90 * <blockquote> 91 * NOTE — The padding octets are for comparison purposes only 92 * and do not appear in the encodings. 93 * </blockquote> 94 */ 95 public abstract class ASN1Set 96 extends ASN1Primitive 97 { 98 private Vector set = new Vector(); 99 private boolean isSorted = false; 100 101 /** 102 * return an ASN1Set from the given object. 103 * 104 * @param obj the object we want converted. 105 * @exception IllegalArgumentException if the object cannot be converted. 106 * @return an ASN1Set instance, or null. 107 */ getInstance( Object obj)108 public static ASN1Set getInstance( 109 Object obj) 110 { 111 if (obj == null || obj instanceof ASN1Set) 112 { 113 return (ASN1Set)obj; 114 } 115 else if (obj instanceof ASN1SetParser) 116 { 117 return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive()); 118 } 119 else if (obj instanceof byte[]) 120 { 121 try 122 { 123 return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); 124 } 125 catch (IOException e) 126 { 127 throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage()); 128 } 129 } 130 else if (obj instanceof ASN1Encodable) 131 { 132 ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); 133 134 if (primitive instanceof ASN1Set) 135 { 136 return (ASN1Set)primitive; 137 } 138 } 139 140 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 141 } 142 143 /** 144 * Return an ASN1 set from a tagged object. There is a special 145 * case here, if an object appears to have been explicitly tagged on 146 * reading but we were expecting it to be implicitly tagged in the 147 * normal course of events it indicates that we lost the surrounding 148 * set - so we need to add it back (this will happen if the tagged 149 * object is a sequence that contains other sequences). If you are 150 * dealing with implicitly tagged sets you really <b>should</b> 151 * be using this method. 152 * 153 * @param obj the tagged object. 154 * @param explicit true if the object is meant to be explicitly tagged 155 * false otherwise. 156 * @exception IllegalArgumentException if the tagged object cannot 157 * be converted. 158 * @return an ASN1Set instance. 159 */ getInstance( ASN1TaggedObject obj, boolean explicit)160 public static ASN1Set getInstance( 161 ASN1TaggedObject obj, 162 boolean explicit) 163 { 164 if (explicit) 165 { 166 if (!obj.isExplicit()) 167 { 168 throw new IllegalArgumentException("object implicit - explicit expected."); 169 } 170 171 return (ASN1Set)obj.getObject(); 172 } 173 else 174 { 175 // 176 // constructed object which appears to be explicitly tagged 177 // and it's really implicit means we have to add the 178 // surrounding set. 179 // 180 if (obj.isExplicit()) 181 { 182 if (obj instanceof BERTaggedObject) 183 { 184 return new BERSet(obj.getObject()); 185 } 186 else 187 { 188 return new DLSet(obj.getObject()); 189 } 190 } 191 else 192 { 193 if (obj.getObject() instanceof ASN1Set) 194 { 195 return (ASN1Set)obj.getObject(); 196 } 197 198 // 199 // in this case the parser returns a sequence, convert it 200 // into a set. 201 // 202 if (obj.getObject() instanceof ASN1Sequence) 203 { 204 ASN1Sequence s = (ASN1Sequence)obj.getObject(); 205 206 if (obj instanceof BERTaggedObject) 207 { 208 return new BERSet(s.toArray()); 209 } 210 else 211 { 212 return new DLSet(s.toArray()); 213 } 214 } 215 } 216 } 217 218 throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 219 } 220 ASN1Set()221 protected ASN1Set() 222 { 223 } 224 225 /** 226 * create a sequence containing one object 227 * @param obj object to be added to the SET. 228 */ ASN1Set( ASN1Encodable obj)229 protected ASN1Set( 230 ASN1Encodable obj) 231 { 232 set.addElement(obj); 233 } 234 235 /** 236 * create a sequence containing a vector of objects. 237 * @param v a vector of objects to make up the SET. 238 * @param doSort true if should be sorted DER style, false otherwise. 239 */ ASN1Set( ASN1EncodableVector v, boolean doSort)240 protected ASN1Set( 241 ASN1EncodableVector v, 242 boolean doSort) 243 { 244 for (int i = 0; i != v.size(); i++) 245 { 246 set.addElement(v.get(i)); 247 } 248 249 if (doSort) 250 { 251 this.sort(); 252 } 253 } 254 255 /** 256 * create a sequence containing a vector of objects. 257 */ ASN1Set( ASN1Encodable[] array, boolean doSort)258 protected ASN1Set( 259 ASN1Encodable[] array, 260 boolean doSort) 261 { 262 for (int i = 0; i != array.length; i++) 263 { 264 set.addElement(array[i]); 265 } 266 267 if (doSort) 268 { 269 this.sort(); 270 } 271 } 272 getObjects()273 public Enumeration getObjects() 274 { 275 return set.elements(); 276 } 277 278 /** 279 * return the object at the set position indicated by index. 280 * 281 * @param index the set number (starting at zero) of the object 282 * @return the object at the set position indicated by index. 283 */ getObjectAt( int index)284 public ASN1Encodable getObjectAt( 285 int index) 286 { 287 return (ASN1Encodable)set.elementAt(index); 288 } 289 290 /** 291 * return the number of objects in this set. 292 * 293 * @return the number of objects in this set. 294 */ size()295 public int size() 296 { 297 return set.size(); 298 } 299 toArray()300 public ASN1Encodable[] toArray() 301 { 302 ASN1Encodable[] values = new ASN1Encodable[this.size()]; 303 304 for (int i = 0; i != this.size(); i++) 305 { 306 values[i] = this.getObjectAt(i); 307 } 308 309 return values; 310 } 311 parser()312 public ASN1SetParser parser() 313 { 314 final ASN1Set outer = this; 315 316 return new ASN1SetParser() 317 { 318 private final int max = size(); 319 320 private int index; 321 322 public ASN1Encodable readObject() throws IOException 323 { 324 if (index == max) 325 { 326 return null; 327 } 328 329 ASN1Encodable obj = getObjectAt(index++); 330 if (obj instanceof ASN1Sequence) 331 { 332 return ((ASN1Sequence)obj).parser(); 333 } 334 if (obj instanceof ASN1Set) 335 { 336 return ((ASN1Set)obj).parser(); 337 } 338 339 return obj; 340 } 341 342 public ASN1Primitive getLoadedObject() 343 { 344 return outer; 345 } 346 347 public ASN1Primitive toASN1Primitive() 348 { 349 return outer; 350 } 351 }; 352 } 353 hashCode()354 public int hashCode() 355 { 356 Enumeration e = this.getObjects(); 357 int hashCode = size(); 358 359 while (e.hasMoreElements()) 360 { 361 Object o = getNext(e); 362 hashCode *= 17; 363 364 hashCode ^= o.hashCode(); 365 } 366 367 return hashCode; 368 } 369 370 /** 371 * Change current SET object to be encoded as {@link DERSet}. 372 * This is part of Distinguished Encoding Rules form serialization. 373 */ toDERObject()374 ASN1Primitive toDERObject() 375 { 376 if (isSorted) 377 { 378 ASN1Set derSet = new DERSet(); 379 380 derSet.set = this.set; 381 382 return derSet; 383 } 384 else 385 { 386 Vector v = new Vector(); 387 388 for (int i = 0; i != set.size(); i++) 389 { 390 v.addElement(set.elementAt(i)); 391 } 392 393 ASN1Set derSet = new DERSet(); 394 395 derSet.set = v; 396 397 derSet.sort(); 398 399 return derSet; 400 } 401 } 402 403 /** 404 * Change current SET object to be encoded as {@link DLSet}. 405 * This is part of Direct Length form serialization. 406 */ toDLObject()407 ASN1Primitive toDLObject() 408 { 409 ASN1Set derSet = new DLSet(); 410 411 derSet.set = this.set; 412 413 return derSet; 414 } 415 asn1Equals( ASN1Primitive o)416 boolean asn1Equals( 417 ASN1Primitive o) 418 { 419 if (!(o instanceof ASN1Set)) 420 { 421 return false; 422 } 423 424 ASN1Set other = (ASN1Set)o; 425 426 if (this.size() != other.size()) 427 { 428 return false; 429 } 430 431 Enumeration s1 = this.getObjects(); 432 Enumeration s2 = other.getObjects(); 433 434 while (s1.hasMoreElements()) 435 { 436 ASN1Encodable obj1 = getNext(s1); 437 ASN1Encodable obj2 = getNext(s2); 438 439 ASN1Primitive o1 = obj1.toASN1Primitive(); 440 ASN1Primitive o2 = obj2.toASN1Primitive(); 441 442 if (o1 == o2 || o1.equals(o2)) 443 { 444 continue; 445 } 446 447 return false; 448 } 449 450 return true; 451 } 452 getNext(Enumeration e)453 private ASN1Encodable getNext(Enumeration e) 454 { 455 ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); 456 457 // unfortunately null was allowed as a substitute for DER null 458 if (encObj == null) 459 { 460 return DERNull.INSTANCE; 461 } 462 463 return encObj; 464 } 465 466 /** 467 * return true if a <= b (arrays are assumed padded with zeros). 468 */ lessThanOrEqual( byte[] a, byte[] b)469 private boolean lessThanOrEqual( 470 byte[] a, 471 byte[] b) 472 { 473 int len = Math.min(a.length, b.length); 474 for (int i = 0; i != len; ++i) 475 { 476 if (a[i] != b[i]) 477 { 478 return (a[i] & 0xff) < (b[i] & 0xff); 479 } 480 } 481 return len == a.length; 482 } 483 getDEREncoded( ASN1Encodable obj)484 private byte[] getDEREncoded( 485 ASN1Encodable obj) 486 { 487 try 488 { 489 return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER); 490 } 491 catch (IOException e) 492 { 493 throw new IllegalArgumentException("cannot encode object added to SET"); 494 } 495 } 496 sort()497 protected void sort() 498 { 499 if (!isSorted) 500 { 501 isSorted = true; 502 if (set.size() > 1) 503 { 504 boolean swapped = true; 505 int lastSwap = set.size() - 1; 506 507 while (swapped) 508 { 509 int index = 0; 510 int swapIndex = 0; 511 byte[] a = getDEREncoded((ASN1Encodable)set.elementAt(0)); 512 513 swapped = false; 514 515 while (index != lastSwap) 516 { 517 byte[] b = getDEREncoded((ASN1Encodable)set.elementAt(index + 1)); 518 519 if (lessThanOrEqual(a, b)) 520 { 521 a = b; 522 } 523 else 524 { 525 Object o = set.elementAt(index); 526 527 set.setElementAt(set.elementAt(index + 1), index); 528 set.setElementAt(o, index + 1); 529 530 swapped = true; 531 swapIndex = index; 532 } 533 534 index++; 535 } 536 537 lastSwap = swapIndex; 538 } 539 } 540 } 541 } 542 isConstructed()543 boolean isConstructed() 544 { 545 return true; 546 } 547 encode(ASN1OutputStream out)548 abstract void encode(ASN1OutputStream out) 549 throws IOException; 550 toString()551 public String toString() 552 { 553 return set.toString(); 554 } 555 } 556