001: /*
002: * @(#)X500Principal.java 1.22 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package javax.security.auth.x500;
028:
029: import java.io.*;
030: import java.security.Principal;
031: import sun.security.x509.X500Name;
032: import sun.security.util.*;
033:
034: /**
035: * <p> This class represents an X.500 <code>Principal</code>.
036: * <code>X500Principal</code>s are represented by distinguished names such as
037: * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US".
038: *
039: * <p> This class can be instantiated by using a string representation
040: * of the distinguished name, or by using the ASN.1 DER encoded byte
041: * representation of the distinguished name. The current specification
042: * for the string representation of a distinguished name is defined in
043: * <a href="http://www.ietf.org/rfc/rfc2253.html">RFC 2253</a>.
044: * This class, however, accepts string formats from both RFC 2253 and
045: * <a href="http://www.ietf.org/rfc/rfc1779.html">RFC 1779</a>,
046: * and also recognizes attribute type keywords whose OIDs
047: * (Object Identifiers) are defined in
048: * <a href="http://www.ietf.org/rfc/rfc2459.html">RFC 2459</a>.
049: *
050: * <p> The string representation for this <code>X500Principal</code>
051: * can be obtained by calling the <code>getName</code> methods.
052: *
053: * <p> Note that the <code>getSubjectX500Principal</code> and
054: * <code>getIssuerX500Principal</code> methods of
055: * <code>X509Certificate</code> return X500Principals representing the
056: * issuer and subject fields of the certificate.
057: *
058: * @version 1.22, 10/10/06
059: * @see java.security.cert.X509Certificate
060: * @since 1.4
061: */
062: public final class X500Principal implements Principal,
063: java.io.Serializable {
064:
065: private static final long serialVersionUID = -500463348111345721L;
066:
067: /**
068: * RFC 1779 String format of Distinguished Names.
069: */
070: public static final String RFC1779 = "RFC1779";
071: /**
072: * RFC 2253 String format of Distinguished Names.
073: */
074: public static final String RFC2253 = "RFC2253";
075: /**
076: * Canonical String format of Distinguished Names.
077: */
078: public static final String CANONICAL = "CANONICAL";
079:
080: /**
081: * The X500Name representing this principal.
082: *
083: * NOTE: this field is reflectively accessed from within X500Name.
084: */
085: private transient X500Name this X500Name;
086:
087: /**
088: * Creates an X500Principal by wrapping an X500Name.
089: *
090: * NOTE: The constructor is package private. It is intended to be accessed
091: * using privileged reflection from classes in sun.security.*.
092: * Currently referenced from sun.security.x509.X500Name.asX500Principal().
093: */
094: X500Principal(X500Name x500Name) {
095: this X500Name = x500Name;
096: }
097:
098: /**
099: * Creates an <code>X500Principal</code> from a string representation of
100: * an X.500 distinguished name (ex:
101: * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
102: * The distinguished name must be specified using the grammar defined in
103: * RFC 1779 or RFC 2253 (either format is acceptable).
104: *
105: * <p>This constructor recognizes the attribute type keywords
106: * defined in RFC 1779 and RFC 2253
107: * (and listed in {@link #getName(String format) getName(String format)}),
108: * as well as the T, DNQ or DNQUALIFIER, SURNAME, GIVENNAME, INITIALS,
109: * GENERATION, EMAILADDRESS, and SERIALNUMBER keywords whose OIDs are
110: * defined in RFC 2459 and its successor.
111: * Any other attribute type must be specified as an OID.
112: *
113: * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
114: * @exception NullPointerException if the <code>name</code>
115: * is <code>null</code>
116: * @exception IllegalArgumentException if the <code>name</code>
117: * is improperly specified
118: */
119: public X500Principal(String name) {
120: if (name == null) {
121: throw new NullPointerException(
122: sun.security.util.ResourcesMgr
123: .getString("provided null name"));
124: }
125:
126: try {
127: this X500Name = new X500Name(name);
128: } catch (Exception e) {
129: IllegalArgumentException iae = new IllegalArgumentException(
130: "improperly specified input name: " + name);
131: iae.initCause(e);
132: throw iae;
133: }
134:
135: }
136:
137: /**
138: * Creates an <code>X500Principal</code> from a distinguished name in
139: * ASN.1 DER encoded form. The ASN.1 notation for this structure is as
140: * follows.
141: * <pre><code>
142: * Name ::= CHOICE {
143: * RDNSequence }
144: *
145: * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
146: *
147: * RelativeDistinguishedName ::=
148: * SET SIZE (1 .. MAX) OF AttributeTypeAndValue
149: *
150: * AttributeTypeAndValue ::= SEQUENCE {
151: * type AttributeType,
152: * value AttributeValue }
153: *
154: * AttributeType ::= OBJECT IDENTIFIER
155: *
156: * AttributeValue ::= ANY DEFINED BY AttributeType
157: * ....
158: * DirectoryString ::= CHOICE {
159: * teletexString TeletexString (SIZE (1..MAX)),
160: * printableString PrintableString (SIZE (1..MAX)),
161: * universalString UniversalString (SIZE (1..MAX)),
162: * utf8String UTF8String (SIZE (1.. MAX)),
163: * bmpString BMPString (SIZE (1..MAX)) }
164: * </code></pre>
165: *
166: * @param name a byte array containing the distinguished name in ASN.1
167: * DER encoded form
168: * @throws IllegalArgumentException if an encoding error occurs
169: * (incorrect form for DN)
170: */
171: public X500Principal(byte[] name) {
172: try {
173: this X500Name = new X500Name(name);
174: } catch (Exception e) {
175: IllegalArgumentException iae = new IllegalArgumentException(
176: "improperly specified input name");
177: iae.initCause(e);
178: throw iae;
179: }
180: }
181:
182: /**
183: * Creates an <code>X500Principal</code> from an <code>InputStream</code>
184: * containing the distinguished name in ASN.1 DER encoded form.
185: * The ASN.1 notation for this structure is supplied in the
186: * documentation for
187: * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
188: *
189: * <p> The read position of the input stream is positioned
190: * to the next available byte after the encoded distinguished name.
191: *
192: * @param is an <code>InputStream</code> containing the distinguished
193: * name in ASN.1 DER encoded form
194: *
195: * @exception NullPointerException if the <code>InputStream</code>
196: * is <code>null</code>
197: * @exception IllegalArgumentException if an encoding error occurs
198: * (incorrect form for DN)
199: */
200: public X500Principal(InputStream is) {
201: if (is == null) {
202: throw new NullPointerException("provided null input stream");
203: }
204:
205: try {
206: if (is.markSupported())
207: is.mark(is.available() + 1);
208: DerValue der = new DerValue(is);
209: this X500Name = new X500Name(der.data);
210: } catch (Exception e) {
211: if (is.markSupported()) {
212: try {
213: is.reset();
214: } catch (IOException ioe) {
215: IllegalArgumentException iae = new IllegalArgumentException(
216: "improperly specified input stream "
217: + ("and unable to reset input stream"));
218: iae.initCause(e);
219: throw iae;
220: }
221: }
222: IllegalArgumentException iae = new IllegalArgumentException(
223: "improperly specified input stream");
224: iae.initCause(e);
225: throw iae;
226: }
227: }
228:
229: /**
230: * Returns a string representation of the X.500 distinguished name using
231: * the format defined in RFC 2253.
232: *
233: * <p>This method is equivalent to calling
234: * <code>getName(X500Principal.RFC2253)</code>.
235: *
236: * @return the distinguished name of this <code>X500Principal</code>
237: */
238: public String getName() {
239: return getName(X500Principal.RFC2253);
240: }
241:
242: /**
243: * Returns a string representation of the X.500 distinguished name
244: * using the specified format. Valid values for the format are
245: * "RFC1779", "RFC2253", and "CANONICAL" (case insensitive).
246: *
247: * <p> If "RFC1779" is specified as the format,
248: * this method emits the attribute type keywords defined in
249: * RFC 1779 (CN, L, ST, O, OU, C, STREET).
250: * Any other attribute type is emitted as an OID.
251: *
252: * <p> If "RFC2253" is specified as the format,
253: * this method emits the attribute type keywords defined in
254: * RFC 2253 (CN, L, ST, O, OU, C, STREET, DC, UID).
255: * Any other attribute type is emitted as an OID.
256: * Under a strict reading, RFC 2253 only specifies a UTF-8 string
257: * representation. The String returned by this method is the
258: * Unicode string achieved by decoding this UTF-8 representation.
259: *
260: * <p> If "CANONICAL" is specified as the format,
261: * this method returns an RFC 2253 conformant string representation
262: * with the following additional canonicalizations:
263: *
264: * <p><ol>
265: * <li> Leading zeros are removed from attribute types
266: * that are encoded as dotted decimal OIDs
267: * <li> DirectoryString attribute values of type
268: * PrintableString and UTF8String are not
269: * output in hexadecimal format
270: * <li> DirectoryString attribute values of types
271: * other than PrintableString and UTF8String
272: * are output in hexadecimal format
273: * <li> Leading and trailing white space characters
274: * are removed from non-hexadecimal attribute values
275: * (unless the value consists entirely of white space characters)
276: * <li> Internal substrings of one or more white space characters are
277: * converted to a single space in non-hexadecimal
278: * attribute values
279: * <li> Relative Distinguished Names containing more than one
280: * Attribute Value Assertion (AVA) are output in the
281: * following order: an alphabetical ordering of AVAs
282: * containing standard keywords, followed by a numeric
283: * ordering of AVAs containing OID keywords.
284: * <li> The only characters in attribute values that are escaped are
285: * those which section 2.4 of RFC 2253 states must be escaped
286: * (they are escaped using a preceding backslash character)
287: * <li> The entire name is converted to upper case
288: * using <code>String.toUpperCase(Locale.US)</code>
289: * <li> The entire name is converted to lower case
290: * using <code>String.toLowerCase(Locale.US)</code>
291: * <li> The name is finally normalized using normalization form KD,
292: * as described in the Unicode Standard and UAX #15
293: * </ol>
294: *
295: * <p> Additional standard formats may be introduced in the future.
296: *
297: * @param format the format to use
298: *
299: * @return a string representation of this <code>X500Principal</code>
300: * using the specified format
301: * @throws IllegalArgumentException if the specified format is invalid
302: */
303: public String getName(String format) {
304: if (format != null) {
305: if (format.equalsIgnoreCase(RFC1779)) {
306: return this X500Name.getRFC1779Name();
307: } else if (format.equalsIgnoreCase(RFC2253)) {
308: return this X500Name.getRFC2253Name();
309: } else if (format.equalsIgnoreCase(CANONICAL)) {
310: return this X500Name.getRFC2253CanonicalName();
311: }
312: }
313: throw new IllegalArgumentException("invalid format specified");
314: }
315:
316: /**
317: * Returns the distinguished name in ASN.1 DER encoded form. The ASN.1
318: * notation for this structure is supplied in the documentation for
319: * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
320: *
321: * <p>Note that the byte array returned is cloned to protect against
322: * subsequent modifications.
323: *
324: * @return a byte array containing the distinguished name in ASN.1 DER
325: * encoded form
326: */
327: public byte[] getEncoded() {
328: try {
329: return this X500Name.getEncoded();
330: } catch (IOException e) {
331: throw new RuntimeException("unable to get encoding", e);
332: }
333: }
334:
335: /**
336: * Return a user-friendly string representation of this
337: * <code>X500Principal</code>.
338: *
339: * @return a string representation of this <code>X500Principal</code>
340: */
341: public String toString() {
342: return this X500Name.toString();
343: }
344:
345: /**
346: * Compares the specified <code>Object</code> with this
347: * <code>X500Principal</code> for equality.
348: *
349: * <p> Specifically, this method returns <code>true</code> if
350: * the <code>Object</code> <i>o</i> is an <code>X500Principal</code>
351: * and if the respective canonical string representations
352: * (obtained via the <code>getName(X500Principal.CANONICAL)</code> method)
353: * of this object and <i>o</i> are equal.
354: *
355: * <p> This implementation is compliant with the requirements of RFC 2459.
356: *
357: * @param o Object to be compared for equality with this
358: * <code>X500Principal</code>
359: *
360: * @return <code>true</code> if the specified <code>Object</code> is equal
361: * to this <code>X500Principal</code>, <code>false</code> otherwise
362: */
363: public boolean equals(Object o) {
364: if (this == o) {
365: return true;
366: }
367: if (o instanceof X500Principal == false) {
368: return false;
369: }
370: X500Principal other = (X500Principal) o;
371: return this .this X500Name.equals(other.this X500Name);
372: }
373:
374: /**
375: * Return a hash code for this <code>X500Principal</code>.
376: *
377: * <p> The hash code is calculated via:
378: * <code>getName(X500Principal.CANONICAL).hashCode()</code>
379: *
380: * @return a hash code for this <code>X500Principal</code>
381: */
382: public int hashCode() {
383: return this X500Name.hashCode();
384: }
385:
386: /**
387: * Save the X500Principal object to a stream.
388: *
389: * @serialData this <code>X500Principal</code> is serialized
390: * by writing out its DER-encoded form
391: * (the value of <code>getEncoded</code> is serialized).
392: */
393: private void writeObject(java.io.ObjectOutputStream s)
394: throws IOException {
395: s.writeObject(this X500Name.getEncodedInternal());
396: }
397:
398: /**
399: * Reads this object from a stream (i.e., deserializes it).
400: */
401: private void readObject(java.io.ObjectInputStream s)
402: throws java.io.IOException, java.io.NotActiveException,
403: ClassNotFoundException {
404:
405: // re-create thisX500Name
406: this X500Name = new X500Name((byte[]) s.readObject());
407: }
408: }
|