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