1 /*
   2  * Copyright (c) 2000, 2013, 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://www.ietf.org/rfc/rfc2253.txt">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://www.ietf.org/rfc/rfc1779.txt">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://www.ietf.org/rfc/rfc3280.txt">RFC 3280: 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     private static final long serialVersionUID = -500463348111345721L;
  67 
  68     /**
  69      * RFC 1779 String format of Distinguished Names.
  70      */
  71     public static final String RFC1779 = "RFC1779";
  72     /**
  73      * RFC 2253 String format of Distinguished Names.
  74      */
  75     public static final String RFC2253 = "RFC2253";
  76     /**
  77      * Canonical String format of Distinguished Names.
  78      */
  79     public static final String CANONICAL = "CANONICAL";
  80 
  81     /**
  82      * The X500Name representing this principal.
  83      *
  84      * NOTE: this field is reflectively accessed from within X500Name.
  85      */
  86     private transient X500Name thisX500Name;
  87 
  88     /**
  89      * Creates an X500Principal by wrapping an X500Name.
  90      *
  91      * NOTE: The constructor is package private. It is intended to be accessed
  92      * using privileged reflection from classes in sun.security.*.
  93      * Currently referenced from sun.security.x509.X500Name.asX500Principal().
  94      */
  95     X500Principal(X500Name x500Name) {
  96         thisX500Name = x500Name;
  97     }
  98 
  99     /**
 100      * Creates an {@code X500Principal} from a string representation of
 101      * an X.500 distinguished name (ex:
 102      * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
 103      * The distinguished name must be specified using the grammar defined in
 104      * RFC 1779 or RFC 2253 (either format is acceptable).
 105      *
 106      * <p>This constructor recognizes the attribute type keywords
 107      * defined in RFC 1779 and RFC 2253
 108      * (and listed in {@link #getName(String format) getName(String format)}),
 109      * as well as the T, DNQ or DNQUALIFIER, SURNAME, GIVENNAME, INITIALS,
 110      * GENERATION, EMAILADDRESS, and SERIALNUMBER keywords whose Object
 111      * Identifiers (OIDs) are defined in RFC 3280 and its successor.
 112      * Any other attribute type must be specified as an OID.
 113      *
 114      * <p>This implementation enforces a more restrictive OID syntax than
 115      * defined in RFC 1779 and 2253. It uses the more correct syntax defined in
 116      * <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which
 117      * specifies that OIDs contain at least 2 digits:
 118      *
 119      * <p>{@code numericoid = number 1*( DOT number ) }
 120      *
 121      * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
 122      * @exception NullPointerException if the {@code name}
 123      *                  is {@code null}
 124      * @exception IllegalArgumentException if the {@code name}
 125      *                  is improperly specified
 126      */
 127     public X500Principal(String name) {
 128         this(name, Collections.<String, String>emptyMap());
 129     }
 130 
 131     /**
 132      * Creates an {@code X500Principal} from a string representation of
 133      * an X.500 distinguished name (ex:
 134      * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
 135      * The distinguished name must be specified using the grammar defined in
 136      * RFC 1779 or RFC 2253 (either format is acceptable).
 137      *
 138      * <p> This constructor recognizes the attribute type keywords specified
 139      * in {@link #X500Principal(String)} and also recognizes additional
 140      * keywords that have entries in the {@code keywordMap} parameter.
 141      * Keyword entries in the keywordMap take precedence over the default
 142      * keywords recognized by {@code X500Principal(String)}. Keywords
 143      * MUST be specified in all upper-case, otherwise they will be ignored.
 144      * Improperly specified keywords are ignored; however if a keyword in the
 145      * name maps to an improperly specified Object Identifier (OID), an
 146      * {@code IllegalArgumentException} is thrown. It is permissible to
 147      * have 2 different keywords that map to the same OID.
 148      *
 149      * <p>This implementation enforces a more restrictive OID syntax than
 150      * defined in RFC 1779 and 2253. It uses the more correct syntax defined in
 151      * <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which
 152      * specifies that OIDs contain at least 2 digits:
 153      *
 154      * <p>{@code numericoid = number 1*( DOT number ) }
 155      *
 156      * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
 157      * @param keywordMap an attribute type keyword map, where each key is a
 158      *   keyword String that maps to a corresponding object identifier in String
 159      *   form (a sequence of nonnegative integers separated by periods). The map
 160      *   may be empty but never {@code null}.
 161      * @exception NullPointerException if {@code name} or
 162      *   {@code keywordMap} is {@code null}
 163      * @exception IllegalArgumentException if the {@code name} is
 164      *   improperly specified or a keyword in the {@code name} maps to an
 165      *   OID that is not in the correct form
 166      * @since 1.6
 167      */
 168     public X500Principal(String name, Map<String, String> keywordMap) {
 169         if (name == null) {
 170             throw new NullPointerException
 171                 (sun.security.util.ResourcesMgr.getString
 172                 ("provided.null.name"));
 173         }
 174         if (keywordMap == null) {
 175             throw new NullPointerException
 176                 (sun.security.util.ResourcesMgr.getString
 177                 ("provided.null.keyword.map"));
 178         }
 179 
 180         try {
 181             thisX500Name = new X500Name(name, keywordMap);
 182         } catch (Exception e) {
 183             IllegalArgumentException iae = new IllegalArgumentException
 184                         ("improperly specified input name: " + name);
 185             iae.initCause(e);
 186             throw iae;
 187         }
 188     }
 189 
 190     /**
 191      * Creates an {@code X500Principal} from a distinguished name in
 192      * ASN.1 DER encoded form. The ASN.1 notation for this structure is as
 193      * follows.
 194      * <pre>{@code
 195      * Name ::= CHOICE {
 196      *   RDNSequence }
 197      *
 198      * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
 199      *
 200      * RelativeDistinguishedName ::=
 201      *   SET SIZE (1 .. MAX) OF AttributeTypeAndValue
 202      *
 203      * AttributeTypeAndValue ::= SEQUENCE {
 204      *   type     AttributeType,
 205      *   value    AttributeValue }
 206      *
 207      * AttributeType ::= OBJECT IDENTIFIER
 208      *
 209      * AttributeValue ::= ANY DEFINED BY AttributeType
 210      * ....
 211      * DirectoryString ::= CHOICE {
 212      *       teletexString           TeletexString (SIZE (1..MAX)),
 213      *       printableString         PrintableString (SIZE (1..MAX)),
 214      *       universalString         UniversalString (SIZE (1..MAX)),
 215      *       utf8String              UTF8String (SIZE (1.. MAX)),
 216      *       bmpString               BMPString (SIZE (1..MAX)) }
 217      * }</pre>
 218      *
 219      * @param name a byte array containing the distinguished name in ASN.1
 220      * DER encoded form
 221      * @throws IllegalArgumentException if an encoding error occurs
 222      *          (incorrect form for DN)
 223      */
 224     public X500Principal(byte[] name) {
 225         try {
 226             thisX500Name = new X500Name(name);
 227         } catch (Exception e) {
 228             IllegalArgumentException iae = new IllegalArgumentException
 229                         ("improperly specified input name");
 230             iae.initCause(e);
 231             throw iae;
 232         }
 233     }
 234 
 235     /**
 236      * Creates an {@code X500Principal} from an {@code InputStream}
 237      * containing the distinguished name in ASN.1 DER encoded form.
 238      * The ASN.1 notation for this structure is supplied in the
 239      * documentation for
 240      * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
 241      *
 242      * <p> The read position of the input stream is positioned
 243      * to the next available byte after the encoded distinguished name.
 244      *
 245      * @param is an {@code InputStream} containing the distinguished
 246      *          name in ASN.1 DER encoded form
 247      *
 248      * @exception NullPointerException if the {@code InputStream}
 249      *          is {@code null}
 250      * @exception IllegalArgumentException if an encoding error occurs
 251      *          (incorrect form for DN)
 252      */
 253     public X500Principal(InputStream is) {
 254         if (is == null) {
 255             throw new NullPointerException("provided null input stream");
 256         }
 257 
 258         try {
 259             if (is.markSupported())
 260                 is.mark(is.available() + 1);
 261             DerValue der = new DerValue(is);
 262             thisX500Name = new X500Name(der.data);
 263         } catch (Exception e) {
 264             if (is.markSupported()) {
 265                 try {
 266                     is.reset();
 267                 } catch (IOException ioe) {
 268                     IllegalArgumentException iae = new IllegalArgumentException
 269                         ("improperly specified input stream " +
 270                         ("and unable to reset input stream"));
 271                     iae.initCause(e);
 272                     throw iae;
 273                 }
 274             }
 275             IllegalArgumentException iae = new IllegalArgumentException
 276                         ("improperly specified input stream");
 277             iae.initCause(e);
 278             throw iae;
 279         }
 280     }
 281 
 282     /**
 283      * Returns a string representation of the X.500 distinguished name using
 284      * the format defined in RFC 2253.
 285      *
 286      * <p>This method is equivalent to calling
 287      * {@code getName(X500Principal.RFC2253)}.
 288      *
 289      * @return the distinguished name of this {@code X500Principal}
 290      */
 291     public String getName() {
 292         return getName(X500Principal.RFC2253);
 293     }
 294 
 295     /**
 296      * Returns a string representation of the X.500 distinguished name
 297      * using the specified format. Valid values for the format are
 298      * "RFC1779", "RFC2253", and "CANONICAL" (case insensitive).
 299      *
 300      * <p> If "RFC1779" is specified as the format,
 301      * this method emits the attribute type keywords defined in
 302      * RFC 1779 (CN, L, ST, O, OU, C, STREET).
 303      * Any other attribute type is emitted as an OID.
 304      *
 305      * <p> If "RFC2253" is specified as the format,
 306      * this method emits the attribute type keywords defined in
 307      * RFC 2253 (CN, L, ST, O, OU, C, STREET, DC, UID).
 308      * Any other attribute type is emitted as an OID.
 309      * Under a strict reading, RFC 2253 only specifies a UTF-8 string
 310      * representation. The String returned by this method is the
 311      * Unicode string achieved by decoding this UTF-8 representation.
 312      *
 313      * <p> If "CANONICAL" is specified as the format,
 314      * this method returns an RFC 2253 conformant string representation
 315      * with the following additional canonicalizations:
 316      *
 317      * <p><ol>
 318      * <li> Leading zeros are removed from attribute types
 319      *          that are encoded as dotted decimal OIDs
 320      * <li> DirectoryString attribute values of type
 321      *          PrintableString and UTF8String are not
 322      *          output in hexadecimal format
 323      * <li> DirectoryString attribute values of types
 324      *          other than PrintableString and UTF8String
 325      *          are output in hexadecimal format
 326      * <li> Leading and trailing white space characters
 327      *          are removed from non-hexadecimal attribute values
 328      *          (unless the value consists entirely of white space characters)
 329      * <li> Internal substrings of one or more white space characters are
 330      *          converted to a single space in non-hexadecimal
 331      *          attribute values
 332      * <li> Relative Distinguished Names containing more than one
 333      *          Attribute Value Assertion (AVA) are output in the
 334      *          following order: an alphabetical ordering of AVAs
 335      *          containing standard keywords, followed by a numeric
 336      *          ordering of AVAs containing OID keywords.
 337      * <li> The only characters in attribute values that are escaped are
 338      *          those which section 2.4 of RFC 2253 states must be escaped
 339      *          (they are escaped using a preceding backslash character)
 340      * <li> The entire name is converted to upper case
 341      *          using {@code String.toUpperCase(Locale.US)}
 342      * <li> The entire name is converted to lower case
 343      *          using {@code String.toLowerCase(Locale.US)}
 344      * <li> The name is finally normalized using normalization form KD,
 345      *          as described in the Unicode Standard and UAX #15
 346      * </ol>
 347      *
 348      * <p> Additional standard formats may be introduced in the future.
 349      *
 350      * @param format the format to use
 351      *
 352      * @return a string representation of this {@code X500Principal}
 353      *          using the specified format
 354      * @throws IllegalArgumentException if the specified format is invalid
 355      *          or null
 356      */
 357     public String getName(String format) {
 358         if (format != null) {
 359             if (format.equalsIgnoreCase(RFC1779)) {
 360                 return thisX500Name.getRFC1779Name();
 361             } else if (format.equalsIgnoreCase(RFC2253)) {
 362                 return thisX500Name.getRFC2253Name();
 363             } else if (format.equalsIgnoreCase(CANONICAL)) {
 364                 return thisX500Name.getRFC2253CanonicalName();
 365             }
 366         }
 367         throw new IllegalArgumentException("invalid format specified");
 368     }
 369 
 370     /**
 371      * Returns a string representation of the X.500 distinguished name
 372      * using the specified format. Valid values for the format are
 373      * "RFC1779" and "RFC2253" (case insensitive). "CANONICAL" is not
 374      * permitted and an {@code IllegalArgumentException} will be thrown.
 375      *
 376      * <p>This method returns Strings in the format as specified in
 377      * {@link #getName(String)} and also emits additional attribute type
 378      * keywords for OIDs that have entries in the {@code oidMap}
 379      * parameter. OID entries in the oidMap take precedence over the default
 380      * OIDs recognized by {@code getName(String)}.
 381      * Improperly specified OIDs are ignored; however if an OID
 382      * in the name maps to an improperly specified keyword, an
 383      * {@code IllegalArgumentException} is thrown.
 384      *
 385      * <p> Additional standard formats may be introduced in the future.
 386      *
 387      * <p> Warning: additional attribute type keywords may not be recognized
 388      * by other implementations; therefore do not use this method if
 389      * you are unsure if these keywords will be recognized by other
 390      * implementations.
 391      *
 392      * @param format the format to use
 393      * @param oidMap an OID map, where each key is an object identifier in
 394      *  String form (a sequence of nonnegative integers separated by periods)
 395      *  that maps to a corresponding attribute type keyword String.
 396      *  The map may be empty but never {@code null}.
 397      * @return a string representation of this {@code X500Principal}
 398      *          using the specified format
 399      * @throws IllegalArgumentException if the specified format is invalid,
 400      *  null, or an OID in the name maps to an improperly specified keyword
 401      * @throws NullPointerException if {@code oidMap} is {@code null}
 402      * @since 1.6
 403      */
 404     public String getName(String format, Map<String, String> oidMap) {
 405         if (oidMap == null) {
 406             throw new NullPointerException
 407                 (sun.security.util.ResourcesMgr.getString
 408                 ("provided.null.OID.map"));
 409         }
 410         if (format != null) {
 411             if (format.equalsIgnoreCase(RFC1779)) {
 412                 return thisX500Name.getRFC1779Name(oidMap);
 413             } else if (format.equalsIgnoreCase(RFC2253)) {
 414                 return thisX500Name.getRFC2253Name(oidMap);
 415             }
 416         }
 417         throw new IllegalArgumentException("invalid format specified");
 418     }
 419 
 420     /**
 421      * Returns the distinguished name in ASN.1 DER encoded form. The ASN.1
 422      * notation for this structure is supplied in the documentation for
 423      * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
 424      *
 425      * <p>Note that the byte array returned is cloned to protect against
 426      * subsequent modifications.
 427      *
 428      * @return a byte array containing the distinguished name in ASN.1 DER
 429      * encoded form
 430      */
 431     public byte[] getEncoded() {
 432         try {
 433             return thisX500Name.getEncoded();
 434         } catch (IOException e) {
 435             throw new RuntimeException("unable to get encoding", e);
 436         }
 437     }
 438 
 439     /**
 440      * Return a user-friendly string representation of this
 441      * {@code X500Principal}.
 442      *
 443      * @return a string representation of this {@code X500Principal}
 444      */
 445     public String toString() {
 446         return thisX500Name.toString();
 447     }
 448 
 449     /**
 450      * Compares the specified {@code Object} with this
 451      * {@code X500Principal} for equality.
 452      *
 453      * <p> Specifically, this method returns {@code true} if
 454      * the {@code Object} <i>o</i> is an {@code X500Principal}
 455      * and if the respective canonical string representations
 456      * (obtained via the {@code getName(X500Principal.CANONICAL)} method)
 457      * of this object and <i>o</i> are equal.
 458      *
 459      * <p> This implementation is compliant with the requirements of RFC 3280.
 460      *
 461      * @param o Object to be compared for equality with this
 462      *          {@code X500Principal}
 463      *
 464      * @return {@code true} if the specified {@code Object} is equal
 465      *          to this {@code X500Principal}, {@code false} otherwise
 466      */
 467     public boolean equals(Object o) {
 468         if (this == o) {
 469             return true;
 470         }
 471         if (o instanceof X500Principal == false) {
 472             return false;
 473         }
 474         X500Principal other = (X500Principal)o;
 475         return this.thisX500Name.equals(other.thisX500Name);
 476     }
 477 
 478     /**
 479      * Return a hash code for this {@code X500Principal}.
 480      *
 481      * <p> The hash code is calculated via:
 482      * {@code getName(X500Principal.CANONICAL).hashCode()}
 483      *
 484      * @return a hash code for this {@code X500Principal}
 485      */
 486     public int hashCode() {
 487         return thisX500Name.hashCode();
 488     }
 489 
 490     /**
 491      * Save the X500Principal object to a stream.
 492      *
 493      * @serialData this {@code X500Principal} is serialized
 494      *          by writing out its DER-encoded form
 495      *          (the value of {@code getEncoded} is serialized).
 496      */
 497     private void writeObject(java.io.ObjectOutputStream s)
 498         throws IOException {
 499         s.writeObject(thisX500Name.getEncodedInternal());
 500     }
 501 
 502     /**
 503      * Reads this object from a stream (i.e., deserializes it).
 504      */
 505     private void readObject(java.io.ObjectInputStream s)
 506         throws java.io.IOException,
 507                java.io.NotActiveException,
 508                ClassNotFoundException {
 509 
 510         // re-create thisX500Name
 511         thisX500Name = new X500Name((byte[])s.readObject());
 512     }
 513 }