1 /*
2 * Copyright (c) 2000, 2014, 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 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 5280.
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 5280.
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 }
514