blob: e24a412417314e44983faf03fe8dc6a8b45f8df2 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.x509;
27
28import java.io.IOException;
29import java.io.OutputStream;
30import java.util.Arrays;
31import sun.security.util.*;
32
33/**
34 * Represent a X509 Extension Attribute.
35 *
36 * <p>Extensions are additional attributes which can be inserted in a X509
37 * v3 certificate. For example a "Driving License Certificate" could have
38 * the driving license number as a extension.
39 *
40 * <p>Extensions are represented as a sequence of the extension identifier
41 * (Object Identifier), a boolean flag stating whether the extension is to
42 * be treated as being critical and the extension value itself (this is again
43 * a DER encoding of the extension value).
44 * <pre>
45 * ASN.1 definition of Extension:
46 * Extension ::= SEQUENCE {
47 * ExtensionId OBJECT IDENTIFIER,
48 * critical BOOLEAN DEFAULT FALSE,
49 * extensionValue OCTET STRING
50 * }
51 * </pre>
52 * All subclasses need to implement a constructor of the form
53 * <pre>
54 * <subclass> (Boolean, Object)
55 * </pre>
56 * where the Object is typically an array of DER encoded bytes.
57 * <p>
58 * @author Amit Kapoor
59 * @author Hemma Prafullchandra
60 */
61public class Extension implements java.security.cert.Extension {
62
63 protected ObjectIdentifier extensionId = null;
64 protected boolean critical = false;
65 protected byte[] extensionValue = null;
66
67 /**
68 * Default constructor. Used only by sub-classes.
69 */
70 public Extension() { }
71
72 /**
73 * Constructs an extension from a DER encoded array of bytes.
74 */
75 public Extension(DerValue derVal) throws IOException {
76
77 DerInputStream in = derVal.toDerInputStream();
78
79 // Object identifier
80 extensionId = in.getOID();
81
82 // If the criticality flag was false, it will not have been encoded.
83 DerValue val = in.getDerValue();
84 if (val.tag == DerValue.tag_Boolean) {
85 critical = val.getBoolean();
86
87 // Extension value (DER encoded)
88 val = in.getDerValue();
89 extensionValue = val.getOctetString();
90 } else {
91 critical = false;
92 extensionValue = val.getOctetString();
93 }
94 }
95
96 /**
97 * Constructs an Extension from individual components of ObjectIdentifier,
98 * criticality and the DER encoded OctetString.
99 *
100 * @param extensionId the ObjectIdentifier of the extension
101 * @param critical the boolean indicating if the extension is critical
102 * @param extensionValue the DER encoded octet string of the value.
103 */
104 public Extension(ObjectIdentifier extensionId, boolean critical,
105 byte[] extensionValue) throws IOException {
106 this.extensionId = extensionId;
107 this.critical = critical;
108 // passed in a DER encoded octet string, strip off the tag
109 // and length
110 DerValue inDerVal = new DerValue(extensionValue);
111 this.extensionValue = inDerVal.getOctetString();
112 }
113
114 /**
115 * Constructs an Extension from another extension. To be used for
116 * creating decoded subclasses.
117 *
118 * @param ext the extension to create from.
119 */
120 public Extension(Extension ext) {
121 this.extensionId = ext.extensionId;
122 this.critical = ext.critical;
123 this.extensionValue = ext.extensionValue;
124 }
125
126 /**
127 * Constructs an Extension from individual components of ObjectIdentifier,
128 * criticality and the raw encoded extension value.
129 *
130 * @param extensionId the ObjectIdentifier of the extension
131 * @param critical the boolean indicating if the extension is critical
132 * @param rawExtensionValue the raw DER-encoded extension value (this
133 * is not the encoded OctetString).
134 */
135 public static Extension newExtension(ObjectIdentifier extensionId,
136 boolean critical, byte[] rawExtensionValue) throws IOException {
137 Extension ext = new Extension();
138 ext.extensionId = extensionId;
139 ext.critical = critical;
140 ext.extensionValue = rawExtensionValue;
141 return ext;
142 }
143
144 public void encode(OutputStream out) throws IOException {
145 if (out == null) {
146 throw new NullPointerException();
147 }
148
149 DerOutputStream dos1 = new DerOutputStream();
150 DerOutputStream dos2 = new DerOutputStream();
151
152 dos1.putOID(extensionId);
153 if (critical) {
154 dos1.putBoolean(critical);
155 }
156 dos1.putOctetString(extensionValue);
157
158 dos2.write(DerValue.tag_Sequence, dos1);
159 out.write(dos2.toByteArray());
160 }
161
162 /**
163 * Write the extension to the DerOutputStream.
164 *
165 * @param out the DerOutputStream to write the extension to.
166 * @exception IOException on encoding errors
167 */
168 public void encode(DerOutputStream out) throws IOException {
169
170 if (extensionId == null)
171 throw new IOException("Null OID to encode for the extension!");
172 if (extensionValue == null)
173 throw new IOException("No value to encode for the extension!");
174
175 DerOutputStream dos = new DerOutputStream();
176
177 dos.putOID(extensionId);
178 if (critical)
179 dos.putBoolean(critical);
180 dos.putOctetString(extensionValue);
181
182 out.write(DerValue.tag_Sequence, dos);
183 }
184
185 /**
186 * Returns true if extension is critical.
187 */
188 public boolean isCritical() {
189 return critical;
190 }
191
192 /**
193 * Returns the ObjectIdentifier of the extension.
194 */
195 public ObjectIdentifier getExtensionId() {
196 return extensionId;
197 }
198
199 public byte[] getValue() {
200 return extensionValue.clone();
201 }
202
203 /**
204 * Returns the extension value as an byte array for further processing.
205 * Note, this is the raw DER value of the extension, not the DER
206 * encoded octet string which is in the certificate.
207 * This method does not return a clone; it is the responsibility of the
208 * caller to clone the array if necessary.
209 */
210 public byte[] getExtensionValue() {
211 return extensionValue;
212 }
213
214 public String getId() {
215 return extensionId.toString();
216 }
217
218 /**
219 * Returns the Extension in user readable form.
220 */
221 public String toString() {
222 String s = "ObjectId: " + extensionId.toString();
223 if (critical) {
224 s += " Criticality=true\n";
225 } else {
226 s += " Criticality=false\n";
227 }
228 return (s);
229 }
230
231 // Value to mix up the hash
232 private static final int hashMagic = 31;
233
234 /**
235 * Returns a hashcode value for this Extension.
236 *
237 * @return the hashcode value.
238 */
239 public int hashCode() {
240 int h = 0;
241 if (extensionValue != null) {
242 byte[] val = extensionValue;
243 int len = val.length;
244 while (len > 0)
245 h += len * val[--len];
246 }
247 h = h * hashMagic + extensionId.hashCode();
248 h = h * hashMagic + (critical?1231:1237);
249 return h;
250 }
251
252 /**
253 * Compares this Extension for equality with the specified
254 * object. If the <code>other</code> object is an
255 * <code>instanceof</code> <code>Extension</code>, then
256 * its encoded form is retrieved and compared with the
257 * encoded form of this Extension.
258 *
259 * @param other the object to test for equality with this Extension.
260 * @return true iff the other object is of type Extension, and the
261 * criticality flag, object identifier and encoded extension value of
262 * the two Extensions match, false otherwise.
263 */
264 public boolean equals(Object other) {
265 if (this == other)
266 return true;
267 if (!(other instanceof Extension))
268 return false;
269 Extension otherExt = (Extension) other;
270 if (critical != otherExt.critical)
271 return false;
272 if (!extensionId.equals(otherExt.extensionId))
273 return false;
274 return Arrays.equals(extensionValue, otherExt.extensionValue);
275 }
276}