001: /*
002: * @(#)OtherName.java 1.12 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:
028: package sun.security.x509;
029:
030: import java.io.IOException;
031: import java.lang.reflect.Constructor;
032: import java.lang.reflect.InvocationTargetException;
033: import java.util.Arrays;
034:
035: import sun.security.util.*;
036:
037: /**
038: * This class represents the OtherName as required by the GeneralNames
039: * ASN.1 object. It supplies the generic framework to allow specific
040: * Other Name types, and also provides minimal support for unrecognized
041: * Other Name types.
042: *
043: * The ASN.1 definition for OtherName is:
044: * <pre>
045: * OtherName ::= SEQUENCE {
046: * type-id OBJECT IDENTIFIER,
047: * value [0] EXPLICIT ANY DEFINED BY type-id
048: * }
049: * </pre>
050: * @author Hemma Prafullchandra
051: * @version 1.12, 10/10/06
052: */
053: public class OtherName implements GeneralNameInterface {
054:
055: private String name;
056: private ObjectIdentifier oid;
057: private byte[] nameValue = null;
058: private GeneralNameInterface gni = null;
059:
060: private static final byte TAG_VALUE = 0;
061:
062: /**
063: * Create the OtherName object from a passed ObjectIdentfier and
064: * byte array name value
065: *
066: * @param oid ObjectIdentifier of this OtherName object
067: * @param value the DER-encoded value of the OtherName
068: * @throws IOException on error
069: */
070: public OtherName(ObjectIdentifier oid, byte[] value)
071: throws IOException {
072: if (oid == null || value == null) {
073: throw new NullPointerException("parameters may not be null");
074: }
075: this .oid = oid;
076: this .nameValue = value;
077: gni = getGNI(oid, value);
078: if (gni != null) {
079: name = gni.toString();
080: } else {
081: name = "Unrecognized ObjectIdentifier: " + oid.toString();
082: }
083: }
084:
085: /**
086: * Create the OtherName object from the passed encoded Der value.
087: *
088: * @param derValue the encoded DER OtherName.
089: * @exception IOException on error.
090: */
091: public OtherName(DerValue derValue) throws IOException {
092: DerInputStream in = derValue.toDerInputStream();
093:
094: oid = in.getOID();
095: DerValue val = in.getDerValue();
096: nameValue = val.toByteArray();
097: gni = getGNI(oid, nameValue);
098: if (gni != null) {
099: name = gni.toString();
100: } else {
101: name = "Unrecognized ObjectIdentifier: " + oid.toString();
102: }
103: }
104:
105: /**
106: * Get ObjectIdentifier
107: */
108: public ObjectIdentifier getOID() {
109: //NOTE: May want to consider cloning this
110: return oid;
111: }
112:
113: /**
114: * Get name value
115: */
116: public byte[] getNameValue() {
117: return (byte[]) nameValue.clone();
118: }
119:
120: /**
121: * Get GeneralNameInterface
122: */
123: private GeneralNameInterface getGNI(ObjectIdentifier oid,
124: byte[] nameValue) throws IOException {
125: try {
126: Class extClass = OIDMap.getClass(oid);
127: if (extClass == null) { // Unsupported OtherName
128: return null;
129: }
130: Class[] params = { Object.class };
131: Constructor cons = extClass.getConstructor(params);
132:
133: Object[] passed = new Object[] { nameValue };
134: GeneralNameInterface gni = (GeneralNameInterface) cons
135: .newInstance(passed);
136: return gni;
137: } catch (Exception e) {
138: throw (IOException) new IOException("Instantiation error: "
139: + e).initCause(e);
140: }
141: }
142:
143: /**
144: * Return the type of the GeneralName.
145: */
146: public int getType() {
147: return GeneralNameInterface.NAME_ANY;
148: }
149:
150: /**
151: * Encode the Other name into the DerOutputStream.
152: *
153: * @param out the DER stream to encode the Other-Name to.
154: * @exception IOException on encoding errors.
155: */
156: public void encode(DerOutputStream out) throws IOException {
157: if (gni != null) {
158: // This OtherName has a supported class
159: gni.encode(out);
160: return;
161: } else {
162: // This OtherName has no supporting class
163: DerOutputStream tmp = new DerOutputStream();
164: tmp.putOID(oid);
165: tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
166: TAG_VALUE), nameValue);
167: out.write(DerValue.tag_Sequence, tmp);
168: }
169: }
170:
171: /**
172: * Compares this name with another, for equality.
173: *
174: * @return true iff the names are identical.
175: */
176: public boolean equals(Object other) {
177: if (this == other) {
178: return true;
179: }
180: if (!(other instanceof OtherName)) {
181: return false;
182: }
183: OtherName otherOther = (OtherName) other;
184: if (!(otherOther.oid.equals(oid))) {
185: return false;
186: }
187: GeneralNameInterface otherGNI = null;
188: try {
189: otherGNI = getGNI(otherOther.oid, otherOther.nameValue);
190: } catch (IOException ioe) {
191: return false;
192: }
193:
194: boolean result;
195: if (otherGNI != null) {
196: try {
197: result = (otherGNI.constrains(this ) == NAME_MATCH);
198: } catch (UnsupportedOperationException ioe) {
199: result = false;
200: }
201: } else {
202: result = Arrays.equals(nameValue, otherOther.nameValue);
203: }
204:
205: return result;
206: }
207:
208: /**
209: * Convert the name into user readable string.
210: */
211: public String toString() {
212: return "Other-Name: " + name;
213: }
214:
215: /**
216: * Return type of constraint inputName places on this name:<ul>
217: * <li>NAME_DIFF_TYPE = -1: input name is different type from name
218: * (i.e. does not constrain).
219: * <li>NAME_MATCH = 0: input name matches name.
220: * <li>NAME_NARROWS = 1: input name narrows name (is lower in the
221: * naming subtree)
222: * <li>NAME_WIDENS = 2: input name widens name (is higher in the
223: * naming subtree)
224: * <li>NAME_SAME_TYPE = 3: input name does not match or narrow name,
225: * but is same type.
226: * </ul>. These results are used in checking NameConstraints during
227: * certification path verification.
228: *
229: * @param inputName to be checked for being constrained
230: * @returns constraint type above
231: * @throws UnsupportedOperationException if name is same type, but
232: * comparison operations are not supported for this name type.
233: */
234: public int constrains(GeneralNameInterface inputName) {
235: int constraintType;
236: if (inputName == null) {
237: constraintType = NAME_DIFF_TYPE;
238: } else if (inputName.getType() != NAME_ANY) {
239: constraintType = NAME_DIFF_TYPE;
240: } else {
241: throw new UnsupportedOperationException(
242: "Narrowing, widening, "
243: + "and matching are not supported for OtherName.");
244: }
245: return constraintType;
246: }
247:
248: /**
249: * Return subtree depth of this name for purposes of determining
250: * NameConstraints minimum and maximum bounds.
251: *
252: * @returns distance of name from root
253: * @throws UnsupportedOperationException if not supported for this name type
254: */
255: public int subtreeDepth() {
256: throw new UnsupportedOperationException(
257: "subtreeDepth() not supported for generic OtherName");
258: }
259:
260: }
|