1 package org.bouncycastle.asn1.x509; 2 3 import java.util.Enumeration; 4 import java.util.Hashtable; 5 import java.util.Vector; 6 7 import org.bouncycastle.asn1.*; 8 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 9 import org.bouncycastle.util.encoders.Hex; 10 import org.bouncycastle.util.Strings; 11 12 /** 13 * <pre> 14 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName 15 * 16 * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue 17 * 18 * AttributeTypeAndValue ::= SEQUENCE { 19 * type OBJECT IDENTIFIER, 20 * value ANY } 21 * </pre> 22 */ 23 public class X509Name 24 extends ASN1Encodable 25 { 26 /** 27 * country code - StringType(SIZE(2)) 28 */ 29 public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6"); 30 31 /** 32 * organization - StringType(SIZE(1..64)) 33 */ 34 public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10"); 35 36 /** 37 * organizational unit name - StringType(SIZE(1..64)) 38 */ 39 public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11"); 40 41 /** 42 * Title 43 */ 44 public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12"); 45 46 /** 47 * common name - StringType(SIZE(1..64)) 48 */ 49 public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3"); 50 51 /** 52 * device serial number name - StringType(SIZE(1..64)) 53 */ 54 public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5"); 55 56 /** 57 * street - StringType(SIZE(1..64)) 58 */ 59 public static final DERObjectIdentifier STREET = new DERObjectIdentifier("2.5.4.9"); 60 61 /** 62 * device serial number name - StringType(SIZE(1..64)) 63 */ 64 public static final DERObjectIdentifier SERIALNUMBER = SN; 65 66 /** 67 * locality name - StringType(SIZE(1..64)) 68 */ 69 public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7"); 70 71 /** 72 * state, or province name - StringType(SIZE(1..64)) 73 */ 74 public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8"); 75 76 /** 77 * Naming attributes of type X520name 78 */ 79 public static final DERObjectIdentifier SURNAME = new DERObjectIdentifier("2.5.4.4"); 80 public static final DERObjectIdentifier GIVENNAME = new DERObjectIdentifier("2.5.4.42"); 81 public static final DERObjectIdentifier INITIALS = new DERObjectIdentifier("2.5.4.43"); 82 public static final DERObjectIdentifier GENERATION = new DERObjectIdentifier("2.5.4.44"); 83 public static final DERObjectIdentifier UNIQUE_IDENTIFIER = new DERObjectIdentifier("2.5.4.45"); 84 85 /** 86 * businessCategory - DirectoryString(SIZE(1..128) 87 */ 88 public static final DERObjectIdentifier BUSINESS_CATEGORY = new DERObjectIdentifier( 89 "2.5.4.15"); 90 91 /** 92 * postalCode - DirectoryString(SIZE(1..40) 93 */ 94 public static final DERObjectIdentifier POSTAL_CODE = new DERObjectIdentifier( 95 "2.5.4.17"); 96 97 /** 98 * dnQualifier - DirectoryString(SIZE(1..64) 99 */ 100 public static final DERObjectIdentifier DN_QUALIFIER = new DERObjectIdentifier( 101 "2.5.4.46"); 102 103 /** 104 * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) 105 */ 106 public static final DERObjectIdentifier PSEUDONYM = new DERObjectIdentifier( 107 "2.5.4.65"); 108 109 110 /** 111 * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z 112 */ 113 public static final DERObjectIdentifier DATE_OF_BIRTH = new DERObjectIdentifier( 114 "1.3.6.1.5.5.7.9.1"); 115 116 /** 117 * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) 118 */ 119 public static final DERObjectIdentifier PLACE_OF_BIRTH = new DERObjectIdentifier( 120 "1.3.6.1.5.5.7.9.2"); 121 122 /** 123 * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" 124 */ 125 public static final DERObjectIdentifier GENDER = new DERObjectIdentifier( 126 "1.3.6.1.5.5.7.9.3"); 127 128 /** 129 * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 130 * codes only 131 */ 132 public static final DERObjectIdentifier COUNTRY_OF_CITIZENSHIP = new DERObjectIdentifier( 133 "1.3.6.1.5.5.7.9.4"); 134 135 /** 136 * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166 137 * codes only 138 */ 139 public static final DERObjectIdentifier COUNTRY_OF_RESIDENCE = new DERObjectIdentifier( 140 "1.3.6.1.5.5.7.9.5"); 141 142 143 /** 144 * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) 145 */ 146 public static final DERObjectIdentifier NAME_AT_BIRTH = new DERObjectIdentifier("1.3.36.8.3.14"); 147 148 /** 149 * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF 150 * DirectoryString(SIZE(1..30)) 151 */ 152 public static final DERObjectIdentifier POSTAL_ADDRESS = new DERObjectIdentifier( 153 "2.5.4.16"); 154 155 /** 156 * Email address (RSA PKCS#9 extension) - IA5String. 157 * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. 158 */ 159 public static final DERObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress; 160 161 /** 162 * more from PKCS#9 163 */ 164 public static final DERObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName; 165 public static final DERObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress; 166 167 /** 168 * email address in Verisign certificates 169 */ 170 public static final DERObjectIdentifier E = EmailAddress; 171 172 /* 173 * others... 174 */ 175 public static final DERObjectIdentifier DC = new DERObjectIdentifier("0.9.2342.19200300.100.1.25"); 176 177 /** 178 * LDAP User id. 179 */ 180 public static final DERObjectIdentifier UID = new DERObjectIdentifier("0.9.2342.19200300.100.1.1"); 181 182 /** 183 * look up table translating OID values into their common symbols - this static is scheduled for deletion 184 */ 185 public static Hashtable OIDLookUp = new Hashtable(); 186 187 /** 188 * determines whether or not strings should be processed and printed 189 * from back to front. 190 */ 191 public static boolean DefaultReverse = false; 192 193 /** 194 * default look up table translating OID values into their common symbols following 195 * the convention in RFC 2253 with a few extras 196 */ 197 public static Hashtable DefaultSymbols = OIDLookUp; 198 199 /** 200 * look up table translating OID values into their common symbols following the convention in RFC 2253 201 * 202 */ 203 public static Hashtable RFC2253Symbols = new Hashtable(); 204 205 /** 206 * look up table translating OID values into their common symbols following the convention in RFC 1779 207 * 208 */ 209 public static Hashtable RFC1779Symbols = new Hashtable(); 210 211 /** 212 * look up table translating string values into their OIDS - 213 * this static is scheduled for deletion 214 */ 215 public static Hashtable SymbolLookUp = new Hashtable(); 216 217 /** 218 * look up table translating common symbols into their OIDS. 219 */ 220 public static Hashtable DefaultLookUp = SymbolLookUp; 221 222 // BEGIN android-removed 223 //private static final Boolean TRUE = new Boolean(true); // for J2ME compatibility 224 //private static final Boolean FALSE = new Boolean(false); 225 // END android-removed 226 227 static 228 { 229 DefaultSymbols.put(C, "C"); 230 DefaultSymbols.put(O, "O"); 231 DefaultSymbols.put(T, "T"); 232 DefaultSymbols.put(OU, "OU"); 233 DefaultSymbols.put(CN, "CN"); 234 DefaultSymbols.put(L, "L"); 235 DefaultSymbols.put(ST, "ST"); 236 DefaultSymbols.put(SN, "SN"); 237 DefaultSymbols.put(EmailAddress, "E"); 238 DefaultSymbols.put(DC, "DC"); 239 DefaultSymbols.put(UID, "UID"); 240 DefaultSymbols.put(STREET, "STREET"); 241 DefaultSymbols.put(SURNAME, "SURNAME"); 242 DefaultSymbols.put(GIVENNAME, "GIVENNAME"); 243 DefaultSymbols.put(INITIALS, "INITIALS"); 244 DefaultSymbols.put(GENERATION, "GENERATION"); 245 DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress"); 246 DefaultSymbols.put(UnstructuredName, "unstructuredName"); 247 DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier"); 248 DefaultSymbols.put(DN_QUALIFIER, "DN"); 249 DefaultSymbols.put(PSEUDONYM, "Pseudonym"); 250 DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress"); 251 DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth"); 252 DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship"); 253 DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence"); 254 DefaultSymbols.put(GENDER, "Gender"); 255 DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth"); 256 DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth"); 257 DefaultSymbols.put(POSTAL_CODE, "PostalCode"); 258 DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory"); 259 260 RFC2253Symbols.put(C, "C"); 261 RFC2253Symbols.put(O, "O"); 262 RFC2253Symbols.put(OU, "OU"); 263 RFC2253Symbols.put(CN, "CN"); 264 RFC2253Symbols.put(L, "L"); 265 RFC2253Symbols.put(ST, "ST"); 266 RFC2253Symbols.put(STREET, "STREET"); 267 RFC2253Symbols.put(DC, "DC"); 268 RFC2253Symbols.put(UID, "UID"); 269 270 RFC1779Symbols.put(C, "C"); 271 RFC1779Symbols.put(O, "O"); 272 RFC1779Symbols.put(OU, "OU"); 273 RFC1779Symbols.put(CN, "CN"); 274 RFC1779Symbols.put(L, "L"); 275 RFC1779Symbols.put(ST, "ST"); 276 RFC1779Symbols.put(STREET, "STREET"); 277 278 DefaultLookUp.put("c", C); 279 DefaultLookUp.put("o", O); 280 DefaultLookUp.put("t", T); 281 DefaultLookUp.put("ou", OU); 282 DefaultLookUp.put("cn", CN); 283 DefaultLookUp.put("l", L); 284 DefaultLookUp.put("st", ST); 285 DefaultLookUp.put("sn", SN); 286 DefaultLookUp.put("serialnumber", SN); 287 DefaultLookUp.put("street", STREET); 288 DefaultLookUp.put("emailaddress", E); 289 DefaultLookUp.put("dc", DC); 290 DefaultLookUp.put("e", E); 291 DefaultLookUp.put("uid", UID); 292 DefaultLookUp.put("surname", SURNAME); 293 DefaultLookUp.put("givenname", GIVENNAME); 294 DefaultLookUp.put("initials", INITIALS); 295 DefaultLookUp.put("generation", GENERATION); 296 DefaultLookUp.put("unstructuredaddress", UnstructuredAddress); 297 DefaultLookUp.put("unstructuredname", UnstructuredName); 298 DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER); 299 DefaultLookUp.put("dn", DN_QUALIFIER); 300 DefaultLookUp.put("pseudonym", PSEUDONYM); 301 DefaultLookUp.put("postaladdress", POSTAL_ADDRESS); 302 DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH); 303 DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP); 304 DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE); 305 DefaultLookUp.put("gender", GENDER); 306 DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH); 307 DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH); 308 DefaultLookUp.put("postalcode", POSTAL_CODE); 309 DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY); 310 } 311 312 private X509NameEntryConverter converter = null; 313 // BEGIN android-changed 314 private X509NameElementList elems = new X509NameElementList(); 315 // END android-changed 316 317 private ASN1Sequence seq; 318 319 /** 320 * Return a X509Name based on the passed in tagged object. 321 * 322 * @param obj tag object holding name. 323 * @param explicit true if explicitly tagged false otherwise. 324 * @return the X509Name 325 */ 326 public static X509Name getInstance( 327 ASN1TaggedObject obj, 328 boolean explicit) 329 { 330 return getInstance(ASN1Sequence.getInstance(obj, explicit)); 331 } 332 333 public static X509Name getInstance( 334 Object obj) 335 { 336 if (obj == null || obj instanceof X509Name) 337 { 338 return (X509Name)obj; 339 } 340 else if (obj instanceof ASN1Sequence) 341 { 342 return new X509Name((ASN1Sequence)obj); 343 } 344 345 throw new IllegalArgumentException("unknown object in factory \"" + obj.getClass().getName()+"\""); 346 } 347 348 /** 349 * Constructor from ASN1Sequence 350 * 351 * the principal will be a list of constructed sets, each containing an (OID, String) pair. 352 */ 353 public X509Name( 354 ASN1Sequence seq) 355 { 356 this.seq = seq; 357 358 Enumeration e = seq.getObjects(); 359 360 while (e.hasMoreElements()) 361 { 362 ASN1Set set = (ASN1Set)e.nextElement(); 363 364 for (int i = 0; i < set.size(); i++) 365 { 366 // BEGIN android-changed 367 ASN1Sequence s = (ASN1Sequence)set.getObjectAt(i); 368 369 DERObjectIdentifier key = 370 (DERObjectIdentifier) s.getObjectAt(0); 371 DEREncodable value = s.getObjectAt(1); 372 String valueStr; 373 374 if (value instanceof DERString) 375 { 376 valueStr = ((DERString)value).getString(); 377 } 378 else 379 { 380 valueStr = "#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded())); 381 } 382 383 /* 384 * The added flag set to (i != 0), to allow earlier JDK 385 * compatibility. 386 */ 387 elems.add(key, valueStr, i != 0); 388 // END android-changed 389 } 390 } 391 } 392 393 /** 394 * constructor from a table of attributes. 395 * <p> 396 * it's is assumed the table contains OID/String pairs, and the contents 397 * of the table are copied into an internal table as part of the 398 * construction process. 399 * <p> 400 * <b>Note:</b> if the name you are trying to generate should be 401 * following a specific ordering, you should use the constructor 402 * with the ordering specified below. 403 */ 404 public X509Name( 405 Hashtable attributes) 406 { 407 this(null, attributes); 408 } 409 410 /** 411 * Constructor from a table of attributes with ordering. 412 * <p> 413 * it's is assumed the table contains OID/String pairs, and the contents 414 * of the table are copied into an internal table as part of the 415 * construction process. The ordering vector should contain the OIDs 416 * in the order they are meant to be encoded or printed in toString. 417 */ 418 public X509Name( 419 Vector ordering, 420 Hashtable attributes) 421 { 422 this(ordering, attributes, new X509DefaultEntryConverter()); 423 } 424 425 /** 426 * Constructor from a table of attributes with ordering. 427 * <p> 428 * it's is assumed the table contains OID/String pairs, and the contents 429 * of the table are copied into an internal table as part of the 430 * construction process. The ordering vector should contain the OIDs 431 * in the order they are meant to be encoded or printed in toString. 432 * <p> 433 * The passed in converter will be used to convert the strings into their 434 * ASN.1 counterparts. 435 */ 436 public X509Name( 437 Vector ordering, 438 Hashtable attributes, 439 X509DefaultEntryConverter converter) 440 { 441 // BEGIN android-changed 442 DERObjectIdentifier problem = null; 443 this.converter = converter; 444 445 if (ordering != null) 446 { 447 for (int i = 0; i != ordering.size(); i++) 448 { 449 DERObjectIdentifier key = 450 (DERObjectIdentifier) ordering.elementAt(i); 451 String value = (String) attributes.get(key); 452 if (value == null) 453 { 454 problem = key; 455 break; 456 } 457 elems.add(key, value); 458 } 459 } 460 else 461 { 462 Enumeration e = attributes.keys(); 463 464 while (e.hasMoreElements()) 465 { 466 DERObjectIdentifier key = 467 (DERObjectIdentifier) e.nextElement(); 468 String value = (String) attributes.get(key); 469 if (value == null) 470 { 471 problem = key; 472 break; 473 } 474 elems.add(key, value); 475 } 476 } 477 478 if (problem != null) 479 { 480 throw new IllegalArgumentException("No attribute for object id - " + problem.getId() + " - passed to distinguished name"); 481 } 482 // END android-changed 483 } 484 485 /** 486 * Takes two vectors one of the oids and the other of the values. 487 */ 488 public X509Name( 489 Vector oids, 490 Vector values) 491 { 492 this(oids, values, new X509DefaultEntryConverter()); 493 } 494 495 /** 496 * Takes two vectors one of the oids and the other of the values. 497 * <p> 498 * The passed in converter will be used to convert the strings into their 499 * ASN.1 counterparts. 500 */ 501 public X509Name( 502 Vector oids, 503 Vector values, 504 X509NameEntryConverter converter) 505 { 506 this.converter = converter; 507 508 if (oids.size() != values.size()) 509 { 510 throw new IllegalArgumentException("oids vector must be same length as values."); 511 } 512 513 for (int i = 0; i < oids.size(); i++) 514 { 515 // BEGIN android-changed 516 elems.add((DERObjectIdentifier) oids.elementAt(i), 517 (String) values.elementAt(i)); 518 // END android-changed 519 } 520 } 521 522 /** 523 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 524 * some such, converting it into an ordered set of name attributes. 525 */ 526 public X509Name( 527 String dirName) 528 { 529 this(DefaultReverse, DefaultLookUp, dirName); 530 } 531 532 /** 533 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 534 * some such, converting it into an ordered set of name attributes with each 535 * string value being converted to its associated ASN.1 type using the passed 536 * in converter. 537 */ 538 public X509Name( 539 String dirName, 540 X509NameEntryConverter converter) 541 { 542 this(DefaultReverse, DefaultLookUp, dirName, converter); 543 } 544 545 /** 546 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 547 * some such, converting it into an ordered set of name attributes. If reverse 548 * is true, create the encoded version of the sequence starting from the 549 * last element in the string. 550 */ 551 public X509Name( 552 boolean reverse, 553 String dirName) 554 { 555 this(reverse, DefaultLookUp, dirName); 556 } 557 558 /** 559 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 560 * some such, converting it into an ordered set of name attributes with each 561 * string value being converted to its associated ASN.1 type using the passed 562 * in converter. If reverse is true the ASN.1 sequence representing the DN will 563 * be built by starting at the end of the string, rather than the start. 564 */ 565 public X509Name( 566 boolean reverse, 567 String dirName, 568 X509NameEntryConverter converter) 569 { 570 this(reverse, DefaultLookUp, dirName, converter); 571 } 572 573 /** 574 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 575 * some such, converting it into an ordered set of name attributes. lookUp 576 * should provide a table of lookups, indexed by lowercase only strings and 577 * yielding a DERObjectIdentifier, other than that OID. and numeric oids 578 * will be processed automatically. 579 * <br> 580 * If reverse is true, create the encoded version of the sequence 581 * starting from the last element in the string. 582 * @param reverse true if we should start scanning from the end (RFC 2553). 583 * @param lookUp table of names and their oids. 584 * @param dirName the X.500 string to be parsed. 585 */ 586 public X509Name( 587 boolean reverse, 588 Hashtable lookUp, 589 String dirName) 590 { 591 this(reverse, lookUp, dirName, new X509DefaultEntryConverter()); 592 } 593 594 private DERObjectIdentifier decodeOID( 595 String name, 596 Hashtable lookUp) 597 { 598 if (Strings.toUpperCase(name).startsWith("OID.")) 599 { 600 return new DERObjectIdentifier(name.substring(4)); 601 } 602 else if (name.charAt(0) >= '0' && name.charAt(0) <= '9') 603 { 604 return new DERObjectIdentifier(name); 605 } 606 607 DERObjectIdentifier oid = (DERObjectIdentifier)lookUp.get(Strings.toLowerCase(name)); 608 if (oid == null) 609 { 610 throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name"); 611 } 612 613 return oid; 614 } 615 616 /** 617 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 618 * some such, converting it into an ordered set of name attributes. lookUp 619 * should provide a table of lookups, indexed by lowercase only strings and 620 * yielding a DERObjectIdentifier, other than that OID. and numeric oids 621 * will be processed automatically. The passed in converter is used to convert the 622 * string values to the right of each equals sign to their ASN.1 counterparts. 623 * <br> 624 * @param reverse true if we should start scanning from the end, false otherwise. 625 * @param lookUp table of names and oids. 626 * @param dirName the string dirName 627 * @param converter the converter to convert string values into their ASN.1 equivalents 628 */ 629 public X509Name( 630 boolean reverse, 631 Hashtable lookUp, 632 String dirName, 633 X509NameEntryConverter converter) 634 { 635 this.converter = converter; 636 X509NameTokenizer nTok = new X509NameTokenizer(dirName); 637 638 while (nTok.hasMoreTokens()) 639 { 640 String token = nTok.nextToken(); 641 int index = token.indexOf('='); 642 643 if (index == -1) 644 { 645 throw new IllegalArgumentException("badly formatted directory string"); 646 } 647 648 String name = token.substring(0, index); 649 String value = token.substring(index + 1); 650 DERObjectIdentifier oid = decodeOID(name, lookUp); 651 652 if (value.indexOf('+') > 0) 653 { 654 X509NameTokenizer vTok = new X509NameTokenizer(value, '+'); 655 656 // BEGIN android-changed 657 elems.add(oid, vTok.nextToken()); 658 // END android-changed 659 660 while (vTok.hasMoreTokens()) 661 { 662 String sv = vTok.nextToken(); 663 int ndx = sv.indexOf('='); 664 665 String nm = sv.substring(0, ndx); 666 String vl = sv.substring(ndx + 1); 667 // BEGIN android-changed 668 elems.add(decodeOID(nm, lookUp), vl, true); 669 // END android-changed 670 } 671 } 672 else 673 { 674 // BEGIN android-changed 675 elems.add(oid, value); 676 // END android-changed 677 } 678 } 679 680 if (reverse) 681 { 682 // BEGIN android-changed 683 elems = elems.reverse(); 684 // END android-changed 685 } 686 } 687 688 /** 689 * return a vector of the oids in the name, in the order they were found. 690 */ 691 public Vector getOIDs() 692 { 693 // BEGIN android-changed 694 Vector v = new Vector(); 695 int size = elems.size(); 696 697 for (int i = 0; i < size; i++) 698 { 699 v.addElement(elems.getKey(i)); 700 } 701 702 return v; 703 // END android-changed 704 } 705 706 /** 707 * return a vector of the values found in the name, in the order they 708 * were found. 709 */ 710 public Vector getValues() 711 { 712 // BEGIN android-changed 713 Vector v = new Vector(); 714 int size = elems.size(); 715 716 for (int i = 0; i < size; i++) 717 { 718 v.addElement(elems.getValue(i)); 719 } 720 721 return v; 722 // END android-changed 723 } 724 725 public DERObject toASN1Object() 726 { 727 if (seq == null) 728 { 729 // BEGIN android-changed 730 ASN1EncodableVector vec = new ASN1EncodableVector(); 731 ASN1EncodableVector sVec = new ASN1EncodableVector(); 732 DERObjectIdentifier lstOid = null; 733 int size = elems.size(); 734 735 for (int i = 0; i != size; i++) 736 { 737 ASN1EncodableVector v = new ASN1EncodableVector(); 738 DERObjectIdentifier oid = elems.getKey(i); 739 740 v.add(oid); 741 742 String str = elems.getValue(i); 743 744 v.add(converter.getConvertedValue(oid, str)); 745 746 if (lstOid == null || elems.getAdded(i)) 747 { 748 sVec.add(new DERSequence(v)); 749 } 750 else 751 { 752 vec.add(new DERSet(sVec)); 753 sVec = new ASN1EncodableVector(); 754 755 sVec.add(new DERSequence(v)); 756 } 757 758 lstOid = oid; 759 } 760 761 vec.add(new DERSet(sVec)); 762 763 seq = new DERSequence(vec); 764 // END android-changed 765 } 766 767 return seq; 768 } 769 770 /** 771 * @param inOrder if true the order of both X509 names must be the same, 772 * as well as the values associated with each element. 773 */ 774 public boolean equals(Object _obj, boolean inOrder) 775 { 776 if (_obj == this) 777 { 778 return true; 779 } 780 781 if (!inOrder) 782 { 783 return this.equals(_obj); 784 } 785 786 if (!(_obj instanceof X509Name)) 787 { 788 return false; 789 } 790 791 X509Name _oxn = (X509Name)_obj; 792 // BEGIN android-changed 793 int _orderingSize = elems.size(); 794 795 if (_orderingSize != _oxn.elems.size()) 796 { 797 return false; 798 } 799 // END android-changed 800 801 for(int i = 0; i < _orderingSize; i++) 802 { 803 // BEGIN android-changed 804 String _oid = elems.getKey(i).getId(); 805 String _val = elems.getValue(i); 806 807 String _oOID = _oxn.elems.getKey(i).getId(); 808 String _oVal = _oxn.elems.getValue(i); 809 // BEGIN android-changed 810 811 if (_oid.equals(_oOID)) 812 { 813 _val = Strings.toLowerCase(_val.trim()); 814 _oVal = Strings.toLowerCase(_oVal.trim()); 815 if (_val.equals(_oVal)) 816 { 817 continue; 818 } 819 else 820 { 821 StringBuffer v1 = new StringBuffer(); 822 StringBuffer v2 = new StringBuffer(); 823 824 if (_val.length() != 0) 825 { 826 char c1 = _val.charAt(0); 827 828 v1.append(c1); 829 830 for (int k = 1; k < _val.length(); k++) 831 { 832 char c2 = _val.charAt(k); 833 if (!(c1 == ' ' && c2 == ' ')) 834 { 835 v1.append(c2); 836 } 837 c1 = c2; 838 } 839 } 840 841 if (_oVal.length() != 0) 842 { 843 char c1 = _oVal.charAt(0); 844 845 v2.append(c1); 846 847 for (int k = 1; k < _oVal.length(); k++) 848 { 849 char c2 = _oVal.charAt(k); 850 if (!(c1 == ' ' && c2 == ' ')) 851 { 852 v2.append(c2); 853 } 854 c1 = c2; 855 } 856 } 857 858 if (!v1.toString().equals(v2.toString())) 859 { 860 return false; 861 } 862 } 863 } 864 else 865 { 866 return false; 867 } 868 } 869 870 return true; 871 } 872 873 /** 874 * test for equality - note: case is ignored. 875 */ 876 public boolean equals(Object _obj) 877 { 878 if (_obj == this) 879 { 880 return true; 881 } 882 883 if (!(_obj instanceof X509Name || _obj instanceof ASN1Sequence)) 884 { 885 return false; 886 } 887 888 DERObject derO = ((DEREncodable)_obj).getDERObject(); 889 890 if (this.getDERObject().equals(derO)) 891 { 892 return true; 893 } 894 895 if (!(_obj instanceof X509Name)) 896 { 897 return false; 898 } 899 900 X509Name _oxn = (X509Name)_obj; 901 902 // BEGIN android-changed 903 int _orderingSize = elems.size(); 904 905 if (_orderingSize != _oxn.elems.size()) 906 { 907 return false; 908 } 909 // END android-changed 910 911 boolean[] _indexes = new boolean[_orderingSize]; 912 913 for(int i = 0; i < _orderingSize; i++) 914 { 915 boolean _found = false; 916 // BEGIN android-changed 917 String _oid = elems.getKey(i).getId(); 918 String _val = elems.getValue(i); 919 // END android-changed 920 921 for(int j = 0; j < _orderingSize; j++) 922 { 923 if (_indexes[j]) 924 { 925 continue; 926 } 927 928 // BEGIN android-changed 929 String _oOID = elems.getKey(j).getId(); 930 String _oVal = _oxn.elems.getValue(j); 931 // END android-changed 932 933 if (_oid.equals(_oOID)) 934 { 935 _val = Strings.toLowerCase(_val.trim()); 936 _oVal = Strings.toLowerCase(_oVal.trim()); 937 if (_val.equals(_oVal)) 938 { 939 _indexes[j] = true; 940 _found = true; 941 break; 942 } 943 else 944 { 945 StringBuffer v1 = new StringBuffer(); 946 StringBuffer v2 = new StringBuffer(); 947 948 if (_val.length() != 0) 949 { 950 char c1 = _val.charAt(0); 951 952 v1.append(c1); 953 954 for (int k = 1; k < _val.length(); k++) 955 { 956 char c2 = _val.charAt(k); 957 if (!(c1 == ' ' && c2 == ' ')) 958 { 959 v1.append(c2); 960 } 961 c1 = c2; 962 } 963 } 964 965 if (_oVal.length() != 0) 966 { 967 char c1 = _oVal.charAt(0); 968 969 v2.append(c1); 970 971 for (int k = 1; k < _oVal.length(); k++) 972 { 973 char c2 = _oVal.charAt(k); 974 if (!(c1 == ' ' && c2 == ' ')) 975 { 976 v2.append(c2); 977 } 978 c1 = c2; 979 } 980 } 981 982 if (v1.toString().equals(v2.toString())) 983 { 984 _indexes[j] = true; 985 _found = true; 986 break; 987 } 988 } 989 } 990 } 991 992 if(!_found) 993 { 994 return false; 995 } 996 } 997 998 return true; 999 } 1000 1001 public int hashCode() 1002 { 1003 ASN1Sequence seq = (ASN1Sequence)this.getDERObject(); 1004 Enumeration e = seq.getObjects(); 1005 int hashCode = 0; 1006 1007 while (e.hasMoreElements()) 1008 { 1009 hashCode ^= e.nextElement().hashCode(); 1010 } 1011 1012 return hashCode; 1013 } 1014 1015 private void appendValue( 1016 StringBuffer buf, 1017 Hashtable oidSymbols, 1018 DERObjectIdentifier oid, 1019 String value) 1020 { 1021 String sym = (String)oidSymbols.get(oid); 1022 1023 if (sym != null) 1024 { 1025 buf.append(sym); 1026 } 1027 else 1028 { 1029 buf.append(oid.getId()); 1030 } 1031 1032 buf.append('='); 1033 1034 int index = buf.length(); 1035 1036 buf.append(value); 1037 1038 int end = buf.length(); 1039 1040 while (index != end) 1041 { 1042 if ((buf.charAt(index) == ',') 1043 || (buf.charAt(index) == '"') 1044 || (buf.charAt(index) == '\\') 1045 || (buf.charAt(index) == '+') 1046 || (buf.charAt(index) == '<') 1047 || (buf.charAt(index) == '>') 1048 || (buf.charAt(index) == ';')) 1049 { 1050 buf.insert(index, "\\"); 1051 index++; 1052 end++; 1053 } 1054 1055 index++; 1056 } 1057 } 1058 1059 /** 1060 * convert the structure to a string - if reverse is true the 1061 * oids and values are listed out starting with the last element 1062 * in the sequence (ala RFC 2253), otherwise the string will begin 1063 * with the first element of the structure. If no string definition 1064 * for the oid is found in oidSymbols the string value of the oid is 1065 * added. Two standard symbol tables are provided DefaultSymbols, and 1066 * RFC2253Symbols as part of this class. 1067 * 1068 * @param reverse if true start at the end of the sequence and work back. 1069 * @param oidSymbols look up table strings for oids. 1070 */ 1071 public String toString( 1072 boolean reverse, 1073 Hashtable oidSymbols) 1074 { 1075 StringBuffer buf = new StringBuffer(); 1076 boolean first = true; 1077 1078 if (reverse) 1079 { 1080 // BEGIN android-changed 1081 for (int i = elems.size() - 1; i >= 0; i--) 1082 { 1083 if (first) 1084 { 1085 first = false; 1086 } 1087 else 1088 { 1089 if (elems.getAdded(i + 1)) 1090 { 1091 buf.append('+'); 1092 } 1093 else 1094 { 1095 buf.append(','); 1096 } 1097 } 1098 1099 appendValue(buf, oidSymbols, 1100 elems.getKey(i), 1101 elems.getValue(i)); 1102 } 1103 // END android-changed 1104 } 1105 else 1106 { 1107 // BEGIN android-changed 1108 for (int i = 0; i < elems.size(); i++) 1109 { 1110 if (first) 1111 { 1112 first = false; 1113 } 1114 else 1115 { 1116 if (elems.getAdded(i)) 1117 { 1118 buf.append('+'); 1119 } 1120 else 1121 { 1122 buf.append(','); 1123 } 1124 } 1125 1126 appendValue(buf, oidSymbols, 1127 elems.getKey(i), 1128 elems.getValue(i)); 1129 } 1130 // END android-changed 1131 } 1132 1133 return buf.toString(); 1134 } 1135 1136 private String bytesToString( 1137 byte[] data) 1138 { 1139 char[] cs = new char[data.length]; 1140 1141 for (int i = 0; i != cs.length; i++) 1142 { 1143 cs[i] = (char)(data[i] & 0xff); 1144 } 1145 1146 return new String(cs); 1147 } 1148 1149 public String toString() 1150 { 1151 return toString(DefaultReverse, DefaultSymbols); 1152 } 1153 } 1154