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