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