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.math.BigInteger;
31 import java.util.Enumeration;
32 
33 import sun.security.util.*;
34 
35 /**
36  * Represent the CRL Number Extension.
37  *
38  * <p>This extension, if present, conveys a monotonically increasing
39  * sequence number for each CRL issued by a given CA through a specific
40  * CA X.500 Directory entry or CRL distribution point. This extension
41  * allows users to easily determine when a particular CRL supersedes
42  * another CRL.
43  *
44  * @author Hemma Prafullchandra
45  * @see Extension
46  * @see CertAttrSet
47  */
48 public class CRLNumberExtension extends Extension
49 implements CertAttrSet<String> {
50 
51     /**
52      * Attribute name.
53      */
54     public static final String NAME = "CRLNumber";
55     public static final String NUMBER = "value";
56 
57     private static final String LABEL = "CRL Number";
58 
59     private BigInteger crlNumber = null;
60     private String extensionName;
61     private String extensionLabel;
62 
63     // Encode this extension value
encodeThis()64     private void encodeThis() throws IOException {
65         if (crlNumber == null) {
66             this.extensionValue = null;
67             return;
68         }
69         DerOutputStream os = new DerOutputStream();
70         os.putInteger(this.crlNumber);
71         this.extensionValue = os.toByteArray();
72     }
73 
74     /**
75      * Create a CRLNumberExtension with the integer value .
76      * The criticality is set to false.
77      *
78      * @param crlNum the value to be set for the extension.
79      */
CRLNumberExtension(int crlNum)80     public CRLNumberExtension(int crlNum) throws IOException {
81         this(PKIXExtensions.CRLNumber_Id, false, BigInteger.valueOf(crlNum),
82         NAME, LABEL);
83     }
84 
85     /**
86      * Create a CRLNumberExtension with the BigInteger value .
87      * The criticality is set to false.
88      *
89      * @param crlNum the value to be set for the extension.
90      */
CRLNumberExtension(BigInteger crlNum)91     public CRLNumberExtension(BigInteger crlNum) throws IOException {
92         this(PKIXExtensions.CRLNumber_Id, false, crlNum, NAME, LABEL);
93     }
94 
95     /**
96      * Creates the extension (also called by the subclass).
97      */
CRLNumberExtension(ObjectIdentifier extensionId, boolean isCritical, BigInteger crlNum, String extensionName, String extensionLabel)98     protected CRLNumberExtension(ObjectIdentifier extensionId,
99         boolean isCritical, BigInteger crlNum, String extensionName,
100         String extensionLabel) throws IOException {
101 
102         this.extensionId = extensionId;
103         this.critical = isCritical;
104         this.crlNumber = crlNum;
105         this.extensionName = extensionName;
106         this.extensionLabel = extensionLabel;
107         encodeThis();
108     }
109 
110     /**
111      * Create the extension from the passed DER encoded value of the same.
112      *
113      * @param critical true if the extension is to be treated as critical.
114      * @param value an array of DER encoded bytes of the actual value.
115      * @exception ClassCastException if value is not an array of bytes
116      * @exception IOException on error.
117      */
CRLNumberExtension(Boolean critical, Object value)118     public CRLNumberExtension(Boolean critical, Object value)
119     throws IOException {
120         this(PKIXExtensions.CRLNumber_Id, critical, value, NAME, LABEL);
121     }
122 
123     /**
124      * Creates the extension (also called by the subclass).
125      */
CRLNumberExtension(ObjectIdentifier extensionId, Boolean critical, Object value, String extensionName, String extensionLabel)126     protected CRLNumberExtension(ObjectIdentifier extensionId,
127         Boolean critical, Object value, String extensionName,
128         String extensionLabel) throws IOException {
129 
130         this.extensionId = extensionId;
131         this.critical = critical.booleanValue();
132         this.extensionValue = (byte[]) value;
133         DerValue val = new DerValue(this.extensionValue);
134         this.crlNumber = val.getBigInteger();
135         this.extensionName = extensionName;
136         this.extensionLabel = extensionLabel;
137     }
138 
139     /**
140      * Set the attribute value.
141      */
set(String name, Object obj)142     public void set(String name, Object obj) throws IOException {
143         if (name.equalsIgnoreCase(NUMBER)) {
144             if (!(obj instanceof BigInteger)) {
145                 throw new IOException("Attribute must be of type BigInteger.");
146             }
147             crlNumber = (BigInteger)obj;
148         } else {
149           throw new IOException("Attribute name not recognized by"
150                                 + " CertAttrSet:" + extensionName + ".");
151         }
152         encodeThis();
153     }
154 
155     /**
156      * Get the attribute value.
157      */
get(String name)158     public BigInteger get(String name) throws IOException {
159         if (name.equalsIgnoreCase(NUMBER)) {
160             if (crlNumber == null) return null;
161             else return crlNumber;
162         } else {
163           throw new IOException("Attribute name not recognized by"
164                                 + " CertAttrSet:" + extensionName + ".");
165         }
166     }
167 
168     /**
169      * Delete the attribute value.
170      */
delete(String name)171     public void delete(String name) throws IOException {
172         if (name.equalsIgnoreCase(NUMBER)) {
173             crlNumber = null;
174         } else {
175           throw new IOException("Attribute name not recognized by"
176                                 + " CertAttrSet:" + extensionName + ".");
177         }
178         encodeThis();
179     }
180 
181     /**
182      * Returns a printable representation of the CRLNumberExtension.
183      */
toString()184     public String toString() {
185         String s = super.toString() + extensionLabel + ": " +
186                    ((crlNumber == null) ? "" : Debug.toHexString(crlNumber))
187                    + "\n";
188         return (s);
189     }
190 
191     /**
192      * Write the extension to the DerOutputStream.
193      *
194      * @param out the DerOutputStream to write the extension to.
195      * @exception IOException on encoding errors.
196      */
encode(OutputStream out)197     public void encode(OutputStream out) throws IOException {
198        DerOutputStream  tmp = new DerOutputStream();
199         encode(out, PKIXExtensions.CRLNumber_Id, true);
200     }
201 
202     /**
203      * Write the extension to the DerOutputStream.
204      * (Also called by the subclass)
205      */
encode(OutputStream out, ObjectIdentifier extensionId, boolean isCritical)206     protected void encode(OutputStream out, ObjectIdentifier extensionId,
207         boolean isCritical) throws IOException {
208 
209        DerOutputStream  tmp = new DerOutputStream();
210 
211        if (this.extensionValue == null) {
212            this.extensionId = extensionId;
213            this.critical = isCritical;
214            encodeThis();
215        }
216        super.encode(tmp);
217        out.write(tmp.toByteArray());
218     }
219 
220     /**
221      * Return an enumeration of names of attributes existing within this
222      * attribute.
223      */
getElements()224     public Enumeration<String> getElements() {
225         AttributeNameEnumeration elements = new AttributeNameEnumeration();
226         elements.addElement(NUMBER);
227         return (elements.elements());
228     }
229 
230     /**
231      * Return the name of this attribute.
232      */
getName()233     public String getName() {
234         return (extensionName);
235     }
236 }
237