1 /* 2 * Copyright (c) 1997, 2009, 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.Enumeration; 31 32 import sun.security.util.*; 33 34 /** 35 * This class represents the Authority Key Identifier Extension. 36 * 37 * <p>The authority key identifier extension provides a means of 38 * identifying the particular public key used to sign a certificate. 39 * This extension would be used where an issuer has multiple signing 40 * keys (either due to multiple concurrent key pairs or due to 41 * changeover). 42 * <p> 43 * The ASN.1 syntax for this is: 44 * <pre> 45 * AuthorityKeyIdentifier ::= SEQUENCE { 46 * keyIdentifier [0] KeyIdentifier OPTIONAL, 47 * authorityCertIssuer [1] GeneralNames OPTIONAL, 48 * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL 49 * } 50 * KeyIdentifier ::= OCTET STRING 51 * </pre> 52 * @author Amit Kapoor 53 * @author Hemma Prafullchandra 54 * @see Extension 55 * @see CertAttrSet 56 */ 57 public class AuthorityKeyIdentifierExtension extends Extension 58 implements CertAttrSet<String> { 59 /** 60 * Identifier for this attribute, to be used with the 61 * get, set, delete methods of Certificate, x509 type. 62 */ 63 public static final String IDENT = 64 "x509.info.extensions.AuthorityKeyIdentifier"; 65 /** 66 * Attribute names. 67 */ 68 public static final String NAME = "AuthorityKeyIdentifier"; 69 public static final String KEY_ID = "key_id"; 70 public static final String AUTH_NAME = "auth_name"; 71 public static final String SERIAL_NUMBER = "serial_number"; 72 73 // Private data members 74 private static final byte TAG_ID = 0; 75 private static final byte TAG_NAMES = 1; 76 private static final byte TAG_SERIAL_NUM = 2; 77 78 private KeyIdentifier id = null; 79 private GeneralNames names = null; 80 private SerialNumber serialNum = null; 81 82 // Encode only the extension value encodeThis()83 private void encodeThis() throws IOException { 84 if (id == null && names == null && serialNum == null) { 85 this.extensionValue = null; 86 return; 87 } 88 DerOutputStream seq = new DerOutputStream(); 89 DerOutputStream tmp = new DerOutputStream(); 90 if (id != null) { 91 DerOutputStream tmp1 = new DerOutputStream(); 92 id.encode(tmp1); 93 tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, 94 false, TAG_ID), tmp1); 95 } 96 try { 97 if (names != null) { 98 DerOutputStream tmp1 = new DerOutputStream(); 99 names.encode(tmp1); 100 tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, 101 true, TAG_NAMES), tmp1); 102 } 103 } catch (Exception e) { 104 throw new IOException(e.toString()); 105 } 106 if (serialNum != null) { 107 DerOutputStream tmp1 = new DerOutputStream(); 108 serialNum.encode(tmp1); 109 tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, 110 false, TAG_SERIAL_NUM), tmp1); 111 } 112 seq.write(DerValue.tag_Sequence, tmp); 113 this.extensionValue = seq.toByteArray(); 114 } 115 116 /** 117 * The default constructor for this extension. Null parameters make 118 * the element optional (not present). 119 * 120 * @param kid the KeyIdentifier associated with this extension. 121 * @param names the GeneralNames associated with this extension 122 * @param sn the CertificateSerialNumber associated with 123 * this extension. 124 * @exception IOException on error. 125 */ AuthorityKeyIdentifierExtension(KeyIdentifier kid, GeneralNames names, SerialNumber sn)126 public AuthorityKeyIdentifierExtension(KeyIdentifier kid, GeneralNames names, 127 SerialNumber sn) 128 throws IOException { 129 this.id = kid; 130 this.names = names; 131 this.serialNum = sn; 132 133 this.extensionId = PKIXExtensions.AuthorityKey_Id; 134 this.critical = false; 135 encodeThis(); 136 } 137 138 /** 139 * Create the extension from the passed DER encoded value of the same. 140 * 141 * @param critical true if the extension is to be treated as critical. 142 * @param value an array of DER encoded bytes of the actual value. 143 * @exception ClassCastException if value is not an array of bytes 144 * @exception IOException on error. 145 */ AuthorityKeyIdentifierExtension(Boolean critical, Object value)146 public AuthorityKeyIdentifierExtension(Boolean critical, Object value) 147 throws IOException { 148 this.extensionId = PKIXExtensions.AuthorityKey_Id; 149 this.critical = critical.booleanValue(); 150 151 this.extensionValue = (byte[]) value; 152 DerValue val = new DerValue(this.extensionValue); 153 if (val.tag != DerValue.tag_Sequence) { 154 throw new IOException("Invalid encoding for " + 155 "AuthorityKeyIdentifierExtension."); 156 } 157 158 // Note that all the fields in AuthorityKeyIdentifier are defined as 159 // being OPTIONAL, i.e., there could be an empty SEQUENCE, resulting 160 // in val.data being null. 161 while ((val.data != null) && (val.data.available() != 0)) { 162 DerValue opt = val.data.getDerValue(); 163 164 // NB. this is always encoded with the IMPLICIT tag 165 // The checks only make sense if we assume implicit tagging, 166 // with explicit tagging the form is always constructed. 167 if (opt.isContextSpecific(TAG_ID) && !opt.isConstructed()) { 168 if (id != null) 169 throw new IOException("Duplicate KeyIdentifier in " + 170 "AuthorityKeyIdentifier."); 171 opt.resetTag(DerValue.tag_OctetString); 172 id = new KeyIdentifier(opt); 173 174 } else if (opt.isContextSpecific(TAG_NAMES) && 175 opt.isConstructed()) { 176 if (names != null) 177 throw new IOException("Duplicate GeneralNames in " + 178 "AuthorityKeyIdentifier."); 179 opt.resetTag(DerValue.tag_Sequence); 180 names = new GeneralNames(opt); 181 182 } else if (opt.isContextSpecific(TAG_SERIAL_NUM) && 183 !opt.isConstructed()) { 184 if (serialNum != null) 185 throw new IOException("Duplicate SerialNumber in " + 186 "AuthorityKeyIdentifier."); 187 opt.resetTag(DerValue.tag_Integer); 188 serialNum = new SerialNumber(opt); 189 } else 190 throw new IOException("Invalid encoding of " + 191 "AuthorityKeyIdentifierExtension."); 192 } 193 } 194 195 /** 196 * Return the object as a string. 197 */ toString()198 public String toString() { 199 StringBuilder sb = new StringBuilder(); 200 sb.append(super.toString()) 201 .append("AuthorityKeyIdentifier [\n"); 202 if (id != null) { 203 sb.append(id); // id already has a newline 204 } 205 if (names != null) { 206 sb.append(names).append('\n'); 207 } 208 if (serialNum != null) { 209 sb.append(serialNum).append('\n'); 210 } 211 sb.append("]\n"); 212 return sb.toString(); 213 } 214 215 /** 216 * Write the extension to the OutputStream. 217 * 218 * @param out the OutputStream to write the extension to. 219 * @exception IOException on error. 220 */ encode(OutputStream out)221 public void encode(OutputStream out) throws IOException { 222 DerOutputStream tmp = new DerOutputStream(); 223 if (this.extensionValue == null) { 224 extensionId = PKIXExtensions.AuthorityKey_Id; 225 critical = false; 226 encodeThis(); 227 } 228 super.encode(tmp); 229 out.write(tmp.toByteArray()); 230 } 231 232 /** 233 * Set the attribute value. 234 */ set(String name, Object obj)235 public void set(String name, Object obj) throws IOException { 236 if (name.equalsIgnoreCase(KEY_ID)) { 237 if (!(obj instanceof KeyIdentifier)) { 238 throw new IOException("Attribute value should be of " + 239 "type KeyIdentifier."); 240 } 241 id = (KeyIdentifier)obj; 242 } else if (name.equalsIgnoreCase(AUTH_NAME)) { 243 if (!(obj instanceof GeneralNames)) { 244 throw new IOException("Attribute value should be of " + 245 "type GeneralNames."); 246 } 247 names = (GeneralNames)obj; 248 } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) { 249 if (!(obj instanceof SerialNumber)) { 250 throw new IOException("Attribute value should be of " + 251 "type SerialNumber."); 252 } 253 serialNum = (SerialNumber)obj; 254 } else { 255 throw new IOException("Attribute name not recognized by " + 256 "CertAttrSet:AuthorityKeyIdentifier."); 257 } 258 encodeThis(); 259 } 260 261 /** 262 * Get the attribute value. 263 */ get(String name)264 public Object get(String name) throws IOException { 265 if (name.equalsIgnoreCase(KEY_ID)) { 266 return (id); 267 } else if (name.equalsIgnoreCase(AUTH_NAME)) { 268 return (names); 269 } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) { 270 return (serialNum); 271 } else { 272 throw new IOException("Attribute name not recognized by " + 273 "CertAttrSet:AuthorityKeyIdentifier."); 274 } 275 } 276 277 /** 278 * Delete the attribute value. 279 */ delete(String name)280 public void delete(String name) throws IOException { 281 if (name.equalsIgnoreCase(KEY_ID)) { 282 id = null; 283 } else if (name.equalsIgnoreCase(AUTH_NAME)) { 284 names = null; 285 } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) { 286 serialNum = null; 287 } else { 288 throw new IOException("Attribute name not recognized by " + 289 "CertAttrSet:AuthorityKeyIdentifier."); 290 } 291 encodeThis(); 292 } 293 294 /** 295 * Return an enumeration of names of attributes existing within this 296 * attribute. 297 */ getElements()298 public Enumeration<String> getElements() { 299 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 300 elements.addElement(KEY_ID); 301 elements.addElement(AUTH_NAME); 302 elements.addElement(SERIAL_NUMBER); 303 304 return (elements.elements()); 305 } 306 307 /** 308 * Return the name of this attribute. 309 */ getName()310 public String getName() { 311 return (NAME); 312 } 313 314 /** 315 * Return the encoded key identifier, or null if not specified. 316 */ getEncodedKeyIdentifier()317 public byte[] getEncodedKeyIdentifier() throws IOException { 318 if (id != null) { 319 DerOutputStream derOut = new DerOutputStream(); 320 id.encode(derOut); 321 return derOut.toByteArray(); 322 } 323 return null; 324 } 325 } 326