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             return crlNumber;
161         } else {
162             throw new IOException("Attribute name not recognized by" +
163                                   " CertAttrSet:" + extensionName + '.');
164         }
165     }
166 
167     /**
168      * Delete the attribute value.
169      */
delete(String name)170     public void delete(String name) throws IOException {
171         if (name.equalsIgnoreCase(NUMBER)) {
172             crlNumber = null;
173         } else {
174             throw new IOException("Attribute name not recognized by" +
175                                   " CertAttrSet:" + extensionName + '.');
176         }
177         encodeThis();
178     }
179 
180     /**
181      * Returns a printable representation of the CRLNumberExtension.
182      */
toString()183     public String toString() {
184         StringBuilder sb = new StringBuilder();
185         sb.append(super.toString())
186             .append(extensionLabel)
187             .append(": ");
188         if (crlNumber != null) {
189             sb.append(Debug.toHexString(crlNumber));
190         }
191         sb.append('\n');
192         return sb.toString();
193     }
194 
195     /**
196      * Write the extension to the DerOutputStream.
197      *
198      * @param out the DerOutputStream to write the extension to.
199      * @exception IOException on encoding errors.
200      */
encode(OutputStream out)201     public void encode(OutputStream out) throws IOException {
202         DerOutputStream tmp = new DerOutputStream();
203         encode(out, PKIXExtensions.CRLNumber_Id, true);
204     }
205 
206     /**
207      * Write the extension to the DerOutputStream.
208      * (Also called by the subclass)
209      */
encode(OutputStream out, ObjectIdentifier extensionId, boolean isCritical)210     protected void encode(OutputStream out, ObjectIdentifier extensionId,
211         boolean isCritical) throws IOException {
212 
213        DerOutputStream  tmp = new DerOutputStream();
214 
215        if (this.extensionValue == null) {
216            this.extensionId = extensionId;
217            this.critical = isCritical;
218            encodeThis();
219        }
220        super.encode(tmp);
221        out.write(tmp.toByteArray());
222     }
223 
224     /**
225      * Return an enumeration of names of attributes existing within this
226      * attribute.
227      */
getElements()228     public Enumeration<String> getElements() {
229         AttributeNameEnumeration elements = new AttributeNameEnumeration();
230         elements.addElement(NUMBER);
231         return (elements.elements());
232     }
233 
234     /**
235      * Return the name of this attribute.
236      */
getName()237     public String getName() {
238         return (extensionName);
239     }
240 }
241