1 /* 2 * Copyright (c) 1997, 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.io.OutputStream; 30 import java.util.Arrays; 31 import 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 */ 61 public 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((Object)otherExt.extensionId)) 273 return false; 274 return Arrays.equals(extensionValue, otherExt.extensionValue); 275 } 276 } 277