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.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 */ X500Name(String dname)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 */ X500Name(String dname, Map<String, String> keywordMap)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 */ X500Name(String dname, String format)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 */ X500Name(String commonName, String organizationUnit, String organizationName, String country)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 */ X500Name(String commonName, String organizationUnit, String organizationName, String localityName, String stateName, String country)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 */ X500Name(RDN[] rdnArray)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 */ X500Name(DerValue value)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 */ X500Name(DerInputStream in)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 */ X500Name(byte[] name)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 */ rdns()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 */ size()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 */ allAvas()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 } 351 return list; 352 } 353 354 /** 355 * Return the total number of AVAs contained in all the RDNs of 356 * this X500Name. 357 */ avaSize()358 public int avaSize() { 359 return allAvas().size(); 360 } 361 362 /** 363 * Return whether this X500Name is empty. An X500Name is not empty 364 * if it has at least one RDN containing at least one AVA. 365 */ isEmpty()366 public boolean isEmpty() { 367 int n = names.length; 368 if (n == 0) { 369 return true; 370 } 371 for (int i = 0; i < n; i++) { 372 if (names[i].assertion.length != 0) { 373 return false; 374 } 375 } 376 return true; 377 } 378 379 /** 380 * Calculates a hash code value for the object. Objects 381 * which are equal will also have the same hashcode. 382 */ hashCode()383 public int hashCode() { 384 return getRFC2253CanonicalName().hashCode(); 385 } 386 387 /** 388 * Compares this name with another, for equality. 389 * 390 * @return true iff the names are identical. 391 */ equals(Object obj)392 public boolean equals(Object obj) { 393 if (this == obj) { 394 return true; 395 } 396 if (obj instanceof X500Name == false) { 397 return false; 398 } 399 X500Name other = (X500Name)obj; 400 // if we already have the canonical forms, compare now 401 if ((this.canonicalDn != null) && (other.canonicalDn != null)) { 402 return this.canonicalDn.equals(other.canonicalDn); 403 } 404 // quick check that number of RDNs and AVAs match before canonicalizing 405 int n = this.names.length; 406 if (n != other.names.length) { 407 return false; 408 } 409 for (int i = 0; i < n; i++) { 410 RDN r1 = this.names[i]; 411 RDN r2 = other.names[i]; 412 if (r1.assertion.length != r2.assertion.length) { 413 return false; 414 } 415 } 416 // definite check via canonical form 417 String thisCanonical = this.getRFC2253CanonicalName(); 418 String otherCanonical = other.getRFC2253CanonicalName(); 419 return thisCanonical.equals(otherCanonical); 420 } 421 422 /* 423 * Returns the name component as a Java string, regardless of its 424 * encoding restrictions. 425 */ getString(DerValue attribute)426 private String getString(DerValue attribute) throws IOException { 427 if (attribute == null) 428 return null; 429 String value = attribute.getAsString(); 430 431 if (value == null) 432 throw new IOException("not a DER string encoding, " 433 + attribute.tag); 434 else 435 return value; 436 } 437 438 /** 439 * Return type of GeneralName. 440 */ getType()441 public int getType() { 442 return (GeneralNameInterface.NAME_DIRECTORY); 443 } 444 445 /** 446 * Returns a "Country" name component. If more than one 447 * such attribute exists, the topmost one is returned. 448 * 449 * @return "C=" component of the name, if any. 450 */ getCountry()451 public String getCountry() throws IOException { 452 DerValue attr = findAttribute(countryName_oid); 453 454 return getString(attr); 455 } 456 457 458 /** 459 * Returns an "Organization" name component. If more than 460 * one such attribute exists, the topmost one is returned. 461 * 462 * @return "O=" component of the name, if any. 463 */ getOrganization()464 public String getOrganization() throws IOException { 465 DerValue attr = findAttribute(orgName_oid); 466 467 return getString(attr); 468 } 469 470 471 /** 472 * Returns an "Organizational Unit" name component. If more 473 * than one such attribute exists, the topmost one is returned. 474 * 475 * @return "OU=" component of the name, if any. 476 */ getOrganizationalUnit()477 public String getOrganizationalUnit() throws IOException { 478 DerValue attr = findAttribute(orgUnitName_oid); 479 480 return getString(attr); 481 } 482 483 484 /** 485 * Returns a "Common Name" component. If more than one such 486 * attribute exists, the topmost one is returned. 487 * 488 * @return "CN=" component of the name, if any. 489 */ getCommonName()490 public String getCommonName() throws IOException { 491 DerValue attr = findAttribute(commonName_oid); 492 493 return getString(attr); 494 } 495 496 497 /** 498 * Returns a "Locality" name component. If more than one 499 * such component exists, the topmost one is returned. 500 * 501 * @return "L=" component of the name, if any. 502 */ getLocality()503 public String getLocality() throws IOException { 504 DerValue attr = findAttribute(localityName_oid); 505 506 return getString(attr); 507 } 508 509 /** 510 * Returns a "State" name component. If more than one 511 * such component exists, the topmost one is returned. 512 * 513 * @return "S=" component of the name, if any. 514 */ getState()515 public String getState() throws IOException { 516 DerValue attr = findAttribute(stateName_oid); 517 518 return getString(attr); 519 } 520 521 /** 522 * Returns a "Domain" name component. If more than one 523 * such component exists, the topmost one is returned. 524 * 525 * @return "DC=" component of the name, if any. 526 */ getDomain()527 public String getDomain() throws IOException { 528 DerValue attr = findAttribute(DOMAIN_COMPONENT_OID); 529 530 return getString(attr); 531 } 532 533 /** 534 * Returns a "DN Qualifier" name component. If more than one 535 * such component exists, the topmost one is returned. 536 * 537 * @return "DNQ=" component of the name, if any. 538 */ getDNQualifier()539 public String getDNQualifier() throws IOException { 540 DerValue attr = findAttribute(DNQUALIFIER_OID); 541 542 return getString(attr); 543 } 544 545 /** 546 * Returns a "Surname" name component. If more than one 547 * such component exists, the topmost one is returned. 548 * 549 * @return "SURNAME=" component of the name, if any. 550 */ getSurname()551 public String getSurname() throws IOException { 552 DerValue attr = findAttribute(SURNAME_OID); 553 554 return getString(attr); 555 } 556 557 /** 558 * Returns a "Given Name" name component. If more than one 559 * such component exists, the topmost one is returned. 560 * 561 * @return "GIVENNAME=" component of the name, if any. 562 */ getGivenName()563 public String getGivenName() throws IOException { 564 DerValue attr = findAttribute(GIVENNAME_OID); 565 566 return getString(attr); 567 } 568 569 /** 570 * Returns an "Initials" name component. If more than one 571 * such component exists, the topmost one is returned. 572 * 573 * @return "INITIALS=" component of the name, if any. 574 */ getInitials()575 public String getInitials() throws IOException { 576 DerValue attr = findAttribute(INITIALS_OID); 577 578 return getString(attr); 579 } 580 581 /** 582 * Returns a "Generation Qualifier" name component. If more than one 583 * such component exists, the topmost one is returned. 584 * 585 * @return "GENERATION=" component of the name, if any. 586 */ getGeneration()587 public String getGeneration() throws IOException { 588 DerValue attr = findAttribute(GENERATIONQUALIFIER_OID); 589 590 return getString(attr); 591 } 592 593 /** 594 * Returns an "IP address" name component. If more than one 595 * such component exists, the topmost one is returned. 596 * 597 * @return "IP=" component of the name, if any. 598 */ getIP()599 public String getIP() throws IOException { 600 DerValue attr = findAttribute(ipAddress_oid); 601 602 return getString(attr); 603 } 604 605 /** 606 * Returns a string form of the X.500 distinguished name. 607 * The format of the string is from RFC 1779. The returned string 608 * may contain non-standardised keywords for more readability 609 * (keywords from RFCs 1779, 2253, and 3280). 610 */ toString()611 public String toString() { 612 if (dn == null) { 613 generateDN(); 614 } 615 return dn; 616 } 617 618 /** 619 * Returns a string form of the X.500 distinguished name 620 * using the algorithm defined in RFC 1779. Only standard attribute type 621 * keywords defined in RFC 1779 are emitted. 622 */ getRFC1779Name()623 public String getRFC1779Name() { 624 return getRFC1779Name(Collections.<String, String>emptyMap()); 625 } 626 627 /** 628 * Returns a string form of the X.500 distinguished name 629 * using the algorithm defined in RFC 1779. Attribute type 630 * keywords defined in RFC 1779 are emitted, as well as additional 631 * keywords contained in the OID/keyword map. 632 */ getRFC1779Name(Map<String, String> oidMap)633 public String getRFC1779Name(Map<String, String> oidMap) 634 throws IllegalArgumentException { 635 if (oidMap.isEmpty()) { 636 // return cached result 637 if (rfc1779Dn != null) { 638 return rfc1779Dn; 639 } else { 640 rfc1779Dn = generateRFC1779DN(oidMap); 641 return rfc1779Dn; 642 } 643 } 644 return generateRFC1779DN(oidMap); 645 } 646 647 /** 648 * Returns a string form of the X.500 distinguished name 649 * using the algorithm defined in RFC 2253. Only standard attribute type 650 * keywords defined in RFC 2253 are emitted. 651 */ getRFC2253Name()652 public String getRFC2253Name() { 653 return getRFC2253Name(Collections.<String, String>emptyMap()); 654 } 655 656 /** 657 * Returns a string form of the X.500 distinguished name 658 * using the algorithm defined in RFC 2253. Attribute type 659 * keywords defined in RFC 2253 are emitted, as well as additional 660 * keywords contained in the OID/keyword map. 661 */ getRFC2253Name(Map<String, String> oidMap)662 public String getRFC2253Name(Map<String, String> oidMap) { 663 /* check for and return cached name */ 664 if (oidMap.isEmpty()) { 665 if (rfc2253Dn != null) { 666 return rfc2253Dn; 667 } else { 668 rfc2253Dn = generateRFC2253DN(oidMap); 669 return rfc2253Dn; 670 } 671 } 672 return generateRFC2253DN(oidMap); 673 } 674 generateRFC2253DN(Map<String, String> oidMap)675 private String generateRFC2253DN(Map<String, String> oidMap) { 676 /* 677 * Section 2.1 : if the RDNSequence is an empty sequence 678 * the result is the empty or zero length string. 679 */ 680 if (names.length == 0) { 681 return ""; 682 } 683 684 /* 685 * 2.1 (continued) : Otherwise, the output consists of the string 686 * encodings of each RelativeDistinguishedName in the RDNSequence 687 * (according to 2.2), starting with the last element of the sequence 688 * and moving backwards toward the first. 689 * 690 * The encodings of adjoining RelativeDistinguishedNames are separated 691 * by a comma character (',' ASCII 44). 692 */ 693 StringBuilder fullname = new StringBuilder(48); 694 for (int i = names.length - 1; i >= 0; i--) { 695 if (i < names.length - 1) { 696 fullname.append(','); 697 } 698 fullname.append(names[i].toRFC2253String(oidMap)); 699 } 700 return fullname.toString(); 701 } 702 getRFC2253CanonicalName()703 public String getRFC2253CanonicalName() { 704 /* check for and return cached name */ 705 if (canonicalDn != null) { 706 return canonicalDn; 707 } 708 /* 709 * Section 2.1 : if the RDNSequence is an empty sequence 710 * the result is the empty or zero length string. 711 */ 712 if (names.length == 0) { 713 canonicalDn = ""; 714 return canonicalDn; 715 } 716 717 /* 718 * 2.1 (continued) : Otherwise, the output consists of the string 719 * encodings of each RelativeDistinguishedName in the RDNSequence 720 * (according to 2.2), starting with the last element of the sequence 721 * and moving backwards toward the first. 722 * 723 * The encodings of adjoining RelativeDistinguishedNames are separated 724 * by a comma character (',' ASCII 44). 725 */ 726 StringBuilder fullname = new StringBuilder(48); 727 for (int i = names.length - 1; i >= 0; i--) { 728 if (i < names.length - 1) { 729 fullname.append(','); 730 } 731 fullname.append(names[i].toRFC2253String(true)); 732 } 733 canonicalDn = fullname.toString(); 734 return canonicalDn; 735 } 736 737 /** 738 * Returns the value of toString(). This call is needed to 739 * implement the java.security.Principal interface. 740 */ getName()741 public String getName() { return toString(); } 742 743 /** 744 * Find the first instance of this attribute in a "top down" 745 * search of all the attributes in the name. 746 */ findAttribute(ObjectIdentifier attribute)747 private DerValue findAttribute(ObjectIdentifier attribute) { 748 if (names != null) { 749 for (int i = 0; i < names.length; i++) { 750 DerValue value = names[i].findAttribute(attribute); 751 if (value != null) { 752 return value; 753 } 754 } 755 } 756 return null; 757 } 758 759 /** 760 * Find the most specific ("last") attribute of the given 761 * type. 762 */ findMostSpecificAttribute(ObjectIdentifier attribute)763 public DerValue findMostSpecificAttribute(ObjectIdentifier attribute) { 764 if (names != null) { 765 for (int i = names.length - 1; i >= 0; i--) { 766 DerValue value = names[i].findAttribute(attribute); 767 if (value != null) { 768 return value; 769 } 770 } 771 } 772 return null; 773 } 774 775 /****************************************************************/ 776 parseDER(DerInputStream in)777 private void parseDER(DerInputStream in) throws IOException { 778 // 779 // X.500 names are a "SEQUENCE OF" RDNs, which means zero or 780 // more and order matters. We scan them in order, which 781 // conventionally is big-endian. 782 // 783 DerValue[] nameseq = null; 784 byte[] derBytes = in.toByteArray(); 785 786 try { 787 nameseq = in.getSequence(5); 788 } catch (IOException ioe) { 789 if (derBytes == null) { 790 nameseq = null; 791 } else { 792 DerValue derVal = new DerValue(DerValue.tag_Sequence, 793 derBytes); 794 derBytes = derVal.toByteArray(); 795 nameseq = new DerInputStream(derBytes).getSequence(5); 796 } 797 } 798 799 if (nameseq == null) { 800 names = new RDN[0]; 801 } else { 802 names = new RDN[nameseq.length]; 803 for (int i = 0; i < nameseq.length; i++) { 804 names[i] = new RDN(nameseq[i]); 805 } 806 } 807 } 808 809 /** 810 * Encodes the name in DER-encoded form. 811 * 812 * @deprecated Use encode() instead 813 * @param out where to put the DER-encoded X.500 name 814 */ 815 @Deprecated emit(DerOutputStream out)816 public void emit(DerOutputStream out) throws IOException { 817 encode(out); 818 } 819 820 /** 821 * Encodes the name in DER-encoded form. 822 * 823 * @param out where to put the DER-encoded X.500 name 824 */ encode(DerOutputStream out)825 public void encode(DerOutputStream out) throws IOException { 826 DerOutputStream tmp = new DerOutputStream(); 827 for (int i = 0; i < names.length; i++) { 828 names[i].encode(tmp); 829 } 830 out.write(DerValue.tag_Sequence, tmp); 831 } 832 833 /** 834 * Returned the encoding as an uncloned byte array. Callers must 835 * guarantee that they neither modify it not expose it to untrusted 836 * code. 837 */ getEncodedInternal()838 public byte[] getEncodedInternal() throws IOException { 839 if (encoded == null) { 840 DerOutputStream out = new DerOutputStream(); 841 DerOutputStream tmp = new DerOutputStream(); 842 for (int i = 0; i < names.length; i++) { 843 names[i].encode(tmp); 844 } 845 out.write(DerValue.tag_Sequence, tmp); 846 encoded = out.toByteArray(); 847 } 848 return encoded; 849 } 850 851 /** 852 * Gets the name in DER-encoded form. 853 * 854 * @return the DER encoded byte array of this name. 855 */ getEncoded()856 public byte[] getEncoded() throws IOException { 857 return getEncodedInternal().clone(); 858 } 859 860 /* 861 * Parses a Distinguished Name (DN) in printable representation. 862 * 863 * According to RFC 1779, RDNs in a DN are separated by comma. 864 * The following examples show both methods of quoting a comma, so that it 865 * is not considered a separator: 866 * 867 * O="Sue, Grabbit and Runn" or 868 * O=Sue\, Grabbit and Runn 869 * 870 * This method can parse RFC 1779, 2253 or 4514 DNs and non-standard 3280 871 * keywords. Additional keywords can be specified in the keyword/OID map. 872 */ parseDN(String input, Map<String, String> keywordMap)873 private void parseDN(String input, Map<String, String> keywordMap) 874 throws IOException { 875 if (input == null || input.length() == 0) { 876 names = new RDN[0]; 877 return; 878 } 879 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 /** 949 * Disallow new lines and tabs at the beginning of DN. 950 * 951 * @throws java.lang.IllegalArgumentException if the DN starts with new line or tab. 952 */ checkNoNewLinesNorTabsAtBeginningOfDN(String input)953 private void checkNoNewLinesNorTabsAtBeginningOfDN(String input) { 954 for (int i = 0; i < input.length(); i++) { 955 char c = input.charAt(i); 956 if (c != ' ') { 957 if (c == '\t' || c == '\n') { 958 throw new IllegalArgumentException("DN cannot start with newline nor tab"); 959 } 960 break; 961 } 962 } 963 } 964 parseRFC2253DN(String dnString)965 private void parseRFC2253DN(String dnString) throws IOException { 966 if (dnString.length() == 0) { 967 names = new RDN[0]; 968 return; 969 } 970 971 List<RDN> dnVector = new ArrayList<>(); 972 int dnOffset = 0; 973 String rdnString; 974 int searchOffset = 0; 975 int rdnEnd = dnString.indexOf(','); 976 while (rdnEnd >=0) { 977 /* 978 * We have encountered an RDN delimiter (comma). 979 * If the comma in the RDN under consideration is 980 * preceded by a backslash (escape), it 981 * is part of the RDN. Otherwise, it is used as a separator, to 982 * delimit the RDN under consideration from any subsequent RDNs. 983 */ 984 if (rdnEnd > 0 && !escaped(rdnEnd, searchOffset, dnString)) { 985 986 /* 987 * Comma is a separator 988 */ 989 rdnString = dnString.substring(dnOffset, rdnEnd); 990 991 // Parse RDN, and store it in vector 992 RDN rdn = new RDN(rdnString, "RFC2253"); 993 dnVector.add(rdn); 994 995 // Increase the offset 996 dnOffset = rdnEnd + 1; 997 } 998 999 searchOffset = rdnEnd + 1; 1000 rdnEnd = dnString.indexOf(',', searchOffset); 1001 } 1002 1003 // Parse last or only RDN, and store it in vector 1004 rdnString = dnString.substring(dnOffset); 1005 RDN rdn = new RDN(rdnString, "RFC2253"); 1006 dnVector.add(rdn); 1007 1008 /* 1009 * Store the vector elements as an array of RDNs 1010 * NOTE: It's only on output that little-endian ordering is used. 1011 */ 1012 Collections.reverse(dnVector); 1013 names = dnVector.toArray(new RDN[dnVector.size()]); 1014 } 1015 1016 /* 1017 * Counts double quotes in string. 1018 * Escaped quotes are ignored. 1019 */ countQuotes(String string, int from, int to)1020 static int countQuotes(String string, int from, int to) { 1021 int count = 0; 1022 1023 int escape = 0; 1024 for (int i = from; i < to; i++) { 1025 if (string.charAt(i) == '"' && escape % 2 == 0) { 1026 count++; 1027 } 1028 escape = (string.charAt(i) == '\\') ? escape + 1 : 0; 1029 } 1030 1031 return count; 1032 } 1033 escaped(int rdnEnd, int searchOffset, String dnString)1034 private static boolean escaped 1035 (int rdnEnd, int searchOffset, String dnString) { 1036 1037 if (rdnEnd == 1 && dnString.charAt(rdnEnd - 1) == '\\') { 1038 1039 // case 1: 1040 // \, 1041 1042 return true; 1043 1044 } else if (rdnEnd > 1 && dnString.charAt(rdnEnd - 1) == '\\' && 1045 dnString.charAt(rdnEnd - 2) != '\\') { 1046 1047 // case 2: 1048 // foo\, 1049 1050 return true; 1051 1052 } else if (rdnEnd > 1 && dnString.charAt(rdnEnd - 1) == '\\' && 1053 dnString.charAt(rdnEnd - 2) == '\\') { 1054 1055 // case 3: 1056 // foo\\\\\, 1057 1058 int count = 0; 1059 rdnEnd--; // back up to last backSlash 1060 while (rdnEnd >= searchOffset) { 1061 if (dnString.charAt(rdnEnd) == '\\') { 1062 count++; // count consecutive backslashes 1063 } 1064 rdnEnd--; 1065 } 1066 1067 // if count is odd, then rdnEnd is escaped 1068 return (count % 2) != 0 ? true : false; 1069 1070 } else { 1071 return false; 1072 } 1073 } 1074 1075 /* 1076 * Dump the printable form of a distinguished name. Each relative 1077 * name is separated from the next by a ",", and assertions in the 1078 * relative names have "label=value" syntax. 1079 * 1080 * Uses RFC 1779 syntax (i.e. little-endian, comma separators) 1081 */ generateDN()1082 private void generateDN() { 1083 if (names.length == 1) { 1084 dn = names[0].toString(); 1085 return; 1086 } 1087 1088 StringBuilder sb = new StringBuilder(48); 1089 if (names != null) { 1090 for (int i = names.length - 1; i >= 0; i--) { 1091 if (i != names.length - 1) { 1092 sb.append(", "); 1093 } 1094 sb.append(names[i].toString()); 1095 } 1096 } 1097 dn = sb.toString(); 1098 } 1099 1100 /* 1101 * Dump the printable form of a distinguished name. Each relative 1102 * name is separated from the next by a ",", and assertions in the 1103 * relative names have "label=value" syntax. 1104 * 1105 * Uses RFC 1779 syntax (i.e. little-endian, comma separators) 1106 * Valid keywords from RFC 1779 are used. Additional keywords can be 1107 * specified in the OID/keyword map. 1108 */ generateRFC1779DN(Map<String, String> oidMap)1109 private String generateRFC1779DN(Map<String, String> oidMap) { 1110 if (names.length == 1) { 1111 return names[0].toRFC1779String(oidMap); 1112 } 1113 1114 StringBuilder sb = new StringBuilder(48); 1115 if (names != null) { 1116 for (int i = names.length - 1; i >= 0; i--) { 1117 if (i != names.length - 1) { 1118 sb.append(", "); 1119 } 1120 sb.append(names[i].toRFC1779String(oidMap)); 1121 } 1122 } 1123 return sb.toString(); 1124 } 1125 1126 /****************************************************************/ 1127 1128 /* 1129 * Maybe return a preallocated OID, to reduce storage costs 1130 * and speed recognition of common X.500 attributes. 1131 */ intern(ObjectIdentifier oid)1132 static ObjectIdentifier intern(ObjectIdentifier oid) { 1133 ObjectIdentifier interned = internedOIDs.get(oid); 1134 if (interned != null) { 1135 return interned; 1136 } 1137 internedOIDs.put(oid, oid); 1138 return oid; 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 */ constrains(GeneralNameInterface inputName)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 */ isWithinSubtree(X500Name other)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 */ subtreeDepth()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 */ commonAncestor(X500Name other)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 */ asX500Principal()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 */ asX500Name(X500Principal p)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