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