      1 /*
      2  * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25
     26 package javax.security.auth.x500;
     27
     28 import java.io.*;
     29 import java.security.Principal;
     30 import java.util.Collections;
     31 import java.util.Map;
     32 import sun.security.x509.X500Name;
     33 import sun.security.util.*;
     34
     35 /**
     36  * <p> This class represents an X.500 {@code Principal}.
     37  * {@code X500Principal}s are represented by distinguished names such as
     38  * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US".
     39  *
     40  * <p> This class can be instantiated by using a string representation
     41  * of the distinguished name, or by using the ASN.1 DER encoded byte
     42  * representation of the distinguished name.  The current specification
     43  * for the string representation of a distinguished name is defined in
     44  * <a href="http://tools.ietf.org/html/rfc2253">RFC 2253: Lightweight
     45  * Directory Access Protocol (v3): UTF-8 String Representation of
     46  * Distinguished Names</a>. This class, however, accepts string formats from
     47  * both RFC 2253 and <a href="http://tools.ietf.org/html/rfc1779">RFC 1779:
     48  * A String Representation of Distinguished Names</a>, and also recognizes
     49  * attribute type keywords whose OIDs (Object Identifiers) are defined in
     50  * <a href="http://tools.ietf.org/html/rfc5280">RFC 5280: Internet X.509
     51  * Public Key Infrastructure Certificate and CRL Profile</a>.
     52  *
     53  * <p> The string representation for this {@code X500Principal}
     54  * can be obtained by calling the {@code getName} methods.
     55  *
     56  * <p> Note that the {@code getSubjectX500Principal} and
     57  * {@code getIssuerX500Principal} methods of
     58  * {@code X509Certificate} return X500Principals representing the
     59  * issuer and subject fields of the certificate.
     60  *
     61  * @see java.security.cert.X509Certificate
     62  * @since 1.4
     63  */
     64 public final class X500Principal implements Principal, java.io.Serializable {
     65
     66     @java.io.Serial
     67     private static final long serialVersionUID = -500463348111345721L;
     68
     69     /**
     70      * RFC 1779 String format of Distinguished Names.
     71      */
     72     public static final String RFC1779 = "RFC1779";
     73     /**
     74      * RFC 2253 String format of Distinguished Names.
     75      */
     76     public static final String RFC2253 = "RFC2253";
     77     /**
     78      * Canonical String format of Distinguished Names.
     79      */
     80     public static final String CANONICAL = "CANONICAL";
     81
     82     /**
     83      * The X500Name representing this principal.
     84      *
     85      * NOTE: this field is reflectively accessed from within X500Name.
     86      */
     87     private transient X500Name thisX500Name;
     88
     89     /**
     90      * Creates an X500Principal by wrapping an X500Name.
     91      *
     92      * NOTE: The constructor is package private. It is intended to be accessed
     93      * using privileged reflection from classes in sun.security.*.
     94      * Currently referenced from sun.security.x509.X500Name.asX500Principal().
     95      */
     96     X500Principal(X500Name x500Name) {
     97         thisX500Name = x500Name;
     98     }
     99
    100     /**
    101      * Creates an {@code X500Principal} from a string representation of
    102      * an X.500 distinguished name (ex:
    103      * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
    104      * The distinguished name must be specified using the grammar defined in
    105      * RFC 1779 or RFC 2253 (either format is acceptable).
    106      *
    107      * <p>This constructor recognizes the attribute type keywords
    108      * defined in RFC 1779 and RFC 2253
    109      * (and listed in {@link #getName(String format) getName(String format)}),
    110      * as well as the T, DNQ or DNQUALIFIER, SURNAME, GIVENNAME, INITIALS,
    111      * GENERATION, EMAILADDRESS, and SERIALNUMBER keywords whose Object
    112      * Identifiers (OIDs) are defined in RFC 5280.
    113      * Any other attribute type must be specified as an OID.
    114      *
    115      * <p>This implementation enforces a more restrictive OID syntax than
    116      * defined in RFC 1779 and 2253. It uses the more correct syntax defined in
    117      * <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which
    118      * specifies that OIDs contain at least 2 digits:
    119      *
    120      * <p>{@code numericoid = number 1*( DOT number ) }
    121      *
    122      * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
    123      * @exception NullPointerException if the {@code name}
    124      *                  is {@code null}
    125      * @exception IllegalArgumentException if the {@code name}
    126      *                  is improperly specified
    127      */
    128     public X500Principal(String name) {
    129         this(name, Collections.<String, String>emptyMap());
    130     }
    131
    132     /**
    133      * Creates an {@code X500Principal} from a string representation of
    134      * an X.500 distinguished name (ex:
    135      * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
    136      * The distinguished name must be specified using the grammar defined in
    137      * RFC 1779 or RFC 2253 (either format is acceptable).
    138      *
    139      * <p> This constructor recognizes the attribute type keywords specified
    140      * in {@link #X500Principal(String)} and also recognizes additional
    141      * keywords that have entries in the {@code keywordMap} parameter.
    142      * Keyword entries in the keywordMap take precedence over the default
    143      * keywords recognized by {@code X500Principal(String)}. Keywords
    144      * MUST be specified in all upper-case, otherwise they will be ignored.
    145      * Improperly specified keywords are ignored; however if a keyword in the
    146      * name maps to an improperly specified Object Identifier (OID), an
    147      * {@code IllegalArgumentException} is thrown. It is permissible to
    148      * have 2 different keywords that map to the same OID.
    149      *
    150      * <p>This implementation enforces a more restrictive OID syntax than
    151      * defined in RFC 1779 and 2253. It uses the more correct syntax defined in
    152      * <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which
    153      * specifies that OIDs contain at least 2 digits:
    154      *
    155      * <p>{@code numericoid = number 1*( DOT number ) }
    156      *
    157      * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
    158      * @param keywordMap an attribute type keyword map, where each key is a
    159      *   keyword String that maps to a corresponding object identifier in String
    160      *   form (a sequence of nonnegative integers separated by periods). The map
    161      *   may be empty but never {@code null}.
    162      * @exception NullPointerException if {@code name} or
    163      *   {@code keywordMap} is {@code null}
    164      * @exception IllegalArgumentException if the {@code name} is
    165      *   improperly specified or a keyword in the {@code name} maps to an
    166      *   OID that is not in the correct form
    167      * @since 1.6
    168      */
    169     public X500Principal(String name, Map<String, String> keywordMap) {
    170         if (name == null) {
    171             throw new NullPointerException
    172                 (sun.security.util.ResourcesMgr.getString
    173                 ("provided.null.name"));
    174         }
    175         if (keywordMap == null) {
    176             throw new NullPointerException
    177                 (sun.security.util.ResourcesMgr.getString
    178                 ("provided.null.keyword.map"));
    179         }
    180
    181         try {
    182             thisX500Name = new X500Name(name, keywordMap);
    183         } catch (Exception e) {
    184             IllegalArgumentException iae = new IllegalArgumentException
    185                         ("improperly specified input name: " + name);
    186             iae.initCause(e);
    187             throw iae;
    188         }
    189     }
    190
    191     /**
    192      * Creates an {@code X500Principal} from a distinguished name in
    193      * ASN.1 DER encoded form. The ASN.1 notation for this structure is as
    194      * follows.
    195      * <pre>{@code
    196      * Name ::= CHOICE {
    197      *   RDNSequence }
    198      *
    199      * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
    200      *
    201      * RelativeDistinguishedName ::=
    202      *   SET SIZE (1 .. MAX) OF AttributeTypeAndValue
    203      *
    204      * AttributeTypeAndValue ::= SEQUENCE {
    205      *   type     AttributeType,
    206      *   value    AttributeValue }
    207      *
    208      * AttributeType ::= OBJECT IDENTIFIER
    209      *
    210      * AttributeValue ::= ANY DEFINED BY AttributeType
    211      * ....
    212      * DirectoryString ::= CHOICE {
    213      *       teletexString           TeletexString (SIZE (1..MAX)),
    214      *       printableString         PrintableString (SIZE (1..MAX)),
    215      *       universalString         UniversalString (SIZE (1..MAX)),
    216      *       utf8String              UTF8String (SIZE (1.. MAX)),
    217      *       bmpString               BMPString (SIZE (1..MAX)) }
    218      * }</pre>
    219      *
    220      * @param name a byte array containing the distinguished name in ASN.1
    221      * DER encoded form
    222      * @throws IllegalArgumentException if an encoding error occurs
    223      *          (incorrect form for DN)
    224      */
    225     public X500Principal(byte[] name) {
    226         try {
    227             thisX500Name = new X500Name(name);
    228         } catch (Exception e) {
    229             IllegalArgumentException iae = new IllegalArgumentException
    230                         ("improperly specified input name");
    231             iae.initCause(e);
    232             throw iae;
    233         }
    234     }
    235
    236     /**
    237      * Creates an {@code X500Principal} from an {@code InputStream}
    238      * containing the distinguished name in ASN.1 DER encoded form.
    239      * The ASN.1 notation for this structure is supplied in the
    240      * documentation for
    241      * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
    242      *
    243      * <p> The read position of the input stream is positioned
    244      * to the next available byte after the encoded distinguished name.
    245      *
    246      * @param is an {@code InputStream} containing the distinguished
    247      *          name in ASN.1 DER encoded form
    248      *
    249      * @exception NullPointerException if the {@code InputStream}
    250      *          is {@code null}
    251      * @exception IllegalArgumentException if an encoding error occurs
    252      *          (incorrect form for DN)
    253      */
    254     public X500Principal(InputStream is) {
    255         if (is == null) {
    256             throw new NullPointerException("provided null input stream");
    257         }
    258
    259         try {
    260             if (is.markSupported())
    261                 is.mark(is.available() + 1);
    262             DerValue der = new DerValue(is);
    263             thisX500Name = new X500Name(der.data);
    264         } catch (Exception e) {
    265             if (is.markSupported()) {
    266                 try {
    267                     is.reset();
    268                 } catch (IOException ioe) {
    269                     IllegalArgumentException iae = new IllegalArgumentException
    270                         ("improperly specified input stream " +
    271                         ("and unable to reset input stream"));
    272                     iae.initCause(e);
    273                     throw iae;
    274                 }
    275             }
    276             IllegalArgumentException iae = new IllegalArgumentException
    277                         ("improperly specified input stream");
    278             iae.initCause(e);
    279             throw iae;
    280         }
    281     }
    282
    283     /**
    284      * Returns a string representation of the X.500 distinguished name using
    285      * the format defined in RFC 2253.
    286      *
    287      * <p>This method is equivalent to calling
    288      * {@code getName(X500Principal.RFC2253)}.
    289      *
    290      * @return the distinguished name of this {@code X500Principal}
    291      */
    292     public String getName() {
    293         return getName(X500Principal.RFC2253);
    294     }
    295
    296     /**
    297      * Returns a string representation of the X.500 distinguished name
    298      * using the specified format. Valid values for the format are
    299      * "RFC1779", "RFC2253", and "CANONICAL" (case insensitive).
    300      *
    301      * <p> If "RFC1779" is specified as the format,
    302      * this method emits the attribute type keywords defined in
    303      * RFC 1779 (CN, L, ST, O, OU, C, STREET).
    304      * Any other attribute type is emitted as an OID.
    305      *
    306      * <p> If "RFC2253" is specified as the format,
    307      * this method emits the attribute type keywords defined in
    308      * RFC 2253 (CN, L, ST, O, OU, C, STREET, DC, UID).
    309      * Any other attribute type is emitted as an OID.
    310      * Under a strict reading, RFC 2253 only specifies a UTF-8 string
    311      * representation. The String returned by this method is the
    312      * Unicode string achieved by decoding this UTF-8 representation.
    313      *
    314      * <p> If "CANONICAL" is specified as the format,
    315      * this method returns an RFC 2253 conformant string representation
    316      * with the following additional canonicalizations:
    317      *
    318      * <ol>
    319      * <li> Leading zeros are removed from attribute types
    320      *          that are encoded as dotted decimal OIDs
    321      * <li> DirectoryString attribute values of type
    322      *          PrintableString and UTF8String are not
    323      *          output in hexadecimal format
    324      * <li> DirectoryString attribute values of types
    325      *          other than PrintableString and UTF8String
    326      *          are output in hexadecimal format
    327      * <li> Leading and trailing white space characters
    328      *          are removed from non-hexadecimal attribute values
    329      *          (unless the value consists entirely of white space characters)
    330      * <li> Internal substrings of one or more white space characters are
    331      *          converted to a single space in non-hexadecimal
    332      *          attribute values
    333      * <li> Relative Distinguished Names containing more than one
    334      *          Attribute Value Assertion (AVA) are output in the
    335      *          following order: an alphabetical ordering of AVAs
    336      *          containing standard keywords, followed by a numeric
    337      *          ordering of AVAs containing OID keywords.
    338      * <li> The only characters in attribute values that are escaped are
    339      *          those which section 2.4 of RFC 2253 states must be escaped
    340      *          (they are escaped using a preceding backslash character)
    341      * <li> The entire name is converted to upper case
    342      *          using {@code String.toUpperCase(Locale.US)}
    343      * <li> The entire name is converted to lower case
    344      *          using {@code String.toLowerCase(Locale.US)}
    345      * <li> The name is finally normalized using normalization form KD,
    346      *          as described in the Unicode Standard and UAX #15
    347      * </ol>
    348      *
    349      * <p> Additional standard formats may be introduced in the future.
    350      *
    351      * @param format the format to use
    352      *
    353      * @return a string representation of this {@code X500Principal}
    354      *          using the specified format
    355      * @throws IllegalArgumentException if the specified format is invalid
    356      *          or null
    357      */
    358     public String getName(String format) {
    359         if (format != null) {
    360             if (format.equalsIgnoreCase(RFC1779)) {
    361                 return thisX500Name.getRFC1779Name();
    362             } else if (format.equalsIgnoreCase(RFC2253)) {
    363                 return thisX500Name.getRFC2253Name();
    364             } else if (format.equalsIgnoreCase(CANONICAL)) {
    365                 return thisX500Name.getRFC2253CanonicalName();
    366             }
    367         }
    368         throw new IllegalArgumentException("invalid format specified");
    369     }
    370
    371     /**
    372      * Returns a string representation of the X.500 distinguished name
    373      * using the specified format. Valid values for the format are
    374      * "RFC1779" and "RFC2253" (case insensitive). "CANONICAL" is not
    375      * permitted and an {@code IllegalArgumentException} will be thrown.
    376      *
    377      * <p>This method returns Strings in the format as specified in
    378      * {@link #getName(String)} and also emits additional attribute type
    379      * keywords for OIDs that have entries in the {@code oidMap}
    380      * parameter. OID entries in the oidMap take precedence over the default
    381      * OIDs recognized by {@code getName(String)}.
    382      * Improperly specified OIDs are ignored; however if an OID
    383      * in the name maps to an improperly specified keyword, an
    384      * {@code IllegalArgumentException} is thrown.
    385      *
    386      * <p> Additional standard formats may be introduced in the future.
    387      *
    388      * <p> Warning: additional attribute type keywords may not be recognized
    389      * by other implementations; therefore do not use this method if
    390      * you are unsure if these keywords will be recognized by other
    391      * implementations.
    392      *
    393      * @param format the format to use
    394      * @param oidMap an OID map, where each key is an object identifier in
    395      *  String form (a sequence of nonnegative integers separated by periods)
    396      *  that maps to a corresponding attribute type keyword String.
    397      *  The map may be empty but never {@code null}.
    398      * @return a string representation of this {@code X500Principal}
    399      *          using the specified format
    400      * @throws IllegalArgumentException if the specified format is invalid,
    401      *  null, or an OID in the name maps to an improperly specified keyword
    402      * @throws NullPointerException if {@code oidMap} is {@code null}
    403      * @since 1.6
    404      */
    405     public String getName(String format, Map<String, String> oidMap) {
    406         if (oidMap == null) {
    407             throw new NullPointerException
    408                 (sun.security.util.ResourcesMgr.getString
    409                 ("provided.null.OID.map"));
    410         }
    411         if (format != null) {
    412             if (format.equalsIgnoreCase(RFC1779)) {
    413                 return thisX500Name.getRFC1779Name(oidMap);
    414             } else if (format.equalsIgnoreCase(RFC2253)) {
    415                 return thisX500Name.getRFC2253Name(oidMap);
    416             }
    417         }
    418         throw new IllegalArgumentException("invalid format specified");
    419     }
    420
    421     /**
    422      * Returns the distinguished name in ASN.1 DER encoded form. The ASN.1
    423      * notation for this structure is supplied in the documentation for
    424      * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
    425      *
    426      * <p>Note that the byte array returned is cloned to protect against
    427      * subsequent modifications.
    428      *
    429      * @return a byte array containing the distinguished name in ASN.1 DER
    430      * encoded form
    431      */
    432     public byte[] getEncoded() {
    433         try {
    434             return thisX500Name.getEncoded();
    435         } catch (IOException e) {
    436             throw new RuntimeException("unable to get encoding", e);
    437         }
    438     }
    439
    440     /**
    441      * Return a user-friendly string representation of this
    442      * {@code X500Principal}.
    443      *
    444      * @return a string representation of this {@code X500Principal}
    445      */
    446     public String toString() {
    447         return thisX500Name.toString();
    448     }
    449
    450     /**
    451      * Compares the specified {@code Object} with this
    452      * {@code X500Principal} for equality.
    453      *
    454      * <p> Specifically, this method returns {@code true} if
    455      * the {@code Object} <i>o</i> is an {@code X500Principal}
    456      * and if the respective canonical string representations
    457      * (obtained via the {@code getName(X500Principal.CANONICAL)} method)
    458      * of this object and <i>o</i> are equal.
    459      *
    460      * <p> This implementation is compliant with the requirements of RFC 5280.
    461      *
    462      * @param o Object to be compared for equality with this
    463      *          {@code X500Principal}
    464      *
    465      * @return {@code true} if the specified {@code Object} is equal
    466      *          to this {@code X500Principal}, {@code false} otherwise
    467      */
    468     public boolean equals(Object o) {
    469         if (this == o) {
    470             return true;
    471         }
    472         if (o instanceof X500Principal == false) {
    473             return false;
    474         }
    475         X500Principal other = (X500Principal)o;
    476         return this.thisX500Name.equals(other.thisX500Name);
    477     }
    478
    479     /**
    480      * Return a hash code for this {@code X500Principal}.
    481      *
    482      * <p> The hash code is calculated via:
    483      * {@code getName(X500Principal.CANONICAL).hashCode()}
    484      *
    485      * @return a hash code for this {@code X500Principal}
    486      */
    487     public int hashCode() {
    488         return thisX500Name.hashCode();
    489     }
    490
    491     /**
    492      * Save the X500Principal object to a stream.
    493      *
    494      * @serialData this {@code X500Principal} is serialized
    495      *          by writing out its DER-encoded form
    496      *          (the value of {@code getEncoded} is serialized).

    497      */
    498     @java.io.Serial
    499     private void writeObject(java.io.ObjectOutputStream s)
    500         throws IOException {
    501         s.writeObject(thisX500Name.getEncodedInternal());
    502     }
    503
    504     /**
    505      * Reads this object from a stream (i.e., deserializes it).

    506      */
    507     @java.io.Serial
    508     private void readObject(java.io.ObjectInputStream s)
    509         throws java.io.IOException,
    510                java.io.NotActiveException,
    511                ClassNotFoundException {
    512
    513         // re-create thisX500Name
    514         thisX500Name = new X500Name((byte[])s.readObject());
    515     }
    516 }
    --- EOF ---