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