Home | History | Annotate | Download | only in x509
      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 Key Usage Extension.
     36  *
     37  * <p>This extension, if present, defines the purpose (e.g., encipherment,
     38  * signature, certificate signing) of the key contained in the certificate.
     39  * The usage restriction might be employed when a multipurpose key is to be
     40  * restricted (e.g., when an RSA key should be used only for signing or only
     41  * for key encipherment).
     42  *
     43  * @author Amit Kapoor
     44  * @author Hemma Prafullchandra
     45  * @see Extension
     46  * @see CertAttrSet
     47  */
     48 public class KeyUsageExtension extends Extension
     49 implements CertAttrSet<String> {
     50 
     51     /**
     52      * Identifier for this attribute, to be used with the
     53      * get, set, delete methods of Certificate, x509 type.
     54      */
     55     public static final String IDENT = "x509.info.extensions.KeyUsage";
     56     /**
     57      * Attribute names.
     58      */
     59     public static final String NAME = "KeyUsage";
     60     public static final String DIGITAL_SIGNATURE = "digital_signature";
     61     public static final String NON_REPUDIATION = "non_repudiation";
     62     public static final String KEY_ENCIPHERMENT = "key_encipherment";
     63     public static final String DATA_ENCIPHERMENT = "data_encipherment";
     64     public static final String KEY_AGREEMENT = "key_agreement";
     65     public static final String KEY_CERTSIGN = "key_certsign";
     66     public static final String CRL_SIGN = "crl_sign";
     67     public static final String ENCIPHER_ONLY = "encipher_only";
     68     public static final String DECIPHER_ONLY = "decipher_only";
     69 
     70     // Private data members
     71     private boolean[] bitString;
     72 
     73     // Encode this extension value
     74     private void encodeThis() throws IOException {
     75         DerOutputStream os = new DerOutputStream();
     76         os.putTruncatedUnalignedBitString(new BitArray(this.bitString));
     77         this.extensionValue = os.toByteArray();
     78     }
     79 
     80     /**
     81      * Check if bit is set.
     82      *
     83      * @param position the position in the bit string to check.
     84      */
     85     private boolean isSet(int position) {
     86         return bitString[position];
     87     }
     88 
     89     /**
     90      * Set the bit at the specified position.
     91      */
     92     private void set(int position, boolean val) {
     93         // enlarge bitString if necessary
     94         if (position >= bitString.length) {
     95             boolean[] tmp = new boolean[position+1];
     96             System.arraycopy(bitString, 0, tmp, 0, bitString.length);
     97             bitString = tmp;
     98         }
     99         bitString[position] = val;
    100     }
    101 
    102     /**
    103      * Create a KeyUsageExtension with the passed bit settings. The criticality
    104      * is set to true.
    105      *
    106      * @param bitString the bits to be set for the extension.
    107      */
    108     public KeyUsageExtension(byte[] bitString) throws IOException {
    109         this.bitString =
    110             new BitArray(bitString.length*8,bitString).toBooleanArray();
    111         this.extensionId = PKIXExtensions.KeyUsage_Id;
    112         this.critical = true;
    113         encodeThis();
    114     }
    115 
    116     /**
    117      * Create a KeyUsageExtension with the passed bit settings. The criticality
    118      * is set to true.
    119      *
    120      * @param bitString the bits to be set for the extension.
    121      */
    122     public KeyUsageExtension(boolean[] bitString) throws IOException {
    123         this.bitString = bitString;
    124         this.extensionId = PKIXExtensions.KeyUsage_Id;
    125         this.critical = true;
    126         encodeThis();
    127     }
    128 
    129     /**
    130      * Create a KeyUsageExtension with the passed bit settings. The criticality
    131      * is set to true.
    132      *
    133      * @param bitString the bits to be set for the extension.
    134      */
    135     public KeyUsageExtension(BitArray bitString) throws IOException {
    136         this.bitString = bitString.toBooleanArray();
    137         this.extensionId = PKIXExtensions.KeyUsage_Id;
    138         this.critical = true;
    139         encodeThis();
    140     }
    141 
    142     /**
    143      * Create the extension from the passed DER encoded value of the same.
    144      * The DER encoded value may be wrapped in an OCTET STRING.
    145      *
    146      * @param critical true if the extension is to be treated as critical.
    147      * @param value an array of DER encoded bytes of the actual value (possibly
    148      * wrapped in an OCTET STRING).
    149      * @exception ClassCastException if value is not an array of bytes
    150      * @exception IOException on error.
    151      */
    152     public KeyUsageExtension(Boolean critical, Object value)
    153     throws IOException {
    154         this.extensionId = PKIXExtensions.KeyUsage_Id;
    155         this.critical = critical.booleanValue();
    156         /*
    157          * The following check should be activated again after
    158          * the PKIX profiling work becomes standard and the check
    159          * is not a barrier to interoperability !
    160          * if (!this.critical) {
    161          *   throw new IOException("KeyUsageExtension not marked critical,"
    162          *                         + " invalid profile.");
    163          * }
    164          */
    165         byte[] extValue = (byte[]) value;
    166         if (extValue[0] == DerValue.tag_OctetString) {
    167             this.extensionValue = new DerValue(extValue).getOctetString();
    168         } else {
    169             this.extensionValue = extValue;
    170         }
    171         DerValue val = new DerValue(this.extensionValue);
    172         this.bitString = val.getUnalignedBitString().toBooleanArray();
    173     }
    174 
    175     /**
    176      * Create a default key usage.
    177      */
    178     public KeyUsageExtension() {
    179         extensionId = PKIXExtensions.KeyUsage_Id;
    180         critical = true;
    181         bitString = new boolean[0];
    182     }
    183 
    184     /**
    185      * Set the attribute value.
    186      */
    187     public void set(String name, Object obj) throws IOException {
    188         if (!(obj instanceof Boolean)) {
    189             throw new IOException("Attribute must be of type Boolean.");
    190         }
    191         boolean val = ((Boolean)obj).booleanValue();
    192         if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
    193             set(0,val);
    194         } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
    195             set(1,val);
    196         } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
    197             set(2,val);
    198         } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
    199             set(3,val);
    200         } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
    201             set(4,val);
    202         } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
    203             set(5,val);
    204         } else if (name.equalsIgnoreCase(CRL_SIGN)) {
    205             set(6,val);
    206         } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
    207             set(7,val);
    208         } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
    209             set(8,val);
    210         } else {
    211           throw new IOException("Attribute name not recognized by"
    212                                 + " CertAttrSet:KeyUsage.");
    213         }
    214         encodeThis();
    215     }
    216 
    217     /**
    218      * Get the attribute value.
    219      */
    220     public Object get(String name) throws IOException {
    221         if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
    222             return Boolean.valueOf(isSet(0));
    223         } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
    224             return Boolean.valueOf(isSet(1));
    225         } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
    226             return Boolean.valueOf(isSet(2));
    227         } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
    228             return Boolean.valueOf(isSet(3));
    229         } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
    230             return Boolean.valueOf(isSet(4));
    231         } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
    232             return Boolean.valueOf(isSet(5));
    233         } else if (name.equalsIgnoreCase(CRL_SIGN)) {
    234             return Boolean.valueOf(isSet(6));
    235         } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
    236             return Boolean.valueOf(isSet(7));
    237         } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
    238             return Boolean.valueOf(isSet(8));
    239         } else {
    240           throw new IOException("Attribute name not recognized by"
    241                                 + " CertAttrSet:KeyUsage.");
    242         }
    243     }
    244 
    245     /**
    246      * Delete the attribute value.
    247      */
    248     public void delete(String name) throws IOException {
    249         if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
    250             set(0,false);
    251         } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
    252             set(1,false);
    253         } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
    254             set(2,false);
    255         } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
    256             set(3,false);
    257         } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
    258             set(4,false);
    259         } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
    260             set(5,false);
    261         } else if (name.equalsIgnoreCase(CRL_SIGN)) {
    262             set(6,false);
    263         } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
    264             set(7,false);
    265         } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
    266             set(8,false);
    267         } else {
    268           throw new IOException("Attribute name not recognized by"
    269                                 + " CertAttrSet:KeyUsage.");
    270         }
    271         encodeThis();
    272     }
    273 
    274     /**
    275      * Returns a printable representation of the KeyUsage.
    276      */
    277     public String toString() {
    278         String s = super.toString() + "KeyUsage [\n";
    279 
    280         try {
    281             if (isSet(0)) {
    282                 s += "  DigitalSignature\n";
    283             }
    284             if (isSet(1)) {
    285                 s += "  Non_repudiation\n";
    286             }
    287             if (isSet(2)) {
    288                 s += "  Key_Encipherment\n";
    289             }
    290             if (isSet(3)) {
    291                 s += "  Data_Encipherment\n";
    292             }
    293             if (isSet(4)) {
    294                 s += "  Key_Agreement\n";
    295             }
    296             if (isSet(5)) {
    297                 s += "  Key_CertSign\n";
    298             }
    299             if (isSet(6)) {
    300                 s += "  Crl_Sign\n";
    301             }
    302             if (isSet(7)) {
    303                 s += "  Encipher_Only\n";
    304             }
    305             if (isSet(8)) {
    306                 s += "  Decipher_Only\n";
    307             }
    308         } catch (ArrayIndexOutOfBoundsException ex) {}
    309 
    310         s += "]\n";
    311 
    312         return (s);
    313     }
    314 
    315     /**
    316      * Write the extension to the DerOutputStream.
    317      *
    318      * @param out the DerOutputStream to write the extension to.
    319      * @exception IOException on encoding errors.
    320      */
    321     public void encode(OutputStream out) throws IOException {
    322        DerOutputStream  tmp = new DerOutputStream();
    323 
    324        if (this.extensionValue == null) {
    325            this.extensionId = PKIXExtensions.KeyUsage_Id;
    326            this.critical = true;
    327            encodeThis();
    328        }
    329        super.encode(tmp);
    330        out.write(tmp.toByteArray());
    331     }
    332 
    333     /**
    334      * Return an enumeration of names of attributes existing within this
    335      * attribute.
    336      */
    337     public Enumeration<String> getElements() {
    338         AttributeNameEnumeration elements = new AttributeNameEnumeration();
    339         elements.addElement(DIGITAL_SIGNATURE);
    340         elements.addElement(NON_REPUDIATION);
    341         elements.addElement(KEY_ENCIPHERMENT);
    342         elements.addElement(DATA_ENCIPHERMENT);
    343         elements.addElement(KEY_AGREEMENT);
    344         elements.addElement(KEY_CERTSIGN);
    345         elements.addElement(CRL_SIGN);
    346         elements.addElement(ENCIPHER_ONLY);
    347         elements.addElement(DECIPHER_ONLY);
    348 
    349         return (elements.elements());
    350     }
    351 
    352 
    353     public boolean[] getBits() {
    354         return bitString.clone();
    355     }
    356 
    357     /**
    358      * Return the name of this attribute.
    359      */
    360     public String getName() {
    361         return (NAME);
    362     }
    363 }
    364