X500Principal.java 20.8 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
10 11 12 13 14 15 16 17 18 19 20
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
21 22 23
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
24 25 26 27 28 29 30 31 32 33 34 35
 */

package javax.security.auth.x500;

import java.io.*;
import java.security.Principal;
import java.util.Collections;
import java.util.Map;
import sun.security.x509.X500Name;
import sun.security.util.*;

/**
J
juh 已提交
36 37
 * <p> This class represents an X.500 {@code Principal}.
 * {@code X500Principal}s are represented by distinguished names such as
D
duke 已提交
38 39 40 41 42 43
 * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US".
 *
 * <p> This class can be instantiated by using a string representation
 * of the distinguished name, or by using the ASN.1 DER encoded byte
 * representation of the distinguished name.  The current specification
 * for the string representation of a distinguished name is defined in
44
 * <a href="http://tools.ietf.org/html/rfc2253">RFC 2253: Lightweight
D
duke 已提交
45 46
 * Directory Access Protocol (v3): UTF-8 String Representation of
 * 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:
D
duke 已提交
48 49
 * A String Representation of Distinguished Names</a>, and also recognizes
 * attribute type keywords whose OIDs (Object Identifiers) are defined in
50
 * <a href="http://tools.ietf.org/html/rfc5280">RFC 5280: Internet X.509
D
duke 已提交
51 52
 * Public Key Infrastructure Certificate and CRL Profile</a>.
 *
J
juh 已提交
53 54
 * <p> The string representation for this {@code X500Principal}
 * can be obtained by calling the {@code getName} methods.
D
duke 已提交
55
 *
J
juh 已提交
56 57 58
 * <p> Note that the {@code getSubjectX500Principal} and
 * {@code getIssuerX500Principal} methods of
 * {@code X509Certificate} return X500Principals representing the
D
duke 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
 * issuer and subject fields of the certificate.
 *
 * @see java.security.cert.X509Certificate
 * @since 1.4
 */
public final class X500Principal implements Principal, java.io.Serializable {

    private static final long serialVersionUID = -500463348111345721L;

    /**
     * RFC 1779 String format of Distinguished Names.
     */
    public static final String RFC1779 = "RFC1779";
    /**
     * RFC 2253 String format of Distinguished Names.
     */
    public static final String RFC2253 = "RFC2253";
    /**
     * Canonical String format of Distinguished Names.
     */
    public static final String CANONICAL = "CANONICAL";

    /**
     * The X500Name representing this principal.
     *
     * NOTE: this field is reflectively accessed from within X500Name.
     */
    private transient X500Name thisX500Name;

    /**
     * Creates an X500Principal by wrapping an X500Name.
     *
     * NOTE: The constructor is package private. It is intended to be accessed
     * using privileged reflection from classes in sun.security.*.
     * Currently referenced from sun.security.x509.X500Name.asX500Principal().
     */
    X500Principal(X500Name x500Name) {
        thisX500Name = x500Name;
    }

    /**
J
juh 已提交
100
     * Creates an {@code X500Principal} from a string representation of
D
duke 已提交
101 102 103 104 105 106 107 108 109
     * an X.500 distinguished name (ex:
     * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
     * The distinguished name must be specified using the grammar defined in
     * RFC 1779 or RFC 2253 (either format is acceptable).
     *
     * <p>This constructor recognizes the attribute type keywords
     * defined in RFC 1779 and RFC 2253
     * (and listed in {@link #getName(String format) getName(String format)}),
     * 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.
D
duke 已提交
112 113
     * Any other attribute type must be specified as an OID.
     *
114 115 116 117 118 119 120
     * <p>This implementation enforces a more restrictive OID syntax than
     * defined in RFC 1779 and 2253. It uses the more correct syntax defined in
     * <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which
     * specifies that OIDs contain at least 2 digits:
     *
     * <p>{@code numericoid = number 1*( DOT number ) }
     *
D
duke 已提交
121
     * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
J
juh 已提交
122 123 124
     * @exception NullPointerException if the {@code name}
     *                  is {@code null}
     * @exception IllegalArgumentException if the {@code name}
D
duke 已提交
125 126 127
     *                  is improperly specified
     */
    public X500Principal(String name) {
128
        this(name, Collections.<String, String>emptyMap());
D
duke 已提交
129 130 131
    }

    /**
J
juh 已提交
132
     * Creates an {@code X500Principal} from a string representation of
D
duke 已提交
133 134 135 136 137 138 139
     * an X.500 distinguished name (ex:
     * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
     * The distinguished name must be specified using the grammar defined in
     * RFC 1779 or RFC 2253 (either format is acceptable).
     *
     * <p> This constructor recognizes the attribute type keywords specified
     * in {@link #X500Principal(String)} and also recognizes additional
J
juh 已提交
140
     * keywords that have entries in the {@code keywordMap} parameter.
D
duke 已提交
141
     * Keyword entries in the keywordMap take precedence over the default
J
juh 已提交
142
     * keywords recognized by {@code X500Principal(String)}. Keywords
D
duke 已提交
143 144
     * MUST be specified in all upper-case, otherwise they will be ignored.
     * Improperly specified keywords are ignored; however if a keyword in the
145
     * name maps to an improperly specified Object Identifier (OID), an
J
juh 已提交
146
     * {@code IllegalArgumentException} is thrown. It is permissible to
D
duke 已提交
147 148
     * have 2 different keywords that map to the same OID.
     *
149 150 151 152 153 154 155
     * <p>This implementation enforces a more restrictive OID syntax than
     * defined in RFC 1779 and 2253. It uses the more correct syntax defined in
     * <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which
     * specifies that OIDs contain at least 2 digits:
     *
     * <p>{@code numericoid = number 1*( DOT number ) }
     *
D
duke 已提交
156 157 158 159
     * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
     * @param keywordMap an attribute type keyword map, where each key is a
     *   keyword String that maps to a corresponding object identifier in String
     *   form (a sequence of nonnegative integers separated by periods). The map
J
juh 已提交
160 161 162 163 164
     *   may be empty but never {@code null}.
     * @exception NullPointerException if {@code name} or
     *   {@code keywordMap} is {@code null}
     * @exception IllegalArgumentException if the {@code name} is
     *   improperly specified or a keyword in the {@code name} maps to an
D
duke 已提交
165 166 167 168 169 170 171
     *   OID that is not in the correct form
     * @since 1.6
     */
    public X500Principal(String name, Map<String, String> keywordMap) {
        if (name == null) {
            throw new NullPointerException
                (sun.security.util.ResourcesMgr.getString
172
                ("provided.null.name"));
D
duke 已提交
173 174 175 176
        }
        if (keywordMap == null) {
            throw new NullPointerException
                (sun.security.util.ResourcesMgr.getString
177
                ("provided.null.keyword.map"));
D
duke 已提交
178 179 180 181 182 183 184 185 186 187 188 189 190
        }

        try {
            thisX500Name = new X500Name(name, keywordMap);
        } catch (Exception e) {
            IllegalArgumentException iae = new IllegalArgumentException
                        ("improperly specified input name: " + name);
            iae.initCause(e);
            throw iae;
        }
    }

    /**
J
juh 已提交
191
     * Creates an {@code X500Principal} from a distinguished name in
D
duke 已提交
192 193
     * ASN.1 DER encoded form. The ASN.1 notation for this structure is as
     * follows.
J
juh 已提交
194
     * <pre>{@code
D
duke 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
     * Name ::= CHOICE {
     *   RDNSequence }
     *
     * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
     *
     * RelativeDistinguishedName ::=
     *   SET SIZE (1 .. MAX) OF AttributeTypeAndValue
     *
     * AttributeTypeAndValue ::= SEQUENCE {
     *   type     AttributeType,
     *   value    AttributeValue }
     *
     * AttributeType ::= OBJECT IDENTIFIER
     *
     * AttributeValue ::= ANY DEFINED BY AttributeType
     * ....
     * DirectoryString ::= CHOICE {
     *       teletexString           TeletexString (SIZE (1..MAX)),
     *       printableString         PrintableString (SIZE (1..MAX)),
     *       universalString         UniversalString (SIZE (1..MAX)),
     *       utf8String              UTF8String (SIZE (1.. MAX)),
     *       bmpString               BMPString (SIZE (1..MAX)) }
J
juh 已提交
217
     * }</pre>
D
duke 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
     *
     * @param name a byte array containing the distinguished name in ASN.1
     * DER encoded form
     * @throws IllegalArgumentException if an encoding error occurs
     *          (incorrect form for DN)
     */
    public X500Principal(byte[] name) {
        try {
            thisX500Name = new X500Name(name);
        } catch (Exception e) {
            IllegalArgumentException iae = new IllegalArgumentException
                        ("improperly specified input name");
            iae.initCause(e);
            throw iae;
        }
    }

    /**
J
juh 已提交
236
     * Creates an {@code X500Principal} from an {@code InputStream}
D
duke 已提交
237 238 239 240 241 242 243 244
     * containing the distinguished name in ASN.1 DER encoded form.
     * The ASN.1 notation for this structure is supplied in the
     * documentation for
     * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
     *
     * <p> The read position of the input stream is positioned
     * to the next available byte after the encoded distinguished name.
     *
J
juh 已提交
245
     * @param is an {@code InputStream} containing the distinguished
D
duke 已提交
246 247
     *          name in ASN.1 DER encoded form
     *
J
juh 已提交
248 249
     * @exception NullPointerException if the {@code InputStream}
     *          is {@code null}
D
duke 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
     * @exception IllegalArgumentException if an encoding error occurs
     *          (incorrect form for DN)
     */
    public X500Principal(InputStream is) {
        if (is == null) {
            throw new NullPointerException("provided null input stream");
        }

        try {
            if (is.markSupported())
                is.mark(is.available() + 1);
            DerValue der = new DerValue(is);
            thisX500Name = new X500Name(der.data);
        } catch (Exception e) {
            if (is.markSupported()) {
                try {
                    is.reset();
                } catch (IOException ioe) {
                    IllegalArgumentException iae = new IllegalArgumentException
                        ("improperly specified input stream " +
                        ("and unable to reset input stream"));
                    iae.initCause(e);
                    throw iae;
                }
            }
            IllegalArgumentException iae = new IllegalArgumentException
                        ("improperly specified input stream");
            iae.initCause(e);
            throw iae;
        }
    }

    /**
     * Returns a string representation of the X.500 distinguished name using
     * the format defined in RFC 2253.
     *
     * <p>This method is equivalent to calling
J
juh 已提交
287
     * {@code getName(X500Principal.RFC2253)}.
D
duke 已提交
288
     *
J
juh 已提交
289
     * @return the distinguished name of this {@code X500Principal}
D
duke 已提交
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
     */
    public String getName() {
        return getName(X500Principal.RFC2253);
    }

    /**
     * Returns a string representation of the X.500 distinguished name
     * using the specified format. Valid values for the format are
     * "RFC1779", "RFC2253", and "CANONICAL" (case insensitive).
     *
     * <p> If "RFC1779" is specified as the format,
     * this method emits the attribute type keywords defined in
     * RFC 1779 (CN, L, ST, O, OU, C, STREET).
     * Any other attribute type is emitted as an OID.
     *
     * <p> If "RFC2253" is specified as the format,
     * this method emits the attribute type keywords defined in
     * RFC 2253 (CN, L, ST, O, OU, C, STREET, DC, UID).
     * Any other attribute type is emitted as an OID.
     * Under a strict reading, RFC 2253 only specifies a UTF-8 string
     * representation. The String returned by this method is the
     * Unicode string achieved by decoding this UTF-8 representation.
     *
     * <p> If "CANONICAL" is specified as the format,
     * this method returns an RFC 2253 conformant string representation
     * with the following additional canonicalizations:
     *
317
     * <ol>
D
duke 已提交
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
     * <li> Leading zeros are removed from attribute types
     *          that are encoded as dotted decimal OIDs
     * <li> DirectoryString attribute values of type
     *          PrintableString and UTF8String are not
     *          output in hexadecimal format
     * <li> DirectoryString attribute values of types
     *          other than PrintableString and UTF8String
     *          are output in hexadecimal format
     * <li> Leading and trailing white space characters
     *          are removed from non-hexadecimal attribute values
     *          (unless the value consists entirely of white space characters)
     * <li> Internal substrings of one or more white space characters are
     *          converted to a single space in non-hexadecimal
     *          attribute values
     * <li> Relative Distinguished Names containing more than one
     *          Attribute Value Assertion (AVA) are output in the
     *          following order: an alphabetical ordering of AVAs
     *          containing standard keywords, followed by a numeric
     *          ordering of AVAs containing OID keywords.
     * <li> The only characters in attribute values that are escaped are
     *          those which section 2.4 of RFC 2253 states must be escaped
     *          (they are escaped using a preceding backslash character)
     * <li> The entire name is converted to upper case
J
juh 已提交
341
     *          using {@code String.toUpperCase(Locale.US)}
D
duke 已提交
342
     * <li> The entire name is converted to lower case
J
juh 已提交
343
     *          using {@code String.toLowerCase(Locale.US)}
D
duke 已提交
344 345 346 347 348 349 350 351
     * <li> The name is finally normalized using normalization form KD,
     *          as described in the Unicode Standard and UAX #15
     * </ol>
     *
     * <p> Additional standard formats may be introduced in the future.
     *
     * @param format the format to use
     *
J
juh 已提交
352
     * @return a string representation of this {@code X500Principal}
D
duke 已提交
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
     *          using the specified format
     * @throws IllegalArgumentException if the specified format is invalid
     *          or null
     */
    public String getName(String format) {
        if (format != null) {
            if (format.equalsIgnoreCase(RFC1779)) {
                return thisX500Name.getRFC1779Name();
            } else if (format.equalsIgnoreCase(RFC2253)) {
                return thisX500Name.getRFC2253Name();
            } else if (format.equalsIgnoreCase(CANONICAL)) {
                return thisX500Name.getRFC2253CanonicalName();
            }
        }
        throw new IllegalArgumentException("invalid format specified");
    }

    /**
     * Returns a string representation of the X.500 distinguished name
     * using the specified format. Valid values for the format are
     * "RFC1779" and "RFC2253" (case insensitive). "CANONICAL" is not
J
juh 已提交
374
     * permitted and an {@code IllegalArgumentException} will be thrown.
D
duke 已提交
375 376 377
     *
     * <p>This method returns Strings in the format as specified in
     * {@link #getName(String)} and also emits additional attribute type
J
juh 已提交
378
     * keywords for OIDs that have entries in the {@code oidMap}
D
duke 已提交
379
     * parameter. OID entries in the oidMap take precedence over the default
J
juh 已提交
380
     * OIDs recognized by {@code getName(String)}.
D
duke 已提交
381 382
     * Improperly specified OIDs are ignored; however if an OID
     * in the name maps to an improperly specified keyword, an
J
juh 已提交
383
     * {@code IllegalArgumentException} is thrown.
D
duke 已提交
384 385 386 387 388 389 390 391 392 393 394 395
     *
     * <p> Additional standard formats may be introduced in the future.
     *
     * <p> Warning: additional attribute type keywords may not be recognized
     * by other implementations; therefore do not use this method if
     * you are unsure if these keywords will be recognized by other
     * implementations.
     *
     * @param format the format to use
     * @param oidMap an OID map, where each key is an object identifier in
     *  String form (a sequence of nonnegative integers separated by periods)
     *  that maps to a corresponding attribute type keyword String.
J
juh 已提交
396 397
     *  The map may be empty but never {@code null}.
     * @return a string representation of this {@code X500Principal}
D
duke 已提交
398 399 400
     *          using the specified format
     * @throws IllegalArgumentException if the specified format is invalid,
     *  null, or an OID in the name maps to an improperly specified keyword
J
juh 已提交
401
     * @throws NullPointerException if {@code oidMap} is {@code null}
D
duke 已提交
402 403 404 405 406 407
     * @since 1.6
     */
    public String getName(String format, Map<String, String> oidMap) {
        if (oidMap == null) {
            throw new NullPointerException
                (sun.security.util.ResourcesMgr.getString
408
                ("provided.null.OID.map"));
D
duke 已提交
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
        }
        if (format != null) {
            if (format.equalsIgnoreCase(RFC1779)) {
                return thisX500Name.getRFC1779Name(oidMap);
            } else if (format.equalsIgnoreCase(RFC2253)) {
                return thisX500Name.getRFC2253Name(oidMap);
            }
        }
        throw new IllegalArgumentException("invalid format specified");
    }

    /**
     * Returns the distinguished name in ASN.1 DER encoded form. The ASN.1
     * notation for this structure is supplied in the documentation for
     * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
     *
     * <p>Note that the byte array returned is cloned to protect against
     * subsequent modifications.
     *
     * @return a byte array containing the distinguished name in ASN.1 DER
     * encoded form
     */
    public byte[] getEncoded() {
        try {
            return thisX500Name.getEncoded();
        } catch (IOException e) {
            throw new RuntimeException("unable to get encoding", e);
        }
    }

    /**
     * Return a user-friendly string representation of this
J
juh 已提交
441
     * {@code X500Principal}.
D
duke 已提交
442
     *
J
juh 已提交
443
     * @return a string representation of this {@code X500Principal}
D
duke 已提交
444 445 446 447 448 449
     */
    public String toString() {
        return thisX500Name.toString();
    }

    /**
J
juh 已提交
450 451
     * Compares the specified {@code Object} with this
     * {@code X500Principal} for equality.
D
duke 已提交
452
     *
J
juh 已提交
453 454
     * <p> Specifically, this method returns {@code true} if
     * the {@code Object} <i>o</i> is an {@code X500Principal}
D
duke 已提交
455
     * and if the respective canonical string representations
J
juh 已提交
456
     * (obtained via the {@code getName(X500Principal.CANONICAL)} method)
D
duke 已提交
457 458
     * of this object and <i>o</i> are equal.
     *
459
     * <p> This implementation is compliant with the requirements of RFC 5280.
D
duke 已提交
460 461
     *
     * @param o Object to be compared for equality with this
J
juh 已提交
462
     *          {@code X500Principal}
D
duke 已提交
463
     *
J
juh 已提交
464 465
     * @return {@code true} if the specified {@code Object} is equal
     *          to this {@code X500Principal}, {@code false} otherwise
D
duke 已提交
466 467 468 469 470 471 472 473 474 475 476 477 478
     */
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o instanceof X500Principal == false) {
            return false;
        }
        X500Principal other = (X500Principal)o;
        return this.thisX500Name.equals(other.thisX500Name);
    }

    /**
J
juh 已提交
479
     * Return a hash code for this {@code X500Principal}.
D
duke 已提交
480 481
     *
     * <p> The hash code is calculated via:
J
juh 已提交
482
     * {@code getName(X500Principal.CANONICAL).hashCode()}
D
duke 已提交
483
     *
J
juh 已提交
484
     * @return a hash code for this {@code X500Principal}
D
duke 已提交
485 486 487 488 489 490 491 492
     */
    public int hashCode() {
        return thisX500Name.hashCode();
    }

    /**
     * Save the X500Principal object to a stream.
     *
J
juh 已提交
493
     * @serialData this {@code X500Principal} is serialized
D
duke 已提交
494
     *          by writing out its DER-encoded form
J
juh 已提交
495
     *          (the value of {@code getEncoded} is serialized).
D
duke 已提交
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
     */
    private void writeObject(java.io.ObjectOutputStream s)
        throws IOException {
        s.writeObject(thisX500Name.getEncodedInternal());
    }

    /**
     * Reads this object from a stream (i.e., deserializes it).
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException,
               java.io.NotActiveException,
               ClassNotFoundException {

        // re-create thisX500Name
        thisX500Name = new X500Name((byte[])s.readObject());
    }
}