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.InputStream;
30 import java.io.OutputStream;
31 import java.util.Enumeration;
32 
33 import sun.security.util.*;
34 
35 /**
36  * Represent the CRL Reason Flags.
37  *
38  * <p>This extension, if present, defines the identifies
39  * the reason for the certificate revocation.
40  * <p>The ASN.1 syntax for this is:
41  * <pre>
42  * ReasonFlags ::= BIT STRING {
43  *    unused                  (0),
44  *    keyCompromise           (1),
45  *    cACompromise            (2),
46  *    affiliationChanged      (3),
47  *    superseded              (4),
48  *    cessationOfOperation    (5),
49  *    certificateHold         (6),
50  *    privilegeWithdrawn      (7),
51  *    aACompromise            (8) }
52  * </pre>
53  *
54  * @author Hemma Prafullchandra
55  */
56 public class ReasonFlags {
57 
58     /**
59      * Reasons
60      */
61     public static final String UNUSED = "unused";
62     public static final String KEY_COMPROMISE = "key_compromise";
63     public static final String CA_COMPROMISE = "ca_compromise";
64     public static final String AFFILIATION_CHANGED = "affiliation_changed";
65     public static final String SUPERSEDED = "superseded";
66     public static final String CESSATION_OF_OPERATION
67                                    = "cessation_of_operation";
68     public static final String CERTIFICATE_HOLD = "certificate_hold";
69     public static final String PRIVILEGE_WITHDRAWN = "privilege_withdrawn";
70     public static final String AA_COMPROMISE = "aa_compromise";
71 
72     private final static String[] NAMES = {
73         UNUSED,
74         KEY_COMPROMISE,
75         CA_COMPROMISE,
76         AFFILIATION_CHANGED,
77         SUPERSEDED,
78         CESSATION_OF_OPERATION,
79         CERTIFICATE_HOLD,
80         PRIVILEGE_WITHDRAWN,
81         AA_COMPROMISE,
82     };
83 
name2Index(String name)84     private static int name2Index(String name) throws IOException {
85         for( int i=0; i<NAMES.length; i++ ) {
86             if( NAMES[i].equalsIgnoreCase(name) ) {
87                 return i;
88             }
89         }
90         throw new IOException("Name not recognized by ReasonFlags");
91     }
92 
93     // Private data members
94     private boolean[] bitString;
95 
96     /**
97      * Check if bit is set.
98      *
99      * @param position the position in the bit string to check.
100      */
isSet(int position)101     private boolean isSet(int position) {
102         return (position < bitString.length) &&
103                 bitString[position];
104     }
105 
106     /**
107      * Set the bit at the specified position.
108      */
set(int position, boolean val)109     private void set(int position, boolean val) {
110         // enlarge bitString if necessary
111         if (position >= bitString.length) {
112             boolean[] tmp = new boolean[position+1];
113             System.arraycopy(bitString, 0, tmp, 0, bitString.length);
114             bitString = tmp;
115         }
116         bitString[position] = val;
117     }
118 
119     /**
120      * Create a ReasonFlags with the passed bit settings.
121      *
122      * @param reasons the bits to be set for the ReasonFlags.
123      */
ReasonFlags(byte[] reasons)124     public ReasonFlags(byte[] reasons) {
125         bitString = new BitArray(reasons.length*8, reasons).toBooleanArray();
126     }
127 
128     /**
129      * Create a ReasonFlags with the passed bit settings.
130      *
131      * @param reasons the bits to be set for the ReasonFlags.
132      */
ReasonFlags(boolean[] reasons)133     public ReasonFlags(boolean[] reasons) {
134         this.bitString = reasons;
135     }
136 
137     /**
138      * Create a ReasonFlags with the passed bit settings.
139      *
140      * @param reasons the bits to be set for the ReasonFlags.
141      */
ReasonFlags(BitArray reasons)142     public ReasonFlags(BitArray reasons) {
143         this.bitString = reasons.toBooleanArray();
144     }
145 
146     /**
147      * Create the object from the passed DER encoded value.
148      *
149      * @param in the DerInputStream to read the ReasonFlags from.
150      * @exception IOException on decoding errors.
151      */
ReasonFlags(DerInputStream in)152     public ReasonFlags(DerInputStream in) throws IOException {
153         DerValue derVal = in.getDerValue();
154         this.bitString = derVal.getUnalignedBitString(true).toBooleanArray();
155     }
156 
157     /**
158      * Create the object from the passed DER encoded value.
159      *
160      * @param derVal the DerValue decoded from the stream.
161      * @exception IOException on decoding errors.
162      */
ReasonFlags(DerValue derVal)163     public ReasonFlags(DerValue derVal) throws IOException {
164         this.bitString = derVal.getUnalignedBitString(true).toBooleanArray();
165     }
166 
167     /**
168      * Returns the reason flags as a boolean array.
169      */
getFlags()170     public boolean[] getFlags() {
171         return bitString;
172     }
173 
174     /**
175      * Set the attribute value.
176      */
set(String name, Object obj)177     public void set(String name, Object obj) throws IOException {
178         if (!(obj instanceof Boolean)) {
179             throw new IOException("Attribute must be of type Boolean.");
180         }
181         boolean val = ((Boolean)obj).booleanValue();
182         set(name2Index(name), val);
183     }
184 
185     /**
186      * Get the attribute value.
187      */
get(String name)188     public Object get(String name) throws IOException {
189         return Boolean.valueOf(isSet(name2Index(name)));
190     }
191 
192     /**
193      * Delete the attribute value.
194      */
delete(String name)195     public void delete(String name) throws IOException {
196         set(name, Boolean.FALSE);
197     }
198 
199     /**
200      * Returns a printable representation of the ReasonFlags.
201      */
toString()202     public String toString() {
203         StringBuilder sb = new StringBuilder("Reason Flags [\n");
204 
205         if (isSet(0)) {
206             sb.append("  Unused\n");
207         }
208         if (isSet(1)) {
209             sb.append("  Key Compromise\n");
210         }
211         if (isSet(2)) {
212             sb.append("  CA Compromise\n");
213         }
214         if (isSet(3)) {
215             sb.append("  Affiliation_Changed\n");
216         }
217         if (isSet(4)) {
218             sb.append("  Superseded\n");
219         }
220         if (isSet(5)) {
221             sb.append("  Cessation Of Operation\n");
222         }
223         if (isSet(6)) {
224             sb.append("  Certificate Hold\n");
225         }
226         if (isSet(7)) {
227             sb.append("  Privilege Withdrawn\n");
228         }
229         if (isSet(8)) {
230             sb.append("  AA Compromise\n");
231         }
232         sb.append("]\n");
233 
234         return sb.toString();
235     }
236 
237     /**
238      * Write the extension to the DerOutputStream.
239      *
240      * @param out the DerOutputStream to write the extension to.
241      * @exception IOException on encoding errors.
242      */
encode(DerOutputStream out)243     public void encode(DerOutputStream out) throws IOException {
244         out.putTruncatedUnalignedBitString(new BitArray(this.bitString));
245     }
246 
247     /**
248      * Return an enumeration of names of attributes existing within this
249      * attribute.
250      */
getElements()251     public Enumeration<String> getElements () {
252         AttributeNameEnumeration elements = new AttributeNameEnumeration();
253         for( int i=0; i<NAMES.length; i++ ) {
254             elements.addElement(NAMES[i]);
255         }
256         return (elements.elements());
257     }
258 }
259