View Javadoc
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      * <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 }