001: /*
002: * @(#)AuthorityKeyIdentifierExtension.java 1.22 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.io.InputStream;
032: import java.io.OutputStream;
033: import java.lang.reflect.Array;
034: import java.util.Enumeration;
035:
036: import sun.security.util.*;
037:
038: /**
039: * This class represents the Authority Key Identifier Extension.
040: *
041: * <p>The authority key identifier extension provides a means of
042: * identifying the particular public key used to sign a certificate.
043: * This extension would be used where an issuer has multiple signing
044: * keys (either due to multiple concurrent key pairs or due to
045: * changeover).
046: * <p>
047: * The ASN.1 syntax for this is:
048: * <pre>
049: * AuthorityKeyIdentifier ::= SEQUENCE {
050: * keyIdentifier [0] KeyIdentifier OPTIONAL,
051: * authorityCertIssuer [1] GeneralNames OPTIONAL,
052: * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL
053: * }
054: * KeyIdentifier ::= OCTET STRING
055: * </pre>
056: * @author Amit Kapoor
057: * @author Hemma Prafullchandra
058: * @version 1.15
059: * @see Extension
060: * @see CertAttrSet
061: */
062: public class AuthorityKeyIdentifierExtension extends Extension
063: implements CertAttrSet {
064: /**
065: * Identifier for this attribute, to be used with the
066: * get, set, delete methods of Certificate, x509 type.
067: */
068: public static final String IDENT = "x509.info.extensions.AuthorityKeyIdentifier";
069: /**
070: * Attribute names.
071: */
072: public static final String NAME = "AuthorityKeyIdentifier";
073: public static final String KEY_ID = "key_id";
074: public static final String AUTH_NAME = "auth_name";
075: public static final String SERIAL_NUMBER = "serial_number";
076:
077: // Private data members
078: private static final byte TAG_ID = 0;
079: private static final byte TAG_NAMES = 1;
080: private static final byte TAG_SERIAL_NUM = 2;
081:
082: private KeyIdentifier id = null;
083: private GeneralNames names = null;
084: private SerialNumber serialNum = null;
085:
086: // Encode only the extension value
087: private void encodeThis() throws IOException {
088: if (id == null && names == null && serialNum == null) {
089: this .extensionValue = null;
090: return;
091: }
092: DerOutputStream seq = new DerOutputStream();
093: DerOutputStream tmp = new DerOutputStream();
094: if (id != null) {
095: DerOutputStream tmp1 = new DerOutputStream();
096: id.encode(tmp1);
097: tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
098: false, TAG_ID), tmp1);
099: }
100: try {
101: if (names != null) {
102: DerOutputStream tmp1 = new DerOutputStream();
103: names.encode(tmp1);
104: tmp.writeImplicit(DerValue.createTag(
105: DerValue.TAG_CONTEXT, true, TAG_NAMES), tmp1);
106: }
107: } catch (Exception e) {
108: throw new IOException(e.toString());
109: }
110: if (serialNum != null) {
111: DerOutputStream tmp1 = new DerOutputStream();
112: serialNum.encode(tmp1);
113: tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
114: false, TAG_SERIAL_NUM), tmp1);
115: }
116: seq.write(DerValue.tag_Sequence, tmp);
117: this .extensionValue = seq.toByteArray();
118: }
119:
120: /**
121: * The default constructor for this extension. Null parameters make
122: * the element optional (not present).
123: *
124: * @param id the KeyIdentifier associated with this extension.
125: * @param names the GeneralNames associated with this extension
126: * @param serialNum the CertificateSerialNumber associated with
127: * this extension.
128: * @exception IOException on error.
129: */
130: public AuthorityKeyIdentifierExtension(KeyIdentifier kid,
131: GeneralNames name, SerialNumber sn) throws IOException {
132: this .id = kid;
133: this .names = name;
134: this .serialNum = sn;
135:
136: this .extensionId = PKIXExtensions.AuthorityKey_Id;
137: this .critical = false;
138: encodeThis();
139: }
140:
141: /**
142: * Create the extension from the passed DER encoded value of the same.
143: *
144: * @param critical true if the extension is to be treated as critical.
145: * @param value Array of DER encoded bytes of the actual value.
146: * @exception IOException on error.
147: */
148: public AuthorityKeyIdentifierExtension(Boolean critical,
149: Object value) throws IOException {
150: this .extensionId = PKIXExtensions.AuthorityKey_Id;
151: this .critical = critical.booleanValue();
152:
153: if (!(value instanceof byte[]))
154: throw new IOException("Illegal argument type");
155:
156: int len = Array.getLength(value);
157: byte[] extValue = new byte[len];
158: System.arraycopy(value, 0, extValue, 0, len);
159:
160: this .extensionValue = extValue;
161: DerValue val = new DerValue(extValue);
162: if (val.tag != DerValue.tag_Sequence) {
163: throw new IOException("Invalid encoding for "
164: + "AuthorityKeyIdentifierExtension.");
165: }
166:
167: // Note that all the fields in AuthorityKeyIdentifier are defined as
168: // being OPTIONAL, i.e., there could be an empty SEQUENCE, resulting
169: // in val.data being null.
170: while ((val.data != null) && (val.data.available() != 0)) {
171: DerValue opt = val.data.getDerValue();
172:
173: // NB. this is always encoded with the IMPLICIT tag
174: // The checks only make sense if we assume implicit tagging,
175: // with explicit tagging the form is always constructed.
176: if (opt.isContextSpecific(TAG_ID) && !opt.isConstructed()) {
177: if (id != null)
178: throw new IOException("Duplicate KeyIdentifier in "
179: + "AuthorityKeyIdentifier.");
180: opt.resetTag(DerValue.tag_OctetString);
181: id = new KeyIdentifier(opt);
182:
183: } else if (opt.isContextSpecific(TAG_NAMES)
184: && opt.isConstructed()) {
185: if (names != null)
186: throw new IOException("Duplicate GeneralNames in "
187: + "AuthorityKeyIdentifier.");
188: opt.resetTag(DerValue.tag_Sequence);
189: names = new GeneralNames(opt);
190:
191: } else if (opt.isContextSpecific(TAG_SERIAL_NUM)
192: && !opt.isConstructed()) {
193: if (serialNum != null)
194: throw new IOException("Duplicate SerialNumber in "
195: + "AuthorityKeyIdentifier.");
196: opt.resetTag(DerValue.tag_Integer);
197: serialNum = new SerialNumber(opt);
198: } else
199: throw new IOException("Invalid encoding of "
200: + "AuthorityKeyIdentifierExtension.");
201: }
202: }
203:
204: /**
205: * Return the object as a string.
206: */
207: public String toString() {
208: String s = super .toString() + "AuthorityKeyIdentifier [\n";
209: if (id != null) {
210: s += id.toString() + "\n";
211: }
212: if (names != null) {
213: s += names.toString() + "\n";
214: }
215: if (serialNum != null) {
216: s += serialNum.toString() + "\n";
217: }
218: return (s + "]\n");
219: }
220:
221: /**
222: * Decode the extension from the InputStream.
223: *
224: * @param in the InputStream to unmarshal the contents from.
225: * @exception IOException on decoding or validity errors.
226: */
227: public void decode(InputStream in) throws IOException {
228: throw new IOException("Method not to be called directly.");
229: }
230:
231: /**
232: * Write the extension to the OutputStream.
233: *
234: * @param out the OutputStream to write the extension to.
235: * @exception IOException on error.
236: */
237: public void encode(OutputStream out) throws IOException {
238: DerOutputStream tmp = new DerOutputStream();
239: if (this .extensionValue == null) {
240: extensionId = PKIXExtensions.AuthorityKey_Id;
241: critical = false;
242: encodeThis();
243: }
244: super .encode(tmp);
245: out.write(tmp.toByteArray());
246: }
247:
248: /**
249: * Set the attribute value.
250: */
251: public void set(String name, Object obj) throws IOException {
252: if (name.equalsIgnoreCase(KEY_ID)) {
253: if (!(obj instanceof KeyIdentifier)) {
254: throw new IOException("Attribute value should be of "
255: + "type KeyIdentifier.");
256: }
257: id = (KeyIdentifier) obj;
258: } else if (name.equalsIgnoreCase(AUTH_NAME)) {
259: if (!(obj instanceof GeneralNames)) {
260: throw new IOException("Attribute value should be of "
261: + "type GeneralNames.");
262: }
263: names = (GeneralNames) obj;
264: } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {
265: if (!(obj instanceof SerialNumber)) {
266: throw new IOException("Attribute value should be of "
267: + "type SerialNumber.");
268: }
269: serialNum = (SerialNumber) obj;
270: } else {
271: throw new IOException("Attribute name not recognized by "
272: + "CertAttrSet:AuthorityKeyIdentifier.");
273: }
274: encodeThis();
275: }
276:
277: /**
278: * Get the attribute value.
279: */
280: public Object get(String name) throws IOException {
281: if (name.equalsIgnoreCase(KEY_ID)) {
282: return (id);
283: } else if (name.equalsIgnoreCase(AUTH_NAME)) {
284: return (names);
285: } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {
286: return (serialNum);
287: } else {
288: throw new IOException("Attribute name not recognized by "
289: + "CertAttrSet:AuthorityKeyIdentifier.");
290: }
291: }
292:
293: /**
294: * Delete the attribute value.
295: */
296: public void delete(String name) throws IOException {
297: if (name.equalsIgnoreCase(KEY_ID)) {
298: id = null;
299: } else if (name.equalsIgnoreCase(AUTH_NAME)) {
300: names = null;
301: } else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {
302: serialNum = null;
303: } else {
304: throw new IOException("Attribute name not recognized by "
305: + "CertAttrSet:AuthorityKeyIdentifier.");
306: }
307: encodeThis();
308: }
309:
310: /**
311: * Return an enumeration of names of attributes existing within this
312: * attribute.
313: */
314: public Enumeration getElements() {
315: AttributeNameEnumeration elements = new AttributeNameEnumeration();
316: elements.addElement(KEY_ID);
317: elements.addElement(AUTH_NAME);
318: elements.addElement(SERIAL_NUMBER);
319:
320: return (elements.elements());
321: }
322:
323: /**
324: * Return the name of this attribute.
325: */
326: public String getName() {
327: return (NAME);
328: }
329: }
|