001: /*
002: * @(#)Extension.java 1.23 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.util.Arrays;
032: import sun.security.util.*;
033:
034: /**
035: * Represent a X509 Extension Attribute.
036: *
037: * <p>Extensions are additional attributes which can be inserted in a X509
038: * v3 certificate. For example a "Driving License Certificate" could have
039: * the driving license number as a extension.
040: *
041: * <p>Extensions are represented as a sequence of the extension identifier
042: * (Object Identifier), a boolean flag stating whether the extension is to
043: * be treated as being critical and the extension value itself (this is again
044: * a DER encoding of the extension value).
045: * <pre>
046: * ASN.1 definition of Extension:
047: * Extension ::= SEQUENCE {
048: * ExtensionId OBJECT IDENTIFIER,
049: * critical BOOLEAN DEFAULT FALSE,
050: * extensionValue OCTET STRING
051: * }
052: * </pre>
053: * All subclasses need to implement a constructor of the form
054: * <pre>
055: * <subclass> (Boolean, Object)
056: * <pre>
057: * where the Object is typically an array of DER encoded bytes.
058: * <p>
059: * @author Amit Kapoor
060: * @author Hemma Prafullchandra
061: * @version 1.16
062: */
063: public class Extension {
064: protected ObjectIdentifier extensionId = null;
065: protected boolean critical = false;
066: protected byte[] extensionValue = null;
067:
068: /**
069: * Default constructor. Used only by sub-classes.
070: */
071: public Extension() {
072: }
073:
074: /**
075: * Constructs an extension from a DER encoded array of bytes.
076: */
077: public Extension(DerValue derVal) throws IOException {
078:
079: DerInputStream in = derVal.toDerInputStream();
080:
081: // Object identifier
082: extensionId = in.getOID();
083:
084: // If the criticality flag was false, it will not have been encoded.
085: DerValue val = in.getDerValue();
086: if (val.tag == DerValue.tag_Boolean) {
087: critical = val.getBoolean();
088:
089: // Extension value (DER encoded)
090: val = in.getDerValue();
091: extensionValue = val.getOctetString();
092: } else {
093: critical = false;
094: extensionValue = val.getOctetString();
095: }
096: }
097:
098: /**
099: * Constructs an Extension from individual components of ObjectIdentifier,
100: * criticality and the DER encoded OctetString.
101: *
102: * @param extensionId the ObjectIdentifier of the extension
103: * @param critical the boolean indicating if the extension is critical
104: * @param extensionValue the DER encoded octet string of the value.
105: */
106: public Extension(ObjectIdentifier extensionId, boolean critical,
107: byte[] extensionValue) throws IOException {
108: this .extensionId = extensionId;
109: this .critical = critical;
110: // passed in a DER encoded octet string, strip off the tag
111: // and length
112: DerValue inDerVal = new DerValue(extensionValue);
113: this .extensionValue = inDerVal.getOctetString();
114: }
115:
116: /**
117: * Constructs an Extension from another extension. To be used for
118: * creating decoded subclasses.
119: *
120: * @param ext the extension to create from.
121: */
122: public Extension(Extension ext) {
123: this .extensionId = ext.extensionId;
124: this .critical = ext.critical;
125: this .extensionValue = ext.extensionValue;
126: }
127:
128: /**
129: * Write the extension to the DerOutputStream.
130: *
131: * @param out the DerOutputStream to write the extension to.
132: * @exception IOException on encoding errors
133: */
134: public void encode(DerOutputStream out) throws IOException {
135:
136: if (extensionId == null)
137: throw new IOException(
138: "Null OID to encode for the extension!");
139: if (extensionValue == null)
140: throw new IOException(
141: "No value to encode for the extension!");
142:
143: DerOutputStream dos = new DerOutputStream();
144:
145: dos.putOID(extensionId);
146: if (critical)
147: dos.putBoolean(critical);
148: dos.putOctetString(extensionValue);
149:
150: out.write(DerValue.tag_Sequence, dos);
151: }
152:
153: /**
154: * Returns true if extension is critical.
155: */
156: public boolean isCritical() {
157: return (critical);
158: }
159:
160: /**
161: * Returns the ObjectIdentifier of the extension.
162: */
163: public ObjectIdentifier getExtensionId() {
164: return (extensionId);
165: }
166:
167: /**
168: * Returns the extension value as an byte array for further processing.
169: * Note, this is the raw DER value of the extension, not the DER
170: * encoded octet string which is in the certificate.
171: */
172: public byte[] getExtensionValue() {
173: if (extensionValue == null)
174: return null;
175:
176: byte[] dup = new byte[extensionValue.length];
177: System.arraycopy(extensionValue, 0, dup, 0, dup.length);
178: return (dup);
179: }
180:
181: /**
182: * Returns the Extension in user readable form.
183: */
184: public String toString() {
185: String s = "ObjectId: " + extensionId.toString();
186: if (critical) {
187: s += " Criticality=true\n";
188: } else {
189: s += " Criticality=false\n";
190: }
191: return (s);
192: }
193:
194: // Value to mix up the hash
195: private static final int hashMagic = 31;
196:
197: /**
198: * Returns a hashcode value for this Extension.
199: *
200: * @return the hashcode value.
201: */
202: public int hashCode() {
203: int h = 0;
204: if (extensionValue != null) {
205: byte[] val = extensionValue;
206: int len = val.length;
207: while (len > 0)
208: h += len * val[--len];
209: }
210: h = h * hashMagic + extensionId.hashCode();
211: h = h * hashMagic + (critical ? 1231 : 1237);
212: return h;
213: }
214:
215: /**
216: * Compares this Extension for equality with the specified
217: * object. If the <code>other</code> object is an
218: * <code>instanceof</code> <code>Extension</code>, then
219: * its encoded form is retrieved and compared with the
220: * encoded form of this Extension.
221: *
222: * @param other the object to test for equality with this Extension.
223: * @return true iff the other object is of type Extension, and the
224: * criticality flag, object identifier and encoded extension value of
225: * the two Extensions match, false otherwise.
226: */
227: public boolean equals(Object other) {
228: if (this == other)
229: return true;
230: if (!(other instanceof Extension))
231: return false;
232: Extension otherExt = (Extension) other;
233: if (critical != otherExt.critical)
234: return false;
235: if (!extensionId.equals(otherExt.extensionId))
236: return false;
237: return Arrays.equals(extensionValue, otherExt.extensionValue);
238: }
239: }
|