Home | History | Annotate | Download | only in x509
      1 /*
      2  * Copyright (c) 1997, 2015, 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 (position < bitString.length) &&
     87                 bitString[position];
     88     }
     89 
     90     /**
     91      * Set the bit at the specified position.
     92      */
     93     private void set(int position, boolean val) {
     94         // enlarge bitString if necessary
     95         if (position >= bitString.length) {
     96             boolean[] tmp = new boolean[position+1];
     97             System.arraycopy(bitString, 0, tmp, 0, bitString.length);
     98             bitString = tmp;
     99         }
    100         bitString[position] = val;
    101     }
    102 
    103     /**
    104      * Create a KeyUsageExtension with the passed bit settings. The criticality
    105      * is set to true.
    106      *
    107      * @param bitString the bits to be set for the extension.
    108      */
    109     public KeyUsageExtension(byte[] bitString) throws IOException {
    110         this.bitString =
    111             new BitArray(bitString.length*8,bitString).toBooleanArray();
    112         this.extensionId = PKIXExtensions.KeyUsage_Id;
    113         this.critical = true;
    114         encodeThis();
    115     }
    116 
    117     /**
    118      * Create a KeyUsageExtension with the passed bit settings. The criticality
    119      * is set to true.
    120      *
    121      * @param bitString the bits to be set for the extension.
    122      */
    123     public KeyUsageExtension(boolean[] bitString) throws IOException {
    124         this.bitString = bitString;
    125         this.extensionId = PKIXExtensions.KeyUsage_Id;
    126         this.critical = true;
    127         encodeThis();
    128     }
    129 
    130     /**
    131      * Create a KeyUsageExtension with the passed bit settings. The criticality
    132      * is set to true.
    133      *
    134      * @param bitString the bits to be set for the extension.
    135      */
    136     public KeyUsageExtension(BitArray bitString) throws IOException {
    137         this.bitString = bitString.toBooleanArray();
    138         this.extensionId = PKIXExtensions.KeyUsage_Id;
    139         this.critical = true;
    140         encodeThis();
    141     }
    142 
    143     /**
    144      * Create the extension from the passed DER encoded value of the same.
    145      * The DER encoded value may be wrapped in an OCTET STRING.
    146      *
    147      * @param critical true if the extension is to be treated as critical.
    148      * @param value an array of DER encoded bytes of the actual value (possibly
    149      * wrapped in an OCTET STRING).
    150      * @exception ClassCastException if value is not an array of bytes
    151      * @exception IOException on error.
    152      */
    153     public KeyUsageExtension(Boolean critical, Object value)
    154     throws IOException {
    155         this.extensionId = PKIXExtensions.KeyUsage_Id;
    156         this.critical = critical.booleanValue();
    157         /*
    158          * The following check should be activated again after
    159          * the PKIX profiling work becomes standard and the check
    160          * is not a barrier to interoperability !
    161          * if (!this.critical) {
    162          *   throw new IOException("KeyUsageExtension not marked critical,"
    163          *                         + " invalid profile.");
    164          * }
    165          */
    166         byte[] extValue = (byte[]) value;
    167         if (extValue[0] == DerValue.tag_OctetString) {
    168             this.extensionValue = new DerValue(extValue).getOctetString();
    169         } else {
    170             this.extensionValue = extValue;
    171         }
    172         DerValue val = new DerValue(this.extensionValue);
    173         this.bitString = val.getUnalignedBitString().toBooleanArray();
    174     }
    175 
    176     /**
    177      * Create a default key usage.
    178      */
    179     public KeyUsageExtension() {
    180         extensionId = PKIXExtensions.KeyUsage_Id;
    181         critical = true;
    182         bitString = new boolean[0];
    183     }
    184 
    185     /**
    186      * Set the attribute value.
    187      */
    188     public void set(String name, Object obj) throws IOException {
    189         if (!(obj instanceof Boolean)) {
    190             throw new IOException("Attribute must be of type Boolean.");
    191         }
    192         boolean val = ((Boolean)obj).booleanValue();
    193         if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
    194             set(0,val);
    195         } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
    196             set(1,val);
    197         } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
    198             set(2,val);
    199         } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
    200             set(3,val);
    201         } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
    202             set(4,val);
    203         } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
    204             set(5,val);
    205         } else if (name.equalsIgnoreCase(CRL_SIGN)) {
    206             set(6,val);
    207         } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
    208             set(7,val);
    209         } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
    210             set(8,val);
    211         } else {
    212           throw new IOException("Attribute name not recognized by"
    213                                 + " CertAttrSet:KeyUsage.");
    214         }
    215         encodeThis();
    216     }
    217 
    218     /**
    219      * Get the attribute value.
    220      */
    221     public Boolean get(String name) throws IOException {
    222         if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
    223             return Boolean.valueOf(isSet(0));
    224         } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
    225             return Boolean.valueOf(isSet(1));
    226         } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
    227             return Boolean.valueOf(isSet(2));
    228         } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
    229             return Boolean.valueOf(isSet(3));
    230         } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
    231             return Boolean.valueOf(isSet(4));
    232         } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
    233             return Boolean.valueOf(isSet(5));
    234         } else if (name.equalsIgnoreCase(CRL_SIGN)) {
    235             return Boolean.valueOf(isSet(6));
    236         } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
    237             return Boolean.valueOf(isSet(7));
    238         } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
    239             return Boolean.valueOf(isSet(8));
    240         } else {
    241           throw new IOException("Attribute name not recognized by"
    242                                 + " CertAttrSet:KeyUsage.");
    243         }
    244     }
    245 
    246     /**
    247      * Delete the attribute value.
    248      */
    249     public void delete(String name) throws IOException {
    250         if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
    251             set(0,false);
    252         } else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
    253             set(1,false);
    254         } else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
    255             set(2,false);
    256         } else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
    257             set(3,false);
    258         } else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
    259             set(4,false);
    260         } else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
    261             set(5,false);
    262         } else if (name.equalsIgnoreCase(CRL_SIGN)) {
    263             set(6,false);
    264         } else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
    265             set(7,false);
    266         } else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
    267             set(8,false);
    268         } else {
    269           throw new IOException("Attribute name not recognized by"
    270                                 + " CertAttrSet:KeyUsage.");
    271         }
    272         encodeThis();
    273     }
    274 
    275     /**
    276      * Returns a printable representation of the KeyUsage.
    277      */
    278     public String toString() {
    279         StringBuilder sb = new StringBuilder();
    280         sb.append(super.toString());
    281         sb.append("KeyUsage [\n");
    282 
    283         if (isSet(0)) {
    284             sb.append("  DigitalSignature\n");
    285         }
    286         if (isSet(1)) {
    287             sb.append("  Non_repudiation\n");
    288         }
    289         if (isSet(2)) {
    290             sb.append("  Key_Encipherment\n");
    291         }
    292         if (isSet(3)) {
    293             sb.append("  Data_Encipherment\n");
    294         }
    295         if (isSet(4)) {
    296             sb.append("  Key_Agreement\n");
    297         }
    298         if (isSet(5)) {
    299             sb.append("  Key_CertSign\n");
    300         }
    301         if (isSet(6)) {
    302             sb.append("  Crl_Sign\n");
    303         }
    304         if (isSet(7)) {
    305             sb.append("  Encipher_Only\n");
    306         }
    307         if (isSet(8)) {
    308             sb.append("  Decipher_Only\n");
    309         }
    310         sb.append("]\n");
    311 
    312         return sb.toString();
    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