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