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
26package sun.security.x509;
27
28import java.io.IOException;
29import java.io.InputStream;
30import java.io.OutputStream;
31import java.util.Enumeration;
32
33import sun.security.util.*;
34
35/**
36 * This class defines the version of the X509 Certificate.
37 *
38 * @author Amit Kapoor
39 * @author Hemma Prafullchandra
40 * @see CertAttrSet
41 */
42public class CertificateVersion implements CertAttrSet<String> {
43    /**
44     * X509Certificate Version 1
45     */
46    public static final int     V1 = 0;
47    /**
48     * X509Certificate Version 2
49     */
50    public static final int     V2 = 1;
51    /**
52     * X509Certificate Version 3
53     */
54    public static final int     V3 = 2;
55    /**
56     * Identifier for this attribute, to be used with the
57     * get, set, delete methods of Certificate, x509 type.
58     */
59    public static final String IDENT = "x509.info.version";
60    /**
61     * Sub attributes name for this CertAttrSet.
62     */
63    public static final String NAME = "version";
64    public static final String VERSION = "number";
65
66    // Private data members
67    int version = V1;
68
69    // Returns the version number.
70    private int getVersion() {
71        return(version);
72    }
73
74    // Construct the class from the passed DerValue
75    private void construct(DerValue derVal) throws IOException {
76        if (derVal.isConstructed() && derVal.isContextSpecific()) {
77            derVal = derVal.data.getDerValue();
78            version = derVal.getInteger();
79            if (derVal.data.available() != 0) {
80                throw new IOException("X.509 version, bad format");
81            }
82        }
83    }
84
85    /**
86     * The default constructor for this class,
87     *  sets the version to 0 (i.e. X.509 version 1).
88     */
89    public CertificateVersion() {
90        version = V1;
91    }
92
93    /**
94     * The constructor for this class for the required version.
95     *
96     * @param version the version for the certificate.
97     * @exception IOException if the version is not valid.
98     */
99    public CertificateVersion(int version) throws IOException {
100
101        // check that it is a valid version
102        if (version == V1 || version == V2 || version == V3)
103            this.version = version;
104        else {
105            throw new IOException("X.509 Certificate version " +
106                                   version + " not supported.\n");
107        }
108    }
109
110    /**
111     * Create the object, decoding the values from the passed DER stream.
112     *
113     * @param in the DerInputStream to read the CertificateVersion from.
114     * @exception IOException on decoding errors.
115     */
116    public CertificateVersion(DerInputStream in) throws IOException {
117        version = V1;
118        DerValue derVal = in.getDerValue();
119
120        construct(derVal);
121    }
122
123    /**
124     * Create the object, decoding the values from the passed stream.
125     *
126     * @param in the InputStream to read the CertificateVersion from.
127     * @exception IOException on decoding errors.
128     */
129    public CertificateVersion(InputStream in) throws IOException {
130        version = V1;
131        DerValue derVal = new DerValue(in);
132
133        construct(derVal);
134    }
135
136    /**
137     * Create the object, decoding the values from the passed DerValue.
138     *
139     * @param val the Der encoded value.
140     * @exception IOException on decoding errors.
141     */
142    public CertificateVersion(DerValue val) throws IOException {
143        version = V1;
144
145        construct(val);
146    }
147
148    /**
149     * Return the version number of the certificate.
150     */
151    public String toString() {
152        return("Version: V" + (version+1));
153    }
154
155    /**
156     * Encode the CertificateVersion period in DER form to the stream.
157     *
158     * @param out the OutputStream to marshal the contents to.
159     * @exception IOException on errors.
160     */
161    public void encode(OutputStream out) throws IOException {
162        // Nothing for default
163        if (version == V1) {
164            return;
165        }
166        DerOutputStream tmp = new DerOutputStream();
167        tmp.putInteger(version);
168
169        DerOutputStream seq = new DerOutputStream();
170        seq.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0),
171                  tmp);
172
173        out.write(seq.toByteArray());
174    }
175
176    /**
177     * Set the attribute value.
178     */
179    public void set(String name, Object obj) throws IOException {
180        if (!(obj instanceof Integer)) {
181            throw new IOException("Attribute must be of type Integer.");
182        }
183        if (name.equalsIgnoreCase(VERSION)) {
184            version = ((Integer)obj).intValue();
185        } else {
186            throw new IOException("Attribute name not recognized by " +
187                                  "CertAttrSet: CertificateVersion.");
188        }
189    }
190
191    /**
192     * Get the attribute value.
193     */
194    public Integer get(String name) throws IOException {
195        if (name.equalsIgnoreCase(VERSION)) {
196            return(getVersion());
197        } else {
198            throw new IOException("Attribute name not recognized by " +
199                                  "CertAttrSet: CertificateVersion.");
200        }
201    }
202
203    /**
204     * Delete the attribute value.
205     */
206    public void delete(String name) throws IOException {
207        if (name.equalsIgnoreCase(VERSION)) {
208            version = V1;
209        } else {
210            throw new IOException("Attribute name not recognized by " +
211                                  "CertAttrSet: CertificateVersion.");
212        }
213    }
214
215    /**
216     * Return an enumeration of names of attributes existing within this
217     * attribute.
218     */
219    public Enumeration<String> getElements() {
220        AttributeNameEnumeration elements = new AttributeNameEnumeration();
221        elements.addElement(VERSION);
222
223        return (elements.elements());
224    }
225
226    /**
227     * Return the name of this attribute.
228     */
229    public String getName() {
230        return(NAME);
231    }
232
233    /**
234     * Compare versions.
235     */
236    public int compare(int vers) {
237        return(version - vers);
238    }
239}
240