1 /*
   2  * Copyright (c) 1997, 2006, 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  * 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  */
  55 public class SubjectKeyIdentifierExtension extends Extension
  56 implements 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 Object 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 }