Home | History | Annotate | Download | only in x509
      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 
     26 package sun.security.x509;
     27 
     28 import java.io.IOException;
     29 import java.io.OutputStream;
     30 import java.util.Arrays;
     31 import sun.security.util.*;
     32 
     33 /**
     34  * Represent a X509 Extension Attribute.
     35  *
     36  * <p>Extensions are additional attributes which can be inserted in a X509
     37  * v3 certificate. For example a "Driving License Certificate" could have
     38  * the driving license number as a extension.
     39  *
     40  * <p>Extensions are represented as a sequence of the extension identifier
     41  * (Object Identifier), a boolean flag stating whether the extension is to
     42  * be treated as being critical and the extension value itself (this is again
     43  * a DER encoding of the extension value).
     44  * <pre>
     45  * ASN.1 definition of Extension:
     46  * Extension ::= SEQUENCE {
     47  *      ExtensionId     OBJECT IDENTIFIER,
     48  *      critical        BOOLEAN DEFAULT FALSE,
     49  *      extensionValue  OCTET STRING
     50  * }
     51  * </pre>
     52  * All subclasses need to implement a constructor of the form
     53  * <pre>
     54  *     <subclass> (Boolean, Object)
     55  * </pre>
     56  * where the Object is typically an array of DER encoded bytes.
     57  * <p>
     58  * @author Amit Kapoor
     59  * @author Hemma Prafullchandra
     60  */
     61 public class Extension implements java.security.cert.Extension {
     62 
     63     protected ObjectIdentifier  extensionId = null;
     64     protected boolean           critical = false;
     65     protected byte[]            extensionValue = null;
     66 
     67     /**
     68      * Default constructor.  Used only by sub-classes.
     69      */
     70     public Extension() { }
     71 
     72     /**
     73      * Constructs an extension from a DER encoded array of bytes.
     74      */
     75     public Extension(DerValue derVal) throws IOException {
     76 
     77         DerInputStream in = derVal.toDerInputStream();
     78 
     79         // Object identifier
     80         extensionId = in.getOID();
     81 
     82         // If the criticality flag was false, it will not have been encoded.
     83         DerValue val = in.getDerValue();
     84         if (val.tag == DerValue.tag_Boolean) {
     85             critical = val.getBoolean();
     86 
     87             // Extension value (DER encoded)
     88             val = in.getDerValue();
     89             extensionValue = val.getOctetString();
     90         } else {
     91             critical = false;
     92             extensionValue = val.getOctetString();
     93         }
     94     }
     95 
     96     /**
     97      * Constructs an Extension from individual components of ObjectIdentifier,
     98      * criticality and the DER encoded OctetString.
     99      *
    100      * @param extensionId the ObjectIdentifier of the extension
    101      * @param critical the boolean indicating if the extension is critical
    102      * @param extensionValue the DER encoded octet string of the value.
    103      */
    104     public Extension(ObjectIdentifier extensionId, boolean critical,
    105                      byte[] extensionValue) throws IOException {
    106         this.extensionId = extensionId;
    107         this.critical = critical;
    108         // passed in a DER encoded octet string, strip off the tag
    109         // and length
    110         DerValue inDerVal = new DerValue(extensionValue);
    111         this.extensionValue = inDerVal.getOctetString();
    112     }
    113 
    114     /**
    115      * Constructs an Extension from another extension. To be used for
    116      * creating decoded subclasses.
    117      *
    118      * @param ext the extension to create from.
    119      */
    120     public Extension(Extension ext) {
    121         this.extensionId = ext.extensionId;
    122         this.critical = ext.critical;
    123         this.extensionValue = ext.extensionValue;
    124     }
    125 
    126     /**
    127      * Constructs an Extension from individual components of ObjectIdentifier,
    128      * criticality and the raw encoded extension value.
    129      *
    130      * @param extensionId the ObjectIdentifier of the extension
    131      * @param critical the boolean indicating if the extension is critical
    132      * @param rawExtensionValue the raw DER-encoded extension value (this
    133      * is not the encoded OctetString).
    134      */
    135     public static Extension newExtension(ObjectIdentifier extensionId,
    136         boolean critical, byte[] rawExtensionValue) throws IOException {
    137         Extension ext = new Extension();
    138         ext.extensionId = extensionId;
    139         ext.critical = critical;
    140         ext.extensionValue = rawExtensionValue;
    141         return ext;
    142     }
    143 
    144     public void encode(OutputStream out) throws IOException {
    145         if (out == null) {
    146             throw new NullPointerException();
    147         }
    148 
    149         DerOutputStream dos1 = new DerOutputStream();
    150         DerOutputStream dos2 = new DerOutputStream();
    151 
    152         dos1.putOID(extensionId);
    153         if (critical) {
    154             dos1.putBoolean(critical);
    155         }
    156         dos1.putOctetString(extensionValue);
    157 
    158         dos2.write(DerValue.tag_Sequence, dos1);
    159         out.write(dos2.toByteArray());
    160     }
    161 
    162     /**
    163      * Write the extension to the DerOutputStream.
    164      *
    165      * @param out the DerOutputStream to write the extension to.
    166      * @exception IOException on encoding errors
    167      */
    168     public void encode(DerOutputStream out) throws IOException {
    169 
    170         if (extensionId == null)
    171             throw new IOException("Null OID to encode for the extension!");
    172         if (extensionValue == null)
    173             throw new IOException("No value to encode for the extension!");
    174 
    175         DerOutputStream dos = new DerOutputStream();
    176 
    177         dos.putOID(extensionId);
    178         if (critical)
    179             dos.putBoolean(critical);
    180         dos.putOctetString(extensionValue);
    181 
    182         out.write(DerValue.tag_Sequence, dos);
    183     }
    184 
    185     /**
    186      * Returns true if extension is critical.
    187      */
    188     public boolean isCritical() {
    189         return critical;
    190     }
    191 
    192     /**
    193      * Returns the ObjectIdentifier of the extension.
    194      */
    195     public ObjectIdentifier getExtensionId() {
    196         return extensionId;
    197     }
    198 
    199     public byte[] getValue() {
    200         return extensionValue.clone();
    201     }
    202 
    203     /**
    204      * Returns the extension value as an byte array for further processing.
    205      * Note, this is the raw DER value of the extension, not the DER
    206      * encoded octet string which is in the certificate.
    207      * This method does not return a clone; it is the responsibility of the
    208      * caller to clone the array if necessary.
    209      */
    210     public byte[] getExtensionValue() {
    211         return extensionValue;
    212     }
    213 
    214     public String getId() {
    215         return extensionId.toString();
    216     }
    217 
    218     /**
    219      * Returns the Extension in user readable form.
    220      */
    221     public String toString() {
    222         String s = "ObjectId: " + extensionId.toString();
    223         if (critical) {
    224             s += " Criticality=true\n";
    225         } else {
    226             s += " Criticality=false\n";
    227         }
    228         return (s);
    229     }
    230 
    231     // Value to mix up the hash
    232     private static final int hashMagic = 31;
    233 
    234     /**
    235      * Returns a hashcode value for this Extension.
    236      *
    237      * @return the hashcode value.
    238      */
    239     public int hashCode() {
    240         int h = 0;
    241         if (extensionValue != null) {
    242             byte[] val = extensionValue;
    243             int len = val.length;
    244             while (len > 0)
    245                 h += len * val[--len];
    246         }
    247         h = h * hashMagic + extensionId.hashCode();
    248         h = h * hashMagic + (critical?1231:1237);
    249         return h;
    250     }
    251 
    252     /**
    253      * Compares this Extension for equality with the specified
    254      * object. If the <code>other</code> object is an
    255      * <code>instanceof</code> <code>Extension</code>, then
    256      * its encoded form is retrieved and compared with the
    257      * encoded form of this Extension.
    258      *
    259      * @param other the object to test for equality with this Extension.
    260      * @return true iff the other object is of type Extension, and the
    261      * criticality flag, object identifier and encoded extension value of
    262      * the two Extensions match, false otherwise.
    263      */
    264     public boolean equals(Object other) {
    265         if (this == other)
    266             return true;
    267         if (!(other instanceof Extension))
    268             return false;
    269         Extension otherExt = (Extension) other;
    270         if (critical != otherExt.critical)
    271             return false;
    272         if (!extensionId.equals((Object)otherExt.extensionId))
    273             return false;
    274         return Arrays.equals(extensionValue, otherExt.extensionValue);
    275     }
    276 }
    277