Home | History | Annotate | Download | only in x509
      1 /*
      2  * Copyright (c) 1998, 2011, 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 sun.security.x509;
     27 
     28 import java.io.IOException;
     29 import java.lang.reflect.Constructor;
     30 import java.util.Arrays;
     31 
     32 import sun.security.util.*;
     33 
     34 /**
     35  * This class represents the OtherName as required by the GeneralNames
     36  * ASN.1 object. It supplies the generic framework to allow specific
     37  * Other Name types, and also provides minimal support for unrecognized
     38  * Other Name types.
     39  *
     40  * The ASN.1 definition for OtherName is:
     41  * <pre>
     42  * OtherName ::= SEQUENCE {
     43  *     type-id    OBJECT IDENTIFIER,
     44  *     value      [0] EXPLICIT ANY DEFINED BY type-id
     45  * }
     46  * </pre>
     47  * @author Hemma Prafullchandra
     48  */
     49 public class OtherName implements GeneralNameInterface {
     50 
     51     private String name;
     52     private ObjectIdentifier oid;
     53     private byte[] nameValue = null;
     54     private GeneralNameInterface gni = null;
     55 
     56     private static final byte TAG_VALUE = 0;
     57 
     58     private int myhash = -1;
     59 
     60     /**
     61      * Create the OtherName object from a passed ObjectIdentfier and
     62      * byte array name value
     63      *
     64      * @param oid ObjectIdentifier of this OtherName object
     65      * @param value the DER-encoded value of the OtherName
     66      * @throws IOException on error
     67      */
     68     public OtherName(ObjectIdentifier oid, byte[] value) throws IOException {
     69         if (oid == null || value == null) {
     70             throw new NullPointerException("parameters may not be null");
     71         }
     72         this.oid = oid;
     73         this.nameValue = value;
     74         gni = getGNI(oid, value);
     75         if (gni != null) {
     76             name = gni.toString();
     77         } else {
     78             name = "Unrecognized ObjectIdentifier: " + oid.toString();
     79         }
     80     }
     81 
     82     /**
     83      * Create the OtherName object from the passed encoded Der value.
     84      *
     85      * @param derValue the encoded DER OtherName.
     86      * @exception IOException on error.
     87      */
     88     public OtherName(DerValue derValue) throws IOException {
     89         DerInputStream in = derValue.toDerInputStream();
     90 
     91         oid = in.getOID();
     92         DerValue val = in.getDerValue();
     93         nameValue = val.toByteArray();
     94         gni = getGNI(oid, nameValue);
     95         if (gni != null) {
     96             name = gni.toString();
     97         } else {
     98             name = "Unrecognized ObjectIdentifier: " + oid.toString();
     99         }
    100     }
    101 
    102     /**
    103      * Get ObjectIdentifier
    104      */
    105     public ObjectIdentifier getOID() {
    106         //XXXX May want to consider cloning this
    107         return oid;
    108     }
    109 
    110     /**
    111      * Get name value
    112      */
    113     public byte[] getNameValue() {
    114         return nameValue.clone();
    115     }
    116 
    117     /**
    118      * Get GeneralNameInterface
    119      */
    120     private GeneralNameInterface getGNI(ObjectIdentifier oid, byte[] nameValue)
    121             throws IOException {
    122         try {
    123             Class<?> extClass = OIDMap.getClass(oid);
    124             if (extClass == null) {   // Unsupported OtherName
    125                 return null;
    126             }
    127             Class<?>[] params = { Object.class };
    128             Constructor<?> cons = extClass.getConstructor(params);
    129 
    130             Object[] passed = new Object[] { nameValue };
    131             GeneralNameInterface gni =
    132                        (GeneralNameInterface)cons.newInstance(passed);
    133             return gni;
    134         } catch (Exception e) {
    135             throw new IOException("Instantiation error: " + e, e);
    136         }
    137     }
    138 
    139     /**
    140      * Return the type of the GeneralName.
    141      */
    142     public int getType() {
    143         return GeneralNameInterface.NAME_ANY;
    144     }
    145 
    146     /**
    147      * Encode the Other name into the DerOutputStream.
    148      *
    149      * @param out the DER stream to encode the Other-Name to.
    150      * @exception IOException on encoding errors.
    151      */
    152     public void encode(DerOutputStream out) throws IOException {
    153         if (gni != null) {
    154             // This OtherName has a supported class
    155             gni.encode(out);
    156             return;
    157         } else {
    158             // This OtherName has no supporting class
    159             DerOutputStream tmp = new DerOutputStream();
    160             tmp.putOID(oid);
    161             tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_VALUE), nameValue);
    162             out.write(DerValue.tag_Sequence, tmp);
    163         }
    164     }
    165 
    166     /**
    167      * Compares this name with another, for equality.
    168      *
    169      * @return true iff the names are identical.
    170      */
    171     public boolean equals(Object other) {
    172         if (this == other) {
    173             return true;
    174         }
    175         if (!(other instanceof OtherName)) {
    176             return false;
    177         }
    178         OtherName otherOther = (OtherName)other;
    179         if (!(otherOther.oid.equals((Object)oid))) {
    180             return false;
    181         }
    182         GeneralNameInterface otherGNI = null;
    183         try {
    184             otherGNI = getGNI(otherOther.oid, otherOther.nameValue);
    185         } catch (IOException ioe) {
    186             return false;
    187         }
    188 
    189         boolean result;
    190         if (otherGNI != null) {
    191             try {
    192                 result = (otherGNI.constrains(this) == NAME_MATCH);
    193             } catch (UnsupportedOperationException ioe) {
    194                 result = false;
    195             }
    196         } else {
    197             result = Arrays.equals(nameValue, otherOther.nameValue);
    198         }
    199 
    200         return result;
    201     }
    202 
    203     /**
    204      * Returns the hash code for this OtherName.
    205      *
    206      * @return a hash code value.
    207      */
    208     public int hashCode() {
    209         if (myhash == -1) {
    210             myhash = 37 + oid.hashCode();
    211             for (int i = 0; i < nameValue.length; i++) {
    212                 myhash = 37 * myhash + nameValue[i];
    213             }
    214         }
    215         return myhash;
    216     }
    217 
    218     /**
    219      * Convert the name into user readable string.
    220      */
    221     public String toString() {
    222         return "Other-Name: " + name;
    223     }
    224 
    225     /**
    226      * Return type of constraint inputName places on this name:<ul>
    227      *   <li>NAME_DIFF_TYPE = -1: input name is different type from name
    228      *       (i.e. does not constrain).
    229      *   <li>NAME_MATCH = 0: input name matches name.
    230      *   <li>NAME_NARROWS = 1: input name narrows name (is lower in the
    231      *       naming subtree)
    232      *   <li>NAME_WIDENS = 2: input name widens name (is higher in the
    233      *       naming subtree)
    234      *   <li>NAME_SAME_TYPE = 3: input name does not match or narrow name,
    235      *       but is same type.
    236      * </ul>.  These results are used in checking NameConstraints during
    237      * certification path verification.
    238      *
    239      * @param inputName to be checked for being constrained
    240      * @returns constraint type above
    241      * @throws UnsupportedOperationException if name is same type, but
    242      *         comparison operations are not supported for this name type.
    243      */
    244     public int constrains(GeneralNameInterface inputName) {
    245         int constraintType;
    246         if (inputName == null) {
    247             constraintType = NAME_DIFF_TYPE;
    248         } else if (inputName.getType() != NAME_ANY) {
    249             constraintType = NAME_DIFF_TYPE;
    250         } else {
    251             throw new UnsupportedOperationException("Narrowing, widening, "
    252                 + "and matching are not supported for OtherName.");
    253         }
    254         return constraintType;
    255     }
    256 
    257     /**
    258      * Return subtree depth of this name for purposes of determining
    259      * NameConstraints minimum and maximum bounds.
    260      *
    261      * @returns distance of name from root
    262      * @throws UnsupportedOperationException if not supported for this name type
    263      */
    264     public int subtreeDepth() {
    265         throw new UnsupportedOperationException
    266             ("subtreeDepth() not supported for generic OtherName");
    267     }
    268 
    269 }
    270