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.security.cert.CRLReason;
     31 import java.util.Enumeration;
     32 
     33 import sun.security.util.*;
     34 
     35 /**
     36  * The reasonCode is a non-critical CRL entry extension that identifies
     37  * the reason for the certificate revocation. CAs are strongly
     38  * encouraged to include reason codes in CRL entries; however, the
     39  * reason code CRL entry extension should be absent instead of using the
     40  * unspecified (0) reasonCode value.
     41  * <p>The ASN.1 syntax for this is:
     42  * <pre>
     43  *  id-ce-cRLReason OBJECT IDENTIFIER ::= { id-ce 21 }
     44  *
     45  *  -- reasonCode ::= { CRLReason }
     46  *
     47  * CRLReason ::= ENUMERATED {
     48  *    unspecified             (0),
     49  *    keyCompromise           (1),
     50  *    cACompromise            (2),
     51  *    affiliationChanged      (3),
     52  *    superseded              (4),
     53  *    cessationOfOperation    (5),
     54  *    certificateHold         (6),
     55  *    removeFromCRL           (8),
     56  *    privilegeWithdrawn      (9),
     57  *    aACompromise           (10) }
     58  * </pre>
     59  * @author Hemma Prafullchandra
     60  * @see Extension
     61  * @see CertAttrSet
     62  */
     63 public class CRLReasonCodeExtension extends Extension
     64         implements CertAttrSet<String> {
     65 
     66     /**
     67      * Attribute name and Reason codes
     68      */
     69     public static final String NAME = "CRLReasonCode";
     70     public static final String REASON = "reason";
     71 
     72     public static final int UNSPECIFIED = 0;
     73     public static final int KEY_COMPROMISE = 1;
     74     public static final int CA_COMPROMISE = 2;
     75     public static final int AFFLIATION_CHANGED = 3;
     76     public static final int SUPERSEDED = 4;
     77     public static final int CESSATION_OF_OPERATION = 5;
     78     public static final int CERTIFICATE_HOLD = 6;
     79     // note 7 missing in syntax
     80     public static final int REMOVE_FROM_CRL = 8;
     81     public static final int PRIVILEGE_WITHDRAWN = 9;
     82     public static final int AA_COMPROMISE = 10;
     83 
     84     private static CRLReason[] values = CRLReason.values();
     85 
     86     private int reasonCode = 0;
     87 
     88     private void encodeThis() throws IOException {
     89         if (reasonCode == 0) {
     90             this.extensionValue = null;
     91             return;
     92         }
     93         DerOutputStream dos = new DerOutputStream();
     94         dos.putEnumerated(reasonCode);
     95         this.extensionValue = dos.toByteArray();
     96     }
     97 
     98     /**
     99      * Create a CRLReasonCodeExtension with the passed in reason.
    100      * Criticality automatically set to false.
    101      *
    102      * @param reason the enumerated value for the reason code.
    103      */
    104     public CRLReasonCodeExtension(int reason) throws IOException {
    105         this(false, reason);
    106     }
    107 
    108     /**
    109      * Create a CRLReasonCodeExtension with the passed in reason.
    110      *
    111      * @param critical true if the extension is to be treated as critical.
    112      * @param reason the enumerated value for the reason code.
    113      */
    114     public CRLReasonCodeExtension(boolean critical, int reason)
    115     throws IOException {
    116         this.extensionId = PKIXExtensions.ReasonCode_Id;
    117         this.critical = critical;
    118         this.reasonCode = reason;
    119         encodeThis();
    120     }
    121 
    122     /**
    123      * Create the extension from the passed DER encoded value of the same.
    124      *
    125      * @param critical true if the extension is to be treated as critical.
    126      * @param value an array of DER encoded bytes of the actual value.
    127      * @exception ClassCastException if value is not an array of bytes
    128      * @exception IOException on error.
    129      */
    130     public CRLReasonCodeExtension(Boolean critical, Object value)
    131     throws IOException {
    132         this.extensionId = PKIXExtensions.ReasonCode_Id;
    133         this.critical = critical.booleanValue();
    134         this.extensionValue = (byte[]) value;
    135         DerValue val = new DerValue(this.extensionValue);
    136         this.reasonCode = val.getEnumerated();
    137     }
    138 
    139     /**
    140      * Set the attribute value.
    141      */
    142     public void set(String name, Object obj) throws IOException {
    143         if (!(obj instanceof Integer)) {
    144             throw new IOException("Attribute must be of type Integer.");
    145         }
    146         if (name.equalsIgnoreCase(REASON)) {
    147             reasonCode = ((Integer)obj).intValue();
    148         } else {
    149             throw new IOException
    150                 ("Name not supported by CRLReasonCodeExtension");
    151         }
    152         encodeThis();
    153     }
    154 
    155     /**
    156      * Get the attribute value.
    157      */
    158     public Object get(String name) throws IOException {
    159         if (name.equalsIgnoreCase(REASON)) {
    160             return new Integer(reasonCode);
    161         } else {
    162             throw new IOException
    163                 ("Name not supported by CRLReasonCodeExtension");
    164         }
    165     }
    166 
    167     /**
    168      * Delete the attribute value.
    169      */
    170     public void delete(String name) throws IOException {
    171         if (name.equalsIgnoreCase(REASON)) {
    172             reasonCode = 0;
    173         } else {
    174             throw new IOException
    175                 ("Name not supported by CRLReasonCodeExtension");
    176         }
    177         encodeThis();
    178     }
    179 
    180     /**
    181      * Returns a printable representation of the Reason code.
    182      */
    183     public String toString() {
    184         return super.toString() + "    Reason Code: " + values[reasonCode];
    185     }
    186 
    187     /**
    188      * Write the extension to the DerOutputStream.
    189      *
    190      * @param out the DerOutputStream to write the extension to.
    191      * @exception IOException on encoding errors.
    192      */
    193     public void encode(OutputStream out) throws IOException {
    194         DerOutputStream  tmp = new DerOutputStream();
    195 
    196         if (this.extensionValue == null) {
    197             this.extensionId = PKIXExtensions.ReasonCode_Id;
    198             this.critical = false;
    199             encodeThis();
    200         }
    201         super.encode(tmp);
    202         out.write(tmp.toByteArray());
    203     }
    204 
    205     /**
    206      * Return an enumeration of names of attributes existing within this
    207      * attribute.
    208      */
    209     public Enumeration<String> getElements() {
    210         AttributeNameEnumeration elements = new AttributeNameEnumeration();
    211         elements.addElement(REASON);
    212 
    213         return elements.elements();
    214     }
    215 
    216     /**
    217      * Return the name of this attribute.
    218      */
    219     public String getName() {
    220         return NAME;
    221     }
    222 
    223     /**
    224      * Return the reason as a CRLReason enum.
    225      */
    226     public CRLReason getReasonCode() {
    227         // if out-of-range, return UNSPECIFIED
    228         if (reasonCode > 0 && reasonCode < values.length) {
    229             return values[reasonCode];
    230         } else {
    231             return CRLReason.UNSPECIFIED;
    232         }
    233     }
    234 }
    235