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 */ OtherName(ObjectIdentifier oid, byte[] value)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 */ OtherName(DerValue derValue)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 */ getOID()105 public ObjectIdentifier getOID() { 106 //XXXX May want to consider cloning this 107 return oid; 108 } 109 110 /** 111 * Get name value 112 */ getNameValue()113 public byte[] getNameValue() { 114 return nameValue.clone(); 115 } 116 117 /** 118 * Get GeneralNameInterface 119 */ getGNI(ObjectIdentifier oid, byte[] nameValue)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 */ getType()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 */ encode(DerOutputStream out)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 */ equals(Object other)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 */ hashCode()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 */ toString()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 */ constrains(GeneralNameInterface inputName)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 */ subtreeDepth()264 public int subtreeDepth() { 265 throw new UnsupportedOperationException 266 ("subtreeDepth() not supported for generic OtherName"); 267 } 268 269 } 270