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
26package sun.security.x509;
27
28import java.io.IOException;
29import java.io.OutputStream;
30import java.util.Enumeration;
31
32import sun.security.util.*;
33
34/**
35 * Represent the Subject Key Identifier Extension.
36 *
37 * This extension, if present, provides a means of identifying the particular
38 * public key used in an application.  This extension by default is marked
39 * non-critical.
40 *
41 * <p>Extensions are addiitonal attributes which can be inserted in a X509
42 * v3 certificate. For example a "Driving License Certificate" could have
43 * the driving license number as a extension.
44 *
45 * <p>Extensions are represented as a sequence of the extension identifier
46 * (Object Identifier), a boolean flag stating whether the extension is to
47 * be treated as being critical and the extension value itself (this is again
48 * a DER encoding of the extension value).
49 *
50 * @author Amit Kapoor
51 * @author Hemma Prafullchandra
52 * @see Extension
53 * @see CertAttrSet
54 */
55public class SubjectKeyIdentifierExtension extends Extension
56implements CertAttrSet<String> {
57    /**
58     * Identifier for this attribute, to be used with the
59     * get, set, delete methods of Certificate, x509 type.
60     */
61    public static final String IDENT =
62                         "x509.info.extensions.SubjectKeyIdentifier";
63    /**
64     * Attribute names.
65     */
66    public static final String NAME = "SubjectKeyIdentifier";
67    public static final String KEY_ID = "key_id";
68
69    // Private data member
70    private KeyIdentifier id = null;
71
72    // Encode this extension value
73    private void encodeThis() throws IOException {
74        if (id == null) {
75            this.extensionValue = null;
76            return;
77        }
78        DerOutputStream os = new DerOutputStream();
79        id.encode(os);
80        this.extensionValue = os.toByteArray();
81    }
82
83    /**
84     * Create a SubjectKeyIdentifierExtension with the passed octet string.
85     * The criticality is set to False.
86     * @param octetString the octet string identifying the key identifier.
87     */
88    public SubjectKeyIdentifierExtension(byte[] octetString)
89    throws IOException {
90        id = new KeyIdentifier(octetString);
91
92        this.extensionId = PKIXExtensions.SubjectKey_Id;
93        this.critical = false;
94        encodeThis();
95    }
96
97    /**
98     * Create the extension from the passed DER encoded value.
99     *
100     * @param critical true if the extension is to be treated as critical.
101     * @param value an array of DER encoded bytes of the actual value.
102     * @exception ClassCastException if value is not an array of bytes
103     * @exception IOException on error.
104     */
105    public SubjectKeyIdentifierExtension(Boolean critical, Object value)
106    throws IOException {
107        this.extensionId = PKIXExtensions.SubjectKey_Id;
108        this.critical = critical.booleanValue();
109        this.extensionValue = (byte[]) value;
110        DerValue val = new DerValue(this.extensionValue);
111        this.id = new KeyIdentifier(val);
112    }
113
114    /**
115     * Returns a printable representation.
116     */
117    public String toString() {
118        return super.toString() + "SubjectKeyIdentifier [\n"
119                + String.valueOf(id) + "]\n";
120    }
121
122    /**
123     * Write the extension to the OutputStream.
124     *
125     * @param out the OutputStream to write the extension to.
126     * @exception IOException on encoding errors.
127     */
128    public void encode(OutputStream out) throws IOException {
129        DerOutputStream tmp = new DerOutputStream();
130        if (extensionValue == null) {
131            extensionId = PKIXExtensions.SubjectKey_Id;
132            critical = false;
133            encodeThis();
134        }
135        super.encode(tmp);
136        out.write(tmp.toByteArray());
137    }
138
139    /**
140     * Set the attribute value.
141     */
142    public void set(String name, Object obj) throws IOException {
143        if (name.equalsIgnoreCase(KEY_ID)) {
144            if (!(obj instanceof KeyIdentifier)) {
145              throw new IOException("Attribute value should be of" +
146                                    " type KeyIdentifier.");
147            }
148            id = (KeyIdentifier)obj;
149        } else {
150          throw new IOException("Attribute name not recognized by " +
151                "CertAttrSet:SubjectKeyIdentifierExtension.");
152        }
153        encodeThis();
154    }
155
156    /**
157     * Get the attribute value.
158     */
159    public KeyIdentifier get(String name) throws IOException {
160        if (name.equalsIgnoreCase(KEY_ID)) {
161            return (id);
162        } else {
163          throw new IOException("Attribute name not recognized by " +
164                "CertAttrSet:SubjectKeyIdentifierExtension.");
165        }
166    }
167
168    /**
169     * Delete the attribute value.
170     */
171    public void delete(String name) throws IOException {
172        if (name.equalsIgnoreCase(KEY_ID)) {
173            id = null;
174        } else {
175          throw new IOException("Attribute name not recognized by " +
176                "CertAttrSet:SubjectKeyIdentifierExtension.");
177        }
178        encodeThis();
179    }
180
181    /**
182     * Return an enumeration of names of attributes existing within this
183     * attribute.
184     */
185    public Enumeration<String> getElements() {
186        AttributeNameEnumeration elements = new AttributeNameEnumeration();
187        elements.addElement(KEY_ID);
188
189        return (elements.elements());
190    }
191
192    /**
193     * Return the name of this attribute.
194     */
195    public String getName() {
196        return (NAME);
197    }
198}
199