Home | History | Annotate | Download | only in x509
      1 /*
      2  * Copyright (c) 1998, 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.*;
     31 
     32 import sun.security.util.*;
     33 
     34 /**
     35  * Represents Netscape Certificate Type Extension.
     36  * The details are defined
     37  * <a href=http://www.netscape.com/eng/security/comm4-cert-exts.html>
     38  * here </a>.
     39  *
     40  * <p>This extension, if present, defines both the purpose
     41  * (e.g., encipherment, signature, certificate signing) and the application
     42  * (e.g., SSL, S/Mime or Object Signing of the key contained in the
     43  * certificate. This extension has been superseded by IETF PKIX extensions
     44  * but is provided here for compatibility reasons.
     45  *
     46  * @author Hemma Prafullchandra
     47  * @see Extension
     48  * @see CertAttrSet
     49  */
     50 
     51 public class NetscapeCertTypeExtension extends Extension
     52 implements CertAttrSet<String> {
     53 
     54     /**
     55      * Identifier for this attribute, to be used with the
     56      * get, set, delete methods of Certificate, x509 type.
     57      */
     58     public static final String IDENT = "x509.info.extensions.NetscapeCertType";
     59 
     60     /**
     61      * Attribute names.
     62      */
     63     public static final String NAME = "NetscapeCertType";
     64     public static final String SSL_CLIENT = "ssl_client";
     65     public static final String SSL_SERVER = "ssl_server";
     66     public static final String S_MIME = "s_mime";
     67     public static final String OBJECT_SIGNING = "object_signing";
     68     public static final String SSL_CA = "ssl_ca";
     69     public static final String S_MIME_CA = "s_mime_ca";
     70     public static final String OBJECT_SIGNING_CA = "object_signing_ca";
     71 
     72     private static final int CertType_data[] = { 2, 16, 840, 1, 113730, 1, 1 };
     73 
     74     /**
     75      * Object identifier for the Netscape-Cert-Type extension.
     76      */
     77     public static ObjectIdentifier NetscapeCertType_Id;
     78 
     79     static {
     80         try {
     81             NetscapeCertType_Id = new ObjectIdentifier(CertType_data);
     82         } catch (IOException ioe) {
     83             // should not happen
     84         }
     85     }
     86 
     87     private boolean[] bitString;
     88 
     89     private static class MapEntry {
     90         String mName;
     91         int mPosition;
     92 
     93         MapEntry(String name, int position) {
     94             mName = name;
     95             mPosition = position;
     96         }
     97     }
     98 
     99     private static MapEntry[] mMapData = {
    100         new MapEntry(SSL_CLIENT, 0),
    101         new MapEntry(SSL_SERVER, 1),
    102         new MapEntry(S_MIME, 2),
    103         new MapEntry(OBJECT_SIGNING, 3),
    104         // note that bit 4 is reserved
    105         new MapEntry(SSL_CA, 5),
    106         new MapEntry(S_MIME_CA, 6),
    107         new MapEntry(OBJECT_SIGNING_CA, 7),
    108     };
    109 
    110     private static final Vector<String> mAttributeNames = new Vector<String>();
    111     static {
    112         for (MapEntry entry : mMapData) {
    113             mAttributeNames.add(entry.mName);
    114         }
    115     }
    116 
    117     private static int getPosition(String name) throws IOException {
    118         for (int i = 0; i < mMapData.length; i++) {
    119             if (name.equalsIgnoreCase(mMapData[i].mName))
    120                 return mMapData[i].mPosition;
    121         }
    122         throw new IOException("Attribute name [" + name
    123                              + "] not recognized by CertAttrSet:NetscapeCertType.");
    124     }
    125 
    126     // Encode this extension value
    127     private void encodeThis() throws IOException {
    128         DerOutputStream os = new DerOutputStream();
    129         os.putTruncatedUnalignedBitString(new BitArray(this.bitString));
    130         this.extensionValue = os.toByteArray();
    131     }
    132 
    133     /**
    134      * Check if bit is set.
    135      *
    136      * @param position the position in the bit string to check.
    137      */
    138     private boolean isSet(int position) {
    139         return (position < bitString.length) &&
    140                 bitString[position];
    141     }
    142 
    143     /**
    144      * Set the bit at the specified position.
    145      */
    146     private void set(int position, boolean val) {
    147         // enlarge bitString if necessary
    148         if (position >= bitString.length) {
    149             boolean[] tmp = new boolean[position+1];
    150             System.arraycopy(bitString, 0, tmp, 0, bitString.length);
    151             bitString = tmp;
    152         }
    153         bitString[position] = val;
    154     }
    155 
    156     /**
    157      * Create a NetscapeCertTypeExtension with the passed bit settings.
    158      * The criticality is set to true.
    159      *
    160      * @param bitString the bits to be set for the extension.
    161      */
    162     public NetscapeCertTypeExtension(byte[] bitString) throws IOException {
    163         this.bitString =
    164             new BitArray(bitString.length*8, bitString).toBooleanArray();
    165         this.extensionId = NetscapeCertType_Id;
    166         this.critical = true;
    167         encodeThis();
    168     }
    169 
    170     /**
    171      * Create a NetscapeCertTypeExtension with the passed bit settings.
    172      * The criticality is set to true.
    173      *
    174      * @param bitString the bits to be set for the extension.
    175      */
    176     public NetscapeCertTypeExtension(boolean[] bitString) throws IOException {
    177         this.bitString = bitString;
    178         this.extensionId = NetscapeCertType_Id;
    179         this.critical = true;
    180         encodeThis();
    181     }
    182 
    183     /**
    184      * Create the extension from the passed DER encoded value of the same.
    185      *
    186      * @param critical true if the extension is to be treated as critical.
    187      * @param value an array of DER encoded bytes of the actual value.
    188      * @exception ClassCastException if value is not an array of bytes
    189      * @exception IOException on error.
    190      */
    191     public NetscapeCertTypeExtension(Boolean critical, Object value)
    192     throws IOException {
    193         this.extensionId = NetscapeCertType_Id;
    194         this.critical = critical.booleanValue();
    195         this.extensionValue = (byte[]) value;
    196         DerValue val = new DerValue(this.extensionValue);
    197         this.bitString = val.getUnalignedBitString().toBooleanArray();
    198     }
    199 
    200     /**
    201      * Create a default key usage.
    202      */
    203     public NetscapeCertTypeExtension() {
    204         extensionId = NetscapeCertType_Id;
    205         critical = true;
    206         bitString = new boolean[0];
    207     }
    208 
    209     /**
    210      * Set the attribute value.
    211      */
    212     public void set(String name, Object obj) throws IOException {
    213         if (!(obj instanceof Boolean))
    214             throw new IOException("Attribute must be of type Boolean.");
    215 
    216         boolean val = ((Boolean)obj).booleanValue();
    217         set(getPosition(name), val);
    218         encodeThis();
    219     }
    220 
    221     /**
    222      * Get the attribute value.
    223      */
    224     public Boolean get(String name) throws IOException {
    225         return Boolean.valueOf(isSet(getPosition(name)));
    226     }
    227 
    228     /**
    229      * Delete the attribute value.
    230      */
    231     public void delete(String name) throws IOException {
    232         set(getPosition(name), false);
    233         encodeThis();
    234     }
    235 
    236     /**
    237      * Returns a printable representation of the NetscapeCertType.
    238      */
    239     public String toString() {
    240         StringBuilder sb = new StringBuilder();
    241         sb.append(super.toString());
    242         sb.append("NetscapeCertType [\n");
    243 
    244         if (isSet(0)) {
    245             sb.append("   SSL client\n");
    246         }
    247         if (isSet(1)) {
    248             sb.append("   SSL server\n");
    249         }
    250         if (isSet(2)) {
    251             sb.append("   S/MIME\n");
    252         }
    253         if (isSet(3)) {
    254             sb.append("   Object Signing\n");
    255         }
    256         if (isSet(5)) {
    257             sb.append("   SSL CA\n");
    258         }
    259         if (isSet(6)) {
    260             sb.append("   S/MIME CA\n");
    261         }
    262         if (isSet(7)) {
    263             sb.append("   Object Signing CA");
    264         }
    265 
    266         sb.append("]\n");
    267         return sb.toString();
    268     }
    269 
    270     /**
    271      * Write the extension to the DerOutputStream.
    272      *
    273      * @param out the DerOutputStream to write the extension to.
    274      * @exception IOException on encoding errors.
    275      */
    276     public void encode(OutputStream out) throws IOException {
    277         DerOutputStream  tmp = new DerOutputStream();
    278 
    279         if (this.extensionValue == null) {
    280             this.extensionId = NetscapeCertType_Id;
    281             this.critical = true;
    282             encodeThis();
    283         }
    284         super.encode(tmp);
    285         out.write(tmp.toByteArray());
    286     }
    287 
    288     /**
    289      * Return an enumeration of names of attributes existing within this
    290      * attribute.
    291      */
    292     public Enumeration<String> getElements() {
    293         return mAttributeNames.elements();
    294     }
    295 
    296     /**
    297      * Return the name of this attribute.
    298      */
    299     public String getName() {
    300         return (NAME);
    301     }
    302 
    303     /**
    304      * Get a boolean array representing the bits of this extension,
    305      * as it maps to the KeyUsage extension.
    306      * @return the bit values of this extension mapped to the bit values
    307      * of the KeyUsage extension as an array of booleans.
    308      */
    309     public boolean[] getKeyUsageMappedBits() {
    310         KeyUsageExtension keyUsage = new KeyUsageExtension();
    311         Boolean val = Boolean.TRUE;
    312 
    313         try {
    314             if (isSet(getPosition(SSL_CLIENT)) ||
    315                 isSet(getPosition(S_MIME)) ||
    316                 isSet(getPosition(OBJECT_SIGNING)))
    317                 keyUsage.set(KeyUsageExtension.DIGITAL_SIGNATURE, val);
    318 
    319             if (isSet(getPosition(SSL_SERVER)))
    320                 keyUsage.set(KeyUsageExtension.KEY_ENCIPHERMENT, val);
    321 
    322             if (isSet(getPosition(SSL_CA)) ||
    323                 isSet(getPosition(S_MIME_CA)) ||
    324                 isSet(getPosition(OBJECT_SIGNING_CA)))
    325                 keyUsage.set(KeyUsageExtension.KEY_CERTSIGN, val);
    326         } catch (IOException e) { }
    327         return keyUsage.getBits();
    328     }
    329 }
    330