1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package sun.security.x509; 28 29 import java.lang.reflect.*; 30 import java.io.IOException; 31 import java.io.StringReader; 32 import java.security.PrivilegedExceptionAction; 33 import java.security.AccessController; 34 import java.security.Principal; 35 import java.util.*; 36 37 import sun.security.util.*; 38 import sun.security.pkcs.PKCS9Attribute; 39 import javax.security.auth.x500.X500Principal; 40 41 /** 42 * Note: As of 1.4, the public class, 43 * javax.security.auth.x500.X500Principal, 44 * should be used when parsing, generating, and comparing X.500 DNs. 45 * This class contains other useful methods for checking name constraints 46 * and retrieving DNs by keyword. 47 * 48 * <p> X.500 names are used to identify entities, such as those which are 49 * identified by X.509 certificates. They are world-wide, hierarchical, 50 * and descriptive. Entities can be identified by attributes, and in 51 * some systems can be searched for according to those attributes. 52 * <p> 53 * The ASN.1 for this is: 54 * <pre> 55 * GeneralName ::= CHOICE { 56 * .... 57 * directoryName [4] Name, 58 * .... 59 * Name ::= CHOICE { 60 * RDNSequence } 61 * 62 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName 63 * 64 * RelativeDistinguishedName ::= 65 * SET OF AttributeTypeAndValue 66 * 67 * AttributeTypeAndValue ::= SEQUENCE { 68 * type AttributeType, 69 * value AttributeValue } 70 * 71 * AttributeType ::= OBJECT IDENTIFIER 72 * 73 * AttributeValue ::= ANY DEFINED BY AttributeType 74 * .... 75 * DirectoryString ::= CHOICE { 76 * teletexString TeletexString (SIZE (1..MAX)), 77 * printableString PrintableString (SIZE (1..MAX)), 78 * universalString UniversalString (SIZE (1..MAX)), 79 * utf8String UTF8String (SIZE (1.. MAX)), 80 * bmpString BMPString (SIZE (1..MAX)) } 81 * </pre> 82 * <p> 83 * This specification requires only a subset of the name comparison 84 * functionality specified in the X.500 series of specifications. The 85 * requirements for conforming implementations are as follows: 86 * <ol TYPE=a> 87 * <li>attribute values encoded in different types (e.g., 88 * PrintableString and BMPString) may be assumed to represent 89 * different strings; 90 * <p> 91 * <li>attribute values in types other than PrintableString are case 92 * sensitive (this permits matching of attribute values as binary 93 * objects); 94 * <p> 95 * <li>attribute values in PrintableString are not case sensitive 96 * (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and 97 * <p> 98 * <li>attribute values in PrintableString are compared after 99 * removing leading and trailing white space and converting internal 100 * substrings of one or more consecutive white space characters to a 101 * single space. 102 * </ol> 103 * <p> 104 * These name comparison rules permit a certificate user to validate 105 * certificates issued using languages or encodings unfamiliar to the 106 * certificate user. 107 * <p> 108 * In addition, implementations of this specification MAY use these 109 * comparison rules to process unfamiliar attribute types for name 110 * chaining. This allows implementations to process certificates with 111 * unfamiliar attributes in the issuer name. 112 * <p> 113 * Note that the comparison rules defined in the X.500 series of 114 * specifications indicate that the character sets used to encode data 115 * in distinguished names are irrelevant. The characters themselves are 116 * compared without regard to encoding. Implementations of the profile 117 * are permitted to use the comparison algorithm defined in the X.500 118 * series. Such an implementation will recognize a superset of name 119 * matches recognized by the algorithm specified above. 120 * <p> 121 * Note that instances of this class are immutable. 122 * 123 * @author David Brownell 124 * @author Amit Kapoor 125 * @author Hemma Prafullchandra 126 * @see GeneralName 127 * @see GeneralNames 128 * @see GeneralNameInterface 129 */ 130 131 public class X500Name implements GeneralNameInterface, Principal { 132 133 private String dn; // roughly RFC 1779 DN, or null 134 private String rfc1779Dn; // RFC 1779 compliant DN, or null 135 private String rfc2253Dn; // RFC 2253 DN, or null 136 private String canonicalDn; // canonical RFC 2253 DN or null 137 private RDN[] names; // RDNs (never null) 138 private X500Principal x500Principal; 139 private byte[] encoded; 140 141 // cached immutable list of the RDNs and all the AVAs 142 private volatile List<RDN> rdnList; 143 private volatile List<AVA> allAvaList; 144 145 /** 146 * Constructs a name from a conventionally formatted string, such 147 * as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US". 148 * (RFC 1779 or RFC 2253 style). 149 * 150 * @param DN X.500 Distinguished Name 151 */ 152 public X500Name(String dname) throws IOException { 153 this(dname, Collections.<String, String>emptyMap()); 154 } 155 156 /** 157 * Constructs a name from a conventionally formatted string, such 158 * as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US". 159 * (RFC 1779 or RFC 2253 style). 160 * 161 * @param DN X.500 Distinguished Name 162 * @param keywordMap an additional keyword/OID map 163 */ 164 public X500Name(String dname, Map<String, String> keywordMap) 165 throws IOException { 166 parseDN(dname, keywordMap); 167 } 168 169 /** 170 * Constructs a name from a string formatted according to format. 171 * Currently, the formats DEFAULT and RFC2253 are supported. 172 * DEFAULT is the default format used by the X500Name(String) 173 * constructor. RFC2253 is format strictly according to RFC2253 174 * without extensions. 175 * 176 * @param DN X.500 Distinguished Name 177 */ 178 public X500Name(String dname, String format) throws IOException { 179 if (dname == null) { 180 throw new NullPointerException("Name must not be null"); 181 } 182 if (format.equalsIgnoreCase("RFC2253")) { 183 parseRFC2253DN(dname); 184 } else if (format.equalsIgnoreCase("DEFAULT")) { 185 parseDN(dname, Collections.<String, String>emptyMap()); 186 } else { 187 throw new IOException("Unsupported format " + format); 188 } 189 } 190 191 /** 192 * Constructs a name from fields common in enterprise application 193 * environments. 194 * 195 * <P><EM><STRONG>NOTE:</STRONG> The behaviour when any of 196 * these strings contain characters outside the ASCII range 197 * is unspecified in currently relevant standards.</EM> 198 * 199 * @param commonName common name of a person, e.g. "Vivette Davis" 200 * @param organizationUnit small organization name, e.g. "Purchasing" 201 * @param organizationName large organization name, e.g. "Onizuka, Inc." 202 * @param country two letter country code, e.g. "CH" 203 */ 204 public X500Name(String commonName, String organizationUnit, 205 String organizationName, String country) 206 throws IOException { 207 names = new RDN[4]; 208 /* 209 * NOTE: it's only on output that little-endian 210 * ordering is used. 211 */ 212 names[3] = new RDN(1); 213 names[3].assertion[0] = new AVA(commonName_oid, 214 new DerValue(commonName)); 215 names[2] = new RDN(1); 216 names[2].assertion[0] = new AVA(orgUnitName_oid, 217 new DerValue(organizationUnit)); 218 names[1] = new RDN(1); 219 names[1].assertion[0] = new AVA(orgName_oid, 220 new DerValue(organizationName)); 221 names[0] = new RDN(1); 222 names[0].assertion[0] = new AVA(countryName_oid, 223 new DerValue(country)); 224 } 225 226 /** 227 * Constructs a name from fields common in Internet application 228 * environments. 229 * 230 * <P><EM><STRONG>NOTE:</STRONG> The behaviour when any of 231 * these strings contain characters outside the ASCII range 232 * is unspecified in currently relevant standards.</EM> 233 * 234 * @param commonName common name of a person, e.g. "Vivette Davis" 235 * @param organizationUnit small organization name, e.g. "Purchasing" 236 * @param organizationName large organization name, e.g. "Onizuka, Inc." 237 * @param localityName locality (city) name, e.g. "Palo Alto" 238 * @param stateName state name, e.g. "California" 239 * @param country two letter country code, e.g. "CH" 240 */ 241 public X500Name(String commonName, String organizationUnit, 242 String organizationName, String localityName, 243 String stateName, String country) 244 throws IOException { 245 names = new RDN[6]; 246 /* 247 * NOTE: it's only on output that little-endian 248 * ordering is used. 249 */ 250 names[5] = new RDN(1); 251 names[5].assertion[0] = new AVA(commonName_oid, 252 new DerValue(commonName)); 253 names[4] = new RDN(1); 254 names[4].assertion[0] = new AVA(orgUnitName_oid, 255 new DerValue(organizationUnit)); 256 names[3] = new RDN(1); 257 names[3].assertion[0] = new AVA(orgName_oid, 258 new DerValue(organizationName)); 259 names[2] = new RDN(1); 260 names[2].assertion[0] = new AVA(localityName_oid, 261 new DerValue(localityName)); 262 names[1] = new RDN(1); 263 names[1].assertion[0] = new AVA(stateName_oid, 264 new DerValue(stateName)); 265 names[0] = new RDN(1); 266 names[0].assertion[0] = new AVA(countryName_oid, 267 new DerValue(country)); 268 } 269 270 /** 271 * Constructs a name from an array of relative distinguished names 272 * 273 * @param rdnArray array of relative distinguished names 274 * @throws IOException on error 275 */ 276 public X500Name(RDN[] rdnArray) throws IOException { 277 if (rdnArray == null) { 278 names = new RDN[0]; 279 } else { 280 names = rdnArray.clone(); 281 for (int i = 0; i < names.length; i++) { 282 if (names[i] == null) { 283 throw new IOException("Cannot create an X500Name"); 284 } 285 } 286 } 287 } 288 289 /** 290 * Constructs a name from an ASN.1 encoded value. The encoding 291 * of the name in the stream uses DER (a BER/1 subset). 292 * 293 * @param value a DER-encoded value holding an X.500 name. 294 */ 295 public X500Name(DerValue value) throws IOException { 296 //Note that toDerInputStream uses only the buffer (data) and not 297 //the tag, so an empty SEQUENCE (OF) will yield an empty DerInputStream 298 this(value.toDerInputStream()); 299 } 300 301 /** 302 * Constructs a name from an ASN.1 encoded input stream. The encoding 303 * of the name in the stream uses DER (a BER/1 subset). 304 * 305 * @param in DER-encoded data holding an X.500 name. 306 */ 307 public X500Name(DerInputStream in) throws IOException { 308 parseDER(in); 309 } 310 311 /** 312 * Constructs a name from an ASN.1 encoded byte array. 313 * 314 * @param name DER-encoded byte array holding an X.500 name. 315 */ 316 public X500Name(byte[] name) throws IOException { 317 DerInputStream in = new DerInputStream(name); 318 parseDER(in); 319 } 320 321 /** 322 * Return an immutable List of all RDNs in this X500Name. 323 */ 324 public List<RDN> rdns() { 325 List<RDN> list = rdnList; 326 if (list == null) { 327 list = Collections.unmodifiableList(Arrays.asList(names)); 328 rdnList = list; 329 } 330 return list; 331 } 332 333 /** 334 * Return the number of RDNs in this X500Name. 335 */ 336 public int size() { 337 return names.length; 338 } 339 340 /** 341 * Return an immutable List of the the AVAs contained in all the 342 * RDNs of this X500Name. 343 */ 344 public List<AVA> allAvas() { 345 List<AVA> list = allAvaList; 346 if (list == null) { 347 list = new ArrayList<AVA>(); 348 for (int i = 0; i < names.length; i++) { 349 list.addAll(names[i].avas()); 350 } 351 } 352 return list; 353 } 354 355 /** 356 * Return the total number of AVAs contained in all the RDNs of 357 * this X500Name. 358 */ 359 public int avaSize() { 360 return allAvas().size(); 361 } 362 363 /** 364 * Return whether this X500Name is empty. An X500Name is not empty 365 * if it has at least one RDN containing at least one AVA. 366 */ 367 public boolean isEmpty() { 368 int n = names.length; 369 if (n == 0) { 370 return true; 371 } 372 for (int i = 0; i < n; i++) { 373 if (names[i].assertion.length != 0) { 374 return false; 375 } 376 } 377 return true; 378 } 379 380 /** 381 * Calculates a hash code value for the object. Objects 382 * which are equal will also have the same hashcode. 383 */ 384 public int hashCode() { 385 return getRFC2253CanonicalName().hashCode(); 386 } 387 388 /** 389 * Compares this name with another, for equality. 390 * 391 * @return true iff the names are identical. 392 */ 393 public boolean equals(Object obj) { 394 if (this == obj) { 395 return true; 396 } 397 if (obj instanceof X500Name == false) { 398 return false; 399 } 400 X500Name other = (X500Name)obj; 401 // if we already have the canonical forms, compare now 402 if ((this.canonicalDn != null) && (other.canonicalDn != null)) { 403 return this.canonicalDn.equals(other.canonicalDn); 404 } 405 // quick check that number of RDNs and AVAs match before canonicalizing 406 int n = this.names.length; 407 if (n != other.names.length) { 408 return false; 409 } 410 for (int i = 0; i < n; i++) { 411 RDN r1 = this.names[i]; 412 RDN r2 = other.names[i]; 413 if (r1.assertion.length != r2.assertion.length) { 414 return false; 415 } 416 } 417 // definite check via canonical form 418 String thisCanonical = this.getRFC2253CanonicalName(); 419 String otherCanonical = other.getRFC2253CanonicalName(); 420 return thisCanonical.equals(otherCanonical); 421 } 422 423 /* 424 * Returns the name component as a Java string, regardless of its 425 * encoding restrictions. 426 */ 427 private String getString(DerValue attribute) throws IOException { 428 if (attribute == null) 429 return null; 430 String value = attribute.getAsString(); 431 432 if (value == null) 433 throw new IOException("not a DER string encoding, " 434 + attribute.tag); 435 else 436 return value; 437 } 438 439 /** 440 * Return type of GeneralName. 441 */ 442 public int getType() { 443 return (GeneralNameInterface.NAME_DIRECTORY); 444 } 445 446 /** 447 * Returns a "Country" name component. If more than one 448 * such attribute exists, the topmost one is returned. 449 * 450 * @return "C=" component of the name, if any. 451 */ 452 public String getCountry() throws IOException { 453 DerValue attr = findAttribute(countryName_oid); 454 455 return getString(attr); 456 } 457 458 459 /** 460 * Returns an "Organization" name component. If more than 461 * one such attribute exists, the topmost one is returned. 462 * 463 * @return "O=" component of the name, if any. 464 */ 465 public String getOrganization() throws IOException { 466 DerValue attr = findAttribute(orgName_oid); 467 468 return getString(attr); 469 } 470 471 472 /** 473 * Returns an "Organizational Unit" name component. If more 474 * than one such attribute exists, the topmost one is returned. 475 * 476 * @return "OU=" component of the name, if any. 477 */ 478 public String getOrganizationalUnit() throws IOException { 479 DerValue attr = findAttribute(orgUnitName_oid); 480 481 return getString(attr); 482 } 483 484 485 /** 486 * Returns a "Common Name" component. If more than one such 487 * attribute exists, the topmost one is returned. 488 * 489 * @return "CN=" component of the name, if any. 490 */ 491 public String getCommonName() throws IOException { 492 DerValue attr = findAttribute(commonName_oid); 493 494 return getString(attr); 495 } 496 497 498 /** 499 * Returns a "Locality" name component. If more than one 500 * such component exists, the topmost one is returned. 501 * 502 * @return "L=" component of the name, if any. 503 */ 504 public String getLocality() throws IOException { 505 DerValue attr = findAttribute(localityName_oid); 506 507 return getString(attr); 508 } 509 510 /** 511 * Returns a "State" name component. If more than one 512 * such component exists, the topmost one is returned. 513 * 514 * @return "S=" component of the name, if any. 515 */ 516 public String getState() throws IOException { 517 DerValue attr = findAttribute(stateName_oid); 518 519 return getString(attr); 520 } 521 522 /** 523 * Returns a "Domain" name component. If more than one 524 * such component exists, the topmost one is returned. 525 * 526 * @return "DC=" component of the name, if any. 527 */ 528 public String getDomain() throws IOException { 529 DerValue attr = findAttribute(DOMAIN_COMPONENT_OID); 530 531 return getString(attr); 532 } 533 534 /** 535 * Returns a "DN Qualifier" name component. If more than one 536 * such component exists, the topmost one is returned. 537 * 538 * @return "DNQ=" component of the name, if any. 539 */ 540 public String getDNQualifier() throws IOException { 541 DerValue attr = findAttribute(DNQUALIFIER_OID); 542 543 return getString(attr); 544 } 545 546 /** 547 * Returns a "Surname" name component. If more than one 548 * such component exists, the topmost one is returned. 549 * 550 * @return "SURNAME=" component of the name, if any. 551 */ 552 public String getSurname() throws IOException { 553 DerValue attr = findAttribute(SURNAME_OID); 554 555 return getString(attr); 556 } 557 558 /** 559 * Returns a "Given Name" name component. If more than one 560 * such component exists, the topmost one is returned. 561 * 562 * @return "GIVENNAME=" component of the name, if any. 563 */ 564 public String getGivenName() throws IOException { 565 DerValue attr = findAttribute(GIVENNAME_OID); 566 567 return getString(attr); 568 } 569 570 /** 571 * Returns an "Initials" name component. If more than one 572 * such component exists, the topmost one is returned. 573 * 574 * @return "INITIALS=" component of the name, if any. 575 */ 576 public String getInitials() throws IOException { 577 DerValue attr = findAttribute(INITIALS_OID); 578 579 return getString(attr); 580 } 581 582 /** 583 * Returns a "Generation Qualifier" name component. If more than one 584 * such component exists, the topmost one is returned. 585 * 586 * @return "GENERATION=" component of the name, if any. 587 */ 588 public String getGeneration() throws IOException { 589 DerValue attr = findAttribute(GENERATIONQUALIFIER_OID); 590 591 return getString(attr); 592 } 593 594 /** 595 * Returns an "IP address" name component. If more than one 596 * such component exists, the topmost one is returned. 597 * 598 * @return "IP=" component of the name, if any. 599 */ 600 public String getIP() throws IOException { 601 DerValue attr = findAttribute(ipAddress_oid); 602 603 return getString(attr); 604 } 605 606 /** 607 * Returns a string form of the X.500 distinguished name. 608 * The format of the string is from RFC 1779. The returned string 609 * may contain non-standardised keywords for more readability 610 * (keywords from RFCs 1779, 2253, and 3280). 611 */ 612 public String toString() { 613 if (dn == null) { 614 generateDN(); 615 } 616 return dn; 617 } 618 619 /** 620 * Returns a string form of the X.500 distinguished name 621 * using the algorithm defined in RFC 1779. Only standard attribute type 622 * keywords defined in RFC 1779 are emitted. 623 */ 624 public String getRFC1779Name() { 625 return getRFC1779Name(Collections.<String, String>emptyMap()); 626 } 627 628 /** 629 * Returns a string form of the X.500 distinguished name 630 * using the algorithm defined in RFC 1779. Attribute type 631 * keywords defined in RFC 1779 are emitted, as well as additional 632 * keywords contained in the OID/keyword map. 633 */ 634 public String getRFC1779Name(Map<String, String> oidMap) 635 throws IllegalArgumentException { 636 if (oidMap.isEmpty()) { 637 // return cached result 638 if (rfc1779Dn != null) { 639 return rfc1779Dn; 640 } else { 641 rfc1779Dn = generateRFC1779DN(oidMap); 642 return rfc1779Dn; 643 } 644 } 645 return generateRFC1779DN(oidMap); 646 } 647 648 /** 649 * Returns a string form of the X.500 distinguished name 650 * using the algorithm defined in RFC 2253. Only standard attribute type 651 * keywords defined in RFC 2253 are emitted. 652 */ 653 public String getRFC2253Name() { 654 return getRFC2253Name(Collections.<String, String>emptyMap()); 655 } 656 657 /** 658 * Returns a string form of the X.500 distinguished name 659 * using the algorithm defined in RFC 2253. Attribute type 660 * keywords defined in RFC 2253 are emitted, as well as additional 661 * keywords contained in the OID/keyword map. 662 */ 663 public String getRFC2253Name(Map<String, String> oidMap) { 664 /* check for and return cached name */ 665 if (oidMap.isEmpty()) { 666 if (rfc2253Dn != null) { 667 return rfc2253Dn; 668 } else { 669 rfc2253Dn = generateRFC2253DN(oidMap); 670 return rfc2253Dn; 671 } 672 } 673 return generateRFC2253DN(oidMap); 674 } 675 676 private String generateRFC2253DN(Map<String, String> oidMap) { 677 /* 678 * Section 2.1 : if the RDNSequence is an empty sequence 679 * the result is the empty or zero length string. 680 */ 681 if (names.length == 0) { 682 return ""; 683 } 684 685 /* 686 * 2.1 (continued) : Otherwise, the output consists of the string 687 * encodings of each RelativeDistinguishedName in the RDNSequence 688 * (according to 2.2), starting with the last element of the sequence 689 * and moving backwards toward the first. 690 * 691 * The encodings of adjoining RelativeDistinguishedNames are separated 692 * by a comma character (',' ASCII 44). 693 */ 694 StringBuilder fullname = new StringBuilder(48); 695 for (int i = names.length - 1; i >= 0; i--) { 696 if (i < names.length - 1) { 697 fullname.append(','); 698 } 699 fullname.append(names[i].toRFC2253String(oidMap)); 700 } 701 return fullname.toString(); 702 } 703 704 public String getRFC2253CanonicalName() { 705 /* check for and return cached name */ 706 if (canonicalDn != null) { 707 return canonicalDn; 708 } 709 /* 710 * Section 2.1 : if the RDNSequence is an empty sequence 711 * the result is the empty or zero length string. 712 */ 713 if (names.length == 0) { 714 canonicalDn = ""; 715 return canonicalDn; 716 } 717 718 /* 719 * 2.1 (continued) : Otherwise, the output consists of the string 720 * encodings of each RelativeDistinguishedName in the RDNSequence 721 * (according to 2.2), starting with the last element of the sequence 722 * and moving backwards toward the first. 723 * 724 * The encodings of adjoining RelativeDistinguishedNames are separated 725 * by a comma character (',' ASCII 44). 726 */ 727 StringBuilder fullname = new StringBuilder(48); 728 for (int i = names.length - 1; i >= 0; i--) { 729 if (i < names.length - 1) { 730 fullname.append(','); 731 } 732 fullname.append(names[i].toRFC2253String(true)); 733 } 734 canonicalDn = fullname.toString(); 735 return canonicalDn; 736 } 737 738 /** 739 * Returns the value of toString(). This call is needed to 740 * implement the java.security.Principal interface. 741 */ 742 public String getName() { return toString(); } 743 744 /** 745 * Find the first instance of this attribute in a "top down" 746 * search of all the attributes in the name. 747 */ 748 private DerValue findAttribute(ObjectIdentifier attribute) { 749 if (names != null) { 750 for (int i = 0; i < names.length; i++) { 751 DerValue value = names[i].findAttribute(attribute); 752 if (value != null) { 753 return value; 754 } 755 } 756 } 757 return null; 758 } 759 760 /** 761 * Find the most specific ("last") attribute of the given 762 * type. 763 */ 764 public DerValue findMostSpecificAttribute(ObjectIdentifier attribute) { 765 if (names != null) { 766 for (int i = names.length - 1; i >= 0; i--) { 767 DerValue value = names[i].findAttribute(attribute); 768 if (value != null) { 769 return value; 770 } 771 } 772 } 773 return null; 774 } 775 776 /****************************************************************/ 777 778 private void parseDER(DerInputStream in) throws IOException { 779 // 780 // X.500 names are a "SEQUENCE OF" RDNs, which means zero or 781 // more and order matters. We scan them in order, which 782 // conventionally is big-endian. 783 // 784 DerValue[] nameseq = null; 785 byte[] derBytes = in.toByteArray(); 786 787 try { 788 nameseq = in.getSequence(5); 789 } catch (IOException ioe) { 790 if (derBytes == null) { 791 nameseq = null; 792 } else { 793 DerValue derVal = new DerValue(DerValue.tag_Sequence, 794 derBytes); 795 derBytes = derVal.toByteArray(); 796 nameseq = new DerInputStream(derBytes).getSequence(5); 797 } 798 } 799 800 if (nameseq == null) { 801 names = new RDN[0]; 802 } else { 803 names = new RDN[nameseq.length]; 804 for (int i = 0; i < nameseq.length; i++) { 805 names[i] = new RDN(nameseq[i]); 806 } 807 } 808 } 809 810 /** 811 * Encodes the name in DER-encoded form. 812 * 813 * @deprecated Use encode() instead 814 * @param out where to put the DER-encoded X.500 name 815 */ 816 @Deprecated 817 public void emit(DerOutputStream out) throws IOException { 818 encode(out); 819 } 820 821 /** 822 * Encodes the name in DER-encoded form. 823 * 824 * @param out where to put the DER-encoded X.500 name 825 */ 826 public void encode(DerOutputStream out) throws IOException { 827 DerOutputStream tmp = new DerOutputStream(); 828 for (int i = 0; i < names.length; i++) { 829 names[i].encode(tmp); 830 } 831 out.write(DerValue.tag_Sequence, tmp); 832 } 833 834 /** 835 * Returned the encoding as an uncloned byte array. Callers must 836 * guarantee that they neither modify it not expose it to untrusted 837 * code. 838 */ 839 public byte[] getEncodedInternal() throws IOException { 840 if (encoded == null) { 841 DerOutputStream out = new DerOutputStream(); 842 DerOutputStream tmp = new DerOutputStream(); 843 for (int i = 0; i < names.length; i++) { 844 names[i].encode(tmp); 845 } 846 out.write(DerValue.tag_Sequence, tmp); 847 encoded = out.toByteArray(); 848 } 849 return encoded; 850 } 851 852 /** 853 * Gets the name in DER-encoded form. 854 * 855 * @return the DER encoded byte array of this name. 856 */ 857 public byte[] getEncoded() throws IOException { 858 return getEncodedInternal().clone(); 859 } 860 861 /* 862 * Parses a Distinguished Name (DN) in printable representation. 863 * 864 * According to RFC 1779, RDNs in a DN are separated by comma. 865 * The following examples show both methods of quoting a comma, so that it 866 * is not considered a separator: 867 * 868 * O="Sue, Grabbit and Runn" or 869 * O=Sue\, Grabbit and Runn 870 * 871 * This method can parse 1779 or 2253 DNs and non-standard 3280 keywords. 872 * Additional keywords can be specified in the keyword/OID map. 873 */ 874 private void parseDN(String input, Map<String, String> keywordMap) 875 throws IOException { 876 if (input == null || input.length() == 0) { 877 names = new RDN[0]; 878 return; 879 } 880 881 checkNoNewLinesNorTabsAtBeginningOfDN(input); 882 883 List<RDN> dnVector = new ArrayList<RDN>(); 884 int dnOffset = 0; 885 int rdnEnd; 886 String rdnString; 887 int quoteCount = 0; 888 889 String dnString = input; 890 891 int searchOffset = 0; 892 int nextComma = dnString.indexOf(','); 893 int nextSemiColon = dnString.indexOf(';'); 894 while (nextComma >=0 || nextSemiColon >=0) { 895 896 if (nextSemiColon < 0) { 897 rdnEnd = nextComma; 898 } else if (nextComma < 0) { 899 rdnEnd = nextSemiColon; 900 } else { 901 rdnEnd = Math.min(nextComma, nextSemiColon); 902 } 903 quoteCount += countQuotes(dnString, searchOffset, rdnEnd); 904 905 /* 906 * We have encountered an RDN delimiter (comma or a semicolon). 907 * If the comma or semicolon in the RDN under consideration is 908 * preceded by a backslash (escape), or by a double quote, it 909 * is part of the RDN. Otherwise, it is used as a separator, to 910 * delimit the RDN under consideration from any subsequent RDNs. 911 */ 912 if (rdnEnd >= 0 && quoteCount != 1 && 913 !escaped(rdnEnd, searchOffset, dnString)) { 914 915 /* 916 * Comma/semicolon is a separator 917 */ 918 rdnString = dnString.substring(dnOffset, rdnEnd); 919 920 // Parse RDN, and store it in vector 921 RDN rdn = new RDN(rdnString, keywordMap); 922 dnVector.add(rdn); 923 924 // Increase the offset 925 dnOffset = rdnEnd + 1; 926 927 // Set quote counter back to zero 928 quoteCount = 0; 929 } 930 931 searchOffset = rdnEnd + 1; 932 nextComma = dnString.indexOf(',', searchOffset); 933 nextSemiColon = dnString.indexOf(';', searchOffset); 934 } 935 936 // Parse last or only RDN, and store it in vector 937 rdnString = dnString.substring(dnOffset); 938 RDN rdn = new RDN(rdnString, keywordMap); 939 dnVector.add(rdn); 940 941 /* 942 * Store the vector elements as an array of RDNs 943 * NOTE: It's only on output that little-endian ordering is used. 944 */ 945 Collections.reverse(dnVector); 946 names = dnVector.toArray(new RDN[dnVector.size()]); 947 } 948 949 /** 950 * Disallow new lines and tabs at the beginning of DN. 951 * 952 * @throws java.lang.IllegalArgumentException if the DN starts with new line or tab. 953 */ 954 private void checkNoNewLinesNorTabsAtBeginningOfDN(String input) { 955 for (int i = 0; i < input.length(); i++) { 956 char c = input.charAt(i); 957 if (c != ' ') { 958 if (c == '\t' || c == '\n') { 959 throw new IllegalArgumentException("DN cannot start with newline nor tab"); 960 } 961 break; 962 } 963 } 964 } 965 966 private void parseRFC2253DN(String dnString) throws IOException { 967 if (dnString.length() == 0) { 968 names = new RDN[0]; 969 return; 970 } 971 972 List<RDN> dnVector = new ArrayList<RDN>(); 973 int dnOffset = 0; 974 String rdnString; 975 976 int searchOffset = 0; 977 int rdnEnd = dnString.indexOf(','); 978 while (rdnEnd >=0) { 979 /* 980 * We have encountered an RDN delimiter (comma). 981 * If the comma in the RDN under consideration is 982 * preceded by a backslash (escape), it 983 * is part of the RDN. Otherwise, it is used as a separator, to 984 * delimit the RDN under consideration from any subsequent RDNs. 985 */ 986 if (rdnEnd > 0 && !escaped(rdnEnd, searchOffset, dnString)) { 987 988 /* 989 * Comma is a separator 990 */ 991 rdnString = dnString.substring(dnOffset, rdnEnd); 992 993 // Parse RDN, and store it in vector 994 RDN rdn = new RDN(rdnString, "RFC2253"); 995 dnVector.add(rdn); 996 997 // Increase the offset 998 dnOffset = rdnEnd + 1; 999 } 1000 1001 searchOffset = rdnEnd + 1; 1002 rdnEnd = dnString.indexOf(',', searchOffset); 1003 } 1004 1005 // Parse last or only RDN, and store it in vector 1006 rdnString = dnString.substring(dnOffset); 1007 RDN rdn = new RDN(rdnString, "RFC2253"); 1008 dnVector.add(rdn); 1009 1010 /* 1011 * Store the vector elements as an array of RDNs 1012 * NOTE: It's only on output that little-endian ordering is used. 1013 */ 1014 Collections.reverse(dnVector); 1015 names = dnVector.toArray(new RDN[dnVector.size()]); 1016 } 1017 1018 /* 1019 * Counts double quotes in string. 1020 * Escaped quotes are ignored. 1021 */ 1022 static int countQuotes(String string, int from, int to) { 1023 int count = 0; 1024 1025 int escape = 0; 1026 for (int i = from; i < to; i++) { 1027 if (string.charAt(i) == '"' && escape % 2 == 0) { 1028 count++; 1029 } 1030 escape = (string.charAt(i) == '\\') ? escape + 1 : 0; 1031 } 1032 1033 return count; 1034 } 1035 1036 private static boolean escaped 1037 (int rdnEnd, int searchOffset, String dnString) { 1038 1039 if (rdnEnd == 1 && dnString.charAt(rdnEnd - 1) == '\\') { 1040 1041 // case 1: 1042 // \, 1043 1044 return true; 1045 1046 } else if (rdnEnd > 1 && dnString.charAt(rdnEnd - 1) == '\\' && 1047 dnString.charAt(rdnEnd - 2) != '\\') { 1048 1049 // case 2: 1050 // foo\, 1051 1052 return true; 1053 1054 } else if (rdnEnd > 1 && dnString.charAt(rdnEnd - 1) == '\\' && 1055 dnString.charAt(rdnEnd - 2) == '\\') { 1056 1057 // case 3: 1058 // foo\\\\\, 1059 1060 int count = 0; 1061 rdnEnd--; // back up to last backSlash 1062 while (rdnEnd >= searchOffset) { 1063 if (dnString.charAt(rdnEnd) == '\\') { 1064 count++; // count consecutive backslashes 1065 } 1066 rdnEnd--; 1067 } 1068 1069 // if count is odd, then rdnEnd is escaped 1070 return (count % 2) != 0 ? true : false; 1071 1072 } else { 1073 return false; 1074 } 1075 } 1076 1077 /* 1078 * Dump the printable form of a distinguished name. Each relative 1079 * name is separated from the next by a ",", and assertions in the 1080 * relative names have "label=value" syntax. 1081 * 1082 * Uses RFC 1779 syntax (i.e. little-endian, comma separators) 1083 */ 1084 private void generateDN() { 1085 if (names.length == 1) { 1086 dn = names[0].toString(); 1087 return; 1088 } 1089 1090 StringBuilder sb = new StringBuilder(48); 1091 if (names != null) { 1092 for (int i = names.length - 1; i >= 0; i--) { 1093 if (i != names.length - 1) { 1094 sb.append(", "); 1095 } 1096 sb.append(names[i].toString()); 1097 } 1098 } 1099 dn = sb.toString(); 1100 } 1101 1102 /* 1103 * Dump the printable form of a distinguished name. Each relative 1104 * name is separated from the next by a ",", and assertions in the 1105 * relative names have "label=value" syntax. 1106 * 1107 * Uses RFC 1779 syntax (i.e. little-endian, comma separators) 1108 * Valid keywords from RFC 1779 are used. Additional keywords can be 1109 * specified in the OID/keyword map. 1110 */ 1111 private String generateRFC1779DN(Map<String, String> oidMap) { 1112 if (names.length == 1) { 1113 return names[0].toRFC1779String(oidMap); 1114 } 1115 1116 StringBuilder sb = new StringBuilder(48); 1117 if (names != null) { 1118 for (int i = names.length - 1; i >= 0; i--) { 1119 if (i != names.length - 1) { 1120 sb.append(", "); 1121 } 1122 sb.append(names[i].toRFC1779String(oidMap)); 1123 } 1124 } 1125 return sb.toString(); 1126 } 1127 1128 /****************************************************************/ 1129 1130 /* 1131 * Maybe return a preallocated OID, to reduce storage costs 1132 * and speed recognition of common X.500 attributes. 1133 */ 1134 static ObjectIdentifier intern(ObjectIdentifier oid) { 1135 ObjectIdentifier interned = internedOIDs.get(oid); 1136 if (interned != null) { 1137 return interned; 1138 } 1139 internedOIDs.put(oid, oid); 1140 return oid; 1141 } 1142 1143 private static final Map<ObjectIdentifier,ObjectIdentifier> internedOIDs 1144 = new HashMap<ObjectIdentifier,ObjectIdentifier>(); 1145 1146 /* 1147 * Selected OIDs from X.520 1148 * Includes all those specified in RFC 3280 as MUST or SHOULD 1149 * be recognized 1150 */ 1151 private static final int commonName_data[] = { 2, 5, 4, 3 }; 1152 private static final int SURNAME_DATA[] = { 2, 5, 4, 4 }; 1153 private static final int SERIALNUMBER_DATA[] = { 2, 5, 4, 5 }; 1154 private static final int countryName_data[] = { 2, 5, 4, 6 }; 1155 private static final int localityName_data[] = { 2, 5, 4, 7 }; 1156 private static final int stateName_data[] = { 2, 5, 4, 8 }; 1157 private static final int streetAddress_data[] = { 2, 5, 4, 9 }; 1158 private static final int orgName_data[] = { 2, 5, 4, 10 }; 1159 private static final int orgUnitName_data[] = { 2, 5, 4, 11 }; 1160 private static final int title_data[] = { 2, 5, 4, 12 }; 1161 private static final int GIVENNAME_DATA[] = { 2, 5, 4, 42 }; 1162 private static final int INITIALS_DATA[] = { 2, 5, 4, 43 }; 1163 private static final int GENERATIONQUALIFIER_DATA[] = { 2, 5, 4, 44 }; 1164 private static final int DNQUALIFIER_DATA[] = { 2, 5, 4, 46 }; 1165 1166 private static final int ipAddress_data[] = { 1, 3, 6, 1, 4, 1, 42, 2, 11, 2, 1 }; 1167 private static final int DOMAIN_COMPONENT_DATA[] = 1168 { 0, 9, 2342, 19200300, 100, 1, 25 }; 1169 private static final int userid_data[] = 1170 { 0, 9, 2342, 19200300, 100, 1, 1 }; 1171 1172 1173 public static final ObjectIdentifier commonName_oid; 1174 public static final ObjectIdentifier countryName_oid; 1175 public static final ObjectIdentifier localityName_oid; 1176 public static final ObjectIdentifier orgName_oid; 1177 public static final ObjectIdentifier orgUnitName_oid; 1178 public static final ObjectIdentifier stateName_oid; 1179 public static final ObjectIdentifier streetAddress_oid; 1180 public static final ObjectIdentifier title_oid; 1181 public static final ObjectIdentifier DNQUALIFIER_OID; 1182 public static final ObjectIdentifier SURNAME_OID; 1183 public static final ObjectIdentifier GIVENNAME_OID; 1184 public static final ObjectIdentifier INITIALS_OID; 1185 public static final ObjectIdentifier GENERATIONQUALIFIER_OID; 1186 public static final ObjectIdentifier ipAddress_oid; 1187 public static final ObjectIdentifier DOMAIN_COMPONENT_OID; 1188 public static final ObjectIdentifier userid_oid; 1189 public static final ObjectIdentifier SERIALNUMBER_OID; 1190 1191 static { 1192 /** OID for the "CN=" attribute, denoting a person's common name. */ 1193 commonName_oid = intern(ObjectIdentifier.newInternal(commonName_data)); 1194 1195 /** OID for the "SERIALNUMBER=" attribute, denoting a serial number for. 1196 a name. Do not confuse with PKCS#9 issuerAndSerialNumber or the 1197 certificate serial number. */ 1198 SERIALNUMBER_OID = intern(ObjectIdentifier.newInternal(SERIALNUMBER_DATA)); 1199 1200 /** OID for the "C=" attribute, denoting a country. */ 1201 countryName_oid = intern(ObjectIdentifier.newInternal(countryName_data)); 1202 1203 /** OID for the "L=" attribute, denoting a locality (such as a city) */ 1204 localityName_oid = intern(ObjectIdentifier.newInternal(localityName_data)); 1205 1206 /** OID for the "O=" attribute, denoting an organization name */ 1207 orgName_oid = intern(ObjectIdentifier.newInternal(orgName_data)); 1208 1209 /** OID for the "OU=" attribute, denoting an organizational unit name */ 1210 orgUnitName_oid = intern(ObjectIdentifier.newInternal(orgUnitName_data)); 1211 1212 /** OID for the "S=" attribute, denoting a state (such as Delaware) */ 1213 stateName_oid = intern(ObjectIdentifier.newInternal(stateName_data)); 1214 1215 /** OID for the "STREET=" attribute, denoting a street address. */ 1216 streetAddress_oid = intern(ObjectIdentifier.newInternal(streetAddress_data)); 1217 1218 /** OID for the "T=" attribute, denoting a person's title. */ 1219 title_oid = intern(ObjectIdentifier.newInternal(title_data)); 1220 1221 /** OID for the "DNQUALIFIER=" or "DNQ=" attribute, denoting DN 1222 disambiguating information.*/ 1223 DNQUALIFIER_OID = intern(ObjectIdentifier.newInternal(DNQUALIFIER_DATA)); 1224 1225 /** OID for the "SURNAME=" attribute, denoting a person's surname.*/ 1226 SURNAME_OID = intern(ObjectIdentifier.newInternal(SURNAME_DATA)); 1227 1228 /** OID for the "GIVENNAME=" attribute, denoting a person's given name.*/ 1229 GIVENNAME_OID = intern(ObjectIdentifier.newInternal(GIVENNAME_DATA)); 1230 1231 /** OID for the "INITIALS=" attribute, denoting a person's initials.*/ 1232 INITIALS_OID = intern(ObjectIdentifier.newInternal(INITIALS_DATA)); 1233 1234 /** OID for the "GENERATION=" attribute, denoting Jr., II, etc.*/ 1235 GENERATIONQUALIFIER_OID = 1236 intern(ObjectIdentifier.newInternal(GENERATIONQUALIFIER_DATA)); 1237 1238 /* 1239 * OIDs from other sources which show up in X.500 names we 1240 * expect to deal with often 1241 */ 1242 /** OID for "IP=" IP address attributes, used with SKIP. */ 1243 ipAddress_oid = intern(ObjectIdentifier.newInternal(ipAddress_data)); 1244 1245 /* 1246 * Domain component OID from RFC 1274, RFC 2247, RFC 3280 1247 */ 1248 1249 /* 1250 * OID for "DC=" domain component attributes, used with DNS names in DN 1251 * format 1252 */ 1253 DOMAIN_COMPONENT_OID = 1254 intern(ObjectIdentifier.newInternal(DOMAIN_COMPONENT_DATA)); 1255 1256 /** OID for "UID=" denoting a user id, defined in RFCs 1274 & 2798. */ 1257 userid_oid = intern(ObjectIdentifier.newInternal(userid_data)); 1258 } 1259 1260 /** 1261 * Return constraint type:<ul> 1262 * <li>NAME_DIFF_TYPE = -1: input name is different type from this name 1263 * (i.e. does not constrain) 1264 * <li>NAME_MATCH = 0: input name matches this name 1265 * <li>NAME_NARROWS = 1: input name narrows this name 1266 * <li>NAME_WIDENS = 2: input name widens this name 1267 * <li>NAME_SAME_TYPE = 3: input name does not match or narrow this name, 1268 & but is same type 1269 * </ul>. These results are used in checking NameConstraints during 1270 * certification path verification. 1271 * 1272 * @param inputName to be checked for being constrained 1273 * @returns constraint type above 1274 * @throws UnsupportedOperationException if name is not exact match, but 1275 * narrowing and widening are not supported for this name type. 1276 */ 1277 public int constrains(GeneralNameInterface inputName) 1278 throws UnsupportedOperationException { 1279 int constraintType; 1280 if (inputName == null) { 1281 constraintType = NAME_DIFF_TYPE; 1282 } else if (inputName.getType() != NAME_DIRECTORY) { 1283 constraintType = NAME_DIFF_TYPE; 1284 } else { // type == NAME_DIRECTORY 1285 X500Name inputX500 = (X500Name)inputName; 1286 if (inputX500.equals(this)) { 1287 constraintType = NAME_MATCH; 1288 } else if (inputX500.names.length == 0) { 1289 constraintType = NAME_WIDENS; 1290 } else if (this.names.length == 0) { 1291 constraintType = NAME_NARROWS; 1292 } else if (inputX500.isWithinSubtree(this)) { 1293 constraintType = NAME_NARROWS; 1294 } else if (isWithinSubtree(inputX500)) { 1295 constraintType = NAME_WIDENS; 1296 } else { 1297 constraintType = NAME_SAME_TYPE; 1298 } 1299 } 1300 return constraintType; 1301 } 1302 1303 /** 1304 * Compares this name with another and determines if 1305 * it is within the subtree of the other. Useful for 1306 * checking against the name constraints extension. 1307 * 1308 * @return true iff this name is within the subtree of other. 1309 */ 1310 private boolean isWithinSubtree(X500Name other) { 1311 if (this == other) { 1312 return true; 1313 } 1314 if (other == null) { 1315 return false; 1316 } 1317 if (other.names.length == 0) { 1318 return true; 1319 } 1320 if (this.names.length == 0) { 1321 return false; 1322 } 1323 if (names.length < other.names.length) { 1324 return false; 1325 } 1326 for (int i = 0; i < other.names.length; i++) { 1327 if (!names[i].equals(other.names[i])) { 1328 return false; 1329 } 1330 } 1331 return true; 1332 } 1333 1334 /** 1335 * Return subtree depth of this name for purposes of determining 1336 * NameConstraints minimum and maximum bounds and for calculating 1337 * path lengths in name subtrees. 1338 * 1339 * @returns distance of name from root 1340 * @throws UnsupportedOperationException if not supported for this name type 1341 */ 1342 public int subtreeDepth() throws UnsupportedOperationException { 1343 return names.length; 1344 } 1345 1346 /** 1347 * Return lowest common ancestor of this name and other name 1348 * 1349 * @param other another X500Name 1350 * @return X500Name of lowest common ancestor; null if none 1351 */ 1352 public X500Name commonAncestor(X500Name other) { 1353 1354 if (other == null) { 1355 return null; 1356 } 1357 int otherLen = other.names.length; 1358 int thisLen = this.names.length; 1359 if (thisLen == 0 || otherLen == 0) { 1360 return null; 1361 } 1362 int minLen = (thisLen < otherLen) ? thisLen: otherLen; 1363 1364 //Compare names from highest RDN down the naming tree 1365 //Note that these are stored in RDN[0]... 1366 int i=0; 1367 for (; i < minLen; i++) { 1368 if (!names[i].equals(other.names[i])) { 1369 if (i == 0) { 1370 return null; 1371 } else { 1372 break; 1373 } 1374 } 1375 } 1376 1377 //Copy matching RDNs into new RDN array 1378 RDN[] ancestor = new RDN[i]; 1379 for (int j=0; j < i; j++) { 1380 ancestor[j] = names[j]; 1381 } 1382 1383 X500Name commonAncestor = null; 1384 try { 1385 commonAncestor = new X500Name(ancestor); 1386 } catch (IOException ioe) { 1387 return null; 1388 } 1389 return commonAncestor; 1390 } 1391 1392 /** 1393 * Constructor object for use by asX500Principal(). 1394 */ 1395 private static final Constructor principalConstructor; 1396 1397 /** 1398 * Field object for use by asX500Name(). 1399 */ 1400 private static final Field principalField; 1401 1402 /** 1403 * Retrieve the Constructor and Field we need for reflective access 1404 * and make them accessible. 1405 */ 1406 static { 1407 PrivilegedExceptionAction<Object[]> pa = 1408 new PrivilegedExceptionAction<Object[]>() { 1409 public Object[] run() throws Exception { 1410 Class pClass = X500Principal.class; 1411 Class[] args = new Class[] {X500Name.class}; 1412 Constructor cons = ((Class<?>)pClass).getDeclaredConstructor(args); 1413 cons.setAccessible(true); 1414 Field field = pClass.getDeclaredField("thisX500Name"); 1415 field.setAccessible(true); 1416 return new Object[] {cons, field}; 1417 } 1418 }; 1419 try { 1420 Object[] result = AccessController.doPrivileged(pa); 1421 principalConstructor = (Constructor)result[0]; 1422 principalField = (Field)result[1]; 1423 } catch (Exception e) { 1424 throw (InternalError)new InternalError("Could not obtain " 1425 + "X500Principal access").initCause(e); 1426 } 1427 } 1428 1429 /** 1430 * Get an X500Principal backed by this X500Name. 1431 * 1432 * Note that we are using privileged reflection to access the hidden 1433 * package private constructor in X500Principal. 1434 */ 1435 public X500Principal asX500Principal() { 1436 if (x500Principal == null) { 1437 try { 1438 Object[] args = new Object[] {this}; 1439 x500Principal = 1440 (X500Principal)principalConstructor.newInstance(args); 1441 } catch (Exception e) { 1442 throw new RuntimeException("Unexpected exception", e); 1443 } 1444 } 1445 return x500Principal; 1446 } 1447 1448 /** 1449 * Get the X500Name contained in the given X500Principal. 1450 * 1451 * Note that the X500Name is retrieved using reflection. 1452 */ 1453 public static X500Name asX500Name(X500Principal p) { 1454 try { 1455 X500Name name = (X500Name)principalField.get(p); 1456 name.x500Principal = p; 1457 return name; 1458 } catch (Exception e) { 1459 throw new RuntimeException("Unexpected exception", e); 1460 } 1461 } 1462 1463 } 1464